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

