aether-shards/specs/CombatIntegration.spec.md

133 lines
3.7 KiB
Markdown
Raw Normal View History

# **Combat Integration Specification: Wiring the Engine**
This document defines how the TurnSystem and MovementSystem integrate into the existing GameLoop.
## **1. System Ownership**
The GameLoop is the central owner of these systems. It ensures they share the same source of truth (VoxelGrid and UnitManager).
**GameLoop Structure Update:**
```js
class GameLoop {
constructor() {
// ... existing systems ...
this.grid = null;
this.unitManager = null;
// NEW: Combat Logic Systems
this.turnSystem = null; // Manages Initiative & Round state
this.movementSystem = null; // Manages Pathfinding & Position updates
}
init(container) {
// ... existing init ...
// Instantiate logic systems (they are stateless until startLevel)
this.turnSystem = new TurnSystem();
this.movementSystem = new MovementSystem();
}
}
```
## **2. Integration Point: Level Initialization**
When startLevel() runs, the new Grid and UnitManager must be injected into the combat systems so they act on the current map.
**Location:** src/core/GameLoop.js -> startLevel()
```js
async startLevel(runData) {
// ... generate grid and units ...
// WIRING: Connect Systems to Data
this.movementSystem.setContext(this.grid, this.unitManager);
this.turnSystem.setContext(this.unitManager);
// WIRING: Listen for Turn Changes (to update UI/Input state)
this.turnSystem.addEventListener('turn-start', (e) => this._onTurnStart(e.detail));
}
```
## **3. Integration Point: Transition to Combat**
The transition from "Placing Units" to "Fighting" happens in finalizeDeployment. This is where the Turn System takes control.
**Location:** src/core/GameLoop.js -> finalizeDeployment()
```js
finalizeDeployment() {
// ... spawn enemies ...
this.setPhase('COMBAT');
// WIRING: Hand control to TurnSystem
const allUnits = this.unitManager.getAllUnits();
this.turnSystem.startCombat(allUnits);
// UI Update: Show Combat HUD
// (Handled via event listeners in index.html)
}
```
## **4. Integration Point: Input Routing (The "Game Loop")**
When the game is in COMBAT phase, inputs must be routed to the active system based on context (Moving vs Targeting).
**Location:** src/core/GameLoop.js -> triggerSelection() (called by InputManager)
```js
triggerSelection() {
const cursor = this.inputManager.getCursorPosition();
// PHASE: DEPLOYMENT (Existing Logic)
if (this.phase === 'DEPLOYMENT') {
// ... deploy logic ...
}
// PHASE: COMBAT (New Logic)
else if (this.phase === 'COMBAT') {
const activeUnit = this.turnSystem.getActiveUnit();
// Security Check: Is it actually the player's turn?
if (activeUnit.team !== 'PLAYER') return;
// Context A: Unit is trying to MOVE
if (this.combatState === 'SELECTING_MOVE') {
// DELEGATE to MovementSystem
if (this.movementSystem.isValidMove(activeUnit, cursor)) {
this.movementSystem.executeMove(activeUnit, cursor);
// Updating AP is handled internally or via event
}
}
// Context B: Unit is targeting a SKILL
else if (this.combatState === 'TARGETING_SKILL') {
// Delegate to SkillSystem (Future)
}
}
}
```
## **5. Visualizing Range (The "Update Loop")**
The blue movement grid needs to update whenever the active unit changes or moves.
**Location:** src/core/GameLoop.js -> animate() or Event Handler
```js
_onTurnStart(unit) {
if (unit.team === 'PLAYER') {
// Ask MovementSystem for reachable tiles
const tiles = this.movementSystem.getReachableTiles(unit);
// Ask VoxelManager to highlight them
this.voxelManager.highlightTiles(tiles, 'BLUE');
} else {
this.voxelManager.clearHighlights();
// Trigger AI processing
}
}
```