# ゲームプレイ MOD

> スキームは、あなたの代わりに戦う AI だけではありません。ルール一式にもなれます。あなた自身がゲームウィンドウでプレイし、MOD が序盤の配置、敵の出現、報酬、画面上のボタンや選択カード、勝敗判定を担当します。openwar3.Mod を継承すれば、ファイル 1 つで遊び方が 1 つできあがります。

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

[AI スキーム](https://war3ai.com/ja/docs/schemes/) には 2 種類あります。`kind: bot` は AI で、あなたの代わりに戦います。`kind: mod` は**ルール一式**です —— あなた自身がゲームウィンドウでプレイし、MOD がお題を出します：序盤をどう配置するか、時間やイベントに応じてどう敵を出すか、どんな報酬を与えるか、画面にどんなボタンや選択カードを出すか、いつ勝ちとするか。

MOD が使うのは、すべて既存の機能です：[UI と入力](https://war3ai.com/ja/docs/ui-input/)（クリックできるボタン、カード、ホットキー、地面のクリック）、[キャンバス](https://war3ai.com/ja/docs/canvas/)（パネル、プログレスバー、ルート）、[JASS チャネル](https://war3ai.com/ja/docs/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` にあります。

```bash
python tools/play.py --bot brains/examples/mod_hero_roguelike.py --inst 9     # ゲームを起動し、MOD が進行を引き受ける。あなたはゲームウィンドウでプレイ
```

## MOD を書く

```python
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` のサブクラスを定義します。

```json
{"id": "survive", "name": "10 ウェーブ耐え抜け", "kind": "mod", "entry": "survive.py", "class": "Survive"}
```

MOD は常に**フェアモードを使わず**（お題を出すレフェリーなので、マップ全体を見てワールドを変える必要があります）、**対戦ルールでの勝敗判定もしません**（勝敗は `finish` で報告します）。マニフェストに `fair` / `judge` を書いても効果はありません。zip のエクスポート、インポート、信頼、戦績は Bot のスキームとまったく同じです。[AI スキーム](https://war3ai.com/ja/docs/schemes/) を参照してください。MOD もコードなので、他の人の MOD も初回実行前に同じく信頼の確認が必要です。

## 実測

2026-09-25、テストインスタンスにて：

- **ヒーローローグライク**：最初のウェーブが出現し、右上のパネルが動いている。ヒーローを 3 レベルに上げる → 画面中央にカードが出て、ゲーム時計が止まる。カードを 2 回クリック → 2 回の強化が反映され（筋力 22 → 27）、時計が再び動き出す。
- **エンドレスディフェンス**：パネル、地面のルート、ボタンがすべて表示されている。F8 + 地面をクリック → 本拠地の横に防御塔が 1 基増えた。ウェーブを片付けきる前にボタンをクリック → 「このウェーブはまだ片付いていません」と表示。

## 制約

- **シングルプレイ専用**：ユニットの生成や属性の変更は JASS チャネルを通るため、マルチプレイでは同期がずれます。これはロックステップモデルによるもので、マルチプレイでの遊び方は同期チャネルを待つ必要があります（[ロードマップ](https://war3ai.com/ja/roadmap/) を参照）。
- MOD はマップ全体を見ます —— お題を出す側であって、プレイヤーではないからです。
- 対戦マップのコンピューター対戦相手は「抑え込まれて」いるだけで、取り除かれてはいません（取り除くと対戦ルールの勝利判定が発動してしまいます）。
