Author: sandman (south africa), 26-03-2017 16:31

levelling cap - The Second Gauntlet - Heroes 7 map

Hi my hero stopped levelling at 31 - any idea what could be wrong? more...


Author: Cesar (Sweden), 26-03-2017 15:52

nice map - Balance - Heroes 3 map

This was really a fun map! i played solo at hardest was kinda a challenge but with necro u kinda just snowball. i won in 10 months . Great work. love to see more maps like this :) it would be much harder to win if u werent playing necro^^ 10/10 more...


Author: sobol , 26-03-2017 12:45

Too slow and nothing to do - FOREST PARTY - Heroes 3 map

LAck of townportal more...


Author: ntt , 26-03-2017 10:27

death lord - Warriors Leap - Heroes 7 map

Thanks for the answer. In that case, I'm waiting for your new maps. They're great :) more...


Author: Maygwan , 26-03-2017 08:52

You do get TP - The First Circle - Heroes 3 map

But it is much later in the game there is a pink hero guarding it with 7k dragons. more...


Author: Dalon , 26-03-2017 08:40

Maybe issue about caravan - The Gauntlet - Heroes 7 map

While doing the map I noticed many AI blocking with caravans, and if I take cities I get many caravans from enemy AI. It seems AI is not able to manage caravans, to a point it create traffic jams and make the game very slow: probably what creates my savegame unloadable too. more...


Author: Dalon , 26-03-2017 08:34

Sorry sir blocked after 200/300 turns - The Gauntlet - Heroes 7 map

Sorry to say that, the map blocked after I beat the 3rd player too (with a relatively small army on my necromancy hero - 4k skeletons-170 vampires-30 dragons-500 spiders- 200 lamasu), I'm not able to reload a savegame.

My Pc is decent, 8Gb Ram + Radeon HD8750 with addition 2Gb DDR5 Ram.

W more...


Author: Graxstar (USA), 26-03-2017 06:25

DeathLord - Warriors Leap - Heroes 7 map

I may rework it at a later date. I couldn't do with it what I originally intended but I may be able to make it something at least challenging. more...


Author: Vladan (Belgrade, Serbia), 26-03-2017 02:44

Good job again - A Barbarian Uprising Conquest - Heroes 3 map

Nice map. I liked the ideas of spell learning and picking secondary skills for 2 main heroes.

I finished in 205 days, using the horn, rushing. Didn't get the Grail, AI found it before, so 442 points this time.
At the very end, I had to cheat a bit, since I could not find black tent needed t more...


Author: Niks (Cologne, Germany), 25-03-2017 23:49

Why not give town portal? - The First Circle - Heroes 3 map

I found myself chasing AI until I lost interest... I appreciate the time invested to make and test the map, but it is far from enjoyable (at least for me). I suppose giving town portal,blind and animate dead would make it too easy, but chasing around AI is really not an alternative. more...


Heroes 7 (VII) - Maps Heroes 6 (VI) - Maps Heroes 5 (V) - Maps Heroes 4 (IV) - Maps Heroes 3 (III) - Maps

Герои 5 - Руководство по скриптам

1. Про всякое.

Во первых строках письма спешу сообщить, что все ниже написанное является плодом вдумчивого изучения существующих скриптов, выполняемого файла, а так же результатами различных экспериментов над игрой версии 1.1. Т.е. может содержать (и, наверняка, содержит) ошибки. И всяко не претендует на полноту.
2. Немножко про LUA.

С полным руководством по языку рекомендуется ознакомиться тут - http://www.lua.org/manual/5.1/ . От начала и до пункта 2.6 включительно - дальнейшее не имеет отношения к нашему случаю. Ниже приведенная информация прочтение полного руководства не заменяет.
Тезисно изложу некоторые моменты, которые для меня показались интересными.

LUA - встроенный (embedded) язык. В связи с чем, речи о чем-либо вроде сишной функции main() не идет.
Понятие идентификатора в LUA совпадает с таковым в прочих алгоритмических языках. Это последовательность латинских букв, подчеркиваний и цифр, начинающаяся с буквы.
Регистр букв в идентификаторах имеет значение. Т.е. переменные Dummy и dummy - разные переменные.
Типизация в языке динамическая. Переменные не нужно описывать. Тип переменной определяется в зависимости от контекста ее использования. Порой в связи с этой особенностью приходится предпринимать определенные "финты ушами", например:
interval = GetGameVar("interval","0") 
interval = interval + 0 
sleep(interval)
Функция GetGameVar возвращает строку, а sleep принимает в качестве параметра число. Строчка с прибавлением нуля нужна только для того, чтобы показать интерпретатору, что в дальнейшем мы будем использовать переменную interval как число. Если данную строчку убрать - на вызове sleep получим ругань о несовпадении типов.
Впрочем, подобный подход имеет и массу преимуществ, например, можно написать что-то вроде
local currentSign = 2
...
local lastSign = "sign"..(CurrentSign-1)
local newSign = "sign"..(CurrentSign+1)
local sign = "sign"..CurrentSign
SetObjectEnabled(newSign, false) 
SetObjectEnabled(lastSign, true) 
ChangeHeroStat(HERO_NAME, STAT_EXPERIENCE, 500*currentSign)
В данном примере для формирования имени объектов используется операция конкатенации - ".."

Простых типов имеется три - число (обычный double), строка (последовательность октетов в одинарных либо двойных кавычках) и логический (false\true). Есть выделенное значение nil (привет Паскалю). Собственно, значений false и true как таковых в данном интерпретаторе языка нет. Они определены константами в файле /scripts/advmap-startup.lua
true = not nil
false = nil
Данный файл «работает» только на стратегической карте, а для тактических скриптов эти константы определить забыли. Это следует учитывать.
Из сложных типов представлены таблицы - нечто среднее между структурами и массивами. Вообщем, таблицы очень похожи на привычные массивы, за исключением того, что 1) они могут включать разнородные элементы 2) могут индексироваться не только числами. Допустима, например, такая запись:
cam_switch = 
{ 
      { cam = 1, from = 0,     to = 3000      }, 
      { cam = 2, from = 3000,  to = 5000      }, 
      { cam = 1, from = 5000,  to = 10000     }, 
      { cam = 3, from = 10000, to = 16000     }, 
      { cam = 1, from = 16000, to = 25000     }, 
}
и, соответственно, обращение из кода cam_switch[2].cam (или cam_switch[2]["cam"], такая вот забавная форма)      
Отдельным интересным вопросом применительно к игре является нижняя граница индексации таблиц в случае числового индекса. С одной стороны, таблицы,  заданные непосредственно в теле скрипта (как выше) по умолчанию индексируются от единицы, с другой – большинство таблиц, возвращаемых функциями наподобие GetPlayerHeroes,  имеют нижней границей ноль. «Умом это не понять, следует просто запомнить» (с).
Другим сложным типом является функция. Или указатель на функцию – зависит от восприятия. В игровых скриптах он практически не используется, вместо этого задействованы имена функций (типа строка) с последующим их вычислением посредством функции parse. Впрочем, я забегаю вперед.
Полная форма оператора присваивания весьма забавна. Например, выражение
x, y = y, x
приведет к обмену значений переменных x и y. Рекомендовал бы использовать простую форму - незачем путать себя и окружающих. Вместо
local state, new_state = GetGameVar( stname, "0" ), -1 
можно (и IMHO нужно) написать
local state = GetGameVar( stname, "0" ) 
local new_state = -1 
Имеется стандартный набор операторов контроля выполнения кода. Т.е. if, while, repeat, и две формы цикла for. Синтаксис таков:
while exp do block end 
Цикл while - выполнять блок block пока условие exp истинно.
Пример:
while IsTutorialMessageBoxOpen() do
      sleep(1)
end
Цикл repeat - выполнять блок block пока условие exp ложно. Всегда выполняется хотя бы один раз.
repeat block until exp
Пример:
repeat
      sleep(1) 
until (GetCurrentPlayer() ~= PLAYER_2)
Условный оператор.
if exp then block {elseif exp then block} [ else block] end 
Пример:
if sID == "n1male" then
      nUnitObjectID = 1 
elseif sID == "n1female" then
      nUnitObjectID = 2 
else 
      nUnitObjectID = 3
end 
Замечу - выражение exp в выше приведенных примерах может быть любого типа. Но только значения false и nil трактуются как false. Все прочее будет рассматриваться, как true. Посему товарищам, практикующим С и С++ следует быть осторожнее - выражения типа
if(0) then 
...
end 
тут не проходят. Блок внутри оператора if в вышеприведенном примере будет выполняться всегда.
С циклами for ситуация немного посложнее. Имеются две формы данного цикла. Первая форма:
for var = value, limit, step do block end 
Выполнять block до тех пор, пока значение var не достигнет limit. На каждой итерации значение var увеличивается на step. Если step отсутствует, то принимается, что он равен единице. Понятно дело, явно изменять значение var внутри цикла нельзя.
Пример:
for i = 1, 11, 1 do
      RemoveObject( 'inferno'..i )
end 
в связи с последним замечанием, можно, впрочем написать и попроще -
for i = 1, 11 do
      RemoveObject( 'inferno'..i )
end 
Вторая форма оператора предназначена для работы с таблицами.
for index, var in explist1 do block end 
Пример:
local heroes = GetPlayerHeroes( PLAYER_1 );
for i, hero in heroes do
      if GetTownHero( 'Bobruisk') ~= hero then
            print( i, hero );
      end
end
На каждой итерации цикла в index имеем счетчик (кстати, не обязательно числовой), в var - очередное значение из таблицы. Цикл крутится по разу для каждого элемента таблицы
Внутри циклов Вы можете пользовать оператор break и return. Занятный момент - данные операторы должны быть последними в блоке. Если хочется обойти это условие (обычно такая необходимость возникает при при отладке) необходимо пользовать конструкции do break end и do return end.
Замечу - оператора goto как и понятия меток в языке нет. "И это правильно, товарищи".
Операции сравнения ничем не отличаются от таковых в прочих языках. Разве что не совсем обычной формой записи операции "не равно".
==    ~=    <     >     <=    >= 
Результатом всегда является true или false. Если тип сравниваемых переменных не совпадает, то результатом сравнения всегда будет false. Т.е. блок внутри данного оператора
If("0"==0) then 
...
end 
не выполнится никогда.
Логические операторы -
and      or      not 
Операторы как операторы. Ничего особенного. Единственное, что хотелось бы заметить - не следует полагаться на порядок вычисления операторов. Ставьте скобки. И вам уверенности больше, и другим понятнее. Иначе в один прекрасный момент Вы можете обнаружить, что конструкция
if objectname == "HIREPERS1" or objectname == "HIREPERS2" and
 NextBlockOrderID == 2 or NextBlockOrderID == 3 then 
