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; actions: Record; 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; 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[]; }