# Игровые моды

> Схема — это не только ИИ, который играет за вас, но и набор правил: вы сами играете в окне игры, а мод расставляет всё на старте, выпускает волны врагов, выдаёт награды, показывает вам на экране кнопки и карточки выбора и определяет исход. Унаследуйте openwar3.Mod — один файл, один геймплей.

Источник: https://war3ai.com/ru/docs/mods/

[ИИ-схемы](https://war3ai.com/ru/docs/schemes/) бывают двух видов: `kind: bot` — это ИИ, который играет за вас; `kind: mod` — это **набор правил**: вы сами играете в окне игры, а мод ставит задачи — как всё расставить на старте, когда выпускать волны врагов (по времени или по событиям), какие давать награды, какие кнопки и карточки показать вам на экране, когда засчитать победу.

Мод использует только готовые возможности: [интерфейс и ввод](https://war3ai.com/ru/docs/ui-input/) (кнопки, карточки, горячие клавиши, клики по земле), [холст](https://war3ai.com/ru/docs/canvas/) (панели, полоски прогресса, маршруты), [JASS-канал](https://war3ai.com/ru/docs/jass/) (создание юнитов, изменение характеристик, выдача предметов), поток событий (гибель, повышение уровня, применение способностей, чат).

## Два примера

Выбираются в Farsight: «ИИ-схемы» → «Встроенные»:

| Мод | Как играть | Что использует |
|---|---|---|
| **Рогалик с героем** `builtin/hero-roguelike` | У вас один паладин, а враги волна за волной наступают со всех сторон; с каждым новым уровнем посреди экрана — выбор одного улучшения из трёх (пока выбираете, игра на паузе); продержались 10 волн — победа, герой погиб — поражение | `g.ui.choice` (кликабельные карточки + пауза), события `hero.levelup` / `killed` / `spell.cast`, команда чата `-help`, изменение характеристик героя и выдача предметов через JASS |
| **Бесконечная оборона** `builtin/endless-defense` | Враги появляются на стартовой точке напротив и по красной линии на земле бегут к вашей ратуше; за каждую отбитую волну — золото; кнопка на экране или F7 досрочно вызывает следующую волну, награда ×1.5; F8, а затем левый клик по земле — бесплатная сторожевая башня (правый клик — отмена) | `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     # запустить матч: управление берёт мод, вы играете в окне игры
```

## Пишем мод

```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)             # пустой слот как «игрок волн»: ни с кем не в союзе, без компьютерного ИИ
        self.every(30, self.wave)                  # волна каждые 30 игровых секунд (на паузе таймер стоит)
        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=)` | Создаёт юнитов по кругу — даже волна из нескольких десятков не вызывает подтормаживаний; возвращает дескрипторы JASS |
| `alive_of(g, игрок)` / `attack_move_all(g, игрок, точка)` | Живые юниты игрока / всех — в атаку с движением к точке (вызывайте раз в несколько секунд, и враги будут преследовать) |
| `home(g)` / `hud(g, заголовок, строки)` | Позиция нашего главного здания / информационная панель в правом верхнем углу |
| `neutralize_ai = True` | Нейтрализовать компьютерного противника на старте: его юниты ставятся на паузу каждые 5 секунд, золото и древесина обнуляются. На картах для обычных матчей компьютерный противник есть всегда, а когда правила задаёт мод, он только мешает |
| `single_player_only = True` | Не запускаться, если в игре есть другие живые игроки (JASS, меняющий мир, вызовет у них рассинхронизацию) |
| `linger_s = 6` | Сколько секунд показывать экран результата после определения исхода, прежде чем завершить |

`finish()` доступен и в `Bot`: обычный бот тоже может сам объявить конец матча.

## Оформить как схему и поделиться

В `scheme.json` укажите `"kind": "mod"`, а в файле входа определите подкласс `Mod`:

```json
{"id": "survive", "name": "Продержаться 10 волн", "kind": "mod", "entry": "survive.py", "class": "Survive"}
```

Мод всегда работает **без честного режима** (он судья, который ставит задачи: ему нужно видеть всю карту и менять мир) и **не определяет исход по правилам обычного матча** (исход сообщает `finish`); `fair` / `judge` в манифесте на него не действуют. Экспорт в zip, импорт, доверие и результаты — точно так же, как у схем-ботов, см. [ИИ-схемы](https://war3ai.com/ru/docs/schemes/). Мод — тоже код, поэтому перед первым запуском чужого мода нужно так же подтвердить доверие.

## Замеры

2026-09-25, тестовый экземпляр:

- **Рогалик с героем**: появилась первая волна, панель в правом верхнем углу обновляется; герой доведён до 3-го уровня → посреди экрана появились карточки, игровые часы остановились; два клика по карточкам → оба улучшения применились (сила 22 → 27), часы снова пошли.
- **Бесконечная оборона**: панель, маршрут на земле и кнопка на месте; F8 + клик по земле → рядом с ратушей появилась сторожевая башня; нажатие кнопки, пока волна ещё не зачищена → подсказка «Эта волна ещё не зачищена».

## Ограничения

- **Только одиночная игра**: создание юнитов и изменение характеристик идут через JASS-канал, а в многопользовательской игре это вызывает рассинхронизацию. Так устроена модель lockstep; многопользовательским режимам придётся дождаться канала синхронизации (см. [дорожную карту](https://war3ai.com/ru/roadmap/)).
- Мод видит всю карту — он ставит задачи, а не играет.
- Компьютерный противник на картах для обычных матчей только «нейтрализован», но не удалён (удаление запустило бы проверку победы по правилам обычного матча).
