WarCraft 3: Текстовые триггеры (custom text)

Осваиваем World Editor

Текстовые триггеры

В этой статье я расскажу про текстовые триггеры, что это такое и зачем они нужны.
Warcraft 3 создавался на определенном языке программирования (скорее всего на C). Создатели игры решили создать редактор WorldEdit, чтобы упростить работу себе и другим людям по созданию карт. Для начала они создали свой мини-язык (текстовые триггеры), команды которого позволяли управлять игрой. Однако язык этот был бы слишком сложен для тех, кто не занимается программированием и поэтому был создан редактор Trigger editor, который заметно упрощал работу.
Вместо того, чтобы вводить текстовые команды вручную, разработчик карт выбирет определенную команду из списка иуказывает определенные параметры (на самом деле, эти триггеры - из Trigger Editor при сохранении карты автоматически переводятся на другой язык - custom text - это файлы с расширением .j , а затем исполняются).
Итак, custom text близок к тому языку, на которм был написан warcraft3. Если бы blizzard сделали хороший Trigger Editor - то работать с custom text не имело бы смысла. Однако не все команды из custom text доступны в Trigger Editor. Пример: команда добавления таймера жизни юнита. Ее нет среди обычных команд Trigger Editor. Есть и другие примеры подобных команд. Другой пример - отсутствие в Trigger Editor нормальных циклов и ветвлений.
Команды For и if then else позволяют делать лишь одно действие. А если действий нужно сделать много? (на самом деле здесь есть такой прием: указать в качестве действия - запуск определенного триггера, в котором и будет реализованы нужные нам команды).Команда For так неудобна, что мало кто ей пользуется. Она реализует лишь один вид циклов, причем далеко не самый нужный. И, наконец, третий очень серьезный недостаток Trigger Editor - отсутствие локальных переменных, но об этом более подробно - в следующей статье.
Если вы захотите получить доступ к тем возможностям, которые не реализованы в Trigger Editor вам придется учиться работать в custom text. К счастью в Trigger Editor есть возможность переводить обычные триггеры в custom text (edit>>custom text). Вы сможете изучить, как выглядят простые триггеры в custom text, а затем и изменять их.
Сразу хочу предупредить, что писать что-то свое в custom text - очень тяжело. Ошибетесь в одном символе - вам будет выдан десяток ошибок, причем вы даже не поймете в чем дело. Даже если ошибок не будет, выдано, это еще не значит, что их нет. Некоторые ошибки не обнаруживаются при запуске, но когда при запуске триггера действие доходит до места с ошибкой - все остальные действия после ошибки отсекаются.
Для начинающих хочу дать пару советов по работе с текстовыми триггерами:
1. Сначала напишите триггер обычными средствами, а затем переведите его в custom text и добавьте то, что хотите: циклы, новые команды, локальные переменные.
2. Перед тем, как перевести триггер в custom text - сделайте с него копию.
3. Когда вы переводите триггер в текст вам будет сделано предупреждение, что данное действие необратимо. Чтож, перевести текст в триггеры действительно нельзя, зато можно отменить сделанное действие с помощью edit>>undo или просто нажать ctrl-z.
4. Как можно меньше набирайте сами, чтобы уменьшить вероятность ошибки. Допустим, вы уже сделали тестовый триггер, что-то в нем изменили и захотели добавить какую-нибудь стандартную команду. Создайте новый не текстовый триггер, который будет содержать одну эту команду, переведите его в текст. Вы увидите, как выглядит нужная вам команда. Не набирайте ее вручную! Используйте буфер обмена: выделяете команду, копируете edit>>copy (ctrl-ins), вставляете edit>>paste (shift-ins).
5. Как проверить правильность текстового триггера. Для этого не обязательно каждый раз запускать сценарий на исполнение. Просто выберете текcтовый триггер, делаете с него копию и измените для нее свойство enabled. Триггер выключится. Если вы попытаетесь его включить, а в триггере есть ошибка - вам будет выдано предупреждение вместе со списком ошибок.
6. Лучше не пытайтесь перевести в текст триггеры со свойством enabled=off или initialy=off. По крайней мере, пока не станете в них разбираться. В противном случае вы создадите текстовый триггер, который не будет работать, даже если вы измените его свойства (enabled, initialy). Чтобы он заработал надо будет удалить определенную команду триггера.
Когда вы преобразуете триггер в текст будут созданы несколько блоков функция (function). Блок с условиями триггера (его название будет оканчиваться на _condition) - идет самым первым.
Второй блок (обычно) - блок с действиями (его название будет оканчивается на _action).
Последний блок - с событиями (начнется function init_trig_:).
Кроме того, каждая проверка какого-то условия или дополнительное действие (ну например из if then else) приведут к созданию новых блоков (это будет группа функций, которые будут оканчиваться на буквенно-цифровые номера).
При переходе от нормальных триггеров к текстовым меняются названия юнитов, констант, переменных. Вместо конкретных юнитов будет какая-нибудь ерунда 'df5b' - что-нибудь в этом роде. Поменяют свои названия спецэффекты: было abilities\orc\: - какой нибудь спецэффект. В тексте придется брать в кавычки и писать не одну черту, а две: "abilities\\orc\\:".

