1 // SONIC ROBO BLAST 2
2 //-----------------------------------------------------------------------------
3 // Copyright (C) 2012-2016 by John "JTE" Muniz.
4 // Copyright (C) 2012-2020 by Sonic Team Junior.
5 //
6 // This program is free software distributed under the
7 // terms of the GNU General Public License, version 2.
8 // See the 'LICENSE' file for more details.
9 //-----------------------------------------------------------------------------
10 /// \file  lua_baselib.c
11 /// \brief basic functions for Lua scripting
12 
13 #include "doomdef.h"
14 #include "fastcmp.h"
15 #include "p_local.h"
16 #include "p_setup.h" // So we can have P_SetupLevelSky
17 #include "p_slopes.h" // P_GetSlopeZAt
18 #include "z_zone.h"
19 #include "r_main.h"
20 #include "r_draw.h"
21 #include "r_things.h" // R_Frame2Char etc
22 #include "m_random.h"
23 #include "s_sound.h"
24 #include "g_game.h"
25 #include "m_menu.h"
26 #include "y_inter.h"
27 #include "hu_stuff.h"	// HU_AddChatText
28 #include "console.h"
29 #include "d_netcmd.h" // IsPlayerAdmin
30 #include "m_menu.h" // Player Setup menu color stuff
31 
32 #include "lua_script.h"
33 #include "lua_libs.h"
34 #include "lua_hud.h" // hud_running errors
35 #include "taglist.h" // P_FindSpecialLineFromTag
36 #include "lua_hook.h" // hook_cmd_running errors
37 
38 #define NOHUD if (hud_running)\
39 return luaL_error(L, "HUD rendering code should not call this function!");\
40 else if (hook_cmd_running)\
41 return luaL_error(L, "CMD building code should not call this function!");
42 
luaL_checkboolean(lua_State * L,int narg)43 boolean luaL_checkboolean(lua_State *L, int narg) {
44 	luaL_checktype(L, narg, LUA_TBOOLEAN);
45 	return lua_toboolean(L, narg);
46 }
47 
48 // String concatination
lib_concat(lua_State * L)49 static int lib_concat(lua_State *L)
50 {
51   int n = lua_gettop(L);  /* number of arguments */
52   int i;
53   char *r = NULL;
54   size_t rl = 0,sl;
55   lua_getglobal(L, "tostring");
56   for (i=1; i<=n; i++) {
57     const char *s;
58     lua_pushvalue(L, -1);  /* function to be called */
59     lua_pushvalue(L, i);   /* value to print */
60     lua_call(L, 1, 1);
61     s = lua_tolstring(L, -1, &sl);  /* get result */
62     if (s == NULL)
63       return luaL_error(L, LUA_QL("tostring") " must return a string to "
64 													 LUA_QL("__add"));
65 		r = Z_Realloc(r, rl+sl, PU_STATIC, NULL);
66 		M_Memcpy(r+rl, s, sl);
67 		rl += sl;
68     lua_pop(L, 1);  /* pop result */
69   }
70   lua_pushlstring(L, r, rl);
71   Z_Free(r);
72 	return 1;
73 }
74 
75 // Wrapper for CONS_Printf
76 // Copied from base Lua code
lib_print(lua_State * L)77 static int lib_print(lua_State *L)
78 {
79   int n = lua_gettop(L);  /* number of arguments */
80   int i;
81   //HUDSAFE
82   lua_getglobal(L, "tostring");
83   for (i=1; i<=n; i++) {
84     const char *s;
85     lua_pushvalue(L, -1);  /* function to be called */
86     lua_pushvalue(L, i);   /* value to print */
87     lua_call(L, 1, 1);
88     s = lua_tostring(L, -1);  /* get result */
89     if (s == NULL)
90       return luaL_error(L, LUA_QL("tostring") " must return a string to "
91 													 LUA_QL("print"));
92     if (i>1) CONS_Printf("\n");
93     CONS_Printf("%s", s);
94     lua_pop(L, 1);  /* pop result */
95   }
96 	CONS_Printf("\n");
97 	return 0;
98 }
99 
100 // Print stuff in the chat, or in the console if we can't.
lib_chatprint(lua_State * L)101 static int lib_chatprint(lua_State *L)
102 {
103 	const char *str = luaL_checkstring(L, 1);	// retrieve string
104 	boolean sound = lua_optboolean(L, 2);	// retrieve sound boolean
105 	int len = strlen(str);
106 
107 	if (str == NULL)	// error if we don't have a string!
108 		return luaL_error(L, LUA_QL("tostring") " must return a string to " LUA_QL("chatprint"));
109 
110 	if (len > 255)	// string is too long!!!
111 		return luaL_error(L, "String exceeds the 255 characters limit of the chat buffer.");
112 
113 	HU_AddChatText(str, sound);
114 	return 0;
115 }
116 
117 // Same as above, but do it for only one player.
lib_chatprintf(lua_State * L)118 static int lib_chatprintf(lua_State *L)
119 {
120 	int n = lua_gettop(L);  /* number of arguments */
121 	const char *str = luaL_checkstring(L, 2);	// retrieve string
122 	boolean sound = lua_optboolean(L, 3);	// sound?
123 	int len = strlen(str);
124 	player_t *plr;
125 
126 	if (n < 2)
127 		return luaL_error(L, "chatprintf requires at least two arguments: player and text.");
128 
129 	plr = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));	// retrieve player
130 	if (!plr)
131 		return LUA_ErrInvalid(L, "player_t");
132 	if (plr != &players[consoleplayer])
133 		return 0;
134 
135 	if (str == NULL)	// error if we don't have a string!
136 		return luaL_error(L, LUA_QL("tostring") " must return a string to " LUA_QL("chatprintf"));
137 
138 	if (len > 255)	// string is too long!!!
139 		return luaL_error(L, "String exceeds the 255 characters limit of the chat buffer.");
140 
141 	HU_AddChatText(str, sound);
142 	return 0;
143 }
144 
145 static const struct {
146 	const char *meta;
147 	const char *utype;
148 } meta2utype[] = {
149 	{META_STATE,        "state_t"},
150 	{META_MOBJINFO,     "mobjinfo_t"},
151 	{META_SFXINFO,      "sfxinfo_t"},
152 	{META_SKINCOLOR,    "skincolor_t"},
153 	{META_COLORRAMP,    "skincolor_t.ramp"},
154 	{META_SPRITEINFO,   "spriteinfo_t"},
155 	{META_PIVOTLIST,    "spriteframepivot_t[]"},
156 	{META_FRAMEPIVOT,   "spriteframepivot_t"},
157 
158 	{META_TAGLIST,      "taglist"},
159 
160 	{META_MOBJ,         "mobj_t"},
161 	{META_MAPTHING,     "mapthing_t"},
162 
163 	{META_PLAYER,       "player_t"},
164 	{META_TICCMD,       "ticcmd_t"},
165 	{META_SKIN,         "skin_t"},
166 	{META_POWERS,       "player_t.powers"},
167 	{META_SOUNDSID,     "skin_t.soundsid"},
168 	{META_SKINSPRITES,  "skin_t.sprites"},
169 	{META_SKINSPRITESLIST,  "skin_t.sprites[]"},
170 
171 	{META_VERTEX,       "vertex_t"},
172 	{META_LINE,         "line_t"},
173 	{META_SIDE,         "side_t"},
174 	{META_SUBSECTOR,    "subsector_t"},
175 	{META_SECTOR,       "sector_t"},
176 	{META_FFLOOR,       "ffloor_t"},
177 #ifdef HAVE_LUA_SEGS
178 	{META_SEG,          "seg_t"},
179 	{META_NODE,         "node_t"},
180 #endif
181 	{META_SLOPE,        "slope_t"},
182 	{META_VECTOR2,      "vector2_t"},
183 	{META_VECTOR3,      "vector3_t"},
184 	{META_MAPHEADER,    "mapheader_t"},
185 
186 	{META_POLYOBJ,      "polyobj_t"},
187 
188 	{META_CVAR,         "consvar_t"},
189 
190 	{META_SECTORLINES,  "sector_t.lines"},
191 #ifdef MUTABLE_TAGS
192 	{META_SECTORTAGLIST, "sector_t.taglist"},
193 #endif
194 	{META_SIDENUM,      "line_t.sidenum"},
195 	{META_LINEARGS,     "line_t.args"},
196 	{META_LINESTRINGARGS, "line_t.stringargs"},
197 
198 	{META_THINGARGS,     "mapthing.args"},
199 	{META_THINGSTRINGARGS, "mapthing.stringargs"},
200 #ifdef HAVE_LUA_SEGS
201 	{META_NODEBBOX,     "node_t.bbox"},
202 	{META_NODECHILDREN, "node_t.children"},
203 #endif
204 
205 	{META_BBOX,         "bbox"},
206 
207 	{META_HUDINFO,      "hudinfo_t"},
208 	{META_PATCH,        "patch_t"},
209 	{META_COLORMAP,     "colormap"},
210 	{META_CAMERA,       "camera_t"},
211 
212 	{META_ACTION,       "action"},
213 
214 	{META_LUABANKS,     "luabanks[]"},
215 	{NULL,              NULL}
216 };
217 
218 // goes through the above list and returns the utype string for the userdata type
219 // returns "unknown" instead if we couldn't find the right userdata type
GetUserdataUType(lua_State * L)220 static const char *GetUserdataUType(lua_State *L)
221 {
222 	UINT8 i;
223 	lua_getmetatable(L, -1);
224 
225 	for (i = 0; meta2utype[i].meta; i++)
226 	{
227 		luaL_getmetatable(L, meta2utype[i].meta);
228 		if (lua_rawequal(L, -1, -2))
229 		{
230 			lua_pop(L, 2);
231 			return meta2utype[i].utype;
232 		}
233 		lua_pop(L, 1);
234 	}
235 
236 	lua_pop(L, 1);
237 	return "unknown";
238 }
239 
240 // Return a string representing the type of userdata the given var is
241 // e.g. players[0] -> "player_t"
242 //   or players[0].powers -> "player_t.powers"
lib_userdataType(lua_State * L)243 static int lib_userdataType(lua_State *L)
244 {
245 	lua_settop(L, 1); // pop everything except arg 1 (in case somebody decided to add more)
246 	luaL_checktype(L, 1, LUA_TUSERDATA);
247 	lua_pushstring(L, GetUserdataUType(L));
248 	return 1;
249 }
250 
251 // Takes a metatable as first and only argument
252 // Only callable during script loading
lib_registerMetatable(lua_State * L)253 static int lib_registerMetatable(lua_State *L)
254 {
255 	static UINT16 nextid = 1;
256 
257 	if (!lua_lumploading)
258 		return luaL_error(L, "This function cannot be called from within a hook or coroutine!");
259 	luaL_checktype(L, 1, LUA_TTABLE);
260 
261 	if (nextid == 0)
262 		return luaL_error(L, "Too many metatables registered?! Please consider rewriting your script once you are sober again.\n");
263 
264 	lua_getfield(L, LUA_REGISTRYINDEX, LREG_METATABLES); // 2
265 		// registry.metatables[metatable] = nextid
266 		lua_pushvalue(L, 1); // 3
267 			lua_pushnumber(L, nextid); // 4
268 		lua_settable(L, 2);
269 
270 		// registry.metatables[nextid] = metatable
271 		lua_pushnumber(L, nextid); // 3
272 			lua_pushvalue(L, 1); // 4
273 		lua_settable(L, 2);
274 	lua_pop(L, 1);
275 
276 	nextid++;
277 
278 	return 0;
279 }
280 
281 // Takes a string as only argument and returns the metatable
282 // associated to the userdata type this string refers to
283 // Returns nil if the string does not refer to a valid userdata type
lib_userdataMetatable(lua_State * L)284 static int lib_userdataMetatable(lua_State *L)
285 {
286 	UINT32 i;
287 	const char *udname = luaL_checkstring(L, 1);
288 
289 	// Find internal metatable name
290 	for (i = 0; meta2utype[i].meta; i++)
291 		if (!strcmp(udname, meta2utype[i].utype))
292 		{
293 			luaL_getmetatable(L, meta2utype[i].meta);
294 			return 1;
295 		}
296 
297 	lua_pushnil(L);
298 	return 1;
299 }
300 
lib_isPlayerAdmin(lua_State * L)301 static int lib_isPlayerAdmin(lua_State *L)
302 {
303 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
304 	//HUDSAFE
305 	if (!player)
306 		return LUA_ErrInvalid(L, "player_t");
307 	lua_pushboolean(L, IsPlayerAdmin(player-players));
308 	return 1;
309 }
310 
lib_reserveLuabanks(lua_State * L)311 static int lib_reserveLuabanks(lua_State *L)
312 {
313 	static boolean reserved = false;
314 	if (!lua_lumploading)
315 		return luaL_error(L, "luabanks[] cannot be reserved from within a hook or coroutine!");
316 	if (reserved)
317 		return luaL_error(L, "luabanks[] has already been reserved! Only one savedata-enabled mod at a time may use this feature.");
318 	reserved = true;
319 	LUA_PushUserdata(L, &luabanks, META_LUABANKS);
320 	return 1;
321 }
322 
323 // M_MENU
324 //////////////
325 
lib_pMoveColorBefore(lua_State * L)326 static int lib_pMoveColorBefore(lua_State *L)
327 {
328 	UINT16 color = (UINT16)luaL_checkinteger(L, 1);
329 	UINT16 targ = (UINT16)luaL_checkinteger(L, 2);
330 
331 	NOHUD
332 	M_MoveColorBefore(color, targ);
333 	return 0;
334 }
335 
lib_pMoveColorAfter(lua_State * L)336 static int lib_pMoveColorAfter(lua_State *L)
337 {
338 	UINT16 color = (UINT16)luaL_checkinteger(L, 1);
339 	UINT16 targ = (UINT16)luaL_checkinteger(L, 2);
340 
341 	NOHUD
342 	M_MoveColorAfter(color, targ);
343 	return 0;
344 }
345 
lib_pGetColorBefore(lua_State * L)346 static int lib_pGetColorBefore(lua_State *L)
347 {
348 	UINT16 color = (UINT16)luaL_checkinteger(L, 1);
349 	lua_pushinteger(L, M_GetColorBefore(color));
350 	return 1;
351 }
352 
lib_pGetColorAfter(lua_State * L)353 static int lib_pGetColorAfter(lua_State *L)
354 {
355 	UINT16 color = (UINT16)luaL_checkinteger(L, 1);
356 	lua_pushinteger(L, M_GetColorAfter(color));
357 	return 1;
358 }
359 
360 // M_RANDOM
361 //////////////
362 
lib_pRandomFixed(lua_State * L)363 static int lib_pRandomFixed(lua_State *L)
364 {
365 	NOHUD
366 	lua_pushfixed(L, P_RandomFixed());
367 	return 1;
368 }
369 
lib_pRandomByte(lua_State * L)370 static int lib_pRandomByte(lua_State *L)
371 {
372 	NOHUD
373 	lua_pushinteger(L, P_RandomByte());
374 	return 1;
375 }
376 
lib_pRandomKey(lua_State * L)377 static int lib_pRandomKey(lua_State *L)
378 {
379 	INT32 a = (INT32)luaL_checkinteger(L, 1);
380 
381 	NOHUD
382 	if (a > 65536)
383 		LUA_UsageWarning(L, "P_RandomKey: range > 65536 is undefined behavior");
384 	lua_pushinteger(L, P_RandomKey(a));
385 	return 1;
386 }
387 
lib_pRandomRange(lua_State * L)388 static int lib_pRandomRange(lua_State *L)
389 {
390 	INT32 a = (INT32)luaL_checkinteger(L, 1);
391 	INT32 b = (INT32)luaL_checkinteger(L, 2);
392 
393 	NOHUD
394 	if (b < a) {
395 		INT32 c = a;
396 		a = b;
397 		b = c;
398 	}
399 	if ((b-a+1) > 65536)
400 		LUA_UsageWarning(L, "P_RandomRange: range > 65536 is undefined behavior");
401 	lua_pushinteger(L, P_RandomRange(a, b));
402 	return 1;
403 }
404 
405 // Macros.
lib_pSignedRandom(lua_State * L)406 static int lib_pSignedRandom(lua_State *L)
407 {
408 	NOHUD
409 	lua_pushinteger(L, P_SignedRandom());
410 	return 1;
411 }
412 
lib_pRandomChance(lua_State * L)413 static int lib_pRandomChance(lua_State *L)
414 {
415 	fixed_t p = luaL_checkfixed(L, 1);
416 	NOHUD
417 	lua_pushboolean(L, P_RandomChance(p));
418 	return 1;
419 }
420 
421 // P_MAPUTIL
422 ///////////////
423 
lib_pAproxDistance(lua_State * L)424 static int lib_pAproxDistance(lua_State *L)
425 {
426 	fixed_t dx = luaL_checkfixed(L, 1);
427 	fixed_t dy = luaL_checkfixed(L, 2);
428 	//HUDSAFE
429 	lua_pushfixed(L, R_PointToDist2(0, 0, dx, dy));
430 	return 1;
431 }
432 
lib_pClosestPointOnLine(lua_State * L)433 static int lib_pClosestPointOnLine(lua_State *L)
434 {
435 	int n = lua_gettop(L);
436 	fixed_t x = luaL_checkfixed(L, 1);
437 	fixed_t y = luaL_checkfixed(L, 2);
438 	vertex_t result;
439 	//HUDSAFE
440 	if (lua_isuserdata(L, 3)) // use a real linedef to get our points
441 	{
442 		line_t *line = *((line_t **)luaL_checkudata(L, 3, META_LINE));
443 		if (!line)
444 			return LUA_ErrInvalid(L, "line_t");
445 		P_ClosestPointOnLine(x, y, line, &result);
446 	}
447 	else // use custom coordinates of our own!
448 	{
449 		vertex_t v1, v2; // fake vertexes
450 		line_t junk; // fake linedef
451 
452 		if (n < 6)
453 			return luaL_error(L, "arguments 3 to 6 not all given (expected 4 fixed-point integers)");
454 
455 		v1.x = luaL_checkfixed(L, 3);
456 		v1.y = luaL_checkfixed(L, 4);
457 		v2.x = luaL_checkfixed(L, 5);
458 		v2.y = luaL_checkfixed(L, 6);
459 
460 		junk.v1 = &v1;
461 		junk.v2 = &v2;
462 		junk.dx = v2.x - v1.x;
463 		junk.dy = v2.y - v1.y;
464 		P_ClosestPointOnLine(x, y, &junk, &result);
465 	}
466 
467 	lua_pushfixed(L, result.x);
468 	lua_pushfixed(L, result.y);
469 	return 2;
470 }
471 
lib_pPointOnLineSide(lua_State * L)472 static int lib_pPointOnLineSide(lua_State *L)
473 {
474 	int n = lua_gettop(L);
475 	fixed_t x = luaL_checkfixed(L, 1);
476 	fixed_t y = luaL_checkfixed(L, 2);
477 	//HUDSAFE
478 	if (lua_isuserdata(L, 3)) // use a real linedef to get our points
479 	{
480 		line_t *line = *((line_t **)luaL_checkudata(L, 3, META_LINE));
481 		if (!line)
482 			return LUA_ErrInvalid(L, "line_t");
483 		lua_pushinteger(L, P_PointOnLineSide(x, y, line));
484 	}
485 	else // use custom coordinates of our own!
486 	{
487 		vertex_t v1, v2; // fake vertexes
488 		line_t junk; // fake linedef
489 
490 		if (n < 6)
491 			return luaL_error(L, "arguments 3 to 6 not all given (expected 4 fixed-point integers)");
492 
493 		v1.x = luaL_checkfixed(L, 3);
494 		v1.y = luaL_checkfixed(L, 4);
495 		v2.x = luaL_checkfixed(L, 5);
496 		v2.y = luaL_checkfixed(L, 6);
497 
498 		junk.v1 = &v1;
499 		junk.v2 = &v2;
500 		junk.dx = v2.x - v1.x;
501 		junk.dy = v2.y - v1.y;
502 		lua_pushinteger(L, P_PointOnLineSide(x, y, &junk));
503 	}
504 	return 1;
505 }
506 
507 // P_ENEMY
508 /////////////
509 
lib_pCheckMeleeRange(lua_State * L)510 static int lib_pCheckMeleeRange(lua_State *L)
511 {
512 	mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
513 	NOHUD
514 	INLEVEL
515 	if (!actor)
516 		return LUA_ErrInvalid(L, "mobj_t");
517 	lua_pushboolean(L, P_CheckMeleeRange(actor));
518 	return 1;
519 }
520 
lib_pJetbCheckMeleeRange(lua_State * L)521 static int lib_pJetbCheckMeleeRange(lua_State *L)
522 {
523 	mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
524 	NOHUD
525 	INLEVEL
526 	if (!actor)
527 		return LUA_ErrInvalid(L, "mobj_t");
528 	lua_pushboolean(L, P_JetbCheckMeleeRange(actor));
529 	return 1;
530 }
531 
lib_pFaceStabCheckMeleeRange(lua_State * L)532 static int lib_pFaceStabCheckMeleeRange(lua_State *L)
533 {
534 	mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
535 	NOHUD
536 	INLEVEL
537 	if (!actor)
538 		return LUA_ErrInvalid(L, "mobj_t");
539 	lua_pushboolean(L, P_FaceStabCheckMeleeRange(actor));
540 	return 1;
541 }
542 
lib_pSkimCheckMeleeRange(lua_State * L)543 static int lib_pSkimCheckMeleeRange(lua_State *L)
544 {
545 	mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
546 	NOHUD
547 	INLEVEL
548 	if (!actor)
549 		return LUA_ErrInvalid(L, "mobj_t");
550 	lua_pushboolean(L, P_SkimCheckMeleeRange(actor));
551 	return 1;
552 }
553 
lib_pCheckMissileRange(lua_State * L)554 static int lib_pCheckMissileRange(lua_State *L)
555 {
556 	mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
557 	NOHUD
558 	INLEVEL
559 	if (!actor)
560 		return LUA_ErrInvalid(L, "mobj_t");
561 	lua_pushboolean(L, P_CheckMissileRange(actor));
562 	return 1;
563 }
564 
lib_pNewChaseDir(lua_State * L)565 static int lib_pNewChaseDir(lua_State *L)
566 {
567 	mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
568 	NOHUD
569 	INLEVEL
570 	if (!actor)
571 		return LUA_ErrInvalid(L, "mobj_t");
572 	P_NewChaseDir(actor);
573 	return 0;
574 }
575 
lib_pLookForPlayers(lua_State * L)576 static int lib_pLookForPlayers(lua_State *L)
577 {
578 	mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
579 	fixed_t dist = (fixed_t)luaL_optinteger(L, 2, 0);
580 	boolean allaround = lua_optboolean(L, 3);
581 	boolean tracer = lua_optboolean(L, 4);
582 	NOHUD
583 	INLEVEL
584 	if (!actor)
585 		return LUA_ErrInvalid(L, "mobj_t");
586 	lua_pushboolean(L, P_LookForPlayers(actor, allaround, tracer, dist));
587 	return 1;
588 }
589 
590 // P_MOBJ
591 ////////////
592 
lib_pSpawnMobj(lua_State * L)593 static int lib_pSpawnMobj(lua_State *L)
594 {
595 	fixed_t x = luaL_checkfixed(L, 1);
596 	fixed_t y = luaL_checkfixed(L, 2);
597 	fixed_t z = luaL_checkfixed(L, 3);
598 	mobjtype_t type = luaL_checkinteger(L, 4);
599 	NOHUD
600 	INLEVEL
601 	if (type >= NUMMOBJTYPES)
602 		return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
603 	LUA_PushUserdata(L, P_SpawnMobj(x, y, z, type), META_MOBJ);
604 	return 1;
605 }
606 
lib_pSpawnMobjFromMobj(lua_State * L)607 static int lib_pSpawnMobjFromMobj(lua_State *L)
608 {
609 	mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
610 	fixed_t x = luaL_checkfixed(L, 2);
611 	fixed_t y = luaL_checkfixed(L, 3);
612 	fixed_t z = luaL_checkfixed(L, 4);
613 	mobjtype_t type = luaL_checkinteger(L, 5);
614 	NOHUD
615 	INLEVEL
616 	if (!actor)
617 		return LUA_ErrInvalid(L, "mobj_t");
618 	if (type >= NUMMOBJTYPES)
619 		return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
620 	LUA_PushUserdata(L, P_SpawnMobjFromMobj(actor, x, y, z, type), META_MOBJ);
621 	return 1;
622 }
623 
lib_pRemoveMobj(lua_State * L)624 static int lib_pRemoveMobj(lua_State *L)
625 {
626 	mobj_t *th = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
627 	NOHUD
628 	INLEVEL
629 	if (!th)
630 		return LUA_ErrInvalid(L, "mobj_t");
631 	if (th->player)
632 		return luaL_error(L, "Attempt to remove player mobj with P_RemoveMobj.");
633 	P_RemoveMobj(th);
634 	return 0;
635 }
636 
637 // 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.
638 
lib_pIsValidSprite2(lua_State * L)639 static int lib_pIsValidSprite2(lua_State *L)
640 {
641 	mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
642 	UINT8 spr2 = (UINT8)luaL_checkinteger(L, 2);
643 	//HUDSAFE
644 	INLEVEL
645 	if (!mobj)
646 		return LUA_ErrInvalid(L, "mobj_t");
647 	lua_pushboolean(L, (mobj->skin && (((skin_t *)mobj->skin)->sprites[spr2].numframes)));
648 	return 1;
649 }
650 
651 // P_SpawnLockOn doesn't exist either, but we want to expose making a local mobj without encouraging hacks.
652 
lib_pSpawnLockOn(lua_State * L)653 static int lib_pSpawnLockOn(lua_State *L)
654 {
655 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
656 	mobj_t *lockon = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
657 	statenum_t state = luaL_checkinteger(L, 3);
658 	NOHUD
659 	INLEVEL
660 	if (!lockon)
661 		return LUA_ErrInvalid(L, "mobj_t");
662 	if (!player)
663 		return LUA_ErrInvalid(L, "player_t");
664 	if (state >= NUMSTATES)
665 		return luaL_error(L, "state %d out of range (0 - %d)", state, NUMSTATES-1);
666 	if (P_IsLocalPlayer(player)) // Only display it on your own view.
667 	{
668 		mobj_t *visual = P_SpawnMobj(lockon->x, lockon->y, lockon->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker
669 		P_SetTarget(&visual->target, lockon);
670 		visual->flags2 |= MF2_DONTDRAW;
671 		P_SetMobjStateNF(visual, state);
672 	}
673 	return 0;
674 }
675 
lib_pSpawnMissile(lua_State * L)676 static int lib_pSpawnMissile(lua_State *L)
677 {
678 	mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
679 	mobj_t *dest = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
680 	mobjtype_t type = luaL_checkinteger(L, 3);
681 	NOHUD
682 	INLEVEL
683 	if (!source || !dest)
684 		return LUA_ErrInvalid(L, "mobj_t");
685 	if (type >= NUMMOBJTYPES)
686 		return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
687 	LUA_PushUserdata(L, P_SpawnMissile(source, dest, type), META_MOBJ);
688 	return 1;
689 }
690 
lib_pSpawnXYZMissile(lua_State * L)691 static int lib_pSpawnXYZMissile(lua_State *L)
692 {
693 	mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
694 	mobj_t *dest = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
695 	mobjtype_t type = luaL_checkinteger(L, 3);
696 	fixed_t x = luaL_checkfixed(L, 4);
697 	fixed_t y = luaL_checkfixed(L, 5);
698 	fixed_t z = luaL_checkfixed(L, 6);
699 	NOHUD
700 	INLEVEL
701 	if (!source || !dest)
702 		return LUA_ErrInvalid(L, "mobj_t");
703 	if (type >= NUMMOBJTYPES)
704 		return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
705 	LUA_PushUserdata(L, P_SpawnXYZMissile(source, dest, type, x, y, z), META_MOBJ);
706 	return 1;
707 }
708 
lib_pSpawnPointMissile(lua_State * L)709 static int lib_pSpawnPointMissile(lua_State *L)
710 {
711 	mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
712 	fixed_t xa = luaL_checkfixed(L, 2);
713 	fixed_t ya = luaL_checkfixed(L, 3);
714 	fixed_t za = luaL_checkfixed(L, 4);
715 	mobjtype_t type = luaL_checkinteger(L, 5);
716 	fixed_t x = luaL_checkfixed(L, 6);
717 	fixed_t y = luaL_checkfixed(L, 7);
718 	fixed_t z = luaL_checkfixed(L, 8);
719 	NOHUD
720 	INLEVEL
721 	if (!source)
722 		return LUA_ErrInvalid(L, "mobj_t");
723 	if (type >= NUMMOBJTYPES)
724 		return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
725 	LUA_PushUserdata(L, P_SpawnPointMissile(source, xa, ya, za, type, x, y, z), META_MOBJ);
726 	return 1;
727 }
728 
lib_pSpawnAlteredDirectionMissile(lua_State * L)729 static int lib_pSpawnAlteredDirectionMissile(lua_State *L)
730 {
731 	mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
732 	mobjtype_t type = luaL_checkinteger(L, 2);
733 	fixed_t x = luaL_checkfixed(L, 3);
734 	fixed_t y = luaL_checkfixed(L, 4);
735 	fixed_t z = luaL_checkfixed(L, 5);
736 	INT32 shiftingAngle = (INT32)luaL_checkinteger(L, 5);
737 	NOHUD
738 	INLEVEL
739 	if (!source)
740 		return LUA_ErrInvalid(L, "mobj_t");
741 	if (type >= NUMMOBJTYPES)
742 		return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
743 	LUA_PushUserdata(L, P_SpawnAlteredDirectionMissile(source, type, x, y, z, shiftingAngle), META_MOBJ);
744 	return 1;
745 }
746 
lib_pColorTeamMissile(lua_State * L)747 static int lib_pColorTeamMissile(lua_State *L)
748 {
749 	mobj_t *missile = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
750 	player_t *source = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
751 	NOHUD
752 	INLEVEL
753 	if (!missile)
754 		return LUA_ErrInvalid(L, "mobj_t");
755 	if (!source)
756 		return LUA_ErrInvalid(L, "player_t");
757 	P_ColorTeamMissile(missile, source);
758 	return 0;
759 }
760 
lib_pSPMAngle(lua_State * L)761 static int lib_pSPMAngle(lua_State *L)
762 {
763 	mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
764 	mobjtype_t type = luaL_checkinteger(L, 2);
765 	angle_t angle = luaL_checkangle(L, 3);
766 	UINT8 allowaim = (UINT8)luaL_optinteger(L, 4, 0);
767 	UINT32 flags2 = (UINT32)luaL_optinteger(L, 5, 0);
768 	NOHUD
769 	INLEVEL
770 	if (!source)
771 		return LUA_ErrInvalid(L, "mobj_t");
772 	if (type >= NUMMOBJTYPES)
773 		return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
774 	LUA_PushUserdata(L, P_SPMAngle(source, type, angle, allowaim, flags2), META_MOBJ);
775 	return 1;
776 }
777 
lib_pSpawnPlayerMissile(lua_State * L)778 static int lib_pSpawnPlayerMissile(lua_State *L)
779 {
780 	mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
781 	mobjtype_t type = luaL_checkinteger(L, 2);
782 	UINT32 flags2 = (UINT32)luaL_optinteger(L, 3, 0);
783 	NOHUD
784 	INLEVEL
785 	if (!source)
786 		return LUA_ErrInvalid(L, "mobj_t");
787 	if (type >= NUMMOBJTYPES)
788 		return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
789 	LUA_PushUserdata(L, P_SpawnPlayerMissile(source, type, flags2), META_MOBJ);
790 	return 1;
791 }
792 
lib_pMobjFlip(lua_State * L)793 static int lib_pMobjFlip(lua_State *L)
794 {
795 	mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
796 	//HUDSAFE
797 	INLEVEL
798 	if (!mobj)
799 		return LUA_ErrInvalid(L, "mobj_t");
800 	lua_pushinteger(L, P_MobjFlip(mobj));
801 	return 1;
802 }
803 
lib_pGetMobjGravity(lua_State * L)804 static int lib_pGetMobjGravity(lua_State *L)
805 {
806 	mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
807 	//HUDSAFE
808 	INLEVEL
809 	if (!mobj)
810 		return LUA_ErrInvalid(L, "mobj_t");
811 	lua_pushfixed(L, P_GetMobjGravity(mobj));
812 	return 1;
813 }
814 
lib_pWeaponOrPanel(lua_State * L)815 static int lib_pWeaponOrPanel(lua_State *L)
816 {
817 	mobjtype_t type = luaL_checkinteger(L, 1);
818 	//HUDSAFE
819 	if (type >= NUMMOBJTYPES)
820 		return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
821 	lua_pushboolean(L, P_WeaponOrPanel(type));
822 	return 1;
823 }
824 
lib_pFlashPal(lua_State * L)825 static int lib_pFlashPal(lua_State *L)
826 {
827 	player_t *pl = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
828 	UINT16 type = (UINT16)luaL_checkinteger(L, 2);
829 	UINT16 duration = (UINT16)luaL_checkinteger(L, 3);
830 	NOHUD
831 	INLEVEL
832 	if (!pl)
833 		return LUA_ErrInvalid(L, "player_t");
834 	P_FlashPal(pl, type, duration);
835 	return 0;
836 }
837 
lib_pGetClosestAxis(lua_State * L)838 static int lib_pGetClosestAxis(lua_State *L)
839 {
840 	mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
841 	//HUDSAFE
842 	INLEVEL
843 	if (!source)
844 		return LUA_ErrInvalid(L, "mobj_t");
845 	LUA_PushUserdata(L, P_GetClosestAxis(source), META_MOBJ);
846 	return 1;
847 }
848 
lib_pSpawnParaloop(lua_State * L)849 static int lib_pSpawnParaloop(lua_State *L)
850 {
851 	fixed_t x = luaL_checkfixed(L, 1);
852 	fixed_t y = luaL_checkfixed(L, 2);
853 	fixed_t z = luaL_checkfixed(L, 3);
854 	fixed_t radius = luaL_checkfixed(L, 4);
855 	INT32 number = (INT32)luaL_checkinteger(L, 5);
856 	mobjtype_t type = luaL_checkinteger(L, 6);
857 	angle_t rotangle = luaL_checkangle(L, 7);
858 	statenum_t nstate = luaL_optinteger(L, 8, S_NULL);
859 	boolean spawncenter = lua_optboolean(L, 9);
860 	NOHUD
861 	INLEVEL
862 	if (type >= NUMMOBJTYPES)
863 		return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
864 	if (nstate >= NUMSTATES)
865 		return luaL_error(L, "state %d out of range (0 - %d)", nstate, NUMSTATES-1);
866 	P_SpawnParaloop(x, y, z, radius, number, type, nstate, rotangle, spawncenter);
867 	return 0;
868 }
869 
lib_pBossTargetPlayer(lua_State * L)870 static int lib_pBossTargetPlayer(lua_State *L)
871 {
872 	mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
873 	boolean closest = lua_optboolean(L, 2);
874 	NOHUD
875 	INLEVEL
876 	if (!actor)
877 		return LUA_ErrInvalid(L, "mobj_t");
878 	lua_pushboolean(L, P_BossTargetPlayer(actor, closest));
879 	return 1;
880 }
881 
lib_pSupermanLook4Players(lua_State * L)882 static int lib_pSupermanLook4Players(lua_State *L)
883 {
884 	mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
885 	NOHUD
886 	INLEVEL
887 	if (!actor)
888 		return LUA_ErrInvalid(L, "mobj_t");
889 	lua_pushboolean(L, P_SupermanLook4Players(actor));
890 	return 1;
891 }
892 
lib_pSetScale(lua_State * L)893 static int lib_pSetScale(lua_State *L)
894 {
895 	mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
896 	fixed_t newscale = luaL_checkfixed(L, 2);
897 	NOHUD
898 	INLEVEL
899 	if (!mobj)
900 		return LUA_ErrInvalid(L, "mobj_t");
901 	if (newscale < FRACUNIT/100)
902 		newscale = FRACUNIT/100;
903 	P_SetScale(mobj, newscale);
904 	return 0;
905 }
906 
lib_pInsideANonSolidFFloor(lua_State * L)907 static int lib_pInsideANonSolidFFloor(lua_State *L)
908 {
909 	mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
910 	ffloor_t *rover = *((ffloor_t **)luaL_checkudata(L, 2, META_FFLOOR));
911 	//HUDSAFE
912 	INLEVEL
913 	if (!mobj)
914 		return LUA_ErrInvalid(L, "mobj_t");
915 	if (!rover)
916 		return LUA_ErrInvalid(L, "ffloor_t");
917 	lua_pushboolean(L, P_InsideANonSolidFFloor(mobj, rover));
918 	return 1;
919 }
920 
lib_pCheckDeathPitCollide(lua_State * L)921 static int lib_pCheckDeathPitCollide(lua_State *L)
922 {
923 	mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
924 	//HUDSAFE
925 	INLEVEL
926 	if (!mo)
927 		return LUA_ErrInvalid(L, "mobj_t");
928 	lua_pushboolean(L, P_CheckDeathPitCollide(mo));
929 	return 1;
930 }
931 
lib_pCheckSolidLava(lua_State * L)932 static int lib_pCheckSolidLava(lua_State *L)
933 {
934 	ffloor_t *rover = *((ffloor_t **)luaL_checkudata(L, 2, META_FFLOOR));
935 	//HUDSAFE
936 	INLEVEL
937 	if (!rover)
938 		return LUA_ErrInvalid(L, "ffloor_t");
939 	lua_pushboolean(L, P_CheckSolidLava(rover));
940 	return 1;
941 }
942 
lib_pCanRunOnWater(lua_State * L)943 static int lib_pCanRunOnWater(lua_State *L)
944 {
945 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
946 	ffloor_t *rover = *((ffloor_t **)luaL_checkudata(L, 2, META_FFLOOR));
947 	//HUDSAFE
948 	INLEVEL
949 	if (!player)
950 		return LUA_ErrInvalid(L, "player_t");
951 	if (!rover)
952 		return LUA_ErrInvalid(L, "ffloor_t");
953 	lua_pushboolean(L, P_CanRunOnWater(player, rover));
954 	return 1;
955 }
956 
lib_pMaceRotate(lua_State * L)957 static int lib_pMaceRotate(lua_State *L)
958 {
959 	mobj_t *center = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
960 	INT32 baserot = luaL_checkinteger(L, 2);
961 	INT32 baseprevrot = luaL_checkinteger(L, 3);
962 	NOHUD
963 	INLEVEL
964 	if (!center)
965 		return LUA_ErrInvalid(L, "mobj_t");
966 	P_MaceRotate(center, baserot, baseprevrot);
967 	return 0;
968 }
969 
lib_pCreateFloorSpriteSlope(lua_State * L)970 static int lib_pCreateFloorSpriteSlope(lua_State *L)
971 {
972 	mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
973 	NOHUD
974 	INLEVEL
975 	if (!mobj)
976 		return LUA_ErrInvalid(L, "mobj_t");
977 	LUA_PushUserdata(L, (pslope_t *)P_CreateFloorSpriteSlope(mobj), META_SLOPE);
978 	return 1;
979 }
980 
lib_pRemoveFloorSpriteSlope(lua_State * L)981 static int lib_pRemoveFloorSpriteSlope(lua_State *L)
982 {
983 	mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
984 	NOHUD
985 	INLEVEL
986 	if (!mobj)
987 		return LUA_ErrInvalid(L, "mobj_t");
988 	P_RemoveFloorSpriteSlope(mobj);
989 	return 1;
990 }
991 
lib_pRailThinker(lua_State * L)992 static int lib_pRailThinker(lua_State *L)
993 {
994 	mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
995 	mobj_t *ptmthing = tmthing;
996 	NOHUD
997 	INLEVEL
998 	if (!mobj)
999 		return LUA_ErrInvalid(L, "mobj_t");
1000 	lua_pushboolean(L, P_RailThinker(mobj));
1001 	P_SetTarget(&tmthing, ptmthing);
1002 	return 1;
1003 }
1004 
lib_pXYMovement(lua_State * L)1005 static int lib_pXYMovement(lua_State *L)
1006 {
1007 	mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
1008 	mobj_t *ptmthing = tmthing;
1009 	NOHUD
1010 	INLEVEL
1011 	if (!actor)
1012 		return LUA_ErrInvalid(L, "mobj_t");
1013 	P_XYMovement(actor);
1014 	P_SetTarget(&tmthing, ptmthing);
1015 	return 0;
1016 }
1017 
lib_pRingXYMovement(lua_State * L)1018 static int lib_pRingXYMovement(lua_State *L)
1019 {
1020 	mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
1021 	mobj_t *ptmthing = tmthing;
1022 	NOHUD
1023 	INLEVEL
1024 	if (!actor)
1025 		return LUA_ErrInvalid(L, "mobj_t");
1026 	P_RingXYMovement(actor);
1027 	P_SetTarget(&tmthing, ptmthing);
1028 	return 0;
1029 }
1030 
lib_pSceneryXYMovement(lua_State * L)1031 static int lib_pSceneryXYMovement(lua_State *L)
1032 {
1033 	mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
1034 	mobj_t *ptmthing = tmthing;
1035 	NOHUD
1036 	INLEVEL
1037 	if (!actor)
1038 		return LUA_ErrInvalid(L, "mobj_t");
1039 	P_SceneryXYMovement(actor);
1040 	P_SetTarget(&tmthing, ptmthing);
1041 	return 0;
1042 }
1043 
lib_pZMovement(lua_State * L)1044 static int lib_pZMovement(lua_State *L)
1045 {
1046 	mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
1047 	NOHUD
1048 	INLEVEL
1049 	if (!actor)
1050 		return LUA_ErrInvalid(L, "mobj_t");
1051 	lua_pushboolean(L, P_ZMovement(actor));
1052 	P_CheckPosition(actor, actor->x, actor->y);
1053 	return 1;
1054 }
1055 
lib_pRingZMovement(lua_State * L)1056 static int lib_pRingZMovement(lua_State *L)
1057 {
1058 	mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
1059 	NOHUD
1060 	INLEVEL
1061 	if (!actor)
1062 		return LUA_ErrInvalid(L, "mobj_t");
1063 	P_RingZMovement(actor);
1064 	P_CheckPosition(actor, actor->x, actor->y);
1065 	return 0;
1066 }
1067 
lib_pSceneryZMovement(lua_State * L)1068 static int lib_pSceneryZMovement(lua_State *L)
1069 {
1070 	mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
1071 	NOHUD
1072 	INLEVEL
1073 	if (!actor)
1074 		return LUA_ErrInvalid(L, "mobj_t");
1075 	lua_pushboolean(L, P_SceneryZMovement(actor));
1076 	P_CheckPosition(actor, actor->x, actor->y);
1077 	return 1;
1078 }
1079 
lib_pPlayerZMovement(lua_State * L)1080 static int lib_pPlayerZMovement(lua_State *L)
1081 {
1082 	mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
1083 	NOHUD
1084 	INLEVEL
1085 	if (!actor)
1086 		return LUA_ErrInvalid(L, "mobj_t");
1087 	P_PlayerZMovement(actor);
1088 	P_CheckPosition(actor, actor->x, actor->y);
1089 	return 0;
1090 }
1091 
1092 // P_USER
1093 ////////////
1094 
lib_pGetPlayerHeight(lua_State * L)1095 static int lib_pGetPlayerHeight(lua_State *L)
1096 {
1097 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1098 	//HUDSAFE
1099 	INLEVEL
1100 	if (!player)
1101 		return LUA_ErrInvalid(L, "player_t");
1102 	lua_pushfixed(L, P_GetPlayerHeight(player));
1103 	return 1;
1104 }
1105 
lib_pGetPlayerSpinHeight(lua_State * L)1106 static int lib_pGetPlayerSpinHeight(lua_State *L)
1107 {
1108 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1109 	//HUDSAFE
1110 	INLEVEL
1111 	if (!player)
1112 		return LUA_ErrInvalid(L, "player_t");
1113 	lua_pushfixed(L, P_GetPlayerSpinHeight(player));
1114 	return 1;
1115 }
1116 
lib_pGetPlayerControlDirection(lua_State * L)1117 static int lib_pGetPlayerControlDirection(lua_State *L)
1118 {
1119 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1120 	//HUDSAFE
1121 	INLEVEL
1122 	if (!player)
1123 		return LUA_ErrInvalid(L, "player_t");
1124 	lua_pushinteger(L, P_GetPlayerControlDirection(player));
1125 	return 1;
1126 }
1127 
lib_pAddPlayerScore(lua_State * L)1128 static int lib_pAddPlayerScore(lua_State *L)
1129 {
1130 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1131 	UINT32 amount = (UINT32)luaL_checkinteger(L, 2);
1132 	NOHUD
1133 	INLEVEL
1134 	if (!player)
1135 		return LUA_ErrInvalid(L, "player_t");
1136 	P_AddPlayerScore(player, amount);
1137 	return 0;
1138 }
1139 
lib_pStealPlayerScore(lua_State * L)1140 static int lib_pStealPlayerScore(lua_State *L)
1141 {
1142 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1143 	UINT32 amount = (UINT32)luaL_checkinteger(L, 2);
1144 	NOHUD
1145 	INLEVEL
1146 	if (!player)
1147 		return LUA_ErrInvalid(L, "player_t");
1148 	P_StealPlayerScore(player, amount);
1149 	return 0;
1150 }
1151 
lib_pGetJumpFlags(lua_State * L)1152 static int lib_pGetJumpFlags(lua_State *L)
1153 {
1154 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1155 	NOHUD
1156 	INLEVEL
1157 	if (!player)
1158 		return LUA_ErrInvalid(L, "player_t");
1159 	lua_pushinteger(L, P_GetJumpFlags(player));
1160 	return 1;
1161 }
1162 
lib_pPlayerInPain(lua_State * L)1163 static int lib_pPlayerInPain(lua_State *L)
1164 {
1165 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1166 	//HUDSAFE
1167 	INLEVEL
1168 	if (!player)
1169 		return LUA_ErrInvalid(L, "player_t");
1170 	lua_pushboolean(L, P_PlayerInPain(player));
1171 	return 1;
1172 }
1173 
lib_pDoPlayerPain(lua_State * L)1174 static int lib_pDoPlayerPain(lua_State *L)
1175 {
1176 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1177 	mobj_t *source = NULL, *inflictor = NULL;
1178 	NOHUD
1179 	INLEVEL
1180 	if (!player)
1181 		return LUA_ErrInvalid(L, "player_t");
1182 	if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
1183 		source = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
1184 	if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
1185 		inflictor = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
1186 	P_DoPlayerPain(player, source, inflictor);
1187 	return 0;
1188 }
1189 
lib_pResetPlayer(lua_State * L)1190 static int lib_pResetPlayer(lua_State *L)
1191 {
1192 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1193 	NOHUD
1194 	INLEVEL
1195 	if (!player)
1196 		return LUA_ErrInvalid(L, "player_t");
1197 	P_ResetPlayer(player);
1198 	return 0;
1199 }
1200 
lib_pPlayerCanDamage(lua_State * L)1201 static int lib_pPlayerCanDamage(lua_State *L)
1202 {
1203 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1204 	mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
1205 	NOHUD // was hud safe but then i added a lua hook
1206 	INLEVEL
1207 	if (!player)
1208 		return LUA_ErrInvalid(L, "player_t");
1209 	if (!thing)
1210 		return LUA_ErrInvalid(L, "mobj_t");
1211 	lua_pushboolean(L, P_PlayerCanDamage(player, thing));
1212 	return 1;
1213 }
1214 
lib_pPlayerFullbright(lua_State * L)1215 static int lib_pPlayerFullbright(lua_State *L)
1216 {
1217 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1218 	INLEVEL
1219 	if (!player)
1220 		return LUA_ErrInvalid(L, "player_t");
1221 	lua_pushboolean(L, P_PlayerFullbright(player));
1222 	return 1;
1223 }
1224 
1225 
lib_pIsObjectInGoop(lua_State * L)1226 static int lib_pIsObjectInGoop(lua_State *L)
1227 {
1228 	mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
1229 	//HUDSAFE
1230 	INLEVEL
1231 	if (!mo)
1232 		return LUA_ErrInvalid(L, "mobj_t");
1233 	lua_pushboolean(L, P_IsObjectInGoop(mo));
1234 	return 1;
1235 }
1236 
lib_pIsObjectOnGround(lua_State * L)1237 static int lib_pIsObjectOnGround(lua_State *L)
1238 {
1239 	mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
1240 	//HUDSAFE
1241 	INLEVEL
1242 	if (!mo)
1243 		return LUA_ErrInvalid(L, "mobj_t");
1244 	lua_pushboolean(L, P_IsObjectOnGround(mo));
1245 	return 1;
1246 }
1247 
lib_pInSpaceSector(lua_State * L)1248 static int lib_pInSpaceSector(lua_State *L)
1249 {
1250 	mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
1251 	//HUDSAFE
1252 	INLEVEL
1253 	if (!mo)
1254 		return LUA_ErrInvalid(L, "mobj_t");
1255 	lua_pushboolean(L, P_InSpaceSector(mo));
1256 	return 1;
1257 }
1258 
lib_pInQuicksand(lua_State * L)1259 static int lib_pInQuicksand(lua_State *L)
1260 {
1261 	mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
1262 	//HUDSAFE
1263 	INLEVEL
1264 	if (!mo)
1265 		return LUA_ErrInvalid(L, "mobj_t");
1266 	lua_pushboolean(L, P_InQuicksand(mo));
1267 	return 1;
1268 }
1269 
lib_pSetObjectMomZ(lua_State * L)1270 static int lib_pSetObjectMomZ(lua_State *L)
1271 {
1272 	mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
1273 	fixed_t value = luaL_checkfixed(L, 2);
1274 	boolean relative = lua_optboolean(L, 3);
1275 	NOHUD
1276 	INLEVEL
1277 	if (!mo)
1278 		return LUA_ErrInvalid(L, "mobj_t");
1279 	P_SetObjectMomZ(mo, value, relative);
1280 	return 0;
1281 }
1282 
lib_pPlayJingle(lua_State * L)1283 static int lib_pPlayJingle(lua_State *L)
1284 {
1285 	player_t *player = NULL;
1286 	jingletype_t jingletype = luaL_checkinteger(L, 2);
1287 	//NOHUD
1288 	//INLEVEL
1289 	if (!lua_isnone(L, 1) && lua_isuserdata(L, 1))
1290 	{
1291 		player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1292 		if (!player)
1293 			return LUA_ErrInvalid(L, "player_t");
1294 	}
1295 	if (jingletype >= NUMJINGLES)
1296 		return luaL_error(L, "jingletype %d out of range (0 - %d)", jingletype, NUMJINGLES-1);
1297 	P_PlayJingle(player, jingletype);
1298 	return 0;
1299 }
1300 
lib_pPlayJingleMusic(lua_State * L)1301 static int lib_pPlayJingleMusic(lua_State *L)
1302 {
1303 	player_t *player = NULL;
1304 	const char *musnamearg = luaL_checkstring(L, 2);
1305 	char musname[7], *p = musname;
1306 	UINT16 musflags = luaL_optinteger(L, 3, 0);
1307 	boolean looping = lua_opttrueboolean(L, 4);
1308 	jingletype_t jingletype = luaL_optinteger(L, 5, JT_OTHER);
1309 	//NOHUD
1310 	//INLEVEL
1311 	if (!lua_isnone(L, 1) && lua_isuserdata(L, 1))
1312 	{
1313 		player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1314 		if (!player)
1315 			return LUA_ErrInvalid(L, "player_t");
1316 	}
1317 	if (jingletype >= NUMJINGLES)
1318 		return luaL_error(L, "jingletype %d out of range (0 - %d)", jingletype, NUMJINGLES-1);
1319 
1320 	musname[6] = '\0';
1321 	strncpy(musname, musnamearg, 6);
1322 
1323 	while (*p) {
1324 		*p = tolower(*p);
1325 		++p;
1326 	}
1327 
1328 	P_PlayJingleMusic(player, musname, musflags, looping, jingletype);
1329 	return 0;
1330 }
1331 
lib_pRestoreMusic(lua_State * L)1332 static int lib_pRestoreMusic(lua_State *L)
1333 {
1334 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1335 	//NOHUD
1336 	//INLEVEL
1337 	if (!player)
1338 		return LUA_ErrInvalid(L, "player_t");
1339 	if (P_IsLocalPlayer(player))
1340 		P_RestoreMusic(player);
1341 	return 0;
1342 }
1343 
lib_pSpawnShieldOrb(lua_State * L)1344 static int lib_pSpawnShieldOrb(lua_State *L)
1345 {
1346 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1347 	NOHUD
1348 	INLEVEL
1349 	if (!player)
1350 		return LUA_ErrInvalid(L, "player_t");
1351 	P_SpawnShieldOrb(player);
1352 	return 0;
1353 }
1354 
lib_pSpawnGhostMobj(lua_State * L)1355 static int lib_pSpawnGhostMobj(lua_State *L)
1356 {
1357 	mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
1358 	NOHUD
1359 	INLEVEL
1360 	if (!mobj)
1361 		return LUA_ErrInvalid(L, "mobj_t");
1362 	LUA_PushUserdata(L, P_SpawnGhostMobj(mobj), META_MOBJ);
1363 	return 1;
1364 }
1365 
lib_pGivePlayerRings(lua_State * L)1366 static int lib_pGivePlayerRings(lua_State *L)
1367 {
1368 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1369 	INT32 num_rings = (INT32)luaL_checkinteger(L, 2);
1370 	NOHUD
1371 	INLEVEL
1372 	if (!player)
1373 		return LUA_ErrInvalid(L, "player_t");
1374 	P_GivePlayerRings(player, num_rings);
1375 	return 0;
1376 }
1377 
lib_pGivePlayerLives(lua_State * L)1378 static int lib_pGivePlayerLives(lua_State *L)
1379 {
1380 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1381 	INT32 numlives = (INT32)luaL_checkinteger(L, 2);
1382 	NOHUD
1383 	INLEVEL
1384 	if (!player)
1385 		return LUA_ErrInvalid(L, "player_t");
1386 	P_GivePlayerLives(player, numlives);
1387 	return 0;
1388 }
1389 
lib_pGiveCoopLives(lua_State * L)1390 static int lib_pGiveCoopLives(lua_State *L)
1391 {
1392 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1393 	INT32 numlives = (INT32)luaL_checkinteger(L, 2);
1394 	boolean sound = (boolean)lua_opttrueboolean(L, 3);
1395 	NOHUD
1396 	INLEVEL
1397 	if (!player)
1398 		return LUA_ErrInvalid(L, "player_t");
1399 	P_GiveCoopLives(player, numlives, sound);
1400 	return 0;
1401 }
1402 
lib_pResetScore(lua_State * L)1403 static int lib_pResetScore(lua_State *L)
1404 {
1405 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1406 	NOHUD
1407 	INLEVEL
1408 	if (!player)
1409 		return LUA_ErrInvalid(L, "player_t");
1410 	P_ResetScore(player);
1411 	return 0;
1412 }
1413 
lib_pDoJumpShield(lua_State * L)1414 static int lib_pDoJumpShield(lua_State *L)
1415 {
1416 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1417 	NOHUD
1418 	INLEVEL
1419 	if (!player)
1420 		return LUA_ErrInvalid(L, "player_t");
1421 	P_DoJumpShield(player);
1422 	return 0;
1423 }
1424 
lib_pDoBubbleBounce(lua_State * L)1425 static int lib_pDoBubbleBounce(lua_State *L)
1426 {
1427 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1428 	NOHUD
1429 	INLEVEL
1430 	if (!player)
1431 		return LUA_ErrInvalid(L, "player_t");
1432 	P_DoBubbleBounce(player);
1433 	return 0;
1434 }
1435 
lib_pBlackOw(lua_State * L)1436 static int lib_pBlackOw(lua_State *L)
1437 {
1438 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1439 	NOHUD
1440 	INLEVEL
1441 	if (!player)
1442 		return LUA_ErrInvalid(L, "player_t");
1443 	P_BlackOw(player);
1444 	return 0;
1445 }
1446 
lib_pElementalFire(lua_State * L)1447 static int lib_pElementalFire(lua_State *L)
1448 {
1449 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1450 	boolean cropcircle = lua_optboolean(L, 2);
1451 	NOHUD
1452 	INLEVEL
1453 	if (!player)
1454 		return LUA_ErrInvalid(L, "player_t");
1455 	P_ElementalFire(player, cropcircle);
1456 	return 0;
1457 }
1458 
lib_pSpawnSkidDust(lua_State * L)1459 static int lib_pSpawnSkidDust(lua_State *L)
1460 {
1461 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1462 	fixed_t radius = luaL_checkfixed(L, 2);
1463 	boolean sound = lua_optboolean(L, 3);
1464 	NOHUD
1465 	INLEVEL
1466 	if (!player)
1467 		return LUA_ErrInvalid(L, "player_t");
1468 	P_SpawnSkidDust(player, radius, sound);
1469 	return 0;
1470 }
1471 
lib_pMovePlayer(lua_State * L)1472 static int lib_pMovePlayer(lua_State *L)
1473 {
1474 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1475 	NOHUD
1476 	INLEVEL
1477 	if (!player)
1478 		return LUA_ErrInvalid(L, "player_t");
1479 	P_MovePlayer(player);
1480 	return 0;
1481 }
1482 
lib_pDoPlayerFinish(lua_State * L)1483 static int lib_pDoPlayerFinish(lua_State *L)
1484 {
1485 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1486 	NOHUD
1487 	INLEVEL
1488 	if (!player)
1489 		return LUA_ErrInvalid(L, "player_t");
1490 	P_DoPlayerFinish(player);
1491 	return 0;
1492 }
1493 
lib_pDoPlayerExit(lua_State * L)1494 static int lib_pDoPlayerExit(lua_State *L)
1495 {
1496 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1497 	NOHUD
1498 	INLEVEL
1499 	if (!player)
1500 		return LUA_ErrInvalid(L, "player_t");
1501 	P_DoPlayerExit(player);
1502 	return 0;
1503 }
1504 
lib_pInstaThrust(lua_State * L)1505 static int lib_pInstaThrust(lua_State *L)
1506 {
1507 	mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
1508 	angle_t angle = luaL_checkangle(L, 2);
1509 	fixed_t move = luaL_checkfixed(L, 3);
1510 	NOHUD
1511 	INLEVEL
1512 	if (!mo)
1513 		return LUA_ErrInvalid(L, "mobj_t");
1514 	P_InstaThrust(mo, angle, move);
1515 	return 0;
1516 }
1517 
lib_pReturnThrustX(lua_State * L)1518 static int lib_pReturnThrustX(lua_State *L)
1519 {
1520 	angle_t angle;
1521 	fixed_t move;
1522 	if (lua_isnil(L, 1) || lua_isuserdata(L, 1))
1523 		lua_remove(L, 1); // ignore mobj as arg1
1524 	angle = luaL_checkangle(L, 1);
1525 	move = luaL_checkfixed(L, 2);
1526 	//HUDSAFE
1527 	lua_pushfixed(L, P_ReturnThrustX(NULL, angle, move));
1528 	return 1;
1529 }
1530 
lib_pReturnThrustY(lua_State * L)1531 static int lib_pReturnThrustY(lua_State *L)
1532 {
1533 	angle_t angle;
1534 	fixed_t move;
1535 	if (lua_isnil(L, 1) || lua_isuserdata(L, 1))
1536 		lua_remove(L, 1); // ignore mobj as arg1
1537 	angle = luaL_checkangle(L, 1);
1538 	move = luaL_checkfixed(L, 2);
1539 	//HUDSAFE
1540 	lua_pushfixed(L, P_ReturnThrustY(NULL, angle, move));
1541 	return 1;
1542 }
1543 
lib_pLookForEnemies(lua_State * L)1544 static int lib_pLookForEnemies(lua_State *L)
1545 {
1546 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1547 	boolean nonenemies = lua_opttrueboolean(L, 2);
1548 	boolean bullet = lua_optboolean(L, 3);
1549 	NOHUD
1550 	INLEVEL
1551 	if (!player)
1552 		return LUA_ErrInvalid(L, "player_t");
1553 	LUA_PushUserdata(L, P_LookForEnemies(player, nonenemies, bullet), META_MOBJ);
1554 	return 1;
1555 }
1556 
lib_pNukeEnemies(lua_State * L)1557 static int lib_pNukeEnemies(lua_State *L)
1558 {
1559 	mobj_t *inflictor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
1560 	mobj_t *source = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
1561 	fixed_t radius = luaL_checkfixed(L, 3);
1562 	NOHUD
1563 	INLEVEL
1564 	if (!inflictor || !source)
1565 		return LUA_ErrInvalid(L, "mobj_t");
1566 	P_NukeEnemies(inflictor, source, radius);
1567 	return 0;
1568 }
1569 
lib_pEarthquake(lua_State * L)1570 static int lib_pEarthquake(lua_State *L)
1571 {
1572 	mobj_t *inflictor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
1573 	mobj_t *source = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
1574 	fixed_t radius = luaL_checkfixed(L, 3);
1575 	NOHUD
1576 	INLEVEL
1577 	if (!inflictor || !source)
1578 		return LUA_ErrInvalid(L, "mobj_t");
1579 	P_Earthquake(inflictor, source, radius);
1580 	return 0;
1581 }
1582 
lib_pHomingAttack(lua_State * L)1583 static int lib_pHomingAttack(lua_State *L)
1584 {
1585 	mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
1586 	mobj_t *enemy = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
1587 	NOHUD
1588 	INLEVEL
1589 	if (!source || !enemy)
1590 		return LUA_ErrInvalid(L, "mobj_t");
1591 	lua_pushboolean(L, P_HomingAttack(source, enemy));
1592 	return 1;
1593 }
1594 
lib_pSuperReady(lua_State * L)1595 static int lib_pSuperReady(lua_State *L)
1596 {
1597 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1598 	//HUDSAFE
1599 	INLEVEL
1600 	if (!player)
1601 		return LUA_ErrInvalid(L, "player_t");
1602 	lua_pushboolean(L, P_SuperReady(player));
1603 	return 1;
1604 }
1605 
lib_pDoJump(lua_State * L)1606 static int lib_pDoJump(lua_State *L)
1607 {
1608 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1609 	boolean soundandstate = (boolean)lua_opttrueboolean(L, 2);
1610 	NOHUD
1611 	INLEVEL
1612 	if (!player)
1613 		return LUA_ErrInvalid(L, "player_t");
1614 	P_DoJump(player, soundandstate);
1615 	return 0;
1616 }
1617 
lib_pSpawnThokMobj(lua_State * L)1618 static int lib_pSpawnThokMobj(lua_State *L)
1619 {
1620 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1621 	NOHUD
1622 	INLEVEL
1623 	if (!player)
1624 		return LUA_ErrInvalid(L, "player_t");
1625 	P_SpawnThokMobj(player);
1626 	return 0;
1627 }
1628 
lib_pSpawnSpinMobj(lua_State * L)1629 static int lib_pSpawnSpinMobj(lua_State *L)
1630 {
1631 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1632 	mobjtype_t type = luaL_checkinteger(L, 2);
1633 	NOHUD
1634 	INLEVEL
1635 	if (!player)
1636 		return LUA_ErrInvalid(L, "player_t");
1637 	if (type >= NUMMOBJTYPES)
1638 		return luaL_error(L, "mobj type %d out of range (0 - %d)", type, NUMMOBJTYPES-1);
1639 	P_SpawnSpinMobj(player, type);
1640 	return 0;
1641 }
1642 
lib_pTelekinesis(lua_State * L)1643 static int lib_pTelekinesis(lua_State *L)
1644 {
1645 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1646 	fixed_t thrust = luaL_checkfixed(L, 2);
1647 	fixed_t range = luaL_checkfixed(L, 3);
1648 	NOHUD
1649 	INLEVEL
1650 	if (!player)
1651 		return LUA_ErrInvalid(L, "player_t");
1652 	P_Telekinesis(player, thrust, range);
1653 	return 0;
1654 }
1655 
lib_pSwitchShield(lua_State * L)1656 static int lib_pSwitchShield(lua_State *L)
1657 {
1658 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1659 	UINT16 shield = luaL_checkinteger(L, 2);
1660 	NOHUD
1661 	INLEVEL
1662 	if (!player)
1663 		return LUA_ErrInvalid(L, "player_t");
1664 	P_SwitchShield(player, shield);
1665 	return 0;
1666 }
1667 
lib_pPlayerCanEnterSpinGaps(lua_State * L)1668 static int lib_pPlayerCanEnterSpinGaps(lua_State *L)
1669 {
1670 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1671 	INLEVEL
1672 	if (!player)
1673 		return LUA_ErrInvalid(L, "player_t");
1674 	lua_pushboolean(L, P_PlayerCanEnterSpinGaps(player));
1675 	return 1;
1676 }
1677 
lib_pPlayerShouldUseSpinHeight(lua_State * L)1678 static int lib_pPlayerShouldUseSpinHeight(lua_State *L)
1679 {
1680 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1681 	INLEVEL
1682 	if (!player)
1683 		return LUA_ErrInvalid(L, "player_t");
1684 	lua_pushboolean(L, P_PlayerShouldUseSpinHeight(player));
1685 	return 1;
1686 }
1687 
1688 // P_MAP
1689 ///////////
1690 
lib_pCheckPosition(lua_State * L)1691 static int lib_pCheckPosition(lua_State *L)
1692 {
1693 	mobj_t *ptmthing = tmthing;
1694 	mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
1695 	fixed_t x = luaL_checkfixed(L, 2);
1696 	fixed_t y = luaL_checkfixed(L, 3);
1697 	NOHUD
1698 	INLEVEL
1699 	if (!thing)
1700 		return LUA_ErrInvalid(L, "mobj_t");
1701 	lua_pushboolean(L, P_CheckPosition(thing, x, y));
1702 	LUA_PushUserdata(L, tmthing, META_MOBJ);
1703 	P_SetTarget(&tmthing, ptmthing);
1704 	return 2;
1705 }
1706 
lib_pTryMove(lua_State * L)1707 static int lib_pTryMove(lua_State *L)
1708 {
1709 	mobj_t *ptmthing = tmthing;
1710 	mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
1711 	fixed_t x = luaL_checkfixed(L, 2);
1712 	fixed_t y = luaL_checkfixed(L, 3);
1713 	boolean allowdropoff = lua_optboolean(L, 4);
1714 	NOHUD
1715 	INLEVEL
1716 	if (!thing)
1717 		return LUA_ErrInvalid(L, "mobj_t");
1718 	lua_pushboolean(L, P_TryMove(thing, x, y, allowdropoff));
1719 	LUA_PushUserdata(L, tmthing, META_MOBJ);
1720 	P_SetTarget(&tmthing, ptmthing);
1721 	return 2;
1722 }
1723 
lib_pMove(lua_State * L)1724 static int lib_pMove(lua_State *L)
1725 {
1726 	mobj_t *ptmthing = tmthing;
1727 	mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
1728 	fixed_t speed = luaL_checkfixed(L, 2);
1729 	NOHUD
1730 	INLEVEL
1731 	if (!actor)
1732 		return LUA_ErrInvalid(L, "mobj_t");
1733 	lua_pushboolean(L, P_Move(actor, speed));
1734 	LUA_PushUserdata(L, tmthing, META_MOBJ);
1735 	P_SetTarget(&tmthing, ptmthing);
1736 	return 2;
1737 }
1738 
lib_pTeleportMove(lua_State * L)1739 static int lib_pTeleportMove(lua_State *L)
1740 {
1741 	mobj_t *ptmthing = tmthing;
1742 	mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
1743 	fixed_t x = luaL_checkfixed(L, 2);
1744 	fixed_t y = luaL_checkfixed(L, 3);
1745 	fixed_t z = luaL_checkfixed(L, 4);
1746 	NOHUD
1747 	INLEVEL
1748 	if (!thing)
1749 		return LUA_ErrInvalid(L, "mobj_t");
1750 	lua_pushboolean(L, P_TeleportMove(thing, x, y, z));
1751 	LUA_PushUserdata(L, tmthing, META_MOBJ);
1752 	P_SetTarget(&tmthing, ptmthing);
1753 	return 2;
1754 }
1755 
lib_pSlideMove(lua_State * L)1756 static int lib_pSlideMove(lua_State *L)
1757 {
1758 	mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
1759 	NOHUD
1760 	INLEVEL
1761 	if (!mo)
1762 		return LUA_ErrInvalid(L, "mobj_t");
1763 	P_SlideMove(mo);
1764 	return 0;
1765 }
1766 
lib_pBounceMove(lua_State * L)1767 static int lib_pBounceMove(lua_State *L)
1768 {
1769 	mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
1770 	NOHUD
1771 	INLEVEL
1772 	if (!mo)
1773 		return LUA_ErrInvalid(L, "mobj_t");
1774 	P_BounceMove(mo);
1775 	return 0;
1776 }
1777 
lib_pCheckSight(lua_State * L)1778 static int lib_pCheckSight(lua_State *L)
1779 {
1780 	mobj_t *t1 = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
1781 	mobj_t *t2 = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
1782 	//HUDSAFE?
1783 	INLEVEL
1784 	if (!t1 || !t2)
1785 		return LUA_ErrInvalid(L, "mobj_t");
1786 	lua_pushboolean(L, P_CheckSight(t1, t2));
1787 	return 1;
1788 }
1789 
lib_pCheckHoopPosition(lua_State * L)1790 static int lib_pCheckHoopPosition(lua_State *L)
1791 {
1792 	mobj_t *hoopthing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
1793 	fixed_t x = luaL_checkfixed(L, 2);
1794 	fixed_t y = luaL_checkfixed(L, 3);
1795 	fixed_t z = luaL_checkfixed(L, 4);
1796 	fixed_t radius = luaL_checkfixed(L, 5);
1797 	NOHUD
1798 	INLEVEL
1799 	if (!hoopthing)
1800 		return LUA_ErrInvalid(L, "mobj_t");
1801 	P_CheckHoopPosition(hoopthing, x, y, z, radius);
1802 	return 0;
1803 }
1804 
lib_pRadiusAttack(lua_State * L)1805 static int lib_pRadiusAttack(lua_State *L)
1806 {
1807 	mobj_t *spot = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
1808 	mobj_t *source = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
1809 	fixed_t damagedist = luaL_checkfixed(L, 3);
1810 	UINT8 damagetype = luaL_optinteger(L, 4, 0);
1811 	boolean sightcheck = lua_opttrueboolean(L, 5);
1812 	NOHUD
1813 	INLEVEL
1814 	if (!spot || !source)
1815 		return LUA_ErrInvalid(L, "mobj_t");
1816 	P_RadiusAttack(spot, source, damagedist, damagetype, sightcheck);
1817 	return 0;
1818 }
1819 
lib_pFloorzAtPos(lua_State * L)1820 static int lib_pFloorzAtPos(lua_State *L)
1821 {
1822 	fixed_t x = luaL_checkfixed(L, 1);
1823 	fixed_t y = luaL_checkfixed(L, 2);
1824 	fixed_t z = luaL_checkfixed(L, 3);
1825 	fixed_t height = luaL_checkfixed(L, 4);
1826 	//HUDSAFE
1827 	INLEVEL
1828 	lua_pushfixed(L, P_FloorzAtPos(x, y, z, height));
1829 	return 1;
1830 }
1831 
lib_pCeilingzAtPos(lua_State * L)1832 static int lib_pCeilingzAtPos(lua_State *L)
1833 {
1834 	fixed_t x = luaL_checkfixed(L, 1);
1835 	fixed_t y = luaL_checkfixed(L, 2);
1836 	fixed_t z = luaL_checkfixed(L, 3);
1837 	fixed_t height = luaL_checkfixed(L, 4);
1838 	//HUDSAFE
1839 	INLEVEL
1840 	lua_pushfixed(L, P_CeilingzAtPos(x, y, z, height));
1841 	return 1;
1842 }
1843 
lib_pDoSpring(lua_State * L)1844 static int lib_pDoSpring(lua_State *L)
1845 {
1846 	mobj_t *spring = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
1847 	mobj_t *object = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
1848 	NOHUD
1849 	INLEVEL
1850 	if (!spring || !object)
1851 		return LUA_ErrInvalid(L, "mobj_t");
1852 	lua_pushboolean(L, P_DoSpring(spring, object));
1853 	return 1;
1854 }
1855 
1856 // P_INTER
1857 ////////////
1858 
lib_pRemoveShield(lua_State * L)1859 static int lib_pRemoveShield(lua_State *L)
1860 {
1861 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1862 	NOHUD
1863 	INLEVEL
1864 	if (!player)
1865 		return LUA_ErrInvalid(L, "player_t");
1866 	P_RemoveShield(player);
1867 	return 0;
1868 }
1869 
lib_pDamageMobj(lua_State * L)1870 static int lib_pDamageMobj(lua_State *L)
1871 {
1872 	mobj_t *target = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)), *inflictor = NULL, *source = NULL;
1873 	INT32 damage;
1874 	UINT8 damagetype;
1875 	NOHUD
1876 	INLEVEL
1877 	if (!target)
1878 		return LUA_ErrInvalid(L, "mobj_t");
1879 	if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
1880 		inflictor = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
1881 	if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
1882 		source = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
1883 	damage = (INT32)luaL_optinteger(L, 4, 1);
1884 	damagetype = (UINT8)luaL_optinteger(L, 5, 0);
1885 	lua_pushboolean(L, P_DamageMobj(target, inflictor, source, damage, damagetype));
1886 	return 1;
1887 }
1888 
lib_pKillMobj(lua_State * L)1889 static int lib_pKillMobj(lua_State *L)
1890 {
1891 	mobj_t *target = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)), *inflictor = NULL, *source = NULL;
1892 	UINT8 damagetype;
1893 	NOHUD
1894 	INLEVEL
1895 	if (!target)
1896 		return LUA_ErrInvalid(L, "mobj_t");
1897 	if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
1898 		inflictor = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
1899 	if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
1900 		source = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
1901 	damagetype = (UINT8)luaL_optinteger(L, 4, 0);
1902 	P_KillMobj(target, inflictor, source, damagetype);
1903 	return 0;
1904 }
1905 
lib_pPlayerRingBurst(lua_State * L)1906 static int lib_pPlayerRingBurst(lua_State *L)
1907 {
1908 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1909 	INT32 num_rings = (INT32)luaL_optinteger(L, 2, -1);
1910 	NOHUD
1911 	INLEVEL
1912 	if (!player)
1913 		return LUA_ErrInvalid(L, "player_t");
1914 	if (num_rings == -1)
1915 		num_rings = player->rings;
1916 	P_PlayerRingBurst(player, num_rings);
1917 	return 0;
1918 }
1919 
lib_pPlayerWeaponPanelBurst(lua_State * L)1920 static int lib_pPlayerWeaponPanelBurst(lua_State *L)
1921 {
1922 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1923 	NOHUD
1924 	INLEVEL
1925 	if (!player)
1926 		return LUA_ErrInvalid(L, "player_t");
1927 	P_PlayerWeaponPanelBurst(player);
1928 	return 0;
1929 }
1930 
lib_pPlayerWeaponAmmoBurst(lua_State * L)1931 static int lib_pPlayerWeaponAmmoBurst(lua_State *L)
1932 {
1933 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1934 	NOHUD
1935 	INLEVEL
1936 	if (!player)
1937 		return LUA_ErrInvalid(L, "player_t");
1938 	P_PlayerWeaponAmmoBurst(player);
1939 	return 0;
1940 }
1941 
lib_pPlayerWeaponPanelOrAmmoBurst(lua_State * L)1942 static int lib_pPlayerWeaponPanelOrAmmoBurst(lua_State *L)
1943 {
1944 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1945 	NOHUD
1946 	INLEVEL
1947 	if (!player)
1948 		return LUA_ErrInvalid(L, "player_t");
1949 	P_PlayerWeaponPanelOrAmmoBurst(player);
1950 	return 0;
1951 }
1952 
lib_pPlayerEmeraldBurst(lua_State * L)1953 static int lib_pPlayerEmeraldBurst(lua_State *L)
1954 {
1955 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1956 	boolean toss = lua_optboolean(L, 2);
1957 	NOHUD
1958 	INLEVEL
1959 	if (!player)
1960 		return LUA_ErrInvalid(L, "player_t");
1961 	P_PlayerEmeraldBurst(player, toss);
1962 	return 0;
1963 }
1964 
lib_pPlayerFlagBurst(lua_State * L)1965 static int lib_pPlayerFlagBurst(lua_State *L)
1966 {
1967 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
1968 	boolean toss = lua_optboolean(L, 2);
1969 	NOHUD
1970 	INLEVEL
1971 	if (!player)
1972 		return LUA_ErrInvalid(L, "player_t");
1973 	P_PlayerFlagBurst(player, toss);
1974 	return 0;
1975 }
1976 
lib_pPlayRinglossSound(lua_State * L)1977 static int lib_pPlayRinglossSound(lua_State *L)
1978 {
1979 	mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
1980 	player_t *player = NULL;
1981 	NOHUD
1982 	INLEVEL
1983 	if (!source)
1984 		return LUA_ErrInvalid(L, "mobj_t");
1985 	if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
1986 	{
1987 		player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
1988 		if (!player)
1989 			return LUA_ErrInvalid(L, "player_t");
1990 	}
1991 	if (!player || P_IsLocalPlayer(player))
1992 		P_PlayRinglossSound(source);
1993 	return 0;
1994 }
1995 
lib_pPlayDeathSound(lua_State * L)1996 static int lib_pPlayDeathSound(lua_State *L)
1997 {
1998 	mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
1999 	player_t *player = NULL;
2000 	NOHUD
2001 	INLEVEL
2002 	if (!source)
2003 		return LUA_ErrInvalid(L, "mobj_t");
2004 	if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
2005 	{
2006 		player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
2007 		if (!player)
2008 			return LUA_ErrInvalid(L, "player_t");
2009 	}
2010 	if (!player || P_IsLocalPlayer(player))
2011 		P_PlayDeathSound(source);
2012 	return 0;
2013 }
2014 
lib_pPlayVictorySound(lua_State * L)2015 static int lib_pPlayVictorySound(lua_State *L)
2016 {
2017 	mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
2018 	player_t *player = NULL;
2019 	NOHUD
2020 	INLEVEL
2021 	if (!source)
2022 		return LUA_ErrInvalid(L, "mobj_t");
2023 	if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
2024 	{
2025 		player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
2026 		if (!player)
2027 			return LUA_ErrInvalid(L, "player_t");
2028 	}
2029 	if (!player || P_IsLocalPlayer(player))
2030 		P_PlayVictorySound(source);
2031 	return 0;
2032 }
2033 
lib_pPlayLivesJingle(lua_State * L)2034 static int lib_pPlayLivesJingle(lua_State *L)
2035 {
2036 	player_t *player = NULL;
2037 	//NOHUD
2038 	//INLEVEL
2039 	if (!lua_isnone(L, 1) && lua_isuserdata(L, 1))
2040 	{
2041 		player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
2042 		if (!player)
2043 			return LUA_ErrInvalid(L, "player_t");
2044 	}
2045 	P_PlayLivesJingle(player);
2046 	return 0;
2047 }
2048 
lib_pCanPickupItem(lua_State * L)2049 static int lib_pCanPickupItem(lua_State *L)
2050 {
2051 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
2052 	boolean weapon = lua_optboolean(L, 2);
2053 	//HUDSAFE
2054 	INLEVEL
2055 	if (!player)
2056 		return LUA_ErrInvalid(L, "player_t");
2057 	lua_pushboolean(L, P_CanPickupItem(player, weapon));
2058 	return 1;
2059 }
2060 
lib_pDoNightsScore(lua_State * L)2061 static int lib_pDoNightsScore(lua_State *L)
2062 {
2063 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
2064 	NOHUD
2065 	INLEVEL
2066 	if (!player)
2067 		return LUA_ErrInvalid(L, "player_t");
2068 	P_DoNightsScore(player);
2069 	return 0;
2070 }
2071 
lib_pDoMatchSuper(lua_State * L)2072 static int lib_pDoMatchSuper(lua_State *L)
2073 {
2074 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
2075 	NOHUD
2076 	INLEVEL
2077 	if (!player)
2078 		return LUA_ErrInvalid(L, "player_t");
2079 	P_DoMatchSuper(player);
2080 	return 0;
2081 }
2082 
2083 // P_SPEC
2084 ////////////
2085 
lib_pThrust(lua_State * L)2086 static int lib_pThrust(lua_State *L)
2087 {
2088 	mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
2089 	angle_t angle = luaL_checkangle(L, 2);
2090 	fixed_t move = luaL_checkfixed(L, 3);
2091 	NOHUD
2092 	INLEVEL
2093 	if (!mo)
2094 		return LUA_ErrInvalid(L, "mobj_t");
2095 	P_Thrust(mo, angle, move);
2096 	return 0;
2097 }
2098 
lib_pSetMobjStateNF(lua_State * L)2099 static int lib_pSetMobjStateNF(lua_State *L)
2100 {
2101 	mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
2102 	statenum_t state = luaL_checkinteger(L, 2);
2103 	NOHUD
2104 	INLEVEL
2105 	if (!mobj)
2106 		return LUA_ErrInvalid(L, "mobj_t");
2107 	if (state >= NUMSTATES)
2108 		return luaL_error(L, "state %d out of range (0 - %d)", state, NUMSTATES-1);
2109 	if (mobj->player && state == S_NULL)
2110 		return luaL_error(L, "Attempt to remove player mobj with S_NULL.");
2111 	lua_pushboolean(L, P_SetMobjStateNF(mobj, state));
2112 	return 1;
2113 }
2114 
lib_pDoSuperTransformation(lua_State * L)2115 static int lib_pDoSuperTransformation(lua_State *L)
2116 {
2117 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
2118 	boolean giverings = lua_optboolean(L, 2);
2119 	NOHUD
2120 	INLEVEL
2121 	if (!player)
2122 		return LUA_ErrInvalid(L, "player_t");
2123 	P_DoSuperTransformation(player, giverings);
2124 	return 0;
2125 }
2126 
lib_pExplodeMissile(lua_State * L)2127 static int lib_pExplodeMissile(lua_State *L)
2128 {
2129 	mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
2130 	NOHUD
2131 	INLEVEL
2132 	if (!mo)
2133 		return LUA_ErrInvalid(L, "mobj_t");
2134 	P_ExplodeMissile(mo);
2135 	return 0;
2136 }
2137 
lib_pPlayerTouchingSectorSpecial(lua_State * L)2138 static int lib_pPlayerTouchingSectorSpecial(lua_State *L)
2139 {
2140 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
2141 	INT32 section = (INT32)luaL_checkinteger(L, 2);
2142 	INT32 number = (INT32)luaL_checkinteger(L, 3);
2143 	//HUDSAFE
2144 	INLEVEL
2145 	if (!player)
2146 		return LUA_ErrInvalid(L, "player_t");
2147 	LUA_PushUserdata(L, P_PlayerTouchingSectorSpecial(player, section, number), META_SECTOR);
2148 	return 1;
2149 }
2150 
lib_pFindLowestFloorSurrounding(lua_State * L)2151 static int lib_pFindLowestFloorSurrounding(lua_State *L)
2152 {
2153 	sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
2154 	//HUDSAFE
2155 	INLEVEL
2156 	if (!sector)
2157 		return LUA_ErrInvalid(L, "sector_t");
2158 	lua_pushfixed(L, P_FindLowestFloorSurrounding(sector));
2159 	return 1;
2160 }
2161 
lib_pFindHighestFloorSurrounding(lua_State * L)2162 static int lib_pFindHighestFloorSurrounding(lua_State *L)
2163 {
2164 	sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
2165 	//HUDSAFE
2166 	INLEVEL
2167 	if (!sector)
2168 		return LUA_ErrInvalid(L, "sector_t");
2169 	lua_pushfixed(L, P_FindHighestFloorSurrounding(sector));
2170 	return 1;
2171 }
2172 
lib_pFindNextHighestFloor(lua_State * L)2173 static int lib_pFindNextHighestFloor(lua_State *L)
2174 {
2175 	sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
2176 	fixed_t currentheight;
2177 	//HUDSAFE
2178 	INLEVEL
2179 	if (!sector)
2180 		return LUA_ErrInvalid(L, "sector_t");
2181 	// defaults to floorheight of sector arg
2182 	currentheight = (fixed_t)luaL_optinteger(L, 2, sector->floorheight);
2183 	lua_pushfixed(L, P_FindNextHighestFloor(sector, currentheight));
2184 	return 1;
2185 }
2186 
lib_pFindNextLowestFloor(lua_State * L)2187 static int lib_pFindNextLowestFloor(lua_State *L)
2188 {
2189 	sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
2190 	fixed_t currentheight;
2191 	//HUDSAFE
2192 	INLEVEL
2193 	if (!sector)
2194 		return LUA_ErrInvalid(L, "sector_t");
2195 	// defaults to floorheight of sector arg
2196 	currentheight = (fixed_t)luaL_optinteger(L, 2, sector->floorheight);
2197 	lua_pushfixed(L, P_FindNextLowestFloor(sector, currentheight));
2198 	return 1;
2199 }
2200 
lib_pFindLowestCeilingSurrounding(lua_State * L)2201 static int lib_pFindLowestCeilingSurrounding(lua_State *L)
2202 {
2203 	sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
2204 	//HUDSAFE
2205 	INLEVEL
2206 	if (!sector)
2207 		return LUA_ErrInvalid(L, "sector_t");
2208 	lua_pushfixed(L, P_FindLowestCeilingSurrounding(sector));
2209 	return 1;
2210 }
2211 
lib_pFindHighestCeilingSurrounding(lua_State * L)2212 static int lib_pFindHighestCeilingSurrounding(lua_State *L)
2213 {
2214 	sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
2215 	//HUDSAFE
2216 	INLEVEL
2217 	if (!sector)
2218 		return LUA_ErrInvalid(L, "sector_t");
2219 	lua_pushfixed(L, P_FindHighestCeilingSurrounding(sector));
2220 	return 1;
2221 }
2222 
lib_pFindSpecialLineFromTag(lua_State * L)2223 static int lib_pFindSpecialLineFromTag(lua_State *L)
2224 {
2225 	INT16 special = (INT16)luaL_checkinteger(L, 1);
2226 	INT16 line = (INT16)luaL_checkinteger(L, 2);
2227 	INT32 start = (INT32)luaL_optinteger(L, 3, -1);
2228 	NOHUD
2229 	INLEVEL
2230 	lua_pushinteger(L, P_FindSpecialLineFromTag(special, line, start));
2231 	return 1;
2232 }
2233 
lib_pSwitchWeather(lua_State * L)2234 static int lib_pSwitchWeather(lua_State *L)
2235 {
2236 	INT32 weathernum = (INT32)luaL_checkinteger(L, 1);
2237 	player_t *user = NULL;
2238 	NOHUD
2239 	INLEVEL
2240 	if (!lua_isnone(L, 2) && lua_isuserdata(L, 2)) // if a player, setup weather for only the player, otherwise setup weather for all players
2241 		user = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
2242 	if (!user) // global
2243 		globalweather = weathernum;
2244 	if (!user || P_IsLocalPlayer(user))
2245 		P_SwitchWeather(weathernum);
2246 	return 0;
2247 }
2248 
lib_pLinedefExecute(lua_State * L)2249 static int lib_pLinedefExecute(lua_State *L)
2250 {
2251 	INT32 tag = (INT16)luaL_checkinteger(L, 1);
2252 	mobj_t *actor = NULL;
2253 	sector_t *caller = NULL;
2254 	NOHUD
2255 	INLEVEL
2256 	if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
2257 		actor = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
2258 	if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
2259 		caller = *((sector_t **)luaL_checkudata(L, 3, META_SECTOR));
2260 	P_LinedefExecute(tag, actor, caller);
2261 	return 0;
2262 }
2263 
lib_pSpawnLightningFlash(lua_State * L)2264 static int lib_pSpawnLightningFlash(lua_State *L)
2265 {
2266 	sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
2267 	NOHUD
2268 	INLEVEL
2269 	if (!sector)
2270 		return LUA_ErrInvalid(L, "sector_t");
2271 	P_SpawnLightningFlash(sector);
2272 	return 0;
2273 }
2274 
lib_pFadeLight(lua_State * L)2275 static int lib_pFadeLight(lua_State *L)
2276 {
2277 	INT16 tag = (INT16)luaL_checkinteger(L, 1);
2278 	INT32 destvalue = (INT32)luaL_checkinteger(L, 2);
2279 	INT32 speed = (INT32)luaL_checkinteger(L, 3);
2280 	boolean ticbased = lua_optboolean(L, 4);
2281 	boolean force = lua_optboolean(L, 5);
2282 	NOHUD
2283 	INLEVEL
2284 	P_FadeLight(tag, destvalue, speed, ticbased, force);
2285 	return 0;
2286 }
2287 
lib_pThingOnSpecial3DFloor(lua_State * L)2288 static int lib_pThingOnSpecial3DFloor(lua_State *L)
2289 {
2290 	mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
2291 	NOHUD
2292 	INLEVEL
2293 	if (!mo)
2294 		return LUA_ErrInvalid(L, "mobj_t");
2295 	LUA_PushUserdata(L, P_ThingOnSpecial3DFloor(mo), META_SECTOR);
2296 	return 1;
2297 }
2298 
lib_pIsFlagAtBase(lua_State * L)2299 static int lib_pIsFlagAtBase(lua_State *L)
2300 {
2301 	mobjtype_t flag = luaL_checkinteger(L, 1);
2302 	NOHUD
2303 	INLEVEL
2304 	if (flag >= NUMMOBJTYPES)
2305 		return luaL_error(L, "mobj type %d out of range (0 - %d)", flag, NUMMOBJTYPES-1);
2306 	lua_pushboolean(L, P_IsFlagAtBase(flag));
2307 	return 1;
2308 }
2309 
lib_pSetupLevelSky(lua_State * L)2310 static int lib_pSetupLevelSky(lua_State *L)
2311 {
2312 	INT32 skynum = (INT32)luaL_checkinteger(L, 1);
2313 	player_t *user = NULL;
2314 	NOHUD
2315 	INLEVEL
2316 	if (!lua_isnone(L, 2) && lua_isuserdata(L, 2)) // if a player, setup sky for only the player, otherwise setup sky for all players
2317 		user = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
2318 	if (!user) // global
2319 		P_SetupLevelSky(skynum, true);
2320 	else if (P_IsLocalPlayer(user))
2321 		P_SetupLevelSky(skynum, false);
2322 	return 0;
2323 }
2324 
2325 // Shhh, P_SetSkyboxMobj doesn't actually exist yet.
lib_pSetSkyboxMobj(lua_State * L)2326 static int lib_pSetSkyboxMobj(lua_State *L)
2327 {
2328 	int n = lua_gettop(L);
2329 	mobj_t *mo = NULL;
2330 	player_t *user = NULL;
2331 	int w = 0;
2332 
2333 	NOHUD
2334 	INLEVEL
2335 	if (!lua_isnil(L,1)) // nil leaves mo as NULL to remove the skybox rendering.
2336 	{
2337 		mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); // otherwise it is a skybox mobj.
2338 		if (!mo)
2339 			return LUA_ErrInvalid(L, "mobj_t");
2340 	}
2341 
2342 	if (n == 1)
2343 		;
2344 	else if (lua_isuserdata(L, 2))
2345 		user = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
2346 	else if (lua_isnil(L, 2))
2347 		w = 0;
2348 	else if (lua_isboolean(L, 2))
2349 	{
2350 		if (lua_toboolean(L, 2))
2351 			w = 1;
2352 		else
2353 			w = 0;
2354 	}
2355 	else
2356 		w = luaL_optinteger(L, 2, 0);
2357 
2358 	if (n > 2 && lua_isuserdata(L, 3))
2359 	{
2360 		user = *((player_t **)luaL_checkudata(L, 3, META_PLAYER));
2361 		if (!user)
2362 			return LUA_ErrInvalid(L, "player_t");
2363 	}
2364 
2365 	if (w > 1 || w < 0)
2366 		return luaL_error(L, "skybox mobj index %d is out of range for P_SetSkyboxMobj argument #2 (expected 0 or 1)", w);
2367 
2368 	if (!user || P_IsLocalPlayer(user))
2369 		skyboxmo[w] = mo;
2370 	return 0;
2371 }
2372 
2373 // Shhh, neither does P_StartQuake.
lib_pStartQuake(lua_State * L)2374 static int lib_pStartQuake(lua_State *L)
2375 {
2376 	fixed_t q_intensity = luaL_checkinteger(L, 1);
2377 	UINT16  q_time = (UINT16)luaL_checkinteger(L, 2);
2378 	static mappoint_t q_epicenter = {0,0,0};
2379 
2380 	NOHUD
2381 	INLEVEL
2382 
2383 	// While technically we don't support epicenter and radius,
2384 	// we get their values anyway if they exist.
2385 	// This way when support is added we won't have to change anything.
2386 	if (!lua_isnoneornil(L, 3))
2387 	{
2388 		luaL_checktype(L, 3, LUA_TTABLE);
2389 
2390 		lua_getfield(L, 3, "x");
2391 		if (lua_isnil(L, -1))
2392 		{
2393 			lua_pop(L, 1);
2394 			lua_rawgeti(L, 3, 1);
2395 		}
2396 		if (!lua_isnil(L, -1))
2397 			q_epicenter.x = luaL_checkinteger(L, -1);
2398 		else
2399 			q_epicenter.x = 0;
2400 		lua_pop(L, 1);
2401 
2402 		lua_getfield(L, 3, "y");
2403 		if (lua_isnil(L, -1))
2404 		{
2405 			lua_pop(L, 1);
2406 			lua_rawgeti(L, 3, 2);
2407 		}
2408 		if (!lua_isnil(L, -1))
2409 			q_epicenter.y = luaL_checkinteger(L, -1);
2410 		else
2411 			q_epicenter.y = 0;
2412 		lua_pop(L, 1);
2413 
2414 		lua_getfield(L, 3, "z");
2415 		if (lua_isnil(L, -1))
2416 		{
2417 			lua_pop(L, 1);
2418 			lua_rawgeti(L, 3, 3);
2419 		}
2420 		if (!lua_isnil(L, -1))
2421 			q_epicenter.z = luaL_checkinteger(L, -1);
2422 		else
2423 			q_epicenter.z = 0;
2424 		lua_pop(L, 1);
2425 
2426 		quake.epicenter = &q_epicenter;
2427 	}
2428 	else
2429 		quake.epicenter = NULL;
2430 	quake.radius = luaL_optinteger(L, 4, 512*FRACUNIT);
2431 
2432 	// These things are actually used in 2.1.
2433 	quake.intensity = q_intensity;
2434 	quake.time = q_time;
2435 	return 0;
2436 }
2437 
lib_evCrumbleChain(lua_State * L)2438 static int lib_evCrumbleChain(lua_State *L)
2439 {
2440 	sector_t *sec = NULL;
2441 	ffloor_t *rover = NULL;
2442 	NOHUD
2443 	INLEVEL
2444 	if (!lua_isnone(L, 2))
2445 	{
2446 		if (!lua_isnil(L, 1))
2447 		{
2448 			sec = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
2449 			if (!sec)
2450 				return LUA_ErrInvalid(L, "sector_t");
2451 		}
2452 		rover = *((ffloor_t **)luaL_checkudata(L, 2, META_FFLOOR));
2453 	}
2454 	else
2455 		rover = *((ffloor_t **)luaL_checkudata(L, 1, META_FFLOOR));
2456 	if (!rover)
2457 		return LUA_ErrInvalid(L, "ffloor_t");
2458 	EV_CrumbleChain(sec, rover);
2459 	return 0;
2460 }
2461 
lib_evStartCrumble(lua_State * L)2462 static int lib_evStartCrumble(lua_State *L)
2463 {
2464 	sector_t *sec = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
2465 	ffloor_t *rover = *((ffloor_t **)luaL_checkudata(L, 2, META_FFLOOR));
2466 	boolean floating = lua_optboolean(L, 3);
2467 	player_t *player = NULL;
2468 	fixed_t origalpha;
2469 	boolean crumblereturn = lua_optboolean(L, 6);
2470 	NOHUD
2471 	if (!sec)
2472 		return LUA_ErrInvalid(L, "sector_t");
2473 	if (!rover)
2474 		return LUA_ErrInvalid(L, "ffloor_t");
2475 	if (!lua_isnone(L, 4) && lua_isuserdata(L, 4))
2476 	{
2477 		player = *((player_t **)luaL_checkudata(L, 4, META_PLAYER));
2478 		if (!player)
2479 			return LUA_ErrInvalid(L, "player_t");
2480 	}
2481 	if (!lua_isnone(L,5))
2482 		origalpha = luaL_checkfixed(L, 5);
2483 	else
2484 		origalpha = rover->alpha;
2485 	lua_pushboolean(L, EV_StartCrumble(sec, rover, floating, player, origalpha, crumblereturn) != 0);
2486 	return 0;
2487 }
2488 
2489 // P_SLOPES
2490 ////////////
2491 
lib_pGetZAt(lua_State * L)2492 static int lib_pGetZAt(lua_State *L)
2493 {
2494 	fixed_t x = luaL_checkfixed(L, 2);
2495 	fixed_t y = luaL_checkfixed(L, 3);
2496 	//HUDSAFE
2497 	if (lua_isnil(L, 1))
2498 	{
2499 		fixed_t z = luaL_checkfixed(L, 4);
2500 		lua_pushfixed(L, P_GetZAt(NULL, x, y, z));
2501 	}
2502 	else
2503 	{
2504 		pslope_t *slope = *((pslope_t **)luaL_checkudata(L, 1, META_SLOPE));
2505 		lua_pushfixed(L, P_GetSlopeZAt(slope, x, y));
2506 	}
2507 
2508 	return 1;
2509 }
2510 
2511 // R_DEFS
2512 ////////////
2513 
lib_rPointToAngle(lua_State * L)2514 static int lib_rPointToAngle(lua_State *L)
2515 {
2516 	fixed_t x = luaL_checkfixed(L, 1);
2517 	fixed_t y = luaL_checkfixed(L, 2);
2518 	//HUDSAFE
2519 	lua_pushangle(L, R_PointToAngle(x, y));
2520 	return 1;
2521 }
2522 
lib_rPointToAngle2(lua_State * L)2523 static int lib_rPointToAngle2(lua_State *L)
2524 {
2525 	fixed_t px2 = luaL_checkfixed(L, 1);
2526 	fixed_t py2 = luaL_checkfixed(L, 2);
2527 	fixed_t px1 = luaL_checkfixed(L, 3);
2528 	fixed_t py1 = luaL_checkfixed(L, 4);
2529 	//HUDSAFE
2530 	lua_pushangle(L, R_PointToAngle2(px2, py2, px1, py1));
2531 	return 1;
2532 }
2533 
lib_rPointToDist(lua_State * L)2534 static int lib_rPointToDist(lua_State *L)
2535 {
2536 	fixed_t x = luaL_checkfixed(L, 1);
2537 	fixed_t y = luaL_checkfixed(L, 2);
2538 	//HUDSAFE
2539 	lua_pushfixed(L, R_PointToDist(x, y));
2540 	return 1;
2541 }
2542 
lib_rPointToDist2(lua_State * L)2543 static int lib_rPointToDist2(lua_State *L)
2544 {
2545 	fixed_t px2 = luaL_checkfixed(L, 1);
2546 	fixed_t py2 = luaL_checkfixed(L, 2);
2547 	fixed_t px1 = luaL_checkfixed(L, 3);
2548 	fixed_t py1 = luaL_checkfixed(L, 4);
2549 	//HUDSAFE
2550 	lua_pushfixed(L, R_PointToDist2(px2, py2, px1, py1));
2551 	return 1;
2552 }
2553 
lib_rPointInSubsector(lua_State * L)2554 static int lib_rPointInSubsector(lua_State *L)
2555 {
2556 	fixed_t x = luaL_checkfixed(L, 1);
2557 	fixed_t y = luaL_checkfixed(L, 2);
2558 	//HUDSAFE
2559 	INLEVEL
2560 	LUA_PushUserdata(L, R_PointInSubsector(x, y), META_SUBSECTOR);
2561 	return 1;
2562 }
2563 
lib_rPointInSubsectorOrNil(lua_State * L)2564 static int lib_rPointInSubsectorOrNil(lua_State *L)
2565 {
2566 	fixed_t x = luaL_checkfixed(L, 1);
2567 	fixed_t y = luaL_checkfixed(L, 2);
2568 	subsector_t *sub = R_PointInSubsectorOrNull(x, y);
2569 	//HUDSAFE
2570 	INLEVEL
2571 	if (sub)
2572 		LUA_PushUserdata(L, sub, META_SUBSECTOR);
2573 	else
2574 		lua_pushnil(L);
2575 	return 1;
2576 }
2577 
2578 // R_THINGS
2579 ////////////
2580 
lib_rChar2Frame(lua_State * L)2581 static int lib_rChar2Frame(lua_State *L)
2582 {
2583 	const char *p = luaL_checkstring(L, 1);
2584 	//HUDSAFE
2585 	lua_pushinteger(L, R_Char2Frame(*p)); // first character only
2586 	return 1;
2587 }
2588 
lib_rFrame2Char(lua_State * L)2589 static int lib_rFrame2Char(lua_State *L)
2590 {
2591 	UINT8 ch = (UINT8)luaL_checkinteger(L, 1);
2592 	char c[2] = "";
2593 	//HUDSAFE
2594 
2595 	c[0] = R_Frame2Char(ch);
2596 	c[1] = 0;
2597 
2598 	lua_pushstring(L, c);
2599 	lua_pushinteger(L, c[0]);
2600 	return 2;
2601 }
2602 
2603 // R_SetPlayerSkin technically doesn't exist either, although it's basically just SetPlayerSkin and SetPlayerSkinByNum handled in one place for convenience
lib_rSetPlayerSkin(lua_State * L)2604 static int lib_rSetPlayerSkin(lua_State *L)
2605 {
2606 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
2607 	INT32 i = -1, j = -1;
2608 	NOHUD
2609 	INLEVEL
2610 	if (!player)
2611 		return LUA_ErrInvalid(L, "player_t");
2612 
2613 	j = (player-players);
2614 
2615 	if (lua_isnoneornil(L, 2))
2616 		return luaL_error(L, "argument #2 not given (expected number or string)");
2617 	else if (lua_type(L, 2) == LUA_TNUMBER) // skin number
2618 	{
2619 		i = luaL_checkinteger(L, 2);
2620 		if (i < 0 || i >= numskins)
2621 			return luaL_error(L, "skin %d (argument #2) out of range (0 - %d)", i, numskins-1);
2622 	}
2623 	else // skin name
2624 	{
2625 		const char *skinname = luaL_checkstring(L, 2);
2626 		i = R_SkinAvailable(skinname);
2627 		if (i == -1)
2628 			return luaL_error(L, "skin %s (argument 2) is not loaded", skinname);
2629 	}
2630 
2631 	if (!R_SkinUsable(j, i))
2632 		return luaL_error(L, "skin %d (argument 2) not usable - check with R_SkinUsable(player_t, skin) first.", i);
2633 	SetPlayerSkinByNum(j, i);
2634 	return 0;
2635 }
2636 
lib_rSkinUsable(lua_State * L)2637 static int lib_rSkinUsable(lua_State *L)
2638 {
2639 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
2640 	INT32 i = -1, j = -1;
2641 	if (player)
2642 		j = (player-players);
2643 	else if (netgame || multiplayer)
2644 		return luaL_error(L, "player_t (argument #1) must be provided in multiplayer games");
2645 	if (lua_isnoneornil(L, 2))
2646 		return luaL_error(L, "argument #2 not given (expected number or string)");
2647 	else if (lua_type(L, 2) == LUA_TNUMBER) // skin number
2648 	{
2649 		i = luaL_checkinteger(L, 2);
2650 		if (i < 0 || i >= numskins)
2651 			return luaL_error(L, "skin %d (argument #2) out of range (0 - %d)", i, numskins-1);
2652 	}
2653 	else // skin name
2654 	{
2655 		const char *skinname = luaL_checkstring(L, 2);
2656 		i = R_SkinAvailable(skinname);
2657 		if (i == -1)
2658 			return luaL_error(L, "skin %s (argument 2) is not loaded", skinname);
2659 	}
2660 
2661 	lua_pushboolean(L, R_SkinUsable(j, i));
2662 	return 1;
2663 }
2664 
2665 // R_DATA
2666 ////////////
2667 
lib_rCheckTextureNumForName(lua_State * L)2668 static int lib_rCheckTextureNumForName(lua_State *L)
2669 {
2670 	const char *name = luaL_checkstring(L, 1);
2671 	//HUDSAFE
2672 	lua_pushinteger(L, R_CheckTextureNumForName(name));
2673 	return 1;
2674 }
2675 
lib_rTextureNumForName(lua_State * L)2676 static int lib_rTextureNumForName(lua_State *L)
2677 {
2678 	const char *name = luaL_checkstring(L, 1);
2679 	//HUDSAFE
2680 	lua_pushinteger(L, R_TextureNumForName(name));
2681 	return 1;
2682 }
2683 
2684 // R_DRAW
2685 ////////////
lib_rGetColorByName(lua_State * L)2686 static int lib_rGetColorByName(lua_State *L)
2687 {
2688 	const char* colorname = luaL_checkstring(L, 1);
2689 	//HUDSAFE
2690 	lua_pushinteger(L, R_GetColorByName(colorname));
2691 	return 1;
2692 }
2693 
lib_rGetSuperColorByName(lua_State * L)2694 static int lib_rGetSuperColorByName(lua_State *L)
2695 {
2696 	const char* colorname = luaL_checkstring(L, 1);
2697 	//HUDSAFE
2698 	lua_pushinteger(L, R_GetSuperColorByName(colorname));
2699 	return 1;
2700 }
2701 
2702 // Lua exclusive function, returns the name of a color from the SKINCOLOR_ constant.
2703 // SKINCOLOR_GREEN > "Green" for example
lib_rGetNameByColor(lua_State * L)2704 static int lib_rGetNameByColor(lua_State *L)
2705 {
2706 	UINT16 colornum = (UINT16)luaL_checkinteger(L, 1);
2707 	if (!colornum || colornum >= numskincolors)
2708 		return luaL_error(L, "skincolor %d out of range (1 - %d).", colornum, numskincolors-1);
2709 	lua_pushstring(L, skincolors[colornum].name);
2710 	return 1;
2711 }
2712 
2713 // S_SOUND
2714 ////////////
GetValidSoundOrigin(lua_State * L,void ** origin)2715 static int GetValidSoundOrigin(lua_State *L, void **origin)
2716 {
2717 	const char *type;
2718 
2719 	lua_settop(L, 1);
2720 	type = GetUserdataUType(L);
2721 
2722 	if (fasticmp(type, "mobj_t"))
2723 	{
2724 		*origin = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
2725 		if (!(*origin))
2726 			return LUA_ErrInvalid(L, "mobj_t");
2727 		return 1;
2728 	}
2729 	else if (fasticmp(type, "sector_t"))
2730 	{
2731 		*origin = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
2732 		if (!(*origin))
2733 			return LUA_ErrInvalid(L, "sector_t");
2734 
2735 		*origin = &((sector_t *)(*origin))->soundorg;
2736 		return 1;
2737 	}
2738 
2739 	return LUA_ErrInvalid(L, "mobj_t/sector_t");
2740 }
2741 
lib_sStartSound(lua_State * L)2742 static int lib_sStartSound(lua_State *L)
2743 {
2744 	void *origin = NULL;
2745 	sfxenum_t sound_id = luaL_checkinteger(L, 2);
2746 	player_t *player = NULL;
2747 	//NOHUD
2748 
2749 	if (sound_id >= NUMSFX)
2750 		return luaL_error(L, "sfx %d out of range (0 - %d)", sound_id, NUMSFX-1);
2751 
2752 	if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
2753 	{
2754 		player = *((player_t **)luaL_checkudata(L, 3, META_PLAYER));
2755 		if (!player)
2756 			return LUA_ErrInvalid(L, "player_t");
2757 	}
2758 	if (!lua_isnil(L, 1))
2759 		if (!GetValidSoundOrigin(L, &origin))
2760 			return 0;
2761 	if (!player || P_IsLocalPlayer(player))
2762 	{
2763 		if (hud_running || hook_cmd_running)
2764 			origin = NULL;	// HUD rendering and CMD building startsound shouldn't have an origin, just remove it instead of having a retarded error.
2765 
2766 		S_StartSound(origin, sound_id);
2767 	}
2768 	return 0;
2769 }
2770 
lib_sStartSoundAtVolume(lua_State * L)2771 static int lib_sStartSoundAtVolume(lua_State *L)
2772 {
2773 	void *origin = NULL;
2774 	sfxenum_t sound_id = luaL_checkinteger(L, 2);
2775 	INT32 volume = (INT32)luaL_checkinteger(L, 3);
2776 	player_t *player = NULL;
2777 	//NOHUD
2778 
2779 	if (sound_id >= NUMSFX)
2780 		return luaL_error(L, "sfx %d out of range (0 - %d)", sound_id, NUMSFX-1);
2781 	if (!lua_isnone(L, 4) && lua_isuserdata(L, 4))
2782 	{
2783 		player = *((player_t **)luaL_checkudata(L, 4, META_PLAYER));
2784 		if (!player)
2785 			return LUA_ErrInvalid(L, "player_t");
2786 	}
2787 	if (!lua_isnil(L, 1))
2788 		if (!GetValidSoundOrigin(L, &origin))
2789 			return LUA_ErrInvalid(L, "mobj_t/sector_t");
2790 
2791 	if (!player || P_IsLocalPlayer(player))
2792 		S_StartSoundAtVolume(origin, sound_id, volume);
2793 	return 0;
2794 }
2795 
lib_sStopSound(lua_State * L)2796 static int lib_sStopSound(lua_State *L)
2797 {
2798 	void *origin = NULL;
2799 	//NOHUD
2800 	if (!GetValidSoundOrigin(L, &origin))
2801 		return LUA_ErrInvalid(L, "mobj_t/sector_t");
2802 
2803 	S_StopSound(origin);
2804 	return 0;
2805 }
2806 
lib_sStopSoundByID(lua_State * L)2807 static int lib_sStopSoundByID(lua_State *L)
2808 {
2809 	void *origin = NULL;
2810 	sfxenum_t sound_id = luaL_checkinteger(L, 2);
2811 	//NOHUD
2812 
2813 	if (sound_id >= NUMSFX)
2814 		return luaL_error(L, "sfx %d out of range (0 - %d)", sound_id, NUMSFX-1);
2815 	if (!lua_isnil(L, 1))
2816 		if (!GetValidSoundOrigin(L, &origin))
2817 			return LUA_ErrInvalid(L, "mobj_t/sector_t");
2818 
2819 	S_StopSoundByID(origin, sound_id);
2820 	return 0;
2821 }
2822 
lib_sChangeMusic(lua_State * L)2823 static int lib_sChangeMusic(lua_State *L)
2824 {
2825 #ifdef MUSICSLOT_COMPATIBILITY
2826 	const char *music_name;
2827 	UINT32 music_num, position, prefadems, fadeinms;
2828 	char music_compat_name[7];
2829 
2830 	boolean looping;
2831 	player_t *player = NULL;
2832 	UINT16 music_flags = 0;
2833 	//NOHUD
2834 
2835 	if (lua_isnumber(L, 1))
2836 	{
2837 		music_num = (UINT32)luaL_checkinteger(L, 1);
2838 		music_flags = (UINT16)(music_num & 0x0000FFFF);
2839 		if (music_flags && music_flags <= 1035)
2840 			snprintf(music_compat_name, 7, "%sM", G_BuildMapName((INT32)music_flags));
2841 		else if (music_flags && music_flags <= 1050)
2842 			strncpy(music_compat_name, compat_special_music_slots[music_flags - 1036], 7);
2843 		else
2844 			music_compat_name[0] = 0; // becomes empty string
2845 		music_compat_name[6] = 0;
2846 		music_name = (const char *)&music_compat_name;
2847 		music_flags = 0;
2848 	}
2849 	else
2850 	{
2851 		music_num = 0;
2852 		music_name = luaL_checkstring(L, 1);
2853 	}
2854 
2855 	looping = (boolean)lua_opttrueboolean(L, 2);
2856 
2857 #else
2858 	const char *music_name = luaL_checkstring(L, 1);
2859 	boolean looping = (boolean)lua_opttrueboolean(L, 2);
2860 	player_t *player = NULL;
2861 	UINT16 music_flags = 0;
2862 	//NOHUD
2863 
2864 #endif
2865 	if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
2866 	{
2867 		player = *((player_t **)luaL_checkudata(L, 3, META_PLAYER));
2868 		if (!player)
2869 			return LUA_ErrInvalid(L, "player_t");
2870 	}
2871 
2872 #ifdef MUSICSLOT_COMPATIBILITY
2873 	if (music_num)
2874 		music_flags = (UINT16)((music_num & 0x7FFF0000) >> 16);
2875 	else
2876 #endif
2877 	music_flags = (UINT16)luaL_optinteger(L, 4, 0);
2878 
2879 	position = (UINT32)luaL_optinteger(L, 5, 0);
2880 	prefadems = (UINT32)luaL_optinteger(L, 6, 0);
2881 	fadeinms = (UINT32)luaL_optinteger(L, 7, 0);
2882 
2883 	if (!player || P_IsLocalPlayer(player))
2884 		S_ChangeMusicEx(music_name, music_flags, looping, position, prefadems, fadeinms);
2885 	return 0;
2886 }
2887 
lib_sSpeedMusic(lua_State * L)2888 static int lib_sSpeedMusic(lua_State *L)
2889 {
2890 	fixed_t fixedspeed = luaL_checkfixed(L, 1);
2891 	float speed = FIXED_TO_FLOAT(fixedspeed);
2892 	player_t *player = NULL;
2893 	//NOHUD
2894 	if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
2895 	{
2896 		player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
2897 		if (!player)
2898 			return LUA_ErrInvalid(L, "player_t");
2899 	}
2900 	if (!player || P_IsLocalPlayer(player))
2901 		S_SpeedMusic(speed);
2902 	return 0;
2903 }
2904 
lib_sStopMusic(lua_State * L)2905 static int lib_sStopMusic(lua_State *L)
2906 {
2907 	player_t *player = NULL;
2908 	//NOHUD
2909 	if (!lua_isnone(L, 1) && lua_isuserdata(L, 1))
2910 	{
2911 		player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
2912 		if (!player)
2913 			return LUA_ErrInvalid(L, "player_t");
2914 	}
2915 	if (!player || P_IsLocalPlayer(player))
2916 		S_StopMusic();
2917 	return 0;
2918 }
2919 
lib_sSetInternalMusicVolume(lua_State * L)2920 static int lib_sSetInternalMusicVolume(lua_State *L)
2921 {
2922 	UINT32 volume = (UINT32)luaL_checkinteger(L, 1);
2923 	player_t *player = NULL;
2924 	//NOHUD
2925 	if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
2926 	{
2927 		player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
2928 		if (!player)
2929 			return LUA_ErrInvalid(L, "player_t");
2930 	}
2931 	if (!player || P_IsLocalPlayer(player))
2932 	{
2933 		S_SetInternalMusicVolume(volume);
2934 		lua_pushboolean(L, true);
2935 	}
2936 	else
2937 		lua_pushnil(L);
2938 	return 1;
2939 }
2940 
lib_sStopFadingMusic(lua_State * L)2941 static int lib_sStopFadingMusic(lua_State *L)
2942 {
2943 	player_t *player = NULL;
2944 	//NOHUD
2945 	if (!lua_isnone(L, 1) && lua_isuserdata(L, 1))
2946 	{
2947 		player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
2948 		if (!player)
2949 			return LUA_ErrInvalid(L, "player_t");
2950 	}
2951 	if (!player || P_IsLocalPlayer(player))
2952 	{
2953 		S_StopFadingMusic();
2954 		lua_pushboolean(L, true);
2955 	}
2956 	else
2957 		lua_pushnil(L);
2958 	return 1;
2959 }
2960 
lib_sFadeMusic(lua_State * L)2961 static int lib_sFadeMusic(lua_State *L)
2962 {
2963 	UINT32 target_volume = (UINT32)luaL_checkinteger(L, 1);
2964 	UINT32 ms;
2965 	INT32 source_volume;
2966 	player_t *player = NULL;
2967 	//NOHUD
2968 	if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
2969 	{
2970 		player = *((player_t **)luaL_checkudata(L, 3, META_PLAYER));
2971 		if (!player)
2972 			return LUA_ErrInvalid(L, "player_t");
2973 		ms = (UINT32)luaL_checkinteger(L, 2);
2974 		source_volume = -1;
2975 	}
2976 	else if (!lua_isnone(L, 4) && lua_isuserdata(L, 4))
2977 	{
2978 		player = *((player_t **)luaL_checkudata(L, 4, META_PLAYER));
2979 		if (!player)
2980 			return LUA_ErrInvalid(L, "player_t");
2981 		source_volume = (INT32)luaL_checkinteger(L, 2);
2982 		ms = (UINT32)luaL_checkinteger(L, 3);
2983 	}
2984 	else if (luaL_optinteger(L, 3, INT32_MAX) == INT32_MAX)
2985 	{
2986 		ms = (UINT32)luaL_checkinteger(L, 2);
2987 		source_volume = -1;
2988 	}
2989 	else
2990 	{
2991 		source_volume = (INT32)luaL_checkinteger(L, 2);
2992 		ms = (UINT32)luaL_checkinteger(L, 3);
2993 	}
2994 
2995 	if (!player || P_IsLocalPlayer(player))
2996 		lua_pushboolean(L, S_FadeMusicFromVolume(target_volume, source_volume, ms));
2997 	else
2998 		lua_pushnil(L);
2999 	return 1;
3000 }
3001 
lib_sFadeOutStopMusic(lua_State * L)3002 static int lib_sFadeOutStopMusic(lua_State *L)
3003 {
3004 	UINT32 ms = (UINT32)luaL_checkinteger(L, 1);
3005 	player_t *player = NULL;
3006 	//NOHUD
3007 	if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
3008 	{
3009 		player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
3010 		if (!player)
3011 			return LUA_ErrInvalid(L, "player_t");
3012 	}
3013 	if (!player || P_IsLocalPlayer(player))
3014 	{
3015 		lua_pushboolean(L, S_FadeOutStopMusic(ms));
3016 	}
3017 	else
3018 		lua_pushnil(L);
3019 	return 1;
3020 }
3021 
lib_sGetMusicLength(lua_State * L)3022 static int lib_sGetMusicLength(lua_State *L)
3023 {
3024 	lua_pushinteger(L, S_GetMusicLength());
3025 	return 1;
3026 }
3027 
lib_sGetMusicPosition(lua_State * L)3028 static int lib_sGetMusicPosition(lua_State *L)
3029 {
3030 	lua_pushinteger(L, S_GetMusicPosition());
3031 	return 1;
3032 }
3033 
lib_sSetMusicPosition(lua_State * L)3034 static int lib_sSetMusicPosition(lua_State *L)
3035 {
3036 	UINT32 pos = (UINT32)luaL_checkinteger(L, 1);
3037 	lua_pushboolean(L, S_SetMusicPosition(pos));
3038 	return 1;
3039 }
3040 
lib_sOriginPlaying(lua_State * L)3041 static int lib_sOriginPlaying(lua_State *L)
3042 {
3043 	void *origin = NULL;
3044 	//NOHUD
3045 	INLEVEL
3046 	if (!GetValidSoundOrigin(L, &origin))
3047 		return LUA_ErrInvalid(L, "mobj_t/sector_t");
3048 
3049 	lua_pushboolean(L, S_OriginPlaying(origin));
3050 	return 1;
3051 }
3052 
lib_sIdPlaying(lua_State * L)3053 static int lib_sIdPlaying(lua_State *L)
3054 {
3055 	sfxenum_t id = luaL_checkinteger(L, 1);
3056 	//NOHUD
3057 	if (id >= NUMSFX)
3058 		return luaL_error(L, "sfx %d out of range (0 - %d)", id, NUMSFX-1);
3059 	lua_pushboolean(L, S_IdPlaying(id));
3060 	return 1;
3061 }
3062 
lib_sSoundPlaying(lua_State * L)3063 static int lib_sSoundPlaying(lua_State *L)
3064 {
3065 	void *origin = NULL;
3066 	sfxenum_t id = luaL_checkinteger(L, 2);
3067 	//NOHUD
3068 	INLEVEL
3069 	if (id >= NUMSFX)
3070 		return luaL_error(L, "sfx %d out of range (0 - %d)", id, NUMSFX-1);
3071 	if (!GetValidSoundOrigin(L, &origin))
3072 		return LUA_ErrInvalid(L, "mobj_t/sector_t");
3073 
3074 	lua_pushboolean(L, S_SoundPlaying(origin, id));
3075 	return 1;
3076 }
3077 
3078 // This doesn't really exist, but we're providing it as a handy netgame-safe wrapper for stuff that should be locally handled.
3079 
lib_sStartMusicCaption(lua_State * L)3080 static int lib_sStartMusicCaption(lua_State *L)
3081 {
3082 	player_t *player = NULL;
3083 	const char *caption = luaL_checkstring(L, 1);
3084 	UINT16 lifespan = (UINT16)luaL_checkinteger(L, 2);
3085 	//HUDSAFE
3086 	//INLEVEL
3087 
3088 	if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
3089 	{
3090 		player = *((player_t **)luaL_checkudata(L, 3, META_PLAYER));
3091 		if (!player)
3092 			return LUA_ErrInvalid(L, "player_t");
3093 	}
3094 
3095 	if (lifespan && (!player || P_IsLocalPlayer(player)))
3096 	{
3097 		strlcpy(S_sfx[sfx_None].caption, caption, sizeof(S_sfx[sfx_None].caption));
3098 		S_StartCaption(sfx_None, -1, lifespan);
3099 	}
3100 	return 0;
3101 }
3102 
lib_sMusicType(lua_State * L)3103 static int lib_sMusicType(lua_State *L)
3104 {
3105 	player_t *player = NULL;
3106 	NOHUD
3107 	if (!lua_isnone(L, 1) && lua_isuserdata(L, 1))
3108 	{
3109 		player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
3110 		if (!player)
3111 			return LUA_ErrInvalid(L, "player_t");
3112 	}
3113 	if (!player || P_IsLocalPlayer(player))
3114 		lua_pushinteger(L, S_MusicType());
3115 	else
3116 		lua_pushnil(L);
3117 	return 1;
3118 }
3119 
lib_sMusicPlaying(lua_State * L)3120 static int lib_sMusicPlaying(lua_State *L)
3121 {
3122 	player_t *player = NULL;
3123 	NOHUD
3124 	if (!lua_isnone(L, 1) && lua_isuserdata(L, 1))
3125 	{
3126 		player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
3127 		if (!player)
3128 			return LUA_ErrInvalid(L, "player_t");
3129 	}
3130 	if (!player || P_IsLocalPlayer(player))
3131 		lua_pushboolean(L, S_MusicPlaying());
3132 	else
3133 		lua_pushnil(L);
3134 	return 1;
3135 }
3136 
lib_sMusicPaused(lua_State * L)3137 static int lib_sMusicPaused(lua_State *L)
3138 {
3139 	player_t *player = NULL;
3140 	NOHUD
3141 	if (!lua_isnone(L, 1) && lua_isuserdata(L, 1))
3142 	{
3143 		player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
3144 		if (!player)
3145 			return LUA_ErrInvalid(L, "player_t");
3146 	}
3147 	if (!player || P_IsLocalPlayer(player))
3148 		lua_pushboolean(L, S_MusicPaused());
3149 	else
3150 		lua_pushnil(L);
3151 	return 1;
3152 }
3153 
lib_sMusicName(lua_State * L)3154 static int lib_sMusicName(lua_State *L)
3155 {
3156 	player_t *player = NULL;
3157 	NOHUD
3158 	if (!lua_isnone(L, 1) && lua_isuserdata(L, 1))
3159 	{
3160 		player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
3161 		if (!player)
3162 			return LUA_ErrInvalid(L, "player_t");
3163 	}
3164 	if (!player || P_IsLocalPlayer(player))
3165 		lua_pushstring(L, S_MusicName());
3166 	else
3167 		lua_pushnil(L);
3168 	return 1;
3169 }
3170 
lib_sMusicExists(lua_State * L)3171 static int lib_sMusicExists(lua_State *L)
3172 {
3173 	boolean checkMIDI = lua_opttrueboolean(L, 2);
3174 	boolean checkDigi = lua_opttrueboolean(L, 3);
3175 #ifdef MUSICSLOT_COMPATIBILITY
3176 	const char *music_name;
3177 	UINT32 music_num;
3178 	char music_compat_name[7];
3179 	UINT16 music_flags = 0;
3180 	NOHUD
3181 	if (lua_isnumber(L, 1))
3182 	{
3183 		music_num = (UINT32)luaL_checkinteger(L, 1);
3184 		music_flags = (UINT16)(music_num & 0x0000FFFF);
3185 		if (music_flags && music_flags <= 1035)
3186 			snprintf(music_compat_name, 7, "%sM", G_BuildMapName((INT32)music_flags));
3187 		else if (music_flags && music_flags <= 1050)
3188 			strncpy(music_compat_name, compat_special_music_slots[music_flags - 1036], 7);
3189 		else
3190 			music_compat_name[0] = 0; // becomes empty string
3191 		music_compat_name[6] = 0;
3192 		music_name = (const char *)&music_compat_name;
3193 	}
3194 	else
3195 	{
3196 		music_num = 0;
3197 		music_name = luaL_checkstring(L, 1);
3198 	}
3199 #else
3200 	const char *music_name = luaL_checkstring(L, 1);
3201 #endif
3202 	NOHUD
3203 	lua_pushboolean(L, S_MusicExists(music_name, checkMIDI, checkDigi));
3204 	return 1;
3205 }
3206 
lib_sSetMusicLoopPoint(lua_State * L)3207 static int lib_sSetMusicLoopPoint(lua_State *L)
3208 {
3209 	UINT32 looppoint = (UINT32)luaL_checkinteger(L, 1);
3210 	player_t *player = NULL;
3211 	NOHUD
3212 	if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
3213 	{
3214 		player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
3215 		if (!player)
3216 			return LUA_ErrInvalid(L, "player_t");
3217 	}
3218 	if (!player || P_IsLocalPlayer(player))
3219 		lua_pushboolean(L, S_SetMusicLoopPoint(looppoint));
3220 	else
3221 		lua_pushnil(L);
3222 	return 1;
3223 }
3224 
lib_sGetMusicLoopPoint(lua_State * L)3225 static int lib_sGetMusicLoopPoint(lua_State *L)
3226 {
3227 	player_t *player = NULL;
3228 	NOHUD
3229 	if (!lua_isnone(L, 1) && lua_isuserdata(L, 1))
3230 	{
3231 		player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
3232 		if (!player)
3233 			return LUA_ErrInvalid(L, "player_t");
3234 	}
3235 	if (!player || P_IsLocalPlayer(player))
3236 		lua_pushinteger(L, (int)S_GetMusicLoopPoint());
3237 	else
3238 		lua_pushnil(L);
3239 	return 1;
3240 }
3241 
lib_sPauseMusic(lua_State * L)3242 static int lib_sPauseMusic(lua_State *L)
3243 {
3244 	player_t *player = NULL;
3245 	NOHUD
3246 	if (!lua_isnone(L, 1) && lua_isuserdata(L, 1))
3247 	{
3248 		player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
3249 		if (!player)
3250 			return LUA_ErrInvalid(L, "player_t");
3251 	}
3252 	if (!player || P_IsLocalPlayer(player))
3253 	{
3254 		S_PauseAudio();
3255 		lua_pushboolean(L, true);
3256 	}
3257 	else
3258 		lua_pushnil(L);
3259 	return 1;
3260 }
3261 
lib_sResumeMusic(lua_State * L)3262 static int lib_sResumeMusic(lua_State *L)
3263 {
3264 	player_t *player = NULL;
3265 	NOHUD
3266 	if (!lua_isnone(L, 1) && lua_isuserdata(L, 1))
3267 	{
3268 		player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
3269 		if (!player)
3270 			return LUA_ErrInvalid(L, "player_t");
3271 	}
3272 	if (!player || P_IsLocalPlayer(player))
3273 	{
3274 		S_ResumeAudio();
3275 		lua_pushboolean(L, true);
3276 	}
3277 	else
3278 		lua_pushnil(L);
3279 	return 1;
3280 }
3281 
3282 // G_GAME
3283 ////////////
3284 
3285 // Copypasted from lib_cvRegisterVar :]
lib_gAddGametype(lua_State * L)3286 static int lib_gAddGametype(lua_State *L)
3287 {
3288 	const char *k;
3289 	lua_Integer i;
3290 
3291 	const char *gtname = NULL;
3292 	const char *gtconst = NULL;
3293 	const char *gtdescription = NULL;
3294 	INT16 newgtidx = 0;
3295 	UINT32 newgtrules = 0;
3296 	UINT32 newgttol = 0;
3297 	INT32 newgtpointlimit = 0;
3298 	INT32 newgttimelimit = 0;
3299 	UINT8 newgtleftcolor = 0;
3300 	UINT8 newgtrightcolor = 0;
3301 	INT16 newgtrankingstype = -1;
3302 	int newgtinttype = 0;
3303 
3304 	luaL_checktype(L, 1, LUA_TTABLE);
3305 	lua_settop(L, 1); // Clear out all other possible arguments, leaving only the first one.
3306 
3307 	if (!lua_lumploading)
3308 		return luaL_error(L, "This function cannot be called from within a hook or coroutine!");
3309 
3310 	// Ran out of gametype slots
3311 	if (gametypecount == NUMGAMETYPEFREESLOTS)
3312 		return luaL_error(L, "Ran out of free gametype slots!");
3313 
3314 #define FIELDERROR(f, e) luaL_error(L, "bad value for " LUA_QL(f) " in table passed to " LUA_QL("G_AddGametype") " (%s)", e);
3315 #define TYPEERROR(f, t) FIELDERROR(f, va("%s expected, got %s", lua_typename(L, t), luaL_typename(L, -1)))
3316 
3317 	lua_pushnil(L);
3318 	while (lua_next(L, 1)) {
3319 		// stack: gametype table, key/index, value
3320 		//               1            2        3
3321 		i = 0;
3322 		k = NULL;
3323 		if (lua_isnumber(L, 2))
3324 			i = lua_tointeger(L, 2);
3325 		else if (lua_isstring(L, 2))
3326 			k = lua_tostring(L, 2);
3327 
3328 		// Sorry, no gametype rules as key names.
3329 		if (i == 1 || (k && fasticmp(k, "name"))) {
3330 			if (!lua_isstring(L, 3))
3331 				TYPEERROR("name", LUA_TSTRING)
3332 			gtname = Z_StrDup(lua_tostring(L, 3));
3333 		} else if (i == 2 || (k && fasticmp(k, "identifier"))) {
3334 			if (!lua_isstring(L, 3))
3335 				TYPEERROR("identifier", LUA_TSTRING)
3336 			gtconst = Z_StrDup(lua_tostring(L, 3));
3337 		} else if (i == 3 || (k && fasticmp(k, "rules"))) {
3338 			if (!lua_isnumber(L, 3))
3339 				TYPEERROR("rules", LUA_TNUMBER)
3340 			newgtrules = (UINT32)lua_tointeger(L, 3);
3341 		} else if (i == 4 || (k && fasticmp(k, "typeoflevel"))) {
3342 			if (!lua_isnumber(L, 3))
3343 				TYPEERROR("typeoflevel", LUA_TNUMBER)
3344 			newgttol = (UINT32)lua_tointeger(L, 3);
3345 		} else if (i == 5 || (k && fasticmp(k, "rankingtype"))) {
3346 			if (!lua_isnumber(L, 3))
3347 				TYPEERROR("rankingtype", LUA_TNUMBER)
3348 			newgtrankingstype = (INT16)lua_tointeger(L, 3);
3349 		} else if (i == 6 || (k && fasticmp(k, "intermissiontype"))) {
3350 			if (!lua_isnumber(L, 3))
3351 				TYPEERROR("intermissiontype", LUA_TNUMBER)
3352 			newgtinttype = (int)lua_tointeger(L, 3);
3353 		} else if (i == 7 || (k && fasticmp(k, "defaultpointlimit"))) {
3354 			if (!lua_isnumber(L, 3))
3355 				TYPEERROR("defaultpointlimit", LUA_TNUMBER)
3356 			newgtpointlimit = (INT32)lua_tointeger(L, 3);
3357 		} else if (i == 8 || (k && fasticmp(k, "defaulttimelimit"))) {
3358 			if (!lua_isnumber(L, 3))
3359 				TYPEERROR("defaulttimelimit", LUA_TNUMBER)
3360 			newgttimelimit = (INT32)lua_tointeger(L, 3);
3361 		} else if (i == 9 || (k && fasticmp(k, "description"))) {
3362 			if (!lua_isstring(L, 3))
3363 				TYPEERROR("description", LUA_TSTRING)
3364 			gtdescription = Z_StrDup(lua_tostring(L, 3));
3365 		} else if (i == 10 || (k && fasticmp(k, "headerleftcolor"))) {
3366 			if (!lua_isnumber(L, 3))
3367 				TYPEERROR("headerleftcolor", LUA_TNUMBER)
3368 			newgtleftcolor = (UINT8)lua_tointeger(L, 3);
3369 		} else if (i == 11 || (k && fasticmp(k, "headerrightcolor"))) {
3370 			if (!lua_isnumber(L, 3))
3371 				TYPEERROR("headerrightcolor", LUA_TNUMBER)
3372 			newgtrightcolor = (UINT8)lua_tointeger(L, 3);
3373 		// Key name specified
3374 		} else if ((!i) && (k && fasticmp(k, "headercolor"))) {
3375 			if (!lua_isnumber(L, 3))
3376 				TYPEERROR("headercolor", LUA_TNUMBER)
3377 			newgtleftcolor = newgtrightcolor = (UINT8)lua_tointeger(L, 3);
3378 		}
3379 		lua_pop(L, 1);
3380 	}
3381 
3382 #undef FIELDERROR
3383 #undef TYPEERROR
3384 
3385 	// pop gametype table
3386 	lua_pop(L, 1);
3387 
3388 	// Set defaults
3389 	if (gtname == NULL)
3390 		gtname = Z_StrDup("Unnamed gametype");
3391 	if (gtdescription == NULL)
3392 		gtdescription = Z_StrDup("???");
3393 
3394 	// Add the new gametype
3395 	newgtidx = G_AddGametype(newgtrules);
3396 	G_AddGametypeTOL(newgtidx, newgttol);
3397 	G_SetGametypeDescription(newgtidx, NULL, newgtleftcolor, newgtrightcolor);
3398 	strncpy(gametypedesc[newgtidx].notes, gtdescription, 441);
3399 
3400 	// Not covered by G_AddGametype alone.
3401 	if (newgtrankingstype == -1)
3402 		newgtrankingstype = newgtidx;
3403 	gametyperankings[newgtidx] = newgtrankingstype;
3404 	intermissiontypes[newgtidx] = newgtinttype;
3405 	pointlimits[newgtidx] = newgtpointlimit;
3406 	timelimits[newgtidx] = newgttimelimit;
3407 
3408 	// Write the new gametype name.
3409 	Gametype_Names[newgtidx] = gtname;
3410 
3411 	// Write the constant name.
3412 	if (gtconst == NULL)
3413 		gtconst = gtname;
3414 	G_AddGametypeConstant(newgtidx, gtconst);
3415 
3416 	// Update gametype_cons_t accordingly.
3417 	G_UpdateGametypeSelections();
3418 
3419 	// done
3420 	CONS_Printf("Added gametype %s\n", Gametype_Names[newgtidx]);
3421 	return 0;
3422 }
3423 
Lcheckmapnumber(lua_State * L,int idx,const char * fun)3424 static int Lcheckmapnumber (lua_State *L, int idx, const char *fun)
3425 {
3426 	if (ISINLEVEL)
3427 		return luaL_optinteger(L, idx, gamemap);
3428 	else
3429 	{
3430 		if (lua_isnoneornil(L, idx))
3431 		{
3432 			return luaL_error(L,
3433 					"%s can only be used without a parameter while in a level.",
3434 					fun
3435 			);
3436 		}
3437 		else
3438 			return luaL_checkinteger(L, idx);
3439 	}
3440 }
3441 
lib_gBuildMapName(lua_State * L)3442 static int lib_gBuildMapName(lua_State *L)
3443 {
3444 	INT32 map = Lcheckmapnumber(L, 1, "G_BuildMapName");
3445 	//HUDSAFE
3446 	lua_pushstring(L, G_BuildMapName(map));
3447 	return 1;
3448 }
3449 
lib_gBuildMapTitle(lua_State * L)3450 static int lib_gBuildMapTitle(lua_State *L)
3451 {
3452 	INT32 map = Lcheckmapnumber(L, 1, "G_BuildMapTitle");
3453 	char *name;
3454 	if (map < 1 || map > NUMMAPS)
3455 	{
3456 		return luaL_error(L,
3457 				"map number %d out of range (1 - %d)",
3458 				map,
3459 				NUMMAPS
3460 		);
3461 	}
3462 	name = G_BuildMapTitle(map);
3463 	lua_pushstring(L, name);
3464 	Z_Free(name);
3465 	return 1;
3466 }
3467 
3468 static void
Lpushdim(lua_State * L,int c,struct searchdim * v)3469 Lpushdim (lua_State *L, int c, struct searchdim *v)
3470 {
3471 	int i;
3472 	lua_createtable(L, c, 0);/* I guess narr is numeric indices??? */
3473 	for (i = 0; i < c; ++i)
3474 	{
3475 		lua_createtable(L, 0, 2);/* and hashed indices (field)... */
3476 			lua_pushnumber(L, v[i].pos);
3477 			lua_setfield(L, -2, "pos");
3478 
3479 			lua_pushnumber(L, v[i].siz);
3480 			lua_setfield(L, -2, "siz");
3481 		lua_rawseti(L, -2, 1 + i);
3482 	}
3483 }
3484 
3485 /*
3486 I decided to make this return a table because userdata
3487 is scary and tables let the user set their own fields.
3488 */
3489 /*
3490 Returns:
3491 
3492 [1] => map number
3493 [2] => map title
3494 [3] => search frequency table
3495 
3496 The frequency table is unsorted. It has the following format:
3497 
3498 {
3499 	['mapnum'],
3500 
3501 	['matchd'] => matches in map title string
3502 	['keywhd'] => matches in map keywords
3503 
3504 	The above two tables have the following format:
3505 
3506 	{
3507 		['pos'] => offset from start of string
3508 		['siz'] => length of match
3509 	}...
3510 
3511 	['total'] => the total matches
3512 }...
3513 */
lib_gFindMap(lua_State * L)3514 static int lib_gFindMap(lua_State *L)
3515 {
3516 	const char *query = luaL_checkstring(L, 1);
3517 
3518 	INT32 map;
3519 	char *realname;
3520 	INT32 frc;
3521 	mapsearchfreq_t *frv;
3522 
3523 	INT32 i;
3524 
3525 	map = G_FindMap(query, &realname, &frv, &frc);
3526 
3527 	lua_settop(L, 0);
3528 
3529 	lua_pushnumber(L, map);
3530 	lua_pushstring(L, realname);
3531 
3532 	lua_createtable(L, frc, 0);
3533 	for (i = 0; i < frc; ++i)
3534 	{
3535 		lua_createtable(L, 0, 4);
3536 			lua_pushnumber(L, frv[i].mapnum);
3537 			lua_setfield(L, -2, "mapnum");
3538 
3539 			Lpushdim(L, frv[i].matchc, frv[i].matchd);
3540 			lua_setfield(L, -2, "matchd");
3541 
3542 			Lpushdim(L, frv[i].keywhc, frv[i].keywhd);
3543 			lua_setfield(L, -2, "keywhd");
3544 
3545 			lua_pushnumber(L, frv[i].total);
3546 			lua_setfield(L, -2, "total");
3547 		lua_rawseti(L, -2, 1 + i);
3548 	}
3549 
3550 	G_FreeMapSearch(frv, frc);
3551 	Z_Free(realname);
3552 
3553 	return 3;
3554 }
3555 
3556 /*
3557 Returns:
3558 
3559 [1] => map number
3560 [2] => map title
3561 */
lib_gFindMapByNameOrCode(lua_State * L)3562 static int lib_gFindMapByNameOrCode(lua_State *L)
3563 {
3564 	const char *query = luaL_checkstring(L, 1);
3565 	INT32 map;
3566 	char *realname;
3567 	map = G_FindMapByNameOrCode(query, &realname);
3568 	lua_pushnumber(L, map);
3569 	if (map)
3570 	{
3571 		lua_pushstring(L, realname);
3572 		Z_Free(realname);
3573 		return 2;
3574 	}
3575 	else
3576 		return 1;
3577 }
3578 
lib_gDoReborn(lua_State * L)3579 static int lib_gDoReborn(lua_State *L)
3580 {
3581 	INT32 playernum = luaL_checkinteger(L, 1);
3582 	NOHUD
3583 	INLEVEL
3584 	if (playernum >= MAXPLAYERS)
3585 		return luaL_error(L, "playernum %d out of range (0 - %d)", playernum, MAXPLAYERS-1);
3586 	G_DoReborn(playernum);
3587 	return 0;
3588 }
3589 
3590 // Another Lua function that doesn't actually exist!
3591 // Sets nextmapoverride & skipstats without instantly ending the level, for instances where other sources should be exiting the level, like normal signposts.
lib_gSetCustomExitVars(lua_State * L)3592 static int lib_gSetCustomExitVars(lua_State *L)
3593 {
3594 	int n = lua_gettop(L); // Num arguments
3595 	NOHUD
3596 	INLEVEL
3597 
3598 	// LUA EXTENSION: Custom exit like support
3599 	// Supported:
3600 	//	G_SetCustomExitVars();			[reset to defaults]
3601 	//	G_SetCustomExitVars(int)		[nextmap override only]
3602 	//	G_SetCustomExitVars(nil, int)	[skipstats only]
3603 	//	G_SetCustomExitVars(int, int)	[both of the above]
3604 
3605 	nextmapoverride = 0;
3606 	skipstats = 0;
3607 
3608 	if (n >= 1)
3609 	{
3610 		nextmapoverride = (INT16)luaL_optinteger(L, 1, 0);
3611 		skipstats = (INT16)luaL_optinteger(L, 2, 0);
3612 	}
3613 
3614 	return 0;
3615 }
3616 
lib_gEnoughPlayersFinished(lua_State * L)3617 static int lib_gEnoughPlayersFinished(lua_State *L)
3618 {
3619 	INLEVEL
3620 	lua_pushboolean(L, G_EnoughPlayersFinished());
3621 	return 1;
3622 }
3623 
lib_gExitLevel(lua_State * L)3624 static int lib_gExitLevel(lua_State *L)
3625 {
3626 	int n = lua_gettop(L); // Num arguments
3627 	NOHUD
3628 	// Moved this bit to G_SetCustomExitVars
3629 	if (n >= 1) // Don't run the reset to defaults option
3630 		lib_gSetCustomExitVars(L);
3631 	G_ExitLevel();
3632 	return 0;
3633 }
3634 
lib_gIsSpecialStage(lua_State * L)3635 static int lib_gIsSpecialStage(lua_State *L)
3636 {
3637 	INT32 mapnum = luaL_optinteger(L, 1, gamemap);
3638 	//HUDSAFE
3639 	INLEVEL
3640 	lua_pushboolean(L, G_IsSpecialStage(mapnum));
3641 	return 1;
3642 }
3643 
lib_gGametypeUsesLives(lua_State * L)3644 static int lib_gGametypeUsesLives(lua_State *L)
3645 {
3646 	//HUDSAFE
3647 	INLEVEL
3648 	lua_pushboolean(L, G_GametypeUsesLives());
3649 	return 1;
3650 }
3651 
lib_gGametypeUsesCoopLives(lua_State * L)3652 static int lib_gGametypeUsesCoopLives(lua_State *L)
3653 {
3654 	//HUDSAFE
3655 	INLEVEL
3656 	lua_pushboolean(L, G_GametypeUsesCoopLives());
3657 	return 1;
3658 }
3659 
lib_gGametypeUsesCoopStarposts(lua_State * L)3660 static int lib_gGametypeUsesCoopStarposts(lua_State *L)
3661 {
3662 	//HUDSAFE
3663 	INLEVEL
3664 	lua_pushboolean(L, G_GametypeUsesCoopStarposts());
3665 	return 1;
3666 }
3667 
lib_gGametypeHasTeams(lua_State * L)3668 static int lib_gGametypeHasTeams(lua_State *L)
3669 {
3670 	//HUDSAFE
3671 	INLEVEL
3672 	lua_pushboolean(L, G_GametypeHasTeams());
3673 	return 1;
3674 }
3675 
lib_gGametypeHasSpectators(lua_State * L)3676 static int lib_gGametypeHasSpectators(lua_State *L)
3677 {
3678 	//HUDSAFE
3679 	INLEVEL
3680 	lua_pushboolean(L, G_GametypeHasSpectators());
3681 	return 1;
3682 }
3683 
lib_gRingSlingerGametype(lua_State * L)3684 static int lib_gRingSlingerGametype(lua_State *L)
3685 {
3686 	//HUDSAFE
3687 	INLEVEL
3688 	lua_pushboolean(L, G_RingSlingerGametype());
3689 	return 1;
3690 }
3691 
lib_gPlatformGametype(lua_State * L)3692 static int lib_gPlatformGametype(lua_State *L)
3693 {
3694 	//HUDSAFE
3695 	INLEVEL
3696 	lua_pushboolean(L, G_PlatformGametype());
3697 	return 1;
3698 }
3699 
lib_gCoopGametype(lua_State * L)3700 static int lib_gCoopGametype(lua_State *L)
3701 {
3702 	//HUDSAFE
3703 	INLEVEL
3704 	lua_pushboolean(L, G_CoopGametype());
3705 	return 1;
3706 }
3707 
lib_gTagGametype(lua_State * L)3708 static int lib_gTagGametype(lua_State *L)
3709 {
3710 	//HUDSAFE
3711 	INLEVEL
3712 	lua_pushboolean(L, G_TagGametype());
3713 	return 1;
3714 }
3715 
lib_gCompetitionGametype(lua_State * L)3716 static int lib_gCompetitionGametype(lua_State *L)
3717 {
3718 	//HUDSAFE
3719 	INLEVEL
3720 	lua_pushboolean(L, G_CompetitionGametype());
3721 	return 1;
3722 }
3723 
lib_gTicsToHours(lua_State * L)3724 static int lib_gTicsToHours(lua_State *L)
3725 {
3726 	tic_t rtic = luaL_checkinteger(L, 1);
3727 	//HUDSAFE
3728 	lua_pushinteger(L, G_TicsToHours(rtic));
3729 	return 1;
3730 }
3731 
lib_gTicsToMinutes(lua_State * L)3732 static int lib_gTicsToMinutes(lua_State *L)
3733 {
3734 	tic_t rtic = luaL_checkinteger(L, 1);
3735 	boolean rfull = lua_optboolean(L, 2);
3736 	//HUDSAFE
3737 	lua_pushinteger(L, G_TicsToMinutes(rtic, rfull));
3738 	return 1;
3739 }
3740 
lib_gTicsToSeconds(lua_State * L)3741 static int lib_gTicsToSeconds(lua_State *L)
3742 {
3743 	tic_t rtic = luaL_checkinteger(L, 1);
3744 	//HUDSAFE
3745 	lua_pushinteger(L, G_TicsToSeconds(rtic));
3746 	return 1;
3747 }
3748 
lib_gTicsToCentiseconds(lua_State * L)3749 static int lib_gTicsToCentiseconds(lua_State *L)
3750 {
3751 	tic_t rtic = luaL_checkinteger(L, 1);
3752 	//HUDSAFE
3753 	lua_pushinteger(L, G_TicsToCentiseconds(rtic));
3754 	return 1;
3755 }
3756 
lib_gTicsToMilliseconds(lua_State * L)3757 static int lib_gTicsToMilliseconds(lua_State *L)
3758 {
3759 	tic_t rtic = luaL_checkinteger(L, 1);
3760 	//HUDSAFE
3761 	lua_pushinteger(L, G_TicsToMilliseconds(rtic));
3762 	return 1;
3763 }
3764 
3765 static luaL_Reg lib[] = {
3766 	{"print", lib_print},
3767 	{"chatprint", lib_chatprint},
3768 	{"chatprintf", lib_chatprintf},
3769 	{"userdataType", lib_userdataType},
3770 	{"registerMetatable", lib_registerMetatable},
3771 	{"userdataMetatable", lib_userdataMetatable},
3772 	{"IsPlayerAdmin", lib_isPlayerAdmin},
3773 	{"reserveLuabanks", lib_reserveLuabanks},
3774 
3775 	// m_menu
3776 	{"M_MoveColorAfter",lib_pMoveColorAfter},
3777 	{"M_MoveColorBefore",lib_pMoveColorBefore},
3778 	{"M_GetColorAfter",lib_pGetColorAfter},
3779 	{"M_GetColorBefore",lib_pGetColorBefore},
3780 
3781 	// m_random
3782 	{"P_RandomFixed",lib_pRandomFixed},
3783 	{"P_RandomByte",lib_pRandomByte},
3784 	{"P_RandomKey",lib_pRandomKey},
3785 	{"P_RandomRange",lib_pRandomRange},
3786 	{"P_SignedRandom",lib_pSignedRandom}, // MACRO
3787 	{"P_RandomChance",lib_pRandomChance}, // MACRO
3788 
3789 	// p_maputil
3790 	{"P_AproxDistance",lib_pAproxDistance},
3791 	{"P_ClosestPointOnLine",lib_pClosestPointOnLine},
3792 	{"P_PointOnLineSide",lib_pPointOnLineSide},
3793 
3794 	// p_enemy
3795 	{"P_CheckMeleeRange", lib_pCheckMeleeRange},
3796 	{"P_JetbCheckMeleeRange", lib_pJetbCheckMeleeRange},
3797 	{"P_FaceStabCheckMeleeRange", lib_pFaceStabCheckMeleeRange},
3798 	{"P_SkimCheckMeleeRange", lib_pSkimCheckMeleeRange},
3799 	{"P_CheckMissileRange", lib_pCheckMissileRange},
3800 	{"P_NewChaseDir", lib_pNewChaseDir},
3801 	{"P_LookForPlayers", lib_pLookForPlayers},
3802 
3803 	// p_mobj
3804 	// don't add P_SetMobjState or P_SetPlayerMobjState, use "mobj.state = S_NEWSTATE" instead.
3805 	{"P_SpawnMobj",lib_pSpawnMobj},
3806 	{"P_SpawnMobjFromMobj",lib_pSpawnMobjFromMobj},
3807 	{"P_RemoveMobj",lib_pRemoveMobj},
3808 	{"P_IsValidSprite2", lib_pIsValidSprite2},
3809 	{"P_SpawnLockOn", lib_pSpawnLockOn},
3810 	{"P_SpawnMissile",lib_pSpawnMissile},
3811 	{"P_SpawnXYZMissile",lib_pSpawnXYZMissile},
3812 	{"P_SpawnPointMissile",lib_pSpawnPointMissile},
3813 	{"P_SpawnAlteredDirectionMissile",lib_pSpawnAlteredDirectionMissile},
3814 	{"P_ColorTeamMissile",lib_pColorTeamMissile},
3815 	{"P_SPMAngle",lib_pSPMAngle},
3816 	{"P_SpawnPlayerMissile",lib_pSpawnPlayerMissile},
3817 	{"P_MobjFlip",lib_pMobjFlip},
3818 	{"P_GetMobjGravity",lib_pGetMobjGravity},
3819 	{"P_WeaponOrPanel",lib_pWeaponOrPanel},
3820 	{"P_FlashPal",lib_pFlashPal},
3821 	{"P_GetClosestAxis",lib_pGetClosestAxis},
3822 	{"P_SpawnParaloop",lib_pSpawnParaloop},
3823 	{"P_BossTargetPlayer",lib_pBossTargetPlayer},
3824 	{"P_SupermanLook4Players",lib_pSupermanLook4Players},
3825 	{"P_SetScale",lib_pSetScale},
3826 	{"P_InsideANonSolidFFloor",lib_pInsideANonSolidFFloor},
3827 	{"P_CheckDeathPitCollide",lib_pCheckDeathPitCollide},
3828 	{"P_CheckSolidLava",lib_pCheckSolidLava},
3829 	{"P_CanRunOnWater",lib_pCanRunOnWater},
3830 	{"P_MaceRotate",lib_pMaceRotate},
3831 	{"P_CreateFloorSpriteSlope",lib_pCreateFloorSpriteSlope},
3832 	{"P_RemoveFloorSpriteSlope",lib_pRemoveFloorSpriteSlope},
3833 	{"P_RailThinker",lib_pRailThinker},
3834 	{"P_XYMovement",lib_pXYMovement},
3835 	{"P_RingXYMovement",lib_pRingXYMovement},
3836 	{"P_SceneryXYMovement",lib_pSceneryXYMovement},
3837 	{"P_ZMovement",lib_pZMovement},
3838 	{"P_RingZMovement",lib_pRingZMovement},
3839 	{"P_SceneryZMovement",lib_pSceneryZMovement},
3840 	{"P_PlayerZMovement",lib_pPlayerZMovement},
3841 
3842 	// p_user
3843 	{"P_GetPlayerHeight",lib_pGetPlayerHeight},
3844 	{"P_GetPlayerSpinHeight",lib_pGetPlayerSpinHeight},
3845 	{"P_GetPlayerControlDirection",lib_pGetPlayerControlDirection},
3846 	{"P_AddPlayerScore",lib_pAddPlayerScore},
3847 	{"P_StealPlayerScore",lib_pStealPlayerScore},
3848 	{"P_GetJumpFlags",lib_pGetJumpFlags},
3849 	{"P_PlayerInPain",lib_pPlayerInPain},
3850 	{"P_DoPlayerPain",lib_pDoPlayerPain},
3851 	{"P_ResetPlayer",lib_pResetPlayer},
3852 	{"P_PlayerCanDamage",lib_pPlayerCanDamage},
3853 	{"P_PlayerFullbright",lib_pPlayerFullbright},
3854 	{"P_IsObjectInGoop",lib_pIsObjectInGoop},
3855 	{"P_IsObjectOnGround",lib_pIsObjectOnGround},
3856 	{"P_InSpaceSector",lib_pInSpaceSector},
3857 	{"P_InQuicksand",lib_pInQuicksand},
3858 	{"P_SetObjectMomZ",lib_pSetObjectMomZ},
3859 	{"P_PlayJingle",lib_pPlayJingle},
3860 	{"P_PlayJingleMusic",lib_pPlayJingleMusic},
3861 	{"P_RestoreMusic",lib_pRestoreMusic},
3862 	{"P_SpawnShieldOrb",lib_pSpawnShieldOrb},
3863 	{"P_SpawnGhostMobj",lib_pSpawnGhostMobj},
3864 	{"P_GivePlayerRings",lib_pGivePlayerRings},
3865 	{"P_GivePlayerLives",lib_pGivePlayerLives},
3866 	{"P_GiveCoopLives",lib_pGiveCoopLives},
3867 	{"P_ResetScore",lib_pResetScore},
3868 	{"P_DoJumpShield",lib_pDoJumpShield},
3869 	{"P_DoBubbleBounce",lib_pDoBubbleBounce},
3870 	{"P_BlackOw",lib_pBlackOw},
3871 	{"P_ElementalFire",lib_pElementalFire},
3872 	{"P_SpawnSkidDust", lib_pSpawnSkidDust},
3873 	{"P_MovePlayer",lib_pMovePlayer},
3874 	{"P_DoPlayerFinish",lib_pDoPlayerFinish},
3875 	{"P_DoPlayerExit",lib_pDoPlayerExit},
3876 	{"P_InstaThrust",lib_pInstaThrust},
3877 	{"P_ReturnThrustX",lib_pReturnThrustX},
3878 	{"P_ReturnThrustY",lib_pReturnThrustY},
3879 	{"P_LookForEnemies",lib_pLookForEnemies},
3880 	{"P_NukeEnemies",lib_pNukeEnemies},
3881 	{"P_Earthquake",lib_pEarthquake},
3882 	{"P_HomingAttack",lib_pHomingAttack},
3883 	{"P_SuperReady",lib_pSuperReady},
3884 	{"P_DoJump",lib_pDoJump},
3885 	{"P_SpawnThokMobj",lib_pSpawnThokMobj},
3886 	{"P_SpawnSpinMobj",lib_pSpawnSpinMobj},
3887 	{"P_Telekinesis",lib_pTelekinesis},
3888 	{"P_SwitchShield",lib_pSwitchShield},
3889 	{"P_PlayerCanEnterSpinGaps",lib_pPlayerCanEnterSpinGaps},
3890 	{"P_PlayerShouldUseSpinHeight",lib_pPlayerShouldUseSpinHeight},
3891 
3892 	// p_map
3893 	{"P_CheckPosition",lib_pCheckPosition},
3894 	{"P_TryMove",lib_pTryMove},
3895 	{"P_Move",lib_pMove},
3896 	{"P_TeleportMove",lib_pTeleportMove},
3897 	{"P_SlideMove",lib_pSlideMove},
3898 	{"P_BounceMove",lib_pBounceMove},
3899 	{"P_CheckSight", lib_pCheckSight},
3900 	{"P_CheckHoopPosition",lib_pCheckHoopPosition},
3901 	{"P_RadiusAttack",lib_pRadiusAttack},
3902 	{"P_FloorzAtPos",lib_pFloorzAtPos},
3903 	{"P_CeilingzAtPos",lib_pCeilingzAtPos},
3904 	{"P_DoSpring",lib_pDoSpring},
3905 
3906 	// p_inter
3907 	{"P_RemoveShield",lib_pRemoveShield},
3908 	{"P_DamageMobj",lib_pDamageMobj},
3909 	{"P_KillMobj",lib_pKillMobj},
3910 	{"P_PlayerRingBurst",lib_pPlayerRingBurst},
3911 	{"P_PlayerWeaponPanelBurst",lib_pPlayerWeaponPanelBurst},
3912 	{"P_PlayerWeaponAmmoBurst",lib_pPlayerWeaponAmmoBurst},
3913 	{"P_PlayerWeaponPanelOrAmmoBurst", lib_pPlayerWeaponPanelOrAmmoBurst},
3914 	{"P_PlayerEmeraldBurst",lib_pPlayerEmeraldBurst},
3915 	{"P_PlayerFlagBurst",lib_pPlayerFlagBurst},
3916 	{"P_PlayRinglossSound",lib_pPlayRinglossSound},
3917 	{"P_PlayDeathSound",lib_pPlayDeathSound},
3918 	{"P_PlayVictorySound",lib_pPlayVictorySound},
3919 	{"P_PlayLivesJingle",lib_pPlayLivesJingle},
3920 	{"P_CanPickupItem",lib_pCanPickupItem},
3921 	{"P_DoNightsScore",lib_pDoNightsScore},
3922 	{"P_DoMatchSuper",lib_pDoMatchSuper},
3923 
3924 	// p_spec
3925 	{"P_Thrust",lib_pThrust},
3926 	{"P_SetMobjStateNF",lib_pSetMobjStateNF},
3927 	{"P_DoSuperTransformation",lib_pDoSuperTransformation},
3928 	{"P_ExplodeMissile",lib_pExplodeMissile},
3929 	{"P_PlayerTouchingSectorSpecial",lib_pPlayerTouchingSectorSpecial},
3930 	{"P_FindLowestFloorSurrounding",lib_pFindLowestFloorSurrounding},
3931 	{"P_FindHighestFloorSurrounding",lib_pFindHighestFloorSurrounding},
3932 	{"P_FindNextHighestFloor",lib_pFindNextHighestFloor},
3933 	{"P_FindNextLowestFloor",lib_pFindNextLowestFloor},
3934 	{"P_FindLowestCeilingSurrounding",lib_pFindLowestCeilingSurrounding},
3935 	{"P_FindHighestCeilingSurrounding",lib_pFindHighestCeilingSurrounding},
3936 	{"P_FindSpecialLineFromTag",lib_pFindSpecialLineFromTag},
3937 	{"P_SwitchWeather",lib_pSwitchWeather},
3938 	{"P_LinedefExecute",lib_pLinedefExecute},
3939 	{"P_SpawnLightningFlash",lib_pSpawnLightningFlash},
3940 	{"P_FadeLight",lib_pFadeLight},
3941 	{"P_ThingOnSpecial3DFloor",lib_pThingOnSpecial3DFloor},
3942 	{"P_IsFlagAtBase",lib_pIsFlagAtBase},
3943 	{"P_SetupLevelSky",lib_pSetupLevelSky},
3944 	{"P_SetSkyboxMobj",lib_pSetSkyboxMobj},
3945 	{"P_StartQuake",lib_pStartQuake},
3946 	{"EV_CrumbleChain",lib_evCrumbleChain},
3947 	{"EV_StartCrumble",lib_evStartCrumble},
3948 
3949 	// p_slopes
3950 	{"P_GetZAt",lib_pGetZAt},
3951 
3952 	// r_defs
3953 	{"R_PointToAngle",lib_rPointToAngle},
3954 	{"R_PointToAngle2",lib_rPointToAngle2},
3955 	{"R_PointToDist",lib_rPointToDist},
3956 	{"R_PointToDist2",lib_rPointToDist2},
3957 	{"R_PointInSubsector",lib_rPointInSubsector},
3958 	{"R_PointInSubsectorOrNil",lib_rPointInSubsectorOrNil},
3959 
3960 	// r_things (sprite)
3961 	{"R_Char2Frame",lib_rChar2Frame},
3962 	{"R_Frame2Char",lib_rFrame2Char},
3963 	{"R_SetPlayerSkin",lib_rSetPlayerSkin},
3964 	{"R_SkinUsable",lib_rSkinUsable},
3965 
3966 	// r_data
3967 	{"R_CheckTextureNumForName",lib_rCheckTextureNumForName},
3968 	{"R_TextureNumForName",lib_rTextureNumForName},
3969 
3970 	// r_draw
3971 	{"R_GetColorByName", lib_rGetColorByName},
3972 	{"R_GetSuperColorByName", lib_rGetSuperColorByName},
3973 	{"R_GetNameByColor", lib_rGetNameByColor},
3974 
3975 	// s_sound
3976 	{"S_StartSound",lib_sStartSound},
3977 	{"S_StartSoundAtVolume",lib_sStartSoundAtVolume},
3978 	{"S_StopSound",lib_sStopSound},
3979 	{"S_StopSoundByID",lib_sStopSoundByID},
3980 	{"S_ChangeMusic",lib_sChangeMusic},
3981 	{"S_SpeedMusic",lib_sSpeedMusic},
3982 	{"S_StopMusic",lib_sStopMusic},
3983 	{"S_SetInternalMusicVolume", lib_sSetInternalMusicVolume},
3984 	{"S_StopFadingMusic",lib_sStopFadingMusic},
3985 	{"S_FadeMusic",lib_sFadeMusic},
3986 	{"S_FadeOutStopMusic",lib_sFadeOutStopMusic},
3987 	{"S_GetMusicLength",lib_sGetMusicLength},
3988 	{"S_GetMusicPosition",lib_sGetMusicPosition},
3989 	{"S_SetMusicPosition",lib_sSetMusicPosition},
3990 	{"S_OriginPlaying",lib_sOriginPlaying},
3991 	{"S_IdPlaying",lib_sIdPlaying},
3992 	{"S_SoundPlaying",lib_sSoundPlaying},
3993 	{"S_StartMusicCaption", lib_sStartMusicCaption},
3994 	{"S_MusicType",lib_sMusicType},
3995 	{"S_MusicPlaying",lib_sMusicPlaying},
3996 	{"S_MusicPaused",lib_sMusicPaused},
3997 	{"S_MusicName",lib_sMusicName},
3998 	{"S_MusicExists",lib_sMusicExists},
3999 	{"S_SetMusicLoopPoint",lib_sSetMusicLoopPoint},
4000 	{"S_GetMusicLoopPoint",lib_sGetMusicLoopPoint},
4001 	{"S_PauseMusic",lib_sPauseMusic},
4002 	{"S_ResumeMusic", lib_sResumeMusic},
4003 
4004 	// g_game
4005 	{"G_AddGametype", lib_gAddGametype},
4006 	{"G_BuildMapName",lib_gBuildMapName},
4007 	{"G_BuildMapTitle",lib_gBuildMapTitle},
4008 	{"G_FindMap",lib_gFindMap},
4009 	{"G_FindMapByNameOrCode",lib_gFindMapByNameOrCode},
4010 	{"G_DoReborn",lib_gDoReborn},
4011 	{"G_SetCustomExitVars",lib_gSetCustomExitVars},
4012 	{"G_EnoughPlayersFinished",lib_gEnoughPlayersFinished},
4013 	{"G_ExitLevel",lib_gExitLevel},
4014 	{"G_IsSpecialStage",lib_gIsSpecialStage},
4015 	{"G_GametypeUsesLives",lib_gGametypeUsesLives},
4016 	{"G_GametypeUsesCoopLives",lib_gGametypeUsesCoopLives},
4017 	{"G_GametypeUsesCoopStarposts",lib_gGametypeUsesCoopStarposts},
4018 	{"G_GametypeHasTeams",lib_gGametypeHasTeams},
4019 	{"G_GametypeHasSpectators",lib_gGametypeHasSpectators},
4020 	{"G_RingSlingerGametype",lib_gRingSlingerGametype},
4021 	{"G_PlatformGametype",lib_gPlatformGametype},
4022 	{"G_CoopGametype",lib_gCoopGametype},
4023 	{"G_TagGametype",lib_gTagGametype},
4024 	{"G_CompetitionGametype",lib_gCompetitionGametype},
4025 	{"G_TicsToHours",lib_gTicsToHours},
4026 	{"G_TicsToMinutes",lib_gTicsToMinutes},
4027 	{"G_TicsToSeconds",lib_gTicsToSeconds},
4028 	{"G_TicsToCentiseconds",lib_gTicsToCentiseconds},
4029 	{"G_TicsToMilliseconds",lib_gTicsToMilliseconds},
4030 
4031 	{NULL, NULL}
4032 };
4033 
LUA_BaseLib(lua_State * L)4034 int LUA_BaseLib(lua_State *L)
4035 {
4036 	// Set metatable for string
4037 	lua_pushliteral(L, "");  // dummy string
4038 	lua_getmetatable(L, -1);  // get string metatable
4039 	lua_pushcfunction(L,lib_concat); // push concatination function
4040 	lua_setfield(L,-2,"__add"); // ... store it as mathematical addition
4041 	lua_pop(L, 2); // pop metatable and dummy string
4042 
4043 	lua_newtable(L);
4044 	lua_setfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS);
4045 
4046 	// Set global functions
4047 	lua_pushvalue(L, LUA_GLOBALSINDEX);
4048 	luaL_register(L, NULL, lib);
4049 	return 0;
4050 }
4051