6. Больше теории Jass’a: управление действиями, условия и циклы
Управление действиями - о том, как сделать возможным ходить разными путями
в программе, {например, как устанавливать порядок действий. Можно создать
множество действий, а потом сделать их последовательными благодаря условиям и
циклам, а можно использовать это и в других целях...} Jass поддерживает это
со своим if и циклическими конструкциями. Так давайте бегло ознакомимся с
ними.
{Примечание: данная часть статьи была переведена лишь потому, что
здесь можно найти некоторые интересные примеры использования циклов при создании
AI-скриптов.}
if
Существует несколько вариантов того, как может
быть использован if. Но основная идея в том, что если что-то - истина, тогда мы
сделаем какие-то действия, в противном случае мы сделаем нечто другое (или может
быть вообще ничего не сделаем).
if condition then
doSomething
doSomethingMore
endif
if GetUnitCount( 'hpea' ) < 12 then
call setProduce( 1, 'hpea', 0)
endif
Эй, а если мы захотим сделать что-то другое, если будем иметь всех
крестьян?
if condition then
doSomething
else
doSomethingElse
endif
if GetUnitCount( 'hpea' ) < 12 then
call setProduce( 1, 'hpea', 0) Строить больше одного крестьянина (в нашей главной базе)
else
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "We need no more peasants" )
endif
Это хорошо, если есть только две возможности, но что если нам нужно выбрать
между тремя отдельными действиями?
if condition then
doSomething
elseif condition2
doSomethingElse
else
doSomeOtherThing
endif
if GetUnitCount( 'hpea' ) < 12 then
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "We need more peasants" )
call setProduce( 1, 'hpea', 0)
elseif GetUnitCount( 'hpea' ) < 20 then
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "We need no more peasants" )
else
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "We have to many peasants" )
endif
Путём добавления большего количества elseif’ов Вы можете сделать программу
выбирающую между несколькими различными действиями. Просто убедитесь, что Вы
поместили ваши условия в соответствующее место. Следующий скрипт
неудачен:
if GetUnitCount( 'hpea' ) < 20 then
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "We need no more peasants" )
elseif GetUnitCount( 'hpea' ) < 12 then
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "We need more peasants" )
call setProduce( 1, 'hpea', 0)
else
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "We have to many peasants" )
endif
Если у нас есть один крестьянин, код скажет, что нам больше не нужны
крестьяне. Это потому что условия проверяются сверху вниз.
Loop
Циклы - это повторяющаяся много раз вещь. Если вы использовали циклы в
других языках, Вы можете ощутить неудобство с циклами Jass'а. Всё же есть способ
реализации циклов while и for в Jass.
Давайте сначала посмотрим на цикл, который будет запускаться
вечно.
loop
doSomethingForever
endloop
loop
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "Let's spam the user forever")
call Sleep( 1.0 )
Endloop
Циклы, которые запускаются навсегда, используются, но они не очень гибкие.
Так давайте введем строки, чтобы выйти из цикла.
loop
doSomething
exitwhen condition
doSomethingMore
endloop
local integer i = 1
loop
call Sleep( 1.0 )
exitwhen i > 10
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "Let's spam the user 10 times")
set i = i + 1
endloop
for
Мы не имеем циклы for в Jass, но мы можем сделать цикл,
который будет вести себя подобно циклу for.
for ( initStatement; condition; endOfIterationStatement ) {
stuff;
}
может быть сделан на Jass как
initStatement
loop
exitwhen not (condition)
stuff
endOfIterationStatement
endloop
А теперь давайте посмотрим на более конкретный пример.
for (int i = 0; i < 10; i++) {
printf("We need to say it 10 times");
}
На Jass’e станет
local integer i = 0
loop
exitwhen not ( i < 10 )
call DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, "We need to say it 10 times")
set i = i + 1
endloop
while
Может быть, вам следует самому попытаться сделать это. Если
вы не имеете обыкновение в использовать цикл while, просто проигнорируйте иго,
Jass, во всяком случае, ничего не знает о нём.
7. Функции, которые мы использовали до этого
Эта часть о тех функциях, которые мы использовали до этого, о том, как они
работают, что они делают, и почему мы хотим, чтобы они делали только это.
Для каждых функций, которые мы использовали, я укажу, как она объявлена в
sourcefiles, объясню аргументы, что она делает и что возвращает.
native Sleep takes real seconds returns nothing
call Sleep(
3.5 ) заставляет наш скрипт заснуть на 3,5
секунд
Если мы никогда не спим, движок получается анормальным и
выводит скрипт из строя после некоторого времени.
constant native GetLocalPlayer takes nothing returns
player
local Player p = GetLocalPlayer() // {создаёт локального
игрока p, которого мы используем, чтобы выдать текст именно ему (смотрите ниже)}
native DisplayTextToPlayer takes player toPlayer, real x, real y, string
message returns nothing
call DisplayTextToPlayer( GetLocalPlayer(),
0.0, 0.0, "Hello local player!" )
Нам нужно сообщить функции, что писать
и кому. Изменяя нули на нечто другое, мы можем также контролировать, где текст
появится на экране. Почувствуйте себя свободным для эксперимента, нули обычно
работают всё же лучше. Это сообщение уйдет после некоторого времени. Время
зависит от длины сообщения.
native DisplayTimedTextToPlayer takes player toPlayer, real x, real y,
real duration, string message returns nothing
call
DisplayTextToPlayer( GetLocalPlayer(), 0.0, 0.0, 60, "Hello for 60 secs!"
)
Также, как и выше, но теперь мы контролируем, как долго будет
показываться текст.
native ClearHarvestAI takes nothing returns nothing
call
ClearHarvestAI() // приказывает искусственному интеллекту, отвечающему за
сбор, остановить сбор.
Это используется с двумя функциями ниже, чтобы
контролировать, как много рабочих собирают золото и дерево.
native HarvestGold takes integer town, integer peons returns
nothing
call HarvestGold( 0, 5 ) // Сообщает 5 рабочим начать сбор
золота в городе 0, который является главным городом.
Если этот вызов сделан
дважды, без ClearHarvestAI, 10 рабочих вместо 5 будут собирать золото.
native HarvestWood takes integer town, integer peons returns
nothing
call HarvestWood( 0, 10 )
Работает точно также, как и
выше, только вместо золота дерево.
native SetProduce takes integer qty, integer id, integer town returns
boolean
local boolean success = SetProduce( 1, 'hpea', 0 ) Попытается создать одного крестьянина в городе 0 (главный
город).
call SetProduce( 1, 'hpea', 0 )
Я не полностью верю обратной
величине, но это, может быть, из-за того, что иногда я немного скептичен.
native GetUnitCount takes integer unitid returns integer
set
numberOfPeasants = GetUnitCount( 'hpea' ) // Считает количество, крестьян,
которое имеет AI-игрок.
Это величина включает и тех крестьян, кто в то время
создаётся.
native GetUnitCountDone takes integer unitid returns
integer
set numberOfPeasants = GetUnitCount( 'hpea' ) // Считает
количество, крестьян, которое имеет AI-игрок.
Это величина не включает тех
крестьян, кто в то время создаётся.
Вы, вероятно, скажете, что всё это очень хорошо, но как я могу построить
или сосчитать другие вещи? Мы скоро рассмотрим, какие секретные величины
использованы, чтобы создавать другие вещи.