# Phase 4: Combat & Progression Systems - Implementation Plan

**Status:** In Progress - Week 2 Complete, Week 3 Next
**Timeline:** 4-5 weeks
**Last Updated:** November 27, 2025
**Document Version:** 1.3

---

## Completion Summary

### Week 1: Combat Backend - COMPLETE

| Task | Description | Status | Tests |
|------|-------------|--------|-------|
| 1.1 | Verify Combat Data Models | ✅ Complete | - |
| 1.2 | Implement Combat Service | ✅ Complete | 25 tests |
| 1.3 | Implement Damage Calculator | ✅ Complete | 39 tests |
| 1.4 | Implement Effect Processor | ✅ Complete | - |
| 1.5 | Implement Combat Actions | ✅ Complete | - |
| 1.6 | Combat API Endpoints | ✅ Complete | 19 tests |
| 1.7 | Manual API Testing | ⏭️ Skipped | - |

**Files Created:**
- `/api/app/models/enemy.py` - EnemyTemplate, LootEntry dataclasses
- `/api/app/services/enemy_loader.py` - YAML-based enemy loading
- `/api/app/services/combat_service.py` - Combat orchestration service
- `/api/app/services/damage_calculator.py` - Damage formula calculations
- `/api/app/api/combat.py` - REST API endpoints
- `/api/app/data/enemies/*.yaml` - 6 sample enemy definitions
- `/api/tests/test_damage_calculator.py` - 39 tests
- `/api/tests/test_enemy_loader.py` - 25 tests
- `/api/tests/test_combat_service.py` - 25 tests
- `/api/tests/test_combat_api.py` - 19 tests

**Total Tests:** 108 passing

### Week 2: Inventory & Equipment - COMPLETE

| Task | Description | Status | Tests |
|------|-------------|--------|-------|
| 2.1 | Item Data Models (Affixes) | ✅ Complete | 24 tests |
| 2.2 | Item Data Files (YAML) | ✅ Complete | - |
| 2.2.1 | Item Generator Service | ✅ Complete | 35 tests |
| 2.3 | Inventory Service | ✅ Complete | 24 tests |
| 2.4 | Inventory API Endpoints | ✅ Complete | 25 tests |
| 2.5 | Character Stats Calculation | ✅ Complete | 17 tests |
| 2.6 | Equipment-Combat Integration | ✅ Complete | 140 tests |
| 2.7 | Combat Loot Integration | ✅ Complete | 59 tests |

**Files Created/Modified:**
- `/api/app/models/items.py` - Item with affix support, spell_power field
- `/api/app/models/affixes.py` - Affix, BaseItemTemplate dataclasses
- `/api/app/models/stats.py` - spell_power_bonus, updated damage formula
- `/api/app/models/combat.py` - Combatant weapon properties
- `/api/app/services/item_generator.py` - Procedural item generation
- `/api/app/services/inventory_service.py` - Equipment management
- `/api/app/services/damage_calculator.py` - Refactored to use stats properties
- `/api/app/services/combat_service.py` - Equipment integration
- `/api/app/api/inventory.py` - REST API endpoints

**Total Tests (Week 2):** 324+ passing

---

## Overview

This phase implements the core combat and progression systems for Code of Conquest, enabling turn-based tactical combat, inventory management, equipment, skill trees, and the NPC shop. This is a prerequisite for the story progression and quest systems.

**Key Deliverables:**
- Turn-based combat system (API + UI)
- Inventory & equipment management
- Skill tree visualization and unlocking
- XP and leveling system
- NPC shop

---

## Phase Structure

| Sub-Phase | Duration | Focus |
|-----------|----------|-------|
| **Phase 4A** | 2-3 weeks | Combat Foundation |
| **Phase 4B** | 1-2 weeks | Skill Trees & Leveling | See [`/PHASE4b.md`](/PHASE4b.md)
| **Phase 4C** | 3-4 days | NPC Shop | [`/PHASE4c.md`](/PHASE4c.md)

**Total Estimated Time:** 4-5 weeks (~140-175 hours)

---

## Phase 4A: Combat Foundation (Weeks 1-3)

### Week 1: Combat Backend & Data Models ✅ COMPLETE