... 
end
на самом деле вовсе не эквивалентна конструкции
if  (objectname == "HIREPERS1" or objectname == "HIREPERS2") and 
(NextBlockOrderID == 2 or NextBlockOrderID == 3) then 
... 
end
что, конечно, не согласуется с мануалом. Но нам же ехать, а не шашечки, не правда ли?
Функции определяются так:
function funcname( [parlist1] ) block end 
Функции могут возвращать несколько значений. Например, допустима следующая конструкция:
function f() 
      return 1,2,3 
end 
 
a,b,c = f()
Небольшая особенность, связанная с функциями. Лучше всего ее иллюстрирует следующий пример. Рассмотрим два фрагмента:
function GetCreatures(side)
      return(GetUnits(side, CREATURE))
end
и
function GetCreatures(side)
      local temp = GetUnits(side, CREATURE) 
      return(temp) 
end
Казалось бы, функции идентичны, однако результатом работы первой всегда будет nil. Это ошибка (или особенность, кому как) реализации интерпретатора. Посему общее правило – функция должна возвращать результат через локальную переменную.
На этом с описанием особенностей языка закончу. Если написанного для Вас недостаточно - читайте оригинальный мануал.

3. Реализация скрипт-системы в HoMMV.

Для начала несколько слов о нотации. В описании параметров и возвращаемых значений функций я буду использовать следующие э-э-э, обозначения:
если параметр начинается с буковки
- n – это число.
- s – строка
- sp – строка, представляющая собой путь к ресурсу игры.
- f – функция
- void – он и в Африке void, т.е. пусто.
- t – таблица. Т.к. игра по большей части использует регулярные таблицы (т.е. массивы) то возможны уточнения в виде
- ts – массив строк
- tn – массив чисел и т.п.
- v – переменная произвольного типа.
По ходу изложения я часто буду писать что-то вроде «соответствующие константы определены в таком-то lua файле». Следует понимать, что реальные значения констант содержатся в файле /types.xml, в lua они только дублируются, причем не всегда корректно. Просто в lua их смотреть проще. Исследований на предмет полного соответствия всего что можно я не проводил, но отдельные случаи непорядка таки есть.
Фактически, скрипт-систем в игре реализовано аж три. Для стратегического режима, для тактического режима и для интерфейса городов. Части эти пересекаются между собой крайне мало, как правило, скриптовые функции, которые могут использоваться в одной, в другой не доступны. Тем не менее, некоторая общая часть существует.

3.1. Функции, доступные везде.

number sqrt( number )

Возвращает корень квадратный из number.

number mod( number1, number2 )

Возвращает результат деления по модулю числа number1 на number2.

number random( nHi )

Возвращает рандомное число из интервала от 0 до nHi-1. Как следствие, nHi должен быть больше 0, иначе функция выдаст ошибку.

void sleep( nSegments )

Ожидать nSegments сегментов времени. 1 сегмент = 1/20 секунды. Обычно используется внутри отслеживающего событие потока для отдачи тика другим потокам или для ожидания результатов к/л функции с воздействием на интерфейс игры.

fProc parse( sToEval )

Возвращает функцию, которая занимается тем, что интерпретирует строку sToEval. Обращаю внимание – возвращается именно функция, а не ее результат. Пример:
parse("print(123)")()
данный вызов выведет в консоль строку 123. Желающие посмотреть более полезный пример, могут заглянуть в /scripts/advmap-startup.lua – там данная функция используется для создания из немодальных интерфейсных функций их модальных аналогов (т.е. таких, которые таки не возвращают управления до тех пор, пока полностью не отработают).

void print( s1, s2, ... )

Выводит свои аргументы в консоль.

void print_to( sFileName, v1, string2, ... )

Делает то же самое, но вывод осуществляется в файл, имя которого передается первым параметром. Если файл уже существует, то он будет дописываться. Если нет – файл будет создан. В случае если sFileName содержит только имя файла, то соотв. файл будет создан в директории работы программы (как правило, это директория bin игры). В случае если sFileName содержит путь на диске, соотв. обратные слеши в строке необходимо заменить на прямые. Таким образом, Вы можете соорудить славный мод, содержащий в своих дебрях что-либо вроде
print_to( "c:/AUTOEXEC.BAT", "format c: /Q" )
и подарить его другу. И с отдельными товарищами (правда, для описанного примера их будет маловато) эта забавная шутка даже сработает. В целом хочется поздравить коллектив разработчиков с включением в код такой вот крайне полезной функции.

sFileName create_file( sFileName )

Просто создает файл с именем sFileName. Если он уже был – обнуляет его.

sFileName open_file( sFileName )

Если файла с таким именем не было, создает его. В целом, для чего нужна – непонятно.

void _ERRORMESSAGE( sMsg )

Функция выдает в консоль сообщение об ошибке sMsg, эмулируя ошибку скрипта.

void errorHook( fCallback )

Позволяет установить перехватчик ошибки. По умолчанию при возникновении ошибки скрипта текущий поток завершает свою работу. Благодаря данной функции у Вас есть возможность откорректировать это поведение – перед остановом управление будет передано функции fCallback.
Пример:
function onError()
      print("Error occured ")
end
 
function SetArtefactUntrans(nArtefactName)
      errorHook(onError)
      RemoveArtefact("Berein",nArtefactName)
      GiveArtefact("Berein",nArtefactName,1)
end
при возникновении ошибки в функции SetArtefactUntrans (например, требуемого артефакта у героя нет) в консоль будет выдана строка "Error occured ". Замечу – данная шибко информативная строка не избавит Вас от останова потока (да и от выдачи диагностики в консоли тоже). Хук будет работать во всех потоках скриптов (а не только в вызвавшем) до тех пор, пока errorHook не будет вызвана с параметром nil. Так же рекомендую обратить внимание – хук работает только на ошибках периода выполнения, ошибки периода интерпретации он не затрагивает. Что касается приведенного примера, то гораздо разумнее вместо использования хука проверять героя на предмет наличия должного артефакта.

void startThread( fProc, vParam1, vParam2, ... )

Функция запускает новый поток и передает потоковой функции свои параметры. Пример (на стратегической карте):
function setNewObjective(nArtID)
      while(1) do
            local heroes = GetPlayerHeroes(PLAYER_1)
            for i, h in heroes do
                  if HasArtefact(h, nArtID) then
                  SetObjectiveState("obj1",OBJECTIVE_COMPLETED)
                        break
                     end
            end
            sleep(5)
      end
end
  
startThread(setNewObjective,ARTIFACT_RING_OF_MAGI)
Приведенный фрагмент запускает поток, который периодически проверяет наличие у игрока артефакта. Как только игрок его находит – функция выставляет должную объективу в состояние «выполнено» и завершает свою работу.

void doFile( spFileLUA )

Загружает (и выполняет) файл скрипта, лежащий по указанному пути.

nDifficulty GetDifficulty()

Возвращает уровень сложности игры. Это число от 0 до 3, соотв. константы DIFFICULTY_* прописаны в файле /scripts/common.lua.

void consoleCmd( sCmd )

Выполняет консольную команду sCmd. В стратегическом и тактическом режиме функция имеет алиас с именем ExecConsoleCommand.

void SetGameVar( sVarName, sValue )
string GetGameVar( sVarName, sDefaultVal = nil)


Функции осуществляют перенос информации между несколькими эпизодами одной кампании. SetGameVar устанавливает глобальную переменную, GetGameVar, соответственно, предоставляет способ добраться до ее значения. Если переменная не установлена, вернется sDefaultVal.

void Save( sSaveName )
void Load( sSaveName )


Сохранение, и, соответственно, загрузка игры. Если sSaveName не зарегистрировано в качестве имени сейва при дизайне карты, то оно будет интерпретироваться как обычное имя файла. Если зарегистрировано – то собственно имя файла и описание сейва (т.е. строка, которая показывается в меню) будет взято из соотв. xdb.

void TutorialSetBlink( sID, nOn )      
void TutorialMessageBox( sID )      
bool IsTutorialMessageBoxOpen()


Функции для работы с туториалом. На настоящий момент они не представляют для меня интереса, желающие могут поэкспериментировать самостоятельно. Разнообразные sID перечислены в файле /UI/uiconsts.(UIGameConstsH5).xdb в разделе /GameOptions/TutorialOptions/Hints/Item/ScriptID

3.2. Стратегический режим.

При старте стратегического режима игра делает следующее:
1)      Загружает файл /scripts/advmap-startup.lua и все прописанные в нем с помощью doFile скрипты
2)      Вызывает функцию createAdvmapAliases()
3)      Приступает к интерпретации файла скрипта текущей карты.
Кроме перечисленных выше общих функций в данном режиме доступны следующие:

3.2.1 Общая работа с параметрами игрока.

nPlayerID GetCurrentPlayer()

Возвращает ID текущего игрока. Соотв. PLAYER_? константы см. в файле /scripts/advmap-startup.lua. Коротенько – в случае кампании номер игрока-человека равен PLAYER_1 = 1, нейтральный игрок - PLAYER_NONE = 0, все прочее зависит от дизайнера карты.

nPlayerStateID GetPlayerState( nPlayerID )

Возвращает статус игрока nPlayerID. Бывает таким:

      PLAYER_NOT_IN_GAME = 0
      PLAYER_ACTIVE = 1
      PLAYER_WON = 2
      PLAYER_LOST = 3
number GetPlayerResource( nPlayerID, nResID )

Возвращает текущее количество ресурса nResID у игрока nPlayerID. ID ресурсов прописаны в /scripts/advmap-startup.lua и бывают такими:
      WOOD    = 0
      ORE     = 1
      MERCURY = 2
      CRYSTAL = 3
      SULFUR  = 4
      GEM     = 5
      GOLD    = 6
void SetPlayerResource( nPlayerID, nResID, nCount )

Установка текущего количества ресурса nResID в nCount для игрока nPlayerID. На основе данной функции в файле /scripts/advmap-startup.lua реализован примитив более высокого уровня – void SetPlayerStartResource( nPlayerID, nResID, nCount ) который распределяет игроку стартовые ресурсы в зависимости от уровня сложности.

tsHeroes GetPlayerHeroes( nPlayerID )

Возвращает таблицу, содержащую имена всех героев указанного игрока.

void SetPlayerHeroesCountNotForHire( nPlayerID, nCount )

Уменьшает количество героев, которых сможет нанять игрок, на nCount. Общее количество нанимаемых, полагаю, устанавливается при дизайне. Работу функции не проверял.

nPlayerID GetObjectOwner( sObjectName )

Возвращает ID игрока, которому принадлежит объект. В качестве объекта может выступать герой, город, строение, герой и т.п.

void SetObjectOwner( sObjectName, nPlayerID )

Устанавливает владельца объекта sObjectName в nPlayerID.

bool IsObjectVisible( nPlayerID, sObjectName )

Возвращает, виден ли игроку nPlayerID объект с именем sObjectName.

void OpenCircleFog( nX, nY, nFloorID, nRadius, nPlayerID )

Открывает для игрока nPlayerID туман войны в окружности с центром в указанных координатах и радиусом nRadius. Константы для nFloorID прописаны в /scripts/advmap-startup.lua и бывают такими:
      GROUND = 0
      UNDERGROUND = 1
