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_infolib.c
11 /// \brief infotable editing library for Lua scripting
12
13 #include "doomdef.h"
14 #include "fastcmp.h"
15 #include "info.h"
16 #include "dehacked.h"
17 #include "deh_tables.h"
18 #include "deh_lua.h"
19 #include "p_mobj.h"
20 #include "p_local.h"
21 #include "z_zone.h"
22 #include "r_patch.h"
23 #include "r_picformats.h"
24 #include "r_things.h"
25 #include "r_draw.h" // R_GetColorByName
26 #include "doomstat.h" // luabanks[]
27
28 #include "lua_script.h"
29 #include "lua_libs.h"
30 #include "lua_hud.h" // hud_running errors
31 #include "lua_hook.h" // hook_cmd_running errors
32
33 extern CV_PossibleValue_t Color_cons_t[];
34 extern UINT8 skincolor_modified[];
35
36 boolean LUA_CallAction(enum actionnum actionnum, mobj_t *actor);
37 state_t *astate;
38
39 enum sfxinfo_read {
40 sfxinfor_name = 0,
41 sfxinfor_singular,
42 sfxinfor_priority,
43 sfxinfor_flags, // "pitch"
44 sfxinfor_caption,
45 sfxinfor_skinsound
46 };
47 const char *const sfxinfo_ropt[] = {
48 "name",
49 "singular",
50 "priority",
51 "flags",
52 "caption",
53 "skinsound",
54 NULL};
55
56 enum sfxinfo_write {
57 sfxinfow_singular = 0,
58 sfxinfow_priority,
59 sfxinfow_flags, // "pitch"
60 sfxinfow_caption
61 };
62 const char *const sfxinfo_wopt[] = {
63 "singular",
64 "priority",
65 "flags",
66 "caption",
67 NULL};
68
69 boolean actionsoverridden[NUMACTIONS] = {false};
70
71 //
72 // Sprite Names
73 //
74
75 // push sprite name
lib_getSprname(lua_State * L)76 static int lib_getSprname(lua_State *L)
77 {
78 UINT32 i;
79
80 lua_remove(L, 1); // don't care about sprnames[] dummy userdata.
81
82 if (lua_isnumber(L, 1))
83 {
84 i = lua_tonumber(L, 1);
85 if (i > NUMSPRITES)
86 return 0;
87 lua_pushlstring(L, sprnames[i], 4);
88 return 1;
89 }
90 else if (lua_isstring(L, 1))
91 {
92 const char *name = lua_tostring(L, 1);
93 for (i = 0; i < NUMSPRITES; i++)
94 if (fastcmp(name, sprnames[i]))
95 {
96 lua_pushinteger(L, i);
97 return 1;
98 }
99 }
100 return 0;
101 }
102
103 /// \todo Maybe make it tally up the used_spr from dehacked?
lib_sprnamelen(lua_State * L)104 static int lib_sprnamelen(lua_State *L)
105 {
106 lua_pushinteger(L, NUMSPRITES);
107 return 1;
108 }
109
110 //
111 // Player Sprite Names
112 //
113
114 // push sprite name
lib_getSpr2name(lua_State * L)115 static int lib_getSpr2name(lua_State *L)
116 {
117 playersprite_t i;
118
119 lua_remove(L, 1); // don't care about spr2names[] dummy userdata.
120
121 if (lua_isnumber(L, 1))
122 {
123 i = lua_tonumber(L, 1);
124 if (i >= free_spr2)
125 return 0;
126 lua_pushlstring(L, spr2names[i], 4);
127 return 1;
128 }
129 else if (lua_isstring(L, 1))
130 {
131 const char *name = lua_tostring(L, 1);
132 for (i = 0; i < free_spr2; i++)
133 if (fastcmp(name, spr2names[i]))
134 {
135 lua_pushinteger(L, i);
136 return 1;
137 }
138 }
139 return 0;
140 }
141
lib_getSpr2default(lua_State * L)142 static int lib_getSpr2default(lua_State *L)
143 {
144 playersprite_t i;
145
146 lua_remove(L, 1); // don't care about spr2defaults[] dummy userdata.
147
148 if (lua_isnumber(L, 1))
149 i = lua_tonumber(L, 1);
150 else if (lua_isstring(L, 1))
151 {
152 const char *name = lua_tostring(L, 1);
153 for (i = 0; i < free_spr2; i++)
154 if (fastcmp(name, spr2names[i]))
155 break;
156 }
157 else
158 return luaL_error(L, "spr2defaults[] invalid index");
159
160 if (i >= free_spr2)
161 return luaL_error(L, "spr2defaults[] index %d out of range (%d - %d)", i, 0, free_spr2-1);
162
163 lua_pushinteger(L, spr2defaults[i]);
164 return 1;
165 }
166
lib_setSpr2default(lua_State * L)167 static int lib_setSpr2default(lua_State *L)
168 {
169 playersprite_t i;
170 UINT8 j = 0;
171
172 if (hud_running)
173 return luaL_error(L, "Do not alter spr2defaults[] in HUD rendering code!");
174 if (hook_cmd_running)
175 return luaL_error(L, "Do not alter spr2defaults[] in CMD building code!");
176
177 // todo: maybe allow setting below first freeslot..? step 1 is toggling this, step 2 is testing to see whether it's net-safe
178 #ifdef SETALLSPR2DEFAULTS
179 #define FIRSTMODIFY 0
180 #else
181 #define FIRSTMODIFY SPR2_FIRSTFREESLOT
182 if (free_spr2 == SPR2_FIRSTFREESLOT)
183 return luaL_error(L, "You can only modify the spr2defaults[] entries of sprite2 freeslots, and none are currently added.");
184 #endif
185
186 lua_remove(L, 1); // don't care about spr2defaults[] dummy userdata.
187
188 if (lua_isnumber(L, 1))
189 i = lua_tonumber(L, 1);
190 else if (lua_isstring(L, 1))
191 {
192 const char *name = lua_tostring(L, 1);
193 for (i = 0; i < free_spr2; i++)
194 {
195 if (fastcmp(name, spr2names[i]))
196 break;
197 }
198 if (i == free_spr2)
199 return luaL_error(L, "spr2defaults[] invalid index");
200 }
201 else
202 return luaL_error(L, "spr2defaults[] invalid index");
203
204 if (i < FIRSTMODIFY || i >= free_spr2)
205 return luaL_error(L, "spr2defaults[] index %d out of range (%d - %d)", i, FIRSTMODIFY, free_spr2-1);
206 #undef FIRSTMODIFY
207
208 if (lua_isnumber(L, 2))
209 j = lua_tonumber(L, 2);
210 else if (lua_isstring(L, 2))
211 {
212 const char *name = lua_tostring(L, 2);
213 for (j = 0; j < free_spr2; j++)
214 {
215 if (fastcmp(name, spr2names[j]))
216 break;
217 }
218 if (j == free_spr2)
219 return luaL_error(L, "spr2defaults[] invalid set");
220 }
221 else
222 return luaL_error(L, "spr2defaults[] invalid set");
223
224 if (j >= free_spr2)
225 return luaL_error(L, "spr2defaults[] set %d out of range (%d - %d)", j, 0, free_spr2-1);
226
227 spr2defaults[i] = j;
228 return 0;
229 }
230
lib_spr2namelen(lua_State * L)231 static int lib_spr2namelen(lua_State *L)
232 {
233 lua_pushinteger(L, free_spr2);
234 return 1;
235 }
236
237 /////////////////
238 // SPRITE INFO //
239 /////////////////
240
241 // spriteinfo[]
lib_getSpriteInfo(lua_State * L)242 static int lib_getSpriteInfo(lua_State *L)
243 {
244 UINT32 i = NUMSPRITES;
245 lua_remove(L, 1);
246
247 if (lua_isstring(L, 1))
248 {
249 const char *name = lua_tostring(L, 1);
250 INT32 spr;
251 for (spr = 0; spr < NUMSPRITES; spr++)
252 {
253 if (fastcmp(name, sprnames[spr]))
254 {
255 i = spr;
256 break;
257 }
258 }
259 if (i == NUMSPRITES)
260 {
261 char *check;
262 i = strtol(name, &check, 10);
263 if (check == name || *check != '\0')
264 return luaL_error(L, "unknown sprite name %s", name);
265 }
266 }
267 else
268 i = luaL_checkinteger(L, 1);
269
270 if (i == 0 || i >= NUMSPRITES)
271 return luaL_error(L, "spriteinfo[] index %d out of range (1 - %d)", i, NUMSPRITES-1);
272
273 LUA_PushUserdata(L, &spriteinfo[i], META_SPRITEINFO);
274 return 1;
275 }
276
277 #define FIELDERROR(f, e) luaL_error(L, "bad value for " LUA_QL(f) " in table passed to spriteinfo[] (%s)", e);
278 #define TYPEERROR(f, t1, t2) FIELDERROR(f, va("%s expected, got %s", lua_typename(L, t1), lua_typename(L, t2)))
279
PopPivotSubTable(spriteframepivot_t * pivot,lua_State * L,int stk,int idx)280 static int PopPivotSubTable(spriteframepivot_t *pivot, lua_State *L, int stk, int idx)
281 {
282 int okcool = 0;
283 switch (lua_type(L, stk))
284 {
285 case LUA_TTABLE:
286 lua_pushnil(L);
287 while (lua_next(L, stk))
288 {
289 const char *key = NULL;
290 lua_Integer ikey = -1;
291 lua_Integer value = 0;
292 // x or y?
293 switch (lua_type(L, stk+1))
294 {
295 case LUA_TSTRING:
296 key = lua_tostring(L, stk+1);
297 break;
298 case LUA_TNUMBER:
299 ikey = lua_tointeger(L, stk+1);
300 break;
301 default:
302 FIELDERROR("pivot key", va("string or number expected, got %s", luaL_typename(L, stk+1)))
303 }
304 // then get value
305 switch (lua_type(L, stk+2))
306 {
307 case LUA_TNUMBER:
308 value = lua_tonumber(L, stk+2);
309 break;
310 case LUA_TBOOLEAN:
311 value = (UINT8)lua_toboolean(L, stk+2);
312 break;
313 default:
314 TYPEERROR("pivot value", LUA_TNUMBER, lua_type(L, stk+2))
315 }
316 // finally set omg!!!!!!!!!!!!!!!!!!
317 if (ikey == 1 || (key && fastcmp(key, "x")))
318 pivot[idx].x = (INT32)value;
319 else if (ikey == 2 || (key && fastcmp(key, "y")))
320 pivot[idx].y = (INT32)value;
321 else if (ikey == 3 || (key && fastcmp(key, "rotaxis")))
322 pivot[idx].rotaxis = (UINT8)value;
323 else if (ikey == -1 && (key != NULL))
324 FIELDERROR("pivot key", va("invalid option %s", key));
325 okcool = 1;
326 lua_pop(L, 1);
327 }
328 break;
329 default:
330 TYPEERROR("sprite pivot", LUA_TTABLE, lua_type(L, stk))
331 }
332 return okcool;
333 }
334
PopPivotTable(spriteinfo_t * info,lua_State * L,int stk)335 static int PopPivotTable(spriteinfo_t *info, lua_State *L, int stk)
336 {
337 // Just in case?
338 if (!lua_istable(L, stk))
339 TYPEERROR("pivot table", LUA_TTABLE, lua_type(L, stk));
340
341 lua_pushnil(L);
342 // stk = 0 has the pivot table
343 // stk = 1 has the frame key
344 // stk = 2 has the frame table
345 // stk = 3 has either a string or a number as key
346 // stk = 4 has the value for the key mentioned above
347 while (lua_next(L, stk))
348 {
349 int idx = 0;
350 const char *framestr = NULL;
351 switch (lua_type(L, stk+1))
352 {
353 case LUA_TSTRING:
354 framestr = lua_tostring(L, stk+1);
355 idx = R_Char2Frame(framestr[0]);
356 break;
357 case LUA_TNUMBER:
358 idx = lua_tonumber(L, stk+1);
359 break;
360 default:
361 TYPEERROR("pivot frame", LUA_TNUMBER, lua_type(L, stk+1));
362 }
363 if ((idx < 0) || (idx >= 64))
364 return luaL_error(L, "pivot frame %d out of range (0 - %d)", idx, 63);
365 // the values in pivot[] are also tables
366 if (PopPivotSubTable(info->pivot, L, stk+2, idx))
367 info->available = true;
368 lua_pop(L, 1);
369 }
370
371 return 0;
372 }
373
lib_setSpriteInfo(lua_State * L)374 static int lib_setSpriteInfo(lua_State *L)
375 {
376 spriteinfo_t *info;
377
378 if (!lua_lumploading)
379 return luaL_error(L, "Do not alter spriteinfo_t from within a hook or coroutine!");
380 if (hud_running)
381 return luaL_error(L, "Do not alter spriteinfo_t in HUD rendering code!");
382 if (hook_cmd_running)
383 return luaL_error(L, "Do not alter spriteinfo_t in CMD building code!");
384
385 lua_remove(L, 1);
386 {
387 UINT32 i = luaL_checkinteger(L, 1);
388 if (i == 0 || i >= NUMSPRITES)
389 return luaL_error(L, "spriteinfo[] index %d out of range (1 - %d)", i, NUMSPRITES-1);
390 info = &spriteinfo[i]; // get the spriteinfo to assign to.
391 }
392 luaL_checktype(L, 2, LUA_TTABLE); // check that we've been passed a table.
393 lua_remove(L, 1); // pop sprite num, don't need it any more.
394 lua_settop(L, 1); // cut the stack here. the only thing left now is the table of data we're assigning to the spriteinfo.
395
396 lua_pushnil(L);
397 while (lua_next(L, 1)) {
398 lua_Integer i = 0;
399 const char *str = NULL;
400 if (lua_isnumber(L, 2))
401 i = lua_tointeger(L, 2);
402 else
403 str = luaL_checkstring(L, 2);
404
405 if (i == 1 || (str && fastcmp(str, "pivot")))
406 {
407 // pivot[] is a table
408 if (lua_istable(L, 3))
409 return PopPivotTable(info, L, 3);
410 else
411 FIELDERROR("pivot", va("%s expected, got %s", lua_typename(L, LUA_TTABLE), luaL_typename(L, -1)))
412 }
413
414 lua_pop(L, 1);
415 }
416
417 return 0;
418 }
419
420 #undef FIELDERROR
421 #undef TYPEERROR
422
lib_spriteinfolen(lua_State * L)423 static int lib_spriteinfolen(lua_State *L)
424 {
425 lua_pushinteger(L, NUMSPRITES);
426 return 1;
427 }
428
429 // spriteinfo_t
spriteinfo_get(lua_State * L)430 static int spriteinfo_get(lua_State *L)
431 {
432 spriteinfo_t *sprinfo = *((spriteinfo_t **)luaL_checkudata(L, 1, META_SPRITEINFO));
433 const char *field = luaL_checkstring(L, 2);
434
435 I_Assert(sprinfo != NULL);
436
437 // push spriteframepivot_t userdata
438 if (fastcmp(field, "pivot"))
439 {
440 // bypass LUA_PushUserdata
441 void **userdata = lua_newuserdata(L, sizeof(void *));
442 *userdata = &sprinfo->pivot;
443 luaL_getmetatable(L, META_PIVOTLIST);
444 lua_setmetatable(L, -2);
445
446 // stack is left with the userdata on top, as if getting it had originally succeeded.
447 return 1;
448 }
449 else
450 return luaL_error(L, LUA_QL("spriteinfo_t") " has no field named " LUA_QS, field);
451
452 return 0;
453 }
454
spriteinfo_set(lua_State * L)455 static int spriteinfo_set(lua_State *L)
456 {
457 spriteinfo_t *sprinfo = *((spriteinfo_t **)luaL_checkudata(L, 1, META_SPRITEINFO));
458 const char *field = luaL_checkstring(L, 2);
459
460 if (!lua_lumploading)
461 return luaL_error(L, "Do not alter spriteinfo_t from within a hook or coroutine!");
462 if (hud_running)
463 return luaL_error(L, "Do not alter spriteinfo_t in HUD rendering code!");
464 if (hook_cmd_running)
465 return luaL_error(L, "Do not alter spriteinfo_t in CMD building code!");
466
467 I_Assert(sprinfo != NULL);
468
469 lua_remove(L, 1); // remove spriteinfo
470 lua_remove(L, 1); // remove field
471 lua_settop(L, 1); // leave only one value
472
473 if (fastcmp(field, "pivot"))
474 {
475 // pivot[] is a table
476 if (lua_istable(L, 1))
477 return PopPivotTable(sprinfo, L, 1);
478 // pivot[] is userdata
479 else if (lua_isuserdata(L, 1))
480 {
481 spriteframepivot_t *pivot = *((spriteframepivot_t **)luaL_checkudata(L, 1, META_PIVOTLIST));
482 memcpy(&sprinfo->pivot, pivot, sizeof(spriteframepivot_t));
483 sprinfo->available = true; // Just in case?
484 }
485 }
486 else
487 return luaL_error(L, va("Field %s does not exist in spriteinfo_t", field));
488
489 return 0;
490 }
491
spriteinfo_num(lua_State * L)492 static int spriteinfo_num(lua_State *L)
493 {
494 spriteinfo_t *sprinfo = *((spriteinfo_t **)luaL_checkudata(L, 1, META_SPRITEINFO));
495
496 I_Assert(sprinfo != NULL);
497 I_Assert(sprinfo >= spriteinfo);
498
499 lua_pushinteger(L, (UINT32)(sprinfo-spriteinfo));
500 return 1;
501 }
502
503 // framepivot_t
pivotlist_get(lua_State * L)504 static int pivotlist_get(lua_State *L)
505 {
506 void **userdata;
507 spriteframepivot_t *framepivot = *((spriteframepivot_t **)luaL_checkudata(L, 1, META_PIVOTLIST));
508 const char *field = luaL_checkstring(L, 2);
509 UINT8 frame;
510
511 I_Assert(framepivot != NULL);
512
513 frame = R_Char2Frame(field[0]);
514 if (frame == 255)
515 luaL_error(L, "invalid frame %s", field);
516
517 // bypass LUA_PushUserdata
518 userdata = lua_newuserdata(L, sizeof(void *));
519 *userdata = &framepivot[frame];
520 luaL_getmetatable(L, META_FRAMEPIVOT);
521 lua_setmetatable(L, -2);
522
523 // stack is left with the userdata on top, as if getting it had originally succeeded.
524 return 1;
525 }
526
pivotlist_set(lua_State * L)527 static int pivotlist_set(lua_State *L)
528 {
529 // Because I already know it's a spriteframepivot_t anyway
530 spriteframepivot_t *pivotlist = *((spriteframepivot_t **)lua_touserdata(L, 1));
531 //spriteframepivot_t *framepivot = *((spriteframepivot_t **)luaL_checkudata(L, 1, META_FRAMEPIVOT));
532 const char *field = luaL_checkstring(L, 2);
533 UINT8 frame;
534
535 if (!lua_lumploading)
536 return luaL_error(L, "Do not alter spriteframepivot_t from within a hook or coroutine!");
537 if (hud_running)
538 return luaL_error(L, "Do not alter spriteframepivot_t in HUD rendering code!");
539 if (hook_cmd_running)
540 return luaL_error(L, "Do not alter spriteframepivot_t in CMD building code!");
541
542 I_Assert(pivotlist != NULL);
543
544 frame = R_Char2Frame(field[0]);
545 if (frame == 255)
546 luaL_error(L, "invalid frame %s", field);
547
548 // pivot[] is a table
549 if (lua_istable(L, 3))
550 return PopPivotSubTable(pivotlist, L, 3, frame);
551 // pivot[] is userdata
552 else if (lua_isuserdata(L, 3))
553 {
554 spriteframepivot_t *copypivot = *((spriteframepivot_t **)luaL_checkudata(L, 3, META_FRAMEPIVOT));
555 memcpy(&pivotlist[frame], copypivot, sizeof(spriteframepivot_t));
556 }
557
558 return 0;
559 }
560
pivotlist_num(lua_State * L)561 static int pivotlist_num(lua_State *L)
562 {
563 lua_pushinteger(L, 64);
564 return 1;
565 }
566
framepivot_get(lua_State * L)567 static int framepivot_get(lua_State *L)
568 {
569 spriteframepivot_t *framepivot = *((spriteframepivot_t **)luaL_checkudata(L, 1, META_FRAMEPIVOT));
570 const char *field = luaL_checkstring(L, 2);
571
572 I_Assert(framepivot != NULL);
573
574 if (fastcmp("x", field))
575 lua_pushinteger(L, framepivot->x);
576 else if (fastcmp("y", field))
577 lua_pushinteger(L, framepivot->y);
578 else if (fastcmp("rotaxis", field))
579 lua_pushinteger(L, (UINT8)framepivot->rotaxis);
580 else
581 return luaL_error(L, va("Field %s does not exist in spriteframepivot_t", field));
582
583 return 1;
584 }
585
framepivot_set(lua_State * L)586 static int framepivot_set(lua_State *L)
587 {
588 spriteframepivot_t *framepivot = *((spriteframepivot_t **)luaL_checkudata(L, 1, META_FRAMEPIVOT));
589 const char *field = luaL_checkstring(L, 2);
590
591 if (!lua_lumploading)
592 return luaL_error(L, "Do not alter spriteframepivot_t from within a hook or coroutine!");
593 if (hud_running)
594 return luaL_error(L, "Do not alter spriteframepivot_t in HUD rendering code!");
595 if (hook_cmd_running)
596 return luaL_error(L, "Do not alter spriteframepivot_t in CMD building code!");
597
598 I_Assert(framepivot != NULL);
599
600 if (fastcmp("x", field))
601 framepivot->x = luaL_checkinteger(L, 3);
602 else if (fastcmp("y", field))
603 framepivot->y = luaL_checkinteger(L, 3);
604 else if (fastcmp("rotaxis", field))
605 framepivot->rotaxis = luaL_checkinteger(L, 3);
606 else
607 return luaL_error(L, va("Field %s does not exist in spriteframepivot_t", field));
608
609 return 0;
610 }
611
framepivot_num(lua_State * L)612 static int framepivot_num(lua_State *L)
613 {
614 lua_pushinteger(L, 2);
615 return 1;
616 }
617
618 ////////////////
619 // STATE INFO //
620 ////////////////
621
622 // Uses astate to determine which state is calling it
623 // Then looks up which Lua action is assigned to that state and calls it
A_Lua(mobj_t * actor)624 static void A_Lua(mobj_t *actor)
625 {
626 boolean found = false;
627 I_Assert(actor != NULL);
628
629 lua_settop(gL, 0); // Just in case...
630 lua_pushcfunction(gL, LUA_GetErrorMessage);
631
632 // get the action for this state
633 lua_getfield(gL, LUA_REGISTRYINDEX, LREG_STATEACTION);
634 I_Assert(lua_istable(gL, -1));
635 lua_pushlightuserdata(gL, astate);
636 lua_rawget(gL, -2);
637 I_Assert(lua_isfunction(gL, -1));
638 lua_remove(gL, -2); // pop LREG_STATEACTION
639
640 // get the name for this action, if possible.
641 lua_getfield(gL, LUA_REGISTRYINDEX, LREG_ACTIONS);
642 lua_pushnil(gL);
643 while (lua_next(gL, -2))
644 {
645 if (lua_rawequal(gL, -1, -4))
646 {
647 found = true;
648 superactions[superstack] = lua_tostring(gL, -2); // "A_ACTION"
649 ++superstack;
650 lua_pop(gL, 2); // pop the name and function
651 break;
652 }
653 lua_pop(gL, 1);
654 }
655 lua_pop(gL, 1); // pop LREG_ACTION
656
657 LUA_PushUserdata(gL, actor, META_MOBJ);
658 lua_pushinteger(gL, var1);
659 lua_pushinteger(gL, var2);
660 LUA_Call(gL, 3, 0, 1);
661
662 if (found)
663 {
664 --superstack;
665 superactions[superstack] = NULL;
666 }
667 }
668
669 // Arbitrary states[] table index -> state_t *
lib_getState(lua_State * L)670 static int lib_getState(lua_State *L)
671 {
672 UINT32 i;
673 lua_remove(L, 1);
674
675 i = luaL_checkinteger(L, 1);
676 if (i >= NUMSTATES)
677 return luaL_error(L, "states[] index %d out of range (0 - %d)", i, NUMSTATES-1);
678 LUA_PushUserdata(L, &states[i], META_STATE);
679 return 1;
680 }
681
682 // Lua table full of data -> states[] (set the values all at once! :D :D)
lib_setState(lua_State * L)683 static int lib_setState(lua_State *L)
684 {
685 state_t *state;
686 lua_remove(L, 1); // don't care about states[] userdata.
687 {
688 UINT32 i = luaL_checkinteger(L, 1);
689 if (i >= NUMSTATES)
690 return luaL_error(L, "states[] index %d out of range (0 - %d)", i, NUMSTATES-1);
691 state = &states[i]; // get the state to assign to.
692 }
693 luaL_checktype(L, 2, LUA_TTABLE); // check that we've been passed a table.
694 lua_remove(L, 1); // pop state num, don't need it any more.
695 lua_settop(L, 1); // cut the stack here. the only thing left now is the table of data we're assigning to the state.
696
697 if (hud_running)
698 return luaL_error(L, "Do not alter states in HUD rendering code!");
699 if (hook_cmd_running)
700 return luaL_error(L, "Do not alter states in CMD building code!");
701
702 // clear the state to start with, in case of missing table elements
703 memset(state,0,sizeof(state_t));
704 state->tics = -1;
705
706 lua_pushnil(L);
707 while (lua_next(L, 1)) {
708 lua_Integer i = 0;
709 const char *str = NULL;
710 lua_Integer value;
711 if (lua_isnumber(L, 2))
712 i = lua_tointeger(L, 2);
713 else
714 str = luaL_checkstring(L, 2);
715
716 if (i == 1 || (str && fastcmp(str, "sprite"))) {
717 value = luaL_checkinteger(L, 3);
718 if (value < SPR_NULL || value >= NUMSPRITES)
719 return luaL_error(L, "sprite number %d is invalid.", value);
720 state->sprite = (spritenum_t)value;
721 } else if (i == 2 || (str && fastcmp(str, "frame"))) {
722 state->frame = (UINT32)luaL_checkinteger(L, 3);
723 } else if (i == 3 || (str && fastcmp(str, "tics"))) {
724 state->tics = (INT32)luaL_checkinteger(L, 3);
725 } else if (i == 4 || (str && fastcmp(str, "action"))) {
726 switch(lua_type(L, 3))
727 {
728 case LUA_TNIL: // Null? Set the action to nothing, then.
729 state->action.acp1 = NULL;
730 break;
731 case LUA_TSTRING: // It's a string, expect the name of a built-in action
732 LUA_SetActionByName(state, lua_tostring(L, 3));
733 break;
734 case LUA_TUSERDATA: // It's a userdata, expect META_ACTION of a built-in action
735 {
736 actionf_t *action = *((actionf_t **)luaL_checkudata(L, 3, META_ACTION));
737
738 if (!action)
739 return luaL_error(L, "not a valid action?");
740
741 state->action = *action;
742 state->action.acv = action->acv;
743 state->action.acp1 = action->acp1;
744 break;
745 }
746 case LUA_TFUNCTION: // It's a function (a Lua function or a C function? either way!)
747 lua_getfield(L, LUA_REGISTRYINDEX, LREG_STATEACTION);
748 I_Assert(lua_istable(L, -1));
749 lua_pushlightuserdata(L, state); // We'll store this function by the state's pointer in the registry.
750 lua_pushvalue(L, 3); // Bring it to the top of the stack
751 lua_rawset(L, -3); // Set it in the registry
752 lua_pop(L, 1); // pop LREG_STATEACTION
753 state->action.acp1 = (actionf_p1)A_Lua; // Set the action for the userdata.
754 break;
755 default: // ?!
756 return luaL_typerror(L, 3, "function");
757 }
758 } else if (i == 5 || (str && fastcmp(str, "var1"))) {
759 state->var1 = (INT32)luaL_checkinteger(L, 3);
760 } else if (i == 6 || (str && fastcmp(str, "var2"))) {
761 state->var2 = (INT32)luaL_checkinteger(L, 3);
762 } else if (i == 7 || (str && fastcmp(str, "nextstate"))) {
763 value = luaL_checkinteger(L, 3);
764 if (value < S_NULL || value >= NUMSTATES)
765 return luaL_error(L, "nextstate number %d is invalid.", value);
766 state->nextstate = (statenum_t)value;
767 }
768 lua_pop(L, 1);
769 }
770 return 0;
771 }
772
773 // #states -> NUMSTATES
lib_statelen(lua_State * L)774 static int lib_statelen(lua_State *L)
775 {
776 lua_pushinteger(L, NUMSTATES);
777 return 1;
778 }
779
LUA_SetLuaAction(void * stv,const char * action)780 boolean LUA_SetLuaAction(void *stv, const char *action)
781 {
782 state_t *st = (state_t *)stv;
783
784 I_Assert(st != NULL);
785 //I_Assert(st >= states && st < states+NUMSTATES); // if you REALLY want to be paranoid...
786 I_Assert(action != NULL);
787
788 if (!gL) // Lua isn't loaded,
789 return false; // action not set.
790
791 // action is assumed to be in all-caps already !!
792 // the registry is case-sensitive, so we strupr everything that enters it.
793
794 lua_getfield(gL, LUA_REGISTRYINDEX, LREG_ACTIONS);
795 lua_getfield(gL, -1, action);
796
797 if (lua_isnil(gL, -1)) // no match
798 {
799 lua_pop(gL, 2); // pop nil and LREG_ACTIONS
800 return false; // action not set.
801 }
802
803 lua_getfield(gL, LUA_REGISTRYINDEX, LREG_STATEACTION);
804 I_Assert(lua_istable(gL, -1));
805 lua_pushlightuserdata(gL, stv); // We'll store this function by the state's pointer in the registry.
806 lua_pushvalue(gL, -3); // Bring it to the top of the stack
807 lua_rawset(gL, -3); // Set it in the registry
808 lua_pop(gL, 1); // pop LREG_STATEACTION
809
810 lua_pop(gL, 2); // pop the function and LREG_ACTIONS
811 st->action.acp1 = (actionf_p1)A_Lua; // Set the action for the userdata.
812 return true; // action successfully set.
813 }
814
LUA_CallAction(enum actionnum actionnum,mobj_t * actor)815 boolean LUA_CallAction(enum actionnum actionnum, mobj_t *actor)
816 {
817 I_Assert(actor != NULL);
818
819 if (!actionsoverridden[actionnum]) // The action is not overriden,
820 return false; // action not called.
821
822 if (superstack && fasticmp(actionpointers[actionnum].name, superactions[superstack-1])) // the action is calling itself,
823 return false; // let it call the hardcoded function instead.
824
825 lua_pushcfunction(gL, LUA_GetErrorMessage);
826
827 // grab function by uppercase name.
828 lua_getfield(gL, LUA_REGISTRYINDEX, LREG_ACTIONS);
829 lua_getfield(gL, -1, actionpointers[actionnum].name);
830 lua_remove(gL, -2); // pop LREG_ACTIONS
831
832 if (lua_isnil(gL, -1)) // no match
833 {
834 lua_pop(gL, 2); // pop nil and error handler
835 return false; // action not called.
836 }
837
838 if (superstack == MAXRECURSION)
839 {
840 CONS_Alert(CONS_WARNING, "Max Lua Action recursion reached! Cool it on the calling A_Action functions from inside A_Action functions!\n");
841 lua_pop(gL, 2); // pop function and error handler
842 return true;
843 }
844
845 // Found a function.
846 // Call it with (actor, var1, var2)
847 I_Assert(lua_isfunction(gL, -1));
848 LUA_PushUserdata(gL, actor, META_MOBJ);
849 lua_pushinteger(gL, var1);
850 lua_pushinteger(gL, var2);
851
852 superactions[superstack] = actionpointers[actionnum].name;
853 ++superstack;
854
855 LUA_Call(gL, 3, 0, -(2 + 3));
856 lua_pop(gL, -1); // Error handler
857
858 --superstack;
859 superactions[superstack] = NULL;
860 return true; // action successfully called.
861 }
862
863 // state_t *, field -> number
state_get(lua_State * L)864 static int state_get(lua_State *L)
865 {
866 state_t *st = *((state_t **)luaL_checkudata(L, 1, META_STATE));
867 const char *field = luaL_checkstring(L, 2);
868 lua_Integer number;
869
870 if (fastcmp(field,"sprite"))
871 number = st->sprite;
872 else if (fastcmp(field,"frame"))
873 number = st->frame;
874 else if (fastcmp(field,"tics"))
875 number = st->tics;
876 else if (fastcmp(field,"action")) {
877 const char *name;
878 if (!st->action.acp1) // Action is NULL.
879 return 0; // return nil.
880 if (st->action.acp1 == (actionf_p1)A_Lua) { // This is a Lua function?
881 lua_getfield(L, LUA_REGISTRYINDEX, LREG_STATEACTION);
882 I_Assert(lua_istable(L, -1));
883 lua_pushlightuserdata(L, st); // Push the state pointer and
884 lua_rawget(L, -2); // use it to get the actual Lua function.
885 lua_remove(L, -2); // pop LREG_STATEACTION
886 return 1; // Return the Lua function.
887 }
888 name = LUA_GetActionName(&st->action); // find a hardcoded function name
889 if (!name) // If it's not a hardcoded function and it's not a Lua function...
890 return 0; // Just what is this??
891 // get the function from the global
892 // because the metatable will trigger.
893 lua_getglobal(L, name); // actually gets from LREG_ACTIONS if applicable, and pushes a META_ACTION userdata if not.
894 return 1; // return just the function
895 } else if (fastcmp(field,"var1"))
896 number = st->var1;
897 else if (fastcmp(field,"var2"))
898 number = st->var2;
899 else if (fastcmp(field,"nextstate"))
900 number = st->nextstate;
901 else if (devparm)
902 return luaL_error(L, LUA_QL("state_t") " has no field named " LUA_QS, field);
903 else
904 return 0;
905
906 lua_pushinteger(L, number);
907 return 1;
908 }
909
910 // state_t *, field, number -> states[]
state_set(lua_State * L)911 static int state_set(lua_State *L)
912 {
913 state_t *st = *((state_t **)luaL_checkudata(L, 1, META_STATE));
914 const char *field = luaL_checkstring(L, 2);
915 lua_Integer value;
916
917 if (hud_running)
918 return luaL_error(L, "Do not alter states in HUD rendering code!");
919 if (hook_cmd_running)
920 return luaL_error(L, "Do not alter states in CMD building code!");
921
922 if (fastcmp(field,"sprite")) {
923 value = luaL_checknumber(L, 3);
924 if (value < SPR_NULL || value >= NUMSPRITES)
925 return luaL_error(L, "sprite number %d is invalid.", value);
926 st->sprite = (spritenum_t)value;
927 } else if (fastcmp(field,"frame"))
928 st->frame = (UINT32)luaL_checknumber(L, 3);
929 else if (fastcmp(field,"tics"))
930 st->tics = (INT32)luaL_checknumber(L, 3);
931 else if (fastcmp(field,"action")) {
932 switch(lua_type(L, 3))
933 {
934 case LUA_TNIL: // Null? Set the action to nothing, then.
935 st->action.acp1 = NULL;
936 break;
937 case LUA_TSTRING: // It's a string, expect the name of a built-in action
938 LUA_SetActionByName(st, lua_tostring(L, 3));
939 break;
940 case LUA_TUSERDATA: // It's a userdata, expect META_ACTION of a built-in action
941 {
942 actionf_t *action = *((actionf_t **)luaL_checkudata(L, 3, META_ACTION));
943
944 if (!action)
945 return luaL_error(L, "not a valid action?");
946
947 st->action = *action;
948 st->action.acv = action->acv;
949 st->action.acp1 = action->acp1;
950 break;
951 }
952 case LUA_TFUNCTION: // It's a function (a Lua function or a C function? either way!)
953 lua_getfield(L, LUA_REGISTRYINDEX, LREG_STATEACTION);
954 I_Assert(lua_istable(L, -1));
955 lua_pushlightuserdata(L, st); // We'll store this function by the state's pointer in the registry.
956 lua_pushvalue(L, 3); // Bring it to the top of the stack
957 lua_rawset(L, -3); // Set it in the registry
958 lua_pop(L, 1); // pop LREG_STATEACTION
959 st->action.acp1 = (actionf_p1)A_Lua; // Set the action for the userdata.
960 break;
961 default: // ?!
962 return luaL_typerror(L, 3, "function");
963 }
964 } else if (fastcmp(field,"var1"))
965 st->var1 = (INT32)luaL_checknumber(L, 3);
966 else if (fastcmp(field,"var2"))
967 st->var2 = (INT32)luaL_checknumber(L, 3);
968 else if (fastcmp(field,"nextstate")) {
969 value = luaL_checkinteger(L, 3);
970 if (value < S_NULL || value >= NUMSTATES)
971 return luaL_error(L, "nextstate number %d is invalid.", value);
972 st->nextstate = (statenum_t)value;
973 } else
974 return luaL_error(L, LUA_QL("state_t") " has no field named " LUA_QS, field);
975
976 return 0;
977 }
978
979 // state_t * -> S_*
state_num(lua_State * L)980 static int state_num(lua_State *L)
981 {
982 state_t *state = *((state_t **)luaL_checkudata(L, 1, META_STATE));
983 lua_pushinteger(L, state-states);
984 return 1;
985 }
986
987 ///////////////
988 // MOBJ INFO //
989 ///////////////
990
991 // Arbitrary mobjinfo[] table index -> mobjinfo_t *
lib_getMobjInfo(lua_State * L)992 static int lib_getMobjInfo(lua_State *L)
993 {
994 UINT32 i;
995 lua_remove(L, 1);
996
997 i = luaL_checkinteger(L, 1);
998 if (i >= NUMMOBJTYPES)
999 return luaL_error(L, "mobjinfo[] index %d out of range (0 - %d)", i, NUMMOBJTYPES-1);
1000 LUA_PushUserdata(L, &mobjinfo[i], META_MOBJINFO);
1001 return 1;
1002 }
1003
1004 // Lua table full of data -> mobjinfo[]
lib_setMobjInfo(lua_State * L)1005 static int lib_setMobjInfo(lua_State *L)
1006 {
1007 mobjinfo_t *info;
1008 lua_remove(L, 1); // don't care about mobjinfo[] userdata.
1009 {
1010 UINT32 i = luaL_checkinteger(L, 1);
1011 if (i >= NUMMOBJTYPES)
1012 return luaL_error(L, "mobjinfo[] index %d out of range (0 - %d)", i, NUMMOBJTYPES-1);
1013 info = &mobjinfo[i]; // get the mobjinfo to assign to.
1014 }
1015 luaL_checktype(L, 2, LUA_TTABLE); // check that we've been passed a table.
1016 lua_remove(L, 1); // pop mobjtype num, don't need it any more.
1017 lua_settop(L, 1); // cut the stack here. the only thing left now is the table of data we're assigning to the mobjinfo.
1018
1019 if (hud_running)
1020 return luaL_error(L, "Do not alter mobjinfo in HUD rendering code!");
1021 if (hook_cmd_running)
1022 return luaL_error(L, "Do not alter mobjinfo in CMD building code!");
1023
1024 // clear the mobjinfo to start with, in case of missing table elements
1025 memset(info,0,sizeof(mobjinfo_t));
1026 info->doomednum = -1; // default to no editor value
1027 info->spawnhealth = 1; // avoid 'dead' noclip behaviors
1028
1029 lua_pushnil(L);
1030 while (lua_next(L, 1)) {
1031 lua_Integer i = 0;
1032 const char *str = NULL;
1033 lua_Integer value;
1034 if (lua_isnumber(L, 2))
1035 i = lua_tointeger(L, 2);
1036 else
1037 str = luaL_checkstring(L, 2);
1038
1039 if (i == 1 || (str && fastcmp(str,"doomednum")))
1040 info->doomednum = (INT32)luaL_checkinteger(L, 3);
1041 else if (i == 2 || (str && fastcmp(str,"spawnstate"))) {
1042 value = luaL_checkinteger(L, 3);
1043 if (value < S_NULL || value >= NUMSTATES)
1044 return luaL_error(L, "spawnstate number %d is invalid.", value);
1045 info->spawnstate = (statenum_t)value;
1046 } else if (i == 3 || (str && fastcmp(str,"spawnhealth")))
1047 info->spawnhealth = (INT32)luaL_checkinteger(L, 3);
1048 else if (i == 4 || (str && fastcmp(str,"seestate"))) {
1049 value = luaL_checkinteger(L, 3);
1050 if (value < S_NULL || value >= NUMSTATES)
1051 return luaL_error(L, "seestate number %d is invalid.", value);
1052 info->seestate = (statenum_t)value;
1053 } else if (i == 5 || (str && fastcmp(str,"seesound"))) {
1054 value = luaL_checkinteger(L, 3);
1055 if (value < sfx_None || value >= NUMSFX)
1056 return luaL_error(L, "seesound number %d is invalid.", value);
1057 info->seesound = (sfxenum_t)value;
1058 } else if (i == 6 || (str && fastcmp(str,"reactiontime")))
1059 info->reactiontime = (INT32)luaL_checkinteger(L, 3);
1060 else if (i == 7 || (str && fastcmp(str,"attacksound")))
1061 info->attacksound = luaL_checkinteger(L, 3);
1062 else if (i == 8 || (str && fastcmp(str,"painstate")))
1063 info->painstate = luaL_checkinteger(L, 3);
1064 else if (i == 9 || (str && fastcmp(str,"painchance")))
1065 info->painchance = (INT32)luaL_checkinteger(L, 3);
1066 else if (i == 10 || (str && fastcmp(str,"painsound")))
1067 info->painsound = luaL_checkinteger(L, 3);
1068 else if (i == 11 || (str && fastcmp(str,"meleestate")))
1069 info->meleestate = luaL_checkinteger(L, 3);
1070 else if (i == 12 || (str && fastcmp(str,"missilestate")))
1071 info->missilestate = luaL_checkinteger(L, 3);
1072 else if (i == 13 || (str && fastcmp(str,"deathstate")))
1073 info->deathstate = luaL_checkinteger(L, 3);
1074 else if (i == 14 || (str && fastcmp(str,"xdeathstate")))
1075 info->xdeathstate = luaL_checkinteger(L, 3);
1076 else if (i == 15 || (str && fastcmp(str,"deathsound")))
1077 info->deathsound = luaL_checkinteger(L, 3);
1078 else if (i == 16 || (str && fastcmp(str,"speed")))
1079 info->speed = luaL_checkfixed(L, 3);
1080 else if (i == 17 || (str && fastcmp(str,"radius")))
1081 info->radius = luaL_checkfixed(L, 3);
1082 else if (i == 18 || (str && fastcmp(str,"height")))
1083 info->height = luaL_checkfixed(L, 3);
1084 else if (i == 19 || (str && fastcmp(str,"dispoffset")))
1085 info->dispoffset = (INT32)luaL_checkinteger(L, 3);
1086 else if (i == 20 || (str && fastcmp(str,"mass")))
1087 info->mass = (INT32)luaL_checkinteger(L, 3);
1088 else if (i == 21 || (str && fastcmp(str,"damage")))
1089 info->damage = (INT32)luaL_checkinteger(L, 3);
1090 else if (i == 22 || (str && fastcmp(str,"activesound")))
1091 info->activesound = luaL_checkinteger(L, 3);
1092 else if (i == 23 || (str && fastcmp(str,"flags")))
1093 info->flags = (INT32)luaL_checkinteger(L, 3);
1094 else if (i == 24 || (str && fastcmp(str,"raisestate"))) {
1095 info->raisestate = luaL_checkinteger(L, 3);
1096 }
1097 lua_pop(L, 1);
1098 }
1099 return 0;
1100 }
1101
1102 // #mobjinfo -> NUMMOBJTYPES
lib_mobjinfolen(lua_State * L)1103 static int lib_mobjinfolen(lua_State *L)
1104 {
1105 lua_pushinteger(L, NUMMOBJTYPES);
1106 return 1;
1107 }
1108
1109 // mobjinfo_t *, field -> number
mobjinfo_get(lua_State * L)1110 static int mobjinfo_get(lua_State *L)
1111 {
1112 mobjinfo_t *info = *((mobjinfo_t **)luaL_checkudata(L, 1, META_MOBJINFO));
1113 const char *field = luaL_checkstring(L, 2);
1114
1115 I_Assert(info != NULL);
1116 I_Assert(info >= mobjinfo);
1117
1118 if (fastcmp(field,"doomednum"))
1119 lua_pushinteger(L, info->doomednum);
1120 else if (fastcmp(field,"spawnstate"))
1121 lua_pushinteger(L, info->spawnstate);
1122 else if (fastcmp(field,"spawnhealth"))
1123 lua_pushinteger(L, info->spawnhealth);
1124 else if (fastcmp(field,"seestate"))
1125 lua_pushinteger(L, info->seestate);
1126 else if (fastcmp(field,"seesound"))
1127 lua_pushinteger(L, info->seesound);
1128 else if (fastcmp(field,"reactiontime"))
1129 lua_pushinteger(L, info->reactiontime);
1130 else if (fastcmp(field,"attacksound"))
1131 lua_pushinteger(L, info->attacksound);
1132 else if (fastcmp(field,"painstate"))
1133 lua_pushinteger(L, info->painstate);
1134 else if (fastcmp(field,"painchance"))
1135 lua_pushinteger(L, info->painchance);
1136 else if (fastcmp(field,"painsound"))
1137 lua_pushinteger(L, info->painsound);
1138 else if (fastcmp(field,"meleestate"))
1139 lua_pushinteger(L, info->meleestate);
1140 else if (fastcmp(field,"missilestate"))
1141 lua_pushinteger(L, info->missilestate);
1142 else if (fastcmp(field,"deathstate"))
1143 lua_pushinteger(L, info->deathstate);
1144 else if (fastcmp(field,"xdeathstate"))
1145 lua_pushinteger(L, info->xdeathstate);
1146 else if (fastcmp(field,"deathsound"))
1147 lua_pushinteger(L, info->deathsound);
1148 else if (fastcmp(field,"speed"))
1149 lua_pushinteger(L, info->speed); // sometimes it's fixed_t, sometimes it's not...
1150 else if (fastcmp(field,"radius"))
1151 lua_pushfixed(L, info->radius);
1152 else if (fastcmp(field,"height"))
1153 lua_pushfixed(L, info->height);
1154 else if (fastcmp(field,"dispoffset"))
1155 lua_pushinteger(L, info->dispoffset);
1156 else if (fastcmp(field,"mass"))
1157 lua_pushinteger(L, info->mass);
1158 else if (fastcmp(field,"damage"))
1159 lua_pushinteger(L, info->damage);
1160 else if (fastcmp(field,"activesound"))
1161 lua_pushinteger(L, info->activesound);
1162 else if (fastcmp(field,"flags"))
1163 lua_pushinteger(L, info->flags);
1164 else if (fastcmp(field,"raisestate"))
1165 lua_pushinteger(L, info->raisestate);
1166 else {
1167 lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS);
1168 I_Assert(lua_istable(L, -1));
1169 lua_pushlightuserdata(L, info);
1170 lua_rawget(L, -2);
1171 if (!lua_istable(L, -1)) { // no extra values table
1172 CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; returning nil.\n"), "mobjinfo_t", field);
1173 return 0;
1174 }
1175 lua_getfield(L, -1, field);
1176 if (lua_isnil(L, -1)) // no value for this field
1177 CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; returning nil.\n"), "mobjinfo_t", field);
1178 }
1179 return 1;
1180 }
1181
1182 // mobjinfo_t *, field, number -> mobjinfo[]
mobjinfo_set(lua_State * L)1183 static int mobjinfo_set(lua_State *L)
1184 {
1185 mobjinfo_t *info = *((mobjinfo_t **)luaL_checkudata(L, 1, META_MOBJINFO));
1186 const char *field = luaL_checkstring(L, 2);
1187
1188 if (hud_running)
1189 return luaL_error(L, "Do not alter mobjinfo in HUD rendering code!");
1190 if (hook_cmd_running)
1191 return luaL_error(L, "Do not alter mobjinfo in CMD building code!");
1192
1193 I_Assert(info != NULL);
1194 I_Assert(info >= mobjinfo);
1195
1196 if (fastcmp(field,"doomednum"))
1197 info->doomednum = (INT32)luaL_checkinteger(L, 3);
1198 else if (fastcmp(field,"spawnstate"))
1199 info->spawnstate = luaL_checkinteger(L, 3);
1200 else if (fastcmp(field,"spawnhealth"))
1201 info->spawnhealth = (INT32)luaL_checkinteger(L, 3);
1202 else if (fastcmp(field,"seestate"))
1203 info->seestate = luaL_checkinteger(L, 3);
1204 else if (fastcmp(field,"seesound"))
1205 info->seesound = luaL_checkinteger(L, 3);
1206 else if (fastcmp(field,"reactiontime"))
1207 info->reactiontime = (INT32)luaL_checkinteger(L, 3);
1208 else if (fastcmp(field,"attacksound"))
1209 info->attacksound = luaL_checkinteger(L, 3);
1210 else if (fastcmp(field,"painstate"))
1211 info->painstate = luaL_checkinteger(L, 3);
1212 else if (fastcmp(field,"painchance"))
1213 info->painchance = (INT32)luaL_checkinteger(L, 3);
1214 else if (fastcmp(field,"painsound"))
1215 info->painsound = luaL_checkinteger(L, 3);
1216 else if (fastcmp(field,"meleestate"))
1217 info->meleestate = luaL_checkinteger(L, 3);
1218 else if (fastcmp(field,"missilestate"))
1219 info->missilestate = luaL_checkinteger(L, 3);
1220 else if (fastcmp(field,"deathstate"))
1221 info->deathstate = luaL_checkinteger(L, 3);
1222 else if (fastcmp(field,"xdeathstate"))
1223 info->xdeathstate = luaL_checkinteger(L, 3);
1224 else if (fastcmp(field,"deathsound"))
1225 info->deathsound = luaL_checkinteger(L, 3);
1226 else if (fastcmp(field,"speed"))
1227 info->speed = luaL_checkfixed(L, 3);
1228 else if (fastcmp(field,"radius"))
1229 info->radius = luaL_checkfixed(L, 3);
1230 else if (fastcmp(field,"height"))
1231 info->height = luaL_checkfixed(L, 3);
1232 else if (fastcmp(field,"dispoffset"))
1233 info->dispoffset = (INT32)luaL_checkinteger(L, 3);
1234 else if (fastcmp(field,"mass"))
1235 info->mass = (INT32)luaL_checkinteger(L, 3);
1236 else if (fastcmp(field,"damage"))
1237 info->damage = (INT32)luaL_checkinteger(L, 3);
1238 else if (fastcmp(field,"activesound"))
1239 info->activesound = luaL_checkinteger(L, 3);
1240 else if (fastcmp(field,"flags"))
1241 info->flags = (INT32)luaL_checkinteger(L, 3);
1242 else if (fastcmp(field,"raisestate"))
1243 info->raisestate = luaL_checkinteger(L, 3);
1244 else {
1245 lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS);
1246 I_Assert(lua_istable(L, -1));
1247 lua_pushlightuserdata(L, info);
1248 lua_rawget(L, -2);
1249 if (lua_isnil(L, -1)) {
1250 // This index doesn't have a table for extra values yet, let's make one.
1251 lua_pop(L, 1);
1252 CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; adding it as Lua data.\n"), "mobjinfo_t", field);
1253 lua_newtable(L);
1254 lua_pushlightuserdata(L, info);
1255 lua_pushvalue(L, -2); // ext value table
1256 lua_rawset(L, -4); // LREG_EXTVARS table
1257 }
1258 lua_pushvalue(L, 3); // value to store
1259 lua_setfield(L, -2, field);
1260 lua_pop(L, 2);
1261 }
1262 //else
1263 //return luaL_error(L, LUA_QL("mobjinfo_t") " has no field named " LUA_QS, field);
1264 return 0;
1265 }
1266
1267 // mobjinfo_t * -> MT_*
mobjinfo_num(lua_State * L)1268 static int mobjinfo_num(lua_State *L)
1269 {
1270 mobjinfo_t *info = *((mobjinfo_t **)luaL_checkudata(L, 1, META_MOBJINFO));
1271
1272 I_Assert(info != NULL);
1273 I_Assert(info >= mobjinfo);
1274
1275 lua_pushinteger(L, info-mobjinfo);
1276 return 1;
1277 }
1278
1279 //////////////
1280 // SFX INFO //
1281 //////////////
1282
1283 // Arbitrary S_sfx[] table index -> sfxinfo_t *
lib_getSfxInfo(lua_State * L)1284 static int lib_getSfxInfo(lua_State *L)
1285 {
1286 UINT32 i;
1287 lua_remove(L, 1);
1288
1289 i = luaL_checkinteger(L, 1);
1290 if (i == 0 || i >= NUMSFX)
1291 return luaL_error(L, "sfxinfo[] index %d out of range (1 - %d)", i, NUMSFX-1);
1292 LUA_PushUserdata(L, &S_sfx[i], META_SFXINFO);
1293 return 1;
1294 }
1295
1296 // stack: dummy, S_sfx[] table index, table of values to set.
lib_setSfxInfo(lua_State * L)1297 static int lib_setSfxInfo(lua_State *L)
1298 {
1299 sfxinfo_t *info;
1300
1301 lua_remove(L, 1);
1302 {
1303 UINT32 i = luaL_checkinteger(L, 1);
1304 if (i == 0 || i >= NUMSFX)
1305 return luaL_error(L, "sfxinfo[] index %d out of range (1 - %d)", i, NUMSFX-1);
1306 info = &S_sfx[i]; // get the sfxinfo to assign to.
1307 }
1308 luaL_checktype(L, 2, LUA_TTABLE); // check that we've been passed a table.
1309 lua_remove(L, 1); // pop sfx num, don't need it any more.
1310 lua_settop(L, 1); // cut the stack here. the only thing left now is the table of data we're assigning to the sfx.
1311
1312 if (hud_running)
1313 return luaL_error(L, "Do not alter sfxinfo in HUD rendering code!");
1314 if (hook_cmd_running)
1315 return luaL_error(L, "Do not alter sfxinfo in CMD building code!");
1316
1317 lua_pushnil(L);
1318 while (lua_next(L, 1)) {
1319 enum sfxinfo_write i;
1320
1321 if (lua_isnumber(L, 2))
1322 i = lua_tointeger(L, 2) - 1; // lua is one based, this enum is zero based.
1323 else
1324 i = luaL_checkoption(L, 2, NULL, sfxinfo_wopt);
1325
1326 switch(i)
1327 {
1328 case sfxinfow_singular:
1329 info->singularity = luaL_checkboolean(L, 3);
1330 break;
1331 case sfxinfow_priority:
1332 info->priority = (INT32)luaL_checkinteger(L, 3);
1333 break;
1334 case sfxinfow_flags:
1335 info->pitch = (INT32)luaL_checkinteger(L, 3);
1336 break;
1337 case sfxinfow_caption:
1338 strlcpy(info->caption, luaL_checkstring(L, 3), sizeof(info->caption));
1339 break;
1340 default:
1341 break;
1342 }
1343 lua_pop(L, 1);
1344 }
1345
1346 return 0;
1347 }
1348
lib_sfxlen(lua_State * L)1349 static int lib_sfxlen(lua_State *L)
1350 {
1351 lua_pushinteger(L, NUMSFX);
1352 return 1;
1353 }
1354
1355 // sfxinfo_t *, field
sfxinfo_get(lua_State * L)1356 static int sfxinfo_get(lua_State *L)
1357 {
1358 sfxinfo_t *sfx = *((sfxinfo_t **)luaL_checkudata(L, 1, META_SFXINFO));
1359 enum sfxinfo_read field = luaL_checkoption(L, 2, NULL, sfxinfo_ropt);
1360
1361 I_Assert(sfx != NULL);
1362
1363 switch (field)
1364 {
1365 case sfxinfor_name:
1366 lua_pushstring(L, sfx->name);
1367 return 1;
1368 case sfxinfor_singular:
1369 lua_pushboolean(L, sfx->singularity);
1370 return 1;
1371 case sfxinfor_priority:
1372 lua_pushinteger(L, sfx->priority);
1373 return 1;
1374 case sfxinfor_flags:
1375 lua_pushinteger(L, sfx->pitch);
1376 return 1;
1377 case sfxinfor_caption:
1378 lua_pushstring(L, sfx->caption);
1379 return 1;
1380 case sfxinfor_skinsound:
1381 lua_pushinteger(L, sfx->skinsound);
1382 return 1;
1383 default:
1384 return luaL_error(L, "Field does not exist in sfxinfo_t");
1385 }
1386 return 0;
1387 }
1388
1389 // sfxinfo_t *, field, value
sfxinfo_set(lua_State * L)1390 static int sfxinfo_set(lua_State *L)
1391 {
1392 sfxinfo_t *sfx = *((sfxinfo_t **)luaL_checkudata(L, 1, META_SFXINFO));
1393 enum sfxinfo_write field = luaL_checkoption(L, 2, NULL, sfxinfo_wopt);
1394
1395 if (hud_running)
1396 return luaL_error(L, "Do not alter S_sfx in HUD rendering code!");
1397 if (hook_cmd_running)
1398 return luaL_error(L, "Do not alter S_sfx in CMD building code!");
1399
1400 I_Assert(sfx != NULL);
1401
1402 lua_remove(L, 1); // remove sfxinfo
1403 lua_remove(L, 1); // remove field
1404 lua_settop(L, 1); // leave only one value
1405
1406 switch (field)
1407 {
1408 case sfxinfow_singular:
1409 sfx->singularity = luaL_checkboolean(L, 1);
1410 break;
1411 case sfxinfow_priority:
1412 sfx->priority = luaL_checkinteger(L, 1);
1413 break;
1414 case sfxinfow_flags:
1415 sfx->pitch = luaL_checkinteger(L, 1);
1416 break;
1417 case sfxinfow_caption:
1418 strlcpy(sfx->caption, luaL_checkstring(L, 1), sizeof(sfx->caption));
1419 break;
1420 default:
1421 return luaL_error(L, "Field does not exist in sfxinfo_t");
1422 }
1423 return 0;
1424 }
1425
sfxinfo_num(lua_State * L)1426 static int sfxinfo_num(lua_State *L)
1427 {
1428 sfxinfo_t *sfx = *((sfxinfo_t **)luaL_checkudata(L, 1, META_SFXINFO));
1429
1430 I_Assert(sfx != NULL);
1431 I_Assert(sfx >= S_sfx);
1432
1433 lua_pushinteger(L, (UINT32)(sfx-S_sfx));
1434 return 1;
1435 }
1436
1437 //////////////
1438 // LUABANKS //
1439 //////////////
1440
lib_getluabanks(lua_State * L)1441 static int lib_getluabanks(lua_State *L)
1442 {
1443 UINT8 i;
1444
1445 lua_remove(L, 1); // don't care about luabanks[] dummy userdata.
1446
1447 if (lua_isnumber(L, 1))
1448 i = lua_tonumber(L, 1);
1449 else
1450 return luaL_error(L, "luabanks[] invalid index");
1451
1452 if (i >= NUM_LUABANKS)
1453 luaL_error(L, "luabanks[] index %d out of range (%d - %d)", i, 0, NUM_LUABANKS-1);
1454
1455 lua_pushinteger(L, luabanks[i]);
1456 return 1;
1457 }
1458
lib_setluabanks(lua_State * L)1459 static int lib_setluabanks(lua_State *L)
1460 {
1461 UINT8 i;
1462 INT32 j = 0;
1463
1464 if (hud_running)
1465 return luaL_error(L, "Do not alter luabanks[] in HUD rendering code!");
1466 if (hook_cmd_running)
1467 return luaL_error(L, "Do not alter luabanks[] in CMD building code!");
1468
1469 lua_remove(L, 1); // don't care about luabanks[] dummy userdata.
1470
1471 if (lua_isnumber(L, 1))
1472 i = lua_tonumber(L, 1);
1473 else
1474 return luaL_error(L, "luabanks[] invalid index");
1475
1476 if (i >= NUM_LUABANKS)
1477 luaL_error(L, "luabanks[] index %d out of range (%d - %d)", i, 0, NUM_LUABANKS-1);
1478
1479 if (lua_isnumber(L, 2))
1480 j = lua_tonumber(L, 2);
1481 else
1482 return luaL_error(L, "luabanks[] invalid set");
1483
1484 luabanks[i] = j;
1485 return 0;
1486 }
1487
lib_luabankslen(lua_State * L)1488 static int lib_luabankslen(lua_State *L)
1489 {
1490 lua_pushinteger(L, NUM_LUABANKS);
1491 return 1;
1492 }
1493
1494 ////////////////////
1495 // SKINCOLOR INFO //
1496 ////////////////////
1497
1498 // Arbitrary skincolors[] table index -> skincolor_t *
lib_getSkinColor(lua_State * L)1499 static int lib_getSkinColor(lua_State *L)
1500 {
1501 UINT32 i;
1502 lua_remove(L, 1);
1503
1504 i = luaL_checkinteger(L, 1);
1505 if (!i || i >= numskincolors)
1506 return luaL_error(L, "skincolors[] index %d out of range (1 - %d)", i, numskincolors-1);
1507 LUA_PushUserdata(L, &skincolors[i], META_SKINCOLOR);
1508 return 1;
1509 }
1510
1511 //Set the entire c->ramp array
setRamp(lua_State * L,skincolor_t * c)1512 static void setRamp(lua_State *L, skincolor_t* c) {
1513 UINT32 i;
1514 lua_pushnil(L);
1515 for (i=0; i<COLORRAMPSIZE; i++) {
1516 if (lua_objlen(L,-2)!=COLORRAMPSIZE) {
1517 luaL_error(L, LUA_QL("skincolor_t") " field 'ramp' must be %d entries long; got %d.", COLORRAMPSIZE, lua_objlen(L,-2));
1518 break;
1519 }
1520 if (lua_next(L, -2) != 0) {
1521 c->ramp[i] = lua_isnumber(L,-1) ? (UINT8)luaL_checkinteger(L,-1) : 120;
1522 lua_pop(L, 1);
1523 } else
1524 c->ramp[i] = 120;
1525 }
1526 lua_pop(L,1);
1527 }
1528
1529 // Lua table full of data -> skincolors[]
lib_setSkinColor(lua_State * L)1530 static int lib_setSkinColor(lua_State *L)
1531 {
1532 UINT32 j;
1533 skincolor_t *info;
1534 UINT16 cnum; //skincolor num
1535 lua_remove(L, 1); // don't care about skincolors[] userdata.
1536 {
1537 cnum = (UINT16)luaL_checkinteger(L, 1);
1538 if (!cnum || cnum >= numskincolors)
1539 return luaL_error(L, "skincolors[] index %d out of range (1 - %d)", cnum, numskincolors-1);
1540 info = &skincolors[cnum]; // get the skincolor to assign to.
1541 }
1542 luaL_checktype(L, 2, LUA_TTABLE); // check that we've been passed a table.
1543 lua_remove(L, 1); // pop skincolor num, don't need it any more.
1544 lua_settop(L, 1); // cut the stack here. the only thing left now is the table of data we're assigning to the skincolor.
1545
1546 if (hud_running)
1547 return luaL_error(L, "Do not alter skincolors in HUD rendering code!");
1548 if (hook_cmd_running)
1549 return luaL_error(L, "Do not alter skincolors in CMD building code!");
1550
1551 // clear the skincolor to start with, in case of missing table elements
1552 memset(info,0,sizeof(skincolor_t));
1553
1554 Color_cons_t[cnum].value = cnum;
1555 lua_pushnil(L);
1556 while (lua_next(L, 1)) {
1557 lua_Integer i = 0;
1558 const char *str = NULL;
1559 if (lua_isnumber(L, 2))
1560 i = lua_tointeger(L, 2);
1561 else
1562 str = luaL_checkstring(L, 2);
1563
1564 if (i == 1 || (str && fastcmp(str,"name"))) {
1565 const char* n = luaL_checkstring(L, 3);
1566 strlcpy(info->name, n, MAXCOLORNAME+1);
1567 if (strlen(n) > MAXCOLORNAME)
1568 CONS_Alert(CONS_WARNING, "skincolor_t field 'name' ('%s') longer than %d chars; clipped to %s.\n", n, MAXCOLORNAME, info->name);
1569 #if 0
1570 if (strchr(info->name, ' ') != NULL)
1571 CONS_Alert(CONS_WARNING, "skincolor_t field 'name' ('%s') contains spaces.\n", info->name);
1572 #endif
1573
1574 if (info->name[0] != '\0') // don't check empty string for dupe
1575 {
1576 UINT16 dupecheck = R_GetColorByName(info->name);
1577 if (!stricmp(info->name, skincolors[SKINCOLOR_NONE].name) || (dupecheck && (dupecheck != info-skincolors)))
1578 CONS_Alert(CONS_WARNING, "skincolor_t field 'name' ('%s') is a duplicate of another skincolor's name.\n", info->name);
1579 }
1580 } else if (i == 2 || (str && fastcmp(str,"ramp"))) {
1581 if (!lua_istable(L, 3) && luaL_checkudata(L, 3, META_COLORRAMP) == NULL)
1582 return luaL_error(L, LUA_QL("skincolor_t") " field 'ramp' must be a table or array.");
1583 else if (lua_istable(L, 3))
1584 setRamp(L, info);
1585 else
1586 for (j=0; j<COLORRAMPSIZE; j++)
1587 info->ramp[j] = (*((UINT8 **)luaL_checkudata(L, 3, META_COLORRAMP)))[j];
1588 skincolor_modified[cnum] = true;
1589 } else if (i == 3 || (str && fastcmp(str,"invcolor"))) {
1590 UINT16 v = (UINT16)luaL_checkinteger(L, 3);
1591 if (v >= numskincolors)
1592 return luaL_error(L, "skincolor_t field 'invcolor' out of range (1 - %d)", numskincolors-1);
1593 info->invcolor = v;
1594 } else if (i == 4 || (str && fastcmp(str,"invshade")))
1595 info->invshade = (UINT8)luaL_checkinteger(L, 3)%COLORRAMPSIZE;
1596 else if (i == 5 || (str && fastcmp(str,"chatcolor")))
1597 info->chatcolor = (UINT16)luaL_checkinteger(L, 3);
1598 else if (i == 6 || (str && fastcmp(str,"accessible"))) {
1599 boolean v = lua_toboolean(L, 3);
1600 if (cnum < FIRSTSUPERCOLOR && v != skincolors[cnum].accessible)
1601 return luaL_error(L, "skincolors[] index %d is a standard color; accessibility changes are prohibited.", cnum);
1602 else
1603 info->accessible = v;
1604 }
1605 lua_pop(L, 1);
1606 }
1607 return 0;
1608 }
1609
1610 // #skincolors -> numskincolors
lib_skincolorslen(lua_State * L)1611 static int lib_skincolorslen(lua_State *L)
1612 {
1613 lua_pushinteger(L, numskincolors);
1614 return 1;
1615 }
1616
1617 // skincolor_t *, field -> number
skincolor_get(lua_State * L)1618 static int skincolor_get(lua_State *L)
1619 {
1620 skincolor_t *info = *((skincolor_t **)luaL_checkudata(L, 1, META_SKINCOLOR));
1621 const char *field = luaL_checkstring(L, 2);
1622
1623 I_Assert(info != NULL);
1624 I_Assert(info >= skincolors);
1625
1626 if (fastcmp(field,"name"))
1627 lua_pushstring(L, info->name);
1628 else if (fastcmp(field,"ramp"))
1629 LUA_PushUserdata(L, info->ramp, META_COLORRAMP);
1630 else if (fastcmp(field,"invcolor"))
1631 lua_pushinteger(L, info->invcolor);
1632 else if (fastcmp(field,"invshade"))
1633 lua_pushinteger(L, info->invshade);
1634 else if (fastcmp(field,"chatcolor"))
1635 lua_pushinteger(L, info->chatcolor);
1636 else if (fastcmp(field,"accessible"))
1637 lua_pushboolean(L, info->accessible);
1638 else {
1639 CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; returning nil.\n"), "skincolor_t", field);
1640 return 0;
1641 }
1642 return 1;
1643 }
1644
1645 // skincolor_t *, field, number -> skincolors[]
skincolor_set(lua_State * L)1646 static int skincolor_set(lua_State *L)
1647 {
1648 UINT32 i;
1649 skincolor_t *info = *((skincolor_t **)luaL_checkudata(L, 1, META_SKINCOLOR));
1650 const char *field = luaL_checkstring(L, 2);
1651 UINT16 cnum = (UINT16)(info-skincolors);
1652
1653 I_Assert(info != NULL);
1654 I_Assert(info >= skincolors);
1655
1656 if (!cnum || cnum >= numskincolors)
1657 return luaL_error(L, "skincolors[] index %d out of range (1 - %d)", cnum, numskincolors-1);
1658
1659 if (fastcmp(field,"name")) {
1660 const char* n = luaL_checkstring(L, 3);
1661 strlcpy(info->name, n, MAXCOLORNAME+1);
1662 if (strlen(n) > MAXCOLORNAME)
1663 CONS_Alert(CONS_WARNING, "skincolor_t field 'name' ('%s') longer than %d chars; clipped to %s.\n", n, MAXCOLORNAME, info->name);
1664 #if 0
1665 if (strchr(info->name, ' ') != NULL)
1666 CONS_Alert(CONS_WARNING, "skincolor_t field 'name' ('%s') contains spaces.\n", info->name);
1667 #endif
1668
1669 if (info->name[0] != '\0') // don't check empty string for dupe
1670 {
1671 UINT16 dupecheck = R_GetColorByName(info->name);
1672 if (!stricmp(info->name, skincolors[SKINCOLOR_NONE].name) || (dupecheck && (dupecheck != cnum)))
1673 CONS_Alert(CONS_WARNING, "skincolor_t field 'name' ('%s') is a duplicate of another skincolor's name.\n", info->name);
1674 }
1675 } else if (fastcmp(field,"ramp")) {
1676 if (!lua_istable(L, 3) && luaL_checkudata(L, 3, META_COLORRAMP) == NULL)
1677 return luaL_error(L, LUA_QL("skincolor_t") " field 'ramp' must be a table or array.");
1678 else if (lua_istable(L, 3))
1679 setRamp(L, info);
1680 else
1681 for (i=0; i<COLORRAMPSIZE; i++)
1682 info->ramp[i] = (*((UINT8 **)luaL_checkudata(L, 3, META_COLORRAMP)))[i];
1683 skincolor_modified[cnum] = true;
1684 } else if (fastcmp(field,"invcolor")) {
1685 UINT16 v = (UINT16)luaL_checkinteger(L, 3);
1686 if (v >= numskincolors)
1687 return luaL_error(L, "skincolor_t field 'invcolor' out of range (1 - %d)", numskincolors-1);
1688 info->invcolor = v;
1689 } else if (fastcmp(field,"invshade"))
1690 info->invshade = (UINT8)luaL_checkinteger(L, 3)%COLORRAMPSIZE;
1691 else if (fastcmp(field,"chatcolor"))
1692 info->chatcolor = (UINT16)luaL_checkinteger(L, 3);
1693 else if (fastcmp(field,"accessible")) {
1694 boolean v = lua_toboolean(L, 3);
1695 if (cnum < FIRSTSUPERCOLOR && v != skincolors[cnum].accessible)
1696 return luaL_error(L, "skincolors[] index %d is a standard color; accessibility changes are prohibited.", cnum);
1697 else
1698 info->accessible = v;
1699 } else
1700 CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; returning nil.\n"), "skincolor_t", field);
1701 return 1;
1702 }
1703
1704 // skincolor_t * -> SKINCOLOR_*
skincolor_num(lua_State * L)1705 static int skincolor_num(lua_State *L)
1706 {
1707 skincolor_t *info = *((skincolor_t **)luaL_checkudata(L, 1, META_SKINCOLOR));
1708
1709 I_Assert(info != NULL);
1710 I_Assert(info >= skincolors);
1711
1712 lua_pushinteger(L, info-skincolors);
1713 return 1;
1714 }
1715
1716 // ramp, n -> ramp[n]
colorramp_get(lua_State * L)1717 static int colorramp_get(lua_State *L)
1718 {
1719 UINT8 *colorramp = *((UINT8 **)luaL_checkudata(L, 1, META_COLORRAMP));
1720 UINT32 n = luaL_checkinteger(L, 2);
1721 if (n >= COLORRAMPSIZE)
1722 return luaL_error(L, LUA_QL("skincolor_t") " field 'ramp' index %d out of range (0 - %d)", n, COLORRAMPSIZE-1);
1723 lua_pushinteger(L, colorramp[n]);
1724 return 1;
1725 }
1726
1727 // ramp, n, value -> ramp[n] = value
colorramp_set(lua_State * L)1728 static int colorramp_set(lua_State *L)
1729 {
1730 UINT8 *colorramp = *((UINT8 **)luaL_checkudata(L, 1, META_COLORRAMP));
1731 UINT16 cnum = (UINT16)(((UINT8*)colorramp - (UINT8*)(skincolors[0].ramp))/sizeof(skincolor_t));
1732 UINT32 n = luaL_checkinteger(L, 2);
1733 UINT8 i = (UINT8)luaL_checkinteger(L, 3);
1734 if (!cnum || cnum >= numskincolors)
1735 return luaL_error(L, "skincolors[] index %d out of range (1 - %d)", cnum, numskincolors-1);
1736 if (n >= COLORRAMPSIZE)
1737 return luaL_error(L, LUA_QL("skincolor_t") " field 'ramp' index %d out of range (0 - %d)", n, COLORRAMPSIZE-1);
1738 if (hud_running)
1739 return luaL_error(L, "Do not alter skincolor_t in HUD rendering code!");
1740 if (hook_cmd_running)
1741 return luaL_error(L, "Do not alter skincolor_t in CMD building code!");
1742 colorramp[n] = i;
1743 skincolor_modified[cnum] = true;
1744 return 0;
1745 }
1746
1747 // #ramp -> COLORRAMPSIZE
colorramp_len(lua_State * L)1748 static int colorramp_len(lua_State *L)
1749 {
1750 lua_pushinteger(L, COLORRAMPSIZE);
1751 return 1;
1752 }
1753
1754 //////////////////////////////
1755 //
1756 // Now push all these functions into the Lua state!
1757 //
1758 //
LUA_InfoLib(lua_State * L)1759 int LUA_InfoLib(lua_State *L)
1760 {
1761 // index of A_Lua actions to run for each state
1762 lua_newtable(L);
1763 lua_setfield(L, LUA_REGISTRYINDEX, LREG_STATEACTION);
1764
1765 // index of globally available Lua actions by function name
1766 lua_newtable(L);
1767 lua_setfield(L, LUA_REGISTRYINDEX, LREG_ACTIONS);
1768
1769 luaL_newmetatable(L, META_STATE);
1770 lua_pushcfunction(L, state_get);
1771 lua_setfield(L, -2, "__index");
1772
1773 lua_pushcfunction(L, state_set);
1774 lua_setfield(L, -2, "__newindex");
1775
1776 lua_pushcfunction(L, state_num);
1777 lua_setfield(L, -2, "__len");
1778 lua_pop(L, 1);
1779
1780 luaL_newmetatable(L, META_MOBJINFO);
1781 lua_pushcfunction(L, mobjinfo_get);
1782 lua_setfield(L, -2, "__index");
1783
1784 lua_pushcfunction(L, mobjinfo_set);
1785 lua_setfield(L, -2, "__newindex");
1786
1787 lua_pushcfunction(L, mobjinfo_num);
1788 lua_setfield(L, -2, "__len");
1789 lua_pop(L, 1);
1790
1791 luaL_newmetatable(L, META_SKINCOLOR);
1792 lua_pushcfunction(L, skincolor_get);
1793 lua_setfield(L, -2, "__index");
1794
1795 lua_pushcfunction(L, skincolor_set);
1796 lua_setfield(L, -2, "__newindex");
1797
1798 lua_pushcfunction(L, skincolor_num);
1799 lua_setfield(L, -2, "__len");
1800 lua_pop(L, 1);
1801
1802 luaL_newmetatable(L, META_COLORRAMP);
1803 lua_pushcfunction(L, colorramp_get);
1804 lua_setfield(L, -2, "__index");
1805
1806 lua_pushcfunction(L, colorramp_set);
1807 lua_setfield(L, -2, "__newindex");
1808
1809 lua_pushcfunction(L, colorramp_len);
1810 lua_setfield(L, -2, "__len");
1811 lua_pop(L,1);
1812
1813 luaL_newmetatable(L, META_SFXINFO);
1814 lua_pushcfunction(L, sfxinfo_get);
1815 lua_setfield(L, -2, "__index");
1816
1817 lua_pushcfunction(L, sfxinfo_set);
1818 lua_setfield(L, -2, "__newindex");
1819
1820 lua_pushcfunction(L, sfxinfo_num);
1821 lua_setfield(L, -2, "__len");
1822 lua_pop(L, 1);
1823
1824 luaL_newmetatable(L, META_SPRITEINFO);
1825 lua_pushcfunction(L, spriteinfo_get);
1826 lua_setfield(L, -2, "__index");
1827
1828 lua_pushcfunction(L, spriteinfo_set);
1829 lua_setfield(L, -2, "__newindex");
1830
1831 lua_pushcfunction(L, spriteinfo_num);
1832 lua_setfield(L, -2, "__len");
1833 lua_pop(L, 1);
1834
1835 luaL_newmetatable(L, META_PIVOTLIST);
1836 lua_pushcfunction(L, pivotlist_get);
1837 lua_setfield(L, -2, "__index");
1838
1839 lua_pushcfunction(L, pivotlist_set);
1840 lua_setfield(L, -2, "__newindex");
1841
1842 lua_pushcfunction(L, pivotlist_num);
1843 lua_setfield(L, -2, "__len");
1844 lua_pop(L, 1);
1845
1846 luaL_newmetatable(L, META_FRAMEPIVOT);
1847 lua_pushcfunction(L, framepivot_get);
1848 lua_setfield(L, -2, "__index");
1849
1850 lua_pushcfunction(L, framepivot_set);
1851 lua_setfield(L, -2, "__newindex");
1852
1853 lua_pushcfunction(L, framepivot_num);
1854 lua_setfield(L, -2, "__len");
1855 lua_pop(L, 1);
1856
1857 lua_newuserdata(L, 0);
1858 lua_createtable(L, 0, 2);
1859 lua_pushcfunction(L, lib_getSprname);
1860 lua_setfield(L, -2, "__index");
1861
1862 lua_pushcfunction(L, lib_sprnamelen);
1863 lua_setfield(L, -2, "__len");
1864 lua_setmetatable(L, -2);
1865 lua_setglobal(L, "sprnames");
1866
1867 lua_newuserdata(L, 0);
1868 lua_createtable(L, 0, 2);
1869 lua_pushcfunction(L, lib_getSpr2name);
1870 lua_setfield(L, -2, "__index");
1871
1872 lua_pushcfunction(L, lib_spr2namelen);
1873 lua_setfield(L, -2, "__len");
1874 lua_setmetatable(L, -2);
1875 lua_setglobal(L, "spr2names");
1876
1877 lua_newuserdata(L, 0);
1878 lua_createtable(L, 0, 2);
1879 lua_pushcfunction(L, lib_getSpr2default);
1880 lua_setfield(L, -2, "__index");
1881
1882 lua_pushcfunction(L, lib_setSpr2default);
1883 lua_setfield(L, -2, "__newindex");
1884
1885 lua_pushcfunction(L, lib_spr2namelen);
1886 lua_setfield(L, -2, "__len");
1887 lua_setmetatable(L, -2);
1888 lua_setglobal(L, "spr2defaults");
1889
1890 lua_newuserdata(L, 0);
1891 lua_createtable(L, 0, 2);
1892 lua_pushcfunction(L, lib_getState);
1893 lua_setfield(L, -2, "__index");
1894
1895 lua_pushcfunction(L, lib_setState);
1896 lua_setfield(L, -2, "__newindex");
1897
1898 lua_pushcfunction(L, lib_statelen);
1899 lua_setfield(L, -2, "__len");
1900 lua_setmetatable(L, -2);
1901 lua_setglobal(L, "states");
1902
1903 lua_newuserdata(L, 0);
1904 lua_createtable(L, 0, 2);
1905 lua_pushcfunction(L, lib_getMobjInfo);
1906 lua_setfield(L, -2, "__index");
1907
1908 lua_pushcfunction(L, lib_setMobjInfo);
1909 lua_setfield(L, -2, "__newindex");
1910
1911 lua_pushcfunction(L, lib_mobjinfolen);
1912 lua_setfield(L, -2, "__len");
1913 lua_setmetatable(L, -2);
1914 lua_setglobal(L, "mobjinfo");
1915
1916 lua_newuserdata(L, 0);
1917 lua_createtable(L, 0, 2);
1918 lua_pushcfunction(L, lib_getSkinColor);
1919 lua_setfield(L, -2, "__index");
1920
1921 lua_pushcfunction(L, lib_setSkinColor);
1922 lua_setfield(L, -2, "__newindex");
1923
1924 lua_pushcfunction(L, lib_skincolorslen);
1925 lua_setfield(L, -2, "__len");
1926 lua_setmetatable(L, -2);
1927 lua_setglobal(L, "skincolors");
1928
1929 lua_newuserdata(L, 0);
1930 lua_createtable(L, 0, 2);
1931 lua_pushcfunction(L, lib_getSfxInfo);
1932 lua_setfield(L, -2, "__index");
1933
1934 lua_pushcfunction(L, lib_setSfxInfo);
1935 lua_setfield(L, -2, "__newindex");
1936
1937 lua_pushcfunction(L, lib_sfxlen);
1938 lua_setfield(L, -2, "__len");
1939 lua_setmetatable(L, -2);
1940 lua_pushvalue(L, -1);
1941 lua_setglobal(L, "S_sfx");
1942 lua_setglobal(L, "sfxinfo");
1943
1944 lua_newuserdata(L, 0);
1945 lua_createtable(L, 0, 2);
1946 lua_pushcfunction(L, lib_getSpriteInfo);
1947 lua_setfield(L, -2, "__index");
1948
1949 lua_pushcfunction(L, lib_setSpriteInfo);
1950 lua_setfield(L, -2, "__newindex");
1951
1952 lua_pushcfunction(L, lib_spriteinfolen);
1953 lua_setfield(L, -2, "__len");
1954 lua_setmetatable(L, -2);
1955 lua_setglobal(L, "spriteinfo");
1956
1957 luaL_newmetatable(L, META_LUABANKS);
1958 lua_pushcfunction(L, lib_getluabanks);
1959 lua_setfield(L, -2, "__index");
1960
1961 lua_pushcfunction(L, lib_setluabanks);
1962 lua_setfield(L, -2, "__newindex");
1963
1964 lua_pushcfunction(L, lib_luabankslen);
1965 lua_setfield(L, -2, "__len");
1966 lua_pop(L, 1);
1967
1968 return 0;
1969 }
1970