feat: communicate exploration zone unlock conditions in-game
Security Scan and Upload / Security & DefectDojo Upload (pull_request) Successful in 1m3s
CI / Lint, Build & Test (pull_request) Successful in 1m9s

Locked exploration zones now display the specific boss to defeat
and quest to complete required to unlock them. The About panel's
Exploration entry also documents the unlock rule explicitly.

Closes #59
This commit is contained in:
2026-03-19 12:06:55 -07:00
committed by Naomi Carrigan
parent c4b4fba4c9
commit 7629e88463
2 changed files with 45 additions and 2 deletions
+5 -1
View File
@@ -111,7 +111,11 @@ const howToPlay = [
+ " real-time and reward gold, essence, and crafting materials when" + " real-time and reward gold, essence, and crafting materials when"
+ " collected. Each area has a set duration — short explorations are" + " collected. Each area has a set duration — short explorations are"
+ " faster but longer ones offer rarer finds. A 📖 icon marks areas" + " faster but longer ones offer rarer finds. A 📖 icon marks areas"
+ " you've collected from at least once, unlocking a Codex entry.", + " you've collected from at least once, unlocking a Codex entry."
+ " Exploration zones are locked until the corresponding main-game"
+ " zone is unlocked — which requires defeating that zone's final boss"
+ " and completing its final quest. The Exploration tab shows the"
+ " specific boss and quest required for each locked zone.",
title: "🗺️ Exploration", title: "🗺️ Exploration",
}, },
{ {
@@ -6,6 +6,7 @@
*/ */
/* eslint-disable max-lines-per-function -- Complex component with many render paths */ /* eslint-disable max-lines-per-function -- Complex component with many render paths */
/* eslint-disable complexity -- Complex component with many conditional render paths */ /* eslint-disable complexity -- Complex component with many conditional render paths */
/* eslint-disable max-lines -- Exploration panel requires many render paths and result display */
import { type JSX, useState } from "react"; import { type JSX, useState } from "react";
import { useGame } from "../../context/gameContext.js"; import { useGame } from "../../context/gameContext.js";
import { EXPLORATION_AREAS } from "../../data/explorations.js"; import { EXPLORATION_AREAS } from "../../data/explorations.js";
@@ -91,7 +92,24 @@ const ExplorationPanel = (): JSX.Element => {
); );
} }
const { zones, exploration: explorationState } = state; const { zones, exploration: explorationState, bosses, quests } = state;
const activeZone = zones.find((zone) => {
return zone.id === activeZoneId;
});
const zoneIsLocked = activeZone?.status === "locked";
const unlockBoss = activeZone?.unlockBossId === null
|| activeZone?.unlockBossId === undefined
? undefined
: bosses.find((boss) => {
return boss.id === activeZone.unlockBossId;
});
const unlockQuest = activeZone?.unlockQuestId === null
|| activeZone?.unlockQuestId === undefined
? undefined
: quests.find((quest) => {
return quest.id === activeZone.unlockQuestId;
});
const zoneAreas = EXPLORATION_AREAS.filter((area) => { const zoneAreas = EXPLORATION_AREAS.filter((area) => {
return area.zoneId === activeZoneId; return area.zoneId === activeZoneId;
@@ -220,6 +238,27 @@ const ExplorationPanel = (): JSX.Element => {
zones={zones} zones={zones}
/> />
{zoneIsLocked && (unlockBoss !== undefined || unlockQuest !== undefined)
? <div className="exploration-zone-locked-hint">
<p>{"🔒 This zone is locked. Unlock exploration by:"}</p>
{unlockBoss === undefined
? null
: <p>
{"⚔️ Defeat: "}
{unlockBoss.name}
</p>
}
{unlockQuest === undefined
? null
: <p>
{"📜 Complete: "}
{unlockQuest.name}
</p>
}
</div>
: null
}
<div className="exploration-list"> <div className="exploration-list">
{zoneAreas.map((area) => { {zoneAreas.map((area) => {
const areaState = explorationState?.areas.find((explorationArea) => { const areaState = explorationState?.areas.find((explorationArea) => {