[
 {
  "name": "status",
  "category": "meta",
  "status": "verified",
  "mechanism": "ワールドブロック + ファストレーン + クレームテーブル",
  "latency": "ローカル計算",
  "signature": "status() -> 'dict'",
  "doc": "接続状態：pid、ワールドの発行（周期、収集にかかった時間）、ファストレーンのカウンタ。"
 },
 {
  "name": "snapshot",
  "category": "observe",
  "status": "verified",
  "mechanism": "W3P ワールドブロック Local\\War3World_<pid>（ランタイムが 50 ms ごとにプッシュ、seqlock）",
  "latency": "プッシュ型スナップショット",
  "signature": "snapshot(max_age: 'float' = 0.05)",
  "doc": "マップ全体の完全な状態（WorldState）：.units .players .items .clock .me。max_age 秒以内の再呼び出しは同じものを返します。\n⚠ 金鉱に入っているワーカーは一覧に含まれません。デフォルトではマップ全体が見えます（ロックステップモデルではローカルにすべてのデータがあるため）。Game(fair=True) のときだけ視界でフィルタリングされます。"
 },
 {
  "name": "last_seen",
  "category": "observe",
  "status": "verified",
  "mechanism": "プッシュスナップショットの visibleTo（スナップショットを更新するたびに、見えている敵 / クリープのユニットを記録）",
  "latency": "プッシュ型スナップショット",
  "signature": "last_seen(owner: 'str | int' = 'enemy', max_age: 'float | None' = None) -> 'list'",
  "doc": "最後に見た敵（または 'creep' クリープ、あるいは特定のプレイヤー番号）のユニット：[(そのときのユニットの状態, そのときのゲームクロック, 経過秒数)]。新しいものが先頭です。\n死んだのを見たら一覧から削除されます。フェアモードでも通常モードでも「自軍が今見えているもの」を基準に記録します —— これがプレイヤーの頭の中にある地図です：\n偵察した兵力、相手のヒーローを最後に見た場所、相手がいつ拡張したか。max_age を指定すると、その秒数（ゲーム秒）以内のものだけを返します。"
 },
 {
  "name": "map",
  "category": "observe",
  "status": "verified",
  "mechanism": "W3P マップブロック Local\\War3Map_<pid>（試合開始後にランタイムが分割して計算、IsTerrainPathable で通行 / 建設を判定）",
  "latency": "プッシュ型スナップショット",
  "signature": "map()",
  "doc": "この試合の地形表 MapInfo：.walkable(x,y) .buildable(x,y) .at(x,y) .bounds（プレイ可能領域）.starts（スタート地点）.cells（bit0 通行不可、bit1 建設不可）。\n試合開始後、計算完了まで数秒かかり、完了前は None を返します。木は含まれません（trees() を使います）。"
 },
 {
  "name": "me",
  "category": "observe",
  "status": "verified",
  "mechanism": "ワールドブロックのヘッダー",
  "latency": "プッシュ型スナップショット",
  "signature": "me() -> 'int | None'",
  "doc": "自分のプレイヤー番号（0~11）。"
 },
 {
  "name": "resources",
  "category": "observe",
  "status": "verified",
  "mechanism": "ワールドブロック players[16]",
  "latency": "プッシュ型スナップショット",
  "signature": "resources(player: 'int | None' = None) -> 'dict | None'",
  "doc": "{'gold','lumber','food_used','food_cap','gold_gathered','lumber_gathered'}。player のデフォルトは自軍で、どのプレイヤーのものも読めます。\n読み取れない場合は None を返します。0 とみなさないでください。"
 },
 {
  "name": "players",
  "category": "observe",
  "status": "verified",
  "mechanism": "ワールドブロック players[16]",
  "latency": "プッシュ型スナップショット",
  "signature": "players() -> 'list'",
  "doc": "全 16 プレイヤースロット：Player(id, gold, lumber, food_used, food_cap, gold_gathered, lumber_gathered, race, known)。"
 },
 {
  "name": "units",
  "category": "observe",
  "status": "verified",
  "mechanism": "ワールドブロック units[]",
  "latency": "プッシュ型スナップショット",
  "signature": "units(owner: 'str | int' = 'all', types=None, alive: 'bool' = True) -> 'list'",
  "doc": "ユニットを所有者 / 型で絞り込みます。owner：'me' / 'enemy' / 'creep' / 'all' / プレイヤー番号。types：4 文字コードの集合。"
 },
 {
  "name": "unit",
  "category": "observe",
  "status": "verified",
  "mechanism": "ワールドブロック by_handle",
  "latency": "プッシュ型スナップショット",
  "signature": "unit(handle) -> 'object | None'",
  "doc": "ハンドルペア (lo, hi) でユニットを探します（オーダーのターゲット、タスクターゲット、イベントが返すのはいずれもハンドルペアです）。"
 },
 {
  "name": "is_building",
  "category": "observe",
  "status": "verified",
  "mechanism": "スナップショット + units.json（spd==0 = 建物）",
  "latency": "プッシュ型スナップショット",
  "signature": "is_building(u) -> 'bool'",
  "doc": "建物かどうか（タワーを含む）。ユニット表の移動速度 0 で判定します。アンデッドの本拠地は占有面積が 0 なので、占有面積では判定しないでください。"
 },
 {
  "name": "my_workers",
  "category": "observe",
  "status": "verified",
  "mechanism": "プッシュスナップショット",
  "latency": "プッシュ型スナップショット",
  "signature": "my_workers() -> 'list'",
  "doc": "自軍のワーカー（Peasant / Peon / Acolyte / Wisp）。"
 },
 {
  "name": "idle_workers",
  "category": "observe",
  "status": "verified",
  "mechanism": "プッシュスナップショット（オーダースロット + タスクスロット）",
  "latency": "プッシュ型スナップショット",
  "signature": "idle_workers() -> 'list'",
  "doc": "仕事のないワーカー：オーダーもタスクもないもの（このティックで仕事を割り当てたばかりのものは除く）。\n⚠ タスクのあるワーカーに採集命令を出し直すと採集サイクルが中断されます（収入がゼロになります）。"
 },
 {
  "name": "my_heroes",
  "category": "observe",
  "status": "verified",
  "mechanism": "プッシュスナップショット",
  "latency": "プッシュ型スナップショット",
  "signature": "my_heroes() -> 'list'",
  "doc": "自軍の生きているヒーロー（死んだヒーローは祭壇の復活リストにあります。revive を参照）。"
 },
 {
  "name": "my_army",
  "category": "observe",
  "status": "verified",
  "mechanism": "プッシュスナップショット + units.json",
  "latency": "プッシュ型スナップショット",
  "signature": "my_army() -> 'list'",
  "doc": "自軍の戦闘ユニット：ワーカーでも建物でもないもの。"
 },
 {
  "name": "my_buildings",
  "category": "observe",
  "status": "verified",
  "mechanism": "プッシュスナップショット",
  "latency": "プッシュ型スナップショット",
  "signature": "my_buildings(types=None) -> 'list'",
  "doc": "自軍の建物（タワー、建設中の基礎を含む）。types で特定の種類だけに絞れます（例：{'hbar'}）。"
 },
 {
  "name": "is_constructing",
  "category": "observe",
  "status": "verified",
  "mechanism": "プッシュスナップショット（オーダー = 建物の 4 文字コード、または建設命令 / 修理命令）",
  "latency": "プッシュ型スナップショット",
  "signature": "is_constructing(worker) -> 'bool'",
  "doc": "このワーカーが建設中かどうか（建設に向かっている途中 / 修理を手伝っている場合、このティックで割り当てたばかりの場合も含む）。建設担当を選ぶときはこのワーカーを除外してください。そうしないと前の基礎の工事が止まります。"
 },
 {
  "name": "under_construction",
  "category": "observe",
  "status": "verified",
  "mechanism": "プッシュスナップショット（基礎の HP はごく低い値から満タンまで増えていく）",
  "latency": "プッシュ型スナップショット",
  "signature": "under_construction(building) -> 'bool'",
  "doc": "この建物がまだ完成していない（HP が満タンでない）。⚠ ダメージを受けた建物も満タンではありません —— 序盤の判定には十分ですが、戦闘が始まった後は時間と合わせて判断してください。"
 },
 {
  "name": "gold_mines",
  "category": "observe",
  "status": "verified",
  "mechanism": "プッシュスナップショット（ngol/egol/ugol）",
  "latency": "プッシュ型スナップショット",
  "signature": "gold_mines() -> 'list'",
  "doc": "マップ上の金鉱。⚠ ナイトエルフの Entangled Gold Mine と中立の金鉱は同じ座標にそれぞれ 1 ユニットずつあるので、採集には自分の方を割り当ててください。"
 },
 {
  "name": "enemies",
  "category": "observe",
  "status": "verified",
  "mechanism": "プッシュスナップショット",
  "latency": "プッシュ型スナップショット",
  "signature": "enemies(fighters_only: 'bool' = False) -> 'list'",
  "doc": "敵プレイヤーのユニット（クリープを除く）。fighters_only：ワーカーと建物を除外します。"
 },
 {
  "name": "creeps",
  "category": "observe",
  "status": "verified",
  "mechanism": "プッシュスナップショット（owner 12 = 中立敵対）",
  "latency": "プッシュ型スナップショット",
  "signature": "creeps() -> 'list'",
  "doc": "クリープ（中立敵対）。⚠ 夜は視界が短くなり、遠くのキャンプが戦場の霧に入ると、それへのターゲットコマンドは拒否されます（理由コード 1001）。"
 },
 {
  "name": "nearest",
  "category": "meta",
  "status": "verified",
  "mechanism": "純粋な計算",
  "latency": "ローカル計算",
  "signature": "nearest(candidates, to)",
  "doc": "to（ユニットまたは (x,y)）に最も近いもの 1 つ。候補がなければ None を返します。"
 },
 {
  "name": "life_mana",
  "category": "observe",
  "status": "verified",
  "mechanism": "ワールドブロックのユニット hp/hpMax/mana/manaMax",
  "latency": "プッシュ型スナップショット",
  "signature": "life_mana(u) -> 'dict | None'",
  "doc": "{'hp','hp_max','mana','mana_max'}（浮動小数点、エンジンの生の値）。u にはスナップショットで取得したユニットをそのまま渡せます（最新のものに置き換えられます）。"
 },
 {
  "name": "hero_info",
  "category": "observe",
  "status": "verified",
  "mechanism": "ワールドブロックのユニット level/xp/skillPoints",
  "latency": "プッシュ型スナップショット",
  "signature": "hero_info(hero) -> 'dict | None'",
  "doc": "{'level','xp','skill_points'}。"
 },
 {
  "name": "abilities",
  "category": "observe",
  "status": "verified",
  "mechanism": "ワールドブロックの詳細：アビリティ（コード / レベル / フラグ / 残りクールダウン）",
  "latency": "プッシュ型スナップショット",
  "signature": "abilities(u) -> 'list'",
  "doc": "[{code, level, cooldown, flags}]。buff は buffs(u) にあります。「詳細」を持つユニットだけが対象です（ヒーロー > プレイヤーのユニット > クリープの順、最大 256 体）。"
 },
 {
  "name": "buffs",
  "category": "observe",
  "status": "verified",
  "mechanism": "ワールドブロックの詳細：B で始まるアビリティオブジェクト",
  "latency": "プッシュ型スナップショット",
  "signature": "buffs(u) -> 'list'",
  "doc": "ユニットにかかっている buff コード（例：'BHds' Divine Shield、'Bslo' Slow）。各コードの効果は data/game/buffs.json を参照してください。"
 },
 {
  "name": "cooldown",
  "category": "observe",
  "status": "verified",
  "mechanism": "ワールドブロックの詳細：アビリティの残りクールダウン（アビリティのタイマー）",
  "latency": "プッシュ型スナップショット",
  "signature": "cooldown(u, ability: 'str') -> 'float | None'",
  "doc": "このアビリティのクールダウンが残り何秒か（ゲーム秒）。0 = 使用可能。そのアビリティがない（またはこのユニットに詳細がない）場合は None を返します。"
 },
 {
  "name": "inventory",
  "category": "observe",
  "status": "verified",
  "mechanism": "ワールドブロックの詳細：インベントリ 6 スロット",
  "latency": "プッシュ型スナップショット",
  "signature": "inventory(hero) -> 'list | None'",
  "doc": "6 スロットのアイテムの 4 文字コード（空きスロットは None）。インベントリがなければ None を返します。"
 },
 {
  "name": "current_order",
  "category": "observe",
  "status": "verified",
  "mechanism": "ワールドブロックのユニット order / オーダーのターゲット / オーダーのターゲット地点",
  "latency": "プッシュ型スナップショット",
  "signature": "current_order(u) -> 'dict | None'",
  "doc": "{'order','target','x','y'}：ユニットが今持っているオーダー（order は 0x000D00xx または建物の 4 文字コード、0 = アイドル）。\ntarget はハンドルペアで、g.unit(target) でユニットに変換します。"
 },
 {
  "name": "current_target",
  "category": "observe",
  "status": "verified",
  "mechanism": "ワールドブロックのユニットのタスクターゲット",
  "latency": "プッシュ型スナップショット",
  "signature": "current_target(u)",
  "doc": "ユニットが**実際に攻撃 / 追跡している**ユニット（なければ None）。\n⚠ 攻撃命令を出すとオーダースロットはすぐに空になり、攻撃はタスク側に残ります —— 「誰を攻撃しているか」の判定には current_order ではなくこちらを使ってください。"
 },
 {
  "name": "clock",
  "category": "observe",
  "status": "verified",
  "mechanism": "ワールドブロックのヘッダー clockMs（エンジンのゲームクロック）",
  "latency": "プッシュ型スナップショット",
  "signature": "clock() -> 'float | None'",
  "doc": "エンジンのゲームクロック（ゲーム秒、ロード中は 0）。ゲーム速度を上げると実時間より速く進みます。"
 },
 {
  "name": "production",
  "category": "observe",
  "status": "verified",
  "mechanism": "ワールドブロックの生産テーブル（Aque/ABnP/AUnP アビリティオブジェクト + ランタイムが追跡する経過時間。実測誤差 < 0.2 ゲーム秒）",
  "latency": "プッシュ型スナップショット",
  "signature": "production(building)",
  "doc": "この建物が今何をしているか：Production(kind, queue, duration, elapsed, blocked, progress, remaining…)。何もしていなければ None を返します。\n  kind は 'queue'（訓練 / 研究 / ヒーロー。queue は最大 7 スロットで、[0] が実行中のもの）/ 'construction'（建設中）/ 'upgrade'（本拠地 / タワーのアップグレード）。\n  blocked = キューにあるのに始まっていない（たいていは人口不足 —— Farm を建てる時です）。progress は 0..1。\n相手の建物も見られます（フェアモードでは見えている建物のみ）。"
 },
 {
  "name": "queue",
  "category": "observe",
  "status": "verified",
  "mechanism": "ワールドブロックの生産テーブル",
  "latency": "プッシュ型スナップショット",
  "signature": "queue(building) -> 'list'",
  "doc": "訓練 / 研究キュー内の 4 文字コード（[0] が実行中）。アイドルまたは生産建物でない場合 = []。"
 },
 {
  "name": "all_production",
  "category": "observe",
  "status": "verified",
  "mechanism": "ワールドブロックの生産テーブル",
  "latency": "プッシュ型スナップショット",
  "signature": "all_production(owner: 'str | int' = 'me') -> 'list'",
  "doc": "進行中のすべての生産 [(建物, Production)]。owner は units() と同じです：'me' / 'enemy' / プレイヤー番号 / 'all'。\nプロの使い方：相手が何の兵を訓練しているか、何の技術を研究しているか、いつティアアップするかを見る（建物を偵察できたとき）。"
 },
 {
  "name": "path_distance",
  "category": "observe",
  "status": "verified",
  "mechanism": "マップブロック（エンジンの IsTerrainPathable）+ 木ブロック + 建物の占有範囲、SDK 側で A*（1 マス 128）",
  "latency": "プッシュ型スナップショット + ローカル計算",
  "signature": "path_distance(a, b) -> 'float | None'",
  "doc": "地上ユニットが a から b まで歩く距離（a、b はユニットまたは (x,y)）。到達できなければ None。島マップで「このクリープキャンプ / 拡張地点に地上から行けるか」を判定するのに使います。\n直線距離より信頼できます（木立、崖、建物を迂回）。精度は 1 マス 128 で、1 マスより狭い隙間は通れないと判定します。"
 },
 {
  "name": "reachable",
  "category": "observe",
  "status": "verified",
  "mechanism": "同上",
  "latency": "プッシュ型スナップショット + ローカル計算",
  "signature": "reachable(a, b) -> 'bool | None'",
  "doc": "地上から到達できるか（マップブロックの計算が終わっていない = None）。"
 },
 {
  "name": "walk_path",
  "category": "observe",
  "status": "verified",
  "mechanism": "同上",
  "latency": "プッシュ型スナップショット + ローカル計算",
  "signature": "walk_path(a, b) -> 'list | None'",
  "doc": "経路の折れ点 [(x,y)...]（最後の点が b）。path(units, 地点リスト) と組み合わせて、部隊をこの経路に沿って移動させます（タワーを避ける、裏道を通る）。"
 },
 {
  "name": "upkeep",
  "category": "observe",
  "status": "inferred",
  "mechanism": "1.27 の固定ルール：人口 0~50 は徴収なし、51~80 は収入 ×0.7、81~100 は ×0.4",
  "latency": "プッシュ型スナップショット",
  "signature": "upkeep(player: 'int | None' = None) -> 'dict | None'",
  "doc": "維持費の段階：{'level': 'none'/'low'/'high', 'income': 1.0/0.7/0.4, 'next_at': 次の段階になる人口（なければ None）}。\nプロの常識：Tier 3 へのアップグレードや攻防アップグレードの間は人口 50 で止め、決戦の直前にだけ 80 まで上げます。"
 },
 {
  "name": "xp_to_next",
  "category": "observe",
  "status": "verified",
  "mechanism": "ワールドブロック level/xp + MiscGame の NeedHeroXP 式",
  "latency": "プッシュ型スナップショット",
  "signature": "xp_to_next(hero) -> 'int | None'",
  "doc": "ヒーローが次のレベルまでに必要な経験値（レベル 10 = 0）。"
 },
 {
  "name": "creep_camps",
  "category": "observe",
  "status": "verified",
  "mechanism": "プッシュスナップショット（距離 600 以内のクリープを 1 グループにまとめる）+ units.json のレベル",
  "latency": "プッシュ型スナップショット",
  "signature": "creep_camps(link: 'float' = 600.0) -> 'list'",
  "doc": "フィールド上の（見えている）クリープをキャンプにまとめます：[{'x','y','units','level','hp','max_level'}]。自軍の本拠地から近い順です。\nlevel = キャンプの合計レベル（クリープ狩りの難易度によく使われる指標）、hp = 合計 HP。time_to_kill / path_distance と組み合わせて狙うキャンプを選びます。"
 },
 {
  "name": "buff_info",
  "category": "observe",
  "status": "verified",
  "mechanism": "data/game/buffs.json（AbilityData.slk の BuffID -> アビリティ / 効果 / 持続時間）",
  "latency": "ローカルデータ",
  "signature": "buff_info(code: 'str') -> 'dict | None'",
  "doc": "buff コードが何か：{'ability','effect','dur','hero_dur','targets'}（例：'Bslo' -> Slow）。1 つのコードに複数行ある場合は最初の行を返します。"
 },
 {
  "name": "stats",
  "category": "observe",
  "status": "verified",
  "mechanism": "データテーブル（UnitBalance/UnitWeapons/UpgradeData/MiscGame）+ リアルタイムの技術レベル + ヒーローレベル",
  "latency": "プッシュ型スナップショット + ファストレーン（5 秒ごとに 1 バッチ）",
  "signature": "stats(u, player: 'int | None' = None)",
  "doc": "ユニットの戦闘属性 combat.UnitStats：HP / マナ上限、アーマー（攻防アップグレード、ヒーローの敏捷性を含む）、アーマータイプ、移動速度、昼 / 夜の視界、\n武器（攻撃できる対象、射程、攻撃間隔、ダメージ範囲、攻撃タイプ、スプラッシュ）。u にはユニット（所有者の技術とヒーローレベルを自動で使用）または 4 文字コード（player のデフォルトは自軍）を渡します。\nさらに .dps_vs(相手) / .hits_to_kill(相手) / combat.time_to_kill(集団, 相手) と組み合わせます。⚠ アイテム、オーラ、buff は含みません。"
 },
 {
  "name": "time_to_kill",
  "category": "observe",
  "status": "verified",
  "mechanism": "stats() + リアルタイムの HP",
  "latency": "プッシュ型スナップショット",
  "signature": "time_to_kill(attackers, target) -> 'float | None'",
  "doc": "このユニット群が一緒に target を攻撃して倒すまでのゲーム秒数（target の現在の HP を使用。相性、アーマー、攻防アップグレードを考慮し、移動、スプラッシュ、回復は考慮しない）。\nプロの使い方：集中攻撃は一番近い敵ではなく、「最も早く倒せる」敵（time_to_kill が最小のもの）から狙います。攻撃できない = None。"
 },
 {
  "name": "time_of_day",
  "category": "observe",
  "status": "verified",
  "mechanism": "ワールドブロックの拡張領域：GetFloatGameState(GAME_STATE_TIME_OF_DAY)",
  "latency": "プッシュ型スナップショット",
  "signature": "time_of_day() -> 'float | None'",
  "doc": "ゲーム内時刻（時、0~24）。試合開始時は朝 8 時です。1 日 = 480 ゲーム秒（昼と夜がそれぞれ 240 秒で、昼夜の進行速度に応じて伸縮）。\n読み取れない（古いランタイム / 試合中でない）場合は None を返します。"
 },
 {
  "name": "is_night",
  "category": "observe",
  "status": "verified",
  "mechanism": "ワールドブロックの拡張領域（6~18 時が昼）",
  "latency": "プッシュ型スナップショット",
  "signature": "is_night() -> 'bool | None'",
  "doc": "今が夜かどうか（18:00~6:00）。プロの戦術：夜はクリープが眠っている（先手でクリープ狩りをしても囲まれない）、全ユニットの視界が短くなる（奇襲の好機）、\nナイトエルフの Sentinel / ユニットは夜に木のそばで姿を隠す。読み取れない場合は None を返します。"
 },
 {
  "name": "seconds_until",
  "category": "observe",
  "status": "verified",
  "mechanism": "ワールドブロックの拡張領域 + 1 日 480 秒（実測 20 ゲーム秒 / 時）",
  "latency": "プッシュ型スナップショット",
  "signature": "seconds_until(hour: 'float') -> 'float | None'",
  "doc": "ゲーム内時刻が hour 時になるまであと何ゲーム秒か（例：seconds_until(18) = 日没までの時間。夜のクリープ狩りの計画に使います）。"
 },
 {
  "name": "items_on_ground",
  "category": "observe",
  "status": "verified",
  "mechanism": "ワールドブロック items[]（地面のもののみ：所有者のハンドルがすべて FF）",
  "latency": "プッシュ型スナップショット",
  "signature": "items_on_ground() -> 'list'",
  "doc": "地面のアイテム [Item(addr, handle_lo, handle_hi, type, x, y, life)]。拾われる / 使われると item.removed イベントが発行されます。"
 },
 {
  "name": "trees",
  "category": "observe",
  "status": "verified",
  "mechanism": "木ブロック Local\\War3Trees_<pid>（2 秒ごとに更新）",
  "latency": "プッシュ型スナップショット",
  "signature": "trees(x: 'float | None' = None, y: 'float | None' = None, limit: 'int' = 60) -> 'list'",
  "doc": "生きている木（DestructableData で targType に tree を含むもの）。(x,y) を渡すと近い順に並べ、最大 limit 本を返します。\n各要素は Tree(addr, handle_lo, handle_hi, type, x, y, life) で、そのまま gather に渡して伐採させられます。"
 },
 {
  "name": "events",
  "category": "observe",
  "status": "verified",
  "mechanism": "イベントリング Local\\War3Events_<pid>（発行の比較 + ランタイムが捕捉したダメージイベント）",
  "latency": "プッシュ型スナップショット",
  "signature": "events() -> 'list'",
  "doc": "前回の呼び出し以降に起きたこと：unit.appeared / unit.died / unit.removed / unit.damaged / order.changed /\nhero.levelup / owner.changed / item.appeared / item.removed / game.started（これらは発行の比較から得られ、精度 = 発行周期 50 ms）、\nさらにエンジンレベルの damage / killed（ランタイムがゲームスレッド上でその場で記録するため、**1 発ごと**に発生）：\n    damage：handle = 攻撃を受けた側、.source_addr = 攻撃した側（snapshot().unit_by_addr でユニットに変換）、.value = 実際に減った HP、\n            .raw_damage = アーマー適用前のダメージ、.attack_type（normal/pierce/siege/magic/chaos/hero/spell）、.damage_type\n    killed：この 1 発でとどめを刺した、.source_addr = 倒した側\nさらにランタイムが生産テーブルを追跡して得る production.done（精度 = 発行周期）：ユニット = 建物、.done_code = 完了した 4 文字コード、\n    .done_kind = 'training'（兵 / ヒーロー / 復活）/ 'research' / 'construction'（建物の完成）/ 'upgrade'（ティアアップ / タワーのアップグレード）、.value = かかったゲーム秒数\n09-25 の補完：\n    spell.cast：ユニット = 詠唱者、.spell スキルの 4 文字コード、b レベル、value クールダウン秒数、x,y 詠唱地点（スキルのクールダウン開始時に検出、精度 = 発行周期）\n    player.left：.player 退出した / 敗北判定で除外されたプレイヤー番号。game.ended：試合から退出\n    selection.changed：ローカルプレイヤーの選択が変わった（ユニットは g.selection() で取得）\n    message：画面のメッセージ枠に出た 1 件（ゲームのヒント、チャット、システム）：.text 全文、.frame メッセージ枠の番号、\n             .chat = {'channel', 'sender', 'text'}（チャットの場合。プレイヤーがチャット欄に打った文字はここから読む）\n    ui.click / ui.hover / hotkey / mouse.world：UI と入力（g.ui）。.key はキャンバスの key / ホットキーの書き方\n各要素は Event(seq, kind, clock, addr, handle, type, owner, a, b, x, y, value, extra)。\nフェアモード（fair=True）で渡されるのは、自分のユニットのイベント、今見えている（または 1 秒以内まで見えていた）ユニットのイベント、自軍が受けた / 自軍が与えたダメージ、\nそしてローカルの UI / メッセージ / 試合関連のイベントだけです。"
 },
 {
  "name": "selection",
  "category": "observe",
  "status": "verified",
  "mechanism": "W3P ワールドブロックの拡張領域 selAddrs（ランタイムが発行のたびにローカルプレイヤーの選択を含める）",
  "latency": "プッシュ型スナップショット",
  "signature": "selection() -> 'list'",
  "doc": "ローカルプレイヤーが今選択しているユニット（メインのユニットが先頭。最大 12 体）。選択が変わると selection.changed イベントが発行されます。"
 },
 {
  "name": "messages",
  "category": "observe",
  "status": "verified",
  "mechanism": "共有メモリ Local\\War3Msgs_<pid>（ランタイムが捕捉した画面メッセージ）",
  "latency": "プッシュ型スナップショット",
  "signature": "messages() -> 'list'",
  "doc": "前回の呼び出し以降に画面のメッセージ枠へ新しく出たメッセージ：[{'text', 'frame', 'repeat', 'seq', 'game_ms'}]。\nゲームのヒント（「Farm がもっと必要です」「そこには建設できません」）、チャット、システムメッセージがすべてここに入ります。frame でどのメッセージ枠かを区別します。\nイベントストリームの message イベントと同じものです（カーソルはそれぞれ別）。"
 },
 {
  "name": "ui",
  "category": "control",
  "status": "verified",
  "mechanism": "W3P 74 input_enable + 共有メモリ Local\\War3Input_<pid>（ランタイムがウィンドウ入力を受け取る）",
  "latency": "共有メモリ",
  "signature": "ui()",
  "doc": "UI と入力（openwar3.ui.UI）：クリックできるボタンと選択カード、ホットキー、地面のクリックによる位置指定、マウスが指している場所。\nボタン上のクリックはゲームに届きません。ローカルの入力 + ローカルの描画だけなので、マルチプレイでも安全です。"
 },
 {
  "name": "tech",
  "category": "observe",
  "status": "verified",
  "mechanism": "W3P クエリ q_tech（エンジンのプレイヤー技術カウント）",
  "latency": "ファストレーン",
  "signature": "tech(code: 'str', player: 'int | None' = None) -> 'int | None'",
  "doc": "研究レベル / 完成した建物の数（アップグレード系列も含む：Castle も htow として数える）。player のデフォルトは自軍で、どのプレイヤーでも問い合わせられます。"
 },
 {
  "name": "can_do",
  "category": "observe",
  "status": "verified",
  "mechanism": "W3P クエリ q_feasible（エンジンの実行可否チェック）",
  "latency": "ファストレーン",
  "signature": "can_do(u, code: 'str') -> 'int | None'",
  "doc": "エンジンの実行可否判定：0/220 なら実行可能。3 人口不足、8 ゴールド不足、9 木材不足、32 キューがいっぱい、183 前提条件不足、185 祭壇で復活中、221 その項目がない / 建設中。\n⚠ ワーカーの建物建設に対しては常に 221 になるため、設置場所の判定には使えません（build_near を使います）。"
 },
 {
  "name": "can_do_many",
  "category": "observe",
  "status": "verified",
  "mechanism": "W3P クエリ q_feasible × N、1 バッチで送信",
  "latency": "ファストレーン × 1",
  "signature": "can_do_many(pairs) -> 'list'",
  "doc": "can_do をまとめて問い合わせます：pairs = [(ユニット, 4 文字コード), ...]。同じ順序の判定コードのリストを返します（問い合わせできなかったものは None）。\n1 ティックで何を建てる / 訓練するかを計画するときは、先にまとめて問い合わせると、can_do を 1 つずつ呼ぶより N 倍速くなります（リファレンスブレイン 09-23：建設計画 76 -> 25 ms）。"
 },
 {
  "name": "tech_many",
  "category": "observe",
  "status": "verified",
  "mechanism": "W3P クエリ q_tech × N、1 バッチで送信",
  "latency": "ファストレーン × 1",
  "signature": "tech_many(codes, player: 'int | None' = None) -> 'dict'",
  "doc": "多数の技術 / 建物のカウントを一度に問い合わせます：{4 文字コード: 数または None}。"
 },
 {
  "name": "visible",
  "category": "observe",
  "status": "verified",
  "mechanism": "W3P クエリ q_visible（見えている / 戦場の霧 / ブラックマスク）",
  "latency": "ファストレーン",
  "signature": "visible(x: 'float', y: 'float') -> 'bool | None'",
  "doc": "この地点が今自軍から見えているか（戦場の霧 / ブラックマスクの中でないか）。フェアモードの bot は見えている敵だけを使うべきです。"
 },
 {
  "name": "gold_left",
  "category": "observe",
  "status": "inferred",
  "mechanism": "W3P クエリ q_mine_gold（エンジンの金鉱残量）",
  "latency": "ファストレーン",
  "signature": "gold_left(mine) -> 'int | None'",
  "doc": "金鉱の残りゴールド。"
 },
 {
  "name": "enemy_ai_plan",
  "category": "observe",
  "status": "verified",
  "mechanism": "W3P クエリ q_captain（敵兵が従っているコンピューターのキャプテン）",
  "latency": "ファストレーン",
  "signature": "enemy_ai_plan(enemy_unit) -> 'dict | None'",
  "doc": "コンピューター AI のキャプテン：兵を連れてどこへ向かうか（出撃前に、あなたの基地のどこを攻めるかが分かります）。コンピューターの相手にのみ有効です。キャプテンについていないユニットなら None を返します。"
 },
 {
  "name": "batch",
  "category": "command",
  "status": "verified",
  "mechanism": "ブロック内のコマンドを 1 バッチにため、ブロック終了時に一括送信（同じフレームで実行し、ゲームスレッドを待つのは 1 回だけ）",
  "latency": "ファストレーン × 1",
  "signature": "batch() -> 'Batch'",
  "doc": "1 ティック分のコマンドを 1 つのバッチにまとめます：\n\n    with g.batch() as b:\n        g.attack(archers, target)          # Pending を返し、ブロック終了後にレシートになる\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\nコマンドを 1 件ずつ送るとそのたびにゲームスレッドの処理を 1 回待ちます（約 10 ms）。バッチなら待つのは 1 回だけです —— リファレンスブレインは 09-23 にこれで 1 ラウンドを 48 -> 26 ms に短縮しました。\n* クレームテーブルによる調停はこれまでどおり 1 件ずつ行われます（押さえられているユニットはその場で held のレシートを受け取り、バッチには入りません）。\n* ブロック内のコマンドは Pending を返します：ブロック終了前に .ok を読むと例外が発生し（レシートがまだ存在しないため）、ブロック終了後は Receipt と同じように使えます。\n* ブロック内で例外が発生した = バッチ全体を破棄（status 97 cancelled）し、押さえていたユニットは解放されます。\n* クエリ（can_do / tech / visible …）と build_near、buy はバッチに入らず、これまでどおりその場で問い合わせます —— 結果をすぐに使うためです。\n  一度に多数を問い合わせるなら can_do_many / tech_many を使います。\n* ネストした with g.batch() は一番外側のバッチに統合されます。16 件を超えるとランタイムが自動で複数の区間に分けます（区間ごとに 1 回待機）。"
 },
 {
  "name": "order_of",
  "category": "observe",
  "status": "verified",
  "mechanism": "スナップショットのオーダー + このプロセスで受理されたばかりのコマンド（レシート）",
  "latency": "プッシュ型スナップショット",
  "signature": "order_of(u) -> 'int | None'",
  "doc": "ユニットの現在のオーダー。**このティックで出したばかりのものを含みます**（スナップショットがまだ追いついていないときはレシートの新しいオーダーを使います）。\n⚠ 09-23 の実戦：hello_bot が農民を Farm の建設に送った直後、同じティックで rush_bot がスナップショット上でその農民を「アイドル」と判断して Barracks の建設に送り、Farm が何度も途中で放棄されました。\n  「手が空いている / 建設中でない」ユニットを選ぶときは、u.order ではなくこれを使ってください。"
 },
 {
  "name": "move",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P point：move（extra ビット = キュー方式）",
  "latency": "ファストレーン",
  "signature": "move(units, x: 'float', y: 'float', queue: 'str | None' = None)",
  "doc": "(x,y) まで移動し、途中で攻撃しません（撤退にはこれを使います）。ユニット 1 体またはリストを渡せます（同じフレームでまとめて命令）。\nqueue='after'：今の作業を終えてから向かいます（現在のオーダーの後ろに差し込む）。レシートの values[0] = 命令後にこのユニットがキューに持っているオーダー数（実行中のものを含む）。"
 },
 {
  "name": "attack_move",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P point：attack を地点指定",
  "latency": "ファストレーン",
  "signature": "attack_move(units, x: 'float', y: 'float', queue: 'str | None' = None)",
  "doc": "アタックムーブ（A で地面を指定）：途中で敵に遭遇すれば攻撃します。queue は move と同じです。"
 },
 {
  "name": "attack",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P target：ターゲットコマンド（右クリック smart）",
  "latency": "ファストレーン",
  "signature": "attack(units, target, force: 'bool' = False, queue: 'str | None' = None)",
  "doc": "target を攻撃します。デフォルトでは右クリックを使います（敵に対して = その 1 体を攻撃。09-23 の実測でオーダーのターゲットもタスクターゲットもそのユニット）。\n⚠ ターゲットは視界内にいる必要があり、見えないものは拒否されます（理由コード 1001）。\nforce=True で攻撃オーダー 0x0F を使います（味方や中立の小動物を攻撃するときに必要）—— 実測では、攻撃オーダーに切り替わるだけでターゲットを記憶せず、\n近くの別の敵を攻撃しに行きます。特定のターゲットを攻撃する用途には使わないでください。"
 },
 {
  "name": "stop",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P immediate：stop",
  "latency": "ファストレーン",
  "signature": "stop(units)",
  "doc": "手元のすべての作業を止めます（オーダー ID 0x000D0004）。キューにあるオーダーも消去されます。"
 },
 {
  "name": "hold",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P immediate：holdposition",
  "latency": "ファストレーン",
  "signature": "hold(units, queue: 'str | None' = None)",
  "doc": "その場で待機します（追いかけず、射程内の敵だけを攻撃）。"
 },
 {
  "name": "patrol",
  "category": "command",
  "status": "inferred",
  "mechanism": "W3P point：patrol",
  "latency": "ファストレーン",
  "signature": "patrol(units, x: 'float', y: 'float', queue: 'str | None' = None)",
  "doc": "現在位置と (x,y) の間をパトロールします。"
 },
 {
  "name": "attack_ground",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P point：attackground（攻城ユニット / Mortar Team / Demolisher）",
  "latency": "ファストレーン",
  "signature": "attack_ground(units, x: 'float', y: 'float', queue: 'str | None' = None)",
  "doc": "地面攻撃：砲で一帯を砲撃します（透明ユニットや木立の裏の敵を撃つ、通路を封鎖する）。地面攻撃ができるユニットだけが受け付けます。"
 },
 {
  "name": "cancel",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P immediate：cancel",
  "latency": "ファストレーン",
  "signature": "cancel(building)",
  "doc": "キャンセル：訓練 / 研究キューの最後のスロット（返金）、建設中の建物（75% 返金）、アップグレード中の本拠地。"
 },
 {
  "name": "path",
  "category": "command",
  "status": "verified",
  "mechanism": "1 バッチ：最初の区間は即時実行、残りは逆順に queue='after' で差し込む（エンジンには「現在のオーダーの後ろに差し込む」しかないため）",
  "latency": "ファストレーン × 1",
  "signature": "path(units, points, attack: 'bool' = False)",
  "doc": "一連の地点を順番に通過します（Shift で連続指定：ウェイポイント、タワーの迂回、偵察ルート）。attack=True なら各区間がアタックムーブになります。\n一括で送信し、レシートは地点ごとに 1 つ（points の順）返ります。"
 },
 {
  "name": "gather",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P target：harvest（金鉱または木）",
  "latency": "ファストレーン",
  "signature": "gather(workers, target, queue: 'str | None' = None)",
  "doc": "ゴールドの採掘 / 伐採（target は金鉱または trees() の木）。⚠ 手の空いたワーカー（idle_workers）にだけ割り当ててください：タスクのあるワーカーに出し直すと採集サイクルが中断されます。\nプロの使い方：建て終わったら採掘に戻る = build(...) の後に gather(worker, mine, queue='after')。"
 },
 {
  "name": "repair",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P target：repair",
  "latency": "ファストレーン",
  "signature": "repair(workers, building, queue: 'str | None' = None)",
  "doc": "修理 / 建設の手伝い（ヒューマンとオークの建設現場は、建てる人がいないと工事が止まります）。"
 },
 {
  "name": "build",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P build：建設オーダー。同じフレームでワーカーのオーダーを読み戻して確認",
  "latency": "ファストレーン",
  "signature": "build(worker, code: 'str', x: 'float', y: 'float', queue: 'str | None' = None)",
  "doc": "ワーカーに (x,y) で code を建てさせます（座標は 32 単位にスナップ）。レシートが受理 = ワーカーのオーダーがすでにこの建物（または着工命令）になっている。\nqueue='after' のとき = ワーカーのオーダーキューに入った（レシートの values[0] がキュー数）。\n⚠ 受理 ≠ 建てられる：木立の中の地点もエンジンはその場で受理し、ワーカーが到着してから失敗します（09-23 実測）。ゴールドが別のところで使われても基礎は現れません。\nどこに置けるか分からないなら build_near を使います（結果を追跡し、失敗した地点をブラックリストに入れます）。続けて何棟も建てるなら build_queue を使います。"
 },
 {
  "name": "build_queue",
  "category": "command",
  "status": "verified",
  "mechanism": "1 バッチ：最初の 1 棟は即時、残りは逆順に queue='after'",
  "latency": "ファストレーン × 1",
  "signature": "build_queue(worker, plan)",
  "doc": "1 人のワーカーに順番に何棟も建てさせます（Shift で連続建設）：plan = [(4 文字コード, x, y), ...]。一括で送信し、レシートは plan の順です。\n⚠ ゴールドは着工時に引かれます（キューに入れた時点では引かれません）—— 3 棟入れてもゴールドが 1 棟分しかなければ、残りの 2 棟はワーカーが到着した時点で失敗します。"
 },
 {
  "name": "build_near",
  "category": "command",
  "status": "verified",
  "mechanism": "地点ごとに build + 追跡（基礎が現れた = 成功。ワーカーがオーダーを放棄し、基礎もない = その地点をブラックリストに入れる）",
  "latency": "ファストレーン × 試行した地点数",
  "signature": "build_near(worker, code: 'str', x: 'float', y: 'float', min_r: 'float' = 450, max_r: 'float' = 1500, max_tries: 'int' = 24)",
  "doc": "(x,y) の周囲で近いところから順に置ける場所を探して code を建てます。**ブロックしない**ので、毎ティック呼んでも構いません：\n  * この種類の建物の建設が進行中（ワーカーが移動中）-> その地点を返し、命令を出し直さない。\n  * 前回成功した（基礎が現れた）-> 今回は必要に応じて新しい地点を探す。\n  * 前回失敗した（ワーカーが到着してから置けないと分かり、エンジンがオーダーを取り消し、基礎もない）-> その地点を 45 秒間ブラックリストに入れ、次の地点を試す。\n  * ゴールドが足りない -> そのまま None を返す（試さない、ブラックリストにも入れない）。すべて試し終えたら None を返す。\n⚠ なぜ追跡が必要か：09-23 の実戦で、木立の中の地点をエンジンは**その場で受理**し、ワーカーが到着してから失敗しました（同じフレームのレシートでは判定できない）。\n  また、エンジンの設置可否チェックはワーカーの建物建設に対して常に 221 を返すため、先に「確認」してから建てることもできません。明らかに埋まっている地点（本拠地のど真ん中）だけはその場で拒否されます。"
 },
 {
  "name": "can_afford",
  "category": "observe",
  "status": "verified",
  "mechanism": "プッシュスナップショットの自軍資源 + units.json の価格",
  "latency": "プッシュ型スナップショット",
  "signature": "can_afford(code: 'str') -> 'bool'",
  "doc": "今のゴールド / 木材で code（ユニット、建物）を買えるか（units.json の価格で判定）。価格表にないものはすべて買えるとみなします。\n⚠ ティアアップの 4 文字コードは表では累計価格なので、ここでの判定はやや保守的になります。最終的にはエンジンのレシートが正です。"
 },
 {
  "name": "train",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P immediate：4 文字コード。拒否時は実行可否の理由コード付き",
  "latency": "ファストレーン",
  "signature": "train(building, code: 'str')",
  "doc": "ユニットの訓練 / 技術の研究 / 本拠地のアップグレード（ティアアップ = 本拠地自体にアップグレード先の本拠地の 4 文字コードを指定。例：'hkee'）。\n拒否されると、レシートの reason に理由が入ります（人口不足、ゴールド不足、木材不足、キューがいっぱい、前提条件不足……）。"
 },
 {
  "name": "learn",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P learn：スキルポイントが減った場合にのみ習得とみなす",
  "latency": "ファストレーン",
  "signature": "learn(hero, ability: 'str')",
  "doc": "ヒーローがアビリティを習得します（4 文字コード。例：'AHbz' Blizzard）。"
 },
 {
  "name": "cast",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P target / point / immediate（引数に応じて選択）",
  "latency": "ファストレーン",
  "signature": "cast(u, spell, target=None, x: 'float | None' = None, y: 'float | None' = None)",
  "doc": "スキルを使います。spell はオーダー文字列（'thunderbolt' Storm Bolt、'blizzard'、'holybolt' Holy Light…、data/order-ids.txt を参照）またはオーダー ID。\ntarget を渡す = ユニット対象、x,y を渡す = 地面対象、どちらも渡さない = ターゲットなし（Thunder Clap、Divine Shield、Summon Water Elemental）。\nレシートの受理はエンジンが受け付けたことを示すだけです。実際に発動したかは、cooldown() がクールダウンに入ったか、buffs() に現れたかで確認します。"
 },
 {
  "name": "rally",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P rally",
  "latency": "ファストレーン",
  "signature": "rally(building, x: 'float | None' = None, y: 'float | None' = None, target=None)",
  "doc": "集結地点を設定します（地点指定、またはユニット / 金鉱を指定）。"
 },
 {
  "name": "revive",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P revive：死亡ヒーロー一覧 -> 祭壇が死んだヒーローに復活を実行",
  "latency": "ファストレーン",
  "signature": "revive(altar, hero=None)",
  "doc": "祭壇で死んだヒーローを復活させます（hero を渡さなければリストの最初のヒーロー）。\n拒否されるよくある理由（レシートの reason に書かれます）：人口不足（ヒーローも人口を使う）、ゴールド不足、死んでから間もない（死後約 3 ゲーム秒経たないと復活できない）、\nすでに復活が進行中（受理された時点でエンジンがそのスロットをその場で消去する）。"
 },
 {
  "name": "pick_up",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P target：アイテムを右クリック",
  "latency": "ファストレーン",
  "signature": "pick_up(hero, item)",
  "doc": "ヒーローが地面のアイテムを拾いに行きます（item は items_on_ground から取得）。拾うとインベントリに現れ、地面側では item.removed イベントが発行されます。"
 },
 {
  "name": "use_item",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P use_item（スロット番号で指定）",
  "latency": "ファストレーン",
  "signature": "use_item(hero, slot: 'int', target=None, x: 'float | None' = None, y: 'float | None' = None)",
  "doc": "インベントリの slot 番目（0~5）のアイテムを使います。ターゲットユニットまたはターゲット地点を指定できます。\n⚠ 地点指定でアイテムを使う場合（例：Ivory Tower）、エンジンは成功しても 0 を返すため、レシートは常に受理扱いになります —— インベントリのそのスロットが空いたかで確認してください。"
 },
 {
  "name": "drop_item",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P item_drop（JASS の UnitDropItemPoint を踏襲：dropitem 0xD0021 を地点指定 + アイテムを即時ターゲット）",
  "latency": "ファストレーン",
  "signature": "drop_item(hero, slot: 'int', x: 'float', y: 'float')",
  "doc": "インベントリの slot 番目のアイテムを (x,y) に落とします（ヒーローが歩いて行って置きます）。"
 },
 {
  "name": "give_item",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P item_drop（JASS の UnitDropItemTarget を踏襲：dropitem をユニット指定）",
  "latency": "ファストレーン",
  "signature": "give_item(hero, slot: 'int', to)",
  "doc": "インベントリの slot 番目のアイテムを to（別のヒーロー / ユニット。歩いて行って手渡す）に渡します。ショップに渡す = 売却（sell_item を参照）。"
 },
 {
  "name": "sell_item",
  "category": "command",
  "status": "verified",
  "mechanism": "give_item と同じで、ターゲットがショップ（実測：Staff of Sanctuary が 125 ゴールドで売れた）",
  "latency": "ファストレーン",
  "signature": "sell_item(hero, slot: 'int', shop)",
  "doc": "インベントリの slot 番目のアイテムをショップに売ります（ヒーローがショップの隣まで行く必要があります。売却可能なアイテムのみ受け付け、価格の半分が返ります）。"
 },
 {
  "name": "move_item",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P target：オーダー 0xD0022+スロット番号、ターゲット = アイテム（JASS の UnitDropItemSlot を踏襲）",
  "latency": "ファストレーン",
  "signature": "move_item(hero, slot: 'int', to_slot: 'int')",
  "doc": "インベントリ内でスロットを移動します（slot 番目を to_slot 番目へ。両方にアイテムがあれば入れ替え）。ショートカットキーの配置を整えるのに使います。"
 },
 {
  "name": "buy",
  "category": "command",
  "status": "inferred",
  "mechanism": "W3P buy：ショップが隣にいるヒーローに売る",
  "latency": "ファストレーン",
  "signature": "buy(shop, item_code: 'str')",
  "doc": "ショップでアイテムを買います（ショップの隣に立っているヒーローに渡されます）。技術の前提条件が足りないとエンジンは 0 を返し、ゴールドは引かれません。"
 },
 {
  "name": "call_to_arms",
  "category": "command",
  "status": "verified",
  "mechanism": "W3P immediate：townbellon/off",
  "latency": "ファストレーン",
  "signature": "call_to_arms(hall, on: 'bool' = True)",
  "doc": "ヒューマンの Call to Arms：農民が Militia になります（Tier 1 の Town Hall にはこのアビリティがなく、Keep / Castle でのみ有効）。"
 },
 {
  "name": "set_speed",
  "category": "control",
  "status": "verified",
  "mechanism": "アクション 47（25~800%）",
  "latency": "コントロールチャネル",
  "signature": "set_speed(percent: 'int') -> 'bool'",
  "doc": "ゲーム速度（100 = 通常速度）。"
 },
 {
  "name": "pause",
  "category": "control",
  "status": "verified",
  "mechanism": "W3P pause",
  "latency": "ファストレーン",
  "signature": "pause(on: 'bool' = True)",
  "doc": "ゲームの一時停止 / 再開。一時停止中はエンジンクロックが止まりますが、ファストレーンからは通常どおり命令できます（イベントディスパッチは動き続けています）。"
 },
 {
  "name": "set_publish_period",
  "category": "control",
  "status": "verified",
  "mechanism": "ワールドブロック requestedPeriodMs",
  "latency": "プッシュ型スナップショット",
  "signature": "set_publish_period(ms: 'int') -> 'None'",
  "doc": "ワールド状態の発行周期（16~1000 ミリ秒、デフォルト 50）。1 回の収集は約 0.5 ms なので、33 ms でも問題ありません。値はマシン全体で共有され、最後に書き込んだものが有効になります。"
 },
 {
  "name": "say",
  "category": "control",
  "status": "verified",
  "mechanism": "アクション 56",
  "latency": "コントロールチャネル",
  "signature": "say(u, text: 'str', seconds: 'float' = 4.0) -> 'bool'",
  "doc": "ユニットの頭上にチャットの吹き出しを出します（配信 / デバッグ用。ゲームには影響しません）。出せなかったときは False を返し、理由は g.last_say_error に入ります。"
 },
 {
  "name": "message",
  "category": "control",
  "status": "inferred",
  "mechanism": "アクション 45",
  "latency": "コントロールチャネル",
  "signature": "message(text: 'str') -> 'bool'",
  "doc": "ゲーム画面左下のメッセージ欄に 1 行表示します（このマシンでのみ表示）。ゲーム自身が先に一度メッセージを表示している必要があります（DLL はそのときにメッセージ枠を捕捉します）。"
 },
 {
  "name": "end_game",
  "category": "control",
  "status": "verified",
  "mechanism": "アクション 22",
  "latency": "コントロールチャネル",
  "signature": "end_game() -> 'bool'",
  "doc": "このゲームプロセスを終了します（farm.py --keep を使っていれば、next_game.json に従って次の試合が自動で始まります）。"
 },
 {
  "name": "canvas",
  "category": "control",
  "status": "verified",
  "mechanism": "W3P 73 canvas_enable + 共有メモリ Local\\War3Canvas_<pid>（ランタイムが毎フレーム、ゲームがカーソルを描く直前に描画。カーソルがその上に重なる）",
  "latency": "共有メモリ",
  "signature": "canvas()",
  "doc": "キャンバス：ゲーム画面にテキストボックス、パネル、プログレスバー、画像、地面の円やルートを描きます（openwar3.canvas.Canvas）。\nランタイムが自前で描画し、ゲームのハンドルを作らず、ゲームの状態も変えません —— マルチプレイでも安全です。スタイルは自由（CJK 文字、角丸、半透明）。"
 },
 {
  "name": "press_to_continue",
  "category": "control",
  "status": "verified",
  "mechanism": "PostMessage WM_KEYDOWN/UP でスペースをゲームウィンドウに送信（フォーカスは奪わない）",
  "latency": "ウィンドウメッセージ",
  "signature": "press_to_continue() -> 'bool'",
  "doc": "「任意のキーを押して続行」のロード画面でスペースキーを 1 回押します。多くの RPG / ストーリーマップはロード後にキーを押さないと始まりません（09-24 WarChasers で実測：\n押さないとロード画面のまま止まり、ゲームクロックは 0、ファストレーンのキューも処理されない）。openwar3.run などはゲームに入る際に自動で押すので、通常は手動で呼ぶ必要はありません。"
 },
 {
  "name": "map_data",
  "category": "observe",
  "status": "verified",
  "mechanism": "マップファイル（ランチャーの --map のパス）：w3u/w3t/w3a + wts。保護されたマップはマップ内の TXT を読む",
  "latency": "ファイル読み取り（初回は約 0.1 秒）",
  "signature": "map_data()",
  "doc": "プレイ中のマップのデータ（openwar3.mapdata.MapData）：name_of('HC07') でカスタムユニット / アイテム / アビリティの名前、hero_names、tooltip。\nRPG マップのユニットはほとんどがマップ独自のもので、組み込みの名前表にはありません。ランチャーから起動したゲームでない場合（マップファイルが見つからない）は None を返します。"
 },
 {
  "name": "jass",
  "category": "sandbox",
  "status": "verified",
  "mechanism": "W3P 70 jass（ランタイムが名前で native テーブルを引く。1291 個）",
  "latency": "ファストレーン",
  "signature": "jass()",
  "doc": "任意の JASS native を名前で呼び出します：g.jass.CreateUnit(g.jass.Player(1), \"Hpal\", x, y, 270.0)。\n引数 I/R/B/S/H は自動で変換されます（ユニット / アイテムのオブジェクトはそのまま渡せます）。マルチプレイでは読み取り専用のものしか呼べません。詳しくは openwar3/jass.py と docs/COMPANION_ZH.md を参照してください。"
 },
 {
  "name": "player_slots",
  "category": "sandbox",
  "status": "verified",
  "mechanism": "JASS GetPlayerController / GetPlayerSlotState / IsPlayerAlly",
  "latency": "ファストレーン",
  "signature": "player_slots() -> 'list[dict]'",
  "doc": "16 個のプレイヤースロット：controller（user 人間 / computer / neutral…）、state（empty / playing / left）、human、me、ally（自分と同盟かどうか）。\nRPG マップでコンパニオンを置く空きスロットを探したり、シングルプレイかどうかを判定したりするのに使います。"
 },
 {
  "name": "spawn",
  "category": "sandbox",
  "status": "verified",
  "mechanism": "JASS CreateUnit + W3P 72 ハンドル -> ユニット",
  "latency": "ファストレーン",
  "signature": "spawn(code: 'str', x: 'float', y: 'float', player: 'int | None' = None, facing: 'float' = 270.0)",
  "doc": "(x,y) にユニットを 1 体生成し（player のデフォルトはローカルプレイヤー）、スナップショット内のユニットを返します（次のワールド発行を待つので約 50 ms）。生成できなければ None を返します。\n返されるユニットには jass_handle 属性が追加されます。⚠ シングルプレイでのみ使用できます（マルチプレイでは同期ずれを起こします）。"
 },
 {
  "name": "set_alliance",
  "category": "sandbox",
  "status": "verified",
  "mechanism": "JASS SetPlayerAlliance",
  "latency": "ファストレーン",
  "signature": "set_alliance(a: 'int', b: 'int', allied: 'bool' = True, vision: 'bool' = True, control: 'bool' = False, xp: 'bool' = False, both: 'bool' = True) -> 'None'",
  "doc": "プレイヤー a から b への同盟関係を設定します：allied = 互いに攻撃しない + 互いに救援要請、vision = 視界の共有、control = ユニット制御の共有（b が a のユニットを指揮できる）、\nxp = 経験値の共有。both=True なら両方向を同時に設定します（control は a -> b のみ）。"
 },
 {
  "name": "set_player_name",
  "category": "sandbox",
  "status": "verified",
  "mechanism": "JASS SetPlayerName",
  "latency": "ファストレーン",
  "signature": "set_player_name(player: 'int', name: 'str') -> 'None'",
  "doc": "プレイヤー名を変更します（スコアボード、チャット、同盟パネルに表示される名前）。コンパニオンに名前を付けるのに使います。"
 },
 {
  "name": "show_text",
  "category": "sandbox",
  "status": "verified",
  "mechanism": "JASS DisplayTimedTextToPlayer",
  "latency": "ファストレーン",
  "signature": "show_text(text: 'str', seconds: 'float' = 6.0, player: 'int | None' = None) -> 'None'",
  "doc": "ゲーム画面の左下に 1 行のテキストを表示します（マップのトリガーが使うあのテキスト）。デフォルトではローカルプレイヤーに表示します。|cffRRGGBB カラーコードに対応。"
 }
]