namespace LivingVillage.Desktop open LivingVillage.Kernel open LivingVillage.Kernel.Sim module WorldBootstrap = let private tileCenter (x: int) (y: int) : Vec2 = { X = float32 (x * Sim.tilePixels + Sim.tilePixels / 2) Y = float32 (y * Sim.tilePixels + Sim.tilePixels / 2) } let private npcSpawnTiles : (int * int) array = [| for y in [ 14; 18; 28; 32; 36; 40 ] do for x in [ 24; 28; 32; 36; 40 ] do yield x, y |] let private avatarSpawnPosition = tileCenter 31 25 let private daylightStartTick = 6L * Sim.ticksPerDay / 24L let initialWorldWithOccupation (startAtDaylight: bool) (seed: uint64) (count: int) (occupation: Occupation.State option) : World = if count < 0 || count > npcSpawnTiles.Length then invalidArg (nameof count) "Desktop bootstrap supports at most 30 NPCs." let startTick = if startAtDaylight then daylightStartTick else 0L let baseWorld = Sim.initialWorldN seed count let avatar = let baseAvatar = { baseWorld.Avatar with Pos = avatarSpawnPosition Mind = { baseWorld.Avatar.Mind with Target = avatarSpawnPosition } } match occupation with | None -> baseAvatar | Some state -> let needs = baseAvatar.Mind.Needs { baseAvatar with Mind = { baseAvatar.Mind with Needs = { needs with Money = float32 state.Profile.InitialMoney Energy = state.Profile.InitialEnergy } } } let npcs = baseWorld.Npcs |> Array.mapi (fun index npc -> let x, y = npcSpawnTiles.[index] { npc with Pos = tileCenter x y }) { baseWorld with Tick = startTick Time = float startTick * Sim.dtSeconds Avatar = avatar Npcs = npcs } let initialWorldForDaylight (startAtDaylight: bool) (seed: uint64) (count: int) : World = initialWorldWithOccupation startAtDaylight seed count None let initialWorld (seed: uint64) (count: int) : World = initialWorldWithOccupation false seed count None