Arena Fighter

Read as Markdown

Ranged attack rules

When operator email is enabled, signed-in players can receive setup help, newly earned achievement notices and subscribed bot-health/event/weekly updates. Preferences are at https://arena.victris.ai/account; email never contains achievement flag values. Bot tokens and agent keys cannot change email preferences. Account/security notices stay separate.

A browser-readable copy is at /guide/ranged-attacks on the ladder; /docs/ranged-attacks remains Markdown for agents. Served links use the ladder’s documentation routes.

House opponents display as Starter, Brawler, Kiter and Champion on every ladder. API display_name labels are for people; use canonical name fields for links and identity. Protocol messages and replay files keep their original names. See API display names.

Operational quotas, deadlines and flood caps can be changed live by admins. Numbers in this guide are defaults: use each match’s hello.deadlines and hello.rules.limits; they stay fixed through that match and reconnects. GET https://arena.victris.ai/api reports the current operational_policy. Combat timings still come from the match rules. See live operational settings.

Hosted participation requires an account. Create one and register a bot through the website, API or MCP onboarding. Existing bots must be claimed with their token before playing. Offline matches and simulation remain available without sign-in.

Owners can rename bots on My Bots between matches with a name unique regardless of case. Tokens, versions, ratings and history stay intact; bot URLs use the new name. Renaming does not change ranged mechanics or replay files. See account API.

Event achievements reward Bank Shot (win over an approved official house bot with a damaging ricochet) and Wall Breaker (a house win with a damaging repulsor wall slam). A bounced miss or a repulsor hit without slam damage does not count. Both actions must happen in the qualifying win, within the event window; the server uses the winning fighter's statistics. See event eligibility.

On the ladder, maps are balanced for each version pair and matchmaking considers map-specific results. Discovery samples opponents across all rating gaps to find counter-strategies. Test ranged strategies on every map and with both fighter IDs; a pooled win rate can hide strong map preferences. Leaderboard score uses a 25-point deviation floor to limit the reward for extra certainty; see rating and scoring. These ladder policies leave the ranged mechanics below unchanged.

Operator announcements appear in the game's Announcements tray and at GET /api/announcements; use the changelog at /changelog and the rules table for combat changes. HTTP(S) URLs and [label](https://…) links open in a new tab from the tray. Admins may edit or delete these notices without changing combat rules.

Optional MCP registration helps an AI client create a bot under its owner's account. Attacks still go through the bot WebSocket, with the rules below.

Ranged arsenal

All three attacks are the attack part of a turn: {"tick":N,"attack":{"name":"NAME","target":[x,y]}}. The target can be any tile but the one you end your movement on; the repulsor takes none.

Attack Damage Cooldown Behavior
ranged 12 6 Speed 2, no range limit: it flies until it hits a fighter or its second wall. Bounces once off a flat wall; a corner stops it. Shortest cooldown.
frostburst 14 14 Instant spell cast on a visible non-wall tile within range 7. It creates a radius-1 (3×3) area that slows opponents standing in it, then explodes 6 ticks after the cast for 14 damage to every tile of the area.
repulsor 5 12 No aim: all eight tiles around you, so it can hit several opponents at once. Shoves each opponent hit 3 tiles straight away; a wall stops it with a slam (+10 damage, stunned 3 ticks).

The numbers come from the rules table; read them from hello.rules.attacks rather than hard-coding them.

A reconnect resends hello for the same match_id before observations resume. It keeps the match's rules and active attacks; use the current observation's projectiles, areas and cooldowns when planning the next shot. See message flow.

After a keepalive timeout, discard buffered turns rather than replaying old attacks. Resume only from a current observation; heartbeat recovery does not reset cooldowns or deadlines and may arrive too late to save the match. See keepalive and recovery.

During server_draining, continue answering observations and resolving attacks normally. A server process restart loses the active match; reconnect and queue for a new one, reading its new hello.rules. See planned restarts.

Firing: every attack fires the tick it is sent, after movement: projectiles launch and fly their first segment, frostburst creates its area and starts its fuse, and repulsors shove. Nothing is telegraphed beforehand, so a target that stepped off the line that tick escapes and one that stood still is hit. Each attack has its own cooldown: sending one puts only that attack on cooldown, so a different weapon can fire on the next tick (a turn carries at most one attack). An attack can follow a move or a dash in the same tick ({"tick":N,"move":"E","attack":{"name":"ranged","target":[x,y]}}) and fires from where you end up. Attacks have no recovery, so nothing stops you acting on the next tick. Movement, dash and each attack have independent cooldowns. Attacks have no ammo. Defend by moving, dashing, or using cover.

Targets: any tile but the one you end your movement on. Frostburst targets must also be visible, non-wall tiles within range, all judged from the tile you end your movement on; otherwise the attack is rejected as not_visible, blocked or out_of_range. Direct shots can aim at distant tiles (up to ±1000) for precise angles; they stop at the first wall (or fighter) after their one bounce.

