feat(sprint3): items + forge + craft + loot — équipement, artisanat lazy-calc, forge risque GDD
This commit is contained in:
68
src/forge/forge.service.ts
Normal file
68
src/forge/forge.service.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import { Injectable, BadRequestException, NotFoundException } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { CharacterItem } from '../item/character-item.entity';
|
||||
import { Character } from '../character/entities/character.entity';
|
||||
import { User } from '../user/user.entity';
|
||||
|
||||
const MAX_FORGE_LEVEL = 5;
|
||||
const FORGE_BONUS_PER_LEVEL = 2; // +2 attack (weapon) ou +2 defense (armor) par niveau affiché
|
||||
|
||||
// Risque d'échec par niveau cible (GDD exact)
|
||||
const FORGE_FAIL_CHANCE: Record<number, number> = {
|
||||
1: 0,
|
||||
2: 0,
|
||||
3: 0.20,
|
||||
4: 0.30,
|
||||
5: 0.40,
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class ForgeService {
|
||||
constructor(
|
||||
@InjectRepository(CharacterItem)
|
||||
private readonly charItemRepository: Repository<CharacterItem>,
|
||||
@InjectRepository(Character)
|
||||
private readonly characterRepository: Repository<Character>,
|
||||
) {}
|
||||
|
||||
async upgradeItem(charItemId: string, user: User) {
|
||||
const char = await this.characterRepository.findOne({ where: { userId: user.id } });
|
||||
if (!char) throw new BadRequestException('Aucun personnage trouvé');
|
||||
|
||||
const charItem = await this.charItemRepository.findOne({
|
||||
where: { id: charItemId, characterId: char.id },
|
||||
});
|
||||
if (!charItem) throw new NotFoundException('Item non trouvé dans l\'inventaire');
|
||||
if (charItem.forgeLevel >= MAX_FORGE_LEVEL) {
|
||||
throw new BadRequestException(`Niveau de forge maximum atteint (${MAX_FORGE_LEVEL})`);
|
||||
}
|
||||
|
||||
const targetLevel = charItem.forgeLevel + 1;
|
||||
const failChance = FORGE_FAIL_CHANCE[targetLevel] ?? 0;
|
||||
const success = Math.random() >= failChance;
|
||||
|
||||
if (success) {
|
||||
charItem.forgeLevel = targetLevel;
|
||||
await this.charItemRepository.save(charItem);
|
||||
|
||||
const statLabel = charItem.item.type === 'weapon'
|
||||
? `+${FORGE_BONUS_PER_LEVEL} ATK`
|
||||
: `+${FORGE_BONUS_PER_LEVEL} DEF`;
|
||||
|
||||
return {
|
||||
success: true,
|
||||
forgeLevel: charItem.forgeLevel,
|
||||
item: charItem.item.name,
|
||||
message: `Forge réussie ! ${charItem.item.name} [+${charItem.forgeLevel}] (${statLabel}).`,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
success: false,
|
||||
forgeLevel: charItem.forgeLevel,
|
||||
item: charItem.item.name,
|
||||
message: `Échec de forge ! ${charItem.item.name} reste au niveau [+${charItem.forgeLevel}].`,
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user