feat: communicate quest failure mechanics in the UI #82

Merged
naomi merged 1 commits from feat/quest-failure-clarity into main 2026-03-19 17:57:18 -07:00
3 changed files with 18 additions and 3 deletions
+5 -1
View File
@@ -44,7 +44,11 @@ const howToPlay = [
body: body:
"Send your guild on quests that complete over time and reward gold," "Send your guild on quests that complete over time and reward gold,"
+ " essence, crystals, equipment, and upgrades. Multiple quests can run" + " essence, crystals, equipment, and upgrades. Multiple quests can run"
+ " simultaneously. Completing quests also unlocks new zones.", + " simultaneously. Completing quests also unlocks new zones."
+ " Each quest has a failure chance that increases in later zones"
+ " (from 10% in the starting zone up to 40% in the hardest zones)."
+ " If a quest fails, no rewards are granted and the quest resets —"
+ " your party must be sent again to retry it.",
title: "📜 Quests", title: "📜 Quests",
}, },
{ {
+12 -1
View File
@@ -10,6 +10,7 @@
/* eslint-disable max-statements -- Many local variables needed for quest state */ /* eslint-disable max-statements -- Many local variables needed for quest state */
import { useState, type JSX } from "react"; import { useState, type JSX } from "react";
import { useGame } from "../../context/gameContext.js"; import { useGame } from "../../context/gameContext.js";
import { zoneFailureChance } from "../../engine/tick.js";
import { cdnImage } from "../../utils/cdn.js"; import { cdnImage } from "../../utils/cdn.js";
import { LockToggle } from "../ui/lockToggle.js"; import { LockToggle } from "../ui/lockToggle.js";
import { ZoneSelector } from "./zoneSelector.js"; import { ZoneSelector } from "./zoneSelector.js";
@@ -143,8 +144,18 @@ const QuestCard = ({
: null} : null}
</> </>
} }
{quest.status === "available"
&& <p className="quest-failure-chance">
{"🎲 "}
{String(Math.round((zoneFailureChance[quest.zoneId] ?? 0) * 100))}
{"% failure chance — if failed, the quest resets"}
{" and must be retried."}
</p>
}
{quest.status === "available" && quest.lastFailedAt !== undefined {quest.status === "available" && quest.lastFailedAt !== undefined
&& <p className="quest-failed-hint">{"⚠️ Last attempt failed"}</p> && <p className="quest-failed-hint">
{"⚠️ Last attempt failed — no rewards were granted."}
</p>
} }
{quest.status === "available" {quest.status === "available"
&& <button && <button
+1 -1
View File
@@ -93,7 +93,7 @@ export const RESOURCE_CAP = 1e300;
* On failure the quest resets to "available" with no rewards; the player must wait the * On failure the quest resets to "available" with no rewards; the player must wait the
* full duration again on their next attempt. * full duration again on their next attempt.
*/ */
const zoneFailureChance: Record<string, number> = { export const zoneFailureChance: Record<string, number> = {
abyssal_trench: 0.24, abyssal_trench: 0.24,
astral_void: 0.2, astral_void: 0.2,
celestial_reaches: 0.22, celestial_reaches: 0.22,