diff --git a/src/components/game/SpireTab.tsx b/src/components/game/SpireTab.tsx
deleted file mode 100755
index 7ab8222..0000000
--- a/src/components/game/SpireTab.tsx
+++ /dev/null
@@ -1,486 +0,0 @@
-'use client';
-
-import { useGameStore, canAffordSpellCost, fmt, fmtDec, calcDamage, getEnemyName } from '@/lib/game/store';
-import type { ActivityLogEntry } from '@/lib/game/types';
-import { ELEMENTS, GUARDIANS, SPELLS_DEF, ROOM_TYPE_LABELS } from '@/lib/game/constants';
-import { useManaStats, useCombatStats, useStudyStats } from '@/lib/game/hooks/useGameDerived';
-import { formatSpellCost, getSpellCostColor, formatStudyTime } from '@/lib/game/formatting';
-import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
-import { Badge } from '@/components/ui/badge';
-import { Button } from '@/components/ui/button';
-import { Progress } from '@/components/ui/progress';
-import { ScrollArea } from '@/components/ui/scroll-area';
-import { Separator } from '@/components/ui/separator';
-import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
-import { X, BookOpen, Skull, Shield, Wind } from 'lucide-react';
-
-export function SpireTab() {
- const store = useGameStore();
- const { effectiveRegen, meditationMultiplier, incursionStrength } = useManaStats();
- const {
- floorElem, floorElemDef, isGuardianFloor, currentGuardian,
- activeSpellDef, dps, damageBreakdown
- } = useCombatStats();
- const { effectiveStudySpeedMult } = useStudyStats();
-
- // Get room type info
- const currentRoom = store.currentRoom;
- const roomType = currentRoom?.roomType || 'combat';
- const roomConfig = ROOM_TYPE_LABELS[roomType] || ROOM_TYPE_LABELS.combat;
-
- // Check if spell can be cast
- const canCastSpell = (spellId: string): boolean => {
- const spell = SPELLS_DEF[spellId];
- if (!spell) return false;
- return canAffordSpellCost(spell.cost, store.rawMana, store.elements);
- };
-
- // Get enemy display info
- const getEnemyDisplayInfo = () => {
- if (!currentRoom || !currentRoom.enemies || currentRoom.enemies.length === 0) {
- return { primaryEnemy: null, swarmEnemies: [] };
- }
-
- const enemies = currentRoom.enemies;
- const primaryEnemy = enemies[0];
-
- // For swarm rooms, return all enemies
- if (roomType === 'swarm') {
- return { primaryEnemy: null, swarmEnemies: enemies };
- }
-
- return { primaryEnemy, swarmEnemies: [] };
- };
-
- const { primaryEnemy, swarmEnemies } = getEnemyDisplayInfo();
-
- // Render study progress
- const renderStudyProgress = () => {
- if (!store.currentStudyTarget) return null;
-
- const target = store.currentStudyTarget;
- const progressPct = Math.min(100, (target.progress / target.required) * 100);
- const isSkill = target.type === 'skill';
- const def = isSkill ? SPELLS_DEF[target.id] : SPELLS_DEF[target.id];
-
- return (
-
-
-
-
-
- {def?.name}
-
-
-
-
-
-
- {formatStudyTime(target.progress)} / {formatStudyTime(target.required)}
- {effectiveStudySpeedMult.toFixed(1)}x speed
-
-
- );
- };
-
- return (
-
-
- {/* Current Floor Card */}
-
-
-
- Current Floor
-
- {roomConfig.icon} {roomConfig.label}
-
-
-
-
-
-
- {store.currentFloor}
-
- / 100
-
- {floorElemDef?.sym} {floorElemDef?.name}
-
- {isGuardianFloor && (
- GUARDIAN
- )}
-
-
- {isGuardianFloor && currentGuardian && (
-
- ⚔️ {currentGuardian.name}
-
- )}
-
- {/* Single Enemy Display (Combat/Speed/Guardian) */}
- {!isGuardianFloor && primaryEnemy && roomType !== 'swarm' && (
-
-
-
-
-
- {primaryEnemy.name || 'Unknown Enemy'}
-
-
-
- {ELEMENTS[primaryEnemy.element]?.sym} {ELEMENTS[primaryEnemy.element]?.name}
-
-
-
- {/* Enemy HP Bar */}
-
-
-
- {fmt(primaryEnemy.hp)} / {fmt(primaryEnemy.maxHP)} HP
-
-
-
- {/* Enemy Properties */}
-
- {primaryEnemy.armor > 0 && (
-
-
-
-
- {(primaryEnemy.armor * 100).toFixed(0)}% Armor
-
-
-
- Reduces incoming damage by {(primaryEnemy.armor * 100).toFixed(0)}%
-
-
- )}
- {primaryEnemy.dodgeChance > 0 && (
-
-
-
-
- {(primaryEnemy.dodgeChance * 100).toFixed(0)}% Dodge
-
-
-
- Chance to dodge attacks and reduce progress
-
-
- )}
-
-
- )}
-
- {/* Swarm Enemies Display */}
- {roomType === 'swarm' && swarmEnemies.length > 0 && (
-
-
- Swarm Enemies ({swarmEnemies.length})
-
- {swarmEnemies.map((enemy, index) => (
-
-
-
-
-
- {enemy.name || `Enemy ${index + 1}`}
-
-
-
- {ELEMENTS[enemy.element]?.sym} {fmt(enemy.hp)}/{fmt(enemy.maxHP)} HP
-
-
-
-
- ))}
-
- )}
-
- {/* Puzzle Room Display */}
- {roomType === 'puzzle' && (
-
-
- 🧩
-
- {currentRoom.puzzleId ? currentRoom.puzzleId.replace(/_/g, ' ').toUpperCase() : 'Puzzle Room'}
-
-
-
-
- Progress
- {((currentRoom.puzzleProgress || 0) * 100).toFixed(0)}%
-
-
-
-
- )}
-
- {/* Floor HP Bar (for non-swarm, non-puzzle) */}
- {roomType !== 'swarm' && roomType !== 'puzzle' && (
-
-
-
- {fmt(store.floorHP)} / {fmt(store.floorMaxHP)} HP
- DPS: {store.currentAction === 'climb' && canCastSpell(store.activeSpell) ? fmtDec(dps) : '—'}
-
-
- )}
-
-
-
-
- Best: Floor {store.maxFloorReached} •
- Pacts: {store.signedPacts.length}
-
-
-
-
- {/* Active Spell Card */}
-
-
- Active Spell
-
-
- {activeSpellDef ? (
- <>
-
- {activeSpellDef.name}
- {activeSpellDef.tier === 0 && Basic}
- {activeSpellDef.tier >= 4 && Legendary}
-
-
- ⚔️ {fmt(calcDamage(store, store.activeSpell))} dmg •
-
- {' '}{formatSpellCost(activeSpellDef.cost)}
-
- {' '}• ⚡ {(activeSpellDef.castSpeed || 1).toFixed(1)} casts/hr
-
-
- {/* Cast progress bar when climbing */}
- {store.currentAction === 'climb' && (
-
-
- Cast Progress
- {((store.castProgress || 0) * 100).toFixed(0)}%
-
-
-
- )}
-
- {activeSpellDef.desc && (
- {activeSpellDef.desc}
- )}
- {activeSpellDef.effects && activeSpellDef.effects.length > 0 && (
-
- {activeSpellDef.effects.map((eff, i) => (
-
- {eff.type === 'burn' && `🔥 Burn ${eff.value}/hr`}
- {eff.type === 'stun' && `⚡ Stun ${eff.value}s`}
- {eff.type === 'pierce' && `🗡️ Pierce ${Math.round(eff.value * 100)}%`}
- {eff.type === 'multicast' && `✨ ${Math.round(eff.value * 100)}% Multicast`}
- {eff.type === 'buff' && `💪 Buff`}
-
- ))}
-
- )}
- >
- ) : (
- No spell selected
- )}
-
- {/* Can cast indicator */}
- {activeSpellDef && (
-
- {canCastSpell(store.activeSpell) ? '✓ Can cast' : '✗ Insufficient mana'}
-
- )}
-
- {incursionStrength > 0 && (
-
-
LABYRINTH INCURSION
-
- -{Math.round(incursionStrength * 100)}% mana regen
-
-
- )}
-
-
-
- {/* Current Study (if any) */}
- {store.currentStudyTarget && (
-
-
- {renderStudyProgress()}
-
- {/* Parallel Study Progress */}
- {store.parallelStudyTarget && (
-
-
-
-
-
- Parallel: {store.parallelStudyTarget.type === 'skill' ? store.parallelStudyTarget.id : store.parallelStudyTarget.id}
-
-
-
-
-
-
- {formatStudyTime(store.parallelStudyTarget.progress)} / {formatStudyTime(store.parallelStudyTarget.required)}
- 50% speed (Parallel Study)
-
-
- )}
-
-
- )}
-
- {/* Pact Signing Progress */}
-
-
- {/* Spells Available */}
-
-
- Known Spells
-
-
-
- {Object.entries(store.spells)
- .filter(([, state]) => state.learned)
- .map(([id, state]) => {
- const def = SPELLS_DEF[id];
- if (!def) return null;
- const elemDef = def.elem === 'raw' ? null : ELEMENTS[def.elem];
- const isActive = store.activeSpell === id;
- const canCast = canCastSpell(id);
-
- return (
-
- );
- })}
-
-
-
-
- {/* Activity Log */}
-
-
- Activity Log
-
-
-
-
- {(store.activityLog || []).slice(0, 50).map((entry: ActivityLogEntry, i) => {
- // Style based on event type
- const getEventStyle = (eventType: string) => {
- switch (eventType) {
- case 'enemy_defeated':
- case 'floor_cleared':
- return 'text-green-400';
- case 'damage_dealt':
- return 'text-red-400';
- case 'dodge':
- return 'text-yellow-400';
- case 'armor_proc':
- return 'text-blue-400';
- case 'special_effect':
- return 'text-purple-400';
- case 'floor_transition':
- return 'text-cyan-400';
- case 'spell_cast':
- return 'text-amber-400';
- case 'golem_attack':
- return 'text-orange-400';
- case 'puzzle_solved':
- return 'text-pink-400';
- default:
- return 'text-gray-300';
- }
- };
-
- return (
-
- {entry.message}
-
- );
- })}
- {(store.activityLog || []).length === 0 && (
-
No activity yet...
- )}
-
-
-
-
-
-
- );
-}
-
-SpireTab.displayName = "SpireTab";
diff --git a/src/components/game/tabs/SpireTab.tsx b/src/components/game/tabs/SpireTab.tsx
index 6bc6642..55488bc 100755
--- a/src/components/game/tabs/SpireTab.tsx
+++ b/src/components/game/tabs/SpireTab.tsx
@@ -353,11 +353,11 @@ export function SpireTab({ store, simpleMode = false }: SpireTabProps) {
- ⚔️ {fmt(totalDPS)} DPS •
+ ⚔️ {fmt(calcDamage(store, spellId))} dmg/cast •
{' '}{formatSpellCost(spellDef.cost)}
- {' '}• ⚡ {(spellDef.castSpeed || 1).toFixed(1)}/hr
+ {' '}• ⚡ {fmt(Math.floor(calcDamage(store, spellId) * (spellDef.castSpeed || 1)))} dmg/hr
{/* Cast progress bar when climbing */}
diff --git a/src/lib/game/store.ts b/src/lib/game/store.ts
index a1ce171..aacd6fe 100755
--- a/src/lib/game/store.ts
+++ b/src/lib/game/store.ts
@@ -847,8 +847,8 @@ function addActivityLogEntry(
details?: ActivityLogEntry['details']
): ActivityLogEntry[] {
const entry = createActivityEntry(eventType, message, details);
- // Keep last 100 entries, newest first
- return [entry, ...state.activityLog.slice(0, 99)];
+ // Keep last 50 entries, newest first (Task 10)
+ return [entry, ...state.activityLog.slice(0, 49)];
}
// ─── Game Store ───────────────────────────────────────────────────────────────