diff --git a/game/app.odin b/game/app.odin index 3fd3318..016a7b2 100644 --- a/game/app.odin +++ b/game/app.odin @@ -12,7 +12,7 @@ run :: proc() { world := init_world() defer { delete(world.path) - delete(world.towers) + delete(world.combat.towers) delete(world.events) delete(world.spawner.recipe) } diff --git a/game/enemy.odin b/game/enemy.odin index ccceff4..51cd31a 100644 --- a/game/enemy.odin +++ b/game/enemy.odin @@ -59,8 +59,8 @@ get_enemy_archetype :: proc(kind: Enemy_Kind, wave: int) -> Enemy_Archetype { acquire_enemy :: proc(world: ^World) -> ^Enemy { // create an object pool with fixed slots to reuse instead of allocate/free every spawn for i in 0 ..< MAX_ENEMIES { - if !world.enemies[i].active { - return &world.enemies[i] + if !world.combat.enemies[i].active { + return &world.combat.enemies[i] } } @@ -90,7 +90,7 @@ update_enemies :: proc(world: ^World, dt: f32) { if len(world.path) < 2 do return for i in 0 ..< MAX_ENEMIES { - e := &world.enemies[i] + e := &world.combat.enemies[i] if !e.active do continue if e.path_index >= len(world.path) { @@ -118,7 +118,7 @@ update_enemies :: proc(world: ^World, dt: f32) { active_enemy_count :: proc(world: ^World) -> int { count := 0 for i in 0 ..< MAX_ENEMIES { - if world.enemies[i].active do count += 1 + if world.combat.enemies[i].active do count += 1 } return count @@ -126,7 +126,7 @@ active_enemy_count :: proc(world: ^World) -> int { render_enemies :: proc(world: ^World) { for i in 0 ..< MAX_ENEMIES { - e := world.enemies[i] + e := world.combat.enemies[i] if !e.active do continue color := rl.MAROON size := 11 diff --git a/game/events.odin b/game/events.odin index b71b397..7d77917 100644 --- a/game/events.odin +++ b/game/events.odin @@ -18,9 +18,9 @@ process_events :: proc(world: ^World) { for ev in world.events { switch ev.kind { case .Enemy_Killed: - world.gold += ev.gold_reward + world.economy.gold += ev.gold_reward case .Wave_Survived: - world.gold += ev.gold_reward + world.economy.gold += ev.gold_reward } } clear(&world.events) diff --git a/game/overlay.odin b/game/overlay.odin index c3bec01..bd9eb36 100644 --- a/game/overlay.odin +++ b/game/overlay.odin @@ -12,7 +12,7 @@ render_overlay :: proc(world: ^World) { gap: i32 : 16 - gold := fmt.ctprintf("Gold: %d", world.gold) + gold := fmt.ctprintf("Gold: %d", world.economy.gold) rl.DrawText(gold, OVERLAY_PADDING, OVERLAY_PADDING, 18, OVERLAY_GOLD_COLOR) x += rl.MeasureText(gold, font_size) + gap diff --git a/game/projectile.odin b/game/projectile.odin index 1dd21a3..4be1aa1 100644 --- a/game/projectile.odin +++ b/game/projectile.odin @@ -20,8 +20,8 @@ Projectile_Mode :: enum { acquire_projectile :: proc(world: ^World) -> ^Projectile { for i in 0 ..< MAX_PROJECTILES { - if !world.projectiles[i].active { - return &world.projectiles[i] + if !world.combat.projectiles[i].active { + return &world.combat.projectiles[i] } } @@ -30,7 +30,7 @@ acquire_projectile :: proc(world: ^World) -> ^Projectile { enemy_still_on_map :: proc(world: ^World, slot: int) -> (^Enemy, bool) { if slot < 0 || slot >= MAX_ENEMIES do return nil, false - e := &world.enemies[slot] + e := &world.combat.enemies[slot] if !e.active do return nil, false if len(world.path) == 0 do return nil, false if e.path_index >= len(world.path) do return nil, false @@ -68,7 +68,7 @@ spawn_ballistic :: proc(world: ^World, from, dir: Vec2, damage: int, splash: f32 hit_enemy_at :: proc(world: ^World, pos: Vec2, damage: int) -> bool { for i in 0 ..< MAX_ENEMIES { - e := &world.enemies[i] + e := &world.combat.enemies[i] if !e.active do continue if distance(pos, e.position) <= PROJECTILE_HIT_RADIUS { apply_tower_hit(world, e, damage) @@ -80,7 +80,7 @@ hit_enemy_at :: proc(world: ^World, pos: Vec2, damage: int) -> bool { update_projectiles :: proc(world: ^World, dt: f32) { for i in 0 ..< MAX_PROJECTILES { - p := &world.projectiles[i] + p := &world.combat.projectiles[i] if !p.active do continue switch p.mode { @@ -132,7 +132,7 @@ update_ballistic_projectile :: proc(world: ^World, p: ^Projectile, dt: f32) { render_projectiles :: proc(world: ^World) { for i in 0 ..< MAX_PROJECTILES { - p := world.projectiles[i] + p := world.combat.projectiles[i] if !p.active do continue color := rl.GOLD radius: f32 = 4 @@ -149,7 +149,7 @@ apply_splash_damage :: proc(world: ^World, center: Vec2, damage: int, radius: f3 hit_any := false for i in 0 ..< MAX_ENEMIES { - e := &world.enemies[i] + e := &world.combat.enemies[i] if !e.active do continue if distance(center, e.position) <= radius { apply_tower_hit(world, e, damage) diff --git a/game/tower.odin b/game/tower.odin index fea6c16..1e3b837 100644 --- a/game/tower.odin +++ b/game/tower.odin @@ -88,7 +88,7 @@ tower_stats_at_level :: proc(tower: Tower) -> (damage: int, range: f32) { can_place_tower :: proc(world: ^World, gx, gy: int, kind: Tower_Kind) -> bool { if world.phase != .Build do return false arch := get_archetype(kind) - if world.gold < arch.cost do return false + if world.economy.gold < arch.cost do return false if !footprint_fits_map(&world.world_map, gx, gy, arch.footprint_w, arch.footprint_h) do return false if footprint_blocked(world, gx, gy, arch.footprint_w, arch.footprint_h) do return false return true @@ -130,7 +130,7 @@ footprint_fits_map :: proc(world_map: ^Map, gx, gy, footprint_w, footprint_h: in } footprint_blocked :: proc(world: ^World, gx, gy, footprint_w, footprint_h: int) -> bool { - for placed_tower in world.towers { + for placed_tower in world.combat.towers { archetype := get_archetype(placed_tower.kind) if rects_overlap( gx, @@ -162,9 +162,9 @@ try_upgrade_tower :: proc(world: ^World, gx, gy: int) -> bool { if t.upgrade_level >= arch.max_upgrade do return false cost := arch.upgrade_cost + t.upgrade_level * 25 - if world.gold < cost do return false + if world.economy.gold < cost do return false - world.gold -= cost + world.economy.gold -= cost t.upgrade_level += 1 return true } @@ -173,9 +173,9 @@ try_place_tower :: proc(world: ^World, gx, gy: int, kind: Tower_Kind) -> bool { if !can_place_tower(world, gx, gy, kind) do return false arch := get_archetype(kind) - world.gold -= arch.cost + world.economy.gold -= arch.cost append( - &world.towers, + &world.combat.towers, Tower { position = footprint_center(gx, gy, arch.footprint_w, arch.footprint_h), anchor_gx = gx, @@ -188,8 +188,8 @@ try_place_tower :: proc(world: ^World, gx, gy: int, kind: Tower_Kind) -> bool { } tower_at_grid :: proc(world: ^World, gx, gy: int) -> ^Tower { - for i in 0 ..< len(world.towers) { - t := &world.towers[i] + for i in 0 ..< len(world.combat.towers) { + t := &world.combat.towers[i] arch := get_archetype(t.kind) if gx >= t.anchor_gx && gx < t.anchor_gx + arch.footprint_w && @@ -206,7 +206,7 @@ find_target_slot :: proc(tower: Tower, world: ^World) -> int { best_dist: f32 = 999999 for i in 0 ..< MAX_ENEMIES { - e := &world.enemies[i] + e := &world.combat.enemies[i] if !e.active do continue if e.path_index >= len(world.path) do continue @@ -221,8 +221,8 @@ find_target_slot :: proc(tower: Tower, world: ^World) -> int { } update_towers :: proc(world: ^World, dt: f32) { - for i in 0 ..< len(world.towers) { - t := &world.towers[i] + for i in 0 ..< len(world.combat.towers) { + t := &world.combat.towers[i] t.cooldown -= dt if t.cooldown > 0 do continue @@ -272,13 +272,13 @@ apply_ice_hit :: proc(world: ^World, target: ^Enemy, damage: int) { enemy_at_slot :: proc(world: ^World, slot: int) -> ^Enemy { if slot < 0 || slot >= MAX_ENEMIES do return nil - e := &world.enemies[slot] + e := &world.combat.enemies[slot] if !e.active do return nil return e } render_towers :: proc(world: ^World) { - for t in world.towers { + for t in world.combat.towers { archetype := get_archetype(t.kind) pixel_width := f32(archetype.footprint_w * TILE_SIZE) pixel_height := f32(archetype.footprint_h * TILE_SIZE) diff --git a/game/world.odin b/game/world.odin index fec5502..af6fc95 100644 --- a/game/world.odin +++ b/game/world.odin @@ -1,23 +1,34 @@ package game World :: struct { - gold: int, + economy: Economy, + combat: Combat, base_health: int, world_map: Map, path: [dynamic]Vec2, - enemies: [MAX_ENEMIES]Enemy, - towers: [dynamic]Tower, events: [dynamic]Event, phase: Game_Phase, wave: int, spawner: Wave_Spawner, - projectiles: [MAX_PROJECTILES]Projectile, selected_tower: Tower_Kind, } +Economy :: struct { + gold: int, +} + +Combat :: struct { + enemies: [MAX_ENEMIES]Enemy, + towers: [dynamic]Tower, + projectiles: [MAX_PROJECTILES]Projectile, +} + init_world :: proc() -> World { + economy := Economy { + gold = 100, + } world := World { - gold = 100, + economy = economy, base_health = 20, phase = .Build, selected_tower = .Archer,