Локальные переменные в Custom Text

Что такое глобальные переменные вы уже знаете. Все переменные, которые вы создаете в Trigger Editor - глобальные. На глобальные переменные можно ссылаться из всех триггеров. Глобальные переменные создаются в начале игры и действуют до ее конца.
Что касается локальных переменыых, то это переменные, которые создаются внутри определенного триггер (даже не триггера, а его определенной части). Создаются они в тот момент, когда триггер запускается на исполнение и перестают существовать, когда действие триггера окончено.
Если триггер запущен на исполнение несколько раз, то при каждом запуске создается свою набор локальных переменных, никак не связанный с другими наборами.
В Trigger Editor нет возможности создавать локальные переменные, а жаль.
Поясню на примере.
Допустим, что я захотел создать юнит, который стрелят огнем (огнеметчик). Допустим так же, что я выбрал такой способ: при атаке огнеметчика, создается спецэффект огня на земле. Затем определяется, стоият ли в радиусе поражения какие-нибудь юниты и им наносится повреждние.
Такой триггер не так уж сложно создать. (см триггер из примера, высланного ниже). И все бы хорошо, но: Что если мы захотим сделать два юнита - огнеметчика? Создавать для ниго еще один триггер, новые переменные: А если юнитов-огнеметчиков 10 и более? Если мы хотим, чтоюы этот юнит можно было производить в бараках?
Хотелось бы свести все к одному триггеру, но не получится. Ведь мы создаем спецэффект огонь (special effect) и чтобы его можно было убрать, нужно поместить спецэффект в переменнуюА если в игре несколько огнеметчиков и они атакуют одновременно - в одни и те же переменные будут записаны сначала одни спецэффекты, а затем другие. Но поскольку спецэффекту первого огнеметчика не успели убраться, они так и останутся. Получится эдакий "вечный огонь". Более того, если наш огнеметчик атакует достаточно быстро, тогда старые спецэффекты опять же не успеют убраться до того, как возникнут новые (огонь то должен погореть пару секунд).
Обычными триггерами эту задачу решить очень сложно (хотя и возможно). Однако с локальными переменными она решается в два счета.
Я не буду объяснять, как я научился делать такие вещи - это приходит с опытом, когда вы учитесь программировать.
Нам нужно, чтобы огонь любого огнеметчика в игре погорел пару секунд и потух. При этом мы уже добились этого для одного огнеметчика с помощью стандартных триггеров и глобальных переменных.
Переводим наш триггер в custom text. Прежде всего необходимо каждый параметр, имеющий отношение к конкретному случаю использования юнитом огнемета поместить в локальные переменные типа unit.
Например - event response attacking unit и event response attacked unit - именно такие параметры. Ведь если огнемет применит другой юнит, то и значения этих функций будут совершенно другими.
Затем - переменные со спецэффектами. В каждом случае должны создаваться свои спецэффекты с огнем - значит нужны локальные переменные типа special effect.
И последний нужный параметр - угол между атакующим и атакуемым юнитом - в локальную переменную типа real.
Создаются локальные переменные такой командой:
local <тип переменной> <имя переменной>
local integer i - создаст переменную i типа integer
local real r - создаст переменную r типа real
local effect s - создаст переменную s типа effect
local unit u - создаст переменную u типа unit
Итак, создали переменные, а затем помещаем в них нужные данные:
Set <переменная> = <значение> - помещает в переменную определенное значение. В качестве значения можно использовать функции типа EventResponseAttacking unit.
Заменяем глобальные переменные и функции на локальные.переменные.
Смотрим, что у нас получилось.
При запуске триггера все глобальные параметры записываются в локальные переменные. Действия триггера не изменилось, но (!) если у нас будет несколько юнитов-огнеметчиков, то они никак не будут мешать друг другу. Ведь при каждом запуске триггера будет создан (!) свой набор локальных переменных, которые будут существовать пока идет действие триггера.
Теперь можно делать сколько угодно огнеметчиков, назначать им любую скорость выстрелов - никаких проблем со спецэффектами не возникнет.

