Skip to content

API Reference

github-actions[bot] edited this page Sep 27, 2026 · 9 revisions

API Reference — Gearbox v1.3

Generated from sdk/abi.json, which is checked against the host's own capability table by tests/mod_abi_test.cpp. If a language binding disagrees with this page, the binding is wrong.

Strings are (ptr, len) pairs of UTF-8 bytes in your linear memory. They are not null-terminated, and the host never keeps a pointer into your memory after a call returns.

Index

Core

Import module gearbox:core. Always granted; cannot be revoked.

log

(import "gearbox:core" "log" (func (param i32 i32 i32)))
Parameter Type
level i32
msg i32 pointer into your memory
msg_len i32 byte length

Returns: nothing

Write a line to the game log and the mod menu's log view. Messages longer than 2048 bytes are truncated. An out-of-bounds (ptr,len) is refused and logged as an error against your mod rather than read.

env

(import "gearbox:core" "env" (func (param i32)))
Parameter Type
out i32 pointer into your memory

Returns: nothing

Fill a gearbox_env_t. Write your own sizeof into out->size FIRST; the host writes at most that many bytes, so an older mod stays safe against a newer host. If size is 0 or larger than the host's struct, the host uses its own size.

abort

(import "gearbox:core" "abort" (func (param i32 i32)))
Parameter Type
msg i32 pointer into your memory
msg_len i32 byte length

Returns: nothing — does not return, traps your mod.

Unrecoverable error. Traps out of the current call, disables the mod, and shows the message to the user. Prefer returning an error from a hook where you can.

fuel_budget

(import "gearbox:core" "fuel_budget" (func (result i64)))

Returns: i64

The instruction budget for the current hook, or 0xFFFFFFFFFFFFFFFF when unmetered. This is the LIMIT, not a live countdown: it does not decrease as you run. Use it to size your work up front and count your own iterations.

GameState.Read

Import module gearbox:gamestate.read. Requires the GameState.Read capability in your manifest.

turn_number

(import "gearbox:gamestate.read" "turn_number" (func (result i32)))

Returns: i32

The current turn. 0 when no world is loaded.

country_count

(import "gearbox:gamestate.read" "country_count" (func (result i32)))

Returns: i32

How many countries exist. 0 when no world is loaded. Rebel factions are not included.

country_at

(import "gearbox:gamestate.read" "country_at" (func (param i32) (result i32)))
Parameter Type
index i32

Returns: i32

The country at index in [0, country_count). Returns GEARBOX_INVALID (0xFFFFFFFF) if out of range. Ordering is stable within a turn but not across turns.

country_name

(import "gearbox:gamestate.read" "country_name" (func (param i32 i32 i32) (result i32)))
Parameter Type
country i32 opaque country handle
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

Two-call sizing. Writes at most cap bytes of UTF-8 and returns the FULL length. Call with cap 0 to size, then again to fill. A return greater than cap means truncation, not failure. Returns 0 for an unknown country.

country_treasury

(import "gearbox:gamestate.read" "country_treasury" (func (param i32) (result f64)))
Parameter Type
country i32 opaque country handle

Returns: f64

Treasury balance. 0 for an unknown country.

country_province_count

(import "gearbox:gamestate.read" "country_province_count" (func (param i32) (result i32)))
Parameter Type
country i32 opaque country handle

Returns: i32

How many provinces the country owns. 0 for an unknown country.

province_population

(import "gearbox:gamestate.read" "province_population" (func (param i32) (result i64)))
Parameter Type
province i32 opaque province handle

Returns: i64

Population of a province. 0 for an unknown province.

province_owner

(import "gearbox:gamestate.read" "province_owner" (func (param i32) (result i32)))
Parameter Type
province i32 opaque province handle

Returns: i32

Owning country, or GEARBOX_INVALID if unowned or unknown.

province_monument

(import "gearbox:gamestate.read" "province_monument" (func (param i32) (result i32)))
Parameter Type
province i32

Returns: i32

Which monument stands in a province, as a monument_kind, or -1 for none. One per province is the rule. A map script gets the key instead (province..monument), because a script is text.

province_monument_level

(import "gearbox:gamestate.read" "province_monument_level" (func (param i32) (result i32)))
Parameter Type
province i32

Returns: i32

The level of the monument in a province, 1 upwards, or 0 when there is none.

province_monument_active

(import "gearbox:gamestate.read" "province_monument_active" (func (param i32) (result i32)))
Parameter Type
province i32

Returns: i32

1 when the monument is switched on and so taking one of the country's paid slots, 0 when it is off or absent. An inactive monument has no effect at all.

country_exists

(import "gearbox:gamestate.read" "country_exists" (func (param i32) (result i32)))
Parameter Type
country i32 opaque country handle

Returns: i32

Whether a country id names a country that exists. A mod holding an id from its own storage, a save, or a previous turn has no other way to ask before using it -- a country can be annexed between turns, and every other accessor answers 0 or an empty string for a dead id, which is indistinguishable from a live country with nothing in it.

province_exists

(import "gearbox:gamestate.read" "province_exists" (func (param i32) (result i32)))
Parameter Type
province i32 opaque province handle

Returns: i32

Whether a province id names a province that exists. Same reason as country_exists: a stored id needs a validity check that is not 'iterate every province and compare'.

UI

Import module gearbox:ui. Requires the UI capability in your manifest.

panel_register

(import "gearbox:ui" "panel_register" (func (param i32 i32 i32 i32) (result i32)))
Parameter Type
title i32 pointer into your memory
title_len i32 byte length
min_w i32
min_h i32

Returns: i32

Register a panel and return its handle. Returns 0 (invalid) when headless or when you already hold 8 panels. NOT when UI is revoked: a module that imports gearbox:ui is refused at instantiation, so a mod whose UI the user revoked does not load at all and this never runs. Titles are truncated to 64 bytes. Call this from mod_load, not from your draw hook.

draw_rect

(import "gearbox:ui" "draw_rect" (func (param i32 i32 i32 i32 i32 i32)))
Parameter Type
panel i32 opaque panel handle
x i32
y i32
w i32
h i32
rgba i32 0xRRGGBBAA

Returns: nothing

Filled rectangle in panel-relative coordinates. Colour is 0xRRGGBBAA. Coordinates outside the panel are clipped by the host; they cannot escape it.

draw_text

(import "gearbox:ui" "draw_text" (func (param i32 i32 i32 i32 i32 i32)))
Parameter Type
panel i32 opaque panel handle
x i32
y i32
rgba i32 0xRRGGBBAA
text i32 pointer into your memory
text_len i32 byte length

Returns: nothing

UTF-8 text in panel-relative coordinates. Truncated to 512 bytes per call.

button

(import "gearbox:ui" "button" (func (param i32 i32 i32 i32 i32 i32 i32) (result i32)))
Parameter Type
panel i32 opaque panel handle
x i32
y i32
w i32
h i32
label i32 pointer into your memory
label_len i32 byte length

Returns: i32

Immediate-mode button: draws it and returns 1 on the frame it is clicked. One click activates one button -- the host consumes it, so overlapping rects do not all fire. Label truncated to 64 bytes.

draw_line

(import "gearbox:ui" "draw_line" (func (param i32 i32 i32 i32 i32 f64 i32)))
Parameter Type
panel i32 opaque panel handle
x1 i32
y1 i32
x2 i32
y2 i32
thickness f64
rgba i32

Returns: nothing

Queue a line from (x1,y1) to (x2,y2) in panel-relative pixels. Thickness is clamped to 0.25..64. Clipped to your panel like every other command.

draw_circle

(import "gearbox:ui" "draw_circle" (func (param i32 i32 i32 f64 i32)))
Parameter Type
panel i32 opaque panel handle
cx i32
cy i32
radius f64
rgba i32

Returns: nothing

Queue a filled circle centred at (cx,cy), panel-relative. Radius is clamped to 0..4096.

draw_image

(import "gearbox:ui" "draw_image" (func (param i32 i32 i32 i32 i32 i32 i32 i32)))
Parameter Type
panel i32 opaque panel handle
x i32
y i32
w i32
h i32
name i32 pointer into your memory
name_len i32 byte length
tint i32

Returns: nothing

Queue an image from YOUR OWN package -- name is a path inside your .odmod, resolved exactly as gearbox:assets/read resolves it, so you cannot name a file on disk, a game asset, or another mod's art. Pass w or h as 0 to use the image's own size. tint 0xFFFFFFFF draws it unmodified. Decoded once and cached; a name that fails to decode draws nothing and does not retry. PNG, JPG, BMP, TGA and GIF are recognised by extension. This is the call that makes a real reskin possible.

draw_text_sized

(import "gearbox:ui" "draw_text_sized" (func (param i32 i32 i32 i32 i32 i32 i32)))
Parameter Type
panel i32 opaque panel handle
x i32
y i32
size i32
rgba i32
text i32 pointer into your memory
text_len i32 byte length

Returns: nothing

Like draw_text but with a type size, clamped to 6..96. draw_text remains 14pt, unchanged, so v1.0 mods look exactly as they did.

measure_text

(import "gearbox:ui" "measure_text" (func (param i32 i32 i32) (result i32)))
Parameter Type
text i32 pointer into your memory
text_len i32 byte length
size i32

Returns: i32

Width in pixels of text at size, measured with the font the game will actually draw. Centring, right-alignment and wrapping all need this before the text is queued.

panel_width

(import "gearbox:ui" "panel_width" (func (param i32) (result i32)))
Parameter Type
panel i32 opaque panel handle

Returns: i32

The width the host assigned your panel this frame, in pixels. Lay out against this rather than against min_w -- the host may have given you more.

panel_height

(import "gearbox:ui" "panel_height" (func (param i32) (result i32)))
Parameter Type
panel i32 opaque panel handle

Returns: i32

The height the host assigned your panel this frame, in pixels.

panel_set_visible

(import "gearbox:ui" "panel_set_visible" (func (param i32 i32)))
Parameter Type
panel i32 opaque panel handle
visible i32 0 or 1

Returns: nothing

Show or hide one of your panels. A hidden panel is not drawn and receives no input, but keeps its handle and its registration.

mouse_x

(import "gearbox:ui" "mouse_x" (func (param i32) (result f64)))
Parameter Type
panel i32 opaque panel handle

Returns: f64

Cursor X, panel-relative, or 0 when the cursor is not over your panel. You cannot observe the pointer outside your own box.

mouse_y

(import "gearbox:ui" "mouse_y" (func (param i32) (result f64)))
Parameter Type
panel i32 opaque panel handle

Returns: f64

Cursor Y, panel-relative, or 0 when the cursor is not over your panel.

mouse_inside