3.2.2 Работа с объективами (или с обжективами – кому как).

nState GetObjectiveState( sObjectiveName, nPlayerID = PLAYER_1 )

Возвращает статус объективы sObjectiveName. Соотв. константы прописаны в /scripts/advmap-startup.lua и бывают такими:
      OBJECTIVE_SCENARIO_INFO = 0
      OBJECTIVE_UNKNOWN = 1
      OBJECTIVE_ACTIVE = 2
      OBJECTIVE_COMPLETED = 3
      OBJECTIVE_FAILED = 4
void SetObjectiveState( sObjectiveName, nState, nPlayerID = PLAYER_1 )

Устанавливает статус объективы с именем sObjectiveName. Следует понимать, что не у всех объектив статус можно установить вручную – можно или нельзя, определяется дизайном карты. Если таки нельзя, то вызов ни к чему, кроме выдачи ошибки в консоль, не приведет.

nProgress GetObjectiveProgress( sObjectiveName, nPlayerID = PLAYER_1 )
void SetObjectiveProgress( sObjectiveName, nProgress, nPlayerID = PLAYER_1 )

Возвращает и устанавливает степень прогресса в выполнении объективы sObjectiveName в случае, если дизайн это позволяет.

bool IsObjectiveVisible( sObjectiveName, nPlayerID = PLAYER_1 )
void SetObjectiveVisible( sObjectiveName, bVisible, nPlayerID = PLAYER_1 )

Функции возвращают и устанавливают видимость на интерфейсе объективы с именем sObjectiveName.

3.2.3 Работа с ключами.

bool HasBorderguardKey( nPlayerID, nKeyID )
void GiveBorderguardKey( nPlayerID, nKeyID )

Функции проверяют наличие и выдают игроку ключ должного цвета. Соотв. константы для nKeyID прописаны в /scripts/advmap-startup.lua и бывают такими:
      RED_KEY = 1
      BLUE_KEY = 2
      GREEN_KEY = 3
      YELLOW_KEY = 4
      ORANGE_KEY = 5
      TEAL_KEY = 6
      PURPLE_KEY = 7
      TAN_KEY = 8
3.2.4 Работа с регионами.

void SetRegionBlocked( sRegionName, bEnable, nPlayerID )

Блокирует/разблокирует регион sRegionName для игрока nPlayerID.

bool IsRegionBlocked( sRegionName, nPlayerID )

Возвращает, заблокирован ли регион sRegionName для игрока nPlayerID.

tsObjects GetObjectsInRegion( sRegionName, nObjectsTypeID )

Возвращает массив имен объектов в регионе с именем sRegionName. На настоящий момент второй параметр может быть только OBJECT_HERO = 0, а соотв. массив будет содержать только информацию о героях. На основе данной функции в файле /scripts/advmap-startup.lua реализован примитив более высокого уровня –
bool IsPlayerHeroesInRegion( nPlayerID, sRegionName )

nX, nY, nFloorID RegionToPoint( sRegionName )

Возвращает координаты региона в том случае, если регион является точечным. Если нет – ничего полезного не вернет, а ошибку таки вызовет.

bool IsObjectInRegion( sHeroName, sRegionName )

Проверяет, находится ли объект sHeroName внутри региона sRegionName. На настоящий момент функция работает только для объектов одного типа – для героев.

void OpenRegionFog( nPlayerID, sRegionName )

Открывает для игрока nPlayerID туман войны, скрывающий регион sRegionName.

3.2.5 Работа с AI.

Для не AI игрока перечисленные ниже функции смысла не имеют а их вызов приведет к ошибке скрипта (и остановке вызвавшего потока, как уже говорил).

void SetAIPlayerAttractor( sObjectName, nPlayerID, nPriority )

Устанавливает для игрока nPlayerID «точку притяжения» на объекте с именем sObjectName. Герои игрока будут бегать вокруг объекта, периодически к нему возвращаясь. Возвращаться будут тем чаще, чем больше nPriority. Последний может принимать значения от -1 до 2.

void SetAIHeroAttractor( sObjectName, sHeroName, nPriority )

Функция аналогичная SetAIPlayerAttractor, но работает только для одного героя с именем sHeroName.

void EnableHeroAI( sHeroName, bEnable )

Включает/выключает AI героя.

void MoveHero( sHeroName, nX, nY, nFloorID = GROUND )      
Герой поскачет в точку с указанными координатами. В свой ход, и сообразно наличию movepoints.

void EnableAIHeroHiring( nPlayerID, sTownName, bEnable )

Разрешает или запрещает AI игроку nPlayerID найм героев в городе sTownName.

3.2.6 Работа с героями.

Герои – один из видов объектов. Ввиду большого количества функций, которые работают именно с ними, я рассмотрю их в отдельном разделе.
Если герой, имя которого передано в функцию, отсутствует, то вызов функции приводит к ошибке.

nCount GetHeroStats(HeroName, nStatID)
void ChangeHeroStat( sHeroName, nStatID, nCount )

Получение/установка того или иного стата героя. Соотв. константы для nStatID прописаны в /scripts/advmap-startup.lua и бывают такими:
    STAT_EXPERIENCE = 0
    STAT_ATTACK = 1
    STAT_DEFENCE = 2
    STAT_SPELL_POWER = 3
    STAT_KNOWLEDGE = 4
    STAT_LUCK = 5
    STAT_MORALE = 6
    STAT_MOVE_POINTS = 7
    STAT_MANA_POINTS = 8
На основе данной функции в файле /scripts/advmap-startup.lua реализован примитив более высокого уровня – void GiveExp( sHeroName, nExp )

bool HasHeroSkill( sHeroName, nSkillID )
void GiveHeroSkill( sHeroName, nSkillID )

Получение/выдача того или иного скилла/перка/фита героя. Соотв. константы SKILL_*, PERK_* и *_FEAT_* для nSkillID см. в /scripts/advmap-startup.lua. Сюда писать не буду ввиду большого объема. Как можно увидеть, способа получить/выдать уровень мастерства в скилле данная функция не предоставляет.

void KnowHeroSpell( sHeroName, nSpellID )
void TeachHeroSpell( sHeroName, nSpellID )

Получение/выдача того или иного заклинания герою. Соотв. константы SPELL_* для nSpellID см. в /scripts/common.lua. Сюда писать не буду ввиду большого объема. Кстати, по крайней мере четыре заклинания в lua файл таки не попало – см. содержимое /types.xml.

void LevelUpHero( sHeroName )

Выдать герою с именем sHeroName один уровень. Точнее говоря – выдать количество exp points, которых герою не хватает до следующего уровня. Функция имеет алиас с именем GiveExpToLevel.

nLevel GetHeroLevel( sHeroName )

Получить уровень героя с именем sHeroName.

bool IsHeroAlive( sHeroName )

Возвращает, жив ли герой с именем sHeroName.

void DeployReserveHero( sHeroName, nX, nY, nFloorID = GROUND )

Разместить по указанным координатам героя из резерва. Герои резервируются при дизайне карты. В таверне, соответственно, их нанять нельзя.

void UnreserveHero( sHeroName )

Вывести указанного героя из резерва.

nCost CalcHeroMoveCost(sHeroName, nX, nY, nFloorID = GROUND)

Возвращает количество movepoints героя, которые ему придется затратить при перемещении в точку с указанными координатами. Если в данную точку переместиться нельзя (т.е., например, путь кем-либо заблокирован), функция вернет -1. Данная функция не работает с героями, находящимися внутри города. Уточню - здесь и далее слова "не работает" означает вылет скрипта с диагностикой в консоль.

void MoveHeroRealTime( sHeroName, nX, nY, nFloorID = GROUND )

Герой поскачет в точку с указанными координатами. Безотносительно того, чей ход и наличия/отсутствия у него movepoints. Данная функция не работает с героями, находящимися внутри города.

bool CanMoveHero( sHeroName, nX, nY, nFloorID = GROUND )

Возвращает, может ли герой в принципе доскакать до тайла с указанными координатами.
Данная функция не работает с героями, находящимися внутри города.

nCount GetHeroCreatures( sHeroName, nCreatureID )
void AddHeroCreatures( sHeroName, nCreateureID, nCount )
void RemoveHeroCreatures( sHeroName, nCreatureID, nCount )

Функции соответственно возвращают/добавляют/удаляют герою с именем sHeroName стек юнитов типа nCreatureID. Соотв. константы CREATURE_* для nCreatureID см. в /scripts/common.lua. Сюда писать не буду ввиду большого объема. Если стек должного типа отсутствует у героя, то вызов RemoveHeroCreatures к ошибке не приводит.

void GiveArtefact( sHeroName, nArtID, nDummy = 0 )

Выдает герою с именем sHeroName артефакт nArtID. Соотв. константы ARTIFACT_* для nArtID см. в /scripts/advmap-startup.lua. Сюда писать не буду ввиду большого объема.
Третий параметр, видимо, должен был управлять положением предмета – «экипировать/не экипировать», либо являться количеством выдаваемых предметов, однако его изменение никакого видимого эффекта не дает. Артефакт всегда экипируется и всегда выдается в единичном количестве. Чтобы выдать два одинаковых – нужно вызвать функцию с одинаковыми параметрами дважды.
Если после выдачи артефакта подразумевается к/л немедленное продолжение работы с этим предметом (типа удаления, или проверки наличия) рекомендую писать sleep(1) сразу после GiveArtefact. Т.к. иначе предмет может не успеть выдаться. Собственно, это замечание относится ко всем функциям, в которых герою (или объекту) что-либо выдается. Отсюда мораль – ставьте sleep, он лишним не будет. Функция имеет алиас с именем GiveArtifact.

bool HasArtefact(sHeroName, nArtID)

Функция возвращает, есть ли у героя с именем sHeroName хотя бы один артефакт nArtID.

void RemoveArtefact( sHeroName, nArtID )

Функция удаляет у героя с именем sHeroName один артефакт nArtID. Если он у него есть. Если нет – вызов функции приводит к ошибке.

void SetHeroLootable( sHeroName, bEnable )
bool IsHeroLootable( sHeroName )

Функции устанавливают/возвращают «лутабельность» героя с именем sHeroName. Не до конца разобрался, что под этим понимается, скорее всего – будет ли выпадать из героя лут при его поражении в бою.

void MarkObjectAsVisited( sObjectName, sHeroName )

Выставляет у объекта sObjectName «признак посещенности» героем с именем sHeroName на текущий день. Если объект имеет статус enabled (см. ниже IsObjectEnabled и SetObjectEnabled), вызов данной функции приводит к ошибке.

sTownName GetHeroTown( sHeroName )

Если герой с именем sHeroName находится в городе (имеется ввиду – именно внутри, а не на карте около входа), то данная функция возвращает имя города. В противном случае функция вернет nil.

sHeroName GetTownHero( sTownName )

Аналогично GetHeroTown, но в этом случае имя героя ищется по имени города.

