-
Notifications
You must be signed in to change notification settings - Fork 81
Lua support in KeeperFX is currently incomplete and not yet functional. The work-in-progress implementation is available in this PR. This documentation is also a work in progress and subject to change.
KeeperFX uses LuaJIT, which is based on Lua 5.1. For general Lua language reference, see the official Lua 5.1 manual. This document focuses specifically on KeeperFX's Lua implementation.
The recommended IDE for writing Lua scripts in KeeperFX is VS Code with the sumneko Lua extension.
Note:
- This is the second one when searching for lua extension in vscode, the first one isn't as comprehensive as the sumneko one
- Install the Lua extension in VS Code.
- Set the workspace folder and path. (TODO: more detail)
- Change the Lua runtime to LuaJIT:
- Open VS Code Settings (
Ctrl + ,
). - Search for "Lua › Runtime › Version."
- Set it to LuaJIT.
- Open VS Code Settings (
Lua scripts in KeeperFX are event-driven, meaning they respond to in-game events (triggers). All available triggers are defined in fxdata/lua/triggers.lua
(TODO: Make link to final file in github).
The following example listens for when a creature is slapped and executes an action at the slap's location:
function ThingToDoWhenSlapIsCast(eventData, triggerData)
ThingToDoAtSlapPosition(eventData.stl_x, eventData.stl_y)
end
function OnGameStart()
RegisterPowerCastEvent(ThingToDoWhenSlapIsCast, "POWER_SLAP")
end
-
OnGameStart
is a fixed function that runs at level start. It is commonly used to set up triggers. -
RegisterPowerCastEvent
binds an event listener for when a spell is cast.
The function below registers an event trigger for a spell being cast:
---@param action function|string Function to call when the event occurs
---@param powerKind? power_kind Optional: Specific spell type that triggers the event
---@return Trigger
function RegisterPowerCastEvent(action, powerKind)
local trigData = {PowerKind = powerKind}
local trigger = CreateTrigger("PowerCast", action, trigData)
if powerKind then
TriggerAddCondition(trigger, function(eventData, triggerData)
return eventData.PowerKind == triggerData.PowerKind
end)
end
return trigger
end
- If
powerKind
is specified, the event will only trigger for that spell type. - The event type is "PowerCast".
the OnPowerCast
has more details on all the data that is accessible related to the event
--- Called when a spell is cast on a unit
--- @param pwkind power_kind Spell type
--- @param caster Player Caster of the spell
--- @param target_thing Creature Target creature (if applicable)
--- @param stl_x integer X-coordinate (if applicable)
--- @param stl_y integer Y-coordinate (if applicable)
--- @param splevel integer Spell level
function OnPowerCast(pwkind, caster, target_thing, stl_x, stl_y, splevel)
local eventData = {
Thing = target_thing,
PowerKind = pwkind,
Player = caster,
stl_x = stl_x,
stl_y = stl_y,
splevel = splevel
}
ProcessEvent("PowerCast", eventData)
end
Note:
- Not all spells target specific units or locations, those values would then just be
nil
all native functions can be found in this file, https://github.com/PieterVdc/keeperfx/blob/lua/config/fxdata/lua/native.lua the file makes the IDE aware of the functions DK provides, and doubles as documentation if you want to find something
the lua has support for most of the commands in the DKscript language, while also repeated in the native.lua file, the dkscript documentation could also be referenced for the overlapping ones, some commands might be changed, and some might only exist in 1 of the 2 or have an alternative way of doing so Level-Script-Commands
the flow control is also different
NEXT_COMMAND_REUSABLE
is not a thing in lua, all commands are always reusable in lua
you have to control flow in other ways, GameStart for example will generally only be run once, so all initialization code goes there
the special IF's in dkscript are also replaced with different syntax you just compare variables which you can fetch like this
- PLAYER0.MONEY
- IF_ACTION_POINT todo
- IF_AVAILABLE
PLAYER0.AVAILABLE.WORKSHOP
- IF_CONTROLS
PLAYER0.CONTROLS.IMP
- IF_SLAB_OWNER and IF_SLAB_TYPE
slb = GET_SLAB(x,y) slb.owner slb.type slb.style
- IF_ALLIED PLAYER0.ALLIED_WITH(PLAYER2)
the commands related to flags are removed to assign to a flag simply assign
PLAYER0.FLAG0 = 1
calculations can also be done in lua, so no need for COMPUTE_FLAG either
PLAYER0.CAMPAIGN_FLAG2 = PLAYER0.MONEY + 75 * PLAYER0.IMP
the assignable variables, are regular flags
eg. PLAYER0.FLAG0 = 1
campaign flags
eg. PLAYER0.CAMPAIGN_FLAG2 = 1
´
sacrificed creatures
eg. PLAYER0.SACRIFICED.IMP = 1
and temple rewarded creatures
eg. PLAYER0.REWARDED.IMP = 1
attempting to assign to a variable that's not assignable will throw an error
commands that select a creature by criteria in DKScript now take a Creature directly, to still fetch them by criteria you can use getCreatureByCriterion
all globals should be the global Game table, so it gets serialized