(import "gearbox:ui" "mouse_inside" (func (param i32) (result i32)))
Parameter Type
panel i32 opaque panel handle

Returns: i32

Whether the cursor is over your panel this frame.

theme_accent

(import "gearbox:ui" "theme_accent" (func (result i32)))

Returns: i32

The PLAYER's accent colour as 0x00RRGGBB -- not another mod's override. Build your palette around this and you harmonise with what they chose.

set_theme_accent

(import "gearbox:ui" "set_theme_accent" (func (param i32) (result i32)))
Parameter Type
rgb i32

Returns: i32

Restyle the whole interface. The accent is read at over a hundred sites -- every heading, highlight, selection and button -- so this is the cheapest full reskin there is. It is NOT persisted: the game's settings file keeps the player's own colour, and the override is dropped the moment no mod is running, so it cannot outlive uninstalling you.

Assets

Import module gearbox:assets. Requires the Assets capability in your manifest.

size

(import "gearbox:assets" "size" (func (param i32 i32) (result i32)))
Parameter Type
name i32 pointer into your memory
name_len i32 byte length

Returns: i32

Byte size of one of your own data/ files, or 0 if there is no such asset. Names are relative to data/ and use '/' separators: data/flags/fr.png is "flags/fr.png".

read

(import "gearbox:assets" "read" (func (param i32 i32 i32 i32) (result i32)))
Parameter Type
name i32 pointer into your memory
name_len i32 byte length
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

Two-call sizing, like country_name. Writes at most cap bytes and returns the asset's full size. The name is looked up in your package's entry list, never resolved as a filesystem path.

Audio

Import module gearbox:audio. Requires the Audio capability in your manifest.

play

(import "gearbox:audio" "play" (func (param i32 i32 f32) (result i32)))
Parameter Type
path i32 pointer into your memory
path_len i32 byte length
volume f32

Returns: i32

Play a sound from your own mod's assets. path is relative to your mod root; a path outside it is refused rather than resolved. Volume is 0..1 and is multiplied by the player's own effects setting, so a mod cannot be louder than they allowed. Returns a handle, or 0 if it could not be played.

stop

(import "gearbox:audio" "stop" (func (param i32)))
Parameter Type
handle i32

Returns: nothing

Stop a sound this mod started. A handle belonging to another mod, or one that already finished, does nothing.

set_volume

(import "gearbox:audio" "set_volume" (func (param i32 f32)))
Parameter Type
handle i32
volume f32

Returns: nothing

Change the volume of a playing sound, 0..1, again scaled by the player's setting.

is_playing

(import "gearbox:audio" "is_playing" (func (param i32) (result i32)))
Parameter Type
handle i32

Returns: i32

Whether that handle is still making sound.

Net

Import module gearbox:net. Requires the Net capability in your manifest.

send

(import "gearbox:net" "send" (func (param i32 i32 i32) (result i32)))
Parameter Type
peer i32
data i32 pointer into your memory
data_len i32 byte length

Returns: i32

Send a message to the same mod running on another peer. peer is a peer id -- the value recv reported in from_peer -- and -1 broadcasts to every other peer, the host included. There is no fixed id for the host: a host that plays holds an ordinary seat, and a dedicated one holds none. The host stamps your mod id on the message, so you cannot send as another mod, and it never carries game traffic: orders, deltas and chat do not travel here. Messages larger than 8192 bytes are refused. Returns 0 if this is not a network game, or the message was too large.

recv

(import "gearbox:net" "recv" (func (param i32 i32 i32) (result i32)))
Parameter Type
out i32 pointer into your memory
out_len i32 byte length
from_peer i32 pointer into your memory

Returns: i32

Take the next message addressed to this mod, writing it into out and the sender's peer id into from_peer. Returns the number of bytes written, or 0 when the queue is empty. A message longer than out_len is truncated rather than dropped, so a small buffer loses data instead of stalling the queue.

peer_count

(import "gearbox:net" "peer_count" (func (result i32)))

Returns: i32

How many players this session has, a playing host included. 0 when this is not a network game, which is how a mod tells the difference. Spectators are not counted.

self_peer

(import "gearbox:net" "self_peer" (func (result i32)))

Returns: i32

This machine's own peer id. 0 means this is not a network game, or this is a dedicated host holding no seat -- a host that plays has an ordinary peer id like anyone else, so do not use this to tell host from client. is_host is that question.

is_host

(import "gearbox:net" "is_host" (func (result i32)))

Returns: i32

Whether this copy is the authoritative one. A mod that computes anything the game depends on must do it here and send the result, not compute it separately on each machine.

peer_at

(import "gearbox:net" "peer_at" (func (param i32) (result i32)))
Parameter Type
index i32

Returns: i32

The peer id at index in 0..peer_count-1, or 0xFFFFFFFF past the end. This is the id net/send takes.

peer_name

(import "gearbox:net" "peer_name" (func (param i32 i32 i32) (result i32)))
Parameter Type
index i32
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

That peer's display name -- deliberately NOT their account id or issuer. A mod has no business correlating players across sessions. Two-call sizing: call with cap 0 to learn the length, allocate, call again. Returns the full length either way; the copy is truncated to cap.

max_message_bytes

(import "gearbox:net" "max_message_bytes" (func (result i32)))

Returns: i32

The largest payload net/send will accept. Chunk against this rather than discovering the limit by having a message dropped.

WasiStub

Import module wasi_snapshot_preview1. Requires the WasiStub capability in your manifest.

fd_write

(import "wasi_snapshot_preview1" "fd_write" (func (param i32 i32 i32 i32) (result i32)))
Parameter Type
fd i32
iovs i32
iovs_len i32
nwritten i32

Returns: i32

Writes to fd 1 or 2 only, and the bytes go to the mod log where the user can see them. Any other fd returns EBADF. This is how print() in an interpreted mod reaches you.

proc_exit

(import "wasi_snapshot_preview1" "proc_exit" (func (param i32)))
Parameter Type
code i32

Returns: nothing

Traps the mod. A runtime calling exit() must not return into code that believes the process is gone.

random_get

(import "wasi_snapshot_preview1" "random_get" (func (param i32 i32) (result i32)))
Parameter Type
buf i32
buf_len i32

Returns: i32

DETERMINISTIC pseudo-random bytes, seeded from your mod id -- not OS entropy. Real entropy is a machine fingerprint and would make self-play and save replay irreproducible. Two mods get different streams; one mod gets the same stream every run. Do not use for anything security-relevant.

clock_time_get

(import "wasi_snapshot_preview1" "clock_time_get" (func (param i32 i64 i32) (result i32)))
Parameter Type
clock_id i32
precision i64
time i32

Returns: i32

Returns the turn number expressed as nanoseconds, not the wall clock. Monotonic and coarse. A mod cannot learn the real date, the timezone, or how long anything took -- all of which are fingerprints.

environ_sizes_get

(import "wasi_snapshot_preview1" "environ_sizes_get" (func (param i32 i32) (result i32)))
Parameter Type
count i32
buf_size i32

Returns: i32

Always reports zero variables. There is no environment.

environ_get

(import "wasi_snapshot_preview1" "environ_get" (func (param i32 i32) (result i32)))
Parameter Type
environ i32
buf i32

Returns: i32

No-op; there is no environment to write.

args_sizes_get

(import "wasi_snapshot_preview1" "args_sizes_get" (func (param i32 i32) (result i32)))
Parameter Type
count i32
buf_size i32

Returns: i32

Always reports zero arguments. Reports success rather than failing, because runtimes commonly abort at startup if argv cannot be read.

args_get

(import "wasi_snapshot_preview1" "args_get" (func (param i32 i32) (result i32)))
Parameter Type
argv i32
buf i32

Returns: i32

No-op; there are no arguments.

fd_close

(import "wasi_snapshot_preview1" "fd_close" (func (param i32) (result i32)))
Parameter Type
fd i32

Returns: i32

EBADF. There are no real descriptors.

fd_fdstat_get

(import "wasi_snapshot_preview1" "fd_fdstat_get" (func (param i32 i32) (result i32)))
Parameter Type
fd i32
stat i32

Returns: i32

ENOTCAPABLE.

fd_prestat_get

(import "wasi_snapshot_preview1" "fd_prestat_get" (func (param i32 i32) (result i32)))
Parameter Type
fd i32
prestat i32

Returns: i32

ENOTCAPABLE. No preopened directories, so no filesystem root exists to walk.

fd_prestat_dir_name

(import "wasi_snapshot_preview1" "fd_prestat_dir_name" (func (param i32 i32 i32) (result i32)))
Parameter Type
fd i32
path i32
path_len i32

Returns: i32

ENOTCAPABLE.

fd_read

(import "wasi_snapshot_preview1" "fd_read" (func (param i32 i32 i32 i32) (result i32)))
Parameter Type
fd i32
iovs i32
iovs_len i32
nread i32

Returns: i32

ENOTCAPABLE. There is no stdin and no file to read.

fd_seek

(import "wasi_snapshot_preview1" "fd_seek" (func (param i32 i64 i32 i32) (result i32)))
Parameter Type
fd i32
offset i64
whence i32
newoffset i32

Returns: i32

EBADF.

path_open

(import "wasi_snapshot_preview1" "path_open" (func (param i32 i32 i32 i32 i32 i64 i64 i32 i32) (result i32)))
Parameter Type
dirfd i32
dirflags i32
path i32
path_len i32
oflags i32
fs_rights_base i64
fs_rights_inheriting i64
fdflags i32
fd i32

Returns: i32

ENOTCAPABLE, always. Opening a file is refused rather than stubbed -- this is the single import that would turn the shim into the hole the sandbox exists to prevent.

clock_res_get

(import "wasi_snapshot_preview1" "clock_res_get" (func (param i32 i32) (result i32)))
Parameter Type
id i32
out i32

Returns: i32

Reports a fixed, coarse resolution matching clock_time_get's one-tick-per-turn granularity. Claiming anything finer would be a lie a runtime might act on.

sched_yield

(import "wasi_snapshot_preview1" "sched_yield" (func (result i32)))

Returns: i32

Succeeds and does nothing. A mod is single-threaded; there is nothing to yield to.

fd_advise

(import "wasi_snapshot_preview1" "fd_advise" (func (param i32 i64 i64 i32) (result i32)))
Parameter Type
fd i32
offset i64
len i64
advice i32

Returns: i32

Refused (EBADF). There is no filesystem.

fd_allocate

(import "wasi_snapshot_preview1" "fd_allocate" (func (param i32 i64 i64) (result i32)))
Parameter Type
fd i32
offset i64
len i64

Returns: i32

Refused (EBADF). There is no filesystem.

fd_datasync

(import "wasi_snapshot_preview1" "fd_datasync" (func (param i32) (result i32)))
Parameter Type
fd i32

