Обработка событий
Ниже представлена таблица соответствия ЕРМ триггеров и новых именованных событий:
Code:
BA0 'OnBeforeBattle'
BA1 'OnAfterBattle'
BR 'OnBattleRound'
BG0 'OnBeforeBattleAction'
BG1 'OnAfterBattleAction'
MW0 'OnWanderingMonsterReach'
MW1 'OnWanderingMonsterDeath'
MR0 'OnMagicBasicResistance'
MR1 'OnMagicCorrectedResistance'
MR2 'OnDwarfMagicResistance'
CM0 'OnAdventureMapRightMouseClick'
CM1 'OnTownMouseClick'
CM2 'OnHeroScreenMouseClick'
CM3 'OnHeroesMeetScreenMouseClick'
CM4 'OnBattleScreenMouseClick'
CM5 'OnAdventureMapLeftMouseClick'
AE0 'OnEquipArt'
AE1 'OnUnequipArt'
MM0 'OnBattleMouseHint'
MM1 'OnTownMouseHint'
MP 'OnMp3MusicChange'
SN 'OnSoundPlay'
MG0 'OnBeforeAdventureMagic'
MG1 'OnAfterAdventureMagic'
TH0 'OnEnterTown'
TH1 'OnLeaveTown'
IP0 'OnBeforeBattleBeforeDataSend'
IP1 'OnBeforeBattleAfterDataReceived'
IP2 'OnAfterBattleBeforeDataSend'
IP3 'OnAfterBattleAfterDataReceived'
CO0 'OnOpenCommanderWindow'
CO1 'OnCloseCommanderWindow'
CO2 'OnAfterCommanderBuy'
CO3 'OnAfterCommanderResurrect'
BA50 'OnBeforeBattleForThisPcDefender'
BA51 'OnAfterBattleForThisPcDefender'
BA52 'OnBeforeBattleUniversal'
BA53 'OnAfterBattleUniversal'
GM0 'OnAfterLoadGame'
GM1 'OnBeforeSaveGame'
PI 'OnAfterErmInstructions'
DL 'OnCustomDialogEvent'
HM 'OnHeroMove'
HL 'OnHeroGainLevel'
BF 'OnSetupBattlefield'
MF1 'OnMonsterPhysicalDamage'
TL0 'OnEverySecond'
TL1 'OnEvery2Seconds'
TL2 'OnEvery5Seconds'
TL3 'OnEvery10Seconds'
TL4 'OnEveryMinute'
TMn 'OnErmTimer n'
HEn 'OnHeroInteraction n'
HMn 'OnHeroMove n'
HLn 'OnHeroGainLevel n'
LEx/y/z 'OnLocalEvent x/y/z'
OBx/y/z 'OnBeforeVisitObject x/y/z'
OBтип/подтип 'OnBeforeVisitObject тип/подтип'
!$OBx/y/z 'OnAfterVisitObject x/y/z'
!$OBтип/подтип 'OnAfterVisitObject тип/подтип'
FU[n] 'OnErmFunction n'
SAVEGAME_WRITE 'OnSavegameWrite'
SAVEGAME_READ 'OnSavegameRead'
KEYPRESS 'OnKeyPressed'
OPEN_HEROSCREEN 'OnOpenHeroScreen'
CLOSE_HEROSCREEN 'OnCloseHeroScreen'
STACK_OBTAINS_TURN 'OnBattleStackObtainsTurn'
REGENERATE_PHASE 'OnBattleRegeneratePhase'
AFTER_SAVE_GAME 'OnAfterSaveGame'
BEFOREHEROINTERACT 'OnBeforeHeroInteraction'
AFTERHEROINTERACT 'OnAfterHeroInteraction'
ONSTACKTOSTACKDAMAGE 'OnStackToStackDamage'
ONAICALCSTACKATTACKEFFECT 'OnAICalcStackAttackEffect'
ONCHAT 'OnChat'
ONGAMEENTER 'OnGameEnter'
ONGAMELEAVE 'OnGameLeave'
Для подписки на события используется функция
era.on из модуля
era.
function era.on (eventName, eventHandler, opts)
Функция принимает три аргумента: имя события, функцию-обработчик и опции в виде таблицы (не обязательно). Возможные опции:
Code:
{
oneTime = true, -- выполнить обработчик только один раз и удалить
priority = число -- приоритет обработчика, 0 по умолчанию
}
Обработчики событий выполняются в порядке их приоритета и регистрации. Обработчики с низким приоритетом выполняются первее, с более высоким — позднее. С одинаковым приоритетом — в порядке регистрации.
Пример.
Code:
era.on('OnHeroScreenMouseClick', function (event, handler, eventName)
print('Вы щёлкнули мышкой в окне героя')
end)
Обработчик получает следующие аргументы при вызове:
event — для событий, генерируемых Эрой и плагинами — указатель на следующую структуру:
Code:
typedef struct TEvent {
char* name;
void* data;
int dataSize;
};
Для событий, генерируемых скриптами Lua для скриптов Lua — произвольная таблица.
handler — вызываемая функция-обработчик. Позволяет применять рекурсию для анонимных функций или отписываться от обработки события.
eventName — имя текущего события.
Указанные выше параметры являются опциональными. Минимизированный пример выше:
Code:
era.on('OnHeroScreenMouseClick', function ()
print('Вы щёлкнули мышкой в окне героя')
end)
Внимание!
По умолчанию события, регистрируемые через
era.on являются удаляемыми — обработчики будут удаляться при загрузке/старте новой игры, как это происходит и с ЕРМ-триггерами. Системные плагины могут использовать аналогичную функцию
era.bind для регистрации обработчика, который не будет удалён никогда.
Отписка от событий
Помимо возможности установить одноразовый обработчик через
era.on('...', handler, { oneTime = true }), имеется возможность полностью удалить определённый обработчик, передав в функцию
era.off имя события и старую функцию-обработчик.
Code:
era.on('OnHeroScreenMouseClick', function (event, handler, eventName)
print('Это сообщение отобразится один раз')
era.off(eventName, handler)
end)
Если обработчик — локальная именованная функция, то можно видоизменить пример:
Code:
local function MyHandler ()
print('Это сообщение отобразится один раз')
era.off('OnHeroScreenMouseClick', MyHandler) -- отключить обработчик
end
era.on('OnHeroScreenMouseClick', MyHandler)
Динамическое добавление/удаление обработчиков во время обработки событий
При наступлении события создаётся полная копия его обработчиков, отсортированная в порядке приоритетов и даты регистрации. Любые добавления удаления обработчиков повлияют на
новые генерации события, но не на текущее. Это значит, что нельзя в рамках одного и того же события отключить другой обработчик для данного события. Отключённый обработчик будет выполнен 1 раз, поскольку при генерации события была получена его копия.
Пример.
Code:
local function MyHandler2 ()
print('Привет 2')
end
local function MyHandler1 (event, handler, eventName)
print('Привет 1')
era.off(eventName, MyHandler)
end
era.on('OnHeroScreenMouseClick', MyHandler1)
era.on('OnHeroScreenMouseClick', MyHandler2)
Обработчик 1 выполняется до обработчика 2, так как у них одинаковые приоритеты, а он был зарегистрирован первым. Обработчик 1 сразу же отключает обработчик 2, но только для будущих генераций событий. В текущей генерации уже создана копия списка обработчиков (обработчик 1, обработчик 2). Поэтому при множественных щелчках в окне героя получим сообщения:
Привет 1
Привет 2
Привет 1
Привет 1
Привет 1...