#### Task 1.1: Verify Combat Data Models ✅ COMPLETE

**Files:** `/api/app/models/combat.py`, `effects.py`, `abilities.py`, `stats.py`

Verified: Combatant, CombatEncounter dataclasses, effect types (BUFF, DEBUFF, DOT, HOT, STUN, SHIELD), stacking logic, YAML ability loading, serialization methods.

---

#### Task 1.2: Implement Combat Service ✅ COMPLETE

**File:** `/api/app/services/combat_service.py`

Implemented: `CombatService` class with `initiate_combat()`, `process_action()`, initiative rolling, turn management, death checking, combat end detection.

---

#### Task 1.3: Implement Damage Calculator ✅ COMPLETE

**File:** `/api/app/services/damage_calculator.py`

Implemented: `calculate_physical_damage()`, `calculate_magical_damage()`, `apply_damage()` with shield absorption. Physical formula: `weapon.damage + (STR/2) - defense`. 39 unit tests.

---

#### Task 1.4: Implement Effect Processor ✅ COMPLETE

**File:** `/api/app/models/effects.py`

Implemented: `tick()` method for DOT/HOT damage/healing, duration tracking, stat modifiers via `get_effective_stats()`.

---

#### Task 1.5: Implement Combat Actions ✅ COMPLETE

**File:** `/api/app/services/combat_service.py`

Implemented: `_execute_attack()`, `_execute_spell()`, `_execute_item()`, `_execute_defend()` with mana costs, cooldowns, effect application.

---

#### Task 1.6: Combat API Endpoints ✅ COMPLETE

**File:** `/api/app/api/combat.py`

**Endpoints:**
- `POST /api/v1/combat/start` - Initiate combat
- `POST /api/v1/combat/<combat_id>/action` - Take action
- `GET /api/v1/combat/<combat_id>/state` - Get state
- `POST /api/v1/combat/<combat_id>/flee` - Attempt flee
- `POST /api/v1/combat/<combat_id>/enemy-turn` - Enemy AI
- `GET /api/v1/combat/enemies` - List templates (public)
- `GET /api/v1/combat/enemies/<id>` - Enemy details (public)

19 integration tests passing.

---

#### Task 1.7: Manual API Testing ⏭️ SKIPPED

Covered by 108 comprehensive automated tests.

---

### Week 2: Inventory & Equipment System ✅ COMPLETE

#### Task 2.1: Item Data Models ✅ COMPLETE

**Files:** `/api/app/models/items.py`, `affixes.py`, `enums.py`

Implemented: `Item` dataclass with affix support (`applied_affixes`, `base_template_id`, `generated_name`, `is_generated`), `Affix` model (PREFIX/SUFFIX types, MINOR/MAJOR/LEGENDARY tiers), `BaseItemTemplate` for procedural generation. 24 tests.

---

#### Task 2.2: Item Data Files ✅ COMPLETE

**Directory:** `/api/app/data/`

Created:
- `base_items/weapons.yaml` - 13 weapon templates
- `base_items/armor.yaml` - 12 armor templates (cloth/leather/chain/plate)
- `affixes/prefixes.yaml` - 18 prefixes (elemental, material, quality, legendary)
- `affixes/suffixes.yaml` - 11 suffixes (stat bonuses, animal totems, legendary)
- `items/consumables/potions.yaml` - Health/mana potions (small/medium/large)

---

#### Task 2.2.1: Item Generator Service ✅ COMPLETE

**Files:** `/api/app/services/item_generator.py`, `affix_loader.py`, `base_item_loader.py`

Implemented Diablo-style procedural generation:
- Affix distribution: COMMON/UNCOMMON (0), RARE (1), EPIC (2), LEGENDARY (3)
- Name generation: "Flaming Dagger of Strength"
- Tier weights by rarity (RARE: 80% MINOR, EPIC: 70% MAJOR, LEGENDARY: 50% LEGENDARY)
- Luck-influenced rarity rolling

35 tests.

---

#### Task 2.3: Implement Inventory Service ✅ COMPLETE

**File:** `/api/app/services/inventory_service.py`

