Spaces:
Runtime error
Runtime error
| import { writable, derived } from 'svelte/store'; | |
| import type { GameState, PlayerState, Room, Unit, Building } from '$lib/types'; | |
| import { UNIT_SUPPLY_COST, BUILDING_SUPPLY_PROVIDED } from '$lib/types'; | |
| // โโ Session โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| export const myPlayerId = writable<string | null>(null); | |
| export const playerName = writable<string>(''); | |
| export const roomState = writable<Room | null>(null); | |
| export const roomId = writable<string | null>(null); | |
| // โโ Game โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| export const gameState = writable<GameState | null>(null); | |
| export const winnerId = writable<string | null>(null); | |
| export const isTutorial = writable<boolean>(false); | |
| // โโ UI โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| export const selectedUnit = writable<Unit | null>(null); | |
| export const selectedBuilding = writable<Building | null>(null); | |
| export const mapViewport = writable<{ vx: number; vy: number; vw: number; vh: number }>({ vx: 0, vy: 0, vw: 40, vh: 40 }); | |
| export const mapVisibleCells = writable<Set<string>>(new Set()); | |
| export const mapExploredCells = writable<Set<string>>(new Set()); | |
| /** When set, main map recenters on (cx, cy); consumed by Map.svelte */ | |
| export const mapCenterRequest = writable<{ cx: number; cy: number } | null>(null); | |
| export const voiceStatus = writable<'idle' | 'recording' | 'processing'>('idle'); | |
| export const lastTranscription = writable<string>(''); | |
| export const lastFeedback = writable<string>(''); | |
| export const feedbackLevel = writable<'ok' | 'warning' | 'error'>('ok'); | |
| /** | |
| * Progressive map texture URL. | |
| * Starts null โ set to MAP_quarter blob โ MAP_half blob | |
| * by the landing-page preloader. Map.svelte falls back to the direct URL | |
| * if this is still null (e.g. user navigated directly to /game). | |
| */ | |
| export const mapTextureUrl = writable<string | null>(null); | |
| // โโ Derived โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| export const myPlayer = derived( | |
| [gameState, myPlayerId], | |
| ([$gs, $id]): PlayerState | null => { | |
| if (!$gs || !$id) return null; | |
| return $gs.players[$id] ?? null; | |
| } | |
| ); | |
| export const enemyPlayer = derived( | |
| [gameState, myPlayerId], | |
| ([$gs, $id]): PlayerState | null => { | |
| if (!$gs || !$id) return null; | |
| return Object.values($gs.players).find((p) => p.player_id !== $id) ?? null; | |
| } | |
| ); | |
| /** Supply computed client-side from actual units + active buildings. */ | |
| export const mySupply = derived( | |
| [gameState, myPlayerId], | |
| ([$gs, $id]): { used: number; max: number } => { | |
| if (!$gs || !$id) return { used: 0, max: 0 }; | |
| const player = $gs.players[$id]; | |
| if (!player) return { used: 0, max: 0 }; | |
| const used = Object.values(player.units).reduce( | |
| (sum, u) => sum + (UNIT_SUPPLY_COST[u.unit_type] ?? 0), | |
| 0 | |
| ); | |
| const max = Object.values(player.buildings).reduce( | |
| (sum, b) => | |
| b.status === 'constructing' || b.status === 'destroyed' | |
| ? sum | |
| : sum + (BUILDING_SUPPLY_PROVIDED[b.building_type] ?? 0), | |
| 0 | |
| ); | |
| return { used, max }; | |
| } | |
| ); | |
| export const allUnitsFlat = derived(gameState, ($gs) => { | |
| if (!$gs) return []; | |
| return Object.values($gs.players).flatMap((p) => | |
| Object.values(p.units).map((u) => ({ unit: u, isOwn: false })) | |
| ); | |
| }); | |