package game Tower :: struct { position: Vec2, kind: Tower_Kind, cooldown: f32, } Tower_Kind :: enum { Archer, } Tower_Archetype :: struct { kind: Tower_Kind, range: f32, damage: int, fire_rate: f32, cost: int, } TOWER_ARCHETYPES: [Tower_Kind]Tower_Archetype = { .Archer = {kind = .Archer, range = 20, damage = 12, fire_rate = 0.45, cost = TOWER_COST}, } get_archetype :: proc(kind: Tower_Kind) -> Tower_Archetype { return TOWER_ARCHETYPES[kind] } try_place_tower :: proc(world: ^World, gx, gy: int, kind: Tower_Kind) -> bool { if world.phase != .Build do return false arch := get_archetype(kind) if !can_build_at(&world.world_map, gx, gy) do return false if world.gold < TOWER_COST do return false pos := grid_to_center(gx, gy) for t in world.towers { if distance(t.position, pos) < 1 do return false } world.gold -= arch.cost append(&world.towers, Tower{position = pos, kind = kind, cooldown = 0}) return true } find_target_slot :: proc(tower: Tower, world: ^World) -> int { arch := get_archetype(tower.kind) best_slot: int = -1 best_dist: f32 = 999999 for i in 0 ..< MAX_ENEMIES { e := &world.enemies[i] if !e.active do continue if e.path_index >= len(world.path) do continue d := distance(tower.position, e.position) if d <= arch.range && d < best_dist { best_slot = i best_dist = d } } return best_slot } update_towers :: proc(world: ^World, dt: f32) { for i in 0 ..< len(world.towers) { t := &world.towers[i] t.cooldown -= dt if t.cooldown > 0 do continue slot := find_target_slot(t^, world) if slot < 0 do continue arch := get_archetype(t.kind) switch t.kind { case .Archer: spawn_projectile(world, t.position, slot, arch.damage) t.cooldown = arch.fire_rate } } }