forked from phenom/healer-man
Release Healer Man 0.1.22
This commit is contained in:
1 parent
f6f2375145
commit
7f6001723a
144 files changed
+54107
-690
No files matched your search
+48
-13
@@ -1,4 +1,11 @@
|
||||
import { useCallback, useEffect, useMemo, useState, type CSSProperties } from "react";
|
||||
import {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
useSyncExternalStore,
|
||||
type CSSProperties,
|
||||
} from "react";
|
||||
import { useProgress } from "@react-three/drei";
|
||||
import { classById, raceById } from "../app/characterCatalog";
|
||||
import { useShellStore } from "../app/shellStore";
|
||||
@@ -19,7 +26,6 @@ import { ExperienceBar } from "./ExperienceBar";
|
||||
import { Minimap } from "./Minimap";
|
||||
import { PlayerStatusPanel } from "./PlayerStatusPanel";
|
||||
import { EncounterTimeline } from "./EncounterTimeline";
|
||||
import { PlayerFrame } from "./PlayerFrame";
|
||||
import { PartyFrames } from "./PartyFrames";
|
||||
import { TimedEffectStrip } from "./TimedEffectStrip";
|
||||
import { AuraStrip } from "./AuraStrip";
|
||||
@@ -29,6 +35,11 @@ import { BossLootWindow } from "./BossLootWindow";
|
||||
import { SummonFrames } from "./SummonFrames";
|
||||
import { useOnlineSessionStore } from "../app/onlineSessionStore";
|
||||
import { onlineAccountIdFromActor, onlinePlayerActorId } from "../game/onlineSessionRuntime";
|
||||
import {
|
||||
activeDungeonEncounterRevision,
|
||||
activeDungeonRunIsComplete,
|
||||
subscribeDungeonEncounterSnapshots,
|
||||
} from "../game/dungeonEncounterRuntime";
|
||||
|
||||
function LoadingOverlay() {
|
||||
const activeDungeonId = useGameStore((state) => state.activeDungeonId);
|
||||
@@ -106,6 +117,27 @@ export function DefeatedPrompt({
|
||||
);
|
||||
}
|
||||
|
||||
export function DungeonCompletePrompt({
|
||||
dungeonTitle,
|
||||
onFinish,
|
||||
}: {
|
||||
readonly dungeonTitle: string;
|
||||
readonly onFinish: () => void;
|
||||
}) {
|
||||
return (
|
||||
<section className="dungeon-complete-banner" role="status" aria-live="polite">
|
||||
<span aria-hidden="true">◆</span>
|
||||
<p>
|
||||
<strong>{dungeonTitle} complete</strong>
|
||||
<small>Every required encounter is defeated. Loot the room or finish the run.</small>
|
||||
</p>
|
||||
<button type="button" className="button button--primary" onClick={onFinish}>
|
||||
Finish dungeon
|
||||
</button>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export function Hud() {
|
||||
const character = useShellStore((state) => state.activeCharacter);
|
||||
const gameMode = useGameStore((state) => state.gameMode);
|
||||
@@ -130,10 +162,6 @@ export function Hud() {
|
||||
const xpToNext = useCombatStore((state) => state.xpToNext);
|
||||
const health = useCombatStore((state) => state.health);
|
||||
const maxHealth = useCombatStore((state) => state.maxHealth);
|
||||
const shield = useCombatStore((state) => state.shield);
|
||||
const namedAbsorb = useCombatStore((state) => state.auras
|
||||
.filter((aura) => aura.targetId === PLAYER_AGGRO_ID)
|
||||
.reduce((total, aura) => total + aura.absorbs.reduce((sum, pool) => sum + pool.remaining, 0), 0));
|
||||
const resource = useCombatStore((state) => state.resource);
|
||||
const maxResource = useCombatStore((state) => state.maxResource);
|
||||
const resourcePools = useCombatStore((state) => state.resourcePools);
|
||||
@@ -160,6 +188,13 @@ export function Hud() {
|
||||
const settings = useCombatStore((state) => state.settings);
|
||||
const onlineSession = useOnlineSessionStore((state) => state.snapshot);
|
||||
const [clock, setClock] = useState(() => Date.now());
|
||||
useSyncExternalStore(
|
||||
subscribeDungeonEncounterSnapshots,
|
||||
activeDungeonEncounterRevision,
|
||||
activeDungeonEncounterRevision,
|
||||
);
|
||||
const dungeonComplete = gameMode === "dungeon"
|
||||
&& activeDungeonRunIsComplete(activeDungeonId);
|
||||
|
||||
useEffect(() => {
|
||||
const timer = window.setInterval(() => setClock(Date.now()), 100);
|
||||
@@ -318,24 +353,24 @@ export function Hud() {
|
||||
}
|
||||
respawnDefeatedPlayer();
|
||||
};
|
||||
const finishDungeon = () => {
|
||||
useShellStore.getState().saveActiveDungeonRunCheckpoint(null);
|
||||
useShellStore.getState().returnToMainMenu();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="hud" style={{ "--game-ui-scale": settings.uiScale } as CSSProperties}>
|
||||
<ManastormStatus />
|
||||
<BossLootWindow />
|
||||
{dungeonComplete && health > 0 ? (
|
||||
<DungeonCompletePrompt dungeonTitle={dungeon.title} onFinish={finishDungeon} />
|
||||
) : null}
|
||||
{feedback?.kind === "loot" ? (
|
||||
<section className="loot-reward" role="status" aria-live="polite">
|
||||
<span aria-hidden="true">◆</span>
|
||||
<p><strong>Loot acquired</strong><small>{feedback.message}</small><em>Press I to inspect and equip</em></p>
|
||||
</section>
|
||||
) : null}
|
||||
<PlayerFrame
|
||||
character={character ? { ...character, level } : null}
|
||||
health={{ current: health, maximum: maxHealth, label: "Health", tone: "health" }}
|
||||
resource={{ current: resource, maximum: maxResource, label: resourceName, tone: resourceTone }}
|
||||
shield={shield + namedAbsorb}
|
||||
dead={health <= 0}
|
||||
/>
|
||||
<PartyFrames />
|
||||
<SummonFrames now={clock} />
|
||||
|
||||
|
||||
Reference in new issue
Block a user