Add step-through replay controls to the battle view
Prev/next/play-pause/restart and a step counter let a player walk the battle log manually and replay it before hitting Next. Local-only view state; nothing is shared or sent to the server.
This commit is contained in:
@@ -180,12 +180,25 @@ export function BattlePhase({ view, send }: Props) {
|
|||||||
const done = step >= events.length
|
const done = step >= events.length
|
||||||
const lastEvent = step > 0 ? events[step - 1] : null
|
const lastEvent = step > 0 ? events[step - 1] : null
|
||||||
|
|
||||||
|
// paused freezes auto-advance so the player can walk the log manually.
|
||||||
|
const [paused, setPaused] = useState(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (done) return
|
if (done || paused) return
|
||||||
const delay = EVENT_MS[events[step].type] ?? 1000
|
const delay = EVENT_MS[events[step].type] ?? 1000
|
||||||
const t = window.setTimeout(() => setStep((s) => s + 1), delay)
|
const t = window.setTimeout(() => setStep((s) => s + 1), delay)
|
||||||
return () => window.clearTimeout(t)
|
return () => window.clearTimeout(t)
|
||||||
}, [step, done, events])
|
}, [step, done, paused, events])
|
||||||
|
|
||||||
|
// Manual controls. Stepping by hand pauses playback so it doesn't fight you.
|
||||||
|
const stepTo = (n: number) => {
|
||||||
|
setPaused(true)
|
||||||
|
setStep(Math.max(0, Math.min(events.length, n)))
|
||||||
|
}
|
||||||
|
const restart = () => {
|
||||||
|
setPaused(false)
|
||||||
|
setStep(0)
|
||||||
|
}
|
||||||
|
|
||||||
const sides = useMemo(
|
const sides = useMemo(
|
||||||
() => replay(events, battle.stackSizes, step),
|
() => replay(events, battle.stackSizes, step),
|
||||||
@@ -318,11 +331,43 @@ export function BattlePhase({ view, send }: Props) {
|
|||||||
<div className="battle">
|
<div className="battle">
|
||||||
<div className="battle-header">
|
<div className="battle-header">
|
||||||
<h2>Battle! Round {battle.round}</h2>
|
<h2>Battle! Round {battle.round}</h2>
|
||||||
{!done && (
|
<div className="battle-controls">
|
||||||
<button className="btn btn-ghost btn-sm" onClick={() => setStep(events.length)}>
|
<button className="btn btn-ghost btn-sm" onClick={restart} title="Replay from the start">
|
||||||
Skip ⏭
|
⏮
|
||||||
</button>
|
</button>
|
||||||
)}
|
<button
|
||||||
|
className="btn btn-ghost btn-sm"
|
||||||
|
onClick={() => stepTo(step - 1)}
|
||||||
|
disabled={step === 0}
|
||||||
|
title="Previous step"
|
||||||
|
>
|
||||||
|
◀
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="btn btn-ghost btn-sm"
|
||||||
|
onClick={() => setPaused((p) => !p)}
|
||||||
|
disabled={done}
|
||||||
|
title={paused ? 'Play' : 'Pause'}
|
||||||
|
>
|
||||||
|
{paused ? '▶' : '⏸'}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="btn btn-ghost btn-sm"
|
||||||
|
onClick={() => stepTo(step + 1)}
|
||||||
|
disabled={done}
|
||||||
|
title="Next step"
|
||||||
|
>
|
||||||
|
▶
|
||||||
|
</button>
|
||||||
|
<span className="battle-step">
|
||||||
|
{Math.min(step, events.length)} / {events.length}
|
||||||
|
</span>
|
||||||
|
{!done && (
|
||||||
|
<button className="btn btn-ghost btn-sm" onClick={() => setStep(events.length)}>
|
||||||
|
Skip ⏭
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="battle-names">
|
<div className="battle-names">
|
||||||
|
|||||||
@@ -726,6 +726,21 @@ h3 {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 14px;
|
gap: 14px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.battle-controls {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.battle-step {
|
||||||
|
font-family: var(--font-display);
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: rgba(253, 243, 220, 0.7);
|
||||||
|
min-width: 3.5em;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.battle-names {
|
.battle-names {
|
||||||
|
|||||||
Reference in New Issue
Block a user