feat(sprint3): items + forge + craft + loot — équipement, artisanat lazy-calc, forge risque GDD

This commit is contained in:
2026-03-15 08:22:20 +01:00
parent 6d1230d16a
commit 23f7dd0f3c
25 changed files with 1169 additions and 2 deletions

View File

@@ -7,6 +7,8 @@ import { MonsterService } from '../monster/monster.service';
import { CombatLog } from './combat-log.entity';
import { StartCombatDto } from './dto/start-combat.dto';
import { User } from '../user/user.entity';
import { ItemService } from '../item/item.service';
import { MaterialService } from '../material/material.service';
import {
resolveCombat,
applyXpGain,
@@ -27,6 +29,8 @@ export class CombatService {
@InjectRepository(CombatLog)
private readonly combatLogRepository: Repository<CombatLog>,
private readonly monsterService: MonsterService,
private readonly itemService: ItemService,
private readonly materialService: MaterialService,
) {}
async startCombat(dto: StartCombatDto, user: User) {
@@ -54,6 +58,16 @@ export class CombatService {
throw new BadRequestException('Votre personnage est KO — récupérez d\'abord vos PV');
}
// Charger l'équipement actif du personnage
const equipped = await this.itemService.getEquippedItems(character.id);
const FORGE_BONUS_PER_LEVEL = 2;
const weaponAttack = equipped.weapon
? equipped.weapon.item.attackBonus + equipped.weapon.forgeLevel * FORGE_BONUS_PER_LEVEL
: 0;
const armorDefense = equipped.armor
? equipped.armor.item.defenseBonus + equipped.armor.forgeLevel * FORGE_BONUS_PER_LEVEL
: 0;
// Construire les stats des combattants
const playerStats: CombatantStats = {
name: character.name,
@@ -63,8 +77,8 @@ export class CombatService {
agilite: character.agilite,
intelligence: character.intelligence,
chance: character.chance,
attack: 0, // pas d'arme Sprint 2
defense: 0, // pas d'armure Sprint 2
attack: weaponAttack,
defense: armorDefense,
attackType: dto.attackType,
};
@@ -118,6 +132,13 @@ export class CombatService {
character.lastEnduranceTs = new Date();
await this.characterRepository.save(character);
// Loot matériaux — 40% de chance après victoire si le monstre a un drop_material_id
let lootMaterial: { name: string; quantity: number } | null = null;
if (result.winner === 'player' && monster.dropMaterialId && Math.random() < 0.4) {
await this.materialService.addMaterial(character.id, monster.dropMaterialId, 1);
lootMaterial = { name: 'matériau', quantity: 1 };
}
// Persister le log
const combatLog = this.combatLogRepository.create({
characterId: character.id,
@@ -144,6 +165,10 @@ export class CombatService {
if (goldLost > 0) summaryParts.push(`${goldLost} Or perdu.`);
}
if (lootMaterial) {
summaryParts.push(`Loot : 1 matériau obtenu !`);
}
return {
winner: result.winner,
rounds: result.rounds,
@@ -155,6 +180,7 @@ export class CombatService {
levelUp: levelUpData.levelsGained > 0,
newLevel: levelUpData.newLevel,
statPointsGained: levelUpData.statPointsGained,
loot: lootMaterial,
},
character: {
level: character.level,