Implemented: `add_item()`, `remove_item()`, `equip_item()`, `unequip_item()`, `use_consumable()`, `use_consumable_in_combat()`. Full object storage for generated items. Validation for slots, levels, item types. 24 tests.

---

#### Task 2.4: Inventory API Endpoints ✅ COMPLETE

**File:** `/api/app/api/inventory.py`

**Endpoints:**
- `GET /api/v1/characters/<id>/inventory` - Get inventory + equipped
- `POST /api/v1/characters/<id>/inventory/equip` - Equip item
- `POST /api/v1/characters/<id>/inventory/unequip` - Unequip item
- `POST /api/v1/characters/<id>/inventory/use` - Use consumable
- `DELETE /api/v1/characters/<id>/inventory/<item_id>` - Drop item

25 tests.

---

#### Task 2.5: Update Character Stats Calculation ✅ COMPLETE

**Files:** `/api/app/models/stats.py`, `character.py`

Added `damage_bonus`, `defense_bonus`, `resistance_bonus` fields to Stats. Updated `get_effective_stats()` to populate from equipped weapon/armor. 17 tests.

---

#### Task 2.6: Equipment-Combat Integration ✅ COMPLETE

**Files:** `stats.py`, `items.py`, `character.py`, `combat.py`, `combat_service.py`, `damage_calculator.py`

Key changes:
- Damage scaling: `int(STR * 0.75) + damage_bonus` (was `STR // 2`)
- Added `spell_power` system for magical weapons
- Combatant weapon properties (crit_chance, crit_multiplier, elemental support)
- DamageCalculator uses `stats.damage` directly (removed `weapon_damage` param)

140 tests.

---

#### Task 2.7: Combat Loot Integration ✅ COMPLETE

**Files:** `combat_loot_service.py`, `static_item_loader.py`, `app/models/enemy.py`

Implemented hybrid loot system:
- Static drops (consumables, materials) via `StaticItemLoader`
- Procedural drops (equipment) via `ItemGenerator`
- Difficulty bonuses: EASY +0%, MEDIUM +5%, HARD +15%, BOSS +30%
- Enemy variants: goblin_scout, goblin_warrior, goblin_chieftain

59 tests.

---

### Week 3: Combat UI

#### Task 3.1: Create Combat Template ✅ COMPLETE

**Objective:** Build HTMX-powered combat interface

**File:** `/public_web/templates/game/combat.html`

**Layout:**

```
┌─────────────────────────────────────────────────────────────┐
│                        COMBAT ENCOUNTER                      │
├───────────────┬─────────────────────────┬───────────────────┤
│               │                         │                   │
│  YOUR         │   COMBAT LOG            │  TURN ORDER       │
│  CHARACTER    │                         │  ───────────      │
│  ─────────    │   Goblin attacks you    │  1. Aragorn ✓     │
│  HP: ████ 80  │   for 12 damage!        │  2. Goblin        │
│  MP: ███  60  │                         │  3. Orc           │
│               │   You attack Goblin     │                   │
│  ENEMY        │   for 18 damage!        │  ACTIVE EFFECTS   │
│  ─────────    │   CRITICAL HIT!         │  ───────────      │
│  Goblin       │                         │  🛡️ Defending     │
│  HP: ██   12  │   Goblin is stunned!    │  (1 turn)         │
│               │                         │                   │
│               │   ─────────────────     │                   │
│               │   ACTION BUTTONS        │                   │
│               │   ─────────────────     │                   │
│               │   [Attack] [Spell]      │                   │
│               │   [Item]   [Defend]     │                   │
│               │                         │                   │
└───────────────┴─────────────────────────┴───────────────────┘
```

**Implementation:**

