WDL ~ Lua Scripting and WDL - uchicago-cs/chiventure GitHub Wiki

Based on the new WDL++ specification written by the WDL team, this document describes on a high-level how lua scripts can be implemented to allow for action sequence chaining that could be useful for custom actions.

Below is an example of how custom actions can be implemented in WDL++ (taken from Feature Wishlist wiki page (https://github.com/uchicago-cs/chiventure/wiki/Feature-Wishlist#custom-actions)

{
"action": "LIFESTEAL ", // designate the LIFESTEAL command with 1 variable- target
"help": "Steals 2-10 health from the target and restores it to the user", // for displaying in the help screen
"environments": [ "combat" ], // allow this command only in a combat environment
"sequence":
[
{ "block": "assert self mana 4"}, // see if the user has 4+ mana left, otherwise exit the sequence (self refers to the user)
{ "block": "stat self mana - 4"}, // see if the user has 4+ mana left, otherwise exit the sequence
{ "block": "generate_rand i 2 10"}, // generate a random number between 2 and 10 and store in i
{ "block": "stat target health - i" }, // decrease the target's health by i
{ "block": "stat self health + i" }, // increase the caster's health by i
]
}

According to WDL++ team, we can call Lua script to execute a block of action by passing in path to .lua file and arguments (e.g: name of the action we want Lua to execute) to pass into Lua functions:

{ "action": "act_PUSH",
"sequence": [
{"block": "if", "params": "inventory has item_SPINACH"},
{"block": "set", "params": "obj_CHAIR flipped"},
{"block": "say", "params": "'You pushed the chair. It flipped!'"},
{"block": "else", "params": ""},
{"block": "say", "params": "'Couldn't push the chair. Spinach needed.''"},
{"block": "endif", "params": ""},
{"block": "say", "params": "'This is printed regardless of push success.'"},
{"block": "lua", "params": "'path/to/example.lua' arg0 arg1 arg2 arg3"}
]
}

To use Lua, we can have a C module that deals with loading and running Lua script:
#include "lauxlib.h"
#include "lua.h"
#include "lualib.h"

A struct that holds lua_State, which is like a stack. All data exchange from Lua to C and from C to Lua occurs through this stack

typedef struct _lua_state {
lua_State *L;
} Lua

This function loads the lua_State from lua file

lua_State *LoadLua (char *filename) {
lua_State *L = luaL_newstate();
luaL_openlibs(L);
luaL_dofile(L, "filename.lua");
lua_setglobal(L, "filename");
lua_settop(L, 0);
return L;
}

This function goes into lua, find the function that we want Lua to operate, pass in the objects or data we want Lua to operate on, and return the data that that Lua function changes. This is just a very high-level view to see how WDL++ parsing can work to produce arguments for this runLuaFunction. Eventually, if we want Lua to change different things about the game (action, items, dialogue), we would have to think more about what data from the game we want to pass to Lua

void* runLuaFunction (char filename, char functionname, void* userdata) {
Lua *L = malloc(sizeof (Lua));
Lua->L = LoadLua (filename);
lua_getglobal(Lua->L, "functionname"); // push the function on top of Lua stack
lua_pushuserdata (Lua->L, userdata); // push userdata on top of Lua stack
lua_call (Lua->L, int numArguments, int numReturnValues); // call the function
return lua_touserdata (Lua->L, int stackLocation); // extract the data off Lua stack
}

In accordance to WDL++ team’s visualisation of how Lua scripting could work in sequence action chaining:
{"block": "lua", "params": "'path/to/example.lua' arg0 arg1 arg2 arg3"}
We can change it to something like this so WDL++ file can parse these parameters and extract them into runLuaFunction function:
{"block": "lua", "params": "'path/to/example.lua' 'functionname' arg0"}

Lua scripting can be implemented in other parts of the game other than custom actions, such as NPC and Game State using the same WDL++ interaction to create new game states and NPC dialogue.

⚠️ **GitHub.com Fallback** ⚠️