Release Healer Man 0.1.40

This commit is contained in:
phenom committed 2026-09-13 13:21:27 -04:00
1 parent ed0d2fea3d
commit 197a64117c
215 files changed
+5131 -181

No files matched your search

+13 -4
View File
@@ -31,6 +31,8 @@ import { useOnlineGroupStore } from "../app/onlineGroupStore";
import { specializationById } from "../game/specializationCatalog";
import { DUNGEON_RELEASE_STAGE_LABELS } from "../game/dungeonReleaseStage";
import { useDungeonReports } from "./useDungeonReports";
import { DungeonDifficultySlider } from "./DungeonDifficultySlider";
import { bossDifficultyLabel } from "../game/dungeonDifficulty";
installDungeonShellRuntime();
@@ -82,10 +84,11 @@ export function DungeonSelectScreen() {
const selectedDefinition = selectedDungeon ? dungeonDefinitionById(selectedDungeon.id) : null;
const [clearFilter, setClearFilter] = useState<DungeonClearFilter>("final");
const [difficultyId, setDifficultyId] = useState("");
const [bossDifficulty, setBossDifficulty] = useState(1);
const [expandedRuns, setExpandedRuns] = useState<ReadonlySet<string>>(new Set());
const leaderboardDifficulty = selectedDefinition?.difficultyVariants.find((variant) => variant.id === difficultyId)
?? selectedDefinition?.difficultyVariants.find((variant) => variant.id === selectedDefinition.defaultDifficultyId);
const leaderboard = useDungeonLeaderboard(selectedDungeon?.id ?? "", leaderboardDifficulty?.id ?? "normal", clearFilter);
const leaderboard = useDungeonLeaderboard(selectedDungeon?.id ?? "", leaderboardDifficulty?.id ?? "normal", clearFilter, bossDifficulty);
const toggleRun = (id: string) => setExpandedRuns((current) => {
const next = new Set(current); if (next.has(id)) next.delete(id); else next.add(id); return next;
});
@@ -121,7 +124,7 @@ export function DungeonSelectScreen() {
const continueAsRole = async (role: PartyRole) => {
if (!selectedDungeon?.available || !character) return;
if (!onlineGroup || !session || session.kind !== "account") {
enterDungeon(selectedDungeon.id, role);
enterDungeon(selectedDungeon.id, role, { difficultyId: leaderboardDifficulty?.id, bossDifficulty });
return;
}
if (!await updateOnlineMember(session, character, role)) return;
@@ -132,6 +135,8 @@ export function DungeonSelectScreen() {
await startOnlineActivity(session, {
type: "dungeon",
contentId: selectedDungeon.id,
difficultyId: leaderboardDifficulty?.id,
bossDifficulty,
partySize: 5,
});
};
@@ -199,6 +204,8 @@ export function DungeonSelectScreen() {
{ id: "leaderboard-full", run: () => setClearFilter("full") },
{ id: "leaderboard-difficulty", run: cycleDifficulty, enabled: (selectedDefinition?.difficultyVariants.length ?? 0) > 1 },
{ id: "leaderboard-refresh", run: leaderboard.refresh },
{ id: "boss-difficulty-down", run: () => setBossDifficulty((value) => Math.max(1, value - 1)), enabled: bossDifficulty > 1 },
{ id: "boss-difficulty-up", run: () => setBossDifficulty((value) => Math.min(10, value + 1)), enabled: bossDifficulty < 10 },
...leaderboard.data.entries.map((entry) => ({ id: `leaderboard-run-${entry.id}`, run: () => toggleRun(entry.id) })),
{ id: "leaderboard-prev", run: () => leaderboard.setOffset(Math.max(0, leaderboard.offset - DUNGEON_LEADERBOARD_PAGE_SIZE)),
enabled: !leaderboard.loading && leaderboard.offset > 0 },
@@ -219,7 +226,7 @@ export function DungeonSelectScreen() {
run: () => setRolePickerOpen(false),
}] : []),
{ id: "dungeon-back", run: returnToMainMenu },
], [availableRoles, categoryDungeons, downloading, firstCategoryDungeon, pendingDownload, returnToMainMenu, rolePickerOpen, selectedCategory, selectedDungeon, selectedDefinition, leaderboard, expandedRuns, leaderboardDifficulty]);
], [availableRoles, categoryDungeons, downloading, firstCategoryDungeon, pendingDownload, returnToMainMenu, rolePickerOpen, selectedCategory, selectedDungeon, selectedDefinition, leaderboard, expandedRuns, leaderboardDifficulty, bossDifficulty]);
const controller = useMenuController(actions, {
initialId: firstAvailable ? `dungeon-${firstAvailable.id}` : "dungeon-back",
onBack: pendingDownload
@@ -318,7 +325,7 @@ export function DungeonSelectScreen() {
<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}
onRefresh={leaderboard.refresh} difficultyLabel={leaderboardDifficulty?.difficulty === "heroic" ? "Heroic" : "Normal"}
onRefresh={leaderboard.refresh} difficultyLabel={`${bossDifficultyLabel(bossDifficulty)} · ${leaderboardDifficulty?.difficulty === "heroic" ? "Heroic" : "Normal"}`}
onDifficulty={(selectedDefinition?.difficultyVariants.length ?? 0) > 1 ? cycleDifficulty : undefined}
selectedId={controller.selectedId} select={controller.select} />
<section className="dungeon-select-copy">
@@ -326,6 +333,8 @@ export function DungeonSelectScreen() {
<h2>{selectedDungeon.title}</h2>
<span className="dungeon-release-stage">{DUNGEON_RELEASE_STAGE_LABELS[selectedDungeon.releaseStage]}</span>
<p>{selectedDungeon.summary}</p>
<DungeonDifficultySlider value={bossDifficulty} onChange={setBossDifficulty}
selectedId={controller.selectedId} select={controller.select} />
{!canStart && selectedDungeon.availabilityReason && (
<p className="front-notice" role="status">{selectedDungeon.availabilityReason}</p>
)}