ゲームプレイ MOD
スキームは、あなたの代わりに戦う AI だけではありません。ルール一式にもなれます。あなた自身がゲームウィンドウでプレイし、MOD が序盤の配置、敵の出現、報酬、画面上のボタンや選択カード、勝敗判定を担当します。openwar3.Mod を継承すれば、ファイル 1 つで遊び方が 1 つできあがります。
AI スキーム には 2 種類あります。kind: bot は AI で、あなたの代わりに戦います。kind: mod はルール一式です —— あなた自身がゲームウィンドウでプレイし、MOD がお題を出します:序盤をどう配置するか、時間やイベントに応じてどう敵を出すか、どんな報酬を与えるか、画面にどんなボタンや選択カードを出すか、いつ勝ちとするか。
MOD が使うのは、すべて既存の機能です:UI と入力(クリックできるボタン、カード、ホットキー、地面のクリック)、キャンバス(パネル、プログレスバー、ルート)、JASS チャネル(ユニットの生成、属性の変更、アイテムの付与)、イベントストリーム(死亡、レベルアップ、スキル使用、チャット)。
2 つのサンプル
Farsight の「AI スキーム」→「組み込み」から選べます。
| MOD | 遊び方 | 使っている機能 |
|---|---|---|
ヒーローローグライク builtin/hero-roguelike | あなたの手元にはパラディンが 1 体だけ。敵が四方からウェーブごとに押し寄せます。レベルが上がるたびに、画面中央の 3 択から強化を 1 つ選びます(選ぶ間ゲームは一時停止)。10 ウェーブ耐え抜けば勝ち、ヒーローが死んだら負け | g.ui.choice(クリックできるカード + 一時停止)、hero.levelup / killed / spell.cast イベント、チャットの -help、JASS によるヒーローの属性変更とアイテム付与 |
エンドレスディフェンス builtin/endless-defense | 敵は反対側のスタート地点から、地面に描かれた赤い線に沿って本拠地へ突撃してきます。1 ウェーブ守り切るごとにゴールドがもらえます。画面のボタンをクリックするか F7 を押すと次のウェーブを前倒しで呼べて、報酬は ×1.5。F8 を押してから地面を左クリックすると、無料の Guard Tower を 1 基置けます(右クリックでキャンセル) | g.ui.button、g.ui.hotkey、g.ui.mouse(地面のクリックを捕捉)、キャンバスのパネル / プログレスバー / ルート、JASS による敵の出現とゴールドの追加 |
どちらのサンプルも 150 行ほどで、コードは brains/examples/mod_hero_roguelike.py と brains/examples/mod_endless_defense.py にあります。
python tools/play.py --bot brains/examples/mod_hero_roguelike.py --inst 9 # ゲームを起動し、MOD が進行を引き受ける。あなたはゲームウィンドウでプレイ
MOD を書く
from openwar3 import Mod
class Survive(Mod):
name = "survive"
def on_start(self, g):
super().on_start(g) # シングルプレイのチェック + コンピューター対戦相手を抑え込む
self.foe = self.wave_player(g) # 空きスロットのプレイヤーを「ウェーブ側」にする:誰とも同盟せず、コンピューター AI もなし
self.every(30, self.wave) # 30 ゲーム秒ごとに 1 ウェーブ(一時停止中は進まない)
g.ui.hotkey("F7", lambda g, ev: self.wave(g))
def wave(self, g):
self.spawn_ring(g, self.foe, "ugho", 6, self.home(g), 1400, attack_to=self.home(g))
def on_event(self, g, ev):
if ev.kind == "unit.died" and ev.type == "htow":
self.finish("loss", "本拠地が落とされた")
Mod は Bot に次のものを加えたものです。
| メソッド / 属性 | 説明 |
|---|---|
on_start / on_tick / on_event / on_end | Bot と同じです。on_start / on_tick をオーバーライドするときは、先に super() を呼ぶのを忘れないでください |
every(秒, fn, first=) / after(秒, fn) | ゲーム時間で進むタイマー。コールバックは fn(g) |
finish(result, reason) | この試合を終わらせます('win' / 'loss' / 'unknown')。ランナーは次のティックで停止し、画面中央に結果パネルを描き、スキームの戦績はこれに従って記録されます |
wave_player(g) | 最初の空きスロットのプレイヤー。ウェーブ側として使います |
spawn_ring(g, プレイヤー, ユニット, 数, 中心, 半径, attack_to=) | 円周上にユニットを出します。1 ウェーブ数十体でも重くなりません。JASS ハンドルを返します |
alive_of(g, プレイヤー) / attack_move_all(g, プレイヤー, 地点) | あるプレイヤーの生存ユニット / 全員をアタックムーブで向かわせる(数秒おきに呼べば、敵が追いかけ続けます) |
home(g) / hud(g, タイトル, 行) | 自軍の本拠地の位置 / 右上の情報パネル |
neutralize_ai = True | 開始時にコンピューター対戦相手を抑え込みます:そのユニットを 5 秒ごとに一時停止させ、ゴールドと木材を 0 にします。対戦マップには必ずコンピューターが 1 人いるので、MOD が独自のルールを決めるときに邪魔をさせないためです |
single_player_only = True | 他に人間のプレイヤーがいれば実行を拒否します(ワールドを変える JASS は他の人との同期ずれを起こします) |
linger_s = 6 | 勝敗が決まった後、結果画面で何秒止めてから終了するか |
finish() は Bot でも使えます。通常の Bot も自分で終了を宣言できます。
スキームにして共有する
scheme.json に "kind": "mod" と書き、エントリファイルで Mod のサブクラスを定義します。
{"id": "survive", "name": "10 ウェーブ耐え抜け", "kind": "mod", "entry": "survive.py", "class": "Survive"}
MOD は常にフェアモードを使わず(お題を出すレフェリーなので、マップ全体を見てワールドを変える必要があります)、対戦ルールでの勝敗判定もしません(勝敗は finish で報告します)。マニフェストに fair / judge を書いても効果はありません。zip のエクスポート、インポート、信頼、戦績は Bot のスキームとまったく同じです。AI スキーム を参照してください。MOD もコードなので、他の人の MOD も初回実行前に同じく信頼の確認が必要です。
実測
2026-09-25、テストインスタンスにて:
- ヒーローローグライク:最初のウェーブが出現し、右上のパネルが動いている。ヒーローを 3 レベルに上げる → 画面中央にカードが出て、ゲーム時計が止まる。カードを 2 回クリック → 2 回の強化が反映され(筋力 22 → 27)、時計が再び動き出す。
- エンドレスディフェンス:パネル、地面のルート、ボタンがすべて表示されている。F8 + 地面をクリック → 本拠地の横に防御塔が 1 基増えた。ウェーブを片付けきる前にボタンをクリック → 「このウェーブはまだ片付いていません」と表示。
制約
- シングルプレイ専用:ユニットの生成や属性の変更は JASS チャネルを通るため、マルチプレイでは同期がずれます。これはロックステップモデルによるもので、マルチプレイでの遊び方は同期チャネルを待つ必要があります(ロードマップ を参照)。
- MOD はマップ全体を見ます —— お題を出す側であって、プレイヤーではないからです。
- 対戦マップのコンピューター対戦相手は「抑え込まれて」いるだけで、取り除かれてはいません(取り除くと対戦ルールの勝利判定が発動してしまいます)。