diff --git a/game/tower.odin b/game/tower.odin index 3d0860d..cd7617f 100644 --- a/game/tower.odin +++ b/game/tower.odin @@ -3,9 +3,11 @@ package game import rl "vendor:raylib" Tower :: struct { - position: Vec2, - kind: Tower_Kind, - cooldown: f32, + position: Vec2, + kind: Tower_Kind, + cooldown: f32, + anchor_gx: int, + anchor_gy: int, } Tower_Kind :: enum { @@ -13,15 +15,78 @@ Tower_Kind :: enum { } Tower_Archetype :: struct { - kind: Tower_Kind, - range: f32, - damage: int, - fire_rate: f32, - cost: int, + kind: Tower_Kind, + range: f32, + damage: int, + fire_rate: f32, + cost: int, + footprint_w: int, // 1 column wide + footprint_h: int, // two rows tall } TOWER_ARCHETYPES: [Tower_Kind]Tower_Archetype = { - .Archer = {kind = .Archer, range = 50, damage = 12, fire_rate = 0.45, cost = TOWER_COST}, + .Archer = { + kind = .Archer, + range = 50, + damage = 12, + fire_rate = 0.45, + cost = TOWER_COST, + footprint_w = 1, + footprint_h = 2, + }, +} + +rects_overlap :: proc( + left_a, top_a, width_a, height_a: int, + left_b, top_b, width_b, height_b: int, +) -> bool { + return( + left_a < left_b + width_b && + left_a + width_a > left_b && + top_a < top_b + height_b && + top_a + height_a > top_b \ + ) +} + +footprint_center :: proc(gx, gy, footprint_w, footprint_h: int) -> Vec2 { + return Vec2 { + f32(gx * TILE_SIZE + (footprint_w * TILE_SIZE) / 2), + f32(gy * TILE_SIZE + (footprint_h + TILE_SIZE) / 2), + } +} + +footprint_fits_map :: proc(world_map: ^Map, gx, gy, footprint_w, footprint_h: int) -> bool { + if gx < 0 || gy < 0 do return false + if gx + footprint_w > MAP_W do return false + if gy + footprint_h > MAP_H do return false + + for row in gy ..< gy + footprint_h { + for column in gx ..< gx + footprint_w { + if !can_build_at(world_map, column, row) do return false + } + } + + return true +} + +footprint_blocked :: proc(world: ^World, gx, gy, footprint_w, footprint_h: int) -> bool { + for placed_tower in world.towers { + archetype := get_archetype(placed_tower.kind) + if rects_overlap( + gx, + gy, + footprint_w, + footprint_h, + placed_tower.anchor_gx, + placed_tower.anchor_gy, + archetype.footprint_w, + archetype.footprint_h, + ) { + return true + } + } + + return false } get_archetype :: proc(kind: Tower_Kind) -> Tower_Archetype { @@ -30,17 +95,26 @@ get_archetype :: proc(kind: Tower_Kind) -> Tower_Archetype { 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 - } + arch := get_archetype(kind) + footprint_w := arch.footprint_w + footprint_h := arch.footprint_h + + if !footprint_fits_map(&world.world_map, gx, gy, footprint_w, footprint_h) do return false + if footprint_blocked(world, gx, gy, footprint_w, footprint_h) do return false + if world.gold < arch.cost do return false world.gold -= arch.cost - append(&world.towers, Tower{position = pos, kind = kind, cooldown = 0}) + append( + &world.towers, + Tower { + position = footprint_center(gx, gy, footprint_w, footprint_h), + anchor_gx = gx, + anchor_gy = gy, + kind = kind, + cooldown = 0, + }, + ) return true } @@ -85,11 +159,14 @@ update_towers :: proc(world: ^World, dt: f32) { render_towers :: proc(world: ^World) { for t in world.towers { + archetype := get_archetype(t.kind) + pixel_width := f32(archetype.footprint_w * TILE_SIZE) + pixel_height := f32(archetype.footprint_h * TILE_SIZE) rl.DrawRectangle( - i32(t.position.x - 14), - i32(t.position.y - 14), - 28, - 28, + i32(t.position.x - pixel_width * 0.5), + i32(t.position.y - pixel_height * 0.5), + i32(pixel_width), + i32(pixel_height), rl.Color{255, 203, 0, 255}, ) }