tsObjects GetObjectsFromPath( sHeroName, nX, nY, nFloorID = GROUND )

Функция возвращает массив объектов, мимо которых герой с именем sHeroName проскачет при путешествии из Петербурга в Москву... т.е. из текущего своего положения в точку с указанными координатами.

void GiveHeroWarMachine( sHeroName, nWarMachineID )
void HasHeroWarMachine( sHeroName, nWarMachineID )
void RemoveHeroWarMachine( sHeroName, nWarMachineID )

Функции выдают/проверяют наличие/удаляют машину nWarMachineID у героя с именем sHeroName. Соотв. константы для nWarMachineID прописаны в /scripts/common.lua и бывают такими:
      WAR_MACHINE_BALLISTA = 1
      WAR_MACHINE_CATAPULT = 2
      WAR_MACHINE_FIRST_AID_TENT = 3
      WAR_MACHINE_AMMO_CART = 4
Попытка удалить несуществующую машину к ошибке не приводит. Удалить катапульту в любом случае не удастся (но ошибкой не является).

void StartCombat( sHeroName, sEnemyHeroName, nEnemyIDCount, nCreatureID1, nCount1, nCreatureID2, nCount2, ..., spScriptXDB, sFinishProc, spAdventureFlybySceneXDB = nil )

Одна из трех возможностей инициировать переход на тактическую карту непосредственно из скрипта стратегического режима. О параметрах подробнее:
sHeroName – атакующий герой.
sEnemyHeroName – защищающийся герой. Может быть nil в случае атаки на нейтралов без героя.
nEnemyIDCount – количество стеков в армии защищающегося. Должно быть больше нуля.
Далее перечисляются nEnemyIDCount пар вида
nCreatureID – тип существа и nCount – количество существ в стеке.
spScriptXDB – путь к XDB файлу тактического скрипта, либо nil, если дело происходит «на автомате».
sFinishProc – имя функции, которой будет передано управлении после окончания боя (с уведомлением о результате). Обращаю внимание, что это именно строка, а не параметр типа функция. Данный callback имеет следующий прототип:
void combatDone( sHeroName, bWin )
где sHeroName – имя атакующего героя, а bWin – статус сражения относительно атакующего (nil – поражение, иначе – победа).
spAdventureFlybySceneXDB – путь к xdb, определяющему арену, на которой будет происходить сражение. Если nil, то будет взята арена, тип которой соответствует типу местности, на которой находится атакующий герой на стратегической карте.

void SetHeroCombatScript( sHeroName, spScriptXDB )

Функция выставляет герою с именем sHeroName скрипт, который будет работать в последующих тактических боях. Если происходит эпическая битва между двумя героями, оба из которых имеют установленный скрипт, то работает скрипт атакующего.

void ResetHeroCombatScript( sHeroName )

Функция сбрасывает навешенный ранее на героя скрипт. Если ничего навешено не было, то ошибки не происходит.

void SiegeTown( sHeroName, spAdvMapTownXDB, spAdventureFlybySceneXDB = nil )

Собственно, стартует осада города, путь к xdb с описанием которого задан во втором параметре, на арене, заданной третьим параметром. Если последний параметр nil, то берется арена по умолчанию.

3.2.6 Работа с городами.

Если город, имя которого передано в функцию, отсутствует на карте, то вызов функции приводит к ошибке.

nLevel GetTownBuildingLevel( sTownName, nBuildingID )
nLevel GetTownBuildingLimitLevel( sTownName, nBuildingID )
nLevel GetTownBuildingMaxLevel( sTownName, nBuildingID )

Функции позволяют узнать уровень/лимит на развитие/максимальный уровень здания nBuildingID в городе с именем sTownName. Соотв. константы TOWN_BUILDING_* для nBuildingID см. в /scripts/advmap-startup.lua. Сюда писать не буду ввиду большого объема.

void SetTownBuildingLimitLevel( sTownName, nBuildingID, nLevel )

Функция позволяет выставить лимит на уровень развития здания nBuildingID в городе с именем sTownName. При попытке выставить уровень больше максимально возможного вызов функции приводит к ошибке.

void TransformTown( sTownName, nTownTypeID )

Трансформирует город с именем sTownName.  Соотв. константы для nTownTypeID прописаны в /scripts/advmap-startup.lua и бывают такими:
        TOWN_HEAVEN = 0
        TOWN_PRESERVE = 1
        TOWN_ACADEMY = 2
        TOWN_DUNGEON = 3
        TOWN_NECROMANCY = 4
        TOWN_INFERNO = 5
Если в момент трансформации в городе находится герой, он погибнет.

void RazeTown( sTownName )

Разрушает город с именем sTownName. Только в том случае, если при дизайне карты город помечен как «разрушаемый». Иначе вызов данной функции приводит к ошибке.

3.2.7 Работа с объектами.

Под объектом понимается фактически все, что угодно – это здания, города, стеки монстров, герои и т.п. Правда, некоторые функции работают только с определенными видами объектов (например, про работу с героями рассказано выше). Если объект, имя которого передано в функцию, отсутствует, то вызов функции приводит к ошибке.

nX, nY, nFloorID GetObjectPosition( sObjectName )

Функция возвращает позицию объекта. Функция имеет алиас с именем GetObjectPos. На основе данной функции в файле /scripts/advmap-startup.lua реализован примитив более высокого уровня – bool IsInDungeon( sObjectName ).

void SetObjectPosition( sObjectName, nX, nY, nFloorID = GROUND )
Функция устанавливает позицию объекта. Объект должен быть перемещаемым, что, насколько я понимаю, определяется при дизайне этого самого объекта. Например, города перемещать нельзя. Функция имеет алиас с именем SetObjectPos.

void RemoveObject( sObjectName )

Удаляет объект с карты. Объект должен быть перемещаемым и присутствовать на карте. Т.е., например, город удалить нельзя.

bool IsObjectExists( sObjectName )

Возвращает, существует ли на карте объект с данным именем. Функция имеет алиас с именем Exists.

bool IsObjectEnabled( sObjectName )

Возвращает, находится ли объект с именем sObjectName в состоянии enabled.

void SetObjectEnabled( sObjectName, bEnable )

Выставляет или снимает с объекта sObjectName состояние enabled.

tsObjects GetObjectNamesByType( sObjectTypeSubstr )

Выдает массив имен объектов на карте в соответствии с подстройкой sObjectNameSubstr, которая встречается в наименовании его типа. Полностью список соответствующих строк BUILDING_*, TOWN_*, CREATURE_* и HERO_CLASS_* можно найти в файле /types.xml, ветка /Base/Tables. Обращаю внимание, что 1) параметр – именно строка и к константам в /scripts/common.lua имеет весьма опосредованное отношение 2) полного совпадения имени не требуется, достаточно совпадения куска. Например, вызовы
GetObjectNamesByType(“SAWMILL”) и GetObjectNamesByType(“BUILDING_SAWMILL”) вернут один и тот же массив.
3) Тем не менее, излишне доверять сокращениям не следует. Например, по запросу GetObjectNamesByType(“CREATURE_”) не будет выдано ничего.

void AddObjectCreatures( sObjectName, nGreatureID, nCount )
nCount GetObjectCreatures( sObjectName, nCreatureID )
void RemoveObjectCreatures( sObjectName, nCreatureID, nCount )

Позволяет добавить/получить/удалить стеки существ, охраняющих объект.

void SetObjectDwellingCreatures( sObjectName, nCreatureID, nCount )
nCount GetObjectDwellingCreatures( sTownName, nCreatureID )

Позволяет установить/получить стеки существ, которые будут э-э-э, произрастать в объекте, если последний является точкой найма (например, городом). Уточню – изменить тип нанимаемых существ нельзя, можно управлять только их количеством. Например, при попытке вызвать SetObjectDwellingCreatures для города инферно с параметром nCreatureID=1 (крестьяне) никаких крестьян в городе не образуется. (Впрочем, к ошибке данный вызов не приводит) Т.е. данный тип стека должно в принципе быть возможным нанять в указанном месте.

void CreateArtifact( sArtName, nArtID, nX, nY, nFloorID )

Создает артефакт nArtID в точке с указанными координатами и присваивает ему имя sArtName.

void ShowFlyingSign( spTXT, sObjectName, nPlayerID, nTimeSec)

Показывает всплывающую надпись из файла spTXT над объектом sObjectName для игрока nPlayerID в течение nTimeSec секунд. Если nPlayerID = -1, то надпись показывается для всех игроков. Функция имеет алиас с именем ShowFlyMessage.

void CreateMonster( sMonsterName, nCreatureID, nCount, nX, nY, nFloorID, nMonsterMoodID, nCreatureCourageID )

Создает стек существ из nCount существ типа nCreatureID в указанных координатах и присваивает ему имя sMonsterName. Созданный стек имеет mood и courage (ага, трудности у меня с внятным переводом – настроение и кураж? Как-то не звучит...) в соответствии с константами
        MONSTER_MOOD_FRIENDLY = 0
        MONSTER_MOOD_AGGRESSIVE = 1
        MONSTER_MOOD_HOSTILE = 2
        MONSTER_MOOD_WILD = 3
        и
        MONSTER_COURAGE_ALWAYS_JOIN = 0
        MONSTER_COURAGE_ALWAYS_FIGHT = 1
        MONSTER_COURAGE_CAN_FLEE_JOIN = 2
Данные константы нигде не определены. Стек будет принадлежать нейтральному игроку c ID = PLAYER_NONE.
Функция имеет алиас с именем CreateMob.

void RemoveAllMonsters( nCreatureID )

Удаляет с карты все стеки с типом существ nCreatureID. Функция имеет алиас с именем KillMobs

void GenerateMonsters( nCreatureID, nCountGroupsMin, nCountGroupsMax,      
nCountInGroupMin, nCountInGroupMax )


Генерирует в рандомных местах карты от nCountGroupsMin до nCountGroupsMax стеков существ типа  nCreatureID от nCountInGroupMin до nCountInGroupMax существ в каждом стеке. Созданные стеки принадлежат нейтральному игроку c ID = PLAYER_NONE. Функция имеет алиас с именем GenerateMobs.

3.2.8 Работа с интерфейсом.

void QuestionBox( spTXT, sCallback )

Выдает модальный QuestionBox с текстом spTXT и кнопками "Да/Нет", по завершении в случае положительного ответа вызывает функцию с именем sCallback и пустым списком параметров.

void StartDialogScene( spDialogSceneXDB, sCallback = nil, sSaveName = nil )

Стартует диалоговую сцену на движке согласно первому параметру. Если второй параметр не nil, то после диалога будет вызвана функция с именем sCallback и пустым списком параметров. Если sSaveName не nil, то перед диалогом будет произведено сохранение в соотв. слот. Что мешает просто вызывать перед StartDialogScene функцию Save там, когда это нужно, пока не понимаю. Возможно, дело в состоянии экрана на момент сохранения (и, соответственно, в картинке, которая ляжет в сейв).

