На этой странице
Документация Расширения игры

Игровые моды

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

ИИ-схемы бывают двух видов: kind: bot — это ИИ, который играет за вас; kind: mod — это набор правил: вы сами играете в окне игры, а мод ставит задачи — как всё расставить на старте, когда выпускать волны врагов (по времени или по событиям), какие давать награды, какие кнопки и карточки показать вам на экране, когда засчитать победу.

Мод использует только готовые возможности: интерфейс и ввод (кнопки, карточки, горячие клавиши, клики по земле), холст (панели, полоски прогресса, маршруты), 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.

python tools/play.py --bot brains/examples/mod_hero_roguelike.py --inst 9     # запустить матч: управление берёт мод, вы играете в окне игры

Пишем мод

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:

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

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

Замеры

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

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

Ограничения

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