Implement multiple game improvements
All checks were successful
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m53s

- Guardian barriers with 3x HP regen on guardian floors
- Compound mana types auto-unlock when components available
- Legs equipment slot with 5 equipment types
- Expeditious Retreat and movement enchantments for legs
- Fixed tests for current skill definitions (65/65 pass)
- New achievements for elements, attunements, and guardians
- Removed nonsensical mechanics (thorns, manaShield for player)
- Cleaned up skill test references to match current implementation
This commit is contained in:
Z User
2026-03-28 10:04:48 +00:00
parent 416b2fcde6
commit f07454e024
11 changed files with 991 additions and 339 deletions

View File

@@ -7,10 +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, Heart, Shield } from 'lucide-react';
import type { GameStore } from '@/lib/game/types';
import { ELEMENTS, GUARDIANS, SPELLS_DEF, SKILLS_DEF, GOLEM_DEFS, GOLEM_VARIANTS } from '@/lib/game/constants';
import { fmt, fmtDec, getFloorElement, canAffordSpellCost } from '@/lib/game/store';
import { ELEMENTS, GUARDIANS, SPELLS_DEF, SKILLS_DEF, GOLEM_DEFS, GOLEM_VARIANTS, HOURS_PER_TICK } from '@/lib/game/constants';
import { fmt, fmtDec, getFloorElement, canAffordSpellCost, getFloorHPRegen } from '@/lib/game/store';
import { getActiveEquipmentSpells, getTotalDPS } from '@/lib/game/computed-stats';
import { formatSpellCost, getSpellCostColor, formatStudyTime } from '@/lib/game/formatting';
import { CraftingProgress, StudyProgress } from '@/components/game';
@@ -34,6 +34,11 @@ export function SpireTab({ store }: SpireTabProps) {
const floorMaxBarrier = store.floorMaxBarrier || 0;
const hasBarrier = floorBarrier > 0;
// HP Regeneration rate (all floors regen during combat)
// Guardian floors: 3% per hour, Non-guardian floors: 1% per hour
const floorHPRegenRate = getFloorHPRegen(store.currentFloor);
const isClimbing = store.currentAction === 'climb';
// Check if current floor is cleared (for respawn indicator)
const isFloorCleared = clearedFloors[store.currentFloor];
@@ -98,14 +103,19 @@ export function SpireTab({ store }: SpireTabProps) {
{isGuardianFloor && floorMaxBarrier > 0 && (
<div className="space-y-1">
<div className="flex items-center justify-between text-xs">
<span className="text-gray-400">🛡 Barrier</span>
<span className="text-gray-400 flex items-center gap-1">
<Shield className="w-3 h-3" />
Barrier
<span className="text-gray-500">(no regen)</span>
</span>
<span className="text-gray-500 game-mono">{fmt(floorBarrier)} / {fmt(floorMaxBarrier)}</span>
</div>
<div className="h-2 bg-gray-800 rounded-full overflow-hidden">
<div
className="h-full rounded-full transition-all duration-300 bg-gray-500"
className="h-full rounded-full transition-all duration-300"
style={{
width: `${Math.max(0, (floorBarrier / floorMaxBarrier) * 100)}%`,
background: hasBarrier ? 'linear-gradient(90deg, #6B7280, #9CA3AF)' : 'linear-gradient(90deg, #374151, #4B5563)',
}}
/>
</div>
@@ -125,7 +135,15 @@ export function SpireTab({ store }: SpireTabProps) {
/>
</div>
<div className="flex justify-between text-xs text-gray-400 game-mono">
<span>{fmt(store.floorHP)} / {fmt(store.floorMaxHP)} HP</span>
<span className="flex items-center gap-1">
{fmt(store.floorHP)} / {fmt(store.floorMaxHP)} HP
{isClimbing && floorHPRegenRate > 0 && (
<span className="text-green-500 flex items-center gap-0.5">
<Heart className="w-3 h-3 animate-pulse" />
+{fmt(floorHPRegenRate)}/hr
</span>
)}
</span>
<span>
{store.currentAction === 'climb' && (activeEquipmentSpells.length > 0 || activeGolemsOnFloor.length > 0) ? (
<span>