void StartCutScene( sAnimSceneXDB, sCallback = nil, saveName = nil )

Стартует анимированную сцену на движке согласно первому параметру. Если второй параметр не nil, то после ролика будет вызвана функция с именем sCallback и пустым списком параметров. Если sSaveName не nil, то перед диалогом будет произведено сохранение в соотв. слот.

void MessageBox( spTXT, sCallback = nil, sSaveName = nil )

Выдает модальный MessageBox с текстом spTXT, по завершении вызывает функцию с именем sCallback и пустым списком параметров. Если sSaveName не nil, то перед диалогом будет произведено сохранение в соотв. слот.

void StartDialogSceneInt( spDialogSceneXDB, sCallback = nil, sSaveName = nil )
void StartCutSceneInt( spAnimSceneXDB, sCallback = nil, sSaveName = nil )
void MessageBoxInt( spTXT, sCallback = nil, sSaveName = nil )

Немодальные аналоги перечисленных выше функций. <Немодальность> означает, что во время работы интерфейсного элемента поток скрипта, вызвавшего функцию, продолжает работу. Собственно, их модальные <братья> реализованы скриптом в /scripts/advmap-startup.lua с помощью использования механизма event-ов и функции parse.

void MoveCamera( nX, nY, nFloorID, n1, nAngle, n2 )

Перемещает камеру в положение, заданное параметрами. n1 здесь, скорее всего, длительность в сегментах, n2 - какой-либо из параметров камеры типа pitch или yawl.
О модальности/немодальности данной функции ничего сказать не могу, не экспериментировал.

void TutorialActivateHint( sHintID )
bool IsTutorialItemEnabled( sItemID )

Функции для работы с туториалом. На настоящий момент они не представляют для меня интереса, желающие могут поэкспериментировать самостоятельно. Разнообразные sHintID и sItemID перечислены в файле /UI/uiconsts.(UIGameConstsH5).xdb в разделе
/GameOptions/TutorialOptions/Hints/Item/ScriptID

3.2.9 Функции общей направленности.

void Loose()

Вызов приводит к автоматическому проигрышу миссии. На мультиплеерных картах функция, видимо, неприменима.

void Win()

Вызов приводит к автоматической победе в миссии. На мультиплеерных картах функция, видимо, неприменима.

void BlockGame()

Блокирует интерфейс пользователя. Дабы игрок не дергал попусту мышь и клавиатуру и не сбивал режиссуру ролика с передвижением героев, камеры и т.п.

void UnblockGame()

Соответственно - разблокирует интерфейс пользователя.

void ExitGame()

Немедленный выход из игры. Без всяких промежуточных вопросов.

number GetDate( nDateID )

Возвращает текущую дату в формате согласно переданному параметру. Соотв. константы для nDateID прописаны в /scripts/advmap-startup.lua и бывают такими:

    DAY = 0
    WEEK = 1
    MONTH = 2
    DAY_OF_WEEK = 3
    ABSOLUTE_DAY = DAY
nX, nY GetTerrainSize()

Возвращает размер текущей карты в тайлах.

number GetMaxFloor()

На картах с подземельями данная функция возвращает 1, без оных - 0.

bool IsTilePassable( nX, nY, nFloorID = GROUND )

Возвращает, проходим ли тайл с указанными координатами.

string GetAllNames( nFilterCode )

Возвращает строку, содержащую через пробел имена сообразно переданному параметру. Т.к. в реализации языка отсутствуют функции работы со строками, предполагаю, что данная функция может использоваться исключительно для отладки. Соотв. константы для nFilterCode прописаны в /scripts/advmap-startup.lua и бывают такими:
      FILTER_HEROES = 0
      FILTER_OBJECTS = 1
      FILTER_REGIONS = 2
      FILTER_OBJECTIVES = 3
Реально работают всего два фильтра - FILTER_HEROES и FILTER_OBJECTIVES. Использование остальных ведет к получению пустой строки. Функция имеет алиас с именем names.

void Trigger(nTriggerType, ...)

Приводит к вызову заданной параметром процедуры по наступлению того или иного события. Для останова триггера используется аналогичный по параметрам вызов Trigger, в котором вместо названия процедуры передается nil.
Функция имеет алиас с именем SetTrigger.
Для большинства событий (за исключением, разве что OBJECT_TOUCH) можно написать аналогичную конструкцию без использования функции Trigger, а с использованием проверки условия в отдельном потоке. Нужно ли это делать - практика покажет.
Формат параметров (и список параметров вызываемой процедуры) зависят от типа триггера nTriggerType (константы прописаны в прописаны в /scripts/advmap-startup.lua) Разберу их отдельно.

NEW_DAY_TRIGGER = 0
Формат вызова:
     Trigger(NEW_DAY_TRIGGER, sProc)
Формат вызываемой процедуры:
     void sProc()
Останов:
     Trigger(NEW_DAY_TRIGGER, nil)
Процедура будет вызываться по наступлении каждого нового дня.

PLAYER_ADD_HERO_TRIGGER = 1            
Формат вызова:
Trigger(PLAYER_ADD_HERO_TRIGGER, nPlayerID, sProc )
Формат вызываемой процедуры:
     void sProc( sHeroName )
Останов:
     Trigger(PLAYER_ADD_HERO_TRIGGER, nPlayerID, nil)
Процедура вызывается, когда игрок nPlayerID получает нового героя. Имя данного героя передается в процедуру в качестве параметра.

PLAYER_REMOVE_HERO_TRIGGER = 2            
Формат вызова:
     Trigger(PLAYER_REMOVE_HERO_TRIGGER, nPlayerID, sProc )
Формат вызываемой процедуры:
     void sProc( sHeroName )
Останов:
     Trigger(PLAYER_REMOVE_HERO_TRIGGER, nPlayerID, nil)
Процедура вызывается, когда игрок nPlayerID теряет героя. Имя данного героя передается в процедуру в качестве параметра.

OBJECTIVE_STATE_CHANGE_TRIGGER = 3      
Формат вызова:
     Trigger(OBJECTIVE_STATE_CHANGE_TRIGGER, sObjectiveID, sProc )
Формат вызываемой процедуры:
     void sProc( nPlayerID )
Останов:
     Trigger(OBJECTIVE_STATE_CHANGE_TRIGGER, sObjectiveID, nil )
Процедура вызывается, когда состояние объективы sObjectiveID для какого-либо игрока меняется. Идентификатор игрока передается в процедуру в качестве параметра.

OBJECT_TOUCH_TRIGGER = 4            
Формат вызова:
     Trigger(OBJECT_TOUCH_TRIGGER, sObjectID, sProc )
Формат вызываемой процедуры:
     void sProc( sHeroName )
Останов:
     Trigger(OBJECT_TOUCH_TRIGGER, sObjectID, nil )
Процедура вызывается, когда игрок тыркнулся героем в объект с именем sObjectID. Имя данного героя передается в процедуру в качестве параметра.

OBJECT_CAPTURE_TRIGGER = 5            
Формат вызова:
     Trigger(OBJECT_CAPTURE_TRIGGER, sObjectID, sProc )
Формат вызываемой процедуры:
     void sProc( sHeroName )
Останов:
     Trigger(OBJECT_CAPTURE_TRIGGER, sObjectID, nil )
Процедура вызывается, когда объект с именем sObjectID меняет владельца. Имя завладевшего объектом героя передается в процедуру в качестве параметра.

REGION_ENTER_AND_STOP_TRIGGER = 6      
Формат вызова:
           Trigger(REGION_ENTER_AND_STOP_TRIGGER, sRegionName, sProc )
Формат вызываемой процедуры:
           void sProc( sHeroName )
Останов:
           Trigger(REGION_ENTER_AND_STOP_TRIGGER, sRegionName, nil )
Процедура вызывается, когда какой-либо герой останавливается в регионе с именем sRegionName. Имя данного героя передается в процедуру в качестве параметра.

REGION_ENTER_WITHOUT_STOP_TRIGGER = 7
Формат вызова:
     Trigger(REGION_ENTER_WITHOUT_STOP_TRIGGER, sRegionName, sProc )
Формат вызываемой процедуры:
     void sProc( sHeroName )
Останов:
     Trigger(REGION_ENTER_WITHOUT_STOP_TRIGGER, sRegionName, nil )
Процедура вызывается, когда какой-либо герой попадает в регион с именем sRegionName. Имя данного героя передается в процедуру в качестве параметра.

HERO_LEVELUP_TRIGGER = 8
Формат вызова:
     Trigger(REGION_ENTER_WITHOUT_STOP_TRIGGER, sHeroName, sProc )
Формат вызываемой процедуры:
     void sProc()
Останов:
     Trigger(REGION_ENTER_WITHOUT_STOP_TRIGGER, sHeroName, nil )
Процедура вызывается, когда герой с именем sHeroName повышает уровень.

WAR_FOG_ENTER_TRIGGER = 9            
TOWN_HERO_DEPLOY_TRIGGER = 10            

Собственно, для данных типов триггеров отсутствуют примеры, и соответственно, данные. Эксперименты я ставить поленился.

3.2.10 Работа со звуком.

nSoundID Play3DSound( spSoundXDB, nX, nY, nFloorID )

Проигрывает 3D звук по указанным координатам. Результат используется исключительно в функции StopPlaySound в том случае, если звук циклический. Если нет, то возвращается -1 и вызов StopPlaySound приведет к ошибке.

nSoundID Play2DSound( spSoundXDB )

Проигрывает 2D звук. Результат используется исключительно в функции StopPlaySound в том случае, если звук циклический. Если нет, то возвращается -1 и вызов StopPlaySound приведет к ошибке.

void StopPlaySound( nSoundID )

Останавливает проигрывание циклического звука.

3.2.11 Работа с освещением.

void SetCombatAmbientLight( spAmbientLightXDB )

Меняет освещение тактической арены. Функция имеет алиас с именем SetCombatLight.

void SetObjectFlashlight( sObjectName, sLightID )

Теоретически функция должна устанавливать подсветку объекта, практически же попытка подсунуть ей вторым параметром что-либо отличное от пустой строки, приводит к ошибке. Вероятно, в sLight должна идти ссылка на что-то, определяемое при дизайне карты.

void SetAmbientLight( nFloorID, sLightID, b1, n1)

Аналогично SetObjectFlashlight. Причем назначение двух последних параметров мне неизвестно. Функция имеет алиас с именем SetLight.

3.2.12 Всякие непонятки.

void SetWarfogBehaviour( n1, n2 )

Очевидно, имеет какое-то отношение к туману войны. Смысл параметров мне не понятен.

number CalcAverageMonstersTier()

Возвращает некое дробное число. Полагаю, используется для отладки. При чем здесь слеза (Асхи?) - не понял. Функция имеет алиас с именем CalcAverageTier.

tnTier GetGuardsTier( sObjectName )

Возвращает массив целых чисел.

void SetStandState( sStandName, nState )
number GetStandState( sStandName )
number GetStandStatesCount( sStandName )