Returns: i32

Refused (EBADF). There is no filesystem.

fd_sync

(import "wasi_snapshot_preview1" "fd_sync" (func (param i32) (result i32)))
Parameter Type
fd i32

Returns: i32

Refused (EBADF). There is no filesystem.

fd_fdstat_set_flags

(import "wasi_snapshot_preview1" "fd_fdstat_set_flags" (func (param i32 i32) (result i32)))
Parameter Type
fd i32
flags i32

Returns: i32

Refused (EBADF). There is no filesystem.

fd_filestat_get

(import "wasi_snapshot_preview1" "fd_filestat_get" (func (param i32 i32) (result i32)))
Parameter Type
fd i32
out i32

Returns: i32

Refused (EBADF). File metadata would describe a filesystem the mod cannot reach.

fd_tell

(import "wasi_snapshot_preview1" "fd_tell" (func (param i32 i32) (result i32)))
Parameter Type
fd i32
out i32

Returns: i32

Refused (EBADF). There is no filesystem.

fd_renumber

(import "wasi_snapshot_preview1" "fd_renumber" (func (param i32 i32) (result i32)))
Parameter Type
from i32
to i32

Returns: i32

Refused (EBADF). There are no descriptors to renumber.

fd_filestat_set_size

(import "wasi_snapshot_preview1" "fd_filestat_set_size" (func (param i32 i64) (result i32)))
Parameter Type
fd i32
size i64

Returns: i32

Refused (EBADF). There is no filesystem.

fd_filestat_set_times

(import "wasi_snapshot_preview1" "fd_filestat_set_times" (func (param i32 i64 i64 i32) (result i32)))
Parameter Type
fd i32
atim i64
mtim i64
fst_flags i32

Returns: i32

Refused (EBADF). There is no filesystem.

fd_pread

(import "wasi_snapshot_preview1" "fd_pread" (func (param i32 i32 i32 i64 i32) (result i32)))
Parameter Type
fd i32
iovs i32
iovs_len i32
offset i64
nread i32

Returns: i32

Refused (EBADF). Reading is not provided; assets come from the Assets module instead.

fd_pwrite

(import "wasi_snapshot_preview1" "fd_pwrite" (func (param i32 i32 i32 i64 i32) (result i32)))
Parameter Type
fd i32
iovs i32
iovs_len i32
offset i64
nwritten i32

Returns: i32

Refused (EBADF). A mod cannot write files; use the host log.

fd_readdir

(import "wasi_snapshot_preview1" "fd_readdir" (func (param i32 i32 i32 i64 i32) (result i32)))
Parameter Type
fd i32
buf i32
buf_len i32
cookie i64
bufused i32

Returns: i32

Refused (EBADF). Listing a directory would reveal a filesystem the sandbox denies.

path_create_directory

(import "wasi_snapshot_preview1" "path_create_directory" (func (param i32 i32 i32) (result i32)))
Parameter Type
fd i32
path i32
path_len i32

Returns: i32

Refused (ENOTCAPABLE). There is no filesystem, by design.

path_remove_directory

(import "wasi_snapshot_preview1" "path_remove_directory" (func (param i32 i32 i32) (result i32)))
Parameter Type
fd i32
path i32
path_len i32

Returns: i32

Refused (ENOTCAPABLE). There is no filesystem, by design.

path_unlink_file

(import "wasi_snapshot_preview1" "path_unlink_file" (func (param i32 i32 i32) (result i32)))
Parameter Type
fd i32
path i32
path_len i32

Returns: i32

Refused (ENOTCAPABLE). There is no filesystem, by design.

path_filestat_get

(import "wasi_snapshot_preview1" "path_filestat_get" (func (param i32 i32 i32 i32 i32) (result i32)))
Parameter Type
fd i32
flags i32
path i32
path_len i32
out i32

Returns: i32

Refused (ENOTCAPABLE). Answering would tell a mod whether a path exists on your machine.

path_symlink

(import "wasi_snapshot_preview1" "path_symlink" (func (param i32 i32 i32 i32 i32) (result i32)))
Parameter Type
old_path i32
old_path_len i32
fd i32
new_path i32
new_path_len i32

Returns: i32

Refused (ENOTCAPABLE). There is no filesystem, by design.

path_readlink

(import "wasi_snapshot_preview1" "path_readlink" (func (param i32 i32 i32 i32 i32 i32) (result i32)))
Parameter Type
fd i32
path i32
path_len i32
buf i32
buf_len i32
bufused i32

Returns: i32

Refused (ENOTCAPABLE). There is no filesystem, by design.

path_rename

(import "wasi_snapshot_preview1" "path_rename" (func (param i32 i32 i32 i32 i32 i32) (result i32)))
Parameter Type
fd i32
old_path i32
old_path_len i32
new_fd i32
new_path i32
new_path_len i32

Returns: i32

Refused (ENOTCAPABLE). There is no filesystem, by design.

path_link

(import "wasi_snapshot_preview1" "path_link" (func (param i32 i32 i32 i32 i32 i32 i32) (result i32)))
Parameter Type
old_fd i32
old_flags i32
old_path i32
old_path_len i32
new_fd i32
new_path i32
new_path_len i32

Returns: i32

Refused (ENOTCAPABLE). There is no filesystem, by design.

path_filestat_set_times

(import "wasi_snapshot_preview1" "path_filestat_set_times" (func (param i32 i32 i32 i32 i64 i64 i32) (result i32)))
Parameter Type
fd i32
flags i32
path i32
path_len i32
atim i64
mtim i64
fst_flags i32

Returns: i32

Refused (ENOTCAPABLE). There is no filesystem, by design.

poll_oneoff

(import "wasi_snapshot_preview1" "poll_oneoff" (func (param i32 i32 i32 i32) (result i32)))
Parameter Type
in i32
out i32
nsubscriptions i32
nevents i32

Returns: i32

Refused (ENOTCAPABLE). There is nothing to poll: no files, no sockets, no timers a mod may wait on.

sock_accept

(import "wasi_snapshot_preview1" "sock_accept" (func (param i32 i32 i32) (result i32)))
Parameter Type
fd i32
flags i32
out_fd i32

Returns: i32

Refused (ENOTCAPABLE). A mod has no network access, which is much of the point of the sandbox.

sock_recv

(import "wasi_snapshot_preview1" "sock_recv" (func (param i32 i32 i32 i32 i32 i32) (result i32)))
Parameter Type
fd i32
ri_data i32
ri_data_len i32
ri_flags i32
ro_datalen i32
ro_flags i32

Returns: i32

Refused (ENOTCAPABLE). A mod has no network access.

sock_send

(import "wasi_snapshot_preview1" "sock_send" (func (param i32 i32 i32 i32 i32) (result i32)))
Parameter Type
fd i32
si_data i32
si_data_len i32
si_flags i32
so_datalen i32

Returns: i32

Refused (ENOTCAPABLE). A mod has no network access.

sock_shutdown

(import "wasi_snapshot_preview1" "sock_shutdown" (func (param i32 i32) (result i32)))
Parameter Type
fd i32
how i32

Returns: i32

Refused (EBADF). A mod has no network access.

Storage

Import module gearbox:storage. Requires the Storage capability in your manifest.

get

(import "gearbox:storage" "get" (func (param i32 i32 i32 i32) (result i32)))
Parameter Type
key i32 pointer into your memory
key_len i32 byte length
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

Reads one of your own keys. Two-call sizing: returns the full value length and writes at most cap bytes. Returns GEARBOX_INVALID if the key is absent -- which is NOT the same as a zero-length value, so you can tell 'never stored' from 'stored empty'. Values are arbitrary bytes, not text.

set

(import "gearbox:storage" "set" (func (param i32 i32 i32 i32) (result i32)))
Parameter Type
key i32 pointer into your memory
key_len i32 byte length
value i32 pointer into your memory
value_len i32 byte length

Returns: i32

Stores bytes under one of your own keys. Returns 1 on success, 0 if a quota was exceeded (256 keys, 128-byte keys, 16 KiB per value, 64 KiB total per mod) -- the reason is written to your log. Not written to disk immediately: the store is flushed at turn boundaries and on unload, because a mod may call this from a draw hook.

remove

(import "gearbox:storage" "remove" (func (param i32 i32) (result i32)))
Parameter Type
key i32 pointer into your memory
key_len i32 byte length

Returns: i32

Deletes one of your own keys. Returns 1 if it existed, 0 if it did not.

Map

Import module gearbox:map. Requires the Map capability in your manifest.

width

(import "gearbox:map" "width" (func (result i32)))

Returns: i32

Width of the province map in pixels. 0 when no world is loaded.

height

(import "gearbox:map" "height" (func (result i32)))

Returns: i32

Height of the province map in pixels. 0 when no world is loaded.

province_count

(import "gearbox:map" "province_count" (func (result i32)))

Returns: i32

How many provinces the loaded map has. 0 when no world is loaded.

province_at

(import "gearbox:map" "province_at" (func (param i32) (result i32)))
Parameter Type
index i32

Returns: i32

Province handle at an index in [0, province_count). Returns GEARBOX_INVALID if out of range. The order is stable across runs, unlike the game's internal storage, so an index is safe to remember within a session.

province_name

(import "gearbox:map" "province_name" (func (param i32 i32 i32) (result i32)))
Parameter Type
province i32 opaque province handle
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

The province's name. Two-call sizing: returns the full length and writes at most cap bytes. Empty for an unknown province.

province_center_x

(import "gearbox:map" "province_center_x" (func (param i32) (result f64)))
Parameter Type
province i32 opaque province handle

Returns: f64

X pixel coordinate of the province's centre. 0 for an unknown province.

province_center_y

(import "gearbox:map" "province_center_y" (func (param i32) (result f64)))
Parameter Type
province i32 opaque province handle

Returns: f64

Y pixel coordinate of the province's centre. 0 for an unknown province.

province_is_land

(import "gearbox:map" "province_is_land" (func (param i32) (result i32)))
Parameter Type
province i32 opaque province handle

Returns: i32

1 if the province is land, 0 if it is sea or unknown. Sampled at the province centre.

province_neighbor_count

(import "gearbox:map" "province_neighbor_count" (func (param i32) (result i32)))
Parameter Type
province i32 opaque province handle

Returns: i32

How many provinces border this one. 0 for an unknown province.

province_neighbor_at

(import "gearbox:map" "province_neighbor_at" (func (param i32 i32) (result i32)))
Parameter Type
province i32 opaque province handle
index i32

Returns: i32

The bordering province at an index in [0, province_neighbor_count). GEARBOX_INVALID if out of range. Adjacency is computed once when the map loads, so walking it is cheap.

province_is_coastal

