[
 {
  "name": "status",
  "category": "meta",
  "status": "verified",
  "mechanism": "World block + fast lane + claim table",
  "latency": "Local compute",
  "signature": "status() -> 'dict'",
  "doc": "Connection status: pid, world publishing (period, sampling time), fast lane counters."
 },
 {
  "name": "snapshot",
  "category": "observe",
  "status": "verified",
  "mechanism": "W3P world block Local\\War3World_<pid> (pushed by the runtime every 50 ms, seqlock)",
  "latency": "Pushed snapshot",
  "signature": "snapshot(max_age: 'float' = 0.05)",
  "doc": "Full state of the whole map (WorldState): .units .players .items .clock .me; repeated calls within max_age seconds return the same copy.\n⚠ Workers inside a gold mine are not in the list; by default the whole map is visible (in the lockstep model everything exists locally), and only Game(fair=True) filters by vision."
 },
 {
  "name": "last_seen",
  "category": "observe",
  "status": "verified",
  "mechanism": "visibleTo of the pushed snapshot (every snapshot refresh records the visible enemy/creep units)",
  "latency": "Pushed snapshot",
  "signature": "last_seen(owner: 'str | int' = 'enemy', max_age: 'float | None' = None) -> 'list'",
  "doc": "Enemy units (or 'creep' for creeps, or a given player number) as last seen: [(the unit as it was then, the game clock at that time, seconds elapsed since)], newest first.\nUnits seen dying are removed from the list. Both fair mode and normal mode record based on \"what we can see right now\" — this is the map in a player's head:\nscouted army, where the enemy hero was last seen, when the enemy expansion went up. max_age keeps only entries from within that many game seconds."
 },
 {
  "name": "map",
  "category": "observe",
  "status": "verified",
  "mechanism": "W3P map block Local\\War3Map_<pid> (computed in batches by the runtime after the game starts; IsTerrainPathable walk/build)",
  "latency": "Pushed snapshot",
  "signature": "map()",
  "doc": "This game's terrain table MapInfo: .walkable(x,y) .buildable(x,y) .at(x,y) .bounds (playable area) .starts (start locations) .cells (bit0 unwalkable, bit1 unbuildable).\nIt takes a few seconds after the game starts to compute; returns None until it's ready. Trees aren't included (use trees())."
 },
 {
  "name": "me",
  "category": "observe",
  "status": "verified",
  "mechanism": "World block header",
  "latency": "Pushed snapshot",
  "signature": "me() -> 'int | None'",
  "doc": "Which player number I am (0~11)."
 },
 {
  "name": "resources",
  "category": "observe",
  "status": "verified",
  "mechanism": "World block players[16]",
  "latency": "Pushed snapshot",
  "signature": "resources(player: 'int | None' = None) -> 'dict | None'",
  "doc": "{'gold','lumber','food_used','food_cap','gold_gathered','lumber_gathered'}; player defaults to us, and any player can be read.\nReturns None when it can't be read — don't treat that as 0."
 },
 {
  "name": "players",
  "category": "observe",
  "status": "verified",
  "mechanism": "World block players[16]",
  "latency": "Pushed snapshot",
  "signature": "players() -> 'list'",
  "doc": "All 16 player slots: Player(id, gold, lumber, food_used, food_cap, gold_gathered, lumber_gathered, race, known)."
 },
 {
  "name": "units",
  "category": "observe",
  "status": "verified",
  "mechanism": "World block units[]",
  "latency": "Pushed snapshot",
  "signature": "units(owner: 'str | int' = 'all', types=None, alive: 'bool' = True) -> 'list'",
  "doc": "Filter units by owner/type. owner: 'me' / 'enemy' / 'creep' / 'all' / player number. types: a set of four-character codes."
 },
 {
  "name": "unit",
  "category": "observe",
  "status": "verified",
  "mechanism": "World block by_handle",
  "latency": "Pushed snapshot",
  "signature": "unit(handle) -> 'object | None'",
  "doc": "Find a unit by handle pair (lo, hi) (order targets, task targets and events all give handle pairs)."
 },
 {
  "name": "is_building",
  "category": "observe",
  "status": "verified",
  "mechanism": "Snapshot + units.json (spd==0 = building)",
  "latency": "Pushed snapshot",
  "signature": "is_building(u) -> 'bool'",
  "doc": "Whether it's a building (including towers). Determined by movement speed 0 in the unit table; the Undead hall has a footprint of 0, so don't go by footprint."
 },
 {
  "name": "my_workers",
  "category": "observe",
  "status": "verified",
  "mechanism": "Pushed snapshot",
  "latency": "Pushed snapshot",
  "signature": "my_workers() -> 'list'",
  "doc": "Our workers (Peasants/Peons/Acolytes/Wisps)."
 },
 {
  "name": "idle_workers",
  "category": "observe",
  "status": "verified",
  "mechanism": "Pushed snapshot (order slot + task slot)",
  "latency": "Pushed snapshot",
  "signature": "idle_workers() -> 'list'",
  "doc": "Workers with nothing to do: no order and no task (workers you just gave a job this tick don't count).\n⚠ Re-issuing a gather order to a worker that has a task interrupts its harvest cycle (income drops to zero)."
 },
 {
  "name": "my_heroes",
  "category": "observe",
  "status": "verified",
  "mechanism": "Pushed snapshot",
  "latency": "Pushed snapshot",
  "signature": "my_heroes() -> 'list'",
  "doc": "Our living heroes (dead ones are in the altar's revive list; see revive)."
 },
 {
  "name": "my_army",
  "category": "observe",
  "status": "verified",
  "mechanism": "Pushed snapshot + units.json",
  "latency": "Pushed snapshot",
  "signature": "my_army() -> 'list'",
  "doc": "Our combat units: not workers, not buildings."
 },
 {
  "name": "my_buildings",
  "category": "observe",
  "status": "verified",
  "mechanism": "Pushed snapshot",
  "latency": "Pushed snapshot",
  "signature": "my_buildings(types=None) -> 'list'",
  "doc": "Our buildings (including towers and foundations under construction); types can restrict it to certain kinds, e.g. {'hbar'}."
 },
 {
  "name": "is_constructing",
  "category": "observe",
  "status": "verified",
  "mechanism": "Pushed snapshot (order = building four-character code, or construction/repair order)",
  "latency": "Pushed snapshot",
  "signature": "is_constructing(worker) -> 'bool'",
  "doc": "Whether this worker is building something (or walking over to build / helping repair; includes jobs assigned this tick). Skip it when picking a builder, otherwise the previous foundation stops."
 },
 {
  "name": "under_construction",
  "category": "observe",
  "status": "verified",
  "mechanism": "Pushed snapshot (a foundation's HP climbs from very low all the way to full)",
  "latency": "Pushed snapshot",
  "signature": "under_construction(building) -> 'bool'",
  "doc": "This building isn't finished yet (HP not full). ⚠ Damaged buildings aren't at full HP either — good enough for the opening, but once fighting starts, combine it with timing."
 },
 {
  "name": "gold_mines",
  "category": "observe",
  "status": "verified",
  "mechanism": "Pushed snapshot (ngol/egol/ugol)",
  "latency": "Pushed snapshot",
  "signature": "gold_mines() -> 'list'",
  "doc": "Gold mines on the map. ⚠ A Night Elf Entangled Gold Mine and the neutral gold mine are two separate units at the same coordinates; send harvesters to your own one."
 },
 {
  "name": "enemies",
  "category": "observe",
  "status": "verified",
  "mechanism": "Pushed snapshot",
  "latency": "Pushed snapshot",
  "signature": "enemies(fighters_only: 'bool' = False) -> 'list'",
  "doc": "Units belonging to enemy players (not creeps). fighters_only: excludes workers and buildings."
 },
 {
  "name": "creeps",
  "category": "observe",
  "status": "verified",
  "mechanism": "Pushed snapshot (owner 12 = neutral hostile)",
  "latency": "Pushed snapshot",
  "signature": "creeps() -> 'list'",
  "doc": "Creeps (neutral hostile). ⚠ Vision shrinks at night; once distant camps fall into the fog of war, target commands on them are rejected (reason code 1001)."
 },
 {
  "name": "nearest",
  "category": "meta",
  "status": "verified",
  "mechanism": "Pure computation",
  "latency": "Local compute",
  "signature": "nearest(candidates, to)",
  "doc": "The one closest to to (a unit or (x,y)); returns None if there are no candidates."
 },
 {
  "name": "life_mana",
  "category": "observe",
  "status": "verified",
  "mechanism": "World block unit hp/hpMax/mana/manaMax",
  "latency": "Pushed snapshot",
  "signature": "life_mana(u) -> 'dict | None'",
  "doc": "{'hp','hp_max','mana','mana_max'} (floats, raw engine values). Passing the unit you got from a snapshot is fine (it's swapped for the latest copy)."
 },
 {
  "name": "hero_info",
  "category": "observe",
  "status": "verified",
  "mechanism": "World block unit level/xp/skillPoints",
  "latency": "Pushed snapshot",
  "signature": "hero_info(hero) -> 'dict | None'",
  "doc": "{'level','xp','skill_points'}."
 },
 {
  "name": "abilities",
  "category": "observe",
  "status": "verified",
  "mechanism": "World block details: abilities (code/level/flags/cooldown remaining)",
  "latency": "Pushed snapshot",
  "signature": "abilities(u) -> 'list'",
  "doc": "[{code, level, cooldown, flags}]; buffs are in buffs(u). Only available for units that \"have details\" (heroes > player units > creeps, up to 256)."
 },
 {
  "name": "buffs",
  "category": "observe",
  "status": "verified",
  "mechanism": "World block details: ability objects starting with B",
  "latency": "Pushed snapshot",
  "signature": "buffs(u) -> 'list'",
  "doc": "Buff codes on the unit (e.g. 'BHds' Divine Shield, 'Bslo' Slow). See data/game/buffs.json for what each code does."
 },
 {
  "name": "cooldown",
  "category": "observe",
  "status": "verified",
  "mechanism": "World block details: ability cooldown remaining (ability timer)",
  "latency": "Pushed snapshot",
  "signature": "cooldown(u, ability: 'str') -> 'float | None'",
  "doc": "Seconds of cooldown left on this ability (game seconds); 0 = ready to cast; returns None if the unit doesn't have this ability (or has no details)."
 },
 {
  "name": "inventory",
  "category": "observe",
  "status": "verified",
  "mechanism": "World block details: 6 inventory slots",
  "latency": "Pushed snapshot",
  "signature": "inventory(hero) -> 'list | None'",
  "doc": "Four-character codes of the 6 item slots (None for empty slots); returns None if there's no inventory."
 },
 {
  "name": "current_order",
  "category": "observe",
  "status": "verified",
  "mechanism": "World block unit order / order target / order target point",
  "latency": "Pushed snapshot",
  "signature": "current_order(u) -> 'dict | None'",
  "doc": "{'order','target','x','y'}: the order the unit is currently carrying out (order is 0x000D00xx or a building four-character code; 0 = idle).\ntarget is a handle pair; use g.unit(target) to turn it into a unit."
 },
 {
  "name": "current_target",
  "category": "observe",
  "status": "verified",
  "mechanism": "World block unit task target",
  "latency": "Pushed snapshot",
  "signature": "current_target(u)",
  "doc": "The unit it is **actually attacking/chasing** (None if there isn't one).\n⚠ After an attack order, the order slot quickly empties and the attack hangs on the task — to tell \"what it's attacking\", use this, not current_order."
 },
 {
  "name": "clock",
  "category": "observe",
  "status": "verified",
  "mechanism": "World block header clockMs (engine game clock)",
  "latency": "Pushed snapshot",
  "signature": "clock() -> 'float | None'",
  "doc": "Engine game clock (game seconds; 0 while loading). At higher game speeds it runs faster than the wall clock."
 },
 {
  "name": "production",
  "category": "observe",
  "status": "verified",
  "mechanism": "World block production table (Aque/ABnP/AUnP ability objects + elapsed time tracked by the runtime; measured error < 0.2 game seconds)",
  "latency": "Pushed snapshot",
  "signature": "production(building)",
  "doc": "What this building is producing: Production(kind, queue, duration, elapsed, blocked, progress, remaining…); returns None if it's idle.\n  kind 'queue' (training/research/hero; queue has up to 7 slots, [0] is the one in progress) / 'construction' (being built) / 'upgrade' (upgrading a hall/tower);\n  blocked = something is queued but hasn't started (usually not enough food — time to build a Farm); progress 0..1.\nOpponents' buildings can be inspected too (in fair mode, only buildings you can see)."
 },
 {
  "name": "queue",
  "category": "observe",
  "status": "verified",
  "mechanism": "World block production table",
  "latency": "Pushed snapshot",
  "signature": "queue(building) -> 'list'",
  "doc": "Four-character codes in the training/research queue ([0] is in progress); idle or not a production building = []."
 },
 {
  "name": "all_production",
  "category": "observe",
  "status": "verified",
  "mechanism": "World block production table",
  "latency": "Pushed snapshot",
  "signature": "all_production(owner: 'str | int' = 'me') -> 'list'",
  "doc": "All production in progress [(building, Production)]. owner works like units(): 'me' / 'enemy' / player number / 'all'.\nPro use: see what units the opponent is training, what tech it's researching, and when it tiers up (once you've scouted the buildings)."
 },
 {
  "name": "path_distance",
  "category": "observe",
  "status": "verified",
  "mechanism": "Map block (engine IsTerrainPathable) + tree block + building footprints, A* on the SDK side (128 per cell)",
  "latency": "Pushed snapshot + local compute",
  "signature": "path_distance(a, b) -> 'float | None'",
  "doc": "Walking distance for a ground unit from a to b (a and b can be units or (x,y)); None if unreachable. On island maps, use this to decide \"can ground units reach this creep camp/expansion\" —\nit's more reliable than straight-line distance (it goes around forests, cliffs and buildings). Precision is one 128 cell; gaps narrower than a cell count as blocked."
 },
 {
  "name": "reachable",
  "category": "observe",
  "status": "verified",
  "mechanism": "Same as above",
  "latency": "Pushed snapshot + local compute",
  "signature": "reachable(a, b) -> 'bool | None'",
  "doc": "Whether it can be reached on the ground (map block not ready = None)."
 },
 {
  "name": "walk_path",
  "category": "observe",
  "status": "verified",
  "mechanism": "Same as above",
  "latency": "Pushed snapshot + local compute",
  "signature": "walk_path(a, b) -> 'list | None'",
  "doc": "Path corner points [(x,y)...] (the last point is b); combine with path(units, points) to move the army along this route (around towers, via side paths)."
 },
 {
  "name": "upkeep",
  "category": "observe",
  "status": "inferred",
  "mechanism": "Fixed 1.27 rule: 0~50 food no upkeep, 51~80 income ×0.7, 81~100 ×0.4",
  "latency": "Pushed snapshot",
  "signature": "upkeep(player: 'int | None' = None) -> 'dict | None'",
  "doc": "Upkeep level: {'level': 'none'/'low'/'high', 'income': 1.0/0.7/0.4, 'next_at': food count at which the next level starts (None if there isn't one)}.\nPro common knowledge: stay at 50 food while teching to tier 3 / getting attack/armor upgrades, and only go up to 80 right before the decisive fight."
 },
 {
  "name": "xp_to_next",
  "category": "observe",
  "status": "verified",
  "mechanism": "World block level/xp + MiscGame NeedHeroXP formula",
  "latency": "Pushed snapshot",
  "signature": "xp_to_next(hero) -> 'int | None'",
  "doc": "How much XP the hero still needs for the next level (level 10 = 0)."
 },
 {
  "name": "creep_camps",
  "category": "observe",
  "status": "verified",
  "mechanism": "Pushed snapshot (creeps within 600 of each other are grouped together) + levels from units.json",
  "latency": "Pushed snapshot",
  "signature": "creep_camps(link: 'float' = 600.0) -> 'list'",
  "doc": "Groups the (visible) creeps on the map into camps: [{'x','y','units','level','hp','max_level'}], sorted from nearest to farthest from our main base.\nlevel = total camp level (the usual measure of creeping difficulty), hp = total HP. Combine with time_to_kill / path_distance to pick camps."
 },
 {
  "name": "buff_info",
  "category": "observe",
  "status": "verified",
  "mechanism": "data/game/buffs.json (BuffID -> ability/effect/duration from AbilityData.slk)",
  "latency": "Local data",
  "signature": "buff_info(code: 'str') -> 'dict | None'",
  "doc": "What a buff code is: {'ability','effect','dur','hero_dur','targets'} (e.g. 'Bslo' -> Slow). When a code has multiple rows, the first row is returned."
 },
 {
  "name": "stats",
  "category": "observe",
  "status": "verified",
  "mechanism": "Data tables (UnitBalance/UnitWeapons/UpgradeData/MiscGame) + live tech levels + hero level",
  "latency": "Pushed snapshot + fast lane (batched every 5 s)",
  "signature": "stats(u, player: 'int | None' = None)",
  "doc": "The unit's combat stats combat.UnitStats: max HP/mana, armor (including attack/armor upgrades and hero agility), armor type, movement speed, day/night sight range,\nweapons (what it can hit, range, attack cooldown, damage range, attack type, splash). u is a unit (automatically uses its owner's tech and its hero level) or a four-character code (player defaults to us).\nThen use .dps_vs(other) / .hits_to_kill(other) / combat.time_to_kill(group, other). ⚠ Doesn't include items, auras or buffs."
 },
 {
  "name": "time_to_kill",
  "category": "observe",
  "status": "verified",
  "mechanism": "stats() + live HP",
  "latency": "Pushed snapshot",
  "signature": "time_to_kill(attackers, target) -> 'float | None'",
  "doc": "How many game seconds this group of units needs to kill target together (uses target's current HP; accounts for counters, armor and attack/armor upgrades; not for movement, splash or healing).\nPro use: focus fire the one that \"dies fastest\" (smallest time_to_kill) first, not the closest one. Can't hit it = None."
 },
 {
  "name": "time_of_day",
  "category": "observe",
  "status": "verified",
  "mechanism": "World block extension area: GetFloatGameState(GAME_STATE_TIME_OF_DAY)",
  "latency": "Pushed snapshot",
  "signature": "time_of_day() -> 'float | None'",
  "doc": "In-game time of day (hours, 0~24). The game starts at 8 AM; a full day = 480 game seconds (240 seconds each for day and night, scaled by the day/night speed).\nReturns None when it can't be read (old runtime / not in a game)."
 },
 {
  "name": "is_night",
  "category": "observe",
  "status": "verified",
  "mechanism": "World block extension area (daytime is 6~18)",
  "latency": "Pushed snapshot",
  "signature": "is_night() -> 'bool | None'",
  "doc": "Whether it's night now (18:00~6:00). Pro play: at night creeps are asleep (you get the first hit when creeping, without being surrounded), and every unit's sight range shrinks (a good time for surprise attacks);\nNight Elf Sentinels/units are invisible next to trees at night. Returns None when it can't be read."
 },
 {
  "name": "seconds_until",
  "category": "observe",
  "status": "verified",
  "mechanism": "World block extension area + a 480-second day (measured 20 game seconds per hour)",
  "latency": "Pushed snapshot",
  "signature": "seconds_until(hour: 'float') -> 'float | None'",
  "doc": "Game seconds until the in-game time reaches hour o'clock (e.g. seconds_until(18) = time until nightfall, for planning night creeping)."
 },
 {
  "name": "items_on_ground",
  "category": "observe",
  "status": "verified",
  "mechanism": "World block items[] (ground items only: holder handle is all FF)",
  "latency": "Pushed snapshot",
  "signature": "items_on_ground() -> 'list'",
  "doc": "Items on the ground [Item(addr, handle_lo, handle_hi, type, x, y, life)]. Picking one up or using it emits an item.removed event."
 },
 {
  "name": "trees",
  "category": "observe",
  "status": "verified",
  "mechanism": "Tree block Local\\War3Trees_<pid> (refreshed every 2 seconds)",
  "latency": "Pushed snapshot",
  "signature": "trees(x: 'float | None' = None, y: 'float | None' = None, limit: 'int' = 60) -> 'list'",
  "doc": "Living trees (those whose targType in DestructableData includes tree); given (x,y), sorted from nearest to farthest, up to limit trees.\nEach is Tree(addr, handle_lo, handle_hi, type, x, y, life), and can be passed straight to gather to harvest lumber."
 },
 {
  "name": "events",
  "category": "observe",
  "status": "verified",
  "mechanism": "Event ring Local\\War3Events_<pid> (publish diffing + damage events captured by the runtime)",
  "latency": "Pushed snapshot",
  "signature": "events() -> 'list'",
  "doc": "What happened since the last call: unit.appeared / unit.died / unit.removed / unit.damaged / order.changed /\nhero.levelup / owner.changed / item.appeared / item.removed / game.started (these come from diffing publishes; precision = publish period 50 ms),\nplus the engine-level damage / killed (the runtime records them on the game thread as they happen, so there's one for **every single hit**):\n    damage: handle = the unit being hit, .source_addr = who hit it (snapshot().unit_by_addr turns it into a unit), .value = actual HP lost,\n            .raw_damage = pre-armor damage, .attack_type (normal/pierce/siege/magic/chaos/hero/spell), .damage_type\n    killed: this hit killed it, .source_addr = the killer\nplus production.done, derived by the runtime tracking the production table (precision = publish period): unit = the building, .done_code = four-character code of what finished,\n    .done_kind = 'training' (units/heroes/revives) / 'research' / 'construction' (building completed) / 'upgrade' (tier-up/tower upgrade), .value = game seconds taken\nAdded 09-25:\n    spell.cast: unit = the caster, .spell spell four-character code, b level, value cooldown seconds, x,y cast point (recognized when the spell's cooldown starts; precision = publish period)\n    player.left: .player the number of the player who left / was removed after being defeated; game.ended: left the game\n    selection.changed: the local player's selection changed (get the units with g.selection())\n    message: a line in an on-screen message frame (game hints, chat, system): .text full text, .frame message frame number,\n             .chat = {'channel', 'sender', 'text'} (when it's chat; this is where you read what the player typed in the chat box)\n    ui.click / ui.hover / hotkey / mouse.world: UI & input (g.ui); .key is the canvas key / hotkey string\nEach one is Event(seq, kind, clock, addr, handle, type, owner, a, b, x, y, value, extra).\nFair mode (fair=True) only gives: events for your own units, events for units visible right now (or still visible within the last 1 second), damage dealt to us or by us,\nand local UI / message / game events."
 },
 {
  "name": "selection",
  "category": "observe",
  "status": "verified",
  "mechanism": "W3P world block extension area selAddrs (the runtime includes the local player's selection in every publish)",
  "latency": "Pushed snapshot",
  "signature": "selection() -> 'list'",
  "doc": "The units the local player has selected right now (the main unit comes first; up to 12). Any change to the selection fires a selection.changed event."
 },
 {
  "name": "messages",
  "category": "observe",
  "status": "verified",
  "mechanism": "Shared memory Local\\War3Msgs_<pid> (screen messages captured by the runtime)",
  "latency": "Pushed snapshot",
  "signature": "messages() -> 'list'",
  "doc": "Messages newly shown in the on-screen message frames since the last call: [{'text', 'frame', 'repeat', 'seq', 'game_ms'}].\nGame hints (\"You need more farms\", \"Can't build there\"), chat and system messages are all here; frame tells you which message frame.\nSame batch as the message events in the event stream (each has its own cursor)."
 },
 {
  "name": "ui",
  "category": "control",
  "status": "verified",
  "mechanism": "W3P 74 input_enable + shared memory Local\\War3Input_<pid> (the runtime receives window input)",
  "latency": "Shared memory",
  "signature": "ui()",
  "doc": "UI & input (openwar3.ui.UI): clickable buttons and choice cards, hotkeys, picking a position by clicking the ground, where the mouse is pointing.\nThe game never receives the click that lands on a button; pure local input + local drawing, so it's safe in multiplayer."
 },
 {
  "name": "tech",
  "category": "observe",
  "status": "verified",
  "mechanism": "W3P query q_tech (the engine's player tech count)",
  "latency": "Fast lane",
  "signature": "tech(code: 'str', player: 'int | None' = None) -> 'int | None'",
  "doc": "Research level / number of completed buildings (upgrade chains count: a Castle also counts as htow). player defaults to us; any player can be queried."
 },
 {
  "name": "can_do",
  "category": "observe",
  "status": "verified",
  "mechanism": "W3P query q_feasible (engine feasibility check)",
  "latency": "Fast lane",
  "signature": "can_do(u, code: 'str') -> 'int | None'",
  "doc": "The engine's feasibility verdict: 0/220 OK; 3 not enough food, 8 not enough gold, 9 not enough lumber, 32 queue full, 183 missing prerequisite, 185 altar is reviving, 221 no such item/under construction.\n⚠ Always 221 for a worker constructing a building, so it can't be used to check placement (use build_near)."
 },
 {
  "name": "can_do_many",
  "category": "observe",
  "status": "verified",
  "mechanism": "W3P query q_feasible × N, submitted as one batch",
  "latency": "Fast lane × 1",
  "signature": "can_do_many(pairs) -> 'list'",
  "doc": "Ask many can_do at once: pairs = [(unit, four-character code), ...]; returns a list of verdict codes in the same order (None where it couldn't be asked).\nWhen planning what to build/train in a tick, ask about everything at once first — N times faster than one can_do at a time (reference brain 09-23: build planning 76 -> 25 ms)."
 },
 {
  "name": "tech_many",
  "category": "observe",
  "status": "verified",
  "mechanism": "W3P query q_tech × N, submitted as one batch",
  "latency": "Fast lane × 1",
  "signature": "tech_many(codes, player: 'int | None' = None) -> 'dict'",
  "doc": "Look up many tech/building counts at once: {four-character code: count or None}."
 },
 {
  "name": "visible",
  "category": "observe",
  "status": "verified",
  "mechanism": "W3P query q_visible (visible / fog of war / black mask)",
  "latency": "Fast lane",
  "signature": "visible(x: 'float', y: 'float') -> 'bool | None'",
  "doc": "Whether we can see this point right now (not in the fog of war/black mask). Bots in fair mode should only use visible enemies."
 },
 {
  "name": "gold_left",
  "category": "observe",
  "status": "inferred",
  "mechanism": "W3P query q_mine_gold (the engine's remaining gold in the mine)",
  "latency": "Fast lane",
  "signature": "gold_left(mine) -> 'int | None'",
  "doc": "How much gold is left in a gold mine."
 },
 {
  "name": "enemy_ai_plan",
  "category": "observe",
  "status": "verified",
  "mechanism": "W3P query q_captain (the computer captain that enemy units follow)",
  "latency": "Fast lane",
  "signature": "enemy_ai_plan(enemy_unit) -> 'dict | None'",
  "doc": "The computer AI's captain: where it's taking its army (you know which part of your base it will attack before it leaves home). Only works against computer opponents; returns None if the unit isn't following a captain."
 },
 {
  "name": "batch",
  "category": "command",
  "status": "verified",
  "mechanism": "Commands in the block are gathered into one batch and submitted once when the block ends (executed in the same frame, waiting on the game thread only once)",
  "latency": "Fast lane × 1",
  "signature": "batch() -> 'Batch'",
  "doc": "Combine a tick's commands into one batch:\n\n    with g.batch() as b:\n        g.attack(archers, target)          # returns Pending; becomes a receipt only after the block ends\n        g.move(wounded, *home)\n        g.cast(hero, \"thunderclap\")\n    print(b.sent, b.wait_ms, [r.reason for r in b.receipts])\n\nSent one by one, every command waits for the game thread once (about 10 ms); a batch waits only once — this is how the reference brain cut a round from 48 -> 26 ms on 09-23.\n* Claims are still checked per command (a unit held by someone else gets a held receipt immediately and isn't added to the batch);\n* Commands inside the block return Pending: reading its .ok before the block ends raises an error (the receipt doesn't exist yet); after the block ends, use it like a Receipt;\n* An exception inside the block = the whole batch is discarded (status 97 cancelled), and the units it held are released;\n* Queries (can_do / tech / visible …), build_near and buy aren't batched and are still asked immediately — their results are needed on the spot;\n  to ask about many things at once, use can_do_many / tech_many;\n* A nested with g.batch() merges into the outermost batch; beyond 16 commands the runtime automatically splits it into several segments (one wait per segment)."
 },
 {
  "name": "order_of",
  "category": "observe",
  "status": "verified",
  "mechanism": "Snapshot order + commands just accepted in this process (receipts)",
  "latency": "Pushed snapshot",
  "signature": "order_of(u) -> 'int | None'",
  "doc": "The unit's current order, **including ones you just issued this tick** (uses the new order from the receipt until the snapshot catches up).\n⚠ 09-23 live game: hello_bot had just sent a peasant to build a Farm, and in the same tick rush_bot saw it as \"idle\" in the snapshot and sent it to build Barracks, so the Farm was abandoned halfway over and over.\n  When picking \"idle/not building\" units, use this instead of u.order."
 },
 {
  "name": "move",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P point: move (extra bits = queue mode)",
  "latency": "Fast lane",
  "signature": "move(units, x: 'float', y: 'float', queue: 'str | None' = None)",
  "doc": "Move to (x,y) without fighting on the way (use this for retreating). Accepts a single unit or a list (ordered together in the same frame).\nqueue='after': go after finishing the current task (inserted after the current order). Receipt values[0] = how many orders this unit has queued after the command (including the current one)."
 },
 {
  "name": "attack_move",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P point: attack at a point",
  "latency": "Fast lane",
  "signature": "attack_move(units, x: 'float', y: 'float', queue: 'str | None' = None)",
  "doc": "Attack-move (A-click on the ground): attacks any enemy met on the way. queue works like move."
 },
 {
  "name": "attack",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P target: target command (right-click smart)",
  "latency": "Fast lane",
  "signature": "attack(units, target, force: 'bool' = False, queue: 'str | None' = None)",
  "doc": "Attack target. Uses right-click by default (on an enemy = attack this one; measured 09-23: both the order target and the task target are it).\n⚠ The target must be in vision; targets you can't see are rejected (reason code 1001).\nforce=True uses the attack order 0x0F (needed to attack your own units/neutral critters) — measured: it only switches to the attack order and doesn't remember the target,\nso the unit goes off to attack other enemies nearby. Don't use it to attack a specific target."
 },
 {
  "name": "stop",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P immediate: stop",
  "latency": "Fast lane",
  "signature": "stop(units)",
  "doc": "Stop everything it's doing (order ID 0x000D0004), and clear queued orders too."
 },
 {
  "name": "hold",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P immediate: holdposition",
  "latency": "Fast lane",
  "signature": "hold(units, queue: 'str | None' = None)",
  "doc": "Hold position (doesn't chase; only attacks what's in range)."
 },
 {
  "name": "patrol",
  "category": "command",
  "status": "inferred",
  "mechanism": "W3P point: patrol",
  "latency": "Fast lane",
  "signature": "patrol(units, x: 'float', y: 'float', queue: 'str | None' = None)",
  "doc": "Patrol between the current position and (x,y)."
 },
 {
  "name": "attack_ground",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P point: attackground (siege units / Mortar Teams / Demolishers)",
  "latency": "Fast lane",
  "signature": "attack_ground(units, x: 'float', y: 'float', queue: 'str | None' = None)",
  "doc": "Attack ground: artillery fires at an area (to hit invisible units, units behind trees, or to block a choke point). Only units that can attack ground accept it."
 },
 {
  "name": "cancel",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P immediate: cancel",
  "latency": "Fast lane",
  "signature": "cancel(building)",
  "doc": "Cancel: the last slot of the training/research queue (refunded), a building under construction (75% refunded), or a hall that's upgrading."
 },
 {
  "name": "path",
  "category": "command",
  "status": "verified",
  "mechanism": "One batch: the first leg runs immediately, the rest are inserted in reverse order with queue='after' (the engine can only insert right after the current order)",
  "latency": "Fast lane × 1",
  "signature": "path(units, points, attack: 'bool' = False)",
  "doc": "Move through a series of points in order (Shift-click waypoints: patrol routes, routing around towers, scouting routes). attack=True makes every leg an attack-move.\nSubmitted once; one receipt per point (in points order)."
 },
 {
  "name": "gather",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P target: harvest (gold mine or tree)",
  "latency": "Fast lane",
  "signature": "gather(workers, target, queue: 'str | None' = None)",
  "doc": "Harvest gold/lumber (target is a gold mine or a tree from trees()). ⚠ Only assign idle workers (idle_workers): re-issuing to a worker that has a task interrupts its harvest cycle.\nPro use: go back to mining after building = gather(worker, mine, queue='after') after build(...)."
 },
 {
  "name": "repair",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P target: repair",
  "latency": "Fast lane",
  "signature": "repair(workers, building, queue: 'str | None' = None)",
  "doc": "Repair / help build (Human and Orc construction sites stop when nobody is building them)."
 },
 {
  "name": "build",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P build: build order, with the worker's order read back in the same frame to confirm",
  "latency": "Fast lane",
  "signature": "build(worker, code: 'str', x: 'float', y: 'float', queue: 'str | None' = None)",
  "doc": "Have a worker build code at (x,y) (coordinates aligned to a 32 grid). Receipt accepted = the worker's order is now this building (or the start-construction order);\nwith queue='after' = added to the worker's order queue (receipt values[0] is the queue count).\n⚠ Accepted ≠ built: the engine also accepts a spot inside a forest on the spot, and the worker only fails once it gets there (measured 09-23); gold being spent elsewhere can also keep the foundation from appearing.\nIf you don't know where it fits, use build_near (it tracks the result and blacklists failed spots). To build several in a row, use build_queue."
 },
 {
  "name": "build_queue",
  "category": "command",
  "status": "verified",
  "mechanism": "One batch: the first immediately, the rest in reverse order with queue='after'",
  "latency": "Fast lane × 1",
  "signature": "build_queue(worker, plan)",
  "doc": "One worker builds several in order (Shift-queued building): plan = [(four-character code, x, y), ...]. Submitted once; receipts in plan order.\n⚠ Gold is deducted only when construction starts (not when queued) — if you queue 3 but can only afford 1, the other two fail when the worker gets there."
 },
 {
  "name": "build_near",
  "category": "command",
  "status": "verified",
  "mechanism": "Per-point build + tracking (foundation appears = success; worker drops the order with no foundation = that spot is blacklisted)",
  "latency": "Fast lane × points tried",
  "signature": "build_near(worker, code: 'str', x: 'float', y: 'float', min_r: 'float' = 450, max_r: 'float' = 1500, max_tries: 'int' = 24)",
  "doc": "Find a spot that fits around (x,y), searching from near to far, and build code there. **Non-blocking** — fine to call every tick:\n  * An attempt for this building type is still in progress (the worker is on its way) -> returns that spot without re-issuing the order;\n  * The last attempt succeeded (the foundation appeared) -> finds a new spot this time if needed;\n  * The last attempt failed (the worker found on arrival that it didn't fit, the engine dropped the order, no foundation) -> that spot is blacklisted for 45 seconds and the next one is tried;\n  * Not enough gold -> returns None right away (no attempt, no blacklisting); returns None once every spot has been tried.\n⚠ Why tracking is needed: in 09-23 live games, the engine **accepted on the spot** a point inside a forest, and the worker only failed once it got there (the same-frame receipt can't tell);\n  and the engine's placement check always returns 221 for a worker constructing a building, so you can't \"check\" before building either. Only obviously occupied spots (the middle of the hall) are rejected on the spot."
 },
 {
  "name": "can_afford",
  "category": "observe",
  "status": "verified",
  "mechanism": "Our resources from the pushed snapshot + prices from units.json",
  "latency": "Pushed snapshot",
  "signature": "can_afford(code: 'str') -> 'bool'",
  "doc": "Whether current gold/lumber is enough to buy code (units, buildings; by the prices in units.json). Anything missing from the price table is treated as affordable.\n⚠ Tier-up four-character codes have cumulative prices in the table, so this errs on the conservative side; the engine's receipt is the final word."
 },
 {
  "name": "train",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P immediate: four-character code, with the feasibility reason code when rejected",
  "latency": "Fast lane",
  "signature": "train(building, code: 'str')",
  "doc": "Train units / research tech / upgrade the hall (tier up = give the hall itself the target hall's four-character code, e.g. 'hkee').\nWhen rejected, the receipt's reason says why (not enough food, not enough gold, not enough lumber, queue full, missing prerequisite…)."
 },
 {
  "name": "learn",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P learn: only counts as learned once the skill points decrease",
  "latency": "Fast lane",
  "signature": "learn(hero, ability: 'str')",
  "doc": "The hero learns an ability (four-character code, e.g. 'AHbz' Blizzard)."
 },
 {
  "name": "cast",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P target / point / immediate (chosen by arguments)",
  "latency": "Fast lane",
  "signature": "cast(u, spell, target=None, x: 'float | None' = None, y: 'float | None' = None)",
  "doc": "Cast a spell. spell is an order string ('thunderbolt' Storm Bolt, 'blizzard', 'holybolt' Holy Light…; see data/order-ids.txt) or an order ID.\nGive target = on a unit; give x,y = on the ground; neither = no target (Thunder Clap, Divine Shield, Summon Water Elemental).\nAn accepted receipt only means the engine accepted it; to see whether it actually went off, check whether cooldown() shows a cooldown or buffs() shows the buff."
 },
 {
  "name": "rally",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P rally",
  "latency": "Fast lane",
  "signature": "rally(building, x: 'float | None' = None, y: 'float | None' = None, target=None)",
  "doc": "Set the rally point (on a point, or on a unit/gold mine)."
 },
 {
  "name": "revive",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P revive: dead hero list -> the altar casts revive on the dead hero",
  "latency": "Fast lane",
  "signature": "revive(altar, hero=None)",
  "doc": "Revive a dead hero at the altar (if hero isn't given, revives the first one in the list).\nCommon rejection reasons (written in the receipt's reason): not enough food (heroes cost food too), not enough gold, died too recently (a hero can only be revived about 3 game seconds after dying),\nrevive already in progress (the engine clears that slot on the spot once it's accepted)."
 },
 {
  "name": "pick_up",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P target: right-click the item",
  "latency": "Fast lane",
  "signature": "pick_up(hero, item)",
  "doc": "The hero goes to pick up an item from the ground (item comes from items_on_ground). Once picked up, it appears in the inventory and an item.removed event is emitted for the ground item."
 },
 {
  "name": "use_item",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P use_item (by slot number)",
  "latency": "Fast lane",
  "signature": "use_item(hero, slot: 'int', target=None, x: 'float | None' = None, y: 'float | None' = None)",
  "doc": "Use the item in inventory slot slot (0~5); can take a target unit or a target point.\n⚠ For point-targeted item use (e.g. Ivory Tower), the engine returns 0 even on success, so the receipt always counts as accepted — check whether that slot has emptied."
 },
 {
  "name": "drop_item",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P item_drop (mirrors JASS UnitDropItemPoint: dropitem 0xD0021 on a point + the item as the instant target)",
  "latency": "Fast lane",
  "signature": "drop_item(hero, slot: 'int', x: 'float', y: 'float')",
  "doc": "Drop the item in inventory slot slot at (x,y) (the hero walks over and puts it down)."
 },
 {
  "name": "give_item",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P item_drop (mirrors JASS UnitDropItemTarget: dropitem on a unit)",
  "latency": "Fast lane",
  "signature": "give_item(hero, slot: 'int', to)",
  "doc": "Give the item in inventory slot slot to to (another hero / unit; the hero walks over and hands it over). Giving it to a shop = selling it (see sell_item)."
 },
 {
  "name": "sell_item",
  "category": "command",
  "status": "verified",
  "mechanism": "Same as give_item, with the shop as the target (measured: Staff of Sanctuary sells for 125 gold)",
  "latency": "Fast lane",
  "signature": "sell_item(hero, slot: 'int', shop)",
  "doc": "Sell the item in inventory slot slot to a shop (the hero must walk next to the shop; only sellable items are accepted, for half the price)."
 },
 {
  "name": "move_item",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P target: order 0xD0022 + slot number, target = the item (mirrors JASS UnitDropItemSlot)",
  "latency": "Fast lane",
  "signature": "move_item(hero, slot: 'int', to_slot: 'int')",
  "doc": "Move an item within the inventory (from slot slot to slot to_slot; if both slots hold items, they swap). Useful for arranging hotkey positions."
 },
 {
  "name": "buy",
  "category": "command",
  "status": "inferred",
  "mechanism": "W3P buy: the shop sells to a nearby hero",
  "latency": "Fast lane",
  "signature": "buy(shop, item_code: 'str')",
  "doc": "Buy an item at a shop (for a hero standing next to the shop). If a tech prerequisite is missing, the engine returns 0 and no gold is spent."
 },
 {
  "name": "call_to_arms",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P immediate: townbellon/off",
  "latency": "Fast lane",
  "signature": "call_to_arms(hall, on: 'bool' = True)",
  "doc": "Human Call to Arms: Peasants become Militia (a tier-1 Town Hall doesn't have this ability; only works on a Keep/Castle)."
 },
 {
  "name": "set_speed",
  "category": "control",
  "status": "verified",
  "mechanism": "Action 47 (25~800%)",
  "latency": "Control channel",
  "signature": "set_speed(percent: 'int') -> 'bool'",
  "doc": "Game speed (100 = normal speed)."
 },
 {
  "name": "pause",
  "category": "control",
  "status": "verified",
  "mechanism": "W3P pause",
  "latency": "Fast lane",
  "signature": "pause(on: 'bool' = True)",
  "doc": "Pause / resume the game. While paused, the engine clock stops, but the fast lane can still issue orders (event dispatch keeps running)."
 },
 {
  "name": "set_publish_period",
  "category": "control",
  "status": "verified",
  "mechanism": "World block requestedPeriodMs",
  "latency": "Pushed snapshot",
  "signature": "set_publish_period(ms: 'int') -> 'None'",
  "doc": "Publish period of the world state (16~1000 ms, default 50). One sample takes about 0.5 ms, so even 33 ms is fine; there's a single value shared machine-wide, and the last write wins."
 },
 {
  "name": "say",
  "category": "control",
  "status": "verified",
  "mechanism": "Action 56",
  "latency": "Control channel",
  "signature": "say(u, text: 'str', seconds: 'float' = 4.0) -> 'bool'",
  "doc": "Show a chat bubble over a unit's head (for streaming/debugging; doesn't affect the game). Returns False if the bubble didn't appear; the reason is in g.last_say_error."
 },
 {
  "name": "message",
  "category": "control",
  "status": "inferred",
  "mechanism": "Action 45",
  "latency": "Control channel",
  "signature": "message(text: 'str') -> 'bool'",
  "doc": "Print a line in the message area at the bottom left of the game (visible only on this machine). The game must have shown a notice on its own first (the DLL grabs the message box from that one)."
 },
 {
  "name": "end_game",
  "category": "control",
  "status": "verified",
  "mechanism": "Action 22",
  "latency": "Control channel",
  "signature": "end_game() -> 'bool'",
  "doc": "End this game process (farm.py --keep automatically starts the next game according to next_game.json)."
 },
 {
  "name": "canvas",
  "category": "control",
  "status": "verified",
  "mechanism": "W3P 73 canvas_enable + shared memory Local\\War3Canvas_<pid> (drawn by the runtime every frame just before the game draws the mouse cursor; the cursor covers it)",
  "latency": "Shared memory",
  "signature": "canvas()",
  "doc": "Canvas: draw text boxes, panels, progress bars, images, circles on the ground and routes on the game screen (openwar3.canvas.Canvas).\nDrawn by the runtime itself — no game handles created, no game state changed — so it's safe in multiplayer; style it however you like (CJK text, rounded corners, translucency)."
 },
 {
  "name": "press_to_continue",
  "category": "control",
  "status": "verified",
  "mechanism": "PostMessage WM_KEYDOWN/UP Space to the game window (doesn't steal focus)",
  "latency": "Window message",
  "signature": "press_to_continue() -> 'bool'",
  "doc": "Press Space once on the \"Press any key to continue\" loading screen. Many RPG / story maps need a key press after loading before they start (measured on WarChasers, 09-24:\nwithout it the game sits on the loading screen, the game clock stays at 0 and the fast lane never drains). openwar3.run presses it itself while waiting to enter the game, so you rarely need to call it by hand."
 },
 {
  "name": "map_data",
  "category": "observe",
  "status": "verified",
  "mechanism": "Map file (the launcher's --map path): w3u/w3t/w3a + wts; for protected maps, reads the TXT files inside the map",
  "latency": "Read file (~0.1 s the first time)",
  "signature": "map_data()",
  "doc": "Data for the map being played (openwar3.mapdata.MapData): name_of('HC07') for the names of custom units/items/abilities, hero_names, tooltip.\nMost units in RPG maps are created by the map itself and aren't in the built-in name table. Returns None for games not started by the launcher (the map file can't be found)."
 },
 {
  "name": "jass",
  "category": "sandbox",
  "status": "verified",
  "mechanism": "W3P 70 jass (the runtime looks the name up in the native table, 1291 entries)",
  "latency": "Fast lane",
  "signature": "jass()",
  "doc": "Call any JASS native by name: g.jass.CreateUnit(g.jass.Player(1), \"Hpal\", x, y, 270.0).\nArguments I/R/B/S/H are converted automatically (pass unit/item objects directly); in multiplayer only read-only natives can be called. See openwar3/jass.py and docs/COMPANION_ZH.md for details."
 },
 {
  "name": "player_slots",
  "category": "sandbox",
  "status": "verified",
  "mechanism": "JASS GetPlayerController / GetPlayerSlotState / IsPlayerAlly",
  "latency": "Fast lane",
  "signature": "player_slots() -> 'list[dict]'",
  "doc": "The 16 player slots: controller (user = human / computer / neutral…), state (empty / playing / left), human, me, ally (whether it's allied with me).\nUse it in RPG maps to find an empty slot for a companion, or to tell whether it's a single-player game."
 },
 {
  "name": "spawn",
  "category": "sandbox",
  "status": "verified",
  "mechanism": "JASS CreateUnit + W3P 72 handle -> unit",
  "latency": "Fast lane",
  "signature": "spawn(code: 'str', x: 'float', y: 'float', player: 'int | None' = None, facing: 'float' = 270.0)",
  "doc": "Create a unit at (x,y) (player defaults to the local player) and return it as a snapshot unit (after the next world publish, ~50 ms); returns None if it can't be created.\nThe returned unit has an extra attribute, jass_handle. ⚠ Single-player only (it desyncs in multiplayer)."
 },
 {
  "name": "set_alliance",
  "category": "sandbox",
  "status": "verified",
  "mechanism": "JASS SetPlayerAlliance",
  "latency": "Fast lane",
  "signature": "set_alliance(a: 'int', b: 'int', allied: 'bool' = True, vision: 'bool' = True, control: 'bool' = False, xp: 'bool' = False, both: 'bool' = True) -> 'None'",
  "doc": "Set player a's alliance toward b: allied = don't attack each other + request help from each other; vision = shared vision; control = shared unit control (b can command a's units);\nxp = shared experience. both=True sets both directions at once (control is only set a -> b)."
 },
 {
  "name": "set_player_name",
  "category": "sandbox",
  "status": "verified",
  "mechanism": "JASS SetPlayerName",
  "latency": "Fast lane",
  "signature": "set_player_name(player: 'int', name: 'str') -> 'None'",
  "doc": "Change a player's name (the one shown on the scoreboard, in chat and in the allies panel). Used to give a companion a name."
 },
 {
  "name": "show_text",
  "category": "sandbox",
  "status": "verified",
  "mechanism": "JASS DisplayTimedTextToPlayer",
  "latency": "Fast lane",
  "signature": "show_text(text: 'str', seconds: 'float' = 6.0, player: 'int | None' = None) -> 'None'",
  "doc": "Show a line of text at the bottom left of the screen (the kind map triggers use), shown to the local player by default. Supports |cffRRGGBB color codes."
 }
]