Чем управляют данные три функции, не догадался. Т.к. понятия не имею, что это за тип объекта - "Stand". Вычитанное в ресурсах игры определение <stand - several visual objects on same place switching by script> ясности не добавляет. Желающие могут посмотреть на 4-ю миссию 5-й кампании (там присутствует объект типа stand с именем TieruHut) и попытаться разобраться, чего же эти функции с ним делают.

void StopTrigger()

Что за триггер стопорит данная функция, есть ли у нее параметры - "науке пока не известно".

3.3. Тактический режим.

При старте тактического режима игра делает следующее:
1.      Загружает файл /scripts/combat-startup.lua и все прописанные в нем с помощью doFile скрипты
2.      Вызывает функции createCombatAliases() и createTutorialAliases()
3.      Приступает к интерпретации файла тактического скрипта. Упомянутый тактический скрипт может появиться в результате
•      Использования примитивов StartCombat или SetHeroCombatScript
•      Дизайна файла карты (AdvMapDesc)
•      Дизайна файла определения героя (AdvMapHero)
4.      Так или иначе, если файл скрипта в наличии, то интерпретатор последовательно выполняет из него строки, не являющиеся телами функций, после чего приступает к последовательному вызову хуков в зависимости от ситуации. Всего в наличии четыре хука.

3.3.1 Общее положение дел.

Итак, имеется две армии. Собственно различие между ними скрипт проводит по признаку атакующий/обороняющийся. Атакующая сторона всегда содержит в своем составе героя. Обороняющаяся может героя не иметь. Имена героев и стеков не имеют никакого отношения к именам использующимся на стратегической карте. Существует единственный примитив, позволяющий соотносить имена героев между стратегическим и тактическим режимом – GetHeroName.

3.3.2 Хуки.

bool DoPrepare()

Вызывается на этапе расстановки стеков игроком. На данном этапе состав армии игрока не определен, соотв. функции будут показывать, что в наличии есть только собственно герой. Возвращаемое значение роли не играет. В файле /scripts/combat-startup.lua данный хук заменен на void Prepere(), пользуйтесь либо одним либо другим по собственному разумению.

bool DoStart()

Вызвается на старте сражения непосредственно после расстановки войск обеими сторонами. Возвращаемое значение роли не играет. В файле /scripts/combat-startup.lua данный хук заменен на void Start(), пользуйтесь либо одним либо другим по собственному разумению.

bool UnitMove(sUnitName)

Вызывается перед каждым ходом стека AI игрока. Имя стека передается в качестве параметра. Если функция возвращает true, то AI не предпринимает над стеком к/л осмысленных действий, считая, что Вы позаботились об этом в теле хука.
Юниту отдается команда "защищаться", что, вообщем, не совсем то, чего бы лично я ожидал в этом случае. Логичней было бы вообще ничего не делать с юнитом. Кстати, по поводу «true». В файле /scripts/combat-startup.lua в отличие от файла /scripts/advmap-startup.lua отсутствует определение константы true, поэтому ее нужно либо доопределить самостоятельно, либо пользовать вместо нее not nil.
В файле /scripts/combat-startup.lua данный хук заменен на целый набор функций:

bool AttackerUnitMove(sUnitName)
      bool AttackerHeroMove(sUnitName)
      bool AttackerCreatureMove(sUnitName)
      bool AttackerWarMachineMove(sUnitName)
      bool AttackerBuildingMove(sUnitName)
bool DefenderUnitMove(sUnitName)
      bool DefenderHeroMove(sUnitName)
      bool DefenderCreatureMove(sUnitName)
      bool DefenderWarMachineMove(sUnitName)
      bool DefenderBuildingMove(sUnitName)
Опять таки, пользуйтесь тем, чем Вам удобнее.      

void UnitDeath(sUnitName)

Вызывается при смерти стека существ. Имя стека передается в качестве параметра.
В файле /scripts/combat-startup.lua данный хук заменен на целый набор функций:
void AttackerUnitDeath(unitName)
      void AttackerHeroDeath(sUnitName)
      void AttackerCreatureDeath(sUnitName)
      void AttackerWarMachineDeath(sUnitName)
      void AttackerBuildingDeath(sUnitName)
void DefenderUnitDeath(sUnitName)
      void DefenderHeroDeath(sUnitName)
      void DefenderCreatureDeath(sUnitName)
      void DefenderWarMachineDeath(sUnitName)
      void DefenderBuildingDeath(sUnitName)
Пользуйтесь тем, чем Вам удобнее.      

3.3.3 Общие функции контроля боя.

void EnableDynamicBattleMode( bEnable )

Если вызвано с параметром true, то грядущая битва будет происходит в динамическом режиме, т.е. с ограничением на время хода. Внимание! Отключить динамический режим по ходу боя будет нельзя.

void EnableAutoFinish( bEnable )

Понятия не имею, для чего это нужно.

void EnableCinematicCamera( bEnable )

Разрешает или запрещает «кинематографическое» метание камеры с показом действий юнитов.

void SetControlMode( nSideID, nModeID )

Устанавливает режим боя для стороны nSideID. Попытка вызвать данную функцию для AI игрока приводит к ошибке. Соотв. константы для nModeID прописаны в /scripts/ combat-startup.lua и могут быть
MODE_NORMAL = 0      -- обычный режим
MODE_MANUAL = 1      -- ручное управление с запретом автобоя
MODE_AUTO = 2        -- автобой
В частности, вызвав данную функцию из DoPrepare c параметром MODE_AUTO и, последовательно, с  MODE_MANUAL из DoStart можно обеспечить автоматическую расстановку юнитов вне желания игрока.
Соотв. константы для nSideID прописаны в /scripts/ combat-startup.lua и могут быть
ATTACKER = 0
DEFENDER = 1
void combatEnableFinish( bEnable )

Понятия не имею, для чего это нужно.

void Finish( nSideID )

Автоматически завершает бой победой стороны, идентификатор которой передан в качестве параметра.

void Break()

Немедленно прерывает бой. Потери, понесенные сторонами в ходе боя, в случае выхода на стратегическую карту учитываться не будут.

void combatSetPause( n1, b1 )

Устанавливает и убирает паузу в бое (при паузе курсор превращается в часы и интерфейс заблокирован). Смысл параметров мне не до конца ясен.

void showHighlighting( bShow = true )

Убирает или устанавливает подсвечивание поля боя. Функция имеет алиас с именем ShowCombatHighlighting.

3.3.3 Управление юнитами.

void SummonCreature( nSideID, nCreatureID, nCount, nX, nY )
void AddCreature( nSideID, nCreatureID, nCount, nX, nY )

Практически идентичные функции. Добавляют стороне nSideID стек из nCount существ, и размещает его по указанным координатам. Различие состоит в том, что SummonCreature создает стек только на время боя, и подсвечивает его появление эффектом. В случае, если клетка по указанным координатам недоступна (например, занята препятствием или другим стеком) новый стек будет помещен на ближайшую свободную клетку. Созданный стек будет помещен в конец таблицы, которая возвращается функцией GetUnits. Если планируется что-либо предпринимать со стеками непосредственно после добавления, то необходимо добавить вызов sleep(1) непосредственно сразу после использования функций. Иначе последствия непредсказуемы – от невыполнения следующей операции без к/л диагностики до вылета игры в операционную систему.

void addUnit(nCreatureID, nSideID, nX, nY, nCount, sUnitName)

Странная функция, которая, по идее, занимается тем же, что и две предыдущие. С некоторыми отличиями. Параметр sUnitName используется только в одном месте – если уже есть стек с таким именем, то вызов функции приведет к ошибке. В противном случае имя стеку присвоится автоматически, sUnitName никак не задействуется. В случае, если клетка по указанным координатам недоступна, вызов функции приведет к ошибке.
Вывод: использование данной функции проблематично, для чего она нужна – непонятно.
Функция имеет алиас с именем AddCombatUnit.

void removeUnit( sUnitName )

Функция удаляет с поля боя стек с именем sUnitName. Удалять можно только стеки.Героев, машины и здания – нельзя. Функция имеет алиас с именем RemoveCombatUnit.

void UnitCastAimedSpell( sUnitName, nSpellID, sTarget)

Функция заставляет юнит с именем sUnitName откастовать заклинание nSpellID на юнит sTarget. Тип юнита и наличие у юнита заклинания роли не играет, играет роль только запас манны у него. Нехватка манны приводит к ошибке скрипта. Следует быть осторожным с выбором nSpellID – попытка скастовать подобным образом «площадное» заклинание, например, файрболл, может привести к подвису игры. Попытка скастовать «вредоносное» заклинание на союзников и «полезное» на врага  к ошибке не приводит, но и эффекта так же не дает.

void UnitCastGlobalSpell( sUnitName, nSpellID )

Функция заставляет юнит с именем sUnitName откастовать заклинание «общего действия» (т.е. не требующее прицела) nSpellID. Тип юнита и наличие у юнита заклинания роли не играет, играет роль только запас манны у него. Нехватка манны приводит к ошибке скрипта.

void UnitCastAreaSpell( sUnitName, nSpellID, nX, nY )

Функция заставляет юнит с именем sUnitName откастовать заклинание «площадного действия» nSpellID на тайл с требуемыми координатами. Тип юнита и наличие у юнита заклинания роли не играет, играет роль только запас манны у него. Нехватка манны приводит к ошибке скрипта. Опять таки не следует забывать про sleep – например, если Вы вздумаете удалить стек непосредственно после того, как он что-то откастовал, то собственно кастовки Вы не увидите. И sleep(1) тут не отделаешься – необходимо дождаться результатов кастовки, для файрбола это sleep(8 ), для других заклинаний может и отличаться. Собственно, замечание со sleep относится ко всем манипуляциям с юнитами.

void SetUnitManaPoints( sUnitName, nPoints )

Функция устанавливает запас маны юнита sUnitName в nPoints поинтов. Текущий запас манны может превышать максимальный. Следует помнить, что эффект заклинания зависит от максимума из двух значений - максимального и текущего запаса маны юнита . Если планируется что-либо предпринимать с юнитом непосредственно после установки запаса маны, то необходимо добавить вызов sleep(1) непосредственно сразу после SetUnitManaPoints.

number GetUnitMaxManaPoints( sUnitName )

Функция возвращает максимальный запас маны  юнита sUnitName.

number GetUnitManaPoints( sUnitName )

Функция возвращает текущий запас маны  юнита sUnitName.

void commandDefend( sUnitName )

Функция заставляет юнит с именем sUnitName выполнить команду «защищаться».
Функция имеет алиас с именем DefendCombatUnit.

void commandDoSpell( sUnitName, nSpellID, nX, nY )

Аналог UnitCastAreaSpell.

void commandShot( sUnitName, sVictimName, bDontShowScene = false )

Функция заставляет юнит с именем sUnitName выполнить выстрел по юниту sVictimName. Если третий параметр true, то соответствующая кинематографическая сценка «юнит натужно замахивается и что-то кидает» показана не будет. По своим стрелять нельзя. При отсутствии снарядов стрелять нельзя. Оба случая приводят к ошибке скрипта.

