Lua: nhcore script with function callbacks
Adds possible callbacks for "start_new_game", "restore_old_game", "moveloop_turn", and "game_exit" which when defined, will be called from core code at the appropriate time. Adds lua hooks for dump_fmtstr (only if DUMPLOG), dnum_name, u.moves, u.uhave_amulet, and u.depth.
This commit is contained in:
74
dat/nhcore.lua
Normal file
74
dat/nhcore.lua
Normal file
@@ -0,0 +1,74 @@
|
||||
|
||||
-- This file contains lua code used by NetHack core.
|
||||
-- Is it loaded once, at game start, and kept in memory until game exit.
|
||||
|
||||
|
||||
-- This is an example of generating an external file during gameplay,
|
||||
-- which is updated periodically.
|
||||
-- Intended for public servers using dgamelaunch as their login manager.
|
||||
local prev_dgl_extrainfo = 0;
|
||||
function mk_dgl_extrainfo()
|
||||
if ((prev_dgl_extrainfo == 0) or (prev_dgl_extrainfo + 50 < u.moves)) then
|
||||
local filename = nh.dump_fmtstr("/tmp/nethack.%n.%d.log");
|
||||
local extrai, err = io.open(filename, "w");
|
||||
if extrai then
|
||||
local sortval = 0;
|
||||
local dname = nh.dnum_name(u.dnum);
|
||||
local dstr = "";
|
||||
local astr = " ";
|
||||
if u.uhave_amulet == 1 then
|
||||
sortval = sortval + 1024;
|
||||
astr = "A";
|
||||
end
|
||||
if dname == "Fort Ludios" then
|
||||
dstr = "Knx";
|
||||
sortval = sortval + 245;
|
||||
elseif dname == "The Quest" then
|
||||
dstr = "Q" .. u.dlevel;
|
||||
sortval = sortval + 250 + u.dlevel;
|
||||
elseif dname == "The Elemental Planes" then
|
||||
dstr = "End";
|
||||
sortval = sortval + 256;
|
||||
elseif dname == "Vlad's Tower" then
|
||||
dstr = "T" .. u.dlevel;
|
||||
sortval = sortval + 235 + u.depth;
|
||||
elseif dname == "Sokoban" then
|
||||
dstr = "S" .. u.dlevel;
|
||||
sortval = sortval + 225 + u.depth;
|
||||
elseif dname == "The Gnomish Mines" then
|
||||
dstr = "M" .. u.dlevel;
|
||||
sortval = sortval + 215 + u.dlevel;
|
||||
else
|
||||
dstr = "D" .. u.depth;
|
||||
sortval = sortval + u.depth;
|
||||
end
|
||||
local str = sortval .. "|" .. astr .. " " .. dstr;
|
||||
|
||||
extrai:write(str);
|
||||
extrai:close();
|
||||
else
|
||||
-- failed to open the file.
|
||||
nh.pline("Failed to open dgl extrainfo file: " .. err);
|
||||
end
|
||||
prev_dgl_extrainfo = u.moves;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Callback functions
|
||||
nhcore = {
|
||||
-- start_new_game called once, when starting a new game
|
||||
-- after "Welcome to NetHack" message has been given.
|
||||
-- start_new_game = function() nh.pline("NEW GAME!"); end,
|
||||
|
||||
-- restore_old_game called once, when restoring a saved game
|
||||
-- after "Welcome back to NetHack" message has been given.
|
||||
-- restore_old_game = function() nh.pline("RESTORED OLD GAME!"); end,
|
||||
|
||||
-- moveloop_turn is called once per turn.
|
||||
-- moveloop_turn = mk_dgl_extrainfo,
|
||||
|
||||
-- game_exit is called when the game exits (quit, saved, ...)
|
||||
-- game_exit = function() end,
|
||||
};
|
||||
|
||||
@@ -890,6 +890,7 @@ split off some of the functionality that was in makedefs (compiled-in options
|
||||
and accessed on the target platform
|
||||
replace quest.txt and associated conversion to quest.dat via makedefs with
|
||||
Lua quest texts loaded at runtime
|
||||
callback lua functions from core at certain game actions
|
||||
some altars are displayed in different colors (for tty and curses at least)
|
||||
add 'quick_farsight' option to provide some control over random clairvoyance
|
||||
where pausing to be able to browse temporarily visible aspects of the
|
||||
|
||||
29
doc/lua.adoc
29
doc/lua.adoc
@@ -14,6 +14,35 @@ Example:
|
||||
|
||||
local str = nh.an("unicorn");
|
||||
|
||||
=== dnum_name
|
||||
|
||||
Returns the full dungeon name (as defined in dungeon.lua) for the dungeon
|
||||
number given as parameter.
|
||||
|
||||
Example:
|
||||
|
||||
local dungeon_name = nh.dnum_name(u.dnum);
|
||||
|
||||
=== dump_fmtstr
|
||||
|
||||
Returns a string replacing special format chars with game data.
|
||||
Only available if NetHack was compiled with DUMPLOG.
|
||||
|
||||
|===
|
||||
| %% | literal '%'
|
||||
| %t | game start, timestamp
|
||||
| %T | current time, timestamp
|
||||
| %d | game start, YYYYMMDDhhmmss
|
||||
| %D | current time, YYYYMMDDhhmmss
|
||||
| %v | game version, eg. '3.7.0-0'
|
||||
| %u | UID
|
||||
| %n | player name
|
||||
| %N | first character of player name
|
||||
|===
|
||||
|
||||
Example:
|
||||
|
||||
local filename = nh.dump_fmtstr("/tmp/nethack.%n.%d.log");
|
||||
|
||||
=== getlin
|
||||
|
||||
|
||||
@@ -995,6 +995,9 @@ struct instance_globals {
|
||||
int lusername_size;
|
||||
#endif
|
||||
|
||||
/* nhlua.c */
|
||||
genericptr_t luacore; /* lua_State * */
|
||||
|
||||
/* o_init.c */
|
||||
short disco[NUM_OBJECTS];
|
||||
|
||||
|
||||
@@ -1657,6 +1657,9 @@ extern int l_obj_register(lua_State *);
|
||||
/* ### nhlua.c ### */
|
||||
|
||||
#if !defined(CROSSCOMPILE) || defined(CROSSCOMPILE_TARGET)
|
||||
extern void l_nhcore_init(void);
|
||||
extern void l_nhcore_done(void);
|
||||
extern void l_nhcore_call(int);
|
||||
extern lua_State * nhl_init(void);
|
||||
extern void nhl_done(lua_State *);
|
||||
extern boolean nhl_loadlua(lua_State *, const char *);
|
||||
|
||||
@@ -421,6 +421,16 @@ typedef struct sortloot_item Loot;
|
||||
#define SUPPRESS_HISTORY 4
|
||||
#define URGENT_MESSAGE 8
|
||||
|
||||
/* Lua callback functions */
|
||||
enum nhcore_calls {
|
||||
NHCORE_START_NEW_GAME = 0,
|
||||
NHCORE_RESTORE_OLD_GAME,
|
||||
NHCORE_MOVELOOP_TURN,
|
||||
NHCORE_GAME_EXIT,
|
||||
|
||||
NUM_NHCORE_CALLS
|
||||
};
|
||||
|
||||
/* Macros for messages referring to hands, eyes, feet, etc... */
|
||||
enum bodypart_types {
|
||||
ARM = 0,
|
||||
|
||||
@@ -201,6 +201,8 @@ moveloop(boolean resuming)
|
||||
/* once-per-turn things go here */
|
||||
/********************************/
|
||||
|
||||
l_nhcore_call(NHCORE_MOVELOOP_TURN);
|
||||
|
||||
if (Glib)
|
||||
glibr();
|
||||
nh_timeout();
|
||||
@@ -633,6 +635,8 @@ newgame(void)
|
||||
* any artifacts */
|
||||
u_init();
|
||||
|
||||
l_nhcore_init();
|
||||
|
||||
#ifndef NO_SIGNAL
|
||||
(void) signal(SIGINT, (SIG_RET_TYPE) done1);
|
||||
#endif
|
||||
@@ -709,6 +713,8 @@ welcome(boolean new_game) /* false => restoring an old game */
|
||||
: "%s %s, the%s %s %s, welcome back to NetHack!",
|
||||
Hello((struct monst *) 0), g.plname, buf, g.urace.adj,
|
||||
(currentgend && g.urole.name.f) ? g.urole.name.f : g.urole.name.m);
|
||||
|
||||
l_nhcore_call(new_game ? NHCORE_START_NEW_GAME : NHCORE_RESTORE_OLD_GAME);
|
||||
}
|
||||
|
||||
#ifdef POSITIONBAR
|
||||
|
||||
@@ -517,6 +517,9 @@ const struct instance_globals g_init = {
|
||||
MAX_LAN_USERNAME, /* lusername_size */
|
||||
#endif /* MAX_LAN_USERNAME */
|
||||
|
||||
/* nhlua.c */
|
||||
UNDEFINED_VALUE, /* luacore */
|
||||
|
||||
/* o_init.c */
|
||||
DUMMY, /* disco */
|
||||
|
||||
|
||||
@@ -1753,6 +1753,8 @@ void
|
||||
nh_terminate(int status)
|
||||
{
|
||||
g.program_state.in_moveloop = 0; /* won't be returning to normal play */
|
||||
|
||||
l_nhcore_call(NHCORE_GAME_EXIT);
|
||||
#ifdef MAC
|
||||
getreturn("to exit");
|
||||
#endif
|
||||
@@ -1761,6 +1763,7 @@ nh_terminate(int status)
|
||||
if (!g.program_state.panicking) {
|
||||
freedynamicdata();
|
||||
dlb_cleanup();
|
||||
l_nhcore_done();
|
||||
}
|
||||
|
||||
#ifdef VMS
|
||||
|
||||
113
src/nhlua.c
113
src/nhlua.c
@@ -14,6 +14,10 @@
|
||||
/* */
|
||||
|
||||
/* lua_CFunction prototypes */
|
||||
#ifdef DUMPLOG
|
||||
static int nhl_dump_fmtstr(lua_State *);
|
||||
#endif /* DUMPLOG */
|
||||
static int nhl_dnum_name(lua_State *);
|
||||
static int nhl_test(lua_State *);
|
||||
static int nhl_getmap(lua_State *);
|
||||
static void nhl_add_table_entry_bool(lua_State *, const char *, boolean);
|
||||
@@ -46,6 +50,68 @@ static void init_u_data(lua_State *);
|
||||
static int nhl_set_package_path(lua_State *, const char *);
|
||||
static int traceback_handler(lua_State *);
|
||||
|
||||
static const char *nhcore_call_names[NUM_NHCORE_CALLS] = {
|
||||
"start_new_game",
|
||||
"restore_old_game",
|
||||
"moveloop_turn",
|
||||
"game_exit",
|
||||
};
|
||||
static boolean nhcore_call_available[NUM_NHCORE_CALLS];
|
||||
|
||||
void
|
||||
l_nhcore_init(void)
|
||||
{
|
||||
if ((g.luacore = nhl_init()) != 0) {
|
||||
if (!nhl_loadlua(g.luacore, "nhcore.lua")) {
|
||||
g.luacore = (lua_State *) 0;
|
||||
} else {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_NHCORE_CALLS; i++)
|
||||
nhcore_call_available[i] = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
l_nhcore_done(void)
|
||||
{
|
||||
if (g.luacore) {
|
||||
nhl_done(g.luacore);
|
||||
g.luacore = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
l_nhcore_call(int callidx)
|
||||
{
|
||||
int ltyp;
|
||||
|
||||
if (callidx < 0 || callidx >= NUM_NHCORE_CALLS
|
||||
|| !g.luacore || !nhcore_call_available[callidx])
|
||||
return;
|
||||
|
||||
lua_getglobal(g.luacore, "nhcore");
|
||||
if (!lua_istable(g.luacore, -1)) {
|
||||
/*impossible("nhcore is not a lua table");*/
|
||||
nhl_done(g.luacore);
|
||||
g.luacore = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
lua_getfield(g.luacore, -1, nhcore_call_names[callidx]);
|
||||
ltyp = lua_type(g.luacore, -1);
|
||||
if (ltyp == LUA_TFUNCTION) {
|
||||
lua_remove(g.luacore, -2); /* nhcore_call_names[callidx] */
|
||||
lua_remove(g.luacore, -2); /* nhcore */
|
||||
lua_call(g.luacore, 0, 1);
|
||||
} else {
|
||||
/*impossible("nhcore.%s is not a lua function",
|
||||
nhcore_call_names[callidx]);*/
|
||||
nhcore_call_available[callidx] = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nhl_error(lua_State *L, const char *msg)
|
||||
{
|
||||
@@ -780,6 +846,40 @@ get_table_option(lua_State *L,
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef DUMPLOG
|
||||
/* local fname = dump_fmtstr("/tmp/nethack.%n.%d.log"); */
|
||||
static int
|
||||
nhl_dump_fmtstr(lua_State *L)
|
||||
{
|
||||
int argc = lua_gettop(L);
|
||||
char buf[512];
|
||||
|
||||
if (argc == 1)
|
||||
lua_pushstring(L, dump_fmtstr(luaL_checkstring(L, 1), buf, TRUE));
|
||||
else
|
||||
nhl_error(L, "Expected a string parameter");
|
||||
return 1;
|
||||
}
|
||||
#endif /* DUMPLOG */
|
||||
|
||||
/* local dungeon_name = dnum_name(u.dnum); */
|
||||
static int
|
||||
nhl_dnum_name(lua_State *L)
|
||||
{
|
||||
int argc = lua_gettop(L);
|
||||
|
||||
if (argc == 1) {
|
||||
int dnum = luaL_checkinteger(L, 1);
|
||||
|
||||
if (dnum >= 0 && dnum < g.n_dgns)
|
||||
lua_pushstring(L, g.dungeons[dnum].dname);
|
||||
else
|
||||
lua_pushstring(L, "");
|
||||
} else
|
||||
nhl_error(L, "Expected an integer parameter");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
test( { x = 123, y = 456 } );
|
||||
*/
|
||||
@@ -831,6 +931,10 @@ static const struct luaL_Reg nhl_functions[] = {
|
||||
{"parse_config", nhl_parse_config},
|
||||
{"get_config", nhl_get_config},
|
||||
{"get_config_errors", l_get_config_errors},
|
||||
#ifdef DUMPLOG
|
||||
{"dump_fmtstr", nhl_dump_fmtstr},
|
||||
#endif /* DUMPLOG */
|
||||
{"dnum_name", nhl_dnum_name},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
@@ -927,6 +1031,15 @@ nhl_meta_u_index(lua_State *L)
|
||||
} else if (!strcmp(tkey, "role")) {
|
||||
lua_pushstring(L, g.urole.name.m);
|
||||
return 1;
|
||||
} else if (!strcmp(tkey, "moves")) {
|
||||
lua_pushinteger(L, g.moves);
|
||||
return 1;
|
||||
} else if (!strcmp(tkey, "uhave_amulet")) {
|
||||
lua_pushinteger(L, u.uhave.amulet);
|
||||
return 1;
|
||||
} else if (!strcmp(tkey, "depth")) {
|
||||
lua_pushinteger(L, depth(&u.uz));
|
||||
return 1;
|
||||
}
|
||||
|
||||
nhl_error(L, "Unknown u table index");
|
||||
|
||||
@@ -86,7 +86,7 @@ DATHELP = help hh cmdhelp keyhelp history opthelp wizhelp
|
||||
SPEC_LEVS = asmodeus.lua baalz.lua bigrm-*.lua castle.lua fakewiz?.lua \
|
||||
juiblex.lua knox.lua medusa-?.lua minend-?.lua minefill.lua \
|
||||
minetn-?.lua oracle.lua orcus.lua sanctum.lua soko?-?.lua \
|
||||
tower?.lua valley.lua wizard?.lua nhlib.lua themerms.lua \
|
||||
tower?.lua valley.lua wizard?.lua nhcore.lua nhlib.lua themerms.lua \
|
||||
astral.lua air.lua earth.lua fire.lua water.lua
|
||||
QUEST_LEVS = ???-goal.lua ???-fil?.lua ???-loca.lua ???-strt.lua
|
||||
|
||||
|
||||
@@ -1140,6 +1140,7 @@
|
||||
"$(NH_DAT_DIR)/Mon-goal.lua",
|
||||
"$(NH_DAT_DIR)/Mon-loca.lua",
|
||||
"$(NH_DAT_DIR)/Mon-strt.lua",
|
||||
"$(NH_DAT_DIR)/nhcore.lua",
|
||||
"$(NH_DAT_DIR)/nhlib.lua",
|
||||
"$(NH_DAT_DIR)/oracle.lua",
|
||||
"$(NH_DAT_DIR)/orcus.lua",
|
||||
@@ -1206,7 +1207,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "cd \"${NH_DAT_DIR}\"\n\"${NH_UTIL_DIR}\"/dlb cf nhdat help hh cmdhelp keyhelp history opthelp wizhelp dungeon.lua tribute asmodeus.lua baalz.lua bigrm-*.lua castle.lua fakewiz?.lua juiblex.lua knox.lua medusa-?.lua minend-?.lua minefill.lua minetn-?.lua oracle.lua orcus.lua sanctum.lua soko?-?.lua tower?.lua valley.lua wizard?.lua nhlib.lua themerms.lua astral.lua air.lua earth.lua fire.lua water.lua ???-goal.lua ???-fil?.lua ???-loca.lua ???-strt.lua bogusmon data engrave epitaph oracles options quest.lua rumors\n";
|
||||
shellScript = "cd \"${NH_DAT_DIR}\"\n\"${NH_UTIL_DIR}\"/dlb cf nhdat help hh cmdhelp keyhelp history opthelp wizhelp dungeon.lua tribute asmodeus.lua baalz.lua bigrm-*.lua castle.lua fakewiz?.lua juiblex.lua knox.lua medusa-?.lua minend-?.lua minefill.lua minetn-?.lua oracle.lua orcus.lua sanctum.lua soko?-?.lua tower?.lua valley.lua wizard?.lua nhcore.lua nhlib.lua themerms.lua astral.lua air.lua earth.lua fire.lua water.lua ???-goal.lua ???-fil?.lua ???-loca.lua ???-strt.lua bogusmon data engrave epitaph oracles options quest.lua rumors\n";
|
||||
};
|
||||
3192867021A39F6A00325BEB /* Install */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
|
||||
Reference in New Issue
Block a user