Lua: Persistent variables
Add a way for the lua scripts to set and retrieve variables that are persistent - saved and restored with the game. Invalidates saves.
This commit is contained in:
@@ -4,6 +4,15 @@
|
||||
-- This file contains lua code used by NetHack core.
|
||||
-- Is it loaded once, at game start, and kept in memory until game exit.
|
||||
|
||||
-- Data in nh_lua_variables table can be set and queried with nh.variable()
|
||||
-- This table is saved and restored along with the game.
|
||||
nh_lua_variables = {
|
||||
};
|
||||
|
||||
-- wrapper to simplify calling from nethack core
|
||||
function get_variables_string()
|
||||
return "nh_lua_variables=" .. table_stringify(nh_lua_variables) .. ";";
|
||||
end
|
||||
|
||||
-- This is an example of generating an external file during gameplay,
|
||||
-- which is updated periodically.
|
||||
|
||||
@@ -107,3 +107,35 @@ end
|
||||
function pline(fmt, ...)
|
||||
nh.pline(string.format(fmt, table.unpack({...})));
|
||||
end
|
||||
|
||||
-- wrapper to make calling from nethack core easier
|
||||
function nh_set_variables_string(key, tbl)
|
||||
return "nh_lua_variables[\"" .. key .. "\"]=" .. table_stringify(tbl) .. ";";
|
||||
end
|
||||
|
||||
-- wrapper to make calling from nethack core easier
|
||||
function nh_get_variables_string(tbl)
|
||||
return "return " .. table_stringify(tbl) .. ";";
|
||||
end
|
||||
|
||||
-- return the (simple) table tbl converted into a string
|
||||
function table_stringify(tbl)
|
||||
local str = "";
|
||||
for key, value in pairs(tbl) do
|
||||
local typ = type(value);
|
||||
if (typ == "table") then
|
||||
str = str .. "[\"" .. key .. "\"]=" .. table_stringify(value);
|
||||
elseif (typ == "string") then
|
||||
str = str .. "[\"" .. key .. "\"]=[[" .. value .. "]]";
|
||||
elseif (typ == "boolean") then
|
||||
str = str .. "[\"" .. key .. "\"]=" .. tostring(value);
|
||||
elseif (typ == "number") then
|
||||
str = str .. "[\"" .. key .. "\"]=" .. value;
|
||||
elseif (typ == "nil") then
|
||||
str = str .. "[\"" .. key .. "\"]=nil";
|
||||
end
|
||||
str = str .. ",";
|
||||
end
|
||||
-- pline("table_stringify:(%s)", str);
|
||||
return "{" .. str .. "}";
|
||||
end
|
||||
|
||||
13
doc/lua.adoc
13
doc/lua.adoc
@@ -376,6 +376,19 @@ Example:
|
||||
nh.stop_timer_at({x=5,y=6}, "melt-ice");
|
||||
|
||||
|
||||
=== variable
|
||||
|
||||
Set or get a global variable. These are persistent, saved and restored along with the game.
|
||||
Supports only strings, booleans, numbers, or tables.
|
||||
|
||||
Example:
|
||||
|
||||
nh.variable("test", 10);
|
||||
local ten = nh.variable("test");
|
||||
nh.variable("tbl", { a = 1, b = "foo" });
|
||||
local tbl = nh.variable("tbl");
|
||||
|
||||
|
||||
=== verbalize
|
||||
|
||||
Show the text in the message area as if someone said it, obeying eg. hero's deafness.
|
||||
|
||||
@@ -1839,6 +1839,9 @@ extern void l_nhcore_call(int);
|
||||
extern lua_State * nhl_init(nhl_sandbox_info *);
|
||||
extern void nhl_done(lua_State *);
|
||||
extern boolean nhl_loadlua(lua_State *, const char *);
|
||||
extern char *get_nh_lua_variables(void);
|
||||
extern void save_luadata(NHFILE *);
|
||||
extern void restore_luadata(NHFILE *);
|
||||
extern int nhl_pcall(lua_State *, int, int);
|
||||
extern boolean load_lua(const char *, nhl_sandbox_info *);
|
||||
ATTRNORETURN extern void nhl_error(lua_State *, const char *) NORETURN;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* Incrementing EDITLEVEL can be used to force invalidation of old bones
|
||||
* and save files.
|
||||
*/
|
||||
#define EDITLEVEL 68
|
||||
#define EDITLEVEL 69
|
||||
|
||||
/*
|
||||
* Development status possibilities.
|
||||
|
||||
134
src/nhlua.c
134
src/nhlua.c
@@ -1030,6 +1030,139 @@ nhl_dnum_name(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* set or get variables which are saved and restored along the game.
|
||||
nh.variable("test", 10);
|
||||
local ten = nh.variable("test"); */
|
||||
static int
|
||||
nhl_variable(lua_State *L)
|
||||
{
|
||||
int argc = lua_gettop(L);
|
||||
int typ;
|
||||
const char *key;
|
||||
|
||||
if (!gl.luacore) {
|
||||
nhl_error(L, "nh luacore not inited");
|
||||
return 0;
|
||||
}
|
||||
|
||||
lua_getglobal(gl.luacore, "nh_lua_variables");
|
||||
if (!lua_istable(gl.luacore, -1)) {
|
||||
impossible("nh_lua_variables is not a lua table");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (argc == 1) {
|
||||
key = luaL_checkstring(L, 1);
|
||||
|
||||
lua_getfield(gl.luacore, -1, key);
|
||||
typ = lua_type(gl.luacore, -1);
|
||||
if (typ == LUA_TSTRING)
|
||||
lua_pushstring(L, lua_tostring(gl.luacore, -1));
|
||||
else if (typ == LUA_TNIL)
|
||||
lua_pushnil(L);
|
||||
else if (typ == LUA_TBOOLEAN)
|
||||
lua_pushboolean(L, lua_toboolean(gl.luacore, -1));
|
||||
else if (typ == LUA_TNUMBER)
|
||||
lua_pushinteger(L, lua_tointeger(gl.luacore, -1));
|
||||
else if (typ == LUA_TTABLE) {
|
||||
lua_getglobal(gl.luacore, "nh_get_variables_string");
|
||||
lua_pushvalue(gl.luacore, -2);
|
||||
nhl_pcall(gl.luacore, 1, 1);
|
||||
luaL_loadstring(L, lua_tostring(gl.luacore, -1));
|
||||
nhl_pcall(L, 0, 1);
|
||||
} else
|
||||
nhl_error(L, "Cannot get variable of that type");
|
||||
return 1;
|
||||
} else if (argc == 2) {
|
||||
/* set nh_lua_variables[key] = value;
|
||||
nh.variable("key", value); */
|
||||
key = luaL_checkstring(L, 1);
|
||||
//pline("SETVAR:%s", key);
|
||||
typ = lua_type(L, -1);
|
||||
|
||||
if (typ == LUA_TSTRING) {
|
||||
lua_pushstring(gl.luacore, lua_tostring(L, -1));
|
||||
lua_setfield(gl.luacore, -2, key);
|
||||
} else if (typ == LUA_TNIL) {
|
||||
lua_pushnil(gl.luacore);
|
||||
lua_setfield(gl.luacore, -2, key);
|
||||
} else if (typ == LUA_TBOOLEAN) {
|
||||
lua_pushboolean(gl.luacore, lua_toboolean(L, -1));
|
||||
lua_setfield(gl.luacore, -2, key);
|
||||
} else if (typ == LUA_TNUMBER) {
|
||||
lua_pushinteger(gl.luacore, lua_tointeger(L, -1));
|
||||
lua_setfield(gl.luacore, -2, key);
|
||||
} else if (typ == LUA_TTABLE) {
|
||||
lua_getglobal(L, "nh_set_variables_string");
|
||||
lua_pushstring(L, key);
|
||||
lua_pushvalue(L, -3); /* copy value to top */
|
||||
nhl_pcall(L, 2, 1);
|
||||
luaL_loadstring(gl.luacore, lua_tostring(L, -1));
|
||||
nhl_pcall(gl.luacore, 0, 0);
|
||||
} else
|
||||
nhl_error(L, "Cannot set variable of that type");
|
||||
return 0;
|
||||
} else
|
||||
nhl_error(L, "Wrong number of arguments");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* return nh_lua_variable lua table as a string */
|
||||
char *
|
||||
get_nh_lua_variables(void)
|
||||
{
|
||||
char *key = NULL;
|
||||
|
||||
if (!gl.luacore) {
|
||||
nhl_error(gl.luacore, "nh luacore not inited");
|
||||
return key;
|
||||
}
|
||||
|
||||
lua_getglobal(gl.luacore, "nh_lua_variables");
|
||||
if (!lua_istable(gl.luacore, -1)) {
|
||||
impossible("nh_lua_variables is not a lua table");
|
||||
return key;
|
||||
}
|
||||
|
||||
lua_getglobal(gl.luacore, "get_variables_string");
|
||||
if (lua_type(gl.luacore, -1) == LUA_TFUNCTION) {
|
||||
if (nhl_pcall(gl.luacore, 0, 1)) {
|
||||
impossible("Lua error: %s", lua_tostring(gl.luacore, -1));
|
||||
return key;
|
||||
}
|
||||
key = dupstr(lua_tostring(gl.luacore, -1));
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
/* save nh_lua_variables table to file */
|
||||
void
|
||||
save_luadata(NHFILE *nhfp)
|
||||
{
|
||||
char *lua_data = get_nh_lua_variables();
|
||||
long lua_data_len = strlen(lua_data) + 1;
|
||||
|
||||
bwrite(nhfp->fd, (genericptr_t) &lua_data_len, sizeof lua_data_len);
|
||||
bwrite(nhfp->fd, (genericptr_t) lua_data, strlen(lua_data) + 1);
|
||||
free(lua_data);
|
||||
}
|
||||
|
||||
/* restore nh_lua_variables table from file */
|
||||
void
|
||||
restore_luadata(NHFILE *nhfp)
|
||||
{
|
||||
long lua_data_len;
|
||||
char *lua_data;
|
||||
|
||||
mread(nhfp->fd, (genericptr_t) &lua_data_len, sizeof lua_data_len);
|
||||
lua_data = (char *) alloc(lua_data_len);
|
||||
mread(nhfp->fd, (genericptr_t) lua_data, lua_data_len);
|
||||
if (!gl.luacore)
|
||||
l_nhcore_init();
|
||||
luaL_loadstring(gl.luacore, lua_data);
|
||||
nhl_pcall(gl.luacore, 0, 0);
|
||||
}
|
||||
|
||||
/* local stairs = stairways(); */
|
||||
static int
|
||||
nhl_stairways(lua_State *L)
|
||||
@@ -1319,6 +1452,7 @@ static const struct luaL_Reg nhl_functions[] = {
|
||||
{"dump_fmtstr", nhl_dump_fmtstr},
|
||||
#endif /* DUMPLOG */
|
||||
{"dnum_name", nhl_dnum_name},
|
||||
{"variable", nhl_variable},
|
||||
{"stairways", nhl_stairways},
|
||||
{"pushkey", nhl_pushkey},
|
||||
{"doturn", nhl_doturn},
|
||||
|
||||
@@ -688,6 +688,7 @@ restgamestate(NHFILE* nhfp, unsigned int* stuckid, unsigned int* steedid)
|
||||
restnames(nhfp);
|
||||
restore_msghistory(nhfp);
|
||||
restore_gamelog(nhfp);
|
||||
restore_luadata(nhfp);
|
||||
/* must come after all mons & objs are restored */
|
||||
relink_timers(FALSE);
|
||||
relink_light_sources(FALSE);
|
||||
|
||||
@@ -344,6 +344,7 @@ savegamestate(NHFILE *nhfp)
|
||||
savenames(nhfp);
|
||||
save_msghistory(nhfp);
|
||||
save_gamelog(nhfp);
|
||||
save_luadata(nhfp);
|
||||
if (nhfp->structlevel)
|
||||
bflush(nhfp->fd);
|
||||
gp.program_state.saving--;
|
||||
|
||||
Reference in New Issue
Block a user