Skip to content

Clientside NPCs clientside ​

The NPC this for clientside NPC scripts and triggerAction (npc.client.d.ts), on top of the client globals.

Source

Generated from templates/server/data/scripts/npc.client.d.ts. To change this page, edit the JSDoc in that file.

Overview ​

Ambient declarations for CLIENTSIDE NPC scripts (the clientScript baked into a level's NPCs). NPC scripts also see the weapon client globals (weapons/globals.client.d.ts) — player is still the LOCAL player, and echo/findimg/keydown/timers all work.

Inside every handler, this is the NPC as seen by THIS client (use function declarations, not arrow functions). Property writes are client-local: they change what this client sees and never go on the wire. Unknown properties are a per-NPC state bag that persists between calls.

  • export function onCreated(): void
    The NPC appeared on this client (level entered, or hot reload).
  • export function onPlayerEnters(player: ChatPlayer): void
    A player entered the level (the local player included, right after onCreated).
  • export function onPlayerChats(player: ChatPlayer, chat: string): void
    A player chatted. /-prefixed commands arrive here too (they are not shown as bubbles).
  • export function onUpdate(dt: number): void
    Every frame; dt is the frame time in seconds.
  • export function onKeyPressed(key: string): void
    A key went down (once per press — held keys don't repeat). Same key names and rules as for weapons (see weapons/globals.client.d.ts).
  • export function onAction<Name>(...params: any[]): void
    A serverside level.triggerAction hit this NPC. <Name> is the action name with its first letter uppercased.
  • export function onPMReceived(sender: PMSender): void
    A PM arrived for the local player (notification only — no text), same as for weapons (see weapons/globals.client.d.ts).
  • export function onShotAt(x: number, y: number, data: any): void
    A projectile stopped in this level (blocking tile or lifetime expiry) at (x, y) — level tiles, gmap-global on a gmap. Fires on every clientside NPC script and every weapon; data is the shoot payload.
  • export function onShot(data: any): void
    A projectile hit THIS NPC's shape. Fires on this NPC's clientside script on every client (and its serverside script on the server).
  • export function onMovementFinished(): void
    A clientside this.move() with option 8 ended (reached or blocked). Moves started by the serverside script fire it serverside only.

setTimeout/setInterval/sleep work per-NPC: timer callbacks keep this bound to the NPC, and timers die when the NPC unloads (level change or hot reload).

Declarations ​

triggerAction function ​

ts
declare function triggerAction(x: number, y: number, action: string, ...params: any[]): void

Asks the server to fire onAction<Name> on the serverside script of every NPC whose shape contains (x, y) — tile units. The serverside handler receives (player, ...params) with the triggering player first. Strict Graal routing: nothing runs clientside from this call.

NpcThis interface ​

ts
interface NpcThis

this inside a clientside NPC handler: this client's copy of the NPC. Writes are local to this client (the server's copy is the authority for everyone else).

NpcThis.id ​

ts
readonly id: number

Runtime id of this NPC (unique per server run).

NpcThis.name ​

ts
readonly name: string

"npc-<id>": a client-side identifier for this NPC.

NpcThis.x ​

ts
x: number

Position in tiles (fractional allowed). Assigning moves the NPC on this client only and cancels any move(). While a move() runs (serverside or clientside) these read the interpolated position.

NpcThis.y ​

ts
y: number

Position in tiles (fractional allowed). Assigning moves the NPC on this client only and cancels any move(). While a move() runs (serverside or clientside) these read the interpolated position.

NpcThis.dir ​

ts
dir: number

Facing: 0 up, 1 left, 2 down, 3 right (Graal convention). Assigning is client-local.

NpcThis.move ​

ts
move(dx: number, dy: number, time: number, options?: number): void

Graal's move(dx, dy, time, options) on THIS client only: glides the NPC by (dx, dy) tiles over time seconds. A later serverside move or position change overrides it.

Options is a bitmask (Graal's move flags; combine with |):

ts
1  cache      — queue behind the moves already pending instead of
                replacing them (without it, pending moves are dropped
                and this one starts from the current position)
2  append     — dx/dy are measured from the end of the queued path
                instead of the current position
4  blockcheck — stop at the last clear spot when the NPC would walk
                into a wall (a character NPC's walking footprint, else
                its shape/image); drops the rest of the queue
8  onMovementFinished fires when this move ends (reached or blocked)
16 apply direction — face the move's dominant axis when it starts

time <= 0 moves instantly (on the next update). Assigning x or y cancels every pending move.

NpcThis.image ​

ts
image: string

Asset-relative image, e.g. "images/sign.png". '' = invisible (unless showCharacter).

NpcThis.chat ​

ts
chat: string

Chat bubble text on this client ('' clears it).

NpcThis.head ​

ts
head: string

Appearance when rendered as a character ('' = the gani defaults).

NpcThis.body ​

ts
body: string

Appearance when rendered as a character ('' = the gani defaults).

NpcThis.colors ​

ts
colors: string[]

Body colors as 'r,g,b' strings, like player.colors: [0] skin, [1] coat, [2] sleeves, [3] shoes, [4] belt. Assigning an index or an array changes them on this client only (batched like the other props); invalid indices or values are ignored.

NpcThis.ani ​

ts
ani: string

Current animation name; only visible after showCharacter().

NpcThis.showCharacter ​

ts
showCharacter(): void

Renders the NPC as a gani character (idle) on this client only.

NpcThis.setAni ​

ts
setAni(name: string): void

Plays an animation on this NPC on this client only.

NpcThis.dontblock ​

ts
dontblock(): void

Graal dontblock() on THIS client only: the local player and this client's NPC moves pass through it. The serverside this.dontblock() applies for everyone (and overrides this on its next change).

NpcThis.blockagain ​

ts
blockagain(): void

Graal blockagain() on this client only: undoes dontblock().

NpcThis.blocking ​

ts
readonly blocking: boolean

False after dontblock() (this client's view).

NpcThis.setShape ​

ts
setShape(x: number, y: number, w: number, h: number): void

Sets this client's copy of the trigger hitbox: offset and size in PIXELS relative to the NPC's top-left. Note the server hit-tests its OWN shapes for triggerAction, so a client-local setShape does not change what triggers hit.

NpcThis.drawaslight ​

ts
drawaslight(): void

Marks this NPC as a light source on this client. Only visible while the ambient light is below full (see setambient) unless lightmode is 1. The light follows this.x/y, and blocking (type-22) tiles eat it far faster than air, so walls cast shadows. One-way like showCharacter(); turn the light off with this.lightintensity = 0.

NpcThis.lightcolor ​

ts
lightcolor: string

Light color as 'r,g,b' (0-255 each). Default '255,255,255'.

NpcThis.lightintensity ​

ts
lightintensity: number

Brightness at the source: 1 = full. Values above 1 overdrive the core so full brightness extends further out (the lightmap clamps at 1). Default 1, max 10.

NpcThis.lightradius ​

ts
lightradius: number

Distance in tiles at which the light fades out in open air. Default 8, max 48.

NpcThis.lightshape ​

ts
lightshape: string

Falloff shape of the light. Default 'circle'.

ts
'circle'  — round glow
'diamond' — pointed on the axes
'square'  — even brightness out to a square edge
'cone'    — directional wedge, aimed with lightdir/lightarc
'ring'    — glowing band at ~2/3 radius, dark center

Every shape is still blocked by walls.

NpcThis.lightdir ​

ts
lightdir: number

Cone aim in degrees: 0 = up, 90 = right (clockwise). Default 0.

NpcThis.lightarc ​

ts
lightarc: number

Cone width in degrees (the full wedge). Default 90, max 360.

NpcThis.lightmode ​

ts
lightmode: number

0 (default): the light only shows where setambient has darkened the world. 1: the light is also drawn as an additive glow on top of the scene, the

ts
same by day or night, so it stays visible at full ambient. At night it
still lights the tiles under it like mode 0. Additive saturates fast:
use a lower lightintensity (0.3-0.6) for a subtle daytime glow.

NpcThis.join ​

ts
join(name: string): boolean

Joins 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.

NpcThis.leave ​

ts
leave(name: string): boolean

Removes a joined class's handlers from this script.

NpcThis.joinedclasses ​

ts
readonly joinedclasses: readonly string[]

Currently joined class names, in join order.

NpcThis.[key] ​

ts
[key: string]: any

Anything else is per-NPC script state, kept between handler calls.