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

JASS-канал

1291 функцию JASS, доступную авторам карт, теперь можно вызывать по имени извне игры: создавать юнитов, менять свойства, эффекты, панели, диалоги, звук, камеру, туман войны… Четыре способа: консоль Farsight, командная строка, HTTP и Python.

Все native-функции JASS (их 1291), которыми авторы карт пользуются в скриптах карт, теперь можно вызывать по имени извне игры: создавать юнитов, менять свойства, рисовать эффекты, показывать панели и диалоги, играть звуки, двигать камеру, менять туман войны… Это путь к дальнейшей настройке игры под себя: помощники для RPG, ИИ-компаньон, собственные мини-режимы, инструменты отладки.

СпособДля чегоГде
Страница «JASS-консоль» в FarsightПробовать вручную, смотреть и править на ходуЛевая панель «Система → JASS-консоль»: пишете скрипт и нажимаете «Выполнить», справа — функции по категориям, щелчок вставляет функцию в скрипт
Командная строкаПробовать вручную или запускать файл-скрипт снова и сноваpython -m openwar3 jass --inst 20 (интерактивно), -e "код", my_script.j, --list слово
HTTPВнешние программы на любом языкеPOST /api/instances/{n}/jass и др. (см. ниже), бэкенд Farsight слушает только локальный адрес
PythonСхемы, компаньоны, инструментыg.jass.ЛюбаяФункция(...); частые визуальные эффекты и взаимодействие обёрнуты в openwar3.visual

Три ограничения, и все продиктованы механикой:

  • Менять мир можно только в одиночной игре (против компьютера на вашей машине). Если ваш компьютер в одностороннем порядке создаёт объекты и меняет юнитов, в многопользовательской игре у остальных игроков начнётся рассинхронизация, — поэтому там пропускаются только функции для чтения (Get*, Is*, Count*…).
  • Только для ваших локальных инструментов: вызовы через подключение от имени игрока (Game(player=N)) или в честном режиме отклоняются.
  • Только для одиночных игр и игр по локальной сети, созданных вами.

Чтобы добавить что-то на экран в многопользовательской игре, используйте холст: его рисует сам рантайм, состояние игры не меняется.

Как писать скрипты

