Update Healer Man server
This commit is contained in:
1 parent
7449abdad2
commit
a641a6e948
9 files changed
+363
-47
No files matched your search
@@ -0,0 +1,116 @@
|
||||
import type { CharacterProfile, PlayerSession } from "./types";
|
||||
import type { OnlineGroup, StartOnlineGroupActivityInput } from "./onlineGroupTypes";
|
||||
import { dungeonContentIsUsable, installContentPack } from "../content/contentManager";
|
||||
import { dungeonContentPackId } from "../game/dungeonContentSource";
|
||||
import { randomDungeonByCategory, randomRegularDungeon, type DungeonCatalogEntry } from "../game/dungeonCatalog";
|
||||
import { dungeonDefinitionById } from "../game/dungeonRegistry";
|
||||
import { classCanFillPartyRole, type PartyRole } from "../game/partyRoles";
|
||||
import { specializationById } from "../game/specializationCatalog";
|
||||
import type { DungeonEntrySettings } from "./dungeonShellRuntimeBridge";
|
||||
|
||||
export type RandomDungeonQueueMode = "regular" | "bite-sized";
|
||||
export type RandomDungeonQueueStage = "rolling" | "downloading" | "entering";
|
||||
|
||||
export interface RandomDungeonQueueOptions {
|
||||
readonly mode: RandomDungeonQueueMode;
|
||||
readonly role: PartyRole;
|
||||
readonly character: CharacterProfile | null;
|
||||
readonly session: PlayerSession | null;
|
||||
readonly group: OnlineGroup | null;
|
||||
readonly includeBetaSpecs: boolean;
|
||||
readonly fillWithAi: boolean;
|
||||
readonly onProgress: (stage: RandomDungeonQueueStage, dungeon: DungeonCatalogEntry | null) => void;
|
||||
readonly enterDungeon: (dungeonId: string, role: PartyRole, settings: DungeonEntrySettings) => boolean;
|
||||
readonly updateOnlineMember: (session: PlayerSession, character: CharacterProfile, role: PartyRole) => Promise<boolean>;
|
||||
readonly startOnlineActivity: (session: PlayerSession, input: StartOnlineGroupActivityInput) => Promise<boolean>;
|
||||
readonly failureNotice: () => string;
|
||||
}
|
||||
|
||||
interface RandomDungeonQueueDependencies {
|
||||
readonly random: () => number;
|
||||
readonly contentIsUsable: (dungeonId: string) => boolean;
|
||||
readonly installPack: (packId: string) => Promise<void>;
|
||||
readonly installDungeonRuntime: () => Promise<void>;
|
||||
}
|
||||
|
||||
const DEFAULT_DEPENDENCIES: RandomDungeonQueueDependencies = {
|
||||
random: Math.random,
|
||||
contentIsUsable: dungeonContentIsUsable,
|
||||
installPack: installContentPack,
|
||||
installDungeonRuntime: async () => {
|
||||
const { installDungeonShellRuntime } = await import("./dungeonShellRuntime");
|
||||
installDungeonShellRuntime();
|
||||
},
|
||||
};
|
||||
|
||||
export type RandomDungeonQueueResult =
|
||||
| { readonly status: "entered" | "waiting" | "started"; readonly dungeonTitle?: string }
|
||||
| { readonly status: "error"; readonly message: string };
|
||||
|
||||
/** Rolls only after Queue is pressed; downloads the selected map before local or shared entry. */
|
||||
export async function queueRandomDungeon(
|
||||
options: RandomDungeonQueueOptions,
|
||||
dependencies: RandomDungeonQueueDependencies = DEFAULT_DEPENDENCIES,
|
||||
): Promise<RandomDungeonQueueResult> {
|
||||
const { character, session, group, role } = options;
|
||||
if (!character || !session) return { status: "error", message: "Select a character before queuing." };
|
||||
const specialization = specializationById(character.specializationId);
|
||||
if ((character.categoryId !== "rom" && specialization?.role !== role)
|
||||
|| !classCanFillPartyRole(character.classId, role)) {
|
||||
return { status: "error", message: "That role is unavailable for this character." };
|
||||
}
|
||||
if (group && (session.kind !== "account" || !session.accessToken)) {
|
||||
return { status: "error", message: "Reconnect before queuing with your group." };
|
||||
}
|
||||
|
||||
try {
|
||||
if (group) {
|
||||
if (!await options.updateOnlineMember(session, character, role)) {
|
||||
return { status: "error", message: options.failureNotice() || "The group role could not be updated." };
|
||||
}
|
||||
if (group.leaderAccountId !== session.ownerId) return { status: "waiting" };
|
||||
}
|
||||
|
||||
options.onProgress("rolling", null);
|
||||
const dungeon = options.mode === "regular"
|
||||
? randomRegularDungeon(undefined, dependencies.random)
|
||||
: randomDungeonByCategory("bite-sized", undefined, dependencies.random);
|
||||
if (!dungeon) return { status: "error", message: "No dungeon is currently ready for this queue." };
|
||||
if (!dependencies.contentIsUsable(dungeon.id)) {
|
||||
options.onProgress("downloading", dungeon);
|
||||
await dependencies.installPack(dungeonContentPackId(dungeon.id));
|
||||
if (!dependencies.contentIsUsable(dungeon.id)) {
|
||||
return { status: "error", message: `${dungeon.title} could not be verified after downloading.` };
|
||||
}
|
||||
}
|
||||
|
||||
const difficultyId = dungeonDefinitionById(dungeon.id)?.defaultDifficultyId;
|
||||
options.onProgress("entering", dungeon);
|
||||
if (group) {
|
||||
const started = await options.startOnlineActivity(session, {
|
||||
type: "dungeon",
|
||||
contentId: dungeon.id,
|
||||
difficultyId,
|
||||
bossDifficulty: 1,
|
||||
partySize: 5,
|
||||
fillWithAi: options.fillWithAi,
|
||||
includeBetaSpecs: options.includeBetaSpecs,
|
||||
});
|
||||
return started
|
||||
? { status: "started", dungeonTitle: dungeon.title }
|
||||
: { status: "error", message: options.failureNotice() || "The group dungeon could not be started." };
|
||||
}
|
||||
|
||||
await dependencies.installDungeonRuntime();
|
||||
const entered = options.enterDungeon(dungeon.id, role, {
|
||||
difficultyId,
|
||||
bossDifficulty: 1,
|
||||
freshRun: true,
|
||||
});
|
||||
return entered
|
||||
? { status: "entered", dungeonTitle: dungeon.title }
|
||||
: { status: "error", message: options.failureNotice() || `Could not enter ${dungeon.title}.` };
|
||||
} catch (error) {
|
||||
return { status: "error", message: error instanceof Error ? error.message : "The random dungeon queue failed." };
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user