Task 2: SpireTab Overhaul - add Climb the Spire button, implement Spire Mode with exit condition

This commit is contained in:
Refactoring Agent
2026-04-26 13:44:09 +02:00
parent 9f029d93e1
commit 50ce70efdd
6 changed files with 426 additions and 294 deletions
+43 -33
View File
@@ -749,6 +749,9 @@ function makeInitial(overrides: Partial<GameState> = {}): GameState {
// Mana Well Effects (Phase 4)
manaHeartBonus: manaHeartBonus, // Cumulative +10% max mana per loop from MANA_HEART
// Spire Mode - simplified UI for climbing
spireMode: false,
};
}
@@ -801,6 +804,10 @@ interface GameStore extends GameState, CraftingActions {
getMeditationMultiplier: () => number;
canCastSpell: (spellId: string) => boolean;
getSkillUpgradeChoices: (skillId: string, milestone: 5 | 10) => { available: SkillUpgradeChoice[]; selected: string[] };
// Spire Mode actions
enterSpireMode: () => void;
exitSpireMode: () => void;
}
export const useGameStore = create<GameStore>()(
@@ -833,6 +840,9 @@ export const useGameStore = create<GameStore>()(
// Compute unified effects (includes skill upgrades AND equipment enchantments)
const effects = getUnifiedEffects(state);
// Track current action for potential auto-transitions
let currentAction = state.currentAction;
const maxMana = computeMaxMana(state, effects);
const baseRegen = computeRegen(state, effects);
@@ -878,7 +888,7 @@ export const useGameStore = create<GameStore>()(
let meditateTicks = state.meditateTicks;
let meditationMultiplier = 1;
if (state.currentAction === 'meditate') {
if (currentAction === 'meditate') {
meditateTicks++;
meditationMultiplier = getMeditationBonus(meditateTicks, state.skills);
@@ -973,7 +983,7 @@ export const useGameStore = create<GameStore>()(
let unlockedEffects = state.unlockedEffects;
let consecutiveStudyHours = state.consecutiveStudyHours;
if (state.currentAction === 'study' && currentStudyTarget) {
if (currentAction === 'study' && currentStudyTarget) {
// Calculate base study speed
let studySpeedMult = getStudySpeedMultiplier(skills);
@@ -1076,11 +1086,13 @@ export const useGameStore = create<GameStore>()(
log = [`📖 ${SPELLS_DEF[spellId]?.name} learned!`, ...log.slice(0, 49)];
}
currentStudyTarget = null;
// Auto-transition to meditate when study completes
currentAction = 'meditate';
}
}
// Parallel Study processing (PARALLEL_STUDY special effect)
let parallelStudyTarget = state.parallelStudyTarget;
if (parallelStudyTarget && state.currentAction === 'study') {
if (parallelStudyTarget && currentAction === 'study') {
// Parallel study progresses at 50% speed
const parallelProgressGain = HOURS_PER_TICK * 0.5;
parallelStudyTarget = {
@@ -1101,7 +1113,7 @@ export const useGameStore = create<GameStore>()(
}
// Convert action - auto convert mana
if (state.currentAction === 'convert') {
if (currentAction === 'convert') {
const unlockedElements = Object.entries(elements)
.filter(([, e]) => e.unlocked && e.current < e.max);
@@ -1130,7 +1142,7 @@ export const useGameStore = create<GameStore>()(
const floorElement = getFloorElement(currentFloor);
// Handle puzzle rooms separately
if (state.currentAction === 'climb' && currentRoom.roomType === 'puzzle') {
if (currentAction === 'climb' && currentRoom.roomType === 'puzzle') {
const progressSpeed = getPuzzleProgressSpeed(
currentRoom.puzzleId || '',
state.attunements
@@ -1154,7 +1166,7 @@ export const useGameStore = create<GameStore>()(
maxFloorReached = Math.max(maxFloorReached, currentFloor);
castProgress = 0;
}
} else if (state.currentAction === 'climb') {
} else if (currentAction === 'climb') {
const spellId = state.activeSpell;
const spellDef = SPELLS_DEF[spellId];
@@ -1358,7 +1370,7 @@ export const useGameStore = create<GameStore>()(
const floorChanged = currentFloor !== golemancy.lastSummonFloor;
const inCombatRoom = currentRoom.roomType !== 'puzzle';
if (state.currentAction === 'climb' && inCombatRoom && floorChanged && maxGolemSlots > 0) {
if (currentAction === 'climb' && inCombatRoom && floorChanged && maxGolemSlots > 0) {
// Determine which golems should be summoned
const unlockedElementIds = Object.entries(elements)
.filter(([, e]) => e.unlocked)
@@ -1406,7 +1418,7 @@ export const useGameStore = create<GameStore>()(
}
// Process golem maintenance and attacks each tick
if (golemancy.summonedGolems.length > 0 && state.currentAction === 'climb' && inCombatRoom) {
if (golemancy.summonedGolems.length > 0 && currentAction === 'climb' && inCombatRoom) {
const floorDuration = getGolemFloorDuration(skills);
const survivingGolems: typeof golemancy.summonedGolems = [];
let anyGolemDismissed = false;
@@ -1525,7 +1537,7 @@ export const useGameStore = create<GameStore>()(
}
// Unsummon golems when not climbing or in puzzle room
if ((state.currentAction !== 'climb' || !inCombatRoom) && golemancy.summonedGolems.length > 0) {
if ((currentAction !== 'climb' || !inCombatRoom) && golemancy.summonedGolems.length > 0) {
log = [`🗿 Golems returned to the earth.`, ...log.slice(0, 49)];
golemancy = {
...golemancy,
@@ -1559,31 +1571,10 @@ export const useGameStore = create<GameStore>()(
// Apply crafting updates
if (craftingUpdates.rawMana !== undefined) rawMana = craftingUpdates.rawMana;
if (craftingUpdates.log !== undefined) log = craftingUpdates.log;
// If crafting slice set currentAction (e.g., auto-transition to meditate), use it
if (craftingUpdates.currentAction !== undefined) {
set({
...craftingUpdates,
day,
hour,
rawMana,
meditateTicks,
totalManaGathered,
currentFloor,
floorHP,
floorMaxHP,
maxFloorReached,
signedPacts,
currentRoom,
incursionStrength,
currentStudyTarget,
skills,
skillProgress,
spells,
elements,
log,
castProgress,
golemancy,
});
return;
currentAction = craftingUpdates.currentAction;
}
set({
@@ -1599,6 +1590,7 @@ export const useGameStore = create<GameStore>()(
signedPacts,
currentRoom,
incursionStrength,
currentAction,
currentStudyTarget,
parallelStudyTarget,
skills,
@@ -1929,6 +1921,24 @@ export const useGameStore = create<GameStore>()(
set(newState);
},
// Spire Mode - enter simplified UI for climbing
enterSpireMode: () => {
set((state) => ({
spireMode: true,
currentAction: 'climb',
log: ['🏔️ Entered Spire Mode! The climb begins...', ...state.log.slice(0, 49)],
}));
},
// Exit Spire Mode - return to normal game UI
exitSpireMode: () => {
set((state) => ({
spireMode: false,
currentAction: 'meditate',
log: ['⬇️ Climbed down from the Spire. Returning to normal view.', ...state.log.slice(0, 49)],
}));
},
togglePause: () => {
set((state) => ({ paused: !state.paused }));
},