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_maplib.c
11 /// \brief game map library for Lua scripting
12 
13 #include "doomdef.h"
14 #include "r_state.h"
15 #include "p_local.h"
16 #include "p_setup.h"
17 #include "z_zone.h"
18 #include "p_slopes.h"
19 #include "p_polyobj.h"
20 #include "r_main.h"
21 
22 #include "lua_script.h"
23 #include "lua_libs.h"
24 #include "lua_hud.h" // hud_running errors
25 #include "lua_hook.h" // hook_cmd_running errors
26 
27 #include "dehacked.h"
28 #include "fastcmp.h"
29 #include "doomstat.h"
30 
31 enum sector_e {
32 	sector_valid = 0,
33 	sector_floorheight,
34 	sector_ceilingheight,
35 	sector_floorpic,
36 	sector_ceilingpic,
37 	sector_lightlevel,
38 	sector_special,
39 	sector_tag,
40 	sector_taglist,
41 	sector_thinglist,
42 	sector_heightsec,
43 	sector_camsec,
44 	sector_lines,
45 	sector_ffloors,
46 	sector_fslope,
47 	sector_cslope
48 };
49 
50 static const char *const sector_opt[] = {
51 	"valid",
52 	"floorheight",
53 	"ceilingheight",
54 	"floorpic",
55 	"ceilingpic",
56 	"lightlevel",
57 	"special",
58 	"tag",
59 	"taglist",
60 	"thinglist",
61 	"heightsec",
62 	"camsec",
63 	"lines",
64 	"ffloors",
65 	"f_slope",
66 	"c_slope",
67 	NULL};
68 
69 enum subsector_e {
70 	subsector_valid = 0,
71 	subsector_sector,
72 	subsector_numlines,
73 	subsector_firstline,
74 	subsector_polyList
75 };
76 
77 static const char *const subsector_opt[] = {
78 	"valid",
79 	"sector",
80 	"numlines",
81 	"firstline",
82 	"polyList",
83 	NULL};
84 
85 enum line_e {
86 	line_valid = 0,
87 	line_v1,
88 	line_v2,
89 	line_dx,
90 	line_dy,
91 	line_flags,
92 	line_special,
93 	line_tag,
94 	line_taglist,
95 	line_args,
96 	line_stringargs,
97 	line_sidenum,
98 	line_frontside,
99 	line_backside,
100 	line_alpha,
101 	line_executordelay,
102 	line_slopetype,
103 	line_frontsector,
104 	line_backsector,
105 	line_polyobj,
106 	line_text,
107 	line_callcount
108 };
109 
110 static const char *const line_opt[] = {
111 	"valid",
112 	"v1",
113 	"v2",
114 	"dx",
115 	"dy",
116 	"flags",
117 	"special",
118 	"tag",
119 	"taglist",
120 	"args",
121 	"stringargs",
122 	"sidenum",
123 	"frontside",
124 	"backside",
125 	"alpha",
126 	"executordelay",
127 	"slopetype",
128 	"frontsector",
129 	"backsector",
130 	"polyobj",
131 	"text",
132 	"callcount",
133 	NULL};
134 
135 enum side_e {
136 	side_valid = 0,
137 	side_textureoffset,
138 	side_rowoffset,
139 	side_toptexture,
140 	side_bottomtexture,
141 	side_midtexture,
142 	side_line,
143 	side_sector,
144 	side_special,
145 	side_repeatcnt,
146 	side_text
147 };
148 
149 static const char *const side_opt[] = {
150 	"valid",
151 	"textureoffset",
152 	"rowoffset",
153 	"toptexture",
154 	"bottomtexture",
155 	"midtexture",
156 	"line",
157 	"sector",
158 	"special",
159 	"repeatcnt",
160 	"text",
161 	NULL};
162 
163 enum vertex_e {
164 	vertex_valid = 0,
165 	vertex_x,
166 	vertex_y,
167 	vertex_floorz,
168 	vertex_floorzset,
169 	vertex_ceilingz,
170 	vertex_ceilingzset
171 };
172 
173 static const char *const vertex_opt[] = {
174 	"valid",
175 	"x",
176 	"y",
177 	"floorz",
178 	"floorzset",
179 	"ceilingz",
180 	"ceilingzset",
181 	NULL};
182 
183 enum ffloor_e {
184 	ffloor_valid = 0,
185 	ffloor_topheight,
186 	ffloor_toppic,
187 	ffloor_toplightlevel,
188 	ffloor_bottomheight,
189 	ffloor_bottompic,
190 	ffloor_tslope,
191 	ffloor_bslope,
192 	ffloor_sector,
193 	ffloor_flags,
194 	ffloor_master,
195 	ffloor_target,
196 	ffloor_next,
197 	ffloor_prev,
198 	ffloor_alpha,
199 };
200 
201 static const char *const ffloor_opt[] = {
202 	"valid",
203 	"topheight",
204 	"toppic",
205 	"toplightlevel",
206 	"bottomheight",
207 	"bottompic",
208 	"t_slope",
209 	"b_slope",
210 	"sector", // secnum pushed as control sector userdata
211 	"flags",
212 	"master", // control linedef
213 	"target", // target sector
214 	"next",
215 	"prev",
216 	"alpha",
217 	NULL};
218 
219 #ifdef HAVE_LUA_SEGS
220 enum seg_e {
221 	seg_valid = 0,
222 	seg_v1,
223 	seg_v2,
224 	seg_side,
225 	seg_offset,
226 	seg_angle,
227 	seg_sidedef,
228 	seg_linedef,
229 	seg_frontsector,
230 	seg_backsector,
231 	seg_polyseg
232 };
233 
234 static const char *const seg_opt[] = {
235 	"valid",
236 	"v1",
237 	"v2",
238 	"side",
239 	"offset",
240 	"angle",
241 	"sidedef",
242 	"linedef",
243 	"frontsector",
244 	"backsector",
245 	"polyseg",
246 	NULL};
247 
248 enum node_e {
249 	node_valid = 0,
250 	node_x,
251 	node_y,
252 	node_dx,
253 	node_dy,
254 	node_bbox,
255 	node_children,
256 };
257 
258 static const char *const node_opt[] = {
259 	"valid",
260 	"x",
261 	"y",
262 	"dx",
263 	"dy",
264 	"bbox",
265 	"children",
266 	NULL};
267 
268 enum nodechild_e {
269 	nodechild_valid = 0,
270 	nodechild_right,
271 	nodechild_left,
272 };
273 
274 static const char *const nodechild_opt[] = {
275 	"valid",
276 	"right",
277 	"left",
278 	NULL};
279 #endif
280 
281 enum bbox_e {
282 	bbox_valid = 0,
283 	bbox_top,
284 	bbox_bottom,
285 	bbox_left,
286 	bbox_right,
287 };
288 
289 static const char *const bbox_opt[] = {
290 	"valid",
291 	"top",
292 	"bottom",
293 	"left",
294 	"right",
295 	NULL};
296 
297 enum slope_e {
298 	slope_valid = 0,
299 	slope_o,
300 	slope_d,
301 	slope_zdelta,
302 	slope_normal,
303 	slope_zangle,
304 	slope_xydirection,
305 	slope_flags
306 };
307 
308 static const char *const slope_opt[] = {
309 	"valid",
310 	"o",
311 	"d",
312 	"zdelta",
313 	"normal",
314 	"zangle",
315 	"xydirection",
316 	"flags",
317 	NULL};
318 
319 // shared by both vector2_t and vector3_t
320 enum vector_e {
321 	vector_x = 0,
322 	vector_y,
323 	vector_z
324 };
325 
326 static const char *const vector_opt[] = {
327 	"x",
328 	"y",
329 	"z",
330 	NULL};
331 
332 static const char *const array_opt[] ={"iterate",NULL};
333 static const char *const valid_opt[] ={"valid",NULL};
334 
335 /////////////////////////////////////////////
336 // sector/subsector list iterate functions //
337 /////////////////////////////////////////////
338 
339 // iterates through a sector's thinglist!
lib_iterateSectorThinglist(lua_State * L)340 static int lib_iterateSectorThinglist(lua_State *L)
341 {
342 	mobj_t *state = NULL;
343 	mobj_t *thing = NULL;
344 
345 	INLEVEL
346 
347 	if (lua_gettop(L) < 2)
348 		return luaL_error(L, "Don't call sector.thinglist() directly, use it as 'for rover in sector.thinglist do <block> end'.");
349 
350 	if (!lua_isnil(L, 1))
351 		state = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
352 	else
353 		return 0; // no thinglist to iterate through sorry!
354 
355 	lua_settop(L, 2);
356 	lua_remove(L, 1); // remove state now.
357 
358 	if (!lua_isnil(L, 1))
359 	{
360 		thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
361 		thing = thing->snext;
362 	}
363 	else
364 		thing = state; // state is used as the "start" of the thinglist
365 
366 	if (thing)
367 	{
368 		LUA_PushUserdata(L, thing, META_MOBJ);
369 		return 1;
370 	}
371 	return 0;
372 }
373 
374 // iterates through the ffloors list in a sector!
lib_iterateSectorFFloors(lua_State * L)375 static int lib_iterateSectorFFloors(lua_State *L)
376 {
377 	ffloor_t *state = NULL;
378 	ffloor_t *ffloor = NULL;
379 
380 	INLEVEL
381 
382 	if (lua_gettop(L) < 2)
383 		return luaL_error(L, "Don't call sector.ffloors() directly, use it as 'for rover in sector.ffloors do <block> end'.");
384 
385 	if (!lua_isnil(L, 1))
386 		state = *((ffloor_t **)luaL_checkudata(L, 1, META_FFLOOR));
387 	else
388 		return 0; // no ffloors to iterate through sorry!
389 
390 	lua_settop(L, 2);
391 	lua_remove(L, 1); // remove state now.
392 
393 	if (!lua_isnil(L, 1))
394 	{
395 		ffloor = *((ffloor_t **)luaL_checkudata(L, 1, META_FFLOOR));
396 		ffloor = ffloor->next;
397 	}
398 	else
399 		ffloor = state; // state is used as the "start" of the ffloor list
400 
401 	if (ffloor)
402 	{
403 		LUA_PushUserdata(L, ffloor, META_FFLOOR);
404 		return 1;
405 	}
406 	return 0;
407 }
408 
409 // iterates through a subsector's polyList! (for polyobj_t)
lib_iterateSubSectorPolylist(lua_State * L)410 static int lib_iterateSubSectorPolylist(lua_State *L)
411 {
412 	polyobj_t *state = NULL;
413 	polyobj_t *po = NULL;
414 
415 	INLEVEL
416 
417 	if (lua_gettop(L) < 2)
418 		return luaL_error(L, "Don't call subsector.polyList() directly, use it as 'for polyobj in subsector.polyList do <block> end'.");
419 
420 	if (!lua_isnil(L, 1))
421 		state = *((polyobj_t **)luaL_checkudata(L, 1, META_POLYOBJ));
422 	else
423 		return 0; // no polylist to iterate through sorry!
424 
425 	lua_settop(L, 2);
426 	lua_remove(L, 1); // remove state now.
427 
428 	if (!lua_isnil(L, 1))
429 	{
430 		po = *((polyobj_t **)luaL_checkudata(L, 1, META_POLYOBJ));
431 		po = (polyobj_t *)(po->link.next);
432 	}
433 	else
434 		po = state; // state is used as the "start" of the polylist
435 
436 	if (po)
437 	{
438 		LUA_PushUserdata(L, po, META_POLYOBJ);
439 		return 1;
440 	}
441 	return 0;
442 }
443 
sector_iterate(lua_State * L)444 static int sector_iterate(lua_State *L)
445 {
446 	lua_pushvalue(L, lua_upvalueindex(1)); // iterator function, or the "generator"
447 	lua_pushvalue(L, lua_upvalueindex(2)); // state (used as the "start" of the list for our purposes
448 	lua_pushnil(L); // initial value (unused)
449 	return 3;
450 }
451 
452 ////////////////////
453 // sector.lines[] //
454 ////////////////////
455 
456 // sector.lines, i -> sector.lines[i]
457 // sector.lines.valid, for validity checking
458 //
459 // 25/9/19 Monster Iestyn
460 // Modified this and _num to use triple pointers, to allow for a new hack of mine involving offsetof
461 // this way we don't need to check frontsector or backsector of line #0 in the array
462 //
sectorlines_get(lua_State * L)463 static int sectorlines_get(lua_State *L)
464 {
465 	line_t ***seclines = *((line_t ****)luaL_checkudata(L, 1, META_SECTORLINES));
466 	size_t i;
467 	size_t numoflines = 0;
468 	lua_settop(L, 2);
469 	if (!lua_isnumber(L, 2))
470 	{
471 		int field = luaL_checkoption(L, 2, NULL, valid_opt);
472 		if (!seclines || !(*seclines))
473 		{
474 			if (field == 0) {
475 				lua_pushboolean(L, 0);
476 				return 1;
477 			}
478 			return luaL_error(L, "accessed sector_t.lines doesn't exist anymore.");
479 		} else if (field == 0) {
480 			lua_pushboolean(L, 1);
481 			return 1;
482 		}
483 	}
484 
485 /* a snip from sector_t struct in r_defs.h, for reference
486 	size_t linecount;
487 	struct line_s **lines; // [linecount] size
488 */
489 	// get the "linecount" by shifting our retrieved memory address of "lines" to where "linecount" is in the sector_t, then dereferencing the result
490 	// we need this to determine the array's actual size, and therefore also the maximum value allowed as an index
491 	// this only works if seclines is actually a pointer to a sector's lines member in memory, oh boy
492 	numoflines = *(size_t *)FIELDFROM (sector_t, seclines, lines,/* -> */linecount);
493 
494 /* OLD HACK
495 	// check first linedef to figure which of its sectors owns this sector->lines pointer
496 	// then check that sector's linecount to get a maximum index
497 	//if (!(*seclines)[0])
498 		//return luaL_error(L, "no lines found!"); // no first linedef?????
499 	if ((*seclines)[0]->frontsector->lines == *seclines)
500 		numoflines = (*seclines)[0]->frontsector->linecount;
501 	else if ((*seclines)[0]->backsector && *seclines[0]->backsector->lines == *seclines) // check backsector exists first
502 		numoflines = (*seclines)[0]->backsector->linecount;
503 	//if neither sector has it then ???
504 */
505 
506 	if (!numoflines)
507 		return luaL_error(L, "no lines found!");
508 
509 	i = (size_t)lua_tointeger(L, 2);
510 	if (i >= numoflines)
511 		return 0;
512 	LUA_PushUserdata(L, (*seclines)[i], META_LINE);
513 	return 1;
514 }
515 
516 // #(sector.lines) -> sector.linecount
sectorlines_num(lua_State * L)517 static int sectorlines_num(lua_State *L)
518 {
519 	line_t ***seclines = *((line_t ****)luaL_checkudata(L, 1, META_SECTORLINES));
520 	size_t numoflines = 0;
521 
522 	if (!seclines || !(*seclines))
523 		return luaL_error(L, "accessed sector_t.lines doesn't exist anymore.");
524 
525 	// see comments in the _get function above
526 	numoflines = *(size_t *)FIELDFROM (sector_t, seclines, lines,/* -> */linecount);
527 	lua_pushinteger(L, numoflines);
528 	return 1;
529 }
530 
531 //////////////
532 // sector_t //
533 //////////////
534 
sector_get(lua_State * L)535 static int sector_get(lua_State *L)
536 {
537 	sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
538 	enum sector_e field = luaL_checkoption(L, 2, sector_opt[0], sector_opt);
539 	INT16 i;
540 
541 	if (!sector)
542 	{
543 		if (field == sector_valid) {
544 			lua_pushboolean(L, 0);
545 			return 1;
546 		}
547 		return luaL_error(L, "accessed sector_t doesn't exist anymore.");
548 	}
549 
550 	switch(field)
551 	{
552 	case sector_valid: // valid
553 		lua_pushboolean(L, 1);
554 		return 1;
555 	case sector_floorheight:
556 		lua_pushfixed(L, sector->floorheight);
557 		return 1;
558 	case sector_ceilingheight:
559 		lua_pushfixed(L, sector->ceilingheight);
560 		return 1;
561 	case sector_floorpic: // floorpic
562 	{
563 		levelflat_t *levelflat = &levelflats[sector->floorpic];
564 		for (i = 0; i < 8; i++)
565 			if (!levelflat->name[i])
566 				break;
567 		lua_pushlstring(L, levelflat->name, i);
568 		return 1;
569 	}
570 	case sector_ceilingpic: // ceilingpic
571 	{
572 		levelflat_t *levelflat = &levelflats[sector->ceilingpic];
573 		for (i = 0; i < 8; i++)
574 			if (!levelflat->name[i])
575 				break;
576 		lua_pushlstring(L, levelflat->name, i);
577 		return 1;
578 	}
579 	case sector_lightlevel:
580 		lua_pushinteger(L, sector->lightlevel);
581 		return 1;
582 	case sector_special:
583 		lua_pushinteger(L, sector->special);
584 		return 1;
585 	case sector_tag:
586 		lua_pushinteger(L, (UINT16)Tag_FGet(&sector->tags));
587 		return 1;
588 	case sector_taglist:
589 		LUA_PushUserdata(L, &sector->tags, META_SECTORTAGLIST);
590 		return 1;
591 	case sector_thinglist: // thinglist
592 		lua_pushcfunction(L, lib_iterateSectorThinglist);
593 		LUA_PushUserdata(L, sector->thinglist, META_MOBJ);
594 		lua_pushcclosure(L, sector_iterate, 2); // push lib_iterateSectorThinglist and sector->thinglist as upvalues for the function
595 		return 1;
596 	case sector_heightsec: // heightsec - fake floor heights
597 		if (sector->heightsec < 0)
598 			return 0;
599 		LUA_PushUserdata(L, &sectors[sector->heightsec], META_SECTOR);
600 		return 1;
601 	case sector_camsec: // camsec - camera clipping heights
602 		if (sector->camsec < 0)
603 			return 0;
604 		LUA_PushUserdata(L, &sectors[sector->camsec], META_SECTOR);
605 		return 1;
606 	case sector_lines: // lines
607 		LUA_PushUserdata(L, &sector->lines, META_SECTORLINES); // push the address of the "lines" member in the struct, to allow our hacks in sectorlines_get/_num to work
608 		return 1;
609 	case sector_ffloors: // ffloors
610 		lua_pushcfunction(L, lib_iterateSectorFFloors);
611 		LUA_PushUserdata(L, sector->ffloors, META_FFLOOR);
612 		lua_pushcclosure(L, sector_iterate, 2); // push lib_iterateFFloors and sector->ffloors as upvalues for the function
613 		return 1;
614 	case sector_fslope: // f_slope
615 		LUA_PushUserdata(L, sector->f_slope, META_SLOPE);
616 		return 1;
617 	case sector_cslope: // c_slope
618 		LUA_PushUserdata(L, sector->c_slope, META_SLOPE);
619 		return 1;
620 	}
621 	return 0;
622 }
623 
sector_set(lua_State * L)624 static int sector_set(lua_State *L)
625 {
626 	sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
627 	enum sector_e field = luaL_checkoption(L, 2, sector_opt[0], sector_opt);
628 
629 	if (!sector)
630 		return luaL_error(L, "accessed sector_t doesn't exist anymore.");
631 
632 	if (hud_running)
633 		return luaL_error(L, "Do not alter sector_t in HUD rendering code!");
634 	if (hook_cmd_running)
635 		return luaL_error(L, "Do not alter sector_t in CMD building code!");
636 
637 	switch(field)
638 	{
639 	case sector_valid: // valid
640 	case sector_thinglist: // thinglist
641 	case sector_heightsec: // heightsec
642 	case sector_camsec: // camsec
643 	case sector_lines: // lines
644 	case sector_ffloors: // ffloors
645 	case sector_fslope: // f_slope
646 	case sector_cslope: // c_slope
647 	default:
648 		return luaL_error(L, "sector_t field " LUA_QS " cannot be set.", sector_opt[field]);
649 	case sector_floorheight: { // floorheight
650 		boolean flag;
651 		mobj_t *ptmthing = tmthing;
652 		fixed_t lastpos = sector->floorheight;
653 		sector->floorheight = luaL_checkfixed(L, 3);
654 		flag = P_CheckSector(sector, true);
655 		if (flag && sector->numattached)
656 		{
657 			sector->floorheight = lastpos;
658 			P_CheckSector(sector, true);
659 		}
660 		P_SetTarget(&tmthing, ptmthing);
661 		break;
662 	}
663 	case sector_ceilingheight: { // ceilingheight
664 		boolean flag;
665 		mobj_t *ptmthing = tmthing;
666 		fixed_t lastpos = sector->ceilingheight;
667 		sector->ceilingheight = luaL_checkfixed(L, 3);
668 		flag = P_CheckSector(sector, true);
669 		if (flag && sector->numattached)
670 		{
671 			sector->ceilingheight = lastpos;
672 			P_CheckSector(sector, true);
673 		}
674 		P_SetTarget(&tmthing, ptmthing);
675 		break;
676 	}
677 	case sector_floorpic:
678 		sector->floorpic = P_AddLevelFlatRuntime(luaL_checkstring(L, 3));
679 		break;
680 	case sector_ceilingpic:
681 		sector->ceilingpic = P_AddLevelFlatRuntime(luaL_checkstring(L, 3));
682 		break;
683 	case sector_lightlevel:
684 		sector->lightlevel = (INT16)luaL_checkinteger(L, 3);
685 		break;
686 	case sector_special:
687 		sector->special = (INT16)luaL_checkinteger(L, 3);
688 		break;
689 	case sector_tag:
690 		Tag_SectorFSet((UINT32)(sector - sectors), (INT16)luaL_checkinteger(L, 3));
691 		break;
692 	case sector_taglist:
693 		return LUA_ErrSetDirectly(L, "sector_t", "taglist");
694 	}
695 	return 0;
696 }
697 
sector_num(lua_State * L)698 static int sector_num(lua_State *L)
699 {
700 	sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
701 	lua_pushinteger(L, sector-sectors);
702 	return 1;
703 }
704 
705 /////////////////
706 // subsector_t //
707 /////////////////
708 
subsector_get(lua_State * L)709 static int subsector_get(lua_State *L)
710 {
711 	subsector_t *subsector = *((subsector_t **)luaL_checkudata(L, 1, META_SUBSECTOR));
712 	enum subsector_e field = luaL_checkoption(L, 2, subsector_opt[0], subsector_opt);
713 
714 	if (!subsector)
715 	{
716 		if (field == subsector_valid) {
717 			lua_pushboolean(L, 0);
718 			return 1;
719 		}
720 		return luaL_error(L, "accessed subsector_t doesn't exist anymore.");
721 	}
722 
723 	switch(field)
724 	{
725 	case subsector_valid: // valid
726 		lua_pushboolean(L, 1);
727 		return 1;
728 	case subsector_sector:
729 		LUA_PushUserdata(L, subsector->sector, META_SECTOR);
730 		return 1;
731 	case subsector_numlines:
732 		lua_pushinteger(L, subsector->numlines);
733 		return 1;
734 	case subsector_firstline:
735 		lua_pushinteger(L, subsector->firstline);
736 		return 1;
737 	case subsector_polyList: // polyList
738 		lua_pushcfunction(L, lib_iterateSubSectorPolylist);
739 		LUA_PushUserdata(L, subsector->polyList, META_POLYOBJ);
740 		lua_pushcclosure(L, sector_iterate, 2); // push lib_iterateSubSectorPolylist and subsector->polyList as upvalues for the function
741 		return 1;
742 	}
743 	return 0;
744 }
745 
subsector_num(lua_State * L)746 static int subsector_num(lua_State *L)
747 {
748 	subsector_t *subsector = *((subsector_t **)luaL_checkudata(L, 1, META_SUBSECTOR));
749 	lua_pushinteger(L, subsector-subsectors);
750 	return 1;
751 }
752 
753 ////////////
754 // line_t //
755 ////////////
756 
757 // args, i -> args[i]
lineargs_get(lua_State * L)758 static int lineargs_get(lua_State *L)
759 {
760 	INT32 *args = *((INT32**)luaL_checkudata(L, 1, META_LINEARGS));
761 	int i = luaL_checkinteger(L, 2);
762 	if (i < 0 || i >= NUMLINEARGS)
763 		return luaL_error(L, LUA_QL("line_t.args") " index cannot be %d", i);
764 	lua_pushinteger(L, args[i]);
765 	return 1;
766 }
767 
768 // #args -> NUMLINEARGS
lineargs_len(lua_State * L)769 static int lineargs_len(lua_State* L)
770 {
771 	lua_pushinteger(L, NUMLINEARGS);
772 	return 1;
773 }
774 
775 // stringargs, i -> stringargs[i]
linestringargs_get(lua_State * L)776 static int linestringargs_get(lua_State *L)
777 {
778 	char **stringargs = *((char***)luaL_checkudata(L, 1, META_LINESTRINGARGS));
779 	int i = luaL_checkinteger(L, 2);
780 	if (i < 0 || i >= NUMLINESTRINGARGS)
781 		return luaL_error(L, LUA_QL("line_t.stringargs") " index cannot be %d", i);
782 	lua_pushstring(L, stringargs[i]);
783 	return 1;
784 }
785 
786 // #stringargs -> NUMLINESTRINGARGS
linestringargs_len(lua_State * L)787 static int linestringargs_len(lua_State *L)
788 {
789 	lua_pushinteger(L, NUMLINESTRINGARGS);
790 	return 1;
791 }
792 
line_get(lua_State * L)793 static int line_get(lua_State *L)
794 {
795 	line_t *line = *((line_t **)luaL_checkudata(L, 1, META_LINE));
796 	enum line_e field = luaL_checkoption(L, 2, line_opt[0], line_opt);
797 
798 	if (!line)
799 	{
800 		if (field == line_valid) {
801 			lua_pushboolean(L, 0);
802 			return 1;
803 		}
804 		return luaL_error(L, "accessed line_t doesn't exist anymore.");
805 	}
806 
807 	switch(field)
808 	{
809 	case line_valid: // valid
810 		lua_pushboolean(L, 1);
811 		return 1;
812 	case line_v1:
813 		LUA_PushUserdata(L, line->v1, META_VERTEX);
814 		return 1;
815 	case line_v2:
816 		LUA_PushUserdata(L, line->v2, META_VERTEX);
817 		return 1;
818 	case line_dx:
819 		lua_pushfixed(L, line->dx);
820 		return 1;
821 	case line_dy:
822 		lua_pushfixed(L, line->dy);
823 		return 1;
824 	case line_flags:
825 		lua_pushinteger(L, line->flags);
826 		return 1;
827 	case line_special:
828 		lua_pushinteger(L, line->special);
829 		return 1;
830 	case line_tag:
831 		// HELLO
832 		// THIS IS LJ SONIC
833 		// HOW IS YOUR DAY?
834 		// BY THE WAY WHEN 2.3 OR 3.0 OR 4.0 OR SRB3 OR SRB4 OR WHATEVER IS OUT
835 		// YOU SHOULD REMEMBER TO CHANGE THIS SO IT ALWAYS RETURNS A UNSIGNED VALUE
836 		// HAVE A NICE DAY
837 		//
838 		//
839 		//
840 		//
841 		// you are ugly
842 		lua_pushinteger(L, Tag_FGet(&line->tags));
843 		return 1;
844 	case line_taglist:
845 		LUA_PushUserdata(L, &line->tags, META_TAGLIST);
846 		return 1;
847 	case line_args:
848 		LUA_PushUserdata(L, line->args, META_LINEARGS);
849 		return 1;
850 	case line_stringargs:
851 		LUA_PushUserdata(L, line->stringargs, META_LINESTRINGARGS);
852 		return 1;
853 	case line_sidenum:
854 		LUA_PushUserdata(L, line->sidenum, META_SIDENUM);
855 		return 1;
856 	case line_frontside: // frontside
857 		LUA_PushUserdata(L, &sides[line->sidenum[0]], META_SIDE);
858 		return 1;
859 	case line_backside: // backside
860 		if (line->sidenum[1] == 0xffff)
861 			return 0;
862 		LUA_PushUserdata(L, &sides[line->sidenum[1]], META_SIDE);
863 		return 1;
864 	case line_alpha:
865 		lua_pushfixed(L, line->alpha);
866 		return 1;
867 	case line_executordelay:
868 		lua_pushinteger(L, line->executordelay);
869 		return 1;
870 	case line_slopetype:
871 		switch(line->slopetype)
872 		{
873 		case ST_HORIZONTAL:
874 			lua_pushliteral(L, "horizontal");
875 			break;
876 		case ST_VERTICAL:
877 			lua_pushliteral(L, "vertical");
878 			break;
879 		case ST_POSITIVE:
880 			lua_pushliteral(L, "positive");
881 			break;
882 		case ST_NEGATIVE:
883 			lua_pushliteral(L, "negative");
884 			break;
885 		}
886 		return 1;
887 	case line_frontsector:
888 		LUA_PushUserdata(L, line->frontsector, META_SECTOR);
889 		return 1;
890 	case line_backsector:
891 		LUA_PushUserdata(L, line->backsector, META_SECTOR);
892 		return 1;
893 	case line_polyobj:
894 		LUA_PushUserdata(L, line->polyobj, META_POLYOBJ);
895 		return 1;
896 	case line_text:
897 		lua_pushstring(L, line->text);
898 		return 1;
899 	case line_callcount:
900 		lua_pushinteger(L, line->callcount);
901 		return 1;
902 	}
903 	return 0;
904 }
905 
line_num(lua_State * L)906 static int line_num(lua_State *L)
907 {
908 	line_t *line = *((line_t **)luaL_checkudata(L, 1, META_LINE));
909 	lua_pushinteger(L, line-lines);
910 	return 1;
911 }
912 
913 ////////////////////
914 // line.sidenum[] //
915 ////////////////////
916 
sidenum_get(lua_State * L)917 static int sidenum_get(lua_State *L)
918 {
919 	UINT16 *sidenum = *((UINT16 **)luaL_checkudata(L, 1, META_SIDENUM));
920 	int i;
921 	lua_settop(L, 2);
922 	if (!lua_isnumber(L, 2))
923 	{
924 		int field = luaL_checkoption(L, 2, NULL, valid_opt);
925 		if (!sidenum)
926 		{
927 			if (field == 0) {
928 				lua_pushboolean(L, 0);
929 				return 1;
930 			}
931 			return luaL_error(L, "accessed line_t doesn't exist anymore.");
932 		} else if (field == 0) {
933 			lua_pushboolean(L, 1);
934 			return 1;
935 		}
936 	}
937 
938 	i = lua_tointeger(L, 2);
939 	if (i < 0 || i > 1)
940 		return 0;
941 	lua_pushinteger(L, sidenum[i]);
942 	return 1;
943 }
944 
945 ////////////
946 // side_t //
947 ////////////
948 
side_get(lua_State * L)949 static int side_get(lua_State *L)
950 {
951 	side_t *side = *((side_t **)luaL_checkudata(L, 1, META_SIDE));
952 	enum side_e field = luaL_checkoption(L, 2, side_opt[0], side_opt);
953 
954 	if (!side)
955 	{
956 		if (field == side_valid) {
957 			lua_pushboolean(L, 0);
958 			return 1;
959 		}
960 		return luaL_error(L, "accessed side_t doesn't exist anymore.");
961 	}
962 
963 	switch(field)
964 	{
965 	case side_valid: // valid
966 		lua_pushboolean(L, 1);
967 		return 1;
968 	case side_textureoffset:
969 		lua_pushfixed(L, side->textureoffset);
970 		return 1;
971 	case side_rowoffset:
972 		lua_pushfixed(L, side->rowoffset);
973 		return 1;
974 	case side_toptexture:
975 		lua_pushinteger(L, side->toptexture);
976 		return 1;
977 	case side_bottomtexture:
978 		lua_pushinteger(L, side->bottomtexture);
979 		return 1;
980 	case side_midtexture:
981 		lua_pushinteger(L, side->midtexture);
982 		return 1;
983 	case side_line:
984 		LUA_PushUserdata(L, side->line, META_LINE);
985 		return 1;
986 	case side_sector:
987 		LUA_PushUserdata(L, side->sector, META_SECTOR);
988 		return 1;
989 	case side_special:
990 		lua_pushinteger(L, side->special);
991 		return 1;
992 	case side_repeatcnt:
993 		lua_pushinteger(L, side->repeatcnt);
994 		return 1;
995 	case side_text:
996 		lua_pushstring(L, side->text);
997 		return 1;
998 	}
999 	return 0;
1000 }
1001 
side_set(lua_State * L)1002 static int side_set(lua_State *L)
1003 {
1004 	side_t *side = *((side_t **)luaL_checkudata(L, 1, META_SIDE));
1005 	enum side_e field = luaL_checkoption(L, 2, side_opt[0], side_opt);
1006 
1007 	if (!side)
1008 	{
1009 		if (field == side_valid) {
1010 			lua_pushboolean(L, 0);
1011 			return 1;
1012 		}
1013 		return luaL_error(L, "accessed side_t doesn't exist anymore.");
1014 	}
1015 
1016 	switch(field)
1017 	{
1018 	case side_valid: // valid
1019 	case side_line:
1020 	case side_sector:
1021 	case side_special:
1022 	case side_text:
1023 	default:
1024 		return luaL_error(L, "side_t field " LUA_QS " cannot be set.", side_opt[field]);
1025 	case side_textureoffset:
1026 		side->textureoffset = luaL_checkfixed(L, 3);
1027 		break;
1028 	case side_rowoffset:
1029 		side->rowoffset = luaL_checkfixed(L, 3);
1030 		break;
1031 	case side_toptexture:
1032 		side->toptexture = luaL_checkinteger(L, 3);
1033 		break;
1034 	case side_bottomtexture:
1035 		side->bottomtexture = luaL_checkinteger(L, 3);
1036 		break;
1037 	case side_midtexture:
1038 		side->midtexture = luaL_checkinteger(L, 3);
1039 		break;
1040 	case side_repeatcnt:
1041 		side->repeatcnt = luaL_checkinteger(L, 3);
1042 		break;
1043 	}
1044 	return 0;
1045 }
1046 
side_num(lua_State * L)1047 static int side_num(lua_State *L)
1048 {
1049 	side_t *side = *((side_t **)luaL_checkudata(L, 1, META_SIDE));
1050 	lua_pushinteger(L, side-sides);
1051 	return 1;
1052 }
1053 
1054 //////////////
1055 // vertex_t //
1056 //////////////
1057 
vertex_get(lua_State * L)1058 static int vertex_get(lua_State *L)
1059 {
1060 	vertex_t *vertex = *((vertex_t **)luaL_checkudata(L, 1, META_VERTEX));
1061 	enum vertex_e field = luaL_checkoption(L, 2, vertex_opt[0], vertex_opt);
1062 
1063 	if (!vertex)
1064 	{
1065 		if (field == vertex_valid) {
1066 			lua_pushboolean(L, 0);
1067 			return 1;
1068 		}
1069 		return luaL_error(L, "accessed vertex_t doesn't exist anymore.");
1070 	}
1071 
1072 	switch(field)
1073 	{
1074 	case vertex_valid: // valid
1075 		lua_pushboolean(L, 1);
1076 		return 1;
1077 	case vertex_x:
1078 		lua_pushfixed(L, vertex->x);
1079 		return 1;
1080 	case vertex_y:
1081 		lua_pushfixed(L, vertex->y);
1082 		return 1;
1083 	case vertex_floorzset:
1084 		lua_pushboolean(L, vertex->floorzset);
1085 		return 1;
1086 	case vertex_ceilingzset:
1087 		lua_pushboolean(L, vertex->ceilingzset);
1088 		return 1;
1089 	case vertex_floorz:
1090 		lua_pushfixed(L, vertex->floorz);
1091 		return 1;
1092 	case vertex_ceilingz:
1093 		lua_pushfixed(L, vertex->ceilingz);
1094 		return 1;
1095 	}
1096 	return 0;
1097 }
1098 
vertex_num(lua_State * L)1099 static int vertex_num(lua_State *L)
1100 {
1101 	vertex_t *vertex = *((vertex_t **)luaL_checkudata(L, 1, META_VERTEX));
1102 	lua_pushinteger(L, vertex-vertexes);
1103 	return 1;
1104 }
1105 
1106 #ifdef HAVE_LUA_SEGS
1107 
1108 ///////////
1109 // seg_t //
1110 ///////////
1111 
seg_get(lua_State * L)1112 static int seg_get(lua_State *L)
1113 {
1114 	seg_t *seg = *((seg_t **)luaL_checkudata(L, 1, META_SEG));
1115 	enum seg_e field = luaL_checkoption(L, 2, seg_opt[0], seg_opt);
1116 
1117 	if (!seg)
1118 	{
1119 		if (field == seg_valid) {
1120 			lua_pushboolean(L, 0);
1121 			return 1;
1122 		}
1123 		return luaL_error(L, "accessed seg_t doesn't exist anymore.");
1124 	}
1125 
1126 	switch(field)
1127 	{
1128 	case seg_valid: // valid
1129 		lua_pushboolean(L, 1);
1130 		return 1;
1131 	case seg_v1:
1132 		LUA_PushUserdata(L, seg->v1, META_VERTEX);
1133 		return 1;
1134 	case seg_v2:
1135 		LUA_PushUserdata(L, seg->v2, META_VERTEX);
1136 		return 1;
1137 	case seg_side:
1138 		lua_pushinteger(L, seg->side);
1139 		return 1;
1140 	case seg_offset:
1141 		lua_pushfixed(L, seg->offset);
1142 		return 1;
1143 	case seg_angle:
1144 		lua_pushangle(L, seg->angle);
1145 		return 1;
1146 	case seg_sidedef:
1147 		LUA_PushUserdata(L, seg->sidedef, META_SIDE);
1148 		return 1;
1149 	case seg_linedef:
1150 		LUA_PushUserdata(L, seg->linedef, META_LINE);
1151 		return 1;
1152 	case seg_frontsector:
1153 		LUA_PushUserdata(L, seg->frontsector, META_SECTOR);
1154 		return 1;
1155 	case seg_backsector:
1156 		LUA_PushUserdata(L, seg->backsector, META_SECTOR);
1157 		return 1;
1158 	case seg_polyseg:
1159 		LUA_PushUserdata(L, seg->polyseg, META_POLYOBJ);
1160 		return 1;
1161 	}
1162 	return 0;
1163 }
1164 
seg_num(lua_State * L)1165 static int seg_num(lua_State *L)
1166 {
1167 	seg_t *seg = *((seg_t **)luaL_checkudata(L, 1, META_SEG));
1168 	lua_pushinteger(L, seg-segs);
1169 	return 1;
1170 }
1171 
1172 ////////////
1173 // node_t //
1174 ////////////
1175 
node_get(lua_State * L)1176 static int node_get(lua_State *L)
1177 {
1178 	node_t *node = *((node_t **)luaL_checkudata(L, 1, META_NODE));
1179 	enum node_e field = luaL_checkoption(L, 2, node_opt[0], node_opt);
1180 
1181 	if (!node)
1182 	{
1183 		if (field == node_valid) {
1184 			lua_pushboolean(L, 0);
1185 			return 1;
1186 		}
1187 		return luaL_error(L, "accessed node_t doesn't exist anymore.");
1188 	}
1189 
1190 	switch(field)
1191 	{
1192 	case node_valid: // valid
1193 		lua_pushboolean(L, 1);
1194 		return 1;
1195 	case node_x:
1196 		lua_pushfixed(L, node->x);
1197 		return 1;
1198 	case node_y:
1199 		lua_pushfixed(L, node->y);
1200 		return 1;
1201 	case node_dx:
1202 		lua_pushfixed(L, node->x);
1203 		return 1;
1204 	case node_dy:
1205 		lua_pushfixed(L, node->x);
1206 		return 1;
1207 	case node_bbox:
1208 		LUA_PushUserdata(L, node->bbox, META_NODEBBOX);
1209 		return 1;
1210 	case node_children:
1211 		LUA_PushUserdata(L, node->children, META_NODECHILDREN);
1212 		return 1;
1213 	}
1214 	return 0;
1215 }
1216 
node_num(lua_State * L)1217 static int node_num(lua_State *L)
1218 {
1219 	node_t *node = *((node_t **)luaL_checkudata(L, 1, META_NODE));
1220 	lua_pushinteger(L, node-nodes);
1221 	return 1;
1222 }
1223 
1224 ///////////////
1225 // node.bbox //
1226 ///////////////
1227 
1228 /*
1229 // node.bbox[i][j]: i = 0 or 1, j = 0 1 2 or 3
1230 // NOTE: 2D arrays are NOT double pointers,
1231 //       the second bbox will be directly after the first in memory (hence the way the bbox is pushed here)
1232 // this function handles the [i] part, bbox_get handles the [j] part
1233 static int nodebbox_get(lua_State *L)
1234 {
1235 	fixed_t *bbox = *((fixed_t **)luaL_checkudata(L, 1, META_NODEBBOX));
1236 	int i;
1237 	lua_settop(L, 2);
1238 	if (!lua_isnumber(L, 2))
1239 	{
1240 		int field = luaL_checkoption(L, 2, NULL, valid_opt);
1241 		if (!bbox)
1242 		{
1243 			if (field == 0) {
1244 				lua_pushboolean(L, 0);
1245 				return 1;
1246 			}
1247 			return luaL_error(L, "accessed node_t doesn't exist anymore.");
1248 		} else if (field == 0) {
1249 			lua_pushboolean(L, 1);
1250 			return 1;
1251 		}
1252 	}
1253 
1254 	i = lua_tointeger(L, 2);
1255 	if (i < 0 || i > 1)
1256 		return 0;
1257 	LUA_PushUserdata(L, bbox + i*4*sizeof(fixed_t), META_BBOX);
1258 	return 1;
1259 }
1260 */
nodebbox_call(lua_State * L)1261 static int nodebbox_call(lua_State *L)
1262 {
1263 	fixed_t *bbox = *((fixed_t **)luaL_checkudata(L, 1, META_NODEBBOX));
1264 	int i, j;
1265 	int n = lua_gettop(L);
1266 
1267 	if (!bbox)
1268 		return luaL_error(L, "accessed node bbox doesn't exist anymore.");
1269 	if (n < 3)
1270 		return luaL_error(L, "arguments 2 and/or 3 not given (expected node.bbox(child, coord))");
1271 	// get child
1272 	if (!lua_isnumber(L, 2)) {
1273 		enum nodechild_e field = luaL_checkoption(L, 2, nodechild_opt[0], nodechild_opt);
1274 		switch (field) {
1275 			case nodechild_right: i = 0; break;
1276 			case nodechild_left:  i = 1; break;
1277 			default:
1278 				return luaL_error(L, "invalid node child \"%s\".", lua_tostring(L, 2));
1279 		}
1280 	}
1281 	else {
1282 		i = lua_tointeger(L, 2);
1283 		if (i < 0 || i > 1)
1284 			return 0;
1285 	}
1286 	// get bbox coord
1287 	if (!lua_isnumber(L, 3)) {
1288 		enum bbox_e field = luaL_checkoption(L, 3, bbox_opt[0], bbox_opt);
1289 		switch (field) {
1290 			case bbox_top:    j = BOXTOP;    break;
1291 			case bbox_bottom: j = BOXBOTTOM; break;
1292 			case bbox_left:   j = BOXLEFT;   break;
1293 			case bbox_right:  j = BOXRIGHT;  break;
1294 			default:
1295 				return luaL_error(L, "invalid bbox coordinate \"%s\".", lua_tostring(L, 3));
1296 		}
1297 	}
1298 	else {
1299 		j = lua_tointeger(L, 3);
1300 		if (j < 0 || j > 3)
1301 			return 0;
1302 	}
1303 	lua_pushinteger(L, bbox[i*4 + j]);
1304 	return 1;
1305 }
1306 
1307 /////////////////////
1308 // node.children[] //
1309 /////////////////////
1310 
1311 // node.children[i]: i = 0 or 1
nodechildren_get(lua_State * L)1312 static int nodechildren_get(lua_State *L)
1313 {
1314 	UINT16 *children = *((UINT16 **)luaL_checkudata(L, 1, META_NODECHILDREN));
1315 	int i;
1316 	lua_settop(L, 2);
1317 	if (!lua_isnumber(L, 2))
1318 	{
1319 		enum nodechild_e field = luaL_checkoption(L, 2, nodechild_opt[0], nodechild_opt);
1320 		if (!children)
1321 		{
1322 			if (field == nodechild_valid) {
1323 				lua_pushboolean(L, 0);
1324 				return 1;
1325 			}
1326 			return luaL_error(L, "accessed node_t doesn't exist anymore.");
1327 		} else if (field == nodechild_valid) {
1328 			lua_pushboolean(L, 1);
1329 			return 1;
1330 		} else switch (field) {
1331 			case nodechild_right: i = 0; break;
1332 			case nodechild_left:  i = 1; break;
1333 			default:              return 0;
1334 		}
1335 	}
1336 	else {
1337 		i = lua_tointeger(L, 2);
1338 		if (i < 0 || i > 1)
1339 			return 0;
1340 	}
1341 	lua_pushinteger(L, children[i]);
1342 	return 1;
1343 }
1344 #endif
1345 
1346 //////////
1347 // bbox //
1348 //////////
1349 
1350 // bounding box (aka fixed_t array with four elements)
1351 // NOTE: may be useful for polyobjects or other things later
bbox_get(lua_State * L)1352 static int bbox_get(lua_State *L)
1353 {
1354 	fixed_t *bbox = *((fixed_t **)luaL_checkudata(L, 1, META_BBOX));
1355 	int i;
1356 	lua_settop(L, 2);
1357 	if (!lua_isnumber(L, 2))
1358 	{
1359 		enum bbox_e field = luaL_checkoption(L, 2, bbox_opt[0], bbox_opt);
1360 		if (!bbox)
1361 		{
1362 			if (field == bbox_valid) {
1363 				lua_pushboolean(L, 0);
1364 				return 1;
1365 			}
1366 			return luaL_error(L, "accessed bbox doesn't exist anymore.");
1367 		} else if (field == bbox_valid) {
1368 			lua_pushboolean(L, 1);
1369 			return 1;
1370 		} else switch (field) {
1371 			case bbox_top:    i = BOXTOP;    break;
1372 			case bbox_bottom: i = BOXBOTTOM; break;
1373 			case bbox_left:   i = BOXLEFT;   break;
1374 			case bbox_right:  i = BOXRIGHT;  break;
1375 			default:          return 0;
1376 		}
1377 	}
1378 	else {
1379 		i = lua_tointeger(L, 2);
1380 		if (i < 0 || i > 3)
1381 			return 0;
1382 	}
1383 	lua_pushinteger(L, bbox[i]);
1384 	return 1;
1385 }
1386 
1387 ///////////////
1388 // sectors[] //
1389 ///////////////
1390 
lib_iterateSectors(lua_State * L)1391 static int lib_iterateSectors(lua_State *L)
1392 {
1393 	size_t i = 0;
1394 	INLEVEL
1395 	if (lua_gettop(L) < 2)
1396 		return luaL_error(L, "Don't call sectors.iterate() directly, use it as 'for sector in sectors.iterate do <block> end'.");
1397 	lua_settop(L, 2);
1398 	lua_remove(L, 1); // state is unused.
1399 	if (!lua_isnil(L, 1))
1400 		i = (size_t)(*((sector_t **)luaL_checkudata(L, 1, META_SECTOR)) - sectors)+1;
1401 	if (i < numsectors)
1402 	{
1403 		LUA_PushUserdata(L, &sectors[i], META_SECTOR);
1404 		return 1;
1405 	}
1406 	return 0;
1407 }
1408 
lib_getSector(lua_State * L)1409 static int lib_getSector(lua_State *L)
1410 {
1411 	INLEVEL
1412 	if (lua_isnumber(L, 2))
1413 	{
1414 		size_t i = lua_tointeger(L, 2);
1415 		if (i >= numsectors)
1416 			return 0;
1417 		LUA_PushUserdata(L, &sectors[i], META_SECTOR);
1418 		return 1;
1419 	}
1420 	return 0;
1421 }
1422 
lib_numsectors(lua_State * L)1423 static int lib_numsectors(lua_State *L)
1424 {
1425 	lua_pushinteger(L, numsectors);
1426 	return 1;
1427 }
1428 
1429 //////////////////
1430 // subsectors[] //
1431 //////////////////
1432 
lib_iterateSubsectors(lua_State * L)1433 static int lib_iterateSubsectors(lua_State *L)
1434 {
1435 	size_t i = 0;
1436 	INLEVEL
1437 	if (lua_gettop(L) < 2)
1438 		return luaL_error(L, "Don't call subsectors.iterate() directly, use it as 'for subsector in subsectors.iterate do <block> end'.");
1439 	lua_settop(L, 2);
1440 	lua_remove(L, 1); // state is unused.
1441 	if (!lua_isnil(L, 1))
1442 		i = (size_t)(*((subsector_t **)luaL_checkudata(L, 1, META_SUBSECTOR)) - subsectors)+1;
1443 	if (i < numsubsectors)
1444 	{
1445 		LUA_PushUserdata(L, &subsectors[i], META_SUBSECTOR);
1446 		return 1;
1447 	}
1448 	return 0;
1449 }
1450 
lib_getSubsector(lua_State * L)1451 static int lib_getSubsector(lua_State *L)
1452 {
1453 	int field;
1454 	INLEVEL
1455 	lua_settop(L, 2);
1456 	lua_remove(L, 1); // dummy userdata table is unused.
1457 	if (lua_isnumber(L, 1))
1458 	{
1459 		size_t i = lua_tointeger(L, 1);
1460 		if (i >= numsubsectors)
1461 			return 0;
1462 		LUA_PushUserdata(L, &subsectors[i], META_SUBSECTOR);
1463 		return 1;
1464 	}
1465 	field = luaL_checkoption(L, 1, NULL, array_opt);
1466 	switch(field)
1467 	{
1468 	case 0: // iterate
1469 		lua_pushcfunction(L, lib_iterateSubsectors);
1470 		return 1;
1471 	}
1472 	return 0;
1473 }
1474 
lib_numsubsectors(lua_State * L)1475 static int lib_numsubsectors(lua_State *L)
1476 {
1477 	lua_pushinteger(L, numsubsectors);
1478 	return 1;
1479 }
1480 
1481 /////////////
1482 // lines[] //
1483 /////////////
1484 
lib_iterateLines(lua_State * L)1485 static int lib_iterateLines(lua_State *L)
1486 {
1487 	size_t i = 0;
1488 	INLEVEL
1489 	if (lua_gettop(L) < 2)
1490 		return luaL_error(L, "Don't call lines.iterate() directly, use it as 'for line in lines.iterate do <block> end'.");
1491 	lua_settop(L, 2);
1492 	lua_remove(L, 1); // state is unused.
1493 	if (!lua_isnil(L, 1))
1494 		i = (size_t)(*((line_t **)luaL_checkudata(L, 1, META_LINE)) - lines)+1;
1495 	if (i < numlines)
1496 	{
1497 		LUA_PushUserdata(L, &lines[i], META_LINE);
1498 		return 1;
1499 	}
1500 	return 0;
1501 }
1502 
lib_getLine(lua_State * L)1503 static int lib_getLine(lua_State *L)
1504 {
1505 	INLEVEL
1506 	if (lua_isnumber(L, 2))
1507 	{
1508 		size_t i = lua_tointeger(L, 2);
1509 		if (i >= numlines)
1510 			return 0;
1511 		LUA_PushUserdata(L, &lines[i], META_LINE);
1512 		return 1;
1513 	}
1514 	return 0;
1515 }
1516 
lib_numlines(lua_State * L)1517 static int lib_numlines(lua_State *L)
1518 {
1519 	lua_pushinteger(L, numlines);
1520 	return 1;
1521 }
1522 
1523 /////////////
1524 // sides[] //
1525 /////////////
1526 
lib_iterateSides(lua_State * L)1527 static int lib_iterateSides(lua_State *L)
1528 {
1529 	size_t i = 0;
1530 	INLEVEL
1531 	if (lua_gettop(L) < 2)
1532 		return luaL_error(L, "Don't call sides.iterate() directly, use it as 'for side in sides.iterate do <block> end'.");
1533 	lua_settop(L, 2);
1534 	lua_remove(L, 1); // state is unused.
1535 	if (!lua_isnil(L, 1))
1536 		i = (size_t)(*((side_t **)luaL_checkudata(L, 1, META_SIDE)) - sides)+1;
1537 	if (i < numsides)
1538 	{
1539 		LUA_PushUserdata(L, &sides[i], META_SIDE);
1540 		return 1;
1541 	}
1542 	return 0;
1543 }
1544 
lib_getSide(lua_State * L)1545 static int lib_getSide(lua_State *L)
1546 {
1547 	int field;
1548 	INLEVEL
1549 	lua_settop(L, 2);
1550 	lua_remove(L, 1); // dummy userdata table is unused.
1551 	if (lua_isnumber(L, 1))
1552 	{
1553 		size_t i = lua_tointeger(L, 1);
1554 		if (i >= numsides)
1555 			return 0;
1556 		LUA_PushUserdata(L, &sides[i], META_SIDE);
1557 		return 1;
1558 	}
1559 	field = luaL_checkoption(L, 1, NULL, array_opt);
1560 	switch(field)
1561 	{
1562 	case 0: // iterate
1563 		lua_pushcfunction(L, lib_iterateSides);
1564 		return 1;
1565 	}
1566 	return 0;
1567 }
1568 
lib_numsides(lua_State * L)1569 static int lib_numsides(lua_State *L)
1570 {
1571 	lua_pushinteger(L, numsides);
1572 	return 1;
1573 }
1574 
1575 ////////////////
1576 // vertexes[] //
1577 ////////////////
1578 
lib_iterateVertexes(lua_State * L)1579 static int lib_iterateVertexes(lua_State *L)
1580 {
1581 	size_t i = 0;
1582 	INLEVEL
1583 	if (lua_gettop(L) < 2)
1584 		return luaL_error(L, "Don't call vertexes.iterate() directly, use it as 'for vertex in vertexes.iterate do <block> end'.");
1585 	lua_settop(L, 2);
1586 	lua_remove(L, 1); // state is unused.
1587 	if (!lua_isnil(L, 1))
1588 		i = (size_t)(*((vertex_t **)luaL_checkudata(L, 1, META_VERTEX)) - vertexes)+1;
1589 	if (i < numvertexes)
1590 	{
1591 		LUA_PushUserdata(L, &vertexes[i], META_VERTEX);
1592 		return 1;
1593 	}
1594 	return 0;
1595 }
1596 
lib_getVertex(lua_State * L)1597 static int lib_getVertex(lua_State *L)
1598 {
1599 	int field;
1600 	INLEVEL
1601 	lua_settop(L, 2);
1602 	lua_remove(L, 1); // dummy userdata table is unused.
1603 	if (lua_isnumber(L, 1))
1604 	{
1605 		size_t i = lua_tointeger(L, 1);
1606 		if (i >= numvertexes)
1607 			return 0;
1608 		LUA_PushUserdata(L, &vertexes[i], META_VERTEX);
1609 		return 1;
1610 	}
1611 	field = luaL_checkoption(L, 1, NULL, array_opt);
1612 	switch(field)
1613 	{
1614 	case 0: // iterate
1615 		lua_pushcfunction(L, lib_iterateVertexes);
1616 		return 1;
1617 	}
1618 	return 0;
1619 }
1620 
lib_numvertexes(lua_State * L)1621 static int lib_numvertexes(lua_State *L)
1622 {
1623 	lua_pushinteger(L, numvertexes);
1624 	return 1;
1625 }
1626 
1627 #ifdef HAVE_LUA_SEGS
1628 
1629 ////////////
1630 // segs[] //
1631 ////////////
1632 
lib_iterateSegs(lua_State * L)1633 static int lib_iterateSegs(lua_State *L)
1634 {
1635 	size_t i = 0;
1636 	INLEVEL
1637 	if (lua_gettop(L) < 2)
1638 		return luaL_error(L, "Don't call segs.iterate() directly, use it as 'for seg in segs.iterate do <block> end'.");
1639 	lua_settop(L, 2);
1640 	lua_remove(L, 1); // state is unused.
1641 	if (!lua_isnil(L, 1))
1642 		i = (size_t)(*((seg_t **)luaL_checkudata(L, 1, META_SEG)) - segs)+1;
1643 	if (i < numsegs)
1644 	{
1645 		LUA_PushUserdata(L, &segs[i], META_SEG);
1646 		return 1;
1647 	}
1648 	return 0;
1649 }
1650 
lib_getSeg(lua_State * L)1651 static int lib_getSeg(lua_State *L)
1652 {
1653 	int field;
1654 	INLEVEL
1655 	lua_settop(L, 2);
1656 	lua_remove(L, 1); // dummy userdata table is unused.
1657 	if (lua_isnumber(L, 1))
1658 	{
1659 		size_t i = lua_tointeger(L, 1);
1660 		if (i >= numsegs)
1661 			return 0;
1662 		LUA_PushUserdata(L, &segs[i], META_SEG);
1663 		return 1;
1664 	}
1665 	field = luaL_checkoption(L, 1, NULL, array_opt);
1666 	switch(field)
1667 	{
1668 	case 0: // iterate
1669 		lua_pushcfunction(L, lib_iterateSegs);
1670 		return 1;
1671 	}
1672 	return 0;
1673 }
1674 
lib_numsegs(lua_State * L)1675 static int lib_numsegs(lua_State *L)
1676 {
1677 	lua_pushinteger(L, numsegs);
1678 	return 1;
1679 }
1680 
1681 /////////////
1682 // nodes[] //
1683 /////////////
1684 
lib_iterateNodes(lua_State * L)1685 static int lib_iterateNodes(lua_State *L)
1686 {
1687 	size_t i = 0;
1688 	INLEVEL
1689 	if (lua_gettop(L) < 2)
1690 		return luaL_error(L, "Don't call nodes.iterate() directly, use it as 'for node in nodes.iterate do <block> end'.");
1691 	lua_settop(L, 2);
1692 	lua_remove(L, 1); // state is unused.
1693 	if (!lua_isnil(L, 1))
1694 		i = (size_t)(*((node_t **)luaL_checkudata(L, 1, META_NODE)) - nodes)+1;
1695 	if (i < numsegs)
1696 	{
1697 		LUA_PushUserdata(L, &nodes[i], META_NODE);
1698 		return 1;
1699 	}
1700 	return 0;
1701 }
1702 
lib_getNode(lua_State * L)1703 static int lib_getNode(lua_State *L)
1704 {
1705 	int field;
1706 	INLEVEL
1707 	lua_settop(L, 2);
1708 	lua_remove(L, 1); // dummy userdata table is unused.
1709 	if (lua_isnumber(L, 1))
1710 	{
1711 		size_t i = lua_tointeger(L, 1);
1712 		if (i >= numnodes)
1713 			return 0;
1714 		LUA_PushUserdata(L, &nodes[i], META_NODE);
1715 		return 1;
1716 	}
1717 	field = luaL_checkoption(L, 1, NULL, array_opt);
1718 	switch(field)
1719 	{
1720 	case 0: // iterate
1721 		lua_pushcfunction(L, lib_iterateNodes);
1722 		return 1;
1723 	}
1724 	return 0;
1725 }
1726 
lib_numnodes(lua_State * L)1727 static int lib_numnodes(lua_State *L)
1728 {
1729 	lua_pushinteger(L, numnodes);
1730 	return 1;
1731 }
1732 #endif
1733 
1734 //////////////
1735 // ffloor_t //
1736 //////////////
1737 
ffloor_get(lua_State * L)1738 static int ffloor_get(lua_State *L)
1739 {
1740 	ffloor_t *ffloor = *((ffloor_t **)luaL_checkudata(L, 1, META_FFLOOR));
1741 	enum ffloor_e field = luaL_checkoption(L, 2, ffloor_opt[0], ffloor_opt);
1742 	INT16 i;
1743 
1744 	if (!ffloor)
1745 	{
1746 		if (field == ffloor_valid) {
1747 			lua_pushboolean(L, 0);
1748 			return 1;
1749 		}
1750 		return luaL_error(L, "accessed ffloor_t doesn't exist anymore.");
1751 	}
1752 
1753 	switch(field)
1754 	{
1755 	case ffloor_valid: // valid
1756 		lua_pushboolean(L, 1);
1757 		return 1;
1758 	case ffloor_topheight:
1759 		lua_pushfixed(L, *ffloor->topheight);
1760 		return 1;
1761 	case ffloor_toppic: { // toppic
1762 		levelflat_t *levelflat = &levelflats[*ffloor->toppic];
1763 		for (i = 0; i < 8; i++)
1764 			if (!levelflat->name[i])
1765 				break;
1766 		lua_pushlstring(L, levelflat->name, i);
1767 		return 1;
1768 	}
1769 	case ffloor_toplightlevel:
1770 		lua_pushinteger(L, *ffloor->toplightlevel);
1771 		return 1;
1772 	case ffloor_bottomheight:
1773 		lua_pushfixed(L, *ffloor->bottomheight);
1774 		return 1;
1775 	case ffloor_bottompic: { // bottompic
1776 		levelflat_t *levelflat = &levelflats[*ffloor->bottompic];
1777 		for (i = 0; i < 8; i++)
1778 			if (!levelflat->name[i])
1779 				break;
1780 		lua_pushlstring(L, levelflat->name, i);
1781 		return 1;
1782 	}
1783 	case ffloor_tslope:
1784 		LUA_PushUserdata(L, *ffloor->t_slope, META_SLOPE);
1785 		return 1;
1786 	case ffloor_bslope:
1787 		LUA_PushUserdata(L, *ffloor->b_slope, META_SLOPE);
1788 		return 1;
1789 	case ffloor_sector:
1790 		LUA_PushUserdata(L, &sectors[ffloor->secnum], META_SECTOR);
1791 		return 1;
1792 	case ffloor_flags:
1793 		lua_pushinteger(L, ffloor->flags);
1794 		return 1;
1795 	case ffloor_master:
1796 		LUA_PushUserdata(L, ffloor->master, META_LINE);
1797 		return 1;
1798 	case ffloor_target:
1799 		LUA_PushUserdata(L, ffloor->target, META_SECTOR);
1800 		return 1;
1801 	case ffloor_next:
1802 		LUA_PushUserdata(L, ffloor->next, META_FFLOOR);
1803 		return 1;
1804 	case ffloor_prev:
1805 		LUA_PushUserdata(L, ffloor->prev, META_FFLOOR);
1806 		return 1;
1807 	case ffloor_alpha:
1808 		lua_pushinteger(L, ffloor->alpha);
1809 		return 1;
1810 	}
1811 	return 0;
1812 }
1813 
ffloor_set(lua_State * L)1814 static int ffloor_set(lua_State *L)
1815 {
1816 	ffloor_t *ffloor = *((ffloor_t **)luaL_checkudata(L, 1, META_FFLOOR));
1817 	enum ffloor_e field = luaL_checkoption(L, 2, ffloor_opt[0], ffloor_opt);
1818 
1819 	if (!ffloor)
1820 		return luaL_error(L, "accessed ffloor_t doesn't exist anymore.");
1821 
1822 	if (hud_running)
1823 		return luaL_error(L, "Do not alter ffloor_t in HUD rendering code!");
1824 	if (hook_cmd_running)
1825 		return luaL_error(L, "Do not alter ffloor_t in CMD building code!");
1826 
1827 	switch(field)
1828 	{
1829 	case ffloor_valid: // valid
1830 	case ffloor_tslope: // t_slope
1831 	case ffloor_bslope: // b_slope
1832 	case ffloor_sector: // sector
1833 	case ffloor_master: // master
1834 	case ffloor_target: // target
1835 	case ffloor_next: // next
1836 	case ffloor_prev: // prev
1837 	default:
1838 		return luaL_error(L, "ffloor_t field " LUA_QS " cannot be set.", ffloor_opt[field]);
1839 	case ffloor_topheight: { // topheight
1840 		boolean flag;
1841 		fixed_t lastpos = *ffloor->topheight;
1842 		mobj_t *ptmthing = tmthing;
1843 		sector_t *sector = &sectors[ffloor->secnum];
1844 		sector->ceilingheight = luaL_checkfixed(L, 3);
1845 		flag = P_CheckSector(sector, true);
1846 		if (flag && sector->numattached)
1847 		{
1848 			*ffloor->topheight = lastpos;
1849 			P_CheckSector(sector, true);
1850 		}
1851 		P_SetTarget(&tmthing, ptmthing);
1852 		break;
1853 	}
1854 	case ffloor_toppic:
1855 		*ffloor->toppic = P_AddLevelFlatRuntime(luaL_checkstring(L, 3));
1856 		break;
1857 	case ffloor_toplightlevel:
1858 		*ffloor->toplightlevel = (INT16)luaL_checkinteger(L, 3);
1859 		break;
1860 	case ffloor_bottomheight: { // bottomheight
1861 		boolean flag;
1862 		fixed_t lastpos = *ffloor->bottomheight;
1863 		mobj_t *ptmthing = tmthing;
1864 		sector_t *sector = &sectors[ffloor->secnum];
1865 		sector->floorheight = luaL_checkfixed(L, 3);
1866 		flag = P_CheckSector(sector, true);
1867 		if (flag && sector->numattached)
1868 		{
1869 			*ffloor->bottomheight = lastpos;
1870 			P_CheckSector(sector, true);
1871 		}
1872 		P_SetTarget(&tmthing, ptmthing);
1873 		break;
1874 	}
1875 	case ffloor_bottompic:
1876 		*ffloor->bottompic = P_AddLevelFlatRuntime(luaL_checkstring(L, 3));
1877 		break;
1878 	case ffloor_flags: {
1879 		ffloortype_e oldflags = ffloor->flags; // store FOF's old flags
1880 		ffloor->flags = luaL_checkinteger(L, 3);
1881 		if (ffloor->flags != oldflags)
1882 			ffloor->target->moved = true; // reset target sector's lightlist
1883 		break;
1884 	}
1885 	case ffloor_alpha:
1886 		ffloor->alpha = (INT32)luaL_checkinteger(L, 3);
1887 		break;
1888 	}
1889 	return 0;
1890 }
1891 
1892 //////////////
1893 // pslope_t //
1894 //////////////
1895 
slope_get(lua_State * L)1896 static int slope_get(lua_State *L)
1897 {
1898 	pslope_t *slope = *((pslope_t **)luaL_checkudata(L, 1, META_SLOPE));
1899 	enum slope_e field = luaL_checkoption(L, 2, slope_opt[0], slope_opt);
1900 
1901 	if (!slope)
1902 	{
1903 		if (field == slope_valid) {
1904 			lua_pushboolean(L, 0);
1905 			return 1;
1906 		}
1907 		return luaL_error(L, "accessed pslope_t doesn't exist anymore.");
1908 	}
1909 
1910 	switch(field)
1911 	{
1912 	case slope_valid: // valid
1913 		lua_pushboolean(L, 1);
1914 		return 1;
1915 	case slope_o: // o
1916 		LUA_PushUserdata(L, &slope->o, META_VECTOR3);
1917 		return 1;
1918 	case slope_d: // d
1919 		LUA_PushUserdata(L, &slope->d, META_VECTOR2);
1920 		return 1;
1921 	case slope_zdelta: // zdelta
1922 		lua_pushfixed(L, slope->zdelta);
1923 		return 1;
1924 	case slope_normal: // normal
1925 		LUA_PushUserdata(L, &slope->normal, META_VECTOR3);
1926 		return 1;
1927 	case slope_zangle: // zangle
1928 		lua_pushangle(L, slope->zangle);
1929 		return 1;
1930 	case slope_xydirection: // xydirection
1931 		lua_pushangle(L, slope->xydirection);
1932 		return 1;
1933 	case slope_flags: // flags
1934 		lua_pushinteger(L, slope->flags);
1935 		return 1;
1936 	}
1937 	return 0;
1938 }
1939 
slope_set(lua_State * L)1940 static int slope_set(lua_State *L)
1941 {
1942 	pslope_t *slope = *((pslope_t **)luaL_checkudata(L, 1, META_SLOPE));
1943 	enum slope_e field = luaL_checkoption(L, 2, slope_opt[0], slope_opt);
1944 
1945 	if (!slope)
1946 		return luaL_error(L, "accessed pslope_t doesn't exist anymore.");
1947 
1948 	if (hud_running)
1949 		return luaL_error(L, "Do not alter pslope_t in HUD rendering code!");
1950 	if (hook_cmd_running)
1951 		return luaL_error(L, "Do not alter pslope_t in CMD building code!");
1952 
1953 	switch(field) // todo: reorganize this shit
1954 	{
1955 	case slope_valid: // valid
1956 	case slope_d: // d
1957 	case slope_flags: // flags
1958 	case slope_normal: // normal
1959 	default:
1960 		return luaL_error(L, "pslope_t field " LUA_QS " cannot be set.", slope_opt[field]);
1961 	case slope_o: { // o
1962 		luaL_checktype(L, 3, LUA_TTABLE);
1963 
1964 		lua_getfield(L, 3, "x");
1965 		if (lua_isnil(L, -1))
1966 		{
1967 			lua_pop(L, 1);
1968 			lua_rawgeti(L, 3, 1);
1969 		}
1970 		if (!lua_isnil(L, -1))
1971 			slope->o.x = luaL_checkfixed(L, -1);
1972 		else
1973 			slope->o.x = 0;
1974 		lua_pop(L, 1);
1975 
1976 		lua_getfield(L, 3, "y");
1977 		if (lua_isnil(L, -1))
1978 		{
1979 			lua_pop(L, 1);
1980 			lua_rawgeti(L, 3, 2);
1981 		}
1982 		if (!lua_isnil(L, -1))
1983 			slope->o.y = luaL_checkfixed(L, -1);
1984 		else
1985 			slope->o.y = 0;
1986 		lua_pop(L, 1);
1987 
1988 		lua_getfield(L, 3, "z");
1989 		if (lua_isnil(L, -1))
1990 		{
1991 			lua_pop(L, 1);
1992 			lua_rawgeti(L, 3, 3);
1993 		}
1994 		if (!lua_isnil(L, -1))
1995 			slope->o.z = luaL_checkfixed(L, -1);
1996 		else
1997 			slope->o.z = 0;
1998 		lua_pop(L, 1);
1999 		break;
2000 	}
2001 	case slope_zdelta: { // zdelta, this is temp until i figure out wtf to do
2002 		slope->zdelta = luaL_checkfixed(L, 3);
2003 		slope->zangle = R_PointToAngle2(0, 0, FRACUNIT, -slope->zdelta);
2004 		P_CalculateSlopeNormal(slope);
2005 		break;
2006 	}
2007 	case slope_zangle: { // zangle
2008 		angle_t zangle = luaL_checkangle(L, 3);
2009 		if (zangle == ANGLE_90 || zangle == ANGLE_270)
2010 			return luaL_error(L, "invalid zangle for slope!");
2011 		slope->zangle = zangle;
2012 		slope->zdelta = -FINETANGENT(((slope->zangle+ANGLE_90)>>ANGLETOFINESHIFT) & 4095);
2013 		P_CalculateSlopeNormal(slope);
2014 		break;
2015 	}
2016 	case slope_xydirection: // xydirection
2017 		slope->xydirection = luaL_checkangle(L, 3);
2018 		slope->d.x = -FINECOSINE((slope->xydirection>>ANGLETOFINESHIFT) & FINEMASK);
2019 		slope->d.y = -FINESINE((slope->xydirection>>ANGLETOFINESHIFT) & FINEMASK);
2020 		P_CalculateSlopeNormal(slope);
2021 		break;
2022 	}
2023 	return 0;
2024 }
2025 
2026 ///////////////
2027 // vector*_t //
2028 ///////////////
2029 
vector2_get(lua_State * L)2030 static int vector2_get(lua_State *L)
2031 {
2032 	vector2_t *vec = *((vector2_t **)luaL_checkudata(L, 1, META_VECTOR2));
2033 	enum vector_e field = luaL_checkoption(L, 2, vector_opt[0], vector_opt);
2034 
2035 	if (!vec)
2036 		return luaL_error(L, "accessed vector2_t doesn't exist anymore.");
2037 
2038 	switch(field)
2039 	{
2040 		case vector_x: lua_pushfixed(L, vec->x); return 1;
2041 		case vector_y: lua_pushfixed(L, vec->y); return 1;
2042 		default: break;
2043 	}
2044 
2045 	return 0;
2046 }
2047 
vector3_get(lua_State * L)2048 static int vector3_get(lua_State *L)
2049 {
2050 	vector3_t *vec = *((vector3_t **)luaL_checkudata(L, 1, META_VECTOR3));
2051 	enum vector_e field = luaL_checkoption(L, 2, vector_opt[0], vector_opt);
2052 
2053 	if (!vec)
2054 		return luaL_error(L, "accessed vector3_t doesn't exist anymore.");
2055 
2056 	switch(field)
2057 	{
2058 		case vector_x: lua_pushfixed(L, vec->x); return 1;
2059 		case vector_y: lua_pushfixed(L, vec->y); return 1;
2060 		case vector_z: lua_pushfixed(L, vec->z); return 1;
2061 		default: break;
2062 	}
2063 
2064 	return 0;
2065 }
2066 
2067 /////////////////////
2068 // mapheaderinfo[] //
2069 /////////////////////
2070 
lib_getMapheaderinfo(lua_State * L)2071 static int lib_getMapheaderinfo(lua_State *L)
2072 {
2073 	// i -> mapheaderinfo[i-1]
2074 
2075 	//int field;
2076 	lua_settop(L, 2);
2077 	lua_remove(L, 1); // dummy userdata table is unused.
2078 	if (lua_isnumber(L, 1))
2079 	{
2080 		size_t i = lua_tointeger(L, 1)-1;
2081 		if (i >= NUMMAPS)
2082 			return 0;
2083 		LUA_PushUserdata(L, mapheaderinfo[i], META_MAPHEADER);
2084 		//CONS_Printf(mapheaderinfo[i]->lvlttl);
2085 		return 1;
2086 	}/*
2087 	field = luaL_checkoption(L, 1, NULL, array_opt);
2088 	switch(field)
2089 	{
2090 	case 0: // iterate
2091 		lua_pushcfunction(L, lib_iterateSubsectors);
2092 		return 1;
2093 	}*/
2094 	return 0;
2095 }
2096 
lib_nummapheaders(lua_State * L)2097 static int lib_nummapheaders(lua_State *L)
2098 {
2099 	lua_pushinteger(L, NUMMAPS);
2100 	return 1;
2101 }
2102 
2103 /////////////////
2104 // mapheader_t //
2105 /////////////////
2106 
mapheaderinfo_get(lua_State * L)2107 static int mapheaderinfo_get(lua_State *L)
2108 {
2109 	mapheader_t *header = *((mapheader_t **)luaL_checkudata(L, 1, META_MAPHEADER));
2110 	const char *field = luaL_checkstring(L, 2);
2111 	INT16 i;
2112 	if (fastcmp(field,"lvlttl"))
2113 		lua_pushstring(L, header->lvlttl);
2114 	else if (fastcmp(field,"subttl"))
2115 		lua_pushstring(L, header->subttl);
2116 	else if (fastcmp(field,"actnum"))
2117 		lua_pushinteger(L, header->actnum);
2118 	else if (fastcmp(field,"typeoflevel"))
2119 		lua_pushinteger(L, header->typeoflevel);
2120 	else if (fastcmp(field,"nextlevel"))
2121 		lua_pushinteger(L, header->nextlevel);
2122 	else if (fastcmp(field,"marathonnext"))
2123 		lua_pushinteger(L, header->marathonnext);
2124 	else if (fastcmp(field,"keywords"))
2125 		lua_pushstring(L, header->keywords);
2126 	else if (fastcmp(field,"musname"))
2127 		lua_pushstring(L, header->musname);
2128 	else if (fastcmp(field,"mustrack"))
2129 		lua_pushinteger(L, header->mustrack);
2130 	else if (fastcmp(field,"muspos"))
2131 		lua_pushinteger(L, header->muspos);
2132 	else if (fastcmp(field,"musinterfadeout"))
2133 		lua_pushinteger(L, header->musinterfadeout);
2134 	else if (fastcmp(field,"musintername"))
2135 		lua_pushstring(L, header->musintername);
2136 	else if (fastcmp(field,"muspostbossname"))
2137 		lua_pushstring(L, header->muspostbossname);
2138 	else if (fastcmp(field,"muspostbosstrack"))
2139 		lua_pushinteger(L, header->muspostbosstrack);
2140 	else if (fastcmp(field,"muspostbosspos"))
2141 		lua_pushinteger(L, header->muspostbosspos);
2142 	else if (fastcmp(field,"muspostbossfadein"))
2143 		lua_pushinteger(L, header->muspostbossfadein);
2144 	else if (fastcmp(field,"musforcereset"))
2145 		lua_pushinteger(L, header->musforcereset);
2146 	else if (fastcmp(field,"forcecharacter"))
2147 		lua_pushstring(L, header->forcecharacter);
2148 	else if (fastcmp(field,"weather"))
2149 		lua_pushinteger(L, header->weather);
2150 	else if (fastcmp(field,"skynum"))
2151 		lua_pushinteger(L, header->skynum);
2152 	else if (fastcmp(field,"skybox_scalex"))
2153 		lua_pushinteger(L, header->skybox_scalex);
2154 	else if (fastcmp(field,"skybox_scaley"))
2155 		lua_pushinteger(L, header->skybox_scaley);
2156 	else if (fastcmp(field,"skybox_scalez"))
2157 		lua_pushinteger(L, header->skybox_scalez);
2158 	else if (fastcmp(field,"interscreen")) {
2159 		for (i = 0; i < 8; i++)
2160 			if (!header->interscreen[i])
2161 				break;
2162 		lua_pushlstring(L, header->interscreen, i);
2163 	} else if (fastcmp(field,"runsoc"))
2164 		lua_pushstring(L, header->runsoc);
2165 	else if (fastcmp(field,"scriptname"))
2166 		lua_pushstring(L, header->scriptname);
2167 	else if (fastcmp(field,"precutscenenum"))
2168 		lua_pushinteger(L, header->precutscenenum);
2169 	else if (fastcmp(field,"cutscenenum"))
2170 		lua_pushinteger(L, header->cutscenenum);
2171 	else if (fastcmp(field,"countdown"))
2172 		lua_pushinteger(L, header->countdown);
2173 	else if (fastcmp(field,"palette"))
2174 		lua_pushinteger(L, header->palette);
2175 	else if (fastcmp(field,"numlaps"))
2176 		lua_pushinteger(L, header->numlaps);
2177 	else if (fastcmp(field,"unlockrequired"))
2178 		lua_pushinteger(L, header->unlockrequired);
2179 	else if (fastcmp(field,"levelselect"))
2180 		lua_pushinteger(L, header->levelselect);
2181 	else if (fastcmp(field,"bonustype"))
2182 		lua_pushinteger(L, header->bonustype);
2183 	else if (fastcmp(field,"ltzzpatch"))
2184 		lua_pushstring(L, header->ltzzpatch);
2185 	else if (fastcmp(field,"ltzztext"))
2186 		lua_pushstring(L, header->ltzztext);
2187 	else if (fastcmp(field,"ltactdiamond"))
2188 		lua_pushstring(L, header->ltactdiamond);
2189 	else if (fastcmp(field,"maxbonuslives"))
2190 		lua_pushinteger(L, header->maxbonuslives);
2191 	else if (fastcmp(field,"levelflags"))
2192 		lua_pushinteger(L, header->levelflags);
2193 	else if (fastcmp(field,"menuflags"))
2194 		lua_pushinteger(L, header->menuflags);
2195 	else if (fastcmp(field,"selectheading"))
2196 		lua_pushstring(L, header->selectheading);
2197 	else if (fastcmp(field,"startrings"))
2198 		lua_pushinteger(L, header->startrings);
2199 	else if (fastcmp(field, "sstimer"))
2200 		lua_pushinteger(L, header->sstimer);
2201 	else if (fastcmp(field, "ssspheres"))
2202 		lua_pushinteger(L, header->ssspheres);
2203 	else if (fastcmp(field, "gravity"))
2204 		lua_pushfixed(L, header->gravity);
2205 	// TODO add support for reading numGradedMares and grades
2206 	else {
2207 		// Read custom vars now
2208 		// (note: don't include the "LUA." in your lua scripts!)
2209 		UINT8 j = 0;
2210 		for (;j < header->numCustomOptions && !fastcmp(field, header->customopts[j].option); ++j);
2211 
2212 		if(j < header->numCustomOptions)
2213 			lua_pushstring(L, header->customopts[j].value);
2214 		else
2215 			lua_pushnil(L);
2216 	}
2217 	return 1;
2218 }
2219 
LUA_MapLib(lua_State * L)2220 int LUA_MapLib(lua_State *L)
2221 {
2222 	luaL_newmetatable(L, META_SECTORLINES);
2223 		lua_pushcfunction(L, sectorlines_get);
2224 		lua_setfield(L, -2, "__index");
2225 
2226 		lua_pushcfunction(L, sectorlines_num);
2227 		lua_setfield(L, -2, "__len");
2228 	lua_pop(L, 1);
2229 
2230 	luaL_newmetatable(L, META_SECTOR);
2231 		lua_pushcfunction(L, sector_get);
2232 		lua_setfield(L, -2, "__index");
2233 
2234 		lua_pushcfunction(L, sector_set);
2235 		lua_setfield(L, -2, "__newindex");
2236 
2237 		lua_pushcfunction(L, sector_num);
2238 		lua_setfield(L, -2, "__len");
2239 	lua_pop(L, 1);
2240 
2241 	luaL_newmetatable(L, META_SUBSECTOR);
2242 		lua_pushcfunction(L, subsector_get);
2243 		lua_setfield(L, -2, "__index");
2244 
2245 		lua_pushcfunction(L, subsector_num);
2246 		lua_setfield(L, -2, "__len");
2247 	lua_pop(L, 1);
2248 
2249 	luaL_newmetatable(L, META_LINE);
2250 		lua_pushcfunction(L, line_get);
2251 		lua_setfield(L, -2, "__index");
2252 
2253 		lua_pushcfunction(L, line_num);
2254 		lua_setfield(L, -2, "__len");
2255 	lua_pop(L, 1);
2256 
2257 	luaL_newmetatable(L, META_LINEARGS);
2258 		lua_pushcfunction(L, lineargs_get);
2259 		lua_setfield(L, -2, "__index");
2260 
2261 		lua_pushcfunction(L, lineargs_len);
2262 		lua_setfield(L, -2, "__len");
2263 	lua_pop(L, 1);
2264 
2265 	luaL_newmetatable(L, META_LINESTRINGARGS);
2266 		lua_pushcfunction(L, linestringargs_get);
2267 		lua_setfield(L, -2, "__index");
2268 
2269 		lua_pushcfunction(L, linestringargs_len);
2270 		lua_setfield(L, -2, "__len");
2271 	lua_pop(L, 1);
2272 
2273 	luaL_newmetatable(L, META_SIDENUM);
2274 		lua_pushcfunction(L, sidenum_get);
2275 		lua_setfield(L, -2, "__index");
2276 	lua_pop(L, 1);
2277 
2278 	luaL_newmetatable(L, META_SIDE);
2279 		lua_pushcfunction(L, side_get);
2280 		lua_setfield(L, -2, "__index");
2281 
2282 		lua_pushcfunction(L, side_set);
2283 		lua_setfield(L, -2, "__newindex");
2284 
2285 		lua_pushcfunction(L, side_num);
2286 		lua_setfield(L, -2, "__len");
2287 	lua_pop(L, 1);
2288 
2289 	luaL_newmetatable(L, META_VERTEX);
2290 		lua_pushcfunction(L, vertex_get);
2291 		lua_setfield(L, -2, "__index");
2292 
2293 		lua_pushcfunction(L, vertex_num);
2294 		lua_setfield(L, -2, "__len");
2295 	lua_pop(L, 1);
2296 
2297 	luaL_newmetatable(L, META_FFLOOR);
2298 		lua_pushcfunction(L, ffloor_get);
2299 		lua_setfield(L, -2, "__index");
2300 
2301 		lua_pushcfunction(L, ffloor_set);
2302 		lua_setfield(L, -2, "__newindex");
2303 	lua_pop(L, 1);
2304 
2305 #ifdef HAVE_LUA_SEGS
2306 	luaL_newmetatable(L, META_SEG);
2307 		lua_pushcfunction(L, seg_get);
2308 		lua_setfield(L, -2, "__index");
2309 
2310 		lua_pushcfunction(L, seg_num);
2311 		lua_setfield(L, -2, "__len");
2312 	lua_pop(L, 1);
2313 
2314 	luaL_newmetatable(L, META_NODE);
2315 		lua_pushcfunction(L, node_get);
2316 		lua_setfield(L, -2, "__index");
2317 
2318 		lua_pushcfunction(L, node_num);
2319 		lua_setfield(L, -2, "__len");
2320 	lua_pop(L, 1);
2321 
2322 	luaL_newmetatable(L, META_NODEBBOX);
2323 		//lua_pushcfunction(L, nodebbox_get);
2324 		//lua_setfield(L, -2, "__index");
2325 		lua_pushcfunction(L, nodebbox_call);
2326 		lua_setfield(L, -2, "__call");
2327 	lua_pop(L, 1);
2328 
2329 	luaL_newmetatable(L, META_NODECHILDREN);
2330 		lua_pushcfunction(L, nodechildren_get);
2331 		lua_setfield(L, -2, "__index");
2332 	lua_pop(L, 1);
2333 #endif
2334 
2335 	luaL_newmetatable(L, META_BBOX);
2336 		lua_pushcfunction(L, bbox_get);
2337 		lua_setfield(L, -2, "__index");
2338 	lua_pop(L, 1);
2339 
2340 	luaL_newmetatable(L, META_SLOPE);
2341 		lua_pushcfunction(L, slope_get);
2342 		lua_setfield(L, -2, "__index");
2343 
2344 		lua_pushcfunction(L, slope_set);
2345 		lua_setfield(L, -2, "__newindex");
2346 	lua_pop(L, 1);
2347 
2348 	luaL_newmetatable(L, META_VECTOR2);
2349 		lua_pushcfunction(L, vector2_get);
2350 		lua_setfield(L, -2, "__index");
2351 	lua_pop(L, 1);
2352 
2353 	luaL_newmetatable(L, META_VECTOR3);
2354 		lua_pushcfunction(L, vector3_get);
2355 		lua_setfield(L, -2, "__index");
2356 	lua_pop(L, 1);
2357 
2358 	luaL_newmetatable(L, META_MAPHEADER);
2359 		lua_pushcfunction(L, mapheaderinfo_get);
2360 		lua_setfield(L, -2, "__index");
2361 
2362 		//lua_pushcfunction(L, mapheaderinfo_num);
2363 		//lua_setfield(L, -2, "__len");
2364 	lua_pop(L, 1);
2365 
2366 	LUA_PushTaggableObjectArray(L, "sectors",
2367 			lib_iterateSectors,
2368 			lib_getSector,
2369 			lib_numsectors,
2370 			tags_sectors,
2371 			&numsectors, &sectors,
2372 			sizeof (sector_t), META_SECTOR);
2373 
2374 	lua_newuserdata(L, 0);
2375 		lua_createtable(L, 0, 2);
2376 			lua_pushcfunction(L, lib_getSubsector);
2377 			lua_setfield(L, -2, "__index");
2378 
2379 			lua_pushcfunction(L, lib_numsubsectors);
2380 			lua_setfield(L, -2, "__len");
2381 		lua_setmetatable(L, -2);
2382 	lua_setglobal(L, "subsectors");
2383 
2384 	LUA_PushTaggableObjectArray(L, "lines",
2385 			lib_iterateLines,
2386 			lib_getLine,
2387 			lib_numlines,
2388 			tags_lines,
2389 			&numlines, &lines,
2390 			sizeof (line_t), META_LINE);
2391 
2392 	lua_newuserdata(L, 0);
2393 		lua_createtable(L, 0, 2);
2394 			lua_pushcfunction(L, lib_getSide);
2395 			lua_setfield(L, -2, "__index");
2396 
2397 			lua_pushcfunction(L, lib_numsides);
2398 			lua_setfield(L, -2, "__len");
2399 		lua_setmetatable(L, -2);
2400 	lua_setglobal(L, "sides");
2401 
2402 	lua_newuserdata(L, 0);
2403 		lua_createtable(L, 0, 2);
2404 			lua_pushcfunction(L, lib_getVertex);
2405 			lua_setfield(L, -2, "__index");
2406 
2407 			lua_pushcfunction(L, lib_numvertexes);
2408 			lua_setfield(L, -2, "__len");
2409 		lua_setmetatable(L, -2);
2410 	lua_setglobal(L, "vertexes");
2411 
2412 #ifdef HAVE_LUA_SEGS
2413 	lua_newuserdata(L, 0);
2414 		lua_createtable(L, 0, 2);
2415 			lua_pushcfunction(L, lib_getSeg);
2416 			lua_setfield(L, -2, "__index");
2417 
2418 			lua_pushcfunction(L, lib_numsegs);
2419 			lua_setfield(L, -2, "__len");
2420 		lua_setmetatable(L, -2);
2421 	lua_setglobal(L, "segs");
2422 
2423 	lua_newuserdata(L, 0);
2424 		lua_createtable(L, 0, 2);
2425 			lua_pushcfunction(L, lib_getNode);
2426 			lua_setfield(L, -2, "__index");
2427 
2428 			lua_pushcfunction(L, lib_numnodes);
2429 			lua_setfield(L, -2, "__len");
2430 		lua_setmetatable(L, -2);
2431 	lua_setglobal(L, "nodes");
2432 #endif
2433 
2434 	lua_newuserdata(L, 0);
2435 		lua_createtable(L, 0, 2);
2436 			lua_pushcfunction(L, lib_getMapheaderinfo);
2437 			lua_setfield(L, -2, "__index");
2438 
2439 			lua_pushcfunction(L, lib_nummapheaders);
2440 			lua_setfield(L, -2, "__len");
2441 		lua_setmetatable(L, -2);
2442 	lua_setglobal(L, "mapheaderinfo");
2443 	return 0;
2444 }
2445