# JASS 通道

> 地圖作者能用的 1291 個 JASS 函式，現在可以從遊戲外面依名稱直接呼叫：造單位、改屬性、特效、面板、對話框、聲音、鏡頭、迷霧……遠見指揮台、命令列、HTTP、Python 四種用法。

來源: https://war3ai.com/zh-tw/docs/jass/

地圖作者在地圖腳本裡能用的 **1291 個 JASS native**，現在都能從遊戲外面依名稱直接呼叫：造單位、改屬性、畫特效、彈出面板和對話框、播放聲音、移動鏡頭、改迷霧……拿來為遊戲做進一步的自訂 —— RPG 輔助、[AI 玩伴](https://war3ai.com/zh-tw/docs/companion/)、自製小玩法、偵錯工具。

| 用法 | 適合 | 入口 |
|---|---|---|
| **遠見「JASS 控制台」頁** | 手動試、邊看邊改 | 左側欄「系統 → JASS 控制台」：寫好腳本點執行，右邊依分類查函式，點一下就插入腳本 |
| **命令列** | 手動試，或寫成腳本檔案反覆執行 | `python -m openwar3 jass --inst 20`（互動）、`-e "程式碼"`、`my_script.j`、`--list 關鍵字` |
| **HTTP** | 任何語言的外部程式 | `POST /api/instances/{n}/jass` 等（見下文），遠見後端只監聽本機 |
| **Python** | 寫方案、寫玩伴、寫工具 | `g.jass.任意函式(...)`；常用的畫面和互動封裝在 `openwar3.visual` |

> **注意**
>
> 三條邊界，都是機制決定的：
> 
> - 只有**單人局**（和本機的電腦打）能修改世界。本機單方面建立物件、修改單位會讓多人局裡其他玩家不同步 —— 多人局只放行唯讀的函式（`Get*`、`Is*`、`Count*`……）。
> - 只給本機自己的工具使用；以玩家身分連線（`Game(player=N)`）或在公平模式下呼叫會被拒絕。
> - 只用於單機、區域網路自建的遊戲。
> 
> 要在多人局裡往畫面上加東西，用 [畫板](https://war3ai.com/zh-tw/docs/canvas/)：它是執行環境自己畫的，不修改遊戲狀態。

## 腳本寫法

控制台、命令列、HTTP 用的是同一套腳本。一行一句，**可以直接貼上 JASS**（`call` / `set` / `local`、`true` / `false` / `null`、`'Hpal'` 四字碼、`//` 註解），也可以寫成 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')` 找一個單位、`unit_at(x, y)`、`wait(秒)`、`print(...)`。單位能讀 `.x`、`.y`、`.hp`、`.hp_max`、`.mana`、`.type`、`.owner`、`.level`，支援四則運算和比較。
- **不支援** `if`、`loop`、`function` —— 要寫邏輯，就用 Python 的 `g.jass`（它就是普通的函式呼叫），或者寫成 [方案](https://war3ai.com/zh-tw/docs/schemes/)。
- 出錯時會告訴你第幾行、為什麼（沒有這個函式、參數個數不對、變數未定義……）；出錯之前的語句已經生效。

參數和回傳值：

| 簽章裡 | 傳什麼 | 說明 |
|---|---|---|
| 整數 | 數字；`'Hpal'` 四字碼自動轉換 | |
| 實數 | 數字 | 執行環境轉成引擎要的格式 |
| 布林 | `true` / `false` | |
| 字串 | `"..."` | 支援中文和遊戲的顏色碼；會被遊戲存起來的那些（浮動文字、面板、按鈕、聊天命令）都是當場複製一份，安全 |
| 控制代碼 | 變數裡的控制代碼，或者單位（`hero()` 這種會自動換成控制代碼） | |
| 函式（code） | 只能 `null` | 從外面給不出 JASS 函式；`TimerStart(t, 60, false, null)` 這種可以 |
| 回傳字串 | —— | 引擎回傳的是字串表編號，讀不回文字。單位名稱用 `g.map_data.name_of` |

## 分類

函式依名稱分了類，控制台右邊和 `--list` 都依這個分：

| 分類 | 個數 | 例子 |
|---|---|---|
| 畫面效果 | 80 | 浮動文字、閃電連線、特效、地面貼圖、地面印記、單位變色 / 縮放 / 播放動作 |
| 介面面板 | 146 | 多行面板、排行榜、倒數計時視窗、對話框、任務、螢幕文字、小地圖閃點、頭像對白、全螢幕濾鏡 |
| 鏡頭 | 44 | 鏡頭欄位、平移、鏡頭震動 |
| 聲音音樂 | 50 | 建立和播放聲音、播放音樂 |
| 迷霧視野 | 25 | 可見區域、開關迷霧 |
| 物品 / 英雄 / 單位 | 63 / 32 / 161 | 造物品、設英雄等級、換擁有者、加技能 |
| 玩家 / 同盟 / 資源 | 71 | 設同盟、改金錢木材 |
| 觸發器 / 事件 / 計時器 | 62 | 建立觸發器、註冊事件、計時器 |
| 地形 / 天氣 / 可破壞物 | 45 | 天氣效果、改地形、造可破壞物 |
| 遊戲流程 | 57 | 遊戲速度、暫停、晝夜時間 |
| 其他 | …… | 單位組與區域、儲存、電腦 AI 腳本、型別轉換與數學、事件回應…… |

2026-09-24 逐一實機呼叫、親眼看過效果的有 **94 個**；其餘走的是同一條路，只是沒有逐一看過效果。

> **說明**
>
> 「事件回應」類函式（`GetTriggerUnit`、`GetClickedButton`……）只在觸發器執行的那一刻有值，從外面呼叫拿到的是 0 或空值。想知道「發生了沒有」，用下文的事件計數。

## HTTP

遠見後端（預設 `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`。實測一次請求 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)` 把實測過的常用畫面效果封裝成一句話一個（每拍呼叫一次 `v.tick()`：到期的刪掉、跟著單位的線和圈移過去；`v.clear()` 全部刪除）：

| 方法 | 效果 |
|---|---|
| `float_text(文字, 單位或點, ...)` | 浮動文字：傷害數字、頭頂提示，中文和顏色都行 |
| `link(a, b, kind)` | 兩個單位之間一條線，跟著單位走：牽引 / 靈魂鏈 / 吸血 / 治療波 |
| `effect(模型, 單位或點, ...)` | 特效模型：頭頂、腳下，或者播放一次（爆炸、光柱） |
| `ring(單位或點, 半徑, color)` | 地上的範圍圈：技能範圍、危險區、集合點，可以跟隨單位 |
| `ping(點, color)` | 小地圖閃點 |
| `board(標題, 行...)` | 右上角多行面板（帶圖示），可以逐格修改 |
| `countdown(標題, 秒)` | 右上角倒數計時視窗，遊戲自己走秒 |
| `scene(名字, 話, portrait)` | 頭像對白：底部頭像換成會說話的單位，畫面上出現「名字：話」字幕 |
| `screen_tint(color, alpha)` | 全螢幕濾鏡（預設四周泛紅：殘血警告） |
| `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 事件發生了幾次：單位死亡、進入區域、受傷、計時器…… |

局限是只知道「發生了幾次」，不知道「是誰、打了什麼字」。要分清是誰，就為每個物件各建一個計數器。[AI 玩伴](https://war3ai.com/zh-tw/docs/companion/) 的聊天命令就是這樣接上的。

## 注意事項

- **建立出來的東西要自己刪**：浮動文字、連線、貼圖、面板、觸發器……不刪就一直在（`Visual.clear()` 會刪它自己建立的）。遊戲裡同時最多約 100 個浮動文字。
- **BJ 函式不是 native**：`CreateTextTagUnitBJ` 這類是地圖腳本裡用 native 組出來的，這裡沒有 —— 照著它的實作去呼叫 native。
- **有些常數要先轉換**：例如 `ConvertPlayerColor(1)`、`ConvertFogState(4)`（取值見 common.j）。
- 一次呼叫約 13 ms（含控制代碼換算）；協定層是 W3P 操作碼 70 ~ 72，見 [W3P 協定](https://war3ai.com/zh-tw/docs/protocol/)。
