From 0ed54b458be9c1a1994a63981ac5702fe03346fb Mon Sep 17 00:00:00 2001 From: Denis Ranneft Date: Tue, 31 Mar 2026 12:54:54 +0300 Subject: [PATCH] disable buff buttons when dead --- frontend/src/App.tsx | 4 ++++ frontend/src/ui/BuffBar.tsx | 41 ++++++++++++++++++++++++++++++------- frontend/src/ui/HUD.tsx | 1 + 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index c256d98..284593b 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -863,6 +863,10 @@ export function App() { const hero = engine?.gameState.hero; const now = Date.now(); + if (engine?.gameState.phase === GamePhase.Dead) { + return; + } + // Check per-buff charge quota if (hero) { const charge = hero.buffCharges?.[type]; diff --git a/frontend/src/ui/BuffBar.tsx b/frontend/src/ui/BuffBar.tsx index ab50fd3..c92e16d 100644 --- a/frontend/src/ui/BuffBar.tsx +++ b/frontend/src/ui/BuffBar.tsx @@ -17,6 +17,8 @@ interface BuffBarProps { buffCharges: Partial>; /** When true, UI max charge labels use subscriber caps (×2). */ subscriptionActive?: boolean; + /** When true (e.g. hero dead), buff taps do nothing and refill flow is blocked. */ + buffsLocked?: boolean; nowMs: number; onActivate: (type: BuffType) => void; /** Called when a buff refill purchase returns an updated hero */ @@ -31,6 +33,7 @@ interface BuffButtonProps { onActivate: () => void; onRefill?: (type: BuffType) => void; nowMs: number; + buffsLocked?: boolean; } // ---- Tooltip ---- @@ -166,7 +169,7 @@ const buttonBase: CSSProperties = { WebkitTapHighlightColor: 'transparent', }; -function BuffButton({ buff, meta, charge, maxCharges, onActivate, onRefill, nowMs }: BuffButtonProps) { +function BuffButton({ buff, meta, charge, maxCharges, onActivate, onRefill, nowMs, buffsLocked }: BuffButtonProps) { const tr = useT(); const [pressed, setPressed] = useState(false); const [showTooltip, setShowTooltip] = useState(false); @@ -189,7 +192,7 @@ function BuffButton({ buff, meta, charge, maxCharges, onActivate, onRefill, nowM const remaining = charge?.remaining; const hasChargeData = remaining != null; const isOutOfCharges = hasChargeData && remaining === 0; - const isDisabled = isOnCooldown || (isOutOfCharges && !isActive); + const isDisabled = isOnCooldown || (isOutOfCharges && !isActive) || !!buffsLocked; useEffect(() => { return () => { @@ -198,6 +201,13 @@ function BuffButton({ buff, meta, charge, maxCharges, onActivate, onRefill, nowM }; }, []); + useEffect(() => { + if (buffsLocked) { + setShowTooltip(false); + setShowRefillConfirm(false); + } + }, [buffsLocked]); + const openTooltip = (): void => { setShowTooltip(true); if (autoHideTimer.current) clearTimeout(autoHideTimer.current); @@ -210,6 +220,7 @@ function BuffButton({ buff, meta, charge, maxCharges, onActivate, onRefill, nowM }; const handleTouchStart = (): void => { + if (buffsLocked) return; didLongPress.current = false; longPressTimer.current = setTimeout(() => { didLongPress.current = true; @@ -225,6 +236,7 @@ function BuffButton({ buff, meta, charge, maxCharges, onActivate, onRefill, nowM }; const handleClick = (): void => { + if (buffsLocked) return; if (didLongPress.current) { didLongPress.current = false; return; @@ -242,7 +254,11 @@ function BuffButton({ buff, meta, charge, maxCharges, onActivate, onRefill, nowM onActivate(); }; - const dimmedFaceOpacity = isDisabled ? (isOutOfCharges && !isOnCooldown ? 0.3 : 0.55) : 1; + const dimmedFaceOpacity = buffsLocked + ? 0.4 + : isDisabled + ? (isOutOfCharges && !isOnCooldown ? 0.3 : 0.55) + : 1; const hitStyle: CSSProperties = { position: 'relative', @@ -251,7 +267,8 @@ function BuffButton({ buff, meta, charge, maxCharges, onActivate, onRefill, nowM padding: 0, border: 'none', background: 'transparent', - cursor: isDisabled ? 'not-allowed' : 'pointer', + pointerEvents: buffsLocked ? 'none' : 'auto', + cursor: buffsLocked || isDisabled ? 'not-allowed' : 'pointer', transform: pressed ? 'scale(0.94)' : 'scale(1)', transition: 'transform 80ms ease', }; @@ -282,8 +299,8 @@ function BuffButton({ buff, meta, charge, maxCharges, onActivate, onRefill, nowM onTouchStart={handleTouchStart} onTouchEnd={handleTouchEnd} onTouchCancel={handleTouchEnd} - onMouseEnter={openTooltip} - onMouseLeave={closeTooltip} + onMouseEnter={buffsLocked ? undefined : openTooltip} + onMouseLeave={buffsLocked ? undefined : closeTooltip} aria-disabled={isDisabled} aria-label={`${meta.label}: ${meta.desc}`} > @@ -515,7 +532,16 @@ function getBuffEntry( }; } -export function BuffBar({ buffs, cooldownEndsAt, buffCharges, subscriptionActive, nowMs, onActivate, onHeroUpdated }: BuffBarProps) { +export function BuffBar({ + buffs, + cooldownEndsAt, + buffCharges, + subscriptionActive, + buffsLocked, + nowMs, + onActivate, + onHeroUpdated, +}: BuffBarProps) { const handleActivate = useCallback( (type: BuffType) => () => onActivate(type), [onActivate], @@ -552,6 +578,7 @@ export function BuffBar({ buffs, cooldownEndsAt, buffCharges, subscriptionActive onActivate={handleActivate(type)} onRefill={handleRefill} nowMs={nowMs} + buffsLocked={buffsLocked} /> ); })} diff --git a/frontend/src/ui/HUD.tsx b/frontend/src/ui/HUD.tsx index f7f6776..4db3c42 100644 --- a/frontend/src/ui/HUD.tsx +++ b/frontend/src/ui/HUD.tsx @@ -332,6 +332,7 @@ export function HUD({ cooldownEndsAt={buffCooldownEndsAt} buffCharges={hero.buffCharges} subscriptionActive={hero.subscriptionActive} + buffsLocked={phase === GamePhase.Dead} nowMs={nowMs} onActivate={handleBuffActivate} onHeroUpdated={onHeroUpdated}