Skip to content
Lucent
Esc
↑↓navigate↵open
On this page

api.events

Events you can listen for

Event When it happens
aura-added An aura is added to or refreshed on a player or monster.
aura-removed An aura is removed from a player or monster.
counter-attack-end A monster’s counter attack ends.
counter-attack-start A monster’s counter attack starts.
item-drop An item drops.
join-map A map finishes loading.
login A game session starts.
logout A game session ends.
monster-death A monster dies.
monster-respawn A monster respawns.
player-afk A player goes AFK or comes back.
player-death A player dies.
player-location A player’s location changes.
players-changed A player joins or leaves the current map.
quest-complete A quest turn-in succeeds.
update-message A yellow combat message appears.
zone The current map’s encounter zone changes.

Event details

Each event includes the information shown below.

aura-added

An aura is added to or refreshed on a player or monster.

{
  readonly type: "aura-added";
  /** The aura duration in seconds, when available. */
  readonly duration?: number;
  readonly icon?: string;
  readonly name: string;
  /** The applying entity's map-scoped ID, when known. */
  readonly sourceId?: number;
  readonly sourceType?: "monster" | "player";
  /** The affected entity's map-scoped ID. */
  readonly targetId: number;
  readonly targetType: "monster" | "player";
}

aura-removed

An aura is removed from a player or monster.

{
  readonly type: "aura-removed";
  /** The aura duration in seconds, when available. */
  readonly duration?: number;
  readonly icon?: string;
  readonly name: string;
  /** The applying entity's map-scoped ID, when known. */
  readonly sourceId?: number;
  readonly sourceType?: "monster" | "player";
  /** The affected entity's map-scoped ID. */
  readonly targetId: number;
  readonly targetType: "monster" | "player";
}

counter-attack-end

A monster’s counter attack ends.

{
  readonly type: "counter-attack-end";
  /** The monster's map-scoped ID. */
  readonly monsterMapId: number;
  /** Where the trigger was detected. */
  readonly source: "aura" | "message";
  /** A stable identifier for the recognized trigger. */
  readonly triggerId: string;
  /** The aura name or combat message that matched the trigger. */
  readonly triggerText: string;
}

counter-attack-start

A monster’s counter attack starts.

{
  readonly type: "counter-attack-start";
  /** The expected window duration in milliseconds, when known. */
  readonly durationMs?: number;
  /** The monster's map-scoped ID. */
  readonly monsterMapId: number;
  /** Where the trigger was detected. */
  readonly source: "aura" | "message";
  /** A stable identifier for the recognized trigger. */
  readonly triggerId: string;
  /** The aura name or combat message that matched the trigger. */
  readonly triggerText: string;
}

item-drop

An item drops.

{
  readonly type: "item-drop";
  readonly item: ItemSnapshot;
}

join-map

A map finishes loading.

{
  readonly type: "join-map";
  readonly map: { readonly id: number; readonly name: string; readonly roomNumber: number; };
}

login

A game session starts.

{
  readonly type: "login";
}

logout

A game session ends.

{
  readonly type: "logout";
}

monster-death

A monster dies.

{
  readonly type: "monster-death";
  readonly monsterMapId: number;
}

monster-respawn

A monster respawns.

{
  readonly type: "monster-respawn";
  readonly monsterMapId: number;
}

player-afk

A player goes AFK or comes back.

{
  readonly type: "player-afk";
  readonly afk: boolean;
  readonly entityId: number;
  readonly username: string;
}

player-death

A player dies.

{
  readonly type: "player-death";
  readonly entityId: number;
  readonly username: string;
}

player-location

A player’s location changes.

{
  readonly type: "player-location";
  readonly cell: string;
  readonly entityId: number;
  readonly pad: string;
  /** The latest known coordinates for the player. */
  readonly position: { readonly x: number; readonly y: number; };
  readonly username: string;
  /** The destination reported by a complete walk update. */
  readonly destination: { readonly x: number; readonly y: number; };
  readonly kind: "walk";
} | {
  readonly type: "player-location";
  readonly cell: string;
  readonly entityId: number;
  readonly pad: string;
  /** The latest known coordinates for the player. */
  readonly position: { readonly x: number; readonly y: number; };
  readonly username: string;
  /** `position` reports coordinates; `cell` reports only cell/pad. */
  readonly kind: "cell" | "position";
}

players-changed

A player joins or leaves the current map.

{
  readonly type: "players-changed";
}

quest-complete

A quest turn-in succeeds.

{
  readonly type: "quest-complete";
  readonly questId: number;
}

update-message

A yellow combat message appears.

{
  readonly type: "update-message";
  /** The animation's `animStr`, when present. */
  readonly animation?: string;
  readonly message: string;
  /** The related monster's map-scoped ID, when the message names one. */
  readonly monsterMapId?: number;
  readonly source: "animation" | "aura";
}

zone

The current map’s encounter zone changes.

{
  readonly type: "zone";
  readonly map: string;
  readonly zone: string;
}

Members

api.events.on()

Runs a handler for every matching event. The handler must return an Effect or generator; plain values and Promises are not supported.

Call the returned function to stop listening early. The subscription is also removed automatically when the script stops.

api.events.on<const T extends ScriptEventType>(query: ScriptEventSelectorForType<T>, handler: (event: ScriptEventForType<T>) => ScriptCallbackResult): Effect.Effect<() => void, never, never>
api.events.on(query: undefined, handler: (event: ScriptEvent) => ScriptCallbackResult): Effect.Effect<() => void, never, never>
api.events.on(query: ProjectionEventSelector | undefined, handler: (event: ScriptEvent) => ScriptCallbackResult): Effect.Effect<() => void, never, never>
Name Type Required Default Description
query ProjectionEventSelector | undefined
handler (event: ScriptEvent) => ScriptCallbackResult

Returns: () => void

Errors: never

Example

const script = require("lucent/script");

const unsubscribe = yield* api.events.on(
  { type: "monster-death" },
  function* (event) {
    yield* script.log(`Monster ${event.monsterMapId} died.`);
  },
);

yield* script.sleep("30 seconds");
unsubscribe();

api.events.once()

Waits for the next matching event. With a trigger, starts listening before running that action so an immediate event is not missed.

Returns null if the trigger returns false or the wait times out. The timeout starts after the trigger finishes; omitting it waits indefinitely. Timing out stops the wait but does not undo the action started by the trigger.

api.events.once<const T extends ScriptEventType, E = never, R = never>(query: ScriptEventSelectorForType<T>, options?: TriggeredWaitOptions<E, R> | undefined): Effect.Effect<ScriptEventForType<T> | null, E, Exclude<R, Scope.Scope>>
api.events.once<E = never, R = never>(selector?: ProjectionEventSelector | undefined, options?: TriggeredWaitOptions<E, R> | undefined): Effect.Effect<ProjectionEvent | null, E, Exclude<R, Scope.Scope>>
Name Type Required Default Description
selector ProjectionEventSelector | undefined
options TriggeredWaitOptions<E, R> | undefined

Returns: ScriptEvent | null

Errors: E

Example

const script = require("lucent/script");

const [monster] = yield* api.monsters.getAvailable();
if (monster !== undefined) {
  const death = yield* api.events.once(
    { type: "monster-death", monsterMapId: monster.monsterMapId },
    {
      trigger: api.combat.attack(monster.monsterMapId),
      timeout: "30 seconds",
    },
  );
  yield* api.combat.cancelAutoAttack();

  if (death === null) {
    yield* script.log("Attack failed or the monster did not die in time.");
  }
}
Type preview
Open page

Last updated on September 26, 2026

Was this page helpful?