generated from nhcarrigan/template
feat: sequential zone unlocking with dual boss+quest gate conditions
Zones now unlock in strict linear order. Each zone requires both the final boss AND the final quest of the previous zone to be completed: Verdant Vale → Shattered Ruins (forest_giant + ancient_ruins) Shattered Ruins → Frozen Peaks (elder_dragon + dragon_lair) Frozen Peaks → Shadow Marshes (void_titan + storm_citadel) Shadow Marshes → Volcanic Depths (mud_kraken + plague_ruins) Volcanic Depths → Astral Void (phoenix_lord + the_forge) - Zone type gains `unlockQuestId` field alongside `unlockBossId` - boss.ts checks both conditions before unlocking zone on boss defeat - tick.ts checks both conditions and unlocks zones + first boss on quest completion if the boss condition is already met - GameContext optimistic update also respects dual-condition logic - BossPanel zone-gate hints now show both "⚔️ Defeat: X & 📜 Complete: Y" - game.ts backfill syncs unlockQuestId and re-verifies zone status using both conditions, reverting incorrectly-unlocked saves
This commit is contained in:
@@ -279,7 +279,14 @@ export const GameProvider = ({ children }: { children: React.ReactNode }): React
|
||||
const nextZoneBossId = zoneBosses[zoneIdx + 1]?.id;
|
||||
|
||||
// Find newly unlocked zones and their first bosses
|
||||
const newlyUnlockedZones = (prev.zones ?? []).filter((z) => z.unlockBossId === bossId && z.status === "locked");
|
||||
// A zone unlocks when BOTH the gate boss is defeated AND the gate quest is completed
|
||||
const newlyUnlockedZones = (prev.zones ?? []).filter((z) => {
|
||||
if (z.status !== "locked" || z.unlockBossId !== bossId) return false;
|
||||
const questOk =
|
||||
z.unlockQuestId == null ||
|
||||
prev.quests.some((q) => q.id === z.unlockQuestId && q.status === "completed");
|
||||
return questOk;
|
||||
});
|
||||
const newZoneFirstBossIds = newlyUnlockedZones.map((z) => {
|
||||
const firstBoss = prev.bosses.find((b) => b.zoneId === z.id);
|
||||
return firstBoss?.id;
|
||||
@@ -297,9 +304,13 @@ export const GameProvider = ({ children }: { children: React.ReactNode }): React
|
||||
}
|
||||
return b;
|
||||
}),
|
||||
zones: (prev.zones ?? []).map((z) =>
|
||||
z.unlockBossId === bossId ? { ...z, status: "unlocked" as const } : z,
|
||||
),
|
||||
zones: (prev.zones ?? []).map((z) => {
|
||||
if (z.status !== "locked" || z.unlockBossId !== bossId) return z;
|
||||
const questOk =
|
||||
z.unlockQuestId == null ||
|
||||
prev.quests.some((q) => q.id === z.unlockQuestId && q.status === "completed");
|
||||
return questOk ? { ...z, status: "unlocked" as const } : z;
|
||||
}),
|
||||
resources: result.rewards
|
||||
? {
|
||||
...prev.resources,
|
||||
|
||||
Reference in New Issue
Block a user