75 lines
2.5 KiB
TypeScript
75 lines
2.5 KiB
TypeScript
import type { CharacterProfile } from "../app/types";
|
|
import { ArenaSimulation } from "../../server/arena-simulation.mjs";
|
|
import type { ArenaAuthoritativeSnapshot, ArenaCombatIntent, ArenaResult, ArenaRole, ArenaStageManifest } from "./arenaTypes";
|
|
|
|
interface PracticeOptions {
|
|
character: CharacterProfile;
|
|
role: ArenaRole;
|
|
bracket: "2v2" | "3v3";
|
|
ruleset: "wow" | "coa" | "rom";
|
|
stage: ArenaStageManifest;
|
|
difficulty: number;
|
|
onSnapshot: (snapshot: ArenaAuthoritativeSnapshot) => void;
|
|
onResult: (result: ArenaResult) => void;
|
|
}
|
|
|
|
function teamRoles(teamSize: number, playerRole?: ArenaRole): ArenaRole[] {
|
|
const roles: ArenaRole[] = playerRole ? [playerRole] : [];
|
|
if (!roles.includes("healer")) roles.push("healer");
|
|
while (roles.length < teamSize) roles.push("damage");
|
|
return roles;
|
|
}
|
|
|
|
export function createArenaPractice(options: PracticeOptions) {
|
|
const id = `practice-${Date.now().toString(36)}`;
|
|
const teamSize = options.bracket === "2v2" ? 2 : 3;
|
|
const participants = [
|
|
...teamRoles(teamSize, options.role).map((role, index) => ({
|
|
actorId: index === 0 ? "practice-player" : `practice-ally-${index}`,
|
|
accountId: null,
|
|
characterId: index === 0 ? options.character.id : null,
|
|
name: index === 0 ? options.character.name : role === "healer" ? "Training Medic" : `Training Ally ${index}`,
|
|
team: 0 as const,
|
|
role,
|
|
isBot: index !== 0,
|
|
rating: options.difficulty,
|
|
})),
|
|
...teamRoles(teamSize).map((role, index) => ({
|
|
actorId: `practice-enemy-${index}`,
|
|
accountId: null,
|
|
characterId: null,
|
|
name: role === "healer" ? "Opponent Medic" : `Opponent ${index + 1}`,
|
|
team: 1 as const,
|
|
role,
|
|
isBot: true,
|
|
rating: options.difficulty,
|
|
})),
|
|
];
|
|
const simulation = new ArenaSimulation({
|
|
id,
|
|
stage: options.stage,
|
|
bracket: options.bracket,
|
|
mode: "practice",
|
|
ruleset: options.ruleset,
|
|
participants,
|
|
onSnapshot: (snapshot) => options.onSnapshot({ ...snapshot, controlledActorId: "practice-player" }),
|
|
onResult: (result) => options.onResult({ ...result, ratingUpdates: [] }),
|
|
});
|
|
options.onSnapshot({ ...simulation.snapshot(), controlledActorId: "practice-player" });
|
|
let started = false;
|
|
return {
|
|
start() {
|
|
if (started) return;
|
|
started = true;
|
|
simulation.resetPreparationClock();
|
|
simulation.start();
|
|
},
|
|
intent(intent: ArenaCombatIntent) {
|
|
return simulation.receiveIntent("practice-player", intent);
|
|
},
|
|
stop() {
|
|
simulation.stop();
|
|
},
|
|
};
|
|
}
|