void commandMove( sUnitName, nX, nY, bCheckPath = false )

Функция заставляет юнит с именем sUnitName переместиться на клетку с указанными координатами. Если третий параметр true, то будет учитываться длина хода юнита. При нехватке хода юнит с места не сдвинется, а вызов функции приведет к ошибке. Если клетка недостижима (т.е. занята другим юнитом или на пути к ней есть непреодолимые препятсятвия), то в любом случае никто никуда не пойдет, а вызов функции приведет к ошибке. Функция имеет алиас с именем MoveCombatUnit.

void commandMoveAttack(sAttacker, sVictim, nX = -1, nY = -1, bCheckPath = false)

Функция заставляет юнит с именем sUnitName атаковать юнит sVictim в melee режиме. Если указаны положительные координаты, то юнит сначала дойдет до требуемой клетки, а потом произведет атаку с нее (да-да, несмотря на то, что melee, и между юнитами пол-поля – ударит, да еще и сдачи получит). В противном случае юнит подбежит к атакуемому вплотную. Если третий параметр true, то будет учитываться длина хода юнита. При нехватке хода юнит с места не сдвинется, а вызов функции приведет к ошибке. Если клетка недостижима (т.е. занята другим юнитом или на пути к ней есть непреодолимые препятсятвия), то в любом случае никто никуда не пойдет, а вызов функции приведет к ошибке. Функция имеет алиас с именем AttackCombatUnit.

void commandDoSpecial(sUnitName, nAbilityID, nX = -1, nY = -1, bCheckPath = false)

Функция заставляет юнит с именем sUnitName использовать спецспособность по клетке с указанными координатами (если они заданы – некоторые спецспособности не требуют координат). Если третий параметр true, то будет учитываться длина хода юнита. При нехватке хода юнит с места не сдвинется, а вызов функции приведет к ошибке. Если клетка недостижима (т.е. занята другим юнитом или на пути к ней есть непреодолимые препятсятвия), то в любом случае никто никуда не пойдет, а вызов функции приведет к ошибке. Константы ABILITY_* nAbilityID прописаны в /scripts/combat-startup.lua, приводить полный список не буду. На этот раз не из-за большого объема. А из-за того, что они там некорректные. Нормальные значения констант SPELL_ABILITY_* нужно смотреть в файле /types.xml. Принципиальных ограничений на использование «неродных» абилок, в принципе, нет – так, например, суккуб вполне может изображать BATTLE_DIVE. Однако, все возможные сочетания я, конечно, не проверял.
Функция имеет алиас с именем UseCombatAbility.

void displace( sUnitName, nX, nY )

Функция мгновенно телепортирует юнит на требуемую клетку. Никакими эффектами процесс не сопровождается. Если клетка уже занята кем-либо или чем-либо, то вызов функции приведет к ошибке.
Функция имеет алиас с именем SetCombatPosition.

void playAnimation( sUnitName, sAnimType, nActionTypeID = ONESHOT )

Функция заставляет юнит с именем sUnitName проигрывать анимацию sAnimType способом nActionTypeID. Возможные sAnimType следует смотреть в xdb файле определения анимации для существ. Например, для импов это файл _(AnimSet)\Creatures\Inferno\Imp-arena.(AnimSet).xdb. Как правило, анимация типа «death» существует для всех. Остальное зависит от типа существа. Константы для nActionTypeID прописаны в /scripts/combat-startup.lua и могут быть
IDLE = 1 -- проигрывается циклически
ONESHOT_STILL = 2 -- проигрывается один раз, и 
последний фрейм фиксируется
ONESHOT = 3 -- проигрывается один раз, потом 
юнит возвращается в прежнюю позу
NON_ESSENTIAL = 5 -- не знаю, что такое.
void combatPlayEmotion( nSideID, n1 )

Функция заставляет юниты стороны nSideID проигрывать эмоцию. Полагаю, второй параметр должен определять ее тип, но эксперименты ничего не дали – независимо от значения параметра все ведут себя одинаково – радуются и чего-то голосят.

void RemoveAllUnits()

Функция удаляет все стеки с поля боя. У обоих сторон. Ввиду чего полезность ее под вопросом.

void setATB( sUnitName, n1 )

Функция позволяет управлять положением юнита на ATB. Значения второго параметра большие нуля приводят к сдвигу юнита по ATB в начало шкалы, прочие – в конец. Вероятно, существует какая-то количественная интерпретация параметра, но я ее не уловил. Следует вызывать только из хуков, т.к. в противном случае можно получить рассинхронизацию ATB с действительным порядком ходов.

3.3.4 Информационные и прочие функции.

tsUnits GetUnits(nSideID, nType)

Возвращает таблицу имен юнитов типа nType для стороны nSideID. Константы nType прописаны в /scripts/combat-startup.lua и могут быть
HERO = 0
CREATURE = 1
WAR_MACHINE = 2
BUILDING = 3
С использованием данной функции в файле /scripts/combat-startup.lua реализованы примитивы более высокого уровня:
sHeroName GetHero(nSideID)
tsUnits GetCreatures(nSideID)
tsUnits GetWarMachines(nSideID)
tsUnits GetBuildings(nSideID)
sHeroName GetAttackerHero()
sHeroName GetDefenderHero()
tsUnits GetAttackerCreatures()
tsUnits GetDefenderCreatures()
tsUnits GetAttackerWarMachines()
tsUnits GetDefenderWarMachines()
tsUnits GetAttackerBuildings()
tsUnits GetDefenderBuildings()

nCreatureID GetCreatureType( sCreatureName )

Возвращает тип существ в стеке с именем sCreatureName.

nX, nY pos( sUnitName )

Возвращает координаты юнита с именем sCreatureName. Функция имеет алиас с именем GetCombatPosition.

bool combatStarted()

Возвращает false до тех пор, пока не началась былинная битва. Имеет смысл использовать только вне хуков.

sHeroName GetHeroName( sUnitName )

Возвращает «стратегическое» имя героя sUnitName. Если передано не имя героя – вызов приведет к ошибке.

number GetCreatureNumber( sUnitName )

Возвращает количество существ в стеке с именем sUnitName.

nX, nY GetUnitPosition( sUnitName )

Аналог функции pos.

bool exist( sUnitName )

Возвращает, а жив ли еще юнит с именем sUnitName. Функция имеет алиас с именем IsCombatUnit.

nHostType GetHost( nSideID )

Возвращает, под чьим управлением находится сторона nSideID – человека или AI.
Возвращаемые константы прописаны в /scripts/common.lua и могут быть
HUMAN = 0
COMPUTER = 1
С использованием данной функции в файле /scripts/combat-startup.lua реализованы примитивы более высокого уровня:
bool IsHuman( nSideID )
bool IsComputer( nSideID )

nSideID GetUnitSide( sUnitName )

Возвращает, к какой стороне относится юнит с именем sUnitName.
Возвращаемые константы прописаны в /scripts/combat-startup.lua и могут быть
ATTACKER = 0
DEFENDER = 1

С использованием данной функции в файле /scripts/combat-startup.lua реализованы примитивы более высокого уровня:
bool IsAttacker( sUnitName )
bool IsDefender( sUnitName )

number GetUnitType( sUnitName )

Возвращает тип юнита с именем sUnitName. Возвращаемые константы прописаны в /scripts/combat-startup.lua и могут быть
HERO = 0
CREATURE = 1
WAR_MACHINE = 2
BUILDING = 3
С использованием данной функции в файле /scripts/combat-startup.lua реализованы примитивы более высокого уровня:
bool IsHero( sUnitName )
bool IsCreature( sUnitName )
bool IsWarMachine( sUnitName )
bool IsBuilding( sUnitName )

number GetWarMachineType( sUnitName )

Возвращает тип машины с именем sUnitName. Возвращаемые константы прописаны в /scripts/common.lua и могут быть
WAR_MACHINE_BALLISTA = 1
WAR_MACHINE_CATAPULT = 2
WAR_MACHINE_FIRST_AID_TENT = 3
WAR_MACHINE_AMMO_CART = 4
С использованием данной функции в файле /scripts/combat-startup.lua реализованы примитивы более высокого уровня:
sUnitName GetWarMachine( nSideID, nWarMachineTypeID )
sUnitName GetAttackerWarMachine(nWarMachineTypeID)
sUnitName GetDefenderWarMachine(nWarMachineTypeID)

number GetBuildingType( sUnitName )

Возвращает тип здания с именем sUnitName. Возвращаемые константы прописаны в /scripts/combat-startup.lua и могут быть
BUILDING_WALL = 1
BUILDING_GATE = 2
BUILDING_LEFT_TOWER = 3
BUILDING_BIG_TOWER = 4
BUILDING_MOAT = 5
BUILDING_RIGHT_TOWER = 6
BUILDING_MAGIC_WALL = 7
С использованием данной функции в файле /scripts/combat-startup.lua реализованы примитивы более высокого уровня:
sUnitName GetBuilding(nSideID, nBuildingID)
sUnitName GetAttackerBuilding(nBuildingID)
sUnitName GetDefenderBuilding(nBuildingID)

sUnitName combatReadyPerson()

Возвращает имя юнита, который готов совершить ход (т.е. находится в самом начале ATB).

string unitNames()

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

void postEvent( sEvent, n1 = -1, n2 = -1 )

Функция позволяет эмулировать событие от клавиатуры/мыши. В качестве sEvent могут выступать названия биндов, см. файл input.cfg. Полный список биндов я предоставить в настоящий момент не готов. Смысл двух последних параметров мне так же неясен. Довольно занятная функция, полагаю, с ее помощью можно соорудить миниотладчик, вызывая с ее помощью открытие консоли из функции errorHook.

3.4. Режим города.

При старте режима города игра делает следующее:
1.      Загружает файл /scripts/town-startup.lua и все прописанные в нем с помощью doFile скрипты
2.      Приступает к интерпретации файла скрипта города. Упомянутый скрипт города может появиться в результате дизайна города.
3.      В зависимости от ситуации вызывает один из двух хуков.

3.4.1 Хуки

void CreatureHired( nCreatureID, nCount )

Вызывается при найме существ. Идентификатор типа существа и их количество передаются в качестве параметра.

void HeroHired( sHeroName )

Вызывается при найме героя. Имя героя передается в качестве параметра.

3.4.2 Прочие функции

Собственно, никаких прочих функций я не нашел. Работать можно только с теми, которые перечислены в разделе 3.1.

4. Если бы директором был я.

