102 lines
3.7 KiB
Markdown
102 lines
3.7 KiB
Markdown
---
|
|
description: Combat state and movement logic for turn-based combat loop
|
|
globs: src/systems/TurnSystem.js, src/systems/MovementSystem.js, src/types/CombatState.ts, src/types/Actions.ts
|
|
alwaysApply: 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)**
|
|
|
|
```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 Requirements**
|
|
|
|
### **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`
|
|
|
|
### **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
|
|
|
|
|