Files
healer-man/src/game/arenaTypes.ts
T
2026-09-11 14:26:15 -04:00

209 lines
6.2 KiB
TypeScript

import type { ArenaBracket, ArenaMode, ArenaRuleset } from "./arenaRules";
import type { AbilityDefinition, ClassResourceProfile } from "./abilityCatalog";
export interface ArenaCharacterKit {
readonly seed?: import("./combatStore").CharacterCombatSeed;
readonly stats?: { readonly health: number; readonly spellPower: number };
classId: string;
level: number;
resource: ClassResourceProfile;
abilities: Readonly<Record<string, AbilityDefinition>>;
actionBindings: Readonly<Record<string, string | null>>;
}
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" | "command" | "jump" | "bindings";
command?: "attack" | "defend" | "stop" | "recall" | "cancel-cast";
actionBindings?: Readonly<Record<string, string | null>>;
groundPosition?: Vec3Tuple;
movement?: { x: number; z: number };
facing?: number;
targetActorId?: string;
abilityId?: string;
clientTick?: number;
}
export interface ArenaActorSnapshot {
avatar?: import("../avatar/CharacterModel").AvatarIdentity;
visualEquipment?: readonly import("./lootTypes").InventoryItem[];
combat?: {
resourcePools: import("./combatStore").CombatState["resourcePools"];
maxResourcePools: import("./combatStore").CombatState["maxResourcePools"];
runes: import("./combatStore").CombatState["deathKnightRunes"];
comboPoints: number;
comboTargetId: string | null;
shield: number;
activeCast: import("./combatStore").ActiveCast | null;
summons: readonly import("./combatStore").CombatSummon[];
areaEffects: readonly import("./combatStore").CombatAreaEffect[];
controlledUntil: number;
schoolLockedUntil: import("./combatStore").CombatState["schoolLockedUntil"];
talentRanks: import("./combatStore").CombatState["talentRanks"];
gearStats: import("./combatStore").CombatState["gearStats"];
specializationId: string | null;
playerAnimationEvent: import("./combatAnimation").CharacterCombatAnimationEvent | null;
};
id: string;
characterId?: string | null;
classId?: string;
level?: number;
actionBindings?: Readonly<Record<string, string | null>>;
abilityIds?: readonly string[];
resourceType?: string;
gcdRemainingMs?: number;
lastAbilityId?: string;
abilityRevision?: number;
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; icon?: string; disposition?: "buff" | "debuff" }[];
}
export interface ArenaDynamicObjectSnapshot {
id: string;
state: "closed" | "warning" | "active" | "open" | "raised" | "moving" | "lowered";
progress: number;
collisionEnabled: boolean;
}
export interface ArenaAuthoritativeSnapshot {
combatPresentation?: readonly import("./combatPresentation").CombatPresentationEvent[];
combatEvents?: readonly import("./combatEvents").StructuredCombatEvent[];
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[];
}