(import "gearbox:map" "province_is_coastal" (func (param i32) (result i32)))
Parameter Type
province i32

Returns: i32

Whether a province touches water. Ports, embarking and naval bombardment all require it.

sea_route_exists

(import "gearbox:map" "sea_route_exists" (func (param f64 f64 f64 f64) (result i32)))
Parameter Type
from_lon f64
from_lat f64
to_lon f64
to_lat f64

Returns: i32

Whether a fleet could get from one point to another by sea, using the game's own navigation grid. You cannot compute this from province neighbours: those describe LAND adjacency.

point_is_land

(import "gearbox:map" "point_is_land" (func (param f64 f64) (result i32)))
Parameter Type
lon f64
lat f64

Returns: i32

Whether a world coordinate is land. Ordering a ship onto land is not an error -- the resolver clamps it -- but knowing first is cheaper.

Diplomacy

Import module gearbox:diplomacy. Requires the Diplomacy capability in your manifest.

at_war

(import "gearbox:diplomacy" "at_war" (func (param i32 i32) (result i32)))
Parameter Type
a i32 opaque country handle
b i32 opaque country handle

Returns: i32

1 if the two countries are at war. Relations are symmetric, so the argument order does not matter. 0 for unknown countries or for a country with itself.

allied

(import "gearbox:diplomacy" "allied" (func (param i32 i32) (result i32)))
Parameter Type
a i32 opaque country handle
b i32 opaque country handle

Returns: i32

1 if the two countries are allied.

non_aggression

(import "gearbox:diplomacy" "non_aggression" (func (param i32 i32) (result i32)))
Parameter Type
a i32 opaque country handle
b i32 opaque country handle

Returns: i32

1 if the two countries have a non-aggression pact.

guaranteed

(import "gearbox:diplomacy" "guaranteed" (func (param i32 i32) (result i32)))
Parameter Type
a i32 opaque country handle
b i32 opaque country handle

Returns: i32

1 if the first country guarantees the second.

propose_war

(import "gearbox:diplomacy" "propose_war" (func (param i32 i32) (result i32)))
Parameter Type
attacker i32 opaque country handle
defender i32 opaque country handle

Returns: i32

PROPOSES a declaration of war, and returns 1 only if the game accepted it. It is routed through the same code path any other actor uses, so guarantee chains and war consequences follow exactly as normal -- a mod cannot produce a diplomatic state the game itself could not reach. Refused (0) if either country is unknown, they are the same country, or they are already at war. Either outcome is written to your mod log, so a player can see after the fact that a mod started a war.

GameState.Write

Import module gearbox:gamestate.write. Requires the GameState.Write capability in your manifest.

set_country_treasury

(import "gearbox:gamestate.write" "set_country_treasury" (func (param i32 f64) (result i32)))
Parameter Type
country i32 opaque country handle
value f64

Returns: i32

Sets a country's treasury outright. Returns 1 on success, 0 if the country is unknown or the value is not finite and within +/-1e12 -- NaN or infinity would silently poison every later calculation, so they are refused rather than stored.

add_country_treasury

(import "gearbox:gamestate.write" "add_country_treasury" (func (param i32 f64) (result i32)))
Parameter Type
country i32 opaque country handle
delta f64

Returns: i32

Adds to a country's treasury. Usually what you want instead of set: it composes with whatever the economy did this turn. Refused (0) if the result would leave the sane range.

set_province_owner

(import "gearbox:gamestate.write" "set_province_owner" (func (param i32 i32) (result i32)))
Parameter Type
province i32 opaque province handle
country i32 opaque country handle

Returns: i32

Transfers a province to another country. Routed through the same code the game's own ceasefires use, so the province, the ownership lookup, the per-pixel country map and both countries' pixel lists all stay consistent -- and the previous owner's troops in that province are disbanded, as they are for any other transfer. Returns 0 if either handle is unknown or the country already owns it. Always written to your mod log: territory changing hands is the most consequential thing a mod can do.

set_province_population

(import "gearbox:gamestate.write" "set_province_population" (func (param i32 i64) (result i32)))
Parameter Type
province i32 opaque province handle
value i64

Returns: i32

Sets a province's population. Returns 0 if the province is unknown, the value is negative, or it exceeds 100 billion. The game stores population in two places -- a map and a dense array used by the population texture -- and this updates both, which is why it exists as an import rather than being something a mod could do by other means.

Neural

Import module gearbox:neural. Requires the Neural capability in your manifest.

feature_count

(import "gearbox:neural" "feature_count" (func (result i32)))

Returns: i32

How many floats are in the AI's feature vector. 0 when there is no AI or no world.

features

(import "gearbox:neural" "features" (func (param i32 i32 i32) (result i32)))
Parameter Type
country i32 opaque country handle
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

Copies the feature vector the AI would see for a country, as 32-bit floats. Two-call sizing, but note cap counts FLOATS and the buffer must therefore be cap*4 bytes. This is a snapshot: writing to your copy does not affect the AI.

reward_count

(import "gearbox:neural" "reward_count" (func (result i32)))

Returns: i32

How many reward channels the AI tracks (economy, politics, war, navy).

reward_mean

(import "gearbox:neural" "reward_mean" (func (param i32) (result f64)))
Parameter Type
index i32

Returns: f64

The running mean reward for one channel, indexed in [0, reward_count). 0 if out of range. OBSERVE ONLY: this capability has no import that writes to the model, the optimiser state or the reward history, which is deliberate -- a trained model is hours of work and a mod that could quietly retrain it is not something a user can meaningfully consent to.

module_count

(import "gearbox:neural" "module_count" (func (result i32)))

Returns: i32

How many decision modules the AI has. Each acts independently every turn.

module_name

(import "gearbox:neural" "module_name" (func (param i32 i32 i32) (result i32)))
Parameter Type
module i32
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

The module's name: "economy", "politics", "war", "navy". Two-call sizing: call with cap 0 to learn the length, allocate, call again. Returns the full length either way; the copy is truncated to cap.

action_count

(import "gearbox:neural" "action_count" (func (param i32) (result i32)))
Parameter Type
module i32

Returns: i32

How many actions that module can choose between.

action_name

(import "gearbox:neural" "action_name" (func (param i32 i32 i32 i32) (result i32)))
Parameter Type
module i32
action i32
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

The action's name, e.g. "reinforce", "embark", "propose_alliance". THE FEATURE VECTOR IS DELIBERATELY NOT NAMED: its 143 slots are an implementation detail that has changed before and will again, and a mod written against those names would break silently. What the AI CAN DO is stable enough to build an advisor or a decision log against. Two-call sizing: call with cap 0 to learn the length, allocate, call again. Returns the full length either way; the copy is truncated to cap.

country_is_ai

(import "gearbox:neural" "country_is_ai" (func (param i32) (result i32)))
Parameter Type
country i32

Returns: i32

Whether a country is played by the AI rather than by the local player.

update_count

(import "gearbox:neural" "update_count" (func (result i64)))

Returns: i64

Gradient updates the loaded model has been through -- roughly, how much training it has seen.

model_loaded

(import "gearbox:neural" "model_loaded" (func (result i32)))

Returns: i32

Whether an AI model is loaded at all. False in a game with no AI players.

ai_version

(import "gearbox:neural" "ai_version" (func (param i32 i32) (result i32)))
Parameter Type
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

The AI's own version, e.g. "ParrotZero 8.4.0" -- ARCH.RULES.PATCH, and independent of the game's version. ARCH is the network shape and action space, RULES is behaviour a benchmark can see, PATCH cannot move a number. A mod that reads the feature vector should check ARCH before trusting its layout, and anything comparing measurements across builds should record RULES. Two-call sizing: call with cap 0 to learn the length, allocate, call again. Returns the full length either way; the copy is truncated to cap.

ai_arch

(import "gearbox:neural" "ai_arch" (func (result i32)))

Returns: i32

The AI's ARCH number on its own, which is also the model file's format byte. The feature count and the action sets are only stable within one ARCH; a bump means old weights are refused on purpose.

country_stance

(import "gearbox:neural" "country_stance" (func (param i32) (result i32)))
Parameter Type
country i32

Returns: i32

The posture the AI has chosen for this country -- 0 expand, 1 consolidate, 2 defend, 3 develop -- or GEARBOX_INVALID if it holds none (a country the AI does not play, or one that has not been given a stance yet). Held for several turns at a time rather than chosen fresh each turn.

stance_name

(import "gearbox:neural" "stance_name" (func (param i32 i32 i32) (result i32)))
Parameter Type
index i32
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

The stance's name: "expand", "consolidate", "defend", "develop". Never translated, and stable within an ARCH. Two-call sizing: call with cap 0 to learn the length, allocate, call again. Returns the full length either way; the copy is truncated to cap.

stance_count

(import "gearbox:neural" "stance_count" (func (result i32)))

Returns: i32

How many stances there are to choose between.

Military.Read

Import module gearbox:military.read. Requires the Military.Read capability in your manifest.

ship_count

(import "gearbox:military.read" "ship_count" (func (result i32)))

Returns: i32

How many ships exist in the world, across all owners.

ship_at

(import "gearbox:military.read" "ship_at" (func (param i32) (result i32)))
Parameter Type
index i32

Returns: i32

The ship id at index in 0..ship_count-1, or 0xFFFFFFFF past the end. Ids are stable within a turn and not across turns -- do not store one.

ship_exists

(import "gearbox:military.read" "ship_exists" (func (param i32) (result i32)))
Parameter Type
ship i32

Returns: i32

Whether a ship id is still live. Check this before acting on an id you read earlier in the same turn; ships sink.

ship_owner

(import "gearbox:military.read" "ship_owner" (func (param i32) (result i32)))
Parameter Type
ship i32

Returns: i32

The country that owns a ship, or 0xFFFFFFFF for an id that does not exist.

ship_type

(import "gearbox:military.read" "ship_type" (func (param i32 i32 i32) (result i32)))
Parameter Type
ship i32
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

The hull type as a lowercase string: "transport", "destroyer", "battleship", "carrier", "submarine". Two-call sizing: call with cap 0 to learn the length, allocate, call again. Returns the full length either way; the copy is truncated to cap.

ship_lon

(import "gearbox:military.read" "ship_lon" (func (param i32) (result f64)))
Parameter Type
ship i32

Returns: f64

Longitude in degrees, -180..180. Ships live in world coordinates, not provinces.

ship_lat

(import "gearbox:military.read" "ship_lat" (func (param i32) (result f64)))
Parameter Type
ship i32

Returns: f64

Latitude in degrees, -90..90.

ship_health

(import "gearbox:military.read" "ship_health" (func (param i32) (result i32)))
Parameter Type
ship i32

Returns: i32

