163 lines
4.9 KiB
Markdown
163 lines
4.9 KiB
Markdown
|
|
---
|
||
|
|
description: Combat integration - wiring TurnSystem and MovementSystem into the GameLoop
|
||
|
|
globs: src/core/GameLoop.js, src/core/GameLoop.ts
|
||
|
|
alwaysApply: false
|
||
|
|
---
|
||
|
|
|
||
|
|
# **Combat Integration Rule**
|
||
|
|
|
||
|
|
This rule 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
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## **6. Conditions of Acceptance (CoA)**
|
||
|
|
|
||
|
|
**CoA 1: System Initialization**
|
||
|
|
|
||
|
|
- When `startLevel()` is called, both `turnSystem` and `movementSystem` must receive valid references to the current grid and unit manager
|
||
|
|
|
||
|
|
**CoA 2: Phase Transitions**
|
||
|
|
|
||
|
|
- Calling `finalizeDeployment()` must transition the game to COMBAT phase and initialize the turn queue
|
||
|
|
|
||
|
|
**CoA 3: Input Routing**
|
||
|
|
|
||
|
|
- During COMBAT phase, player inputs must be routed to the appropriate system (MovementSystem for moves, SkillTargetingSystem for skills)
|
||
|
|
|
||
|
|
**CoA 4: Visual Feedback**
|
||
|
|
|
||
|
|
- When a player unit's turn starts, the movement range must be highlighted on the grid
|
||
|
|
- When an enemy unit's turn starts, highlights must be cleared
|
||
|
|
|
||
|
|
## **7. Implementation Requirements**
|
||
|
|
|
||
|
|
- **Responsibility:** The GameLoop is the "God Object" responsible for tying systems together. It owns the Scene, Renderer, Grid, and Managers
|
||
|
|
- **Phases:** The loop must respect the current phase: INIT, DEPLOYMENT, COMBAT, RESOLUTION
|
||
|
|
- **Input Routing:** The loop routes raw inputs from InputManager to the appropriate system (e.g., MovementSystem vs SkillTargeting) based on the current Phase
|
||
|
|
|
||
|
|
|