Files
TetaRdPG/SPRINT3.md

245 lines
7.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TetaRdPG — Brief Sprint 3
> Statut : 🔄 En cours
> Objectif : Items + Inventaire + Artisanat (Craft) + Forge
> Stack : NestJS · PostgreSQL · TypeORM (synchronize dev)
> Prérequis : Sprint 2 livré ✅
---
## Scope Sprint 3
### ✅ In scope
- Entité `items` (armes + armures) avec bonus stats
- Inventaire joueur (`character_items`) — possession + équipement actif
- Intégration combat : `player.attack` et `player.defense` depuis l'équipement équipé
- Entité `materials` + inventaire joueur (`character_materials`) — loot post-combat
- Entité `recipes` + ingrédients en jsonb
- Artisanat (`craft_jobs`) — lazy calc timer (même pattern que endurance)
- Forge — amélioration item niveau 15 avec risque croissant
- Seeds : 5 items de base, 5 matériaux, 3 recettes
- API : voir section dédiée
### ❌ Out of scope
- Boutique (achat/vente) — Sprint 4
- Bonus de sets d'équipement — Sprint 4
- TetardCoin (accélération craft, forge garantie) — sprint monétisation
- Twitch, PvP, guildes
- Frontend React
---
## Décisions de design (game-designer)
| Décision | Valeur | Justification |
|----------|--------|---------------|
| Slots équipement | weapon + armor | Simplifié Sprint 3 — casque/bottes Sprint 4 |
| Player.attack en combat | `char.weapon?.attackBonus ?? 0` | Remplace attack=0 Sprint 2 |
| Player.defense en combat | `char.armor?.defenseBonus ?? 0` | Remplace defense=0 Sprint 2 |
| Loot drop | 40% de chance après victoire | 1 matériau aléatoire parmi ceux du monstre |
| Craft timer | lazy calc : `startedAt + durationMs` | Même pattern endurance — zéro job schedulé |
| Forge risque | Niv.12 : 0% | 3 : 20% | 4 : 30% | 5 : 40% | GDD exact |
| Forge succès garanti | 12 TetardCoin (non implémenté Sprint 3) | Placeholder, champ `forcedSuccess` |
| Forge échec | item inchangé, pas de coût matériaux Sprint 3 | coût matériaux forge = Sprint 4 |
| Durée craft | court: 15s (dev) / long: 60s (dev) | Valeurs réelles en prod : 15min2h |
---
## Schéma DB
### `items`
```
id uuid PK
name varchar(100)
description text
type varchar(20) -- 'weapon' | 'armor'
rarity varchar(20) -- 'common' | 'rare' | 'epic' | 'legendary'
attack_bonus int default 0
defense_bonus int default 0
force_bonus int default 0
agilite_bonus int default 0
intelligence_bonus int default 0
chance_bonus int default 0
vitalite_bonus int default 0
```
### `character_items`
```
id uuid PK
character_id uuid FK characters
item_id uuid FK items
forge_level int default 0 -- 0 = non forgé
equipped boolean default false
acquired_at timestamp
```
### `materials`
```
id uuid PK
name varchar(100)
description text
rarity varchar(20)
```
### `character_materials`
```
id uuid PK
character_id uuid FK characters
material_id uuid FK materials
quantity int default 0
```
### `recipes`
```
id uuid PK
name varchar(100)
result_item_id uuid FK items
craft_duration_seconds int
endurance_cost int
ingredients jsonb -- [{ materialId, quantity }]
```
### `craft_jobs`
```
id uuid PK
character_id uuid FK characters
recipe_id uuid FK recipes
started_at timestamp
completed_at timestamp -- lazy : startedAt + duration
collected boolean default false
```
---
## Seeds
### Items (5)
| Nom | Type | Rareté | Attack | Defense | Notes |
|-----|------|--------|--------|---------|-------|
| Bâton de Roseau | weapon | common | 3 | 0 | Arme de départ |
| Dague Rouillée | weapon | common | 5 | 0 | |
| Épée Courte | weapon | rare | 9 | 0 | |
| Gilet de Cuir | armor | common | 0 | 3 | |
| Cotte de Mailles | armor | rare | 0 | 7 | |
### Matériaux (5)
| Nom | Rareté | Sources |
|-----|--------|---------|
| Bave de Têtard | common | Têtard Vase |
| Écailles de Grenouille | common | Grenouille Boueuse |
| Venin de Serpent | rare | Serpent des Marais |
| Spores Vénéneuses | rare | Champi Vénéneux |
| Fragment de Boue | common | Golem de Boue |
### Recettes (3)
| Nom | Résultat | Durée (dev) | Endurance | Ingrédients |
|-----|----------|-------------|-----------|-------------|
| Forge Bâton Renforcé | Bâton de Roseau+? | 15s | 5 | 2× Bave de Têtard |
| Craft Dague | Dague Rouillée | 15s | 8 | 3× Bave + 1× Écaille |
| Craft Gilet de Cuir | Gilet de Cuir | 30s | 10 | 3× Écaille + 2× Fragment |
---
## API Sprint 3
```
# Items
GET /api/items → liste tous les items (catalogue)
GET /api/items/inventory → inventaire du personnage connecté
POST /api/items/equip/:itemId → équiper un item (character_items.id)
POST /api/items/unequip/:slot → déséquiper un slot (weapon|armor)
# Materials
GET /api/materials → catalogue matériaux
GET /api/materials/inventory → matériaux du personnage connecté
# Craft
GET /api/craft/recipes → liste recettes
POST /api/craft/start → { recipeId } → lance le craft
GET /api/craft/active → craft en cours (lazy status)
POST /api/craft/collect/:jobId → collecter si terminé
# Forge
POST /api/forge/upgrade → { characterItemId } → tente amélioration
```
---
## Architecture modules
```
src/
├── item/
│ ├── item.entity.ts
│ ├── character-item.entity.ts
│ ├── item.module.ts
│ ├── item.service.ts
│ └── item.controller.ts
├── material/
│ ├── material.entity.ts
│ ├── character-material.entity.ts
│ ├── material.module.ts
│ ├── material.service.ts
│ └── material.controller.ts
├── craft/
│ ├── recipe.entity.ts
│ ├── craft-job.entity.ts
│ ├── craft.module.ts
│ ├── craft.service.ts
│ └── craft.controller.ts
├── forge/
│ ├── forge.module.ts
│ ├── forge.service.ts
│ └── forge.controller.ts
└── database/
└── items-seed.ts
```
---
## Intégration combat (CombatEngine)
```typescript
// Dans CombatService.startCombat() — charger l'équipement
const weaponBonus = char.equippedWeapon?.item.attackBonus ?? 0;
const armorBonus = char.equippedArmor?.item.defenseBonus ?? 0;
const playerStats: CombatantStats = {
...
attack: weaponBonus, // était 0 Sprint 2
defense: armorBonus, // était 0 Sprint 2
};
```
Loot post-victoire :
```typescript
if (result.winner === 'player' && Math.random() < 0.4) {
// créditer 1 matériau aléatoire dans character_materials
}
```
---
## Critères de validation integrator
- [ ] `GET /api/items` → 5 items seedés
- [ ] `GET /api/materials` → 5 matériaux seedés
- [ ] `POST /api/items/equip/:id` → item équipé, character mis à jour
- [ ] Combat avec arme équipée → player.attack = weaponBonus
- [ ] Victoire combat → chance de loot matériau (40%)
- [ ] `GET /api/materials/inventory` → quantité augmentée après loot
- [ ] `GET /api/craft/recipes` → 3 recettes disponibles
- [ ] `POST /api/craft/start` → job créé, endurance déduite
- [ ] `GET /api/craft/active` → status `pending` | `ready` | `none`
- [ ] `POST /api/craft/collect/:jobId` → item ajouté à l'inventaire
- [ ] Collect avant fin → 400 "not ready yet"
- [ ] `POST /api/forge/upgrade` → niveau 1 : succès garanti
- [ ] Forge niveau 3 → 20% chance échec (matériaux déduits, forgeLvl inchangé)
- [ ] Sans cookie → 401 sur toutes les routes protégées
- [ ] Endurance insuffisante pour craft → 400