aether-shards/.cursor/rules/core/CombatIntegration/RULE.md
Matthew Mone 5c335b4b3c Add HubScreen and MissionBoard components for campaign management
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.
2025-12-31 10:49:26 -08:00

4.9 KiB

description globs alwaysApply
Combat integration - wiring TurnSystem and MovementSystem into the GameLoop src/core/GameLoop.js, src/core/GameLoop.ts 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:

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()

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()

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)

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

_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