# JASS チャネル

> マップ作者が使える 1291 個の JASS 関数を、ゲームの外から名前で直接呼び出せるようになりました。ユニット作成、属性変更、エフェクト、パネル、ダイアログ、サウンド、カメラ、霧……Farsight コンソール、コマンドライン、HTTP、Python の 4 通りの使い方があります。

出典: https://war3ai.com/ja/docs/jass/

マップ作者がマップスクリプトで使える **1291 個の JASS native** を、すべてゲームの外から名前で直接呼び出せるようになりました。ユニット作成、属性変更、エフェクト描画、パネルやダイアログの表示、サウンド再生、カメラ操作、霧の変更……ゲームをさらにカスタマイズするのに使えます —— RPG の補助、[AI コンパニオン](https://war3ai.com/ja/docs/companion/)、自作のミニゲーム、デバッグツールなど。

| 使い方 | 向いている用途 | 入口 |
|---|---|---|
| **Farsight の「JASS コンソール」ページ** | 手で試す、結果を見ながら直す | 左サイドバーの「システム → JASS コンソール」：スクリプトを書いて実行をクリック。右側で分類ごとに関数を調べ、クリックするとスクリプトに挿入 |
| **コマンドライン** | 手で試す、またはスクリプトファイルにして繰り返し実行する | `python -m openwar3 jass --inst 20`（対話モード）、`-e "コード"`、`my_script.j`、`--list キーワード` |
| **HTTP** | 任意の言語の外部プログラム | `POST /api/instances/{n}/jass` など（下記参照）。Farsight のバックエンドはローカルでのみ待ち受け |
| **Python** | スキーム、コンパニオン、ツールを書く | `g.jass.任意の関数(...)`。よく使う画面演出とインタラクションは `openwar3.visual` にまとめてあります |

> **注意**
>
> 境界は 3 つあり、どれも仕組み上の制約です。
> 
> - ワールドを変更できるのは**シングルプレイ**（ローカルのコンピューターとの対戦）だけです。自分のマシンが一方的にオブジェクトを作ったりユニットを変更したりすると、マルチプレイでは他のプレイヤーと同期がずれます —— マルチプレイでは読み取り専用の関数（`Get*`、`Is*`、`Count*`……）だけを許可します。
> - 自分のマシン上のツール専用です。プレイヤーとして接続した場合（`Game(player=N)`）やフェアモードでの呼び出しは拒否されます。
> - ローカル、または LAN で自分で立てたゲーム専用です。
> 
> マルチプレイで画面に何かを追加したいなら、[キャンバス](https://war3ai.com/ja/docs/canvas/) を使ってください。ランタイムが自前で描くもので、ゲームの状態は変えません。

## スクリプトの書き方

コンソール、コマンドライン、HTTP は同じスクリプトを使います。1 行に 1 文で、**JASS をそのまま貼り付けられます**（`call` / `set` / `local`、`true` / `false` / `null`、`'Hpal'` の 4 文字コード、`//` コメント）。Python 風に書くこともできます。

```text
set h = hero()                                   // 組み込み：自軍のメインヒーロー
local texttag t = CreateTextTag()
call SetTextTagText(t, "|cffffcc00+128 クリティカル！|r", 0.024)
call SetTextTagPosUnit(t, h, 60)
call SetTextTagVelocity(t, 0, 0.03)
call SetTextTagPermanent(t, false)
call SetTextTagLifespan(t, 4)
call SetTextTagVisibility(t, true)
call PingMinimapEx(h.x, h.y + 300, 3, 255, 0, 0, false)
set u = CreateUnit(Player(0), 'hfoo', h.x + 200, h.y, 270)
print("作成した", u, "ヒーローレベル", GetHeroLevel(h))
```

- **変数は保持されます**：同じインスタンスの同じゲームの中なら、ある実行で `set` した変数を次の実行でもそのまま使えます。ゲームが変わると自動でクリアされ、手動でクリアすることもできます。
- **組み込み関数**：`hero()` 自軍のメインヒーロー、`me()` ローカルプレイヤー、`unit('hfoo')` ユニットを 1 体探す、`unit_at(x, y)`、`wait(秒)`、`print(...)`。ユニットからは `.x`、`.y`、`.hp`、`.hp_max`、`.mana`、`.type`、`.owner`、`.level` を読め、四則演算と比較ができます。
- `if`、`loop`、`function` は**使えません** —— ロジックを書くなら Python の `g.jass`（普通の関数呼び出しです）を使うか、[スキーム](https://war3ai.com/ja/docs/schemes/) にしてください。
- エラーが起きると、何行目で、なぜ失敗したか（その関数がない、引数の個数が違う、変数が未定義……）を教えてくれます。エラーより前の文はすでに実行されています。

引数と戻り値：

| シグネチャ上の型 | 渡すもの | 説明 |
|---|---|---|
| 整数 | 数値。`'Hpal'` の 4 文字コードは自動で変換 | |
| 実数 | 数値 | ランタイムがエンジンの要求する形式に変換 |
| 真偽値 | `true` / `false` | |
| 文字列 | `"..."` | 中国語やゲームのカラーコードに対応。ゲームが保持し続けるもの（フローティングテキスト、パネル、ボタン、チャットコマンド）は、その場でコピーを取るので安全 |
| ハンドル | 変数に入ったハンドル、またはユニット（`hero()` などは自動でハンドルに変換） | |
| 関数（code） | `null` のみ | 外から JASS 関数は渡せません。`TimerStart(t, 60, false, null)` のような使い方は可能 |
| 文字列の戻り値 | —— | エンジンが返すのは文字列テーブルの番号なので、テキストは読み戻せません。ユニット名には `g.map_data.name_of` を使います |

## 分類

関数は名前で分類されていて、コンソールの右側と `--list` はどちらもこの分類を使います。

| 分類 | 個数 | 例 |
|---|---|---|
| 画面効果 | 80 | フローティングテキスト、ライトニングの線、エフェクト、地面の画像、地面のマーク、ユニットの色 / 拡大縮小 / アニメーション再生 |
| UI パネル | 146 | 複数行パネル、リーダーボード、カウントダウンウィンドウ、ダイアログ、クエスト、画面テキスト、ミニマップのピン、ポートレート会話、全画面フィルター |
| カメラ | 44 | カメラフィールド、パン、カメラの揺れ |
| サウンド・音楽 | 50 | サウンドの作成と再生、音楽の再生 |
| 霧・視界 | 25 | 可視領域、霧のオン / オフ |
| アイテム / ヒーロー / ユニット | 63 / 32 / 161 | アイテム作成、ヒーローのレベル設定、所有者の変更、スキル追加 |
| プレイヤー / 同盟 / 資源 | 71 | 同盟の設定、ゴールドと木材の変更 |
| トリガー / イベント / タイマー | 62 | トリガー作成、イベント登録、タイマー |
| 地形 / 天候 / 破壊可能オブジェクト | 45 | 天候エフェクト、地形の変更、破壊可能オブジェクトの作成 |
| ゲーム進行 | 57 | ゲーム速度、一時停止、時刻（昼夜） |
| その他 | …… | ユニットグループと領域、ストレージ、コンピューター AI スクリプト、型変換と数学、イベントレスポンス…… |

2026-09-24 に 1 つずつ実機で呼び出し、効果を目で確認したのは **94 個**です。残りも同じ経路を通りますが、1 つずつ効果を確認してはいません。

> **補足**
>
> 「イベントレスポンス」系の関数（`GetTriggerUnit`、`GetClickedButton`……）は、トリガーが実行されているその瞬間にしか値を持たず、外から呼ぶと 0 か空になります。「起きたかどうか」を知りたいなら、後述のイベントカウントを使ってください。

## HTTP

Farsight のバックエンド（デフォルトは `127.0.0.1:8866`、ローカルでのみ待ち受け）：

```http
GET  /api/jass/natives?q=TextTag&cat=visual
POST /api/instances/20/jass        {"code": "set h = hero()\ncall PingMinimapEx(h.x, h.y, 3, 255, 0, 0, false)"}
     -> {"ok": true, "rows": [...], "printed": [...], "vars": {...}}
     -> エラー時：{"ok": false, "error": "第 2 行：...", "line": 2}
POST /api/instances/20/jass/call   {"name": "SetUnitScale", "args": [{"unit": 599669636}, 1.4, 1.4, 1.4]}
POST /api/instances/20/jass/reset  記憶した変数をクリア
```

ユニット引数は `{"unit": アドレス}` と書きます。アドレスは、スナップショット内のユニットの `addr` です。実測で 1 リクエストあたり 60 〜 90 ms。

## Python：g.jass と openwar3.visual

```python
j = g.jass
t = j.CreateTextTag()
j.SetTextTagText(t, "こんにちは", 0.024)  # 引数のルールはスクリプトと同じ。スナップショットのユニットやアイテムのオブジェクトをそのまま渡せる
j.signature("CreateImage")               # シグネチャを調べる
```

`openwar3.visual.Visual(g)` は、実測済みのよく使う画面演出を、1 つにつき 1 行で呼べるようにまとめたものです（ティックごとに `v.tick()` を 1 回呼ぶと、期限切れのものを削除し、ユニットに追従する線や円を移動させます。`v.clear()` ですべて削除）。

| メソッド | 効果 |
|---|---|
| `float_text(テキスト, ユニットまたは地点, ...)` | フローティングテキスト：ダメージ数値、頭上のヒント。中国語も色も使えます |
| `link(a, b, kind)` | 2 体のユニットの間に線を引き、ユニットに追従させる：牽引 / スピリットリンク / ライフドレイン / ヒーリングウェーブ |
| `effect(モデル, ユニットまたは地点, ...)` | エフェクトモデル：頭上、足元、または 1 回だけ再生（爆発、光の柱） |
| `ring(ユニットまたは地点, 半径, color)` | 地面の範囲円：スキル範囲、危険エリア、集合地点。ユニットに追従させることも可能 |
| `ping(地点, color)` | ミニマップのピン |
| `board(タイトル, 行...)` | 右上の複数行パネル（アイコン付き）。セルごとに変更可能 |
| `countdown(タイトル, 秒)` | 右上のカウントダウンウィンドウ。秒読みはゲーム自身が行う |
| `scene(名前, セリフ, portrait)` | ポートレート会話：下部のポートレートが話すユニットに変わり、画面に「名前：セリフ」の字幕が出る |
| `screen_tint(color, alpha)` | 全画面フィルター（デフォルトは周囲が赤くなる：HP 低下の警告） |
| `sound(パス)` / `reveal(地点, 半径, 秒)` / `look(ユニット, ...)` | サウンド再生 / 霧を一部晴らす / ユニットの色変更、拡大、アニメーション再生、点滅 |

## インタラクション：JASS 関数を書かずに、プレイヤーの行動を知る

JASS でプレイヤーに反応するにはトリガー関数を書く必要がありますが、外から関数は渡せません。そこで、**条件もアクションもない空のトリガーを作ってイベントだけを登録し、それが何回実行されたかを数えます。** 実測では、空のトリガーでもきちんとカウントされます。

| メソッド | 用途 |
|---|---|
| `chat_commands(["-follow", "-stay"])` → `.poll()` | プレイヤーがチャット欄に入力したコマンド（完全一致、または前方一致） |
| `menu(タイトル, [ボタン...])` → `.clicked()` | 画面中央のボタンメニュー。どれがクリックされたか |
| `hotkeys(("left", "right", "up", "down", "esc"))` → `.poll()` | 矢印キーと Esc が何回押されたか |
| `on("TriggerRegister...Event", 引数...)` → `.poll()` | 任意の JASS イベントが何回起きたか：ユニットの死亡、領域への進入、被ダメージ、タイマー…… |

制約は、「何回起きたか」しか分からず、「誰が、何を入力したか」は分からないことです。誰なのかを区別したいなら、対象ごとにカウンターを 1 つずつ作ります。[AI コンパニオン](https://war3ai.com/ja/docs/companion/) のチャットコマンドも、この方法でつないでいます。

## 注意点

- **作ったものは自分で削除する**：フローティングテキスト、線、画像、パネル、トリガー……削除しなければずっと残ります（`Visual.clear()` は自分が作ったものを削除します）。ゲーム内で同時に存在できるフローティングテキストは、最大で約 100 個です。
- **BJ 関数は native ではありません**：`CreateTextTagUnitBJ` のような関数は、マップスクリプト内で native を組み合わせて作られたもので、ここにはありません —— その実装に倣って native を呼んでください。
- **定数によっては先に変換が必要**：たとえば `ConvertPlayerColor(1)`、`ConvertFogState(4)`（値は common.j を参照）。
- 1 回の呼び出しは約 13 ms（ハンドル変換を含む）。プロトコル層は W3P オペコード 70 〜 72 です。[W3P プロトコル](https://war3ai.com/ja/docs/protocol/) を参照してください。