Просмотров: 24 652

» Лучшие комментарии


Пафос #1 - 7 лет назад 3
В конце 5-ой строки''иуказывает'' слитно написано с(=
almazqwe #2 - 6 лет назад 3
чтоюы - чтобы
Alister #3 - 5 лет назад 5
Успокойтесь)
EAX #4 - 5 лет назад 5
Большое спасибо. Статья помогает понять смысл текстовых переменных - очень помогло!
просто Юрок #5 - 5 лет назад 3
Тут написано, мол "не все команды из custom text доступны в Trigger Editor. Пример: команда добавления таймера жизни юнита.", однако оно есть. Как понимать?
ScorpioT1000 #6 - 5 лет назад 4
просто Юрок, Создан 11.01.03
BcaDHuK #7 - 4 года назад 3
Ребят,а как можно со взломанной карты,перевести текстовые триггеры в обычные?После взлома,Все триггеры поместились в 1 и получилась каша(как в джазе)можно ли их обратно перевести?карта есть 1,делать по новой долго,добавлять триггеры нельзя,карта крашится...
ЧТо сделать можно?
Buulichkaa #8 - 4 года назад (отредактировано ) 3
BcaDHuK, Переводить триггеры в гуи - очень и очень трудо и ресурсо - емкая задача, за это никто не платит, а если бы и платили, то недостаточно, т. к. гемор невероятный.
Если у тебя вышло вытащить читабельный файлик .j из защищенной мапы то это уже великое достижение, изучи джасс и ты поймешь что там собственно написано.
Вопрос, а не об опендоте ли, случайно, идет речь?
nvc123 #9 - 4 года назад 4
ну во первых если ты вскрыл карту депротетором то после сохранения карта станет нерабочей
надо вытаскивать mpq архиватором код из карты(код в ,j файлике будет отличатся от кода в триггере)
и да ,переводить кучу кода на гуи за бесплатно некто не станет да и за деньги немного желающих будет(кроме того карта может быть использовать функции которых нету в гуи )
Buulichkaa #10 - 4 года назад (отредактировано ) 3
nvc123, Вся трудоемкость в том и состоит чтобы впилить несуществующие в гуях функции.
Emisar #11 - 4 года назад 3
В строчках, где автор описывает принцип создания переменных, вроде допущенная ошибка (выделяю в кавычки):
local integer i - создаст переменную i типа integer
local real r - создаст переменную r типа real
local "effect" s - создаст переменную s типа "real"
local "effect" u - создаст переменную u типа "unit"
Или так и должно быть?
Buulichkaa #12 - 4 года назад 4
Emisar, что еще вы нашли в статье 10-и летней давности
ramungamepro #13 - 2 года назад 0
отличная статья. очень дозированно погружает в понимание тригеров
WakVellios #14 - 1 год назад 0
Ребят, как делать не глобальную, приватную переменную что бы она работала ни в одной функции а в одном триггере?
Ige #15 - 1 год назад (отредактировано ) 0
триггере или функции?
скорее всего тебе нужен vJass
WakVellios #16 - 1 год назад 0
local работает только внутри 1 из функций триггера, допустим в action. Мне нужно было что бы это "Локальная" переменная работала во всем триггере, и во всех его доп функциях, но не была видна в других триггера. Так сказать private
Ige #17 - 1 год назад 0
nvc123 #18 - 1 год назад 0
WakVellios, ставь jngp и юзай библиотеки вместо триггеров и модификатор private для переменных
иначе никак
вот мануал на русском