Events
Multiverse has plenty of registerd callbacks that are executed when a specific event is triggered. To start receiving events, you first have to define the event's corresponding callback function inside your Lua script. You may expect parameters to be passed back to you, some of which are passed by reference.
warning
You may not have multiple definitions of the same callback, even if the second definition is located inside a secondary (require
) script file or module. View the example below, where only one OnTurn
event will work.
module = require(get_script_dir() .. 'module.lua')
function OnTurn() end
local module = {}
function OnTurn() end
return module
Essential ✨​
OnScript​
Description:
OnScript
is a crucial event and is generally always found inside the main.lua
script, which is considered the Parent
. This event is triggered when scripts are supposed to be loaded, e.g. level restart, load, etc.
Parameters
Type | Name | Description |
---|---|---|
UBYTE | level | The current level being loaded by the user. |
Code Example
function OnScript(level)
if (level == 1) then
AddScript("level_1.lua")
else
AddScript("level_2.lua")
end
end
OnTurn​
Description: This event is triggered every time a game turn has passed. No parameters are being passed to this callback. To fetch the current game turn, use the example below.
Parameters None.
Notes
tip
Use the reserved Game
object to call the getTurn
method to get the current turn, or alternatively, the method getTurnSecond
, depending on the units you want to work with. Do note that one second is equal to 12 game turns!
caution
When using getTurnSecond
, it's advisable to check for a valid value. If the turn has already been processed, it will return an ULONG_MAX
(0xffffffff). However, getTurn
does not require this check.
Code Example
function OnTurn()
local turn = Game.getTurnSecond()
-- We ensure we only process the turn once.
if (turn ~= ULONG_MAX) then
Log(string.format("Current turn: %i", turn))
end
end
OnThing​
Description: This event is triggered every time a game object is created, but only for objects created after the first game turn (anything above GT 0).
Type | Name | Description |
---|---|---|
Thing* | thing | The thing object. |
Notes
note
The thing object is passed by reference, so you may modify the object inside the callback function.
tip
If you're only interested in parsing spells, OnPlayerSpell will be a better alternative to OnThing, since you won't be having to parse hundreds of objects.
caution
Seralized objects that spawn during the first game turn (i.e. placed through the World Editor) will never trigger this event. This is intentional but might change in the future.
Code Example
function OnThing(thing)
Log(string.format("[OnThing] Type: %i, Model: %i, Owner: %i", thing.Type, thing.Model, thing.Owner))
thing.Owner = thing.Owner + 1
if (thing.Owner > TRIBE_GREEN) then thing.Owner = TRIBE_BLUE end
end
OnRegenerate​
Description: This event will trigger when a level is loaded for the first time, or during an on-going level that is restarted.
Parameters
Type | Name | Description |
---|---|---|
UBYTE | level | The current level the user is playing. |
Notes
caution
This event will not trigger when the user loads a game save file of the level, as it has already been generated before.
Code Example
function OnRegenerate(level)
initialize_my_important_stuff()
end
Input ✨​
OnKeyDown​
Description: This event will trigger when a key is pressed, the passed argument being the key code that was pressed.
Parameters
Type | Name | Description |
---|---|---|
TbInputKey | key | Key code that was pressed. |
Return
It is expected of you to return a boolean, indicating whether you want the game to handle the key event. Returning a true
value will tell the input system to not handle the keystroke.
Notes
caution
Not all keys trigger this event – for a full list of possible key codes check the TbInputKey data structure.
Code Example
function OnKeyDown(key)
if (key == TbInputKey.LB_KEY_Q) then
Log("'Q' key down!)
end
end
OnKeyUp​
Description: This event will trigger when a key is released, the passed argument being the key code that was released.
Parameters
Type | Name | Description |
---|---|---|
TbInputKey | key | Key code that was released. |
Notes
caution
Not all keys trigger this event – for a full list of possible key codes check the TbInputKey data structure.
Code Example
function OnKeyUp(key)
if (key == TbInputKey.LB_KEY_Q) then
Log("'Q' key released!)
end
end
OnMouse​
Description: This event will trigger when a mouse button is pressed, the passed argument being a MouseEvent.
Parameters
Type | Name | Description |
---|---|---|
MouseEvent | event | Mouse event containing the button type and state, as well as the click location in screen space. |
Return
It is expected of you to return a boolean, indicating whether you want the game to handle the click event or not. Returning a true
value will tell the input system to not handle the click. This is useful for cases where you want to create your own scripted GUI and consume the click events yourself.
Notes
note
The event will fire even whilst inside the main game menu or during a game pause.
Code Example
function OnMouse(event)
if (event.Button == TbInputKey.LB_KEY_MOUSE0 and event.Down == true) then
Log(string.format("Left mouse button click at screen pos: %i, %i", e.Pos.X, e.Pos.Y))
end
end
OnChat​
Description: This event will trigger when a message is sent using the TAB + F11 chatbox, the passed argument being the message sent.
Parameters
Type | Name | Description |
---|---|---|
string | message | Message sent by the user. |
Code Example
function OnChat(message)
if (message == "/surrender") then
Log("I surrender!")
end
end
Serialization ✨​
OnSave​
Description: This event will trigger when the user saves the game. You may use this event to save the state of your variables.
Parameters
Type | Name | Description |
---|---|---|
SLONG | slot | This is the save slot chosen by the user. |
Notes
tip
You can either save individual variables or tables containing one or more elements.
warning
Saving will fail on local objects – ensure they're global before attempting to do so. To create a global table, simply declare it outside the scope of a function – there's no global
keyword.
function my_function()
local MyCoolTable = { error="this table is only 'visible' in this function block!" }
end
...
SaveTable("MyCoolTable", slot) -- error, cannot find this table defined anywhere!
Code Example
MyTable = { Foo=0, Bar=1 }
MySecondTable = {nil, 42, Foo=1, Bar=function() Log("Bar") end}
function OnSave(slot)
SaveTable("MyTable", slot)
SaveTable("MySecondTable", slot)
end
OnLoad​
Description: This event will trigger when the user loads a game save file. You may use this event to load the previous state of your variables.
Parameters
Type | Name | Description |
---|---|---|
SLONG | slot | This is the save slot chosen by the user. |
Notes
Code Example
-- Based on the OnSave code example above,
-- 'MyTable' and 'MySecondTable' were previously serialized.
function OnLoad(slot)
LoadTable("MyTable", slot)
LoadTable("MySecondTable", slot)
end
Sound ✨​
OnSoundPlay​
Description: This event will trigger when a sound from the custom music engine starts playing.
Parameters
Type | Name | Description |
---|---|---|
string | name | This is the name of the playing sound file. |
Code Example
function OnSoundPlay(name)
Log(string.format("Now playing: %s", name))
end
OnSoundStop​
This event will trigger when a sound from the custom music engine stops playing.
Parameters
Type | Name | Description |
---|---|---|
SoundReceiverInfo | sri | This is a data structure containing the sound name and the reason it stopped playing. |
Notes
warning
Trying to play a custom music track from within this function will result in a crash, instead call the play method somewhere else, i.e inside OnTurn.
Code Example
function OnSoundStop(sri)
Log(string.format("Stopped playing: %s, reason: %i", sri.FileName, sri.Reason))
end
Drawing ✨​
OnFrame​
This event will trigger every time a frame has finished rendering – essential for drawing text, sprites or shapes to the screen space.
Parameters None.
Notes
tip
Get and cache a reference to the object gnsi
to get the current screen width and height. You will most certainly need this for drawing inside OnFrame
!
_gnsi = gnsi() -- global variable and called only once
...
local scrW, scrH = _gnsi.ScreenW, _gnsi.ScreenH
Code Example
function OnFrame()
local scrW, scrH = _gnsi.ScreenW, _gnsi.ScreenH
local x, y = math.floor(scrW / 2), math.floor(scrH / 2)
DrawBox(x, y, 220, 30, 0)
PopSetFont(P3_V_LARGE_FONT, 0)
DrawTextStr(x, y, "Hello from Lua!")
end
OnSpriteFrame​
This event will trigger every after the engine draws a sprite to the screen. It does not receive events from GUI drawing.
Parameters
Type | Name | Description |
---|---|---|
SpriteFrameEvent* | frame | This is a data structure containing information about the sprite frame that has just been rendered. |
Notes
note
This event is useful for drawing your own text, sprites or shapes in world space, but introduces quite a bit of overhead.
caution
There's a possibility for the frame to contain a non T_PERSON object, as a result of a few unique objects being rendered through this pipeline.
warning
The structure SpriteFrameEvent
and OnSpriteFrame
event is subject to heavy API changes in future Multiverse updates.
OnAnimSpriteFrame​
This event will trigger every after the engine draws a person sprite to the screen.
Parameters
Type | Name | Description |
---|---|---|
SpriteFrameEvent* | frame | This is a data structure containing information about the sprite frame that has just been rendered. |
Notes
note
This event is useful for drawing your own text, sprites or shapes in world space, but introduces quite a bit of overhead.
caution
There's a possibility for the frame to contain a non T_PERSON object, as a result of a few unique objects being rendered through this pipeline.
warning
The structure SpriteFrameEvent
and OnAnimSpriteFrame
event is subject to heavy API changes in future Multiverse updates.
Code Example
function OnAnimSpriteFrame(frame)
if (frame.Thing.Type == T_PERSON) then
if (frame.Thing.Model == M_PERSON_MEDICINE_MAN) then
local life = frame.Thing.u.Pers.Life
local bar_w, bar_h = 100, 8
local x, y = frame.x - (bar_w / 2), frame.y - frame.h - 10
DrawBox(x, y, bar_w+2, bar_h+2, COLOUR(CLR_BLACK))
DrawBox(x, y, bar_w, bar_h, COLOUR(CLR_BLACK))
local life_bar_w = math.floor((bar_w * (life)) / frame.Thing.u.Pers.MaxLife)
if (life > 0) then DrawBox(x, y, life_bar_w, bar_h, COLOUR(CLR_RED)) end
local life_str = string.format("%i / %i", life, frame.Thing.u.Pers.MaxLife)
PopSetFont(P3_SMALL_FONT_NORMAL, 0)
DrawTextStr(math.floor((x - (string_width(life_str) / 2)) + (bar_w / 2)), y, life_str)
end
end
end
Code Result
Other ✨​
OnPlayerHintDisplay​
This event will trigger when a hint is being displayed by the game. See PlayerHintDisplay for more details..
Hint example.
Parameters
Type | Name | Description |
---|---|---|
PlayerHintDisplay* | hint | This is a data structure containing information about the hint. |
Code Example
function OnPlayerHintDisplay(hint)
Log(string.format("Hint StrId: %i, hint.StrId))
end
OnPlayerSpell​
This event will trigger when a spell is being cast. It is similar to the OnThing event, but you're guaranteed to only parse spells.
Parameters
Type | Name | Description |
---|---|---|
Thing* | thing | The spell object. |
Notes
note
The thing object is passed by reference, so you may modify the object inside the callback function.
tip
If you're only interested in parsing spells, OnPlayerSpell will be a better alternative to OnThing, since you won't be having to parse hundreds of objects.
Code Example
function OnPlayerSpell(thing)
if (thing.Owner == TRIBE_BLUE) then
thing.Model = M_SPELL_FIRESTORM
end
end
OnDamage​
This event will trigger when a person receives damage. Visit this page for more information about the DamageEvent structure.
Parameters
Type | Name | Description |
---|---|---|
DamageEvent | event | The damage event, this being a data structure. |
Notes
caution
Not all damage sources will trigger this event.
Code Example
function OnDamage(event)
if (event.DamagingPlayer == TRIBE_RED) then
event.Thing.u.Pers.Life = event.Thing.u.Pers.Life + math.floor(event.Damage * 2) -- heal the person
end
end
OnDeinit​
This event will trigger when a script is being removed, i.e script is no longer active.
Parameters None.
Notes
note
This event gives you the opportunity to clean up after yourself.
Code Example None.
OnLoadPalTables​
This event will trigger when the game generates the ghost
and fade
color tables.
Parameters
Type | Name | Description |
---|---|---|
UBYTE | level | Current level being played. |
Notes
warning
This event might become deprecated as there's no use for it any longer.
Code Examples None.
OnFrontEnd​
This event will trigger every time the user goes back into the main menu screen.
Parameters None.
Notes
caution
The event can only be called by a Parent
script.
Code Examples
function OnFrontEnd()
Log("User has entered the front end menu!")
end
OnFrameCredits​
It is expected of you to return a boolean, indicating whether you want the game to draw the original scrolling credits text. Returning a true
value will tell the game not to draw the credits text.
Parameters None.
Notes
caution
The event can only be called by a Parent
script.
Code Examples
function OnFrameCredits()
-- Draw a red background
DrawBox(0,0,800,600,COLOUR(CLR_RED))
return true
end
OnFrontEndFrame​
Called every frame whilst inside front end menus. For example, main menu, level select menu, in-game pause menu, etc.
Parameters None.
Code Examples
function OnFrontEndFrame()
-- Draw a red background
DrawBox(0,0,800,600,COLOUR(CLR_RED))
end