forked from phenom/healer-man
Release Healer Man 0.1.47
This commit is contained in:
1 parent
9ff574ac0b
commit
2162039b49
24 files changed
+486
-55
No files matched your search
@@ -3,6 +3,8 @@ import { dungeonRouteDefinition } from "../game/dungeonRoutes";
|
||||
import type { DungeonSimulationSpeed } from "../game/dungeonSimulationTypes";
|
||||
import { finalizeDungeonSimulation } from "../scene/DungeonSimulationSceneBridge";
|
||||
import { useShellStore } from "../app/shellStore";
|
||||
import { classById } from "../app/characterCatalog";
|
||||
import { PARTY_ROLE_LABELS, usePartyStore } from "../game/partyStore";
|
||||
|
||||
const SPEEDS: readonly DungeonSimulationSpeed[] = [0.5, 1, 2, 4];
|
||||
|
||||
@@ -25,11 +27,15 @@ function downloadReport(): void {
|
||||
|
||||
export function DungeonSimulationHud() {
|
||||
const simulation = useDungeonSimulationStore();
|
||||
const partyMembers = usePartyStore((state) => state.members);
|
||||
const route = simulation.dungeonId
|
||||
? dungeonRouteDefinition(simulation.dungeonId, simulation.routeId ?? "primary")
|
||||
: null;
|
||||
const leg = route?.legs.find((candidate) => candidate.objectiveId === simulation.objectiveId) ?? null;
|
||||
const replayDuration = simulation.replay?.durationMs ?? 0;
|
||||
const fallbackMember = partyMembers.find((member) => member.health > 0) ?? partyMembers[0] ?? null;
|
||||
const spectatedMember = partyMembers.find((member) => member.id === simulation.spectatedMemberId)
|
||||
?? fallbackMember;
|
||||
|
||||
const returnToGmTools = () => {
|
||||
useDungeonSimulationStore.getState().leave();
|
||||
@@ -61,10 +67,21 @@ export function DungeonSimulationHud() {
|
||||
{speed}×
|
||||
</button>
|
||||
))}
|
||||
<button type="button" onClick={() => simulation.setCameraMode(
|
||||
simulation.cameraMode === "follow-leader" ? "free-fly" : "follow-leader",
|
||||
)}>
|
||||
{simulation.cameraMode === "follow-leader" ? "Follow camera" : "Free-fly camera"}
|
||||
<button
|
||||
type="button"
|
||||
className={simulation.cameraMode === "follow-member" ? "is-active" : undefined}
|
||||
aria-pressed={simulation.cameraMode === "follow-member"}
|
||||
onClick={() => simulation.setCameraMode("follow-member")}
|
||||
>
|
||||
Follow member
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={simulation.cameraMode === "free-fly" ? "is-active" : undefined}
|
||||
aria-pressed={simulation.cameraMode === "free-fly"}
|
||||
onClick={() => simulation.setCameraMode("free-fly")}
|
||||
>
|
||||
Free camera
|
||||
</button>
|
||||
{simulation.sessionMode === "spectate-live" && simulation.runState !== "finished" ? (
|
||||
<button type="button" className="is-danger" onClick={() => void finalizeDungeonSimulation("stopped")}>
|
||||
@@ -75,6 +92,35 @@ export function DungeonSimulationHud() {
|
||||
{simulation.runState === "finished" && <button type="button" onClick={returnToGmTools}>Return to GM Tools</button>}
|
||||
</div>
|
||||
|
||||
<section className="dungeon-sim-hud__spectate" aria-label="Spectate party member">
|
||||
<header>
|
||||
<span>{simulation.cameraMode === "free-fly" ? "Free camera" : "Following"}</span>
|
||||
<strong>{simulation.cameraMode === "free-fly" ? "Detached" : spectatedMember?.name ?? "Waiting for party"}</strong>
|
||||
</header>
|
||||
<div>
|
||||
{partyMembers.map((member) => {
|
||||
const characterClass = classById(member.classId);
|
||||
const selected = simulation.cameraMode === "follow-member" && member.id === spectatedMember?.id;
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
key={member.id}
|
||||
className={selected ? "is-active" : undefined}
|
||||
aria-pressed={selected}
|
||||
onClick={() => simulation.setSpectatedMember(member.id)}
|
||||
>
|
||||
<i style={{ background: characterClass.color }} aria-hidden="true" />
|
||||
<span><strong>{member.name}</strong><small>{PARTY_ROLE_LABELS[member.role]} · {member.specialization}</small></span>
|
||||
<em>{Math.max(0, Math.ceil(member.health))}</em>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<p>{simulation.cameraMode === "free-fly"
|
||||
? "Right-drag to look · WASD fly · E/Space up · Q/Ctrl down · Shift boost"
|
||||
: "Choose a party member to follow · Right-drag to orbit"}</p>
|
||||
</section>
|
||||
|
||||
{simulation.sessionMode === "spectate-replay" && (
|
||||
<label className="dungeon-sim-hud__seek">
|
||||
<span>Replay position</span>
|
||||
|
||||
Reference in new issue
Block a user