Консоль, командная строка и HTTP используют один и тот же язык скриптов. Одна строка — одна инструкция; можно вставлять JASS как есть (call / set / local, true / false / null, четырёхсимвольные коды вида 'Hpal', комментарии //), а можно писать в стиле Python:

set h = hero()                                   // встроенная: главный герой нашей стороны
local texttag t = CreateTextTag()
call SetTextTagText(t, "|cffffcc00+128 Крит!|r", 0.024)
call SetTextTagPosUnit(t, h, 60)
call SetTextTagVelocity(t, 0, 0.03)
call SetTextTagPermanent(t, false)
call SetTextTagLifespan(t, 4)
call SetTextTagVisibility(t, true)
call PingMinimapEx(h.x, h.y + 300, 3, 255, 0, 0, false)
set u = CreateUnit(Player(0), 'hfoo', h.x + 200, h.y, 270)
print("Создан", u, "уровень героя", GetHeroLevel(h))
  • Переменные сохраняются: в том же экземпляре и в том же матче переменные, заданные через set в одном фрагменте, доступны в следующем; при смене матча они очищаются автоматически, можно очистить их и вручную.
  • Встроенные функции: hero() — главный герой нашей стороны, me() — локальный игрок, unit('hfoo') — найти юнита, unit_at(x, y), wait(секунды), print(...). У юнита можно читать .x, .y, .hp, .hp_max, .mana, .type, .owner, .level; поддерживаются арифметика и сравнения.
  • Не поддерживаются if, loop, function — для логики используйте g.jass в Python (это обычные вызовы функций) или оформите всё как схему.
  • При ошибке вы узнаете номер строки и причину (нет такой функции, неверное число аргументов, переменная не определена…); инструкции до ошибки уже выполнены.

Параметры и возвращаемые значения:

В сигнатуреЧто передаватьПояснение
ЦелоеЧисло; четырёхсимвольный код 'Hpal' преобразуется автоматически
ВещественноеЧислоРантайм переводит его в формат, нужный движку
Логическоеtrue / false
Строка"..."Поддерживаются китайские символы и цветовые коды игры; строки, которые игра сохраняет у себя (всплывающий текст, панели, кнопки, команды чата), копируются в момент вызова — это безопасно
ДескрипторДескриптор из переменной или юнит (например, hero() автоматически превращается в дескриптор)
Функция (code)Только nullФункцию JASS извне передать нельзя; вызов вида TimerStart(t, 60, false, null) работает
Возвращаемая строка—Движок возвращает номер в таблице строк, текст прочитать нельзя. Имена юнитов — через g.map_data.name_of

Категории

Функции разбиты на категории по именам; по ним же устроены правая панель консоли и --list:

КатегорияЧислоПримеры
Визуальные эффекты80Всплывающий текст, молнии между юнитами, спецэффекты, изображения на земле, отпечатки на земле, цвет / масштаб / анимация юнита
Панели интерфейса146Многострочные панели, таблица лидеров, окна таймера, диалоги, задания, текст на экране, сигналы на миникарте, диалог с портретом, полноэкранные фильтры
Камера44Поля камеры, панорамирование, тряска камеры
Звук и музыка50Создание и воспроизведение звуков, музыка
Туман войны и обзор25Области видимости, включение и выключение тумана
Предметы / герои / юниты63 / 32 / 161Создать предмет, задать уровень героя, сменить владельца, добавить способность
Игроки / союзы / ресурсы71Настроить союз, изменить золото и древесину
Триггеры / события / таймеры62Создание триггеров, регистрация событий, таймеры
Рельеф / погода / разрушаемые объекты45Погодные эффекты, изменение рельефа, создание разрушаемых объектов
Ход игры57Скорость игры, пауза, время суток
Прочее…Группы юнитов и области, хранилище, скрипты компьютерного ИИ, преобразование типов и математика, ответы на события…

На 2026-09-24 в реальной игре по одной вызваны и проверены глазами 94 функции; остальные работают по тому же пути, просто их эффект не проверялся для каждой по отдельности.

Функции категории «ответы на события» (GetTriggerUnit, GetClickedButton…) имеют значение только в момент срабатывания триггера; при вызове извне они возвращают 0 или пустое значение. Чтобы узнать, «случилось ли событие», используйте счётчики событий, описанные ниже.

HTTP

Бэкенд Farsight (по умолчанию 127.0.0.1:8866, слушает только локальный адрес):

GET  /api/jass/natives?q=TextTag&cat=visual
POST /api/instances/20/jass        {"code": "set h = hero()\ncall PingMinimapEx(h.x, h.y, 3, 255, 0, 0, false)"}
     -> {"ok": true, "rows": [...], "printed": [...], "vars": {...}}
     -> ошибка: {"ok": false, "error": "第 2 行:...", "line": 2}
POST /api/instances/20/jass/call   {"name": "SetUnitScale", "args": [{"unit": 599669636}, 1.4, 1.4, 1.4]}
POST /api/instances/20/jass/reset  сбросить запомненные переменные

Параметр-юнит записывается как {"unit": адрес}, где адрес — это addr юнита из снимка. Замер: 60 ~ 90 ms на запрос.

Python: g.jass и openwar3.visual

j = g.jass
t = j.CreateTextTag()
j.SetTextTagText(t, "Привет", 0.024)   # правила для параметров те же, что в скриптах; юниты и предметы из снимка можно передавать как есть
j.signature("CreateImage")             # узнать сигнатуру

openwar3.visual.Visual(g) оборачивает проверенные частые визуальные эффекты — по одной строке на эффект (каждый тик вызывайте v.tick(): он удаляет истёкшее и передвигает линии и круги, привязанные к юнитам; v.clear() удаляет всё):

МетодЭффект
float_text(текст, юнит или точка, ...)Всплывающий текст: числа урона, подсказки над головой; китайские символы и цвета поддерживаются
link(a, b, kind)Линия между двумя юнитами, следует за ними: привязь / духовная связь / похищение жизни / волна исцеления
effect(модель, юнит или точка, ...)Модель эффекта: над головой, под ногами или однократно (взрыв, столб света)
ring(юнит или точка, радиус, color)Круг на земле: радиус способности, опасная зона, точка сбора; может следовать за юнитом
ping(точка, color)Сигнал на миникарте
board(заголовок, строки...)Многострочная панель в правом верхнем углу (с иконками), ячейки можно менять по одной
countdown(заголовок, секунды)Окно таймера в правом верхнем углу, отсчёт ведёт сама игра
scene(имя, реплика, portrait)Диалог с портретом: портрет внизу меняется на говорящего юнита, на экране появляется субтитр «имя: реплика»
screen_tint(color, alpha)Полноэкранный фильтр (по умолчанию красноватые края: предупреждение о малом здоровье)
sound(путь) / reveal(точка, радиус, секунды) / look(юнит, ...)Звук / рассеять туман на участке / перекрасить юнита, увеличить, проиграть анимацию, мигнуть

Взаимодействие: что сделал игрок — без функций JASS

Чтобы реагировать на действия игрока, в JASS нужно писать функции триггеров, а передать функцию извне нельзя. Выход такой: создать пустой триггер без условий и действий, только зарегистрировать событие — и считать, сколько раз он сработал. Проверено: пустой триггер тоже ведёт счёт.

МетодНазначение
chat_commands(["-follow", "-stay"]) → .poll()Команды, которые игрок набрал в чате (точное совпадение или по началу строки)
menu(заголовок, [кнопки...]) → .clicked()Меню из кнопок посреди экрана: какую нажали
hotkeys(("left", "right", "up", "down", "esc")) → .poll()Сколько раз нажаты стрелки и Esc
on("TriggerRegister...Event", аргументы...) → .poll()Сколько раз произошло любое событие JASS: гибель юнита, вход в область, получение урона, таймер…

Ограничение: известно только, «сколько раз это произошло», но не «кто это был и что именно напечатал». Чтобы различать, кто это был, заведите по счётчику на каждый объект. Именно так подключены команды чата у ИИ-компаньона.

Замечания

  • Созданное удаляйте сами: всплывающий текст, линии, изображения, панели, триггеры… Если не удалить, они так и останутся (Visual.clear() удаляет то, что создал сам). Одновременно в игре может быть не больше ~100 всплывающих текстов.
  • BJ-функции — не native: CreateTextTagUnitBJ и подобные собраны из native в скриптах карт, здесь их нет — вызывайте native так, как это сделано в их реализации.
  • Некоторые константы нужно сначала преобразовать: например, ConvertPlayerColor(1), ConvertFogState(4) (значения см. в common.j).
  • Один вызов — около 13 ms (включая преобразование дескрипторов); на уровне протокола это коды операций W3P 70 ~ 72, см. Протокол W3P.