Hull integrity, 0..100. A ship at 0 has already sunk and will not appear.

ship_crew

(import "gearbox:military.read" "ship_crew" (func (param i32) (result i32)))
Parameter Type
ship i32

Returns: i32

Crew aboard. For a transport this includes the embarked army, which is why a sunk transport costs so much more than its hull.

ship_range

(import "gearbox:military.read" "ship_range" (func (param i32) (result f64)))
Parameter Type
ship i32

Returns: f64

How far this hull may move in one turn, in degrees. The resolver clamps any order beyond it, so read this before ordering a move rather than discovering the clamp afterwards.

army_stack_count

(import "gearbox:military.read" "army_stack_count" (func (param i32) (result i32)))
Parameter Type
province i32

Returns: i32

How many distinct owners have troops in a province. Usually 1; more than one means a contested or garrisoned province.

army_stack_owner

(import "gearbox:military.read" "army_stack_owner" (func (param i32 i32) (result i32)))
Parameter Type
province i32
index i32

Returns: i32

The country owning stack index in a province, or 0xFFFFFFFF past the end.

army_stack_size

(import "gearbox:military.read" "army_stack_size" (func (param i32 i32) (result i64)))
Parameter Type
province i32
index i32

Returns: i64

How many troops are in that stack.

country_army

(import "gearbox:military.read" "country_army" (func (param i32) (result i64)))
Parameter Type
country i32

Returns: i64

A country's total troops everywhere, which is the number its own army screen shows.

province_fortification

(import "gearbox:military.read" "province_fortification" (func (param i32) (result i32)))
Parameter Type
province i32

Returns: i32

Fortification level, 0..5. Multiplies the defender's strength.

province_port_level

(import "gearbox:military.read" "province_port_level" (func (param i32) (result i32)))
Parameter Type
province i32

Returns: i32

Port level, 0..3. 0 means no port, so no embarking and no ship repair.

troop_type_count

(import "gearbox:military.read" "troop_type_count" (func (result i32)))

Returns: i32

How many kinds of soldier exist.

troop_type_id

(import "gearbox:military.read" "troop_type_id" (func (param i32 i32 i32) (result i32)))
Parameter Type
index i32
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

The stable id of troop type index -- line, militia, assault, mech. Never translated. Two-call sizing: call with cap 0 to learn the length, allocate, call again. Returns the full length either way; the copy is truncated to cap.

country_army_of_type

(import "gearbox:military.read" "country_army_of_type" (func (param i32 i32 i32) (result i64)))
Parameter Type
country i32
troop_type i32 pointer into your memory
troop_type_len i32 byte length

Returns: i64

How many soldiers of that kind this country has, everywhere. 0 for a troop type that does not exist.

province_troops_of_type

(import "gearbox:military.read" "province_troops_of_type" (func (param i32 i32 i32 i32) (result i64)))
Parameter Type
province i32
country i32
troop_type i32 pointer into your memory
troop_type_len i32 byte length

Returns: i64

How many soldiers of that kind this country has standing in that province.

Military.Write

Import module gearbox:military.write. Requires the Military.Write capability in your manifest.

order_army_move

(import "gearbox:military.write" "order_army_move" (func (param i32 i32 i32) (result i32)))
Parameter Type
from i32
to i32
percent i32

Returns: i32

Move percent (0..100) of the troops in from into the adjacent province to. Into an enemy province this is an attack; into your own or an ally's it is a transfer. Non-adjacent moves are refused. QUEUES AN ORDER; it does not move anything. It lands in the same queue the player's own click writes to and is validated by the same resolver at end of turn, so a mod cannot teleport, cheat range, or attack across an ocean. Returns 0 if the order is rejected outright.

order_ship_move

(import "gearbox:military.write" "order_ship_move" (func (param i32 f64 f64) (result i32)))
Parameter Type
ship i32
lon f64
lat f64

Returns: i32

Sail a ship toward (lon,lat). The resolver routes around land and clamps to ship_range, so a destination on land or beyond range moves the ship as far as it legally can rather than failing. QUEUES AN ORDER; it does not move anything. It lands in the same queue the player's own click writes to and is validated by the same resolver at end of turn, so a mod cannot teleport, cheat range, or attack across an ocean. Returns 0 if the order is rejected outright.

order_ship_engage

(import "gearbox:military.write" "order_ship_engage" (func (param i32 i32) (result i32)))
Parameter Type
ship i32
target i32

Returns: i32

Attack another ship. Requires that you are at war with its owner and that it is within range; both are checked by the resolver. QUEUES AN ORDER; it does not move anything. It lands in the same queue the player's own click writes to and is validated by the same resolver at end of turn, so a mod cannot teleport, cheat range, or attack across an ocean. Returns 0 if the order is rejected outright.

order_ship_bombard

(import "gearbox:military.write" "order_ship_bombard" (func (param i32 i32 i32 i32) (result i32)))
Parameter Type
ship i32
province i32
ammo i32 pointer into your memory
ammo_len i32 byte length

Returns: i32

Bombard a coastal province. ammo names the shell type; pass an empty string for the default. QUEUES AN ORDER; it does not move anything. It lands in the same queue the player's own click writes to and is validated by the same resolver at end of turn, so a mod cannot teleport, cheat range, or attack across an ocean. Returns 0 if the order is rejected outright.

Research.Read

Import module gearbox:research.read. Requires the Research.Read capability in your manifest.

node_count

(import "gearbox:research.read" "node_count" (func (result i32)))

Returns: i32

How many technologies exist in the tree.

node_id

(import "gearbox:research.read" "node_id" (func (param i32 i32 i32) (result i32)))
Parameter Type
index i32
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

The stable string id of technology index, which is what country_has_researched takes. Two-call sizing: call with cap 0 to learn the length, allocate, call again. Returns the full length either way; the copy is truncated to cap.

node_name

(import "gearbox:research.read" "node_name" (func (param i32 i32 i32) (result i32)))
Parameter Type
index i32
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

The technology's display name, which is localised and NOT stable -- never match on it. Two-call sizing: call with cap 0 to learn the length, allocate, call again. Returns the full length either way; the copy is truncated to cap.

node_category

(import "gearbox:research.read" "node_category" (func (param i32 i32 i32) (result i32)))
Parameter Type
index i32
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

Which branch of the tree it sits in. Two-call sizing: call with cap 0 to learn the length, allocate, call again. Returns the full length either way; the copy is truncated to cap.

node_cost

(import "gearbox:research.read" "node_cost" (func (param i32) (result i32)))
Parameter Type
index i32

Returns: i32

Research points required.

country_has_researched

(import "gearbox:research.read" "country_has_researched" (func (param i32 i32 i32) (result i32)))
Parameter Type
country i32
node_id i32 pointer into your memory
node_id_len i32 byte length

Returns: i32

Whether a country has completed a technology. Takes the id from node_id, not the display name.

country_funding

(import "gearbox:research.read" "country_funding" (func (param i32) (result f64)))
Parameter Type
country i32

Returns: f64

Research funding as A SHARE OF INCOME, 0..1 -- not an absolute sum. That is how the game stores it and how its own economy screen presents it.

country_research_groups

(import "gearbox:research.read" "country_research_groups" (func (param i32) (result i32)))
Parameter Type
country i32

Returns: i32

How many research programmes this country may run at once, 1 to 3. This is the effective number, including any override a script or a mod has set.

Research.Write

Import module gearbox:research.write. Requires the Research.Write capability in your manifest.

set_country_funding

(import "gearbox:research.write" "set_country_funding" (func (param i32 f64) (result i32)))
Parameter Type
country i32
share f64

Returns: i32

Set research funding as a share of income. Clamped to 0..1; a value in 'points per turn' is not a quantity this game has.

set_country_research_groups

(import "gearbox:research.write" "set_country_research_groups" (func (param i32 i32) (result i32)))
Parameter Type
country i32
groups i32

Returns: i32

Force how many research programmes a country may run, 1 to 3, or 0 to hand the decision back to its economy. Outranks the economic gate in both directions and is saved with the game. Returns 1 on success.

Politics.Read

Import module gearbox:politics.read. Requires the Politics.Read capability in your manifest.

country_compass_econ

(import "gearbox:politics.read" "country_compass_econ" (func (param i32) (result f64)))
Parameter Type
country i32

Returns: f64

Economic axis of the political compass, -100 (planned) to 100 (market).

country_compass_social

(import "gearbox:politics.read" "country_compass_social" (func (param i32) (result f64)))
Parameter Type
country i32

Returns: f64

Social axis, -100 (authoritarian) to 100 (libertarian).

province_unrest

(import "gearbox:politics.read" "province_unrest" (func (param i32) (result f64)))
Parameter Type
province i32

Returns: f64

This province's chance of rebelling, as the game itself computes it.

policy_count

(import "gearbox:politics.read" "policy_count" (func (result i32)))

Returns: i32

How many policies exist.

policy_id

(import "gearbox:politics.read" "policy_id" (func (param i32 i32 i32) (result i32)))
Parameter Type
index i32
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

The stable string id of policy index. Two-call sizing: call with cap 0 to learn the length, allocate, call again. Returns the full length either way; the copy is truncated to cap.

policy_name

(import "gearbox:politics.read" "policy_name" (func (param i32 i32 i32) (result i32)))
Parameter Type
index i32
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

The policy's display name; localised, not stable, do not match on it. Two-call sizing: call with cap 0 to learn the length, allocate, call again. Returns the full length either way; the copy is truncated to cap.

country_has_policy

(import "gearbox:politics.read" "country_has_policy" (func (param i32 i32 i32) (result i32)))
Parameter Type
country i32
policy_id i32 pointer into your memory
policy_id_len i32 byte length

Returns: i32

Whether a country currently has a policy active or implementing.

province_minority_count

(import "gearbox:politics.read" "province_minority_count" (func (param i32) (result i32)))
Parameter Type
province i32

Returns: i32

How many named minority groups live in a province.

province_minority_name

(import "gearbox:politics.read" "province_minority_name" (func (param i32 i32 i32 i32) (result i32)))
Parameter Type
province i32
index i32
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

The minority's name. Two-call sizing: call with cap 0 to learn the length, allocate, call again. Returns the full length either way; the copy is truncated to cap.

province_minority_share

(import "gearbox:politics.read" "province_minority_share" (func (param i32 i32) (result f64)))
Parameter Type
province i32
index i32

Returns: f64

That minority's share of the province's population, 0..1.

country_district_count

(import "gearbox:politics.read" "country_district_count" (func (param i32) (result i32)))
Parameter Type
country i32

Returns: i32

How many districts this country is divided into. Districts are built on demand, so asking is what creates the default one for a country that has never been divided.

country_district_name

