# 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