Files
healer-man/src/game/arenaTypes.ts
T
2026-09-05 20:42:38 -04:00

165 lines
4.1 KiB
TypeScript

import type { ArenaBracket, ArenaMode, ArenaRuleset } from "./arenaRules";
export type Vec3Tuple = readonly [number, number, number];
export type ArenaRole = "healer" | "damage";
export type ArenaPhase = "queue" | "ready-check" | "preparation" | "active" | "finished" | "void";
export interface ArenaStageAsset {
id: "visual" | "collision" | "navigation";
url: string;
checksum?: string;
byteLength?: number;
}
export interface ArenaStageValidation {
status: "source-ready" | "repair-required" | "validated";
traversal: boolean;
collision: boolean;
spawnSafety: boolean;
lineOfSight: boolean;
performance: boolean;
notes: string[];
}
export interface ArenaLineOfSightObject {
id: string;
shape: "box" | "cylinder";
position: Vec3Tuple;
size: Vec3Tuple;
dynamicObjectId?: string;
}
export interface ArenaDynamicObjectDefinition {
id: string;
kind: "pipe-knockback" | "waterfall" | "starting-elevators" | "fire-cycle" | "moving-pillars";
initialDelayMs?: number;
initialDelayRangeMs?: readonly [number, number];
runtimeStartMs?: number;
warningMs: number;
activeMs: number;
cycleMs: number;
}
export interface ArenaStageManifest {
id: string;
name: string;
sourceMap: string;
mapId: number;
assetBaseUrl: string;
assets: readonly ArenaStageAsset[];
bounds: { min: Vec3Tuple; max: Vec3Tuple };
teamSpawns: readonly [Vec3Tuple, Vec3Tuple];
preparationGates: readonly [Vec3Tuple, Vec3Tuple];
spectatorPositions: readonly [Vec3Tuple, Vec3Tuple];
shadowSight: readonly [Vec3Tuple, Vec3Tuple];
lineOfSight: readonly ArenaLineOfSightObject[];
dynamicObjects: readonly ArenaDynamicObjectDefinition[];
validation: ArenaStageValidation;
}
export interface ArenaLoadout {
slot: number;
name: string;
characterId: string;
classId: string;
specializationId: string;
role: ArenaRole;
ruleset: ArenaRuleset;
level: 80;
talents: Record<string, number>;
actions: Record<string, string>;
version: number;
selected: boolean;
updatedAt: number;
}
export interface ArenaQueueRequest {
characterId: string;
loadoutSlot: number;
bracket: ArenaBracket;
mode: ArenaMode;
ruleset: ArenaRuleset;
botDifficulty?: number;
groupMembers?: readonly { accountId: string; characterId: string; loadoutSlot: number }[];
}
export interface ArenaQueueState {
status: "idle" | "queued" | "ready-check" | "matched";
ticketId?: string;
joinedAt?: number;
searchRange?: number;
readyDeadline?: number;
matchId?: string;
lockedLoadout?: ArenaLoadout;
}
export interface ArenaCombatIntent {
sequence: number;
type: "movement" | "facing" | "target" | "ability";
movement?: { x: number; z: number };
facing?: number;
targetActorId?: string;
abilityId?: string;
clientTick?: number;
}
export interface ArenaActorSnapshot {
id: string;
name: string;
team: 0 | 1;
role: ArenaRole;
isBot: boolean;
disconnected: boolean;
alive: boolean;
position: Vec3Tuple;
facing: number;
health: number;
maxHealth: number;
resource: number;
maxResource: number;
targetActorId: string | null;
cooldowns: Record<string, number>;
effects: readonly { id: string; remainingMs: number; stacks?: number }[];
}
export interface ArenaDynamicObjectSnapshot {
id: string;
state: "closed" | "warning" | "active" | "open" | "raised" | "moving" | "lowered";
progress: number;
collisionEnabled: boolean;
}
export interface ArenaAuthoritativeSnapshot {
matchId: string;
tick: number;
serverTime: number;
phase: ArenaPhase;
phaseEndsAt: number | null;
stageId: string;
bracket: ArenaBracket;
mode: ArenaMode;
ruleset: ArenaRuleset;
dampening: number;
actors: readonly ArenaActorSnapshot[];
dynamicObjects: readonly ArenaDynamicObjectSnapshot[];
acknowledgedSequence?: number;
controlledActorId?: string;
}
export interface ArenaRatingUpdate {
characterId: string;
bracket: ArenaBracket;
before: number;
delta: number;
after: number;
title: string;
}
export interface ArenaResult {
matchId: string;
winnerTeam: 0 | 1 | null;
draw: boolean;
reason: "elimination" | "simultaneous-elimination" | "void";
ratingUpdates: readonly ArenaRatingUpdate[];
}