// 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_playerlib.c /// \brief player object library for Lua scripting #include "doomdef.h" #include "fastcmp.h" #include "p_mobj.h" #include "d_player.h" #include "g_game.h" #include "p_local.h" #include "lua_script.h" #include "lua_libs.h" #include "lua_hud.h" // hud_running errors #include "lua_hook.h" // hook_cmd_running errors static int lib_iteratePlayers(lua_State *L) { INT32 i = -1; if (lua_gettop(L) < 2) { //return luaL_error(L, "Don't call players.iterate() directly, use it as 'for player in players.iterate do end'."); lua_pushcfunction(L, lib_iteratePlayers); return 1; } lua_settop(L, 2); lua_remove(L, 1); // state is unused. if (!lua_isnil(L, 1)) i = (INT32)(*((player_t **)luaL_checkudata(L, 1, META_PLAYER)) - players); for (i++; i < MAXPLAYERS; i++) { if (!playeringame[i]) continue; if (!players[i].mo) continue; LUA_PushUserdata(L, &players[i], META_PLAYER); return 1; } return 0; } 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; } // #players -> MAXPLAYERS static int lib_lenPlayer(lua_State *L) { lua_pushinteger(L, MAXPLAYERS); return 1; } enum player_e { player_valid, player_name, player_realmo, player_mo, player_cmd, player_playerstate, player_camerascale, player_shieldscale, player_viewz, player_viewheight, player_deltaviewheight, player_bob, player_viewrollangle, player_aiming, player_drawangle, player_rings, player_spheres, player_pity, player_currentweapon, player_ringweapons, player_ammoremoval, player_ammoremovaltimer, player_ammoremovalweapon, player_powers, player_pflags, player_panim, player_flashcount, player_flashpal, player_skincolor, player_skin, player_availabilities, player_score, player_recordscore, player_dashspeed, player_normalspeed, player_runspeed, player_thrustfactor, player_accelstart, player_acceleration, player_charability, player_charability2, player_charflags, player_thokitem, player_spinitem, player_revitem, player_followitem, player_followmobj, player_actionspd, player_mindash, player_maxdash, player_jumpfactor, player_height, player_spinheight, player_lives, player_continues, player_xtralife, player_gotcontinue, player_speed, player_secondjump, player_fly1, player_scoreadd, player_glidetime, player_climbing, player_deadtimer, player_exiting, player_homing, player_dashmode, player_skidtime, player_cmomx, player_cmomy, player_rmomx, player_rmomy, player_numboxes, player_totalring, player_realtime, player_laps, player_ctfteam, player_gotflag, player_weapondelay, player_tossdelay, player_starpostx, player_starposty, player_starpostz, player_starpostnum, player_starposttime, player_starpostangle, player_starpostscale, player_angle_pos, player_old_angle_pos, player_axis1, player_axis2, player_bumpertime, player_flyangle, player_drilltimer, player_linkcount, player_linktimer, player_anotherflyangle, player_nightstime, player_drillmeter, player_drilldelay, player_bonustime, player_capsule, player_drone, player_oldscale, player_mare, player_marelap, player_marebonuslap, player_marebegunat, player_lastmaretime, player_startedtime, player_finishedtime, player_lapbegunat, player_lapstartedtime, player_finishedspheres, player_finishedrings, player_marescore, player_lastmarescore, player_totalmarescore, player_lastmare, player_lastmarelap, player_lastmarebonuslap, player_totalmarelap, player_totalmarebonuslap, player_maxlink, player_texttimer, player_textvar, player_lastsidehit, player_lastlinehit, player_losstime, player_timeshit, player_onconveyor, player_awayviewmobj, player_awayviewtics, player_awayviewaiming, player_spectator, player_outofcoop, player_bot, player_botleader, player_lastbuttons, player_blocked, player_jointime, player_quittime, player_lastinputtime, player_ping, player_fovadd }; static const char *const player_opt[] = { "valid", "name", "realmo", "mo", "cmd", "playerstate", "camerascale", "shieldscale", "viewz", "viewheight", "deltaviewheight", "bob", "viewrollangle", "aiming", "drawangle", "rings", "spheres", "pity", "currentweapon", "ringweapons", "ammoremoval", "ammoremovaltimer", "ammoremovalweapon", "powers", "pflags", "panim", "flashcount", "flashpal", "skincolor", "skin", "availabilities", "score", "recordscore", "dashspeed", "normalspeed", "runspeed", "thrustfactor", "accelstart", "acceleration", "charability", "charability2", "charflags", "thokitem", "spinitem", "revitem", "followitem", "followmobj", "actionspd", "mindash", "maxdash", "jumpfactor", "height", "spinheight", "lives", "continues", "xtralife", "gotcontinue", "speed", "secondjump", "fly1", "scoreadd", "glidetime", "climbing", "deadtimer", "exiting", "homing", "dashmode", "skidtime", "cmomx", "cmomy", "rmomx", "rmomy", "numboxes", "totalring", "realtime", "laps", "ctfteam", "gotflag", "weapondelay", "tossdelay", "starpostx", "starposty", "starpostz", "starpostnum", "starposttime", "starpostangle", "starpostscale", "angle_pos", "old_angle_pos", "axis1", "axis2", "bumpertime", "flyangle", "drilltimer", "linkcount", "linktimer", "anotherflyangle", "nightstime", "drillmeter", "drilldelay", "bonustime", "capsule", "drone", "oldscale", "mare", "marelap", "marebonuslap", "marebegunat", "lastmaretime", "startedtime", "finishedtime", "lapbegunat", "lapstartedtime", "finishedspheres", "finishedrings", "marescore", "lastmarescore", "totalmarescore", "lastmare", "lastmarelap", "lastmarebonuslap", "totalmarelap", "totalmarebonuslap", "maxlink", "texttimer", "textvar", "lastsidehit", "lastlinehit", "losstime", "timeshit", "onconveyor", "awayviewmobj", "awayviewtics", "awayviewaiming", "spectator", "outofcoop", "bot", "botleader", "lastbuttons", "blocked", "jointime", "quittime", "lastinputtime", "ping", "fovadd", NULL, }; static int player_fields_ref = LUA_NOREF; static int player_get(lua_State *L) { player_t *plr = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); enum player_e field = Lua_optoption(L, 2, -1, player_fields_ref); lua_settop(L, 2); if (!plr) { if (field == player_valid) { lua_pushboolean(L, false); return 1; } return LUA_ErrInvalid(L, "player_t"); } switch (field) { case player_valid: lua_pushboolean(L, true); break; case player_name: lua_pushstring(L, player_names[plr-players]); break; case player_realmo: LUA_PushUserdata(L, plr->mo, META_MOBJ); break; // TODO: 2.3: Kept for backward-compatibility // Should be fixed to work like "realmo" later case player_mo: if (plr->spectator) lua_pushnil(L); else LUA_PushUserdata(L, plr->mo, META_MOBJ); break; case player_cmd: LUA_PushUserdata(L, &plr->cmd, META_TICCMD); break; case player_playerstate: lua_pushinteger(L, plr->playerstate); break; case player_camerascale: lua_pushfixed(L, plr->camerascale); break; case player_shieldscale: lua_pushfixed(L, plr->shieldscale); break; case player_viewz: lua_pushfixed(L, plr->viewz); break; case player_viewheight: lua_pushfixed(L, plr->viewheight); break; case player_deltaviewheight: lua_pushfixed(L, plr->deltaviewheight); break; case player_bob: lua_pushfixed(L, plr->bob); break; case player_viewrollangle: lua_pushangle(L, plr->viewrollangle); break; case player_aiming: lua_pushangle(L, plr->aiming); break; case player_drawangle: lua_pushangle(L, plr->drawangle); break; case player_rings: lua_pushinteger(L, plr->rings); break; case player_spheres: lua_pushinteger(L, plr->spheres); break; case player_pity: lua_pushinteger(L, plr->pity); break; case player_currentweapon: lua_pushinteger(L, plr->currentweapon); break; case player_ringweapons: lua_pushinteger(L, plr->ringweapons); break; case player_ammoremoval: lua_pushinteger(L, plr->ammoremoval); break; case player_ammoremovaltimer: lua_pushinteger(L, plr->ammoremovaltimer); break; case player_ammoremovalweapon: lua_pushinteger(L, plr->ammoremovalweapon); break; case player_powers: LUA_PushUserdata(L, plr->powers, META_POWERS); break; case player_pflags: lua_pushinteger(L, plr->pflags); break; case player_panim: lua_pushinteger(L, plr->panim); break; case player_flashcount: lua_pushinteger(L, plr->flashcount); break; case player_flashpal: lua_pushinteger(L, plr->flashpal); break; case player_skincolor: lua_pushinteger(L, plr->skincolor); break; case player_skin: lua_pushinteger(L, plr->skin); break; case player_availabilities: lua_pushinteger(L, plr->availabilities); break; case player_score: lua_pushinteger(L, plr->score); break; case player_recordscore: lua_pushinteger(L, plr->recordscore); break; case player_dashspeed: lua_pushfixed(L, plr->dashspeed); break; case player_normalspeed: lua_pushfixed(L, plr->normalspeed); break; case player_runspeed: lua_pushfixed(L, plr->runspeed); break; case player_thrustfactor: lua_pushinteger(L, plr->thrustfactor); break; case player_accelstart: lua_pushinteger(L, plr->accelstart); break; case player_acceleration: lua_pushinteger(L, plr->acceleration); break; case player_charability: lua_pushinteger(L, plr->charability); break; case player_charability2: lua_pushinteger(L, plr->charability2); break; case player_charflags: lua_pushinteger(L, plr->charflags); break; case player_thokitem: lua_pushinteger(L, plr->thokitem); break; case player_spinitem: lua_pushinteger(L, plr->spinitem); break; case player_revitem: lua_pushinteger(L, plr->revitem); break; case player_followitem: lua_pushinteger(L, plr->followitem); break; case player_followmobj: LUA_PushUserdata(L, plr->followmobj, META_MOBJ); break; case player_actionspd: lua_pushfixed(L, plr->actionspd); break; case player_mindash: lua_pushfixed(L, plr->mindash); break; case player_maxdash: lua_pushfixed(L, plr->maxdash); break; case player_jumpfactor: lua_pushfixed(L, plr->jumpfactor); break; case player_height: lua_pushfixed(L, plr->height); break; case player_spinheight: lua_pushfixed(L, plr->spinheight); break; case player_lives: lua_pushinteger(L, plr->lives); break; case player_continues: lua_pushinteger(L, plr->continues); break; case player_xtralife: lua_pushinteger(L, plr->xtralife); break; case player_gotcontinue: lua_pushinteger(L, plr->gotcontinue); break; case player_speed: lua_pushfixed(L, plr->speed); break; case player_secondjump: lua_pushinteger(L, plr->secondjump); break; case player_fly1: lua_pushinteger(L, plr->fly1); break; case player_scoreadd: lua_pushinteger(L, plr->scoreadd); break; case player_glidetime: lua_pushinteger(L, plr->glidetime); break; case player_climbing: lua_pushinteger(L, plr->climbing); break; case player_deadtimer: lua_pushinteger(L, plr->deadtimer); break; case player_exiting: lua_pushinteger(L, plr->exiting); break; case player_homing: lua_pushinteger(L, plr->homing); break; case player_dashmode: lua_pushinteger(L, plr->dashmode); break; case player_skidtime: lua_pushinteger(L, plr->skidtime); break; case player_cmomx: lua_pushfixed(L, plr->cmomx); break; case player_cmomy: lua_pushfixed(L, plr->cmomy); break; case player_rmomx: lua_pushfixed(L, plr->rmomx); break; case player_rmomy: lua_pushfixed(L, plr->rmomy); break; case player_numboxes: lua_pushinteger(L, plr->numboxes); break; case player_totalring: lua_pushinteger(L, plr->totalring); break; case player_realtime: lua_pushinteger(L, plr->realtime); break; case player_laps: lua_pushinteger(L, plr->laps); break; case player_ctfteam: lua_pushinteger(L, plr->ctfteam); break; case player_gotflag: lua_pushinteger(L, plr->gotflag); break; case player_weapondelay: lua_pushinteger(L, plr->weapondelay); break; case player_tossdelay: lua_pushinteger(L, plr->tossdelay); break; case player_starpostx: lua_pushinteger(L, plr->starpostx); break; case player_starposty: lua_pushinteger(L, plr->starposty); break; case player_starpostz: lua_pushinteger(L, plr->starpostz); break; case player_starpostnum: lua_pushinteger(L, plr->starpostnum); break; case player_starposttime: lua_pushinteger(L, plr->starposttime); break; case player_starpostangle: lua_pushangle(L, plr->starpostangle); break; case player_starpostscale: lua_pushfixed(L, plr->starpostscale); break; case player_angle_pos: lua_pushangle(L, plr->angle_pos); break; case player_old_angle_pos: lua_pushangle(L, plr->old_angle_pos); break; case player_axis1: LUA_PushUserdata(L, plr->axis1, META_MOBJ); break; case player_axis2: LUA_PushUserdata(L, plr->axis2, META_MOBJ); break; case player_bumpertime: lua_pushinteger(L, plr->bumpertime); break; case player_flyangle: lua_pushinteger(L, plr->flyangle); break; case player_drilltimer: lua_pushinteger(L, plr->drilltimer); break; case player_linkcount: lua_pushinteger(L, plr->linkcount); break; case player_linktimer: lua_pushinteger(L, plr->linktimer); break; case player_anotherflyangle: lua_pushinteger(L, plr->anotherflyangle); break; case player_nightstime: lua_pushinteger(L, plr->nightstime); break; case player_drillmeter: lua_pushinteger(L, plr->drillmeter); break; case player_drilldelay: lua_pushinteger(L, plr->drilldelay); break; case player_bonustime: lua_pushboolean(L, plr->bonustime); break; case player_capsule: LUA_PushUserdata(L, plr->capsule, META_MOBJ); break; case player_drone: LUA_PushUserdata(L, plr->drone, META_MOBJ); break; case player_oldscale: lua_pushfixed(L, plr->oldscale); break; case player_mare: lua_pushinteger(L, plr->mare); break; case player_marelap: lua_pushinteger(L, plr->marelap); break; case player_marebonuslap: lua_pushinteger(L, plr->marebonuslap); break; case player_marebegunat: lua_pushinteger(L, plr->marebegunat); break; case player_lastmaretime: lua_pushinteger(L, plr->lastmaretime); break; case player_startedtime: lua_pushinteger(L, plr->startedtime); break; case player_finishedtime: lua_pushinteger(L, plr->finishedtime); break; case player_lapbegunat: lua_pushinteger(L, plr->lapbegunat); break; case player_lapstartedtime: lua_pushinteger(L, plr->lapstartedtime); break; case player_finishedspheres: lua_pushinteger(L, plr->finishedspheres); break; case player_finishedrings: lua_pushinteger(L, plr->finishedrings); break; case player_marescore: lua_pushinteger(L, plr->marescore); break; case player_lastmarescore: lua_pushinteger(L, plr->lastmarescore); break; case player_totalmarescore: lua_pushinteger(L, plr->totalmarescore); break; case player_lastmare: lua_pushinteger(L, plr->lastmare); break; case player_lastmarelap: lua_pushinteger(L, plr->lastmarelap); break; case player_lastmarebonuslap: lua_pushinteger(L, plr->lastmarebonuslap); break; case player_totalmarelap: lua_pushinteger(L, plr->totalmarelap); break; case player_totalmarebonuslap: lua_pushinteger(L, plr->totalmarebonuslap); break; case player_maxlink: lua_pushinteger(L, plr->maxlink); break; case player_texttimer: lua_pushinteger(L, plr->texttimer); break; case player_textvar: lua_pushinteger(L, plr->textvar); break; case player_lastsidehit: lua_pushinteger(L, plr->lastsidehit); break; case player_lastlinehit: lua_pushinteger(L, plr->lastlinehit); break; case player_losstime: lua_pushinteger(L, plr->losstime); break; case player_timeshit: lua_pushinteger(L, plr->timeshit); break; case player_onconveyor: lua_pushinteger(L, plr->onconveyor); break; case player_awayviewmobj: LUA_PushUserdata(L, plr->awayviewmobj, META_MOBJ); break; case player_awayviewtics: lua_pushinteger(L, plr->awayviewtics); break; case player_awayviewaiming: lua_pushangle(L, plr->awayviewaiming); break; case player_spectator: lua_pushboolean(L, plr->spectator); break; case player_outofcoop: lua_pushboolean(L, plr->outofcoop); break; case player_bot: lua_pushinteger(L, plr->bot); break; case player_botleader: LUA_PushUserdata(L, plr->botleader, META_PLAYER); break; case player_lastbuttons: lua_pushinteger(L, plr->lastbuttons); break; case player_blocked: lua_pushboolean(L, plr->blocked); break; case player_jointime: lua_pushinteger(L, plr->jointime); break; case player_quittime: lua_pushinteger(L, plr->quittime); break; case player_lastinputtime: lua_pushinteger(L, plr->lastinputtime); break; case player_ping: lua_pushinteger(L, playerpingtable[plr - players]); break; case player_fovadd: lua_pushfixed(L, plr->fovadd); break; default: lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS); I_Assert(lua_istable(L, -1)); lua_pushlightuserdata(L, plr); 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"), "player_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"), "player_t", lua_tostring(L, 2)); break; } return 1; } #define NOSET luaL_error(L, LUA_QL("player_t") " field " LUA_QS " should not be set directly.", player_opt[field]) static int player_set(lua_State *L) { player_t *plr = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); enum player_e field = Lua_optoption(L, 2, player_cmd, player_fields_ref); if (!plr) return LUA_ErrInvalid(L, "player_t"); if (hud_running) return luaL_error(L, "Do not alter player_t in HUD rendering code!"); if (hook_cmd_running) return luaL_error(L, "Do not alter player_t in CMD building code!"); switch (field) { case player_mo: case player_realmo: { mobj_t *newmo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); plr->mo->player = NULL; // remove player pointer from old mobj (newmo->player = plr)->mo = newmo; // set player pointer for new mobj, and set new mobj as the player's mobj break; } case player_cmd: return NOSET; case player_playerstate: plr->playerstate = luaL_checkinteger(L, 3); break; case player_camerascale: plr->camerascale = luaL_checkfixed(L, 3); break; case player_shieldscale: plr->shieldscale = luaL_checkfixed(L, 3); break; case player_viewz: plr->viewz = luaL_checkfixed(L, 3); break; case player_viewheight: plr->viewheight = luaL_checkfixed(L, 3); break; case player_deltaviewheight: plr->deltaviewheight = luaL_checkfixed(L, 3); break; case player_bob: plr->bob = luaL_checkfixed(L, 3); break; case player_viewrollangle: plr->viewrollangle = luaL_checkangle(L, 3); break; case player_aiming: { plr->aiming = luaL_checkangle(L, 3); if (plr == &players[consoleplayer]) localaiming = plr->aiming; else if (plr == &players[secondarydisplayplayer]) localaiming2 = plr->aiming; break; } case player_drawangle: plr->drawangle = luaL_checkangle(L, 3); break; case player_rings: plr->rings = (INT32)luaL_checkinteger(L, 3); break; case player_spheres: plr->spheres = (INT32)luaL_checkinteger(L, 3); break; case player_pity: plr->pity = (SINT8)luaL_checkinteger(L, 3); break; case player_currentweapon: plr->currentweapon = (INT32)luaL_checkinteger(L, 3); break; case player_ringweapons: plr->ringweapons = (INT32)luaL_checkinteger(L, 3); break; case player_ammoremoval: plr->ammoremoval = (UINT16)luaL_checkinteger(L, 3); break; case player_ammoremovaltimer: plr->ammoremovaltimer = (tic_t)luaL_checkinteger(L, 3); break; case player_ammoremovalweapon: plr->ammoremovalweapon = (INT32)luaL_checkinteger(L, 3); break; case player_powers: return NOSET; case player_pflags: plr->pflags = luaL_checkinteger(L, 3); break; case player_panim: plr->panim = luaL_checkinteger(L, 3); break; case player_flashcount: plr->flashcount = (UINT16)luaL_checkinteger(L, 3); break; case player_flashpal: plr->flashpal = (UINT16)luaL_checkinteger(L, 3); break; case player_skincolor: { UINT16 newcolor = (UINT16)luaL_checkinteger(L,3); if (newcolor >= numskincolors) return luaL_error(L, "player.skincolor %d out of range (0 - %d).", newcolor, numskincolors-1); plr->skincolor = newcolor; break; } case player_skin: return NOSET; case player_availabilities: return NOSET; case player_score: plr->score = (UINT32)luaL_checkinteger(L, 3); break; case player_recordscore: plr->recordscore = (UINT32)luaL_checkinteger(L, 3); break; case player_dashspeed: plr->dashspeed = luaL_checkfixed(L, 3); break; case player_normalspeed: plr->normalspeed = luaL_checkfixed(L, 3); break; case player_runspeed: plr->runspeed = luaL_checkfixed(L, 3); break; case player_thrustfactor: plr->thrustfactor = (UINT8)luaL_checkinteger(L, 3); break; case player_accelstart: plr->accelstart = (UINT8)luaL_checkinteger(L, 3); break; case player_acceleration: plr->acceleration = (UINT8)luaL_checkinteger(L, 3); break; case player_charability: plr->charability = (UINT8)luaL_checkinteger(L, 3); break; case player_charability2: plr->charability2 = (UINT8)luaL_checkinteger(L, 3); break; case player_charflags: plr->charflags = (UINT32)luaL_checkinteger(L, 3); break; case player_thokitem: plr->thokitem = luaL_checkinteger(L, 3); break; case player_spinitem: plr->spinitem = luaL_checkinteger(L, 3); break; case player_revitem: plr->revitem = luaL_checkinteger(L, 3); break; case player_followitem: plr->followitem = luaL_checkinteger(L, 3); break; case player_followmobj: { mobj_t *mo = NULL; if (!lua_isnil(L, 3)) mo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); P_SetTarget(&plr->followmobj, mo); break; } case player_actionspd: plr->actionspd = (INT32)luaL_checkinteger(L, 3); break; case player_mindash: plr->mindash = (INT32)luaL_checkinteger(L, 3); break; case player_maxdash: plr->maxdash = (INT32)luaL_checkinteger(L, 3); break; case player_jumpfactor: plr->jumpfactor = (INT32)luaL_checkinteger(L, 3); break; case player_height: plr->height = luaL_checkfixed(L, 3); break; case player_spinheight: plr->spinheight = luaL_checkfixed(L, 3); break; case player_lives: plr->lives = (SINT8)luaL_checkinteger(L, 3); break; case player_continues: plr->continues = (SINT8)luaL_checkinteger(L, 3); break; case player_xtralife: plr->xtralife = (SINT8)luaL_checkinteger(L, 3); break; case player_gotcontinue: plr->gotcontinue = (UINT8)luaL_checkinteger(L, 3); break; case player_speed: plr->speed = luaL_checkfixed(L, 3); break; case player_secondjump: plr->secondjump = (UINT8)luaL_checkinteger(L, 3); break; case player_fly1: plr->fly1 = (UINT8)luaL_checkinteger(L, 3); break; case player_scoreadd: plr->scoreadd = (UINT8)luaL_checkinteger(L, 3); break; case player_glidetime: plr->glidetime = (tic_t)luaL_checkinteger(L, 3); break; case player_climbing: plr->climbing = (INT32)luaL_checkinteger(L, 3); break; case player_deadtimer: plr->deadtimer = (INT32)luaL_checkinteger(L, 3); break; case player_exiting: plr->exiting = (tic_t)luaL_checkinteger(L, 3); break; case player_homing: plr->homing = (UINT8)luaL_checkinteger(L, 3); break; case player_dashmode: plr->dashmode = (tic_t)luaL_checkinteger(L, 3); break; case player_skidtime: plr->skidtime = (tic_t)luaL_checkinteger(L, 3); break; case player_cmomx: plr->cmomx = luaL_checkfixed(L, 3); break; case player_cmomy: plr->cmomy = luaL_checkfixed(L, 3); break; case player_rmomx: plr->rmomx = luaL_checkfixed(L, 3); break; case player_rmomy: plr->rmomy = luaL_checkfixed(L, 3); break; case player_numboxes: plr->numboxes = (INT16)luaL_checkinteger(L, 3); break; case player_totalring: plr->totalring = (INT16)luaL_checkinteger(L, 3); break; case player_realtime: plr->realtime = (tic_t)luaL_checkinteger(L, 3); break; case player_laps: plr->laps = (UINT8)luaL_checkinteger(L, 3); break; case player_ctfteam: plr->ctfteam = (INT32)luaL_checkinteger(L, 3); break; case player_gotflag: plr->gotflag = (UINT16)luaL_checkinteger(L, 3); break; case player_weapondelay: plr->weapondelay = (INT32)luaL_checkinteger(L, 3); break; case player_tossdelay: plr->tossdelay = (INT32)luaL_checkinteger(L, 3); break; case player_starpostx: plr->starpostx = (INT16)luaL_checkinteger(L, 3); break; case player_starposty: plr->starposty = (INT16)luaL_checkinteger(L, 3); break; case player_starpostz: plr->starpostz = (INT16)luaL_checkinteger(L, 3); break; case player_starpostnum: plr->starpostnum = (INT32)luaL_checkinteger(L, 3); break; case player_starposttime: plr->starposttime = (tic_t)luaL_checkinteger(L, 3); break; case player_starpostangle: plr->starpostangle = luaL_checkangle(L, 3); break; case player_starpostscale: plr->starpostscale = luaL_checkfixed(L, 3); break; case player_angle_pos: plr->angle_pos = luaL_checkangle(L, 3); break; case player_old_angle_pos: plr->old_angle_pos = luaL_checkangle(L, 3); break; case player_axis1: { mobj_t *mo = NULL; if (!lua_isnil(L, 3)) mo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); P_SetTarget(&plr->axis1, mo); break; } case player_axis2: { mobj_t *mo = NULL; if (!lua_isnil(L, 3)) mo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); P_SetTarget(&plr->axis2, mo); break; } case player_bumpertime: plr->bumpertime = (tic_t)luaL_checkinteger(L, 3); break; case player_flyangle: plr->flyangle = (INT32)luaL_checkinteger(L, 3); break; case player_drilltimer: plr->drilltimer = (tic_t)luaL_checkinteger(L, 3); break; case player_linkcount: plr->linkcount = (INT32)luaL_checkinteger(L, 3); break; case player_linktimer: plr->linktimer = (tic_t)luaL_checkinteger(L, 3); break; case player_anotherflyangle: plr->anotherflyangle = (INT32)luaL_checkinteger(L, 3); break; case player_nightstime: plr->nightstime = (tic_t)luaL_checkinteger(L, 3); break; case player_drillmeter: plr->drillmeter = (INT32)luaL_checkinteger(L, 3); break; case player_drilldelay: plr->drilldelay = (UINT8)luaL_checkinteger(L, 3); break; case player_bonustime: plr->bonustime = luaL_checkboolean(L, 3); break; case player_capsule: { mobj_t *mo = NULL; if (!lua_isnil(L, 3)) mo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); P_SetTarget(&plr->capsule, mo); break; } case player_drone: { mobj_t *mo = NULL; if (!lua_isnil(L, 3)) mo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); P_SetTarget(&plr->drone, mo); break; } case player_oldscale: plr->oldscale = luaL_checkfixed(L, 3); break; case player_mare: plr->mare = (UINT8)luaL_checkinteger(L, 3); break; case player_marelap: plr->marelap = (UINT8)luaL_checkinteger(L, 3); break; case player_marebonuslap: plr->marebonuslap = (UINT8)luaL_checkinteger(L, 3); break; case player_marebegunat: plr->marebegunat = (tic_t)luaL_checkinteger(L, 3); break; case player_lastmaretime: plr->lastmaretime = (tic_t)luaL_checkinteger(L, 3); break; case player_startedtime: plr->startedtime = (tic_t)luaL_checkinteger(L, 3); break; case player_finishedtime: plr->finishedtime = (tic_t)luaL_checkinteger(L, 3); break; case player_lapbegunat: plr->lapbegunat = (tic_t)luaL_checkinteger(L, 3); break; case player_lapstartedtime: plr->lapstartedtime = (tic_t)luaL_checkinteger(L, 3); break; case player_finishedspheres: plr->finishedspheres = (INT16)luaL_checkinteger(L, 3); break; case player_finishedrings: plr->finishedrings = (INT16)luaL_checkinteger(L, 3); break; case player_marescore: plr->marescore = (UINT32)luaL_checkinteger(L, 3); break; case player_lastmarescore: plr->lastmarescore = (UINT32)luaL_checkinteger(L, 3); break; case player_totalmarescore: plr->totalmarescore = (UINT32)luaL_checkinteger(L, 3); break; case player_lastmare: plr->lastmare = (UINT8)luaL_checkinteger(L, 3); break; case player_lastmarelap: plr->lastmarelap = (UINT8)luaL_checkinteger(L, 3); break; case player_lastmarebonuslap: plr->lastmarebonuslap = (UINT8)luaL_checkinteger(L, 3); break; case player_totalmarelap: plr->totalmarelap = (UINT8)luaL_checkinteger(L, 3); break; case player_totalmarebonuslap: plr->totalmarebonuslap = (UINT8)luaL_checkinteger(L, 3); break; case player_maxlink: plr->maxlink = (INT32)luaL_checkinteger(L, 3); break; case player_texttimer: plr->texttimer = (UINT8)luaL_checkinteger(L, 3); break; case player_textvar: plr->textvar = (UINT8)luaL_checkinteger(L, 3); break; case player_lastsidehit: plr->lastsidehit = (INT16)luaL_checkinteger(L, 3); break; case player_lastlinehit: plr->lastlinehit = (INT16)luaL_checkinteger(L, 3); break; case player_losstime: plr->losstime = (tic_t)luaL_checkinteger(L, 3); break; case player_timeshit: plr->timeshit = (UINT8)luaL_checkinteger(L, 3); break; case player_onconveyor: plr->onconveyor = (INT32)luaL_checkinteger(L, 3); break; case player_awayviewmobj: { mobj_t *mo = NULL; if (!lua_isnil(L, 3)) mo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); if (plr->awayviewmobj != mo) { P_SetTarget(&plr->awayviewmobj, mo); if (plr->awayviewtics) { if (!plr->awayviewmobj) plr->awayviewtics = 0; // can't have a NULL awayviewmobj with awayviewtics! if (plr == &players[displayplayer]) P_ResetCamera(plr, &camera); // reset p1 camera on p1 getting an awayviewmobj else if (splitscreen && plr == &players[secondarydisplayplayer]) P_ResetCamera(plr, &camera2); // reset p2 camera on p2 getting an awayviewmobj } } break; } case player_awayviewtics: { INT32 tics = (INT32)luaL_checkinteger(L, 3); if (tics && !plr->awayviewmobj) // awayviewtics must ALWAYS have an awayviewmobj set!! P_SetTarget(&plr->awayviewmobj, plr->mo); // but since the script might set awayviewmobj immediately AFTER setting awayviewtics, use player mobj as filler for now. if ((tics && !plr->awayviewtics) || (!tics && plr->awayviewtics)) { if (plr == &players[displayplayer]) P_ResetCamera(plr, &camera); // reset p1 camera on p1 transitioning to/from zero awayviewtics else if (splitscreen && plr == &players[secondarydisplayplayer]) P_ResetCamera(plr, &camera2); // reset p2 camera on p2 transitioning to/from zero awayviewtics } plr->awayviewtics = tics; break; } case player_awayviewaiming: plr->awayviewaiming = luaL_checkangle(L, 3); break; case player_spectator: plr->spectator = lua_toboolean(L, 3); break; case player_outofcoop: plr->outofcoop = lua_toboolean(L, 3); break; case player_bot: return NOSET; case player_botleader: { player_t *player = NULL; if (!lua_isnil(L, 3)) player = *((player_t **)luaL_checkudata(L, 3, META_PLAYER)); plr->botleader = player; break; } case player_lastbuttons: plr->lastbuttons = (UINT16)luaL_checkinteger(L, 3); break; case player_blocked: plr->blocked = (UINT8)luaL_checkinteger(L, 3); break; case player_jointime: plr->jointime = (tic_t)luaL_checkinteger(L, 3); break; case player_quittime: plr->quittime = (tic_t)luaL_checkinteger(L, 3); break; case player_lastinputtime: plr->lastinputtime = (tic_t)luaL_checkinteger(L, 3); break; case player_fovadd: plr->fovadd = luaL_checkfixed(L, 3); break; default: lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS); I_Assert(lua_istable(L, -1)); lua_pushlightuserdata(L, plr); lua_rawget(L, -2); if (lua_isnil(L, -1)) { // This index doesn't have a table for extra values yet, let's make one. lua_pop(L, 1); CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; adding it as Lua data.\n"), "player_t", lua_tostring(L, 2)); lua_newtable(L); lua_pushlightuserdata(L, plr); lua_pushvalue(L, -2); // ext value table lua_rawset(L, -4); // LREG_EXTVARS table } lua_pushvalue(L, 2); // key lua_pushvalue(L, 3); // value to store lua_settable(L, -3); lua_pop(L, 2); break; } return 0; } #undef NOSET static int player_num(lua_State *L) { player_t *plr = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); if (!plr) return luaL_error(L, "accessed player_t doesn't exist anymore."); lua_pushinteger(L, plr-players); return 1; } // powers, p -> powers[p] static int power_get(lua_State *L) { UINT16 *powers = *((UINT16 **)luaL_checkudata(L, 1, META_POWERS)); powertype_t p = luaL_checkinteger(L, 2); if (p >= NUMPOWERS) return luaL_error(L, LUA_QL("powertype_t") " cannot be %d", (INT16)p); lua_pushinteger(L, powers[p]); return 1; } // powers, p, value -> powers[p] = value static int power_set(lua_State *L) { UINT16 *powers = *((UINT16 **)luaL_checkudata(L, 1, META_POWERS)); powertype_t p = luaL_checkinteger(L, 2); UINT16 i = (UINT16)luaL_checkinteger(L, 3); if (p >= NUMPOWERS) return luaL_error(L, LUA_QL("powertype_t") " cannot be %d", (INT16)p); if (hud_running) return luaL_error(L, "Do not alter player_t in HUD rendering code!"); if (hook_cmd_running) return luaL_error(L, "Do not alter player_t in CMD building code!"); powers[p] = i; return 0; } // #powers -> NUMPOWERS static int power_len(lua_State *L) { lua_pushinteger(L, NUMPOWERS); return 1; } #define NOFIELD luaL_error(L, "%s %s", LUA_QL("ticcmd_t"), va("has no field named %ui", field)) #define NOSET luaL_error(L, LUA_QL("ticcmd_t") " field %s should not be set directly.", ticcmd_opt[field]) enum ticcmd_e { ticcmd_forwardmove, ticcmd_sidemove, ticcmd_angleturn, ticcmd_aiming, ticcmd_buttons, ticcmd_latency, }; static const char *const ticcmd_opt[] = { "forwardmove", "sidemove", "angleturn", "aiming", "buttons", "latency", NULL, }; static int ticcmd_fields_ref = LUA_NOREF; static int ticcmd_get(lua_State *L) { ticcmd_t *cmd = *((ticcmd_t **)luaL_checkudata(L, 1, META_TICCMD)); enum ticcmd_e field = Lua_optoption(L, 2, -1, ticcmd_fields_ref); if (!cmd) return LUA_ErrInvalid(L, "player_t"); if (field == (enum ticcmd_e)-1) return LUA_ErrInvalid(L, "fields"); switch (field) { case ticcmd_forwardmove: lua_pushinteger(L, cmd->forwardmove); break; case ticcmd_sidemove: lua_pushinteger(L, cmd->sidemove); break; case ticcmd_angleturn: lua_pushinteger(L, cmd->angleturn); break; case ticcmd_aiming: lua_pushinteger(L, cmd->aiming); break; case ticcmd_buttons: lua_pushinteger(L, cmd->buttons); break; case ticcmd_latency: lua_pushinteger(L, cmd->latency); break; default: return NOFIELD; } return 1; } static int ticcmd_set(lua_State *L) { ticcmd_t *cmd = *((ticcmd_t **)luaL_checkudata(L, 1, META_TICCMD)); enum ticcmd_e field = Lua_optoption(L, 2, -1, ticcmd_fields_ref); if (!cmd) return LUA_ErrInvalid(L, "ticcmd_t"); if (field == (enum ticcmd_e)-1) return LUA_ErrInvalid(L, "fields"); if (hud_running) return luaL_error(L, "Do not alter player_t in HUD rendering code!"); switch (field) { case ticcmd_forwardmove: cmd->forwardmove = (SINT8)luaL_checkinteger(L, 3); break; case ticcmd_sidemove: cmd->sidemove = (SINT8)luaL_checkinteger(L, 3); break; case ticcmd_angleturn: cmd->angleturn = (INT16)luaL_checkinteger(L, 3); break; case ticcmd_aiming: cmd->aiming = (INT16)luaL_checkinteger(L, 3); break; case ticcmd_buttons: cmd->buttons = (UINT16)luaL_checkinteger(L, 3); break; case ticcmd_latency: return NOSET; default: return NOFIELD; } return 0; } #undef NOFIELD #undef NOSET int LUA_PlayerLib(lua_State *L) { LUA_RegisterUserdataMetatable(L, META_PLAYER, player_get, player_set, player_num); LUA_RegisterUserdataMetatable(L, META_POWERS, power_get, power_set, power_len); LUA_RegisterUserdataMetatable(L, META_TICCMD, ticcmd_get, ticcmd_set, NULL); player_fields_ref = Lua_CreateFieldTable(L, player_opt); ticcmd_fields_ref = Lua_CreateFieldTable(L, ticcmd_opt); LUA_RegisterGlobalUserdata(L, "players", lib_getPlayer, NULL, lib_lenPlayer); return 0; }