diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b6b810..64668ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,14 @@ add_subdirectory(engine/) add_executable(PixelDefense + game/systems/s_ai.c + game/systems/s_animation.c + game/systems/s_entity.c + game/systems/s_event.c + game/systems/s_input.c + game/systems/s_ui.c + game/systems/systems.h + game/buildings.c game/buildings.h game/components.c @@ -23,11 +31,6 @@ add_executable(PixelDefense game/map_layers.h game/pathfinding.c game/pathfinding.h - game/systems.h - game/systems_ai.c - game/systems_entity.c - game/systems_input.c - game/systems_ui.c game/ui_widgets.c game/ui_widgets.h game/unit_actions.c diff --git a/game/components.c b/game/components.c index 06db7ad..3d41350 100644 --- a/game/components.c +++ b/game/components.c @@ -21,6 +21,9 @@ ECS_COMPONENT_DECLARE(Path); ECS_COMPONENT_DECLARE(TextureRegion); ECS_COMPONENT_DECLARE(Animation); +ECS_COMPONENT_DECLARE(Easing); + +ECS_COMPONENT_DECLARE(HarvestEvent); ECS_COMPONENT_DECLARE(UnitAI); ECS_COMPONENT_DECLARE(UnitAction); @@ -29,7 +32,7 @@ ECS_TAG_DECLARE(Selectable); ECS_TAG_DECLARE(Selected); ECS_TAG_DECLARE(Unit); -ECS_TAG_DECLARE(Worker); +ECS_COMPONENT_DECLARE(Worker); ECS_TAG_DECLARE(Harvestable); ECS_TAG_DECLARE(Buildable); ECS_TAG_DECLARE(Workable); @@ -56,6 +59,9 @@ void initComponentIDs(ecs_world_t *ecs) { ECS_COMPONENT_DEFINE(ecs, TextureRegion); ECS_COMPONENT_DEFINE(ecs, Animation); + ECS_COMPONENT_DEFINE(ecs, Easing); + + ECS_COMPONENT_DEFINE(ecs, HarvestEvent); ECS_COMPONENT_DEFINE(ecs, UnitAI); ECS_COMPONENT_DEFINE(ecs, UnitAction); @@ -64,7 +70,7 @@ void initComponentIDs(ecs_world_t *ecs) { ECS_TAG_DEFINE(ecs, Selected); ECS_TAG_DEFINE(ecs, Unit); - ECS_TAG_DEFINE(ecs, Worker); + ECS_COMPONENT_DEFINE(ecs, Worker); ECS_TAG_DEFINE(ecs, Harvestable); ECS_TAG_DEFINE(ecs, Buildable); ECS_TAG_DEFINE(ecs, Workable); diff --git a/game/components.h b/game/components.h index 6edf69d..43cc8ba 100644 --- a/game/components.h +++ b/game/components.h @@ -86,7 +86,6 @@ extern ECS_COMPONENT_DECLARE(Path); typedef struct TextureRegion { Texture2D texture; Rectangle rec; - f32 rotation; bool flipX : 1; bool flipY : 1; } TextureRegion; @@ -109,12 +108,49 @@ typedef struct Animation { } Animation; extern ECS_COMPONENT_DECLARE(Animation); +typedef enum EasingType { + EASE_ROTATION, + EASE_POS_X, + EASE_POS_Y, + EASE_SIZE_X, + EASE_SIZE_Y, +} EasingType; + +typedef struct Easing { + EasingType type; + BzEaseType easingFunc; + + // start + target * (easeStart + (easeTarget * x) + easeOffset) + offset + + f32 target; + f32 start; + f32 offset; + f32 easeTarget; + f32 easeStart; + f32 easeOffset; + + f32 x; + f32 elapsed; + f32 duration; + + //struct Easing *next; +} Easing; +extern ECS_COMPONENT_DECLARE(Easing); + typedef struct EntityArms { ecs_entity_t left; ecs_entity_t right; } EntityArms; //extern ECS_COMPONENT_DECLARE(EntityArms); +/********************************************************** + * Event components + *********************************************************/ + typedef struct HarvestEvent { + i32 amount; + } HarvestEvent; + extern ECS_COMPONENT_DECLARE(HarvestEvent); + /********************************************************** * Gameplay components *********************************************************/ @@ -134,7 +170,16 @@ extern ECS_TAG_DECLARE(Unit); // - Build // - Work // - Attack (since it is also a unit) -extern ECS_TAG_DECLARE(Worker); +typedef struct Worker { + // stats + f32 collectSpeed; + f32 depositSpeed; + + i32 carry; + i32 carryCapacity; + ResourceType carryRes; +} Worker; +extern ECS_COMPONENT_DECLARE(Worker); extern ECS_TAG_DECLARE(Harvestable); extern ECS_TAG_DECLARE(Buildable); diff --git a/game/main.c b/game/main.c index 62ae331..347b9ca 100644 --- a/game/main.c +++ b/game/main.c @@ -4,7 +4,7 @@ #include #include -#include "systems.h" +#include "systems/systems.h" #include "components.h" #include "game_state.h" #include "game_tileset.h" @@ -228,9 +228,10 @@ bool init(void *userData) { ecs_set_hooks(ECS, Path, { .dtor = ecs_dtor(Path) }); - ECS_OBSERVER(ECS, entityPathRemove, EcsOnRemove, Path); - //ECS_OBSERVER(ECS, entitySetAnimationState, EcsOnSet, Animation, AnimationType); + //setupSystems(ECS) + + ECS_OBSERVER(ECS, entityPathRemove, EcsOnRemove, Path); ECS_SYSTEM(ECS, entityUpdateSpatialID, EcsOnUpdate, Position, Size, Velocity, SpatialGridID); ECS_SYSTEM(ECS, entityUpdateKinematic, EcsOnUpdate, Position, Rotation, Velocity, Steering); @@ -238,14 +239,14 @@ bool init(void *userData) { ECS_SYSTEM(ECS, entityMoveToTarget, EcsOnUpdate, Position, Rotation, Velocity, TargetPosition, Steering); ECS_SYSTEM(ECS, entityFollowPath, EcsOnUpdate, Path); - //ECS_SYSTEM(ECS, entityHarvestTaskSystem, EcsOnUpdate, Position, Rotation, HarvestTask); ECS_SYSTEM(ECS, handleUnitActionsSystem, EcsOnUpdate, UnitAction); ECS_SYSTEM(ECS, updateUnitAISystem, EcsOnUpdate, UnitAI, UnitAction); // Needs to be called after AI update, since it removes finished actions ECS_SYSTEM(ECS, updateUnitActionsSystem, EcsOnUpdate, UnitAction); - ECS_SYSTEM(ECS, entityUpdateAnimationState, EcsOnUpdate, Animation, TextureRegion); - ECS_SYSTEM(ECS, entityUpdateAnimation, EcsOnUpdate, Animation, TextureRegion); + ECS_SYSTEM(ECS, updateAnimationState, EcsOnUpdate, Animation, TextureRegion); + ECS_SYSTEM(ECS, updateAnimation, EcsOnUpdate, Animation, TextureRegion); + ECS_SYSTEM(ECS, updateEasingSystem, EcsOnUpdate, Easing, Position, Size, Rotation); ECS_SYSTEM(ECS, renderDebugPath, EcsOnUpdate, Path); @@ -348,7 +349,9 @@ static void renderGame(Game *game, float dt) { TextureRegion *t = ecs_field(&it, TextureRegion, 4); for (i32 i = 0; i < it.count; i++) { Rectangle dst = {p[i].x, p[i].y, s[i].x, s[i].y}; - Vector2 origin = {dst.width * 0.5f, dst.height * 0.5f}; + Vector2 origin = {dst.width * 0.5f, dst.height}; + dst.x += origin.x - dst.width * 0.5f; + dst.y += origin.y - dst.height * 0.5f; Rectangle src = t[i].rec; if (t[i].flipX) src.width *= -1.0f; if (t[i].flipY) src.height *= -1.0f; @@ -357,7 +360,7 @@ static void renderGame(Game *game, float dt) { .src = src, .dst = dst, .origin = origin, - .rotation = t[i].rotation + .rotation = r[i] }); } } diff --git a/game/map_init.c b/game/map_init.c index 9d3b844..c773077 100644 --- a/game/map_init.c +++ b/game/map_init.c @@ -160,6 +160,10 @@ ecs_entity_t createWorker(Position position, Size size, BzSpatialGrid *grid, BzT ecs_set(ECS, e, UnitAction, {NULL, NULL}); ecs_add_id(ECS, e, Selectable); ecs_add_id(ECS, e, Unit); - ecs_add_id(ECS, e, Worker); + ecs_set(ECS, e, Worker, { + .collectSpeed = 0.8f, + .depositSpeed = 0.2f, + .carryCapacity = 5, + }); return e; } diff --git a/game/systems/s_ai.c b/game/systems/s_ai.c index a557d7d..f5217ea 100644 --- a/game/systems/s_ai.c +++ b/game/systems/s_ai.c @@ -1,9 +1,9 @@ #include "systems.h" -#include "game_state.h" +#include "../game_state.h" -#include "unit_ai.h" -#include "unit_actions.h" +#include "../unit_ai.h" +#include "../unit_actions.h" void handleUnitActionsSystem(ecs_iter_t *it) { Game *game = ecs_singleton_get_mut(ECS, Game); diff --git a/game/systems/s_animation.c b/game/systems/s_animation.c new file mode 100644 index 0000000..669acb0 --- /dev/null +++ b/game/systems/s_animation.c @@ -0,0 +1,97 @@ +#include "systems.h" + +#include "../game_state.h" + +#include + +void updateAnimationState(ecs_iter_t *it) { + Animation *anim = ecs_field(it, Animation, 1); + TextureRegion *text = ecs_field(it, TextureRegion, 2); + for (i32 i = 0; i < it->count; i++) { + ecs_entity_t entity = it->entities[i]; + AnimType type = ANIM_IDLE; + if (ecs_has(ECS, entity, Velocity)) { + Velocity vel = *ecs_get(ECS, entity, Velocity); + f32 len = Vector2Length(vel); + if (len > 1.0f) { + type = ANIM_WALK; + text[i].flipX = vel.x < 0; + } + } + + if (type != anim[i].animType) { + anim[i].animType = type; + anim[i].sequence = entityGetAnimationSequence(anim[i].entityType, type); + anim[i].curFrame = 0; + anim[i].elapsed = 0; + } + } +} +void updateAnimation(ecs_iter_t *it) { + Game *game = ecs_singleton_get_mut(ECS, Game); + Animation *anim = ecs_field(it, Animation, 1); + TextureRegion *texture = ecs_field(it, TextureRegion, 2); + + float dt = GetFrameTime(); + + for (i32 i = 0; i < it->count; i++) { + AnimationFrame frame = anim[i].frame; + AnimationSequence seq = anim[i].sequence; + + anim[i].elapsed += dt; + if (anim[i].elapsed < frame.duration) continue; + + i32 nextFrame = (anim[i].curFrame + 1) % seq.frameCount; + anim[i].curFrame = nextFrame; + anim[i].frame = entityGetAnimationFrame(anim[i].entityType, anim[i].animType, nextFrame); + anim[i].elapsed = 0.0f; + + texture[i].rec = bzTilesetGetTileRegion(anim[i].tileset, anim[i].frame.frame); + } +} + +void updateEasingSystem(ecs_iter_t *it) { + Easing *easing = ecs_field(it, Easing, 1); + Position *position = ecs_field(it, Position, 2); + Size *size = ecs_field(it, Size, 3); + Rotation *rotation = ecs_field(it, Rotation, 4); + + f32 dt = GetFrameTime(); + + for (i32 i = 0; i < it->count; i++) { + ecs_entity_t entity = it->entities[i]; + if (easing[i].elapsed > easing[i].duration) { + ecs_remove(ECS, entity, Easing); + continue; + } + easing[i].elapsed += dt; + f32 alpha = easing[i].elapsed / easing[i].duration; + alpha = BZ_MIN(1.0f, alpha); + easing[i].x = bzEase(easing[i].easingFunc, alpha); + + const Easing *e = &easing[i]; + f32 x = e->x; + // Inner + x = e->easeStart + e->easeTarget * x + e->easeOffset; + // Outer + x = e->start + e->target * x + e->offset; + + switch (easing->type) { + case EASE_ROTATION: + rotation[i] = x; + break; + case EASE_POS_X: + position[i].x = x; + break; + case EASE_POS_Y: + position[i].y = x; + break; + case EASE_SIZE_X: + size[i].x = x; + break; + case EASE_SIZE_Y: + size[i].y = x; + break; + } + } +} diff --git a/game/systems/s_entity.c b/game/systems/s_entity.c index 03d6c4c..7267b2f 100644 --- a/game/systems/s_entity.c +++ b/game/systems/s_entity.c @@ -1,9 +1,9 @@ #include "systems.h" -#include "game_state.h" -#include "input.h" -#include "pathfinding.h" +#include "../game_state.h" +#include "../input.h" +#include "../pathfinding.h" #include #include @@ -88,7 +88,7 @@ void entityUpdateKinematic(ecs_iter_t *it) { Vector2 mouse = input->mouseDownWorld; f32 rot = Vector2Angle(position[i], mouse) + 270 * DEG2RAD; - rotation[i] = rot; + //rotation[i] = rot; } @@ -126,7 +126,7 @@ void entityMoveToTarget(ecs_iter_t *it) { if (Vector2Length(velocity[i]) > 10.0f) { f32 rot = Vector2Angle(position[i], target); - rotation[i] = rot; + //rotation[i] = rot; } if (dst < 8.0f) { @@ -162,52 +162,6 @@ void entityFollowPath(ecs_iter_t *it) { } } -void entityUpdateAnimationState(ecs_iter_t *it) { - Animation *anim = ecs_field(it, Animation, 1); - TextureRegion *text = ecs_field(it, TextureRegion, 2); - for (i32 i = 0; i < it->count; i++) { - ecs_entity_t entity = it->entities[i]; - AnimType type = ANIM_IDLE; - if (ecs_has(ECS, entity, Velocity)) { - Velocity vel = *ecs_get(ECS, entity, Velocity); - f32 len = Vector2Length(vel); - if (len > 1.0f) { - type = ANIM_WALK; - text[i].flipX = vel.x < 0; - } - } - - if (type != anim[i].animType) { - anim[i].animType = type; - anim[i].sequence = entityGetAnimationSequence(anim[i].entityType, type); - anim[i].curFrame = 0; - anim[i].elapsed = 0; - } - } -} -void entityUpdateAnimation(ecs_iter_t *it) { - Game *game = ecs_singleton_get_mut(ECS, Game); - Animation *anim = ecs_field(it, Animation, 1); - TextureRegion *texture = ecs_field(it, TextureRegion, 2); - - float dt = GetFrameTime(); - - for (i32 i = 0; i < it->count; i++) { - AnimationFrame frame = anim[i].frame; - AnimationSequence seq = anim[i].sequence; - - anim[i].elapsed += dt; - if (anim[i].elapsed < frame.duration) continue; - - i32 nextFrame = (anim[i].curFrame + 1) % seq.frameCount; - anim[i].curFrame = nextFrame; - anim[i].frame = entityGetAnimationFrame(anim[i].entityType, anim[i].animType, nextFrame); - anim[i].elapsed = 0.0f; - - texture[i].rec = bzTilesetGetTileRegion(anim[i].tileset, anim[i].frame.frame); - } -} - void renderColliders(ecs_iter_t *it) { Position *pos = ecs_field(it, Position, 1); Size *size = ecs_field(it, Size, 2); diff --git a/game/systems/s_event.c b/game/systems/s_event.c new file mode 100644 index 0000000..adbc44b --- /dev/null +++ b/game/systems/s_event.c @@ -0,0 +1,28 @@ +#include "systems.h" + +#include "../game_state.h" + +i32 harvestEvent(ecs_entity_t entity, HarvestEvent event) { + BZ_ASSERT(ecs_has_id(ECS, entity, Harvestable)); + BZ_ASSERT(ecs_has(ECS, entity, Resource)); + + ecs_set(ECS, entity, Easing, { + .type = EASE_ROTATION, + .easingFunc = BZ_EASE_OUT_ELASTIC, + .duration = 0.4f, + + // 45 * (1.0f + (-1.0f) * x) + .target = 45, + .easeTarget = -1.0f, + .easeStart = 1.0f + }); + + Resource *res = ecs_get_mut(ECS, entity, Resource); + event.amount = BZ_MIN(event.amount, res->amount); + res->amount -= event.amount; + + if (res->amount <= 0) + ecs_delete(ECS, entity); + + return event.amount; +} diff --git a/game/systems/s_input.c b/game/systems/s_input.c index a4e2bd1..2e3957a 100644 --- a/game/systems/s_input.c +++ b/game/systems/s_input.c @@ -1,10 +1,11 @@ #include "systems.h" -#include "game_state.h" -#include "input.h" -#include "buildings.h" -#include "pathfinding.h" -#include "unit_ai.h" -#include "unit_actions.h" + +#include "../game_state.h" +#include "../input.h" +#include "../buildings.h" +#include "../pathfinding.h" +#include "../unit_ai.h" +#include "../unit_actions.h" #include #include diff --git a/game/systems/s_ui.c b/game/systems/s_ui.c index 722f029..56cae2c 100644 --- a/game/systems/s_ui.c +++ b/game/systems/s_ui.c @@ -1,6 +1,6 @@ #include "systems.h" -#include "game_state.h" +#include "../game_state.h" void uiTask(ecs_iter_t *it) { const Game *game = ecs_singleton_get(ECS, Game); diff --git a/game/systems/systems.h b/game/systems/systems.h index 3b5ef6d..aa5b063 100644 --- a/game/systems/systems.h +++ b/game/systems/systems.h @@ -3,7 +3,7 @@ #include -#include "components.h" +#include "../components.h" typedef struct Game Game; @@ -36,6 +36,30 @@ void updateUnitAISystem(ecs_iter_t *it); */ void updateUnitActionsSystem(ecs_iter_t *it); +/* + * 1: Easing + * 2: Position + * 3: Size + * 4: Rotation + */ +void updateEasingSystem(ecs_iter_t *it); + +/********************************** + * Animation Systems + **********************************/ + + +/* + * 1: Animation + * 2: TextureRegion + */ +void updateAnimationState(ecs_iter_t *it); +/* + * 0: + * 1: Animation + * 2: TextureRegion + */ +void updateAnimation(ecs_iter_t *it); /********************************** * Entity Systems @@ -81,19 +105,6 @@ void entityMoveToTarget(ecs_iter_t *it); void entityFollowPath(ecs_iter_t *it); -/* - * 1: Animation - * 2: TextureRegion - */ -void entityUpdateAnimationState(ecs_iter_t *it); -/* - * 0: - * 1: Animation - * 2: TextureRegion - */ -void entityUpdateAnimation(ecs_iter_t *it); - - /* * 1: Position * 2: Size @@ -147,4 +158,33 @@ void drawPlayerInputUI(); * UI systems **********************************/ +/********************************** + * MISC + **********************************/ + +static void setupSystems(ecs_world_t *ecs) { + + ECS_OBSERVER(ecs, entityPathRemove, EcsOnRemove, Path); + + ECS_SYSTEM(ecs, entityUpdateSpatialID, EcsOnUpdate, Position, Size, Velocity, SpatialGridID); + ECS_SYSTEM(ecs, entityUpdateKinematic, EcsOnUpdate, Position, Rotation, Velocity, Steering); + + ECS_SYSTEM(ecs, entityMoveToTarget, EcsOnUpdate, Position, Rotation, Velocity, TargetPosition, Steering); + ECS_SYSTEM(ecs, entityFollowPath, EcsOnUpdate, Path); + + ECS_SYSTEM(ecs, handleUnitActionsSystem, EcsOnUpdate, UnitAction); + ECS_SYSTEM(ecs, updateUnitAISystem, EcsOnUpdate, UnitAI, UnitAction); + // Needs to be called after AI update, since it removes finished actions + ECS_SYSTEM(ecs, updateUnitActionsSystem, EcsOnUpdate, UnitAction); + + ECS_SYSTEM(ecs, updateAnimationState, EcsOnUpdate, Animation, TextureRegion); + ECS_SYSTEM(ecs, updateAnimation, EcsOnUpdate, Animation, TextureRegion); + ECS_SYSTEM(ecs, updateEasingSystem, EcsOnUpdate, Easing, Position, Size, Rotation); + + ECS_SYSTEM(ecs, renderDebugPath, EcsOnUpdate, Path); + + ECS_SYSTEM(ecs, renderColliders, EcsOnUpdate, Position, Size); + ECS_SYSTEM(ecs, renderRotationDirection, EcsOnUpdate, Position, Rotation); +} + #endif //PIXELDEFENSE_SYSTEMS_H diff --git a/game/unit_actions.c b/game/unit_actions.c index 3d4d177..fcd8025 100644 --- a/game/unit_actions.c +++ b/game/unit_actions.c @@ -1,7 +1,7 @@ #include "unit_actions.h" #include "game_state.h" #include "components.h" -#include "systems.h" +#include "systems/systems.h" #include @@ -22,10 +22,24 @@ void actionMoveTo(ecs_entity_t entity, Action *action, Game *game) { } void actionCollectResource(ecs_entity_t entity, Action *action, Game *game) { if (action->finished) return; - if (action->elapsed > 2.0f) { + 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; - ecs_delete(ECS, target); + } + + 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; } } @@ -107,6 +121,20 @@ void addAction(ecs_entity_t entity, Game *game, const Action *action) { 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) { diff --git a/game/unit_actions.h b/game/unit_actions.h index 206cc68..a1b7dd9 100644 --- a/game/unit_actions.h +++ b/game/unit_actions.h @@ -25,6 +25,9 @@ typedef struct ActionDepositResource { ecs_entity_t entity; } ActionDepositResource; +typedef struct Action Action; +typedef void (*ActionCb)(ecs_entity_t entity, Action *action, Game *game); + typedef struct Action { ActionType type; union { @@ -37,6 +40,9 @@ typedef struct Action { bool finished; bool failed; + ActionCb onBegin; + ActionCb onFinish; + struct Action *next; } Action; @@ -49,6 +55,7 @@ void handleAction(ecs_entity_t entity, UnitAction *unitAction, Game *game); void updateAction(UnitAction *unitAction, Game *game); void clearActions(ecs_entity_t entity, Game *game); void addAction(ecs_entity_t entity, Game *game, const Action *action); +void prependAction(ecs_entity_t entity, Game *game, const Action *action); const char *actionTypeToPrettyStr(ActionType type); diff --git a/game/unit_ai.c b/game/unit_ai.c index ba0d7d6..8fd901b 100644 --- a/game/unit_ai.c +++ b/game/unit_ai.c @@ -62,28 +62,59 @@ static ecs_entity_t findNearestResource(Game *game, Position pos, ResourceType t void aiWorkerBuild(ecs_entity_t entity, UnitAI *unitAI, Game *game) { } +/********************************** + * Worker AI + **********************************/ + +void actionCollectResourceOnFinish(ecs_entity_t entity, Action *action, Game *game) { + Worker *worker = ecs_get_mut(ECS, entity, Worker); + // Full, nothing to be done + if (worker->carry >= worker->carryCapacity) + return; + + // Not full yet, find a new resource + Position pos = *ecs_get(ECS, entity, Position); + ecs_entity_t target = findNearestResource(game, pos, worker->carryRes, 20.0f); + if (target) { + + } +} + void aiWorkerHarvestUpdate(ecs_entity_t entity, UnitAI *unitAI, Game *game) { const Action *action = unitAI->action; + + BZ_ASSERT(ecs_has(ECS, entity, Worker)); + Worker *worker = ecs_get_mut(ECS, entity, Worker); + + if (action && action->type == ACTION_COLLECT_RESOURCE && action->finished) { + // Full, nothing to be done + if (worker->carry >= worker->carryCapacity) + return; + + // TODO: Not full yet, find a new resource + + } + if (action) return; - AIWorkerHarvest worker = unitAI->as.workerHarvest; + AIWorkerHarvest workerAI = unitAI->as.workerHarvest; Position workerPos = *ecs_get(ECS, entity, Position); // Finished all tasks, repeat - ecs_entity_t target = worker.target; - Position targetPos = worker.targetPosition; + ecs_entity_t target = workerAI.target; + Position targetPos = workerAI.targetPosition; if (!ecs_is_alive(ECS, target)) { // Find new resource - target = findNearestResource(game, targetPos, worker.resource, 20.0f); + target = findNearestResource(game, targetPos, workerAI.resource, 20.0f); if (!target) return; - worker.target = target; - worker.targetPosition = *ecs_get(ECS, target, Position); + workerAI.target = target; + workerAI.targetPosition = *ecs_get(ECS, target, Position); } // Find the closest warehouse Position warehousePos = Vector2Zero(); - ecs_entity_t warehouse = findNearestStorage(workerPos, worker.resource, + ecs_entity_t warehouse = findNearestStorage(workerPos, workerAI.resource, &warehousePos); if (!warehouse) { return; @@ -99,7 +130,7 @@ void aiWorkerHarvestUpdate(ecs_entity_t entity, UnitAI *unitAI, Game *game) { }); addAction(entity, game, &(const Action) { .type = ACTION_COLLECT_RESOURCE, - .as.collectResource.entity = target + .as.collectResource.entity = target, }); addAction(entity, game, &(const Action) { .type = ACTION_MOVE_TO,