Update Healer Man server

This commit is contained in:
phenom committed 2026-09-27 21:48:00 -04:00
1 parent 15a5254380
commit 9d7e0e2f9e
71 files changed
+3490 -81

No files matched your search

+23 -5
View File
@@ -1,4 +1,5 @@
import { useMemo, useState } from "react";
import { BiteSizedBoardFilters, useBiteSizedBoardSelection } from "./BiteSizedBoardFilters";
import { dungeonContentIsUsable, installContentPack } from "../content/contentManager";
import { useContentManagerSnapshot } from "../content/useContentManager";
import { classById, raceById } from "../app/characterCatalog";
@@ -12,7 +13,7 @@ import {
type DungeonCategoryId,
type DungeonId,
} from "../game/dungeonCatalog";
import { dungeonDefinitionById } from "../game/dungeonRegistry";
import { dungeonDefinitionById, legacyBiteSizedRunSelection } from "../game/dungeonRegistry";
import {
partyRolesForClass,
PARTY_ROLE_LABELS,
@@ -38,6 +39,7 @@ import { useCompanionPartyPreferences } from "../game/companionPartyPreferences"
import { CompanionPoolControls } from "./CompanionPoolControls";
import { CompanionReadinessScreen } from "./CompanionReadinessScreen";
import { dungeonContentPackId } from "../game/dungeonContentSource";
import { prepareBiteSizedLayoutContent } from "../app/biteSizedLayoutContent";
installDungeonShellRuntime();
@@ -81,6 +83,7 @@ export function DungeonSelectScreen() {
const [pendingDownload, setPendingDownload] = useState<PendingDungeonDownload | null>(null);
const [downloadError, setDownloadError] = useState("");
const [downloading, setDownloading] = useState(false);
const [preparingSpot, setPreparingSpot] = useState(false);
const categoryDungeons = dungeonsByCategory(selectedCategory);
const firstCategoryDungeon = categoryDungeons.find((dungeon) => dungeon.available) ?? categoryDungeons[0];
const selectedDungeon = categoryDungeons.find((dungeon) => dungeon.id === selectedDungeonId)
@@ -105,8 +108,9 @@ export function DungeonSelectScreen() {
const index = bossOptions.findIndex((boss) => boss.id === selectedBoss?.id);
if (hasBossBoards && bossOptions.length) setLeaderboardBossId(bossOptions[(index + 1) % bossOptions.length].id);
};
const spotBoard = useBiteSizedBoardSelection(selectedDungeon?.id ?? "");
const leaderboard = useDungeonLeaderboard(selectedDungeon?.id ?? "", leaderboardDifficulty?.id ?? "normal",
clearFilter, bossDifficulty, selectedBoss?.id);
clearFilter, bossDifficulty, selectedBoss?.id, spotBoard.spotId, spotBoard.spotRevision);
const toggleRun = (id: string) => setExpandedRuns((current) => {
const next = new Set(current); if (next.has(id)) next.delete(id); else next.add(id); return next;
});
@@ -140,9 +144,20 @@ export function DungeonSelectScreen() {
};
const continueAsRole = async (role: PartyRole) => {
if (!selectedDungeon?.available || !character) return;
if (!selectedDungeon?.available || !character || preparingSpot) return;
if (!onlineGroup || !session || session.kind !== "account") {
enterDungeon(selectedDungeon.id, role, { difficultyId: leaderboardDifficulty?.id, bossDifficulty });
setPreparingSpot(true);
useShellStore.getState().setNotice("Preparing dungeon and creature downloads...");
try {
const checkpoint = character.dungeonRunCheckpoint;
const resume = checkpoint?.dungeonId === selectedDungeon.id && checkpoint.run?.finishedAt == null
&& (leaderboardDifficulty?.id === undefined || checkpoint.difficultyId === leaderboardDifficulty.id)
&& checkpoint.run?.bossDifficulty === bossDifficulty ? checkpoint.run : undefined;
const runId = resume?.id ?? crypto.randomUUID();
const biteSizedSelection = await prepareBiteSizedLayoutContent(selectedDungeon.id, runId, resume ? resume.biteSizedSelection ?? legacyBiteSizedRunSelection(selectedDungeon.id, runId) : undefined);
enterDungeon(selectedDungeon.id, role, { difficultyId: leaderboardDifficulty?.id, bossDifficulty, runId, ...(biteSizedSelection ? { biteSizedSelection } : {}) });
} catch (error) { useShellStore.getState().setNotice(error instanceof Error ? error.message : "Could not prepare the spot."); }
finally { setPreparingSpot(false); }
return;
}
if (!await updateOnlineMember(session, character, role)) return;
@@ -240,6 +255,7 @@ export function DungeonSelectScreen() {
? availableRoles.map((role) => ({
id: `dungeon-role-${role}`,
run: () => enterAsRole(role),
enabled: !preparingSpot,
}))
: [{
id: "choose-dungeon-role",
@@ -251,7 +267,7 @@ export function DungeonSelectScreen() {
run: () => setRolePickerOpen(false),
}] : []),
{ id: "dungeon-back", run: returnToMainMenu },
], [availableRoles, categoryDungeons, downloading, firstCategoryDungeon, pendingDownload, returnToMainMenu, rolePickerOpen, selectedCategory, selectedDungeon, selectedDefinition, leaderboard, leaderboardOpen, expandedRuns, leaderboardDifficulty, bossDifficulty, hasBossBoards, selectedBoss]);
], [availableRoles, categoryDungeons, downloading, preparingSpot, firstCategoryDungeon, pendingDownload, returnToMainMenu, rolePickerOpen, selectedCategory, selectedDungeon, selectedDefinition, leaderboard, leaderboardOpen, expandedRuns, leaderboardDifficulty, bossDifficulty, hasBossBoards, selectedBoss]);
const controller = useMenuController(actions, {
initialId: firstAvailable ? `dungeon-${firstAvailable.id}` : "dungeon-back",
onBack: pendingDownload
@@ -389,6 +405,7 @@ export function DungeonSelectScreen() {
select={controller.select}
className={`dungeon-role-option dungeon-role-option--${role}`}
type="button"
disabled={preparingSpot}
onClick={() => enterAsRole(role)}
>
<b aria-hidden="true">{ROLE_DETAILS[role].sigil}</b>
@@ -433,6 +450,7 @@ export function DungeonSelectScreen() {
</section>
{leaderboardOpen && (
<div id="dungeon-select-leaderboard" className="dungeon-select-leaderboard-column">
<BiteSizedBoardFilters selection={spotBoard} />
<DungeonLeaderboard dungeonTitle={selectedDungeon.title} data={leaderboard.data} scope={leaderboard.scope}
loading={leaderboard.loading} filter={clearFilter} onFilter={setClearFilter}
expanded={expandedRuns} onExpand={toggleRun} offset={leaderboard.offset} onPage={leaderboard.setOffset}