-
Notifications
You must be signed in to change notification settings - Fork 2
Lua Support
Lua support makes it easier to add content to the game. This document explains the Lua API and gives examples of how to extend the game using the Lua framework supported in the game.
Every scene has a <scene-name>.lua file which resides in resources/lua
folder. This Lua file contains all code that is used by the scene and the scene's components.
Scenes will emit three events that can be caught in Lua. These are: onInit
, onEnter
and onExit
. These are the default names and will be called automatically when the event is triggered. The names can be overriden using the JSON configuration like so:
{
"onInit": "scene_onInit",
"onEnter": "scene_onEnter",
"onExit": "scene_onExit",
}
Each event is passed a Scene
object as the first parameter (see Scene API
below).
A Hello World example using the configuration above might look like:
function scene_onInit(scene)
print('Hello from '..scene:name..'!')
end
function scene_onEnter(scene)
print('Entering scene '..scene:name..'!')
end
function scene_onExit(scene)
print('Now leaving scene '..scene:name..'!')
end
There are three callback functions for every scene.
This function is invoked when the scene is first loaded. This should not be confused with when the scene is entered, which can happen multiple times during the game. onInit
is called only once when the game starts. Note that if game ends and the user starts a new game, onInit
will be called at the start of that new game.
This function is invoked when the player first enters the scene. This callback can be called multiple times in a single game since a user can enter and leave scenes multiple times.
This function is invoked when the playe first exits the scene. This callback can be also be called multiple times.
The argument item
is an Item
object. This function adds an existing Item
object to the current scene, hence the object must already exist when this function is called.
For example:
function onEnter(scene)
local item = ItemFactor.createItem("sax")
scene:addItem(item)
end
Creates a new modal window of type ModalType
for display.
See Modal Window for more details.
Returns a handle to the scene's description window. See "Description Window".
No arguments. Returns a Player
object. This object is only valid for the life of the scene.
Example
function onEnter(scene)
local player = scene:getPlayer()
local health = player:getHealth() - 2
player:setHealth(health)
end
No arguments. Returns the (x,y) coordinates of the player's current tile.
Example
function onEnter(scene)
local x,y = scene:getPlayerTile()
print ("The player is at position "..x..','..y)
end
No arguments. Returns the name of the current scene.
The argument item
is an Item
object. If the scene does not contain the passed in item then nothing happens.
Sets the player's current tile to (x
,y
). There are no bounds checking done on coordinates passed in.
The player object is accessible through Scene.getPlayer
. The player object is only valid for the life of the current scene.
The lifetime of the player object only lasts for the lifetime of the current scene. This means that if the player object is cached, it should be cached with each call to onEnter
. For example, this will cause a crash:
gPlayer = nil
function onEnter(scene)
if gPlayer == nil then
gPlayer = scene:getPlayer()
end
end
function someOtherFunction()
print("Health is "..gPlayer:getHealth()) -- CRASH! (when scene is entered a second time)
end
The first time the scene is entered this will run. However when the player leaves the scene, the data to which gPlayer
points is invalidated but the underlying value of gPlayer
is still non-nil. Hence when the user re-enteres the scene and someOtherFunction
is invoked, the methos Player.getHealth()
will be called on corrupted data.
The correct way to do this would be to just set it every time:
gPlayer = nil
function onEnter(scene)
gPlayer = scene:getPlayer()
end
function someOtherFunction()
print("Health is "..gPlayer:getHealth()) -- OK
end
This also means that the player object is not available during initialization (i.e. onInit
).
function onInit(scene)
local player = scene:getPlayer()
print("Health is "..gPlayer:getHealth()) -- CRASH!
end
Add the item
object to Player
's inventory. item
is an object and not a string value.
Example:
-- give the player 'special-coin' when entering the scene
function scene_onEnter(scene)
local item = ItemFactory.createItem('special-coin')
player:addItem(item)
end
See more about "Items".
No arguments. Returns the value of the player's current balance.
Returns a float value of the player's current balance.
Returns an intenger value of theplayer's current health.
Returns the (x,y) corrdinates of the player's position in terms of the display coordinates.
See Scene.getPlayerTile()
The argument item
is an Item
object (i.e. the type returned from ItemFactory.createItem()
). Behind the scenes, item
holds a pointer to the allocated item and does a raw pointer comparison with all the items contained in player inventory.
The argument itemid
is the ID of the item, which in most cases corresponds to the JSON filename of the item.
The argument item
is a pointer to an Item
object, just like the argument for Player.hasItem
.
The argument itemid
is the ID of the item, which in most cases corresponds to the JSON filename of the item.
Sets the balance of the player to balance
. This should be a numeric value.
Sets the health of the player to health
. This should be an integer value.
Sets the player's display position to (x
,y
). There are no bounds checking done on coordinates passed in.
See Scene.getPlayerTile()
Just like scenes, items have cofigurable events. The events are specified in the JSON file where each individual item is configured.
For example:
"treasure-chest":
[
{
"x": 37, "y": 31, "onPickup": "treasureChest_onPickup"
}
],
These are the item events:
scene
is the current scene, and item
is the item object being picked up.
Parameter itemid
is the item's unique key as determined by the filename. This function returns an Item
object.
Returns the description of the item.
Returns the id of the item.
Returns the name of the item.
Sets the description of the item to text
. Can be empty.
Sets the name of the item to name
. Can be empty.
The description window is the text shown in the center of the HUD. It is safe to cache this in a variable for conviennce. For example the following is safe:
local descw = nil
function onInit(scene)
descw = scene:getDescriptionWindow()
end
function someFunction()
descw:setText("Invoking some function!")
end
Returns the current test of description window.
Sets the text of the description window to text
.
Zones are configured in a scene's JSON file.
Zone events are defined in the zone's JSON configuration like so:
For example:
"zones":
[
{
"name" : "Home",
"description": "Press SPACE to enter your filthy apartment",
"rects" :
[
"48,77,52,80",
],
"transition":
{
"scene": "EuclidHouse",
},
"onSelect" : "home_onSelect"
}
]
The zone events are:
This is event is triggered when the zone has an attached transition and the user triggers the transition (see 'Zones' and 'Transitions' in scenes-dev.md). If there is no transition attached to the zone then this callback is never called.
The event is passed a handle to the current scene
, and a handle to the zone
itself.
This callback must return a boolean where true indicates that the transition should continue (i.e. that the new scene should be loaded) or false to cancel the transition.
The following example implements a "cover charge" for entering a scene:
function club_onSelect(scene, zone)
local player = scene:getPlayer()
local balance = player:getBalance()
if balance > 20 then
player:setBalance(balance - 20)
return true
end
scene:getDescriptionWindow():setText("Entry costs $20")
return false
end
Returns the name of the zone.
Modal windows stop all processing in the game to display text and get input from the user. Modal windows can be used to simulate dialog from NPCs or ask the user questions.
Modal windows are created through the Scene.createModal()
method. There are currently four different types of modal windows.
Example:
function onEnter(scene)
local player = scene:getPlayer()
if player:getHealth() < 30 then
local win = scene:createModal(ModalType.Default)
win:setText("This is a dangerous map. Be careful")
win:exec()
end
end
In this example we displayng a warning to the player when they enter a level if their health is too low.
The four types of modal windows are:
ModalType.Default
ModalType.Messages
ModalType.Options
ModalType.Inventory
This modal window is a standard window that displays a message that can be dismissed by pressing Space or Escape.
The API for Default Modal Windows is available for all types of modal windows.
This function displays the window. Without calling this function the modal window will do nothing. This function is blocking.
There are three ways the window can be vertically aligned:
ModalAlignment.Bottom
ModalAlignment.Center
ModalAlignment.Top
The default is ModalAlignment.Bottom
.
Sets the height of the window to height
while preserving the vertical alignment.
Sets the text to the window to text
. There is no word-wrap functionality, but text
can be broken into lines using \n
.
Sets the width of the window to width
.
The Messages Modal Window allows you to display multiple windows of text within the same modal window instances.
Pushes a message into the queue of messages to be displayed. The messages will be shown in the order they're pushed. The player can go to the next messages by pressing the Space bar. Pressing the Escape key will close the window.
Example:
local w = scene:createModal(ModalType.Messages)
w:pushMessage("This will be shown first")
w:pushMessage("This will be displayed second")
w:pushMessage("This will be printed last")
w:exec()
The Options Modal Window displays a list of choices to the user. The user can scroll through the options using the arrow key, and an option can be selected by pressing Space or Enter. If the user closes the window using Escape then the selection is null.
Here is a full example:
function home_onSelect(scene, zone)
local player = scene:getPlayer()
local balance = player:getBalance()
if balance < 35 then
local er = scene:createModal(ModalType.Default)
er:setText("You do not have enough money")
er:exec()
return false
end
local w = scene:createModal(ModalType.Options)
w:setText("There is a $35 cover charge.\nDo you want to enter?")
w:addOption("Yes")
w:addOption("No")
w:exec()
local r = w:getSelection()
if r == nil or r == 1 then
return false
end
player:setBalance(balance - 35)
return true
end
Adds the option text.
Returns the 0-based index of the selected option. This can also be nil
which means the user dismissed the box with the Escape key (i.e. no selection was made)
The Inventory Modal Window shows the player's inventory. This window uses the same API of the Options Modal Window to get the index of the selection.
Lua's logging mechanism hooks into the same logging mechanism as the C++ code, and therefore will use the same settings, logfile, etc.
The functions available are:
[void] Log.trace(text)
[void] Log.debug(text)
[void] Log.info(text)
[void] Log.warn(text)
[void] Log.error(text)
[void] Log.critical(text)
Example:
function scene_onInit(scene)
Log.info("The scene "..scene:name().." has been initialized")
end
Audio is separated into two types of audio: music and sound effects, or simply "sound". Each type has its own API, though the API calls are nearly identical.
This needs to be called before the audio is used. The audiofile
parameter is the file name of the audio file relative to the resources folder. For example Audio.Music.cache("music/intro.wav")
refers to the music
folder under the resources folder.
The Audio.Music
namespace should be used for music (i.e. background songs).
The API calls to start and stop music is:
[void] Audio.Music.pause(audiofile)
[void] Audio.Music.play(audiofile)
[void] Audio.Music.stop(audiofile)
This needs to be called before the audio is used. The audiofile
parameter is the file name of the audio file relative to the resources folder. For example Audio.Sound.cache("sounds/walking.wav")
refers to the sounds
folder under the resources folder.
The Audio.Sound
namespace should be used for sound effects and short sounds.
The API calls are:
[void] Audio.Sound.pause(audiofile)
[void] Audio.Sound.play(audiofile)
[void] Audio.Sound.stop(audiofile)
The Utils
offers a group of helper functions.
Opens the system's default browser to the passed in url
.
Shows a single message in a modal window. The scene
argument is the current scene.
For example:
function scene_onInit(scene)
Utils.showModal(scene, "Welcome to the game!")
end
is functionally equivalent to:
function scene_onInit(scene)
local window = scene:createModal(ModalType.Default)
window:setText("Welcome to the game!")
window.exec()
end
Shows a message in a modal window and gives the user a "Yes" or no "Option".
Example:
local res = Utils.showYesNo(scene, "Would you like to continue?")
if res then
-- code to continue
else
-- code not to continue
end
Getting Started
For Users
For Developers