fix: quest progression (events after tx), abandon quest, endurance display
All checks were successful
CI/CD — Build & Deploy / Build & Deploy (push) Successful in 34s
All checks were successful
CI/CD — Build & Deploy / Build & Deploy (push) Successful in 34s
- Events (achievement/community/quest) émis APRÈS la transaction combat au lieu de dedans — corrige les quêtes qui ne progressaient pas - POST /api/quests/abandon/:id — abandonner une quête active - Frontend: bouton "Abandonner" sur les quêtes actives non complétées - Fix endurance display (enduranceCurrent field mapping) - Types Character mis à jour (xpToNextLevel, activeTitle, enduranceCurrent)
This commit is contained in:
@@ -44,7 +44,7 @@ export class CombatService {
|
||||
const monster = await this.monsterService.findOne(dto.monsterId);
|
||||
|
||||
// Transaction isolée — empêche les combats simultanés sur le même perso
|
||||
return this.dataSource.transaction(async (manager) => {
|
||||
const txResult = await this.dataSource.transaction(async (manager) => {
|
||||
// SELECT ... FOR UPDATE — verrouille le personnage
|
||||
const character = await manager
|
||||
.getRepository(Character)
|
||||
@@ -168,12 +168,11 @@ export class CombatService {
|
||||
|
||||
// Loot matériaux — 40% de chance après victoire
|
||||
let lootMaterial: { name: string; quantity: number } | null = null;
|
||||
let lootedMaterialId: string | 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 };
|
||||
this.eventEmitter.emit('quest.progress', {
|
||||
characterId: character.id, type: 'gather_material', targetId: monster.dropMaterialId, increment: 1,
|
||||
});
|
||||
lootedMaterialId = monster.dropMaterialId;
|
||||
}
|
||||
|
||||
// Persister le log
|
||||
@@ -189,32 +188,6 @@ export class CombatService {
|
||||
});
|
||||
await manager.save(combatLog);
|
||||
|
||||
// Events émis après la transaction (fire-and-forget)
|
||||
if (result.winner === 'player') {
|
||||
this.eventEmitter.emit('achievement.check', {
|
||||
characterId: character.id, type: 'combat_wins', increment: 1,
|
||||
});
|
||||
this.eventEmitter.emit('achievement.check', {
|
||||
characterId: character.id, type: 'level_reached', increment: 0, absolute: character.level,
|
||||
});
|
||||
this.eventEmitter.emit('achievement.check', {
|
||||
characterId: character.id, type: 'gold_accumulated', increment: 0, absolute: Number(character.totalGoldEarned),
|
||||
});
|
||||
this.eventEmitter.emit('community.contribute', {
|
||||
characterId: character.id, type: 'total_monsters_killed', increment: 1,
|
||||
});
|
||||
this.eventEmitter.emit('community.contribute', {
|
||||
characterId: character.id, type: 'total_gold_earned', increment: result.goldEarned,
|
||||
});
|
||||
// Quest progress
|
||||
this.eventEmitter.emit('quest.progress', {
|
||||
characterId: character.id, type: 'kill_any', increment: 1,
|
||||
});
|
||||
this.eventEmitter.emit('quest.progress', {
|
||||
characterId: character.id, type: 'kill_monster', targetId: monster.id, increment: 1,
|
||||
});
|
||||
}
|
||||
|
||||
// Construire la réponse
|
||||
const summaryParts: string[] = [];
|
||||
if (result.winner === 'player') {
|
||||
@@ -233,31 +206,52 @@ export class CombatService {
|
||||
}
|
||||
|
||||
return {
|
||||
winner: result.winner,
|
||||
rounds: result.rounds,
|
||||
summary: summaryParts.join(' '),
|
||||
rewards: {
|
||||
xp: result.xpEarned,
|
||||
gold: result.goldEarned,
|
||||
goldLost,
|
||||
levelUp: levelUpData.levelsGained > 0,
|
||||
newLevel: levelUpData.newLevel,
|
||||
statPointsGained: levelUpData.statPointsGained,
|
||||
loot: lootMaterial,
|
||||
},
|
||||
character: {
|
||||
level: character.level,
|
||||
xp: character.xp,
|
||||
xpToNextLevel: xpRequiredForLevel(character.level),
|
||||
gold: character.gold,
|
||||
hpCurrent: character.hpCurrent,
|
||||
hpMax: character.hpMax,
|
||||
enduranceCurrent: character.enduranceSaved,
|
||||
enduranceMax: character.enduranceMax,
|
||||
statPoints: character.statPoints ?? 0,
|
||||
characterId: character.id,
|
||||
lootedMaterialId,
|
||||
response: {
|
||||
winner: result.winner,
|
||||
rounds: result.rounds,
|
||||
summary: summaryParts.join(' '),
|
||||
rewards: {
|
||||
xp: result.xpEarned,
|
||||
gold: result.goldEarned,
|
||||
goldLost,
|
||||
levelUp: levelUpData.levelsGained > 0,
|
||||
newLevel: levelUpData.newLevel,
|
||||
statPointsGained: levelUpData.statPointsGained,
|
||||
loot: lootMaterial,
|
||||
},
|
||||
character: {
|
||||
level: character.level,
|
||||
xp: character.xp,
|
||||
xpToNextLevel: xpRequiredForLevel(character.level),
|
||||
gold: character.gold,
|
||||
hpCurrent: character.hpCurrent,
|
||||
hpMax: character.hpMax,
|
||||
enduranceCurrent: character.enduranceSaved,
|
||||
enduranceMax: character.enduranceMax,
|
||||
statPoints: character.statPoints ?? 0,
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
// Events émis APRÈS la transaction (fire-and-forget)
|
||||
if (txResult.response.winner === 'player') {
|
||||
const cid = txResult.characterId;
|
||||
this.eventEmitter.emit('achievement.check', { characterId: cid, type: 'combat_wins', increment: 1 });
|
||||
this.eventEmitter.emit('achievement.check', { characterId: cid, type: 'level_reached', increment: 0, absolute: txResult.response.character.level });
|
||||
this.eventEmitter.emit('achievement.check', { characterId: cid, type: 'gold_accumulated', increment: 0, absolute: txResult.response.rewards.gold });
|
||||
this.eventEmitter.emit('community.contribute', { characterId: cid, type: 'total_monsters_killed', increment: 1 });
|
||||
this.eventEmitter.emit('community.contribute', { characterId: cid, type: 'total_gold_earned', increment: txResult.response.rewards.gold });
|
||||
this.eventEmitter.emit('quest.progress', { characterId: cid, type: 'kill_any', increment: 1 });
|
||||
this.eventEmitter.emit('quest.progress', { characterId: cid, type: 'kill_monster', targetId: monster.id, increment: 1 });
|
||||
if (txResult.lootedMaterialId) {
|
||||
this.eventEmitter.emit('quest.progress', { characterId: cid, type: 'gather_material', targetId: txResult.lootedMaterialId, increment: 1 });
|
||||
}
|
||||
}
|
||||
|
||||
return txResult.response;
|
||||
}
|
||||
|
||||
async getHistory(user: User) {
|
||||
|
||||
Reference in New Issue
Block a user