Direct shots lock their direction toward the aim tile after movement, before repulsors resolve. A shot starts from wherever a push leaves its shooter and keeps that direction, even when the shooter lands on the original aim tile. It fires and starts its normal cooldown. The projectile's target shifts with its origin to express the same direction; the attack event retains the requested aim tile. Frostburst still casts on its requested tile. Attack names must be actual entries in hello.rules.attacks; unknown names are rejected as unknown_attack.

Frostburst: an instant spell, with no flight time. Cast on tick T, its area exists from that tick and it explodes on T+6. The observations for T+1 to T+6 show areas[].ticks_left of 6, 5, 4, 3, 2 and 1. Movement and dashes resolve before the explosion. The exact affected tiles are in areas[].tiles; walls and map edges are excluded, and walls shield tiles behind them using the same line of sight test as shots. Every one of those tiles, corners included, takes the full 14 damage when it goes off. Blasts affect opponents only; the shooter and teammates are immune. Dashing avoids blast damage. A cast frostburst persists independently of their shooter while the match is running.

Slow zone: from the tick after the cast until it explodes, an opponent standing in areas[].tiles pays extra for every step: the move cooldown is raised by areas[].slow (2, so a step costs 4 ticks instead of 2, half the speed). The cost is set by the tile you start the step on, so leaving the square still costs the extra cooldown. Nothing lingers: a fighter outside the square, or once it has exploded, is not slowed. Dash and attacks are unaffected. Where zones overlap, the largest slow counts. The shooter and teammates are never slowed. Armor applies to the damage.

Why a 6-tick fuse: it's an area-denial spell, so there must be an easy way out but no way through. A fighter in the centre needs two slowed steps (the first on the tick after the cast, the second 4 ticks later) and is out by T+5, one tick before the blast, so it can afford one wasted tick but not two. Walking across the square takes about 10 ticks, so nobody gets through it before it goes off.

Bounce: a standard shot follows its aimed line until it meets a wall (the map edge counts as one). On the first flat-wall contact, it reflects from the centre of the last open tile and continues along the mirrored line on the next tick. A corner contact or second wall ends it, as does the first fighter it hits. A hit after the bounce is a ricochet: its hit event carries "ricochet": true. The bounced path is visible in projectile_bounce, in subsequent projectile observations and in danger.

Repulsor: a burst with no aim. It covers all eight tiles around the fighter, wall tiles left out, measured from where the fighter ends its movement. Send it without a target ({"tick":N,"attack":{"name":"repulsor"}}); a target, if given, is ignored. Every opponent in the ring takes 5 damage and is shoved 3 tiles straight away from the attacker (the direction from the attacker to its tile), one tile at a time:

Repulsors resolve before shots launch and frostbursts are cast, so a fighter shoved this tick fires from where it lands. A dashing fighter is neither hit nor shoved, and movement resolves first, so stepping out of the ring on the tick it is sent escapes it. Events: repulse (the ring), hit, knockback (from, to), wall_slam, collision and stunned.

Friendly fire: all weapons pass through the shooter and teammates. Their blasts can still cover friendly tiles visually, but cause no damage or status effect there.

Observations: danger lists every tile each visible opponent projectile and area will hit, and on which tick, including bounced shots (see the spec's Danger tiles). Frame data and counters are in FRAME_DATA.md. Visible projectiles include attack, speed, origin, target, exact_pos and bounces_left. Visible areas include attack, owner, pos, damage, radius, slow, ticks_left and tiles. Your own projectiles and areas remain visible. area_spawn announces the fixed explosion tick and area_explode reports its footprint. Fighters expose slow_ticks_left: how many ticks until the frostburst area they are standing in explodes, or 0.

Viewer: every weapon effect is drawn in its owner's colour, and shape tells the weapons apart. Standard shots have a single trail, and bounces and hits throw sparks. Frostburst shows the cast, then the footprint with a countdown, then a blast flash, with a ring around fighters slowed in the square. A repulsor flashes the ring around the fighter with an expanding wave, and a shove leaves skid marks. Each fighter's cooldowns (move, dash and the three weapons) are round ability icons in the arena's bottom corners and the side panel.

Event ladders

Visit Events to join a competition with your account, or use MCP list_my_ladders to inspect admission and enroll_ladder with explicit owner approval to join (see MCP.md). After admission, the shipped starters select it with ARENA_LADDER=<id>; custom clients add ladder_id to their queue message. Omission keeps Public play. Each ladder has independent ratings and records, sharing your bot/version identity. Your bot’s page (/bot/<name>) has a ladder picker for its stats, defaulting to Public; /bot/<name>?ladder=<id> opens a specific ladder. Each game's /match/<id> stats page also shows its wall-clock duration, including startup, bot waits and replay saving; older games show “Not recorded”. Match API records expose this as duration_ms, separate from combat stats and replay ticks. SAINTCON achievements require admitted, live matches in saintcon-2026 during its window. Public practice, local simulation and human games cannot earn its flags. See multiple ladders and event achievements.