# Combat System ## Overview A stateless CombatSystem node that creates pre-combat proposals and applies combat resolution between two units. The system encapsulates all combat stat calculation so other systems don't need to know proposal logic. ## CombatProposal Resource `resources/resource_definitions/combat_proposal.gd` A Resource containing two sides — attacker and defender. Each side holds: - A reference to the `Unit` node - Pre-combat snapshot stats via an inner class `CombatantStats`: - `hp: int` — from `current_stats.current_hp` - `sp: int` — from `current_stats.current_sp` - `hit: int` — calculated as `own hit - opponent's eva` - `atk: int` — from `current_stats.phys_atk` - `def: int` — from `current_stats.phys_def` - `spd: int` — from `current_stats.spd` ### Stat Calculation For the **attacker** side: - `atk` = attacker's `phys_atk` - `def` = attacker's `phys_def` - `hit` = attacker's `hit` - defender's `eva` - `hp`, `sp`, `spd` copied directly from attacker's `current_stats` For the **defender** side: - `atk` = defender's `phys_atk` - `def` = defender's `phys_def` - `hit` = defender's `hit` - attacker's `eva` - `hp`, `sp`, `spd` copied directly from defender's `current_stats` In the future, different attacks may swap between physical and magic stats, but for now only physical stats are used. ## CombatSystem Node `nodes/combat_system.gd` A `Node` added to the strategy phase scene tree. Stateless — operates purely on units passed in. ### `create_proposal(attacker: Unit, defender: Unit) -> CombatProposal` - Reads both units' `current_stats` - Builds a `CombatProposal` with snapshot stats for each side - Applies cross-calculations (hit - eva) - Returns the proposal without modifying any unit state ### `apply_proposal(proposal: CombatProposal) -> void` 1. **Attacker strikes:** Roll random int 1–100. If roll <= attacker's calculated `hit`, apply `max(attacker.atk - defender.def, 0)` damage to the defender Unit's `current_stats.current_hp` (modifies the actual unit, not the snapshot). 2. **Counterattack:** If the defender Unit's `current_stats.current_hp > 0` after the attack, roll 1–100 for defender. If roll <= defender's calculated `hit`, apply `max(defender.atk - attacker.def, 0)` damage to the attacker Unit's `current_stats.current_hp`. - Damage has a floor of 0 (no negative damage / healing). - Range is ignored for now. In the future, counterattack will depend on whether the defender has skills at appropriate range (defaulting to a "defend" action if not). ## Scene Integration The CombatSystem node is added to `scenes/strategy_phase.tscn` as a sibling of PlayerController, CombatMap, etc. No exports needed. ``` CombatTest (Node2D) ├─ CombatUI ├─ CombatMap ├─ PlayerController ├─ CombatSystem <-- new ├─ Camera2D └─ AudioStreamPlayer ``` ## Files Changed | File | Change | |------|--------| | `resources/resource_definitions/combat_proposal.gd` | New — CombatProposal resource with CombatantStats inner class | | `nodes/combat_system.gd` | New — CombatSystem node with `create_proposal` and `apply_proposal` | | `scenes/strategy_phase.tscn` | Add CombatSystem node to scene tree | ## Out of Scope - Magic attack/defense selection (future: different attack types swap stats) - Range-based counterattack eligibility (future: defend action when no skills in range) - Critical hits - UI for displaying the combat proposal - Animations or visual feedback for combat resolution