Files
PixelDefense/game/entity_factory.c

155 lines
4.6 KiB
C

#include "entity_factory.h"
#include "ai_actions.h"
ecs_entity_t entityCreateEmpty() {
ecs_entity_t e = ecs_new_id(ECS);
ecs_add_id(ECS, e, GameEntity);
return e;
}
ecs_entity_t entityCreateBaseUnit(const Position position, f32 size, Player player,
EntityType type, AnimType startAnim, Game *game) {
BzTileset *tileset = &game->tileset;
BzTileID tileID = getEntityTile(type);
TextureRegion region = {
tileset->tiles,
getTextureRect(tileID)
};
HitBox hitbox = getEntityHitBoxRec(tileID);
ecs_entity_t e = entityCreateEmpty();
ecs_set_ptr(ECS, e, Position, &position);
f32 scl = size / region.rec.width;
ecs_set(ECS, e, Size, {region.rec.width * scl, region.rec.height * scl});
hitbox.x *= scl;
hitbox.y *= scl;
hitbox.width *= scl;
hitbox.height *= scl;
ecs_set_ptr(ECS, e, HitBox, &hitbox);
BzSpatialGridID spatialID = bzSpatialGridInsert(game->entityGrid, &e,
position.x + hitbox.x, position.y + hitbox.y,
hitbox.width, hitbox.height);
ecs_set(ECS, e, SpatialGridID, { spatialID });
ecs_set(ECS, e, Rotation, { 0.0f });
ecs_set(ECS, e, Orientation, {0.0f});
ecs_set(ECS, e, Velocity, {});
ecs_set(ECS, e, Steering, {});
ecs_set(ECS, e, Owner, {player});
ecs_set_ptr(ECS, e, TextureRegion, &region);
if (startAnim != ANIM_NONE) {
ecs_set(ECS, e, Animation, {
.entityType = type,
.animType = startAnim,
.sequence = entityGetAnimationSequence(type, startAnim),
.tileset = tileset,
.curFrame = 0,
.elapsed = 0.0f,
});
}
ecs_set(ECS, e, BzBTState, {
.root = NULL,
.nodeStatePool = game->pools.btNodeState
});
ecs_set(ECS, e, AIBlackboard, {.entity = e});
ecs_add_id(ECS, e, Selectable);
ecs_set(ECS, e, Unit, {
.attackElapsed = 0.0f,
.attackCooldown = 1.0f,
.minDamage = 1.0f,
.maxDamage = 2.0f,
.acceleration = 80.0f,
.maxSpeed = 15.0f,
.deceleration = 0.1f,
.unitType = type
});
ecs_set(ECS, e, ConsumePopCapacity, {1});
return e;
}
ecs_entity_t entityCreateSoldier(const Position position, Player player, Game *game) {
ecs_entity_t e = entityCreateBaseUnit(position, 10.0f, player, ENTITY_SOLDIER, ANIM_IDLE, game);
ecs_set(ECS, e, Health, {
.startHP = 40.0f,
.hp = 40.0f,
.lastChanged = -1.0f
});
Unit *unit = ecs_get_mut(ECS, e, Unit);
unit->minDamage = 5.0f;
unit->maxDamage = 10.0f;
unit->attackCooldown = 1.0f;
return e;
}
ecs_entity_t entityCreateWarrior(const Position position, Player player, Game *game) {
ecs_entity_t e = entityCreateBaseUnit(position, 10.0f, player, ENTITY_WARRIOR, ANIM_IDLE, game);
ecs_set(ECS, e, Health, {
.startHP = 80.0f,
.hp = 80.0f,
.lastChanged = -1.0f
});
Unit *unit = ecs_get_mut(ECS, e, Unit);
unit->minDamage = 8.0f;
unit->maxDamage = 22.0f;
unit->attackCooldown = 1.8f;
return e;
}
ecs_entity_t entityCreateWorker(const Position position, Player player, Game *game) {
BzTileset *tileset = &game->tileset;
ecs_entity_t e = entityCreateBaseUnit(position, 10.0f, player, ENTITY_WORKER, ANIM_IDLE, game);
ecs_set(ECS, e, Worker, {
.collectSpeed = 0.8f,
.depositSpeed = 0.2f,
.carryCapacity = 5,
});
ecs_set(ECS, e, Health, {
.startHP = 20.0f,
.hp = 20.0f,
.lastChanged = -1.0f
});
return e;
}
ecs_entity_t entityRecruit(EntityType type, Position position, Player player, Game *game) {
switch (type) {
case ENTITY_WORKER:
entityCreateWorker(position, player, game);
default:
return 0;
}
}
void getEntityCost(EntityType type, i32 cost[RES_COUNT]) {
for (i32 i = 0; i < RES_COUNT; i++) {
cost[i] = 0;
}
switch (type) {
case ENTITY_WORKER:
cost[RES_FOOD] = 50;
break;
case ENTITY_SOLDIER:
cost[RES_FOOD] = 50;
cost[RES_GOLD] = 50;
break;
case ENTITY_WARRIOR:
cost[RES_FOOD] = 200;
cost[RES_GOLD] = 100;
break;
default:;
}
}
bool canAffordEntity(EntityType type, PlayerResources res) {
i32 needed[RES_COUNT] = {0, };
getEntityCost(type, needed);
if (needed[RES_WOOD] > res.wood) return false;
if (needed[RES_FOOD] > res.food) return false;
if (needed[RES_GOLD] > res.gold) return false;
return true;
}