Glossary¶
Anomaly modding uses a set of domain-specific terms that appear throughout the codebase. This page defines each one and links to more detailed coverage where it exists.
alife¶
The alife ("artificial life") system is the offline simulation that manages all entities in the game world — squads, NPCs, anomalies, items — even when they are far from the player. When the player is nowhere near an entity, the alife simulator handles it: moving squads between smart terrains, tracking deaths, running timed events.
In scripts, alife() returns the CALifeSimulator singleton — the central registry of all server entities.
See Engine Internals → The alife simulator.
binder¶
See object binder.
callback¶
A callback is a Lua function you register with the engine to be called when a specific event occurs — an NPC dies, the actor fires a weapon, a save is loaded. Anomaly's callback system is managed by axr_main.script via RegisterScriptCallback / UnregisterScriptCallback.
See The Callback System and the Callbacks Reference.
clsid¶
A clsid (class ID) is an integer constant that identifies the C++ type of a game object or server entity. Type-checking in Lua is done by comparing obj:clsid() against constants in the global clsid table (e.g. clsid.script_stalker, clsid.bloodsucker). The _g.script helpers (IsStalker(), IsMonster(), etc.) wrap this pattern.
Server-side entities follow the naming convention clsid.typename_s (e.g. clsid.bloodsucker_s, clsid.online_offline_group_s). Online (client-side) objects use the bare name (e.g. clsid.bloodsucker).
local c = obj:clsid()
if c == clsid.script_stalker or c == clsid.script_actor then
-- human NPC or actor
end
-- The helper functions in _g.script do this for you:
if IsStalker(obj, c) then ... end
community¶
The community is the faction string used in scripts to identify which faction an NPC belongs to. Access it via npc:character_community(). Common values: "stalker", "freedom", "duty", "army", "bandit", "monolith", "csky", "ecolog", "killer".
This is the internal identifier used in config files and condition lists — not the localised display name shown to the player.
condition list¶
A condition list is a declarative mini-language embedded in LTX string fields. It lets AI logic, quest scripts, and NPC behaviour specify conditional transitions without writing Lua code.
The format is:
{...}— conditions evaluated to decide which entry matches- The bare name after
}— the value returned when conditions pass %...%— effects applied when this entry is chosen (optional)
Sigils inside {...} and %...%:
| Sigil | Meaning |
|---|---|
+info_id |
Actor must have this info_portion |
-info_id |
Actor must not have this info_portion |
=func(args) |
Call xr_conditions.func() — must return true |
!func(args) |
Call xr_conditions.func() — must return false |
~N |
Random: N% probability |
+info_id in %...% |
Give this info_portion as a side-effect |
-info_id in %...% |
Remove this info_portion |
=func(args) in %...% |
Call xr_effects.func() as a side-effect |
Multiple entries are chained with commas — the first entry whose conditions all pass is used:
; Switch to "sr_idle@timer" if both info_portions are set
on_info = {+base_defense_enemy_1_killed +base_defense_enemy_2_killed} sr_idle@timer
; Call a Lua function as a condition
on_info = {=surge_started} walker@surge, {=is_night} walker@sleep
Condition lists are parsed once at load by xr_logic.parse_condlist() and evaluated by xr_logic.pick_section_from_condlist().
db.actor¶
db.actor is the game_object for the player's character. It is available from the actor_on_first_update callback onward and is nil before the first update tick.
See db.actor reference.
db.storage¶
db.storage is a global Lua table that maps online object IDs to per-object state tables. Object binders populate it when entities come online and clean it up when they go offline.
See What is db.storage?.
gamedata¶
gamedata is the directory that holds all modifiable game assets — scripts, configs, textures, sounds, UI definitions. Anomaly loads files from gamedata/ in preference to the base archives. Mods ship their files inside a gamedata/ subfolder within their archive.
See Gamedata Structure.
game_object¶
A game_object is the Lua-side handle to an entity that is currently online (loaded near the player). It provides the full runtime API: position, animation, physics, AI state, and inventory. When an entity goes offline, its game_object is destroyed — any stored reference becomes stale.
game graph¶
The game graph is the global alife navigation graph that connects all levels. Each node is a game_vertex_id, and each vertex belongs to some level.
The engine uses the game graph for cross-level simulation decisions (for example, routing squads and tracking entities that move between maps). Server entities store a game-graph anchor so alife can reason about them even when they are offline.
When spawning with alife():create(section, pos, lvid, gvid), gvid is the node in this graph.
game_vertex_id¶
A game vertex is a node in the global navigation graph that spans all levels. Unlike level vertices (which are local to one map), game vertices allow the alife simulation to track entities across level boundaries. Access via obj:game_vertex_id() or se_obj.m_game_vertex_id.
game_vertex_id() (method)¶
obj:game_vertex_id() returns the object's current game_vertex_id: a node in the global cross-level graph.
When calling alife():create(section, pos, lvid, gvid), the gvid argument is this global graph anchor. It is not ownership metadata; it does not mean the spawned object belongs to the source object.
For spawned entities, scripts often use db.actor:game_vertex_id() as a convenient valid gvid when the actor is online.
info_portion¶
An info_portion is a named boolean flag attached to the actor. It is either set or unset — there is no associated value. Info_portions are the primary mechanism for tracking quest state, dialog history, and one-time events.
db.actor:give_info_portion("my_quest_started") -- set the flag
db.actor:has_info("my_quest_started") -- check (returns bool)
db.actor:disable_info_portion("my_quest_started") -- unset the flag
Info_portions are declared in XML files under configs/gameplay/ (e.g. info_portions.xml). They appear as +name / -name sigils inside condition list blocks, and as <has_info> / <dont_has_info> / <give_info> tags in dialog XML files.
level_vertex_id¶
A level vertex is a node in the level graph for the current level. obj:level_vertex_id() returns the ID of the navmesh node nearest to the object.
level graph¶
The level graph is the per-map AI navigation graph (navmesh) for one level only. Its nodes are level_vertex_id values that represent walkable locations on that map.
AI pathfinding within the currently loaded level uses this graph. Unlike the game graph, level-graph IDs are only meaningful inside that one map and cannot be used across levels.
level.vertex_id(pos)¶
level.vertex_id(pos) returns the level_vertex_id nearest to pos on the current map.
This is commonly used when spawning server entities:
local pos = vector():set(x, y, z)
local lvid = level.vertex_id(pos) -- map-local navmesh node
local gvid = db.actor:game_vertex_id() -- global graph node
local se = alife():create(section, pos, lvid, gvid)
alife():create expects both IDs:
lvidplaces the entity on the current level graph.gvidregisters the entity in the global game graph.
modded exes¶
The modded exes are a community-maintained fork of the Anomaly engine by themrdemonized. They add Lua callbacks not present in vanilla Anomaly (actor_on_weapon_fired, npc_shot_dispersion, bullet_on_hit, on_xml_read, and several actor_on_before_* / npc_on_before_* variants), the game_object:is_valid() method, memory optimisations, and engine bug fixes.
Source: xray-monolith on GitHub.
Features that require the modded exes are tagged Exes in the Callbacks Reference.
object binder¶
An object binder is a Lua class (inheriting from object_binder) that attaches to a specific game_object and receives per-object lifecycle callbacks: spawn, destroy, per-frame update, save, and load. The base game registers binders for all NPCs, monsters, the actor, helicopters, and anomaly zones.
See Object Binders.
online / offline¶
Every entity in Anomaly exists in one of two states:
- Online — the entity is within simulation distance of the player. A
game_objectexists; the entity has physics, AI, and render presence. - Offline — the entity is beyond the switch distance. Only the server entity exists; it is tracked by the alife simulator with no in-world representation.
The default switch distance is 750m, with a hysteresis gap (online at 675m, offline at 825m) to prevent rapid flickering at the boundary.
See Engine Internals → Online and offline.
section¶
"Section" has two distinct meanings in Anomaly, and both appear frequently in the codebase.
Sense 1 — LTX block: A [section_name] block in an LTX file. It is a named group of key-value pairs that defines something — an item, a weapon, a spawn template, AI logic. Example:
Sense 2 — entity config type: The config-section name of a specific object — the string returned by obj:section(). Every instance of a medkit returns "medkit" from obj:section(). This string is what you use to look up config data, check item type, or classify objects in script:
In both senses, a section is an identifier that maps to a block of config data. When reading code, "the object's section" usually means sense 2; "the LTX section" usually means sense 1.
See LTX Format for sense 1, and What is a game_object? for sense 2.
server entity¶
The server entity (Lua base type: se_abstract) is the permanent alife-side record for every entity. It exists from creation until the entity is released, regardless of online/offline state. Access it via alife_object(id). It provides a limited API compared to game_object: section, position, vertex IDs, and spawn data — but no physics, animation, or inventory.
See What is a game_object? → Client vs server.
smart terrain¶
A smart terrain is a named alife zone that owns a set of jobs — scripted activities such as patrolling, sitting at a campfire, standing guard, or manning a post. NPCs do not pick destinations independently; the simulation board assigns squads to smart terrains, and the terrain assigns each NPC to one of its jobs.
From a modding perspective, smart terrains define where NPCs go and what they do when they get there. A terrain's LTX config specifies max_population, faction restrictions, job definitions (patrol paths, idle animations, etc.), and optional respawn behaviour.
Access from scripts: db.smart_terrain_by_id[id] returns the server entity.
See Smart Terrains for the full system walkthrough.
squad¶
A squad is the atomic unit of NPC grouping in the alife simulation. It is a server-side object (sim_squad_scripted) that owns one or more NPC server entities and moves as a unit between smart terrains. Individual NPCs do not navigate the alife simulation independently — their squad does.
Squads have a faction, a current smart terrain, and a target smart terrain (evaluated as a condition list). Members are iterated with for k in squad:squad_members() do — k.id is the alife ID of each NPC server entity.
-- Find a named squad and iterate its members
local squad = get_story_squad("my_named_squad")
if squad then
for k in squad:squad_members() do
local npc = level.object_by_id(k.id) -- nil if offline
if npc then
-- do something with the online NPC
end
end
end
story_id¶
A story_id is a stable, human-readable string alias permanently bound to a specific alife entity — an NPC, squad, item, or smart terrain. Because numeric alife IDs are volatile (they can be reused across saves), story_ids are the correct way to reference specific named entities across save/load boundaries.
Story_ids are declared in spawn config LTX files:
Lookup functions in _g.script:
get_story_se_object("bar_barman") -- server entity (always available)
get_story_object("bar_barman") -- game_object (nil if offline)
get_story_object_id("bar_barman") -- numeric alife ID
get_object_story_id(obj_id) -- reverse lookup: numeric ID → story_id string
Story_ids must be globally unique across all mods. If two objects claim the same story_id, story_objects.script logs a warning and the second registration wins.