#include "buildings.h" #include "components.h" #include "entity_factory.h" #include "game_state.h" #include "map_layers.h" #include "systems/systems.h" #include bool canPlaceBuilding(Game *game, BuildingType type, BzTile tileX, BzTile tileY) { i32 sizeX, sizeY; getBuildingSize(type, &sizeX, &sizeY); if (sizeX == 0 || sizeY == 0) return false; BzTileMap *map = &game->map; // Ensure that it is within the map if (tileX < 0 || tileX + sizeX > map->width || tileY < 0 || tileY + sizeY > map->height) return false; Rectangle buildArea = {tileX * map->tileWidth, tileY * map->tileHeight, sizeX * map->tileWidth, sizeY * map->tileHeight}; BzSpatialGridIter it = bzSpatialGridIter(game->entityGrid, buildArea.x, buildArea.y, buildArea.width, buildArea.height); while (bzSpatialGridQueryNext(&it)) { ecs_entity_t entity = *(ecs_entity_t *) it.data; Rectangle bounds; if (!getEntityBounds(entity, NULL, NULL, &bounds)) continue; if (CheckCollisionRecs(buildArea, bounds)) return false; } return true; } ecs_entity_t placeBuilding(Game *game, BuildingType type, BzTile posX, BzTile posY, Owner owner) { if (type <= BUILDING_NONE || type >= BUILDING_COUNT) return 0; i32 sizeX, sizeY; getBuildingSize(type, &sizeX, &sizeY); const i32 tileWidth = game->map.tileWidth; const i32 tileHeight = game->map.tileHeight; // Create entity ecs_entity_t building = entityCreateEmpty(); ecs_add_id(ECS, building, Selectable); ecs_set(ECS, building, Building, { .type = type, .pos = (Vec2i) { posX, posY }, .size = (Vec2i) { sizeX, sizeY } }); Position pos = { .x = posX * tileWidth + sizeX * tileWidth * 0.5f, .y = posY * tileHeight + sizeY * tileHeight * 0.5f }; Size size = { .x = sizeX * tileWidth, .y = sizeY * tileHeight }; ecs_set_ptr(ECS, building, Position, &pos); ecs_set_ptr(ECS, building, Size, &size); ecs_set(ECS, building, Rotation, {0}); SpatialGridID gridID = bzSpatialGridInsert(game->entityGrid, &building, pos.x - size.x * 0.5f, pos.y - size.y * 0.5f, size.x, size.y); ecs_set_ptr(ECS, building, SpatialGridID, &gridID); ecs_set_ptr(ECS, building, Owner, &owner); BzTileset *tileset = &game->tileset; TextureRegion region = { tileset->tiles, bzTilesetGetTileRegion(tileset, getBuildingTile(type)) }; region.rec.width *= sizeX; region.rec.height *= sizeY; ecs_set_ptr(ECS, building, TextureRegion, ®ion); bzTileMapSetCollisions(&game->map, true, COLL_LAYER_BUILDINGS, posX, posY, sizeX, sizeY); switch (type) { case BUILDING_KEEP: ecs_add_id(ECS, building, Storage); break; default: break; } return building; } Vector2 getPositionNearBuilding(ecs_entity_t building, Vector2 fromPos) { BZ_ASSERT(ecs_is_alive(ECS, building)); BZ_ASSERT(ecs_has(ECS, building, Position)); BZ_ASSERT(ecs_has(ECS, building, Size)); Vector2 pos = *ecs_get(ECS, building, Position); Vector2 size = *ecs_get(ECS, building, Size); size = Vector2SubtractValue(size, 10.0f); Vector2 dir = Vector2Normalize(Vector2Subtract(fromPos, pos)); dir = Vector2Multiply(dir, size); pos = Vector2Add(pos, dir); return pos; }