The pack
meleeCombat
function meleeCombat():Pack<{meleeCombat:typeof rules & typeof bot}>
Install renderer-independent melee combat policies: game.meleeCombat, the constructors and the duel bot.
Helpers
createDuelBot
function createDuelBot(melee: MeleeCombat, self: string, foe: string, options: DuelBotOptions = {}): DuelBot
A fighter for self against foe, both actors of melee.
createMelee
function createMelee(actors: readonly MeleeActor[], attacks: readonly MeleeAttack[] = duelAttacks)
A MeleeCombat for the fighters and attacks (default duelAttacks) with the default parry window of 0.14 s.
duelAttacks
const duelAttacks: MeleeAttack[]
The default attacks: a quick jab and a slow, wide cleave, each of which can follow the other.
meleeActor
function meleeActor(id: string, team: string, x: number, y: number, facing = 0): MeleeActor
A living fighter of team at (x, y), facing facing radians (0 is +x), with body radius 14, guard down and no attack.
Classes
MeleeCombat
class MeleeCombat
Timeline policy independent of movement. Call attack/block, then tick with world positions and optional occlusion.
readonly definitions: MeleeAttack[]— The attacks in play, cloned from the constructor's.readonly actors: MeleeActor[]— The live fighters, cloned from the constructor's;tickreads and writes them.readonly events: MeleeEvent[]— Events raised since the lastdrain.constructor(actors: readonly MeleeActor[], attacks: readonly MeleeAttack[] = duelAttacks, readonly parryWindow = .14)get(id: string)— The live fighter with this id. ThrowsUnknown fighterfor an unknown id.attack(id: string, move: string): { ok: boolean; reason: string; }— Start attackmovefor fighterid, or queue it as a follow-up when an attack is in progress and its combo window is open. Returnsok: falsewith a reason when the fighter is dead or stunned, or the window is closed. Starting an attack drops the guard. Throws for an unknown fighter or attack.block(id: string, held: boolean)— Raise (heldtrue) or lower the guard of fighterid. Raising it restartsblockTime; it stays down while the fighter attacks, is stunned or is dead. Throws for an unknown fighter.phase(id: string)— What fighteridis doing:stunned,block,ready, or the attack'sstartup,activeorrecovery. Throws for an unknown fighter.tick(dt: number, canHit: (a: MeleeActor, b: MeleeActor) => boolean = () => true)— Advance every fighter bydtseconds (0 to 1): count down stuns, advance attacks, resolve the hits that become active, and start queued follow-ups.canHitis an occlusion test and may veto a hit between two fighters. Throws for adtoutside 0 to 1.drain()— Take and clear the events raised since the last drain, oldest first.
Types
DuelBot
interface DuelBot
A duel fighter.
next(dt: number): DuelOrders— The orders for the nextdtseconds.
DuelBotOptions
interface DuelBotOptions
How the fighter fights.
opener?: string— The attack it opens with. Default the first defined.reach?: number— Where it stands to strike, as a fraction of the opener's range. Default 0.8.aggression?: number— Swings a second it starts, on average, while in reach and ready. Default 1.2.combo?: number— The chance it follows a swing with the next in its combo. Default 0.5.guard?: number— The chance it guards against a swing it sees coming. Default 0.6.react?: number— Seconds into the other's swing before it reacts. Default 0.12.seed?: number— Default 1.
DuelOrders
interface DuelOrders
What to do this step.
x: number— The way to walk, normalised (zero to stand).y: number— The y part of the way to walk; seex.facing: number— The way to face: at the other fighter.attack: string | null— An attack to start or queue, or none.block: boolean— Hold the guard.
MeleeActor
interface MeleeActor extends Point
A fighter: a position (world units) with a body, a facing, a guard and the attack in progress.
id: string— Unique fighter id.team: string— Team name; fighters on the same team never hit each other.r: number— Body radius in world units; added to an attack's range when it is the target.facing: number— Direction the fighter faces, radians; 0 is +x.alive: boolean— Whether the fighter is still in the fight; the dead neither attack nor get hit.blocking: boolean— Whether the guard is up. Set withMeleeCombat.block.blockTime: number— Seconds the guard has been held; a swing that lands within the parry window is a parry.stunned: number— Seconds of stun left; a stunned fighter cannot attack or block.attack: null | { /** Id of the attack being performed. */ id: string; /** Seconds since it began. */ elapsed: number; /** Ids of the fighters this swing has already struck, so none is hit twice. */ hit: string[]; /** The follow-up attack queued for when this one completes, or null. */ queued: string | null; }— The attack in progress, or null.
MeleeAttack
interface MeleeAttack
One attack: a timeline of startup, active and recovery, a reach, and the attacks that can follow it.
id: string— Unique attack name, such asjab.startup: number— Seconds from the swing starting until it can hit; at least 0.active: number— Seconds the swing can hit for, at least 0.001.recovery: number— Seconds from the end of the active frames until the fighter is ready again; at least 0.range: number— Reach in world units from the attacker's centre, at least 1; a target's own radius is added.arc: number— Full width of the swing's cone, in radians, 0 to 2π, centred on the attacker'sfacing.damage: number— Damage dealt by a clean hit; at least 0.knockback: number— Size of the push on the target in world units, at least 0; a block cuts it to 15%.comboOpen: number— Seconds into the attack at which the next attack can first be queued; at least 0.comboClose: number— Seconds into the attack after which no follow-up can be queued; fromcomboOpento the attack's total duration.next: string[]— Ids of the attacks that can follow this one inside the combo window; each must be defined.
MeleeEvent
interface MeleeEvent
Something that happened in a tick, taken with MeleeCombat.drain.
kind: 'swing' | 'hit' | 'blocked' | 'parried' | 'complete'—swing: an attack started;hit: it landed;blocked: the target's guard took it;parried: the guard went up just in time and stunned the attacker;complete: the attack ran its course.source: string— Id of the attacker.target: string— Id of the fighter struck; empty forswingandcomplete.damage: number— Damage dealt; 0 for a block, a parry, a swing or a completion.knockback: Point— Push on the target in world units, directed away from the attacker; zero forswingandcomplete.attack: string— Id of the attack concerned.


