feat: zone locking — progression par arcs narratifs + arcs Égouts/Désert
All checks were successful
CI/CD — Build & Deploy / Build & Deploy (push) Successful in 33s

Zones verrouillées: marais toujours ouvert, égouts après arc Marais,
désert après arc Égouts. Filtrage backend sur monstres ET boutique.

Arc "Les Égouts de la Cité" (4 quêtes, lv4-7, boss Roi des Rats)
Arc "Les Sables Brûlants" (3 quêtes, lv8-12, boss Sphinx)

GET /api/monsters/zones — retourne les zones avec statut unlocked.
Combat page: monstres groupés par zone, zones lockées avec icône cadenas.
Boutique: items filtrés par zones débloquées (potions toujours visibles).
This commit is contained in:
2026-03-24 17:57:23 +01:00
parent 8cb5fcd5ba
commit d1609efaae
8 changed files with 222 additions and 29 deletions

44
src/common/zone-access.ts Normal file
View File

@@ -0,0 +1,44 @@
import { Repository } from 'typeorm';
import { PlayerQuestArc } from '../quest/player-quest-arc.entity';
import { QuestArc } from '../quest/quest-arc.entity';
// Zone unlock chain: each zone requires completing the previous zone's arc
// marais → always open
// egouts → requires "Les Marais du Têtard" arc completed
// desert → requires the egouts arc completed
const ZONE_ORDER = ['marais', 'egouts', 'desert'];
export async function getUnlockedZones(
characterId: string,
arcRepo: Repository<QuestArc>,
playerArcRepo: Repository<PlayerQuestArc>,
): Promise<string[]> {
const unlocked: string[] = ['marais']; // always accessible
// Get all completed arcs for this character
const completedArcs = await playerArcRepo.find({
where: { characterId, completed: true },
relations: ['questArc'],
});
const completedArcZones = new Set(completedArcs.map(pa => pa.questArc?.zone).filter(Boolean));
// Check zone chain: each zone unlocks the next
for (let i = 0; i < ZONE_ORDER.length - 1; i++) {
const currentZone = ZONE_ORDER[i];
const nextZone = ZONE_ORDER[i + 1];
// Find arc for current zone
const arc = await arcRepo.findOne({ where: { zone: currentZone } });
if (!arc) continue;
// If this zone's arc is completed, unlock the next zone
const isCompleted = completedArcs.some(pa => pa.questArcId === arc.id);
if (isCompleted) {
unlocked.push(nextZone);
} else {
break; // Can't skip zones
}
}
return unlocked;
}