(import "gearbox:politics.read" "country_district_name" (func (param i32 i32 i32 i32) (result i32)))
Parameter Type
country i32
index i32
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

The district's name. Two-call sizing: call with cap 0 to learn the length, allocate, call again. Returns the full length either way; the copy is truncated to cap.

country_district_share

(import "gearbox:politics.read" "country_district_share" (func (param i32 i32) (result i32)))
Parameter Type
country i32
index i32

Returns: i32

This district's claim on the country's pacification budget, in percent. The shares of a country's districts sum to 100.

country_district_province_count

(import "gearbox:politics.read" "country_district_province_count" (func (param i32 i32) (result i32)))
Parameter Type
country i32
index i32

Returns: i32

How many provinces this district holds.

country_district_province

(import "gearbox:politics.read" "country_district_province" (func (param i32 i32 i32) (result i32)))
Parameter Type
country i32
index i32
n i32

Returns: i32

Province n of this district, or GEARBOX_INVALID if there is no such one.

country_district_law_count

(import "gearbox:politics.read" "country_district_law_count" (func (param i32 i32) (result i32)))
Parameter Type
country i32
index i32

Returns: i32

How many regional laws this district runs.

country_district_law

(import "gearbox:politics.read" "country_district_law" (func (param i32 i32 i32 i32 i32) (result i32)))
Parameter Type
country i32
index i32
n i32
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

The stable id of regional law n in this district. Two-call sizing: call with cap 0 to learn the length, allocate, call again. Returns the full length either way; the copy is truncated to cap.

district_law_count

(import "gearbox:politics.read" "district_law_count" (func (result i32)))

Returns: i32

How many regional laws exist to choose from.

district_law_id

(import "gearbox:politics.read" "district_law_id" (func (param i32 i32 i32) (result i32)))
Parameter Type
index i32
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

The stable id of regional law index. Two-call sizing: call with cap 0 to learn the length, allocate, call again. Returns the full length either way; the copy is truncated to cap.

district_law_name

(import "gearbox:politics.read" "district_law_name" (func (param i32 i32 i32) (result i32)))
Parameter Type
index i32
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

The display name of regional law index, untranslated. Two-call sizing: call with cap 0 to learn the length, allocate, call again. Returns the full length either way; the copy is truncated to cap.

country_discloses

(import "gearbox:politics.read" "country_discloses" (func (param i32 i32) (result i32)))
Parameter Type
country i32
field i32

Returns: i32

Whether this country publishes that figure in its profile: 1 if it does, 0 if it keeps it to itself. See the disclosure_field enum. Publishing is a decision with a consequence -- migrants read it -- rather than a display setting.

country_party_count

(import "gearbox:politics.read" "country_party_count" (func (param i32) (result i32)))
Parameter Type
country i32

Returns: i32

How many parties sit in a country's legislature. 0 when the party rules are off, which is the default -- so a mod must treat 0 as 'this world has no party politics' rather than as an error.

country_party_name

(import "gearbox:politics.read" "country_party_name" (func (param i32 i32 i32 i32) (result i32)))
Parameter Type
country i32
index i32
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

The party's name. Two-call sizing: call with cap 0 to learn the length, allocate, call again. Returns the full length either way; the copy is truncated to cap.

country_party_short_name

(import "gearbox:politics.read" "country_party_short_name" (func (param i32 i32 i32 i32) (result i32)))
Parameter Type
country i32
index i32
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

The party's abbreviation, for a list that has to fit -- "SPD", "INC". Same two-call sizing as country_party_name. May be empty.

country_party_support

(import "gearbox:politics.read" "country_party_support" (func (param i32 i32) (result f64)))
Parameter Type
country i32
index i32

Returns: f64

That party's share of the country, 0..1. The shares of one country's parties are a partition and sum to 1, so they may be compared directly but must never be added across countries.

country_party_compass_econ

(import "gearbox:politics.read" "country_party_compass_econ" (func (param i32 i32) (result f64)))
Parameter Type
country i32
index i32

Returns: f64

Where the party stands on the economic axis, -100 (planned) to 100 (market) -- the same axis and scale as country_compass_econ, so the distance between a party and its government is meaningful.

country_party_compass_social

(import "gearbox:politics.read" "country_party_compass_social" (func (param i32 i32) (result f64)))
Parameter Type
country i32
index i32

Returns: f64

Where the party stands on the social axis, -100 (authoritarian) to 100 (libertarian). Same scale as country_compass_social.

country_party_is_historical

(import "gearbox:politics.read" "country_party_is_historical" (func (param i32 i32) (result i32)))
Parameter Type
country i32
index i32

Returns: i32

1 when this party is a matter of record for the scenario's date -- it existed, under this name -- and 0 when the name was generated from its stance. A mod that displays party names should say which it is showing: "Workers' Party" is a description, "SPD" is a claim. See data/parties.json.

country_ruling_party

(import "gearbox:politics.read" "country_ruling_party" (func (param i32) (result i32)))
Parameter Type
country i32

Returns: i32

The index of the party that governs, or -1 if none does. That party pulls the government compass toward its own stance every turn it holds power, which is why the two are on the same scale.

Politics.Write

Import module gearbox:politics.write. Requires the Politics.Write capability in your manifest.

set_country_policy

(import "gearbox:politics.write" "set_country_policy" (func (param i32 i32 i32 i32) (result i32)))
Parameter Type
country i32
policy_id i32 pointer into your memory
policy_id_len i32 byte length
enabled i32 0 or 1

Returns: i32

Enact or cancel a policy. GOES THROUGH THE GAME'S OWN enactPolicy, so the cost, the prerequisites and the per-turn enactment cap all still apply -- a country cannot end up running policies it could never have afforded. Returns 1 if the policy is already in the requested state.

set_country_district_share

(import "gearbox:politics.write" "set_country_district_share" (func (param i32 i32 i32) (result i32)))
Parameter Type
country i32
index i32
percent i32

Returns: i32

Set this district's claim on the pacification budget. The other districts are rebalanced so the shares still sum to 100, exactly as dragging the slider does. Returns 1 on success.

set_country_district_law

(import "gearbox:politics.write" "set_country_district_law" (func (param i32 i32 i32 i32 i32) (result i32)))
Parameter Type
country i32
index i32
law i32 pointer into your memory
law_len i32 byte length
on i32

Returns: i32

Pass or repeal a regional law in this district. Returns 1 on success, 0 for an unknown law or district.

set_country_disclosure

(import "gearbox:politics.write" "set_country_disclosure" (func (param i32 i32 i32) (result i32)))
Parameter Type
country i32
field i32
on i32

Returns: i32

Publish or withhold one of the figures in this country's profile. Returns 1 on success.

Economy.Read

Import module gearbox:economy.read. Requires the Economy.Read capability in your manifest.

country_income_gross

(import "gearbox:economy.read" "country_income_gross" (func (param i32) (result f64)))
Parameter Type
country i32

Returns: f64

Income per turn before upkeep.

country_income_net

(import "gearbox:economy.read" "country_income_net" (func (param i32) (result f64)))
Parameter Type
country i32

Returns: f64

Income per turn after army and navy upkeep. Negative means the treasury is draining.

country_army_upkeep

(import "gearbox:economy.read" "country_army_upkeep" (func (param i32) (result f64)))
Parameter Type
country i32

Returns: f64

What the standing army costs per turn.

country_navy_upkeep

(import "gearbox:economy.read" "country_navy_upkeep" (func (param i32) (result f64)))
Parameter Type
country i32

Returns: f64

What the fleet costs per turn. Ships a country is not using still cost this, which is what makes scrapping a real decision.

country_is_bankrupt

(import "gearbox:economy.read" "country_is_bankrupt" (func (param i32) (result i32)))
Parameter Type
country i32

Returns: i32

Whether a country is currently bankrupt.

province_industry_level

(import "gearbox:economy.read" "province_industry_level" (func (param i32) (result i32)))
Parameter Type
province i32

Returns: i32

Industry level, 0..10.

province_industry_specialization

(import "gearbox:economy.read" "province_industry_specialization" (func (param i32 i32 i32) (result i32)))
Parameter Type
province i32
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

What this province's industry specialises in, or an empty string for none. Two-call sizing: call with cap 0 to learn the length, allocate, call again. Returns the full length either way; the copy is truncated to cap.

province_resource

(import "gearbox:economy.read" "province_resource" (func (param i32 i32 i32) (result f64)))
Parameter Type
province i32
which i32 pointer into your memory
which_len i32 byte length

Returns: f64

How much of a resource a province holds, 0..100. which is one of "oil", "gold", "rubber", "gemstones", "metal"; anything else reads 0.

country_expenses

(import "gearbox:economy.read" "country_expenses" (func (param i32) (result f64)))
Parameter Type
country i32

Returns: f64

What this country spent last turn, in total. The same figure its profile publishes and the economy screen draws.

country_national_value

(import "gearbox:economy.read" "country_national_value" (func (param i32) (result f64)))
Parameter Type
country i32

Returns: f64

What the whole country is worth: every industry level, fort, port and division at what it cost to raise. A stock, where the income figures are flows.

country_population

(import "gearbox:economy.read" "country_population" (func (param i32) (result i64)))
Parameter Type
country i32

Returns: i64

How many people live in this country.

Economy.Write

Import module gearbox:economy.write. Requires the Economy.Write capability in your manifest.

set_province_industry_level

(import "gearbox:economy.write" "set_province_industry_level" (func (param i32 i32) (result i32)))
Parameter Type
province i32
level i32

Returns: i32

Set a province's industry level, clamped to 0..10. This writes the built level directly and does not charge for it -- it is a scenario-authoring tool, not a build order.

MapEditor

Import module gearbox:mapeditor. Requires the MapEditor capability in your manifest.

editor_active

(import "gearbox:mapeditor" "editor_active" (func (result i32)))

Returns: i32

Whether the map editor is open with a project loaded. EVERY OTHER CALL IN THIS MODULE returns 0 or an empty string when this is 0, including from inside a running game: the data behind them is an editor project, and a game does not have one. Check this first.

editor_province_count

(import "gearbox:mapeditor" "editor_province_count" (func (result i32)))

Returns: i32

How many provinces the open project has. Returns a neutral value unless the map editor is open with a project loaded -- see mapeditor/active.

editor_province_at

(import "gearbox:mapeditor" "editor_province_at" (func (param i32) (result i32)))
Parameter Type
index i32

Returns: i32

The province id at index, in ascending id order, or 0xFFFFFFFF past the end. Returns a neutral value unless the map editor is open with a project loaded -- see mapeditor/active.

editor_province_population

(import "gearbox:mapeditor" "editor_province_population" (func (param i32) (result i64)))
Parameter Type
province i32

Returns: i64

