// 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; }
static int mobj_get(lua_State *L) { mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); enum mobj_e field = Lua_optoption(L, 2, NULL, mobj_opt); lua_settop(L, 2); if (!mo) { if (field == mobj_valid) { lua_pushboolean(L, 0); return 1; } return LUA_ErrInvalid(L, "mobj_t"); } switch(field) { case mobj_valid: lua_pushboolean(L, 1); break; case mobj_x: lua_pushinteger(L, mo->x); break; case mobj_y: lua_pushinteger(L, mo->y); break; case mobj_z: lua_pushinteger(L, mo->z); break; case mobj_snext: LUA_PushUserdata(L, mo->snext, META_MOBJ); break; case mobj_sprev: // sprev is actually the previous mobj's snext pointer, // or the subsector->sector->thing_list if there is no previous mobj, // i.e. it will always ultimately point to THIS mobj -- so that's actually not useful to Lua and won't be included. return UNIMPLEMENTED; case mobj_angle: lua_pushinteger(L, mo->angle); break; case mobj_sprite: lua_pushinteger(L, mo->sprite); break; case mobj_frame: lua_pushinteger(L, mo->frame); break; case mobj_touching_sectorlist: return UNIMPLEMENTED; case mobj_subsector: LUA_PushUserdata(L, mo->subsector, META_SUBSECTOR); break; case mobj_floorz: lua_pushinteger(L, mo->floorz); break; case mobj_ceilingz: lua_pushinteger(L, mo->ceilingz); break; case mobj_radius: lua_pushinteger(L, mo->radius); break; case mobj_height: lua_pushinteger(L, mo->height); break; case mobj_momx: lua_pushinteger(L, mo->momx); break; case mobj_momy: lua_pushinteger(L, mo->momy); break; case mobj_momz: lua_pushinteger(L, mo->momz); break; case mobj_pmomz: lua_pushinteger(L, mo->pmomz); break; case mobj_tics: lua_pushinteger(L, mo->tics); break; case mobj_state: // state number, not struct lua_pushinteger(L, mo->state-states); break; case mobj_flags: lua_pushinteger(L, mo->flags); break; case mobj_flags2: lua_pushinteger(L, mo->flags2); break; case mobj_eflags: lua_pushinteger(L, mo->eflags); break; case mobj_skin: // skin name or nil, not struct if (!mo->skin) return 0; lua_pushstring(L, ((skin_t *)mo->skin)->name); break; case mobj_color: lua_pushinteger(L, mo->color); break; case mobj_bnext: LUA_PushUserdata(L, mo->bnext, META_MOBJ); break; case mobj_bprev: // bprev -- same deal as sprev above, but for the blockmap. return UNIMPLEMENTED; case mobj_hnext: LUA_PushUserdata(L, mo->hnext, META_MOBJ); break; case mobj_hprev: // implimented differently from sprev and bprev because SSNTails. LUA_PushUserdata(L, mo->hprev, META_MOBJ); break; case mobj_type: lua_pushinteger(L, mo->type); break; case mobj_info: LUA_PushUserdata(L, &mobjinfo[mo->type], META_MOBJINFO); break; case mobj_health: lua_pushinteger(L, mo->health); break; case mobj_movedir: lua_pushinteger(L, mo->movedir); break; case mobj_movecount: lua_pushinteger(L, mo->movecount); break; case mobj_target: if (mo->target && P_MobjWasRemoved(mo->target)) { // don't put invalid mobj back into Lua. P_SetTarget(&mo->target, NULL); return 0; } LUA_PushUserdata(L, mo->target, META_MOBJ); break; case mobj_reactiontime: lua_pushinteger(L, mo->reactiontime); break; case mobj_threshold: lua_pushinteger(L, mo->threshold); break; case mobj_player: LUA_PushUserdata(L, mo->player, META_PLAYER); break; case mobj_lastlook: lua_pushinteger(L, mo->lastlook); break; case mobj_spawnpoint: LUA_PushUserdata(L, mo->spawnpoint, META_MAPTHING); break; case mobj_tracer: if (mo->tracer && P_MobjWasRemoved(mo->tracer)) { // don't put invalid mobj back into Lua. P_SetTarget(&mo->tracer, NULL); return 0; } LUA_PushUserdata(L, mo->tracer, META_MOBJ); break; case mobj_friction: lua_pushinteger(L, mo->friction); break; case mobj_movefactor: lua_pushinteger(L, mo->movefactor); break; case mobj_fuse: lua_pushinteger(L, mo->fuse); break; case mobj_watertop: lua_pushinteger(L, mo->watertop); break; case mobj_waterbottom: lua_pushinteger(L, mo->waterbottom); break; case mobj_mobjnum: // mobjnum is a networking thing generated for $$$.sav // and therefore shouldn't be used by Lua. return UNIMPLEMENTED; case mobj_scale: lua_pushinteger(L, mo->scale); break; case mobj_destscale: lua_pushinteger(L, mo->destscale); break; case mobj_scalespeed: lua_pushinteger(L, mo->scalespeed); break; case mobj_extravalue1: lua_pushinteger(L, mo->extravalue1); break; case mobj_extravalue2: lua_pushinteger(L, mo->extravalue2); break; case mobj_cusval: lua_pushinteger(L, mo->cusval); break; case mobj_cvmem: lua_pushinteger(L, mo->cvmem); break; default: // extra custom variables in Lua memory lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS); I_Assert(lua_istable(L, -1)); lua_pushlightuserdata(L, mo); lua_rawget(L, -2); if (!lua_istable(L, -1)) { // no extra values table CONS_Debug(DBG_LUA, M_GetText("'%s' has no extvars table or field named '%s'; returning nil.\n"), "mobj_t", lua_tostring(L, 2)); return 0; } lua_pushvalue(L, 2); // field name lua_gettable(L, -2); if (lua_isnil(L, -1)) // no value for this field CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; returning nil.\n"), "mobj_t", lua_tostring(L, 2)); break; } return 1; }
// Helper function for "lines" search static UINT8 lib_searchBlockmap_Lines(lua_State *L, INT32 x, INT32 y, mobj_t *thing) { INT32 offset; const INT32 *list; // Big blockmap #ifdef POLYOBJECTS polymaplink_t *plink; // haleyjd 02/22/06 #endif line_t *ld; if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight) return 0; offset = y*bmapwidth + x; #ifdef POLYOBJECTS // haleyjd 02/22/06: consider polyobject lines plink = polyblocklinks[offset]; while (plink) { polyobj_t *po = plink->po; if (po->validcount != validcount) // if polyobj hasn't been checked { size_t i; po->validcount = validcount; for (i = 0; i < po->numLines; ++i) { if (po->lines[i]->validcount == validcount) // line has been checked continue; po->lines[i]->validcount = validcount; lua_pushvalue(L, 1); LUA_PushUserdata(L, thing, META_MOBJ); LUA_PushUserdata(L, po->lines[i], META_LINE); 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)) return 2; } } plink = (polymaplink_t *)(plink->link.next); } #endif offset = *(blockmap + offset); // offset = blockmap[y*bmapwidth+x]; // First index is really empty, so +1 it. for (list = blockmaplump + offset + 1; *list != -1; list++) { ld = &lines[*list]; if (ld->validcount == validcount) continue; // Line has already been checked. ld->validcount = validcount; lua_pushvalue(L, 1); LUA_PushUserdata(L, thing, META_MOBJ); LUA_PushUserdata(L, ld, META_LINE); 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)) return 2; } return 0; // Everything was checked. }
// The searchBlockmap function // arguments: searchBlockmap(searchtype, function, mobj, [x1, x2, y1, y2]) // return value: // true = search completely uninteruppted, // false = searching of at least one block stopped mid-way (including if the whole search was stopped) static int lib_searchBlockmap(lua_State *L) { int searchtype = luaL_checkoption(L, 1, "objects", search_opt); int n; mobj_t *mobj; INT32 xl, xh, yl, yh, bx, by; fixed_t x1, x2, y1, y2; boolean retval = true; UINT8 funcret = 0; blockmap_func searchFunc; lua_remove(L, 1); // remove searchtype, stack is now function, mobj, [x1, x2, y1, y2] luaL_checktype(L, 1, LUA_TFUNCTION); switch (searchtype) { case 0: // "objects" default: searchFunc = lib_searchBlockmap_Objects; break; case 1: // "lines" searchFunc = lib_searchBlockmap_Lines; break; } // the mobj we are searching around, the "calling" mobj we could say mobj = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ)); if (!mobj) return LUA_ErrInvalid(L, "mobj_t"); n = lua_gettop(L); if (n > 2) // specific x/y ranges have been supplied { if (n < 6) return luaL_error(L, "arguments 4 to 6 not all given (expected 4 fixed-point integers)"); x1 = luaL_checkfixed(L, 3); x2 = luaL_checkfixed(L, 4); y1 = luaL_checkfixed(L, 5); y2 = luaL_checkfixed(L, 6); } else // mobj and function only - search around mobj's radius by default { fixed_t radius = mobj->radius + MAXRADIUS; x1 = mobj->x - radius; x2 = mobj->x + radius; y1 = mobj->y - radius; y2 = mobj->y + radius; } lua_settop(L, 2); // pop everything except function, mobj xl = (unsigned)(x1 - bmaporgx)>>MAPBLOCKSHIFT; xh = (unsigned)(x2 - bmaporgx)>>MAPBLOCKSHIFT; yl = (unsigned)(y1 - bmaporgy)>>MAPBLOCKSHIFT; yh = (unsigned)(y2 - bmaporgy)>>MAPBLOCKSHIFT; BMBOUNDFIX(xl, xh, yl, yh); blockfuncerror = false; // reset validcount++; for (bx = xl; bx <= xh; bx++) for (by = yl; by <= yh; by++) { funcret = searchFunc(L, bx, by, mobj); // return value of searchFunc determines searchFunc's return value and/or when to stop if (funcret == 2){ // stop whole search lua_pushboolean(L, false); // return false return 1; } else if (funcret == 1) // search was interrupted for this block retval = false; // this changes the return value, but doesn't stop the whole search // else don't do anything, continue as normal if (P_MobjWasRemoved(mobj)){ // ...unless the original object was removed lua_pushboolean(L, false); // in which case we have to stop now regardless return 1; } } lua_pushboolean(L, retval); return 1; }
// // P_Ticker // void P_Ticker(boolean run) { INT32 i; //Increment jointime even if paused. for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) ++players[i].jointime; if (objectplacing) { if (OP_FreezeObjectplace()) { P_MapStart(); OP_ObjectplaceMovement(&players[0]); P_MoveChaseCamera(&players[0], &camera, false); P_MapEnd(); return; } } // Check for pause or menu up in single player if (paused || P_MenuActivePause()) return; postimgtype = postimgtype2 = postimg_none; P_MapStart(); if (run) { if (demorecording) G_WriteDemoTiccmd(&players[consoleplayer].cmd, 0); if (demoplayback) G_ReadDemoTiccmd(&players[consoleplayer].cmd, 0); for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo)) P_PlayerThink(&players[i]); } // Keep track of how long they've been playing! totalplaytime++; if (!useNightsSS && G_IsSpecialStage(gamemap)) P_DoSpecialStageStuff(); if (runemeraldmanager) P_EmeraldManager(); // Power stone mode if (run) { P_RunThinkers(); // Run any "after all the other thinkers" stuff for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo)) P_PlayerAfterThink(&players[i]); #ifdef HAVE_BLUA LUAh_ThinkFrame(); #endif } // Run shield positioning P_RunShields(); P_UpdateSpecials(); P_RespawnSpecials(); // Lightning, rain sounds, etc. P_PrecipitationEffects(); if (run) leveltime++; timeinmap++; if (G_TagGametype()) P_DoTagStuff(); if (G_GametypeHasTeams()) P_DoCTFStuff(); if (run) { if (countdowntimer && --countdowntimer <= 0) { countdowntimer = 0; countdowntimeup = true; for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i] || players[i].spectator) continue; if (!players[i].mo) continue; P_DamageMobj(players[i].mo, NULL, NULL, 10000); } } if (countdown > 1) countdown--; if (countdown2) countdown2--; if (quake.time) { fixed_t ir = quake.intensity>>1; /// \todo Calculate distance from epicenter if set and modulate the intensity accordingly based on radius. quake.x = M_RandomRange(-ir,ir); quake.y = M_RandomRange(-ir,ir); quake.z = M_RandomRange(-ir,ir); --quake.time; } else