void LUAh_NetArchiveHook(lua_CFunction archFunc) { hook_p hookp; if (!gL || !(hooksAvailable[hook_NetVars/8] & (1<<(hook_NetVars%8)))) return; // stack: tables I_Assert(lua_gettop(gL) > 0); I_Assert(lua_istable(gL, -1)); // tables becomes an upvalue of archFunc lua_pushvalue(gL, -1); lua_pushcclosure(gL, archFunc, 1); // stack: tables, archFunc for (hookp = roothook; hookp; hookp = hookp->next) if (hookp->type == hook_NetVars) { lua_pushfstring(gL, FMT_HOOKID, hookp->id); lua_gettable(gL, LUA_REGISTRYINDEX); lua_pushvalue(gL, -2); // archFunc LUA_Call(gL, 1); } lua_pop(gL, 1); // pop archFunc // stack: tables }
// Hook for HUD rendering void LUAh_GameHUD(player_t *stplyr) { if (!gL || !(hudAvailable & (1<<hudhook_game))) return; hud_running = true; lua_pop(gL, -1); lua_getfield(gL, LUA_REGISTRYINDEX, "HUD"); I_Assert(lua_istable(gL, -1)); lua_rawgeti(gL, -1, 2); // HUD[2] = rendering funcs I_Assert(lua_istable(gL, -1)); lua_rawgeti(gL, -2, 1); // HUD[1] = lib_draw I_Assert(lua_istable(gL, -1)); lua_remove(gL, -3); // pop HUD LUA_PushUserdata(gL, stplyr, META_PLAYER); lua_pushnil(gL); while (lua_next(gL, -4) != 0) { lua_pushvalue(gL, -4); // graphics library (HUD[1]) lua_pushvalue(gL, -4); // stplyr LUA_Call(gL, 2); } lua_pop(gL, -1); lua_gc(gL, LUA_GCCOLLECT, 0); hud_running = false; }
boolean LUA_SetLuaAction(void *stv, const char *action) { state_t *st = (state_t *)stv; I_Assert(st != NULL); //I_Assert(st >= states && st < states+NUMSTATES); // if you REALLY want to be paranoid... I_Assert(action != NULL); if (!gL) // Lua isn't loaded, return false; // action not set. // action is assumed to be in all-caps already !! // the registry is case-sensitive, so we strupr everything that enters it. lua_getfield(gL, LUA_REGISTRYINDEX, LREG_ACTIONS); lua_getfield(gL, -1, action); if (lua_isnil(gL, -1)) // no match { lua_pop(gL, 2); // pop nil and LREG_ACTIONS return false; // action not set. } lua_getfield(gL, LUA_REGISTRYINDEX, LREG_STATEACTION); I_Assert(lua_istable(gL, -1)); lua_pushlightuserdata(gL, stv); // We'll store this function by the state's pointer in the registry. lua_pushvalue(gL, -3); // Bring it to the top of the stack lua_rawset(gL, -3); // Set it in the registry lua_pop(gL, 1); // pop LREG_STATEACTION lua_pop(gL, 2); // pop the function and LREG_ACTIONS st->action.acp1 = (actionf_p1)A_Lua; // Set the action for the userdata. return true; // action successfully set. }
void LUAh_ScoresHUD(void) { if (!gL || !(hudAvailable & (1<<hudhook_scores))) return; hud_running = true; lua_pop(gL, -1); lua_getfield(gL, LUA_REGISTRYINDEX, "HUD"); I_Assert(lua_istable(gL, -1)); lua_rawgeti(gL, -1, 3); // HUD[3] = rendering funcs I_Assert(lua_istable(gL, -1)); lua_rawgeti(gL, -2, 1); // HUD[1] = lib_draw I_Assert(lua_istable(gL, -1)); lua_remove(gL, -3); // pop HUD lua_pushnil(gL); while (lua_next(gL, -3) != 0) { lua_pushvalue(gL, -3); // graphics library (HUD[1]) LUA_Call(gL, 1); } lua_pop(gL, -1); lua_gc(gL, LUA_GCCOLLECT, 0); hud_running = false; }
static void UnArchiveExtVars(void *pointer) { int TABLESINDEX; UINT16 field_count = READUINT16(save_p); UINT16 i; char field[1024]; if (field_count == 0) return; I_Assert(gL != NULL); TABLESINDEX = lua_gettop(gL); lua_createtable(gL, 0, field_count); // pointer's ext vars subtable for (i = 0; i < field_count; i++) { READSTRING(save_p, field); UnArchiveValue(TABLESINDEX); lua_setfield(gL, -2, field); } lua_getfield(gL, LUA_REGISTRYINDEX, LREG_EXTVARS); I_Assert(lua_istable(gL, -1)); lua_pushlightuserdata(gL, pointer); lua_pushvalue(gL, -3); // pointer's ext vars subtable lua_rawset(gL, -3); lua_pop(gL, 2); // pop LREG_EXTVARS and pointer's subtable }
// When userdata is freed, use this function to remove it from Lua. void LUA_InvalidateUserdata(void *data) { void **userdata; if (!gL) return; // fetch the userdata lua_getfield(gL, LUA_REGISTRYINDEX, LREG_VALID); I_Assert(lua_istable(gL, -1)); lua_pushlightuserdata(gL, data); lua_rawget(gL, -2); if (lua_isnil(gL, -1)) { // not found, not in lua lua_pop(gL, 2); // pop nil and LREG_VALID return; } // nullify any additional data lua_getfield(gL, LUA_REGISTRYINDEX, LREG_EXTVARS); I_Assert(lua_istable(gL, -1)); lua_pushlightuserdata(gL, data); lua_pushnil(gL); lua_rawset(gL, -3); lua_pop(gL, 1); // invalidate the userdata userdata = lua_touserdata(gL, -1); *userdata = NULL; lua_pop(gL, 1); // remove it from the registry lua_pushlightuserdata(gL, data); lua_pushnil(gL); lua_rawset(gL, -3); lua_pop(gL, 1); // pop LREG_VALID }
static int sfxinfo_num(lua_State *L) { sfxinfo_t *sfx = *((sfxinfo_t **)luaL_checkudata(L, 1, META_SFXINFO)); I_Assert(sfx != NULL); I_Assert(sfx >= S_sfx); lua_pushinteger(L, (UINT32)(sfx-S_sfx)); return 1; }
// mobjinfo_t * -> MT_* static int mobjinfo_num(lua_State *L) { mobjinfo_t *info = *((mobjinfo_t **)luaL_checkudata(L, 1, META_MOBJINFO)); I_Assert(info != NULL); I_Assert(info >= mobjinfo); lua_pushinteger(L, info-mobjinfo); return 1; }
boolean LUA_CallAction(const char *csaction, mobj_t *actor) { I_Assert(csaction != NULL); I_Assert(actor != NULL); if (!gL) // Lua isn't loaded, return false; // action not called. if (superstack && fasticmp(csaction, superactions[superstack-1])) // the action is calling itself, return false; // let it call the hardcoded function instead. // grab function by uppercase name. lua_getfield(gL, LUA_REGISTRYINDEX, LREG_ACTIONS); { char *action = Z_StrDup(csaction); strupr(action); lua_getfield(gL, -1, action); Z_Free(action); } lua_remove(gL, -2); // pop LREG_ACTIONS if (lua_isnil(gL, -1)) // no match { lua_pop(gL, 1); // pop nil return false; // action not called. } if (superstack == MAXRECURSION) { CONS_Alert(CONS_WARNING, "Max Lua Action recursion reached! Cool it on the calling A_Action functions from inside A_Action functions!\n"); return true; } // Found a function. // Call it with (actor, var1, var2) I_Assert(lua_isfunction(gL, -1)); LUA_PushUserdata(gL, actor, META_MOBJ); lua_pushinteger(gL, var1); lua_pushinteger(gL, var2); superactions[superstack] = csaction; ++superstack; LUA_Call(gL, 3); --superstack; superactions[superstack] = NULL; return true; // action successfully called. }
static void ArchiveExtVars(void *pointer, const char *ptype) { int TABLESINDEX; UINT16 i; if (!gL) { if (fastcmp(ptype,"player")) // players must always be included, even if no vars WRITEUINT16(save_p, 0); return; } TABLESINDEX = lua_gettop(gL); lua_getfield(gL, LUA_REGISTRYINDEX, LREG_EXTVARS); I_Assert(lua_istable(gL, -1)); lua_pushlightuserdata(gL, pointer); lua_rawget(gL, -2); lua_remove(gL, -2); // pop LREG_EXTVARS if (!lua_istable(gL, -1)) { // no extra values table lua_pop(gL, 1); if (fastcmp(ptype,"player")) // players must always be included, even if no vars WRITEUINT16(save_p, 0); return; } lua_pushnil(gL); for (i = 0; lua_next(gL, -2); i++) lua_pop(gL, 1); if (i == 0 && !fastcmp(ptype,"player")) // skip anything that has an empty table and isn't a player. return; if (fastcmp(ptype,"mobj")) // mobjs must write their mobjnum as a header WRITEUINT32(save_p, ((mobj_t *)pointer)->mobjnum); WRITEUINT16(save_p, i); lua_pushnil(gL); while (lua_next(gL, -2)) { I_Assert(lua_type(gL, -2) == LUA_TSTRING); WRITESTRING(save_p, lua_tostring(gL, -2)); if (ArchiveValue(TABLESINDEX, -1) == 2) CONS_Alert(CONS_ERROR, "Type of value for %s entry '%s' (%s) could not be archived!\n", ptype, lua_tostring(gL, -2), luaL_typename(gL, -1)); lua_pop(gL, 1); } lua_pop(gL, 1); }
INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority) { FMOD_SOUND *sound; FMOD_CHANNEL *chan; INT32 i; float frequency; sound = (FMOD_SOUND *)S_sfx[id].data; I_Assert(sound != NULL); FMR(FMOD_System_PlaySound(fsys, FMOD_CHANNEL_FREE, sound, true, &chan)); if (sep == 0) sep = 1; FMR(FMOD_Channel_SetVolume(chan, (vol / 255.0) * (sfx_volume / 31.0))); FMR(FMOD_Channel_SetPan(chan, (sep - 128) / 127.0)); FMR(FMOD_Sound_GetDefaults(sound, &frequency, NULL, NULL, NULL)); FMR(FMOD_Channel_SetFrequency(chan, (pitch / 128.0) * frequency)); FMR(FMOD_Channel_SetPriority(chan, priority)); //UNREFERENCED_PARAMETER(priority); //FMR(FMOD_Channel_SetPriority(chan, 1 + ((0xff-vol)>>1))); // automatic priority 1 - 128 based on volume (priority 0 is music) FMR(FMOD_Channel_GetIndex(chan, &i)); FMR(FMOD_Channel_SetPaused(chan, false)); return i; }
// Takes a pointer, any pointer, and a metatable name // Creates a userdata for that pointer with the given metatable // Pushes it to the stack and stores it in the registry. void LUA_PushUserdata(lua_State *L, void *data, const char *meta) { void **userdata; if (!data) { // push a NULL lua_pushnil(L); return; } lua_getfield(L, LUA_REGISTRYINDEX, LREG_VALID); I_Assert(lua_istable(L, -1)); lua_pushlightuserdata(L, data); lua_rawget(L, -2); if (lua_isnil(L, -1)) { // no userdata? deary me, we'll have to make one. lua_pop(L, 1); // pop the nil // create the userdata userdata = lua_newuserdata(L, sizeof(void *)); *userdata = data; luaL_getmetatable(L, meta); lua_setmetatable(L, -2); // Set it in the registry so we can find it again lua_pushlightuserdata(L, data); // k (store the userdata via the data's pointer) lua_pushvalue(L, -2); // v (copy of the userdata) lua_rawset(L, -4); // stack is left with the userdata on top, as if getting it had originally succeeded. } lua_remove(L, -2); // remove LREG_VALID }
// sfxinfo_t *, field, value static int sfxinfo_set(lua_State *L) { sfxinfo_t *sfx = *((sfxinfo_t **)luaL_checkudata(L, 1, META_SFXINFO)); enum sfxinfo_e field = luaL_checkoption(L, 2, NULL, sfxinfo_opt); if (hud_running) return luaL_error(L, "Do not alter S_sfx in HUD rendering code!"); I_Assert(sfx != NULL); lua_remove(L, 1); // remove sfxinfo lua_remove(L, 1); // remove field lua_settop(L, 1); // leave only one value switch (field) { case sfxinfo_singularity: sfx->singularity = luaL_checkboolean(L, 1); break; case sfxinfo_priority: sfx->priority = luaL_checkinteger(L, 1); break; case sfxinfo_flags: sfx->pitch = luaL_checkinteger(L, 1); break; case sfxinfo_volume: sfx->volume = luaL_checkinteger(L, 1); break; default: return luaL_error(L, "Can't set 'S_sfx[%u].%s' here.", (UINT32)(sfx-S_sfx), sfxinfo_opt[field]); } return 0; }
// sfxinfo_t *, field static int sfxinfo_get(lua_State *L) { sfxinfo_t *sfx = *((sfxinfo_t **)luaL_checkudata(L, 1, META_SFXINFO)); enum sfxinfo_e field = luaL_checkoption(L, 2, NULL, sfxinfo_opt); I_Assert(sfx != NULL); switch (field) { case sfxinfo_name: lua_pushstring(L, sfx->name); return 1; case sfxinfo_singularity: lua_pushboolean(L, sfx->singularity); return 1; case sfxinfo_priority: lua_pushinteger(L, sfx->priority); return 1; case sfxinfo_flags: lua_pushinteger(L, sfx->pitch); return 1; case sfxinfo_volume: lua_pushinteger(L, sfx->volume); return 1; case sfxinfo_skinsound: lua_pushinteger(L, sfx->skinsound); return 1; } return luaL_error(L, "impossible error"); }
static int patch_get(lua_State *L) { patch_t *patch = *((patch_t **)luaL_checkudata(L, 1, META_PATCH)); enum patch field = luaL_checkoption(L, 2, NULL, patch_opt); // patches are CURRENTLY always valid, expected to be cached with PU_STATIC // this may change in the future, so patch.valid still exists I_Assert(patch != NULL); switch (field) { case patch_valid: lua_pushboolean(L, patch != NULL); break; case patch_width: lua_pushinteger(L, SHORT(patch->width)); break; case patch_height: lua_pushinteger(L, SHORT(patch->height)); break; case patch_leftoffset: lua_pushinteger(L, SHORT(patch->leftoffset)); break; case patch_topoffset: lua_pushinteger(L, SHORT(patch->topoffset)); break; } return 1; }
// must match lua_Writer static int dumpWriter(lua_State *L, const void *p, size_t sz, void *ud) { FILE *handle = (FILE*)ud; I_Assert(handle != NULL); (void)L; if (!sz) return 0; // nothing to write? can't fail that! :D return (fwrite(p, 1, sz, handle) != sz); // if fwrite != sz, we've failed. }
// Uses astate to determine which state is calling it // Then looks up which Lua action is assigned to that state and calls it static void A_Lua(mobj_t *actor) { boolean found = false; I_Assert(actor != NULL); // get the action for this state lua_getfield(gL, LUA_REGISTRYINDEX, LREG_STATEACTION); I_Assert(lua_istable(gL, -1)); lua_pushlightuserdata(gL, astate); lua_rawget(gL, -2); I_Assert(lua_isfunction(gL, -1)); lua_remove(gL, -2); // pop LREG_STATEACTION // get the name for this action, if possible. lua_getfield(gL, LUA_REGISTRYINDEX, LREG_ACTIONS); lua_pushnil(gL); while (lua_next(gL, -2)) { if (lua_rawequal(gL, -1, -4)) { found = true; superactions[superstack] = lua_tostring(gL, -2); // "A_ACTION" ++superstack; lua_pop(gL, 2); // pop the name and function break; } lua_pop(gL, 1); } lua_pop(gL, 1); // pop LREG_ACTION LUA_PushUserdata(gL, actor, META_MOBJ); lua_pushinteger(gL, var1); lua_pushinteger(gL, var2); LUA_Call(gL, 3); if (found) { --superstack; superactions[superstack] = NULL; } lua_gc(gL, LUA_GCSTEP, 1); }
// 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); 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<<field; return 0; }
static int camera_get(lua_State *L) { camera_t *cam = *((camera_t **)luaL_checkudata(L, 1, META_CAMERA)); enum cameraf field = luaL_checkoption(L, 2, NULL, camera_opt); // cameras should always be valid unless I'm a nutter I_Assert(cam != NULL); switch (field) { case camera_chase: lua_pushboolean(L, cam->chase); break; case camera_aiming: lua_pushinteger(L, cam->aiming); break; case camera_x: lua_pushinteger(L, cam->x); break; case camera_y: lua_pushinteger(L, cam->y); break; case camera_z: lua_pushinteger(L, cam->z); break; case camera_angle: lua_pushinteger(L, cam->angle); break; case camera_subsector: LUA_PushUserdata(L, cam->subsector, META_SUBSECTOR); break; case camera_floorz: lua_pushinteger(L, cam->floorz); break; case camera_ceilingz: lua_pushinteger(L, cam->ceilingz); break; case camera_radius: lua_pushinteger(L, cam->radius); break; case camera_height: lua_pushinteger(L, cam->height); break; case camera_momx: lua_pushinteger(L, cam->momx); break; case camera_momy: lua_pushinteger(L, cam->momy); break; case camera_momz: lua_pushinteger(L, cam->momz); break; } return 1; }
void I_ShutdownSound(void) { I_Assert(sound_started); sound_started = false; #ifdef HAVE_LIBGME if (gme) gme_delete(gme); #endif FMR(FMOD_System_Release(fsys)); }
static void Lua_OnChange(void) { I_Assert(gL != NULL); I_Assert(cvname != NULL); /// \todo Network this! XD_LUAVAR // From CV_OnChange registry field, get the function for this cvar by name. lua_getfield(gL, LUA_REGISTRYINDEX, "CV_OnChange"); I_Assert(lua_istable(gL, -1)); lua_getfield(gL, -1, cvname); // get function // From the CV_Vars registry field, get the cvar's userdata by name. lua_getfield(gL, LUA_REGISTRYINDEX, "CV_Vars"); I_Assert(lua_istable(gL, -1)); lua_getfield(gL, -1, cvname); // get consvar_t* userdata. lua_remove(gL, -2); // pop the CV_Vars table. LUA_Call(gL, 1); // call function(cvar) lua_pop(gL, 1); // pop CV_OnChange table }
// Wrapper for COM_AddCommand static int lib_comAddCommand(lua_State *L) { int com_return = -1; const char *luaname = luaL_checkstring(L, 1); // must store in all lowercase char *name = Z_StrDup(luaname); strlwr(name); luaL_checktype(L, 2, LUA_TFUNCTION); NOHUD if (lua_gettop(L) >= 3) { // For the third argument, only take a boolean or a number. lua_settop(L, 3); if (lua_type(L, 3) != LUA_TBOOLEAN) luaL_checktype(L, 3, LUA_TNUMBER); } else { // No third argument? Default to 0. lua_settop(L, 2); lua_pushinteger(L, 0); } lua_getfield(L, LUA_REGISTRYINDEX, "COM_Command"); I_Assert(lua_istable(L, -1)); lua_createtable(L, 2, 0); lua_pushvalue(L, 2); lua_rawseti(L, -2, 1); lua_pushvalue(L, 3); lua_rawseti(L, -2, 2); lua_setfield(L, -2, name); // Try to add the Lua command com_return = COM_AddLuaCommand(name); if (com_return < 0) { // failed to add -- free the lowercased name and return error Z_Free(name); return luaL_error(L, "Couldn't add a new console command \"%s\"", luaname); } else if (com_return == 1) { // command existed already -- free our name as the old string will continue to be used CONS_Printf("Replaced command \"%s\"\n", name); Z_Free(name); } else { // new command was added -- do NOT free the string as it will forever be used by the console CONS_Printf("Added command \"%s\"\n", name); } return 0; }
// state_t *, field, number -> states[] static int state_set(lua_State *L) { state_t *st = *((state_t **)luaL_checkudata(L, 1, META_STATE)); const char *field = luaL_checkstring(L, 2); lua_Integer value; if (hud_running) return luaL_error(L, "Do not alter states in HUD rendering code!"); if (fastcmp(field,"sprite")) { value = luaL_checknumber(L, 3); if (value < SPR_NULL || value >= NUMSPRITES) return luaL_error(L, "sprite number %d is invalid.", value); st->sprite = (spritenum_t)value; } else if (fastcmp(field,"frame")) st->frame = (UINT32)luaL_checknumber(L, 3); else if (fastcmp(field,"tics")) st->tics = (INT32)luaL_checknumber(L, 3); else if (fastcmp(field,"action")) { switch(lua_type(L, 3)) { case LUA_TNIL: // Null? Set the action to nothing, then. st->action.acp1 = NULL; break; case LUA_TSTRING: // It's a string, expect the name of a built-in action LUA_SetActionByName(st, lua_tostring(L, 3)); break; case LUA_TFUNCTION: // It's a function (a Lua function or a C function? either way!) lua_getfield(L, LUA_REGISTRYINDEX, LREG_STATEACTION); I_Assert(lua_istable(L, -1)); lua_pushlightuserdata(L, st); // We'll store this function by the state's pointer in the registry. lua_pushvalue(L, 3); // Bring it to the top of the stack lua_rawset(L, -3); // Set it in the registry lua_pop(L, 1); // pop LREG_STATEACTION st->action.acp1 = (actionf_p1)A_Lua; // Set the action for the userdata. break; default: // ?! return luaL_typerror(L, 3, "function"); } } else if (fastcmp(field,"var1")) st->var1 = (INT32)luaL_checknumber(L, 3); else if (fastcmp(field,"var2")) st->var2 = (INT32)luaL_checknumber(L, 3); else if (fastcmp(field,"nextstate")) { value = luaL_checkinteger(L, 3); if (value < S_NULL || value >= NUMSTATES) return luaL_error(L, "nextstate number %d is invalid.", value); st->nextstate = (statenum_t)value; } else return luaL_error(L, LUA_QL("state_t") " has no field named " LUA_QS, field); return 0; }
void I_StartupSound(void) { I_Assert(!sound_started); sound_started = true; FMR(FMOD_System_Create(&fsys)); FMR(FMOD_System_SetDSPBufferSize(fsys, 44100 / 30, 2)); FMR(FMOD_System_Init(fsys, 64, FMOD_INIT_VOL0_BECOMES_VIRTUAL, NULL)); music_stream = NULL; #ifdef HAVE_LIBGME gme = NULL; #endif current_track = -1; }
static void NetArchiveHook(lua_CFunction archFunc) { int TABLESINDEX; if (!gL) return; TABLESINDEX = lua_gettop(gL); lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); I_Assert(lua_istable(gL, -1)); lua_rawgeti(gL, -1, hook_NetVars); lua_remove(gL, -2); I_Assert(lua_istable(gL, -1)); lua_pushvalue(gL, TABLESINDEX); lua_pushcclosure(gL, archFunc, 1); lua_pushnil(gL); while (lua_next(gL, -3) != 0) { lua_pushvalue(gL, -3); // function LUA_Call(gL, 1); } lua_pop(gL, 2); }
// state_t *, field -> number static int state_get(lua_State *L) { state_t *st = *((state_t **)luaL_checkudata(L, 1, META_STATE)); const char *field = luaL_checkstring(L, 2); lua_Integer number; if (fastcmp(field,"sprite")) number = st->sprite; else if (fastcmp(field,"frame")) number = st->frame; else if (fastcmp(field,"tics")) number = st->tics; else if (fastcmp(field,"action")) { const char *name; if (!st->action.acp1) // Action is NULL. return 0; // return nil. if (st->action.acp1 == (actionf_p1)A_Lua) { // This is a Lua function? lua_getfield(L, LUA_REGISTRYINDEX, LREG_STATEACTION); I_Assert(lua_istable(L, -1)); lua_pushlightuserdata(L, st); // Push the state pointer and lua_rawget(L, -2); // use it to get the actual Lua function. lua_remove(L, -2); // pop LREG_STATEACTION return 1; // Return the Lua function. } name = LUA_GetActionName(&st->action); // find a hardcoded function name if (!name) // If it's not a hardcoded function and it's not a Lua function... return 0; // Just what is this?? // get the function from the global // because the metatable will trigger. lua_getglobal(L, name); // actually gets from LREG_ACTIONS if applicable, and pushes a new C closure if not. lua_pushstring(L, name); // push the name we found. return 2; // return both the function and its name, in case somebody wanted to do a comparison by name or something? } else if (fastcmp(field,"var1")) number = st->var1; else if (fastcmp(field,"var2")) number = st->var2; else if (fastcmp(field,"nextstate")) number = st->nextstate; else if (devparm) return luaL_error(L, LUA_QL("state_t") " has no field named " LUA_QS, field); else return 0; lua_pushinteger(L, number); return 1; }
static int hudinfo_set(lua_State *L) { hudinfo_t *info = *((hudinfo_t **)luaL_checkudata(L, 1, META_HUDINFO)); enum hudinfo field = luaL_checkoption(L, 2, hudinfo_opt[0], hudinfo_opt); I_Assert(info != NULL); switch(field) { case hudinfo_x: info->x = (INT32)luaL_checkinteger(L, 3); break; case hudinfo_y: info->y = (INT32)luaL_checkinteger(L, 3); break; } return 0; }
static int hudinfo_get(lua_State *L) { hudinfo_t *info = *((hudinfo_t **)luaL_checkudata(L, 1, META_HUDINFO)); enum hudinfo field = luaL_checkoption(L, 2, hudinfo_opt[0], hudinfo_opt); I_Assert(info != NULL); // huditems are always valid switch(field) { case hudinfo_x: lua_pushinteger(L, info->x); break; case hudinfo_y: lua_pushinteger(L, info->y); break; } return 1; }
// Wrapper for COM_AddCommand commands void COM_Lua_f(void) { char *buf, *p; UINT8 i, flags; UINT16 len; INT32 playernum = consoleplayer; I_Assert(gL != NULL); lua_getfield(gL, LUA_REGISTRYINDEX, "COM_Command"); // push COM_Command I_Assert(lua_istable(gL, -1)); // use buf temporarily -- must use lowercased string buf = Z_StrDup(COM_Argv(0)); strlwr(buf); lua_getfield(gL, -1, buf); // push command info table I_Assert(lua_istable(gL, -1)); lua_remove(gL, -2); // pop COM_Command Z_Free(buf); lua_rawgeti(gL, -1, 2); // push flags from command info table if (lua_isboolean(gL, -1)) flags = (lua_toboolean(gL, -1) ? 1 : 0); else flags = (UINT8)lua_tointeger(gL, -1); lua_pop(gL, 1); // pop flags if (flags & 2) // flag 2: splitscreen player command. { if (!splitscreen) { lua_pop(gL, 1); // pop command info table return; // can't execute splitscreen command without player 2! } playernum = secondarydisplayplayer; } if (netgame) { // Send the command through the network UINT8 argc; lua_pop(gL, 1); // pop command info table if (flags & 1 && !server && !IsPlayerAdmin(playernum)) // flag 1: only server/admin can use this command. { CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); return; } if (COM_Argc() > UINT8_MAX) argc = UINT8_MAX; else argc = (UINT8)COM_Argc(); if (argc == UINT8_MAX) len = UINT16_MAX; else len = (argc+1)*256; buf = malloc(len); p = buf; WRITEUINT8(p, argc); for (i = 0; i < argc; i++) WRITESTRINGN(p, COM_Argv(i), 255); if (flags & 2) SendNetXCmd2(XD_LUACMD, buf, p-buf); else SendNetXCmd(XD_LUACMD, buf, p-buf); free(buf); return; } // Do the command locally, NetXCmds don't go through outside of GS_LEVEL || GS_INTERMISSION lua_rawgeti(gL, -1, 1); // push function from command info table I_Assert(lua_isfunction(gL, -1)); lua_remove(gL, -2); // pop command info table LUA_PushUserdata(gL, &players[playernum], META_PLAYER); for (i = 1; i < COM_Argc(); i++) lua_pushstring(gL, COM_Argv(i)); LUA_Call(gL, (int)COM_Argc()); // COM_Argc is 1-based, so this will cover the player we passed too. }
static int lib_cvRegisterVar(lua_State *L) { const char *k; lua_Integer i; consvar_t *cvar; luaL_checktype(L, 1, LUA_TTABLE); lua_settop(L, 1); // Clear out all other possible arguments, leaving only the first one. NOHUD cvar = lua_newuserdata(L, sizeof(consvar_t)); luaL_getmetatable(L, META_CVAR); lua_setmetatable(L, -2); #define FIELDERROR(f, e) luaL_error(L, "bad value for " LUA_QL(f) " in table passed to " LUA_QL("CV_RegisterVar") " (%s)", e); #define TYPEERROR(f, t) FIELDERROR(f, va("%s expected, got %s", lua_typename(L, t), luaL_typename(L, -1))) lua_pushnil(L); while (lua_next(L, 1)) { // stack: cvar table, cvar userdata, key/index, value // 1 2 3 4 i = 0; k = NULL; if (lua_isnumber(L, 3)) i = lua_tointeger(L, 3); else if (lua_isstring(L, 3)) k = lua_tostring(L, 3); if (i == 1 || (k && fasticmp(k, "name"))) { if (!lua_isstring(L, 4)) TYPEERROR("name", LUA_TSTRING) cvar->name = Z_StrDup(lua_tostring(L, 4)); } else if (i == 2 || (k && fasticmp(k, "defaultvalue"))) { if (!lua_isstring(L, 4)) TYPEERROR("defaultvalue", LUA_TSTRING) cvar->defaultvalue = Z_StrDup(lua_tostring(L, 4)); } else if (i == 3 || (k && fasticmp(k, "flags"))) { if (!lua_isnumber(L, 4)) TYPEERROR("flags", LUA_TNUMBER) cvar->flags = (INT32)lua_tointeger(L, 4); } else if (i == 4 || (k && fasticmp(k, "PossibleValue"))) { if (lua_islightuserdata(L, 4)) { CV_PossibleValue_t *pv = lua_touserdata(L, 4); if (pv == CV_OnOff || pv == CV_YesNo || pv == CV_Unsigned || pv == CV_Natural) cvar->PossibleValue = pv; else FIELDERROR("PossibleValue", "CV_PossibleValue_t expected, got unrecognised pointer") } else if (lua_istable(L, 4)) { // Accepts tables in the form of {MIN=0, MAX=9999} or {Red=0, Green=1, Blue=2} // and converts them to CV_PossibleValue_t {{0,"MIN"},{9999,"MAX"}} or {{0,"Red"},{1,"Green"},{2,"Blue"}} // // I don't really like the way this does it because a single PossibleValue table // being used for multiple cvars will be converted and stored multiple times. // So maybe instead it should be a seperate function which must be run beforehand or something. size_t count = 0; CV_PossibleValue_t *cvpv; lua_pushnil(L); while (lua_next(L, 4)) { count++; lua_pop(L, 1); } lua_getfield(L, LUA_REGISTRYINDEX, "CV_PossibleValue"); I_Assert(lua_istable(L, 5)); lua_pushvalue(L, 2); // cvar userdata cvpv = lua_newuserdata(L, sizeof(CV_PossibleValue_t) * (count+1)); lua_rawset(L, 5); lua_pop(L, 1); // pop CV_PossibleValue registry table i = 0; lua_pushnil(L); while (lua_next(L, 4)) { // stack: [...] PossibleValue table, index, value // 4 5 6 if (lua_type(L, 5) != LUA_TSTRING || lua_type(L, 6) != LUA_TNUMBER) FIELDERROR("PossibleValue", "custom PossibleValue table requires a format of string=integer, i.e. {MIN=0, MAX=9999}"); cvpv[i].strvalue = Z_StrDup(lua_tostring(L, 5)); cvpv[i].value = (INT32)lua_tonumber(L, 6); i++; lua_pop(L, 1); } cvpv[i].value = 0; cvpv[i].strvalue = NULL; cvar->PossibleValue = cvpv; } else FIELDERROR("PossibleValue", va("%s or CV_PossibleValue_t expected, got %s", lua_typename(L, LUA_TTABLE), luaL_typename(L, -1))) } else if (cvar->flags & CV_CALL && (i == 5 || (k && fasticmp(k, "func")))) {