package sim // Actors need stable handles once echoes, enemies, attacks, and corpses all start // referencing each other. Index plus generation lets us use cache-friendly arrays // later without letting stale handles silently point at recycled actors. Actor_Id :: struct { index: u32, generation: u32, } Actor_Kind :: enum u8 { None, Player, Echo, } Echo_Replay_Mode :: enum u8 { None, Following, Timeline_Ended, } Echo_Replay_State :: struct { source_run_id: u32, replay_tick: u64, mode: Echo_Replay_Mode, } Actor_State :: struct { id: Actor_Id, kind: Actor_Kind, position: Vec2_Fixed, echo: Echo_Replay_State, } Arena_State :: struct { min: Vec2_Fixed, max: Vec2_Fixed, } Initial_State_Descriptor :: struct { player_position: Vec2_Fixed, } DEFAULT_INITIAL_STATE :: Initial_State_Descriptor { player_position = {Fixed(0), Fixed(0)}, } DEFAULT_ARENA :: Arena_State { min = {Fixed(-18 * (1 << FIXED_SHIFT)), Fixed(-10 * (1 << FIXED_SHIFT))}, max = {Fixed(18 * (1 << FIXED_SHIFT)), Fixed(10 * (1 << FIXED_SHIFT))}, } // World_State is the gameplay data owned by a single deterministic run. // It should stay free of renderer, asset, and platform concepts. World_State :: struct { seed: u64, actor_count: u32, arena: Arena_State, player_id: Actor_Id, actors: [MAX_WORLD_ACTORS]Actor_State, } world_spawn_player :: proc(world: ^World_State, position: Vec2_Fixed) -> (Actor_Id, bool) { id, actor := world_spawn_actor(world, .Player, position) if actor == nil { return {}, false } world.player_id = id return id, true } world_spawn_echo :: proc( world: ^World_State, source_run_id: u32, position: Vec2_Fixed, ) -> (Actor_Id, bool) { id, actor := world_spawn_actor(world, .Echo, position) if actor == nil { return {}, false } actor.echo = Echo_Replay_State{ source_run_id = source_run_id, mode = .Following, } return id, true } world_spawn_actor :: proc( world: ^World_State, kind: Actor_Kind, position: Vec2_Fixed, ) -> (Actor_Id, ^Actor_State) { if world.actor_count >= MAX_WORLD_ACTORS { return {}, nil } index := world.actor_count id := Actor_Id{index = index, generation = 1} world.actors[index] = Actor_State{ id = id, kind = kind, position = position, } world.actor_count += 1 return id, &world.actors[index] } world_actor_by_id :: proc(world: ^World_State, id: Actor_Id) -> ^Actor_State { if id.index >= world.actor_count { return nil } actor := &world.actors[id.index] if actor.id.generation != id.generation { return nil } return actor } world_player :: proc(world: ^World_State) -> ^Actor_State { return world_actor_by_id(world, world.player_id) }