Population. Returns a neutral value unless the map editor is open with a project loaded -- see mapeditor/active.

editor_province_industry_level

(import "gearbox:mapeditor" "editor_province_industry_level" (func (param i32) (result i32)))
Parameter Type
province i32

Returns: i32

Industry level, 0..10. Returns a neutral value unless the map editor is open with a project loaded -- see mapeditor/active.

editor_province_fortification

(import "gearbox:mapeditor" "editor_province_fortification" (func (param i32) (result i32)))
Parameter Type
province i32

Returns: i32

Fortification, 0..5. Returns a neutral value unless the map editor is open with a project loaded -- see mapeditor/active.

editor_province_port_level

(import "gearbox:mapeditor" "editor_province_port_level" (func (param i32) (result i32)))
Parameter Type
province i32

Returns: i32

Port level, 0..3. Returns a neutral value unless the map editor is open with a project loaded -- see mapeditor/active.

editor_province_resource

(import "gearbox:mapeditor" "editor_province_resource" (func (param i32 i32 i32) (result f64)))
Parameter Type
province i32
which i32 pointer into your memory
which_len i32 byte length

Returns: f64

Resource amount, 0..100. which is "oil", "gold", "rubber", "gemstones" or "metal". Returns a neutral value unless the map editor is open with a project loaded -- see mapeditor/active.

editor_province_compass_econ

(import "gearbox:mapeditor" "editor_province_compass_econ" (func (param i32) (result f64)))
Parameter Type
province i32

Returns: f64

Province economic compass, -100..100. Returns a neutral value unless the map editor is open with a project loaded -- see mapeditor/active.

editor_province_compass_social

(import "gearbox:mapeditor" "editor_province_compass_social" (func (param i32) (result f64)))
Parameter Type
province i32

Returns: f64

Province social compass, -100..100. Returns a neutral value unless the map editor is open with a project loaded -- see mapeditor/active.

editor_set_province_population

(import "gearbox:mapeditor" "editor_set_province_population" (func (param i32 i64) (result i32)))
Parameter Type
province i32
value i64

Returns: i32

Set population, clamped to 0..2e9. Writes the SAME per-province data the editor's own tools write, so it saves, exports and shows up in the unsaved-changes prompt like any other edit. A province the project does not have is refused rather than created: data without a shape on the province bitmap exports a map the game cannot load.

editor_set_province_industry_level

(import "gearbox:mapeditor" "editor_set_province_industry_level" (func (param i32 i32) (result i32)))
Parameter Type
province i32
level i32

Returns: i32

Set industry level, clamped to 0..10. Writes the SAME per-province data the editor's own tools write, so it saves, exports and shows up in the unsaved-changes prompt like any other edit. A province the project does not have is refused rather than created: data without a shape on the province bitmap exports a map the game cannot load.

editor_set_province_fortification

(import "gearbox:mapeditor" "editor_set_province_fortification" (func (param i32 i32) (result i32)))
Parameter Type
province i32
level i32

Returns: i32

Set fortification, clamped to 0..5. Writes the SAME per-province data the editor's own tools write, so it saves, exports and shows up in the unsaved-changes prompt like any other edit. A province the project does not have is refused rather than created: data without a shape on the province bitmap exports a map the game cannot load.

editor_set_province_port_level

(import "gearbox:mapeditor" "editor_set_province_port_level" (func (param i32 i32) (result i32)))
Parameter Type
province i32
level i32

Returns: i32

Set port level, clamped to 0..3. Writes the SAME per-province data the editor's own tools write, so it saves, exports and shows up in the unsaved-changes prompt like any other edit. A province the project does not have is refused rather than created: data without a shape on the province bitmap exports a map the game cannot load.

editor_set_province_resource

(import "gearbox:mapeditor" "editor_set_province_resource" (func (param i32 i32 i32 f64) (result i32)))
Parameter Type
province i32
which i32 pointer into your memory
which_len i32 byte length
amount f64

Returns: i32

Set a resource amount, clamped to 0..100. An unrecognised name is refused rather than silently mapped onto oil. Writes the SAME per-province data the editor's own tools write, so it saves, exports and shows up in the unsaved-changes prompt like any other edit. A province the project does not have is refused rather than created: data without a shape on the province bitmap exports a map the game cannot load.

editor_set_province_compass

(import "gearbox:mapeditor" "editor_set_province_compass" (func (param i32 f64 f64) (result i32)))
Parameter Type
province i32
econ f64
social f64

Returns: i32

Set both compass axes, each clamped to -100..100. Writes the SAME per-province data the editor's own tools write, so it saves, exports and shows up in the unsaved-changes prompt like any other edit. A province the project does not have is refused rather than created: data without a shape on the province bitmap exports a map the game cannot load.

editor_map_name

(import "gearbox:mapeditor" "editor_map_name" (func (param i32 i32) (result i32)))
Parameter Type
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

The project's map name. Two-call sizing: call with cap 0 to learn the length, allocate, call again. Returns the full length either way; the copy is truncated to cap.

editor_set_map_name

(import "gearbox:mapeditor" "editor_set_map_name" (func (param i32 i32) (result i32)))
Parameter Type
name i32 pointer into your memory
name_len i32 byte length

Returns: i32

Rename the map. Refused if empty or over 96 bytes.

editor_set_author

(import "gearbox:mapeditor" "editor_set_author" (func (param i32 i32) (result i32)))
Parameter Type
author i32 pointer into your memory
author_len i32 byte length

Returns: i32

Set the author recorded in the exported .odmap. Up to 96 bytes.

editor_set_license

(import "gearbox:mapeditor" "editor_set_license" (func (param i32 i32) (result i32)))
Parameter Type
license i32 pointer into your memory
license_len i32 byte length

Returns: i32

Set the licence recorded in the exported .odmap. Up to 96 bytes.

Neural.Decide

Import module gearbox:neural.decide. Requires the Neural.Decide capability in your manifest.

action_valid

(import "gearbox:neural.decide" "action_valid" (func (param i32 i32 i32) (result i32)))
Parameter Type
module i32
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

Which actions the host will accept for this module right now, one byte per action: 1 legal, 0 not. Two-call sizing, like every other copy here. MEANINGFUL ONLY INSIDE mod_ai_choose, because a legality mask is a fact about a decision in progress; outside one it returns 0 and writes nothing. Choosing an action whose byte is 0 is the same as deciding nothing -- the host keeps its own choice, because an illegal action is not a move it can make.

Core.Protected

Import module gearbox:core.protected. Requires the Core.Protected capability in your manifest.

process_bytes

(import "gearbox:core.protected" "process_bytes" (func (result i64)))

Returns: i64

Resident memory the whole game is using, in bytes. 0 where the platform does not report it -- Windows and the web build both return 0 today, and 0 means UNKNOWN rather than 'no memory'.\n\nTHIS IS A FACT ABOUT THE MACHINE, not about the game, which is why it needs its own capability. Every other reading a mod can take is deliberately opaque about the host.

image_bytes

(import "gearbox:core.protected" "image_bytes" (func (result i64)))

Returns: i64

How large the game's own executable is on disk, in bytes. 0 if it cannot be determined. Useful to a mod that reports build size or checks it is running against the build it expects; useless for anything else, which is the point.

mod_count

(import "gearbox:core.protected" "mod_count" (func (result i32)))

Returns: i32

How many mods are INSTALLED, enabled or not. A compatibility checker needs to see the mod it conflicts with even when that mod is switched off, because switching it on is what breaks things.

mod_id

(import "gearbox:core.protected" "mod_id" (func (param i32 i32 i32) (result i32)))
Parameter Type
index i32
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

The installed mod's manifest id -- the stable one, safe to compare. Two-call sizing: call with cap 0 to learn the length, allocate, call again.

mod_name

(import "gearbox:core.protected" "mod_name" (func (param i32 i32 i32) (result i32)))
Parameter Type
index i32
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

Its display name, which is for showing a player and NOT for matching on: it is author-chosen, may be translated, and two mods may share one. Match on mod_id.

Country

Import module gearbox:country. Requires the Country capability in your manifest.

field_add

(import "gearbox:country" "field_add" (func (param i32 i32 i32 i32) (result i32)))
Parameter Type
name i32 pointer into your memory
name_len i32 byte length
mode i32
type i32

Returns: i32

Declare a field on every country. mode 0 HOLLOW, 1 PERSIST; type 0 number, 1 text.

PERSIST is written into the save and read back. HOLLOW is not: the mod redeclares it on every load and fills it from whatever it can recompute, which is right for a cache and wrong for anything a player would be upset to lose.

Redeclaring the same field identically SUCCEEDS -- that is what a hollow field does on every load. Redeclaring it with a different type fails, because the values already stored are of the old one. Refused for an empty name, a name over 64 bytes, or one containing anything but printable ASCII.

field_remove

(import "gearbox:country" "field_remove" (func (param i32 i32) (result i32)))
Parameter Type
name i32 pointer into your memory
name_len i32 byte length

Returns: i32

Forget one of YOUR fields and every country's value for it. Returns whether it existed. A mod cannot remove another mod's field: fields are keyed by (mod, name), so two mods may both add a field called morale and neither can see the other's.

field_has

(import "gearbox:country" "field_has" (func (param i32 i32) (result i32)))
Parameter Type
name i32 pointer into your memory
name_len i32 byte length

Returns: i32

Whether you have declared this field AND own it right now. False for a field read back from a save whose mod is not loaded -- such a field is inert, though its values are kept.

field_count

(import "gearbox:country" "field_count" (func (result i32)))

Returns: i32

How many fields YOU have declared. Not how many exist: another mod's fields are not yours to enumerate.

field_name

(import "gearbox:country" "field_name" (func (param i32 i32 i32) (result i32)))
Parameter Type
index i32
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

The name of your field at index, sorted by name so the order does not shift between runs. Two-call sizing.

set_number

(import "gearbox:country" "set_number" (func (param i32 i32 i32 f64) (result i32)))
Parameter Type
name i32 pointer into your memory
name_len i32 byte length
country i32 opaque country handle
value f64

Returns: i32

Set a country's value for one of your NUMBER fields. Refused if the field is text, was never declared, or belongs to a mod that is not loaded.

get_number

(import "gearbox:country" "get_number" (func (param i32 i32 i32) (result f64)))
Parameter Type
name i32 pointer into your memory
name_len i32 byte length
country i32 opaque country handle

Returns: f64

A country's value, or 0 when the field or the country has none. 0 is a real value too, so a mod that needs to tell unset from zero should keep its own sentinel.

set_text

(import "gearbox:country" "set_text" (func (param i32 i32 i32 i32 i32) (result i32)))
Parameter Type
name i32 pointer into your memory
name_len i32 byte length
country i32 opaque country handle
value i32 pointer into your memory
value_len i32 byte length

