# **Combat State & Movement Specification** This document defines the logic for managing the Turn-Based Combat Loop and the execution of Movement Actions. ## **1. TypeScript Interfaces (Data Models)** ```typescript export type CombatPhase = | "INIT" | "TURN_START" | "WAITING_FOR_INPUT" | "EXECUTING_ACTION" | "TURN_END" | "COMBAT_END"; export interface CombatState { /** Whether combat is currently active */ isActive: boolean; /** Current Round number */ round: number; /** Ordered list of Unit IDs for the current round */ turnQueue: string[]; /** The ID of the unit currently taking their turn */ activeUnitId: string | null; /** Current phase of the turn loop */ phase: CombatPhase; } // src/types/Actions.ts export interface ActionRequest { type: "MOVE" | "SKILL" | "ITEM" | "WAIT"; sourceId: string; targetId?: string; // For targeted skills targetPosition?: { x: number; y: number; z: number }; // For movement/AoE skillId?: string; itemId?: string; } export interface MovementResult { success: boolean; path: { x: number; y: number; z: number }[]; costAP: number; finalPosition: { x: number; y: number; z: number }; } ``` ## **2. Conditions of Acceptance (CoA)** These checks ensure the combat loop feels fair and responsive. ### **System: TurnSystem (src/systems/TurnSystem.js)** - **CoA 1: Initiative Roll:** Upon starting combat, all active units must be sorted into the turnQueue based on their Speed stat (Highest First). - **CoA 2: Turn Start Hygiene:** When a unit's turn begins: - Their currentAP must reset to baseAP. - Status effects (DoTs) must tick. - Cooldowns must decrement. - **CoA 3: Cycling:** Calling endTurn() must move the activeUnitId to the next in the queue. If the queue is empty, increment round and re-roll/reset the queue. ### **System: MovementSystem (src/systems/MovementSystem.js)** - **CoA 1: Validation:** Moving to a tile must fail if: - The tile is blocked/occupied. - No path exists. - The unit has insufficient AP for the _entire_ path. - **CoA 2: Execution:** A successful move must: - Update the Unit's position in the UnitManager. - Update the VoxelGrid occupancy map. - Deduct the correct AP cost (including terrain modifiers). - **CoA 3: Path Snapping:** If the user clicks a tile, but the unit only has AP to reach halfway, the system should allow moving to the _furthest reachable tile_ on that path (optional QoL). ## **3. Implementation Prompts** Use these prompts to generate the specific logic files. ### **Prompt 1: The Turn System** "Create src/systems/TurnSystem.js. It should manage the CombatState. 1. Implement startCombat(units): Sorts units by speed into turnQueue and sets phase to TURN_START. 2. Implement startTurn(): Refills the active unit's AP, processes cooldowns/statuses, and sets phase to WAITING_FOR_INPUT. 3. Implement endTurn(): Rotates the queue. If queue is empty, start new Round. 4. It should accept the UnitManager in the constructor to access unit stats. 5. Dispatch events: combat-start, turn-start, turn-end." ### **Prompt 2: The Movement System** "Create src/systems/MovementSystem.js. It coordinates Pathfinding, VoxelGrid, and UnitManager. 1. Implement validateMove(unit, targetPos): Returns { valid: boolean, cost: number, path: [] }. It checks `A*` pathfinding and compares cost vs unit.currentAP. 2. Implement executeMove(unit, targetPos): - Validates the move first. - Updates grid.moveUnit(unit, targetPos). - Deducts AP. - Returns a Promise that resolves when the visual movement (optional animation hook) would handle it, or immediately for logic."