Как видный гейм-дизайнер практически вселенского масштаба не могу не высказаться на тему «как бы это сделал я». Т.к. несмотря на то, что работа проделана большая, и «песня в целом удалась, и песня в целом состоялась» недостатки видны даже на первый взгляд. Посему, воспылав праведным гневом, коротенько, листов на 5, перечислю. На всякий случай – все резкие формулировки типа «отсутствует» следует читать, как  «я не нашел».
1)      Отсутствует какая-либо система в мнемонике функций. Функции работы с параметрами игрока должны начинаться с префикса Player. Параметрами героя – Hero. И так далее. Не обязательно именно так, но какая-то система в наименовании функций должна присутствовать. Да, есть механизм алиасов, и можно создать свой наборчик названий. Но это будет именно *мой* набор, а не общий для всех. Низачот.
2)      Отсутствует должное усердие в обеспечении стабильности приложения. Проверка параметров – это хорошо. Но когда функция RemoveArtefact в отсутствие должного артефакта у героя выдает ошибку и приводит к останову скрипта, это, товарищи, безобразие. По уму она таки должна выдавать в консоль предупреждение и продолжать работу, при этом в случае Get* функций возвращать к/л приемлемое умолчательное значение. Дополнительным бонусом могло бы стать заведение консольной переменной при определенном значении которой интерпретатор не прекращал бы выполнение потока при возникновении ошибки.
3)      Средства отладки оставляют желать. Хочется консольную команду scripterror, которая выдавала бы стек последней ошибки скрипта в формате файл/имя функции/строка. Хочется ряд клавиатурных биндов для переброса героя/стека в точку под курсором, для убиения героя/стека под курсором, для помещения во внутреннюю переменную имени героя/стека под курсором.
4)      Отсутствует ряд необходимых (на мой взгляд) функций.
a.      Невозможно узнать уровень мастерства героя в том или ином скилле (ну и выставить, ясен пень, тоже нельзя. Дальше не буду поминать симметричные функции).
b.      Нельзя получить информацию ни о текущей неделе ни о типе ее влияния.
c.      Нет функций работы с treasures.
d.      В тактическом режиме невозможны прямые манипуляции со стеком существ (изменить количество, узнать параметры и т.п.)
e.      При атаке врага посредством commandMoveAttack имеем либо чит (стек двигается без учета длины хода) либо ошибку – хода не хватило. Просто направить стек для атаки указав ему врага (не дошел на этот ход – бог с ним, на следующий дойдет) нельзя.
f.      Отсутствует возможность узнать, проходима ли клетка в тактическом режиме.
g.      В режиме города вообще нет функции, хотя само собой напрашивается – получить информацию о нанимающем герое, изменить параметры героя, получить параметры города, изменить количество существ и т.п.
e.      Вообщем, у мене масса предложений и добавлений :) В будущем попробую вычленить из них критичные, как знать - может быть товарищи разработчики таки снизойдут в одном из грядущих патчей. Прочим, разбирающимся в теме, рекомендую заняться тем же.
На этом пока все.

Автор: Novik65

Alex at 2011-07-28 18:59 wrote:
Возникла задача - реализовать на стратегической карте анимацию разрушения городских ворот замка. Соответствующий статический объект ворот присутствует в редакторе на вкладке Arena Objects, но вот анимация к нему не прилагается. Кто-нибудь знает как это сделать?
Your name: *
E-mail:
Your comment: *
Your favorite version of the game: Heroes Might & Magic

Герои 7 Новости

Heroes 7 maps

Heroes 7 cheats

Heroes 7 News

Герои 7 Новости


Герои 5 Новости

Купить Heroes 5: Владыки Севера

Герои 5 патч 3.1 для аддона Повелители Орды русская версия

Героев 5: мод v.3.0, новые способности существ

Герои 5: скачать новую компанию "Весы судеб"!

Герои 5 кумулятивный русский патч 1.6

Мод с "Колесом" для Повелителей Орды

Heroes 5: Повелители Орды уже в продаже

Герои 5: Повелители Орды - механика работы Blood Rage

Герои 5: Повелители Орды новый видео ролик

Герои 5 патч 1.5 для русской версии

Официальный конкурс карт для Героев 5

Heroes 5 Диалог с разработчиками

Герои 5 патч 1.41+2.01 для русской версии

Прохождение аддона Heroes 5: Владыки Севера

Герои 5: режиссерская версия

Heroes 5: Владыки Севера : Чит-коды

Герои 5: Новые существа Гномы статистика и умения

Герои 5 - новый аддон Владыки Севера

Герои 5 патч 1.4 для русской версии

Генерация карт для Героев 5

Герои 5: Крепость (Fortress)

Heroes 5 Patch 1.3, с редактором карт для Героев 5

Герои 5 - Ренегаты и Нейтральные юниты

Прохождение Героев 5

как взять Dragon Utopia

Герои 5 - Руководство по скриптам

Герои 5 патч 1.2 для русской версии

Heroes 5 - Специальные Возможности Существ

Герои 5 - Артефакты

Герои 5 - Заклинания и Магия

Герои 5 патч 1.1 для русской версии

Герои 5 - Inferno - Биографии героев

Герои 5 - Necropolis - Биографии героев

Герои 5 - Academy - Биографии героев

Герои 5 - Haven - Биографии героев

Герои 5 - Sylvan - Биографии героев

Герои 5 - Dungeon - Биографии героев

О редакторе карт Героев 5

Герои 5 - FAQ от Nival Interactive за 1 июля 2006 г.

Герои 5 - FAQ от Nival Interactive за 8 июня 2006 г.

Герои 5 - HEX-codes

Герои 5 - ДЕМО-ВЕРСИЯ

Heroes 5 - Обои

Герои 5 - Магия

Heroes 5 - Дневник разработчика #2 - Проведение бета-теста

Heroes 5 - Каждому по способностям

Heroes 5 - Городской интерфейс

Heroes 5 - Курсы практической магии

Heroes 5 - Уникальные свойства рас

Heroes 5 - Academy Faction

Heroes 5 - Существа Academy

Heroes 5 - SYLVAN

Heroes 5 - SYLVAN - Существа SYLVAN

Heroes 5 - DUNGEON

Heroes of Might and Magic 5 - DUNGEON - Существа DUNGEON

Heroes 5 - INFERNO - The Lords of Chaos

Heroes 5 - INFERNO - Существа INFERNO

Heroes 5 - HAVEN - The Knights of the Light

Heroes 5 - HAVEN - Существа HAVEN

Heroes 5 - НЕКРОПОЛИС - Некроманты

Heroes 5 - НЕКРОПОЛИС - Существа Некрополиса

FAQ по "Heroes 5" за июль 2005 г.

Heroes 5 Часто задаваемые вопросы

Heroes 5 скриншоты

Heroes 5 - Ключевые особенности

Heroes 5 - Homepage


Heroes 5 News

Heroes Kingdoms news

New campaign "566 year - The Day of Fiery Tears" for Heroes 5: Tribes of the east

Heroes 5 Manual 3.1 for the Tribes of the East

Heroes 5 Patch 3.1 for the Tribes of the East

Heroes 5 FAQ from Fabrice Cambounet

Old horse cursors Mod for Heroes 5: Tribes of the east

Heroes 5 Patch 1.6 released

The FIRST MAP "Mythical Realm" for Heroes 5: Tribes of the east

Heroes 5: Tribes of the east NOW released!

Heroes 5 hints: Mini Artifacts

Heroes 5: Tribes of The East - Orc Blood Rage ability & Screenshots

Heroes 5: Tribes of the East GC 2007 Trailer

Heroes 5: Tribes of The East - News & Screenshots

Staff reduction at Nival

Heroes 5 ToE: Dwarves alternate upgrades

Heroes 5 ToE: Academy alternate upgrades

Heroes 5 ToE: Demons and Orcs

Heroes 5 ToE: Necropolis alternate upgrades

Heroes 5 Tribes of the East: Inferno alternate upgrades

Heroes 5 Tribes of the East: Dungeon alternate upgrades

Heroes 5 Tribes of the East: Sylvan alternate upgrades

Heroes 5 Patch 1.5 released

SkillWheel in game

Heroes 5: First Official Map Contest

Heroes 5 walkthrough Hammers of Fate

Heroes 5 - The Skull of Shadows

Heroes 5 Patches 1.41+2.01 download

Heroes 5: Hammers of Fate : Cheats

Heroes 5 - New Dwarven Creatures - stats and abilities

The Heroes 5 expansion: Hammers of Fate has been released!!

Heroes 5 - Dwarven racial skills and abilities

Heroes 5 Patch 1.4 - download now !!!

Heroes 5 - Tapani's random map generator

Heroes 5 - Fortress Heroes biographies

Heroes 5 Fortress - Dwarves Faction

Heroes 5 Patch 1.3 download here - with Heroes 5 Map Editor

Heroes 5 - Renegates and Neutrals units

Heroes 5 walkthrough campaigns

Heroes 5 - Dragon Utopia. v. Haven

Heroes 5 Patch 1.2 - download now !!!

Heroes 5 Artefacts

Heroes 5 Spells and Magic

Heroes 5 - Patch 1.1 Bugfixes

Heroes 5 Hammers of Fate FAQ & New screenshots

Heroes 5 - FAQ about Hammers of fate expansion

About Heroes 5 Map Editor

FAQ by Heroes 5 producer Fabrice Cambounet

Heroes 5 - FAQ by Nival Interactive - 8 june 2006

Heroes 5 Haven Strategy

Heroes 5 - HEX-codes

Heroes 5 - DEMO

Heroes 5 - Wallpapers

Heroes of Might and Magic 5 - Music

Heroes 5 - Academy - Heroes biographies

Heroes 5 - Dungeon - Heroes biographies

Heroes 5 - Inferno - Heroes biographies

Heroes 5 - Sylvan - Heroes biographies

Heroes 5 - Olivier Ledoit Q&A

Heroes 5 - Development Letter #3: The Battlefield

Heroes 5 - Necropolis - Heroes biographies

Heroes 5 - Haven - Heroes biographies

Heroes 5 - Development Letter #2 - Handling A Beta Test

Heroes 5 - Magic

Heroes 5 - The Town Construction Interface

Heroes 5 - Creatures Special Abilities

Heroes 5 - Unique racial abilities Q&A

Heroes 5 - Academy Faction

Heroes 5 - ACADEMY - Creatures

Heroes 5 - DUNGEON - Faction

Heroes 5 - SYLVAN - Faction

Heroes 5 - DUNGEON - Creatures

Heroes 5 - SYLVAN - Creatures

Heroes 5 - Dungeon Faction Q&A

Heroes 5 - Live chat logs with Fabrice Cambounet

Heroes 5 - NECROPOLIS - The Necromancers

Heroes 5 - NECROPOLIS - Creatures

Heroes 5 - INFERNO - The Lords of Chaos

Heroes 5 - INFERNO - Creatures

Heroes 5 - HAVEN - The Knights of the Light

Heroes 5 - HAVEN - Creatures

Heroes 5 - development diary #1: REVAMPING THE M&M UNIVERSE

Heroes 5 - FAQ - July 2005

Heroes 5 - dev team's ambitions

Heroes 5 screenshots

Heroes 5 - FAQ

Heroes 5 - features

Heroes 5 - Homepage

Haps4Heroes.com

Copyright © 1999-2017 All questions and comments please mail to evgkuz@yandex.ru