// SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2012-2016 by John "JTE" Muniz. // Copyright (C) 2012-2023 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. // See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- /// \file lua_maplib.c /// \brief game map library for Lua scripting #include "doomdef.h" #include "r_state.h" #include "p_local.h" #include "p_setup.h" #include "z_zone.h" #include "p_slopes.h" #include "p_polyobj.h" #include "r_main.h" #include "lua_script.h" #include "lua_libs.h" #include "lua_hud.h" // hud_running errors #include "lua_hook.h" // hook_cmd_running errors #include "dehacked.h" #include "fastcmp.h" #include "doomstat.h" enum sector_e { sector_valid = 0, sector_floorheight, sector_ceilingheight, sector_floorpic, sector_floorxoffset, sector_flooryoffset, sector_floorangle, sector_ceilingpic, sector_ceilingxoffset, sector_ceilingyoffset, sector_ceilingangle, sector_lightlevel, sector_floorlightlevel, sector_floorlightabsolute, sector_floorlightsec, sector_ceilinglightlevel, sector_ceilinglightabsolute, sector_ceilinglightsec, sector_special, sector_tag, sector_taglist, sector_thinglist, sector_heightsec, sector_camsec, sector_lines, sector_ffloors, sector_fslope, sector_cslope, sector_flags, sector_specialflags, sector_damagetype, sector_triggertag, sector_triggerer, sector_friction, sector_gravity, }; static const char *const sector_opt[] = { "valid", "floorheight", "ceilingheight", "floorpic", "floorxoffset", "flooryoffset", "floorangle", "ceilingpic", "ceilingxoffset", "ceilingyoffset", "ceilingangle", "lightlevel", "floorlightlevel", "floorlightabsolute", "floorlightsec", "ceilinglightlevel", "ceilinglightabsolute", "ceilinglightsec", "special", "tag", "taglist", "thinglist", "heightsec", "camsec", "lines", "ffloors", "f_slope", "c_slope", "flags", "specialflags", "damagetype", "triggertag", "triggerer", "friction", "gravity", NULL}; static int sector_fields_ref = LUA_NOREF; enum subsector_e { subsector_valid = 0, subsector_sector, subsector_numlines, subsector_firstline, subsector_polyList }; static const char *const subsector_opt[] = { "valid", "sector", "numlines", "firstline", "polyList", NULL}; static int subsector_fields_ref = LUA_NOREF; enum line_e { line_valid = 0, line_v1, line_v2, line_dx, line_dy, line_angle, line_flags, line_special, line_tag, line_taglist, line_args, line_stringargs, line_sidenum, line_frontside, line_backside, line_alpha, line_executordelay, line_slopetype, line_frontsector, line_backsector, line_polyobj, line_text, line_callcount }; static const char *const line_opt[] = { "valid", "v1", "v2", "dx", "dy", "angle", "flags", "special", "tag", "taglist", "args", "stringargs", "sidenum", "frontside", "backside", "alpha", "executordelay", "slopetype", "frontsector", "backsector", "polyobj", "text", "callcount", NULL}; static int line_fields_ref = LUA_NOREF; enum side_e { side_valid = 0, side_textureoffset, side_rowoffset, side_offsetx_top, side_offsety_top, side_offsetx_mid, side_offsety_mid, side_offsetx_bot, side_offsety_bot, side_toptexture, side_bottomtexture, side_midtexture, side_line, side_sector, side_special, side_repeatcnt, side_text }; static const char *const side_opt[] = { "valid", "textureoffset", "rowoffset", "offsetx_top", "offsety_top", "offsetx_mid", "offsety_mid", "offsetx_bot", "offsety_bot", "toptexture", "bottomtexture", "midtexture", "line", "sector", "special", "repeatcnt", "text", NULL}; static int side_fields_ref = LUA_NOREF; enum vertex_e { vertex_valid = 0, vertex_x, vertex_y, vertex_floorz, vertex_floorzset, vertex_ceilingz, vertex_ceilingzset }; static const char *const vertex_opt[] = { "valid", "x", "y", "floorz", "floorzset", "ceilingz", "ceilingzset", NULL}; static int vertex_fields_ref = LUA_NOREF; enum ffloor_e { ffloor_valid = 0, ffloor_topheight, ffloor_toppic, ffloor_toplightlevel, ffloor_bottomheight, ffloor_bottompic, ffloor_tslope, ffloor_bslope, ffloor_sector, ffloor_fofflags, ffloor_flags, ffloor_master, ffloor_target, ffloor_next, ffloor_prev, ffloor_alpha, ffloor_blend, ffloor_bustflags, ffloor_busttype, ffloor_busttag, ffloor_sinkspeed, ffloor_friction, ffloor_bouncestrength, }; static const char *const ffloor_opt[] = { "valid", "topheight", "toppic", "toplightlevel", "bottomheight", "bottompic", "t_slope", "b_slope", "sector", // secnum pushed as control sector userdata "fofflags", "flags", "master", // control linedef "target", // target sector "next", "prev", "alpha", "blend", "bustflags", "busttype", "busttag", "sinkspeed", "friction", "bouncestrength", NULL}; static int ffloor_fields_ref = LUA_NOREF; #ifdef HAVE_LUA_SEGS enum seg_e { seg_valid = 0, seg_v1, seg_v2, seg_side, seg_offset, seg_angle, seg_sidedef, seg_linedef, seg_frontsector, seg_backsector, seg_polyseg }; static const char *const seg_opt[] = { "valid", "v1", "v2", "side", "offset", "angle", "sidedef", "linedef", "frontsector", "backsector", "polyseg", NULL}; static int seg_fields_ref = LUA_NOREF; enum node_e { node_valid = 0, node_x, node_y, node_dx, node_dy, node_bbox, node_children, }; static const char *const node_opt[] = { "valid", "x", "y", "dx", "dy", "bbox", "children", NULL}; static int node_fields_ref = LUA_NOREF; enum nodechild_e { nodechild_valid = 0, nodechild_right, nodechild_left, }; static const char *const nodechild_opt[] = { "valid", "right", "left", NULL}; #endif enum bbox_e { bbox_valid = 0, bbox_top, bbox_bottom, bbox_left, bbox_right, }; static const char *const bbox_opt[] = { "valid", "top", "bottom", "left", "right", NULL}; enum slope_e { slope_valid = 0, slope_o, slope_d, slope_zdelta, slope_normal, slope_zangle, slope_xydirection, slope_flags }; static const char *const slope_opt[] = { "valid", "o", "d", "zdelta", "normal", "zangle", "xydirection", "flags", NULL}; static int slope_fields_ref = LUA_NOREF; // shared by both vector2_t and vector3_t enum vector_e { vector_x = 0, vector_y, vector_z }; static const char *const vector_opt[] = { "x", "y", "z", NULL}; static const char *const array_opt[] ={"iterate",NULL}; static const char *const valid_opt[] ={"valid",NULL}; ///////////////////////////////////////////// // sector/subsector list iterate functions // ///////////////////////////////////////////// // iterates through a sector's thinglist! static int lib_iterateSectorThinglist(lua_State *L) { mobj_t *state = NULL; mobj_t *thing = NULL; INLEVEL if (lua_gettop(L) < 2) return luaL_error(L, "Don't call sector.thinglist() directly, use it as 'for rover in sector.thinglist do 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; } // iterates through the ffloors list in a sector! static int lib_iterateSectorFFloors(lua_State *L) { ffloor_t *state = NULL; ffloor_t *ffloor = NULL; INLEVEL if (lua_gettop(L) < 2) return luaL_error(L, "Don't call sector.ffloors() directly, use it as 'for rover in sector.ffloors do 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 subsector's polyList! (for polyobj_t) static int lib_iterateSubSectorPolylist(lua_State *L) { polyobj_t *state = NULL; polyobj_t *po = NULL; INLEVEL if (lua_gettop(L) < 2) return luaL_error(L, "Don't call subsector.polyList() directly, use it as 'for polyobj in subsector.polyList do end'."); if (!lua_isnil(L, 1)) state = *((polyobj_t **)luaL_checkudata(L, 1, META_POLYOBJ)); else return 0; // no polylist to iterate through sorry! lua_settop(L, 2); lua_remove(L, 1); // remove state now. if (!lua_isnil(L, 1)) { po = *((polyobj_t **)luaL_checkudata(L, 1, META_POLYOBJ)); po = (polyobj_t *)(po->link.next); } else po = state; // state is used as the "start" of the polylist if (po) { LUA_PushUserdata(L, po, META_POLYOBJ); return 1; } return 0; } static int sector_iterate(lua_State *L) { lua_pushvalue(L, lua_upvalueindex(1)); // iterator function, or the "generator" lua_pushvalue(L, lua_upvalueindex(2)); // state (used as the "start" of the list for our purposes lua_pushnil(L); // initial value (unused) return 3; } //////////////////// // sector.lines[] // //////////////////// // sector.lines, i -> sector.lines[i] // sector.lines.valid, for validity checking // // 25/9/19 Monster Iestyn // Modified this and _num to use triple pointers, to allow for a new hack of mine involving offsetof // this way we don't need to check frontsector or backsector of line #0 in the array // static int sectorlines_get(lua_State *L) { line_t ***seclines = *((line_t ****)luaL_checkudata(L, 1, META_SECTORLINES)); size_t i; size_t numoflines = 0; lua_settop(L, 2); if (!lua_isnumber(L, 2)) { int field = luaL_checkoption(L, 2, NULL, valid_opt); if (!seclines || !(*seclines)) { if (field == 0) { lua_pushboolean(L, 0); return 1; } return luaL_error(L, "accessed sector_t.lines doesn't exist anymore."); } else if (field == 0) { lua_pushboolean(L, 1); return 1; } } /* a snip from sector_t struct in r_defs.h, for reference size_t linecount; struct line_s **lines; // [linecount] size */ // get the "linecount" by shifting our retrieved memory address of "lines" to where "linecount" is in the sector_t, then dereferencing the result // we need this to determine the array's actual size, and therefore also the maximum value allowed as an index // this only works if seclines is actually a pointer to a sector's lines member in memory, oh boy numoflines = *(size_t *)FIELDFROM (sector_t, seclines, lines,/* -> */linecount); /* OLD HACK // check first linedef to figure which of its sectors owns this sector->lines pointer // then check that sector's linecount to get a maximum index //if (!(*seclines)[0]) //return luaL_error(L, "no lines found!"); // no first linedef????? if ((*seclines)[0]->frontsector->lines == *seclines) numoflines = (*seclines)[0]->frontsector->linecount; else if ((*seclines)[0]->backsector && *seclines[0]->backsector->lines == *seclines) // check backsector exists first numoflines = (*seclines)[0]->backsector->linecount; //if neither sector has it then ??? */ if (!numoflines) return luaL_error(L, "no lines found!"); i = (size_t)lua_tointeger(L, 2); if (i >= numoflines) return 0; LUA_PushUserdata(L, (*seclines)[i], META_LINE); return 1; } // #(sector.lines) -> sector.linecount static int sectorlines_num(lua_State *L) { line_t ***seclines = *((line_t ****)luaL_checkudata(L, 1, META_SECTORLINES)); size_t numoflines = 0; if (!seclines || !(*seclines)) return luaL_error(L, "accessed sector_t.lines doesn't exist anymore."); // see comments in the _get function above numoflines = *(size_t *)FIELDFROM (sector_t, seclines, lines,/* -> */linecount); lua_pushinteger(L, numoflines); return 1; } ////////////// // sector_t // ////////////// static int sector_get(lua_State *L) { sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR)); enum sector_e field = Lua_optoption(L, 2, sector_valid, sector_fields_ref); INT16 i; if (!sector) { if (field == sector_valid) { lua_pushboolean(L, 0); return 1; } return luaL_error(L, "accessed sector_t doesn't exist anymore."); } switch(field) { case sector_valid: // valid lua_pushboolean(L, 1); return 1; case sector_floorheight: lua_pushfixed(L, sector->floorheight); return 1; case sector_ceilingheight: lua_pushfixed(L, sector->ceilingheight); return 1; case sector_floorpic: // floorpic { levelflat_t *levelflat = &levelflats[sector->floorpic]; for (i = 0; i < 8; i++) if (!levelflat->name[i]) break; lua_pushlstring(L, levelflat->name, i); return 1; } case sector_floorxoffset: { lua_pushfixed(L, sector->floorxoffset); return 1; } case sector_flooryoffset: { lua_pushfixed(L, sector->flooryoffset); return 1; } case sector_floorangle: { lua_pushangle(L, sector->floorangle); return 1; } case sector_ceilingpic: // ceilingpic { levelflat_t *levelflat = &levelflats[sector->ceilingpic]; for (i = 0; i < 8; i++) if (!levelflat->name[i]) break; lua_pushlstring(L, levelflat->name, i); return 1; } case sector_ceilingxoffset: { lua_pushfixed(L, sector->ceilingxoffset); return 1; } case sector_ceilingyoffset: { lua_pushfixed(L, sector->ceilingyoffset); return 1; } case sector_ceilingangle: { lua_pushangle(L, sector->ceilingangle); return 1; } case sector_lightlevel: lua_pushinteger(L, sector->lightlevel); return 1; case sector_floorlightlevel: lua_pushinteger(L, sector->floorlightlevel); return 1; case sector_floorlightabsolute: lua_pushboolean(L, sector->floorlightabsolute); return 1; case sector_floorlightsec: lua_pushinteger(L, sector->floorlightsec); return 1; case sector_ceilinglightlevel: lua_pushinteger(L, sector->ceilinglightlevel); return 1; case sector_ceilinglightabsolute: lua_pushboolean(L, sector->ceilinglightabsolute); return 1; case sector_ceilinglightsec: lua_pushinteger(L, sector->ceilinglightsec); return 1; case sector_special: lua_pushinteger(L, sector->special); return 1; case sector_tag: lua_pushinteger(L, (UINT16)Tag_FGet(§or->tags)); return 1; case sector_taglist: LUA_PushUserdata(L, §or->tags, META_SECTORTAGLIST); return 1; case sector_thinglist: // thinglist lua_pushcfunction(L, lib_iterateSectorThinglist); LUA_PushUserdata(L, sector->thinglist, META_MOBJ); lua_pushcclosure(L, sector_iterate, 2); // push lib_iterateSectorThinglist and sector->thinglist as upvalues for the function return 1; case sector_heightsec: // heightsec - fake floor heights if (sector->heightsec < 0) return 0; LUA_PushUserdata(L, §ors[sector->heightsec], META_SECTOR); return 1; case sector_camsec: // camsec - camera clipping heights if (sector->camsec < 0) return 0; LUA_PushUserdata(L, §ors[sector->camsec], META_SECTOR); return 1; case sector_lines: // lines LUA_PushUserdata(L, §or->lines, META_SECTORLINES); // push the address of the "lines" member in the struct, to allow our hacks in sectorlines_get/_num to work return 1; case sector_ffloors: // ffloors lua_pushcfunction(L, lib_iterateSectorFFloors); LUA_PushUserdata(L, sector->ffloors, META_FFLOOR); lua_pushcclosure(L, sector_iterate, 2); // push lib_iterateFFloors and sector->ffloors as upvalues for the function return 1; case sector_fslope: // f_slope LUA_PushUserdata(L, sector->f_slope, META_SLOPE); return 1; case sector_cslope: // c_slope LUA_PushUserdata(L, sector->c_slope, META_SLOPE); return 1; case sector_flags: // flags lua_pushinteger(L, sector->flags); return 1; case sector_specialflags: // specialflags lua_pushinteger(L, sector->specialflags); return 1; case sector_damagetype: // damagetype lua_pushinteger(L, (UINT8)sector->damagetype); return 1; case sector_triggertag: // triggertag lua_pushinteger(L, (INT16)sector->triggertag); return 1; case sector_triggerer: // triggerer lua_pushinteger(L, (UINT8)sector->triggerer); return 1; case sector_friction: // friction lua_pushfixed(L, sector->friction); return 1; case sector_gravity: // gravity lua_pushfixed(L, sector->gravity); return 1; } return 0; } static int sector_set(lua_State *L) { sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR)); enum sector_e field = Lua_optoption(L, 2, sector_valid, sector_fields_ref); if (!sector) return luaL_error(L, "accessed sector_t doesn't exist anymore."); if (hud_running) return luaL_error(L, "Do not alter sector_t in HUD rendering code!"); if (hook_cmd_running) return luaL_error(L, "Do not alter sector_t in CMD building code!"); switch(field) { case sector_valid: // valid case sector_thinglist: // thinglist case sector_heightsec: // heightsec case sector_camsec: // camsec case sector_lines: // lines case sector_ffloors: // ffloors case sector_fslope: // f_slope case sector_cslope: // c_slope case sector_friction: // friction return luaL_error(L, "sector_t field " LUA_QS " cannot be set.", sector_opt[field]); default: return luaL_error(L, "sector_t has no field named " LUA_QS ".", lua_tostring(L, 2)); case sector_floorheight: { // floorheight boolean flag; mobj_t *ptmthing = tmthing; fixed_t lastpos = sector->floorheight; sector->floorheight = luaL_checkfixed(L, 3); flag = P_CheckSector(sector, true); if (flag && sector->numattached) { sector->floorheight = lastpos; P_CheckSector(sector, true); } P_SetTarget(&tmthing, ptmthing); break; } case sector_ceilingheight: { // ceilingheight boolean flag; mobj_t *ptmthing = tmthing; fixed_t lastpos = sector->ceilingheight; sector->ceilingheight = luaL_checkfixed(L, 3); flag = P_CheckSector(sector, true); if (flag && sector->numattached) { sector->ceilingheight = lastpos; P_CheckSector(sector, true); } P_SetTarget(&tmthing, ptmthing); break; } case sector_floorpic: sector->floorpic = P_AddLevelFlatRuntime(luaL_checkstring(L, 3)); break; case sector_floorxoffset: sector->floorxoffset = luaL_checkfixed(L, 3); break; case sector_flooryoffset: sector->flooryoffset = luaL_checkfixed(L, 3); break; case sector_floorangle: sector->floorangle = luaL_checkangle(L, 3); break; case sector_ceilingpic: sector->ceilingpic = P_AddLevelFlatRuntime(luaL_checkstring(L, 3)); break; case sector_ceilingxoffset: sector->ceilingxoffset = luaL_checkfixed(L, 3); break; case sector_ceilingyoffset: sector->ceilingyoffset = luaL_checkfixed(L, 3); break; case sector_ceilingangle: sector->ceilingangle = luaL_checkangle(L, 3); break; case sector_lightlevel: sector->lightlevel = (INT16)luaL_checkinteger(L, 3); break; case sector_floorlightlevel: sector->floorlightlevel = (INT16)luaL_checkinteger(L, 3); break; case sector_floorlightabsolute: sector->floorlightabsolute = luaL_checkboolean(L, 3); break; case sector_floorlightsec: sector->floorlightsec = (INT32)luaL_checkinteger(L, 3); break; case sector_ceilinglightlevel: sector->ceilinglightlevel = (INT16)luaL_checkinteger(L, 3); break; case sector_ceilinglightabsolute: sector->ceilinglightabsolute = luaL_checkboolean(L, 3); break; case sector_ceilinglightsec: sector->ceilinglightsec = (INT32)luaL_checkinteger(L, 3); break; case sector_special: sector->special = (INT16)luaL_checkinteger(L, 3); break; case sector_tag: Tag_SectorFSet((UINT32)(sector - sectors), (INT16)luaL_checkinteger(L, 3)); break; case sector_taglist: return LUA_ErrSetDirectly(L, "sector_t", "taglist"); case sector_flags: sector->flags = luaL_checkinteger(L, 3); CheckForReverseGravity |= (sector->flags & MSF_GRAVITYFLIP); break; case sector_specialflags: sector->specialflags = luaL_checkinteger(L, 3); break; case sector_damagetype: sector->damagetype = (UINT8)luaL_checkinteger(L, 3); break; case sector_triggertag: sector->triggertag = (INT16)luaL_checkinteger(L, 3); break; case sector_triggerer: sector->triggerer = (UINT8)luaL_checkinteger(L, 3); break; case sector_gravity: sector->gravity = luaL_checkfixed(L, 3); break; } return 0; } static int sector_num(lua_State *L) { sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR)); lua_pushinteger(L, sector-sectors); return 1; } ///////////////// // subsector_t // ///////////////// static int subsector_get(lua_State *L) { subsector_t *subsector = *((subsector_t **)luaL_checkudata(L, 1, META_SUBSECTOR)); enum subsector_e field = Lua_optoption(L, 2, subsector_valid, subsector_fields_ref); 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_polyList: // polyList lua_pushcfunction(L, lib_iterateSubSectorPolylist); LUA_PushUserdata(L, subsector->polyList, META_POLYOBJ); lua_pushcclosure(L, sector_iterate, 2); // push lib_iterateSubSectorPolylist and subsector->polyList as upvalues for the function return 1; } return 0; } static int subsector_num(lua_State *L) { subsector_t *subsector = *((subsector_t **)luaL_checkudata(L, 1, META_SUBSECTOR)); lua_pushinteger(L, subsector-subsectors); return 1; } //////////// // line_t // //////////// // args, i -> args[i] static int lineargs_get(lua_State *L) { INT32 *args = *((INT32**)luaL_checkudata(L, 1, META_LINEARGS)); int i = luaL_checkinteger(L, 2); if (i < 0 || i >= NUMLINEARGS) return luaL_error(L, LUA_QL("line_t.args") " index cannot be %d", i); lua_pushinteger(L, args[i]); return 1; } // #args -> NUMLINEARGS static int lineargs_len(lua_State* L) { lua_pushinteger(L, NUMLINEARGS); return 1; } // stringargs, i -> stringargs[i] static int linestringargs_get(lua_State *L) { char **stringargs = *((char***)luaL_checkudata(L, 1, META_LINESTRINGARGS)); int i = luaL_checkinteger(L, 2); if (i < 0 || i >= NUMLINESTRINGARGS) return luaL_error(L, LUA_QL("line_t.stringargs") " index cannot be %d", i); lua_pushstring(L, stringargs[i]); return 1; } // #stringargs -> NUMLINESTRINGARGS static int linestringargs_len(lua_State *L) { lua_pushinteger(L, NUMLINESTRINGARGS); return 1; } static int line_get(lua_State *L) { line_t *line = *((line_t **)luaL_checkudata(L, 1, META_LINE)); enum line_e field = Lua_optoption(L, 2, line_valid, line_fields_ref); if (!line) { if (field == line_valid) { lua_pushboolean(L, 0); return 1; } return luaL_error(L, "accessed line_t doesn't exist anymore."); } switch(field) { case line_valid: // valid lua_pushboolean(L, 1); return 1; case line_v1: LUA_PushUserdata(L, line->v1, META_VERTEX); return 1; case line_v2: LUA_PushUserdata(L, line->v2, META_VERTEX); return 1; case line_dx: lua_pushfixed(L, line->dx); return 1; case line_dy: lua_pushfixed(L, line->dy); return 1; case line_angle: lua_pushangle(L, line->angle); return 1; case line_flags: lua_pushinteger(L, line->flags); return 1; case line_special: lua_pushinteger(L, line->special); return 1; case line_tag: // TODO: 2.3: Always return a unsigned value lua_pushinteger(L, Tag_FGet(&line->tags)); return 1; case line_taglist: LUA_PushUserdata(L, &line->tags, META_TAGLIST); return 1; case line_args: LUA_PushUserdata(L, line->args, META_LINEARGS); return 1; case line_stringargs: LUA_PushUserdata(L, line->stringargs, META_LINESTRINGARGS); return 1; case line_sidenum: LUA_PushUserdata(L, line->sidenum, META_SIDENUM); return 1; case line_frontside: // frontside LUA_PushUserdata(L, &sides[line->sidenum[0]], META_SIDE); return 1; case line_backside: // backside if (line->sidenum[1] == 0xffff) return 0; LUA_PushUserdata(L, &sides[line->sidenum[1]], META_SIDE); return 1; case line_alpha: lua_pushfixed(L, line->alpha); return 1; case line_executordelay: lua_pushinteger(L, line->executordelay); return 1; case line_slopetype: switch(line->slopetype) { case ST_HORIZONTAL: lua_pushliteral(L, "horizontal"); break; case ST_VERTICAL: lua_pushliteral(L, "vertical"); break; case ST_POSITIVE: lua_pushliteral(L, "positive"); break; case ST_NEGATIVE: lua_pushliteral(L, "negative"); break; } return 1; case line_frontsector: LUA_PushUserdata(L, line->frontsector, META_SECTOR); return 1; case line_backsector: LUA_PushUserdata(L, line->backsector, META_SECTOR); return 1; case line_polyobj: LUA_PushUserdata(L, line->polyobj, META_POLYOBJ); return 1; case line_text: { if (udmf) { LUA_Deprecated(L, "(linedef_t).text", "(linedef_t).stringargs"); lua_pushnil(L); return 1; } if (line->special == 331 || line->special == 443) { // See P_ProcessLinedefsAfterSidedefs, P_ConvertBinaryLinedefTypes lua_pushstring(L, line->stringargs[0]); } else lua_pushnil(L); return 1; } case line_callcount: lua_pushinteger(L, line->callcount); return 1; } return 0; } static int line_num(lua_State *L) { line_t *line = *((line_t **)luaL_checkudata(L, 1, META_LINE)); lua_pushinteger(L, line-lines); return 1; } //////////////////// // line.sidenum[] // //////////////////// static int sidenum_get(lua_State *L) { UINT16 *sidenum = *((UINT16 **)luaL_checkudata(L, 1, META_SIDENUM)); int i; lua_settop(L, 2); if (!lua_isnumber(L, 2)) { int field = luaL_checkoption(L, 2, NULL, valid_opt); if (!sidenum) { if (field == 0) { lua_pushboolean(L, 0); return 1; } return luaL_error(L, "accessed line_t doesn't exist anymore."); } else if (field == 0) { lua_pushboolean(L, 1); return 1; } } i = lua_tointeger(L, 2); if (i < 0 || i > 1) return 0; lua_pushinteger(L, sidenum[i]); return 1; } //////////// // side_t // //////////// static int side_get(lua_State *L) { side_t *side = *((side_t **)luaL_checkudata(L, 1, META_SIDE)); enum side_e field = Lua_optoption(L, 2, side_valid, side_fields_ref); 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_pushfixed(L, side->textureoffset); return 1; case side_rowoffset: lua_pushfixed(L, side->rowoffset); return 1; case side_offsetx_top: lua_pushfixed(L, side->offsetx_top); return 1; case side_offsety_top: lua_pushfixed(L, side->offsety_top); return 1; case side_offsetx_mid: lua_pushfixed(L, side->offsetx_mid); return 1; case side_offsety_mid: lua_pushfixed(L, side->offsety_mid); return 1; case side_offsetx_bot: lua_pushfixed(L, side->offsetx_bot); return 1; case side_offsety_bot: lua_pushfixed(L, side->offsety_bot); 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_line: LUA_PushUserdata(L, side->line, META_LINE); 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: { if (udmf) { LUA_Deprecated(L, "(sidedef_t).text", "(sidedef_t).line.stringargs"); lua_pushnil(L); return 1; } boolean isfrontside = side->line->sidenum[0] == side-sides; lua_pushstring(L, side->line->stringargs[isfrontside ? 0 : 1]); return 1; } } return 0; } static int side_set(lua_State *L) { side_t *side = *((side_t **)luaL_checkudata(L, 1, META_SIDE)); enum side_e field = Lua_optoption(L, 2, side_valid, side_fields_ref); 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 case side_line: case side_sector: case side_special: case side_text: return luaL_error(L, "side_t field " LUA_QS " cannot be set.", side_opt[field]); default: return luaL_error(L, "side_t has no field named " LUA_QS ".", lua_tostring(L, 2)); case side_textureoffset: side->textureoffset = luaL_checkfixed(L, 3); break; case side_rowoffset: side->rowoffset = luaL_checkfixed(L, 3); break; case side_offsetx_top: side->offsetx_top = luaL_checkfixed(L, 3); break; case side_offsety_top: side->offsety_top = luaL_checkfixed(L, 3); break; case side_offsetx_mid: side->offsetx_mid = luaL_checkfixed(L, 3); break; case side_offsety_mid: side->offsety_mid = luaL_checkfixed(L, 3); break; case side_offsetx_bot: side->offsetx_bot = luaL_checkfixed(L, 3); break; case side_offsety_bot: side->offsety_bot = luaL_checkfixed(L, 3); break; case side_toptexture: side->toptexture = luaL_checkinteger(L, 3); break; case side_bottomtexture: side->bottomtexture = luaL_checkinteger(L, 3); break; case side_midtexture: side->midtexture = luaL_checkinteger(L, 3); break; case side_repeatcnt: side->repeatcnt = luaL_checkinteger(L, 3); break; } return 0; } static int side_num(lua_State *L) { side_t *side = *((side_t **)luaL_checkudata(L, 1, META_SIDE)); lua_pushinteger(L, side-sides); return 1; } ////////////// // vertex_t // ////////////// static int vertex_get(lua_State *L) { vertex_t *vertex = *((vertex_t **)luaL_checkudata(L, 1, META_VERTEX)); enum vertex_e field = Lua_optoption(L, 2, vertex_valid, vertex_fields_ref); if (!vertex) { if (field == vertex_valid) { lua_pushboolean(L, 0); return 1; } return luaL_error(L, "accessed vertex_t doesn't exist anymore."); } switch(field) { case vertex_valid: // valid lua_pushboolean(L, 1); return 1; case vertex_x: lua_pushfixed(L, vertex->x); return 1; case vertex_y: lua_pushfixed(L, vertex->y); return 1; case vertex_floorzset: lua_pushboolean(L, vertex->floorzset); return 1; case vertex_ceilingzset: lua_pushboolean(L, vertex->ceilingzset); return 1; case vertex_floorz: lua_pushfixed(L, vertex->floorz); return 1; case vertex_ceilingz: lua_pushfixed(L, vertex->ceilingz); return 1; } return 0; } static int vertex_num(lua_State *L) { vertex_t *vertex = *((vertex_t **)luaL_checkudata(L, 1, META_VERTEX)); lua_pushinteger(L, vertex-vertexes); return 1; } #ifdef HAVE_LUA_SEGS /////////// // seg_t // /////////// static int seg_get(lua_State *L) { seg_t *seg = *((seg_t **)luaL_checkudata(L, 1, META_SEG)); enum seg_e field = Lua_optoption(L, 2, seg_valid, seg_fields_ref); if (!seg) { if (field == seg_valid) { lua_pushboolean(L, 0); return 1; } return luaL_error(L, "accessed seg_t doesn't exist anymore."); } switch(field) { case seg_valid: // valid lua_pushboolean(L, 1); return 1; case seg_v1: LUA_PushUserdata(L, seg->v1, META_VERTEX); return 1; case seg_v2: LUA_PushUserdata(L, seg->v2, META_VERTEX); return 1; case seg_side: lua_pushinteger(L, seg->side); return 1; case seg_offset: lua_pushfixed(L, seg->offset); return 1; case seg_angle: lua_pushangle(L, seg->angle); return 1; case seg_sidedef: LUA_PushUserdata(L, seg->sidedef, META_SIDE); return 1; case seg_linedef: LUA_PushUserdata(L, seg->linedef, META_LINE); return 1; case seg_frontsector: LUA_PushUserdata(L, seg->frontsector, META_SECTOR); return 1; case seg_backsector: LUA_PushUserdata(L, seg->backsector, META_SECTOR); return 1; case seg_polyseg: LUA_PushUserdata(L, seg->polyseg, META_POLYOBJ); return 1; } return 0; } static int seg_num(lua_State *L) { seg_t *seg = *((seg_t **)luaL_checkudata(L, 1, META_SEG)); lua_pushinteger(L, seg-segs); return 1; } //////////// // node_t // //////////// static int node_get(lua_State *L) { node_t *node = *((node_t **)luaL_checkudata(L, 1, META_NODE)); enum node_e field = Lua_optoption(L, 2, node_valid, node_fields_ref); if (!node) { if (field == node_valid) { lua_pushboolean(L, 0); return 1; } return luaL_error(L, "accessed node_t doesn't exist anymore."); } switch(field) { case node_valid: // valid lua_pushboolean(L, 1); return 1; case node_x: lua_pushfixed(L, node->x); return 1; case node_y: lua_pushfixed(L, node->y); return 1; case node_dx: lua_pushfixed(L, node->x); return 1; case node_dy: lua_pushfixed(L, node->x); return 1; case node_bbox: LUA_PushUserdata(L, node->bbox, META_NODEBBOX); return 1; case node_children: LUA_PushUserdata(L, node->children, META_NODECHILDREN); return 1; } return 0; } static int node_num(lua_State *L) { node_t *node = *((node_t **)luaL_checkudata(L, 1, META_NODE)); lua_pushinteger(L, node-nodes); return 1; } /////////////// // node.bbox // /////////////// /* // node.bbox[i][j]: i = 0 or 1, j = 0 1 2 or 3 // NOTE: 2D arrays are NOT double pointers, // the second bbox will be directly after the first in memory (hence the way the bbox is pushed here) // this function handles the [i] part, bbox_get handles the [j] part static int nodebbox_get(lua_State *L) { fixed_t *bbox = *((fixed_t **)luaL_checkudata(L, 1, META_NODEBBOX)); int i; lua_settop(L, 2); if (!lua_isnumber(L, 2)) { int field = luaL_checkoption(L, 2, NULL, valid_opt); if (!bbox) { if (field == 0) { lua_pushboolean(L, 0); return 1; } return luaL_error(L, "accessed node_t doesn't exist anymore."); } else if (field == 0) { lua_pushboolean(L, 1); return 1; } } i = lua_tointeger(L, 2); if (i < 0 || i > 1) return 0; LUA_PushUserdata(L, bbox + i*4*sizeof(fixed_t), META_BBOX); return 1; } */ static int nodebbox_call(lua_State *L) { fixed_t *bbox = *((fixed_t **)luaL_checkudata(L, 1, META_NODEBBOX)); int i, j; int n = lua_gettop(L); if (!bbox) return luaL_error(L, "accessed node bbox doesn't exist anymore."); if (n < 3) return luaL_error(L, "arguments 2 and/or 3 not given (expected node.bbox(child, coord))"); // get child if (!lua_isnumber(L, 2)) { enum nodechild_e field = luaL_checkoption(L, 2, nodechild_opt[0], nodechild_opt); switch (field) { case nodechild_right: i = 0; break; case nodechild_left: i = 1; break; default: return luaL_error(L, "invalid node child \"%s\".", lua_tostring(L, 2)); } } else { i = lua_tointeger(L, 2); if (i < 0 || i > 1) return 0; } // get bbox coord if (!lua_isnumber(L, 3)) { enum bbox_e field = luaL_checkoption(L, 3, bbox_opt[0], bbox_opt); switch (field) { case bbox_top: j = BOXTOP; break; case bbox_bottom: j = BOXBOTTOM; break; case bbox_left: j = BOXLEFT; break; case bbox_right: j = BOXRIGHT; break; default: return luaL_error(L, "invalid bbox coordinate \"%s\".", lua_tostring(L, 3)); } } else { j = lua_tointeger(L, 3); if (j < 0 || j > 3) return 0; } lua_pushinteger(L, bbox[i*4 + j]); return 1; } ///////////////////// // node.children[] // ///////////////////// // node.children[i]: i = 0 or 1 static int nodechildren_get(lua_State *L) { UINT16 *children = *((UINT16 **)luaL_checkudata(L, 1, META_NODECHILDREN)); int i; lua_settop(L, 2); if (!lua_isnumber(L, 2)) { enum nodechild_e field = luaL_checkoption(L, 2, nodechild_opt[0], nodechild_opt); if (!children) { if (field == nodechild_valid) { lua_pushboolean(L, 0); return 1; } return luaL_error(L, "accessed node_t doesn't exist anymore."); } else if (field == nodechild_valid) { lua_pushboolean(L, 1); return 1; } else switch (field) { case nodechild_right: i = 0; break; case nodechild_left: i = 1; break; default: return 0; } } else { i = lua_tointeger(L, 2); if (i < 0 || i > 1) return 0; } lua_pushinteger(L, children[i]); return 1; } #endif ////////// // bbox // ////////// // bounding box (aka fixed_t array with four elements) // NOTE: may be useful for polyobjects or other things later static int bbox_get(lua_State *L) { fixed_t *bbox = *((fixed_t **)luaL_checkudata(L, 1, META_BBOX)); int i; lua_settop(L, 2); if (!lua_isnumber(L, 2)) { enum bbox_e field = luaL_checkoption(L, 2, bbox_opt[0], bbox_opt); if (!bbox) { if (field == bbox_valid) { lua_pushboolean(L, 0); return 1; } return luaL_error(L, "accessed bbox doesn't exist anymore."); } else if (field == bbox_valid) { lua_pushboolean(L, 1); return 1; } else switch (field) { case bbox_top: i = BOXTOP; break; case bbox_bottom: i = BOXBOTTOM; break; case bbox_left: i = BOXLEFT; break; case bbox_right: i = BOXRIGHT; break; default: return 0; } } else { i = lua_tointeger(L, 2); if (i < 0 || i > 3) return 0; } lua_pushinteger(L, bbox[i]); return 1; } /////////////// // sectors[] // /////////////// static int lib_iterateSectors(lua_State *L) { size_t i = 0; INLEVEL if (lua_gettop(L) < 2) return luaL_error(L, "Don't call sectors.iterate() directly, use it as 'for sector in sectors.iterate do end'."); lua_settop(L, 2); lua_remove(L, 1); // state is unused. if (!lua_isnil(L, 1)) i = (size_t)(*((sector_t **)luaL_checkudata(L, 1, META_SECTOR)) - sectors)+1; if (i < numsectors) { LUA_PushUserdata(L, §ors[i], META_SECTOR); return 1; } return 0; } static int lib_getSector(lua_State *L) { INLEVEL if (lua_isnumber(L, 2)) { size_t i = lua_tointeger(L, 2); if (i >= numsectors) return 0; LUA_PushUserdata(L, §ors[i], META_SECTOR); return 1; } return 0; } static int lib_numsectors(lua_State *L) { lua_pushinteger(L, numsectors); return 1; } ////////////////// // subsectors[] // ////////////////// static int lib_iterateSubsectors(lua_State *L) { size_t i = 0; INLEVEL if (lua_gettop(L) < 2) return luaL_error(L, "Don't call subsectors.iterate() directly, use it as 'for subsector in subsectors.iterate do end'."); lua_settop(L, 2); lua_remove(L, 1); // state is unused. if (!lua_isnil(L, 1)) i = (size_t)(*((subsector_t **)luaL_checkudata(L, 1, META_SUBSECTOR)) - subsectors)+1; if (i < numsubsectors) { LUA_PushUserdata(L, &subsectors[i], META_SUBSECTOR); return 1; } return 0; } static int lib_getSubsector(lua_State *L) { int field; INLEVEL 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); if (i >= numsubsectors) return 0; LUA_PushUserdata(L, &subsectors[i], META_SUBSECTOR); 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 lib_numsubsectors(lua_State *L) { lua_pushinteger(L, numsubsectors); return 1; } ///////////// // lines[] // ///////////// static int lib_iterateLines(lua_State *L) { size_t i = 0; INLEVEL if (lua_gettop(L) < 2) return luaL_error(L, "Don't call lines.iterate() directly, use it as 'for line in lines.iterate do end'."); lua_settop(L, 2); lua_remove(L, 1); // state is unused. if (!lua_isnil(L, 1)) i = (size_t)(*((line_t **)luaL_checkudata(L, 1, META_LINE)) - lines)+1; if (i < numlines) { LUA_PushUserdata(L, &lines[i], META_LINE); return 1; } return 0; } static int lib_getLine(lua_State *L) { INLEVEL if (lua_isnumber(L, 2)) { size_t i = lua_tointeger(L, 2); if (i >= numlines) return 0; LUA_PushUserdata(L, &lines[i], META_LINE); return 1; } return 0; } static int lib_numlines(lua_State *L) { lua_pushinteger(L, numlines); return 1; } ///////////// // sides[] // ///////////// static int lib_iterateSides(lua_State *L) { size_t i = 0; INLEVEL if (lua_gettop(L) < 2) return luaL_error(L, "Don't call sides.iterate() directly, use it as 'for side in sides.iterate do end'."); lua_settop(L, 2); lua_remove(L, 1); // state is unused. if (!lua_isnil(L, 1)) i = (size_t)(*((side_t **)luaL_checkudata(L, 1, META_SIDE)) - sides)+1; if (i < numsides) { LUA_PushUserdata(L, &sides[i], META_SIDE); return 1; } return 0; } static int lib_getSide(lua_State *L) { int field; INLEVEL 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); if (i >= numsides) return 0; LUA_PushUserdata(L, &sides[i], META_SIDE); return 1; } field = luaL_checkoption(L, 1, NULL, array_opt); switch(field) { case 0: // iterate lua_pushcfunction(L, lib_iterateSides); return 1; } return 0; } static int lib_numsides(lua_State *L) { lua_pushinteger(L, numsides); return 1; } //////////////// // vertexes[] // //////////////// static int lib_iterateVertexes(lua_State *L) { size_t i = 0; INLEVEL if (lua_gettop(L) < 2) return luaL_error(L, "Don't call vertexes.iterate() directly, use it as 'for vertex in vertexes.iterate do 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; } static int lib_getVertex(lua_State *L) { int field; INLEVEL 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); if (i >= numvertexes) return 0; LUA_PushUserdata(L, &vertexes[i], META_VERTEX); return 1; } field = luaL_checkoption(L, 1, NULL, array_opt); switch(field) { case 0: // iterate lua_pushcfunction(L, lib_iterateVertexes); return 1; } return 0; } static int lib_numvertexes(lua_State *L) { lua_pushinteger(L, numvertexes); return 1; } #ifdef HAVE_LUA_SEGS //////////// // segs[] // //////////// static int lib_iterateSegs(lua_State *L) { size_t i = 0; INLEVEL if (lua_gettop(L) < 2) return luaL_error(L, "Don't call segs.iterate() directly, use it as 'for seg in segs.iterate do end'."); lua_settop(L, 2); lua_remove(L, 1); // state is unused. if (!lua_isnil(L, 1)) i = (size_t)(*((seg_t **)luaL_checkudata(L, 1, META_SEG)) - segs)+1; if (i < numsegs) { LUA_PushUserdata(L, &segs[i], META_SEG); return 1; } return 0; } static int lib_getSeg(lua_State *L) { int field; INLEVEL 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); if (i >= numsegs) return 0; LUA_PushUserdata(L, &segs[i], META_SEG); return 1; } field = luaL_checkoption(L, 1, NULL, array_opt); switch(field) { case 0: // iterate lua_pushcfunction(L, lib_iterateSegs); return 1; } return 0; } static int lib_numsegs(lua_State *L) { lua_pushinteger(L, numsegs); return 1; } ///////////// // nodes[] // ///////////// static int lib_iterateNodes(lua_State *L) { size_t i = 0; INLEVEL if (lua_gettop(L) < 2) return luaL_error(L, "Don't call nodes.iterate() directly, use it as 'for node in nodes.iterate do end'."); lua_settop(L, 2); lua_remove(L, 1); // state is unused. if (!lua_isnil(L, 1)) i = (size_t)(*((node_t **)luaL_checkudata(L, 1, META_NODE)) - nodes)+1; if (i < numsegs) { LUA_PushUserdata(L, &nodes[i], META_NODE); return 1; } return 0; } static int lib_getNode(lua_State *L) { int field; INLEVEL 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); if (i >= numnodes) return 0; LUA_PushUserdata(L, &nodes[i], META_NODE); return 1; } field = luaL_checkoption(L, 1, NULL, array_opt); switch(field) { case 0: // iterate lua_pushcfunction(L, lib_iterateNodes); return 1; } return 0; } static int lib_numnodes(lua_State *L) { lua_pushinteger(L, numnodes); return 1; } #endif ////////////// // ffloor_t // ////////////// static INT32 P_GetOldFOFFlags(ffloor_t *fflr) { INT32 result = 0; if (fflr->fofflags & FOF_EXISTS) result |= FF_OLD_EXISTS; if (fflr->fofflags & FOF_BLOCKPLAYER) result |= FF_OLD_BLOCKPLAYER; if (fflr->fofflags & FOF_BLOCKOTHERS) result |= FF_OLD_BLOCKOTHERS; if (fflr->fofflags & FOF_RENDERSIDES) result |= FF_OLD_RENDERSIDES; if (fflr->fofflags & FOF_RENDERPLANES) result |= FF_OLD_RENDERPLANES; if (fflr->fofflags & FOF_SWIMMABLE) result |= FF_OLD_SWIMMABLE; if (fflr->fofflags & FOF_NOSHADE) result |= FF_OLD_NOSHADE; if (fflr->fofflags & FOF_CUTSOLIDS) result |= FF_OLD_CUTSOLIDS; if (fflr->fofflags & FOF_CUTEXTRA) result |= FF_OLD_CUTEXTRA; if (fflr->fofflags & FOF_CUTSPRITES) result |= FF_OLD_CUTSPRITES; if (fflr->fofflags & FOF_BOTHPLANES) result |= FF_OLD_BOTHPLANES; if (fflr->fofflags & FOF_EXTRA) result |= FF_OLD_EXTRA; if (fflr->fofflags & FOF_TRANSLUCENT) result |= FF_OLD_TRANSLUCENT; if (fflr->fofflags & FOF_FOG) result |= FF_OLD_FOG; if (fflr->fofflags & FOF_INVERTPLANES) result |= FF_OLD_INVERTPLANES; if (fflr->fofflags & FOF_ALLSIDES) result |= FF_OLD_ALLSIDES; if (fflr->fofflags & FOF_INVERTSIDES) result |= FF_OLD_INVERTSIDES; if (fflr->fofflags & FOF_DOUBLESHADOW) result |= FF_OLD_DOUBLESHADOW; if (fflr->fofflags & FOF_FLOATBOB) result |= FF_OLD_FLOATBOB; if (fflr->fofflags & FOF_NORETURN) result |= FF_OLD_NORETURN; if (fflr->fofflags & FOF_CRUMBLE) result |= FF_OLD_CRUMBLE; if (fflr->bustflags & FB_ONLYBOTTOM) result |= FF_OLD_SHATTERBOTTOM; if (fflr->fofflags & FOF_GOOWATER) result |= FF_OLD_GOOWATER; if (fflr->fofflags & FOF_MARIO) result |= FF_OLD_MARIO; if (fflr->fofflags & FOF_BUSTUP) result |= FF_OLD_BUSTUP; if (fflr->fofflags & FOF_QUICKSAND) result |= FF_OLD_QUICKSAND; if (fflr->fofflags & FOF_PLATFORM) result |= FF_OLD_PLATFORM; if (fflr->fofflags & FOF_REVERSEPLATFORM) result |= FF_OLD_REVERSEPLATFORM; if (fflr->fofflags & FOF_INTANGIBLEFLATS) result |= FF_OLD_INTANGIBLEFLATS; if (fflr->busttype == BT_TOUCH) result |= FF_OLD_SHATTER; if (fflr->busttype == BT_SPINBUST) result |= FF_OLD_SPINBUST; if (fflr->busttype == BT_STRONG) result |= FF_OLD_STRONGBUST; if (fflr->fofflags & FOF_RIPPLE) result |= FF_OLD_RIPPLE; if (fflr->fofflags & FOF_COLORMAPONLY) result |= FF_OLD_COLORMAPONLY; return result; } static int ffloor_get(lua_State *L) { ffloor_t *ffloor = *((ffloor_t **)luaL_checkudata(L, 1, META_FFLOOR)); enum ffloor_e field = Lua_optoption(L, 2, ffloor_valid, ffloor_fields_ref); INT16 i; if (!ffloor) { if (field == ffloor_valid) { lua_pushboolean(L, 0); return 1; } return luaL_error(L, "accessed ffloor_t doesn't exist anymore."); } switch(field) { case ffloor_valid: // valid lua_pushboolean(L, 1); return 1; case ffloor_topheight: lua_pushfixed(L, *ffloor->topheight); return 1; case ffloor_toppic: { // toppic levelflat_t *levelflat = &levelflats[*ffloor->toppic]; for (i = 0; i < 8; i++) if (!levelflat->name[i]) break; lua_pushlstring(L, levelflat->name, i); return 1; } case ffloor_toplightlevel: lua_pushinteger(L, *ffloor->toplightlevel); return 1; case ffloor_bottomheight: lua_pushfixed(L, *ffloor->bottomheight); return 1; case ffloor_bottompic: { // bottompic levelflat_t *levelflat = &levelflats[*ffloor->bottompic]; for (i = 0; i < 8; i++) if (!levelflat->name[i]) break; lua_pushlstring(L, levelflat->name, i); return 1; } case ffloor_tslope: LUA_PushUserdata(L, *ffloor->t_slope, META_SLOPE); return 1; case ffloor_bslope: LUA_PushUserdata(L, *ffloor->b_slope, META_SLOPE); return 1; case ffloor_sector: LUA_PushUserdata(L, §ors[ffloor->secnum], META_SECTOR); return 1; case ffloor_fofflags: lua_pushinteger(L, ffloor->fofflags); return 1; case ffloor_flags: lua_pushinteger(L, P_GetOldFOFFlags(ffloor)); return 1; case ffloor_master: LUA_PushUserdata(L, ffloor->master, META_LINE); return 1; case ffloor_target: LUA_PushUserdata(L, ffloor->target, META_SECTOR); return 1; case ffloor_next: LUA_PushUserdata(L, ffloor->next, META_FFLOOR); return 1; case ffloor_prev: LUA_PushUserdata(L, ffloor->prev, META_FFLOOR); return 1; case ffloor_alpha: lua_pushinteger(L, ffloor->alpha); return 1; case ffloor_blend: lua_pushinteger(L, ffloor->blend); return 1; case ffloor_bustflags: lua_pushinteger(L, ffloor->bustflags); return 1; case ffloor_busttype: lua_pushinteger(L, ffloor->busttype); return 1; case ffloor_busttag: lua_pushinteger(L, ffloor->busttag); return 1; case ffloor_sinkspeed: lua_pushfixed(L, ffloor->sinkspeed); return 1; case ffloor_friction: lua_pushfixed(L, ffloor->friction); return 1; case ffloor_bouncestrength: lua_pushfixed(L, ffloor->bouncestrength); return 1; } return 0; } static void P_SetOldFOFFlags(ffloor_t *fflr, oldffloortype_e oldflags) { ffloortype_e originalflags = fflr->fofflags; fflr->fofflags = 0; if (oldflags & FF_OLD_EXISTS) fflr->fofflags |= FOF_EXISTS; if (oldflags & FF_OLD_BLOCKPLAYER) fflr->fofflags |= FOF_BLOCKPLAYER; if (oldflags & FF_OLD_BLOCKOTHERS) fflr->fofflags |= FOF_BLOCKOTHERS; if (oldflags & FF_OLD_RENDERSIDES) fflr->fofflags |= FOF_RENDERSIDES; if (oldflags & FF_OLD_RENDERPLANES) fflr->fofflags |= FOF_RENDERPLANES; if (oldflags & FF_OLD_SWIMMABLE) fflr->fofflags |= FOF_SWIMMABLE; if (oldflags & FF_OLD_NOSHADE) fflr->fofflags |= FOF_NOSHADE; if (oldflags & FF_OLD_CUTSOLIDS) fflr->fofflags |= FOF_CUTSOLIDS; if (oldflags & FF_OLD_CUTEXTRA) fflr->fofflags |= FOF_CUTEXTRA; if (oldflags & FF_OLD_CUTSPRITES) fflr->fofflags |= FOF_CUTSPRITES; if (oldflags & FF_OLD_BOTHPLANES) fflr->fofflags |= FOF_BOTHPLANES; if (oldflags & FF_OLD_EXTRA) fflr->fofflags |= FOF_EXTRA; if (oldflags & FF_OLD_TRANSLUCENT) fflr->fofflags |= FOF_TRANSLUCENT; if (oldflags & FF_OLD_FOG) fflr->fofflags |= FOF_FOG; if (oldflags & FF_OLD_INVERTPLANES) fflr->fofflags |= FOF_INVERTPLANES; if (oldflags & FF_OLD_ALLSIDES) fflr->fofflags |= FOF_ALLSIDES; if (oldflags & FF_OLD_INVERTSIDES) fflr->fofflags |= FOF_INVERTSIDES; if (oldflags & FF_OLD_DOUBLESHADOW) fflr->fofflags |= FOF_DOUBLESHADOW; if (oldflags & FF_OLD_FLOATBOB) fflr->fofflags |= FOF_FLOATBOB; if (oldflags & FF_OLD_NORETURN) fflr->fofflags |= FOF_NORETURN; if (oldflags & FF_OLD_CRUMBLE) fflr->fofflags |= FOF_CRUMBLE; if (oldflags & FF_OLD_GOOWATER) fflr->fofflags |= FOF_GOOWATER; if (oldflags & FF_OLD_MARIO) fflr->fofflags |= FOF_MARIO; if (oldflags & FF_OLD_BUSTUP) fflr->fofflags |= FOF_BUSTUP; if (oldflags & FF_OLD_QUICKSAND) fflr->fofflags |= FOF_QUICKSAND; if (oldflags & FF_OLD_PLATFORM) fflr->fofflags |= FOF_PLATFORM; if (oldflags & FF_OLD_REVERSEPLATFORM) fflr->fofflags |= FOF_REVERSEPLATFORM; if (oldflags & FF_OLD_RIPPLE) fflr->fofflags |= FOF_RIPPLE; if (oldflags & FF_OLD_COLORMAPONLY) fflr->fofflags |= FOF_COLORMAPONLY; if (originalflags & FOF_BOUNCY) fflr->fofflags |= FOF_BOUNCY; if (originalflags & FOF_SPLAT) fflr->fofflags |= FOF_SPLAT; if (oldflags & FF_OLD_SHATTER) fflr->busttype = BT_TOUCH; else if (oldflags & FF_OLD_SPINBUST) fflr->busttype = BT_SPINBUST; else if (oldflags & FF_OLD_STRONGBUST) fflr->busttype = BT_STRONG; else fflr->busttype = BT_REGULAR; if (oldflags & FF_OLD_SHATTERBOTTOM) fflr->bustflags |= FB_ONLYBOTTOM; else fflr->bustflags &= ~FB_ONLYBOTTOM; } static int ffloor_set(lua_State *L) { ffloor_t *ffloor = *((ffloor_t **)luaL_checkudata(L, 1, META_FFLOOR)); enum ffloor_e field = Lua_optoption(L, 2, ffloor_valid, ffloor_fields_ref); if (!ffloor) return luaL_error(L, "accessed ffloor_t doesn't exist anymore."); if (hud_running) return luaL_error(L, "Do not alter ffloor_t in HUD rendering code!"); if (hook_cmd_running) return luaL_error(L, "Do not alter ffloor_t in CMD building code!"); switch(field) { case ffloor_valid: // valid case ffloor_tslope: // t_slope case ffloor_bslope: // b_slope case ffloor_sector: // sector case ffloor_master: // master case ffloor_target: // target case ffloor_next: // next case ffloor_prev: // prev return luaL_error(L, "ffloor_t field " LUA_QS " cannot be set.", ffloor_opt[field]); default: return luaL_error(L, "ffloor_t has no field named " LUA_QS ".", lua_tostring(L, 2)); case ffloor_topheight: { // topheight boolean flag; fixed_t lastpos = *ffloor->topheight; mobj_t *ptmthing = tmthing; sector_t *sector = §ors[ffloor->secnum]; sector->ceilingheight = luaL_checkfixed(L, 3); flag = P_CheckSector(sector, true); if (flag && sector->numattached) { *ffloor->topheight = lastpos; P_CheckSector(sector, true); } P_SetTarget(&tmthing, ptmthing); break; } case ffloor_toppic: *ffloor->toppic = P_AddLevelFlatRuntime(luaL_checkstring(L, 3)); break; case ffloor_toplightlevel: *ffloor->toplightlevel = (INT16)luaL_checkinteger(L, 3); break; case ffloor_bottomheight: { // bottomheight boolean flag; fixed_t lastpos = *ffloor->bottomheight; mobj_t *ptmthing = tmthing; sector_t *sector = §ors[ffloor->secnum]; sector->floorheight = luaL_checkfixed(L, 3); flag = P_CheckSector(sector, true); if (flag && sector->numattached) { *ffloor->bottomheight = lastpos; P_CheckSector(sector, true); } P_SetTarget(&tmthing, ptmthing); break; } case ffloor_bottompic: *ffloor->bottompic = P_AddLevelFlatRuntime(luaL_checkstring(L, 3)); break; case ffloor_fofflags: { ffloortype_e oldflags = ffloor->fofflags; // store FOF's old flags ffloor->fofflags = luaL_checkinteger(L, 3); if (ffloor->fofflags != oldflags) ffloor->target->moved = true; // reset target sector's lightlist break; } case ffloor_flags: { ffloortype_e oldflags = ffloor->fofflags; // store FOF's old flags busttype_e oldbusttype = ffloor->busttype; ffloorbustflags_e oldbustflags = ffloor->bustflags; oldffloortype_e newflags = luaL_checkinteger(L, 3); P_SetOldFOFFlags(ffloor, newflags); if (ffloor->fofflags != oldflags || ffloor->busttype != oldbusttype || ffloor->bustflags != oldbustflags) ffloor->target->moved = true; // reset target sector's lightlist break; } case ffloor_alpha: ffloor->alpha = (INT32)luaL_checkinteger(L, 3); break; case ffloor_blend: ffloor->blend = (INT32)luaL_checkinteger(L, 3); break; } return 0; } ////////////// // pslope_t // ////////////// static int slope_get(lua_State *L) { pslope_t *slope = *((pslope_t **)luaL_checkudata(L, 1, META_SLOPE)); enum slope_e field = Lua_optoption(L, 2, slope_valid, slope_fields_ref); if (!slope) { if (field == slope_valid) { lua_pushboolean(L, 0); return 1; } return luaL_error(L, "accessed pslope_t doesn't exist anymore."); } switch(field) { case slope_valid: // valid lua_pushboolean(L, 1); return 1; case slope_o: // o LUA_PushUserdata(L, &slope->o, META_VECTOR3); return 1; case slope_d: // d LUA_PushUserdata(L, &slope->d, META_VECTOR2); return 1; case slope_zdelta: // zdelta lua_pushfixed(L, slope->zdelta); return 1; case slope_normal: // normal LUA_PushUserdata(L, &slope->normal, META_VECTOR3); return 1; case slope_zangle: // zangle lua_pushangle(L, slope->zangle); return 1; case slope_xydirection: // xydirection lua_pushangle(L, slope->xydirection); return 1; case slope_flags: // flags lua_pushinteger(L, slope->flags); return 1; } return 0; } static int slope_set(lua_State *L) { pslope_t *slope = *((pslope_t **)luaL_checkudata(L, 1, META_SLOPE)); enum slope_e field = Lua_optoption(L, 2, slope_valid, slope_fields_ref); if (!slope) return luaL_error(L, "accessed pslope_t doesn't exist anymore."); if (hud_running) return luaL_error(L, "Do not alter pslope_t in HUD rendering code!"); if (hook_cmd_running) return luaL_error(L, "Do not alter pslope_t in CMD building code!"); switch(field) // todo: reorganize this shit { case slope_valid: // valid case slope_d: // d case slope_flags: // flags case slope_normal: // normal return luaL_error(L, "pslope_t field " LUA_QS " cannot be set.", slope_opt[field]); default: return luaL_error(L, "pslope_t has no field named " LUA_QS ".", lua_tostring(L, 2)); case slope_o: { // o luaL_checktype(L, 3, LUA_TTABLE); lua_getfield(L, 3, "x"); if (lua_isnil(L, -1)) { lua_pop(L, 1); lua_rawgeti(L, 3, 1); } if (!lua_isnil(L, -1)) slope->o.x = luaL_checkfixed(L, -1); else slope->o.x = 0; lua_pop(L, 1); lua_getfield(L, 3, "y"); if (lua_isnil(L, -1)) { lua_pop(L, 1); lua_rawgeti(L, 3, 2); } if (!lua_isnil(L, -1)) slope->o.y = luaL_checkfixed(L, -1); else slope->o.y = 0; lua_pop(L, 1); lua_getfield(L, 3, "z"); if (lua_isnil(L, -1)) { lua_pop(L, 1); lua_rawgeti(L, 3, 3); } if (!lua_isnil(L, -1)) slope->o.z = luaL_checkfixed(L, -1); else slope->o.z = 0; lua_pop(L, 1); break; } case slope_zdelta: { // zdelta, this is temp until i figure out wtf to do slope->zdelta = luaL_checkfixed(L, 3); slope->zangle = R_PointToAngle2(0, 0, FRACUNIT, -slope->zdelta); P_CalculateSlopeNormal(slope); break; } case slope_zangle: { // zangle angle_t zangle = luaL_checkangle(L, 3); if (zangle == ANGLE_90 || zangle == ANGLE_270) return luaL_error(L, "invalid zangle for slope!"); slope->zangle = zangle; slope->zdelta = -FINETANGENT(((slope->zangle+ANGLE_90)>>ANGLETOFINESHIFT) & 4095); P_CalculateSlopeNormal(slope); break; } case slope_xydirection: // xydirection slope->xydirection = luaL_checkangle(L, 3); slope->d.x = -FINECOSINE((slope->xydirection>>ANGLETOFINESHIFT) & FINEMASK); slope->d.y = -FINESINE((slope->xydirection>>ANGLETOFINESHIFT) & FINEMASK); P_CalculateSlopeNormal(slope); break; } return 0; } /////////////// // vector*_t // /////////////// static int vector2_get(lua_State *L) { vector2_t *vec = *((vector2_t **)luaL_checkudata(L, 1, META_VECTOR2)); enum vector_e field = luaL_checkoption(L, 2, vector_opt[0], vector_opt); if (!vec) return luaL_error(L, "accessed vector2_t doesn't exist anymore."); switch(field) { case vector_x: lua_pushfixed(L, vec->x); return 1; case vector_y: lua_pushfixed(L, vec->y); return 1; default: break; } return 0; } static int vector3_get(lua_State *L) { vector3_t *vec = *((vector3_t **)luaL_checkudata(L, 1, META_VECTOR3)); enum vector_e field = luaL_checkoption(L, 2, vector_opt[0], vector_opt); if (!vec) return luaL_error(L, "accessed vector3_t doesn't exist anymore."); switch(field) { case vector_x: lua_pushfixed(L, vec->x); return 1; case vector_y: lua_pushfixed(L, vec->y); return 1; case vector_z: lua_pushfixed(L, vec->z); return 1; default: break; } return 0; } ///////////////////// // mapheaderinfo[] // ///////////////////// 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 lib_nummapheaders(lua_State *L) { lua_pushinteger(L, NUMMAPS); return 1; } ///////////////// // mapheader_t // ///////////////// enum mapheaderinfo_e { mapheaderinfo_lvlttl, mapheaderinfo_subttl, mapheaderinfo_actnum, mapheaderinfo_typeoflevel, mapheaderinfo_nextlevel, mapheaderinfo_marathonnext, mapheaderinfo_keywords, mapheaderinfo_musname, mapheaderinfo_mustrack, mapheaderinfo_muspos, mapheaderinfo_musinterfadeout, mapheaderinfo_musintername, mapheaderinfo_muspostbossname, mapheaderinfo_muspostbosstrack, mapheaderinfo_muspostbosspos, mapheaderinfo_muspostbossfadein, mapheaderinfo_musforcereset, mapheaderinfo_forcecharacter, mapheaderinfo_weather, mapheaderinfo_skynum, mapheaderinfo_skybox_scalex, mapheaderinfo_skybox_scaley, mapheaderinfo_skybox_scalez, mapheaderinfo_interscreen, mapheaderinfo_runsoc, mapheaderinfo_scriptname, mapheaderinfo_precutscenenum, mapheaderinfo_cutscenenum, mapheaderinfo_countdown, mapheaderinfo_palette, mapheaderinfo_numlaps, mapheaderinfo_unlockrequired, mapheaderinfo_levelselect, mapheaderinfo_bonustype, mapheaderinfo_ltzzpatch, mapheaderinfo_ltzztext, mapheaderinfo_ltactdiamond, mapheaderinfo_maxbonuslives, mapheaderinfo_levelflags, mapheaderinfo_menuflags, mapheaderinfo_selectheading, mapheaderinfo_startrings, mapheaderinfo_sstimer, mapheaderinfo_ssspheres, mapheaderinfo_gravity, }; static const char *const mapheaderinfo_opt[] = { "lvlttl", "subttl", "actnum", "typeoflevel", "nextlevel", "marathonnext", "keywords", "musname", "mustrack", "muspos", "musinterfadeout", "musintername", "muspostbossname", "muspostbosstrack", "muspostbosspos", "muspostbossfadein", "musforcereset", "forcecharacter", "weather", "skynum", "skybox_scalex", "skybox_scaley", "skybox_scalez", "interscreen", "runsoc", "scriptname", "precutscenenum", "cutscenenum", "countdown", "palette", "numlaps", "unlockrequired", "levelselect", "bonustype", "ltzzpatch", "ltzztext", "ltactdiamond", "maxbonuslives", "levelflags", "menuflags", "selectheading", "startrings", "sstimer", "ssspheres", "gravity", NULL, }; static int mapheaderinfo_fields_ref = LUA_NOREF; static int mapheaderinfo_get(lua_State *L) { mapheader_t *header = *((mapheader_t **)luaL_checkudata(L, 1, META_MAPHEADER)); enum mapheaderinfo_e field = Lua_optoption(L, 2, -1, mapheaderinfo_fields_ref); INT16 i; switch (field) { case mapheaderinfo_lvlttl: lua_pushstring(L, header->lvlttl); break; case mapheaderinfo_subttl: lua_pushstring(L, header->subttl); break; case mapheaderinfo_actnum: lua_pushinteger(L, header->actnum); break; case mapheaderinfo_typeoflevel: lua_pushinteger(L, header->typeoflevel); break; case mapheaderinfo_nextlevel: lua_pushinteger(L, header->nextlevel); break; case mapheaderinfo_marathonnext: lua_pushinteger(L, header->marathonnext); break; case mapheaderinfo_keywords: lua_pushstring(L, header->keywords); break; case mapheaderinfo_musname: lua_pushstring(L, header->musname); break; case mapheaderinfo_mustrack: lua_pushinteger(L, header->mustrack); break; case mapheaderinfo_muspos: lua_pushinteger(L, header->muspos); break; case mapheaderinfo_musinterfadeout: lua_pushinteger(L, header->musinterfadeout); break; case mapheaderinfo_musintername: lua_pushstring(L, header->musintername); break; case mapheaderinfo_muspostbossname: lua_pushstring(L, header->muspostbossname); break; case mapheaderinfo_muspostbosstrack: lua_pushinteger(L, header->muspostbosstrack); break; case mapheaderinfo_muspostbosspos: lua_pushinteger(L, header->muspostbosspos); break; case mapheaderinfo_muspostbossfadein: lua_pushinteger(L, header->muspostbossfadein); break; case mapheaderinfo_musforcereset: lua_pushinteger(L, header->musforcereset); break; case mapheaderinfo_forcecharacter: lua_pushstring(L, header->forcecharacter); break; case mapheaderinfo_weather: lua_pushinteger(L, header->weather); break; case mapheaderinfo_skynum: lua_pushinteger(L, header->skynum); break; case mapheaderinfo_skybox_scalex: lua_pushinteger(L, header->skybox_scalex); break; case mapheaderinfo_skybox_scaley: lua_pushinteger(L, header->skybox_scaley); break; case mapheaderinfo_skybox_scalez: lua_pushinteger(L, header->skybox_scalez); break; case mapheaderinfo_interscreen: for (i = 0; i < 8; i++) if (!header->interscreen[i]) break; lua_pushlstring(L, header->interscreen, i); break; case mapheaderinfo_runsoc: lua_pushstring(L, header->runsoc); break; case mapheaderinfo_scriptname: lua_pushstring(L, header->scriptname); break; case mapheaderinfo_precutscenenum: lua_pushinteger(L, header->precutscenenum); break; case mapheaderinfo_cutscenenum: lua_pushinteger(L, header->cutscenenum); break; case mapheaderinfo_countdown: lua_pushinteger(L, header->countdown); break; case mapheaderinfo_palette: lua_pushinteger(L, header->palette); break; case mapheaderinfo_numlaps: lua_pushinteger(L, header->numlaps); break; case mapheaderinfo_unlockrequired: lua_pushinteger(L, header->unlockrequired); break; case mapheaderinfo_levelselect: lua_pushinteger(L, header->levelselect); break; case mapheaderinfo_bonustype: lua_pushinteger(L, header->bonustype); break; case mapheaderinfo_ltzzpatch: lua_pushstring(L, header->ltzzpatch); break; case mapheaderinfo_ltzztext: lua_pushstring(L, header->ltzztext); break; case mapheaderinfo_ltactdiamond: lua_pushstring(L, header->ltactdiamond); break; case mapheaderinfo_maxbonuslives: lua_pushinteger(L, header->maxbonuslives); break; case mapheaderinfo_levelflags: lua_pushinteger(L, header->levelflags); break; case mapheaderinfo_menuflags: lua_pushinteger(L, header->menuflags); break; case mapheaderinfo_selectheading: lua_pushstring(L, header->selectheading); break; case mapheaderinfo_startrings: lua_pushinteger(L, header->startrings); break; case mapheaderinfo_sstimer: lua_pushinteger(L, header->sstimer); break; case mapheaderinfo_ssspheres: lua_pushinteger(L, header->ssspheres); break; case mapheaderinfo_gravity: lua_pushfixed(L, header->gravity); break; // TODO add support for reading numGradedMares and grades default: { // Read custom vars now // (note: don't include the "LUA." in your lua scripts!) UINT8 j = 0; for (;j < header->numCustomOptions && !fastcmp(lua_tostring(L, 2), header->customopts[j].option); ++j); if(j < header->numCustomOptions) lua_pushstring(L, header->customopts[j].value); else lua_pushnil(L); } } return 1; } int LUA_MapLib(lua_State *L) { LUA_RegisterUserdataMetatable(L, META_SECTORLINES, sectorlines_get, NULL, sectorlines_num); LUA_RegisterUserdataMetatable(L, META_SECTOR, sector_get, sector_set, sector_num); LUA_RegisterUserdataMetatable(L, META_SUBSECTOR, subsector_get, NULL, subsector_num); LUA_RegisterUserdataMetatable(L, META_LINE, line_get, NULL, line_num); LUA_RegisterUserdataMetatable(L, META_LINEARGS, lineargs_get, NULL, lineargs_len); LUA_RegisterUserdataMetatable(L, META_LINESTRINGARGS, linestringargs_get, NULL, linestringargs_len); LUA_RegisterUserdataMetatable(L, META_SIDENUM, sidenum_get, NULL, NULL); LUA_RegisterUserdataMetatable(L, META_SIDE, side_get, side_set, side_num); LUA_RegisterUserdataMetatable(L, META_VERTEX, vertex_get, NULL, vertex_num); LUA_RegisterUserdataMetatable(L, META_FFLOOR, ffloor_get, ffloor_set, NULL); LUA_RegisterUserdataMetatable(L, META_BBOX, bbox_get, NULL, NULL); LUA_RegisterUserdataMetatable(L, META_SLOPE, slope_get, slope_set, NULL); LUA_RegisterUserdataMetatable(L, META_VECTOR2, vector2_get, NULL, NULL); LUA_RegisterUserdataMetatable(L, META_VECTOR3, vector3_get, NULL, NULL); LUA_RegisterUserdataMetatable(L, META_MAPHEADER, mapheaderinfo_get, NULL, NULL); sector_fields_ref = Lua_CreateFieldTable(L, sector_opt); subsector_fields_ref = Lua_CreateFieldTable(L, subsector_opt); line_fields_ref = Lua_CreateFieldTable(L, line_opt); side_fields_ref = Lua_CreateFieldTable(L, side_opt); vertex_fields_ref = Lua_CreateFieldTable(L, vertex_opt); ffloor_fields_ref = Lua_CreateFieldTable(L, ffloor_opt); slope_fields_ref = Lua_CreateFieldTable(L, slope_opt); mapheaderinfo_fields_ref = Lua_CreateFieldTable(L, mapheaderinfo_opt); LUA_RegisterGlobalUserdata(L, "subsectors", lib_getSubsector, NULL, lib_numsubsectors); LUA_RegisterGlobalUserdata(L, "sides", lib_getSide, NULL, lib_numsides); LUA_RegisterGlobalUserdata(L, "vertexes", lib_getVertex, NULL, lib_numvertexes); LUA_RegisterGlobalUserdata(L, "mapheaderinfo", lib_getMapheaderinfo, NULL, lib_nummapheaders); LUA_PushTaggableObjectArray(L, "sectors", lib_iterateSectors, lib_getSector, lib_numsectors, tags_sectors, &numsectors, §ors, sizeof (sector_t), META_SECTOR); LUA_PushTaggableObjectArray(L, "lines", lib_iterateLines, lib_getLine, lib_numlines, tags_lines, &numlines, &lines, sizeof (line_t), META_LINE); #ifdef HAVE_LUA_SEGS LUA_RegisterUserdataMetatable(L, META_SEG, seg_get, NULL, seg_num); LUA_RegisterUserdataMetatable(L, META_NODE, node_get, NULL, node_num); LUA_RegisterUserdataMetatable(L, META_NODECHILDREN, nodechildren_get, NULL, NULL); seg_fields_ref = Lua_CreateFieldTable(L, seg_opt); node_fields_ref = Lua_CreateFieldTable(L, node_opt); luaL_newmetatable(L, META_NODEBBOX); //LUA_SetCFunctionField(L, "__index", nodebbox_get); LUA_SetCFunctionField(L, "__call", nodebbox_call); lua_pop(L, 1); LUA_RegisterGlobalUserdata(L, "segs", lib_getSeg, NULL, lib_numsegs); LUA_RegisterGlobalUserdata(L, "nodes", lib_getNode, NULL, lib_numnodes); #endif return 0; }