Current time: 15.08.2018, 12:48 Hello There, Guest! (LoginRegister)
Language: english | russian  

Post Reply 
Threaded Mode | Linear Mode
ERM => Lua FAQ
» Вопросы - Ответы
Author Message
Berserker Offline
Administrators

Posts: 10554
Post: #1

Чтение данных по адресу

Code:
local mem = require('era.mem')

local byte   = mem.u8(адрес)  -- 1 байт   0..255
local sbyte  = mem.i8(адрес)  -- 1 байт   -128..127
local word   = mem.u16(адрес) -- 2 байта  0..65535
local sword  = mem.i16(адрес) -- 2 байта  -32768..32767
local dword  = mem.u32(адрес) -- 4 байта  0..4294967295
local sdword = mem.i32(адрес) -- 4 байта  -2147483648..2147483647

Запись данных по адресу

Code:
mem.u8(адрес, значение)  -- 1 байт   0..255
mem.i8(адрес, значение)  -- 1 байт   -128..127
mem.u16(адрес, значение) -- 2 байта  0..65535
mem.i16(адрес, значение) -- 2 байта  -32768..32767
mem.u32(адрес, значение) -- 4 байта  0..4294967295
mem.i32(адрес, значение) -- 4 байта  -2147483648..2147483647


Скачать Герои 3 Эра и всё, что с ней связано
05.01.2018 15:46
Find all posts by this user Quote this message in a reply
Berserker Offline
Administrators

Posts: 10554
Post: #2

Обработка событий

Ниже представлена таблица соответствия ЕРМ триггеров и новых именованных событий:

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...


Скачать Герои 3 Эра и всё, что с ней связано
05.01.2018 16:11
Find all posts by this user Quote this message in a reply
Berserker Offline
Administrators

Posts: 10554
Post: #3

Выполнение ЕРМ команд/ресиверов
Для выполнения ЕРМ кода и доступа к ЕРМ-переменным используется модуль era.erm.

Code:
local erm = require('era.erm')

Модуль позволяет использовать себя как функцию, передавая строку ЕРМ команд, разделённых ";" и без ведущих "!!".

Code:
erm('HE-1:C0/0/?y1/?y2; IF:M^Слот 0. Тип: %Y1. Количество: %Y2.^')

Для доступа к ЕРМ-памяти используются таблицы erm.v, erm.z, erm.y, erm.e, erm.f (логические значения). Таблицы ведут себя как обычные индексированные массивы.

Code:
erm.v[7] = 600          -- записали 600 в v7
erm.z[3] = 'Hi, Valery' -- записали строку в z3
print(erm.z[1])         -- отобразили содержимое строки z1

Дополнительно доступен метод :addr(индекс), возвращающий адрес ЕРМ-переменной в виде обычного числа.

Code:
print('Адрес e50: ' .. erm.e:addr(50))

Модуль erm содержит методы hero(id) и currHero() для получения доступа к объектам героя по его ID или текущему герою (полный аналог HE-1). У возвращаемого объекта имеется метод .w(индекс, значение?) для доступа к w-переменным героя.

Code:
local hero = erm.hero(30) -- получили героя с id = 30
print(hero:w(100))        -- вывели для него переменную w100
hero:w(15, 777)           -- установили для него w15 в 777
hero:w(1, hero:w(1) + 3)  -- увеличили w1 на 3


Скачать Герои 3 Эра и всё, что с ней связано
05.01.2018 17:04
Find all posts by this user Quote this message in a reply
Berserker Offline
Administrators

Posts: 10554
Post: #4

Сохранение и загрузка данных

Хранение данных в сохранённых играх может понадобиться как системным скриптам, так и обычным. ЕРМ-память сохраняется и загружается автоматически.

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

Для примера создадим таблицу с данными, которые нужно хранить в сохранённых играх:

Code:
local save = {
  mithril = 100 -- количество нового ресурса
}

После чего подпишемся на два события, в которых будем сохранять/загружать таблицу save:

Code:
era.on('OnLuaSavegameWrite', function ()
  era.writeSavegame(save, 'ErmToLua.Manual')
end)

era.on('OnLuaSavegameRead', function ()
  save = era.readSavegame('ErmToLua.Manual') or {}

  if not save.mithril then
    save.mithril = 0
  end
end)

OnLuaSavegameWrite возникает, когда нужно записывать таблицу в сохранёнку. Для этого используется функция era.writeSavegame(таблица, уникальное имя).

При загрузке игры (событие OnLuaSavegameRead) мы получаем таблицу по уникальному имени. Конструкция "or {}" возвращает пустую таблицу, если era.readSavegame вернула nil (данные не найдены). Такой подход позволяет загружать сохранённую игру, для которой скрипт ранее не использовался. Соответственно, далее идёт проверка на существование поля в таблице. Если поле отсутствует (старая версия скрипта или сохранение без скрипта), то ему присваивается значение по умолчанию.

Теперь можно работать с save.mithril как обычной переменной: выводить количество мифрила, увеличивать/уменьшать и т.д.

Примечание: в реальном примере мифрил лучше хранить для каждого игрока: local mithril = {0, 0, 0, 0, 0, 0, 0, 0}


Скачать Герои 3 Эра и всё, что с ней связано
06.01.2018 03:43
Find all posts by this user Quote this message in a reply
« Next Oldest | Next Newest »
Post Reply 


Forum Jump:

Powered by MyBB Copyright © 2002-2018 MyBB Group