174 lines
5.3 KiB
C
174 lines
5.3 KiB
C
#include "unit_actions.h"
|
|
#include "game_state.h"
|
|
#include "components.h"
|
|
#include "systems/systems.h"
|
|
|
|
#include <raymath.h>
|
|
|
|
void actionMoveTo(ecs_entity_t entity, Action *action, Game *game) {
|
|
if (action->finished) return;
|
|
const Vector2 target = action->as.moveTo.target;
|
|
if (!ecs_has(ECS, entity, Path)) {
|
|
entitySetPath(entity, target, game);
|
|
return;
|
|
}
|
|
const f32 dt = GetFrameTime();
|
|
const Vector2 pos = *ecs_get(ECS, entity, Position);
|
|
if (ecs_has(ECS, entity, Orientation)) {
|
|
Orientation *orientation = ecs_get_mut(ECS, entity, Orientation);
|
|
f32 dif = Vector2Angle(pos, target) - *orientation;
|
|
dif = Clamp(dif, -10, 10) * dt * 10;
|
|
*orientation += dif;
|
|
}
|
|
f32 dst = Vector2Distance(pos, target);
|
|
if (dst < action->as.moveTo.proximityThreshold) {
|
|
action->finished = true;
|
|
ecs_remove(ECS, entity, Path);
|
|
}
|
|
}
|
|
void actionCollectResource(ecs_entity_t entity, Action *action, Game *game) {
|
|
if (action->finished) return;
|
|
BZ_ASSERT(ecs_has(ECS, entity, Worker));
|
|
Worker *worker = ecs_get_mut(ECS, entity, Worker);
|
|
|
|
if (worker->carry >= worker->carryCapacity) {
|
|
action->finished = true;
|
|
}
|
|
|
|
ecs_entity_t target = action->as.collectResource.entity;
|
|
bool targetAlive = ecs_is_alive(ECS, target);
|
|
action->finished |= !targetAlive;
|
|
|
|
if (!action->finished && action->elapsed > worker->collectSpeed) {
|
|
i32 spareCapacity = worker->carryCapacity - worker->carry;
|
|
i32 collected = harvestEvent(target, (HarvestEvent) {
|
|
.amount = BZ_MIN(1, spareCapacity),
|
|
});
|
|
worker->carry += collected;
|
|
action->elapsed = 0;
|
|
}
|
|
|
|
}
|
|
void actionDepositResource(ecs_entity_t entity, Action *action, Game *game) {
|
|
if (action->finished) return;
|
|
|
|
BZ_ASSERT(ecs_has(ECS, entity, Worker));
|
|
Worker *worker = ecs_get_mut(ECS, entity, Worker);
|
|
|
|
if (worker->carry == 0) {
|
|
action->finished = true;
|
|
}
|
|
ecs_entity_t target = action->as.depositResource.entity;
|
|
bool targetAlive = ecs_is_alive(ECS, target);
|
|
action->finished |= !targetAlive;
|
|
|
|
if (!action->finished && action->elapsed > worker->depositSpeed) {
|
|
depositEvent(target, (DepositEvent) {
|
|
.amount = worker->carry
|
|
});
|
|
worker->carry = 0;
|
|
action->finished = true;
|
|
}
|
|
}
|
|
|
|
void handleAction(ecs_entity_t entity, UnitAction *unitAction, Game *game) {
|
|
Action *action = unitAction->first;
|
|
if (action == NULL) return;
|
|
if (action->finished || action->failed) return;
|
|
switch (action->type) {
|
|
case ACTION_NONE:
|
|
break;
|
|
case ACTION_MOVE_TO:
|
|
actionMoveTo(entity, action, game);
|
|
break;
|
|
case ACTION_COLLECT_RESOURCE:
|
|
actionCollectResource(entity, action, game);
|
|
break;
|
|
case ACTION_DEPOSIT_RESOURCE:
|
|
actionDepositResource(entity, action, game);
|
|
break;
|
|
default:
|
|
BZ_ASSERT(0);
|
|
break;
|
|
}
|
|
|
|
}
|
|
void updateAction(UnitAction *unitAction, Game *game) {
|
|
Action *action = unitAction->first;
|
|
if (action == NULL) return;
|
|
if (action->failed) return;
|
|
action->elapsed += GetFrameTime();
|
|
if (action->finished) {
|
|
unitAction->first = action->next;
|
|
if (unitAction->last == action) {
|
|
unitAction->last = NULL;
|
|
BZ_ASSERT(unitAction->first == unitAction->last);
|
|
}
|
|
BzObjectPool *pool = game->pools.actions;
|
|
bzObjectPoolRelease(pool, action);
|
|
}
|
|
}
|
|
void clearActions(ecs_entity_t entity, Game *game) {
|
|
if (!ecs_has(ECS, entity, UnitAction)) return;
|
|
UnitAction *unitAction = ecs_get_mut(ECS, entity, UnitAction);
|
|
|
|
BzObjectPool *pool = game->pools.actions;
|
|
|
|
Action *pAction = unitAction->first;
|
|
while (pAction) {
|
|
bzObjectPoolRelease(pool, pAction);
|
|
pAction = pAction->next;
|
|
}
|
|
|
|
unitAction->first = NULL;
|
|
unitAction->last = NULL;
|
|
}
|
|
void addAction(ecs_entity_t entity, Game *game, const Action *action) {
|
|
BZ_ASSERT(action);
|
|
BZ_ASSERT(ecs_has(ECS, entity, UnitAction));
|
|
|
|
UnitAction *unitAction = ecs_get_mut(ECS, entity, UnitAction);
|
|
BzObjectPool *pool = game->pools.actions;
|
|
|
|
Action *newAction = bzObjectPool(pool);
|
|
BZ_ASSERT(newAction);
|
|
*newAction = *action;
|
|
|
|
newAction->next = NULL;
|
|
if (unitAction->last) {
|
|
Action *last = unitAction->last;
|
|
last->next = newAction;
|
|
unitAction->last = newAction;
|
|
} else {
|
|
unitAction->first = newAction;
|
|
unitAction->last = newAction;
|
|
}
|
|
}
|
|
void prependAction(ecs_entity_t entity, Game *game, const Action *action) {
|
|
BZ_ASSERT(action);
|
|
BZ_ASSERT(ecs_has(ECS, entity, UnitAction));
|
|
|
|
UnitAction *unitAction = ecs_get_mut(ECS, entity, UnitAction);
|
|
BzObjectPool *pool = game->pools.actions;
|
|
|
|
Action *newAction = bzObjectPool(pool);
|
|
BZ_ASSERT(newAction);
|
|
*newAction = *action;
|
|
|
|
newAction->next = unitAction->first;
|
|
unitAction->first = newAction;
|
|
}
|
|
|
|
const char *actionTypeToPrettyStr(ActionType type) {
|
|
switch (type) {
|
|
case ACTION_MOVE_TO:
|
|
return "MOVE TO";
|
|
case ACTION_COLLECT_RESOURCE:
|
|
return "COLLECT RESOURCE";
|
|
case ACTION_DEPOSIT_RESOURCE:
|
|
return "DEPOSIT RESOURCE";
|
|
default:
|
|
return "NONE";
|
|
}
|
|
}
|