feat: multi-combat ×5/×10 + cooldown anti-spam
Some checks failed
CI/CD — Build & Deploy / Build & Deploy (push) Failing after 30s
Some checks failed
CI/CD — Build & Deploy / Build & Deploy (push) Failing after 30s
- Backend: startMultiCombat boucle séquentielle, arrêt sur défaite - Frontend: cooldown 1.5s entre combats, boutons ×1/×5/×10 - Frontend: résumé multi-combat (wins/losses, XP/Or/loot totaux) - Fix: lock contention par spam de clics résolu
This commit is contained in:
@@ -16,6 +16,10 @@ export class CombatController {
|
||||
@Body() dto: StartCombatDto,
|
||||
@Req() req: Request & { user: User },
|
||||
) {
|
||||
const count = dto.count ?? 1;
|
||||
if (count > 1) {
|
||||
return this.combatService.startMultiCombat(dto, req.user, count);
|
||||
}
|
||||
return this.combatService.startCombat(dto, req.user);
|
||||
}
|
||||
|
||||
|
||||
@@ -287,6 +287,40 @@ export class CombatService {
|
||||
return txResult.response;
|
||||
}
|
||||
|
||||
async startMultiCombat(dto: StartCombatDto, user: User, count: number) {
|
||||
const results: any[] = [];
|
||||
const totals = { wins: 0, losses: 0, xp: 0, gold: 0, goldLost: 0, loot: [] as { name: string; quantity: number }[], levelsGained: 0 };
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
try {
|
||||
const result = await this.startCombat(dto, user);
|
||||
results.push(result);
|
||||
if (result.winner === 'player') {
|
||||
totals.wins++;
|
||||
totals.xp += result.rewards.xp;
|
||||
totals.gold += result.rewards.gold;
|
||||
if (result.rewards.levelUp) totals.levelsGained++;
|
||||
if (result.rewards.loot) totals.loot.push(result.rewards.loot);
|
||||
} else {
|
||||
totals.losses++;
|
||||
totals.goldLost += result.rewards.goldLost ?? 0;
|
||||
break; // Défaite = arrêt de la série
|
||||
}
|
||||
} catch {
|
||||
break; // Endurance insuffisante ou autre erreur = arrêt
|
||||
}
|
||||
}
|
||||
|
||||
const lastResult = results[results.length - 1];
|
||||
return {
|
||||
mode: 'multi',
|
||||
count: results.length,
|
||||
totals,
|
||||
lastResult,
|
||||
character: lastResult?.character,
|
||||
};
|
||||
}
|
||||
|
||||
async getHistory(user: User) {
|
||||
const character = await this.characterRepository.findOne({
|
||||
where: { userId: user.id },
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { IsUUID, IsIn } from 'class-validator';
|
||||
import { IsUUID, IsIn, IsOptional, IsInt, Min, Max } from 'class-validator';
|
||||
import { AttackType } from '../../monster/monster.entity';
|
||||
|
||||
export class StartCombatDto {
|
||||
@@ -7,4 +7,10 @@ export class StartCombatDto {
|
||||
|
||||
@IsIn(['melee', 'ranged', 'magic'])
|
||||
attackType: AttackType;
|
||||
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@Min(1)
|
||||
@Max(10)
|
||||
count?: number;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user