Эта статья будет посвящена, не столь распространенной, теме - Пользовательских подфункций (Sub-Functions), и возможно вы вообще о такой возможности редактора и не слышали. Да что уж там, я сам об этом не так давно узнал и был мягко говоря приятно удивлен этому.
Подфункции - это
продвинутый механизм в редакторе карт StarCraft 2, позволяющий создавать пользовательские конструкции управления потоком выполнения кода. По сути, это инструмент для определения собственных управляющих структур, аналогичных встроенным циклам и условным операторам (таких как If Then Else, Switch и прочих).

Как создать свою собственную подфункцию?

Описание примера
Мы создадим конструктор, который будет перебирать слова в строке подобно тому как работает Pick Each Integer, с возможностью на каждой итерации получить перебираемое слово
Подфункция это обычная функция, но с флагом Sub-Functionв разделе Options. После активации этого флага, вы заметите что строка Actions, в которой добавляются действия заменится на что-то непонятное. Там вы сможете добавлять свои подобные разделы, в которых уже из триггера (или другой функции) сможете назначить разные другие действия или условия.
  1. Создадим действие For Each Word In Strings
  1. Далее добавим параметр String (Просто нажмите по полю выделив его и нажмите Ctrl - W), А также добавим новую подфункцию, выбрав поле Sub-Function Types и нажав на Ctrl - W
  1. Теперь нужно слегка поработать с кодом Galaxy в Custom Script Code.
Вставьте этот код в поле - Custom Script Code
#AUTOVAR(s,string) = #PARAM(string);
#AUTOVAR(len) = StringLength(#PARAM(string));
#AUTOVAR(curIndex) = 1;

for (;;#AUTOVAR(len) -= 1) 
{
    #AUTOVAR(word,string) = StringWord(#PARAM(string),#AUTOVAR(curIndex));
    #AUTOVAR(curIndex) += 1;
    if (#AUTOVAR(word) == "") { break; }
    #SUBFUNCS(Actions)
}
Что делает каждая строка?
#AUTOVAR(s,string) = #PARAM(string);
Создаёт автоматическую переменную со стартовым значением заданным в нашем параметре строки
#PARAM(string)
Получение значения из, переданного в функцию, параметра по его идентификатору.
#AUTOVAR(len) = StringLength(#PARAM(string));
Создает авто-переменную с информацией о длине нашей строки
for (;;#AUTOVAR(len) -= 1) 
{
	. . .
}
Цикл, итерирующийся столько раз, сколько длина строки
#AUTOVAR(word,string) = StringWord(#PARAM(string),#AUTOVAR(curIndex));
Получаем текущее перебираемое слово
#SUBFUNCS(Actions)
Стартуем действия, которые будут добавлены для нашего цикла в самом триггере

Первый итог

Теперь мы уже сможем добавить наш собственный цикл в любой триггер! и даже сможем добавить в него некоторые действия, которые он выполнит на каждое слово строки

Так а как же получить то перебираемое слово?

Если мы посмотрим на существующих примерах таких как встроенных Picked Integer, Picked Unit, Picked Player. То увидим следующую подобную строку
Код из картинки
#INITAUTOVAR(ae,e)
#AUTOVAR(var) = #PARAM(s);
for ( ; #AUTOVAR(var) <= #AUTOVAR(ae); #AUTOVAR(var) += 1 ) {
    #SUBFUNCS(actions)
}
Стандартный цикл "Pick Each Integer", в котором объявляется счётчик
#AUTOVAR(var,ancestor:PickEachInteger)
Получение доступа к счётчику из цикла с помощью функции Picked Integer
Но похоже это нормально не работает. По крайней мере ни один моддер так и не сумел заставить это работать, а если кто-то и сумел, то никому не рассказал как это сделать.

Что же делать?

Есть и другой вариант. Можно использовать "Локальные Таблицы данных" Data Table.
Что такое локальные таблицы данных?
Таблица данных - это структура для хранения данных в формате ключ-значение и существует глобально на всё время игры. Локальная таблица данных в свою очередь может создаваться для каждого триггера отдельно и очищаться после окончания действия триггера,
Добавим эту функцию под присваивание текущего слова в переменную #AUTOVAR(word)
DataTableSetString(false,"ForEachWordInStrings",#AUTOVAR(word));
for (;;#AUTOVAR(len) -= 1) 
{
    #AUTOVAR(word,string) = StringWord(#PARAM(string),#AUTOVAR(curIndex));
    DataTableSetString(false,"ForEachWordInStrings",#AUTOVAR(word)); // Вот она
    #AUTOVAR(curIndex) += 1;
    if (#AUTOVAR(word) == "") { break; }
    #SUBFUNCS(Actions)
}
Эта функция сохранит в локальную таблицу данных текущее перебираемое слово по ключу ForEachWordInStrings (Не обязательно должен быть именно такой ключ, главное чтобы в будущей функции получения слова был такой же ключ что указан здесь).
ВАЖНО. Лучше подбирайте такой ключ, который будет наименее используемым, чтобы не возникало конфликтов на случай если в триггере вдруг будет использоваться данное название ключа для чего-то ещё.

Зачем нам сохранять слово по ключу?

Ключ для таблицы данных нужен для того, чтобы потом по нему можно было получить нужное нам ранее записанное значение, с помощью другой функции

Теперь создадим функцию получения слова

Добавим новую функцию кликнув ПКМ по пустому месту списка триггеров и выбрав в меню New - New Function. Назовём его Picked Word
В качестве Возвращаемого значения Return Type, укажем String.
И после добавим ровно одно действие Return. В его значение укажем функцию Value From Data Table (String), она то нам как раз и вернёт слово записанное в локальной таблице данных по ключу.
У него есть два поля:
  • Name - Строковый параметр, определяющий ключ таблицы данных. В него мы должны вписать тот же ключ что и ранее, например ForEachWordInStrings
  • Scope - Это область видимости таблицы данных Глобальная/локальная. Нам нужно выбрать локальная.

Финал

Осталось проверить.
В уже имеющимся триггере у нас есть наш добавленный цикл и создана локальная переменная.
Переменную можно убрать как и действие Modify Variable (Integer). А в текстовый параметр действия Text Message, можно выбрать функцию конвертации строки в текст Convert String To Text и в нём в качестве строки указать нашу функцию Picked Word

ГОТОВО!

Теперь вы можете быстро и легко перебирать строки по словам и доступно получать перебираемые слова!
Остались вопросы? Задайте их сообществу! Задать вопрос
`
ОЖИДАНИЕ РЕКЛАМЫ...