// Hook for linedef executors boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo, sector_t *sector) { hook_p hookp; boolean hooked = false; if (!gL || !(hooksAvailable[hook_LinedefExecute/8] & (1<<(hook_LinedefExecute%8)))) return 0; lua_settop(gL, 0); for (hookp = roothook; hookp; hookp = hookp->next) if (hookp->type == hook_LinedefExecute && !strcmp(hookp->s.funcname, line->text)) { if (lua_gettop(gL) == 0) { LUA_PushUserdata(gL, line, META_LINE); LUA_PushUserdata(gL, mo, META_MOBJ); LUA_PushUserdata(gL, sector, META_SECTOR); } lua_pushfstring(gL, FMT_HOOKID, hookp->id); lua_gettable(gL, LUA_REGISTRYINDEX); lua_pushvalue(gL, -4); lua_pushvalue(gL, -4); lua_pushvalue(gL, -4); LUA_Call(gL, 3); hooked = true; } lua_settop(gL, 0); return hooked; }
static int lib_iterateThinkers(lua_State *L) { int state = luaL_checkoption(L, 1, "mobj", iter_opt); thinker_t *th = NULL; actionf_p1 searchFunc; const char *searchMeta; lua_settop(L, 2); lua_remove(L, 1); // remove state now. switch(state) { case 0: searchFunc = NULL; searchMeta = NULL; break; case 1: default: searchFunc = (actionf_p1)P_MobjThinker; searchMeta = META_MOBJ; break; } if (!lua_isnil(L, 1)) { if (lua_islightuserdata(L, 1)) th = (thinker_t *)lua_touserdata(L, 1); else if (searchMeta) th = *((thinker_t **)luaL_checkudata(L, 1, searchMeta)); else th = *((thinker_t **)lua_touserdata(L, 1)); } else th = &thinkercap; if (!th) // something got our userdata invalidated! return 0; if (searchFunc == NULL) { if ((th = th->next) != &thinkercap) { if (th->function.acp1 == (actionf_p1)P_MobjThinker) LUA_PushUserdata(L, th, META_MOBJ); else lua_pushlightuserdata(L, th); return 1; } return 0; } for (th = th->next; th != &thinkercap; th = th->next) { if (th->function.acp1 != searchFunc) continue; LUA_PushUserdata(L, th, searchMeta); return 1; } return 0; }
// Hook for B_BuildTailsTiccmd by skin name boolean LUAh_BotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd) { hook_p hookp; boolean hooked = false; if (!gL || !(hooksAvailable[hook_BotAI/8] & (1<<(hook_BotAI%8)))) return false; lua_settop(gL, 0); for (hookp = roothook; hookp; hookp = hookp->next) if (hookp->type == hook_BotAI && (hookp->s.skinname == NULL || !strcmp(hookp->s.skinname, ((skin_t*)tails->skin)->name))) { if (lua_gettop(gL) == 0) { LUA_PushUserdata(gL, sonic, META_MOBJ); LUA_PushUserdata(gL, tails, META_MOBJ); } lua_pushfstring(gL, FMT_HOOKID, hookp->id); lua_gettable(gL, LUA_REGISTRYINDEX); lua_pushvalue(gL, -3); lua_pushvalue(gL, -3); if (lua_pcall(gL, 2, 8, 0)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); hookp->error = true; continue; } // This turns forward, backward, left, right, jump, and spin into a proper ticcmd for tails. if (lua_istable(gL, 2+1)) { boolean forward=false, backward=false, left=false, right=false, strafeleft=false, straferight=false, jump=false, spin=false; #define CHECKFIELD(field) \ lua_getfield(gL, 2+1, #field);\ if (lua_toboolean(gL, -1))\ field = true;\ lua_pop(gL, 1); CHECKFIELD(forward) CHECKFIELD(backward) CHECKFIELD(left) CHECKFIELD(right) CHECKFIELD(strafeleft) CHECKFIELD(straferight) CHECKFIELD(jump) CHECKFIELD(spin) #undef CHECKFIELD B_KeysToTiccmd(tails, cmd, forward, backward, left, right, strafeleft, straferight, jump, spin); } else B_KeysToTiccmd(tails, cmd, lua_toboolean(gL, 2+1), lua_toboolean(gL, 2+2), lua_toboolean(gL, 2+3), lua_toboolean(gL, 2+4), lua_toboolean(gL, 2+5), lua_toboolean(gL, 2+6), lua_toboolean(gL, 2+7), lua_toboolean(gL, 2+8)); lua_pop(gL, 8); hooked = true; } lua_settop(gL, 0); return hooked; }
// Hook for player chat boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg) { hook_p hookp; boolean hooked = false; if (!gL || !(hooksAvailable[hook_PlayerMsg/8] & (1<<(hook_PlayerMsg%8)))) return false; lua_settop(gL, 0); for (hookp = roothook; hookp; hookp = hookp->next) if (hookp->type == hook_PlayerMsg) { if (lua_gettop(gL) == 0) { LUA_PushUserdata(gL, &players[source], META_PLAYER); // Source player if (flags & 2 /*HU_CSAY*/) { // csay TODO: make HU_CSAY accessible outside hu_stuff.c lua_pushinteger(gL, 3); // type lua_pushnil(gL); // target } else if (target == -1) { // sayteam lua_pushinteger(gL, 1); // type lua_pushnil(gL); // target } else if (target == 0) { // say lua_pushinteger(gL, 0); // type lua_pushnil(gL); // target } else { // sayto lua_pushinteger(gL, 2); // type LUA_PushUserdata(gL, &players[target-1], META_PLAYER); // target } lua_pushstring(gL, msg); // msg } lua_pushfstring(gL, FMT_HOOKID, hookp->id); lua_gettable(gL, LUA_REGISTRYINDEX); lua_pushvalue(gL, -5); lua_pushvalue(gL, -5); lua_pushvalue(gL, -5); lua_pushvalue(gL, -5); if (lua_pcall(gL, 4, 1, 0)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); hookp->error = true; continue; } if (lua_toboolean(gL, -1)) hooked = true; lua_pop(gL, 1); } lua_settop(gL, 0); return hooked; }
// iterates through the ffloors list in a sector! static int lib_iterateSectorFFloors(lua_State *L) { ffloor_t *state = NULL; ffloor_t *ffloor = NULL; if (lua_gettop(L) < 2) return luaL_error(L, "Don't call sector.ffloors() directly, use it as 'for rover in sector.ffloors do <block> end'."); if (!lua_isnil(L, 1)) state = *((ffloor_t **)luaL_checkudata(L, 1, META_FFLOOR)); else return 0; // no ffloors to iterate through sorry! lua_settop(L, 2); lua_remove(L, 1); // remove state now. if (!lua_isnil(L, 1)) { ffloor = *((ffloor_t **)luaL_checkudata(L, 1, META_FFLOOR)); ffloor = ffloor->next; } else ffloor = state; // state is used as the "start" of the ffloor list if (ffloor) { LUA_PushUserdata(L, ffloor, META_FFLOOR); return 1; } return 0; }
// iterates through a sector's thinglist! static int lib_iterateSectorThinglist(lua_State *L) { mobj_t *state = NULL; mobj_t *thing = NULL; if (lua_gettop(L) < 2) return luaL_error(L, "Don't call sector.thinglist() directly, use it as 'for rover in sector.thinglist do <block> end'."); if (!lua_isnil(L, 1)) state = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); else return 0; // no thinglist to iterate through sorry! lua_settop(L, 2); lua_remove(L, 1); // remove state now. if (!lua_isnil(L, 1)) { thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); thing = thing->snext; } else thing = state; // state is used as the "start" of the thinglist if (thing) { LUA_PushUserdata(L, thing, META_MOBJ); return 1; } return 0; }
static int lib_getMapheaderinfo(lua_State *L) { // i -> mapheaderinfo[i-1] //int field; lua_settop(L, 2); lua_remove(L, 1); // dummy userdata table is unused. if (lua_isnumber(L, 1)) { size_t i = lua_tointeger(L, 1)-1; if (i >= NUMMAPS) return 0; LUA_PushUserdata(L, mapheaderinfo[i], META_MAPHEADER); //CONS_Printf(mapheaderinfo[i]->lvlttl); return 1; }/* field = luaL_checkoption(L, 1, NULL, array_opt); switch(field) { case 0: // iterate lua_pushcfunction(L, lib_iterateSubsectors); return 1; }*/ return 0; }
static int libd_getColormap(lua_State *L) { INT32 skinnum = TC_DEFAULT; skincolors_t color = luaL_optinteger(L, 2, 0); UINT8* colormap = NULL; HUDONLY if (lua_isnoneornil(L, 1)) ; // defaults to TC_DEFAULT else if (lua_type(L, 1) == LUA_TNUMBER) // skin number { skinnum = (INT32)luaL_checkinteger(L, 1); if (skinnum < TC_ALLWHITE || skinnum >= MAXSKINS) return luaL_error(L, "skin number %d is out of range (%d - %d)", skinnum, TC_ALLWHITE, MAXSKINS-1); } else // skin name { const char *skinname = luaL_checkstring(L, 1); INT32 i = R_SkinAvailable(skinname); if (i != -1) // if -1, just default to TC_DEFAULT as above skinnum = i; } // all was successful above, now we generate the colormap at last! colormap = R_GetTranslationColormap(skinnum, color, GTC_CACHE); LUA_PushUserdata(L, colormap, META_COLORMAP); // push as META_COLORMAP userdata, specifically for patches to use! return 1; }
static int lib_getPlayer(lua_State *L) { const char *field; // i -> players[i] if (lua_type(L, 2) == LUA_TNUMBER) { lua_Integer i = luaL_checkinteger(L, 2); if (i < 0 || i >= MAXPLAYERS) return luaL_error(L, "players[] index %d out of range (0 - %d)", i, MAXPLAYERS-1); if (!playeringame[i]) return 0; if (!players[i].mo) return 0; LUA_PushUserdata(L, &players[i], META_PLAYER); return 1; } field = luaL_checkstring(L, 2); if (fastcmp(field,"iterate")) { lua_pushcfunction(L, lib_iteratePlayers); return 1; } return 0; }
// 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 LUAh_PlayerHook(player_t *plr, enum hook which) { hook_p hookp; boolean hooked = false; if (!gL || !(hooksAvailable[which/8] & (1<<(which%8)))) return false; lua_settop(gL, 0); for (hookp = roothook; hookp; hookp = hookp->next) if (hookp->type == which) { if (lua_gettop(gL) == 0) LUA_PushUserdata(gL, plr, META_PLAYER); lua_pushfstring(gL, FMT_HOOKID, hookp->id); lua_gettable(gL, LUA_REGISTRYINDEX); lua_pushvalue(gL, -2); if (lua_pcall(gL, 1, 1, 0)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); hookp->error = true; continue; } if (lua_toboolean(gL, -1)) hooked = true; lua_pop(gL, 1); } lua_settop(gL, 0); return hooked; }
static int subsector_get(lua_State *L) { subsector_t *subsector = *((subsector_t **)luaL_checkudata(L, 1, META_SUBSECTOR)); enum subsector_e field = luaL_checkoption(L, 2, subsector_opt[0], subsector_opt); if (!subsector) { if (field == subsector_valid) { lua_pushboolean(L, 0); return 1; } return luaL_error(L, "accessed subsector_t doesn't exist anymore."); } switch(field) { case subsector_valid: // valid lua_pushboolean(L, 1); return 1; case subsector_sector: LUA_PushUserdata(L, subsector->sector, META_SECTOR); return 1; case subsector_numlines: lua_pushinteger(L, subsector->numlines); return 1; case subsector_firstline: lua_pushinteger(L, subsector->firstline); return 1; case subsector_validcount: lua_pushinteger(L, subsector->validcount); return 1; } return 0; }
// Hook for P_DamageMobj by mobj type (Should mobj take damage?) UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage) { hook_p hookp; UINT8 shouldDamage = 0; // 0 = default, 1 = force yes, 2 = force no. if (!gL || !(hooksAvailable[hook_ShouldDamage/8] & (1<<(hook_ShouldDamage%8)))) return 0; lua_settop(gL, 0); for (hookp = roothook; hookp; hookp = hookp->next) if (hookp->type == hook_ShouldDamage && (hookp->s.mt == MT_NULL || hookp->s.mt == target->type)) { if (lua_gettop(gL) == 0) { LUA_PushUserdata(gL, target, META_MOBJ); LUA_PushUserdata(gL, inflictor, META_MOBJ); LUA_PushUserdata(gL, source, META_MOBJ); lua_pushinteger(gL, damage); } lua_pushfstring(gL, FMT_HOOKID, hookp->id); lua_gettable(gL, LUA_REGISTRYINDEX); lua_pushvalue(gL, -5); lua_pushvalue(gL, -5); lua_pushvalue(gL, -5); lua_pushvalue(gL, -5); if (lua_pcall(gL, 4, 1, 0)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); hookp->error = true; continue; } if (!lua_isnil(gL, -1)) { if (lua_toboolean(gL, -1)) shouldDamage = 1; // Force yes else shouldDamage = 2; // Force no } lua_pop(gL, 1); } lua_settop(gL, 0); return shouldDamage; }
static int libd_cachePatch(lua_State *L) { if (!hud_running) return luaL_error(L, "HUD rendering code should not be called outside of rendering hooks!"); LUA_PushUserdata(L, W_CachePatchName(luaL_checkstring(L, 1), PU_STATIC), META_PATCH); return 1; }
// Arbitrary S_sfx[] table index -> sfxinfo_t * static int lib_getSfxInfo(lua_State *L) { UINT32 i; lua_remove(L, 1); i = luaL_checkinteger(L, 1); LUA_PushUserdata(L, &S_sfx[i], META_SFXINFO); return 1; }
// Arbitrary mobjinfo[] table index -> mobjinfo_t * static int lib_getMobjInfo(lua_State *L) { UINT32 i; lua_remove(L, 1); i = luaL_checkinteger(L, 1); LUA_PushUserdata(L, &mobjinfo[i], META_MOBJINFO); return 1; }
// Arbitrary states[] table index -> state_t * static int lib_getState(lua_State *L) { UINT32 i; lua_remove(L, 1); i = luaL_checkinteger(L, 1); LUA_PushUserdata(L, &states[i], META_STATE); return 1; }
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; }
// Hook for mobj collisions UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which) { hook_p hookp; UINT8 shouldCollide = 0; // 0 = default, 1 = force yes, 2 = force no. if (!gL || !(hooksAvailable[which/8] & (1<<(which%8)))) return 0; lua_settop(gL, 0); for (hookp = roothook; hookp; hookp = hookp->next) if (hookp->type == which && (hookp->s.mt == MT_NULL || hookp->s.mt == thing1->type)) { if (lua_gettop(gL) == 0) { LUA_PushUserdata(gL, thing1, META_MOBJ); LUA_PushUserdata(gL, thing2, META_MOBJ); } lua_pushfstring(gL, FMT_HOOKID, hookp->id); lua_gettable(gL, LUA_REGISTRYINDEX); lua_pushvalue(gL, -3); lua_pushvalue(gL, -3); if (lua_pcall(gL, 2, 1, 0)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); hookp->error = true; continue; } if (!lua_isnil(gL, -1)) { // if nil, leave shouldCollide = 0. if (lua_toboolean(gL, -1)) shouldCollide = 1; // Force yes else shouldCollide = 2; // Force no } lua_pop(gL, 1); } lua_settop(gL, 0); return shouldCollide; }
static int lib_getHudInfo(lua_State *L) { UINT32 i; lua_remove(L, 1); i = luaL_checkinteger(L, 1); if (i >= NUMHUDITEMS) return luaL_error(L, "hudinfo[] index %d out of range (0 - %d)", i, NUMHUDITEMS-1); LUA_PushUserdata(L, &hudinfo[i], META_HUDINFO); return 1; }
// Hook for P_DamageMobj by mobj type (Mobj actually takes damage!) boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage) { hook_p hookp; boolean hooked = false; if (!gL || !(hooksAvailable[hook_MobjDamage/8] & (1<<(hook_MobjDamage%8)))) return 0; lua_settop(gL, 0); for (hookp = roothook; hookp; hookp = hookp->next) if (hookp->type == hook_MobjDamage && (hookp->s.mt == MT_NULL || hookp->s.mt == target->type)) { if (lua_gettop(gL) == 0) { LUA_PushUserdata(gL, target, META_MOBJ); LUA_PushUserdata(gL, inflictor, META_MOBJ); LUA_PushUserdata(gL, source, META_MOBJ); lua_pushinteger(gL, damage); } lua_pushfstring(gL, FMT_HOOKID, hookp->id); lua_gettable(gL, LUA_REGISTRYINDEX); lua_pushvalue(gL, -5); lua_pushvalue(gL, -5); lua_pushvalue(gL, -5); lua_pushvalue(gL, -5); if (lua_pcall(gL, 4, 1, 0)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); hookp->error = true; continue; } if (lua_toboolean(gL, -1)) hooked = true; lua_pop(gL, 1); } lua_settop(gL, 0); return hooked; }
// Helper function for "objects" search static UINT8 lib_searchBlockmap_Objects(lua_State *L, INT32 x, INT32 y, mobj_t *thing) { mobj_t *mobj, *bnext = NULL; if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight) return 0; // Check interaction with the objects in the blockmap. for (mobj = blocklinks[y*bmapwidth + x]; mobj; mobj = bnext) { P_SetTarget(&bnext, mobj->bnext); // We want to note our reference to bnext here incase it is MF_NOTHINK and gets removed! if (mobj == thing) continue; // our thing just found itself, so move on lua_pushvalue(L, 1); // push function LUA_PushUserdata(L, thing, META_MOBJ); LUA_PushUserdata(L, mobj, META_MOBJ); if (lua_pcall(gL, 2, 1, 0)) { if (!blockfuncerror || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); blockfuncerror = true; return 0; // *shrugs* } if (!lua_isnil(gL, -1)) { // if nil, continue if (lua_toboolean(gL, -1)) return 2; // stop whole search else return 1; // stop block search } lua_pop(gL, 1); if (P_MobjWasRemoved(thing) // func just popped our thing, cannot continue. || (bnext && P_MobjWasRemoved(bnext))) // func just broke blockmap chain, cannot continue. { P_SetTarget(&bnext, NULL); return (P_MobjWasRemoved(thing)) ? 2 : 1; } } return 0; }
// Hook for hurt messages boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source) { hook_p hookp; boolean hooked = false; if (!gL || !(hooksAvailable[hook_HurtMsg/8] & (1<<(hook_HurtMsg%8)))) return false; lua_settop(gL, 0); for (hookp = roothook; hookp; hookp = hookp->next) if (hookp->type == hook_HurtMsg && (hookp->s.mt == MT_NULL || (inflictor && hookp->s.mt == inflictor->type))) { if (lua_gettop(gL) == 0) { LUA_PushUserdata(gL, player, META_PLAYER); LUA_PushUserdata(gL, inflictor, META_MOBJ); LUA_PushUserdata(gL, source, META_MOBJ); } lua_pushfstring(gL, FMT_HOOKID, hookp->id); lua_gettable(gL, LUA_REGISTRYINDEX); lua_pushvalue(gL, -4); lua_pushvalue(gL, -4); lua_pushvalue(gL, -4); if (lua_pcall(gL, 3, 1, 0)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); hookp->error = true; continue; } if (lua_toboolean(gL, -1)) hooked = true; lua_pop(gL, 1); } lua_settop(gL, 0); return hooked; }
static int lib_iterateMapthings(lua_State *L) { size_t i = 0; lua_remove(L, 1); // state is unused. if (!lua_isnil(L, 1)) i = (size_t)(*((mapthing_t **)luaL_checkudata(L, 1, META_MAPTHING)) - mapthings) + 1; if (i < nummapthings) { LUA_PushUserdata(L, &mapthings[i], META_MAPTHING); return 1; } return 0; }
// Hook for P_TouchSpecialThing by mobj type boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher) { hook_p hookp; boolean hooked = false; if (!gL || !(hooksAvailable[hook_TouchSpecial/8] & (1<<(hook_TouchSpecial%8)))) return 0; lua_settop(gL, 0); for (hookp = roothook; hookp; hookp = hookp->next) if (hookp->type == hook_TouchSpecial && (hookp->s.mt == MT_NULL || hookp->s.mt == special->type)) { if (lua_gettop(gL) == 0) { LUA_PushUserdata(gL, special, META_MOBJ); LUA_PushUserdata(gL, toucher, META_MOBJ); } lua_pushfstring(gL, FMT_HOOKID, hookp->id); lua_gettable(gL, LUA_REGISTRYINDEX); lua_pushvalue(gL, -3); lua_pushvalue(gL, -3); if (lua_pcall(gL, 2, 1, 0)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); hookp->error = true; continue; } if (lua_toboolean(gL, -1)) hooked = true; lua_pop(gL, 1); } lua_settop(gL, 0); return hooked; }
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 int side_get(lua_State *L) { side_t *side = *((side_t **)luaL_checkudata(L, 1, META_SIDE)); enum side_e field = luaL_checkoption(L, 2, side_opt[0], side_opt); if (!side) { if (field == side_valid) { lua_pushboolean(L, 0); return 1; } return luaL_error(L, "accessed side_t doesn't exist anymore."); } switch(field) { case side_valid: // valid lua_pushboolean(L, 1); return 1; case side_textureoffset: lua_pushinteger(L, side->textureoffset); return 1; case side_rowoffset: lua_pushinteger(L, side->rowoffset); return 1; case side_toptexture: lua_pushinteger(L, side->toptexture); return 1; case side_bottomtexture: lua_pushinteger(L, side->bottomtexture); return 1; case side_midtexture: lua_pushinteger(L, side->midtexture); return 1; case side_sector: LUA_PushUserdata(L, side->sector, META_SECTOR); return 1; case side_special: lua_pushinteger(L, side->special); return 1; case side_repeatcnt: lua_pushinteger(L, side->repeatcnt); return 1; case side_text: lua_pushstring(L, side->text); return 1; } return 0; }
// Hook for B_BuildTiccmd boolean LUAh_BotTiccmd(player_t *bot, ticcmd_t *cmd) { hook_p hookp; boolean hooked = false; if (!gL || !(hooksAvailable[hook_BotTiccmd/8] & (1<<(hook_BotTiccmd%8)))) return false; lua_settop(gL, 0); for (hookp = roothook; hookp; hookp = hookp->next) if (hookp->type == hook_BotTiccmd) { if (lua_gettop(gL) == 0) { LUA_PushUserdata(gL, bot, META_PLAYER); LUA_PushUserdata(gL, cmd, META_TICCMD); } lua_pushfstring(gL, FMT_HOOKID, hookp->id); lua_gettable(gL, LUA_REGISTRYINDEX); lua_pushvalue(gL, -3); lua_pushvalue(gL, -3); if (lua_pcall(gL, 2, 1, 0)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); hookp->error = true; continue; } if (lua_toboolean(gL, -1)) hooked = true; lua_pop(gL, 1); } lua_settop(gL, 0); return hooked; }
static int lib_iterateMapthings(lua_State *L) { size_t i = 0; if (lua_gettop(L) < 2) return luaL_error(L, "Don't call mapthings.iterate() directly, use it as 'for mapthing in mapthings.iterate do <block> end'."); lua_settop(L, 2); lua_remove(L, 1); // state is unused. if (!lua_isnil(L, 1)) i = (size_t)(*((mapthing_t **)luaL_checkudata(L, 1, META_MAPTHING)) - mapthings) + 1; if (i < nummapthings) { LUA_PushUserdata(L, &mapthings[i], META_MAPTHING); return 1; } return 0; }
static int lib_iterateVertexes(lua_State *L) { size_t i = 0; if (lua_gettop(L) < 2) return luaL_error(L, "Don't call vertexes.iterate() directly, use it as 'for vertex in vertexes.iterate do <block> end'."); lua_settop(L, 2); lua_remove(L, 1); // state is unused. if (!lua_isnil(L, 1)) i = (size_t)(*((vertex_t **)luaL_checkudata(L, 1, META_VERTEX)) - vertexes)+1; if (i < numvertexes) { LUA_PushUserdata(L, &vertexes[i], META_VERTEX); return 1; } return 0; }