Home › Modding Info › Make a brain
Chapter 07

Make a brain

A .oabrain that plays one computer seat: the folder, every manifest key, the tags, levels, full awareness, where the script runs, the budgets, and what happens when it stops.

This chapter summarises docs/brains/oabrain-standard.md, docs/brains/authoring.md and docs/playing-with-brains.md. Those docs are the normative text.

What a brain is

The engine's own computer player stays the default and stays in the engine. A brain plays one computer seat, and only a seat a player set to it. An empty brain id is that built-in player. A seat with no brain, a brain that does not fit, and a brain that stops are all played by that same player. Classic is written in Lua and plays as that player does. It is documentation of that player, not a replacement.

Only the machine that seats the computer player runs the script, so the other players need nothing installed. Their machines mirror the seat's units. A recording played back does not run the script. A brain is Lua source and data. It has no native code, no file, no network and no clock. Full awareness is a flag on the manifest. A brain may set it, may play with it in a network game, and the seat shows the flag.

The package

A brain is one .oabrain file, or the folder that file unpacks to. The manifest is the strict YAML a mod profile uses: one document, one top-level mapping, no anchors and no block scalars. The top of the package holds oabrain.yaml. Beside it, a file is one of these. A file outside that list is refused.

my-brain.oabrainthe file a player gets├─ oabrain.yamlrequired the manifest, at most 256 KiB├─ brain.luathe entry script. The default name is brain.lua. entry names another, and that file has to be in the package├─ lua/further Lua source. require reads only these files. Each part is lower-case letters, digits and _├─ nets/a network the manifest names, nets/ and a stem ending .oann├─ data/one data table, one folder deep: .csv, .tdf, .json or .txt├─ icon.pngthe picture, only when icon names it. Without that key the file is outside├─ README.mda note at the top. The game does not load it└─ LICENSEthe licence at the top. The name licence, and a readme in a subfolder, are outside

The comparison ignores the case of ASCII letters, except where the standard says the bytes must match. brain.lua is outside when entry names some other file. One Lua file is at most 1 MiB. The icon is a square PNG, each side at most 256 pixels, at most 256 KiB. OA installs a brain into Brains/ and the id from the manifest.

The manifest

The reader collects every broken rule and leaves the manifest unchanged when any rule is broken. A key the standard does not list is refused. A profile key belongs in a mod. A mutator key is refused as a mutator's key. Quote a version, because a bare 1.0 is a number, and quote a star, because a bare star is a YAML alias.

KeyRequiredWhat it does
oabrainyesThe format. The integer 1. 1.0 and a quoted 1 are refused.
idyesLower-case kebab-case, 1 to 64 bytes. No leading, trailing or doubled hyphen. The folder name under Brains/.
nameyes1 to 64 bytes, no control character. The name players see.
versionyesQuoted, one to three parts, a mutator version, such as "2.0". A plain number is refused. 2, 2.0 and 2.0.0 compare as equal.
authoryesA mapping. name is required, 1 to 128 bytes. email is optional.
descriptionyesRequired, 1 to 2,000 bytes. A line feed is allowed. Any other control character is refused. The first line, cut to 200 bytes, is the summary.
homepagenoAn http or https address.
iconnoOnly icon.png, the picture at the package's top. Anything else is refused.
tagsyes1 to 4 of the nine tags below, none repeated.
works-withyes1 to 32 conditions, no id twice. A star means any mod and the base game, and it is then the only entry. ta-3.1c means the base game with no mod. Any other id is a mod, with an optional version range.
requiresnoOnly engine and expansions. engine is a range, quoted when it starts with a greater-than sign. expansions is 1 to 16 bundle ids. A brain cannot require a mutator.
levelsyes1 to 6 levels. Each mapping is exactly id, name and difficulty.
fullAwarenessnotrue or false. Absent means false. A quoted true is refused.
networksno1 to 16, each exactly id, file and sha256. file is nets/ and a stem ending .oann. sha256 is 64 lower-case hex digits in quotes.
optionsnoAt most 16, the mutator's option rules. A toggle is true or false, a number is a number, and a choice is its text. me.options reads them.
stringsnoAt most 16 languages. A language may hold name, description, options, labels and levels.
entrynoA Lua file at the package's top, named with lower-case letters, digits and _. Absent means brain.lua.

