feat: add auto-quest and auto-boss toggles

Adds optional automation to the quest and boss panels. Auto-quest
automatically starts the highest-zone available quest (respecting CP
requirements) as soon as none is active. Auto-boss automatically
challenges the highest available boss when one is ready. Both run
exclusively in the client-side RAF tick loop — offline calculations
are unaffected. Toggles persist in GameState via cloud save.
This commit is contained in:
2026-03-07 15:26:41 -08:00
committed by Naomi Carrigan
parent bec972aed1
commit 74d1d21419
6 changed files with 237 additions and 112 deletions
@@ -83,6 +83,10 @@ const HOW_TO_PLAY = [
title: "🔥 Daily Login Bonus",
body: "Log in every day to earn escalating rewards! Each consecutive day awards more gold, and the 7th day of your streak grants bonus crystals. Your streak resets if you miss a day. A week multiplier increases all rewards the longer your overall streak runs. Your current streak is displayed on your character sheet.",
},
{
title: "🤖 Auto-Quest & Auto-Boss",
body: "Toggle automation in the Quests and Boss Encounters panels! Auto-Quest automatically sends your party on the highest-zone available quest as soon as one completes, skipping quests whose combat power requirement isn't met. Auto-Boss automatically challenges the highest available boss as soon as one is ready. Both can be toggled on or off at any time using the 🤖 Auto button in each panel header.",
},
{
title: "☁️ Cloud Saves",
body: "Your progress is automatically saved to the cloud every 30 seconds whilst you play. You can also force a manual save at any time using the sync button in the resource bar. Your save is protected by HMAC validation to ensure data integrity.",
+16 -6
View File
@@ -96,7 +96,7 @@ const BossCard = ({
};
export const BossPanel = (): React.JSX.Element => {
const { state, challengeBoss, formatNumber } = useGame();
const { state, challengeBoss, formatNumber, toggleAutoBoss } = useGame();
const [challengingBossId, setChallengingBossId] = useState<string | null>(null);
const [activeZoneId, setActiveZoneId] = useState("verdant_vale");
const [showLocked, setShowLocked] = useState(true);
@@ -187,11 +187,21 @@ export const BossPanel = (): React.JSX.Element => {
<section className="panel boss-panel">
<div className="panel-header">
<h2>Boss Encounters</h2>
<LockToggle
lockedCount={lockedCount}
showLocked={showLocked}
onToggle={() => { setShowLocked((v) => !v); }}
/>
<div className="panel-header-controls">
<button
className={`auto-toggle-btn ${state.autoBoss ? "auto-toggle-on" : "auto-toggle-off"}`}
onClick={toggleAutoBoss}
title="Automatically challenge the highest available boss"
type="button"
>
🤖 Auto: {state.autoBoss ? "ON" : "OFF"}
</button>
<LockToggle
lockedCount={lockedCount}
showLocked={showLocked}
onToggle={() => { setShowLocked((v) => !v); }}
/>
</div>
</div>
<ZoneSelector
+16 -6
View File
@@ -86,7 +86,7 @@ const QuestCard = ({ quest, partyCombatPower, unlockHint, zoneHint }: QuestCardP
};
export const QuestPanel = (): React.JSX.Element => {
const { state } = useGame();
const { state, toggleAutoQuest } = useGame();
const [activeZoneId, setActiveZoneId] = useState("verdant_vale");
const [showLocked, setShowLocked] = useState(true);
@@ -128,11 +128,21 @@ export const QuestPanel = (): React.JSX.Element => {
<section className="panel quest-panel">
<div className="panel-header">
<h2>Quests</h2>
<LockToggle
lockedCount={lockedCount}
showLocked={showLocked}
onToggle={() => { setShowLocked((v) => !v); }}
/>
<div className="panel-header-controls">
<button
className={`auto-toggle-btn ${state.autoQuest ? "auto-toggle-on" : "auto-toggle-off"}`}
onClick={toggleAutoQuest}
title="Automatically send the party on the highest available quest"
type="button"
>
🤖 Auto: {state.autoQuest ? "ON" : "OFF"}
</button>
<LockToggle
lockedCount={lockedCount}
showLocked={showLocked}
onToggle={() => { setShowLocked((v) => !v); }}
/>
</div>
</div>
<ZoneSelector