1 //-------------------------------------------------------------------------
2 /*
3 Copyright (C) 2010 EDuke32 developers and contributors
4 
5 This file is part of EDuke32.
6 
7 EDuke32 is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License version 2
9 as published by the Free Software Foundation.
10 
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 
15 See the GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 */
21 //-------------------------------------------------------------------------
22 
23 #include "gamestructures.h"
24 
25 #include "compat.h"
26 #include "gamedef.h"
27 #include "sector.h"
28 #include "gameexec.h"
29 #include "global.h"
30 
31 #define LABEL(struct, memb, name, idx)                                                              \
32     {                                                                                                               \
33         name, idx, sizeof(struct[0].memb) | (is_unsigned<decltype(struct[0].memb)>::value ? LABEL_UNSIGNED : 0), 0, \
34         offsetof(remove_pointer_t<decltype(&struct[0])>, memb)                                                      \
35     }
36 
37 #define MEMBER(struct, memb, idx) LABEL(struct, memb, #memb, idx)
38 
39 memberlabel_t const SectorLabels[] =
40 {
41     {                             "wallptr",      SECTOR_WALLPTR, sizeof(sector[0].wallptr) | LABEL_WRITEFUNC, 0, offsetof(usectortype, wallptr) },
42     MEMBER(sector, wallnum,                       SECTOR_WALLNUM),
43 
44     MEMBER(sector, ceilingz,                      SECTOR_CEILINGZ),
45     {                             "ceilingzgoal", SECTOR_CEILINGZGOAL, 0, 0, -1 },
46     {                             "ceilingzvel",  SECTOR_CEILINGZVEL, 0, 0, -1 },
47 
48     MEMBER(sector, floorz,                        SECTOR_FLOORZ),
49     {                             "floorzgoal",   SECTOR_FLOORZGOAL, 0, 0, -1 },
50     {                             "floorzvel",    SECTOR_FLOORZVEL, 0, 0, -1 },
51 
52     MEMBER(sector, ceilingstat,                   SECTOR_CEILINGSTAT),
53     MEMBER(sector, floorstat,                     SECTOR_FLOORSTAT),
54 
55     MEMBER(sector, ceilingpicnum,                 SECTOR_CEILINGPICNUM),
56      LABEL(sector, ceilingheinum, "ceilingslope", SECTOR_CEILINGSLOPE),
57 
58     MEMBER(sector, ceilingshade,                  SECTOR_CEILINGSHADE),
59     MEMBER(sector, ceilingpal,                    SECTOR_CEILINGPAL),
60     MEMBER(sector, ceilingxpanning,               SECTOR_CEILINGXPANNING),
61     MEMBER(sector, ceilingypanning,               SECTOR_CEILINGYPANNING),
62 
63     MEMBER(sector, floorpicnum,                   SECTOR_FLOORPICNUM),
64      LABEL(sector, floorheinum,   "floorslope",   SECTOR_FLOORSLOPE),
65     MEMBER(sector, floorshade,                    SECTOR_FLOORSHADE),
66     MEMBER(sector, floorpal,                      SECTOR_FLOORPAL),
67     MEMBER(sector, floorxpanning,                 SECTOR_FLOORXPANNING),
68     MEMBER(sector, floorypanning,                 SECTOR_FLOORYPANNING),
69 
70     MEMBER(sector, visibility,                    SECTOR_VISIBILITY),
71     MEMBER(sector, fogpal,                        SECTOR_FOGPAL),
72 
73     MEMBER(sector, lotag,                         SECTOR_LOTAG),
74     MEMBER(sector, hitag,                         SECTOR_HITAG),
75     MEMBER(sector, extra,                         SECTOR_EXTRA),
76 
77     {                             "ceilingbunch", SECTOR_CEILINGBUNCH, 0, 0, -1 },
78     {                             "floorbunch",   SECTOR_FLOORBUNCH, 0, 0, -1 },
79 
80     {                             "ulotag",       SECTOR_ULOTAG, sizeof(sector[0].lotag) | LABEL_UNSIGNED, 0, offsetof(usectortype, lotag) },
81     {                             "uhitag",       SECTOR_UHITAG, sizeof(sector[0].hitag) | LABEL_UNSIGNED, 0, offsetof(usectortype, hitag) },
82 
83 };
84 
VM_GetSector(int const sectNum,int32_t labelNum)85 int32_t __fastcall VM_GetSector(int const sectNum, int32_t labelNum)
86 {
87     auto const &s = *(usectorptr_t)&sector[sectNum];
88 
89     switch (labelNum)
90     {
91         case SECTOR_CEILINGZVEL:
92             labelNum = (GetAnimationGoal(&s.ceilingz) == -1) ? 0 : s.extra; break;
93         case SECTOR_CEILINGZGOAL:
94             labelNum = GetAnimationGoal(&s.ceilingz); break;
95 
96         case SECTOR_FLOORZVEL:
97             labelNum = (GetAnimationGoal(&s.floorz) == -1) ? 0 : s.extra; break;
98 
99         case SECTOR_FLOORZGOAL:
100             labelNum = GetAnimationGoal(&s.floorz); break;
101 
102         case SECTOR_CEILINGBUNCH:
103         case SECTOR_FLOORBUNCH:
104 #ifdef YAX_ENABLE
105             labelNum = yax_getbunch(sectNum, labelNum == SECTOR_FLOORBUNCH);
106 #else
107             labelNum = -1;
108 #endif
109             break;
110 
111         default: EDUKE32_UNREACHABLE_SECTION(labelNum = -1; break);
112     }
113 
114     return labelNum;
115 }
116 
VM_SetSector(int const sectNum,int const labelNum,int32_t newValue)117 void __fastcall VM_SetSector(int const sectNum, int const labelNum, int32_t newValue)
118 {
119     auto &s = sector[sectNum];
120 
121     switch (labelNum)
122     {
123         case SECTOR_WALLPTR:
124             setfirstwall(sectNum, newValue); break;
125 
126         case SECTOR_CEILINGZVEL:
127             s.extra = newValue;
128             if ((newValue = GetAnimationGoal(&s.ceilingz)) != -1)
129             {
130         case SECTOR_CEILINGZGOAL:
131                 SetAnimation(sectNum, &s.ceilingz, newValue, s.extra);
132             }
133             break;
134 
135         case SECTOR_FLOORZVEL:
136             s.extra = newValue;
137             if ((newValue = GetAnimationGoal(&s.floorz)) != -1)
138             {
139         case SECTOR_FLOORZGOAL:
140                 SetAnimation(sectNum, &s.floorz, newValue, s.extra);
141             }
142             break;
143 
144         case SECTOR_CEILINGBUNCH:
145         case SECTOR_FLOORBUNCH:
146             break;
147 
148         default: EDUKE32_UNREACHABLE_SECTION(break);
149     }
150 }
151 
152 memberlabel_t const WallLabels[]=
153 {
154     MEMBER(wall, x,          WALL_X),
155     MEMBER(wall, y,          WALL_Y),
156     MEMBER(wall, point2,     WALL_POINT2),
157     MEMBER(wall, nextwall,   WALL_NEXTWALL),
158     MEMBER(wall, nextsector, WALL_NEXTSECTOR),
159     MEMBER(wall, cstat,      WALL_CSTAT),
160     MEMBER(wall, picnum,     WALL_PICNUM),
161     MEMBER(wall, overpicnum, WALL_OVERPICNUM),
162     MEMBER(wall, shade,      WALL_SHADE),
163     MEMBER(wall, pal,        WALL_PAL),
164     MEMBER(wall, xrepeat,    WALL_XREPEAT),
165     MEMBER(wall, yrepeat,    WALL_YREPEAT),
166     MEMBER(wall, xpanning,   WALL_XPANNING),
167     MEMBER(wall, ypanning,   WALL_YPANNING),
168     MEMBER(wall, lotag,      WALL_LOTAG),
169     MEMBER(wall, hitag,      WALL_HITAG),
170     MEMBER(wall, extra,      WALL_EXTRA),
171 
172     { "ulotag", WALL_ULOTAG, sizeof(wall[0].lotag) | LABEL_UNSIGNED, 0, offsetof(uwalltype, lotag) },
173     { "uhitag", WALL_UHITAG, sizeof(wall[0].hitag) | LABEL_UNSIGNED, 0, offsetof(uwalltype, hitag) },
174 
175     { "blend", WALL_BLEND, 0, 0, -1 },
176 };
177 
VM_GetWall(int const wallNum,int32_t labelNum)178 int32_t __fastcall VM_GetWall(int const wallNum, int32_t labelNum)
179 {
180     switch (labelNum)
181     {
182         case WALL_BLEND:
183 #ifdef NEW_MAP_FORMAT
184             labelNum = w.blend;
185 #else
186             labelNum = wallext[wallNum].blend;
187 #endif
188             break;
189 
190         default: EDUKE32_UNREACHABLE_SECTION(labelNum = -1; break);
191     }
192 
193     return labelNum;
194 }
195 
VM_SetWall(int const wallNum,int const labelNum,int32_t const newValue)196 void __fastcall VM_SetWall(int const wallNum, int const labelNum, int32_t const newValue)
197 {
198     switch (labelNum)
199     {
200         case WALL_BLEND:
201 #ifdef NEW_MAP_FORMAT
202             w.blend = newValue;
203 #else
204             wallext[wallNum].blend = newValue;
205 #endif
206             break;
207     }
208 
209 }
210 
211 memberlabel_t const ActorLabels[]=
212 {
213     MEMBER(sprite, x,        ACTOR_X),
214     MEMBER(sprite, y,        ACTOR_Y),
215     MEMBER(sprite, z,        ACTOR_Z),
216     MEMBER(sprite, cstat,    ACTOR_CSTAT),
217     MEMBER(sprite, picnum,   ACTOR_PICNUM),
218     MEMBER(sprite, shade,    ACTOR_SHADE),
219     MEMBER(sprite, pal,      ACTOR_PAL),
220     MEMBER(sprite, clipdist, ACTOR_CLIPDIST),
221     MEMBER(sprite, blend,    ACTOR_DETAIL),
222     MEMBER(sprite, xrepeat,  ACTOR_XREPEAT),
223     MEMBER(sprite, yrepeat,  ACTOR_YREPEAT),
224     MEMBER(sprite, xoffset,  ACTOR_XOFFSET),
225     MEMBER(sprite, yoffset,  ACTOR_YOFFSET),
226     { "sectnum", ACTOR_SECTNUM, sizeof(sprite[0].sectnum) | LABEL_WRITEFUNC, 0, offsetof(uspritetype, sectnum) },
227     { "statnum", ACTOR_STATNUM, sizeof(sprite[0].statnum) | LABEL_WRITEFUNC, 0, offsetof(uspritetype, statnum) },
228     MEMBER(sprite, ang,      ACTOR_ANG),
229     MEMBER(sprite, owner,    ACTOR_OWNER),
230     MEMBER(sprite, xvel,     ACTOR_XVEL),
231     MEMBER(sprite, yvel,     ACTOR_YVEL),
232     MEMBER(sprite, zvel,     ACTOR_ZVEL),
233     MEMBER(sprite, lotag,    ACTOR_LOTAG),
234     MEMBER(sprite, hitag,    ACTOR_HITAG),
235     MEMBER(sprite, extra,    ACTOR_EXTRA),
236 
237     { "ulotag", ACTOR_ULOTAG, sizeof(sprite[0].lotag) | LABEL_UNSIGNED, 0, offsetof(uspritetype, lotag) },
238     { "uhitag", ACTOR_UHITAG, sizeof(sprite[0].hitag) | LABEL_UNSIGNED, 0, offsetof(uspritetype, hitag) },
239 
240     // ActorExtra labels...
241     LABEL(actor, cgg,         "htcgg",          ACTOR_HTCGG),
242     LABEL(actor, picnum,      "htpicnum",       ACTOR_HTPICNUM),
243     LABEL(actor, ang,         "htang",          ACTOR_HTANG),
244     LABEL(actor, extra,       "htextra",        ACTOR_HTEXTRA),
245     LABEL(actor, owner,       "htowner",        ACTOR_HTOWNER),
246     LABEL(actor, movflag,     "htmovflag",      ACTOR_HTMOVFLAG),
247     { "htumovflag", ACTOR_HTUMOVFLAG, sizeof(actor[0].movflag) | LABEL_UNSIGNED, 0, offsetof(actor_t, movflag) },
248     LABEL(actor, tempang,     "httempang",      ACTOR_HTTEMPANG),
249     LABEL(actor, stayput,     "htactorstayput", ACTOR_HTSTAYPUT),
250     LABEL(actor, dispicnum,   "htdispicnum",    ACTOR_HTDISPICNUM),
251     LABEL(actor, timetosleep, "httimetosleep",  ACTOR_HTTIMETOSLEEP),
252     LABEL(actor, floorz,      "htfloorz",       ACTOR_HTFLOORZ),
253     LABEL(actor, ceilingz,    "htceilingz",     ACTOR_HTCEILINGZ),
254     LABEL(actor, lastv.x,     "htlastvx",       ACTOR_HTLASTVX),
255     LABEL(actor, lastv.y,     "htlastvy",       ACTOR_HTLASTVY),
256     LABEL(actor, bpos.x,      "htbposx",        ACTOR_HTBPOSX),
257     LABEL(actor, bpos.y,      "htbposy",        ACTOR_HTBPOSY),
258     LABEL(actor, bpos.z,      "htbposz",        ACTOR_HTBPOSZ),
259 
260     {                         "htg_t",          ACTOR_HTG_T, LABEL_HASPARM2, 10, -1 },
261     LABEL(actor, flags,       "htflags",        ACTOR_HTFLAGS),
262 
263     // model flags
264 
265     LABEL(spriteext, mdangoff,            "angoff",     ACTOR_ANGOFF),
266     LABEL(spriteext, mdpitch,             "pitch",      ACTOR_PITCH),
267     LABEL(spriteext, mdroll,              "roll",       ACTOR_ROLL),
268 
269     LABEL(spriteext, mdpivot_offset.x,    "mdxoff",     ACTOR_MDPIVOTXOFF),
270     LABEL(spriteext, mdpivot_offset.y,    "mdyoff",     ACTOR_MDPIVOTYOFF),
271     LABEL(spriteext, mdpivot_offset.z,    "mdzoff",     ACTOR_MDPIVOTZOFF),
272     LABEL(spriteext, mdposition_offset.x, "mdposxoff",  ACTOR_MDPOSITIONXOFF),
273     LABEL(spriteext, mdposition_offset.y, "mdposyoff",  ACTOR_MDPOSITIONYOFF),
274     LABEL(spriteext, mdposition_offset.z, "mdposzoff",  ACTOR_MDPOSITIONZOFF),
275     LABEL(spriteext, flags,               "mdflags",    ACTOR_MDFLAGS),
276 
277     MEMBER(spriteext, xpanning, ACTOR_XPANNING),
278     MEMBER(spriteext, ypanning, ACTOR_YPANNING),
279 
280     { "alpha",    ACTOR_ALPHA,   0, 0, -1 },
281     { "isvalid",  ACTOR_ISVALID, 0, 0, -1 },
282 
283     // aliases:
284     { "movflags", ACTOR_HITAG,   0, 0, -1 },
285     { "detail",   ACTOR_DETAIL,  0, 0, -1 },  // deprecated name for 'blend'
286 };
287 
VM_SetSprite(int const spriteNum,int const labelNum,int const lParm2,int32_t const newValue)288 void __fastcall VM_SetSprite(int const spriteNum, int const labelNum, int const lParm2, int32_t const newValue)
289 {
290     auto &a   = actor[spriteNum];
291     auto &ext = spriteext[spriteNum];
292 
293     switch (labelNum)
294     {
295         case ACTOR_SECTNUM: changespritesect(spriteNum, newValue); break;
296         case ACTOR_STATNUM: changespritestat(spriteNum, newValue); break;
297         case ACTOR_HTG_T: a.t_data[lParm2] = newValue; break;
298         case ACTOR_ALPHA: ext.alpha = (float)newValue * (1.f / 255.0f); break;
299         default: EDUKE32_UNREACHABLE_SECTION(break);
300     }
301 }
302 
303 
VM_GetSprite(int const spriteNum,int32_t labelNum,int const lParm2)304 int32_t __fastcall VM_GetSprite(int const spriteNum, int32_t labelNum, int const lParm2)
305 {
306     auto const &a   = actor[spriteNum];
307     auto const &s   = sprite[spriteNum];
308     auto const &ext = spriteext[spriteNum];
309 
310     switch (labelNum)
311     {
312         case ACTOR_HTG_T: labelNum = a.t_data[lParm2]; break;
313         case ACTOR_ALPHA: labelNum = (uint8_t)(ext.alpha * 255.0f); break;
314         case ACTOR_ISVALID: labelNum = (s.statnum != MAXSTATUS); break;
315         default: EDUKE32_UNREACHABLE_SECTION(labelNum = -1; break);
316     }
317 
318     return labelNum;
319 }
320 
321 memberlabel_t const TsprLabels[] =
322 {
323     // tsprite access
324 
325     LABEL(sprite, x,        "tsprx",        ACTOR_X),
326     LABEL(sprite, y,        "tspry",        ACTOR_Y),
327     LABEL(sprite, z,        "tsprz",        ACTOR_Z),
328     LABEL(sprite, cstat,    "tsprcstat",    ACTOR_CSTAT),
329     LABEL(sprite, picnum,   "tsprpicnum",   ACTOR_PICNUM),
330     LABEL(sprite, shade,    "tsprshade",    ACTOR_SHADE),
331     LABEL(sprite, pal,      "tsprpal",      ACTOR_PAL),
332     LABEL(sprite, clipdist, "tsprclipdist", ACTOR_CLIPDIST),
333     LABEL(sprite, blend,    "tsprblend",    ACTOR_DETAIL),
334     LABEL(sprite, xrepeat,  "tsprxrepeat",  ACTOR_XREPEAT),
335     LABEL(sprite, yrepeat,  "tspryrepeat",  ACTOR_YREPEAT),
336     LABEL(sprite, xoffset,  "tsprxoffset",  ACTOR_XOFFSET),
337     LABEL(sprite, yoffset,  "tspryoffset",  ACTOR_YOFFSET),
338     LABEL(sprite, sectnum,  "tsprsectnum",  ACTOR_SECTNUM),
339     LABEL(sprite, statnum,  "tsprstatnum",  ACTOR_STATNUM),
340     LABEL(sprite, ang,      "tsprang",      ACTOR_ANG),
341     LABEL(sprite, owner,    "tsprowner",    ACTOR_OWNER),
342     LABEL(sprite, xvel,     "tsprxvel",     ACTOR_XVEL),
343     LABEL(sprite, yvel,     "tspryvel",     ACTOR_YVEL),
344     LABEL(sprite, zvel,     "tsprzvel",     ACTOR_ZVEL),
345     LABEL(sprite, lotag,    "tsprlotag",    ACTOR_LOTAG),
346     LABEL(sprite, hitag,    "tsprhitag",    ACTOR_HITAG),
347     LABEL(sprite, extra,    "tsprextra",    ACTOR_EXTRA),
348 };
349 
350 memberlabel_t const PlayerLabels[] =
351 {
352     MEMBER(g_player[0].ps, zoom,                        PLAYER_ZOOM),
353     {                                "loogiex",         PLAYER_LOOGIEX, LABEL_HASPARM2, 64, -1 },
354     {                                "loogiey",         PLAYER_LOOGIEY, LABEL_HASPARM2, 64, -1 },
355     MEMBER(g_player[0].ps, numloogs,                    PLAYER_NUMLOOGS),
356     MEMBER(g_player[0].ps, loogcnt,                     PLAYER_LOOGCNT),
357      LABEL(g_player[0].ps, pos.x,    "posx",            PLAYER_POSX),
358      LABEL(g_player[0].ps, pos.y,    "posy",            PLAYER_POSY),
359      LABEL(g_player[0].ps, pos.z,    "posz",            PLAYER_POSZ),
360     {                                "horiz",           PLAYER_HORIZ, 0, 0, -1 },
361     {                                "horizoff",        PLAYER_HORIZOFF, 0, 0, -1 },
362     {                                "ohoriz",          PLAYER_OHORIZ, 0, 0, -1 },
363     {                                "ohorizoff",       PLAYER_OHORIZOFF, 0, 0, -1 },
364     MEMBER(g_player[0].ps, q16horiz,                    PLAYER_Q16HORIZ),
365     MEMBER(g_player[0].ps, q16horizoff,                 PLAYER_Q16HORIZOFF),
366     MEMBER(g_player[0].ps, oq16horiz,                   PLAYER_OQ16HORIZ),
367     MEMBER(g_player[0].ps, oq16horizoff,                PLAYER_OQ16HORIZOFF),
368 
369     MEMBER(g_player[0].ps, invdisptime,                 PLAYER_INVDISPTIME),
370 
371      LABEL(g_player[0].ps, bobpos.x, "bobposx",         PLAYER_BOBPOSX),
372      LABEL(g_player[0].ps, bobpos.y, "bobposy",         PLAYER_BOBPOSY),
373 
374      LABEL(g_player[0].ps, opos.x,   "oposx",           PLAYER_OPOSX),
375      LABEL(g_player[0].ps, opos.y,   "oposy",           PLAYER_OPOSY),
376      LABEL(g_player[0].ps, opos.z,   "oposz",           PLAYER_OPOSZ),
377 
378     MEMBER(g_player[0].ps, pyoff,                       PLAYER_PYOFF),
379     MEMBER(g_player[0].ps, opyoff,                      PLAYER_OPYOFF),
380 
381      LABEL(g_player[0].ps, vel.x,    "posxv",           PLAYER_POSXV),
382      LABEL(g_player[0].ps, vel.y,    "posyv",           PLAYER_POSYV),
383      LABEL(g_player[0].ps, vel.z,    "poszv",           PLAYER_POSZV),
384 
385     MEMBER(g_player[0].ps, last_pissed_time,            PLAYER_LAST_PISSED_TIME),
386 
387     MEMBER(g_player[0].ps, truefz,                      PLAYER_TRUEFZ),
388     MEMBER(g_player[0].ps, truecz,                      PLAYER_TRUECZ),
389 
390     MEMBER(g_player[0].ps, player_par,                  PLAYER_PLAYER_PAR),
391 
392     MEMBER(g_player[0].ps, visibility,                  PLAYER_VISIBILITY),
393     MEMBER(g_player[0].ps, bobcounter,                  PLAYER_BOBCOUNTER),
394     MEMBER(g_player[0].ps, weapon_sway,                 PLAYER_WEAPON_SWAY),
395      LABEL(g_player[0].ps, pals.f,   "pals_time",       PLAYER_PALS_TIME),
396     MEMBER(g_player[0].ps, crack_time,                  PLAYER_CRACK_TIME),
397     MEMBER(g_player[0].ps, aim_mode,                    PLAYER_AIM_MODE),
398 
399     {                                "ang",             PLAYER_ANG, 0, 0, -1 },
400     {                                "oang",            PLAYER_OANG, 0, 0, -1 },
401 
402     MEMBER(g_player[0].ps, q16ang,                      PLAYER_Q16ANG),
403     MEMBER(g_player[0].ps, oq16ang,                     PLAYER_OQ16ANG),
404 
405     {                                "angvel",          PLAYER_ANGVEL, 0, 0, -1 },
406 
407     MEMBER(g_player[0].ps, q16angvel,                   PLAYER_Q16ANGVEL),
408 
409     MEMBER(g_player[0].ps, cursectnum,                  PLAYER_CURSECTNUM),
410 
411     MEMBER(g_player[0].ps, look_ang,                    PLAYER_LOOK_ANG),
412     MEMBER(g_player[0].ps, last_extra,                  PLAYER_LAST_EXTRA),
413 
414     MEMBER(g_player[0].ps, subweapon,                   PLAYER_SUBWEAPON),
415 
416     {                                "ammo_amount",     PLAYER_AMMO_AMOUNT, LABEL_HASPARM2, MAX_WEAPONS, -1 },
417 
418     MEMBER(g_player[0].ps, wackedbyactor,               PLAYER_WACKEDBYACTOR),
419 
420     MEMBER(g_player[0].ps, frag,                        PLAYER_FRAG),
421     MEMBER(g_player[0].ps, fraggedself,                 PLAYER_FRAGGEDSELF),
422 
423     MEMBER(g_player[0].ps, curr_weapon,                 PLAYER_CURR_WEAPON),
424     MEMBER(g_player[0].ps, last_weapon,                 PLAYER_LAST_WEAPON),
425 
426     MEMBER(g_player[0].ps, tipincs,                     PLAYER_TIPINCS),
427 
428     MEMBER(g_player[0].ps, wantweaponfire,              PLAYER_WANTWEAPONFIRE),
429 
430      LABEL(g_player[0].ps, inv_amount[GET_HOLODUKE], "holoduke_amount", PLAYER_HOLODUKE_AMOUNT),
431 
432     MEMBER(g_player[0].ps, newowner,                    PLAYER_NEWOWNER),
433     MEMBER(g_player[0].ps, hurt_delay,                  PLAYER_HURT_DELAY),
434     MEMBER(g_player[0].ps, hbomb_hold_delay,            PLAYER_HBOMB_HOLD_DELAY),
435 
436     MEMBER(g_player[0].ps, jumping_counter,             PLAYER_JUMPING_COUNTER),
437     MEMBER(g_player[0].ps, airleft,                     PLAYER_AIRLEFT),
438     MEMBER(g_player[0].ps, knee_incs,                   PLAYER_KNEE_INCS),
439 
440     MEMBER(g_player[0].ps, access_incs,                 PLAYER_ACCESS_INCS),
441 
442     MEMBER(g_player[0].ps, fta,                         PLAYER_FTA),
443     MEMBER(g_player[0].ps, ftq,                         PLAYER_FTQ),
444 
445     MEMBER(g_player[0].ps, access_wallnum,              PLAYER_ACCESS_WALLNUM),
446     MEMBER(g_player[0].ps, access_spritenum,            PLAYER_ACCESS_SPRITENUM),
447 
448     MEMBER(g_player[0].ps, kickback_pic,                PLAYER_KICKBACK_PIC),
449 
450     MEMBER(g_player[0].ps, got_access,                  PLAYER_GOT_ACCESS),
451 
452     MEMBER(g_player[0].ps, weapon_ang,                  PLAYER_WEAPON_ANG),
453      LABEL(g_player[0].ps, inv_amount[GET_FIRSTAID], "firstaid_amount", PLAYER_FIRSTAID_AMOUNT),
454 
455     MEMBER(g_player[0].ps, somethingonplayer,           PLAYER_SOMETHINGONPLAYER),
456     MEMBER(g_player[0].ps, on_crane,                    PLAYER_ON_CRANE),
457     MEMBER(g_player[0].ps, i,                           PLAYER_I),
458     MEMBER(g_player[0].ps, parallax_sectnum,            PLAYER_PARALLAX_SECTNUM),
459 
460     MEMBER(g_player[0].ps, over_shoulder_on,            PLAYER_OVER_SHOULDER_ON),
461 
462     MEMBER(g_player[0].ps, random_club_frame,           PLAYER_RANDOM_CLUB_FRAME),
463     MEMBER(g_player[0].ps, fist_incs,                   PLAYER_FIST_INCS),
464     MEMBER(g_player[0].ps, one_eighty_count,            PLAYER_ONE_EIGHTY_COUNT),
465     MEMBER(g_player[0].ps, cheat_phase,                 PLAYER_CHEAT_PHASE),
466     MEMBER(g_player[0].ps, dummyplayersprite,           PLAYER_DUMMYPLAYERSPRITE),
467     MEMBER(g_player[0].ps, extra_extra8,                PLAYER_EXTRA_EXTRA8),
468 
469     MEMBER(g_player[0].ps, quick_kick,                  PLAYER_QUICK_KICK),
470 
471      LABEL(g_player[0].ps, inv_amount[GET_HEATS], "heat_amount", PLAYER_HEAT_AMOUNT),
472 
473     MEMBER(g_player[0].ps, actorsqu,                    PLAYER_ACTORSQU),
474     MEMBER(g_player[0].ps, timebeforeexit,              PLAYER_TIMEBEFOREEXIT),
475     MEMBER(g_player[0].ps, customexitsound,             PLAYER_CUSTOMEXITSOUND),
476     {                                "weaprecs",        PLAYER_WEAPRECS, LABEL_HASPARM2, MAX_WEAPONS, -1 },
477     MEMBER(g_player[0].ps, weapreccnt,                  PLAYER_WEAPRECCNT),
478     MEMBER(g_player[0].ps, interface_toggle,            PLAYER_INTERFACE_TOGGLE),
479     MEMBER(g_player[0].ps, rotscrnang,                  PLAYER_ROTSCRNANG),
480     MEMBER(g_player[0].ps, dead_flag,                   PLAYER_DEAD_FLAG),
481     MEMBER(g_player[0].ps, show_empty_weapon,           PLAYER_SHOW_EMPTY_WEAPON),
482 
483      LABEL(g_player[0].ps, inv_amount[GET_SCUBA],    "scuba_amount",    PLAYER_SCUBA_AMOUNT),
484      LABEL(g_player[0].ps, inv_amount[GET_JETPACK],  "jetpack_amount",  PLAYER_JETPACK_AMOUNT),
485      LABEL(g_player[0].ps, inv_amount[GET_STEROIDS], "steroids_amount", PLAYER_STEROIDS_AMOUNT),
486      LABEL(g_player[0].ps, inv_amount[GET_SHIELD],   "shield_amount",   PLAYER_SHIELD_AMOUNT),
487 
488     MEMBER(g_player[0].ps, holoduke_on,                 PLAYER_HOLODUKE_ON),
489     MEMBER(g_player[0].ps, pycount,                     PLAYER_PYCOUNT),
490     MEMBER(g_player[0].ps, weapon_pos,                  PLAYER_WEAPON_POS),
491     MEMBER(g_player[0].ps, frag_ps,                     PLAYER_FRAG_PS),
492     MEMBER(g_player[0].ps, transporter_hold,            PLAYER_TRANSPORTER_HOLD),
493     MEMBER(g_player[0].ps, clipdist,                    PLAYER_CLIPDIST),
494     MEMBER(g_player[0].ps, last_full_weapon,            PLAYER_LAST_FULL_WEAPON),
495     MEMBER(g_player[0].ps, footprintshade,              PLAYER_FOOTPRINTSHADE),
496      LABEL(g_player[0].ps, inv_amount[GET_BOOTS],    "boot_amount",     PLAYER_BOOT_AMOUNT),
497     MEMBER(g_player[0].ps, scream_voice,                PLAYER_SCREAM_VOICE),
498     {                                "gm",              PLAYER_GM, sizeof(g_player[0].ps[0].gm) | LABEL_WRITEFUNC, 0, offsetof(DukePlayer_t, gm) },
499     MEMBER(g_player[0].ps, on_warping_sector,           PLAYER_ON_WARPING_SECTOR),
500     MEMBER(g_player[0].ps, footprintcount,              PLAYER_FOOTPRINTCOUNT),
501     MEMBER(g_player[0].ps, hbomb_on,                    PLAYER_HBOMB_ON),
502     MEMBER(g_player[0].ps, jumping_toggle,              PLAYER_JUMPING_TOGGLE),
503     MEMBER(g_player[0].ps, rapid_fire_hold,             PLAYER_RAPID_FIRE_HOLD),
504     MEMBER(g_player[0].ps, on_ground,                   PLAYER_ON_GROUND),
505     {                                "name",            PLAYER_NAME, LABEL_ISSTRING, 32, -1 },
506     MEMBER(g_player[0].ps, inven_icon,                  PLAYER_INVEN_ICON),
507     MEMBER(g_player[0].ps, buttonpalette,               PLAYER_BUTTONPALETTE),
508     MEMBER(g_player[0].ps, jetpack_on,                  PLAYER_JETPACK_ON),
509     MEMBER(g_player[0].ps, spritebridge,                PLAYER_SPRITEBRIDGE),
510     MEMBER(g_player[0].ps, scuba_on,                    PLAYER_SCUBA_ON),
511     MEMBER(g_player[0].ps, footprintpal,                PLAYER_FOOTPRINTPAL),
512     {                                "heat_on",         PLAYER_HEAT_ON, sizeof(g_player[0].ps[0].heat_on) | LABEL_WRITEFUNC, 0, offsetof(DukePlayer_t, heat_on) },
513     MEMBER(g_player[0].ps, holster_weapon,              PLAYER_HOLSTER_WEAPON),
514     MEMBER(g_player[0].ps, falling_counter,             PLAYER_FALLING_COUNTER),
515     {                                "gotweapon",       PLAYER_GOTWEAPON, LABEL_HASPARM2, MAX_WEAPONS, -1 },
516     {                                "palette",         PLAYER_PALETTE, sizeof(g_player[0].ps[0].palette) | LABEL_WRITEFUNC, 0, offsetof(DukePlayer_t, palette) },
517     MEMBER(g_player[0].ps, toggle_key_flag,             PLAYER_TOGGLE_KEY_FLAG),
518     MEMBER(g_player[0].ps, knuckle_incs,                PLAYER_KNUCKLE_INCS),
519     MEMBER(g_player[0].ps, walking_snd_toggle,          PLAYER_WALKING_SND_TOGGLE),
520     MEMBER(g_player[0].ps, palookup,                    PLAYER_PALOOKUP),
521     MEMBER(g_player[0].ps, hard_landing,                PLAYER_HARD_LANDING),
522     MEMBER(g_player[0].ps, max_secret_rooms,            PLAYER_MAX_SECRET_ROOMS),
523     MEMBER(g_player[0].ps, secret_rooms,                PLAYER_SECRET_ROOMS),
524 
525     {                                "pals",            PLAYER_PALS, LABEL_HASPARM2, 3, -1 },
526 
527     MEMBER(g_player[0].ps, max_actors_killed,           PLAYER_MAX_ACTORS_KILLED),
528     MEMBER(g_player[0].ps, actors_killed,               PLAYER_ACTORS_KILLED),
529     MEMBER(g_player[0].ps, return_to_center,            PLAYER_RETURN_TO_CENTER),
530     MEMBER(g_player[0].ps, runspeed,                    PLAYER_RUNSPEED),
531     MEMBER(g_player[0].ps, sbs,                         PLAYER_SBS),
532     MEMBER(g_player[0].ps, reloading,                   PLAYER_RELOADING),
533     MEMBER(g_player[0].ps, auto_aim,                    PLAYER_AUTO_AIM),
534     MEMBER(g_player[0].ps, movement_lock,               PLAYER_MOVEMENT_LOCK),
535     MEMBER(g_player[0].ps, sound_pitch,                 PLAYER_SOUND_PITCH),
536     MEMBER(g_player[0].ps, weaponswitch,                PLAYER_WEAPONSWITCH),
537     MEMBER(g_player[0].ps, team,                        PLAYER_TEAM),
538     MEMBER(g_player[0].ps, max_player_health,           PLAYER_MAX_PLAYER_HEALTH),
539     MEMBER(g_player[0].ps, max_shield_amount,           PLAYER_MAX_SHIELD_AMOUNT),
540     {                                "max_ammo_amount", PLAYER_MAX_AMMO_AMOUNT, LABEL_HASPARM2, MAX_WEAPONS, -1 },
541     MEMBER(g_player[0].ps, last_quick_kick,             PLAYER_LAST_QUICK_KICK),
542     MEMBER(g_player[0].ps, autostep,                    PLAYER_AUTOSTEP),
543     MEMBER(g_player[0].ps, autostep_sbw,                PLAYER_AUTOSTEP_SBW),
544     {                                "hudpal",          PLAYER_HUDPAL, 0, 0, -1 },
545     {                                "index",           PLAYER_INDEX, 0, 0, -1 },
546     {                                "connected",       PLAYER_CONNECTED, 0, 0, -1 },
547     {                                "frags",           PLAYER_FRAGS, LABEL_HASPARM2, MAXPLAYERS, -1 },
548     {                                "deaths",          PLAYER_DEATHS, 0, 0, -1 },
549     MEMBER(g_player[0].ps, last_used_weapon,            PLAYER_LAST_USED_WEAPON),
550     {                                "bsubweapon",      PLAYER_BSUBWEAPON, LABEL_HASPARM2, MAX_WEAPONS, -1 },
551     MEMBER(g_player[0].ps, crouch_toggle,               PLAYER_CROUCH_TOGGLE),
552 };
553 
VM_GetPlayer(int const playerNum,int32_t labelNum,int const lParm2)554 int32_t __fastcall VM_GetPlayer(int const playerNum, int32_t labelNum, int const lParm2)
555 {
556     auto const &ps = *g_player[playerNum].ps;
557 
558     switch (labelNum)
559     {
560         case PLAYER_ANG:       labelNum = fix16_to_int(ps.q16ang);       break;
561         case PLAYER_OANG:      labelNum = fix16_to_int(ps.oq16ang);      break;
562         case PLAYER_ANGVEL:    labelNum = fix16_to_int(ps.q16angvel);    break;
563         case PLAYER_HORIZ:     labelNum = fix16_to_int(ps.q16horiz);     break;
564         case PLAYER_OHORIZ:    labelNum = fix16_to_int(ps.oq16horiz);    break;
565         case PLAYER_HORIZOFF:  labelNum = fix16_to_int(ps.q16horizoff);  break;
566         case PLAYER_OHORIZOFF: labelNum = fix16_to_int(ps.oq16horizoff); break;
567 
568         case PLAYER_HUDPAL:    labelNum = P_GetHudPal(&ps); break;
569         case PLAYER_INDEX:     labelNum = playerNum;        break;
570 
571         case PLAYER_AMMO_AMOUNT:      labelNum = ps.ammo_amount[lParm2];     break;
572         case PLAYER_MAX_AMMO_AMOUNT:  labelNum = ps.max_ammo_amount[lParm2]; break;
573         case PLAYER_GOTWEAPON:        labelNum = (ps.gotweapon & (1<<lParm2)) != 0; break;
574 
575         case PLAYER_PALS:
576             switch (lParm2)
577             {
578                 case 0: labelNum = ps.pals.r; break;
579                 case 1: labelNum = ps.pals.g; break;
580                 case 2: labelNum = ps.pals.b; break;
581             }
582             break;
583 
584         case PLAYER_FRAGS:
585             labelNum = (playerNum == lParm2) ? ps.fraggedself : g_player[playerNum].frags[lParm2]; break;
586 
587         case PLAYER_CONNECTED:  labelNum = g_player[playerNum].playerquitflag;   break;
588         case PLAYER_DEATHS:     labelNum = g_player[playerNum].frags[playerNum]; break;
589         case PLAYER_BSUBWEAPON: labelNum = (ps.subweapon & (1<<lParm2)) != 0;    break;
590 
591         case PLAYER_LOOGIEX:    labelNum = ps.loogiex[lParm2]; break;
592         case PLAYER_LOOGIEY:    labelNum = ps.loogiey[lParm2]; break;
593 
594         case PLAYER_WEAPRECS:   labelNum = ps.weaprecs[lParm2]; break;
595 
596         default: EDUKE32_UNREACHABLE_SECTION(labelNum = -1; break);
597     }
598 
599     return labelNum;
600 }
601 
VM_SetPlayer(int const playerNum,int const labelNum,int const lParm2,int32_t const newValue)602 void __fastcall VM_SetPlayer(int const playerNum, int const labelNum, int const lParm2, int32_t const newValue)
603 {
604     auto &ps = *g_player[playerNum].ps;
605 
606     switch (labelNum)
607     {
608         case PLAYER_HORIZ:     ps.q16horiz     = fix16_from_int(newValue); break;
609         case PLAYER_OHORIZ:    ps.oq16horiz    = fix16_from_int(newValue); break;
610         case PLAYER_OHORIZOFF: ps.oq16horizoff = fix16_from_int(newValue); break;
611         case PLAYER_ANG:       ps.q16ang       = fix16_from_int(newValue); break;
612         case PLAYER_OANG:      ps.oq16ang      = fix16_from_int(newValue); break;
613         case PLAYER_ANGVEL:    ps.q16angvel    = fix16_from_int(newValue); break;
614         case PLAYER_HORIZOFF:  ps.q16horizoff  = fix16_from_int(newValue); break;
615 
616         case PLAYER_AMMO_AMOUNT:     ps.ammo_amount[lParm2]     = newValue; break;
617         case PLAYER_MAX_AMMO_AMOUNT: ps.max_ammo_amount[lParm2] = newValue; break;
618 
619         case PLAYER_HEAT_ON:
620             if (ps.heat_on != newValue)
621             {
622                 ps.heat_on = newValue;
623                 P_UpdateScreenPal(&ps);
624             }
625             break;
626 
627         case PLAYER_GM:
628             if (!(ps.gm & MODE_MENU) && (newValue & MODE_MENU)) Menu_Open(playerNum);
629             else if ((ps.gm & MODE_MENU) && !(newValue & MODE_MENU)) Menu_Close(playerNum);
630             ps.gm = newValue;
631             break;
632 
633         case PLAYER_GOTWEAPON:
634             if (newValue) ps.gotweapon |= (1 << lParm2);
635             else ps.gotweapon &= ~(1 << lParm2);
636             break;
637 
638         case PLAYER_PALETTE: P_SetGamePalette(&ps, newValue, 2 + 16); break;
639 
640         case PLAYER_PALS:
641             switch (lParm2)
642             {
643                 case 0: ps.pals.r = newValue; break;
644                 case 1: ps.pals.g = newValue; break;
645                 case 2: ps.pals.b = newValue; break;
646             }
647             break;
648 
649         case PLAYER_FRAGS:
650             if (playerNum == lParm2) ps.fraggedself = newValue;
651             else g_player[playerNum].frags[lParm2] = newValue;
652             break;
653 
654         case PLAYER_DEATHS: g_player[playerNum].frags[playerNum] = newValue; break;
655 
656         case PLAYER_BSUBWEAPON:
657             if (newValue) ps.subweapon |= (1 << lParm2);
658             else ps.subweapon &= ~(1 << lParm2);
659             break;
660 
661         case PLAYER_LOOGIEX: ps.loogiex[lParm2] = newValue; break;
662         case PLAYER_LOOGIEY: ps.loogiey[lParm2] = newValue; break;
663 
664         case PLAYER_WEAPRECS: ps.weaprecs[lParm2] = newValue; break;
665 
666         default: EDUKE32_UNREACHABLE_SECTION(break);
667     }
668 }
669 
670 memberlabel_t const ProjectileLabels[]=
671 {
672     { "workslike",  PROJ_WORKSLIKE,   0, 0, -1 },
673     { "spawns",     PROJ_SPAWNS,      0, 0, -1 },
674     { "sxrepeat",   PROJ_SXREPEAT,    0, 0, -1 },
675     { "syrepeat",   PROJ_SYREPEAT,    0, 0, -1 },
676     { "sound",      PROJ_SOUND,       0, 0, -1 },
677     { "isound",     PROJ_ISOUND,      0, 0, -1 },
678     { "vel",        PROJ_VEL,         0, 0, -1 },
679     { "extra",      PROJ_EXTRA,       0, 0, -1 },
680     { "decal",      PROJ_DECAL,       0, 0, -1 },
681     { "trail",      PROJ_TRAIL,       0, 0, -1 },
682     { "txrepeat",   PROJ_TXREPEAT,    0, 0, -1 },
683     { "tyrepeat",   PROJ_TYREPEAT,    0, 0, -1 },
684     { "toffset",    PROJ_TOFFSET,     0, 0, -1 },
685     { "tnum",       PROJ_TNUM,        0, 0, -1 },
686     { "drop",       PROJ_DROP,        0, 0, -1 },
687     { "cstat",      PROJ_CSTAT,       0, 0, -1 },
688     { "clipdist",   PROJ_CLIPDIST,    0, 0, -1 },
689     { "shade",      PROJ_SHADE,       0, 0, -1 },
690     { "xrepeat",    PROJ_XREPEAT,     0, 0, -1 },
691     { "yrepeat",    PROJ_YREPEAT,     0, 0, -1 },
692     { "pal",        PROJ_PAL,         0, 0, -1 },
693     { "extra_rand", PROJ_EXTRA_RAND,  0, 0, -1 },
694     { "hitradius",  PROJ_HITRADIUS,   0, 0, -1 },
695     { "velmult",    PROJ_MOVECNT,     0, 0, -1 },
696     { "offset",     PROJ_OFFSET,      0, 0, -1 },
697     { "bounces",    PROJ_BOUNCES,     0, 0, -1 },
698     { "bsound",     PROJ_BSOUND,      0, 0, -1 },
699     { "range",      PROJ_RANGE,       0, 0, -1 },
700     { "flashcolor", PROJ_FLASH_COLOR, 0, 0, -1 },
701     { "userdata",   PROJ_USERDATA,    0, 0, -1 },
702 };
703 
VM_GetProjectile(int const tileNum,int32_t labelNum)704 int32_t __fastcall VM_GetProjectile(int const tileNum, int32_t labelNum)
705 {
706     if (EDUKE32_PREDICT_FALSE((unsigned)tileNum >= MAXTILES || g_tile[tileNum].proj == NULL))
707     {
708         CON_ERRPRINTF("invalid projectile %d\n", tileNum);
709         return -1;
710     }
711 
712     auto const &p = *g_tile[tileNum].proj;
713 
714     switch (labelNum)
715     {
716         case PROJ_BOUNCES:     labelNum = p.bounces;    break;
717         case PROJ_BSOUND:      labelNum = p.bsound;     break;
718         case PROJ_CLIPDIST:    labelNum = p.clipdist;   break;
719         case PROJ_CSTAT:       labelNum = p.cstat;      break;
720         case PROJ_DECAL:       labelNum = p.decal;      break;
721         case PROJ_DROP:        labelNum = p.drop;       break;
722         case PROJ_EXTRA:       labelNum = p.extra;      break;
723         case PROJ_EXTRA_RAND:  labelNum = p.extra_rand; break;
724         case PROJ_FLASH_COLOR: labelNum = p.flashcolor; break;
725         case PROJ_HITRADIUS:   labelNum = p.hitradius;  break;
726         case PROJ_ISOUND:      labelNum = p.isound;     break;
727         case PROJ_MOVECNT:     labelNum = p.movecnt;    break;
728         case PROJ_OFFSET:      labelNum = p.offset;     break;
729         case PROJ_PAL:         labelNum = p.pal;        break;
730         case PROJ_RANGE:       labelNum = p.range;      break;
731         case PROJ_SHADE:       labelNum = p.shade;      break;
732         case PROJ_SOUND:       labelNum = p.sound;      break;
733         case PROJ_SPAWNS:      labelNum = p.spawns;     break;
734         case PROJ_SXREPEAT:    labelNum = p.sxrepeat;   break;
735         case PROJ_SYREPEAT:    labelNum = p.syrepeat;   break;
736         case PROJ_TNUM:        labelNum = p.tnum;       break;
737         case PROJ_TOFFSET:     labelNum = p.toffset;    break;
738         case PROJ_TRAIL:       labelNum = p.trail;      break;
739         case PROJ_TXREPEAT:    labelNum = p.txrepeat;   break;
740         case PROJ_TYREPEAT:    labelNum = p.tyrepeat;   break;
741         case PROJ_USERDATA:    labelNum = p.userdata;   break;
742         case PROJ_VEL:         labelNum = p.vel;        break;
743         case PROJ_WORKSLIKE:   labelNum = p.workslike;  break;
744         case PROJ_XREPEAT:     labelNum = p.xrepeat;    break;
745         case PROJ_YREPEAT:     labelNum = p.yrepeat;    break;
746 
747         default: EDUKE32_UNREACHABLE_SECTION(labelNum = -1; break);
748     }
749 
750     return labelNum;
751 }
752 
VM_SetProjectile(int const tileNum,int const labelNum,int32_t const newValue)753 void __fastcall VM_SetProjectile(int const tileNum, int const labelNum, int32_t const newValue)
754 {
755     if (EDUKE32_PREDICT_FALSE((unsigned) tileNum >= MAXTILES || g_tile[tileNum].proj == NULL))
756     {
757         CON_ERRPRINTF("invalid projectile %d\n", tileNum);
758         return;
759     }
760 
761     auto &p = *g_tile[tileNum].proj;
762 
763     switch (labelNum)
764     {
765         case PROJ_BOUNCES:     p.bounces    = newValue; break;
766         case PROJ_BSOUND:      p.bsound     = newValue; break;
767         case PROJ_CLIPDIST:    p.clipdist   = newValue; break;
768         case PROJ_CSTAT:       p.cstat      = newValue; break;
769         case PROJ_DECAL:       p.decal      = newValue; break;
770         case PROJ_DROP:        p.drop       = newValue; break;
771         case PROJ_EXTRA:       p.extra      = newValue; break;
772         case PROJ_EXTRA_RAND:  p.extra_rand = newValue; break;
773         case PROJ_FLASH_COLOR: p.flashcolor = newValue; break;
774         case PROJ_HITRADIUS:   p.hitradius  = newValue; break;
775         case PROJ_ISOUND:      p.isound     = newValue; break;
776         case PROJ_MOVECNT:     p.movecnt    = newValue; break;
777         case PROJ_OFFSET:      p.offset     = newValue; break;
778         case PROJ_PAL:         p.pal        = newValue; break;
779         case PROJ_RANGE:       p.range      = newValue; break;
780         case PROJ_SHADE:       p.shade      = newValue; break;
781         case PROJ_SOUND:       p.sound      = newValue; break;
782         case PROJ_SPAWNS:      p.spawns     = newValue; break;
783         case PROJ_SXREPEAT:    p.sxrepeat   = newValue; break;
784         case PROJ_SYREPEAT:    p.syrepeat   = newValue; break;
785         case PROJ_TNUM:        p.tnum       = newValue; break;
786         case PROJ_TOFFSET:     p.toffset    = newValue; break;
787         case PROJ_TRAIL:       p.trail      = newValue; break;
788         case PROJ_TXREPEAT:    p.txrepeat   = newValue; break;
789         case PROJ_TYREPEAT:    p.tyrepeat   = newValue; break;
790         case PROJ_USERDATA:    p.userdata   = newValue; break;
791         case PROJ_VEL:         p.vel        = newValue; break;
792         case PROJ_WORKSLIKE:   p.workslike  = newValue; break;
793         case PROJ_XREPEAT:     p.xrepeat    = newValue; break;
794         case PROJ_YREPEAT:     p.yrepeat    = newValue; break;
795     }
796 }
797 
VM_GetActiveProjectile(int const spriteNum,int32_t labelNum)798 int32_t __fastcall VM_GetActiveProjectile(int const spriteNum, int32_t labelNum)
799 {
800     if (EDUKE32_PREDICT_FALSE((unsigned)spriteNum >= MAXSPRITES))
801     {
802         CON_ERRPRINTF("%s invalid for projectile %d\n", ProjectileLabels[labelNum].name, spriteNum);
803         return -1;
804     }
805 
806     auto const &p = SpriteProjectile[spriteNum];
807 
808     switch (labelNum)
809     {
810         case PROJ_WORKSLIKE:   labelNum = p.workslike;  break;
811         case PROJ_SPAWNS:      labelNum = p.spawns;     break;
812         case PROJ_SXREPEAT:    labelNum = p.sxrepeat;   break;
813         case PROJ_SYREPEAT:    labelNum = p.syrepeat;   break;
814         case PROJ_SOUND:       labelNum = p.sound;      break;
815         case PROJ_ISOUND:      labelNum = p.isound;     break;
816         case PROJ_VEL:         labelNum = p.vel;        break;
817         case PROJ_EXTRA:       labelNum = p.extra;      break;
818         case PROJ_DECAL:       labelNum = p.decal;      break;
819         case PROJ_TRAIL:       labelNum = p.trail;      break;
820         case PROJ_TXREPEAT:    labelNum = p.txrepeat;   break;
821         case PROJ_TYREPEAT:    labelNum = p.tyrepeat;   break;
822         case PROJ_TOFFSET:     labelNum = p.toffset;    break;
823         case PROJ_TNUM:        labelNum = p.tnum;       break;
824         case PROJ_DROP:        labelNum = p.drop;       break;
825         case PROJ_CSTAT:       labelNum = p.cstat;      break;
826         case PROJ_CLIPDIST:    labelNum = p.clipdist;   break;
827         case PROJ_SHADE:       labelNum = p.shade;      break;
828         case PROJ_XREPEAT:     labelNum = p.xrepeat;    break;
829         case PROJ_YREPEAT:     labelNum = p.yrepeat;    break;
830         case PROJ_PAL:         labelNum = p.pal;        break;
831         case PROJ_EXTRA_RAND:  labelNum = p.extra_rand; break;
832         case PROJ_HITRADIUS:   labelNum = p.hitradius;  break;
833         case PROJ_MOVECNT:     labelNum = p.movecnt;    break;
834         case PROJ_OFFSET:      labelNum = p.offset;     break;
835         case PROJ_BOUNCES:     labelNum = p.bounces;    break;
836         case PROJ_BSOUND:      labelNum = p.bsound;     break;
837         case PROJ_RANGE:       labelNum = p.range;      break;
838         case PROJ_FLASH_COLOR: labelNum = p.flashcolor; break;
839         case PROJ_USERDATA:    labelNum = p.userdata;   break;
840 
841         default: EDUKE32_UNREACHABLE_SECTION(labelNum = -1; break);
842     }
843 
844     return labelNum;
845 }
846 
VM_SetActiveProjectile(int const spriteNum,int const labelNum,int32_t const newValue)847 void __fastcall VM_SetActiveProjectile(int const spriteNum, int const labelNum, int32_t const newValue)
848 {
849     if (EDUKE32_PREDICT_FALSE((unsigned)spriteNum >= MAXSPRITES))
850     {
851         CON_ERRPRINTF("%s invalid for projectile %d\n", ProjectileLabels[labelNum].name, spriteNum);
852         return;
853     }
854 
855     auto &p = SpriteProjectile[spriteNum];
856 
857     switch (labelNum)
858     {
859         case PROJ_WORKSLIKE:   p.workslike  = newValue; break;
860         case PROJ_SPAWNS:      p.spawns     = newValue; break;
861         case PROJ_SXREPEAT:    p.sxrepeat   = newValue; break;
862         case PROJ_SYREPEAT:    p.syrepeat   = newValue; break;
863         case PROJ_SOUND:       p.sound      = newValue; break;
864         case PROJ_ISOUND:      p.isound     = newValue; break;
865         case PROJ_VEL:         p.vel        = newValue; break;
866         case PROJ_EXTRA:       p.extra      = newValue; break;
867         case PROJ_DECAL:       p.decal      = newValue; break;
868         case PROJ_TRAIL:       p.trail      = newValue; break;
869         case PROJ_TXREPEAT:    p.txrepeat   = newValue; break;
870         case PROJ_TYREPEAT:    p.tyrepeat   = newValue; break;
871         case PROJ_TOFFSET:     p.toffset    = newValue; break;
872         case PROJ_TNUM:        p.tnum       = newValue; break;
873         case PROJ_DROP:        p.drop       = newValue; break;
874         case PROJ_CSTAT:       p.cstat      = newValue; break;
875         case PROJ_CLIPDIST:    p.clipdist   = newValue; break;
876         case PROJ_SHADE:       p.shade      = newValue; break;
877         case PROJ_XREPEAT:     p.xrepeat    = newValue; break;
878         case PROJ_YREPEAT:     p.yrepeat    = newValue; break;
879         case PROJ_PAL:         p.pal        = newValue; break;
880         case PROJ_EXTRA_RAND:  p.extra_rand = newValue; break;
881         case PROJ_HITRADIUS:   p.hitradius  = newValue; break;
882         case PROJ_MOVECNT:     p.movecnt    = newValue; break;
883         case PROJ_OFFSET:      p.offset     = newValue; break;
884         case PROJ_BOUNCES:     p.bounces    = newValue; break;
885         case PROJ_BSOUND:      p.bsound     = newValue; break;
886         case PROJ_RANGE:       p.range      = newValue; break;
887         case PROJ_FLASH_COLOR: p.flashcolor = newValue; break;
888         case PROJ_USERDATA:    p.userdata   = newValue; break;
889     }
890 }
891 
892 memberlabel_t const UserdefsLabels[]=
893 {
894     { "god",                    USERDEFS_GOD,                    0, 0, -1 },
895     { "warp_on",                USERDEFS_WARP_ON,                0, 0, -1 },
896     { "cashman",                USERDEFS_CASHMAN,                0, 0, -1 },
897     { "eog",                    USERDEFS_EOG,                    0, 0, -1 },
898     { "showallmap",             USERDEFS_SHOWALLMAP,             0, 0, -1 },
899     { "show_help",              USERDEFS_SHOW_HELP,              0, 0, -1 },
900     { "scrollmode",             USERDEFS_SCROLLMODE,             0, 0, -1 },
901     { "clipping",               USERDEFS_CLIPPING,               0, 0, -1 },
902     { "user_name",              USERDEFS_USER_NAME,              LABEL_HASPARM2, MAXPLAYERS, -1 },
903     { "ridecule",               USERDEFS_RIDECULE,               LABEL_HASPARM2 | LABEL_ISSTRING, 10, -1 },
904     { "savegame",               USERDEFS_SAVEGAME,               LABEL_HASPARM2 | LABEL_ISSTRING, 10, -1 },
905     { "pwlockout",              USERDEFS_PWLOCKOUT,              LABEL_ISSTRING, 128, -1 },
906     { "rtsname;",               USERDEFS_RTSNAME,                LABEL_ISSTRING, 128, -1 },
907     { "overhead_on",            USERDEFS_OVERHEAD_ON,            0, 0, -1 },
908     { "last_overhead",          USERDEFS_LAST_OVERHEAD,          0, 0, -1 },
909     { "showweapons",            USERDEFS_SHOWWEAPONS,            0, 0, -1 },
910     { "pause_on",               USERDEFS_PAUSE_ON,               0, 0, -1 },
911     { "from_bonus",             USERDEFS_FROM_BONUS,             0, 0, -1 },
912     { "camerasprite",           USERDEFS_CAMERASPRITE,           0, 0, -1 },
913     { "last_camsprite",         USERDEFS_LAST_CAMSPRITE,         0, 0, -1 },
914     { "last_level",             USERDEFS_LAST_LEVEL,             0, 0, -1 },
915     { "secretlevel",            USERDEFS_SECRETLEVEL,            0, 0, -1 },
916     { "const_visibility",       USERDEFS_CONST_VISIBILITY,       0, 0, -1 },
917     { "uw_framerate",           USERDEFS_UW_FRAMERATE,           0, 0, -1 },
918     { "camera_time",            USERDEFS_CAMERA_TIME,            0, 0, -1 },
919     { "folfvel",                USERDEFS_FOLFVEL,                0, 0, -1 },
920     { "folavel",                USERDEFS_FOLAVEL,                0, 0, -1 },
921     { "folx",                   USERDEFS_FOLX,                   0, 0, -1 },
922     { "foly",                   USERDEFS_FOLY,                   0, 0, -1 },
923     { "fola",                   USERDEFS_FOLA,                   0, 0, -1 },
924     { "reccnt",                 USERDEFS_RECCNT,                 0, 0, -1 },
925     { "entered_name",           USERDEFS_ENTERED_NAME,           0, 0, -1 },
926     { "screen_tilting",         USERDEFS_SCREEN_TILTING,         0, 0, -1 },
927     { "shadows",                USERDEFS_SHADOWS,                0, 0, -1 },
928     { "fta_on",                 USERDEFS_FTA_ON,                 0, 0, -1 },
929     { "executions",             USERDEFS_EXECUTIONS,             0, 0, -1 },
930     { "auto_run",               USERDEFS_AUTO_RUN,               0, 0, -1 },
931     { "coords",                 USERDEFS_COORDS,                 0, 0, -1 },
932     { "tickrate",               USERDEFS_TICKRATE,               0, 0, -1 },
933     { "m_coop",                 USERDEFS_M_COOP,                 0, 0, -1 },
934     { "coop",                   USERDEFS_COOP,                   0, 0, -1 },
935     { "screen_size",            USERDEFS_SCREEN_SIZE,            0, 0, -1 },
936     { "lockout",                USERDEFS_LOCKOUT,                0, 0, -1 },
937     { "crosshair",              USERDEFS_CROSSHAIR,              0, 0, -1 },
938     { "playerai",               USERDEFS_PLAYERAI,               0, 0, -1 },
939     { "respawn_monsters",       USERDEFS_RESPAWN_MONSTERS,       0, 0, -1 },
940     { "respawn_items",          USERDEFS_RESPAWN_ITEMS,          0, 0, -1 },
941     { "respawn_inventory",      USERDEFS_RESPAWN_INVENTORY,      0, 0, -1 },
942     { "recstat",                USERDEFS_RECSTAT,                0, 0, -1 },
943     { "monsters_off",           USERDEFS_MONSTERS_OFF,           0, 0, -1 },
944     { "brightness",             USERDEFS_BRIGHTNESS,             0, 0, -1 },
945     { "m_respawn_items",        USERDEFS_M_RESPAWN_ITEMS,        0, 0, -1 },
946     { "m_respawn_monsters",     USERDEFS_M_RESPAWN_MONSTERS,     0, 0, -1 },
947     { "m_respawn_inventory",    USERDEFS_M_RESPAWN_INVENTORY,    0, 0, -1 },
948     { "m_recstat",              USERDEFS_M_RECSTAT,              0, 0, -1 },
949     { "m_monsters_off",         USERDEFS_M_MONSTERS_OFF,         0, 0, -1 },
950     { "detail",                 USERDEFS_DETAIL,                 0, 0, -1 },
951     { "m_ffire",                USERDEFS_M_FFIRE,                0, 0, -1 },
952     { "ffire",                  USERDEFS_FFIRE,                  0, 0, -1 },
953     { "m_player_skill",         USERDEFS_M_PLAYER_SKILL,         0, 0, -1 },
954     { "m_level_number",         USERDEFS_M_LEVEL_NUMBER,         0, 0, -1 },
955     { "m_volume_number",        USERDEFS_M_VOLUME_NUMBER,        0, 0, -1 },
956     { "multimode",              USERDEFS_MULTIMODE,              0, 0, -1 },
957     { "player_skill",           USERDEFS_PLAYER_SKILL,           0, 0, -1 },
958     { "level_number",           USERDEFS_LEVEL_NUMBER,           0, 0, -1 },
959     { "volume_number",          USERDEFS_VOLUME_NUMBER,          0, 0, -1 },
960     { "m_marker",               USERDEFS_M_MARKER,               0, 0, -1 },
961     { "marker",                 USERDEFS_MARKER,                 0, 0, -1 },
962     { "mouseflip",              USERDEFS_MOUSEFLIP,              0, 0, -1 },
963     { "statusbarscale",         USERDEFS_STATUSBARSCALE,         0, 0, -1 },
964     { "drawweapon",             USERDEFS_DRAWWEAPON,             0, 0, -1 },
965     { "mouseaiming",            USERDEFS_MOUSEAIMING,            0, 0, -1 },
966     { "weaponswitch",           USERDEFS_WEAPONSWITCH,           0, 0, -1 },
967     { "democams",               USERDEFS_DEMOCAMS,               0, 0, -1 },
968     { "color",                  USERDEFS_COLOR,                  0, 0, -1 },
969     { "msgdisptime",            USERDEFS_MSGDISPTIME,            0, 0, -1 },
970     { "statusbarmode",          USERDEFS_STATUSBARMODE,          0, 0, -1 },
971     { "m_noexits",              USERDEFS_M_NOEXITS,              0, 0, -1 },
972     { "noexits",                USERDEFS_NOEXITS,                0, 0, -1 },
973     { "autovote",               USERDEFS_AUTOVOTE,               0, 0, -1 },
974     { "automsg",                USERDEFS_AUTOMSG,                0, 0, -1 },
975     { "idplayers",              USERDEFS_IDPLAYERS,              0, 0, -1 },
976     { "team",                   USERDEFS_TEAM,                   0, 0, -1 },
977     { "viewbob",                USERDEFS_VIEWBOB,                0, 0, -1 },
978     { "weaponsway",             USERDEFS_WEAPONSWAY,             0, 0, -1 },
979     { "angleinterpolation",     USERDEFS_ANGLEINTERPOLATION,     0, 0, -1 },
980     { "obituaries",             USERDEFS_OBITUARIES,             0, 0, -1 },
981     { "levelstats",             USERDEFS_LEVELSTATS,             0, 0, -1 },
982     { "crosshairscale",         USERDEFS_CROSSHAIRSCALE,         0, 0, -1 },
983     { "althud",                 USERDEFS_ALTHUD,                 0, 0, -1 },
984     { "display_bonus_screen",   USERDEFS_DISPLAY_BONUS_SCREEN,   0, 0, -1 },
985     { "show_level_text",        USERDEFS_SHOW_LEVEL_TEXT,        0, 0, -1 },
986     { "weaponscale",            USERDEFS_WEAPONSCALE,            0, 0, -1 },
987     { "textscale",              USERDEFS_TEXTSCALE,              0, 0, -1 },
988     { "runkey_mode",            USERDEFS_RUNKEY_MODE,            0, 0, -1 },
989     { "m_origin_x",             USERDEFS_M_ORIGIN_X,             0, 0, -1 },
990     { "m_origin_y",             USERDEFS_M_ORIGIN_Y,             0, 0, -1 },
991     { "playerbest",             USERDEFS_PLAYERBEST,             0, 0, -1 },
992     { "musictoggle",            USERDEFS_MUSICTOGGLE,            0, 0, -1 },
993     { "usevoxels",              USERDEFS_USEVOXELS,              0, 0, -1 },
994     { "usehightile",            USERDEFS_USEHIGHTILE,            0, 0, -1 },
995     { "usemodels",              USERDEFS_USEMODELS,              0, 0, -1 },
996     { "gametypeflags",          USERDEFS_GAMETYPEFLAGS,          0, 0, -1 },
997     { "m_gametypeflags",        USERDEFS_M_GAMETYPEFLAGS,        0, 0, -1 },
998     { "globalflags",            USERDEFS_GLOBALFLAGS,            0, 0, -1 },
999     { "globalgameflags",        USERDEFS_GLOBALGAMEFLAGS,        0, 0, -1 },
1000     { "vm_player",              USERDEFS_VM_PLAYER,              0, 0, -1 },
1001     { "vm_sprite",              USERDEFS_VM_SPRITE,              0, 0, -1 },
1002     { "vm_distance",            USERDEFS_VM_DISTANCE,            0, 0, -1 },
1003     { "soundtoggle",            USERDEFS_SOUNDTOGGLE,            0, 0, -1 },
1004     { "gametext_tracking",      USERDEFS_GAMETEXT_TRACKING,      0, 0, -1 },
1005     { "mgametext_tracking",     USERDEFS_MGAMETEXT_TRACKING,     0, 0, -1 },
1006     { "menutext_tracking",      USERDEFS_MENUTEXT_TRACKING,      0, 0, -1 },
1007     { "maxspritesonscreen",     USERDEFS_MAXSPRITESONSCREEN,     0, 0, -1 },
1008     { "screenarea_x1",          USERDEFS_SCREENAREA_X1,          0, 0, -1 },
1009     { "screenarea_y1",          USERDEFS_SCREENAREA_Y1,          0, 0, -1 },
1010     { "screenarea_x2",          USERDEFS_SCREENAREA_X2,          0, 0, -1 },
1011     { "screenarea_y2",          USERDEFS_SCREENAREA_Y2,          0, 0, -1 },
1012     { "screenfade",             USERDEFS_SCREENFADE,             0, 0, -1 },
1013     { "menubackground",         USERDEFS_MENUBACKGROUND,         0, 0, -1 },
1014     { "statusbarflags",         USERDEFS_STATUSBARFLAGS,         0, 0, -1 },
1015     { "statusbarrange",         USERDEFS_STATUSBARRANGE,         0, 0, -1 },
1016     { "statusbarcustom",        USERDEFS_STATUSBARCUSTOM,        0, 0, -1 },
1017     { "hudontop",               USERDEFS_HUDONTOP,               0, 0, -1 },
1018     { "menu_slidebarz",         USERDEFS_MENU_SLIDEBARZ,         0, 0, -1 },
1019     { "menu_slidebarmargin",    USERDEFS_MENU_SLIDEBARMARGIN,    0, 0, -1 },
1020     { "menu_slidecursorz",      USERDEFS_MENU_SLIDECURSORZ,      0, 0, -1 },
1021     { "global_r",               USERDEFS_GLOBAL_R,               0, 0, -1 },
1022     { "global_g",               USERDEFS_GLOBAL_G,               0, 0, -1 },
1023     { "global_b",               USERDEFS_GLOBAL_B,               0, 0, -1 },
1024     { "default_volume",         USERDEFS_DEFAULT_VOLUME,         0, 0, -1 },
1025     { "default_skill",          USERDEFS_DEFAULT_SKILL,          0, 0, -1 },
1026     { "menu_shadedeselected",   USERDEFS_MENU_SHADEDESELECTED,   0, 0, -1 },
1027     { "menu_shadedisabled",     USERDEFS_MENU_SHADEDISABLED,     0, 0, -1 },
1028     { "menutext_zoom",          USERDEFS_MENUTEXT_ZOOM,          0, 0, -1 },
1029     { "menutext_xspace",        USERDEFS_MENUTEXT_XSPACE,        0, 0, -1 },
1030     { "menutext_pal",           USERDEFS_MENUTEXT_PAL,           0, 0, -1 },
1031     { "menutext_palselected",   USERDEFS_MENUTEXT_PALSELECTED,   0, 0, -1 },
1032     { "menutext_paldeselected", USERDEFS_MENUTEXT_PALDESELECTED, 0, 0, -1 },
1033     { "menutext_paldisabled",   USERDEFS_MENUTEXT_PALDISABLED,   0, 0, -1 },
1034     { "menutext_palselected_right",   USERDEFS_MENUTEXT_PALSELECTED_RIGHT,   0, 0, -1 },
1035     { "menutext_paldeselected_right", USERDEFS_MENUTEXT_PALDESELECTED_RIGHT, 0, 0, -1 },
1036     { "menutext_paldisabled_right",   USERDEFS_MENUTEXT_PALDISABLED_RIGHT,   0, 0, -1 },
1037     { "gametext_zoom",          USERDEFS_GAMETEXT_ZOOM,          0, 0, -1 },
1038     { "gametext_xspace",        USERDEFS_GAMETEXT_XSPACE,        0, 0, -1 },
1039     { "gametext_pal",           USERDEFS_GAMETEXT_PAL,           0, 0, -1 },
1040     { "gametext_palselected",   USERDEFS_GAMETEXT_PALSELECTED,   0, 0, -1 },
1041     { "gametext_paldeselected", USERDEFS_GAMETEXT_PALDESELECTED, 0, 0, -1 },
1042     { "gametext_paldisabled",   USERDEFS_GAMETEXT_PALDISABLED,   0, 0, -1 },
1043     { "gametext_palselected_right",   USERDEFS_GAMETEXT_PALSELECTED_RIGHT,   0, 0, -1 },
1044     { "gametext_paldeselected_right", USERDEFS_GAMETEXT_PALDESELECTED_RIGHT, 0, 0, -1 },
1045     { "gametext_paldisabled_right",   USERDEFS_GAMETEXT_PALDISABLED_RIGHT,   0, 0, -1 },
1046     { "minitext_zoom",          USERDEFS_MINITEXT_ZOOM,          0, 0, -1 },
1047     { "minitext_xspace",        USERDEFS_MINITEXT_XSPACE,        0, 0, -1 },
1048     { "minitext_tracking",      USERDEFS_MINITEXT_TRACKING,      0, 0, -1 },
1049     { "minitext_pal",           USERDEFS_MINITEXT_PAL,           0, 0, -1 },
1050     { "minitext_palselected",   USERDEFS_MINITEXT_PALSELECTED,   0, 0, -1 },
1051     { "minitext_paldeselected", USERDEFS_MINITEXT_PALDESELECTED, 0, 0, -1 },
1052     { "minitext_paldisabled",   USERDEFS_MINITEXT_PALDISABLED,   0, 0, -1 },
1053     { "minitext_palselected_right",   USERDEFS_MINITEXT_PALSELECTED_RIGHT,   0, 0, -1 },
1054     { "minitext_paldeselected_right", USERDEFS_MINITEXT_PALDESELECTED_RIGHT, 0, 0, -1 },
1055     { "minitext_paldisabled_right",   USERDEFS_MINITEXT_PALDISABLED_RIGHT,   0, 0, -1 },
1056     { "menutitle_pal",          USERDEFS_MENUTITLE_PAL,          0, 0, -1 },
1057     { "slidebar_palselected",   USERDEFS_SLIDEBAR_PALSELECTED,   0, 0, -1 },
1058     { "slidebar_paldisabled",   USERDEFS_SLIDEBAR_PALDISABLED,   0, 0, -1 },
1059     { "user_map",               USERDEFS_USER_MAP,               0, 0, -1 },
1060     { "m_user_map",             USERDEFS_M_USER_MAP,             0, 0, -1 },
1061     { "music_episode",          USERDEFS_MUSIC_EPISODE,          0, 0, -1 },
1062     { "music_level",            USERDEFS_MUSIC_LEVEL,            0, 0, -1 },
1063     { "shadow_pal",             USERDEFS_SHADOW_PAL,             0, 0, -1 },
1064     { "menu_scrollbartilenum",  USERDEFS_MENU_SCROLLBARTILENUM,  0, 0, -1 },
1065     { "menu_scrollbarz",        USERDEFS_MENU_SCROLLBARZ,        0, 0, -1 },
1066     { "menu_scrollcursorz",     USERDEFS_MENU_SCROLLCURSORZ,     0, 0, -1 },
1067     { "return",                 USERDEFS_RETURN,                 LABEL_HASPARM2, MAX_RETURN_VALUES, -1 },
1068     { "userbyteversion",        USERDEFS_USERBYTEVERSION,        0, 0, -1 },
1069     { "autosave",               USERDEFS_AUTOSAVE,               0, 0, -1 },
1070     { "draw_y",                 USERDEFS_DRAW_Y,                 0, 0, -1 },
1071     { "draw_yxaspect",          USERDEFS_DRAW_YXASPECT,          0, 0, -1 },
1072     { "fov",                    USERDEFS_FOV,                    0, 0, -1 },
1073     { "newgamecustomopen",      USERDEFS_NEWGAMECUSTOMOPEN,      0, 0, -1 },
1074     { "newgamecustomsubopen",   USERDEFS_NEWGAMECUSTOMSUBOPEN,   LABEL_HASPARM2, MAXMENUGAMEPLAYENTRIES, -1 },
1075     { "gamepadactive",          USERDEFS_GAMEPADACTIVE,          0, 0, -1 },
1076     { "m_newgamecustom",        USERDEFS_M_NEWGAMECUSTOM,        0, 0, -1 },
1077     { "m_newgamecustomsub",     USERDEFS_M_NEWGAMECUSTOMSUB,     0, 0, -1 }
1078 };
1079 
VM_GetUserdef(int32_t labelNum,int const lParm2)1080 int32_t __fastcall VM_GetUserdef(int32_t labelNum, int const lParm2)
1081 {
1082     if (EDUKE32_PREDICT_FALSE(UserdefsLabels[labelNum].flags & LABEL_HASPARM2 && (unsigned) lParm2 >= (unsigned) UserdefsLabels[labelNum].maxParm2))
1083     {
1084         CON_ERRPRINTF("%s[%d] invalid for userdef", UserdefsLabels[labelNum].name, lParm2);
1085         return -1;
1086     }
1087 
1088     switch (labelNum)
1089     {
1090         case USERDEFS_GOD:                    labelNum = ud.god;                          break;
1091         case USERDEFS_WARP_ON:                labelNum = ud.warp_on;                      break;
1092         case USERDEFS_CASHMAN:                labelNum = ud.cashman;                      break;
1093         case USERDEFS_EOG:                    labelNum = ud.eog;                          break;
1094         case USERDEFS_SHOWALLMAP:             labelNum = ud.showallmap;                   break;
1095         case USERDEFS_SHOW_HELP:              labelNum = ud.show_help;                    break;
1096         case USERDEFS_SCROLLMODE:             labelNum = ud.scrollmode;                   break;
1097         case USERDEFS_CLIPPING:               labelNum = ud.noclip;                       break;
1098         //  case USERDEFS_USER_NAME:          labelNum = ud.user_name[MAXPLAYERS][32];    break;
1099         //  case USERDEFS_RIDECULE:           labelNum = ud.ridecule;                     break;
1100         //  case USERDEFS_PWLOCKOUT:          labelNum = ud.pwlockout;                    break;
1101         //  case USERDEFS_RTSNAME:            labelNum = ud.rtsname;                      break;
1102         case USERDEFS_OVERHEAD_ON:            labelNum = ud.overhead_on;                  break;
1103         case USERDEFS_LAST_OVERHEAD:          labelNum = ud.last_overhead;                break;
1104         case USERDEFS_SHOWWEAPONS:            labelNum = ud.showweapons;                  break;
1105         case USERDEFS_PAUSE_ON:               labelNum = ud.pause_on;                     break;
1106         case USERDEFS_FROM_BONUS:             labelNum = ud.from_bonus;                   break;
1107         case USERDEFS_CAMERASPRITE:           labelNum = ud.camerasprite;                 break;
1108         case USERDEFS_LAST_CAMSPRITE:         labelNum = ud.last_camsprite;               break;
1109         case USERDEFS_LAST_LEVEL:             labelNum = ud.last_level;                   break;
1110         case USERDEFS_SECRETLEVEL:            labelNum = ud.secretlevel;                  break;
1111         case USERDEFS_CONST_VISIBILITY:       labelNum = ud.const_visibility;             break;
1112         case USERDEFS_UW_FRAMERATE:           labelNum = ud.uw_framerate;                 break;
1113         case USERDEFS_CAMERA_TIME:            labelNum = ud.camera_time;                  break;
1114         case USERDEFS_FOLFVEL:                labelNum = ud.folfvel;                      break;
1115         case USERDEFS_FOLAVEL:                labelNum = ud.folavel;                      break;
1116         case USERDEFS_FOLX:                   labelNum = ud.folx;                         break;
1117         case USERDEFS_FOLY:                   labelNum = ud.foly;                         break;
1118         case USERDEFS_FOLA:                   labelNum = ud.fola;                         break;
1119         case USERDEFS_RECCNT:                 labelNum = ud.reccnt;                       break;
1120         case USERDEFS_ENTERED_NAME:           labelNum = ud.entered_name;                 break;
1121         case USERDEFS_SCREEN_TILTING:         labelNum = ud.screen_tilting;               break;
1122         case USERDEFS_SHADOWS:                labelNum = ud.shadows;                      break;
1123         case USERDEFS_FTA_ON:                 labelNum = ud.fta_on;                       break;
1124         case USERDEFS_EXECUTIONS:             labelNum = ud.executions;                   break;
1125         case USERDEFS_AUTO_RUN:               labelNum = ud.auto_run;                     break;
1126         case USERDEFS_COORDS:                 labelNum = ud.coords;                       break;
1127         case USERDEFS_TICKRATE:               labelNum = ud.showfps;                      break;
1128         case USERDEFS_M_COOP:                 labelNum = ud.m_coop;                       break;
1129         case USERDEFS_COOP:                   labelNum = ud.coop;                         break;
1130         case USERDEFS_SCREEN_SIZE:            labelNum = ud.screen_size;                  break;
1131         case USERDEFS_LOCKOUT:                labelNum = ud.lockout;                      break;
1132         case USERDEFS_CROSSHAIR:              labelNum = ud.crosshair;                    break;
1133         case USERDEFS_PLAYERAI:               labelNum = ud.playerai;                     break;
1134         case USERDEFS_RESPAWN_MONSTERS:       labelNum = ud.respawn_monsters;             break;
1135         case USERDEFS_RESPAWN_ITEMS:          labelNum = ud.respawn_items;                break;
1136         case USERDEFS_RESPAWN_INVENTORY:      labelNum = ud.respawn_inventory;            break;
1137         case USERDEFS_RECSTAT:                labelNum = ud.recstat;                      break;
1138         case USERDEFS_MONSTERS_OFF:           labelNum = ud.monsters_off;                 break;
1139         case USERDEFS_BRIGHTNESS:             labelNum = ud.brightness;                   break;
1140         case USERDEFS_M_RESPAWN_ITEMS:        labelNum = ud.m_respawn_items;              break;
1141         case USERDEFS_M_RESPAWN_MONSTERS:     labelNum = ud.m_respawn_monsters;           break;
1142         case USERDEFS_M_RESPAWN_INVENTORY:    labelNum = ud.m_respawn_inventory;          break;
1143         case USERDEFS_M_RECSTAT:              labelNum = ud.m_recstat;                    break;
1144         case USERDEFS_M_MONSTERS_OFF:         labelNum = ud.m_monsters_off;               break;
1145         case USERDEFS_DETAIL:                 labelNum = ud.detail;                       break;
1146         case USERDEFS_M_FFIRE:                labelNum = ud.m_ffire;                      break;
1147         case USERDEFS_FFIRE:                  labelNum = ud.ffire;                        break;
1148         case USERDEFS_M_PLAYER_SKILL:         labelNum = ud.m_player_skill;               break;
1149         case USERDEFS_M_LEVEL_NUMBER:         labelNum = ud.m_level_number;               break;
1150         case USERDEFS_M_VOLUME_NUMBER:        labelNum = ud.m_volume_number;              break;
1151         case USERDEFS_M_USER_MAP:             labelNum = Menu_HaveUserMap();              break;
1152         case USERDEFS_MULTIMODE:              labelNum = ud.multimode;                    break;
1153         case USERDEFS_PLAYER_SKILL:           labelNum = ud.player_skill;                 break;
1154         case USERDEFS_LEVEL_NUMBER:           labelNum = ud.level_number;                 break;
1155         case USERDEFS_VOLUME_NUMBER:          labelNum = ud.volume_number;                break;
1156         case USERDEFS_USER_MAP:               labelNum = G_HaveUserMap();                 break;
1157         case USERDEFS_M_MARKER:               labelNum = ud.m_marker;                     break;
1158         case USERDEFS_MARKER:                 labelNum = ud.marker;                       break;
1159         case USERDEFS_MOUSEFLIP:              labelNum = ud.mouseflip;                    break;
1160         case USERDEFS_STATUSBARSCALE:         labelNum = ud.statusbarscale;               break;
1161         case USERDEFS_DRAWWEAPON:             labelNum = ud.drawweapon;                   break;
1162         case USERDEFS_MOUSEAIMING:            labelNum = ud.mouseaiming;                  break;
1163         case USERDEFS_WEAPONSWITCH:           labelNum = ud.weaponswitch;                 break;
1164         case USERDEFS_DEMOCAMS:               labelNum = ud.democams;                     break;
1165         case USERDEFS_COLOR:                  labelNum = ud.color;                        break;
1166         case USERDEFS_MSGDISPTIME:            labelNum = ud.msgdisptime;                  break;
1167         case USERDEFS_STATUSBARMODE:          labelNum = ud.statusbarmode;                break;
1168         case USERDEFS_M_NOEXITS:              labelNum = ud.m_noexits;                    break;
1169         case USERDEFS_NOEXITS:                labelNum = ud.noexits;                      break;
1170         case USERDEFS_AUTOVOTE:               labelNum = ud.autovote;                     break;
1171         case USERDEFS_AUTOMSG:                labelNum = ud.automsg;                      break;
1172         case USERDEFS_IDPLAYERS:              labelNum = ud.idplayers;                    break;
1173         case USERDEFS_TEAM:                   labelNum = ud.team;                         break;
1174         case USERDEFS_VIEWBOB:                labelNum = ud.viewbob;                      break;
1175         case USERDEFS_WEAPONSWAY:             labelNum = ud.weaponsway;                   break;
1176         case USERDEFS_ANGLEINTERPOLATION:     labelNum = ud.angleinterpolation;           break;
1177         case USERDEFS_OBITUARIES:             labelNum = ud.obituaries;                   break;
1178         case USERDEFS_LEVELSTATS:             labelNum = ud.levelstats;                   break;
1179         case USERDEFS_CROSSHAIRSCALE:         labelNum = ud.crosshairscale;               break;
1180         case USERDEFS_ALTHUD:                 labelNum = ud.althud;                       break;
1181         case USERDEFS_DISPLAY_BONUS_SCREEN:   labelNum = ud.display_bonus_screen;         break;
1182         case USERDEFS_SHOW_LEVEL_TEXT:        labelNum = ud.show_level_text;              break;
1183         case USERDEFS_WEAPONSCALE:            labelNum = ud.weaponscale;                  break;
1184         case USERDEFS_TEXTSCALE:              labelNum = ud.textscale;                    break;
1185         case USERDEFS_RUNKEY_MODE:            labelNum = ud.runkey_mode;                  break;
1186         case USERDEFS_M_ORIGIN_X:             labelNum = ud.returnvar[0];                 break;
1187         case USERDEFS_M_ORIGIN_Y:             labelNum = ud.returnvar[1];                 break;
1188         case USERDEFS_PLAYERBEST:             labelNum = ud.playerbest;                   break;
1189         case USERDEFS_MUSICTOGGLE:            labelNum = ud.config.MusicToggle;           break;
1190         case USERDEFS_USEVOXELS:              labelNum = usevoxels;                       break;
1191         case USERDEFS_USEHIGHTILE:
1192 #ifdef USE_OPENGL
1193                                               labelNum = usehightile;                     break;
1194 #endif
1195         case USERDEFS_USEMODELS:
1196 #ifdef USE_OPENGL
1197                                               labelNum = usemodels;                       break;
1198 #else
1199                                               labelNum = 0;                               break;
1200 #endif
1201         case USERDEFS_GAMETYPEFLAGS:          labelNum = g_gametypeFlags[ud.coop];        break;
1202         case USERDEFS_M_GAMETYPEFLAGS:        labelNum = g_gametypeFlags[ud.m_coop];      break;
1203         case USERDEFS_GLOBALFLAGS:            labelNum = globalflags;                     break;
1204         case USERDEFS_GLOBALGAMEFLAGS:        labelNum = duke3d_globalflags;              break;
1205         case USERDEFS_VM_PLAYER:              labelNum = vm.playerNum;                    break;
1206         case USERDEFS_VM_SPRITE:              labelNum = vm.spriteNum;                    break;
1207         case USERDEFS_VM_DISTANCE:            labelNum = vm.playerDist;                   break;
1208         case USERDEFS_SOUNDTOGGLE:            labelNum = ud.config.SoundToggle;           break;
1209         case USERDEFS_GAMETEXT_TRACKING:      labelNum = MF_Bluefont.between.x;           break;
1210         case USERDEFS_MENUTEXT_TRACKING:      labelNum = MF_Redfont.between.x;            break;
1211         case USERDEFS_MAXSPRITESONSCREEN:     labelNum = maxspritesonscreen;              break;
1212         case USERDEFS_SCREENAREA_X1:          labelNum = aGameVars[g_returnVarID].global; break;
1213         case USERDEFS_SCREENAREA_Y1:          labelNum = ud.returnvar[0];                 break;
1214         case USERDEFS_SCREENAREA_X2:          labelNum = ud.returnvar[1];                 break;
1215         case USERDEFS_SCREENAREA_Y2:          labelNum = ud.returnvar[2];                 break;
1216         case USERDEFS_SCREENFADE:             labelNum = ud.screenfade;                   break;
1217         case USERDEFS_MENUBACKGROUND:         labelNum = ud.menubackground;               break;
1218         case USERDEFS_STATUSBARFLAGS:         labelNum = ud.statusbarflags;               break;
1219         case USERDEFS_STATUSBARRANGE:         labelNum = ud.statusbarrange;               break;
1220         case USERDEFS_STATUSBARCUSTOM:        labelNum = ud.statusbarcustom;              break;
1221         case USERDEFS_HUDONTOP:               labelNum = ud.hudontop;                     break;
1222         case USERDEFS_MENU_SLIDEBARZ:         labelNum = ud.menu_slidebarz;               break;
1223         case USERDEFS_MENU_SLIDEBARMARGIN:    labelNum = ud.menu_slidebarmargin;          break;
1224         case USERDEFS_MENU_SLIDECURSORZ:      labelNum = ud.menu_slidecursorz;            break;
1225         case USERDEFS_GLOBAL_R:               labelNum = globalr;                         break;
1226         case USERDEFS_GLOBAL_G:               labelNum = globalg;                         break;
1227         case USERDEFS_GLOBAL_B:               labelNum = globalb;                         break;
1228         case USERDEFS_DEFAULT_VOLUME:         labelNum = ud.default_volume;               break;
1229         case USERDEFS_DEFAULT_SKILL:          labelNum = ud.default_skill;                break;
1230         case USERDEFS_MENU_SHADEDESELECTED:   labelNum = MF_Redfont.shade_deselected;     break;
1231         case USERDEFS_MENU_SHADEDISABLED:     labelNum = MF_Redfont.shade_disabled;       break;
1232         case USERDEFS_MENUTEXT_ZOOM:          labelNum = MF_Redfont.zoom;                 break;
1233         case USERDEFS_MENUTEXT_XSPACE:        labelNum = MF_Redfont.emptychar.x;          break;
1234         case USERDEFS_MENUTEXT_PALSELECTED:   labelNum = MF_Redfont.pal_selected;         break;
1235         case USERDEFS_MENUTEXT_PALDESELECTED: labelNum = MF_Redfont.pal_deselected;       break;
1236         case USERDEFS_MENUTEXT_PALDISABLED:   labelNum = MF_Redfont.pal_disabled;         break;
1237         case USERDEFS_GAMETEXT_ZOOM:          labelNum = MF_Bluefont.zoom;                break;
1238         case USERDEFS_GAMETEXT_XSPACE:        labelNum = MF_Bluefont.emptychar.x;         break;
1239         case USERDEFS_GAMETEXT_PALSELECTED:   labelNum = MF_Bluefont.pal_selected;        break;
1240         case USERDEFS_GAMETEXT_PALDESELECTED: labelNum = MF_Bluefont.pal_deselected;      break;
1241         case USERDEFS_GAMETEXT_PALDISABLED:   labelNum = MF_Bluefont.pal_disabled;        break;
1242         case USERDEFS_MINITEXT_ZOOM:          labelNum = MF_Minifont.zoom;                break;
1243         case USERDEFS_MINITEXT_XSPACE:        labelNum = MF_Minifont.emptychar.x;         break;
1244         case USERDEFS_MINITEXT_TRACKING:      labelNum = MF_Minifont.between.x;           break;
1245         case USERDEFS_MINITEXT_PALSELECTED:   labelNum = MF_Minifont.pal_selected;        break;
1246         case USERDEFS_MINITEXT_PALDESELECTED: labelNum = MF_Minifont.pal_deselected;      break;
1247         case USERDEFS_MINITEXT_PALDISABLED:   labelNum = MF_Minifont.pal_disabled;        break;
1248         case USERDEFS_MENUTITLE_PAL:          labelNum = ud.menutitle_pal;                break;
1249         case USERDEFS_SLIDEBAR_PALSELECTED:   labelNum = ud.slidebar_palselected;         break;
1250         case USERDEFS_SLIDEBAR_PALDISABLED:   labelNum = ud.slidebar_paldisabled;         break;
1251         case USERDEFS_MUSIC_EPISODE:          labelNum = ud.music_episode;                break;
1252         case USERDEFS_MUSIC_LEVEL:            labelNum = ud.music_level;                  break;
1253         case USERDEFS_SHADOW_PAL:             labelNum = ud.shadow_pal;                   break;
1254         case USERDEFS_MENU_SCROLLBARTILENUM:  labelNum = ud.menu_scrollbartilenum;        break;
1255         case USERDEFS_MENU_SCROLLBARZ:        labelNum = ud.menu_scrollbarz;              break;
1256         case USERDEFS_MENU_SCROLLCURSORZ:     labelNum = ud.menu_scrollcursorz;           break;
1257         case USERDEFS_RETURN:
1258             if (lParm2 == 0)
1259                 labelNum = aGameVars[g_returnVarID].global;
1260             else
1261                 labelNum = ud.returnvar[lParm2 - 1];
1262             break;
1263         case USERDEFS_USERBYTEVERSION:        labelNum = ud.userbytever;                  break;
1264         case USERDEFS_AUTOSAVE:               labelNum = ud.autosave;                     break;
1265         case USERDEFS_DRAW_Y:                 labelNum = rotatesprite_y_offset;           break;
1266         case USERDEFS_DRAW_YXASPECT:          labelNum = rotatesprite_yxaspect;           break;
1267         case USERDEFS_FOV:                    labelNum = ud.fov;                          break;
1268         case USERDEFS_GAMEPADACTIVE:          labelNum = (CONTROL_LastSeenInput == LastSeenInput::Joystick); break;
1269         case USERDEFS_M_NEWGAMECUSTOM:        labelNum = ud.m_newgamecustom;              break;
1270         case USERDEFS_M_NEWGAMECUSTOMSUB:     labelNum = ud.m_newgamecustomsub;           break;
1271 
1272         default: EDUKE32_UNREACHABLE_SECTION(labelNum = -1; break);
1273     }
1274 
1275     return labelNum;
1276 }
1277 
VM_SetUserdef(int const labelNum,int const lParm2,int32_t const iSet)1278 void __fastcall VM_SetUserdef(int const labelNum, int const lParm2, int32_t const iSet)
1279 {
1280     if (EDUKE32_PREDICT_FALSE(UserdefsLabels[labelNum].flags & LABEL_HASPARM2 && (unsigned)lParm2 >= (unsigned)UserdefsLabels[labelNum].maxParm2))
1281     {
1282         CON_ERRPRINTF("%s[%d] invalid for userdef", UserdefsLabels[labelNum].name, lParm2);
1283         return;
1284     }
1285 
1286     switch (labelNum)
1287     {
1288         case USERDEFS_GOD:                          ud.god                           = iSet; break;
1289         case USERDEFS_WARP_ON:                      ud.warp_on                       = iSet; break;
1290         case USERDEFS_CASHMAN:                      ud.cashman                       = iSet; break;
1291         case USERDEFS_EOG:                          ud.eog                           = iSet; break;
1292         case USERDEFS_SHOWALLMAP:                   ud.showallmap                    = iSet; break;
1293         case USERDEFS_SHOW_HELP:                    ud.show_help                     = iSet; break;
1294         case USERDEFS_SCROLLMODE:                   ud.scrollmode                    = iSet; break;
1295         case USERDEFS_CLIPPING:                     ud.noclip                        = iSet; break;
1296         //  case USERDEFS_USER_NAME:                ud.user_name[MAXPLAYERS][32]     = lValue; break;
1297         //  case USERDEFS_RIDECULE:                 ud.ridecule                      = lValue; break;
1298         //  case USERDEFS_PWLOCKOUT:                ud.pwlockout                     = lValue; break;
1299         //  case USERDEFS_RTSNAME:                  ud.rtsname                       = lValue; break;
1300         case USERDEFS_OVERHEAD_ON:                  ud.overhead_on                   = iSet; break;
1301         case USERDEFS_LAST_OVERHEAD:                ud.last_overhead                 = iSet; break;
1302         case USERDEFS_SHOWWEAPONS:                  ud.showweapons                   = iSet; break;
1303         case USERDEFS_PAUSE_ON:                     ud.pause_on                      = iSet; break;
1304         case USERDEFS_FROM_BONUS:                   ud.from_bonus                    = iSet; break;
1305         case USERDEFS_CAMERASPRITE:                 ud.camerasprite                  = iSet; break;
1306         case USERDEFS_LAST_CAMSPRITE:               ud.last_camsprite                = iSet; break;
1307         case USERDEFS_LAST_LEVEL:                   ud.last_level                    = iSet; break;
1308         case USERDEFS_SECRETLEVEL:                  ud.secretlevel                   = iSet; break;
1309         case USERDEFS_CONST_VISIBILITY:             ud.const_visibility              = iSet; break;
1310         case USERDEFS_UW_FRAMERATE:                 ud.uw_framerate                  = iSet; break;
1311         case USERDEFS_CAMERA_TIME:                  ud.camera_time                   = iSet; break;
1312         case USERDEFS_FOLFVEL:                      ud.folfvel                       = iSet; break;
1313         case USERDEFS_FOLAVEL:                      ud.folavel                       = iSet; break;
1314         case USERDEFS_FOLX:                         ud.folx                          = iSet; break;
1315         case USERDEFS_FOLY:                         ud.foly                          = iSet; break;
1316         case USERDEFS_FOLA:                         ud.fola                          = iSet; break;
1317         case USERDEFS_RECCNT:                       ud.reccnt                        = iSet; break;
1318         case USERDEFS_ENTERED_NAME:                 ud.entered_name                  = iSet; break;
1319         case USERDEFS_SCREEN_TILTING:               ud.screen_tilting                = iSet; break;
1320         case USERDEFS_SHADOWS:                      ud.shadows                       = iSet; break;
1321         case USERDEFS_FTA_ON:                       ud.fta_on                        = iSet; break;
1322         case USERDEFS_EXECUTIONS:                   ud.executions                    = iSet; break;
1323         case USERDEFS_AUTO_RUN:                     ud.auto_run                      = iSet; break;
1324         case USERDEFS_COORDS:                       ud.coords                        = iSet; break;
1325         case USERDEFS_TICKRATE:                     ud.showfps                       = iSet; break;
1326         case USERDEFS_M_COOP:                       ud.m_coop                        = iSet; break;
1327         case USERDEFS_COOP:                         ud.coop                          = iSet; break;
1328         case USERDEFS_SCREEN_SIZE:
1329             if (ud.screen_size != iSet)
1330             {
1331                 ud.screen_size = iSet;
1332                 G_UpdateScreenArea();
1333             }
1334             break;
1335         case USERDEFS_LOCKOUT:                      ud.lockout                       = iSet; break;
1336         case USERDEFS_CROSSHAIR:                    ud.crosshair                     = iSet; break;
1337         case USERDEFS_PLAYERAI:                     ud.playerai                      = iSet; break;
1338         case USERDEFS_RESPAWN_MONSTERS:             ud.respawn_monsters              = iSet; break;
1339         case USERDEFS_RESPAWN_ITEMS:                ud.respawn_items                 = iSet; break;
1340         case USERDEFS_RESPAWN_INVENTORY:            ud.respawn_inventory             = iSet; break;
1341         case USERDEFS_RECSTAT:                      ud.recstat                       = iSet; break;
1342         case USERDEFS_MONSTERS_OFF:                 ud.monsters_off                  = iSet; break;
1343         case USERDEFS_BRIGHTNESS:                   ud.brightness                    = iSet; break;
1344         case USERDEFS_M_RESPAWN_ITEMS:              ud.m_respawn_items               = iSet; break;
1345         case USERDEFS_M_RESPAWN_MONSTERS:           ud.m_respawn_monsters            = iSet; break;
1346         case USERDEFS_M_RESPAWN_INVENTORY:          ud.m_respawn_inventory           = iSet; break;
1347         case USERDEFS_M_RECSTAT:                    ud.m_recstat                     = iSet; break;
1348         case USERDEFS_M_MONSTERS_OFF:               ud.m_monsters_off                = iSet; break;
1349         // REMINDER: must implement "boolean" setters like "!!iSet" in Lunatic, too.
1350         case USERDEFS_DETAIL:                       ud.detail                        = clamp(iSet, 1, 16); break;
1351         case USERDEFS_M_FFIRE:                      ud.m_ffire                       = iSet; break;
1352         case USERDEFS_FFIRE:                        ud.ffire                         = iSet; break;
1353         case USERDEFS_M_PLAYER_SKILL:               ud.m_player_skill                = iSet; break;
1354         case USERDEFS_M_LEVEL_NUMBER:               ud.m_level_number                = iSet; break;
1355         case USERDEFS_M_VOLUME_NUMBER:              ud.m_volume_number               = iSet; break;
1356         case USERDEFS_MULTIMODE:                    ud.multimode                     = iSet; break;
1357         case USERDEFS_PLAYER_SKILL:                 ud.player_skill                  = iSet; break;
1358         case USERDEFS_LEVEL_NUMBER:                 ud.level_number                  = iSet; break;
1359         case USERDEFS_VOLUME_NUMBER:                ud.volume_number                 = iSet; break;
1360         case USERDEFS_M_MARKER:                     ud.m_marker                      = iSet; break;
1361         case USERDEFS_MARKER:                       ud.marker                        = iSet; break;
1362         case USERDEFS_MOUSEFLIP:                    ud.mouseflip                     = iSet; break;
1363         case USERDEFS_STATUSBARSCALE:               ud.statusbarscale                = iSet; break;
1364         case USERDEFS_DRAWWEAPON:                   ud.drawweapon                    = iSet; break;
1365         case USERDEFS_MOUSEAIMING:                  ud.mouseaiming                   = iSet; break;
1366         case USERDEFS_WEAPONSWITCH:                 ud.weaponswitch                  = iSet; break;
1367         case USERDEFS_DEMOCAMS:                     ud.democams                      = iSet; break;
1368         case USERDEFS_COLOR:                        ud.color                         = iSet; break;
1369         case USERDEFS_MSGDISPTIME:                  ud.msgdisptime                   = iSet; break;
1370         case USERDEFS_STATUSBARMODE:                ud.statusbarmode                 = iSet; break;
1371         case USERDEFS_M_NOEXITS:                    ud.m_noexits                     = iSet; break;
1372         case USERDEFS_NOEXITS:                      ud.noexits                       = iSet; break;
1373         case USERDEFS_AUTOVOTE:                     ud.autovote                      = iSet; break;
1374         case USERDEFS_AUTOMSG:                      ud.automsg                       = iSet; break;
1375         case USERDEFS_IDPLAYERS:                    ud.idplayers                     = iSet; break;
1376         case USERDEFS_TEAM:                         ud.team                          = iSet; break;
1377         case USERDEFS_VIEWBOB:                      ud.viewbob                       = iSet; break;
1378         case USERDEFS_WEAPONSWAY:                   ud.weaponsway                    = iSet; break;
1379         case USERDEFS_ANGLEINTERPOLATION:           ud.angleinterpolation            = iSet; break;
1380         case USERDEFS_OBITUARIES:                   ud.obituaries                    = iSet; break;
1381         case USERDEFS_LEVELSTATS:                   ud.levelstats                    = iSet; break;
1382         case USERDEFS_CROSSHAIRSCALE:               ud.crosshairscale                = iSet; break;
1383         case USERDEFS_ALTHUD:                       ud.althud                        = iSet; break;
1384         case USERDEFS_DISPLAY_BONUS_SCREEN:         ud.display_bonus_screen          = iSet; break;
1385         case USERDEFS_SHOW_LEVEL_TEXT:              ud.show_level_text               = iSet; break;
1386         case USERDEFS_WEAPONSCALE:                  ud.weaponscale                   = iSet; break;
1387         case USERDEFS_TEXTSCALE:                    ud.textscale                     = iSet; break;
1388         case USERDEFS_RUNKEY_MODE:                  ud.runkey_mode                   = iSet; break;
1389         case USERDEFS_M_ORIGIN_X:                   ud.returnvar[0]                  = iSet; break;
1390         case USERDEFS_M_ORIGIN_Y:                   ud.returnvar[1]                  = iSet; break;
1391         case USERDEFS_GLOBALFLAGS:                  globalflags                      = iSet; break;
1392         case USERDEFS_GLOBALGAMEFLAGS:              duke3d_globalflags               = iSet; break;
1393         case USERDEFS_VM_PLAYER:
1394             vm.playerNum = iSet;
1395             vm.pPlayer   = g_player[iSet].ps;
1396             break;
1397         case USERDEFS_VM_SPRITE:
1398             vm.spriteNum = iSet;
1399             vm.pSprite   = &sprite[iSet];
1400             vm.pActor    = &actor[iSet];
1401             vm.pData     = &actor[iSet].t_data[0];
1402             break;
1403         case USERDEFS_VM_DISTANCE: vm.playerDist                                     = iSet; break;
1404         case USERDEFS_GAMETEXT_TRACKING:            MF_Bluefont.between.x            = iSet; break;
1405         case USERDEFS_MENUTEXT_TRACKING:            MF_Redfont.between.x             = iSet; break;
1406         case USERDEFS_MAXSPRITESONSCREEN:           maxspritesonscreen               = clamp(iSet, MAXSPRITESONSCREEN>>2, MAXSPRITESONSCREEN); break;
1407         case USERDEFS_SCREENAREA_X1:                aGameVars[g_returnVarID].global  = iSet; break;
1408         case USERDEFS_SCREENAREA_Y1:                ud.returnvar[0]                  = iSet; break;
1409         case USERDEFS_SCREENAREA_X2:                ud.returnvar[1]                  = iSet; break;
1410         case USERDEFS_SCREENAREA_Y2:                ud.returnvar[2]                  = iSet; break;
1411         case USERDEFS_SCREENFADE:                   ud.screenfade                    = iSet; break;
1412         case USERDEFS_MENUBACKGROUND:               ud.menubackground                = iSet; break;
1413         case USERDEFS_STATUSBARFLAGS:               ud.statusbarflags                = iSet; break;
1414         case USERDEFS_STATUSBARRANGE:               ud.statusbarrange                = iSet; break;
1415         case USERDEFS_STATUSBARCUSTOM:              ud.statusbarcustom               = iSet; break;
1416         case USERDEFS_HUDONTOP:                     ud.hudontop                      = iSet; break;
1417         case USERDEFS_MENU_SLIDEBARZ:               ud.menu_slidebarz                = iSet; break;
1418         case USERDEFS_MENU_SLIDEBARMARGIN:          ud.menu_slidebarmargin           = iSet; break;
1419         case USERDEFS_MENU_SLIDECURSORZ:            ud.menu_slidecursorz             = iSet; break;
1420         case USERDEFS_GLOBAL_R:                     globalr                          = iSet; break;
1421         case USERDEFS_GLOBAL_G:                     globalg                          = iSet; break;
1422         case USERDEFS_GLOBAL_B:                     globalb                          = iSet; break;
1423         case USERDEFS_DEFAULT_VOLUME:               ud.default_volume                = iSet; break;
1424         case USERDEFS_DEFAULT_SKILL:                ud.default_skill                 = iSet; break;
1425         case USERDEFS_MENU_SHADEDESELECTED:         MF_Redfont.shade_deselected      = MF_Bluefont.shade_deselected = MF_Minifont.shade_deselected = iSet; break;
1426         case USERDEFS_MENU_SHADEDISABLED:           MF_Redfont.shade_disabled        = MF_Bluefont.shade_disabled   = MF_Minifont.shade_disabled   = iSet; break;
1427         case USERDEFS_MENUTEXT_ZOOM:                MF_Redfont.zoom                  = iSet; break;
1428         case USERDEFS_MENUTEXT_XSPACE:              MF_Redfont.emptychar.x           = iSet; break;
1429         case USERDEFS_MENUTEXT_PAL:                 MF_Redfont.pal                   = iSet; break;
1430         case USERDEFS_MENUTEXT_PALSELECTED:         MF_Redfont.pal_selected          = iSet; break;
1431         case USERDEFS_MENUTEXT_PALDESELECTED:       MF_Redfont.pal_deselected        = iSet; break;
1432         case USERDEFS_MENUTEXT_PALDISABLED:         MF_Redfont.pal_disabled          = iSet; break;
1433         case USERDEFS_MENUTEXT_PALSELECTED_RIGHT:   MF_Redfont.pal_selected_right    = iSet; break;
1434         case USERDEFS_MENUTEXT_PALDESELECTED_RIGHT: MF_Redfont.pal_deselected_right  = iSet; break;
1435         case USERDEFS_MENUTEXT_PALDISABLED_RIGHT:   MF_Redfont.pal_disabled_right    = iSet; break;
1436         case USERDEFS_GAMETEXT_ZOOM:                MF_Bluefont.zoom                 = iSet; break;
1437         case USERDEFS_GAMETEXT_XSPACE:              MF_Bluefont.emptychar.x          = iSet; break;
1438         case USERDEFS_GAMETEXT_PAL:                 MF_Bluefont.pal                  = iSet; break;
1439         case USERDEFS_GAMETEXT_PALSELECTED:         MF_Bluefont.pal_selected         = iSet; break;
1440         case USERDEFS_GAMETEXT_PALDESELECTED:       MF_Bluefont.pal_deselected       = iSet; break;
1441         case USERDEFS_GAMETEXT_PALDISABLED:         MF_Bluefont.pal_disabled         = iSet; break;
1442         case USERDEFS_GAMETEXT_PALSELECTED_RIGHT:   MF_Bluefont.pal_selected_right   = iSet; break;
1443         case USERDEFS_GAMETEXT_PALDESELECTED_RIGHT: MF_Bluefont.pal_deselected_right = iSet; break;
1444         case USERDEFS_GAMETEXT_PALDISABLED_RIGHT:   MF_Bluefont.pal_disabled_right   = iSet; break;
1445         case USERDEFS_MINITEXT_ZOOM:                MF_Minifont.zoom                 = iSet; break;
1446         case USERDEFS_MINITEXT_XSPACE:              MF_Minifont.emptychar.x          = iSet; break;
1447         case USERDEFS_MINITEXT_TRACKING:            MF_Minifont.between.x            = iSet; break;
1448         case USERDEFS_MINITEXT_PAL:                 MF_Minifont.pal                  = iSet; break;
1449         case USERDEFS_MINITEXT_PALSELECTED:         MF_Minifont.pal_selected         = iSet; break;
1450         case USERDEFS_MINITEXT_PALDESELECTED:       MF_Minifont.pal_deselected       = iSet; break;
1451         case USERDEFS_MINITEXT_PALDISABLED:         MF_Minifont.pal_disabled         = iSet; break;
1452         case USERDEFS_MINITEXT_PALSELECTED_RIGHT:   MF_Minifont.pal_selected_right   = iSet; break;
1453         case USERDEFS_MINITEXT_PALDESELECTED_RIGHT: MF_Minifont.pal_deselected_right = iSet; break;
1454         case USERDEFS_MINITEXT_PALDISABLED_RIGHT:   MF_Minifont.pal_disabled_right   = iSet; break;
1455         case USERDEFS_MENUTITLE_PAL:                ud.menutitle_pal                 = iSet; break;
1456         case USERDEFS_SLIDEBAR_PALSELECTED:         ud.slidebar_palselected          = iSet; break;
1457         case USERDEFS_SLIDEBAR_PALDISABLED:         ud.slidebar_paldisabled          = iSet; break;
1458         case USERDEFS_SHADOW_PAL:                   ud.shadow_pal                    = iSet; break;
1459         case USERDEFS_MENU_SCROLLBARTILENUM:        ud.menu_scrollbartilenum         = iSet; break;
1460         case USERDEFS_MENU_SCROLLBARZ:              ud.menu_scrollbarz               = iSet; break;
1461         case USERDEFS_MENU_SCROLLCURSORZ:           ud.menu_scrollcursorz            = iSet; break;
1462         case USERDEFS_RETURN:
1463             if (lParm2 == 0)
1464                 aGameVars[g_returnVarID].global = iSet;
1465             else
1466                 ud.returnvar[lParm2 - 1] = iSet;
1467             break;
1468         case USERDEFS_USERBYTEVERSION:              ud.userbytever                   = iSet; break;
1469         case USERDEFS_AUTOSAVE:                     ud.autosave                      = iSet; break;
1470         case USERDEFS_DRAW_Y:                       rotatesprite_y_offset            = iSet; break;
1471         case USERDEFS_DRAW_YXASPECT:                rotatesprite_yxaspect            = iSet; break;
1472         case USERDEFS_FOV:                          ud.fov                           = iSet; break;
1473         case USERDEFS_NEWGAMECUSTOMOPEN:
1474             for (unsigned int b = 0; b < MAXMENUGAMEPLAYENTRIES; ++b)
1475                 if (iSet & (1u<<b))
1476                     ME_NEWGAMECUSTOMENTRIES[b].flags = 0;
1477             break;
1478         case USERDEFS_NEWGAMECUSTOMSUBOPEN:
1479             for (unsigned int b = 0; b < MAXMENUGAMEPLAYENTRIES; ++b)
1480                 if (iSet & (1u<<b))
1481                     ME_NEWGAMECUSTOMSUBENTRIES[lParm2][b].flags = 0;
1482             break;
1483     }
1484 }
1485 
1486 memberlabel_t const InputLabels[]=
1487 {
1488     { "avel",    INPUT_AVEL,    0, 0, -1 },
1489     { "q16avel", INPUT_Q16AVEL, 0, 0, -1 },
1490     { "horz",    INPUT_HORZ,    0, 0, -1 },
1491     { "q16horz", INPUT_Q16HORZ, 0, 0, -1 },
1492     { "fvel",    INPUT_FVEL,    0, 0, -1 },
1493     { "svel",    INPUT_SVEL,    0, 0, -1 },
1494     { "bits",    INPUT_BITS,    0, 0, -1 },
1495     { "extbits", INPUT_EXTBITS, 0, 0, -1 },
1496 };
1497 
VM_GetPlayerInput(int const playerNum,int32_t labelNum)1498 int32_t __fastcall VM_GetPlayerInput(int const playerNum, int32_t labelNum)
1499 {
1500     if (EDUKE32_PREDICT_FALSE((unsigned)playerNum >= (unsigned)g_mostConcurrentPlayers))
1501     {
1502         CON_ERRPRINTF("invalid player %d\n", playerNum);
1503         return -1;
1504     }
1505 
1506     auto const &i = g_player[playerNum].input;
1507 
1508     switch (labelNum)
1509     {
1510         case INPUT_AVEL:    labelNum = fix16_to_int(i.q16avel); break;
1511         case INPUT_HORZ:    labelNum = fix16_to_int(i.q16horz); break;
1512         case INPUT_Q16AVEL: labelNum = i.q16avel; break;
1513         case INPUT_Q16HORZ: labelNum = i.q16horz; break;
1514         case INPUT_FVEL:    labelNum = i.fvel;    break;
1515         case INPUT_SVEL:    labelNum = i.svel;    break;
1516         case INPUT_BITS:    labelNum = i.bits;    break;
1517         case INPUT_EXTBITS: labelNum = i.extbits; break;
1518 
1519         default: EDUKE32_UNREACHABLE_SECTION(labelNum = -1; break);
1520     }
1521 
1522     return labelNum;
1523 }
1524 
VM_SetPlayerInput(int const playerNum,int const labelNum,int32_t const newValue)1525 void __fastcall VM_SetPlayerInput(int const playerNum, int const labelNum, int32_t const newValue)
1526 {
1527     if (EDUKE32_PREDICT_FALSE((unsigned)playerNum >= (unsigned)g_mostConcurrentPlayers))
1528     {
1529         CON_ERRPRINTF("invalid player %d\n", playerNum);
1530         return;
1531     }
1532 
1533     auto &i = g_player[playerNum].input;
1534 
1535     switch (labelNum)
1536     {
1537         case INPUT_AVEL:    i.q16avel = fix16_from_int(newValue); break;
1538         case INPUT_HORZ:    i.q16horz = fix16_from_int(newValue); break;
1539         case INPUT_Q16AVEL: i.q16avel = newValue; break;
1540         case INPUT_Q16HORZ: i.q16horz = newValue; break;
1541         case INPUT_FVEL:    i.fvel    = newValue; break;
1542         case INPUT_SVEL:    i.svel    = newValue; break;
1543         case INPUT_BITS:    i.bits    = newValue; break;
1544         case INPUT_EXTBITS: i.extbits = newValue; break;
1545     }
1546 }
1547 
1548 memberlabel_t const TileDataLabels[]=
1549 {
1550     // tilesiz[]
1551     { "xsize",      TILEDATA_XSIZE,      0, 0, -1 },
1552     { "ysize",      TILEDATA_YSIZE,      0, 0, -1 },
1553 
1554     // picanm[]
1555     { "animframes", TILEDATA_ANIMFRAMES, 0, 0, -1 },
1556     { "xoffset",    TILEDATA_XOFFSET,    0, 0, -1 },
1557     { "yoffset",    TILEDATA_YOFFSET,    0, 0, -1 },
1558     { "animspeed",  TILEDATA_ANIMSPEED,  0, 0, -1 },
1559     { "animtype",   TILEDATA_ANIMTYPE,   0, 0, -1 },
1560 
1561     // g_tile[]
1562     { "gameflags",  TILEDATA_GAMEFLAGS,  0, 0, -1 },
1563 };
1564 
VM_GetTileData(int const tileNum,int32_t labelNum)1565 int32_t __fastcall VM_GetTileData(int const tileNum, int32_t labelNum)
1566 {
1567     if (EDUKE32_PREDICT_FALSE((unsigned)tileNum >= MAXTILES))
1568     {
1569         CON_ERRPRINTF("invalid tile %d\n", tileNum);
1570         return -1;
1571     }
1572 
1573     auto const &p = picanm[tileNum];
1574 
1575     switch (labelNum)
1576     {
1577         case TILEDATA_XSIZE: labelNum = tilesiz[tileNum].x; break;
1578         case TILEDATA_YSIZE: labelNum = tilesiz[tileNum].y; break;
1579 
1580         case TILEDATA_GAMEFLAGS: labelNum = g_tile[tileNum].flags; break;
1581 
1582         case TILEDATA_ANIMFRAMES: labelNum = p.num;  break;
1583         case TILEDATA_XOFFSET:    labelNum = p.xofs; break;
1584         case TILEDATA_YOFFSET:    labelNum = p.yofs; break;
1585 
1586         case TILEDATA_ANIMSPEED: labelNum = (p.sf & PICANM_ANIMSPEED_MASK); break;
1587         case TILEDATA_ANIMTYPE:  labelNum = (p.sf & PICANM_ANIMTYPE_MASK) >> PICANM_ANIMTYPE_SHIFT; break;
1588 
1589         default: EDUKE32_UNREACHABLE_SECTION(labelNum = -1; break);
1590     }
1591 
1592     return labelNum;
1593 }
1594 
VM_SetTileData(int const tileNum,int const labelNum,int32_t newValue)1595 void __fastcall VM_SetTileData(int const tileNum, int const labelNum, int32_t newValue)
1596 {
1597     if (EDUKE32_PREDICT_FALSE((unsigned)tileNum >= MAXTILES))
1598     {
1599         CON_ERRPRINTF("invalid tile %d\n", tileNum);
1600         return;
1601     }
1602 
1603     auto &p = picanm[tileNum];
1604 
1605     switch (labelNum)
1606     {
1607         //case TILEDATA_XSIZE: tilesiz[tileNum].x = newValue; break;
1608         //case TILEDATA_YSIZE: tilesiz[tileNum].y = newValue; break;
1609 
1610         case TILEDATA_GAMEFLAGS: g_tile[tileNum].flags = newValue; break;
1611 
1612         case TILEDATA_ANIMFRAMES: p.num  = newValue; break;
1613         case TILEDATA_XOFFSET:    p.xofs = newValue; break;
1614         case TILEDATA_YOFFSET:    p.yofs = newValue; break;
1615 
1616         case TILEDATA_ANIMSPEED: p.sf = (p.sf & ~PICANM_ANIMSPEED_MASK) | (newValue & PICANM_ANIMSPEED_MASK); break;
1617         case TILEDATA_ANIMTYPE:  p.sf = (p.sf & ~PICANM_ANIMTYPE_MASK) | ((newValue << PICANM_ANIMTYPE_SHIFT) & PICANM_ANIMTYPE_MASK); break;
1618     }
1619 }
1620 
1621 memberlabel_t const PalDataLabels[]=
1622 {
1623     // g_noFloorPal[]
1624     { "nofloorpal", PALDATA_NOFLOORPAL, 0, 0, -1 },
1625 };
1626 
VM_GetPalData(int const palNum,int32_t labelNum)1627 int32_t __fastcall VM_GetPalData(int const palNum, int32_t labelNum)
1628 {
1629     if (EDUKE32_PREDICT_FALSE((unsigned)palNum >= MAXPALOOKUPS))
1630     {
1631         CON_ERRPRINTF("invalid palette %d\n", palNum);
1632         return -1;
1633     }
1634 
1635     switch (labelNum)
1636     {
1637         case PALDATA_NOFLOORPAL: labelNum = g_noFloorPal[palNum]; break;
1638         default: EDUKE32_UNREACHABLE_SECTION(labelNum = -1; break);
1639     }
1640 
1641     return labelNum;
1642 }
1643 #undef MEMBER
1644 #undef LABEL
1645 
1646 hashtable_t h_actor      = { ACTOR_END>>1, NULL };
1647 hashtable_t h_input      = { INPUT_END>>1, NULL };
1648 hashtable_t h_paldata    = { PALDATA_END>>1, NULL };
1649 hashtable_t h_player     = { PLAYER_END>>1, NULL };
1650 hashtable_t h_projectile = { PROJ_END>>1, NULL };
1651 hashtable_t h_sector     = { SECTOR_END>>1, NULL };
1652 hashtable_t h_tiledata   = { TILEDATA_END>>1, NULL };
1653 hashtable_t h_tsprite    = { ACTOR_END>>1, NULL };
1654 hashtable_t h_userdef    = { USERDEFS_END>>1, NULL };
1655 hashtable_t h_wall       = { WALL_END>>1, NULL };
1656 
1657 #define STRUCT_HASH_SETUP(table, labels)                 \
1658     do                                                   \
1659     {                                                    \
1660         for (int i = 0; i < ARRAY_SSIZE(labels); i++)    \
1661             hash_add(&table, labels[i].name, i, 0);      \
1662         EDUKE32_STATIC_ASSERT(ARRAY_SSIZE(labels) != 0); \
1663     } while (0)
1664 
VM_InitHashTables(void)1665 void VM_InitHashTables(void)
1666 {
1667     for (auto table : vmStructHashTablePtrs)
1668         hash_init(table);
1669 
1670     inithashnames();
1671     initsoundhashnames();
1672 
1673     STRUCT_HASH_SETUP(h_actor,      ActorLabels);
1674     STRUCT_HASH_SETUP(h_input,      InputLabels);
1675     STRUCT_HASH_SETUP(h_paldata,    PalDataLabels);
1676     STRUCT_HASH_SETUP(h_player,     PlayerLabels);
1677     STRUCT_HASH_SETUP(h_projectile, ProjectileLabels);
1678     STRUCT_HASH_SETUP(h_sector,     SectorLabels);
1679     STRUCT_HASH_SETUP(h_tiledata,   TileDataLabels);
1680     STRUCT_HASH_SETUP(h_tsprite,    TsprLabels);
1681     STRUCT_HASH_SETUP(h_userdef,    UserdefsLabels);
1682     STRUCT_HASH_SETUP(h_wall,       WallLabels);
1683 }
1684 #undef STRUCT_HASH_SETUP
1685 
1686