```html
{% extends "base.html" %}

{% block title %}Combat - Code of Conquest{% endblock %}

{% block extra_head %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/combat.css') }}">
{% endblock %}

{% block content %}
<div class="combat-container">
    <h1 class="combat-title">⚔️ COMBAT ENCOUNTER</h1>

    <div class="combat-grid">
        {# Left Panel - Combatants #}
        <aside class="combat-panel combat-combatants">
            <div class="combatant-card player-card">
                <h3>{{ character.name }}</h3>
                <div class="hp-bar">
                    <div class="hp-fill" style="width: {{ (character.current_hp / character.stats.max_hp * 100)|int }}%"></div>
                    <span class="hp-text">HP: {{ character.current_hp }} / {{ character.stats.max_hp }}</span>
                </div>
                <div class="mp-bar">
                    <div class="mp-fill" style="width: {{ (character.current_mp / character.stats.max_mp * 100)|int }}%"></div>
                    <span class="mp-text">MP: {{ character.current_mp }} / {{ character.stats.max_mp }}</span>
                </div>
            </div>

            <div class="vs-divider">VS</div>

            {% for enemy in enemies %}
            <div class="combatant-card enemy-card" id="enemy-{{ loop.index0 }}">
                <h3>{{ enemy.name }}</h3>
                <div class="hp-bar">
                    <div class="hp-fill enemy" style="width: {{ (enemy.current_hp / enemy.stats.max_hp * 100)|int }}%"></div>
                    <span class="hp-text">HP: {{ enemy.current_hp }} / {{ enemy.stats.max_hp }}</span>
                </div>
                {% if enemy.current_hp > 0 %}
                <button class="btn btn-target" onclick="selectTarget('{{ enemy.combatant_id }}')">
                    Target
                </button>
                {% else %}
                <span class="defeated-badge">DEFEATED</span>
                {% endif %}
            </div>
            {% endfor %}
        </aside>

        {# Middle Panel - Combat Log & Actions #}
        <section class="combat-panel combat-main">
            <div class="combat-log" id="combat-log">
                <h3>Combat Log</h3>
                <div class="log-entries">
                    {% for entry in combat_log[-10:] %}
                    <div class="log-entry">{{ entry }}</div>
                    {% endfor %}
                </div>
            </div>

            <div class="combat-actions" id="combat-actions">
                <h3>Your Turn</h3>
                <div class="action-buttons">
                    <button class="btn btn-action btn-attack"
                            hx-post="/combat/{{ combat_id }}/action"
                            hx-vals='{"action_type": "attack", "ability_id": "basic_attack", "target_id": ""}'
                            hx-target="#combat-container"
                            hx-swap="outerHTML">
                        ⚔️ Attack
                    </button>

                    <button class="btn btn-action btn-spell"
                            onclick="openSpellMenu()">
                        ✨ Cast Spell
                    </button>

                    <button class="btn btn-action btn-item"
                            onclick="openItemMenu()">
                        🎒 Use Item
                    </button>

                    <button class="btn btn-action btn-defend"
                            hx-post="/combat/{{ combat_id }}/action"
                            hx-vals='{"action_type": "defend"}'
                            hx-target="#combat-container"
                            hx-swap="outerHTML">
                        🛡️ Defend
                    </button>
                </div>
            </div>
        </section>

        {# Right Panel - Turn Order & Effects #}
        <aside class="combat-panel combat-sidebar">
            <div class="turn-order">
                <h3>Turn Order</h3>
                <ol>
                    {% for combatant_id in turn_order %}
                    <li class="{% if loop.index0 == current_turn_index %}active-turn{% endif %}">
                        {{ get_combatant_name(combatant_id) }}
                        {% if loop.index0 == current_turn_index %}✓{% endif %}
                    </li>
                    {% endfor %}
                </ol>
            </div>

            <div class="active-effects">
                <h3>Active Effects</h3>
                {% for effect in character.active_effects %}
                <div class="effect-badge {{ effect.effect_type }}">
                    {{ effect.name }} ({{ effect.duration }})
                </div>
                {% endfor %}
            </div>
        </aside>
    </div>
</div>

{# Modal Container #}
<div id="modal-container"></div>
{% endblock %}

{% block scripts %}
<script>
let selectedTargetId = null;

function selectTarget(targetId) {
    selectedTargetId = targetId;

    // Update UI to show selected target
    document.querySelectorAll('.btn-target').forEach(btn => {
        btn.classList.remove('selected');
    });
    event.target.classList.add('selected');
}

function openSpellMenu() {
    // TODO: Open modal with spell selection
}

function openItemMenu() {
    // TODO: Open modal with item selection
}

// Auto-scroll combat log to bottom
const logDiv = document.querySelector('.log-entries');
if (logDiv) {
    logDiv.scrollTop = logDiv.scrollHeight;
}
</script>
{% endblock %}
```