The nine tags

A tag is one of these nine, compared byte for byte. More than four, when the shared tag rule has already passed, is its own problem. A tag that is not one of the nine is refused.

Key
classic
economy
rush
turtle
air
naval
learned
teaching
experimental

Levels and difficulty

levels is a list of 1 to 6 mappings. Each is exactly id, name and difficulty, all required. id is lower-case kebab-case of 1 to 32 bytes, and no id is repeated. name is 1 to 64 bytes with no control character. difficulty is easy, medium or hard, byte for byte.

Those three names are the values 0, 1 and 2. A seat that picks the level uses that value as its income rules, the same difficulty the game already uses.

Full awareness

fullAwareness is true or false. Absent means false. A brain with the flag sees units a seat in the fog would not, the way the built-in computer player does, and its site checks do not need a placing player. The flag is allowed in a network game. The Library shows Sees every unit on the map, as Total Annihilation's own computer player does. The flag is the manifest's own. It is not granted by the package id, and it is not one of the things only Classic is given.

Where a brain runs

Only the machine that seats the computer player needs the package, and only that machine runs the script. A seat is a computer player of this machine. A human seat is refused. game.mode is skirmish, campaign or network.

SituationWhat runs
SkirmishEach computer seat this machine plays, when a player set a brain on it. An empty id is the built-in computer player.
Campaign missionThe campaign seat follows the default brain the player set. A mission does not ignore that default.
Network gameThe machine that owns the computer seat runs the brain, full awareness included. The other machines do not.
Saved game loaded laterThe save names each seat. The standard says what happens when the package is missing or the version differs.
Recording played backThe recording stores the brains text. Playback applies the recorded packets. It does not seat a brain and does not call its hooks.
Deathmatch or tournamentThe launch seats no computer players.

The brain a seat plays is not an input of the simulation hash. Two matches that differ only in which brain is seated keep the same match state hash. The mod's ai.* hack values are part of the mod profile that hash covers, so they still reach every machine.

The runtime's budgets

A brain runs as Lua in one sandbox. Two brains share no modules, no globals and no budgets. The script has no file, no clock, no environment, no process and no network. Every chunk is loaded as text. pcall and xpcall cannot keep a spent phase alive. A turn is one banked call, at the seat's controller point, after the unit sweep. Orders a hook gives take effect in the next tick.

BudgetValue
Instructions in load, fits, start, save and report50,000,000
Instructions one tick adds2,000,000
Ticks the bank may hold, the current tick included30, so the balance opens at 60,000,000
Lua memory64 MiB (67,108,864 bytes). It is not reset between phases.
Network memory64 MiB, separate from the Lua cap
Real time, a phase that is not a turn, in milliseconds10,000
Real time, one turn, in milliseconds250
One string, in bytes65,536

When a brain fails

A brain stops for an error in a hook or a timer, a spent instruction allowance, the real-time backstop, the Lua memory cap, a string past 65,536 bytes, or a load the seat refuses. A failed turn closes the sandbox and clears the hooks before that turn returns. The failing turn still counts as played. The next order tick has no hooks, so the built-in computer player takes it. A brain that is refused, fails to start, or does not fit never has hooks, so that player plays from the start. The notice uses the manifest name and the reason, cut to 160 bytes:

- `{brain} stopped ({reason}); the engine plays this seat on`
- `{brain} could not start ({reason}); the engine plays this seat`
- `{brain} does not fit this game ({reason}); the engine plays this seat`

When the seat has no reason of its own, the reason is the brain could not be seated. A defeated player is simply no longer called. The sandbox closes with the match.