From 95fcf325dcf387c92e88c31c3a04afacdeef4a6b Mon Sep 17 00:00:00 2001 From: Tetardtek Date: Tue, 24 Mar 2026 18:08:49 +0100 Subject: [PATCH] fix: quest available filtering + 6 side quests level 2-4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: getAvailable filtre maintenant les quêtes active/completed (pas juste claimed). Plus de doublons dailies, plus d'internal server error. 6 quêtes secondaires pour combler le gap level 2-5: Chasseur de champignons (lv2, 150 XP), La menace rampante (lv3, 180 XP), Guerrier éprouvé (lv2, 250 XP), Collecteur de trophées (lv3, 500 XP), Exterminateur (lv4, 400 XP), Première forge (lv2, 120 XP). --- src/database/quests-seed.ts | 17 +++++++++++++++++ src/quest/quest.service.ts | 19 ++++++++++++------- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/database/quests-seed.ts b/src/database/quests-seed.ts index 1d66902..c758717 100644 --- a/src/database/quests-seed.ts +++ b/src/database/quests-seed.ts @@ -86,6 +86,23 @@ export async function seedQuests(dataSource: DataSource) { }, ]; + // Side quests — fill the level gaps + const SIDE_QUESTS = [ + { name: 'Chasseur de champignons', description: 'Les Champis Vénéneux infestent les sous-bois. Éliminez-en 3.', objectiveType: 'kill_monster', objectiveTargetId: monsterMap.get('Champi Vénéneux') ?? null as string | null, objectiveCount: 3, rewardXp: 150, rewardGold: 40, rewardTitle: null, arcId: null, arcOrder: 0, minLevel: 2, repeatable: false }, + { name: 'La menace rampante', description: 'Les Serpents des Marais sont de plus en plus agressifs. Tuez-en 3.', objectiveType: 'kill_monster', objectiveTargetId: monsterMap.get('Serpent des Marais') ?? null as string | null, objectiveCount: 3, rewardXp: 180, rewardGold: 50, rewardTitle: null, arcId: null, arcOrder: 0, minLevel: 3, repeatable: false }, + { name: 'Guerrier éprouvé', description: 'Prouvez votre valeur en remportant 20 combats.', objectiveType: 'kill_any', objectiveTargetId: null as string | null, objectiveCount: 20, rewardXp: 250, rewardGold: 80, rewardTitle: null, arcId: null, arcOrder: 0, minLevel: 2, repeatable: false }, + { name: 'Collecteur de trophées', description: 'Remportez 50 combats au total.', objectiveType: 'kill_any', objectiveTargetId: null as string | null, objectiveCount: 50, rewardXp: 500, rewardGold: 200, rewardTitle: 'Vétéran', arcId: null, arcOrder: 0, minLevel: 3, repeatable: false }, + { name: 'Exterminateur', description: 'Éliminez 10 monstres de chaque espèce des marais.', objectiveType: 'kill_any', objectiveTargetId: null as string | null, objectiveCount: 40, rewardXp: 400, rewardGold: 150, rewardTitle: null, arcId: null, arcOrder: 0, minLevel: 4, repeatable: false }, + { name: 'Première forge', description: 'Améliorez un item à la forge 3 fois.', objectiveType: 'forge_item', objectiveTargetId: null as string | null, objectiveCount: 3, rewardXp: 120, rewardGold: 40, rewardTitle: null, arcId: null, arcOrder: 0, minLevel: 2, repeatable: false }, + ]; + + for (const data of SIDE_QUESTS) { + const existing = await questRepo.findOne({ where: { name: data.name } }); + if (!existing) { + await questRepo.save(questRepo.create(data)); + } + } + // Standalone repeatable quests (daily feel) const STANDALONE = [ { diff --git a/src/quest/quest.service.ts b/src/quest/quest.service.ts index 7ee4168..5acefbc 100644 --- a/src/quest/quest.service.ts +++ b/src/quest/quest.service.ts @@ -32,22 +32,27 @@ export class QuestService { const character = await this.characterRepo.findOne({ where: { id: characterId } }); if (!character) throw new BadRequestException('Aucun personnage'); - // All quests the player hasn't completed (or repeatable) - const completed = await this.playerQuestRepo.find({ - where: { characterId, status: 'claimed' }, - select: ['questId'], + // All player quests (any status) + const playerQuests = await this.playerQuestRepo.find({ + where: { characterId }, + select: ['questId', 'status'], }); - const completedIds = new Set(completed.map((pq) => pq.questId)); + const questStatusMap = new Map(playerQuests.map((pq) => [pq.questId, pq.status])); const quests = await this.questRepo.find({ - where: { minLevel: undefined }, // load all, filter in code relations: ['arc'], order: { arcOrder: 'ASC' }, }); return quests.filter((q) => { if (q.minLevel > character.level) return false; - if (completedIds.has(q.id) && !q.repeatable) return false; + + const status = questStatusMap.get(q.id); + // Already active or completed (waiting claim) → not available + if (status === 'active' || status === 'completed') return false; + // Already claimed and not repeatable → not available + if (status === 'claimed' && !q.repeatable) return false; + return true; }); }