# TetaRdPG — Brief Sprint 2

> Statut : 🔄 En cours
> Objectif : Moteur de combat PvE + retours textuels (logs)
> Stack : NestJS · PostgreSQL · TypeORM (synchronize dev)
> Prérequis : Sprint 1 livré ✅

---

## Scope Sprint 2

### ✅ In scope

- Entité `monsters` (5 monstres seedés, level 1–8)
- Moteur de combat PvE — résolution stateless côté serveur (un POST = combat complet)
- Formules GDD : Mêlée/Distance/Magie × 1.5 | Critique | Esquive
- Fin de combat : Victoire (XP + Or + +10% PV) / Défaite (20% PV + −50 endurance + perte or)
- Persistance des combats (`combat_logs`)
- Mise à jour character post-combat : hpCurrent, endurance, xp, gold, level, statPoints
- Level up basique : XP → seuil atteint → level++, +5 statPoints
- API : `GET /api/monsters`, `POST /api/combat/start`, `GET /api/combat/history`

### ❌ Out of scope

- Interactivité tour par tour (choix action par round) — Sprint 3
- Équipement / armure / arme → défense joueur = 0 Sprint 2
- Forge, artisanat, boutique
- Twitch, PvP
- Frontend React

---

## Décisions de design (game-designer)

| Décision | Valeur Sprint 2 | Justification |
|----------|----------------|---------------|
| Dégâts joueur | `Math.floor(stat × 1.5)` | Arme = 0 (pas d'équipement) |
| Défense joueur | 0 | Pas d'armure Sprint 2 |
| Crit | `5% + Chance × 0.2%` → dégâts ×1.5 | GDD |
| Esquive | `5% + Chance × 0.1%` → annule dégâts | GDD |
| Crit/Esquive monstres | Non (Sprint 2) | Simplification, fairness joueur |
| Défaite HP | 20% hpMax (retour auberge) | GDD "retour auberge" |
| Coût combat défaite | −10 (start) + −50 (peine) = −60 | GDD |
| Level up | `XP requise = round(100 × level^1.5)` | Formule GDD |
| Stat points / level | +5 par level franchi | GDD |

---

## Monstres seedés

| Nom | Level min | Level max | HP | Attaque | Défense | Type | XP | Or (min-max) |
|-----|-----------|-----------|-----|---------|---------|------|----|-------------|
| Têtard Vase | 1 | 2 | 40 | 5 | 0 | melee | 25 | 3–8 |
| Grenouille Boueuse | 2 | 4 | 65 | 8 | 1 | melee | 45 | 6–15 |
| Serpent des Marais | 3 | 6 | 90 | 11 | 2 | ranged | 70 | 10–25 |
| Champi Vénéneux | 2 | 5 | 75 | 9 | 3 | magic | 60 | 8–20 |
| Golem de Boue | 6 | 9 | 150 | 16 | 5 | melee | 130 | 25–60 |

---

## API Sprint 2

```
GET  /api/monsters                   → liste tous les monstres
POST /api/combat/start               → { monsterId, attackType: 'melee'|'ranged'|'magic' }
GET  /api/combat/history             → combats du personnage connecté
```

### Format réponse POST /api/combat/start

```json
{
  "winner": "player",
  "rounds": [
    {
      "round": 1,
      "playerDamage": 6, "playerCrit": true, "monsterDodged": false,
      "monsterDamage": 5, "playerDodged": false,
      "playerHp": 95, "monsterHp": 34,
      "log": ["Tetard frappe le Têtard Vase pour 6 dégâts (CRITIQUE) !", "Le Têtard Vase frappe Tetard pour 5 dégâts."]
    }
  ],
  "summary": "Victoire en 7 tours ! +25 XP, +5 Or.",
  "rewards": { "xp": 25, "gold": 5, "levelUp": false },
  "character": { "level": 1, "xp": 25, "gold": 5, "hpCurrent": 75, "enduranceCurrent": 90 }
}
```

---

## Architecture modules

```
src/
├── monster/
│   ├── monster.entity.ts
│   ├── monster.module.ts
│   ├── monster.service.ts
│   └── monster.controller.ts
├── combat/
│   ├── combat.engine.ts          → fonctions pures (pas de dépendances NestJS)
│   ├── combat-log.entity.ts
│   ├── combat.service.ts
│   ├── combat.controller.ts
│   ├── combat.module.ts
│   └── dto/start-combat.dto.ts
└── database/
    └── monsters-seed.ts
```

---

## Critères de validation integrator

- [ ] `GET /api/monsters` → liste 5 monstres
- [ ] `POST /api/combat/start` → combat résolu, log retourné
- [ ] Personnage level 1 peut vaincre Têtard Vase
- [ ] XP et or crédités après victoire
- [ ] `hpCurrent` mis à jour en DB après combat
- [ ] Endurance déduite (−10) après combat
- [ ] Défaite : `hpCurrent` = 20% hpMax, endurance −60 total
- [ ] `GET /api/combat/history` → historique retourné
- [ ] Sans cookie → 401
- [ ] Endurance insuffisante (< 10) → 400
- [ ] Monster inexistant → 404
- [ ] Level up déclenché si XP seuil atteint