**Also create `/public_web/static/css/combat.css`**

**Acceptance Criteria:**
- 3-column layout works
- Combat log displays messages
- HP/MP bars update dynamically
- Action buttons trigger HTMX requests
- Turn order displays correctly
- Active effects shown

---

#### Task 3.2: Combat HTMX Integration ✅ COMPLETE

**Objective:** Wire combat UI to API via HTMX

**File:** `/public_web/app/views/game_views.py`

**Implementation:**

```python
"""
Combat Views

Routes for combat UI.
"""

from flask import Blueprint, render_template, request, g, redirect, url_for

from app.services.api_client import APIClient, APIError
from app.utils.auth import require_auth
from app.utils.logging import get_logger

logger = get_logger(__file__)

combat_bp = Blueprint('combat', __name__)


@combat_bp.route('/<combat_id>')
@require_auth
def combat_view(combat_id: str):
    """Display combat interface."""
    api_client = APIClient()

    try:
        # Get combat state
        response = api_client.get(f'/combat/{combat_id}/state')
        combat_state = response['result']

        return render_template(
            'game/combat.html',
            combat_id=combat_id,
            combat_state=combat_state,
            turn_order=combat_state['turn_order'],
            current_turn_index=combat_state['current_turn_index'],
            combat_log=combat_state['combat_log'],
            character=combat_state['combatants'][0],  # Player is first
            enemies=combat_state['combatants'][1:]     # Rest are enemies
        )

    except APIError as e:
        logger.error(f"Failed to load combat {combat_id}: {e}")
        return redirect(url_for('game.play'))


@combat_bp.route('/<combat_id>/action', methods=['POST'])
@require_auth
def combat_action(combat_id: str):
    """Process combat action (HTMX endpoint)."""
    api_client = APIClient()

    action_data = {
        'action_type': request.form.get('action_type'),
        'ability_id': request.form.get('ability_id'),
        'target_id': request.form.get('target_id'),
        'item_id': request.form.get('item_id')
    }

    try:
        # Submit action to API
        response = api_client.post(f'/combat/{combat_id}/action', json=action_data)
        result = response['result']

        # Check if combat ended
        if result['combat_state']['status'] in ['victory', 'defeat']:
            return redirect(url_for('combat.combat_results', combat_id=combat_id))

        # Re-render combat view with updated state
        return render_template(
            'game/combat.html',
            combat_id=combat_id,
            combat_state=result['combat_state'],
            turn_order=result['combat_state']['turn_order'],
            current_turn_index=result['combat_state']['current_turn_index'],
            combat_log=result['combat_state']['combat_log'],
            character=result['combat_state']['combatants'][0],
            enemies=result['combat_state']['combatants'][1:]
        )

    except APIError as e:
        logger.error(f"Combat action failed: {e}")
        return render_template('partials/error.html', error=str(e))


@combat_bp.route('/<combat_id>/results')
@require_auth
def combat_results(combat_id: str):
    """Display combat results (victory/defeat)."""
    api_client = APIClient()

    try:
        response = api_client.get(f'/combat/{combat_id}/results')
        results = response['result']

        return render_template(
            'game/combat_results.html',
            victory=results['victory'],
            xp_gained=results['xp_gained'],
            gold_gained=results['gold_gained'],
            loot=results['loot']
        )

    except APIError as e:
        logger.error(f"Failed to load combat results: {e}")
        return redirect(url_for('game.play'))
```

**Register blueprint in `/public_web/app/__init__.py`:**

```python
from app.views.combat import combat_bp
app.register_blueprint(combat_bp, url_prefix='/combat')
```

**Acceptance Criteria:**
- Combat view loads from API
- Action buttons submit to API
- Combat state updates dynamically
- Combat results shown at end
- Errors handled gracefully

---

#### Task 3.3: Inventory UI ✅ COMPLETE

**Objective:** Add inventory accordion to character panel

**File:** `/public_web/templates/game/partials/character_panel.html`

**Add Inventory Section:**

