aether-shards/.cursor/rules/logic/TurnSystem/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

3 KiB

description globs alwaysApply
Turn resolution specification - the tick system for transitioning between unit turns src/systems/TurnSystem.js, src/systems/TurnSystem.ts, src/types/TurnSystem.ts false

Turn Resolution Rule

This rule defines the logic that occurs the moment a unit presses "End Turn". It transitions the game from one actor to the next using a time-based simulation.

1. The Logic Flow

When endTurn() is called:

  1. Resolution (Old Unit):
    • Cooldowns: Decrement cooldowns on all skills by 1
    • Status Effects: Tick durations of active effects (Buffs/Debuffs). Remove expired ones
    • Charge Reset: The unit's chargeMeter is reset to 0 (or reduced by action cost)
  2. Time Advancement (The "Tick"):
    • The system enters a while(no_active_unit) loop
    • Tick: Every unit gains Charge += Speed
    • Check: Does anyone have Charge >= 100?
      • Yes: Stop looping. The unit with the highest Charge is the New Active Unit
      • No: Continue looping
  3. Activation (New Unit):
    • AP Refill: Set currentAP to maxAP
    • Start Triggers: Fire ON_TURN_START events (e.g., "Take Poison Damage")
    • Input Unlock: If Player, unlock UI. If Enemy, trigger AI

2. TypeScript Interfaces

// src/types/TurnSystem.ts

export interface TurnState {
  /** The ID of the unit currently acting */
  activeUnitId: string | null;
  /** How many "Ticks" have passed in total (Time) */
  globalTime: number;
  /** Ordered list of who acts next (predicted) for the UI */
  projectedQueue: string[];
}

export interface TurnEvent {
  type: 'TURN_CHANGE';
  previousUnitId: string;
  nextUnitId: string;
  /** Did we wrap around a "virtual round"? */
  isNewRound: boolean;
}

3. Conditions of Acceptance (CoA)

CoA 1: Speed determines frequency

  • If Unit A has Speed 20 and Unit B has Speed 10:
  • Unit A should act roughly twice as often as Unit B over 10 turns

CoA 2: Queue Prediction

  • The system must expose a getPredictedQueue(depth) method that "simulates" future ticks without applying them, so the UI can show the "Next 5 Units" list correctly

CoA 3: Status Duration

  • A Status Effect with duration: 1 applied on Turn X must expire exactly at the start of the unit's next turn (Turn X+1), ensuring it affects them for one full action phase

4. Implementation Requirements

Create src/systems/TurnSystem.js:

  1. State: Maintain a globalTick counter and reference to UnitManager
  2. End Turn Logic: Implement endTurn(unit). Reset the unit's charge to 0. Tick their cooldowns/statuses
  3. Time Loop: Implement advanceToNextTurn(). Loop through all alive units, adding Speed to Charge. Stop as soon as one or more units reach 100
  4. Tie Breaking: If multiple units pass 100 in the same tick, the one with the highest total charge goes first. If equal, Player beats Enemy
  5. Prediction: Implement simulateQueue(depth) which clones the current charge state and runs the loop virtually to return an array of the next depth Unit IDs