Major gameplay improvements - barriers, HP regen, descent mechanic
All checks were successful
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 2m28s

- Fix transference mana display (show unlocked elements even with 0 mana)
- Remove blocking/dodging mechanics (player has no health):
  - Replace Seer's foresight with criticalMastery
  - Replace Warden's defensive skills with mana efficiency skills
  - Replace Strider's evasive with fluidMotion
- Add guardian barriers (50% of HP, doesn't regenerate)
- Add floor HP regeneration (scales with floor level, 0 for guardians)
- Implement climb-down mechanic:
  - Cannot switch away from climb while above floor 1
  - Must fight through each floor to exit
  - Exit Spire button triggers descent
- Update UI to show barrier bar and descent status
This commit is contained in:
Z User
2026-03-28 09:01:00 +00:00
parent a64a412f2c
commit 416b2fcde6
7 changed files with 270 additions and 44 deletions

View File

@@ -26,8 +26,14 @@ export function SpireTab({ store }: SpireTabProps) {
const isGuardianFloor = !!GUARDIANS[store.currentFloor];
const currentGuardian = GUARDIANS[store.currentFloor];
const climbDirection = store.climbDirection || 'up';
const isDescending = store.isDescending || false;
const clearedFloors = store.clearedFloors || {};
// Barrier state
const floorBarrier = store.floorBarrier || 0;
const floorMaxBarrier = store.floorMaxBarrier || 0;
const hasBarrier = floorBarrier > 0;
// Check if current floor is cleared (for respawn indicator)
const isFloorCleared = clearedFloors[store.currentFloor];
@@ -88,6 +94,24 @@ export function SpireTab({ store }: SpireTabProps) {
</div>
)}
{/* Barrier Bar (Guardians only) */}
{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-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"
style={{
width: `${Math.max(0, (floorBarrier / floorMaxBarrier) * 100)}%`,
}}
/>
</div>
</div>
)}
{/* HP Bar */}
<div className="space-y-1">
<div className="h-3 bg-gray-800 rounded-full overflow-hidden">
@@ -95,8 +119,8 @@ export function SpireTab({ store }: SpireTabProps) {
className="h-full rounded-full transition-all duration-300"
style={{
width: `${Math.max(0, (store.floorHP / store.floorMaxHP) * 100)}%`,
background: `linear-gradient(90deg, ${floorElemDef?.color}99, ${floorElemDef?.color})`,
boxShadow: `0 0 10px ${floorElemDef?.glow}`,
background: hasBarrier ? `linear-gradient(90deg, #6B728099, #6B7280)` : `linear-gradient(90deg, ${floorElemDef?.color}99, ${floorElemDef?.color})`,
boxShadow: hasBarrier ? 'none' : `0 0 10px ${floorElemDef?.glow}`,
}}
/>
</div>
@@ -137,6 +161,13 @@ export function SpireTab({ store }: SpireTabProps) {
</div>
</div>
{isDescending && (
<div className="text-xs text-blue-400 text-center flex items-center justify-center gap-1">
<ChevronDown className="w-3 h-3 animate-bounce" />
Descending... Fight through each floor to exit!
</div>
)}
{isFloorCleared && (
<div className="text-xs text-amber-400 text-center flex items-center justify-center gap-1">
<RotateCcw className="w-3 h-3" />
@@ -147,6 +178,18 @@ export function SpireTab({ store }: SpireTabProps) {
<Separator className="bg-gray-700" />
{/* Exit Spire Button */}
{store.currentAction === 'climb' && store.currentFloor > 1 && !isDescending && (
<Button
variant="outline"
className="w-full border-blue-600 text-blue-400 hover:bg-blue-900/20"
onClick={() => store.exitSpire?.()}
>
<X className="w-4 h-4 mr-2" />
Exit Spire (Descend from Floor {store.currentFloor})
</Button>
)}
<div className="text-sm text-gray-400">
Best: Floor <strong className="text-gray-200">{store.maxFloorReached}</strong>
Pacts: <strong className="text-amber-400">{store.signedPacts.length}</strong>