```html
{# Existing character panel code #}

{# Add Inventory Accordion #}
<div class="panel-accordion" data-accordion="inventory">
    <button class="panel-accordion-header" onclick="togglePanelAccordion(this)">
        <span>Inventory <span class="count">({{ character.inventory|length }}/{{ inventory_max }})</span></span>
        <span class="accordion-icon">▼</span>
    </button>
    <div class="panel-accordion-content">
        <div class="inventory-grid">
            {% for item in inventory %}
            <div class="inventory-item {{ item.rarity }}"
                 hx-get="/inventory/{{ character.character_id }}/item/{{ item.item_id }}"
                 hx-target="#modal-container"
                 hx-swap="innerHTML">
                <img src="{{ item.icon_url or '/static/img/items/default.png' }}" alt="{{ item.name }}">
                <span class="item-name">{{ item.name }}</span>
            </div>
            {% endfor %}
        </div>
    </div>
</div>

{# Equipment Section #}
<div class="panel-accordion" data-accordion="equipment">
    <button class="panel-accordion-header" onclick="togglePanelAccordion(this)">
        <span>Equipment</span>
        <span class="accordion-icon">▼</span>
    </button>
    <div class="panel-accordion-content">
        <div class="equipment-slots">
            <div class="equipment-slot">
                <label>Weapon:</label>
                {% if character.equipped.weapon %}
                <span class="equipped-item">{{ get_item_name(character.equipped.weapon) }}</span>
                <button class="btn-small"
                        hx-post="/inventory/{{ character.character_id }}/unequip"
                        hx-vals='{"slot": "weapon"}'
                        hx-target="#character-panel"
                        hx-swap="outerHTML">
                    Unequip
                </button>
                {% else %}
                <span class="empty-slot">Empty</span>
                {% endif %}
            </div>

            <div class="equipment-slot">
                <label>Helmet:</label>
                {# Similar for helmet, chest, boots, etc. #}
            </div>
        </div>
    </div>
</div>
```

**Create `/public_web/templates/game/partials/item_modal.html`:**

```html
<div class="modal-overlay" onclick="closeModal()">
    <div class="modal-content" onclick="event.stopPropagation()">
        <div class="modal-header">
            <h2 class="item-name {{ item.rarity }}">{{ item.name }}</h2>
            <button class="modal-close" onclick="closeModal()">×</button>
        </div>

        <div class="modal-body">
            <p class="item-description">{{ item.description }}</p>

            <div class="item-stats">
                {% if item.item_type == 'weapon' %}
                <p><strong>Damage:</strong> {{ item.damage }}</p>
                <p><strong>Crit Chance:</strong> {{ (item.crit_chance * 100)|int }}%</p>
                {% elif item.item_type == 'armor' %}
                <p><strong>Defense:</strong> {{ item.defense }}</p>
                <p><strong>Resistance:</strong> {{ item.resistance }}</p>
                {% elif item.item_type == 'consumable' %}
                <p><strong>HP Restore:</strong> {{ item.hp_restore }}</p>
                <p><strong>MP Restore:</strong> {{ item.mp_restore }}</p>
                {% endif %}
            </div>

            <p class="item-value">Value: {{ item.value }} gold</p>
        </div>

        <div class="modal-footer">
            {% if item.item_type == 'weapon' %}
            <button class="btn btn-primary"
                    hx-post="/inventory/{{ character_id }}/equip"
                    hx-vals='{"item_id": "{{ item.item_id }}", "slot": "weapon"}'
                    hx-target="#character-panel"
                    hx-swap="outerHTML">
                Equip Weapon
            </button>
            {% elif item.item_type == 'consumable' %}
            <button class="btn btn-primary"
                    hx-post="/inventory/{{ character_id }}/use"
                    hx-vals='{"item_id": "{{ item.item_id }}"}'
                    hx-target="#character-panel"
                    hx-swap="outerHTML">
                Use Item
            </button>
            {% endif %}

            <button class="btn btn-secondary" onclick="closeModal()">Cancel</button>
        </div>
    </div>
</div>
```

**Acceptance Criteria:**
- Inventory displays in character panel
- Click item shows modal with details
- Equip/unequip works via HTMX
- Use consumable works
- Equipment slots show equipped items

---

