From e2671d7afdcb93201e439916298df74369bd8cf0 Mon Sep 17 00:00:00 2001 From: Z User Date: Thu, 2 Apr 2026 10:57:03 +0000 Subject: [PATCH] Fix upgrade reset bugs: milestone merging and tier-up carryover - Fixed commitSkillUpgrades() to preserve upgrades from other milestones (selecting L10 upgrades no longer resets L5 selections) - Fixed tierUpSkill() to carry over upgrades from previous tier (tier 2 now starts with tier 1's upgrades intact) - Added summoned golems display to SpireTab with stats and progress bars --- src/components/game/tabs/SkillsTab.tsx | 2 +- src/components/game/tabs/SpireTab.tsx | 55 +++++++++++++++++++++++++- src/lib/game/store.ts | 38 +++++++++++++----- worklog.md | 30 ++++++++++++++ 4 files changed, 114 insertions(+), 11 deletions(-) diff --git a/src/components/game/tabs/SkillsTab.tsx b/src/components/game/tabs/SkillsTab.tsx index 92e4d97..4edc2a8 100755 --- a/src/components/game/tabs/SkillsTab.tsx +++ b/src/components/game/tabs/SkillsTab.tsx @@ -96,7 +96,7 @@ export function SkillsTab({ store }: SkillsTabProps) { const handleConfirm = () => { const currentSelections = pendingUpgradeSelections.length > 0 ? pendingUpgradeSelections : alreadySelected; if (currentSelections.length === 2 && upgradeDialogSkill) { - store.commitSkillUpgrades(upgradeDialogSkill, currentSelections); + store.commitSkillUpgrades(upgradeDialogSkill, currentSelections, upgradeDialogMilestone); } setPendingUpgradeSelections([]); setUpgradeDialogSkill(null); diff --git a/src/components/game/tabs/SpireTab.tsx b/src/components/game/tabs/SpireTab.tsx index 895fd9a..7dc13fe 100755 --- a/src/components/game/tabs/SpireTab.tsx +++ b/src/components/game/tabs/SpireTab.tsx @@ -7,9 +7,10 @@ import { Badge } from '@/components/ui/badge'; import { ScrollArea } from '@/components/ui/scroll-area'; import { Separator } from '@/components/ui/separator'; import { TooltipProvider } from '@/components/ui/tooltip'; -import { Swords, BookOpen, ChevronUp, ChevronDown, RotateCcw, X } from 'lucide-react'; +import { Swords, BookOpen, ChevronUp, ChevronDown, RotateCcw, X, Mountain } from 'lucide-react'; import type { GameStore } from '@/lib/game/types'; import { ELEMENTS, GUARDIANS, SPELLS_DEF, SKILLS_DEF } from '@/lib/game/constants'; +import { GOLEMS_DEF, getGolemDamage, getGolemAttackSpeed } from '@/lib/game/data/golems'; import { fmt, fmtDec, getFloorElement, canAffordSpellCost } from '@/lib/game/store'; import { getActiveEquipmentSpells, getTotalDPS } from '@/lib/game/computed-stats'; import { formatSpellCost, getSpellCostColor, formatStudyTime } from '@/lib/game/formatting'; @@ -204,6 +205,58 @@ export function SpireTab({ store }: SpireTabProps) { + {/* Summoned Golems Card */} + {store.golemancy.summonedGolems.length > 0 && ( + + + + + Active Golems ({store.golemancy.summonedGolems.length}) + + + + {store.golemancy.summonedGolems.map((summoned) => { + const golemDef = GOLEMS_DEF[summoned.golemId]; + if (!golemDef) return null; + + const elemColor = ELEMENTS[golemDef.baseManaType]?.color || '#888'; + const damage = getGolemDamage(summoned.golemId, store.skills); + const attackSpeed = getGolemAttackSpeed(summoned.golemId, store.skills); + + return ( +
+
+
+ + + {golemDef.name} + +
+ {golemDef.isAoe && ( + AOE {golemDef.aoeTargets} + )} +
+
+ ⚔️ {damage} DMG • ⚡ {attackSpeed.toFixed(1)}/hr • + 🛡️ {Math.floor(golemDef.armorPierce * 100)}% Pierce +
+ {/* Attack progress bar when climbing */} + {store.currentAction === 'climb' && summoned.attackProgress > 0 && ( +
+
+ Attack + {Math.min(100, (summoned.attackProgress * 100)).toFixed(0)}% +
+ +
+ )} +
+ ); + })} +
+
+ )} + {/* Current Study (if any) */} {store.currentStudyTarget && ( diff --git a/src/lib/game/store.ts b/src/lib/game/store.ts index d650973..5434814 100755 --- a/src/lib/game/store.ts +++ b/src/lib/game/store.ts @@ -746,7 +746,7 @@ interface GameStore extends GameState, CraftingActions { addLog: (message: string) => void; selectSkillUpgrade: (skillId: string, upgradeId: string) => void; deselectSkillUpgrade: (skillId: string, upgradeId: string) => void; - commitSkillUpgrades: (skillId: string, upgradeIds: string[]) => void; + commitSkillUpgrades: (skillId: string, upgradeIds: string[], milestone?: 5 | 10) => void; tierUpSkill: (skillId: string) => void; // Attunement XP and leveling @@ -1725,13 +1725,32 @@ export const useGameStore = create()( }); }, - commitSkillUpgrades: (skillId: string, upgradeIds: string[]) => { - set((state) => ({ - skillUpgrades: { - ...state.skillUpgrades, - [skillId]: upgradeIds, - }, - })); + commitSkillUpgrades: (skillId: string, upgradeIds: string[], milestone?: 5 | 10) => { + set((state) => { + const currentUpgrades = state.skillUpgrades?.[skillId] || []; + + // If milestone is specified, merge by keeping other milestone's upgrades + let newUpgrades: string[]; + if (milestone === 5) { + // Keep existing L10 upgrades, replace L5 upgrades + const existingL10 = currentUpgrades.filter(id => id.includes('_l10')); + newUpgrades = [...upgradeIds, ...existingL10]; + } else if (milestone === 10) { + // Keep existing L5 upgrades, replace L10 upgrades + const existingL5 = currentUpgrades.filter(id => id.includes('_l5')); + newUpgrades = [...existingL5, ...upgradeIds]; + } else { + // No milestone specified (legacy behavior), replace all + newUpgrades = upgradeIds; + } + + return { + skillUpgrades: { + ...state.skillUpgrades, + [skillId]: newUpgrades, + }, + }; + }); }, tierUpSkill: (skillId: string) => { @@ -1744,6 +1763,7 @@ export const useGameStore = create()( const nextTierSkillId = `${baseSkillId}_t${nextTier}`; const currentLevel = state.skills[skillId] || 0; + const currentUpgrades = state.skillUpgrades?.[skillId] || []; set({ skillTiers: { @@ -1757,7 +1777,7 @@ export const useGameStore = create()( }, skillUpgrades: { ...state.skillUpgrades, - [nextTierSkillId]: [], // Start fresh with upgrades for new tier + [nextTierSkillId]: currentUpgrades, // Carry over upgrades from previous tier }, log: [`🌟 ${SKILLS_DEF[baseSkillId]?.name || baseSkillId} evolved to Tier ${nextTier}!`, ...state.log.slice(0, 49)], }); diff --git a/worklog.md b/worklog.md index 474bfa5..f9fb8f0 100755 --- a/worklog.md +++ b/worklog.md @@ -633,3 +633,33 @@ Stage Summary: - UI for selecting and managing golems - Documentation updated - Lint passes + +--- +Task ID: 28 +Agent: Main +Task: Fix level upgrade reset loop bug and add golem display to SpireTab + +Work Log: +- **Fixed upgrade reset bug in commitSkillUpgrades()**: + - Root cause: `commitSkillUpgrades()` was replacing ALL upgrades for a skill instead of merging by milestone + - When selecting level 10 upgrades, it would wipe out level 5 selections (and vice versa) + - Added optional `milestone` parameter (5 | 10) to the function + - When milestone is specified, the function now: + - Keeps existing upgrades from OTHER milestones + - Only replaces upgrades for the CURRENT milestone + - Updated type definition in GameStore interface + - Updated SkillsTab.tsx to pass `upgradeDialogMilestone` when committing + +- **Added summoned golems display to SpireTab**: + - Imported GOLEMS_DEF and helper functions + - Added Mountain icon import + - Added "Active Golems" card that appears when golems are summoned + - Shows each golem's name, damage, attack speed, and armor pierce + - Displays attack progress bar when climbing + - AOE badge for golems with area attacks + +Stage Summary: +- Level 5 and level 10 upgrades no longer reset each other +- Players can safely select upgrades at both milestones +- Summoned golems now visible in Spire tab during combat +- Lint passes, dev server running