diff --git a/src/f_finale.c b/src/f_finale.c index e5ed272d4..aecf79fc2 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -41,6 +41,7 @@ #include "console.h" #include "lua_hud.h" +#include "lua_hook.h" // Stage of animation: // 0 = text, 1 = art screen @@ -3421,7 +3422,7 @@ void F_TitleScreenDrawer(void) } luahook: - LUAh_TitleHUD(); + LUA_HUDHOOK(title); } // separate animation timer for backgrounds, since we also count diff --git a/src/hu_stuff.c b/src/hu_stuff.c index d8891d508..f4c5e4c3b 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -2104,7 +2104,7 @@ void HU_Drawer(void) } else HU_DrawCoopOverlay(); - LUAh_ScoresHUD(); + LUA_HUDHOOK(scores); } if (gamestate != GS_LEVEL) diff --git a/src/lua_hook.h b/src/lua_hook.h index 0c79863d6..531d16288 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -79,6 +79,13 @@ automatically. X (LinedefExecute),\ X (ShouldJingleContinue),/* should jingle of the given music continue playing */\ +#define HUD_HOOK_LIST(X) \ + X (game),\ + X (scores),/* emblems/multiplayer list */\ + X (title),/* titlescreen */\ + X (titlecard),\ + X (intermission),\ + /* I chose to access the hook enums through a macro as well. This could provide a hint to lookup the macro's definition instead of the enum's definition. @@ -89,18 +96,26 @@ grepped and found in the lists above. #define MOBJ_HOOK(name) mobjhook_ ## name #define HOOK(name) hook_ ## name +#define HUD_HOOK(name) hudhook_ ## name #define STRING_HOOK(name) stringhook_ ## name -enum { MOBJ_HOOK_LIST (MOBJ_HOOK) MOBJ_HOOK(MAX) }; -enum { HOOK_LIST (HOOK) HOOK(MAX) }; -enum { STRING_HOOK_LIST (STRING_HOOK) STRING_HOOK(MAX) }; +#define ENUM(X) enum { X ## _LIST (X) X(MAX) } + +ENUM (MOBJ_HOOK); +ENUM (HOOK); +ENUM (HUD_HOOK); +ENUM (STRING_HOOK); + +#undef ENUM /* dead simple, LUA_HOOK(GameQuit) */ #define LUA_HOOK(type) LUA_HookVoid(HOOK(type)) +#define LUA_HUDHOOK(type) LUA_HookHUD(HUD_HOOK(type)) extern boolean hook_cmd_running; void LUA_HookVoid(int hook); +void LUA_HookHUD(int hook); int LUA_HookMobj(mobj_t *, int hook); int LUA_Hook2Mobj(mobj_t *, mobj_t *, int hook); diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index de5702209..32b5e52fb 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -31,12 +31,15 @@ ABSTRACTION ========================================================================= */ -static const char * const mobjHookNames[] = { MOBJ_HOOK_LIST (TOSTR) NULL }; -static const char * const hookNames[] = { HOOK_LIST (TOSTR) NULL }; +#define LIST(id, M) \ + static const char * const id [] = { M (TOSTR) NULL } -static const char * const stringHookNames[] = { - STRING_HOOK_LIST (TOSTR) NULL -}; +LIST (mobjHookNames, MOBJ_HOOK_LIST); +LIST (hookNames, HOOK_LIST); +LIST (hudHookNames, HUD_HOOK_LIST); +LIST (stringHookNames, STRING_HOOK_LIST); + +#undef LIST typedef struct { int numHooks; @@ -49,6 +52,7 @@ typedef struct { } stringhook_t; static hook_t hookIds[HOOK(MAX)]; +static hook_t hudHookIds[HUD_HOOK(MAX)]; static hook_t mobjHookIds[NUMMOBJTYPES][MOBJ_HOOK(MAX)]; // Lua tables are used to lookup string hook ids. @@ -56,6 +60,7 @@ static stringhook_t stringHooks[STRING_HOOK(MAX)]; // This will be indexed by hook id, the value of which fetches the registry. static int * hookRefs; +static int nextid; // After a hook errors once, don't print the error again. static UINT8 * hooksErrored; @@ -104,13 +109,13 @@ static void get_table(lua_State *L) lua_remove(L, -2); } -static void add_hook_to_table(lua_State *L, int id, int n) +static void add_hook_to_table(lua_State *L, int n) { - lua_pushnumber(L, id); + lua_pushnumber(L, nextid); lua_rawseti(L, -2, n); } -static void add_string_hook(lua_State *L, int type, int id) +static void add_string_hook(lua_State *L, int type) { stringhook_t * hook = &stringHooks[type]; @@ -146,33 +151,54 @@ static void add_string_hook(lua_State *L, int type, int id) { lua_pushstring(L, string); get_table(L); - add_hook_to_table(L, id, 1 + lua_objlen(L, -1)); + add_hook_to_table(L, 1 + lua_objlen(L, -1)); } else - add_hook_to_table(L, id, ++hook->numGeneric); + add_hook_to_table(L, ++hook->numGeneric); } -static void add_hook(hook_t *map, int id) +static void add_hook(hook_t *map) { Z_Realloc(map->ids, (map->numHooks + 1) * sizeof *map->ids, PU_STATIC, &map->ids); - map->ids[map->numHooks++] = id; + map->ids[map->numHooks++] = nextid; } -static void add_mobj_hook(lua_State *L, int hook_type, int id) +static void add_mobj_hook(lua_State *L, int hook_type) { mobjtype_t mobj_type = luaL_optnumber(L, 3, MT_NULL); luaL_argcheck(L, mobj_type < NUMMOBJTYPES, 3, "invalid mobjtype_t"); - add_hook(&mobjHookIds[mobj_type][hook_type], id); + add_hook(&mobjHookIds[mobj_type][hook_type]); +} + +static void add_hud_hook(lua_State *L, int idx) +{ + add_hook(&hudHookIds[luaL_checkoption(L, + idx, "game", hudHookNames)]); +} + +static void add_hook_ref(lua_State *L, int idx) +{ + if (!(nextid & 7)) + { + Z_Realloc(hooksErrored, + BIT_ARRAY_SIZE (nextid + 1) * sizeof *hooksErrored, + PU_STATIC, &hooksErrored); + hooksErrored[nextid >> 3] = 0; + } + + Z_Realloc(hookRefs, (nextid + 1) * sizeof *hookRefs, PU_STATIC, &hookRefs); + + // set the hook function in the registry. + lua_pushvalue(L, idx); + hookRefs[nextid++] = luaL_ref(L, LUA_REGISTRYINDEX); } // Takes hook, function, and additional arguments (mobj type to act on, etc.) static int lib_addHook(lua_State *L) { - static int nextid; - const char * name; int type; @@ -185,34 +211,26 @@ static int lib_addHook(lua_State *L) /* this is a very special case */ if (( type = hook_in_list(name, stringHookNames) ) < STRING_HOOK(MAX)) { - add_string_hook(L, type, nextid); + add_string_hook(L, type); } else if (( type = hook_in_list(name, mobjHookNames) ) < MOBJ_HOOK(MAX)) { - add_mobj_hook(L, type, nextid); + add_mobj_hook(L, type); } else if (( type = hook_in_list(name, hookNames) ) < HOOK(MAX)) { - add_hook(&hookIds[type], nextid); + add_hook(&hookIds[type]); + } + else if (strcmp(name, "HUD") == 0) + { + add_hud_hook(L, 3); } else { return luaL_argerror(L, 1, lua_pushfstring(L, "invalid hook " LUA_QS, name)); } - if (!(nextid & 7)) - { - Z_Realloc(hooksErrored, - BIT_ARRAY_SIZE (nextid + 1) * sizeof *hooksErrored, - PU_STATIC, &hooksErrored); - hooksErrored[nextid >> 3] = 0; - } - - Z_Realloc(hookRefs, (nextid + 1) * sizeof *hookRefs, PU_STATIC, &hookRefs); - - // set the hook function in the registry. - lua_pushvalue(L, 2);/* the function */ - hookRefs[nextid++] = luaL_ref(L, LUA_REGISTRYINDEX); + add_hook_ref(L, 2);/* the function */ return 0; } @@ -227,6 +245,23 @@ int LUA_HookLib(lua_State *L) return 0; } +/* TODO: remove in next backwards incompatible release */ +#if MODID == 18 +int lib_hudadd(lua_State *L);/* yeah compiler */ +int lib_hudadd(lua_State *L) +{ + if (!lua_lumploading) + return luaL_error(L, "This function cannot be called from within a hook or coroutine!"); + + luaL_checktype(L, 1, LUA_TFUNCTION); + + add_hud_hook(L, 2); + add_hook_ref(L, 1); + + return 0; +} +#endif + typedef struct Hook_State Hook_State; typedef void (*Hook_Callback)(Hook_State *); @@ -259,11 +294,16 @@ static void push_string(void) lua_pushvalue(gL, SINDEX); } -static boolean start_hook_stack(void) +static boolean begin_hook_values(Hook_State *hook) +{ + hook->top = lua_gettop(gL); + return true; +} + +static void start_hook_stack(void) { lua_settop(gL, 0); push_error_handler(); - return true; } static boolean init_hook_type @@ -279,10 +319,11 @@ static boolean init_hook_type if (nonzero) { + start_hook_stack(); hook->hook_type = hook_type; hook->mobj_type = mobj_type; hook->string = string; - return start_hook_stack(); + return begin_hook_values(hook); } else return false; @@ -323,7 +364,7 @@ static boolean prepare_string_hook stringHooks[hook_type].ref)) { lua_pushstring(gL, string); - return true; + return begin_hook_values(hook); } else return false; @@ -332,12 +373,12 @@ static boolean prepare_string_hook static void init_hook_call ( Hook_State * hook, - int values, int results, Hook_Callback results_handler ){ - hook->top = lua_gettop(gL); - hook->values = values; + const int top = lua_gettop(gL); + hook->values = (top - hook->top); + hook->top = top; hook->results = results; hook->results_handler = results_handler; } @@ -447,13 +488,12 @@ static int call_mobj_type_hooks(Hook_State *hook, mobjtype_t mobj_type) static int call_hooks ( Hook_State * hook, - int values, int results, Hook_Callback results_handler ){ int calls = 0; - init_hook_call(hook, values, results, results_handler); + init_hook_call(hook, results, results_handler); if (hook->string) { @@ -514,7 +554,7 @@ int LUA_HookMobj(mobj_t *mobj, int hook_type) if (prepare_mobj_hook(&hook, false, hook_type, mobj->type)) { LUA_PushUserdata(gL, mobj, META_MOBJ); - call_hooks(&hook, 1, 1, res_true); + call_hooks(&hook, 1, res_true); } return hook.status; } @@ -526,7 +566,7 @@ int LUA_Hook2Mobj(mobj_t *t1, mobj_t *t2, int hook_type) { LUA_PushUserdata(gL, t1, META_MOBJ); LUA_PushUserdata(gL, t2, META_MOBJ); - call_hooks(&hook, 2, 1, res_force); + call_hooks(&hook, 1, res_force); } return hook.status; } @@ -535,7 +575,7 @@ void LUA_HookVoid(int type) { Hook_State hook; if (prepare_hook(&hook, 0, type)) - call_hooks(&hook, 0, 0, res_none); + call_hooks(&hook, 0, res_none); } void LUA_HookInt(INT32 number, int hook_type) @@ -544,7 +584,7 @@ void LUA_HookInt(INT32 number, int hook_type) if (prepare_hook(&hook, 0, hook_type)) { lua_pushinteger(gL, number); - call_hooks(&hook, 1, 0, res_none); + call_hooks(&hook, 0, res_none); } } @@ -554,7 +594,7 @@ void LUA_HookBool(boolean value, int hook_type) if (prepare_hook(&hook, 0, hook_type)) { lua_pushboolean(gL, value); - call_hooks(&hook, 1, 0, res_none); + call_hooks(&hook, 0, res_none); } } @@ -564,7 +604,7 @@ int LUA_HookPlayer(player_t *player, int hook_type) if (prepare_hook(&hook, false, hook_type)) { LUA_PushUserdata(gL, player, META_PLAYER); - call_hooks(&hook, 1, 1, res_true); + call_hooks(&hook, 1, res_true); } return hook.status; } @@ -580,7 +620,7 @@ int LUA_HookTiccmd(player_t *player, ticcmd_t *cmd, int hook_type) if (hook_type == HOOK(PlayerCmd)) hook_cmd_running = true; - call_hooks(&hook, 2, 1, res_true); + call_hooks(&hook, 1, res_true); if (hook_type == HOOK(PlayerCmd)) hook_cmd_running = false; @@ -594,11 +634,29 @@ int LUA_HookKey(event_t *event, int hook_type) if (prepare_hook(&hook, false, hook_type)) { LUA_PushUserdata(gL, event, META_KEYEVENT); - call_hooks(&hook, 1, 1, res_true); + call_hooks(&hook, 1, res_true); } return hook.status; } +void LUA_HookHUD(int hook_type) +{ + const hook_t * map = &hudHookIds[hook_type]; + Hook_State hook; + if (map->numHooks > 0) + { + start_hook_stack(); + begin_hook_values(&hook); + + LUA_SetHudHook(hook_type); + + hud_running = true; // local hook + init_hook_call(&hook, 0, res_none); + call_mapped(&hook, map); + hud_running = false; + } +} + /* ========================================================================= SPECIALIZED HOOKS ========================================================================= */ @@ -618,7 +676,7 @@ void LUA_HookThinkFrame(void) if (prepare_hook(&hook, 0, type)) { - init_hook_call(&hook, 0, 0, res_none); + init_hook_call(&hook, 0, res_none); for (k = 0; k < map->numHooks; ++k) { @@ -653,7 +711,7 @@ int LUA_HookMobjLineCollide(mobj_t *mobj, line_t *line) { LUA_PushUserdata(gL, mobj, META_MOBJ); LUA_PushUserdata(gL, line, META_LINE); - call_hooks(&hook, 2, 1, res_force); + call_hooks(&hook, 1, res_force); } return hook.status; } @@ -665,7 +723,7 @@ int LUA_HookTouchSpecial(mobj_t *special, mobj_t *toucher) { LUA_PushUserdata(gL, special, META_MOBJ); LUA_PushUserdata(gL, toucher, META_MOBJ); - call_hooks(&hook, 2, 1, res_true); + call_hooks(&hook, 1, res_true); } return hook.status; } @@ -678,7 +736,6 @@ static int damage_hook INT32 damage, UINT8 damagetype, int hook_type, - int values, Hook_Callback results_handler ){ Hook_State hook; @@ -687,10 +744,10 @@ static int damage_hook LUA_PushUserdata(gL, target, META_MOBJ); LUA_PushUserdata(gL, inflictor, META_MOBJ); LUA_PushUserdata(gL, source, META_MOBJ); - if (values == 5) + if (hook_type != MOBJ_HOOK(MobjDeath)) lua_pushinteger(gL, damage); lua_pushinteger(gL, damagetype); - call_hooks(&hook, values, 1, results_handler); + call_hooks(&hook, 1, results_handler); } return hook.status; } @@ -698,19 +755,19 @@ static int damage_hook int LUA_HookShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype) { return damage_hook(target, inflictor, source, damage, damagetype, - MOBJ_HOOK(ShouldDamage), 5, res_force); + MOBJ_HOOK(ShouldDamage), res_force); } int LUA_HookMobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype) { return damage_hook(target, inflictor, source, damage, damagetype, - MOBJ_HOOK(MobjDamage), 5, res_true); + MOBJ_HOOK(MobjDamage), res_true); } int LUA_HookMobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damagetype) { return damage_hook(target, inflictor, source, 0, damagetype, - MOBJ_HOOK(MobjDeath), 4, res_true); + MOBJ_HOOK(MobjDeath), res_true); } int LUA_HookMobjMoveBlocked(mobj_t *t1, mobj_t *t2, line_t *line) @@ -721,7 +778,7 @@ int LUA_HookMobjMoveBlocked(mobj_t *t1, mobj_t *t2, line_t *line) LUA_PushUserdata(gL, t1, META_MOBJ); LUA_PushUserdata(gL, t2, META_MOBJ); LUA_PushUserdata(gL, line, META_LINE); - call_hooks(&hook, 3, 1, res_true); + call_hooks(&hook, 1, res_true); } return hook.status; } @@ -796,7 +853,7 @@ int LUA_HookBotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd) hook.userdata = &botai; - call_hooks(&hook, 2, 8, res_botai); + call_hooks(&hook, 8, res_botai); } return hook.status; @@ -811,7 +868,7 @@ void LUA_HookLinedefExecute(line_t *line, mobj_t *mo, sector_t *sector) LUA_PushUserdata(gL, line, META_LINE); LUA_PushUserdata(gL, mo, META_MOBJ); LUA_PushUserdata(gL, sector, META_SECTOR); - ps_lua_mobjhooks += call_hooks(&hook, 3, 0, res_none); + ps_lua_mobjhooks += call_hooks(&hook, 0, res_none); } } @@ -835,7 +892,7 @@ int LUA_HookPlayerMsg(int source, int target, int flags, char *msg) LUA_PushUserdata(gL, &players[target-1], META_PLAYER); // target } lua_pushstring(gL, msg); // msg - call_hooks(&hook, 4, 1, res_true); + call_hooks(&hook, 1, res_true); } return hook.status; } @@ -849,7 +906,7 @@ int LUA_HookHurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 d LUA_PushUserdata(gL, inflictor, META_MOBJ); LUA_PushUserdata(gL, source, META_MOBJ); lua_pushinteger(gL, damagetype); - call_hooks(&hook, 4, 1, res_true); + call_hooks(&hook, 1, res_true); } return hook.status; } @@ -868,12 +925,14 @@ void LUA_HookNetArchive(lua_CFunction archFunc) push_error_handler(); lua_insert(gL, EINDEX); + begin_hook_values(&hook); + // tables becomes an upvalue of archFunc lua_pushvalue(gL, -1); lua_pushcclosure(gL, archFunc, 1); // stack: tables, archFunc - init_hook_call(&hook, 1, 0, res_none); + init_hook_call(&hook, 0, res_none); call_mapped(&hook, map); lua_pop(gL, 1); // pop archFunc @@ -889,7 +948,7 @@ int LUA_HookMapThingSpawn(mobj_t *mobj, mapthing_t *mthing) { LUA_PushUserdata(gL, mobj, META_MOBJ); LUA_PushUserdata(gL, mthing, META_MAPTHING); - call_hooks(&hook, 2, 1, res_true); + call_hooks(&hook, 1, res_true); } return hook.status; } @@ -901,7 +960,7 @@ int LUA_HookFollowMobj(player_t *player, mobj_t *mobj) { LUA_PushUserdata(gL, player, META_PLAYER); LUA_PushUserdata(gL, mobj, META_MOBJ); - call_hooks(&hook, 2, 1, res_true); + call_hooks(&hook, 1, res_true); } return hook.status; } @@ -913,7 +972,7 @@ int LUA_HookPlayerCanDamage(player_t *player, mobj_t *mobj) { LUA_PushUserdata(gL, player, META_PLAYER); LUA_PushUserdata(gL, mobj, META_MOBJ); - call_hooks(&hook, 2, 1, res_force); + call_hooks(&hook, 1, res_force); } return hook.status; } @@ -925,7 +984,7 @@ void LUA_HookPlayerQuit(player_t *plr, kickreason_t reason) { LUA_PushUserdata(gL, plr, META_PLAYER); // Player that quit lua_pushinteger(gL, reason); // Reason for quitting - call_hooks(&hook, 2, 0, res_none); + call_hooks(&hook, 0, res_none); } } @@ -939,7 +998,7 @@ int LUA_HookTeamSwitch(player_t *player, int newteam, boolean fromspectators, bo lua_pushboolean(gL, fromspectators); lua_pushboolean(gL, tryingautobalance); lua_pushboolean(gL, tryingscramble); - call_hooks(&hook, 5, 1, res_false); + call_hooks(&hook, 1, res_false); } return hook.status; } @@ -954,7 +1013,7 @@ int LUA_HookViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolea lua_pushboolean(gL, forced); hud_running = true; // local hook - call_hooks(&hook, 3, 1, res_force); + call_hooks(&hook, 1, res_force); hud_running = false; } return hook.status; @@ -969,7 +1028,7 @@ int LUA_HookSeenPlayer(player_t *player, player_t *seenfriend) LUA_PushUserdata(gL, seenfriend, META_PLAYER); hud_running = true; // local hook - call_hooks(&hook, 2, 1, res_false); + call_hooks(&hook, 1, res_false); hud_running = false; } return hook.status; @@ -985,7 +1044,7 @@ int LUA_HookShouldJingleContinue(player_t *player, const char *musname) push_string(); hud_running = true; // local hook - call_hooks(&hook, 2, 1, res_true); + call_hooks(&hook, 1, res_true); hud_running = false; } return hook.status; @@ -1051,7 +1110,8 @@ int LUA_HookMusicChange(const char *oldname, struct MusicChange *param) if (prepare_hook(&hook, false, type)) { - init_hook_call(&hook, 7, 6, res_musicchange); + init_hook_call(&hook, 6, res_musicchange); + hook.values = 7;/* values pushed later */ hook.userdata = param; lua_pushstring(gL, oldname);/* the only constant value */ @@ -1097,7 +1157,7 @@ fixed_t LUA_HookPlayerHeight(player_t *player) if (prepare_hook(&hook, -1, HOOK(PlayerHeight))) { LUA_PushUserdata(gL, player, META_PLAYER); - call_hooks(&hook, 1, 1, res_playerheight); + call_hooks(&hook, 1, res_playerheight); } return hook.status; } @@ -1108,7 +1168,7 @@ int LUA_HookPlayerCanEnterSpinGaps(player_t *player) if (prepare_hook(&hook, 0, HOOK(PlayerCanEnterSpinGaps))) { LUA_PushUserdata(gL, player, META_PLAYER); - call_hooks(&hook, 1, 1, res_force); + call_hooks(&hook, 1, res_force); } return hook.status; } diff --git a/src/lua_hud.h b/src/lua_hud.h index d2f5bceca..c1d2d164b 100644 --- a/src/lua_hud.h +++ b/src/lua_hud.h @@ -47,8 +47,4 @@ extern boolean hud_running; boolean LUA_HudEnabled(enum hud option); -void LUAh_GameHUD(player_t *stplyr); -void LUAh_ScoresHUD(void); -void LUAh_TitleHUD(void); -void LUAh_TitleCardHUD(player_t *stplayr); -void LUAh_IntermissionHUD(boolean failedstage); +void LUA_SetHudHook(int hook); diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 3ce36f4f1..25f513e65 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -23,18 +23,18 @@ #include "v_video.h" #include "w_wad.h" #include "z_zone.h" +#include "y_inter.h" #include "lua_script.h" #include "lua_libs.h" #include "lua_hud.h" +#include "lua_hook.h" #define HUDONLY if (!hud_running) return luaL_error(L, "HUD rendering code should not be called outside of rendering hooks!"); boolean hud_running = false; static UINT8 hud_enabled[(hud_MAX/8)+1]; -static UINT8 hudAvailable; // hud hooks field - // must match enum hud in lua_hud.h static const char *const hud_disable_options[] = { "stagetitle", @@ -95,21 +95,6 @@ static const char *const patch_opt[] = { "topoffset", NULL}; -enum hudhook { - hudhook_game = 0, - hudhook_scores, - hudhook_intermission, - hudhook_title, - hudhook_titlecard -}; -static const char *const hudhook_opt[] = { - "game", - "scores", - "intermission", - "title", - "titlecard", - NULL}; - // alignment types for v.drawString enum align { align_left = 0, @@ -1279,6 +1264,8 @@ static luaL_Reg lib_draw[] = { {NULL, NULL} }; +static int lib_draw_ref; + // // lib_hud // @@ -1313,28 +1300,7 @@ static int lib_hudenabled(lua_State *L) // add a HUD element for rendering -static int lib_hudadd(lua_State *L) -{ - enum hudhook field; - - luaL_checktype(L, 1, LUA_TFUNCTION); - field = luaL_checkoption(L, 2, "game", hudhook_opt); - - if (!lua_lumploading) - return luaL_error(L, "This function cannot be called from within a hook or coroutine!"); - - lua_getfield(L, LUA_REGISTRYINDEX, "HUD"); - I_Assert(lua_istable(L, -1)); - lua_rawgeti(L, -1, field+2); // HUD[2+] - I_Assert(lua_istable(L, -1)); - lua_remove(L, -2); - - lua_pushvalue(L, 1); - lua_rawseti(L, -2, (int)(lua_objlen(L, -2) + 1)); - - hudAvailable |= 1<