#### Task 3.4: Combat Testing & Polish ✅ COMPLETE

**Objective:** Playtest combat and fix bugs

**Testing Checklist:**
- ✅ Start combat from story session
- ✅ Turn order correct
- ✅ Attack deals damage
- ✅ Critical hits work
- ✅ Effects apply and tick correctly
- ✅ Defend action works
- ✅ Victory awards XP/gold/loot
- ✅ Defeat handling works
- ✅ Combat log readable
- ✅ HP/MP bars update
- ✅ Multiple enemies work - would like to update to allow the player to select which enemy to attack
- ✅ Combat state persists (refresh page)

- [ ] Spells consume mana - Need to test
- [ ] Items can be used in combat - Need to test

**Bug Fixes & Polish:**
- Fix any calculation errors
- Improve combat log messages
- Add visual feedback (animations, highlights)
- Improve mobile responsiveness
- Add loading states

**Acceptance Criteria:**
- Combat flows smoothly start to finish
- No critical bugs
- UX feels responsive and clear
- Ready for real gameplay

---


## Phase 4B: Skill Trees & Leveling (Week 4)
See [`/PHASE4b.md`](/PHASE4b.md)

## Phase 4C: NPC Shop (Days 15-18)
See [`/PHASE4c.md`](/PHASE4c.md)


## Success Criteria - Phase 4 Complete

### Combat System
- [ ] Turn-based combat works end-to-end
- [ ] Damage calculations correct (physical, magical, critical)
- [ ] Effects process correctly (DOT, HOT, buffs, debuffs, shields, stun)
- [ ] Combat UI functional and responsive
- [ ] Victory awards XP, gold, loot
- [ ] Combat state persists

### Inventory System
- [ ] Inventory displays in UI
- [ ] Equip/unequip items works
- [ ] Consumables can be used
- [ ] Equipment affects character stats
- [ ] Item YAML data loaded correctly

### Skill Trees
- [ ] Visual skill tree UI works
- [ ] Prerequisites enforced
- [ ] Unlock skills with skill points
- [ ] Respec functionality works
- [ ] Stat bonuses apply immediately

### Leveling
- [ ] XP awarded after combat
- [ ] Level up triggers at threshold
- [ ] Skill points granted on level up
- [ ] Level up modal shown
- [ ] Character stats increase

### NPC Shop
- [ ] Shop inventory displays
- [ ] Purchase validation works
- [ ] Items added to inventory
- [ ] Gold deducted correctly
- [ ] Transactions logged

---

## Next Steps After Phase 4

Once Phase 4 is complete, you'll have a fully playable combat game with progression. The next logical phases are:

**Phase 5: Story Progression & Quests** (Original Phase 4 from roadmap)
- AI-driven story progression
- Action prompts (button-based gameplay)
- Quest system (YAML-driven, context-aware)
- Full gameplay loop: Explore → Combat → Quests → Level Up

**Phase 6: Multiplayer Sessions**
- Invite-based co-op
- Time-limited sessions
- AI-generated campaigns

**Phase 7: Marketplace & Economy**
- Player-to-player trading
- Auction system
- Economy balancing

---

## Appendix: Testing Strategy

### Manual Testing Checklist

**Combat:**
- [ ] Start combat from story
- [ ] Turn order correct
- [ ] Attack deals damage
- [ ] Spells work
- [ ] Items usable in combat
- [ ] Defend action
- [ ] Victory conditions
- [ ] Defeat handling

**Inventory:**
- [ ] Add items
- [ ] Remove items
- [ ] Equip weapons
- [ ] Equip armor
- [ ] Use consumables
- [ ] Inventory UI updates

**Skills:**
- [ ] View skill trees
- [ ] Unlock skills
- [ ] Prerequisites enforced
- [ ] Stat bonuses apply
- [ ] Respec works

**Shop:**
- [ ] Browse inventory
- [ ] Purchase items
- [ ] Insufficient gold handling
- [ ] Transaction logging

---

## Document Maintenance

**Update this document as you complete tasks:**
- Mark tasks complete with ✅
- Add notes about implementation decisions
- Update time estimates based on actual progress
- Document any blockers or challenges

**Good luck with Phase 4 implementation!** 🚀
