RingRacers/src/lua_baselib.c
2025-08-22 23:51:59 +02:00

5959 lines
150 KiB
C

// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2025 by Kart Krew.
// Copyright (C) 2020 by Sonic Team Junior.
// Copyright (C) 2016 by John "JTE" Muniz.
//
// 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_baselib.c
/// \brief basic functions for Lua scripting
#include "doomdef.h"
#include "fastcmp.h"
#include "p_local.h"
#include "p_setup.h" // So we can have P_SetupLevelSky
#include "p_slopes.h" // P_GetSlopeZAt
#include "z_zone.h"
#include "r_main.h"
#include "r_draw.h"
#include "r_things.h" // R_Frame2Char etc
#include "m_random.h"
#include "s_sound.h"
#include "g_game.h"
#include "y_inter.h"
#include "hu_stuff.h" // HU_AddChatText
#include "console.h"
#include "k_kart.h" // SRB2Kart
#include "k_battle.h"
#include "k_boss.h"
#include "k_collide.h"
#include "k_color.h"
#include "k_endcam.h"
#include "k_hud.h"
#include "d_netcmd.h" // IsPlayerAdmin
#include "k_menu.h" // Player Setup menu color stuff
#include "p_spec.h" // P_StartQuake
#include "i_system.h" // I_GetPreciseTime, I_GetPrecisePrecision
#include "hu_stuff.h" // for the cecho
#include "k_powerup.h"
#include "k_hitlag.h"
#include "music.h" // music functions necessary for lua integration
#include "k_terrain.h"
#include "lua_script.h"
#include "lua_libs.h"
#include "lua_hud.h" // hud_running errors
#include "taglist.h" // P_FindSpecialLineFromTag
#include "lua_hook.h" // hook_cmd_running errors
#define NOHUD if (hud_running)\
return luaL_error(L, "HUD rendering code should not call this function!");\
else if (hook_cmd_running)\
return luaL_error(L, "CMD building code should not call this function!");
boolean luaL_checkboolean(lua_State *L, int narg) {
luaL_checktype(L, narg, LUA_TBOOLEAN);
return lua_toboolean(L, narg);
}
// String concatination
static int lib_concat(lua_State *L)
{
int n = lua_gettop(L); /* number of arguments */
int i;
char *r = NULL;
size_t rl = 0,sl;
lua_getglobal(L, "tostring");
for (i=1; i<=n; i++) {
const char *s;
lua_pushvalue(L, -1); /* function to be called */
lua_pushvalue(L, i); /* value to print */
lua_call(L, 1, 1);
s = lua_tolstring(L, -1, &sl); /* get result */
if (s == NULL)
return luaL_error(L, LUA_QL("tostring") " must return a string to "
LUA_QL("__add"));
r = Z_Realloc(r, rl+sl, PU_STATIC, NULL);
M_Memcpy(r+rl, s, sl);
rl += sl;
lua_pop(L, 1); /* pop result */
}
lua_pushlstring(L, r, rl);
Z_Free(r);
return 1;
}
// Wrapper for CONS_Printf
// Copied from base Lua code
static int lib_print(lua_State *L)
{
int n = lua_gettop(L); /* number of arguments */
int i;
//HUDSAFE
lua_getglobal(L, "tostring");
for (i=1; i<=n; i++) {
const char *s;
lua_pushvalue(L, -1); /* function to be called */
lua_pushvalue(L, i); /* value to print */
lua_call(L, 1, 1);
s = lua_tostring(L, -1); /* get result */
if (s == NULL)
return luaL_error(L, LUA_QL("tostring") " must return a string to "
LUA_QL("print"));
if (i>1) CONS_Printf("\n");
CONS_Printf("%s", s);
lua_pop(L, 1); /* pop result */
}
CONS_Printf("\n");
return 0;
}
// Print stuff in the chat, or in the console if we can't.
static int lib_chatprint(lua_State *L)
{
const char *str = luaL_checkstring(L, 1); // retrieve string
boolean sound = lua_optboolean(L, 2); // retrieve sound boolean
int len = strlen(str);
if (str == NULL) // error if we don't have a string!
return luaL_error(L, LUA_QL("tostring") " must return a string to " LUA_QL("chatprint"));
if (len > 255) // string is too long!!!
return luaL_error(L, "String exceeds the 255 characters limit of the chat buffer.");
HU_AddChatText(str, sound);
return 0;
}
// Same as above, but do it for only one player.
static int lib_chatprintf(lua_State *L)
{
int n = lua_gettop(L); /* number of arguments */
const char *str = luaL_checkstring(L, 2); // retrieve string
boolean sound = lua_optboolean(L, 3); // sound?
int len = strlen(str);
player_t *plr;
if (n < 2)
return luaL_error(L, "chatprintf requires at least two arguments: player and text.");
plr = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); // retrieve player
if (!plr)
return LUA_ErrInvalid(L, "player_t");
if (plr != &players[consoleplayer])
return 0;
if (str == NULL) // error if we don't have a string!
return luaL_error(L, LUA_QL("tostring") " must return a string to " LUA_QL("chatprintf"));
if (len > 255) // string is too long!!!
return luaL_error(L, "String exceeds the 255 characters limit of the chat buffer.");
HU_AddChatText(str, sound);
return 0;
}
static const struct {
const char *meta;
const char *utype;
} meta2utype[] = {
{META_STATE, "state_t"},
{META_MOBJINFO, "mobjinfo_t"},
{META_SFXINFO, "sfxinfo_t"},
{META_SKINCOLOR, "skincolor_t"},
{META_COLORRAMP, "skincolor_t.ramp"},
{META_SPRITEINFO, "spriteinfo_t"},
{META_PIVOTLIST, "spriteframepivot_t[]"},
{META_FRAMEPIVOT, "spriteframepivot_t"},
{META_PRECIPPROPS, "precipprops_t"},
{META_TAGLIST, "taglist"},
{META_MOBJ, "mobj_t"},
{META_MAPTHING, "mapthing_t"},
{META_PLAYER, "player_t"},
{META_TICCMD, "ticcmd_t"},
{META_SKIN, "skin_t"},
{META_SOUNDSID, "skin_t.soundsid"},
{META_SKINSPRITES, "skin_t.sprites"},
{META_SKINSPRITESLIST, "skin_t.sprites[]"},
{META_VERTEX, "vertex_t"},
{META_LINE, "line_t"},
{META_SIDE, "side_t"},
{META_SUBSECTOR, "subsector_t"},
{META_SECTOR, "sector_t"},
{META_FFLOOR, "ffloor_t"},
#ifdef HAVE_LUA_SEGS
{META_SEG, "seg_t"},
{META_NODE, "node_t"},
#endif
{META_SLOPE, "slope_t"},
{META_VECTOR2, "vector2_t"},
{META_VECTOR3, "vector3_t"},
{META_MAPHEADER, "mapheader_t"},
{META_POLYOBJ, "polyobj_t"},
{META_POLYOBJVERTICES, "polyobj_t.vertices"},
{META_POLYOBJLINES, "polyobj_t.lines"},
{META_CVAR, "consvar_t"},
{META_SECTORLINES, "sector_t.lines"},
#ifdef MUTABLE_TAGS
{META_SECTORTAGLIST, "sector_t.taglist"},
#endif
{META_SIDENUM, "line_t.sidenum"},
{META_LINEARGS, "line_t.args"},
{META_LINESTRINGARGS, "line_t.stringargs"},
{META_SECTORARGS, "sector_t.args"},
{META_SECTORSTRINGARGS, "sector_t.stringargs"},
{META_THINGARGS, "mapthing.args"},
{META_THINGSTRINGARGS, "mapthing.stringargs"},
#ifdef HAVE_LUA_SEGS
{META_NODEBBOX, "node_t.bbox"},
{META_NODECHILDREN, "node_t.children"},
#endif
{META_BBOX, "bbox"},
{META_PATCH, "patch_t"},
{META_COLORMAP, "colormap"},
{META_CAMERA, "camera_t"},
{META_ACTION, "action"},
{META_LUABANKS, "luabanks[]"},
{META_ACTIVATOR, "activator_t"},
{META_FOLLOWER, "follower_t"},
{META_SONICLOOPVARS, "sonicloopvars_t"},
{META_SONICLOOPCAMVARS, "sonicloopcamvars_t"},
{META_BOTVARS, "botvars_t"},
{META_BOTCONTROLLER, "botcontroller_t"},
{META_SPLASH, "t_splash_t"},
{META_FOOTSTEP, "t_footstep_t"},
{META_OVERLAY, "t_overlay_t"},
{META_TERRAIN, "terrain_t"},
{NULL, NULL}
};
// goes through the above list and returns the utype string for the userdata type
// returns "unknown" instead if we couldn't find the right userdata type
static const char *GetUserdataUType(lua_State *L)
{
UINT8 i;
lua_getmetatable(L, -1);
for (i = 0; meta2utype[i].meta; i++)
{
luaL_getmetatable(L, meta2utype[i].meta);
if (lua_rawequal(L, -1, -2))
{
lua_pop(L, 2);
return meta2utype[i].utype;
}
lua_pop(L, 1);
}
lua_pop(L, 1);
return "unknown";
}
// Return a string representing the type of userdata the given var is
// e.g. players[0] -> "player_t"
// or players[0].powers -> "player_t.powers"
static int lib_userdataType(lua_State *L)
{
lua_settop(L, 1); // pop everything except arg 1 (in case somebody decided to add more)
luaL_checktype(L, 1, LUA_TUSERDATA);
lua_pushstring(L, GetUserdataUType(L));
return 1;
}
// Takes a metatable as first and only argument
// Only callable during script loading
static int lib_registerMetatable(lua_State *L)
{
static UINT16 nextid = 1;
if (!lua_lumploading)
return luaL_error(L, "This function cannot be called from within a hook or coroutine!");
luaL_checktype(L, 1, LUA_TTABLE);
if (nextid == 0)
return luaL_error(L, "Too many metatables registered?! Please consider rewriting your script once you are sober again.\n");
lua_getfield(L, LUA_REGISTRYINDEX, LREG_METATABLES); // 2
// registry.metatables[metatable] = nextid
lua_pushvalue(L, 1); // 3
lua_pushnumber(L, nextid); // 4
lua_settable(L, 2);
// registry.metatables[nextid] = metatable
lua_pushnumber(L, nextid); // 3
lua_pushvalue(L, 1); // 4
lua_settable(L, 2);
lua_pop(L, 1);
nextid++;
return 0;
}
// Takes a string as only argument and returns the metatable
// associated to the userdata type this string refers to
// Returns nil if the string does not refer to a valid userdata type
static int lib_userdataMetatable(lua_State *L)
{
UINT32 i;
const char *udname = luaL_checkstring(L, 1);
// Find internal metatable name
for (i = 0; meta2utype[i].meta; i++)
if (!strcmp(udname, meta2utype[i].utype))
{
luaL_getmetatable(L, meta2utype[i].meta);
return 1;
}
lua_pushnil(L);
return 1;
}
static int lib_isPlayerAdmin(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
//HUDSAFE
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, IsPlayerAdmin(player-players));
return 1;
}
static int lib_reserveLuabanks(lua_State *L)
{
static boolean reserved = false;
if (!lua_lumploading)
return luaL_error(L, "luabanks[] cannot be reserved from within a hook or coroutine!");
if (reserved)
return luaL_error(L, "luabanks[] has already been reserved! Only one savedata-enabled mod at a time may use this feature.");
reserved = true;
LUA_PushUserdata(L, &luabanks, META_LUABANKS);
return 1;
}
// MUSIC
////////////
static int lib_mMusicAddTune(lua_State *L)
{
UINT32 priority, tuneflags;
if (!lua_lumploading)
return luaL_error(L, "Tunes cannot be added from within a hook or coroutine!");
//NOHUD
const char *tune_id = luaL_checkstring(L, 1);
priority = (UINT32)luaL_optinteger(L, 2, 0);
tuneflags = (UINT32)luaL_optinteger(L, 3, 0);
if (!Music_TuneExists(tune_id))
{
Music_AddTune(tune_id, priority, tuneflags);
}
return 0;
}
static int lib_mMusicPlay(lua_State *L)
{
const char *tune_id = luaL_checkstring(L, 1);
player_t *player = NULL;
//NOHUD
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
{
player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!Music_TuneExists(tune_id))
{
return LUA_ErrNoTune(L, tune_id);
}
Music_Play(tune_id);
return 0;
}
static int lib_mMusicStopAll(lua_State *L)
{
player_t *player = NULL;
//NOHUD
if (!lua_isnone(L, 1) && lua_isuserdata(L, 1))
{
player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
Music_StopAll();
return 0;
}
static int lib_mMusicPauseAll(lua_State *L)
{
player_t *player = NULL;
//NOHUD
if (!lua_isnone(L, 1) && lua_isuserdata(L, 1))
{
player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
Music_PauseAll();
return 0;
}
static int lib_mMusicUnPauseAll(lua_State *L)
{
player_t *player = NULL;
//NOHUD
if (!lua_isnone(L, 1) && lua_isuserdata(L, 1))
{
player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
Music_UnPauseAll();
return 0;
}
static int lib_mMusicRemap(lua_State *L)
{
const char *tune_id = luaL_checkstring(L, 1);
const char *music_name = luaL_checkstring(L, 2);
player_t *player = NULL;
//NOHUD
if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
{
player = *((player_t **)luaL_checkudata(L, 3, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!Music_TuneExists(tune_id))
{
return LUA_ErrNoTune(L, tune_id);
}
Music_Remap(tune_id, music_name);
return 0;
}
static int lib_mMusicDim(lua_State *L)
{
tic_t fade = (tic_t)luaL_checkinteger(L, 1);
tic_t duration = INFTICS;
// If a dim is ongoing, do not interrupt it
if (g_musicfade.start < leveltime && g_musicfade.end < leveltime)
{
g_musicfade.start = leveltime;
}
if (!lua_isnoneornil(L, 2))
{
duration = (tic_t)luaL_checkinteger(L, 2);
}
g_musicfade.end = (duration != INFTICS) ? leveltime + duration + 2*fade : INFTICS;
g_musicfade.fade = fade;
g_musicfade.ticked = false;
return 0;
}
static int lib_mMusicSetFadeOut(lua_State *L)
{
UINT32 fadeoutms;
const char *tune_id = luaL_checkstring(L, 1);
fadeoutms = (UINT32)luaL_optinteger(L, 2, 0);
player_t *player = NULL;
//NOHUD
if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
{
player = *((player_t **)luaL_checkudata(L, 3, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!Music_TuneExists(tune_id))
{
return LUA_ErrNoTune(L, tune_id);
}
Music_SetFadeOut(tune_id, fadeoutms);
return 0;
}
static int lib_mMusicSetFadeIn(lua_State *L)
{
UINT32 fadeinms;
const char *tune_id = luaL_checkstring(L, 1);
fadeinms = (UINT32)luaL_optinteger(L, 2, 0);
boolean resumefade = lua_optboolean(L, 3);
player_t *player = NULL;
//NOHUD
if (!lua_isnone(L, 4) && lua_isuserdata(L, 4))
{
player = *((player_t **)luaL_checkudata(L, 4, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!Music_TuneExists(tune_id))
{
return LUA_ErrNoTune(L, tune_id);
}
Music_SetFadeIn(tune_id, fadeinms, resumefade);
return 0;
}
static int lib_mMusicDelayEnd(lua_State *L)
{
tic_t duration;
const char *tune_id = luaL_checkstring(L, 1);
duration = (tic_t)luaL_optinteger(L, 2, 0);
player_t *player = NULL;
//NOHUD
if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
{
player = *((player_t **)luaL_checkudata(L, 3, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!Music_TuneExists(tune_id))
{
return LUA_ErrNoTune(L, tune_id);
}
Music_DelayEnd(tune_id, duration);
return 0;
}
static int lib_mMusicSeek(lua_State *L)
{
UINT32 seekms;
const char *tune_id = luaL_checkstring(L, 1);
seekms = (UINT32)luaL_optinteger(L, 2, 0);
player_t *player = NULL;
//NOHUD
if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
{
player = *((player_t **)luaL_checkudata(L, 3, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!Music_TuneExists(tune_id))
{
return LUA_ErrNoTune(L, tune_id);
}
Music_Seek(tune_id, seekms);
return 0;
}
static int lib_mMusicStop(lua_State *L)
{
const char *tune_id = luaL_checkstring(L, 1);
player_t *player = NULL;
//NOHUD
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
{
player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!Music_TuneExists(tune_id))
{
return LUA_ErrNoTune(L, tune_id);
}
Music_Stop(tune_id);
return 0;
}
static int lib_mMusicPause(lua_State *L)
{
const char *tune_id = luaL_checkstring(L, 1);
player_t *player = NULL;
//NOHUD
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
{
player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!Music_TuneExists(tune_id))
{
return LUA_ErrNoTune(L, tune_id);
}
Music_Pause(tune_id);
return 0;
}
static int lib_mMusicUnPause(lua_State *L)
{
const char *tune_id = luaL_checkstring(L, 1);
player_t *player = NULL;
//NOHUD
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
{
player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!Music_TuneExists(tune_id))
{
return LUA_ErrNoTune(L, tune_id);
}
Music_UnPause(tune_id);
return 0;
}
static int lib_mMusicSuspend(lua_State *L)
{
const char *tune_id = luaL_checkstring(L, 1);
player_t *player = NULL;
//NOHUD
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
{
player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!Music_TuneExists(tune_id))
{
return LUA_ErrNoTune(L, tune_id);
}
Music_Suspend(tune_id);
return 0;
}
static int lib_mMusicUnSuspend(lua_State *L)
{
const char *tune_id = luaL_checkstring(L, 1);
player_t *player = NULL;
//NOHUD
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
{
player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!Music_TuneExists(tune_id))
{
return LUA_ErrNoTune(L, tune_id);
}
Music_UnSuspend(tune_id);
return 0;
}
static int lib_mMusicLoop(lua_State *L)
{
const char *tune_id = luaL_checkstring(L, 1);
boolean loop = lua_optboolean(L, 2);
player_t *player = NULL;
//NOHUD
if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
{
player = *((player_t **)luaL_checkudata(L, 3, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!Music_TuneExists(tune_id))
{
return LUA_ErrNoTune(L, tune_id);
}
Music_Loop(tune_id, loop);
return 0;
}
static int lib_mMusicBatchExempt(lua_State *L)
{
const char *tune_id = luaL_checkstring(L, 1);
player_t *player = NULL;
//NOHUD
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
{
player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!Music_TuneExists(tune_id))
{
return LUA_ErrNoTune(L, tune_id);
}
Music_BatchExempt(tune_id);
return 0;
}
// M_MENU
//////////////
static int lib_pGetEffectiveFollowerColor(lua_State *L)
{
UINT16 followercolor = (UINT16)luaL_checkinteger(L, 1);
UINT16 playercolor = (UINT16)luaL_checkinteger(L, 2);
lua_pushinteger(L, K_GetEffectiveFollowerColor(followercolor, NULL, playercolor, NULL)); // FIXME: follower / skin
return 1;
}
// M_RANDOM
//////////////
// TODO: Lua needs a way to set RNG class, which will break compatibility.
// It will be more desireable to do it when RNG classes can be freeslotted.
static int lib_pRandomFixed(lua_State *L)
{
NOHUD
lua_pushfixed(L, P_RandomFixed(PR_UNDEFINED));
demo_writerng = 2;
return 1;
}
static int lib_pRandomByte(lua_State *L)
{
NOHUD
lua_pushinteger(L, P_RandomByte(PR_UNDEFINED));
demo_writerng = 2;
return 1;
}
static int lib_pRandomKey(lua_State *L)
{
INT32 a = (INT32)luaL_checkinteger(L, 1);
NOHUD
lua_pushinteger(L, P_RandomKey(PR_UNDEFINED, a));
demo_writerng = 2;
return 1;
}
static int lib_pRandomRange(lua_State *L)
{
INT32 a = (INT32)luaL_checkinteger(L, 1);
INT32 b = (INT32)luaL_checkinteger(L, 2);
NOHUD
if (b < a)
{
INT32 c = a;
a = b;
b = c;
}
lua_pushinteger(L, P_RandomRange(PR_UNDEFINED, a, b));
demo_writerng = 2;
return 1;
}
// Macros.
static int lib_pSignedRandom(lua_State *L)
{
NOHUD
lua_pushinteger(L, P_SignedRandom(PR_UNDEFINED));
demo_writerng = 2;
return 1;
}
static int lib_pRandomChance(lua_State *L)
{
fixed_t p = luaL_checkfixed(L, 1);
NOHUD
lua_pushboolean(L, P_RandomChance(PR_UNDEFINED, p));
demo_writerng = 2;
return 1;
}
// P_MAPUTIL
///////////////
static int lib_pAproxDistance(lua_State *L)
{
fixed_t dx = luaL_checkfixed(L, 1);
fixed_t dy = luaL_checkfixed(L, 2);
//HUDSAFE
lua_pushfixed(L, P_AproxDistance(dx, dy));
return 1;
}
static int lib_pClosestPointOnLine(lua_State *L)
{
int n = lua_gettop(L);
fixed_t x = luaL_checkfixed(L, 1);
fixed_t y = luaL_checkfixed(L, 2);
vertex_t result;
//HUDSAFE
if (lua_isuserdata(L, 3)) // use a real linedef to get our points
{
line_t *line = *((line_t **)luaL_checkudata(L, 3, META_LINE));
if (!line)
return LUA_ErrInvalid(L, "line_t");
P_ClosestPointOnLine(x, y, line, &result);
}
else // use custom coordinates of our own!
{
vertex_t v1, v2; // fake vertexes
line_t junk; // fake linedef
if (n < 6)
return luaL_error(L, "arguments 3 to 6 not all given (expected 4 fixed-point integers)");
v1.x = luaL_checkfixed(L, 3);
v1.y = luaL_checkfixed(L, 4);
v2.x = luaL_checkfixed(L, 5);
v2.y = luaL_checkfixed(L, 6);
junk.v1 = &v1;
junk.v2 = &v2;
junk.dx = v2.x - v1.x;
junk.dy = v2.y - v1.y;
P_ClosestPointOnLine(x, y, &junk, &result);
}
lua_pushfixed(L, result.x);
lua_pushfixed(L, result.y);
return 2;
}
static int lib_pPointOnLineSide(lua_State *L)
{
int n = lua_gettop(L);
fixed_t x = luaL_checkfixed(L, 1);
fixed_t y = luaL_checkfixed(L, 2);
//HUDSAFE
if (lua_isuserdata(L, 3)) // use a real linedef to get our points
{
line_t *line = *((line_t **)luaL_checkudata(L, 3, META_LINE));
if (!line)
return LUA_ErrInvalid(L, "line_t");
lua_pushinteger(L, P_PointOnLineSide(x, y, line));
}
else // use custom coordinates of our own!
{
vertex_t v1, v2; // fake vertexes
line_t junk; // fake linedef
if (n < 6)
return luaL_error(L, "arguments 3 to 6 not all given (expected 4 fixed-point integers)");
v1.x = luaL_checkfixed(L, 3);
v1.y = luaL_checkfixed(L, 4);
v2.x = luaL_checkfixed(L, 5);
v2.y = luaL_checkfixed(L, 6);
junk.v1 = &v1;
junk.v2 = &v2;
junk.dx = v2.x - v1.x;
junk.dy = v2.y - v1.y;
lua_pushinteger(L, P_PointOnLineSide(x, y, &junk));
}
return 1;
}
// P_ENEMY
/////////////
static int lib_pCheckMeleeRange(lua_State *L)
{
mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
INLEVEL
if (!actor)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_CheckMeleeRange(actor));
return 1;
}
static int lib_pJetbCheckMeleeRange(lua_State *L)
{
mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
INLEVEL
if (!actor)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_JetbCheckMeleeRange(actor));
return 1;
}
static int lib_pFaceStabCheckMeleeRange(lua_State *L)
{
mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
INLEVEL
if (!actor)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_FaceStabCheckMeleeRange(actor));
return 1;
}
static int lib_pSkimCheckMeleeRange(lua_State *L)
{
mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
INLEVEL
if (!actor)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_SkimCheckMeleeRange(actor));
return 1;
}
static int lib_pCheckMissileRange(lua_State *L)
{
mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
INLEVEL
if (!actor)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_CheckMissileRange(actor));
return 1;
}
static int lib_pNewChaseDir(lua_State *L)
{
mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
INLEVEL
if (!actor)
return LUA_ErrInvalid(L, "mobj_t");
P_NewChaseDir(actor);
return 0;
}
static int lib_pLookForPlayers(lua_State *L)
{
mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
fixed_t dist = (fixed_t)luaL_optinteger(L, 2, 0);
boolean allaround = lua_optboolean(L, 3);
boolean tracer = lua_optboolean(L, 4);
NOHUD
INLEVEL
if (!actor)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_LookForPlayers(actor, allaround, tracer, dist));
return 1;
}
// P_MOBJ
////////////
static int lib_pSpawnMobj(lua_State *L)
{
fixed_t x = luaL_checkfixed(L, 1);
fixed_t y = luaL_checkfixed(L, 2);
fixed_t z = luaL_checkfixed(L, 3);
mobjtype_t type = luaL_checkinteger(L, 4);
NOHUD
INLEVEL
if (type >= NUMMOBJTYPES)
return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
LUA_PushUserdata(L, P_SpawnMobj(x, y, z, type), META_MOBJ);
return 1;
}
static int lib_pSpawnMobjFromMobj(lua_State *L)
{
mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
fixed_t x = luaL_checkfixed(L, 2);
fixed_t y = luaL_checkfixed(L, 3);
fixed_t z = luaL_checkfixed(L, 4);
mobjtype_t type = luaL_checkinteger(L, 5);
NOHUD
INLEVEL
if (!actor)
return LUA_ErrInvalid(L, "mobj_t");
if (type >= NUMMOBJTYPES)
return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
LUA_PushUserdata(L, P_SpawnMobjFromMobj(actor, x, y, z, type), META_MOBJ);
return 1;
}
static int lib_pSpawnMobjFromMobjUnscaled(lua_State *L)
{
mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
fixed_t x = luaL_checkfixed(L, 2);
fixed_t y = luaL_checkfixed(L, 3);
fixed_t z = luaL_checkfixed(L, 4);
mobjtype_t type = luaL_checkinteger(L, 5);
NOHUD
INLEVEL
if (!actor)
return LUA_ErrInvalid(L, "mobj_t");
if (type >= NUMMOBJTYPES)
return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
LUA_PushUserdata(L, P_SpawnMobjFromMobjUnscaled(actor, x, y, z, type), META_MOBJ);
return 1;
}
static int lib_pRemoveMobj(lua_State *L)
{
mobj_t *th = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
INLEVEL
if (!th)
return LUA_ErrInvalid(L, "mobj_t");
if (th->player)
return luaL_error(L, "Attempt to remove player mobj with P_RemoveMobj.");
P_RemoveMobj(th);
return 0;
}
// P_IsValidSprite2 technically doesn't exist, and probably never should... but too much would need to be exposed to allow this to be checked by other methods.
static int lib_pIsValidSprite2(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
UINT8 spr2 = (UINT8)luaL_checkinteger(L, 2);
//HUDSAFE
INLEVEL
if (!mobj)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, (mobj->skin && (((skin_t *)mobj->skin)->sprites[spr2].numframes)));
return 1;
}
// P_SpawnLockOn doesn't exist either, but we want to expose making a local mobj without encouraging hacks.
static int lib_pSpawnLockOn(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
mobj_t *lockon = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
statenum_t state = luaL_checkinteger(L, 3);
NOHUD
INLEVEL
if (!lockon)
return LUA_ErrInvalid(L, "mobj_t");
if (!player)
return LUA_ErrInvalid(L, "player_t");
if (state >= NUMSTATES)
return luaL_error(L, "state %d out of range (0 - %d)", state, NUMSTATES-1);
#if 0
if (P_IsPartyPlayer(player)) // Only display it on your own view.
{
mobj_t *visual = P_SpawnMobj(lockon->x, lockon->y, lockon->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker
P_SetTarget(&visual->target, lockon);
visual->renderflags |= RF_DONTDRAW;
P_SetMobjStateNF(visual, state);
}
#else
CONS_Alert(CONS_WARNING, "TODO: P_SpawnLockOn is deprecated\n");
#endif
return 0;
}
static int lib_pSpawnMissile(lua_State *L)
{
mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *dest = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
mobjtype_t type = luaL_checkinteger(L, 3);
NOHUD
INLEVEL
if (!source || !dest)
return LUA_ErrInvalid(L, "mobj_t");
if (type >= NUMMOBJTYPES)
return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
LUA_PushUserdata(L, P_SpawnMissile(source, dest, type), META_MOBJ);
return 1;
}
static int lib_pSpawnXYZMissile(lua_State *L)
{
mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *dest = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
mobjtype_t type = luaL_checkinteger(L, 3);
fixed_t x = luaL_checkfixed(L, 4);
fixed_t y = luaL_checkfixed(L, 5);
fixed_t z = luaL_checkfixed(L, 6);
NOHUD
INLEVEL
if (!source || !dest)
return LUA_ErrInvalid(L, "mobj_t");
if (type >= NUMMOBJTYPES)
return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
LUA_PushUserdata(L, P_SpawnXYZMissile(source, dest, type, x, y, z), META_MOBJ);
return 1;
}
static int lib_pSpawnPointMissile(lua_State *L)
{
mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
fixed_t xa = luaL_checkfixed(L, 2);
fixed_t ya = luaL_checkfixed(L, 3);
fixed_t za = luaL_checkfixed(L, 4);
mobjtype_t type = luaL_checkinteger(L, 5);
fixed_t x = luaL_checkfixed(L, 6);
fixed_t y = luaL_checkfixed(L, 7);
fixed_t z = luaL_checkfixed(L, 8);
NOHUD
INLEVEL
if (!source)
return LUA_ErrInvalid(L, "mobj_t");
if (type >= NUMMOBJTYPES)
return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
LUA_PushUserdata(L, P_SpawnPointMissile(source, xa, ya, za, type, x, y, z), META_MOBJ);
return 1;
}
static int lib_pSpawnAlteredDirectionMissile(lua_State *L)
{
mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobjtype_t type = luaL_checkinteger(L, 2);
fixed_t x = luaL_checkfixed(L, 3);
fixed_t y = luaL_checkfixed(L, 4);
fixed_t z = luaL_checkfixed(L, 5);
INT32 shiftingAngle = (INT32)luaL_checkinteger(L, 5);
NOHUD
INLEVEL
if (!source)
return LUA_ErrInvalid(L, "mobj_t");
if (type >= NUMMOBJTYPES)
return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
LUA_PushUserdata(L, P_SpawnAlteredDirectionMissile(source, type, x, y, z, shiftingAngle), META_MOBJ);
return 1;
}
static int lib_pColorTeamMissile(lua_State *L)
{
mobj_t *missile = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
player_t *source = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
NOHUD
INLEVEL
if (!missile)
return LUA_ErrInvalid(L, "mobj_t");
if (!source)
return LUA_ErrInvalid(L, "player_t");
P_ColorTeamMissile(missile, source);
return 0;
}
static int lib_pSPMAngle(lua_State *L)
{
mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobjtype_t type = luaL_checkinteger(L, 2);
angle_t angle = luaL_checkangle(L, 3);
UINT8 allowaim = (UINT8)luaL_optinteger(L, 4, 0);
UINT32 flags2 = (UINT32)luaL_optinteger(L, 5, 0);
NOHUD
INLEVEL
if (!source)
return LUA_ErrInvalid(L, "mobj_t");
if (type >= NUMMOBJTYPES)
return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
LUA_PushUserdata(L, P_SPMAngle(source, type, angle, allowaim, flags2), META_MOBJ);
return 1;
}
static int lib_pSpawnPlayerMissile(lua_State *L)
{
mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobjtype_t type = luaL_checkinteger(L, 2);
UINT32 flags2 = (UINT32)luaL_optinteger(L, 3, 0);
NOHUD
INLEVEL
if (!source)
return LUA_ErrInvalid(L, "mobj_t");
if (type >= NUMMOBJTYPES)
return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
LUA_PushUserdata(L, P_SpawnPlayerMissile(source, type, flags2), META_MOBJ);
return 1;
}
static int lib_pMobjFlip(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
//HUDSAFE
INLEVEL
if (!mobj)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushinteger(L, P_MobjFlip(mobj));
return 1;
}
static int lib_pGetMobjGravity(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
//HUDSAFE
INLEVEL
if (!mobj)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushfixed(L, P_GetMobjGravity(mobj));
return 1;
}
static int lib_pFlashPal(lua_State *L)
{
player_t *pl = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
UINT16 type = (UINT16)luaL_checkinteger(L, 2);
UINT16 duration = (UINT16)luaL_checkinteger(L, 3);
NOHUD
INLEVEL
if (!pl)
return LUA_ErrInvalid(L, "player_t");
P_FlashPal(pl, type, duration);
return 0;
}
static int lib_pGetClosestAxis(lua_State *L)
{
mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
//HUDSAFE
INLEVEL
if (!source)
return LUA_ErrInvalid(L, "mobj_t");
LUA_PushUserdata(L, P_GetClosestAxis(source), META_MOBJ);
return 1;
}
static int lib_pSpawnParaloop(lua_State *L)
{
fixed_t x = luaL_checkfixed(L, 1);
fixed_t y = luaL_checkfixed(L, 2);
fixed_t z = luaL_checkfixed(L, 3);
fixed_t radius = luaL_checkfixed(L, 4);
INT32 number = (INT32)luaL_checkinteger(L, 5);
mobjtype_t type = luaL_checkinteger(L, 6);
angle_t rotangle = luaL_checkangle(L, 7);
statenum_t nstate = luaL_optinteger(L, 8, S_NULL);
boolean spawncenter = lua_optboolean(L, 9);
NOHUD
INLEVEL
if (type >= NUMMOBJTYPES)
return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
if (nstate >= NUMSTATES)
return luaL_error(L, "state %d out of range (0 - %d)", nstate, NUMSTATES-1);
P_SpawnParaloop(x, y, z, radius, number, type, nstate, rotangle, spawncenter);
return 0;
}
static int lib_pBossTargetPlayer(lua_State *L)
{
mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
boolean closest = lua_optboolean(L, 2);
NOHUD
INLEVEL
if (!actor)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_BossTargetPlayer(actor, closest));
return 1;
}
static int lib_pSupermanLook4Players(lua_State *L)
{
mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
INLEVEL
if (!actor)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_SupermanLook4Players(actor));
return 1;
}
static int lib_pSetScale(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
fixed_t newscale = luaL_checkfixed(L, 2);
NOHUD
INLEVEL
if (!mobj)
return LUA_ErrInvalid(L, "mobj_t");
if (newscale < FRACUNIT/100)
newscale = FRACUNIT/100;
P_SetScale(mobj, newscale);
return 0;
}
static int lib_pInsideANonSolidFFloor(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
ffloor_t *rover = *((ffloor_t **)luaL_checkudata(L, 2, META_FFLOOR));
//HUDSAFE
INLEVEL
if (!mobj)
return LUA_ErrInvalid(L, "mobj_t");
if (!rover)
return LUA_ErrInvalid(L, "ffloor_t");
lua_pushboolean(L, P_InsideANonSolidFFloor(mobj, rover));
return 1;
}
static int lib_pCheckDeathPitCollide(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
//HUDSAFE
INLEVEL
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_CheckDeathPitCollide(mo));
return 1;
}
static int lib_pCheckSolidLava(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
ffloor_t *rover = *((ffloor_t **)luaL_checkudata(L, 2, META_FFLOOR));
//HUDSAFE
INLEVEL
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
if (!rover)
return LUA_ErrInvalid(L, "ffloor_t");
lua_pushboolean(L, P_CheckSolidLava(mo, rover));
return 1;
}
static int lib_pMaceRotate(lua_State *L)
{
mobj_t *center = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
INT32 baserot = luaL_checkinteger(L, 2);
INT32 baseprevrot = luaL_checkinteger(L, 3);
NOHUD
INLEVEL
if (!center)
return LUA_ErrInvalid(L, "mobj_t");
P_MaceRotate(center, baserot, baseprevrot);
return 0;
}
static int lib_pCreateFloorSpriteSlope(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
INLEVEL
if (!mobj)
return LUA_ErrInvalid(L, "mobj_t");
LUA_PushUserdata(L, (pslope_t *)P_CreateFloorSpriteSlope(mobj), META_SLOPE);
return 1;
}
static int lib_pRemoveFloorSpriteSlope(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
INLEVEL
if (!mobj)
return LUA_ErrInvalid(L, "mobj_t");
P_RemoveFloorSpriteSlope(mobj);
return 1;
}
static int lib_pRailThinker(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
tm_t ptm = g_tm;
NOHUD
INLEVEL
if (!mobj)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_RailThinker(mobj));
P_RestoreTMStruct(ptm);
return 1;
}
static int lib_pXYMovement(lua_State *L)
{
mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
tm_t ptm = g_tm;
NOHUD
INLEVEL
if (!actor)
return LUA_ErrInvalid(L, "mobj_t");
P_XYMovement(actor);
P_RestoreTMStruct(ptm);
return 0;
}
static int lib_pRingXYMovement(lua_State *L)
{
mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
tm_t ptm = g_tm;
NOHUD
INLEVEL
if (!actor)
return LUA_ErrInvalid(L, "mobj_t");
P_RingXYMovement(actor);
P_RestoreTMStruct(ptm);
return 0;
}
static int lib_pSceneryXYMovement(lua_State *L)
{
mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
tm_t ptm = g_tm;
NOHUD
INLEVEL
if (!actor)
return LUA_ErrInvalid(L, "mobj_t");
P_SceneryXYMovement(actor);
P_RestoreTMStruct(ptm);
return 0;
}
static int lib_pZMovement(lua_State *L)
{
mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
tm_t ptm = g_tm;
NOHUD
INLEVEL
if (!actor)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_ZMovement(actor));
P_CheckPosition(actor, actor->x, actor->y, NULL);
P_RestoreTMStruct(ptm);
return 1;
}
static int lib_pRingZMovement(lua_State *L)
{
mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
tm_t ptm = g_tm;
NOHUD
INLEVEL
if (!actor)
return LUA_ErrInvalid(L, "mobj_t");
P_RingZMovement(actor);
P_CheckPosition(actor, actor->x, actor->y, NULL);
P_RestoreTMStruct(ptm);
return 0;
}
static int lib_pSceneryZMovement(lua_State *L)
{
mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
tm_t ptm = g_tm;
NOHUD
INLEVEL
if (!actor)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_SceneryZMovement(actor));
P_CheckPosition(actor, actor->x, actor->y, NULL);
P_RestoreTMStruct(ptm);
return 1;
}
static int lib_pPlayerZMovement(lua_State *L)
{
mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
tm_t ptm = g_tm;
NOHUD
INLEVEL
if (!actor)
return LUA_ErrInvalid(L, "mobj_t");
P_PlayerZMovement(actor);
P_CheckPosition(actor, actor->x, actor->y, NULL);
P_RestoreTMStruct(ptm);
return 0;
}
// P_TICK
////////////
static int lib_pLevelIsFrozen(lua_State *L)
{
INLEVEL
lua_pushboolean(L, P_LevelIsFrozen());
return 1;
}
static int lib_pSetFreezeLevel(lua_State *L)
{
boolean value = luaL_checkboolean(L, 1);
NOHUD
INLEVEL
P_SetFreezeLevel(value);
return 0;
}
static int lib_pMobjIsFrozen(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
INLEVEL
if (!mobj)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_MobjIsFrozen(mobj));
return 1;
}
// P_USER
////////////
static int lib_pAddPlayerScore(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INT32 amount = (UINT32)luaL_checkinteger(L, 2);
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
P_AddPlayerScore(player, amount);
return 0;
}
static int lib_pPlayerInPain(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
//HUDSAFE
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, P_PlayerInPain(player));
return 1;
}
static int lib_pResetPlayer(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
P_ResetPlayer(player);
return 0;
}
static int lib_pPlayerFullbright(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, P_PlayerFullbright(player));
return 1;
}
static int lib_pIsObjectInGoop(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
//HUDSAFE
INLEVEL
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_IsObjectInGoop(mo));
return 1;
}
static int lib_pIsObjectOnGround(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
//HUDSAFE
INLEVEL
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_IsObjectOnGround(mo));
return 1;
}
static int lib_pInQuicksand(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
//HUDSAFE
INLEVEL
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_InQuicksand(mo));
return 1;
}
static int lib_pSetObjectMomZ(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
fixed_t value = luaL_checkfixed(L, 2);
boolean relative = lua_optboolean(L, 3);
NOHUD
INLEVEL
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
P_SetObjectMomZ(mo, value, relative);
return 0;
}
static int lib_pSpawnGhostMobj(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
INLEVEL
if (!mobj)
return LUA_ErrInvalid(L, "mobj_t");
LUA_PushUserdata(L, P_SpawnGhostMobj(mobj), META_MOBJ);
return 1;
}
static int lib_pSpawnFakeShadow(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
UINT8 offset = (UINT8)luaL_checkinteger(L, 2);
NOHUD
INLEVEL
if (!mobj)
return LUA_ErrInvalid(L, "mobj_t");
LUA_PushUserdata(L, P_SpawnFakeShadow(mobj, offset), META_MOBJ);
return 1;
}
static int lib_pGivePlayerRings(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INT32 num_rings = (INT32)luaL_checkinteger(L, 2);
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushinteger(L, P_GivePlayerRings(player, num_rings));
return 1;
}
static int lib_pGivePlayerSpheres(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INT32 num_spheres = (INT32)luaL_checkinteger(L, 2);
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushinteger(L, P_GivePlayerSpheres(player, num_spheres));
return 1;
}
static int lib_pGivePlayerLives(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INT32 numlives = (INT32)luaL_checkinteger(L, 2);
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
P_GivePlayerLives(player, numlives);
return 0;
}
static int lib_pMovePlayer(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
tm_t ptm = g_tm;
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
P_MovePlayer(player);
P_RestoreTMStruct(ptm);
return 0;
}
static int lib_pDoPlayerExit(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
pflags_t flags = luaL_checkinteger(L, 2);
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
P_DoPlayerExit(player, flags);
return 0;
}
static int lib_pDoAllPlayersExit(lua_State *L)
{
pflags_t flags = luaL_checkinteger(L, 1);
boolean trygivelife = lua_optboolean(L, 2);
NOHUD
INLEVEL
P_DoAllPlayersExit(flags, trygivelife);
return 0;
}
static int lib_pInstaThrust(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
angle_t angle = luaL_checkangle(L, 2);
fixed_t move = luaL_checkfixed(L, 3);
NOHUD
INLEVEL
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
P_InstaThrust(mo, angle, move);
return 0;
}
static int lib_pReturnThrustX(lua_State *L)
{
angle_t angle;
fixed_t move;
if (lua_isnil(L, 1) || lua_isuserdata(L, 1))
lua_remove(L, 1); // ignore mobj as arg1
angle = luaL_checkangle(L, 1);
move = luaL_checkfixed(L, 2);
//HUDSAFE
lua_pushfixed(L, P_ReturnThrustX(NULL, angle, move));
return 1;
}
static int lib_pReturnThrustY(lua_State *L)
{
angle_t angle;
fixed_t move;
if (lua_isnil(L, 1) || lua_isuserdata(L, 1))
lua_remove(L, 1); // ignore mobj as arg1
angle = luaL_checkangle(L, 1);
move = luaL_checkfixed(L, 2);
//HUDSAFE
lua_pushfixed(L, P_ReturnThrustY(NULL, angle, move));
return 1;
}
static int lib_pNukeEnemies(lua_State *L)
{
mobj_t *inflictor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *source = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
fixed_t radius = luaL_checkfixed(L, 3);
NOHUD
INLEVEL
if (!inflictor || !source)
return LUA_ErrInvalid(L, "mobj_t");
P_NukeEnemies(inflictor, source, radius);
return 0;
}
static int lib_pSetPlayerAngle(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
angle_t angle = luaL_checkangle(L, 2);
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
P_SetPlayerAngle(player, angle);
return 0;
}
static int lib_pForceLocalAngle(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
angle_t angle = luaL_checkangle(L, 2);
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
P_ForceLocalAngle(player, angle);
return 0;
}
// P_MAP
///////////
static int lib_pCheckPosition(lua_State *L)
{
tm_t ptm = g_tm;
mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
fixed_t x = luaL_checkfixed(L, 2);
fixed_t y = luaL_checkfixed(L, 3);
NOHUD
INLEVEL
if (!thing)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_CheckPosition(thing, x, y, NULL));
LUA_PushUserdata(L, g_tm.thing, META_MOBJ);
P_RestoreTMStruct(ptm);
return 2;
}
static int lib_pTryMove(lua_State *L)
{
tm_t ptm = g_tm;
mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
fixed_t x = luaL_checkfixed(L, 2);
fixed_t y = luaL_checkfixed(L, 3);
boolean allowdropoff = lua_optboolean(L, 4);
NOHUD
INLEVEL
if (!thing)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_TryMove(thing, x, y, allowdropoff, NULL));
LUA_PushUserdata(L, g_tm.thing, META_MOBJ);
P_RestoreTMStruct(ptm);
return 2;
}
static int lib_pMove(lua_State *L)
{
tm_t ptm = g_tm;
mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
fixed_t speed = luaL_checkfixed(L, 2);
NOHUD
INLEVEL
if (!actor)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_Move(actor, speed));
LUA_PushUserdata(L, g_tm.thing, META_MOBJ);
P_RestoreTMStruct(ptm);
return 2;
}
static int lib_pTeleportMove(lua_State *L)
{
tm_t ptm = g_tm;
mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
fixed_t x = luaL_checkfixed(L, 2);
fixed_t y = luaL_checkfixed(L, 3);
fixed_t z = luaL_checkfixed(L, 4);
NOHUD
INLEVEL
if (!thing)
return LUA_ErrInvalid(L, "mobj_t");
LUA_Deprecated(L, "P_TeleportMove", "P_SetOrigin\" or \"P_MoveOrigin");
lua_pushboolean(L, P_MoveOrigin(thing, x, y, z));
LUA_PushUserdata(L, g_tm.thing, META_MOBJ);
P_RestoreTMStruct(ptm);
return 2;
}
static int lib_pSetOrigin(lua_State *L)
{
tm_t ptm = g_tm;
mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
fixed_t x = luaL_checkfixed(L, 2);
fixed_t y = luaL_checkfixed(L, 3);
fixed_t z = luaL_checkfixed(L, 4);
NOHUD
INLEVEL
if (!thing)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_SetOrigin(thing, x, y, z));
LUA_PushUserdata(L, g_tm.thing, META_MOBJ);
P_RestoreTMStruct(ptm);
return 2;
}
static int lib_pMoveOrigin(lua_State *L)
{
tm_t ptm = g_tm;
mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
fixed_t x = luaL_checkfixed(L, 2);
fixed_t y = luaL_checkfixed(L, 3);
fixed_t z = luaL_checkfixed(L, 4);
NOHUD
INLEVEL
if (!thing)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_MoveOrigin(thing, x, y, z));
LUA_PushUserdata(L, g_tm.thing, META_MOBJ);
P_RestoreTMStruct(ptm);
return 2;
}
static int lib_pSetAngle(lua_State *L)
{
mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
angle_t newValue = luaL_checkangle(L, 2);
NOHUD
INLEVEL
if (!thing)
return LUA_ErrInvalid(L, "mobj_t");
//P_SetAngle(thing, newValue);
thing->angle = thing->old_angle = newValue;
return 0;
}
static int lib_pSetPitch(lua_State *L)
{
mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
angle_t newValue = luaL_checkangle(L, 2);
NOHUD
INLEVEL
if (!thing)
return LUA_ErrInvalid(L, "mobj_t");
//P_SetPitch(thing, newValue);
thing->pitch = thing->old_pitch = newValue;
return 0;
}
static int lib_pSetRoll(lua_State *L)
{
mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
angle_t newValue = luaL_checkangle(L, 2);
NOHUD
INLEVEL
if (!thing)
return LUA_ErrInvalid(L, "mobj_t");
//P_SetRoll(thing, newValue);
thing->roll = thing->old_roll = newValue;
return 0;
}
static int lib_pSlideMove(lua_State *L)
{
/*
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
INLEVEL
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
P_SlideMove(mo);
*/
LUA_UsageWarning(L, "FIXME: P_SlideMove needs updated to use result from P_TryMove");
(void)L;
return 0;
}
static int lib_pBounceMove(lua_State *L)
{
/*
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
INLEVEL
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
P_BounceMove(mo);
*/
LUA_UsageWarning(L, "FIXME: P_BounceMove needs updated to use result from P_TryMove");
(void)L;
return 0;
}
static int lib_pCheckSight(lua_State *L)
{
mobj_t *t1 = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *t2 = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
//HUDSAFE?
INLEVEL
if (!t1 || !t2)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_CheckSight(t1, t2));
return 1;
}
static int lib_pTraceBlockingLines(lua_State *L)
{
mobj_t *t1 = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *t2 = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
//HUDSAFE?
INLEVEL
if (!t1 || !t2)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_TraceBlockingLines(t1, t2));
return 1;
}
static int lib_pCheckHoopPosition(lua_State *L)
{
mobj_t *hoopthing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
fixed_t x = luaL_checkfixed(L, 2);
fixed_t y = luaL_checkfixed(L, 3);
fixed_t z = luaL_checkfixed(L, 4);
fixed_t radius = luaL_checkfixed(L, 5);
NOHUD
INLEVEL
if (!hoopthing)
return LUA_ErrInvalid(L, "mobj_t");
P_CheckHoopPosition(hoopthing, x, y, z, radius);
return 0;
}
static int lib_pRadiusAttack(lua_State *L)
{
mobj_t *spot = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *source = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
fixed_t damagedist = luaL_checkfixed(L, 3);
UINT8 damagetype = luaL_optinteger(L, 4, 0);
boolean sightcheck = lua_opttrueboolean(L, 5);
NOHUD
INLEVEL
if (!spot || !source)
return LUA_ErrInvalid(L, "mobj_t");
P_RadiusAttack(spot, source, damagedist, damagetype, sightcheck);
return 0;
}
static int lib_pFloorzAtPos(lua_State *L)
{
fixed_t x = luaL_checkfixed(L, 1);
fixed_t y = luaL_checkfixed(L, 2);
fixed_t z = luaL_checkfixed(L, 3);
fixed_t height = luaL_checkfixed(L, 4);
//HUDSAFE
INLEVEL
lua_pushfixed(L, P_FloorzAtPos(x, y, z, height));
return 1;
}
static int lib_pCeilingzAtPos(lua_State *L)
{
fixed_t x = luaL_checkfixed(L, 1);
fixed_t y = luaL_checkfixed(L, 2);
fixed_t z = luaL_checkfixed(L, 3);
fixed_t height = luaL_checkfixed(L, 4);
//HUDSAFE
INLEVEL
lua_pushfixed(L, P_CeilingzAtPos(x, y, z, height));
return 1;
}
static int lib_pDoSpring(lua_State *L)
{
mobj_t *spring = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *object = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
NOHUD
INLEVEL
if (!spring || !object)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_DoSpring(spring, object));
return 1;
}
// P_INTER
////////////
static int lib_pDamageMobj(lua_State *L)
{
mobj_t *target = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)), *inflictor = NULL, *source = NULL;
INT32 damage;
UINT8 damagetype;
NOHUD
INLEVEL
if (!target)
return LUA_ErrInvalid(L, "mobj_t");
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
inflictor = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
source = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
damage = (INT32)luaL_optinteger(L, 4, 1);
damagetype = (UINT8)luaL_optinteger(L, 5, 0);
lua_pushboolean(L, P_DamageMobj(target, inflictor, source, damage, damagetype));
return 1;
}
static int lib_pKillMobj(lua_State *L)
{
mobj_t *target = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)), *inflictor = NULL, *source = NULL;
UINT8 damagetype;
NOHUD
INLEVEL
if (!target)
return LUA_ErrInvalid(L, "mobj_t");
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
inflictor = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
source = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
damagetype = (UINT8)luaL_optinteger(L, 4, 0);
P_KillMobj(target, inflictor, source, damagetype);
return 0;
}
static int lib_pPlayerRingBurst(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INT32 num_rings = (INT32)luaL_optinteger(L, 2, -1);
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
if (num_rings == -1)
num_rings = player->rings;
P_PlayerRingBurst(player, num_rings);
return 0;
}
static int lib_pPlayRinglossSound(lua_State *L)
{
mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
player_t *player = NULL;
NOHUD
INLEVEL
if (!source)
return LUA_ErrInvalid(L, "mobj_t");
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
{
player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!player || P_IsPartyPlayer(player))
P_PlayRinglossSound(source);
return 0;
}
static int lib_pPlayDeathSound(lua_State *L)
{
mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
player_t *player = NULL;
NOHUD
INLEVEL
if (!source)
return LUA_ErrInvalid(L, "mobj_t");
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
{
player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!player || P_IsPartyPlayer(player))
P_PlayDeathSound(source);
return 0;
}
static int lib_pPlayVictorySound(lua_State *L)
{
mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
player_t *player = NULL;
NOHUD
INLEVEL
if (!source)
return LUA_ErrInvalid(L, "mobj_t");
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
{
player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!player || P_IsPartyPlayer(player))
P_PlayVictorySound(source);
return 0;
}
static int lib_pCanPickupItem(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
UINT8 weapon = (UINT8)luaL_optinteger(L, 2, 0);
//HUDSAFE
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, P_CanPickupItem(player, weapon));
return 1;
}
// P_SPEC
////////////
static int lib_pThrust(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
angle_t angle = luaL_checkangle(L, 2);
fixed_t move = luaL_checkfixed(L, 3);
NOHUD
INLEVEL
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
P_Thrust(mo, angle, move);
return 0;
}
static int lib_pSetMobjStateNF(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
statenum_t state = luaL_checkinteger(L, 2);
NOHUD
INLEVEL
if (!mobj)
return LUA_ErrInvalid(L, "mobj_t");
if (state >= NUMSTATES)
return luaL_error(L, "state %d out of range (0 - %d)", state, NUMSTATES-1);
if (mobj->player && state == S_NULL)
return luaL_error(L, "Attempt to remove player mobj with S_NULL.");
lua_pushboolean(L, P_SetMobjStateNF(mobj, state));
return 1;
}
static int lib_pExplodeMissile(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
INLEVEL
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
P_ExplodeMissile(mo);
return 0;
}
static int lib_pMobjTouchingSectorSpecial(lua_State *L)
{
mobj_t *mo = *((mobj_t**)luaL_checkudata(L, 1, META_MOBJ));
INT32 section = (INT32)luaL_checkinteger(L, 2);
INT32 number = (INT32)luaL_checkinteger(L, 3);
//HUDSAFE
INLEVEL
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
LUA_PushUserdata(L, P_MobjTouchingSectorSpecial(mo, section, number), META_SECTOR);
return 1;
}
static int lib_pMobjTouchingSectorSpecialFlag(lua_State *L)
{
mobj_t *mo = *((mobj_t**)luaL_checkudata(L, 1, META_MOBJ));
sectorspecialflags_t flag = (INT32)luaL_checkinteger(L, 2);
//HUDSAFE
INLEVEL
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
LUA_PushUserdata(L, P_MobjTouchingSectorSpecialFlag(mo, flag), META_SECTOR);
return 1;
}
static int lib_pPlayerTouchingSectorSpecial(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INT32 section = (INT32)luaL_checkinteger(L, 2);
INT32 number = (INT32)luaL_checkinteger(L, 3);
//HUDSAFE
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
LUA_PushUserdata(L, P_PlayerTouchingSectorSpecial(player, section, number), META_SECTOR);
return 1;
}
static int lib_pPlayerTouchingSectorSpecialFlag(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
sectorspecialflags_t flag = (INT32)luaL_checkinteger(L, 2);
//HUDSAFE
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
LUA_PushUserdata(L, P_PlayerTouchingSectorSpecialFlag(player, flag), META_SECTOR);
return 1;
}
static int lib_pFindLowestFloorSurrounding(lua_State *L)
{
sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
//HUDSAFE
INLEVEL
if (!sector)
return LUA_ErrInvalid(L, "sector_t");
lua_pushfixed(L, P_FindLowestFloorSurrounding(sector));
return 1;
}
static int lib_pFindHighestFloorSurrounding(lua_State *L)
{
sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
//HUDSAFE
INLEVEL
if (!sector)
return LUA_ErrInvalid(L, "sector_t");
lua_pushfixed(L, P_FindHighestFloorSurrounding(sector));
return 1;
}
static int lib_pFindNextHighestFloor(lua_State *L)
{
sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
fixed_t currentheight;
//HUDSAFE
INLEVEL
if (!sector)
return LUA_ErrInvalid(L, "sector_t");
// defaults to floorheight of sector arg
currentheight = (fixed_t)luaL_optinteger(L, 2, sector->floorheight);
lua_pushfixed(L, P_FindNextHighestFloor(sector, currentheight));
return 1;
}
static int lib_pFindNextLowestFloor(lua_State *L)
{
sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
fixed_t currentheight;
//HUDSAFE
INLEVEL
if (!sector)
return LUA_ErrInvalid(L, "sector_t");
// defaults to floorheight of sector arg
currentheight = (fixed_t)luaL_optinteger(L, 2, sector->floorheight);
lua_pushfixed(L, P_FindNextLowestFloor(sector, currentheight));
return 1;
}
static int lib_pFindLowestCeilingSurrounding(lua_State *L)
{
sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
//HUDSAFE
INLEVEL
if (!sector)
return LUA_ErrInvalid(L, "sector_t");
lua_pushfixed(L, P_FindLowestCeilingSurrounding(sector));
return 1;
}
static int lib_pFindHighestCeilingSurrounding(lua_State *L)
{
sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
//HUDSAFE
INLEVEL
if (!sector)
return LUA_ErrInvalid(L, "sector_t");
lua_pushfixed(L, P_FindHighestCeilingSurrounding(sector));
return 1;
}
static int lib_pFindSpecialLineFromTag(lua_State *L)
{
INT16 special = (INT16)luaL_checkinteger(L, 1);
INT16 line = (INT16)luaL_checkinteger(L, 2);
INT32 start = (INT32)luaL_optinteger(L, 3, -1);
NOHUD
INLEVEL
lua_pushinteger(L, P_FindSpecialLineFromTag(special, line, start));
return 1;
}
static int lib_pSwitchWeather(lua_State *L)
{
INT32 weathernum = (INT32)luaL_checkinteger(L, 1);
player_t *user = NULL;
NOHUD
INLEVEL
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2)) // if a player, setup weather for only the player, otherwise setup weather for all players
user = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
if (!user) // global
globalweather = weathernum;
if (!user || P_IsPartyPlayer(user))
P_SwitchWeather(weathernum);
return 0;
}
static int lib_pLinedefExecute(lua_State *L)
{
INT32 tag = (INT16)luaL_checkinteger(L, 1);
mobj_t *actor = NULL;
sector_t *caller = NULL;
NOHUD
INLEVEL
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
actor = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
caller = *((sector_t **)luaL_checkudata(L, 3, META_SECTOR));
P_LinedefExecute(tag, actor, caller);
return 0;
}
static int lib_pSpawnLightningFlash(lua_State *L)
{
sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
NOHUD
INLEVEL
if (!sector)
return LUA_ErrInvalid(L, "sector_t");
P_SpawnLightningFlash(sector);
return 0;
}
static int lib_pFadeLight(lua_State *L)
{
INT16 tag = (INT16)luaL_checkinteger(L, 1);
INT32 destvalue = (INT32)luaL_checkinteger(L, 2);
INT32 speed = (INT32)luaL_checkinteger(L, 3);
boolean ticbased = lua_optboolean(L, 4);
boolean force = lua_optboolean(L, 5);
boolean relative = lua_optboolean(L, 6);
NOHUD
INLEVEL
P_FadeLight(tag, destvalue, speed, ticbased, force, relative);
return 0;
}
static int lib_pSetupLevelSky(lua_State *L)
{
const char *skytexname = luaL_checkstring(L, 1);
player_t *user = NULL;
NOHUD
INLEVEL
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2)) // if a player, setup sky for only the player, otherwise setup sky for all players
user = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
if (!user) // global
P_SetupLevelSky(skytexname, true);
else if (P_IsPartyPlayer(user))
P_SetupLevelSky(skytexname, false);
return 0;
}
// Shhh, P_SetSkyboxMobj doesn't actually exist yet.
static int lib_pSetSkyboxMobj(lua_State *L)
{
int n = lua_gettop(L);
mobj_t *mo = NULL;
player_t *user = NULL;
int w = 0;
NOHUD
INLEVEL
if (!lua_isnil(L,1)) // nil leaves mo as NULL to remove the skybox rendering.
{
mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); // otherwise it is a skybox mobj.
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
}
if (n == 1)
;
else if (lua_isuserdata(L, 2))
user = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
else if (lua_isnil(L, 2))
w = 0;
else if (lua_isboolean(L, 2))
{
if (lua_toboolean(L, 2))
w = 1;
else
w = 0;
}
else
w = luaL_optinteger(L, 2, 0);
if (n > 2 && lua_isuserdata(L, 3))
{
user = *((player_t **)luaL_checkudata(L, 3, META_PLAYER));
if (!user)
return LUA_ErrInvalid(L, "player_t");
}
if (w > 1 || w < 0)
return luaL_error(L, "skybox mobj index %d is out of range for P_SetSkyboxMobj argument #2 (expected 0 or 1)", w);
#if 0
if (!user || P_IsPartyPlayer(user))
skyboxmo[w] = mo;
#else
CONS_Alert(CONS_WARNING, "TODO: P_SetSkyboxMobj is unimplemented\n");
#endif
return 0;
}
// Shhh, neither does P_StartQuake.
static int lib_pStartQuake(lua_State *L)
{
tic_t q_time = (tic_t)luaL_checkinteger(L, 1);
fixed_t q_intensity = luaL_checkfixed(L, 2);
fixed_t q_radius = luaL_optinteger(L, 3, 512*FRACUNIT);
static mappoint_t q_epicenter = {0,0,0};
boolean q_epicenter_set = false;
NOHUD
INLEVEL
if (!lua_isnoneornil(L, 4))
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 4, META_MOBJ));
if (mobj != NULL)
{
q_epicenter.x = mobj->x;
q_epicenter.y = mobj->y;
q_epicenter.z = mobj->z;
q_epicenter_set = true;
}
else
{
luaL_checktype(L, 4, LUA_TTABLE);
lua_getfield(L, 4, "x");
if (lua_isnil(L, -1))
{
lua_pop(L, 1);
lua_rawgeti(L, 4, 1);
}
if (!lua_isnil(L, -1))
q_epicenter.x = luaL_checkinteger(L, -1);
else
q_epicenter.x = 0;
lua_pop(L, 1);
lua_getfield(L, 4, "y");
if (lua_isnil(L, -1))
{
lua_pop(L, 1);
lua_rawgeti(L, 4, 2);
}
if (!lua_isnil(L, -1))
q_epicenter.y = luaL_checkinteger(L, -1);
else
q_epicenter.y = 0;
lua_pop(L, 1);
lua_getfield(L, 4, "z");
if (lua_isnil(L, -1))
{
lua_pop(L, 1);
lua_rawgeti(L, 4, 3);
}
if (!lua_isnil(L, -1))
q_epicenter.z = luaL_checkinteger(L, -1);
else
q_epicenter.z = 0;
lua_pop(L, 1);
q_epicenter_set = true;
}
}
P_StartQuake(q_time, q_intensity, q_radius, q_epicenter_set ? &q_epicenter : NULL);
return 0;
}
static int lib_evCrumbleChain(lua_State *L)
{
sector_t *sec = NULL;
ffloor_t *rover = NULL;
NOHUD
INLEVEL
if (!lua_isnone(L, 2))
{
if (!lua_isnil(L, 1))
{
sec = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
if (!sec)
return LUA_ErrInvalid(L, "sector_t");
}
rover = *((ffloor_t **)luaL_checkudata(L, 2, META_FFLOOR));
}
else
rover = *((ffloor_t **)luaL_checkudata(L, 1, META_FFLOOR));
if (!rover)
return LUA_ErrInvalid(L, "ffloor_t");
EV_CrumbleChain(sec, rover);
return 0;
}
static int lib_evStartCrumble(lua_State *L)
{
sector_t *sec = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
ffloor_t *rover = *((ffloor_t **)luaL_checkudata(L, 2, META_FFLOOR));
boolean floating = lua_optboolean(L, 3);
player_t *player = NULL;
fixed_t origalpha;
boolean crumblereturn = lua_optboolean(L, 6);
NOHUD
if (!sec)
return LUA_ErrInvalid(L, "sector_t");
if (!rover)
return LUA_ErrInvalid(L, "ffloor_t");
if (!lua_isnone(L, 4) && lua_isuserdata(L, 4))
{
player = *((player_t **)luaL_checkudata(L, 4, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!lua_isnone(L,5))
origalpha = luaL_checkfixed(L, 5);
else
origalpha = rover->alpha;
lua_pushboolean(L, EV_StartCrumble(sec, rover, floating, player, origalpha, crumblereturn) != 0);
return 0;
}
// P_SLOPES
////////////
static int lib_pGetZAt(lua_State *L)
{
fixed_t x = luaL_checkfixed(L, 2);
fixed_t y = luaL_checkfixed(L, 3);
//HUDSAFE
if (lua_isnil(L, 1))
{
fixed_t z = luaL_checkfixed(L, 4);
lua_pushfixed(L, P_GetZAt(NULL, x, y, z));
}
else
{
pslope_t *slope = *((pslope_t **)luaL_checkudata(L, 1, META_SLOPE));
lua_pushfixed(L, P_GetSlopeZAt(slope, x, y));
}
return 1;
}
static int lib_pButteredSlope(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
INLEVEL
if (!mobj)
return LUA_ErrInvalid(L, "mobj_t");
P_ButteredSlope(mobj);
return 0;
}
// R_DEFS
////////////
static int lib_rPointToAngle(lua_State *L)
{
fixed_t x = luaL_checkfixed(L, 1);
fixed_t y = luaL_checkfixed(L, 2);
//HUDSAFE
lua_pushangle(L, R_PointToAngle(x, y));
return 1;
}
static int lib_rPointToAnglePlayer(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
fixed_t x = luaL_checkfixed(L, 2);
fixed_t y = luaL_checkfixed(L, 3);
//HUDSAFE
lua_pushangle(L, R_PointToAnglePlayer(player, x, y));
return 1;
}
static int lib_rPointToAngle2(lua_State *L)
{
fixed_t px2 = luaL_checkfixed(L, 1);
fixed_t py2 = luaL_checkfixed(L, 2);
fixed_t px1 = luaL_checkfixed(L, 3);
fixed_t py1 = luaL_checkfixed(L, 4);
//HUDSAFE
lua_pushangle(L, R_PointToAngle2(px2, py2, px1, py1));
return 1;
}
static int lib_rPointToDist(lua_State *L)
{
fixed_t x = luaL_checkfixed(L, 1);
fixed_t y = luaL_checkfixed(L, 2);
//HUDSAFE
lua_pushfixed(L, R_PointToDist(x, y));
return 1;
}
static int lib_rPointToDist2(lua_State *L)
{
fixed_t px2 = luaL_checkfixed(L, 1);
fixed_t py2 = luaL_checkfixed(L, 2);
fixed_t px1 = luaL_checkfixed(L, 3);
fixed_t py1 = luaL_checkfixed(L, 4);
//HUDSAFE
lua_pushfixed(L, R_PointToDist2(px2, py2, px1, py1));
return 1;
}
static int lib_rPointInSubsector(lua_State *L)
{
fixed_t x = luaL_checkfixed(L, 1);
fixed_t y = luaL_checkfixed(L, 2);
//HUDSAFE
INLEVEL
LUA_PushUserdata(L, R_PointInSubsector(x, y), META_SUBSECTOR);
return 1;
}
static int lib_rPointInSubsectorOrNil(lua_State *L)
{
fixed_t x = luaL_checkfixed(L, 1);
fixed_t y = luaL_checkfixed(L, 2);
subsector_t *sub = R_PointInSubsectorOrNull(x, y);
//HUDSAFE
INLEVEL
if (sub)
LUA_PushUserdata(L, sub, META_SUBSECTOR);
else
lua_pushnil(L);
return 1;
}
// R_THINGS
////////////
static int lib_rChar2Frame(lua_State *L)
{
const char *p = luaL_checkstring(L, 1);
//HUDSAFE
lua_pushinteger(L, R_Char2Frame(*p)); // first character only
return 1;
}
static int lib_rFrame2Char(lua_State *L)
{
UINT8 ch = (UINT8)luaL_checkinteger(L, 1);
char c[2] = "";
//HUDSAFE
c[0] = R_Frame2Char(ch);
c[1] = 0;
lua_pushstring(L, c);
lua_pushinteger(L, c[0]);
return 2;
}
// R_SetPlayerSkin technically doesn't exist either, although it's basically just SetPlayerSkin and SetPlayerSkinByNum handled in one place for convenience
static int lib_rSetPlayerSkin(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INT32 i = -1, j = -1;
NOHUD
if (!player)
return LUA_ErrInvalid(L, "player_t");
j = (player-players);
if (lua_isnoneornil(L, 2))
return luaL_error(L, "argument #2 not given (expected number or string)");
else if (lua_type(L, 2) == LUA_TNUMBER) // skin number
{
INT32 skincount = (demo.playback ? demo.numskins : numskins);
i = luaL_checkinteger(L, 2);
if (i < 0 || i >= skincount)
return luaL_error(L, "skin %d (argument #2) out of range (0 - %d)", i, skincount-1);
}
else // skin name
{
const char *skinname = luaL_checkstring(L, 2);
i = R_SkinAvailable(skinname);
if (i == -1)
return luaL_error(L, "skin %s (argument 2) is not loaded", skinname);
}
if (!R_SkinUsable(j, i, false))
return luaL_error(L, "skin %d (argument 2) not usable - check with R_SkinUsable(player_t, skin) first.", i);
SetPlayerSkinByNum(j, i);
return 0;
}
static int lib_rSkinUsable(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INT32 i = -1, j = -1;
if (player)
j = (player-players);
else if (netgame || multiplayer)
return luaL_error(L, "player_t (argument #1) must be provided in multiplayer games");
if (lua_isnoneornil(L, 2))
return luaL_error(L, "argument #2 not given (expected number or string)");
else if (lua_type(L, 2) == LUA_TNUMBER) // skin number
{
i = luaL_checkinteger(L, 2);
if (i < 0 || i >= numskins)
return luaL_error(L, "skin %d (argument #2) out of range (0 - %d)", i, numskins-1);
}
else // skin name
{
const char *skinname = luaL_checkstring(L, 2);
i = R_SkinAvailable(skinname);
if (i == -1)
return luaL_error(L, "skin %s (argument 2) is not loaded", skinname);
}
lua_pushboolean(L, R_SkinUsable(j, i, false));
return 1;
}
// R_DATA
////////////
static int lib_rCheckTextureNumForName(lua_State *L)
{
const char *name = luaL_checkstring(L, 1);
//HUDSAFE
lua_pushinteger(L, R_CheckTextureNumForName(name));
return 1;
}
static int lib_rTextureNumForName(lua_State *L)
{
const char *name = luaL_checkstring(L, 1);
//HUDSAFE
lua_pushinteger(L, R_TextureNumForName(name));
return 1;
}
// R_DRAW
////////////
static int lib_rGetColorByName(lua_State *L)
{
const char* colorname = luaL_checkstring(L, 1);
//HUDSAFE
lua_pushinteger(L, R_GetColorByName(colorname));
return 1;
}
static int lib_rGetSuperColorByName(lua_State *L)
{
const char* colorname = luaL_checkstring(L, 1);
//HUDSAFE
lua_pushinteger(L, R_GetSuperColorByName(colorname));
return 1;
}
// Lua exclusive function, returns the name of a color from the SKINCOLOR_ constant.
// SKINCOLOR_GREEN > "Green" for example
static int lib_rGetNameByColor(lua_State *L)
{
UINT16 colornum = (UINT16)luaL_checkinteger(L, 1);
if (!colornum || colornum >= numskincolors)
return luaL_error(L, "skincolor %d out of range (1 - %d).", colornum, numskincolors-1);
lua_pushstring(L, skincolors[colornum].name);
return 1;
}
// S_SOUND
////////////
static int GetValidSoundOrigin(lua_State *L, void **origin)
{
const char *type;
lua_settop(L, 1);
type = GetUserdataUType(L);
if (fasticmp(type, "mobj_t"))
{
*origin = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
if (!(*origin))
return LUA_ErrInvalid(L, "mobj_t");
return 1;
}
else if (fasticmp(type, "sector_t"))
{
*origin = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
if (!(*origin))
return LUA_ErrInvalid(L, "sector_t");
*origin = &((sector_t *)(*origin))->soundorg;
return 1;
}
return LUA_ErrInvalid(L, "mobj_t/sector_t");
}
static int lib_sStartSound(lua_State *L)
{
void *origin = NULL;
sfxenum_t sound_id = luaL_checkinteger(L, 2);
player_t *player = NULL;
//NOHUD
if (sound_id >= NUMSFX)
return luaL_error(L, "sfx %d out of range (0 - %d)", sound_id, NUMSFX-1);
if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
{
player = *((player_t **)luaL_checkudata(L, 3, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!lua_isnil(L, 1))
if (!GetValidSoundOrigin(L, &origin))
return 0;
if (!player || P_IsPartyPlayer(player))
{
if (hud_running || hook_cmd_running)
origin = NULL; // HUD rendering and CMD building startsound shouldn't have an origin, just remove it instead of having a [Hyperlink Blocked] error.
S_StartSound(origin, sound_id);
}
return 0;
}
static int lib_sStartSoundAtVolume(lua_State *L)
{
void *origin = NULL;
sfxenum_t sound_id = luaL_checkinteger(L, 2);
INT32 volume = (INT32)luaL_checkinteger(L, 3);
player_t *player = NULL;
//NOHUD
if (sound_id >= NUMSFX)
return luaL_error(L, "sfx %d out of range (0 - %d)", sound_id, NUMSFX-1);
if (!lua_isnone(L, 4) && lua_isuserdata(L, 4))
{
player = *((player_t **)luaL_checkudata(L, 4, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!lua_isnil(L, 1))
if (!GetValidSoundOrigin(L, &origin))
return LUA_ErrInvalid(L, "mobj_t/sector_t");
if (!player || P_IsPartyPlayer(player))
S_StartSoundAtVolume(origin, sound_id, volume);
return 0;
}
static int lib_sStopSound(lua_State *L)
{
void *origin = NULL;
//NOHUD
if (!GetValidSoundOrigin(L, &origin))
return LUA_ErrInvalid(L, "mobj_t/sector_t");
S_StopSound(origin);
return 0;
}
static int lib_sStopSoundByID(lua_State *L)
{
void *origin = NULL;
sfxenum_t sound_id = luaL_checkinteger(L, 2);
//NOHUD
if (sound_id >= NUMSFX)
return luaL_error(L, "sfx %d out of range (0 - %d)", sound_id, NUMSFX-1);
if (!lua_isnil(L, 1))
if (!GetValidSoundOrigin(L, &origin))
return LUA_ErrInvalid(L, "mobj_t/sector_t");
S_StopSoundByID(origin, sound_id);
return 0;
}
static int lib_sOriginPlaying(lua_State *L)
{
void *origin = NULL;
//NOHUD
INLEVEL
if (!GetValidSoundOrigin(L, &origin))
return LUA_ErrInvalid(L, "mobj_t/sector_t");
lua_pushboolean(L, S_OriginPlaying(origin));
return 1;
}
static int lib_sIdPlaying(lua_State *L)
{
sfxenum_t id = luaL_checkinteger(L, 1);
//NOHUD
if (id >= NUMSFX)
return luaL_error(L, "sfx %d out of range (0 - %d)", id, NUMSFX-1);
lua_pushboolean(L, S_IdPlaying(id));
return 1;
}
static int lib_sSoundPlaying(lua_State *L)
{
void *origin = NULL;
sfxenum_t id = luaL_checkinteger(L, 2);
//NOHUD
INLEVEL
if (id >= NUMSFX)
return luaL_error(L, "sfx %d out of range (0 - %d)", id, NUMSFX-1);
if (!lua_isnil(L, 1))
if (!GetValidSoundOrigin(L, &origin))
return LUA_ErrInvalid(L, "mobj_t/sector_t");
lua_pushboolean(L, S_SoundPlaying(origin, id));
return 1;
}
// This doesn't really exist, but we're providing it as a handy netgame-safe wrapper for stuff that should be locally handled.
static int lib_sStartMusicCaption(lua_State *L)
{
player_t *player = NULL;
const char *caption = luaL_checkstring(L, 1);
UINT16 lifespan = (UINT16)luaL_checkinteger(L, 2);
//HUDSAFE
//INLEVEL
if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
{
player = *((player_t **)luaL_checkudata(L, 3, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (lifespan && (!player || P_IsPartyPlayer(player)))
{
strlcpy(S_sfx[sfx_None].caption, caption, sizeof(S_sfx[sfx_None].caption));
S_StartCaption(sfx_None, -1, lifespan);
}
return 0;
}
static int lib_sShowMusicCredit(lua_State *L)
{
player_t *player = NULL;
//HUDSAFE
if (!lua_isnone(L, 1) && lua_isuserdata(L, 1))
{
player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
}
if (!player || P_IsPartyPlayer(player))
S_ShowMusicCredit();
return 0;
}
// G_GAME
////////////
// Copypasted from lib_cvRegisterVar :]
static int lib_gAddGametype(lua_State *L)
{
const char *k;
lua_Integer i;
gametype_t *newgametype = NULL;
const char *gtname = NULL;
const char *gtconst = NULL;
const char *gppic = NULL;
const char *gppicmini = NULL;
UINT32 newgtrules = 0;
UINT32 newgttol = 0;
INT32 newgtpointlimit = 0;
INT32 newgttimelimit = 0;
UINT8 newgtinttype = 0;
SINT8 newgtspeed = KARTSPEED_AUTO;
INT16 j;
luaL_checktype(L, 1, LUA_TTABLE);
lua_settop(L, 1); // Clear out all other possible arguments, leaving only the first one.
if (!lua_lumploading)
return luaL_error(L, "This function cannot be called from within a hook or coroutine!");
// Ran out of gametype slots
if (numgametypes == GT_LASTFREESLOT)
{
I_Error("Out of Gametype Freeslots while allocating \"%s\"\nLoad less addons to fix this.", gtname);
}
#define FIELDERROR(f, e) luaL_error(L, "bad value for " LUA_QL(f) " in table passed to " LUA_QL("G_AddGametype") " (%s)", e);
#define TYPEERROR(f, t) FIELDERROR(f, va("%s expected, got %s", lua_typename(L, t), luaL_typename(L, -1)))
lua_pushnil(L);
while (lua_next(L, 1)) {
// stack: gametype table, key/index, value
// 1 2 3
i = 0;
k = NULL;
if (lua_isnumber(L, 2))
i = lua_tointeger(L, 2);
else if (lua_isstring(L, 2))
k = lua_tostring(L, 2);
// Sorry, no gametype rules as key names.
if (i == 1 || (k && fasticmp(k, "name"))) {
if (!lua_isstring(L, 3))
TYPEERROR("name", LUA_TSTRING)
gtname = Z_StrDup(lua_tostring(L, 3));
} else if (i == 2 || (k && fasticmp(k, "identifier"))) {
if (!lua_isstring(L, 3))
TYPEERROR("identifier", LUA_TSTRING)
gtconst = Z_StrDup(lua_tostring(L, 3));
} else if (i == 3 || (k && fasticmp(k, "rules"))) {
if (!lua_isnumber(L, 3))
TYPEERROR("rules", LUA_TNUMBER)
newgtrules = (UINT32)lua_tointeger(L, 3);
} else if (i == 4 || (k && fasticmp(k, "typeoflevel"))) {
if (!lua_isnumber(L, 3))
TYPEERROR("typeoflevel", LUA_TNUMBER)
newgttol = (UINT32)lua_tointeger(L, 3);
} else if (i == 5 || (k && fasticmp(k, "intermissiontype"))) {
if (!lua_isnumber(L, 3))
TYPEERROR("intermissiontype", LUA_TNUMBER)
newgtinttype = (int)lua_tointeger(L, 3);
} else if (i == 6 || (k && fasticmp(k, "defaultpointlimit"))) {
if (!lua_isnumber(L, 3))
TYPEERROR("defaultpointlimit", LUA_TNUMBER)
newgtpointlimit = (INT32)lua_tointeger(L, 3);
} else if (i == 7 || (k && fasticmp(k, "defaulttimelimit"))) {
if (!lua_isnumber(L, 3))
TYPEERROR("defaulttimelimit", LUA_TNUMBER)
newgttimelimit = (INT32)lua_tointeger(L, 3);
} else if (i == 8 || (k && fasticmp(k, "gppic"))) {
if (!lua_isstring(L, 3))
TYPEERROR("gppic", LUA_TSTRING)
gppic = lua_tostring(L, 3);
} else if (i == 9 || (k && fasticmp(k, "gppicmini"))) {
if (!lua_isstring(L, 3))
TYPEERROR("gppicmini", LUA_TSTRING)
gppicmini = lua_tostring(L, 3);
} else if (i == 10 || (k && fasticmp(k, "speed"))) {
if (!lua_isnumber(L, 3))
TYPEERROR("speed", LUA_TNUMBER)
newgtspeed = (UINT32)lua_tointeger(L, 3);
if (newgtspeed < KARTSPEED_AUTO || newgtspeed > KARTSPEED_HARD)
{
newgtspeed = KARTSPEED_AUTO;
}
}
lua_pop(L, 1);
}
#undef FIELDERROR
#undef TYPEERROR
if (gtname == NULL)
return luaL_error(L, "Custom gametype must have a name");
if (strlen(gtname) >= MAXGAMETYPELENGTH)
return luaL_error(L, "Custom gametype \"%s\"'s name must be %d long at most", gtname, MAXGAMETYPELENGTH-1);
for (j = 0; j < numgametypes; j++)
if (!strcmp(gtname, gametypes[j]->name))
break;
if (j < numgametypes)
return luaL_error(L, "Custom gametype \"%s\"'s name is already in use", gtname);
// pop gametype table
lua_pop(L, 1);
// Add the new gametype
newgametype = Z_Calloc(sizeof (gametype_t), PU_STATIC, NULL);
if (!newgametype)
{
I_Error("Out of memory allocating gametype \"%s\"", gtname);
}
if (gtconst == NULL)
gtconst = gtname;
newgametype->name = gtname;
newgametype->rules = newgtrules;
newgametype->constant = G_PrepareGametypeConstant(gtconst);
newgametype->tol = newgttol;
newgametype->intermission = newgtinttype;
newgametype->pointlimit = newgtpointlimit;
newgametype->timelimit = newgttimelimit;
newgametype->speed = newgtspeed;
if (gppic != NULL)
{
// Calloc means only set if valid
strlcpy(newgametype->gppic, gppic, 9);
}
if (gppicmini != NULL)
{
// Calloc means only set if valid
strlcpy(newgametype->gppicmini, gppicmini, 9);
}
gametypes[numgametypes++] = newgametype;
// done
CONS_Printf("Added gametype %s\n", gtname);
return 0;
}
static int Lcheckmapnumber (lua_State *L, int idx, const char *fun)
{
if (ISINLEVEL)
return luaL_optinteger(L, idx, gamemap);
else
{
if (lua_isnoneornil(L, idx))
{
return luaL_error(L,
"%s can only be used without a parameter while in a level.",
fun
);
}
else
return luaL_checkinteger(L, idx);
}
}
static int lib_gBuildMapName(lua_State *L)
{
INT32 map = Lcheckmapnumber(L, 1, "G_BuildMapName");
//HUDSAFE
lua_pushstring(L, G_BuildMapName(map));
return 1;
}
static int lib_gBuildMapTitle(lua_State *L)
{
INT32 map = Lcheckmapnumber(L, 1, "G_BuildMapTitle");
char *name;
if (map < 1 || map > nummapheaders)
{
return luaL_error(L,
"map ID %d out of range (1 - %d)",
map,
nummapheaders
);
}
name = G_BuildMapTitle(map);
lua_pushstring(L, name);
Z_Free(name);
return 1;
}
static void
Lpushdim (lua_State *L, int c, struct searchdim *v)
{
int i;
lua_createtable(L, c, 0);/* I guess narr is numeric indices??? */
for (i = 0; i < c; ++i)
{
lua_createtable(L, 0, 2);/* and hashed indices (field)... */
lua_pushnumber(L, v[i].pos);
lua_setfield(L, -2, "pos");
lua_pushnumber(L, v[i].siz);
lua_setfield(L, -2, "siz");
lua_rawseti(L, -2, 1 + i);
}
}
/*
I decided to make this return a table because userdata
is scary and tables let the user set their own fields.
*/
/*
Returns:
[1] => map number
[2] => map title
[3] => search frequency table
The frequency table is unsorted. It has the following format:
{
['mapnum'],
['matchd'] => matches in map title string
['keywhd'] => matches in map keywords
The above two tables have the following format:
{
['pos'] => offset from start of string
['siz'] => length of match
}...
['total'] => the total matches
}...
*/
static int lib_gFindMap(lua_State *L)
{
const char *query = luaL_checkstring(L, 1);
INT32 map;
char *realname;
INT32 frc;
mapsearchfreq_t *frv;
INT32 i;
map = G_FindMap(query, &realname, &frv, &frc);
lua_settop(L, 0);
lua_pushnumber(L, map);
lua_pushstring(L, realname);
lua_createtable(L, frc, 0);
for (i = 0; i < frc; ++i)
{
lua_createtable(L, 0, 4);
lua_pushnumber(L, frv[i].mapnum);
lua_setfield(L, -2, "mapnum");
Lpushdim(L, frv[i].matchc, frv[i].matchd);
lua_setfield(L, -2, "matchd");
Lpushdim(L, frv[i].keywhc, frv[i].keywhd);
lua_setfield(L, -2, "keywhd");
lua_pushnumber(L, frv[i].total);
lua_setfield(L, -2, "total");
lua_rawseti(L, -2, 1 + i);
}
G_FreeMapSearch(frv, frc);
Z_Free(realname);
return 3;
}
/*
Returns:
[1] => map number
[2] => map title
*/
static int lib_gFindMapByNameOrCode(lua_State *L)
{
const char *query = luaL_checkstring(L, 1);
INT32 map;
char *realname;
map = G_FindMapByNameOrCode(query, &realname);
lua_pushnumber(L, map);
if (map)
{
lua_pushstring(L, realname);
Z_Free(realname);
return 2;
}
else
return 1;
}
static int lib_gDoReborn(lua_State *L)
{
INT32 playernum = luaL_checkinteger(L, 1);
NOHUD
INLEVEL
if (playernum >= MAXPLAYERS)
return luaL_error(L, "playernum %d out of range (0 - %d)", playernum, MAXPLAYERS-1);
G_DoReborn(playernum);
return 0;
}
// Another Lua function that doesn't actually exist!
// Sets nextmapoverride & skipstats without instantly ending the level, for instances where other sources should be exiting the level, like normal signposts.
static int lib_gSetCustomExitVars(lua_State *L)
{
int n = lua_gettop(L); // Num arguments
NOHUD
INLEVEL
// LUA EXTENSION: Custom exit like support
// Supported:
// G_SetCustomExitVars(); [reset to defaults]
// G_SetCustomExitVars(int) [nextmap override only]
// G_SetCustomExitVars(nil, int) [skipstats only]
// G_SetCustomExitVars(int, int) [both of the above]
nextmapoverride = 0;
skipstats = 0;
if (n >= 1)
{
nextmapoverride = (INT16)luaL_optinteger(L, 1, 0);
skipstats = (INT16)luaL_optinteger(L, 2, 0);
}
return 0;
}
static int lib_gExitLevel(lua_State *L)
{
int n = lua_gettop(L); // Num arguments
NOHUD
// Moved this bit to G_SetCustomExitVars
if (n >= 1) // Don't run the reset to defaults option
lib_gSetCustomExitVars(L);
G_BeginLevelExit();
G_FinishExitLevel();
return 0;
}
static int lib_gGametypeUsesLives(lua_State *L)
{
//HUDSAFE
INLEVEL
lua_pushboolean(L, G_GametypeUsesLives());
return 1;
}
static int lib_gGametypeAllowsRetrying(lua_State *L)
{
//HUDSAFE
INLEVEL
lua_pushboolean(L, G_GametypeAllowsRetrying());
return 1;
}
static int lib_gGametypeHasTeams(lua_State *L)
{
//HUDSAFE
INLEVEL
lua_pushboolean(L, G_GametypeHasTeams());
return 1;
}
static int lib_gGametypeHasSpectators(lua_State *L)
{
//HUDSAFE
INLEVEL
lua_pushboolean(L, G_GametypeHasSpectators());
return 1;
}
static int lib_gTicsToHours(lua_State *L)
{
tic_t rtic = luaL_checkinteger(L, 1);
//HUDSAFE
lua_pushinteger(L, G_TicsToHours(rtic));
return 1;
}
static int lib_gTicsToMinutes(lua_State *L)
{
tic_t rtic = luaL_checkinteger(L, 1);
boolean rfull = lua_optboolean(L, 2);
//HUDSAFE
lua_pushinteger(L, G_TicsToMinutes(rtic, rfull));
return 1;
}
static int lib_gTicsToSeconds(lua_State *L)
{
tic_t rtic = luaL_checkinteger(L, 1);
//HUDSAFE
lua_pushinteger(L, G_TicsToSeconds(rtic));
return 1;
}
static int lib_gTicsToCentiseconds(lua_State *L)
{
tic_t rtic = luaL_checkinteger(L, 1);
//HUDSAFE
lua_pushinteger(L, G_TicsToCentiseconds(rtic));
return 1;
}
static int lib_gTicsToMilliseconds(lua_State *L)
{
tic_t rtic = luaL_checkinteger(L, 1);
//HUDSAFE
lua_pushinteger(L, G_TicsToMilliseconds(rtic));
return 1;
}
// K_ENDCAM
////////////
static int lib_kStartRoundWinCamera(lua_State *L)
{
mobj_t *origin = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
angle_t focusAngle = luaL_checkangle(L, 2);
fixed_t finalRadius = luaL_checkfixed(L, 3);
tic_t panDuration = luaL_checkinteger(L, 4);
fixed_t panSpeed = luaL_checkfixed(L, 5);
NOHUD
INLEVEL
K_StartRoundWinCamera(origin, focusAngle, finalRadius, panDuration, panSpeed);
return 0;
}
static int lib_kEndCameraIsFreezing(lua_State *L)
{
INLEVEL
lua_pushboolean(L, K_EndCameraIsFreezing());
return 1;
}
// K_HUD
////////////
static int lib_kAddMessage(lua_State *L)
{
const char *msg = luaL_checkstring(L, 1);
boolean interrupt = lua_optboolean(L, 2);
boolean persist = lua_optboolean(L, 3);
INLEVEL
if (msg == NULL)
return luaL_error(L, "argument #1 not given (expected string)");
K_AddMessage(msg, interrupt, persist);
return 0;
}
static int lib_kAddMessageForPlayer(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
const char *msg = luaL_checkstring(L, 2);
boolean interrupt = lua_optboolean(L, 3);
boolean persist = lua_optboolean(L, 4);
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
if (msg == NULL)
return luaL_error(L, "argument #2 not given (expected string)");
K_AddMessageForPlayer(player, msg, interrupt, persist);
return 0;
}
static int lib_kClearPersistentMessages(lua_State *L)
{
INLEVEL
K_ClearPersistentMessages();
lua_pushnil(L);
return 0;
}
static int lib_kClearPersistentMessageForPlayer(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_ClearPersistentMessageForPlayer(player);
return 0;
}
// K_KART
////////////
// Seriously, why weren't those exposed before?
static int lib_kAttackSound(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
if (!mobj->player)
return luaL_error(L, "K_PlayAttackTaunt: mobj_t isn't a player object."); //Nothing bad would happen if we let it run the func, but telling why it ain't doing anything is helpful.
K_PlayAttackTaunt(mobj);
return 0;
}
static int lib_kBoostSound(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
if (!mobj->player)
return luaL_error(L, "K_PlayBoostTaunt: mobj_t isn't a player object."); //Nothing bad would happen if we let it run the func, but telling why it ain't doing anything is helpful.
K_PlayBoostTaunt(mobj);
return 0;
}
static int lib_kOvertakeSound(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
if (!mobj->player)
return luaL_error(L, "K_PlayOvertakeSound: mobj_t isn't a player object."); //Nothing bad would happen if we let it run the func, but telling why it ain't doing anything is helpful.
K_PlayOvertakeSound(mobj);
return 0;
}
static int lib_kPainSound(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *other = NULL;
NOHUD
if (!mobj->player)
return luaL_error(L, "K_PlayPainSound: mobj_t isn't a player object."); //Nothing bad would happen if we let it run the func, but telling why it ain't doing anything is helpful.
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
other = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
K_PlayPainSound(mobj, other);
return 0;
}
static int lib_kHitEmSound(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *other = NULL;
NOHUD
if (!mobj->player)
return luaL_error(L, "K_PlayHitEmSound: mobj_t isn't a player object."); //Nothing bad would happen if we let it run the func, but telling why it ain't doing anything is helpful.
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
other = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
K_PlayHitEmSound(mobj, other);
return 0;
}
static int lib_kTryHurtSoundExchange(lua_State *L)
{
mobj_t *victim = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *attacker = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
NOHUD
if (!victim->player)
return luaL_error(L, "K_TryHurtSoundExchange: mobj_t isn't a player object."); //Nothing bad would happen if we let it run the func, but telling why it ain't doing anything is helpful.
K_TryHurtSoundExchange(victim, attacker);
return 0;
}
static int lib_kGloatSound(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
if (!mobj->player)
return luaL_error(L, "K_PlayPowerGloatSound: mobj_t isn't a player object."); //Nothing bad would happen if we let it run the func, but telling why it ain't doing anything is helpful.
K_PlayPowerGloatSound(mobj);
return 0;
}
static int lib_kLossSound(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); // let's require a mobj for consistency with the other functions
sfxenum_t sfx_id;
NOHUD
if (!mobj->player)
return luaL_error(L, "K_PlayLossSound: mobj_t isn't a player object.");
sfx_id = ((skin_t *)mobj->skin)->soundsid[S_sfx[sfx_klose].skinsound];
S_StartSound(mobj, sfx_id);
return 0;
}
// Note: Pain, Death and Victory are already exposed.
static int lib_kIsPlayerLosing(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
//HUDSAFE
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, K_IsPlayerLosing(player));
return 1;
}
static int lib_kGetPlayerDontDrawFlag(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushinteger(L, K_GetPlayerDontDrawFlag(player));
return 1;
}
static int lib_kReflectAngle(lua_State *L)
{
angle_t angle = luaL_checkangle(L, 1);
angle_t against = luaL_checkangle(L, 2);
fixed_t maxspeed = luaL_optinteger(L, 3, 0);
fixed_t yourspeed = luaL_optinteger(L, 4, 0);
lua_pushangle(L, K_ReflectAngle(angle, against, maxspeed, yourspeed));
return 1;
}
static int lib_kIsDuelItem(lua_State *L)
{
mobjtype_t type = luaL_checkinteger(L, 1);
if (type >= NUMMOBJTYPES)
return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
lua_pushboolean(L, K_IsDuelItem(type));
return 1;
}
static int lib_kGetKartGameSpeedScalar(lua_State *L)
{
SINT8 value = luaL_optinteger(L, 1, gamespeed);
lua_pushfixed(L, K_GetKartGameSpeedScalar(value));
return 1;
}
static int lib_kIsPlayerWanted(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
//HUDSAFE
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, K_IsPlayerWanted(player));
return 1;
}
static int lib_kGetMobjWeight(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *against = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
INLEVEL
if (!mobj)
return LUA_ErrInvalid(L, "mobj_t");
if (!against)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushfixed(L, K_GetMobjWeight(mobj, against));
return 1;
}
static int lib_kPlayerJustBumped(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_PlayerJustBumped(player);
return 0;
}
static int lib_kKartBouncing(lua_State *L)
{
mobj_t *mobj1 = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *mobj2 = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
NOHUD
INLEVEL
if (!mobj1)
return LUA_ErrInvalid(L, "mobj_t");
if (!mobj2)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, K_KartBouncing(mobj1, mobj2));
return 1;
}
static int lib_kKartPainEnergyFling(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_KartPainEnergyFling(player);
return 0;
}
static int lib_kFlipFromObject(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *master = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
NOHUD
INLEVEL
if (!mo || !master)
return LUA_ErrInvalid(L, "mobj_t");
K_FlipFromObject(mo, master);
return 0;
}
static int lib_kKartSolidBounce(lua_State *L)
{
mobj_t *bounceMobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *solidMobj = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
NOHUD
INLEVEL
if (!bounceMobj)
return LUA_ErrInvalid(L, "mobj_t");
if (!solidMobj)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, K_KartSolidBounce(bounceMobj, solidMobj));
return 1;
}
static int lib_kMatchGenericExtraFlags(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *master = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
NOHUD
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
if (!master)
return LUA_ErrInvalid(L, "mobj_t");
K_MatchGenericExtraFlags(mo, master);
return 0;
}
static int lib_kSpawnDashDustRelease(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_SpawnDashDustRelease(player);
return 0;
}
static int lib_kAwardPlayerRings(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
UINT16 rings = luaL_checkinteger(L, 2);
boolean overload = lua_opttrueboolean(L, 3);
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_AwardPlayerRings(player, rings, overload);
return 0;
}
static int lib_kSpawnDriftBoostClip(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_SpawnDriftBoostClip(player);
return 0;
}
static int lib_kSpawnDriftBoostClipSpark(lua_State *L)
{
mobj_t *clip = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
INLEVEL
if (!clip)
return LUA_ErrInvalid(L, "mobj_t");
K_SpawnDriftBoostClipSpark(clip);
return 0;
}
static int lib_kSpawnNormalSpeedLines(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_SpawnNormalSpeedLines(player);
return 0;
}
static int lib_kSpawnGardenTopSpeedLines(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_SpawnGardenTopSpeedLines(player);
return 0;
}
static int lib_kSpawnInvincibilitySpeedLines(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
INLEVEL
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
K_SpawnInvincibilitySpeedLines(mo);
return 0;
}
static int lib_kSpawnBumpEffect(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
INLEVEL
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
K_SpawnBumpEffect(mo);
return 0;
}
static int lib_kGenericExtraFlagsNoZAdjust(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *master = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
NOHUD
INLEVEL
if (!mo || !master)
return LUA_ErrInvalid(L, "mobj_t");
K_GenericExtraFlagsNoZAdjust(mo, master);
return 0;
}
static int lib_kPressingEBrake(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, K_PressingEBrake(player));
return 1;
}
static int lib_kMomentumAngleEx(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
fixed_t threshold = luaL_checkfixed(L, 2);
INLEVEL
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushangle(L, K_MomentumAngleEx(mo, threshold));
return 1;
}
static int lib_kMomentumAngleReal(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
INLEVEL
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushangle(L, K_MomentumAngleReal(mo));
return 1;
}
static int lib_kMomentumAngle(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
INLEVEL
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushangle(L, K_MomentumAngle(mo));
return 1;
}
static int lib_kDoInstashield(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_DoInstashield(player);
return 0;
}
static int lib_kDoPowerClash(lua_State *L)
{
mobj_t *t1 = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *t2 = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
NOHUD
INLEVEL
if (!t1 || !t2)
return LUA_ErrInvalid(L, "mobj_t");
K_DoPowerClash(t1, t2);
return 0;
}
static int lib_kDoGuardBreak(lua_State *L)
{
mobj_t *t1 = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *t2 = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
NOHUD
INLEVEL
if (!t1 || !t2)
return LUA_ErrInvalid(L, "mobj_t");
K_DoGuardBreak(t1, t2);
return 0;
}
static int lib_kBattleAwardHit(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
player_t *victim = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));;
mobj_t *inflictor = NULL;
INT32 damage = (INT32)luaL_optinteger(L, 4, 0);
NOHUD
INLEVEL
if (!player || !victim)
return LUA_ErrInvalid(L, "player_t");
if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
inflictor = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
K_BattleAwardHit(player, victim, inflictor, damage);
return 0;
}
static int lib_kSpawnBattlePoints(lua_State *L)
{
player_t *source = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
player_t *victim = NULL;
UINT8 amount = (UINT8)luaL_checkinteger(L, 3);
NOHUD
if (!source)
return LUA_ErrInvalid(L, "player_t");
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
victim = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
K_SpawnBattlePoints(source, victim, amount);
return 0;
}
static int lib_kRemoveGrowShrink(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_RemoveGrowShrink(player);
return 0;
}
static int lib_kIsBigger(lua_State *L)
{
mobj_t *compare = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *other = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
INLEVEL
if (!compare || !other)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, K_IsBigger(compare, other));
return 1;
}
static int lib_kSpinPlayer(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
mobj_t *inflictor = NULL;
mobj_t *source = NULL;
INT32 type = (INT32)luaL_optinteger(L, 3, 0);
NOHUD
if (!player)
return LUA_ErrInvalid(L, "player_t");
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
inflictor = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
source = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
K_SpinPlayer(player, inflictor, source, type);
return 0;
}
static int lib_kTumblePlayer(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
mobj_t *inflictor = NULL;
mobj_t *source = NULL;
boolean soften = false;
NOHUD
if (!player)
return LUA_ErrInvalid(L, "player_t");
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
inflictor = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
source = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
soften = lua_optboolean(L, 4);
K_TumblePlayer(player, inflictor, source, soften);
return 0;
}
static int lib_kStumbleSlope(lua_State *L)
{
angle_t angle = luaL_checkangle(L, 1);
angle_t pitch = luaL_checkangle(L, 2);
angle_t roll = luaL_checkangle(L, 3);
lua_pushangle(L, K_StumbleSlope(angle, pitch, roll));
return 1;
}
static int lib_kTumbleInterrupt(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_TumbleInterrupt(player);
return 0;
}
static int lib_kStumblePlayer(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
NOHUD
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_StumblePlayer(player);
return 0;
}
static int lib_kCheckStumble(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
angle_t oldPitch = luaL_checkangle(L, 2);
angle_t oldRoll = luaL_checkangle(L, 3);
boolean fromAir = lua_optboolean(L, 4);
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, K_CheckStumble(player, oldPitch, oldRoll, fromAir));
return 1;
}
static int lib_kExplodePlayer(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
mobj_t *source = NULL;
mobj_t *inflictor = NULL;
NOHUD
if (!player)
return LUA_ErrInvalid(L, "player_t");
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
inflictor = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
source = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
lua_pushinteger(L, K_ExplodePlayer(player, inflictor, source));
return 1;
}
static int lib_kDebtStingPlayer(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
mobj_t *source = NULL;
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
source = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
K_DebtStingPlayer(player, source);
return 0;
}
static int lib_kGiveBumpersToPlayer(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
player_t *victim = NULL;
UINT8 amount = (UINT8)luaL_optinteger(L, 3, 1);
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
victim = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
K_GiveBumpersToPlayer(player, victim, amount);
return 0;
}
static int lib_kTakeBumpersFromPlayer(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
player_t *victim = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
UINT8 amount = (UINT8)luaL_optinteger(L, 3, 1);
NOHUD
if (!player)
return LUA_ErrInvalid(L, "player_t");
if (!victim)
return LUA_ErrInvalid(L, "player_t");
K_TakeBumpersFromPlayer(player, victim, amount);
return 0;
}
static int lib_kMineFlashScreen(lua_State *L)
{
mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
INLEVEL
NOHUD
if (!source)
return LUA_ErrInvalid(L, "mobj_t");
K_MineFlashScreen(source);
return 0;
}
static int lib_kGivePointsToPlayer(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
player_t *victim = NULL;
UINT8 amount = (UINT8)luaL_optinteger(L, 3, 1);
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
victim = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
K_GivePointsToPlayer(player, victim, amount);
return 0;
}
static int lib_kSpawnMineExplosion(lua_State *L)
{
mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
skincolornum_t color = luaL_optinteger(L, 2, SKINCOLOR_KETCHUP);
tic_t delay = (tic_t)luaL_optinteger(L, 3, 0);
NOHUD
if (!source)
return LUA_ErrInvalid(L, "mobj_t");
K_SpawnMineExplosion(source, color, delay);
return 0;
}
static int lib_kSpawnLandMineExplosion(lua_State *L)
{
mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
skincolornum_t color = luaL_optinteger(L, 2, SKINCOLOR_KETCHUP);
tic_t delay = (tic_t)luaL_optinteger(L, 3, 0);
NOHUD
INLEVEL
if (!source)
return LUA_ErrInvalid(L, "mobj_t");
K_SpawnLandMineExplosion(source, color, delay);
return 0;
}
static int lib_kDriftSparkColor(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INT32 charge = luaL_checkinteger(L, 2);
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushinteger(L, K_DriftSparkColor(player, charge));
return 1;
}
static int lib_kSpawnBoostTrail(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
NOHUD
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_SpawnBoostTrail(player);
return 0;
}
static int lib_kSpawnSparkleTrail(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
K_SpawnSparkleTrail(mo);
return 0;
}
static int lib_kSpawnWipeoutTrail(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
K_SpawnWipeoutTrail(mo);
return 0;
}
static int lib_kSpawnDraftDust(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
INLEVEL
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
K_SpawnDraftDust(mo);
return 0;
}
static int lib_kSpawnMagicianParticles(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
INT32 spread = luaL_optinteger(L, 2, 5);
NOHUD
INLEVEL
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
K_SpawnMagicianParticles(mo, spread);
return 0;
}
static int lib_kDriftDustHandling(lua_State *L)
{
mobj_t *spawner = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
if (!spawner)
return LUA_ErrInvalid(L, "mobj_t");
K_DriftDustHandling(spawner);
return 0;
}
static int lib_kSquish(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
INLEVEL
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
K_Squish(mo);
return 0;
}
static int lib_kThrowKartItem(lua_State *L)
{
tm_t ptm = g_tm;
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
boolean missile = luaL_checkboolean(L, 2);
mobjtype_t mapthing = luaL_checkinteger(L, 3);
INT32 defaultDir = luaL_optinteger(L, 4, 0);
INT32 altthrow = luaL_optinteger(L, 5, 0);
angle_t angleOffset = luaL_optinteger(L, 6, 0);
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
if (mapthing >= NUMMOBJTYPES)
return luaL_error(L, "mobj type %d out of range (0 - %d)", mapthing, NUMMOBJTYPES-1);
LUA_PushUserdata(L, K_ThrowKartItem(player, missile, mapthing,
defaultDir, altthrow, angleOffset), META_MOBJ);
P_RestoreTMStruct(ptm); // This avoids a g_tm assert.
return 1;
}
static int lib_kDoSneaker(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INT32 type = luaL_optinteger(L, 2, 0);
NOHUD
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_DoSneaker(player, type);
return 0;
}
static int lib_kDoPogoSpring(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
fixed_t vertispeed = (fixed_t)luaL_optinteger(L, 2, 0);
UINT8 sound = (UINT8)luaL_optinteger(L, 3, 1);
NOHUD
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
K_DoPogoSpring(mo, vertispeed, sound);
return 0;
}
static int lib_kDoInvincibility(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
tic_t time = luaL_checkinteger(L, 2);
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_DoInvincibility(player, time);
return 0;
}
static int lib_kKillBananaChain(lua_State *L)
{
mobj_t *banana = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *inflictor = NULL;
mobj_t *source = NULL;
NOHUD
if (!banana)
return LUA_ErrInvalid(L, "mobj_t");
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
inflictor = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
source = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
K_KillBananaChain(banana, inflictor, source);
return 0;
}
static int lib_kRepairOrbitChain(lua_State *L)
{
mobj_t *orbit = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
if (!orbit)
return LUA_ErrInvalid(L, "mobj_t");
K_RepairOrbitChain(orbit);
return 0;
}
static int lib_kFindJawzTarget(lua_State *L)
{
mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
player_t *source = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
angle_t angle = luaL_checkangle(L, 3);
INLEVEL
if (!actor)
return LUA_ErrInvalid(L, "mobj_t");
if (!source)
return LUA_ErrInvalid(L, "player_t");
LUA_PushUserdata(L, K_FindJawzTarget(actor, source, angle), META_MOBJ);
return 1;
}
static int lib_kCheckPlayersRespawnColliding(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
fixed_t x = luaL_checkinteger(L, 2);
fixed_t y = luaL_checkinteger(L, 3);
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, K_CheckPlayersRespawnColliding(player-players, x, y));
return 1;
}
static int lib_kGetKartRingPower(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
boolean boosted = lua_opttrueboolean(L, 2);
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushinteger(L, K_GetKartRingPower(player, boosted));
return 1;
}
static int lib_kUpdateSteeringValue(lua_State *L)
{
fixed_t inputSteering = luaL_checkinteger(L, 1);
fixed_t destSteering = luaL_checkinteger(L, 2);
lua_pushinteger(L, K_UpdateSteeringValue(inputSteering, destSteering));
return 1;
}
static int lib_kGetKartDriftSparkValue(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
//HUDSAFE
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushinteger(L, K_GetKartDriftSparkValue(player));
return 1;
}
static int lib_kStairJankFlip(lua_State *L)
{
INT32 value = luaL_checkinteger(L, 1);
INLEVEL
lua_pushinteger(L, K_StairJankFlip(value));
return 1;
}
static int lib_kSpawnDriftBoostExplosion(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
UINT8 stage = luaL_checkinteger(L, 2);
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_SpawnDriftBoostExplosion(player, stage);
return 0;
}
static int lib_kSpawnDriftElectricSparks(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
skincolornum_t color = luaL_checkinteger(L, 2);
boolean shockwave = lua_optboolean(L, 3);
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_SpawnDriftElectricSparks(player, color, shockwave);
return 0;
}
static int lib_kKartUpdatePosition(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
NOHUD
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_KartUpdatePosition(player);
return 0;
}
static int lib_kDropPaperItem(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
UINT8 itemtype = luaL_optinteger(L, 2, 0);
UINT16 itemamount = luaL_optinteger(L, 3, 1);
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_DropPaperItem(player, itemtype, itemamount);
return 0;
}
static int lib_kCreatePaperItem(lua_State *L)
{
fixed_t x = luaL_checkfixed(L, 1);
fixed_t y = luaL_checkfixed(L, 2);
fixed_t z = luaL_checkfixed(L, 3);
angle_t angle = luaL_optinteger(L, 4, 0);
SINT8 flip = luaL_optinteger(L, 5, 0);
UINT8 type = luaL_optinteger(L, 6, 0);
UINT16 amount = luaL_optinteger(L, 7, 1);
NOHUD
INLEVEL
LUA_PushUserdata(L, K_CreatePaperItem(x, y, z, angle, flip, type, amount), META_MOBJ);
return 1;
}
static int lib_kFlingPaperItem(lua_State *L)
{
fixed_t x = luaL_checkfixed(L, 1);
fixed_t y = luaL_checkfixed(L, 2);
fixed_t z = luaL_checkfixed(L, 3);
angle_t angle = luaL_optinteger(L, 4, 0);
SINT8 flip = luaL_optinteger(L, 5, 0);
UINT8 type = luaL_optinteger(L, 6, 0);
UINT16 amount = luaL_optinteger(L, 7, 1);
NOHUD
INLEVEL
LUA_PushUserdata(L, K_FlingPaperItem(x, y, z, angle, flip, type, amount), META_MOBJ);
return 1;
}
static int lib_kPopPlayerShield(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
NOHUD
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_PopPlayerShield(player);
return 0;
}
static int lib_kDropHnextList(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
NOHUD
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_DropHnextList(player);
return 0;
}
static int lib_kDropItems(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
NOHUD
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_DropItems(player);
return 0;
}
static int lib_kDropRocketSneaker(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_DropRocketSneaker(player);
return 0;
}
static int lib_kDropKitchenSink(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_DropKitchenSink(player);
return 0;
}
static int lib_kStripItems(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
NOHUD
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_StripItems(player);
return 0;
}
static int lib_kStripOther(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
NOHUD
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_StripOther(player);
return 0;
}
static int lib_kMomentumToFacing(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
NOHUD
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_MomentumToFacing(player);
return 0;
}
static int lib_kSpawnWaterRunParticles(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
INLEVEL
if (!mobj)
return LUA_ErrInvalid(L, "mobj_t");
K_SpawnWaterRunParticles(mobj);
return 0;
}
static int lib_kApplyOffroad(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, K_ApplyOffroad(player));
return 1;
}
static int lib_kSlopeResistance(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, K_SlopeResistance(player));
return 1;
}
static int lib_kPlayerTripwireSpeedThreshold(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushfixed(L, K_PlayerTripwireSpeedThreshold(player));
return 1;
}
static int lib_kTripwirePassConditions(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushinteger(L, K_TripwirePassConditions(player));
return 1;
}
static int lib_kTripwirePass(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, K_TripwirePass(player));
return 1;
}
static int lib_kMovingHorizontally(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
INLEVEL
if (!mobj)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, K_MovingHorizontally(mobj));
return 1;
}
static int lib_kWaterRun(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
INLEVEL
if (!mobj)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, K_WaterRun(mobj));
return 1;
}
static int lib_kWaterSkip(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
INLEVEL
if (!mobj)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, K_WaterSkip(mobj));
return 1;
}
static int lib_kIsRidingFloatingTop(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, K_IsRidingFloatingTop(player));
return 1;
}
static int lib_kIsHoldingDownTop(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, K_IsHoldingDownTop(player));
return 1;
}
static int lib_kGetGardenTop(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
LUA_PushUserdata(L, K_GetGardenTop(player), META_MOBJ);
return 1;
}
static int lib_kGetSpindashChargeTime(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushinteger(L, K_GetSpindashChargeTime(player));
return 1;
}
static int lib_kGetSpindashChargeSpeed(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushfixed(L, K_GetSpindashChargeSpeed(player));
return 1;
}
static int lib_kGrowShrinkSpeedMul(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
if (player->mo)
lua_pushfixed(L, K_GrowShrinkSpeedMul(player));
else
lua_pushnil(L);
return 1;
}
static int lib_kGetKartSpeedFromStat(lua_State *L)
{
INT32 kartspeed = luaL_checkinteger(L, 1);
lua_pushfixed(L, K_GetKartSpeedFromStat(kartspeed));
return 1;
}
static int lib_kGetKartSpeed(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
boolean doboostpower = lua_optboolean(L, 2);
boolean dorubberbanding = lua_optboolean(L, 3);
//HUDSAFE
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushfixed(L, K_GetKartSpeed(player, doboostpower, dorubberbanding));
return 1;
}
static int lib_kGetKartAccel(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
//HUDSAFE
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushfixed(L, K_GetKartAccel(player));
return 1;
}
static int lib_kGetKartFlashing(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
//HUDSAFE
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushinteger(L, K_GetKartFlashing(player));
return 1;
}
static int lib_kPlayerShrinkCheat(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, K_PlayerShrinkCheat(player));
return 1;
}
static int lib_kUpdateShrinkCheat(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_UpdateShrinkCheat(player);
return 0;
}
static int lib_kKartKickstart(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, K_KartKickstart(player));
return 1;
}
static int lib_kGetForwardMove(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushinteger(L, player->mo ? K_GetForwardMove(player) : 0);
return 1;
}
static int lib_kGetNewSpeed(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushfixed(L, K_GetNewSpeed(player));
return 1;
}
static int lib_k3dKartMovement(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushfixed(L, player->mo ? K_3dKartMovement(player) : 0);
return 1;
}
static int lib_kGetItemPatch(lua_State *L)
{
UINT8 item = (UINT8)luaL_optinteger(L, 1, KITEM_NONE);
boolean tiny = lua_optboolean(L, 2);
//HUDSAFE
lua_pushstring(L, K_GetItemPatch(item, tiny));
return 1;
}
static int lib_kGetInvincibilityItemFrame(lua_State *L)
{
INLEVEL
lua_pushinteger(L, K_GetInvincibilityItemFrame());
return 1;
}
static int lib_kGetOrbinautItemFrame(lua_State *L)
{
UINT8 count = luaL_optinteger(L, 1, 1);
lua_pushinteger(L, K_GetOrbinautItemFrame(count));
return 1;
}
static int lib_kUpdateMobjItemOverlay(lua_State *L)
{
mobj_t *part = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
SINT8 itemType = luaL_optinteger(L, 2, 0);
UINT8 itemCount = luaL_optinteger(L, 3, 0);
NOHUD
INLEVEL
if (!part)
return LUA_ErrInvalid(L, "mobj_t");
K_UpdateMobjItemOverlay(part, itemType, itemCount);
return 0;
}
static int lib_kPlayerEBrake(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, player->mo ? K_PlayerEBrake(player) : false);
return 1;
}
static int lib_kPlayerGuard(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, K_PlayerGuard(player));
return 1;
}
static int lib_kSliptiding(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushinteger(L, K_Sliptiding(player));
return 1;
}
static int lib_kPlayerBaseFriction(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
fixed_t friction = luaL_optinteger(L, 2, ORIG_FRICTION);
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushfixed(L, K_PlayerBaseFriction(player, friction));
return 1;
}
static int lib_kIsSPBInGame(lua_State *L)
{
INLEVEL
lua_pushboolean(L, K_IsSPBInGame());
return 1;
}
static int lib_kDefaultPlayerRadius(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushfixed(L, player->mo ? K_DefaultPlayerRadius(player) : -1);
return 1;
}
static int lib_kItemScaleForPlayer(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushfixed(L, K_ItemScaleForPlayer(player));
return 1;
}
static int lib_kSetItemOut(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_SetItemOut(player);
return 0;
}
static int lib_kUnsetItemOut(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_UnsetItemOut(player);
return 0;
}
static int lib_kTimeLimitForGametype(lua_State *L)
{
INLEVEL
lua_pushinteger(L, K_TimeLimitForGametype());
return 1;
}
static int lib_kPointLimitForGametype(lua_State *L)
{
INLEVEL
lua_pushinteger(L, K_PointLimitForGametype());
return 1;
}
static int lib_kCooperative(lua_State *L)
{
INLEVEL
lua_pushboolean(L, K_Cooperative());
return 1;
}
static int lib_kIsPlayerInSpecialState(lua_State *L)
{
player_t *p = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!p)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, K_isPlayerInSpecialState(p));
return 1;
}
static int lib_kIsPlayingDisplayPlayer(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, K_IsPlayingDisplayPlayer(player));
return 1;
}
static int lib_kPlayerCanPunt(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, K_PlayerCanPunt(player));
return 1;
}
static int lib_kMakeObjectReappear(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
INLEVEL
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
K_MakeObjectReappear(mo);
return 0;
}
static int lib_kBumperInflate(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_BumperInflate(player);
return 0;
}
static int lib_kThunderDome(lua_State *L)
{
INLEVEL
lua_pushboolean(L, K_ThunderDome());
return 1;
}
static int lib_kPlayerCanUseItem(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, player->mo ? K_PlayerCanUseItem(player) : false);
return 1;
}
static int lib_kSetTireGrease(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
tic_t tics = luaL_checkinteger(L, 2);
INLEVEL
NOHUD
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_SetTireGrease(player, tics);
return 0;
}
static int lib_kGetCollideAngle(lua_State *L)
{
mobj_t *t1 = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *t2 = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
//HUDSAFE
if (!t1)
return LUA_ErrInvalid(L, "mobj_t");
if (!t2)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushinteger(L, K_GetCollideAngle(t1, t2));
return 1;
}
static int lib_kAddHitLag(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
tic_t tics = (tic_t)luaL_checkinteger(L, 2);
boolean fromdamage = lua_opttrueboolean(L, 3);
NOHUD
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
K_AddHitLag(mo, tics, fromdamage);
return 0;
}
static int lib_kSetHitLagForObjects(lua_State *L)
{
mobj_t *victim = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *inflictor = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
mobj_t *source = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
tic_t tics = (tic_t)luaL_checkinteger(L, 4);
boolean fromdamage = lua_opttrueboolean(L, 5);
INLEVEL
NOHUD
if (!victim || !inflictor || !source)
return LUA_ErrInvalid(L, "mobj_t");
K_SetHitLagForObjects(victim, inflictor, source, tics, fromdamage);
return 0;
}
static int lib_kPowerUpRemaining(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
kartitems_t powerup = luaL_checkinteger(L, 2);
//HUDSAFE
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushinteger(L, K_PowerUpRemaining(player, powerup));
return 1;
}
static int lib_kGivePowerUp(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
kartitems_t powerup = luaL_checkinteger(L, 2);
tic_t time = (tic_t)luaL_checkinteger(L, 3);
NOHUD
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_GivePowerUp(player, powerup, time);
return 0;
}
static int lib_kDropPowerUps(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
NOHUD
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_DropPowerUps(player);
return 0;
}
static int lib_kInitBossHealthBar(lua_State *L)
{
const char *enemyname = luaL_checkstring(L, 1);
const char *subtitle = luaL_checkstring(L, 2);
sfxenum_t titlesound = luaL_checkinteger(L, 3);
fixed_t pinchmagnitude = luaL_checkfixed(L, 4);
UINT8 divisions = (UINT8)luaL_checkinteger(L, 5);
NOHUD
K_InitBossHealthBar(enemyname, subtitle, titlesound, pinchmagnitude, divisions);
return 0;
}
static int lib_kUpdateBossHealthBar(lua_State *L)
{
fixed_t magnitude = luaL_checkfixed(L, 1);
tic_t jitterlen = (tic_t)luaL_checkinteger(L, 2);
NOHUD
K_UpdateBossHealthBar(magnitude, jitterlen);
return 0;
}
static int lib_kDeclareWeakspot(lua_State *L)
{
mobj_t *spot = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
spottype_t spottype = luaL_checkinteger(L, 2);
UINT16 color = luaL_checkinteger(L, 3);
boolean minimap = lua_optboolean(L, 4);
NOHUD
if (!spot)
return LUA_ErrInvalid(L, "mobj_t");
K_DeclareWeakspot(spot, spottype, color, minimap);
return 0;
}
static int lib_vsGetArena(lua_State *L)
{
INT32 bossindex = luaL_checkinteger(L, 1);
//HUDSAFE
LUA_PushUserdata(L, VS_GetArena(bossindex), META_MOBJ);
return 1;
}
static int lib_vsPredictAroundArena(lua_State *L)
{
mobj_t *arena = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *movingobject = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
fixed_t magnitude = luaL_checkfixed(L, 3);
fixed_t mompoint = luaL_checkangle(L, 4);
fixed_t radiussubtract = luaL_checkfixed(L, 5);
boolean forcegoaround = lua_optboolean(L, 6);
fixed_t radiusdeltafactor = luaL_optinteger(L, 7, FRACUNIT); //optfixed?
NOHUD
if (!arena || !movingobject)
return LUA_ErrInvalid(L, "mobj_t");
fixed_t *result = VS_PredictAroundArena(arena, movingobject, magnitude, mompoint, radiussubtract, forcegoaround, radiusdeltafactor);
lua_pushfixed(L, result[0]);
lua_pushfixed(L, result[1]);
return 2;
}
static int lib_vsRandomPointOnArena(lua_State *L)
{
mobj_t *arena = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
fixed_t radiussubtract = luaL_checkfixed(L, 2);
NOHUD
if (!arena)
return LUA_ErrInvalid(L, "mobj_t");
fixed_t *result = VS_RandomPointOnArena(arena, radiussubtract);
lua_pushfixed(L, result[0]);
lua_pushfixed(L, result[1]);
return 2;
}
static int lib_kPlayerUsesBotMovement(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, K_PlayerUsesBotMovement(player));
return 1;
}
static int lib_kBotCanTakeCut(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, K_BotCanTakeCut(player));
return 1;
}
static int lib_kGetBotController(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
INLEVEL
if (!mobj)
return LUA_ErrInvalid(L, "mobj_t");
botcontroller_t *botController = K_GetBotController(mobj);
if (botController != NULL)
LUA_PushUserdata(L, botController, META_BOTCONTROLLER);
else
lua_pushnil(L);
return 1;
}
static int lib_kBotMapModifier(lua_State *L)
{
INLEVEL
lua_pushfixed(L, K_BotMapModifier());
return 1;
}
static int lib_kBotRubberband(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushfixed(L, K_BotRubberband(player));
return 1;
}
static int lib_kUpdateRubberband(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushfixed(L, K_UpdateRubberband(player));
return 1;
}
static int lib_kDistanceOfLineFromPoint(lua_State *L)
{
fixed_t v1x = luaL_checkfixed(L, 1);
fixed_t v1y = luaL_checkfixed(L, 2);
fixed_t v2x = luaL_checkfixed(L, 3);
fixed_t v2y = luaL_checkfixed(L, 4);
fixed_t cx = luaL_checkfixed(L, 5);
fixed_t cy = luaL_checkfixed(L, 6);
lua_pushfixed(L, K_DistanceOfLineFromPoint(v1x, v1y, v2x, v2y, cx, cy));
return 1;
}
static int lib_kAddBot(lua_State *L)
{
INT32 skinid = -1;
UINT8 difficulty = luaL_checkinteger(L, 2);
botStyle_e style = luaL_checkinteger(L, 3);
UINT8 newplayernum = 0;
// Copypaste of libd_getSprite2Patch, but fails loudly on each fail state instead.
// get skin first!
if (lua_isnumber(L, 1)) // find skin by number
{
skinid = lua_tonumber(L, 1);
if (skinid < 0 || skinid >= MAXSKINS)
return luaL_error(L, "skin number %d out of range (0 - %d)", skinid, MAXSKINS-1);
if (skinid >= (demo.playback ? demo.numskins : numskins))
return luaL_error(L, "skin number %d out of range in demo (0 - %d)",
skinid, (demo.playback ? demo.numskins : numskins));
}
else // find skin by name
{
const char *name = luaL_checkstring(L, 1);
skinid = R_SkinAvailable(name);
if (skinid == -1)
return luaL_error(L, "could not find skin %s by name", name);
}
INLEVEL
boolean success = K_AddBot(skinid, difficulty, style, &newplayernum);
lua_pushboolean(L, success);
if (success)
LUA_PushUserdata(L, &players[newplayernum - 1], META_PLAYER);
else
lua_pushnil(L);
return 2;
}
static int lib_kSetNameForBot(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
const char *realname = luaL_checkstring(L, 2);
if (!player)
return LUA_ErrInvalid(L, "player_t");
if (!player->bot)
return luaL_error(L, "You may only change bot names.");
K_SetNameForBot(player-players, realname);
return 0;
}
static int lib_kRemoveBot(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
if (!player->bot)
return luaL_error(L, "You may only remove bots.");
CL_RemovePlayer(player-players, KR_LEAVE);
return 0;
}
static int lib_getTimeMicros(lua_State *L)
{
lua_pushinteger(L, I_GetPreciseTime() / (I_GetPrecisePrecision() / 1000000));
return 1;
}
static int lib_startTitlecardCecho(lua_State *L)
{
player_t *player = lua_isnil(L, 1) ? NULL : *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
const char *str = luaL_checkstring(L, 2);
boolean interrupt = lua_optboolean(L, 3);
HU_DoTitlecardCEcho(player, str, interrupt);
return 1;
}
static int lib_kGetDefaultTerrain(lua_State *L)
{
LUA_PushUserdata(L, K_GetDefaultTerrain(), META_TERRAIN);
return 1;
}
static int lib_kGetTerrainForTextureName(lua_State *L)
{
const char *str = luaL_checkstring(L, 1);
LUA_PushUserdata(L, K_GetTerrainForTextureName(str), META_TERRAIN);
return 1;
}
static int lib_kGetTerrainForTextureNum(lua_State *L)
{
INT32 id = luaL_checkinteger(L, 1);
LUA_PushUserdata(L, K_GetTerrainForTextureNum(id), META_TERRAIN);
return 1;
}
static int lib_kProcessTerrainEffect(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
INLEVEL
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
K_ProcessTerrainEffect(mo);
return 0;
}
static int lib_kSetDefaultFriction(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
INLEVEL
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
K_SetDefaultFriction(mo);
return 0;
}
static int lib_kSpawnSplashForMobj(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
fixed_t impact = luaL_optinteger(L, 2, FRACUNIT);
NOHUD
INLEVEL
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
K_SpawnSplashForMobj(mo, impact);
return 0;
}
static int lib_kHandleFootstepParticles(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
INLEVEL
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
K_HandleFootstepParticles(mo);
return 0;
}
static int lib_kUpdateTerrainOverlay(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
INLEVEL
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
K_UpdateTerrainOverlay(mo);
return 0;
}
static int lib_kTerrainHasAffect(lua_State *L)
{
terrain_t *terrain = *((terrain_t **)luaL_checkudata(L, 1, META_TERRAIN));
boolean badonly = lua_optboolean(L, 2);
NOHUD
INLEVEL
if (!terrain)
return LUA_ErrInvalid(L, "terrain_t");
lua_pushboolean(L, K_TerrainHasAffect(terrain, badonly));
return 1;
}
static luaL_Reg lib[] = {
{"print", lib_print},
{"chatprint", lib_chatprint},
{"chatprintf", lib_chatprintf},
{"userdataType", lib_userdataType},
{"registerMetatable", lib_registerMetatable},
{"userdataMetatable", lib_userdataMetatable},
{"IsPlayerAdmin", lib_isPlayerAdmin},
{"reserveLuabanks", lib_reserveLuabanks},
// m_random
{"P_RandomFixed",lib_pRandomFixed},
{"P_RandomByte",lib_pRandomByte},
{"P_RandomKey",lib_pRandomKey},
{"P_RandomRange",lib_pRandomRange},
{"P_SignedRandom",lib_pSignedRandom}, // MACRO
{"P_RandomChance",lib_pRandomChance}, // MACRO
// p_maputil
{"P_AproxDistance",lib_pAproxDistance},
{"P_ClosestPointOnLine",lib_pClosestPointOnLine},
{"P_PointOnLineSide",lib_pPointOnLineSide},
// p_enemy
{"P_CheckMeleeRange", lib_pCheckMeleeRange},
{"P_JetbCheckMeleeRange", lib_pJetbCheckMeleeRange},
{"P_FaceStabCheckMeleeRange", lib_pFaceStabCheckMeleeRange},
{"P_SkimCheckMeleeRange", lib_pSkimCheckMeleeRange},
{"P_CheckMissileRange", lib_pCheckMissileRange},
{"P_NewChaseDir", lib_pNewChaseDir},
{"P_LookForPlayers", lib_pLookForPlayers},
// p_mobj
// don't add P_SetMobjState or P_SetPlayerMobjState, use "mobj.state = S_NEWSTATE" instead.
{"P_SpawnMobj",lib_pSpawnMobj},
{"P_SpawnMobjFromMobj",lib_pSpawnMobjFromMobj},
{"P_SpawnMobjFromMobjUnscaled",lib_pSpawnMobjFromMobjUnscaled},
{"P_RemoveMobj",lib_pRemoveMobj},
{"P_IsValidSprite2", lib_pIsValidSprite2},
{"P_SpawnLockOn", lib_pSpawnLockOn},
{"P_SpawnMissile",lib_pSpawnMissile},
{"P_SpawnXYZMissile",lib_pSpawnXYZMissile},
{"P_SpawnPointMissile",lib_pSpawnPointMissile},
{"P_SpawnAlteredDirectionMissile",lib_pSpawnAlteredDirectionMissile},
{"P_ColorTeamMissile",lib_pColorTeamMissile},
{"P_SPMAngle",lib_pSPMAngle},
{"P_SpawnPlayerMissile",lib_pSpawnPlayerMissile},
{"P_MobjFlip",lib_pMobjFlip},
{"P_GetMobjGravity",lib_pGetMobjGravity},
{"P_FlashPal",lib_pFlashPal},
{"P_GetClosestAxis",lib_pGetClosestAxis},
{"P_SpawnParaloop",lib_pSpawnParaloop},
{"P_BossTargetPlayer",lib_pBossTargetPlayer},
{"P_SupermanLook4Players",lib_pSupermanLook4Players},
{"P_SetScale",lib_pSetScale},
{"P_InsideANonSolidFFloor",lib_pInsideANonSolidFFloor},
{"P_CheckDeathPitCollide",lib_pCheckDeathPitCollide},
{"P_CheckSolidLava",lib_pCheckSolidLava},
{"P_MaceRotate",lib_pMaceRotate},
{"P_CreateFloorSpriteSlope",lib_pCreateFloorSpriteSlope},
{"P_RemoveFloorSpriteSlope",lib_pRemoveFloorSpriteSlope},
{"P_RailThinker",lib_pRailThinker},
{"P_XYMovement",lib_pXYMovement},
{"P_RingXYMovement",lib_pRingXYMovement},
{"P_SceneryXYMovement",lib_pSceneryXYMovement},
{"P_ZMovement",lib_pZMovement},
{"P_RingZMovement",lib_pRingZMovement},
{"P_SceneryZMovement",lib_pSceneryZMovement},
{"P_PlayerZMovement",lib_pPlayerZMovement},
// p_tick
{"P_LevelIsFrozen",lib_pLevelIsFrozen},
{"P_SetFreezeLevel",lib_pSetFreezeLevel},
{"P_MobjIsFrozen",lib_pMobjIsFrozen},
// p_user
{"P_AddPlayerScore",lib_pAddPlayerScore},
{"P_PlayerInPain",lib_pPlayerInPain},
{"P_ResetPlayer",lib_pResetPlayer},
{"P_PlayerFullbright",lib_pPlayerFullbright},
{"P_IsObjectInGoop",lib_pIsObjectInGoop},
{"P_IsObjectOnGround",lib_pIsObjectOnGround},
{"P_InQuicksand",lib_pInQuicksand},
{"P_SetObjectMomZ",lib_pSetObjectMomZ},
{"P_SpawnGhostMobj",lib_pSpawnGhostMobj},
{"P_SpawnFakeShadow",lib_pSpawnFakeShadow},
{"P_GivePlayerRings",lib_pGivePlayerRings},
{"P_GivePlayerSpheres",lib_pGivePlayerSpheres},
{"P_GivePlayerLives",lib_pGivePlayerLives},
{"P_MovePlayer",lib_pMovePlayer},
{"P_DoPlayerExit",lib_pDoPlayerExit},
{"P_DoAllPlayersExit",lib_pDoAllPlayersExit},
{"P_InstaThrust",lib_pInstaThrust},
{"P_ReturnThrustX",lib_pReturnThrustX},
{"P_ReturnThrustY",lib_pReturnThrustY},
{"P_NukeEnemies",lib_pNukeEnemies},
{"P_SetPlayerAngle",lib_pSetPlayerAngle},
{"P_ForceLocalAngle",lib_pForceLocalAngle},
{"K_GetEffectiveFollowerColor",lib_pGetEffectiveFollowerColor},
// p_map
{"P_CheckPosition",lib_pCheckPosition},
{"P_TryMove",lib_pTryMove},
{"P_Move",lib_pMove},
{"P_TeleportMove",lib_pTeleportMove},
{"P_SetOrigin",lib_pSetOrigin},
{"P_MoveOrigin",lib_pMoveOrigin},
{"P_SetAngle",lib_pSetAngle},
{"P_SetPitch",lib_pSetPitch},
{"P_SetRoll",lib_pSetRoll},
{"P_SlideMove",lib_pSlideMove},
{"P_BounceMove",lib_pBounceMove},
{"P_CheckSight", lib_pCheckSight},
{"P_TraceBlockingLines", lib_pTraceBlockingLines},
{"P_CheckHoopPosition",lib_pCheckHoopPosition},
{"P_RadiusAttack",lib_pRadiusAttack},
{"P_FloorzAtPos",lib_pFloorzAtPos},
{"P_CeilingzAtPos",lib_pCeilingzAtPos},
{"P_DoSpring",lib_pDoSpring},
// p_inter
{"P_DamageMobj",lib_pDamageMobj},
{"P_KillMobj",lib_pKillMobj},
{"P_PlayerRingBurst",lib_pPlayerRingBurst},
{"P_PlayRinglossSound",lib_pPlayRinglossSound},
{"P_PlayDeathSound",lib_pPlayDeathSound},
{"P_PlayVictorySound",lib_pPlayVictorySound},
{"P_CanPickupItem",lib_pCanPickupItem},
// p_spec
{"P_Thrust",lib_pThrust},
{"P_SetMobjStateNF",lib_pSetMobjStateNF},
{"P_ExplodeMissile",lib_pExplodeMissile},
{"P_MobjTouchingSectorSpecial",lib_pMobjTouchingSectorSpecial},
{"P_MobjTouchingSectorSpecialFlag",lib_pMobjTouchingSectorSpecialFlag},
{"P_PlayerTouchingSectorSpecial",lib_pPlayerTouchingSectorSpecial},
{"P_PlayerTouchingSectorSpecialFlag",lib_pPlayerTouchingSectorSpecialFlag},
{"P_FindLowestFloorSurrounding",lib_pFindLowestFloorSurrounding},
{"P_FindHighestFloorSurrounding",lib_pFindHighestFloorSurrounding},
{"P_FindNextHighestFloor",lib_pFindNextHighestFloor},
{"P_FindNextLowestFloor",lib_pFindNextLowestFloor},
{"P_FindLowestCeilingSurrounding",lib_pFindLowestCeilingSurrounding},
{"P_FindHighestCeilingSurrounding",lib_pFindHighestCeilingSurrounding},
{"P_FindSpecialLineFromTag",lib_pFindSpecialLineFromTag},
{"P_SwitchWeather",lib_pSwitchWeather},
{"P_LinedefExecute",lib_pLinedefExecute},
{"P_SpawnLightningFlash",lib_pSpawnLightningFlash},
{"P_FadeLight",lib_pFadeLight},
{"P_SetupLevelSky",lib_pSetupLevelSky},
{"P_SetSkyboxMobj",lib_pSetSkyboxMobj},
{"P_StartQuake",lib_pStartQuake},
{"EV_CrumbleChain",lib_evCrumbleChain},
{"EV_StartCrumble",lib_evStartCrumble},
// p_slopes
{"P_GetZAt",lib_pGetZAt},
{"P_ButteredSlope",lib_pButteredSlope},
// r_defs
{"R_PointToAngle",lib_rPointToAngle},
{"R_PointToAnglePlayer", lib_rPointToAnglePlayer},
{"R_PointToAngle2",lib_rPointToAngle2},
{"R_PointToDist",lib_rPointToDist},
{"R_PointToDist2",lib_rPointToDist2},
{"R_PointInSubsector",lib_rPointInSubsector},
{"R_PointInSubsectorOrNil",lib_rPointInSubsectorOrNil},
// r_things (sprite)
{"R_Char2Frame",lib_rChar2Frame},
{"R_Frame2Char",lib_rFrame2Char},
{"R_SetPlayerSkin",lib_rSetPlayerSkin},
{"R_SkinUsable",lib_rSkinUsable},
// r_data
{"R_CheckTextureNumForName",lib_rCheckTextureNumForName},
{"R_TextureNumForName",lib_rTextureNumForName},
// r_draw
{"R_GetColorByName", lib_rGetColorByName},
{"R_GetSuperColorByName", lib_rGetSuperColorByName},
{"R_GetNameByColor", lib_rGetNameByColor},
// s_sound
{"S_StartSound",lib_sStartSound},
{"S_StartSoundAtVolume",lib_sStartSoundAtVolume},
{"S_StopSound",lib_sStopSound},
{"S_StopSoundByID",lib_sStopSoundByID},
{"S_OriginPlaying",lib_sOriginPlaying},
{"S_IdPlaying",lib_sIdPlaying},
{"S_SoundPlaying",lib_sSoundPlaying},
{"S_StartMusicCaption", lib_sStartMusicCaption},
{"S_ShowMusicCredit",lib_sShowMusicCredit},
// g_game
{"G_AddGametype", lib_gAddGametype},
{"G_BuildMapName",lib_gBuildMapName},
{"G_BuildMapTitle",lib_gBuildMapTitle},
{"G_FindMap",lib_gFindMap},
{"G_FindMapByNameOrCode",lib_gFindMapByNameOrCode},
{"G_DoReborn",lib_gDoReborn},
{"G_SetCustomExitVars",lib_gSetCustomExitVars},
{"G_ExitLevel",lib_gExitLevel},
{"G_GametypeUsesLives",lib_gGametypeUsesLives},
{"G_GametypeAllowsRetrying",lib_gGametypeAllowsRetrying},
{"G_GametypeHasTeams",lib_gGametypeHasTeams},
{"G_GametypeHasSpectators",lib_gGametypeHasSpectators},
{"G_TicsToHours",lib_gTicsToHours},
{"G_TicsToMinutes",lib_gTicsToMinutes},
{"G_TicsToSeconds",lib_gTicsToSeconds},
{"G_TicsToCentiseconds",lib_gTicsToCentiseconds},
{"G_TicsToMilliseconds",lib_gTicsToMilliseconds},
{"getTimeMicros",lib_getTimeMicros},
// k_endcam
{"K_StartRoundWinCamera",lib_kStartRoundWinCamera},
{"K_EndCameraIsFreezing",lib_kEndCameraIsFreezing},
// k_hud
{"K_AddMessage", lib_kAddMessage},
{"K_AddMessageForPlayer", lib_kAddMessageForPlayer},
{"K_ClearPersistentMessages", lib_kClearPersistentMessages},
{"K_ClearPersistentMessageForPlayer", lib_kClearPersistentMessageForPlayer},
// k_kart
{"K_PlayAttackTaunt", lib_kAttackSound},
{"K_PlayBoostTaunt", lib_kBoostSound},
{"K_PlayPowerGloatSound", lib_kGloatSound},
{"K_PlayOvertakeSound", lib_kOvertakeSound},
{"K_PlayLossSound", lib_kLossSound},
{"K_PlayPainSound", lib_kPainSound},
{"K_PlayHitEmSound", lib_kHitEmSound},
{"K_TryHurtSoundExchange", lib_kTryHurtSoundExchange},
{"K_GetPlayerDontDrawFlag", lib_kGetPlayerDontDrawFlag},
{"K_ReflectAngle",lib_kReflectAngle},
{"K_IsDuelItem",lib_kIsDuelItem},
{"K_IsPlayerLosing",lib_kIsPlayerLosing},
{"K_GetKartGameSpeedScalar",lib_kGetKartGameSpeedScalar},
{"K_IsPlayerWanted",lib_kIsPlayerWanted},
{"K_GetMobjWeight",lib_kGetMobjWeight},
{"K_PlayerJustBumped",lib_kPlayerJustBumped},
{"K_KartBouncing",lib_kKartBouncing},
{"K_KartPainEnergyFling",lib_kKartPainEnergyFling},
{"K_FlipFromObject",lib_kFlipFromObject},
{"K_KartSolidBounce",lib_kKartSolidBounce},
{"K_MatchGenericExtraFlags",lib_kMatchGenericExtraFlags},
{"K_SpawnDashDustRelease",lib_kSpawnDashDustRelease},
{"K_SpawnDriftBoostClip",lib_kSpawnDriftBoostClip},
{"K_SpawnDriftBoostClipSpark",lib_kSpawnDriftBoostClipSpark},
{"K_SpawnNormalSpeedLines",lib_kSpawnNormalSpeedLines},
{"K_SpawnGardenTopSpeedLines",lib_kSpawnGardenTopSpeedLines},
{"K_SpawnInvincibilitySpeedLines",lib_kSpawnInvincibilitySpeedLines},
{"K_SpawnBumpEffect",lib_kSpawnBumpEffect},
{"K_GenericExtraFlagsNoZAdjust",lib_kGenericExtraFlagsNoZAdjust},
{"K_PressingEBrake",lib_kPressingEBrake},
{"K_MomentumAngleEx",lib_kMomentumAngleEx},
{"K_MomentumAngleReal",lib_kMomentumAngleReal},
{"K_MomentumAngle",lib_kMomentumAngle},
{"K_AwardPlayerRings",lib_kAwardPlayerRings},
{"K_DoInstashield",lib_kDoInstashield},
{"K_DoPowerClash",lib_kDoPowerClash},
{"K_DoGuardBreak",lib_kDoGuardBreak},
{"K_BattleAwardHit",lib_kBattleAwardHit},
{"K_SpawnBattlePoints",lib_kSpawnBattlePoints},
{"K_RemoveGrowShrink",lib_kRemoveGrowShrink},
{"K_IsBigger",lib_kIsBigger},
{"K_SpinPlayer",lib_kSpinPlayer},
{"K_TumblePlayer",lib_kTumblePlayer},
{"K_StumbleSlope",lib_kStumbleSlope},
{"K_TumbleInterrupt",lib_kTumbleInterrupt},
{"K_StumblePlayer",lib_kStumblePlayer},
{"K_CheckStumble",lib_kCheckStumble},
{"K_ExplodePlayer",lib_kExplodePlayer},
{"K_DebtStingPlayer",lib_kDebtStingPlayer},
{"K_GiveBumpersToPlayer",lib_kGiveBumpersToPlayer},
{"K_TakeBumpersFromPlayer",lib_kTakeBumpersFromPlayer},
{"K_MineFlashScreen",lib_kMineFlashScreen},
{"K_GivePointsToPlayer",lib_kGivePointsToPlayer},
{"K_SpawnMineExplosion",lib_kSpawnMineExplosion},
{"K_SpawnLandMineExplosion",lib_kSpawnLandMineExplosion},
{"K_DriftSparkColor",lib_kDriftSparkColor},
{"K_SpawnBoostTrail",lib_kSpawnBoostTrail},
{"K_SpawnSparkleTrail",lib_kSpawnSparkleTrail},
{"K_SpawnWipeoutTrail",lib_kSpawnWipeoutTrail},
{"K_SpawnDraftDust",lib_kSpawnDraftDust},
{"K_SpawnMagicianParticles",lib_kSpawnMagicianParticles},
{"K_DriftDustHandling",lib_kDriftDustHandling},
{"K_Squish",lib_kSquish},
{"K_ThrowKartItem",lib_kThrowKartItem},
{"K_DoSneaker",lib_kDoSneaker},
{"K_DoPogoSpring",lib_kDoPogoSpring},
{"K_DoInvincibility",lib_kDoInvincibility},
{"K_KillBananaChain",lib_kKillBananaChain},
{"K_RepairOrbitChain",lib_kRepairOrbitChain},
{"K_FindJawzTarget",lib_kFindJawzTarget},
{"K_CheckPlayersRespawnColliding",lib_kCheckPlayersRespawnColliding},
{"K_GetKartRingPower",lib_kGetKartRingPower},
{"K_UpdateSteeringValue",lib_kUpdateSteeringValue},
{"K_GetKartDriftSparkValue",lib_kGetKartDriftSparkValue},
{"K_StairJankFlip",lib_kStairJankFlip},
{"K_SpawnDriftBoostExplosion",lib_kSpawnDriftBoostExplosion},
{"K_SpawnDriftElectricSparks",lib_kSpawnDriftElectricSparks},
{"K_KartUpdatePosition",lib_kKartUpdatePosition},
{"K_DropPaperItem",lib_kDropPaperItem},
{"K_CreatePaperItem",lib_kCreatePaperItem},
{"K_FlingPaperItem",lib_kFlingPaperItem},
{"K_PopPlayerShield",lib_kPopPlayerShield},
{"K_DropHnextList",lib_kDropHnextList},
{"K_DropItems",lib_kDropItems},
{"K_DropRocketSneaker",lib_kDropRocketSneaker},
{"K_DropKitchenSink",lib_kDropKitchenSink},
{"K_StripItems",lib_kStripItems},
{"K_StripOther",lib_kStripOther},
{"K_MomentumToFacing",lib_kMomentumToFacing},
{"K_SpawnWaterRunParticles",lib_kSpawnWaterRunParticles},
{"K_ApplyOffroad",lib_kApplyOffroad},
{"K_SlopeResistance",lib_kSlopeResistance},
{"K_PlayerTripwireSpeedThreshold",lib_kPlayerTripwireSpeedThreshold},
{"K_TripwirePassConditions",lib_kTripwirePassConditions},
{"K_TripwirePass",lib_kTripwirePass},
{"K_MovingHorizontally",lib_kMovingHorizontally},
{"K_WaterRun",lib_kWaterRun},
{"K_WaterSkip",lib_kWaterSkip},
{"K_IsRidingFloatingTop",lib_kIsRidingFloatingTop},
{"K_IsHoldingDownTop",lib_kIsHoldingDownTop},
{"K_GetGardenTop",lib_kGetGardenTop},
{"K_GetSpindashChargeTime",lib_kGetSpindashChargeTime},
{"K_GetSpindashChargeSpeed",lib_kGetSpindashChargeSpeed},
{"K_GrowShrinkSpeedMul",lib_kGrowShrinkSpeedMul},
{"K_GetKartSpeedFromStat",lib_kGetKartSpeedFromStat},
{"K_GetKartSpeed",lib_kGetKartSpeed},
{"K_GetKartAccel",lib_kGetKartAccel},
{"K_GetKartFlashing",lib_kGetKartFlashing},
{"K_PlayerShrinkCheat",lib_kPlayerShrinkCheat},
{"K_UpdateShrinkCheat",lib_kUpdateShrinkCheat},
{"K_KartKickstart",lib_kKartKickstart},
{"K_GetForwardMove",lib_kGetForwardMove},
{"K_GetNewSpeed",lib_kGetNewSpeed},
{"K_3dKartMovement",lib_k3dKartMovement},
{"K_GetItemPatch",lib_kGetItemPatch},
{"K_GetInvincibilityItemFrame",lib_kGetInvincibilityItemFrame},
{"K_GetOrbinautItemFrame",lib_kGetOrbinautItemFrame},
{"K_UpdateMobjItemOverlay",lib_kUpdateMobjItemOverlay},
{"K_PlayerEBrake",lib_kPlayerEBrake},
{"K_Sliptiding",lib_kSliptiding},
{"K_PlayerBaseFriction",lib_kPlayerBaseFriction},
{"K_IsSPBInGame",lib_kIsSPBInGame},
{"K_DefaultPlayerRadius",lib_kDefaultPlayerRadius},
{"K_ItemScaleForPlayer",lib_kItemScaleForPlayer},
{"K_SetItemOut",lib_kSetItemOut},
{"K_UnsetItemOut",lib_kUnsetItemOut},
{"K_TimeLimitForGametype",lib_kTimeLimitForGametype},
{"K_PointLimitForGametype",lib_kPointLimitForGametype},
{"K_Cooperative",lib_kCooperative},
{"K_isPlayerInSpecialState",lib_kIsPlayerInSpecialState},
{"K_IsPlayingDisplayPlayer",lib_kIsPlayingDisplayPlayer},
{"K_PlayerCanPunt",lib_kPlayerCanPunt},
{"K_MakeObjectReappear",lib_kMakeObjectReappear},
{"K_BumperInflate",lib_kBumperInflate},
{"K_ThunderDome",lib_kThunderDome},
{"K_PlayerCanUseItem",lib_kPlayerCanUseItem},
{"K_PlayerGuard",lib_kPlayerGuard},
{"K_SetTireGrease",lib_kSetTireGrease},
{"K_GetCollideAngle",lib_kGetCollideAngle},
// k_hitlag
{"K_AddHitLag",lib_kAddHitLag},
{"K_SetHitLagForObjects",lib_kSetHitLagForObjects},
// k_powerup
{"K_PowerUpRemaining",lib_kPowerUpRemaining},
{"K_GivePowerUp",lib_kGivePowerUp},
{"K_DropPowerUps",lib_kDropPowerUps},
// k_boss
{"K_InitBossHealthBar", lib_kInitBossHealthBar},
{"K_UpdateBossHealthBar", lib_kUpdateBossHealthBar},
{"K_DeclareWeakspot", lib_kDeclareWeakspot},
{"VS_GetArena", lib_vsGetArena},
{"VS_PredictAroundArena", lib_vsPredictAroundArena},
{"VS_RandomPointOnArena", lib_vsRandomPointOnArena},
// k_bot
{"K_PlayerUsesBotMovement", lib_kPlayerUsesBotMovement},
{"K_BotCanTakeCut", lib_kBotCanTakeCut},
{"K_GetBotController", lib_kGetBotController},
{"K_BotMapModifier", lib_kBotMapModifier},
{"K_BotRubberband", lib_kBotRubberband},
{"K_UpdateRubberband", lib_kUpdateRubberband},
{"K_DistanceOfLineFromPoint", lib_kDistanceOfLineFromPoint},
{"K_AddBot", lib_kAddBot},
{"K_SetNameForBot", lib_kSetNameForBot},
// Lua-only function to allow safely removing bots.
{"K_RemoveBot", lib_kRemoveBot},
// hu_stuff technically?
{"HU_DoTitlecardCEcho", lib_startTitlecardCecho},
// music
{"Music_AddTune", lib_mMusicAddTune},
{"Music_Play", lib_mMusicPlay},
{"Music_Remap", lib_mMusicRemap},
{"Music_SetFadeOut", lib_mMusicSetFadeOut},
{"Music_SetFadeIn", lib_mMusicSetFadeIn},
{"Music_DelayEnd", lib_mMusicDelayEnd},
{"Music_Dim", lib_mMusicDim},
{"Music_Seek", lib_mMusicSeek},
{"Music_Stop", lib_mMusicStop},
{"Music_Pause", lib_mMusicPause},
{"Music_UnPause", lib_mMusicUnPause},
{"Music_Suspend", lib_mMusicSuspend},
{"Music_UnSuspend", lib_mMusicUnSuspend},
{"Music_StopAll", lib_mMusicStopAll},
{"Music_PauseAll", lib_mMusicPauseAll},
{"Music_UnPauseAll", lib_mMusicUnPauseAll},
{"Music_Loop", lib_mMusicLoop},
{"Music_BatchExempt", lib_mMusicBatchExempt},
// k_terrain
{"K_GetDefaultTerrain", lib_kGetDefaultTerrain},
{"K_GetTerrainForTextureName", lib_kGetTerrainForTextureName},
{"K_GetTerrainForTextureNum", lib_kGetTerrainForTextureNum},
{"K_ProcessTerrainEffect", lib_kProcessTerrainEffect},
{"K_SetDefaultFriction", lib_kSetDefaultFriction},
{"K_SpawnSplashForMobj", lib_kSpawnSplashForMobj},
{"K_HandleFootstepParticles", lib_kHandleFootstepParticles},
{"K_UpdateTerrainOverlay", lib_kUpdateTerrainOverlay},
{"K_TerrainHasAffect", lib_kTerrainHasAffect},
{NULL, NULL}
};
int LUA_BaseLib(lua_State *L)
{
// Set metatable for string
lua_pushliteral(L, ""); // dummy string
lua_getmetatable(L, -1); // get string metatable
lua_pushcfunction(L,lib_concat); // push concatination function
lua_setfield(L,-2,"__add"); // ... store it as mathematical addition
lua_pop(L, 2); // pop metatable and dummy string
lua_newtable(L);
lua_setfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS);
// Set global functions
lua_pushvalue(L, LUA_GLOBALSINDEX);
luaL_register(L, NULL, lib);
return 0;
}