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

77 lines
3 KiB
Markdown

---
description: Turn resolution specification - the tick system for transitioning between unit turns
globs: src/systems/TurnSystem.js, src/systems/TurnSystem.ts, src/types/TurnSystem.ts
alwaysApply: 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**
```typescript
// 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