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.