Appearance
Client globals clientside
Everything available to clientside weapons (*.client.ts), client classes and clientside NPC code (weapons/globals.client.d.ts).
Source
Generated from templates/server/data/scripts/weapons/globals.client.d.ts. To change this page, edit the JSDoc in that file.
Overview
Ambient declarations for host functions injected by the CLIENT's ClearScript V8 runtime (see GClient's WeaponRuntime). These are available to every weapon's clientside script (*.client.ts) without needing an import. The server-side globals (scripts/globals.d.ts) do not exist here.
Fire-and-forget host calls (echo, disabledefmovement, ...) are batched: they queue JS-side and apply at the next flush point — the end of the current onUpdate dispatch at the latest, i.e. still within the same frame. Ordering between batched calls is preserved, but their arguments must be JSON-serializable and they cannot return values. Calls that return values (keydown, player reads) reach the host directly.
Writing player.x / player.y / player.dir is batched too: any number of writes in a flush window fold into ONE host command that applies at flush. Reads see your pending writes immediately (player.x += 2 twice moves by 4), but the clamp to level bounds only happens when the write applies.
Declarations
echo function
ts
declare function echo(msg: string): voidPrints a message to the client console. Batched: applied at the next flush point (end of the current onUpdate dispatch at the latest).
sleep function
ts
declare function sleep(seconds: number): Promise<void>Cooperatively pauses the calling (async) script for the given number of seconds. Other weapon scripts keep running while this one is suspended. Resolution is tied to frames, so resume timing is rounded up to the next frame.
setTimeout function
ts
declare function setTimeout(handler: (...args: any[]) => void, ms?: number, ...args: any[]): numberRuns handler once after ms milliseconds (rounded up to the next frame). Returns an id usable with clearTimeout. Extra args are forwarded to the handler.
clearTimeout function
ts
declare function clearTimeout(id: number): voidCancels a pending setTimeout by id.
setInterval function
ts
declare function setInterval(handler: (...args: any[]) => void, ms?: number, ...args: any[]): numberRuns handler repeatedly every ms milliseconds (fires at most once per frame). Returns an id usable with clearInterval. Extra args are forwarded to the handler.
clearInterval function
ts
declare function clearInterval(id: number): voidCancels a running setInterval by id.
keydown function
ts
declare function keydown(key: string): booleanWhether a key is held this frame. Accepts "up", "down", "left", "right", letters ("a".."z"), digits ("0".."9"), and named keys like "space" or "leftshift". Always false while the game window is inactive or while the player is typing in the chat bar or a text field. Direct call: reads live input, safe to use for movement.
mousex function
ts
declare function mousex(): numberMouse position in window (screen) pixels. The world scrolls under the camera, so convert to world pixels before touching tiles: the hovered tile is floor((mousex() + camerax()) / 16), floor((mousey() + cameray()) / 16). Frozen while the game window is inactive. Direct call: reads live input.
mousey function
ts
declare function mousey(): numberMouse position in window (screen) pixels. The world scrolls under the camera, so convert to world pixels before touching tiles: the hovered tile is floor((mousex() + camerax()) / 16), floor((mousey() + cameray()) / 16). Frozen while the game window is inactive. Direct call: reads live input.
camerax function
ts
declare function camerax(): numberWorld pixels of the screen's top-left corner (the camera offset): worldPx = screenPx + camerax()/cameray(). Direct call: reads live data.
cameray function
ts
declare function cameray(): numberWorld pixels of the screen's top-left corner (the camera offset): worldPx = screenPx + camerax()/cameray(). Direct call: reads live data.
ScreenWidth global
ts
declare const ScreenWidth: numberCurrent client viewport size in pixels. Live values (they track window resizes), handy for centering screen-space findimg images: img.x = ScreenWidth / 2 with style 'c' centers text on screen.
ScreenHeight global
ts
declare const ScreenHeight: numberCurrent client viewport size in pixels. Live values (they track window resizes), handy for centering screen-space findimg images: img.x = ScreenWidth / 2 with style 'c' centers text on screen.
TextMeasurement interface
ts
interface TextMeasurementResult of measuretext().
TextMeasurement.width
ts
width: numberWidth of the widest line, in pixels.
TextMeasurement.height
ts
height: numberTotal height of all lines, in pixels (lines.length * lineheight).
TextMeasurement.lineheight
ts
lineheight: numberHeight of one line in pixels for that font/fontsize/style.
TextMeasurement.lines
ts
lines: string[]The text as rendered lines: explicit newlines, plus word-wrapping when width was given. Join a slice with '\n' to show part of a long text.
measuretext function
ts
declare function measuretext(
text: string,
opts?: { font?: string, fontsize?: number, style?: string, width?: number }
): TextMeasurementMeasures text the way a GuiTextCtrl renders it. font/fontsize/style are the label props (omit for the label defaults); width > 0 word-wraps like a label with that width set, so lines is exactly what such a label would draw. Direct call: returns a value.
setfocus function
ts
declare function setfocus(x: number, y: number): voidPins the camera so tile (x, y) sits at the center of the screen, instead of following the player. Stays pinned until resetfocus(), or until any weapon is removed from the player (the client resets focus, ambient light and default movement whenever a weapon is taken away). Batched.
resetfocus function
ts
declare function resetfocus(): voidReturns the camera to following the player. Batched.
setambient function
ts
declare function setambient(r: number, g: number, b: number): voidSets the ambient light level, 0-255 per channel. Below 255,255,255 the world darkens and NPC lights (drawaslight) become visible; lights with lightmode = 1 are visible at any ambient level. Persists across level changes for the session like setfocus, and resets when any weapon is removed from the player. Default 255,255,255 (lighting off). Batched.
resetambient function
ts
declare function resetambient(): voidRestores full ambient light (disables the lighting pass). Batched.
mousedown function
ts
declare function mousedown(button: 'left' | 'right' | 'middle'): booleanWhether a mouse button is held this frame. Always false while the game window is inactive. Direct call: reads live input.
mouseonui function
ts
declare function mouseonui(): booleanWhether the mouse cursor is over any GUI control (windows, buttons, the chat bar...). Use it to keep world clicks from firing through UI. Chat bubbles are not interactive and don't count. Direct call.
updatelevel function
ts
declare function updatelevel(): voidAsks the server to re-save the current level's .glvl file, persisting every tile painted since the last save ("update level"). Batched.
(There is deliberately no client-side tile-painting function: painting is server-authoritative. Send the edit to a serverside script via triggerServer — it calls setleveltile, and the change comes back to every client in the level as a tile update. See the tileeditor weapon.)
gettile function
ts
declare function gettile(layer: number, x: number, y: number): numberReads a tile of the current level: the row-major tileset index at (x,y) on layer, 65535 for empty, or -1 when out of range / no level is loaded. Direct call: reads live data.
onwall function
ts
declare function onwall(x: number, y: number, w?: number, h?: number): booleanTrue when a blocking collision tile intersects [x, x+w) × [y, y+h), in tile units (fractions allowed). Omit w/h to test the single tile containing (x, y). Tiles outside the level count as blocked, as does having no level loaded. Blocking NPCs count too (see NpcThis.dontblock). The player's walking footprint is the lower body: onwall(player.x, player.y + 1, 2, 1). Direct call: reads live data.
tiletype function
ts
declare function tiletype(x: number, y: number): numberCollision type of the tile containing (x, y): 1 walkable, 22 blocking, etc. -1 when out of range or no level is loaded. Direct call: reads live data.
gmaptolevel function
ts
declare function gmaptolevel(gmapName: string, gx: number, gy: number): { level: string; x: number; y: number } | nullOn a gmap, converts gmap-global tile coordinates to the member level under them and its member-local coordinates. The client only knows its CURRENT gmap: pass '' (or the current gmap's name) for gmapName; anything else — or not being on a gmap — returns null. While on a gmap, player.x/y and all tile/collision functions are gmap-global. Direct call: reads live data.
leveltogmap function
ts
declare function leveltogmap(levelName: string, x: number, y: number): { gmap: string; x: number; y: number } | nullOn a gmap, converts member-level-local tile coordinates to gmap-global. Resolves only members of the CURRENT gmap (the client doesn't know other gmaps); anything else returns null. Direct call: reads live data.
ScriptImage interface
ts
interface ScriptImageA client-only image object (never seen by the server or other players). Property writes are validated at the assignment site, readable back immediately, and coalesced into one batched host command per image per flush window. Draw order is controlled by layer, coordinate space by screen; all images draw below the GUI.
ScriptImage.id
ts
readonly id: numberThe id this image was created with.
ScriptImage.image
ts
image: stringServer asset name, e.g. "images/pics1.png". '' (default) draws a solid width x height rectangle of the tint color. Ignored while polygon is set.
ScriptImage.imagerect
ts
imagerect: string"left,top,width,height" px source region; '' shows the whole image.
ScriptImage.polygon
ts
polygon: number[]Solid filled polygon drawn INSTEAD of the image/rectangle: a flat list of x,y pairs, vertices in order, at least 3 pairs (even length, finite numbers). [1,1, 3,1, 3,3, 1,3] is a 2x2-tile square from (1,1) to (3,3). Vertex units follow screen (tiles, or screen px); x/y offset every vertex and zoom scales them about that anchor, so with the defaults (0,0,1) the coordinates are absolute. Even-odd fill, so concave and self-intersecting outlines work. Respects layer, screen, visible, alpha and tint/red/green/blue; image, imagerect, width and height are ignored while set, and text still takes precedence. [] (default) clears it. Reads return a frozen copy of the last write.
ScriptImage.text
ts
text: stringNon-empty text renders INSTEAD of the image/rectangle. Text respects x/y, layer, screen, zoom (scale), tint/red/green/blue (color) and alpha; width/height and imagerect are ignored for text.
ScriptImage.style
ts
style: stringAny combination of 'b' (bold), 'i' (italic), 'c' (centered on x), in any order — "bci", "ib", "b", '' (default, plain left-aligned).
ScriptImage.font
ts
font: stringFont family for text; '' (default) is the built-in font. Unknown names fall back to the default.
ScriptImage.fontsize
ts
fontsize: numberText size (default 16), in points at 96 DPI (the em is fontsize * 4/3 px), clamped to 256. Each size is rasterized exactly on first use, so any size stays crisp. Composes with zoom.
ScriptImage.textshadow
ts
textshadow: booleantrue draws a drop shadow behind the text (see shadowoffset/shadowcolor).
ScriptImage.shadowoffset
ts
shadowoffset: stringShadow offset "x,y" in px (default "1,1"), scaled with zoom.
ScriptImage.shadowcolor
ts
shadowcolor: stringShadow color "r,g,b" (0-255), default "0,0,0".
ScriptImage.x
ts
x: numberPosition. World mode (screen=false): TILE coordinates like player.x — tile t sits at pixel t*16, and the image scrolls with the camera. Screen mode (screen=true): screen pixels from the top-left of the window.
ScriptImage.y
ts
y: numberPosition. World mode (screen=false): TILE coordinates like player.x — tile t sits at pixel t*16, and the image scrolls with the camera. Screen mode (screen=true): screen pixels from the top-left of the window.
ScriptImage.layer
ts
layer: numberDraw order (default 4). World mode: 0-3 draw under NPCs and players (0 lowest, each layer over the previous); 4+ draw above players and projectiles. Screen mode: pure z-order among screen images, 0 lowest. Negative values clamp to 0; fractions truncate. Equal layers draw in (script, id) order.
ScriptImage.screen
ts
screen: booleanfalse (default): x/y are world tile coordinates. true: x/y are screen pixels — the image ignores the camera and draws above the whole world and chat bubbles, but below GUI controls.
ScriptImage.zoom
ts
zoom: numberScale factor (1 = natural size).
ScriptImage.alpha
ts
alpha: number0 (invisible) .. 1 (opaque).
ScriptImage.red
ts
red: numberColor multiplier channels, 0..1 each (default 1 = unchanged). Applies to the image, rectangle or text — never to the text shadow (shadowcolor). red = 0; blue = 0 leaves only green. Same color as tint, viewed per channel: writing one updates the other.
ScriptImage.green
ts
green: numberColor multiplier channels, 0..1 each (default 1 = unchanged). Applies to the image, rectangle or text — never to the text shadow (shadowcolor). red = 0; blue = 0 leaves only green. Same color as tint, viewed per channel: writing one updates the other.
ScriptImage.blue
ts
blue: numberColor multiplier channels, 0..1 each (default 1 = unchanged). Applies to the image, rectangle or text — never to the text shadow (shadowcolor). red = 0; blue = 0 leaves only green. Same color as tint, viewed per channel: writing one updates the other.
ScriptImage.tint
ts
tint: string"r,g,b" (0-255) color multiplier; "255,255,255" is unchanged. Same color as red/green/blue.
ScriptImage.width
ts
width: numberExplicit size in px, stretching the source region; -1 (default) = natural size.
ScriptImage.height
ts
height: numberExplicit size in px, stretching the source region; -1 (default) = natural size.
ScriptImage.visible
ts
visible: booleanExplicit size in px, stretching the source region; -1 (default) = natural size.
ScriptImage.emitter
ts
readonly emitter: ParticleEmitterThe image's particle emitter (Graal particle engine). Created lazily on first access; does nothing until configured. Destroyed with the image (see emitter.continueafterdestroy). The emitter's origin reads the image's x/y as a WORLD position, so emitters on screen-mode images stay world-anchored (they do not follow the screen position).
ScriptImage.show
ts
show(): voidThe image's particle emitter (Graal particle engine). Created lazily on first access; does nothing until configured. Destroyed with the image (see emitter.continueafterdestroy). The emitter's origin reads the image's x/y as a WORLD position, so emitters on screen-mode images stay world-anchored (they do not follow the screen position).
ScriptImage.hide
ts
hide(): voidThe image's particle emitter (Graal particle engine). Created lazily on first access; does nothing until configured. Destroyed with the image (see emitter.continueafterdestroy). The emitter's origin reads the image's x/y as a WORLD position, so emitters on screen-mode images stay world-anchored (they do not follow the screen position).
ScriptImage.destroy
ts
destroy(): voidRemoves the image for good; the id can be reused with findimg.
ParticleTemplate interface
ts
interface ParticleTemplateDefault attributes for the next emitted particles (emitter.particle). Writes are validated at the assignment site and batched like image props. Distances are in TILES, speeds in tiles/second.
ParticleTemplate.x
ts
x: numberSpawn offset from the emitter, tiles.
ParticleTemplate.y
ts
y: numberSpawn offset from the emitter, tiles.
ParticleTemplate.movex
ts
movex: numberExtra velocity on top of angle/speed, tiles/s.
ParticleTemplate.movey
ts
movey: numberExtra velocity on top of angle/speed, tiles/s.
ParticleTemplate.angle
ts
angle: numberMovement direction in radians; pi/2 moves up the screen.
ParticleTemplate.zangle
ts
zangle: numberAccepted for Graal compatibility; there is no 3D axis (ignored).
ParticleTemplate.speed
ts
speed: numberMovement speed, tiles/s.
ParticleTemplate.spin
ts
spin: numberRotation rate of the image, rad/s.
ParticleTemplate.lifetime
ts
lifetime: numberSeconds until the particle disappears (max 60).
ParticleTemplate.alpha
ts
alpha: number0 (invisible) .. 1 (opaque).
ParticleTemplate.rotation
ts
rotation: numberImage facing angle in radians (independent of movement).
ParticleTemplate.zoom
ts
zoom: numberScale factor.
ParticleTemplate.stretchx
ts
stretchx: numberScale factor.
ParticleTemplate.stretchy
ts
stretchy: numberScale factor.
ParticleTemplate.red
ts
red: numberColor multipliers, 0..1 each.
ParticleTemplate.green
ts
green: numberColor multipliers, 0..1 each.
ParticleTemplate.blue
ts
blue: numberColor multipliers, 0..1 each.
ParticleTemplate.mode
ts
mode: numberBlend mode: 0 = additive, 1 = normal (default), 2 = subtractive.
ParticleTemplate.image
ts
image: stringServer asset name; '' (default) draws a solid 16x16 square.
ParticleModifierHandle interface
ts
interface ParticleModifierHandleHandle returned by the addXmodifier functions; chains extra (variable, modtype, valuemin, valuemax) modifications onto the same schedule.
ParticleModifierHandle.addmod
ts
addmod(variable: string, modtype: 'replace' | 'add' | 'multiply',
valuemin: number, valuemax: number): ParticleModifierHandleParticleEmitter interface
ts
interface ParticleEmitterA particle emitter attached to a script image (Graal particle engine). Configuration writes batch like image props; emit()/modifier calls keep program order with them. The emitter sits at its image's position (plus emissionoffset) and spawns particles that fly on their own.
Modifier schedules — all three functions share the signature (type, rangemin, rangemax, variable, modtype, valuemin, valuemax):
- 'once': fires when the clock passes rangemin, applying a random value
ts
in [valuemin, valuemax].- 'impulse': refires at random intervals in [rangemin, rangemax] seconds.
- 'range': over clock window [rangemin, rangemax]; 'replace' sets the
ts
interpolated valuemin->valuemax value, 'add' treats the interpolated
value as a RATE PER SECOND ('multiply' is not allowed).The clock is the particle's age for addlocalmodifier and the emitter's age for addglobalmodifier (all live particles at once) and addemitmodifier (mutates emitter.particle instead). Modifiable variables: x, y, movex, movey, angle, speed, rotation, spin, stretchx, stretchy, red, green, blue, alpha, zoom (x/y in tiles).
ParticleEmitter.delaymin
ts
delaymin: numberMin/max seconds between automatic bursts (min 0.05). Default 0.5.
ParticleEmitter.delaymax
ts
delaymax: numberMin/max seconds between automatic bursts (min 0.05). Default 0.5.
ParticleEmitter.nrofparticles
ts
nrofparticles: numberParticles per burst (max 100). Default 1.
ParticleEmitter.maxparticles
ts
maxparticles: numberConcurrent particle cap for this emitter (max 1000). Default 100.
ParticleEmitter.emitautomatically
ts
emitautomatically: booleanfalse stops the automatic bursts; emit() still works. Default true.
ParticleEmitter.isfrozen
ts
isfrozen: booleantrue pauses the emitter and all its particles (still drawn).
ParticleEmitter.continueafterdestroy
ts
continueafterdestroy: booleantrue lets live particles finish when the image is destroyed.
ParticleEmitter.attachposition
ts
attachposition: booleantrue keeps particles relative to the emitter as it moves.
ParticleEmitter.firstinfront
ts
firstinfront: booleanFirst-emitted particle draws in front (default true).
ParticleEmitter.autorotation
ts
autorotation: booleantrue points each particle's rotation along its movement.
ParticleEmitter.emissionoffset
ts
emissionoffset: { xd: number; yd: number; zd?: number }Emission position relative to the image, TILES (zd ignored).
ParticleEmitter.clippingbox
ts
clippingbox: { xd1: number; yd1: number; xd2: number; yd2: number; zd1?: number; zd2?: number }Particles outside this emitter-relative box (tiles) are destroyed.
ParticleEmitter.cliptoscreen
ts
cliptoscreen: booleantrue clips to the visible screen instead of clippingbox.
ParticleEmitter.wraptoclippingbox
ts
wraptoclippingbox: booleantrue wraps clipped particles to the other side instead of destroying.
ParticleEmitter.particle
ts
readonly particle: ParticleTemplateDefault attributes for the next emission.
ParticleEmitter.dropemitter
ts
readonly dropemitter: ParticleEmitterSub-emitter bursting where this emitter's particles expire (one level deep).
ParticleEmitter.currentparticlecount
ts
readonly currentparticlecount: numberLive particle count (direct read).
ParticleEmitter.emittedparticles
ts
readonly emittedparticles: numberTotal particles ever emitted (direct read).
ParticleEmitter.emit
ts
emit(): voidOne manual burst of nrofparticles.
ParticleEmitter.removeparticles
ts
removeparticles(): voidDestroys all live particles.
ParticleEmitter.removemodifiers
ts
removemodifiers(): voidRemoves all modifiers.
ParticleEmitter.addlocalmodifier
ts
addlocalmodifier(type: 'once' | 'impulse' | 'range', rangemin: number, rangemax: number,
variable: string, modtype: 'replace' | 'add' | 'multiply',
valuemin: number, valuemax: number): ParticleModifierHandleRemoves all modifiers.
ParticleEmitter.addglobalmodifier
ts
addglobalmodifier(type: 'once' | 'impulse' | 'range', rangemin: number, rangemax: number,
variable: string, modtype: 'replace' | 'add' | 'multiply',
valuemin: number, valuemax: number): ParticleModifierHandleRemoves all modifiers.
ParticleEmitter.addemitmodifier
ts
addemitmodifier(type: 'once' | 'impulse' | 'range', rangemin: number, rangemax: number,
variable: string, modtype: 'replace' | 'add' | 'multiply',
valuemin: number, valuemax: number): ParticleModifierHandleRemoves all modifiers.
findimg function
ts
declare function findimg(id: number): ScriptImageReturns this script's image object with the given id, creating it on first use (visible=true, image=''). An image with no image, text or polygon draws as a solid 16x16 rectangle in its tint (white by default), so set visible = false on images used only as emitter anchors. Ids are PER SCRIPT — another weapon's findimg(1) is a different image. Usable in handlers, onCreated and timer callbacks (timers stay attributed to the script that set them). Images are swept automatically when the weapon unloads.
hideimg function
ts
declare function hideimg(id: number): voidDestroys this script's image with the given id (Graal convention).
disabledefmovement function
ts
declare function disabledefmovement(): voidTurns off the built-in arrow-key movement so this weapon can drive the player itself (by assigning player.x / player.y). Position sync to the server keeps running either way. Default movement comes back on whenever any weapon is removed from the player. Batched.
enabledefmovement function
ts
declare function enabledefmovement(): voidRe-enables the built-in arrow-key movement. Batched.
setAni function
ts
declare function setAni(name: string): voidPlays a .gan animation on the local player; the server relays it to everyone else in the level. Pass the animation name without the extension, e.g. setAni('sword'). Re-setting the current animation restarts it unless the animation is CONTINUOUS (like the default walk). When a non-looping animation finishes, its SETBACKTO chain (usually back to idle) resumes the built-in idle/walk switching. Batched.
replaceAni function
ts
declare function replaceAni(from: string, to: string): voidReplaces a default animation for the local player: wherever from would play — setAni(from), the built-in walk/idle switching, SETBACKTO chains, a server-set animation — to plays instead, and everyone else in the level sees to. If the player is in the old animation right now, it switches on the next frame. replaceAni(from, from) removes the replacement. One level only: replacements don't chain. Replacements last until clearAnis() (or the session ends) — removing the weapon that set them does NOT undo them. Direct (player.replacedAnis reflects it immediately). @example replaceAni('idle', 'handgun-idle'); replaceAni('walk', 'handgun-walk')
clearAnis function
ts
declare function clearAnis(...names: string[]): voidRestores replaced animations to their defaults: clearAnis('walk', 'idle') resets those two, clearAnis() resets every replacement. Direct.
triggerServer function
ts
declare function triggerServer(scriptType: 'weapon' | 'script', scriptName: string, ...params: any[]): voidAsks the server to invoke onActionServerSide on a serverside script, injecting params after the triggering player. Batched; params must be JSON-serializable.
scriptType "weapon" targets the serverside half of one of YOUR weapons (scripts/weapons/<scriptName>.ts — the server rejects weapons you don't have); "script" targets a plain server script (scripts/<scriptName>.ts). scriptName carries no extension — pass this.name to reach your own serverside half:
ts
triggerServer('weapon', this.name, 'dothing', 'hello')
// server: onActionServerSide(player, 'dothing', 'hello')WeaponThis interface
ts
interface WeaponThisEvery handler in a weapon script runs with this bound to the weapon's own object: this.name is the weapon's name (file name without .client.ts), and scripts may stash extra state on this between calls. Only function declarations see it — arrow functions ignore this.
export is optional: every top-level function is exported by the build (so function onCreated() is a handler), and the weapon's own functions and joined class exports are callable on this too. Inside a top-level function this is always the weapon: a bare helper(...) call from a handler falls back to the running script's self instead of JS's undefined.
this types as any in handlers (noImplicitThis is off in tsconfig.json); annotate a handler with this: WeaponThis if you want it typed:
ts
export function onCreated(this: WeaponThis) { ... }WeaponThis.name
ts
name: stringThe weapon's name, e.g. "test" for test.client.ts.
WeaponThis.join
ts
join(name: string): booleanJoins this script to a class's clientside half (scripts/classes/<name>.client.ts): the class's exported handlers fire after this script's own, its exported helpers become callable on this, and its onCreated runs now with this script as this. Serverside joins replicate here automatically. Returns false when the class has no clientside half.
WeaponThis.leave
ts
leave(name: string): booleanRemoves a joined class's handlers from this script.
WeaponThis.joinedclasses
ts
readonly joinedclasses: readonly string[]Currently joined class names, in join order.
WeaponThis.[key]
ts
[key: string]: anyScripts may keep arbitrary state on this.
player global
ts
declare const player: { … }The local player. Reads are live; writes to x / y / dir / chat / head / body / colors are validated at the assignment site, readable back immediately, and coalesced into batched host commands per flush (position clamped to level bounds when it applies). Assigning anything else throws.
player.id
ts
readonly id: numberServer-assigned player id.
player.name
ts
readonly name: stringAccount name.
player.account
ts
readonly account: stringAccount name (same as name).
player.level
ts
readonly level: stringCurrent level (or gmap) name.
player.nick
ts
readonly nick: stringDisplay name rendered under the player. Read-only here — players change it with the setnick chat command, or a server script assigns player.nick. Your own tag is hidden; the showname chat command (and setnick) reveals it for 5 seconds. Other players' tags are always visible.
player.x
ts
x: numberPosition in tiles. Writable; clamped to level bounds at flush.
player.y
ts
y: numberPosition in tiles. Writable; clamped to level bounds at flush.
player.dir
ts
dir: "up" | "down" | "left" | "right"Facing direction. Writable.
player.chat
ts
chat: stringChat bubble above the player's head. Assigning shows it locally AND sends it to the server for everyone in the level ('' clears it); it fades 5s after the player moves. Text is trimmed to 200 chars and control characters become spaces. Batched like x/y/dir.
player.ani
ts
readonly ani: stringThe player's current .gan animation name (without extension), including SETBACKTO chain results. Reports the gani actually played, so with idle replaced by 'handgun-idle' this reads 'handgun-idle' — compare against player.replacedAnis.idle ?? 'idle'. Read-only — play animations with setAni().
player.replacedAnis
ts
readonly replacedAnis: Record<string, string>Current replaceAni() replacements, logical name → played gani, e.g. { idle: 'handgun-idle', walk: 'handgun-walk' }. A fresh snapshot per read; modifying it changes nothing.
player.head
ts
head: stringHead image, e.g. 'head0.png'; '' means the default (head0.png). Assigning is readable back immediately and, at flush, shown locally and sent to the server for everyone in the level (and saved to the account), like the sethead chat command. Invalid names are dropped.
player.body
ts
body: stringBody image, e.g. 'body.png'; '' means the default. Assign like head.
player.colors
ts
colors: string[]Body colors as 'r,g,b' strings, recoloring the body's reserved key colors: [0] skin, [1] coat, [2] sleeves, [3] shoes, [4] belt. Always five entries. Assigning an index (player.colors[1] = '255,0,0') is readable back immediately and, at flush, shown locally and sent to the server for everyone in the level (and saved to the account). Invalid indices or values are ignored. Assigning an array sets each slot it provides.
player.hasWeapon
ts
hasWeapon(name: string): booleanWhether the server currently grants you the named weapon (true as soon as the grant arrives, even if its script is still downloading). Grants change server-side only, via player.addWeapon/removeWeapon there.
client global
ts
declare const client: Record<string, any>The local player's read/write script flags (the same set the server sees as player.client.*). Reads come from a local mirror and are readable back immediately after a write; each changed flag is coalesced per flush window and sent to the server (which does not echo it back). Values must be JSON-serializable; flag names are 1-128 characters, values up to 8192 characters of JSON — violations throw at the assignment site. Assigning null or undefined deletes a flag, as does delete client.foo. Persisted in your account on the server.
Values are stored JSON-normalized, and mutating a nested value does NOT sync it — reassign to write:
ts
const inv = client.inventory ?? []; inv.push('sword');
client.inventory = inv;clientr global
ts
declare const clientr: Readonly<Record<string, any>>Per-player flags the server set with player.clientr.* — read-only here (writes/deletes log a console warning and are ignored). Live-updating: server writes arrive as they happen; the full set arrives at login. Values are deep-frozen (local mutation would never sync anyway).
serverr global
ts
declare const serverr: Readonly<Record<string, any>>Global flags the server set with serverr.* — identical on every client, read-only here (writes/deletes log a console warning and are ignored). Live-updating and deep-frozen like clientr.
CollectionEventMap interface
ts
interface CollectionEventMapEvents a client collection mirror fires.
CollectionEventMap.change
ts
change: (key: string, record: any) => voidOne record changed: (key, record) — record is null on delete.
CollectionEventMap.reset
ts
reset: () => voidThe whole replica was replaced (login snapshot, revoke).
CollectionQueryRow interface
ts
interface CollectionQueryRowA row from a client-side collection query().
CollectionQueryRow.key
ts
key: stringCollectionQueryRow.record
ts
record: anyClientCollection interface
ts
interface ClientCollectionRead-only materialized mirror of a server collection replica: built from snapshots (or the disk cache after a CollectionUpToDate), mutated in place by server deltas — reads are O(1) and records are deep-frozen. Which replicas are live is the server's call: eager owner/all arrive at login, level scopes track your level / gmap window (the mirror reads across every live scope), lazy and group replicas appear when a server script subscribes you and empty when it unsubscribes; anything else reads as empty.
ClientCollection.name
ts
readonly name: stringClientCollection.get
ts
get(key: string): anyThe record's value, or undefined. Frozen — local mutation would never sync.
ClientCollection.keys
ts
keys(): string[]All record keys across the live scopes, sorted.
ClientCollection.forEach
ts
forEach(fn: (key: string, record: any) => void): voidAll record keys across the live scopes, sorted.
ClientCollection.on
ts
on<K extends keyof CollectionEventMap>(event: K, listener: CollectionEventMap[K]): thisSubscribes to mirror changes — rebuild the one slot that changed instead of re-reading everything in onUpdate. Listeners belong to the registering script and are removed when it unloads. Chainable.
ClientCollection.off
ts
off<K extends keyof CollectionEventMap>(event: K, listener?: CollectionEventMap[K]): voidRemoves a listener (or all listeners for the event when omitted).
ClientCollection.query
ts
query(opts?: {
where?: string
params?: (number | string | boolean | null)[]
limit?: number
offset?: number
scope?: string
}): Promise<CollectionQueryRow[]>Explicit paged fetch straight from the server — THE access path for replicate-'none' collections (auction listings), and a paged view over anything sql-backed you may see. Access is audience-checked server-side: 'all' → the global set, 'owner' → your own scope, 'level' / 'group' → scopes you currently hold (pass scope). where addresses record fields by (dotted) name with ? params, like the serverside query API. Default limit 100, max 200.
ClientCollection.fetch
ts
fetch(key: string): Promise<any | null>
fetch(keys: string[]): Promise<(any | null)[]>Per-record on-demand read — THE access path for replicate-'cache' collections (item catalogs). Resolves from the local mirror when the record is cached; otherwise round-trips to the server, which registers you for pushed updates to exactly the fetched keys (a 'change' fires whenever a fetched record later changes — including a key that was missing being created). Missing records resolve null. Concurrent fetches of one key coalesce onto a single request; max 64 keys per call. Rejects for collections that don't replicate 'cache'.
collection function
ts
declare function collection(name: string): ClientCollectionA stateless handle on a collection mirror. Unknown names read as empty.
ChatPlayer interface
ts
interface ChatPlayerFrozen snapshot of a player (yourself or a remote player in the level) handed to event handlers like onPlayerChats.
ChatPlayer.id
ts
readonly id: numberServer-assigned player id; compare with player.id to spot yourself.
ChatPlayer.name
ts
readonly name: stringAccount name.
ChatPlayer.nick
ts
readonly nick: stringDisplay name rendered under the player.
ChatPlayer.x
ts
readonly x: numberPosition in tiles.
ChatPlayer.y
ts
readonly y: numberPosition in tiles.
ChatPlayer.dir
ts
readonly dir: "up" | "down" | "left" | "right"Facing direction.
ChatPlayer.chat
ts
readonly chat: stringThe player's chat at the time of the event.
PMSender interface
ts
interface PMSenderWho a PM came from (onPMReceived).
PMSender.account
ts
readonly account: stringSender's account, or the sending server's name for system PMs.
PMSender.server
ts
readonly server: stringName of the GServer the sender is on ('' if unknown).
PMSender.system
ts
readonly system: booleanTrue for PMs sent by a serverside script (sendPM on a GServer).
Friends, sendPM and reading PM text are NOT available here: they belong to the Login Server's privileged weapons (its global PM system). Game weapons only hear that a PM arrived, and from whom (onPMReceived). Event handlers. A weapon subscribes by exporting a function with the matching name; the client invokes it on every loaded weapon that exports one:
export function onCreated(): void
Fired once when the weapon is loaded on the client (after download or from cache, shortly after login).export function onUpdate(delta: number): void
Fired every frame;deltais the elapsed time in seconds since the previous frame.export function onKeyPressed(key: string): void
Fired once when a key goes down; holding it does not repeat — it fires again only after the key is released and pressed again.keyis the key name: letters uppercase ("T"), digits "0".."9", others like "Enter", "Space", "Up", "LeftShift", "F1" (keydown() accepts the same names). Silent while the chat bar or a text field has focus, or while the window is inactive. Fires on every weapon, clientside NPC script and joined class, before onUpdate in the same frame.export function onActionClientSide(...params: any[]): void
Fired when a serverside script calls triggerClient('weapon', <thisWeapon>, ...params) — the params arrive as the handler's arguments (JSON round-tripped).export function onPlayerChats(player: ChatPlayer, chat: string): void
Fired when any player in the level — yourself included — sets their chat, whether typed in the chat bar, assigned by a script, or set server-side ('' means it was cleared). Only actual changes fire, so setting the same text again is silent and a handler that reacts by writing player.chat can't feed back into itself. NOT fired when a bubble expires (5s after the owner moves) or for chats that already existed when their owner entered the level.
ts
Chat starting with '/' is a COMMAND (e.g. '/te'): it is not shown as a
bubble and never leaves this client, but it IS delivered here — with
the command as `chat` — so weapons can implement chat commands.export function onShotAt(x: number, y: number, data: any): void
A projectile (a serverside level.shoot) stopped in this level: it hit a blocking tile or its lifetime ran out. (x, y) is where it stopped — level tiles, gmap-global tiles on a gmap;datais the shoot call's payload. Fires on every weapon and clientside NPC script.export function onShot(data: any): void
A projectile hit THIS client's player. Only the hit player's client fires it;datais the shoot call's payload.export function onPMReceived(sender: PMSender): void
Someone sent you a private message, from any server — or a serverside script sent a system PM (sender.system is true). A notification only: the text is read by the Login Server's PM system (openPM), never here. Also fires on clientside NPC scripts.
WeaponHandle interface
ts
interface WeaponHandleA handle on another loaded weapon script, from findweapon().
WeaponHandle.name
ts
readonly name: stringThe weapon's name, e.g. "gun".
WeaponHandle.trigger
ts
trigger(event: string, ...params: any[]): booleanInvokes the named exported handler on that weapon RIGHT NOW (its own export, then any joined classes), with this bound to that weapon and the params passed as live values (no JSON round trip). GUI controls and images the handler creates belong to the TARGET weapon. Returns false when the weapon has since unloaded or its handler threw (the error is logged); true otherwise, including when it exports no such handler.
findweapon function
ts
declare function findweapon(name: string): WeaponHandle | nullFinds another weapon script this client currently has LOADED, so one weapon can call into another — the inventory weapon uses it to deliver onWeaponFired / onEquipped / onUnequipped to the equipped item's weapon:
ts
findweapon('gun')?.trigger('onWeaponFired', entry)null when the weapon is not granted or its script hasn't arrived yet, so re-look it up per call rather than caching the handle.
findWeapon function
ts
declare function findWeapon(name: string): WeaponHandle | nullAlias of findweapon.