WarCraft 3: Типы и приведение типов

Создание простого stomp спелла

Типы и приведение типов

Возможно, вы уже немного знакомы с типами, но я пройдусь по ним еще раз, чтобы избежать непонимания.
В JASS существуют следующие типы:
integer – Целые числа, без дробной части.
real – Числа с дробной частью. Например: 0.2, 0.54654675. Число может быть записано без своей дробной части, если это не аргумент, возвращаемый функцией. Таким образом, в большинстве случаев вы можете использовать 1, 35465 , или –340 тоже как реальные числа.
boolean – Может принимать значения true или false.
string – Текст между двойными кавычками. Например, "XGM".
code – Указатель на функцию. Например, call TimerStart(myTimer, 0.05, true, function myFunction). Последний аргумент, function myFunction, как раз имеет тип code.
handle – Handle это объект. Все типы, исключая integer, real, boolean, string и code, производные от handle.
Например, тип timer дочерний по отношению к типу handle. Тип handle родительский по отношению к типу timer.
Тип widget – расширение типа handle. Он потомок типа handle, но в тоже время он родитель таких типов как - unit, destructable и item.
Всякий раз, когда функция берет аргумент, вы можете передать в нее либо заданный тип, либо любой тип-потомок.
Это означает, что если функция берет аргумент типа widget, вы можете передать в нее переменную типов: item, unit или destructable, потому что все эти типы – потомки типа widget.
В случае с переменной, вы можете хранить в ней как данные типа этой переменной, так и данные типов-потомков.
Но как поступить в случае, когда, например, у вас имеется переменная типа handle, и вы хотите использовать ее для передачи в функцию, которая берет параметр типа timer?
Хотя вы знаете, что в данном случае handle будет именно timer, игра не знает об этом и выдаст сообщение об ошибке.
Для того чтобы 'преобразовать' тип handle в тип timer, который примет игра, вы должны использовать подобную функцию:
function MyFunction takes handle h returns timer
    return h
endfunction
Однако если h не является таймером, функция, в которую вы передаете таймер, будет вести себя так, как будто, вы передали в нее значение 'null' – пустое значение.
Blizzard тоже использовали подобные функции, например:
function GetDyingDestructable takes nothing returns destructable
    return GetTriggerWidget()
endfunction
Теперь мы знаем, как ведет себя тип handle, и мы можем 'преобразовывать' его и его потомков. Вы также уже должны знать, как работают базовые функции приведения типов от Blizzard, такие как S2I (string в integer), S2R (string в real), I2S (integer в string), I2R (integer в real) R2I (real в integer), R2S (real to string) и R2SW (real в форматированную строку).
Ну, а если, например, мы хотим преобразовать тип handle в тип integer? Это очень часто используется в JASS, при работе с кэшем (gamecache) для создания более универсального кода или 'баз данных'.
На самом деле, все очень просто. Этот метод называется 'the return bug', потому что он использует ошибку игры и редактора.
Редактор и игра проверяют на совместимость типов только последнее возвращаемое функцией значение (Прим. перев. Имеется ввиду последний по счету оператор return) (функция может вернуть только одно значение, после чего завершится. Но возможно использование несколько операторов return в одной функции, что обычно применяется в функциях с использованием условного оператора if).
Таким образом, преобразование handle в integer, H2I, возможно. Все что нам нужно, это добавить еще один оператор return:
function H2I takes handle h returns integer
    return h
    return 0
endfunction
Эта функция (пожалуй, это самая известная JASS функция, которая была написана не Blizzard) берет значение типа handle, h, и возвращает значение типа integer. Как вы видите, первая строчка возвращает h. Вторая – 0.
Первый оператор return возвратит 'h' как идентификатор (id) типа integer, который использует эта конкретная handle переменная. Вторая строка кода никогда не выполнится, она служит лишь для того, чтобы при проверке этой функции на корректность не возникало ошибок.
И конечно, вы можете провести преобразование и в обратную сторону:
function I2H takes integer i returns handle
    return i
    return null
endfunction
Она работает точно также. Обратите внимание, что последний оператор return возвращает null вместо 0, как это было в предыдущей функции – все потому, что для типа handle, используется именно null, он эквивалентен 0, пустому значению. По правде, говоря, функции-експлойты, использующие return bug, вообще никогда не используют последнее значение, поэтому вы с таким же успехом можете поместить там GetTriggerUnit(), к примеру. Использование значения null, более разумно, так как, он не требует лишнего вызова функции.
А сейчас давайте создадим несколько return bug експлойтов и поместим их в секцию custom script (самый верхний элемент в списке триггеров, имеющий имя вашей карты) карты.
function H2I takes handle h returns integer
    return h
    return 0
endfunction

function I2G takes integer i returns group
    return i
    return null
endfunction
Оба они понадобятся, для создания спелла. Обратите внимание на функцию I2G (integer в group), вместо преобразования в handle, я напрямую преобразовываю ее в group.

Просмотров: 6 682

Комментарии пока отсутcтвуют