RPG 玩伴
在 RPG / 自訂地圖裡幫玩家配一個 AI 夥伴:跟著你、幫你打怪、殘血時幫你補血、陪你聊天。四種形態,繼承一個類別、改幾個屬性,就是你自己的玩伴。
不只是對戰。在 RPG、自訂地圖裡,你可以幫自己配一個 AI 夥伴:它跟著你走、幫你打怪,你殘血時幫你補血,沒事的時候陪你聊兩句 —— 台詞還能接本機 LLM。
怎麼用由你自己決定。 這件事拆成三層 API,從底到頂,哪一層都能直接用:
| 層 | 是什麼 | 適合 |
|---|---|---|
JASS 通道 g.jass | 地圖作者能用的 1291 個 JASS 函式,依名稱直接呼叫(造單位、設盟友、給物品、改名、顯示文字、復活英雄……) | 想自己打造玩法 |
| 便捷 API | g.spawn、g.set_alliance、g.player_slots、g.show_text、g.map_data:常用的幾件事都包好了 | 寫自己的輔助腳本 |
| 玩伴框架 | openwar3.companion.Companion + openwar3.talk.Talk:繼承一下、改幾個屬性,就是一個會跟隨、助戰、補血、聊天的夥伴 | 想要一個夥伴 |
只用於單機、區域網路自建的遊戲。造單位、設盟友這類操作是本機單方面修改世界:單人局(和電腦打)沒問題;多人局會讓其他玩家不同步,所以多人局裡 JASS 通道只放行唯讀的函式,玩伴自動退回「只說話」。
最快上手:在遠見裡一鍵開啟
- 選地圖:遠見「實例」頁 →「下一局設定」→ 地圖,選一張 RPG 地圖(遊戲目錄
Maps底下Scenario、Download裡的都會列出來,例如(4)WarChasers)。 - 選方案:實例卡片的「AI 方案」下拉選單裡選 玩伴範例(buddy) →「選定」。
- 開始測試:遊戲啟動後,你自己在遊戲視窗裡玩。玩伴 —— 一個叫「小聖」的聖騎士 —— 會出現在你身邊。
也可以用命令列:
python tools/play.py --bot brains/examples/buddy.py --inst 20 --rpg --map "<遊戲目錄>\Maps\Scenario\(4)WarChasers.w3m"
--rpg(方案說明書裡是 "judge": false)表示不依對戰規則判定勝負:RPG 裡英雄死了能復活,也沒有「建築全沒了就算輸」。很多 RPG 地圖載入完會停在「按下任意鍵以繼續」,SDK 發現「在局內、但遊戲時鐘一直是 0」時會自己按一下空白鍵(g.press_to_continue(),只往遊戲視窗送按鍵訊息,不搶焦點)。
寫一個自己的玩伴
from openwar3.companion import Companion
from openwar3.talk import Talk
class MyBuddy(Companion):
mode = "ally" # 形態,見下表
unit = "Hpal" # 造什麼:任何四字碼,地圖自訂的也行
nickname = "小聖"
heal = ("holybolt", "AHhb", 0.55) # (施法訂單名, 要學的技能, 主人血量低於多少就補血);None = 不補血
follow_distance = 350
talk = Talk(persona="活潑的小聖騎士,愛幫主人加油")
四種形態
| mode | 玩伴是誰 | 說明 |
|---|---|---|
ally(預設) | 占一個空著的玩家槽位,當你的盟友 | 有自己的顏色和名字(計分板、盟友面板顯示 nickname);你點不到它,它自己打。框架自動設成同盟 + 共享視野 |
own | 造在你名下 | 你隨時能手動指揮它;你不管的時候,AI 替你操作 |
adopt | 接管地圖裡已有的單位 | 覆寫 adopt(g),回傳那個單位(地圖給你的寵物、隨從) |
voice | 不造單位,只說話 | 陪聊、提醒;不修改世界,多人局也能用 |
沒有空槽位時 ally 自動退回 own;多人局或造不出來時自動退回 voice。
ally 形態的玩伴認的是「那個槽位現在最好的單位」(英雄優先),而不是死守一個單位。實測時有地圖把玩伴當成真人玩家,刪掉聖騎士、發了一個地圖英雄 —— 玩伴會直接接管這個英雄,也會學地圖為它設定的技能。英雄死了優先原地復活;地圖自己復活了就接著用。
每一拍做什麼
依序檢查,哪條成立就做哪條:
| 順序 | 行為 | 條件 | 可調 |
|---|---|---|---|
| 1 | 撤退 | 自己血量低於 25% 且附近有敵人:退到主人身後 | retreat_at |
| 2 | 補血 | 主人血量低於設定值、技能冷卻好了、距離在 900 以內 | heal(None 關閉) |
| 3 | 助戰 | 主人身邊有敵人:正在打主人的 > 主人正在打的 > 最近的 | assist_radius,或覆寫 pick_target |
| 4 | 跟隨 | 離主人太遠就跟上;遠到一定程度直接跑回來、不戀戰 | follow_distance、leash |
| 5 | 閒聊 | 沒有敵人時,每隔 1 ~ 2.5 分鐘說一句 | 台詞表 |
「敵人」依遊戲裡的同盟關係判定(每 20 秒更新一次)。RPG 地圖常有好幾家盟友,不能簡單地把「除了我以外的玩家」都當成敵人。
可以覆寫的掛鉤:find_master(誰是主人,預設為本機等級最高的英雄)、adopt、pick_target、on_poke(主人右鍵點了玩伴),以及 Bot 的 on_start / on_tick / on_event / on_end。補血、助戰、擊殺、跟隨、撤退、說話、復活的次數都記在 self.stats 裡,結束時印出。
怎麼叫它
- 聊天命令:在聊天框輸入
-follow跟著我、-stay原地守著、-heal馬上補血、-hi打招呼。要改命令表就改commands,要改反應就覆寫on_command。 - 右鍵點玩伴:觸發
on_poke。範例裡的反應是:主人沒滿血就幫主人補一口血,否則說句話。 - 頭像對白:打招呼、主人倒下、主人升級、玩伴回來,這幾句會用遊戲自己的頭像對白來說(底部頭像換成玩伴,畫面上出現字幕),其餘的用頭頂氣泡顯示。
- 狀態面板:畫面左側一塊面板,顯示玩伴的血條、正在做什麼、心情(開心 / 興奮 / 緊張 / 害怕 / 難過)、擊殺和補血次數。它用 畫板 繪製,多人局也安全。
說話,以及本機 LLM
Talk 依事件挑選台詞,頭頂冒出氣泡;voice 形態或冒不出氣泡時,顯示在畫面左下角。每句話也會寫進方案日誌,事後能查它說過什麼。
| 事件 | 什麼時候 | 事件 | 什麼時候 |
|---|---|---|---|
hello | 剛來 | master_low | 主人殘血 |
poke | 主人右鍵點它 | master_levelup | 主人升級 |
fight | 開打 | master_died / master_back | 主人倒下 / 復活 |
kill | 打死一隻怪(會說出怪的名字) | buddy_low / buddy_died / buddy_back | 玩伴自己殘血 / 倒下 / 回來 |
healed | 幫主人補了血 | idle / item | 閒聊 / 撿到東西 |
台詞裡能用 {master}、{me}、{map}、{enemy}、{level}、{item} 這些預留位置;改台詞直接改 talk.lines,冷卻時間在 talk.cooldown。
接本機 LLM:Talk(llm=LocalLLM(url, model)),任何 OpenAI 相容的 API 都行(LM Studio、Ollama……)。模型在背景執行緒裡回答,答完才說;沒開、逾時或出錯就說固定台詞,不會卡住遊戲。請求只送到你給的本機位址,內容是遊戲裡發生的事(主人叫什麼、打了什麼怪)。
自訂地圖的單位名稱
RPG 地圖的單位、物品、英雄大多是地圖自己新建的(四字碼像 HC07、I00A),內建名稱表裡查不到。g.map_data 直接讀取目前這一局的地圖檔案:
md = g.map_data
md.name_of("HC07") # 'Optimus Primo' —— 地圖改過的名稱優先
md.hero_names("HC07") # 稱號清單
md.hero_skills("OC10") # 地圖為這個英雄設定的技能
md.tooltip("I00A") # 說明文字
有保護、最佳化過的地圖(很多熱門 RPG)不帶標準的物件資料檔,名稱會從地圖裡的文字資料讀取。實測本機 38 張 RPG / 自訂地圖全部解析成功,其中 37 張取得了單位名稱。
做成方案分享
玩伴就是一個 openwar3.Bot 子類別,可以做成 AI 方案 分享給別人。說明書裡多寫兩項:
{"id": "my-buddy", "name": "我的玩伴", "entry": "my_buddy.py", "fair": false, "judge": false}
"fair": false:要用 JASS 通道(造單位、設盟友);"judge": false:不依對戰規則判定勝負。
實測紀錄
2026-09-24,測試實例,WarChasers 地圖,2 倍速:
- JASS 通道 18 項檢查全部通過:玩家槽位、單位和控制代碼的雙向換算、實數回傳值、字串參數、在空槽位造單位、設盟友、改名、刪單位;從玩家車道呼叫、參數個數不對,都被正確拒絕。
- 玩伴:自己按過「按任意鍵繼續」→ 出現在主人身邊打招呼 → 跟著進入選英雄的能量圈、被地圖發了英雄並接管 → 跟隨(離主人 200 ~ 400)→ 打怪、打死一隻說「漂亮!」→ 殘血撤退 → 陣亡後被地圖復活,接著跟。
還沒做的
- 讀不到玩家打的任意聊天文字。固定的聊天命令已經能用;要讓玩伴真的陪你自由聊天,還需要拿到文字本身。
- 玩伴不懂具體地圖的玩法(任務、商店、劇情)。它做的是通用的跟隨、助戰、補血;要懂某一張地圖,就在子類別裡針對那張地圖寫 ——
g.map_data能查名稱,g.jass能呼叫任何函式。這正是留給你自己決定的部分。