1 // SONIC ROBO BLAST 2
2 //-----------------------------------------------------------------------------
3 // Copyright (C) 2014-2016 by John "JTE" Muniz.
4 // Copyright (C) 2014-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_hudlib.c
11 /// \brief custom HUD rendering library for Lua scripting
12 
13 #include "doomdef.h"
14 #include "fastcmp.h"
15 #include "r_defs.h"
16 #include "r_local.h"
17 #include "st_stuff.h" // hudinfo[]
18 #include "g_game.h"
19 #include "i_video.h" // rendermode
20 #include "p_local.h" // camera_t
21 #include "screen.h" // screen width/height
22 #include "m_random.h" // m_random
23 #include "v_video.h"
24 #include "w_wad.h"
25 #include "z_zone.h"
26 
27 #include "lua_script.h"
28 #include "lua_libs.h"
29 #include "lua_hud.h"
30 
31 #define HUDONLY if (!hud_running) return luaL_error(L, "HUD rendering code should not be called outside of rendering hooks!");
32 
33 boolean hud_running = false;
34 static UINT8 hud_enabled[(hud_MAX/8)+1];
35 
36 static UINT8 hudAvailable; // hud hooks field
37 
38 // must match enum hud in lua_hud.h
39 static const char *const hud_disable_options[] = {
40 	"stagetitle",
41 	"textspectator",
42 	"crosshair",
43 
44 	"score",
45 	"time",
46 	"rings",
47 	"lives",
48 
49 	"weaponrings",
50 	"powerstones",
51 	"teamscores",
52 
53 	"nightslink",
54 	"nightsdrill",
55 	"nightsrings",
56 	"nightsscore",
57 	"nightstime",
58 	"nightsrecords",
59 
60 	"rankings",
61 	"coopemeralds",
62 	"tokens",
63 	"tabemblems",
64 
65 	"intermissiontally",
66 	"intermissionmessages",
67 	NULL};
68 
69 enum hudinfo {
70 	hudinfo_x = 0,
71 	hudinfo_y,
72 	hudinfo_f
73 };
74 
75 static const char *const hudinfo_opt[] = {
76 	"x",
77 	"y",
78 	"f",
79 	NULL};
80 
81 enum patch {
82 	patch_valid = 0,
83 	patch_width,
84 	patch_height,
85 	patch_leftoffset,
86 	patch_topoffset
87 };
88 static const char *const patch_opt[] = {
89 	"valid",
90 	"width",
91 	"height",
92 	"leftoffset",
93 	"topoffset",
94 	NULL};
95 
96 enum hudhook {
97 	hudhook_game = 0,
98 	hudhook_scores,
99 	hudhook_intermission,
100 	hudhook_title,
101 	hudhook_titlecard
102 };
103 static const char *const hudhook_opt[] = {
104 	"game",
105 	"scores",
106 	"intermission",
107 	"title",
108 	"titlecard",
109 	NULL};
110 
111 // alignment types for v.drawString
112 enum align {
113 	align_left = 0,
114 	align_center,
115 	align_right,
116 	align_fixed,
117 	align_fixedcenter,
118 	align_fixedright,
119 	align_small,
120 	align_smallfixed,
121 	align_smallfixedcenter,
122 	align_smallfixedright,
123 	align_smallcenter,
124 	align_smallright,
125 	align_smallthin,
126 	align_smallthincenter,
127 	align_smallthinright,
128 	align_smallthinfixed,
129 	align_smallthinfixedcenter,
130 	align_smallthinfixedright,
131 	align_thin,
132 	align_thinfixed,
133 	align_thinfixedcenter,
134 	align_thinfixedright,
135 	align_thincenter,
136 	align_thinright
137 };
138 static const char *const align_opt[] = {
139 	"left",
140 	"center",
141 	"right",
142 	"fixed",
143 	"fixed-center",
144 	"fixed-right",
145 	"small",
146 	"small-fixed",
147 	"small-fixed-center",
148 	"small-fixed-right",
149 	"small-center",
150 	"small-right",
151 	"small-thin",
152 	"small-thin-center",
153 	"small-thin-right",
154 	"small-thin-fixed",
155 	"small-thin-fixed-center",
156 	"small-thin-fixed-right",
157 	"thin",
158 	"thin-fixed",
159 	"thin-fixed-center",
160 	"thin-fixed-right",
161 	"thin-center",
162 	"thin-right",
163 	NULL};
164 
165 // width types for v.stringWidth
166 enum widtht {
167 	widtht_normal = 0,
168 	widtht_small,
169 	widtht_thin
170 };
171 static const char *const widtht_opt[] = {
172 	"normal",
173 	"small",
174 	"thin",
175 	NULL};
176 
177 enum cameraf {
178 	camera_chase = 0,
179 	camera_aiming,
180 	camera_x,
181 	camera_y,
182 	camera_z,
183 	camera_angle,
184 	camera_subsector,
185 	camera_floorz,
186 	camera_ceilingz,
187 	camera_radius,
188 	camera_height,
189 	camera_momx,
190 	camera_momy,
191 	camera_momz
192 };
193 
194 
195 static const char *const camera_opt[] = {
196 	"chase",
197 	"aiming",
198 	"x",
199 	"y",
200 	"z",
201 	"angle",
202 	"subsector",
203 	"floorz",
204 	"ceilingz",
205 	"radius",
206 	"height",
207 	"momx",
208 	"momy",
209 	"momz",
210 	NULL};
211 
lib_getHudInfo(lua_State * L)212 static int lib_getHudInfo(lua_State *L)
213 {
214 	UINT32 i;
215 	lua_remove(L, 1);
216 
217 	i = luaL_checkinteger(L, 1);
218 	if (i >= NUMHUDITEMS)
219 		return luaL_error(L, "hudinfo[] index %d out of range (0 - %d)", i, NUMHUDITEMS-1);
220 	LUA_PushUserdata(L, &hudinfo[i], META_HUDINFO);
221 	return 1;
222 }
223 
lib_hudinfolen(lua_State * L)224 static int lib_hudinfolen(lua_State *L)
225 {
226 	lua_pushinteger(L, NUMHUDITEMS);
227 	return 1;
228 }
229 
hudinfo_get(lua_State * L)230 static int hudinfo_get(lua_State *L)
231 {
232 	hudinfo_t *info = *((hudinfo_t **)luaL_checkudata(L, 1, META_HUDINFO));
233 	enum hudinfo field = luaL_checkoption(L, 2, hudinfo_opt[0], hudinfo_opt);
234 	I_Assert(info != NULL); // huditems are always valid
235 
236 	switch(field)
237 	{
238 	case hudinfo_x:
239 		lua_pushinteger(L, info->x);
240 		break;
241 	case hudinfo_y:
242 		lua_pushinteger(L, info->y);
243 		break;
244 	case hudinfo_f:
245 		lua_pushinteger(L, info->f);
246 		break;
247 	}
248 	return 1;
249 }
250 
hudinfo_set(lua_State * L)251 static int hudinfo_set(lua_State *L)
252 {
253 	hudinfo_t *info = *((hudinfo_t **)luaL_checkudata(L, 1, META_HUDINFO));
254 	enum hudinfo field = luaL_checkoption(L, 2, hudinfo_opt[0], hudinfo_opt);
255 	I_Assert(info != NULL);
256 
257 	switch(field)
258 	{
259 	case hudinfo_x:
260 		info->x = (INT32)luaL_checkinteger(L, 3);
261 		break;
262 	case hudinfo_y:
263 		info->y = (INT32)luaL_checkinteger(L, 3);
264 		break;
265 	case hudinfo_f:
266 		info->f = (INT32)luaL_checkinteger(L, 3);
267 		break;
268 	}
269 	return 0;
270 }
271 
hudinfo_num(lua_State * L)272 static int hudinfo_num(lua_State *L)
273 {
274 	hudinfo_t *info = *((hudinfo_t **)luaL_checkudata(L, 1, META_HUDINFO));
275 	lua_pushinteger(L, info-hudinfo);
276 	return 1;
277 }
278 
colormap_get(lua_State * L)279 static int colormap_get(lua_State *L)
280 {
281 	const UINT8 *colormap = *((UINT8 **)luaL_checkudata(L, 1, META_COLORMAP));
282 	UINT32 i = luaL_checkinteger(L, 2);
283 	if (i >= 256)
284 		return luaL_error(L, "colormap index %d out of range (0 - %d)", i, 255);
285 	lua_pushinteger(L, colormap[i]);
286 	return 1;
287 }
288 
patch_get(lua_State * L)289 static int patch_get(lua_State *L)
290 {
291 	patch_t *patch = *((patch_t **)luaL_checkudata(L, 1, META_PATCH));
292 	enum patch field = luaL_checkoption(L, 2, NULL, patch_opt);
293 
294 	// patches are invalidated when switching renderers
295 	if (!patch) {
296 		if (field == patch_valid) {
297 			lua_pushboolean(L, 0);
298 			return 1;
299 		}
300 		return LUA_ErrInvalid(L, "patch_t");
301 	}
302 
303 	switch (field)
304 	{
305 	case patch_valid:
306 		lua_pushboolean(L, patch != NULL);
307 		break;
308 	case patch_width:
309 		lua_pushinteger(L, patch->width);
310 		break;
311 	case patch_height:
312 		lua_pushinteger(L, patch->height);
313 		break;
314 	case patch_leftoffset:
315 		lua_pushinteger(L, patch->leftoffset);
316 		break;
317 	case patch_topoffset:
318 		lua_pushinteger(L, patch->topoffset);
319 		break;
320 	}
321 	return 1;
322 }
323 
patch_set(lua_State * L)324 static int patch_set(lua_State *L)
325 {
326 	return luaL_error(L, LUA_QL("patch_t") " struct cannot be edited by Lua.");
327 }
328 
camera_get(lua_State * L)329 static int camera_get(lua_State *L)
330 {
331 	camera_t *cam = *((camera_t **)luaL_checkudata(L, 1, META_CAMERA));
332 	enum cameraf field = luaL_checkoption(L, 2, NULL, camera_opt);
333 
334 	// cameras should always be valid unless I'm a nutter
335 	I_Assert(cam != NULL);
336 
337 	switch (field)
338 	{
339 	case camera_chase:
340 		lua_pushboolean(L, cam->chase);
341 		break;
342 	case camera_aiming:
343 		lua_pushinteger(L, cam->aiming);
344 		break;
345 	case camera_x:
346 		lua_pushinteger(L, cam->x);
347 		break;
348 	case camera_y:
349 		lua_pushinteger(L, cam->y);
350 		break;
351 	case camera_z:
352 		lua_pushinteger(L, cam->z);
353 		break;
354 	case camera_angle:
355 		lua_pushinteger(L, cam->angle);
356 		break;
357 	case camera_subsector:
358 		LUA_PushUserdata(L, cam->subsector, META_SUBSECTOR);
359 		break;
360 	case camera_floorz:
361 		lua_pushinteger(L, cam->floorz);
362 		break;
363 	case camera_ceilingz:
364 		lua_pushinteger(L, cam->ceilingz);
365 		break;
366 	case camera_radius:
367 		lua_pushinteger(L, cam->radius);
368 		break;
369 	case camera_height:
370 		lua_pushinteger(L, cam->height);
371 		break;
372 	case camera_momx:
373 		lua_pushinteger(L, cam->momx);
374 		break;
375 	case camera_momy:
376 		lua_pushinteger(L, cam->momy);
377 		break;
378 	case camera_momz:
379 		lua_pushinteger(L, cam->momz);
380 		break;
381 	}
382 	return 1;
383 }
384 
385 //
386 // lib_draw
387 //
388 
libd_patchExists(lua_State * L)389 static int libd_patchExists(lua_State *L)
390 {
391 	HUDONLY
392 	lua_pushboolean(L, W_LumpExists(luaL_checkstring(L, 1)));
393 	return 1;
394 }
395 
libd_cachePatch(lua_State * L)396 static int libd_cachePatch(lua_State *L)
397 {
398 	HUDONLY
399 	LUA_PushUserdata(L, W_CachePatchLongName(luaL_checkstring(L, 1), PU_PATCH), META_PATCH);
400 	return 1;
401 }
402 
403 // v.getSpritePatch(sprite, [frame, [angle, [rollangle]]])
libd_getSpritePatch(lua_State * L)404 static int libd_getSpritePatch(lua_State *L)
405 {
406 	UINT32 i; // sprite prefix
407 	UINT32 frame = 0; // 'A'
408 	UINT8 angle = 0;
409 	spritedef_t *sprdef;
410 	spriteframe_t *sprframe;
411 	HUDONLY
412 
413 	if (lua_isnumber(L, 1)) // sprite number given, e.g. SPR_THOK
414 	{
415 		i = lua_tonumber(L, 1);
416 		if (i >= NUMSPRITES)
417 			return 0;
418 	}
419 	else if (lua_isstring(L, 1)) // sprite prefix name given, e.g. "THOK"
420 	{
421 		const char *name = lua_tostring(L, 1);
422 		for (i = 0; i < NUMSPRITES; i++)
423 			if (fastcmp(name, sprnames[i]))
424 				break;
425 		if (i >= NUMSPRITES)
426 			return 0;
427 	}
428 	else
429 		return 0;
430 
431 	if (i == SPR_PLAY) // Use getSprite2Patch instead!
432 		return 0;
433 
434 	sprdef = &sprites[i];
435 
436 	// set frame number
437 	frame = luaL_optinteger(L, 2, 0);
438 	frame &= FF_FRAMEMASK; // ignore any bits that are not the actual frame, just in case
439 	if (frame >= sprdef->numframes)
440 		return 0;
441 	// set angle number
442 	sprframe = &sprdef->spriteframes[frame];
443 	angle = luaL_optinteger(L, 3, 1);
444 
445 	// convert WAD editor angle numbers (1-8) to internal angle numbers (0-7)
446 	// keep 0 the same since we'll make it default to angle 1 (which is internally 0)
447 	// in case somebody didn't know that angle 0 really just maps all 8/16 angles to the same patch
448 	if (angle != 0)
449 		angle--;
450 
451 	if (angle >= ((sprframe->rotate & SRF_3DGE) ? 16 : 8)) // out of range?
452 		return 0;
453 
454 #ifdef ROTSPRITE
455 	if (lua_isnumber(L, 4))
456 	{
457 		// rotsprite?????
458 		angle_t rollangle = luaL_checkangle(L, 4);
459 		INT32 rot = R_GetRollAngle(rollangle);
460 
461 		if (rot) {
462 			patch_t *rotsprite = Patch_GetRotatedSprite(sprframe, frame, angle, sprframe->flip & (1<<angle), true, &spriteinfo[i], rot);
463 			LUA_PushUserdata(L, rotsprite, META_PATCH);
464 			lua_pushboolean(L, false);
465 			lua_pushboolean(L, true);
466 			return 3;
467 		}
468 	}
469 #endif
470 
471 	// push both the patch and it's "flip" value
472 	LUA_PushUserdata(L, W_CachePatchNum(sprframe->lumppat[angle], PU_SPRITE), META_PATCH);
473 	lua_pushboolean(L, (sprframe->flip & (1<<angle)) != 0);
474 	return 2;
475 }
476 
477 // v.getSprite2Patch(skin, sprite, [super?,] [frame, [angle, [rollangle]]])
libd_getSprite2Patch(lua_State * L)478 static int libd_getSprite2Patch(lua_State *L)
479 {
480 	INT32 i; // skin number
481 	playersprite_t j; // sprite2 prefix
482 	UINT32 frame = 0; // 'A'
483 	UINT8 angle = 0;
484 	spritedef_t *sprdef;
485 	spriteframe_t *sprframe;
486 	boolean super = false; // add FF_SPR2SUPER to sprite2 if true
487 	HUDONLY
488 
489 	// get skin first!
490 	if (lua_isnumber(L, 1)) // find skin by number
491 	{
492 		i = lua_tonumber(L, 1);
493 		if (i < 0 || i >= MAXSKINS)
494 			return luaL_error(L, "skin number %d out of range (0 - %d)", i, MAXSKINS-1);
495 		if (i >= numskins)
496 			return 0;
497 	}
498 	else // find skin by name
499 	{
500 		const char *name = luaL_checkstring(L, 1);
501 		for (i = 0; i < numskins; i++)
502 			if (fastcmp(skins[i].name, name))
503 				break;
504 		if (i >= numskins)
505 			return 0;
506 	}
507 
508 	lua_remove(L, 1); // remove skin now
509 
510 	if (lua_isnumber(L, 1)) // sprite number given, e.g. SPR2_STND
511 	{
512 		j = lua_tonumber(L, 1);
513 		if (j & FF_SPR2SUPER) // e.g. SPR2_STND|FF_SPR2SUPER
514 		{
515 			super = true;
516 			j &= ~FF_SPR2SUPER; // remove flag so the next check doesn't fail
517 		}
518 		if (j >= free_spr2)
519 			return 0;
520 	}
521 	else if (lua_isstring(L, 1)) // sprite prefix name given, e.g. "STND"
522 	{
523 		const char *name = lua_tostring(L, 1);
524 		for (j = 0; j < free_spr2; j++)
525 			if (fastcmp(name, spr2names[j]))
526 				break;
527 		// if you want super flags you'll have to use the optional boolean following this
528 		if (j >= free_spr2)
529 			return 0;
530 	}
531 	else
532 		return 0;
533 
534 	if (lua_isboolean(L, 2)) // optional boolean for superness
535 	{
536 		super = lua_toboolean(L, 2); // note: this can override FF_SPR2SUPER from sprite number
537 		lua_remove(L, 2); // remove
538 	}
539 	// if it's not boolean then just assume it's the frame number
540 
541 	if (super)
542 		j |= FF_SPR2SUPER;
543 
544 	j = P_GetSkinSprite2(&skins[i], j, NULL); // feed skin and current sprite2 through to change sprite2 used if necessary
545 
546 	sprdef = &skins[i].sprites[j];
547 
548 	// set frame number
549 	frame = luaL_optinteger(L, 2, 0);
550 	frame &= FF_FRAMEMASK; // ignore any bits that are not the actual frame, just in case
551 	if (frame >= sprdef->numframes)
552 		return 0;
553 	// set angle number
554 	sprframe = &sprdef->spriteframes[frame];
555 	angle = luaL_optinteger(L, 3, 1);
556 
557 	// convert WAD editor angle numbers (1-8) to internal angle numbers (0-7)
558 	// keep 0 the same since we'll make it default to angle 1 (which is internally 0)
559 	// in case somebody didn't know that angle 0 really just maps all 8/16 angles to the same patch
560 	if (angle != 0)
561 		angle--;
562 
563 	if (angle >= ((sprframe->rotate & SRF_3DGE) ? 16 : 8)) // out of range?
564 		return 0;
565 
566 #ifdef ROTSPRITE
567 	if (lua_isnumber(L, 4))
568 	{
569 		// rotsprite?????
570 		angle_t rollangle = luaL_checkangle(L, 4);
571 		INT32 rot = R_GetRollAngle(rollangle);
572 
573 		if (rot) {
574 			patch_t *rotsprite = Patch_GetRotatedSprite(sprframe, frame, angle, sprframe->flip & (1<<angle), true, &skins[i].sprinfo[j], rot);
575 			LUA_PushUserdata(L, rotsprite, META_PATCH);
576 			lua_pushboolean(L, false);
577 			lua_pushboolean(L, true);
578 			return 3;
579 		}
580 	}
581 #endif
582 
583 	// push both the patch and it's "flip" value
584 	LUA_PushUserdata(L, W_CachePatchNum(sprframe->lumppat[angle], PU_SPRITE), META_PATCH);
585 	lua_pushboolean(L, (sprframe->flip & (1<<angle)) != 0);
586 	return 2;
587 }
588 
libd_draw(lua_State * L)589 static int libd_draw(lua_State *L)
590 {
591 	INT32 x, y, flags;
592 	patch_t *patch;
593 	const UINT8 *colormap = NULL;
594 
595 	HUDONLY
596 	x = luaL_checkinteger(L, 1);
597 	y = luaL_checkinteger(L, 2);
598 	patch = *((patch_t **)luaL_checkudata(L, 3, META_PATCH));
599 	if (!patch)
600 		return LUA_ErrInvalid(L, "patch_t");
601 	flags = luaL_optinteger(L, 4, 0);
602 	if (!lua_isnoneornil(L, 5))
603 		colormap = *((UINT8 **)luaL_checkudata(L, 5, META_COLORMAP));
604 
605 	flags &= ~V_PARAMMASK; // Don't let crashes happen.
606 
607 	V_DrawFixedPatch(x<<FRACBITS, y<<FRACBITS, FRACUNIT, flags, patch, colormap);
608 	return 0;
609 }
610 
libd_drawScaled(lua_State * L)611 static int libd_drawScaled(lua_State *L)
612 {
613 	fixed_t x, y, scale;
614 	INT32 flags;
615 	patch_t *patch;
616 	const UINT8 *colormap = NULL;
617 
618 	HUDONLY
619 	x = luaL_checkinteger(L, 1);
620 	y = luaL_checkinteger(L, 2);
621 	scale = luaL_checkinteger(L, 3);
622 	if (scale < 0)
623 		return luaL_error(L, "negative scale");
624 	patch = *((patch_t **)luaL_checkudata(L, 4, META_PATCH));
625 	if (!patch)
626 		return LUA_ErrInvalid(L, "patch_t");
627 	flags = luaL_optinteger(L, 5, 0);
628 	if (!lua_isnoneornil(L, 6))
629 		colormap = *((UINT8 **)luaL_checkudata(L, 6, META_COLORMAP));
630 
631 	flags &= ~V_PARAMMASK; // Don't let crashes happen.
632 
633 	V_DrawFixedPatch(x, y, scale, flags, patch, colormap);
634 	return 0;
635 }
636 
libd_drawStretched(lua_State * L)637 static int libd_drawStretched(lua_State *L)
638 {
639 	fixed_t x, y, hscale, vscale;
640 	INT32 flags;
641 	patch_t *patch;
642 	const UINT8 *colormap = NULL;
643 
644 	HUDONLY
645 	x = luaL_checkinteger(L, 1);
646 	y = luaL_checkinteger(L, 2);
647 	hscale = luaL_checkinteger(L, 3);
648 	if (hscale < 0)
649 		return luaL_error(L, "negative horizontal scale");
650 	vscale = luaL_checkinteger(L, 4);
651 	if (vscale < 0)
652 		return luaL_error(L, "negative vertical scale");
653 	patch = *((patch_t **)luaL_checkudata(L, 5, META_PATCH));
654 	flags = luaL_optinteger(L, 6, 0);
655 	if (!lua_isnoneornil(L, 7))
656 		colormap = *((UINT8 **)luaL_checkudata(L, 7, META_COLORMAP));
657 
658 	flags &= ~V_PARAMMASK; // Don't let crashes happen.
659 
660 	V_DrawStretchyFixedPatch(x, y, hscale, vscale, flags, patch, colormap);
661 	return 0;
662 }
663 
libd_drawNum(lua_State * L)664 static int libd_drawNum(lua_State *L)
665 {
666 	INT32 x, y, flags, num;
667 	HUDONLY
668 	x = luaL_checkinteger(L, 1);
669 	y = luaL_checkinteger(L, 2);
670 	num = luaL_checkinteger(L, 3);
671 	flags = luaL_optinteger(L, 4, 0);
672 	flags &= ~V_PARAMMASK; // Don't let crashes happen.
673 
674 	V_DrawTallNum(x, y, flags, num);
675 	return 0;
676 }
677 
libd_drawPaddedNum(lua_State * L)678 static int libd_drawPaddedNum(lua_State *L)
679 {
680 	INT32 x, y, flags, num, digits;
681 	HUDONLY
682 	x = luaL_checkinteger(L, 1);
683 	y = luaL_checkinteger(L, 2);
684 	num = labs(luaL_checkinteger(L, 3));
685 	digits = luaL_optinteger(L, 4, 2);
686 	flags = luaL_optinteger(L, 5, 0);
687 	flags &= ~V_PARAMMASK; // Don't let crashes happen.
688 
689 	V_DrawPaddedTallNum(x, y, flags, num, digits);
690 	return 0;
691 }
692 
libd_drawFill(lua_State * L)693 static int libd_drawFill(lua_State *L)
694 {
695 	INT32 x = luaL_optinteger(L, 1, 0);
696 	INT32 y = luaL_optinteger(L, 2, 0);
697 	INT32 w = luaL_optinteger(L, 3, BASEVIDWIDTH);
698 	INT32 h = luaL_optinteger(L, 4, BASEVIDHEIGHT);
699 	INT32 c = luaL_optinteger(L, 5, 31);
700 
701 	HUDONLY
702 	V_DrawFill(x, y, w, h, c);
703 	return 0;
704 }
705 
libd_drawString(lua_State * L)706 static int libd_drawString(lua_State *L)
707 {
708 	fixed_t x = luaL_checkinteger(L, 1);
709 	fixed_t y = luaL_checkinteger(L, 2);
710 	const char *str = luaL_checkstring(L, 3);
711 	INT32 flags = luaL_optinteger(L, 4, V_ALLOWLOWERCASE);
712 	enum align align = luaL_checkoption(L, 5, "left", align_opt);
713 
714 	flags &= ~V_PARAMMASK; // Don't let crashes happen.
715 
716 	HUDONLY
717 	switch(align)
718 	{
719 	// hu_font
720 	case align_left:
721 		V_DrawString(x, y, flags, str);
722 		break;
723 	case align_center:
724 		V_DrawCenteredString(x, y, flags, str);
725 		break;
726 	case align_right:
727 		V_DrawRightAlignedString(x, y, flags, str);
728 		break;
729 	case align_fixed:
730 		V_DrawStringAtFixed(x, y, flags, str);
731 		break;
732 	case align_fixedcenter:
733 		V_DrawCenteredStringAtFixed(x, y, flags, str);
734 		break;
735 	case align_fixedright:
736 		V_DrawRightAlignedStringAtFixed(x, y, flags, str);
737 		break;
738 	// hu_font, 0.5x scale
739 	case align_small:
740 		V_DrawSmallString(x, y, flags, str);
741 		break;
742 	case align_smallfixed:
743 		V_DrawSmallStringAtFixed(x, y, flags, str);
744 		break;
745 	case align_smallfixedcenter:
746 		V_DrawCenteredSmallStringAtFixed(x, y, flags, str);
747 		break;
748 	case align_smallfixedright:
749 		V_DrawRightAlignedSmallStringAtFixed(x, y, flags, str);
750 		break;
751 	case align_smallcenter:
752 		V_DrawCenteredSmallString(x, y, flags, str);
753 		break;
754 	case align_smallright:
755 		V_DrawRightAlignedSmallString(x, y, flags, str);
756 		break;
757 	case align_smallthin:
758 		V_DrawSmallThinString(x, y, flags, str);
759 		break;
760 	case align_smallthincenter:
761 		V_DrawCenteredSmallThinString(x, y, flags, str);
762 		break;
763 	case align_smallthinright:
764 		V_DrawRightAlignedSmallThinString(x, y, flags, str);
765 		break;
766 	case align_smallthinfixed:
767 		V_DrawSmallThinStringAtFixed(x, y, flags, str);
768 		break;
769 	case align_smallthinfixedcenter:
770 		V_DrawCenteredSmallThinStringAtFixed(x, y, flags, str);
771 		break;
772 	case align_smallthinfixedright:
773 		V_DrawRightAlignedSmallThinStringAtFixed(x, y, flags, str);
774 		break;
775 	// tny_font
776 	case align_thin:
777 		V_DrawThinString(x, y, flags, str);
778 		break;
779 	case align_thincenter:
780 		V_DrawCenteredThinString(x, y, flags, str);
781 		break;
782 	case align_thinright:
783 		V_DrawRightAlignedThinString(x, y, flags, str);
784 		break;
785 	case align_thinfixed:
786 		V_DrawThinStringAtFixed(x, y, flags, str);
787 		break;
788 	case align_thinfixedcenter:
789 		V_DrawCenteredThinStringAtFixed(x, y, flags, str);
790 		break;
791 	case align_thinfixedright:
792 		V_DrawRightAlignedThinStringAtFixed(x, y, flags, str);
793 		break;
794 	}
795 	return 0;
796 }
797 
libd_drawNameTag(lua_State * L)798 static int libd_drawNameTag(lua_State *L)
799 {
800 	INT32 x;
801 	INT32 y;
802 	const char *str;
803 	INT32 flags;
804 	UINT16 basecolor;
805 	UINT16 outlinecolor;
806 	UINT8 *basecolormap = NULL;
807 	UINT8 *outlinecolormap = NULL;
808 
809 	HUDONLY
810 
811 	x = luaL_checkinteger(L, 1);
812 	y = luaL_checkinteger(L, 2);
813 	str = luaL_checkstring(L, 3);
814 	flags = luaL_optinteger(L, 4, 0);
815 	basecolor = luaL_optinteger(L, 5, SKINCOLOR_BLUE);
816 	outlinecolor = luaL_optinteger(L, 6, SKINCOLOR_ORANGE);
817 	if (basecolor != SKINCOLOR_NONE)
818 		basecolormap = R_GetTranslationColormap(TC_DEFAULT, basecolor, GTC_CACHE);
819 	if (outlinecolor != SKINCOLOR_NONE)
820 		outlinecolormap = R_GetTranslationColormap(TC_DEFAULT, outlinecolor, GTC_CACHE);
821 
822 	flags &= ~V_PARAMMASK; // Don't let crashes happen.
823 	V_DrawNameTag(x, y, flags, FRACUNIT, basecolormap, outlinecolormap, str);
824 	return 0;
825 }
826 
libd_drawScaledNameTag(lua_State * L)827 static int libd_drawScaledNameTag(lua_State *L)
828 {
829 	fixed_t x;
830 	fixed_t y;
831 	const char *str;
832 	INT32 flags;
833 	fixed_t scale;
834 	UINT16 basecolor;
835 	UINT16 outlinecolor;
836 	UINT8 *basecolormap = NULL;
837 	UINT8 *outlinecolormap = NULL;
838 
839 	HUDONLY
840 
841 	x = luaL_checkfixed(L, 1);
842 	y = luaL_checkfixed(L, 2);
843 	str = luaL_checkstring(L, 3);
844 	flags = luaL_optinteger(L, 4, 0);
845 	scale = luaL_optinteger(L, 5, FRACUNIT);
846 	if (scale < 0)
847 		return luaL_error(L, "negative scale");
848 	basecolor = luaL_optinteger(L, 6, SKINCOLOR_BLUE);
849 	outlinecolor = luaL_optinteger(L, 7, SKINCOLOR_ORANGE);
850 	if (basecolor != SKINCOLOR_NONE)
851 		basecolormap = R_GetTranslationColormap(TC_DEFAULT, basecolor, GTC_CACHE);
852 	if (outlinecolor != SKINCOLOR_NONE)
853 		outlinecolormap = R_GetTranslationColormap(TC_DEFAULT, outlinecolor, GTC_CACHE);
854 
855 	flags &= ~V_PARAMMASK; // Don't let crashes happen.
856 	V_DrawNameTag(FixedInt(x), FixedInt(y), flags, scale, basecolormap, outlinecolormap, str);
857 	return 0;
858 }
859 
libd_stringWidth(lua_State * L)860 static int libd_stringWidth(lua_State *L)
861 {
862 	const char *str = luaL_checkstring(L, 1);
863 	INT32 flags = luaL_optinteger(L, 2, V_ALLOWLOWERCASE);
864 	enum widtht widtht = luaL_checkoption(L, 3, "normal", widtht_opt);
865 
866 	HUDONLY
867 	switch(widtht)
868 	{
869 	case widtht_normal: // hu_font
870 		lua_pushinteger(L, V_StringWidth(str, flags));
871 		break;
872 	case widtht_small: // hu_font, 0.5x scale
873 		lua_pushinteger(L, V_SmallStringWidth(str, flags));
874 		break;
875 	case widtht_thin: // tny_font
876 		lua_pushinteger(L, V_ThinStringWidth(str, flags));
877 		break;
878 	}
879 	return 1;
880 }
881 
libd_nameTagWidth(lua_State * L)882 static int libd_nameTagWidth(lua_State *L)
883 {
884 	HUDONLY
885 	lua_pushinteger(L, V_NameTagWidth(luaL_checkstring(L, 1)));
886 	return 1;
887 }
888 
libd_getColormap(lua_State * L)889 static int libd_getColormap(lua_State *L)
890 {
891 	INT32 skinnum = TC_DEFAULT;
892 	skincolornum_t color = luaL_optinteger(L, 2, 0);
893 	UINT8* colormap = NULL;
894 	HUDONLY
895 	if (lua_isnoneornil(L, 1))
896 		; // defaults to TC_DEFAULT
897 	else if (lua_type(L, 1) == LUA_TNUMBER) // skin number
898 	{
899 		skinnum = (INT32)luaL_checkinteger(L, 1);
900 		if (skinnum >= MAXSKINS)
901 			return luaL_error(L, "skin number %d is out of range (>%d)", skinnum, MAXSKINS-1);
902 		else if (skinnum < 0 && skinnum > TC_DEFAULT)
903 			return luaL_error(L, "translation colormap index is out of range");
904 	}
905 	else // skin name
906 	{
907 		const char *skinname = luaL_checkstring(L, 1);
908 		INT32 i = R_SkinAvailable(skinname);
909 		if (i != -1) // if -1, just default to TC_DEFAULT as above
910 			skinnum = i;
911 	}
912 
913 	// all was successful above, now we generate the colormap at last!
914 
915 	colormap = R_GetTranslationColormap(skinnum, color, GTC_CACHE);
916 	LUA_PushUserdata(L, colormap, META_COLORMAP); // push as META_COLORMAP userdata, specifically for patches to use!
917 	return 1;
918 }
919 
libd_getStringColormap(lua_State * L)920 static int libd_getStringColormap(lua_State *L)
921 {
922 	INT32 flags = luaL_checkinteger(L, 1);
923 	UINT8* colormap = NULL;
924 	HUDONLY
925 	colormap = V_GetStringColormap(flags & V_CHARCOLORMASK);
926 	if (colormap) {
927 		LUA_PushUserdata(L, colormap, META_COLORMAP); // push as META_COLORMAP userdata, specifically for patches to use!
928 		return 1;
929 	}
930 	return 0;
931 }
932 
libd_fadeScreen(lua_State * L)933 static int libd_fadeScreen(lua_State *L)
934 {
935 	UINT16 color = luaL_checkinteger(L, 1);
936 	UINT8 strength = luaL_checkinteger(L, 2);
937 	const UINT8 maxstrength = ((color & 0xFF00) ? 32 : 10);
938 
939 	HUDONLY
940 
941 	if (!strength)
942 		return 0;
943 
944 	if (strength > maxstrength)
945 		return luaL_error(L, "%s fade strength %d out of range (0 - %d)", ((color & 0xFF00) ? "COLORMAP" : "TRANSMAP"), strength, maxstrength);
946 
947 	if (strength == maxstrength) // Allow as a shortcut for drawfill...
948 	{
949 		V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, ((color & 0xFF00) ? 31 : color));
950 		return 0;
951 	}
952 
953 	V_DrawFadeScreen(color, strength);
954 	return 0;
955 }
956 
libd_width(lua_State * L)957 static int libd_width(lua_State *L)
958 {
959 	HUDONLY
960 	lua_pushinteger(L, vid.width); // push screen width
961 	return 1;
962 }
963 
libd_height(lua_State * L)964 static int libd_height(lua_State *L)
965 {
966 	HUDONLY
967 	lua_pushinteger(L, vid.height); // push screen height
968 	return 1;
969 }
970 
libd_dupx(lua_State * L)971 static int libd_dupx(lua_State *L)
972 {
973 	HUDONLY
974 	lua_pushinteger(L, vid.dupx); // push integral scale (patch scale)
975 	lua_pushfixed(L, vid.fdupx); // push fixed point scale (position scale)
976 	return 2;
977 }
978 
libd_dupy(lua_State * L)979 static int libd_dupy(lua_State *L)
980 {
981 	HUDONLY
982 	lua_pushinteger(L, vid.dupy); // push integral scale (patch scale)
983 	lua_pushfixed(L, vid.fdupy); // push fixed point scale (position scale)
984 	return 2;
985 }
986 
libd_renderer(lua_State * L)987 static int libd_renderer(lua_State *L)
988 {
989 	HUDONLY
990 	switch (rendermode) {
991 		case render_opengl: lua_pushliteral(L, "opengl");   break; // OpenGL renderer
992 		case render_soft:   lua_pushliteral(L, "software"); break; // Software renderer
993 		default:            lua_pushliteral(L, "none");     break; // render_none (for dedicated), in case there's any reason this should be run
994 	}
995 	return 1;
996 }
997 
998 // M_RANDOM
999 //////////////
1000 
libd_RandomFixed(lua_State * L)1001 static int libd_RandomFixed(lua_State *L)
1002 {
1003 	HUDONLY
1004 	lua_pushfixed(L, M_RandomFixed());
1005 	return 1;
1006 }
1007 
libd_RandomByte(lua_State * L)1008 static int libd_RandomByte(lua_State *L)
1009 {
1010 	HUDONLY
1011 	lua_pushinteger(L, M_RandomByte());
1012 	return 1;
1013 }
1014 
libd_RandomKey(lua_State * L)1015 static int libd_RandomKey(lua_State *L)
1016 {
1017 	INT32 a = (INT32)luaL_checkinteger(L, 1);
1018 
1019 	HUDONLY
1020 	if (a > 65536)
1021 		LUA_UsageWarning(L, "v.RandomKey: range > 65536 is undefined behavior");
1022 	lua_pushinteger(L, M_RandomKey(a));
1023 	return 1;
1024 }
1025 
libd_RandomRange(lua_State * L)1026 static int libd_RandomRange(lua_State *L)
1027 {
1028 	INT32 a = (INT32)luaL_checkinteger(L, 1);
1029 	INT32 b = (INT32)luaL_checkinteger(L, 2);
1030 
1031 	HUDONLY
1032 	if (b < a) {
1033 		INT32 c = a;
1034 		a = b;
1035 		b = c;
1036 	}
1037 	if ((b-a+1) > 65536)
1038 		LUA_UsageWarning(L, "v.RandomRange: range > 65536 is undefined behavior");
1039 	lua_pushinteger(L, M_RandomRange(a, b));
1040 	return 1;
1041 }
1042 
1043 // Macros.
libd_SignedRandom(lua_State * L)1044 static int libd_SignedRandom(lua_State *L)
1045 {
1046 	HUDONLY
1047 	lua_pushinteger(L, M_SignedRandom());
1048 	return 1;
1049 }
1050 
libd_RandomChance(lua_State * L)1051 static int libd_RandomChance(lua_State *L)
1052 {
1053 	fixed_t p = luaL_checkfixed(L, 1);
1054 	HUDONLY
1055 	lua_pushboolean(L, M_RandomChance(p));
1056 	return 1;
1057 }
1058 
1059 // 30/10/18 Lat': Get st_translucency's value for HUD rendering as a normal V_xxTRANS int
1060 // Could as well be thrown in global vars for ease of access but I guess it makes sense for it to be a HUD fn
libd_getlocaltransflag(lua_State * L)1061 static int libd_getlocaltransflag(lua_State *L)
1062 {
1063 	HUDONLY
1064 	lua_pushinteger(L, (10-st_translucency)*V_10TRANS);
1065 	return 1;
1066 }
1067 
1068 // Get cv_translucenthud's value for HUD rendering as a normal V_xxTRANS int
libd_getusertransflag(lua_State * L)1069 static int libd_getusertransflag(lua_State *L)
1070 {
1071 	HUDONLY
1072 	lua_pushinteger(L, (10-cv_translucenthud.value)*V_10TRANS);	// A bit weird that it's called "translucenthud" yet 10 is fully opaque :V
1073 	return 1;
1074 }
1075 
1076 static luaL_Reg lib_draw[] = {
1077 	// cache
1078 	{"patchExists", libd_patchExists},
1079 	{"cachePatch", libd_cachePatch},
1080 	{"getSpritePatch", libd_getSpritePatch},
1081 	{"getSprite2Patch", libd_getSprite2Patch},
1082 	{"getColormap", libd_getColormap},
1083 	{"getStringColormap", libd_getStringColormap},
1084 	// drawing
1085 	{"draw", libd_draw},
1086 	{"drawScaled", libd_drawScaled},
1087 	{"drawStretched", libd_drawStretched},
1088 	{"drawNum", libd_drawNum},
1089 	{"drawPaddedNum", libd_drawPaddedNum},
1090 	{"drawFill", libd_drawFill},
1091 	{"drawString", libd_drawString},
1092 	{"drawNameTag", libd_drawNameTag},
1093 	{"drawScaledNameTag", libd_drawScaledNameTag},
1094 	{"fadeScreen", libd_fadeScreen},
1095 	// misc
1096 	{"stringWidth", libd_stringWidth},
1097 	{"nameTagWidth", libd_nameTagWidth},
1098 	// m_random
1099 	{"RandomFixed",libd_RandomFixed},
1100 	{"RandomByte",libd_RandomByte},
1101 	{"RandomKey",libd_RandomKey},
1102 	{"RandomRange",libd_RandomRange},
1103 	{"SignedRandom",libd_SignedRandom}, // MACRO
1104 	{"RandomChance",libd_RandomChance}, // MACRO
1105 	// properties
1106 	{"width", libd_width},
1107 	{"height", libd_height},
1108 	{"dupx", libd_dupx},
1109 	{"dupy", libd_dupy},
1110 	{"renderer", libd_renderer},
1111 	{"localTransFlag", libd_getlocaltransflag},
1112 	{"userTransFlag", libd_getusertransflag},
1113 	{NULL, NULL}
1114 };
1115 
1116 //
1117 // lib_hud
1118 //
1119 
1120 // enable vanilla HUD element
lib_hudenable(lua_State * L)1121 static int lib_hudenable(lua_State *L)
1122 {
1123 	enum hud option = luaL_checkoption(L, 1, NULL, hud_disable_options);
1124 	hud_enabled[option/8] |= 1<<(option%8);
1125 	return 0;
1126 }
1127 
1128 // disable vanilla HUD element
lib_huddisable(lua_State * L)1129 static int lib_huddisable(lua_State *L)
1130 {
1131 	enum hud option = luaL_checkoption(L, 1, NULL, hud_disable_options);
1132 	hud_enabled[option/8] &= ~(1<<(option%8));
1133 	return 0;
1134 }
1135 
1136 // 30/10/18: Lat': How come this wasn't here before?
lib_hudenabled(lua_State * L)1137 static int lib_hudenabled(lua_State *L)
1138 {
1139 	enum hud option = luaL_checkoption(L, 1, NULL, hud_disable_options);
1140 	if (hud_enabled[option/8] & (1<<(option%8)))
1141 		lua_pushboolean(L, true);
1142 	else
1143 		lua_pushboolean(L, false);
1144 
1145 	return 1;
1146 }
1147 
1148 
1149 // add a HUD element for rendering
lib_hudadd(lua_State * L)1150 static int lib_hudadd(lua_State *L)
1151 {
1152 	enum hudhook field;
1153 
1154 	luaL_checktype(L, 1, LUA_TFUNCTION);
1155 	field = luaL_checkoption(L, 2, "game", hudhook_opt);
1156 
1157 	if (!lua_lumploading)
1158 		return luaL_error(L, "This function cannot be called from within a hook or coroutine!");
1159 
1160 	lua_getfield(L, LUA_REGISTRYINDEX, "HUD");
1161 	I_Assert(lua_istable(L, -1));
1162 	lua_rawgeti(L, -1, field+2); // HUD[2+]
1163 	I_Assert(lua_istable(L, -1));
1164 	lua_remove(L, -2);
1165 
1166 	lua_pushvalue(L, 1);
1167 	lua_rawseti(L, -2, (int)(lua_objlen(L, -2) + 1));
1168 
1169 	hudAvailable |= 1<<field;
1170 	return 0;
1171 }
1172 
1173 static luaL_Reg lib_hud[] = {
1174 	{"enable", lib_hudenable},
1175 	{"disable", lib_huddisable},
1176 	{"enabled", lib_hudenabled},
1177 	{"add", lib_hudadd},
1178 	{NULL, NULL}
1179 };
1180 
1181 //
1182 //
1183 //
1184 
LUA_HudLib(lua_State * L)1185 int LUA_HudLib(lua_State *L)
1186 {
1187 	memset(hud_enabled, 0xff, (hud_MAX/8)+1);
1188 
1189 	lua_newtable(L); // HUD registry table
1190 		lua_newtable(L);
1191 		luaL_register(L, NULL, lib_draw);
1192 		lua_rawseti(L, -2, 1); // HUD[1] = lib_draw
1193 
1194 		lua_newtable(L);
1195 		lua_rawseti(L, -2, 2); // HUD[2] = game rendering functions array
1196 
1197 		lua_newtable(L);
1198 		lua_rawseti(L, -2, 3); // HUD[3] = scores rendering functions array
1199 
1200 		lua_newtable(L);
1201 		lua_rawseti(L, -2, 4); // HUD[4] = intermission rendering functions array
1202 
1203 		lua_newtable(L);
1204 		lua_rawseti(L, -2, 5); // HUD[5] = title rendering functions array
1205 
1206 		lua_newtable(L);
1207 		lua_rawseti(L, -2, 6); // HUD[6] = title card rendering functions array
1208 	lua_setfield(L, LUA_REGISTRYINDEX, "HUD");
1209 
1210 	luaL_newmetatable(L, META_HUDINFO);
1211 		lua_pushcfunction(L, hudinfo_get);
1212 		lua_setfield(L, -2, "__index");
1213 
1214 		lua_pushcfunction(L, hudinfo_set);
1215 		lua_setfield(L, -2, "__newindex");
1216 
1217 		lua_pushcfunction(L, hudinfo_num);
1218 		lua_setfield(L, -2, "__len");
1219 	lua_pop(L,1);
1220 
1221 	lua_newuserdata(L, 0);
1222 		lua_createtable(L, 0, 2);
1223 			lua_pushcfunction(L, lib_getHudInfo);
1224 			lua_setfield(L, -2, "__index");
1225 
1226 			lua_pushcfunction(L, lib_hudinfolen);
1227 			lua_setfield(L, -2, "__len");
1228 		lua_setmetatable(L, -2);
1229 	lua_setglobal(L, "hudinfo");
1230 
1231 	luaL_newmetatable(L, META_COLORMAP);
1232 		lua_pushcfunction(L, colormap_get);
1233 		lua_setfield(L, -2, "__index");
1234 	lua_pop(L,1);
1235 
1236 	luaL_newmetatable(L, META_PATCH);
1237 		lua_pushcfunction(L, patch_get);
1238 		lua_setfield(L, -2, "__index");
1239 
1240 		lua_pushcfunction(L, patch_set);
1241 		lua_setfield(L, -2, "__newindex");
1242 	lua_pop(L,1);
1243 
1244 	luaL_newmetatable(L, META_CAMERA);
1245 		lua_pushcfunction(L, camera_get);
1246 		lua_setfield(L, -2, "__index");
1247 	lua_pop(L,1);
1248 
1249 	luaL_register(L, "hud", lib_hud);
1250 	return 0;
1251 }
1252 
LUA_HudEnabled(enum hud option)1253 boolean LUA_HudEnabled(enum hud option)
1254 {
1255 	if (!gL || hud_enabled[option/8] & (1<<(option%8)))
1256 		return true;
1257 	return false;
1258 }
1259 
1260 // Hook for HUD rendering
LUAh_GameHUD(player_t * stplayr)1261 void LUAh_GameHUD(player_t *stplayr)
1262 {
1263 	if (!gL || !(hudAvailable & (1<<hudhook_game)))
1264 		return;
1265 
1266 	hud_running = true;
1267 	lua_settop(gL, 0);
1268 
1269 	lua_pushcfunction(gL, LUA_GetErrorMessage);
1270 
1271 	lua_getfield(gL, LUA_REGISTRYINDEX, "HUD");
1272 	I_Assert(lua_istable(gL, -1));
1273 	lua_rawgeti(gL, -1, 2+hudhook_game); // HUD[2] = rendering funcs
1274 	I_Assert(lua_istable(gL, -1));
1275 
1276 	lua_rawgeti(gL, -2, 1); // HUD[1] = lib_draw
1277 	I_Assert(lua_istable(gL, -1));
1278 	lua_remove(gL, -3); // pop HUD
1279 	LUA_PushUserdata(gL, stplayr, META_PLAYER);
1280 
1281 	if (splitscreen && stplayr == &players[secondarydisplayplayer])
1282 		LUA_PushUserdata(gL, &camera2, META_CAMERA);
1283 	else
1284 		LUA_PushUserdata(gL, &camera, META_CAMERA);
1285 
1286 	lua_pushnil(gL);
1287 	while (lua_next(gL, -5) != 0) {
1288 		lua_pushvalue(gL, -5); // graphics library (HUD[1])
1289 		lua_pushvalue(gL, -5); // stplayr
1290 		lua_pushvalue(gL, -5); // camera
1291 		LUA_Call(gL, 3, 0, 1);
1292 	}
1293 	lua_settop(gL, 0);
1294 	hud_running = false;
1295 }
1296 
LUAh_ScoresHUD(void)1297 void LUAh_ScoresHUD(void)
1298 {
1299 	if (!gL || !(hudAvailable & (1<<hudhook_scores)))
1300 		return;
1301 
1302 	hud_running = true;
1303 	lua_settop(gL, 0);
1304 
1305 	lua_pushcfunction(gL, LUA_GetErrorMessage);
1306 
1307 	lua_getfield(gL, LUA_REGISTRYINDEX, "HUD");
1308 	I_Assert(lua_istable(gL, -1));
1309 	lua_rawgeti(gL, -1, 2+hudhook_scores); // HUD[3] = rendering funcs
1310 	I_Assert(lua_istable(gL, -1));
1311 
1312 	lua_rawgeti(gL, -2, 1); // HUD[1] = lib_draw
1313 	I_Assert(lua_istable(gL, -1));
1314 	lua_remove(gL, -3); // pop HUD
1315 	lua_pushnil(gL);
1316 	while (lua_next(gL, -3) != 0) {
1317 		lua_pushvalue(gL, -3); // graphics library (HUD[1])
1318 		LUA_Call(gL, 1, 0, 1);
1319 	}
1320 	lua_settop(gL, 0);
1321 	hud_running = false;
1322 }
1323 
LUAh_TitleHUD(void)1324 void LUAh_TitleHUD(void)
1325 {
1326 	if (!gL || !(hudAvailable & (1<<hudhook_title)))
1327 		return;
1328 
1329 	hud_running = true;
1330 	lua_settop(gL, 0);
1331 
1332 	lua_pushcfunction(gL, LUA_GetErrorMessage);
1333 
1334 	lua_getfield(gL, LUA_REGISTRYINDEX, "HUD");
1335 	I_Assert(lua_istable(gL, -1));
1336 	lua_rawgeti(gL, -1, 2+hudhook_title); // HUD[5] = rendering funcs
1337 	I_Assert(lua_istable(gL, -1));
1338 
1339 	lua_rawgeti(gL, -2, 1); // HUD[1] = lib_draw
1340 	I_Assert(lua_istable(gL, -1));
1341 	lua_remove(gL, -3); // pop HUD
1342 	lua_pushnil(gL);
1343 	while (lua_next(gL, -3) != 0) {
1344 		lua_pushvalue(gL, -3); // graphics library (HUD[1])
1345 		LUA_Call(gL, 1, 0, 1);
1346 	}
1347 	lua_settop(gL, 0);
1348 	hud_running = false;
1349 }
1350 
LUAh_TitleCardHUD(player_t * stplayr)1351 void LUAh_TitleCardHUD(player_t *stplayr)
1352 {
1353 	if (!gL || !(hudAvailable & (1<<hudhook_titlecard)))
1354 		return;
1355 
1356 	hud_running = true;
1357 	lua_settop(gL, 0);
1358 
1359 	lua_pushcfunction(gL, LUA_GetErrorMessage);
1360 
1361 	lua_getfield(gL, LUA_REGISTRYINDEX, "HUD");
1362 	I_Assert(lua_istable(gL, -1));
1363 	lua_rawgeti(gL, -1, 2+hudhook_titlecard); // HUD[6] = rendering funcs
1364 	I_Assert(lua_istable(gL, -1));
1365 
1366 	lua_rawgeti(gL, -2, 1); // HUD[1] = lib_draw
1367 	I_Assert(lua_istable(gL, -1));
1368 	lua_remove(gL, -3); // pop HUD
1369 
1370 	LUA_PushUserdata(gL, stplayr, META_PLAYER);
1371 	lua_pushinteger(gL, lt_ticker);
1372 	lua_pushinteger(gL, (lt_endtime + TICRATE));
1373 	lua_pushnil(gL);
1374 
1375 	while (lua_next(gL, -6) != 0) {
1376 		lua_pushvalue(gL, -6); // graphics library (HUD[1])
1377 		lua_pushvalue(gL, -6); // stplayr
1378 		lua_pushvalue(gL, -6); // lt_ticker
1379 		lua_pushvalue(gL, -6); // lt_endtime
1380 		LUA_Call(gL, 4, 0, 1);
1381 	}
1382 
1383 	lua_settop(gL, 0);
1384 	hud_running = false;
1385 }
1386 
LUAh_IntermissionHUD(void)1387 void LUAh_IntermissionHUD(void)
1388 {
1389 	if (!gL || !(hudAvailable & (1<<hudhook_intermission)))
1390 		return;
1391 
1392 	hud_running = true;
1393 	lua_settop(gL, 0);
1394 
1395 	lua_pushcfunction(gL, LUA_GetErrorMessage);
1396 
1397 	lua_getfield(gL, LUA_REGISTRYINDEX, "HUD");
1398 	I_Assert(lua_istable(gL, -1));
1399 	lua_rawgeti(gL, -1, 2+hudhook_intermission); // HUD[4] = rendering funcs
1400 	I_Assert(lua_istable(gL, -1));
1401 
1402 	lua_rawgeti(gL, -2, 1); // HUD[1] = lib_draw
1403 	I_Assert(lua_istable(gL, -1));
1404 	lua_remove(gL, -3); // pop HUD
1405 	lua_pushnil(gL);
1406 	while (lua_next(gL, -3) != 0) {
1407 		lua_pushvalue(gL, -3); // graphics library (HUD[1])
1408 		LUA_Call(gL, 1, 0, 1);
1409 	}
1410 	lua_settop(gL, 0);
1411 	hud_running = false;
1412 }
1413