Returns: i32

Set a country's value for one of your TEXT fields.

get_text

(import "gearbox:country" "get_text" (func (param i32 i32 i32 i32 i32) (result i32)))
Parameter Type
name i32 pointer into your memory
name_len i32 byte length
country i32 opaque country handle
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

A country's text value, or empty. Two-call sizing.

Scripts

Import module gearbox:scripts. Requires the Scripts capability in your manifest.

command_add

(import "gearbox:scripts" "command_add" (func (param i32 i32) (result i32)))
Parameter Type
name i32 pointer into your memory
name_len i32 byte length

Returns: i32

Claim a command name in the map script language. A script line beginning with it is then handed to your mod_script_command export, whole.

FIRST COME. A script writes reinforce FRA 3, not a mod id and a colon, so the name is global: the first mod to claim it keeps it and the second gets false rather than a silent overwrite, which would make the meaning of a line depend on load order. Re-claiming your own succeeds, because a mod redeclares its commands on every load.

The language's own keywords are refused. A mod that could register if or set would take over every script in the game -- including maps that never asked for it, since scripts ship inside .odmap files and mods are enabled globally. Names must be an identifier: a letter, then letters, digits or underscores, up to 48 bytes.

command_remove

(import "gearbox:scripts" "command_remove" (func (param i32 i32) (result i32)))
Parameter Type
name i32 pointer into your memory
name_len i32 byte length

Returns: i32

Give up one of your own commands. False if it was not yours -- a mod cannot unregister another mod's.

command_count

(import "gearbox:scripts" "command_count" (func (result i32)))

Returns: i32

How many commands YOU have claimed.

command_name

(import "gearbox:scripts" "command_name" (func (param i32 i32 i32) (result i32)))
Parameter Type
index i32
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

The name of your command at index, sorted. Two-call sizing.

command_text

(import "gearbox:scripts" "command_text" (func (param i32 i32) (result i32)))
Parameter Type
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

Inside mod_script_command: which of your commands the script ran. Empty outside that call -- there is no command then, and reporting the last one would be a stale answer that looks like a live one. Two-call sizing.

command_args

(import "gearbox:scripts" "command_args" (func (param i32 i32) (result i32)))
Parameter Type
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

Inside mod_script_command: the rest of the script line, verbatim -- unparsed and untrimmed, because your command knows its own grammar and the engine does not. Empty outside that call. Two-call sizing.

Render

Import module gearbox:render. Requires the Render capability in your manifest.

province_tint

(import "gearbox:render" "province_tint" (func (param i32 i32) (result i32)))
Parameter Type
province i32 opaque province handle
rgba i32

Returns: i32

Tint a province on the map. rgba is 0xRRGGBBAA.

AN ALPHA OF ZERO REMOVES THE TINT. One call does set and clear, so a fading effect that paints transparent every frame cannot grow the list forever -- which is what a separate clear call invites.

Returns false when you are already holding the maximum (4096 tints per mod, which is every province on the largest map twice over). A refusal rather than a slower game: a mod's mistake should not be paid for in frame time by a player who cannot see why.

province_label

(import "gearbox:render" "province_label" (func (param i32 i32 i32 i32) (result i32)))
Parameter Type
province i32 opaque province handle
text i32 pointer into your memory
text_len i32 byte length
rgba i32

Returns: i32

Put a short label at a province. Empty text, or an alpha of zero, removes it.

Truncated at 48 characters and stripped of control characters rather than refused: a label one character too long is a cosmetic mistake, and failing the call would have an author debugging a silent nothing instead of seeing a clipped word. 512 labels per mod.

clear

(import "gearbox:render" "clear" (func (result i32)))

Returns: i32

Drop every tint and label YOU have drawn. A mod cannot clear another mod's -- and unloading a mod clears its own automatically, because a mark left behind by a mod that is no longer running is indistinguishable from the game being wrong.

tint_count

(import "gearbox:render" "tint_count" (func (result i32)))

Returns: i32

How many tints you are currently holding.

label_count

(import "gearbox:render" "label_count" (func (result i32)))

Returns: i32

How many labels you are currently holding.

Content

Import module gearbox:content. Requires the Content capability in your manifest.

add

(import "gearbox:content" "add" (func (param i32 i32 i32 i32 i32 i32) (result i32)))
Parameter Type
kind i32
id i32 pointer into your memory
id_len i32 byte length
json i32 pointer into your memory
json_len i32 byte length
mode i32

Returns: i32

Add or replace one entry in a catalogue. kind 0 doctrine, 1 research, 2 troop type, 3 artillery, 4 district law. mode 0 HOLLOW, 1 PERSIST.

The definition is the SAME JSON the game's own data file uses, and goes through the same parser -- not a second reading of the same fields, which is how 'it works from the file but not from the mod' is made.

AI VISIBILITY IS A FIELD IN THE JSON: "aiVisible": true. It defaults to FALSE, because content the AI was never trained against should not start appearing in its options. For RESEARCH it matters more than it looks -- the tree feeds the neural feature vector, so a visible node changes the shape of the model's input and a model whose parent no longer matches is silently re-initialised.

PERSIST writes the definition into the save, so a world played with your doctrine keeps knowing what that doctrine was after your mod is uninstalled -- otherwise the country still holds the id and nothing can say what it did. HOLLOW is redeclared every load.

Ids are GLOBAL within a catalogue, unlike country fields: a country holds a doctrine by id and a save records it that way, so two meanings for one id would make a save ambiguous. Another mod's id is refused. Lower-case letters, digits, underscore and at most one colon, 64 bytes.

count

(import "gearbox:content" "count" (func (param i32) (result i32)))
Parameter Type
kind i32

Returns: i32

How many entries of this kind YOU have added.

id_at

(import "gearbox:content" "id_at" (func (param i32 i32 i32 i32) (result i32)))
Parameter Type
kind i32
index i32
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

The id of your entry at index within a kind, sorted. Two-call sizing.

owner_of

(import "gearbox:content" "owner_of" (func (param i32 i32 i32 i32 i32) (result i32)))
Parameter Type
kind i32
id i32 pointer into your memory
id_len i32 byte length
buf i32 pointer into your memory
cap i32 byte length

Returns: i32

Which mod owns an id in a catalogue, or empty if nobody does. Lets a mod check whether the content it is about to add already exists -- including content another mod added, which is the collision it cannot otherwise see coming.

remove

(import "gearbox:content" "remove" (func (param i32 i32 i32) (result i32)))
Parameter Type
kind i32
id i32 pointer into your memory
id_len i32 byte length

Returns: i32

Remove one of your own entries. False if it was not yours.

Exports

Functions you provide. Only mod_load is required; a missing optional export is simply not called.

mod_load

(func (export "mod_load") (result i32) ...)

Required: yes. Capability: none

Called once when your mod is enabled, before anything else. Return 0 to accept the load; non-zero refuses it and the value is shown to the user. There is no autorun, so this runs every session the user enables you -- never assume prior state.

mod_unload

(func (export "mod_unload") ...)

Required: no. Capability: none

Called when disabled, reloaded, or at shutdown. Release what you hold. Your state does not survive a reload and there is no hook to serialise it.

mod_pre_turn

(func (export "mod_pre_turn") (param i32) ...)

Required: no. Capability: GameProcess

Called before the host processes a turn. Only invoked if GameProcess is granted.

mod_post_turn

(func (export "mod_post_turn") (param i32) ...)

Required: no. Capability: GameProcess

Called after the host processes a turn. Only invoked if GameProcess is granted.

mod_draw_panel

(func (export "mod_draw_panel") (param i32 i32 i32) ...)

Required: no. Capability: UI

Called once per frame per visible panel you registered. Never called when headless. Re-issue all your draw calls every frame; the command list is cleared between frames.

mod_ai_choose

(func (export "mod_ai_choose") (param i32 i32) (result i32) ...)

Required: no. Capability: Neural.Decide

Choose this country's action for one of the AI's decision modules, in place of the built-in AI. Called once per AI country per module per turn, and only if Neural.Decide is granted. Read the position with neural.features() and the legal moves with neural.decide.action_valid(); return an action index in [0, action_count(module)). Return GEARBOX_INVALID to decide nothing this time, which is not a failure -- the built-in AI chooses instead, so a mod may answer only the turns it has an opinion about. An out-of-range or illegal answer is treated the same way. The host keeps the last word either way: whatever is returned is still put through the same legality and execution path as its own choice, so this changes WHICH legal move is made and never what a legal move is.

mod_script_command

(func (export "mod_script_command") (result i32) ...)

Required: no. Capability: none

Called when a map script runs a command you claimed with command_add. Read which one with scripts.command_text and its arguments with scripts.command_args -- the rest of the line verbatim, unparsed and untrimmed, because your command knows its own grammar and the engine does not. Return 1 if you handled it; 0 reports "Unknown command" to the script author, which is the right answer for arguments you cannot make sense of.

The env struct

28 bytes on wasm32. Layout is part of the ABI: fields are only appended, never reordered. Write your own struct size into size before calling env — the host writes at most that many bytes, so an older mod is safe against a newer host.

Offset Field Type
0 size u32 You write sizeof(gearbox_env_t) here before calling env
4 gearbox_major u32
8 gearbox_minor u32
12 host_version u32 (major<<16)
16 platform u8 enum:platform
17 is_web u8 1 under Emscripten. Fuel is NOT enforced there.
18 is_headless u8 1 when there is no renderer. UI imports no-op.
19 net_role u8 enum:net_role. 0 in singleplayer, which is what an older mod reading this byte as reserved already saw.
20 screen_w u32 0 when headless
24 screen_h u32 0 when headless

log_level — TRACE=0, INFO=1, WARN=2, ERROR=3

platform — UNKNOWN=0, WINDOWS=1, MACOS=2, LINUX=3, WEB=4

net_role — STANDALONE=0, CLIENT=1, SERVER=2, HOST_PLAYER=3

disclosure_field — EXPENSES=0, DOCTRINES=1, TREASURY=2, DISTRICT_LAWS=3

ai_stance — EXPAND=0, CONSOLIDATE=1, DEFEND=2, DEVELOP=3

field_mode — hollow=0, persist=1

field_type — number=0, text=1

content_kind — doctrine=0, research=1, troop=2, artillery=3, district_law=4

content_mode — hollow=0, persist=1

monument_kind — $comment=Appended to, never reordered: a save and this ABI both store the index., university=0, megacity=1, missile_silo=2, defence_corporation=3, factory_conglomerate=4, air_defence=5, strategic_reserve=6, grand_exchange=7, admiralty_yard=8, ministry_of_enlightenment=9, signals_directorate=10

Clone this wiki locally