Introduce the HubScreen as the main interface for managing resources, units, and mission selection, integrating with the GameStateManager for dynamic data binding. Implement the MissionBoard component to display and select available missions, enhancing user interaction with mission details and selection logic. Update the GameStateManager to handle transitions between game states, ensuring a seamless experience for players. Add tests for HubScreen and MissionBoard to validate functionality and integration with the overall game architecture.
3.7 KiB
3.7 KiB
| description | globs | alwaysApply |
|---|---|---|
| Combat state and movement logic for turn-based combat loop | src/systems/TurnSystem.js, src/systems/MovementSystem.js, src/types/CombatState.ts, src/types/Actions.ts | false |
Combat State & Movement Rule
This rule defines the logic for managing the Turn-Based Combat Loop and the execution of Movement Actions.
1. TypeScript Interfaces (Data Models)
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
currentAPmust reset tobaseAP - Status effects (DoTs) must tick
- Cooldowns must decrement
- Their
- CoA 3: Cycling: Calling
endTurn()must move theactiveUnitIdto 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 Requirements
The Turn System
Create src/systems/TurnSystem.js. It should manage the CombatState.
- Implement
startCombat(units): Sorts units by speed into turnQueue and sets phase to TURN_START - Implement
startTurn(): Refills the active unit's AP, processes cooldowns/statuses, and sets phase to WAITING_FOR_INPUT - Implement
endTurn(): Rotates the queue. If queue is empty, start new Round - It should accept the UnitManager in the constructor to access unit stats
- Dispatch events:
combat-start,turn-start,turn-end
The Movement System
Create src/systems/MovementSystem.js. It coordinates Pathfinding, VoxelGrid, and UnitManager.
- Implement
validateMove(unit, targetPos): Returns{ valid: boolean, cost: number, path: [] }. It checksA*pathfinding and compares cost vsunit.currentAP - 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