Moteur combat stateless (POST /api/combat/start résout le combat complet). Formules GDD : Mêlée/Distance/Magie × 1.5, critique (5% + Chance×0.2%), esquive (5% + Chance×0.1%). 5 monstres seedés (Têtard Vase → Golem de Boue, level 1–9). Level up : XP → seuil atteint → level++, +5 statPoints. Persiste combat_logs (jsonb rounds). Validé : victoire, défaite, 401, 400, 404.
4.2 KiB
4.2 KiB
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
{
"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 monstresPOST /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
hpCurrentmis à 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