1 //-------------------------------------------------------------------------
2 /*
3 Copyright (C) 2016 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 "gamedef.h"
24
25 #include "cheats.h"
26 #include "common.h"
27 #include "common_game.h"
28 #include "crc32.h"
29 #include "duke3d.h"
30 #include "gameexec.h"
31 #include "gamestructures.h"
32 #include "kplib.h"
33 #include "namesdyn.h"
34 #include "osd.h"
35 #include "savegame.h"
36 #include "vfs.h"
37
38 #include "microprofile.h"
39
40 #if MICROPROFILE_ENABLED != 0
41 MicroProfileToken g_eventTokens[MAXEVENTS];
42 MicroProfileToken g_eventCounterTokens[MAXEVENTS];
43 MicroProfileToken g_actorTokens[MAXTILES];
44 MicroProfileToken g_statnumTokens[MAXSTATUS];
45 #if 0
46 MicroProfileToken g_instTokens[CON_END];
47 #endif
48 #endif
49
50 #define LINE_NUMBER (g_lineNumber << 12)
51
52 int32_t g_scriptVersion = 13; // 13 = 1.3D-style CON files, 14 = 1.4/1.5 style CON files
53
54 char g_scriptFileName[BMAX_PATH] = "(none)"; // file we're currently compiling
55
56 int32_t g_totalLines;
57 int32_t g_lineNumber;
58 char g_szBuf[1024];
59
60 static char *textptr;
61
62 static char g_szCurrentBlockName[64] = "(none)";
63 static char g_szLastBlockName[64] = "NULL";
64
65 static bool g_checkingCase;
66 static bool g_dynamicSoundMapping;
67 static bool g_dynamicTileMapping;
68 static bool g_labelsOnly;
69 static bool g_processingState;
70 static bool g_skipBranch;
71
72 static int g_checkingIfElse;
73 static int g_checkingSwitch;
74 static int g_lastKeyword = -1;
75 static int g_numBraces;
76 static int g_numCases;
77
78 static intptr_t apScriptGameEventEnd[MAXEVENTS];
79 static intptr_t g_scriptActorOffset;
80 static intptr_t g_scriptEventBreakOffset;
81 static intptr_t g_scriptEventChainOffset;
82 static intptr_t g_scriptEventOffset;
83
84 // The pointer to the start of the case table in a switch statement.
85 // First entry is 'default' code.
86 static intptr_t *g_caseTablePtr;
87
88 static bool C_ParseCommand(bool loop = false);
89 static void C_SetScriptSize(int32_t newsize);
90
91 int32_t g_errorCnt;
92 int32_t g_warningCnt;
93 int32_t g_numXStrings;
94
C_GetLabelType(int const type)95 static char *C_GetLabelType(int const type)
96 {
97 static tokenmap_t const LabelType[] =
98 {
99 { "action", LABEL_ACTION },
100 { "actor", LABEL_ACTOR },
101 { "ai", LABEL_AI },
102 { "define", LABEL_DEFINE },
103 { "event", LABEL_EVENT },
104 { "move", LABEL_MOVE },
105 { "state", LABEL_STATE },
106 };
107
108 char x[64] = {};
109
110 for (auto &label : LabelType)
111 {
112 if ((type & label.val) != label.val)
113 continue;
114
115 if (x[0]) Bstrcat(x, " or ");
116 Bstrcat(x, label.token);
117
118 if (type == label.val)
119 break;
120 }
121
122 return Xstrdup(x);
123 }
124
125 static hashtable_t h_keywords = { CON_END>>1, NULL };
126 static hashtable_t h_iter = { ITER_END>>1, NULL };
127
128 static hashtable_t *const tables[] = {
129 &h_arrays,
130 &h_gamevars,
131 &h_iter,
132 &h_keywords,
133 &h_labels,
134 };
135
136 static hashtable_t *const tables_free[] = {
137 &h_iter,
138 &h_keywords,
139 };
140
141 static tokenmap_t const vm_keywords[] =
142 {
143 { "action", CON_ACTION },
144 { "activate", CON_ACTIVATE },
145 { "activatebysector", CON_ACTIVATEBYSECTOR },
146 { "activatecheat", CON_ACTIVATECHEAT },
147 { "actor", CON_ACTOR },
148 { "actorsound", CON_ACTORSOUND },
149 { "addammo", CON_ADDAMMO },
150 { "addinventory", CON_ADDINVENTORY },
151 { "addkills", CON_ADDKILLS },
152 { "addlog", CON_ADDLOGVAR },
153 { "addlogvar", CON_ADDLOGVAR },
154 { "addphealth", CON_ADDPHEALTH },
155 { "addstrength", CON_ADDSTRENGTH },
156 { "addvar", CON_ADDVAR },
157 { "addvarvar", CON_ADDVARVAR },
158 { "addweapon", CON_ADDWEAPON },
159 { "addweaponvar", CON_ADDWEAPON },
160 { "ai", CON_AI },
161 { "andvar", CON_ANDVAR },
162 { "andvarvar", CON_ANDVARVAR },
163 { "angoff", CON_ANGOFF },
164 { "angoffvar", CON_ANGOFF },
165 { "appendevent", CON_APPENDEVENT },
166 { "betaname", CON_BETANAME },
167 { "break", CON_BREAK },
168 { "cactor", CON_CACTOR },
169 { "calchypotenuse", CON_CALCHYPOTENUSE },
170 { "cansee", CON_CANSEE },
171 { "canseespr", CON_CANSEESPR },
172 { "capia", CON_CAPIA },
173 { "capis", CON_CAPIS },
174 { "case", CON_CASE },
175 { "changespritesect", CON_CHANGESPRITESECT },
176 { "changespritestat", CON_CHANGESPRITESTAT },
177 { "cheatkeys", CON_CHEATKEYS },
178 { "checkactivatormotion", CON_CHECKACTIVATORMOTION },
179 { "checkavailinven", CON_CHECKAVAILINVEN },
180 { "checkavailweapon", CON_CHECKAVAILWEAPON },
181 { "clamp", CON_CLAMP },
182 { "clearmapstate", CON_CLEARMAPSTATE },
183 { "clipdist", CON_CLIPDIST },
184 { "clipmove", CON_CLIPMOVE },
185 { "clipmovenoslide", CON_CLIPMOVENOSLIDE },
186 { "cmenu", CON_CMENU },
187 { "copy", CON_COPY },
188 { "cos", CON_COS },
189 { "count", CON_COUNT },
190 { "cstat", CON_CSTAT },
191 { "cstator", CON_CSTATOR },
192 { "damageeventtile", CON_DAMAGEEVENTTILE },
193 { "damageeventtilerange", CON_DAMAGEEVENTTILERANGE },
194 { "debris", CON_DEBRIS },
195 { "debug", CON_DEBUG },
196 { "default", CON_DEFAULT },
197 { "define", CON_DEFINE },
198 { "definecheat", CON_DEFINECHEAT },
199 { "definecheatdescription", CON_DEFINECHEATDESCRIPTION },
200 { "definegamefuncname", CON_DEFINEGAMEFUNCNAME },
201 { "definegametype", CON_DEFINEGAMETYPE },
202 { "definelevelname", CON_DEFINELEVELNAME },
203 { "defineprojectile", CON_DEFINEPROJECTILE },
204 { "definequote", CON_DEFINEQUOTE },
205 { "defineskillname", CON_DEFINESKILLNAME },
206 { "definesound", CON_DEFINESOUND },
207 { "definevolumeflags", CON_DEFINEVOLUMEFLAGS },
208 { "definevolumename", CON_DEFINEVOLUMENAME },
209 { "defstate", CON_DEFSTATE },
210 { "digitalnumber", CON_DIGITALNUMBER },
211 { "digitalnumberz", CON_DIGITALNUMBERZ },
212 { "displayrand", CON_DISPLAYRAND },
213 { "displayrandvar", CON_DISPLAYRANDVAR },
214 { "displayrandvarvar", CON_DISPLAYRANDVARVAR },
215 { "dist", CON_DIST },
216 { "divr", CON_DIVR },
217 { "divrd", CON_DIVVARVAR }, // div round toward zero -- alias until proven otherwise
218 { "divru", CON_DIVRU },
219 { "divscale", CON_DIVSCALE },
220 { "divvar", CON_DIVVAR },
221 { "divvarvar", CON_DIVVARVAR },
222 { "dragpoint", CON_DRAGPOINT },
223 { "drawline256", CON_DRAWLINE256 },
224 { "drawlinergb", CON_DRAWLINERGB },
225 { "dynamicremap", CON_DYNAMICREMAP },
226 { "dynamicsoundremap", CON_DYNAMICSOUNDREMAP },
227 { "echo", CON_ECHO },
228 { "else", CON_ELSE },
229 { "enda", CON_ENDA },
230 { "endevent", CON_ENDEVENT },
231 { "endofgame", CON_ENDOFGAME },
232 { "endoflevel", CON_ENDOFLEVEL },
233 { "ends", CON_ENDS },
234 { "endswitch", CON_ENDSWITCH },
235 { "enhanced", CON_ENHANCED },
236 { "eqspawnvar", CON_EQSPAWN },
237 { "eshootvar", CON_ESHOOT },
238 { "espawnvar", CON_ESPAWN },
239 { "eventloadactor", CON_EVENTLOADACTOR },
240 { "ezshootvar", CON_EZSHOOT },
241 { "fall", CON_FALL },
242 { "findnearactor3dvar", CON_FINDNEARACTOR3D },
243 { "findnearactorvar", CON_FINDNEARACTOR },
244 { "findnearactorzvar", CON_FINDNEARACTORZ },
245 { "findnearsprite3dvar", CON_FINDNEARSPRITE3D },
246 { "findnearspritevar", CON_FINDNEARSPRITE },
247 { "findnearspritezvar", CON_FINDNEARSPRITEZ },
248 { "findotherplayer", CON_FINDOTHERPLAYER },
249 { "findplayer", CON_FINDPLAYER },
250 { "flash", CON_FLASH },
251 { "for", CON_FOR },
252 { "gamearray", CON_GAMEARRAY },
253 { "gamestartup", CON_GAMESTARTUP },
254 { "gametext", CON_GAMETEXT },
255 { "gametextz", CON_GAMETEXTZ },
256 { "gamevar", CON_GAMEVAR },
257 { "getactor", CON_GETACTOR },
258 { "getactorangle", CON_GETACTORANGLE },
259 { "getactorvar", CON_GETACTORVAR },
260 { "getangle", CON_GETANGLE },
261 { "getangletotarget", CON_GETANGLETOTARGET },
262 { "getarraysequence", CON_GETARRAYSEQUENCE },
263 { "getarraysize", CON_GETARRAYSIZE },
264 { "getceilzofslope", CON_GETCEILZOFSLOPE },
265 { "getclosestcol", CON_GETCLOSESTCOL },
266 { "getcurraddress", CON_GETCURRADDRESS },
267 { "getflorzofslope", CON_GETFLORZOFSLOPE },
268 { "getgamefuncbind", CON_GETGAMEFUNCBIND },
269 { "getincangle", CON_GETINCANGLE },
270 { "getinput", CON_GETINPUT },
271 { "getkeyname", CON_GETKEYNAME },
272 { "getlastpal", CON_GETLASTPAL },
273 { "getmusicposition", CON_GETMUSICPOSITION },
274 { "getplayer", CON_GETPLAYER },
275 { "getplayerangle", CON_GETPLAYERANGLE },
276 { "getplayervar", CON_GETPLAYERVAR },
277 { "getpname", CON_GETPNAME },
278 { "getprojectile", CON_GETPROJECTILE },
279 { "getsector", CON_GETSECTOR },
280 { "gettextureceiling", CON_GETTEXTURECEILING },
281 { "gettexturefloor", CON_GETTEXTUREFLOOR },
282 { "getthisprojectile", CON_GETTHISPROJECTILE },
283 { "getticks", CON_GETTICKS },
284 { "gettiledata", CON_GETTILEDATA }, // OldMP compat.
285 { "gettimedate", CON_GETTIMEDATE },
286 { "gettspr", CON_GETTSPR },
287 { "getuserdef", CON_GETUSERDEF },
288 { "getwall", CON_GETWALL },
289 { "getzrange", CON_GETZRANGE },
290 { "globalsound", CON_GLOBALSOUND },
291 { "globalsoundvar", CON_GLOBALSOUND },
292 { "gmaxammo", CON_GMAXAMMO },
293 { "guniqhudid", CON_GUNIQHUDID },
294 { "guts", CON_GUTS },
295 { "headspritesect", CON_HEADSPRITESECT },
296 { "headspritestat", CON_HEADSPRITESTAT },
297 { "hitradius", CON_HITRADIUS },
298 { "hitradiusvar", CON_HITRADIUS },
299 { "hitscan", CON_HITSCAN },
300 { "ifaction", CON_IFACTION },
301 { "ifactioncount", CON_IFACTIONCOUNT },
302 { "ifactor", CON_IFACTOR },
303 { "ifactornotstayput", CON_IFACTORNOTSTAYPUT },
304 { "ifactorsound", CON_IFACTORSOUND },
305 { "ifai", CON_IFAI },
306 { "ifangdiffl", CON_IFANGDIFFL },
307 { "ifawayfromwall", CON_IFAWAYFROMWALL },
308 { "ifbulletnear", CON_IFBULLETNEAR },
309 { "ifcansee", CON_IFCANSEE },
310 { "ifcanseetarget", CON_IFCANSEETARGET },
311 { "ifcanshoottarget", CON_IFCANSHOOTTARGET },
312 { "ifceilingdistl", CON_IFCEILINGDISTL },
313 { "ifclient", CON_IFCLIENT },
314 { "ifcount", CON_IFCOUNT },
315 { "ifcutscene", CON_IFCUTSCENE },
316 { "ifdead", CON_IFDEAD },
317 { "iffloordistl", CON_IFFLOORDISTL },
318 { "ifgapzl", CON_IFGAPZL },
319 { "ifgotweaponce", CON_IFGOTWEAPONCE },
320 { "ifhitspace", CON_IFHITSPACE },
321 { "ifhitweapon", CON_IFHITWEAPON },
322 { "ifinouterspace", CON_IFINOUTERSPACE },
323 { "ifinspace", CON_IFINSPACE },
324 { "ifinwater", CON_IFINWATER },
325 { "ifmove", CON_IFMOVE },
326 { "ifmultiplayer", CON_IFMULTIPLAYER },
327 { "ifnosounds", CON_IFNOSOUNDS },
328 { "ifnotmoving", CON_IFNOTMOVING },
329 { "ifonwater", CON_IFONWATER },
330 { "ifoutside", CON_IFOUTSIDE },
331 { "ifp", CON_IFP },
332 { "ifpdistg", CON_IFPDISTG },
333 { "ifpdistl", CON_IFPDISTL },
334 { "ifphealthl", CON_IFPHEALTHL },
335 { "ifpinventory", CON_IFPINVENTORY },
336 { "ifplaybackon", CON_IFPLAYBACKON },
337 { "ifplayersl", CON_IFPLAYERSL },
338 { "ifrespawn", CON_IFRESPAWN },
339 { "ifrnd", CON_IFRND },
340 { "ifserver", CON_IFSERVER },
341 { "ifsound", CON_IFSOUND },
342 { "ifspawnedby", CON_IFSPAWNEDBY },
343 { "ifspritepal", CON_IFSPRITEPAL },
344 { "ifsquished", CON_IFSQUISHED },
345 { "ifstrength", CON_IFSTRENGTH },
346 { "ifvara", CON_IFVARA },
347 { "ifvarae", CON_IFVARAE },
348 { "ifvarand", CON_IFVARAND },
349 { "ifvarb", CON_IFVARB },
350 { "ifvarbe", CON_IFVARBE },
351 { "ifvarboth", CON_IFVARBOTH },
352 { "ifvare", CON_IFVARE },
353 { "ifvareither", CON_IFVAREITHER },
354 { "ifvarg", CON_IFVARG },
355 { "ifvarge", CON_IFVARGE },
356 { "ifvarl", CON_IFVARL },
357 { "ifvarle", CON_IFVARLE },
358 { "ifvarn", CON_IFVARN },
359 { "ifvaror", CON_IFVAROR },
360 { "ifvarvara", CON_IFVARVARA },
361 { "ifvarvarae", CON_IFVARVARAE },
362 { "ifvarvarand", CON_IFVARVARAND },
363 { "ifvarvarb", CON_IFVARVARB },
364 { "ifvarvarbe", CON_IFVARVARBE },
365 { "ifvarvarboth", CON_IFVARVARBOTH },
366 { "ifvarvare", CON_IFVARVARE },
367 { "ifvarvareither", CON_IFVARVAREITHER },
368 { "ifvarvarg", CON_IFVARVARG },
369 { "ifvarvarge", CON_IFVARVARGE },
370 { "ifvarvarl", CON_IFVARVARL },
371 { "ifvarvarle", CON_IFVARVARLE },
372 { "ifvarvarn", CON_IFVARVARN },
373 { "ifvarvaror", CON_IFVARVAROR },
374 { "ifvarvarxor", CON_IFVARVARXOR },
375 { "ifvarxor", CON_IFVARXOR },
376 { "ifwasweapon", CON_IFWASWEAPON },
377 { "include", CON_INCLUDE },
378 { "includedefault", CON_INCLUDEDEFAULT },
379 { "inittimer", CON_INITTIMER },
380 { "insertspriteq", CON_INSERTSPRITEQ },
381 { "inv", CON_INV },
382 { "jump", CON_JUMP },
383 { "killit", CON_KILLIT },
384 { "klabs", CON_KLABS },
385 { "ldist", CON_LDIST },
386 { "lineintersect", CON_LINEINTERSECT },
387 { "loadmapstate", CON_LOADMAPSTATE },
388 { "lockplayer", CON_LOCKPLAYER },
389 { "lotsofglass", CON_LOTSOFGLASS },
390 { "mail", CON_MAIL },
391 { "mikesnd", CON_MIKESND },
392 { "minitext", CON_MINITEXT },
393 { "modvar", CON_MODVAR },
394 { "modvarvar", CON_MODVARVAR },
395 { "money", CON_MONEY },
396 { "move", CON_MOVE },
397 { "movesector", CON_MOVESECTOR },
398 { "movesprite", CON_MOVESPRITE },
399 { "mulscale", CON_MULSCALE },
400 { "mulvar", CON_MULVAR },
401 { "mulvarvar", CON_MULVARVAR },
402 { "music", CON_MUSIC },
403 { "myos", CON_MYOS },
404 { "myospal", CON_MYOSPAL },
405 { "myospalx", CON_MYOSPALX },
406 { "myosx", CON_MYOSX },
407 { "neartag", CON_NEARTAG },
408 { "nextsectorneighborz", CON_NEXTSECTORNEIGHBORZ },
409 { "nextspritesect", CON_NEXTSPRITESECT },
410 { "nextspritestat", CON_NEXTSPRITESTAT },
411 { "nullop", CON_NULLOP },
412 { "onevent", CON_ONEVENT },
413 { "operate", CON_OPERATE },
414 { "operateactivators", CON_OPERATEACTIVATORS },
415 { "operatemasterswitches", CON_OPERATEMASTERSWITCHES },
416 { "operaterespawns", CON_OPERATERESPAWNS },
417 { "operatesectors", CON_OPERATESECTORS },
418 { "orvar", CON_ORVAR },
419 { "orvarvar", CON_ORVARVAR },
420 { "palfrom", CON_PALFROM },
421 { "paper", CON_PAPER },
422 { "pkick", CON_PKICK },
423 { "precache", CON_PRECACHE },
424 { "prevspritesect", CON_PREVSPRITESECT },
425 { "prevspritestat", CON_PREVSPRITESTAT },
426 { "preloadtrackslotforswap", CON_PRELOADTRACKSLOTFORSWAP },
427 { "pstomp", CON_PSTOMP },
428 { "qgetsysstr", CON_QGETSYSSTR },
429 { "qspawnvar", CON_QSPAWN },
430 { "qsprintf", CON_QSPRINTF },
431 { "qstrcat", CON_QSTRCAT },
432 { "qstrcmp", CON_QSTRCMP },
433 { "qstrcpy", CON_QSTRCPY },
434 { "qstrdim", CON_QSTRDIM },
435 { "qstrlen", CON_QSTRLEN },
436 { "qstrncat", CON_QSTRNCAT },
437 { "qsubstr", CON_QSUBSTR },
438 { "quake", CON_QUAKE },
439 { "quote", CON_QUOTE },
440 { "randvar", CON_RANDVAR },
441 { "randvarvar", CON_RANDVARVAR },
442 { "rayintersect", CON_RAYINTERSECT },
443 { "readarrayfromfile", CON_READARRAYFROMFILE },
444 { "readgamevar", CON_READGAMEVAR },
445 { "redefinequote", CON_REDEFINEQUOTE },
446 { "resetactioncount", CON_RESETACTIONCOUNT },
447 { "resetcount", CON_RESETCOUNT },
448 { "resetplayer", CON_RESETPLAYER },
449 { "resetplayerflags", CON_RESETPLAYERFLAGS },
450 { "resizearray", CON_RESIZEARRAY },
451 { "respawnhitag", CON_RESPAWNHITAG },
452 { "return", CON_RETURN },
453 { "rotatepoint", CON_ROTATEPOINT },
454 { "rotatesprite", CON_ROTATESPRITE },
455 { "rotatesprite16", CON_ROTATESPRITE16 },
456 { "rotatespritea", CON_ROTATESPRITEA },
457 { "save", CON_SAVE },
458 { "savegamevar", CON_SAVEGAMEVAR },
459 { "savemapstate", CON_SAVEMAPSTATE },
460 { "savenn", CON_SAVENN },
461 { "scalevar", CON_SCALEVAR },
462 { "screenpal", CON_SCREENPAL },
463 { "screensound", CON_SCREENSOUND },
464 { "screentext", CON_SCREENTEXT },
465 { "scriptsize", CON_SCRIPTSIZE },
466 { "sectclearinterpolation", CON_SECTCLEARINTERPOLATION },
467 { "sectgethitag", CON_SECTGETHITAG },
468 { "sectgetlotag", CON_SECTGETLOTAG },
469 { "sectorofwall", CON_SECTOROFWALL },
470 { "sectsetinterpolation", CON_SECTSETINTERPOLATION },
471 { "setactor", CON_SETACTOR },
472 { "setactorangle", CON_SETACTORANGLE },
473 { "setactorsoundpitch", CON_SETACTORSOUNDPITCH },
474 { "setactorvar", CON_SETACTORVAR },
475 { "setarray", CON_SETARRAY },
476 { "setarraysequence", CON_SETARRAYSEQUENCE },
477 { "setaspect", CON_SETASPECT },
478 { "setcfgname", CON_SETCFGNAME },
479 { "setdefname", CON_SETDEFNAME },
480 { "setgamename", CON_SETGAMENAME },
481 { "setgamepalette", CON_SETGAMEPALETTE },
482 { "setinput", CON_SETINPUT },
483 { "setmusicposition", CON_SETMUSICPOSITION },
484 { "setplayer", CON_SETPLAYER },
485 { "setplayerangle", CON_SETPLAYERANGLE },
486 { "setplayervar", CON_SETPLAYERVAR },
487 { "setprojectile", CON_SETPROJECTILE },
488 { "setsector", CON_SETSECTOR },
489 { "setsprite", CON_SETSPRITE },
490 { "setthisprojectile", CON_SETTHISPROJECTILE },
491 { "settiledata", CON_SETTILEDATA },
492 { "settspr", CON_SETTSPR },
493 { "setuserdef", CON_SETUSERDEF },
494 { "setvar", CON_SETVAR },
495 { "setvarvar", CON_SETVARVAR },
496 { "setwall", CON_SETWALL },
497 { "shadeto", CON_SHADETO },
498 { "shiftvarl", CON_SHIFTVARL },
499 { "shiftvarr", CON_SHIFTVARR },
500 { "shiftvarvarl", CON_SHIFTVARVARL },
501 { "shiftvarvarr", CON_SHIFTVARVARR },
502 { "shootvar", CON_SHOOT },
503 { "showview", CON_SHOWVIEW },
504 { "showviewunbiased", CON_SHOWVIEWUNBIASED },
505 { "showviewq16", CON_SHOWVIEWQ16 },
506 { "showviewq16unbiased", CON_SHOWVIEWQ16UNBIASED },
507 { "sin", CON_SIN },
508 { "sizeat", CON_SIZEAT },
509 { "sizeto", CON_SIZETO },
510 { "sleeptime", CON_SLEEPTIME },
511 { "smaxammo", CON_SMAXAMMO },
512 { "sound", CON_SOUND },
513 { "soundonce", CON_SOUNDONCE },
514 { "soundoncevar", CON_SOUNDONCE },
515 { "soundvar", CON_SOUND },
516 { "spawn", CON_SPAWN },
517 { "spawnceilingglass", CON_SPAWNCEILINGGLASS },
518 { "spawnwallstainedglass", CON_SPAWNWALLSTAINEDGLASS },
519 { "spawnwallglass", CON_SPAWNWALLGLASS },
520 { "spgethitag", CON_SPGETHITAG },
521 { "spgetlotag", CON_SPGETLOTAG },
522 { "spriteflags", CON_SPRITEFLAGS },
523 { "spritenopal", CON_SPRITENOPAL },
524 { "spritenoshade", CON_SPRITENOSHADE },
525 { "spritenvg", CON_SPRITENVG },
526 { "spritepal", CON_SPRITEPAL },
527 { "spriteshadow", CON_SPRITESHADOW },
528 { "sqrt", CON_SQRT },
529 { "ssp", CON_SSP },
530 { "startcutscene", CON_STARTCUTSCENE },
531 { "startlevel", CON_STARTLEVEL },
532 { "startscreen", CON_STARTSCREEN },
533 { "starttrack", CON_STARTTRACK },
534 { "starttrackslot", CON_STARTTRACKSLOT },
535 { "starttrackvar", CON_STARTTRACK },
536 { "state", CON_STATE },
537 { "stopactorsound", CON_STOPACTORSOUND },
538 { "stopallmusic", CON_STOPALLMUSIC },
539 { "stopallsounds", CON_STOPALLSOUNDS },
540 { "stopsound", CON_STOPSOUND },
541 { "stopsoundvar", CON_STOPSOUND },
542 { "strength", CON_STRENGTH },
543 { "subvar", CON_SUBVAR },
544 { "subvarvar", CON_SUBVARVAR },
545 { "switch", CON_SWITCH },
546 { "swaparrays", CON_SWAPARRAYS },
547 { "swaptrackslot", CON_SWAPTRACKSLOT },
548 { "time", CON_TIME },
549 { "tip", CON_TIP },
550 { "tossweapon", CON_TOSSWEAPON },
551 { "undefinecheat", CON_UNDEFINECHEAT },
552 { "undefinegamefunc", CON_UNDEFINEGAMEFUNC },
553 { "undefinelevel", CON_UNDEFINELEVEL },
554 { "undefineskill", CON_UNDEFINESKILL },
555 { "undefinevolume", CON_UNDEFINEVOLUME },
556 { "updatesector", CON_UPDATESECTOR },
557 { "updatesectorz", CON_UPDATESECTORZ },
558 { "updatesectorneighbor", CON_UPDATESECTORNEIGHBOR },
559 { "updatesectorneighborz", CON_UPDATESECTORNEIGHBORZ },
560 { "useractor", CON_USERACTOR },
561 { "userquote", CON_USERQUOTE },
562 { "wackplayer", CON_WACKPLAYER },
563 { "whilevarl", CON_WHILEVARL },
564 { "whilevarn", CON_WHILEVARN },
565 { "whilevarvarl", CON_WHILEVARVARL },
566 { "whilevarvarn", CON_WHILEVARVARN },
567 { "writearraytofile", CON_WRITEARRAYTOFILE },
568 { "xorvar", CON_XORVAR },
569 { "xorvarvar", CON_XORVARVAR },
570 { "zshootvar", CON_ZSHOOT },
571 { "{", CON_LEFTBRACE },
572 { "}", CON_RIGHTBRACE },
573
574 { "#define", CON_DEFINE },
575 { "#include", CON_INCLUDE },
576 { "al", CON_ADDLOGVAR },
577 { "var", CON_GAMEVAR },
578 { "array", CON_GAMEARRAY },
579 { "shiftl", CON_SHIFTVARVARL },
580 { "shiftr", CON_SHIFTVARVARR },
581 { "rand", CON_RANDVARVAR },
582 { "set", CON_SETVARVAR },
583 { "add", CON_ADDVARVAR },
584 { "sub", CON_SUBVARVAR },
585 { "mul", CON_MULVARVAR },
586 { "div", CON_DIVVARVAR },
587 { "mod", CON_MODVARVAR },
588 { "and", CON_ANDVARVAR },
589 { "or", CON_ORVARVAR },
590 { "xor", CON_XORVARVAR },
591 { "ifa", CON_IFVARVARA },
592 { "ifae", CON_IFVARVARAE },
593 { "ifb", CON_IFVARVARB },
594 { "ifbe", CON_IFVARVARBE },
595 { "ifl", CON_IFVARVARL },
596 { "ifle", CON_IFVARVARLE },
597 { "ifg", CON_IFVARVARG },
598 { "ifge", CON_IFVARVARGE },
599 { "ife", CON_IFVARVARE },
600 { "ifn", CON_IFVARVARN },
601 { "ifand", CON_IFVARVARAND },
602 { "ifor", CON_IFVARVAROR },
603 { "ifxor", CON_IFVARVARXOR },
604 { "ifeither", CON_IFVARVAREITHER },
605 { "ifboth", CON_IFVARVARBOTH },
606 { "whilen", CON_WHILEVARVARN },
607 { "whilel", CON_WHILEVARVARL },
608 { "abs", CON_KLABS },
609
610 { "getp", CON_GETPLAYER },
611 { "getpv", CON_GETPLAYERVAR },
612 { "gets", CON_GETSECTOR },
613 { "geta", CON_GETACTOR },
614 { "getav", CON_GETACTORVAR },
615 { "getw", CON_GETWALL },
616 { "getu", CON_GETUSERDEF },
617 { "geti", CON_GETINPUT },
618 { "getarrayseq", CON_GETARRAYSEQUENCE },
619
620 { "setp", CON_SETPLAYER },
621 { "setpv", CON_SETPLAYERVAR },
622 { "sets", CON_SETSECTOR },
623 { "seta", CON_SETACTOR },
624 { "setav", CON_SETACTORVAR },
625 { "setw", CON_SETWALL },
626 { "setu", CON_SETUSERDEF },
627 { "seti", CON_SETINPUT },
628 { "setarrayseq", CON_SETARRAYSEQUENCE },
629
630 { "string", CON_DEFINEQUOTE },
631 { "print", CON_QUOTE },
632
633 { "dc", CON_DEFINECHEAT },
634 { "dcd", CON_DEFINECHEATDESCRIPTION },
635 { "udc", CON_UNDEFINECHEAT },
636 { "ck", CON_CHEATKEYS },
637
638 { "qputs", CON_REDEFINEQUOTE },
639
640 { "espawn", CON_ESPAWN },
641 { "qspawn", CON_QSPAWN },
642 { "eqspawn", CON_EQSPAWN },
643
644 { "eshoot", CON_ESHOOT },
645 { "zshoot", CON_ZSHOOT },
646 { "ezshoot", CON_EZSHOOT },
647 { "shoot", CON_SHOOT },
648
649 { "findnearactor", CON_FINDNEARACTOR },
650 { "findnearactor3d", CON_FINDNEARACTOR3D },
651 { "findnearactorz", CON_FINDNEARACTORZ },
652
653 { "findnearsprite", CON_FINDNEARSPRITE },
654 { "findnearsprite3d", CON_FINDNEARSPRITE3D },
655 { "findnearspritez", CON_FINDNEARSPRITEZ },
656 };
657
658 static const vec2_t varvartable[] =
659 {
660 { CON_IFVARVARA, CON_IFVARA },
661 { CON_IFVARVARAE, CON_IFVARAE },
662 { CON_IFVARVARAND, CON_IFVARAND },
663 { CON_IFVARVARB, CON_IFVARB },
664 { CON_IFVARVARBE, CON_IFVARBE },
665 { CON_IFVARVARBOTH, CON_IFVARBOTH },
666 { CON_IFVARVARE, CON_IFVARE },
667 { CON_IFVARVAREITHER, CON_IFVAREITHER },
668 { CON_IFVARVARG, CON_IFVARG },
669 { CON_IFVARVARGE, CON_IFVARGE },
670 { CON_IFVARVARL, CON_IFVARL },
671 { CON_IFVARVARLE, CON_IFVARLE },
672 { CON_IFVARVARN, CON_IFVARN },
673 { CON_IFVARVAROR, CON_IFVAROR },
674 { CON_IFVARVARXOR, CON_IFVARXOR },
675
676 { CON_ADDVARVAR, CON_ADDVAR },
677 { CON_ANDVARVAR, CON_ANDVAR },
678 { CON_DISPLAYRANDVARVAR, CON_DISPLAYRANDVAR },
679 { CON_DIVVARVAR, CON_DIVVAR },
680 { CON_MODVARVAR, CON_MODVAR },
681 { CON_MULVARVAR, CON_MULVAR },
682 { CON_ORVARVAR, CON_ORVAR },
683 { CON_RANDVARVAR, CON_RANDVAR },
684 { CON_SETVARVAR, CON_SETVAR },
685 { CON_SHIFTVARVARL, CON_SHIFTVARL },
686 { CON_SHIFTVARVARR, CON_SHIFTVARR },
687 { CON_SUBVARVAR, CON_SUBVAR },
688 { CON_WHILEVARVARL, CON_WHILEVARL },
689 { CON_WHILEVARVARN, CON_WHILEVARN },
690 { CON_XORVARVAR, CON_XORVAR },
691 };
692
693 static const vec2_t globalvartable[] =
694 {
695 { CON_SETVAR, CON_SETVAR_GLOBAL },
696 #ifdef CON_DISCRETE_VAR_ACCESS
697 { CON_IFVARA, CON_IFVARA_GLOBAL },
698 { CON_IFVARAE, CON_IFVARAE_GLOBAL },
699 { CON_IFVARAND, CON_IFVARAND_GLOBAL },
700 { CON_IFVARB, CON_IFVARB_GLOBAL },
701 { CON_IFVARBE, CON_IFVARBE_GLOBAL },
702 { CON_IFVARBOTH, CON_IFVARBOTH_GLOBAL },
703 { CON_IFVARE, CON_IFVARE_GLOBAL },
704 { CON_IFVAREITHER, CON_IFVAREITHER_GLOBAL },
705 { CON_IFVARG, CON_IFVARG_GLOBAL },
706 { CON_IFVARGE, CON_IFVARGE_GLOBAL },
707 { CON_IFVARL, CON_IFVARL_GLOBAL },
708 { CON_IFVARLE, CON_IFVARLE_GLOBAL },
709 { CON_IFVARN, CON_IFVARN_GLOBAL },
710 { CON_IFVAROR, CON_IFVAROR_GLOBAL },
711 { CON_IFVARXOR, CON_IFVARXOR_GLOBAL },
712 { CON_WHILEVARL, CON_WHILEVARL_GLOBAL },
713 { CON_WHILEVARN, CON_WHILEVARN_GLOBAL },
714
715 { CON_ADDVAR, CON_ADDVAR_GLOBAL },
716 { CON_ANDVAR, CON_ANDVAR_GLOBAL },
717 { CON_DIVVAR, CON_DIVVAR_GLOBAL },
718 { CON_MODVAR, CON_MODVAR_GLOBAL },
719 { CON_MULVAR, CON_MULVAR_GLOBAL },
720 { CON_ORVAR, CON_ORVAR_GLOBAL },
721 { CON_RANDVAR, CON_RANDVAR_GLOBAL },
722 { CON_SHIFTVARL, CON_SHIFTVARL_GLOBAL },
723 { CON_SHIFTVARR, CON_SHIFTVARR_GLOBAL },
724 { CON_SUBVAR, CON_SUBVAR_GLOBAL },
725 { CON_XORVAR, CON_XORVAR_GLOBAL },
726 #endif
727 };
728
729 static const vec2_t playervartable[] =
730 {
731 { CON_SETVAR, CON_SETVAR_PLAYER },
732 #ifdef CON_DISCRETE_VAR_ACCESS
733 { CON_IFVARA, CON_IFVARA_PLAYER },
734 { CON_IFVARAE, CON_IFVARAE_PLAYER },
735 { CON_IFVARAND, CON_IFVARAND_PLAYER },
736 { CON_IFVARB, CON_IFVARB_PLAYER },
737 { CON_IFVARBE, CON_IFVARBE_PLAYER },
738 { CON_IFVARBOTH, CON_IFVARBOTH_PLAYER },
739 { CON_IFVARE, CON_IFVARE_PLAYER },
740 { CON_IFVAREITHER, CON_IFVAREITHER_PLAYER },
741 { CON_IFVARG, CON_IFVARG_PLAYER },
742 { CON_IFVARGE, CON_IFVARGE_PLAYER },
743 { CON_IFVARL, CON_IFVARL_PLAYER },
744 { CON_IFVARLE, CON_IFVARLE_PLAYER },
745 { CON_IFVARN, CON_IFVARN_PLAYER },
746 { CON_IFVAROR, CON_IFVAROR_PLAYER },
747 { CON_IFVARXOR, CON_IFVARXOR_PLAYER },
748 { CON_WHILEVARL, CON_WHILEVARL_PLAYER },
749 { CON_WHILEVARN, CON_WHILEVARN_PLAYER },
750
751 { CON_ADDVAR, CON_ADDVAR_PLAYER },
752 { CON_ANDVAR, CON_ANDVAR_PLAYER },
753 { CON_DIVVAR, CON_DIVVAR_PLAYER },
754 { CON_MODVAR, CON_MODVAR_PLAYER },
755 { CON_MULVAR, CON_MULVAR_PLAYER },
756 { CON_ORVAR, CON_ORVAR_PLAYER },
757 { CON_RANDVAR, CON_RANDVAR_PLAYER },
758 { CON_SHIFTVARL, CON_SHIFTVARL_PLAYER },
759 { CON_SHIFTVARR, CON_SHIFTVARR_PLAYER },
760 { CON_SUBVAR, CON_SUBVAR_PLAYER },
761 { CON_XORVAR, CON_XORVAR_PLAYER },
762 #endif
763 };
764
765 static const vec2_t actorvartable[] =
766 {
767 { CON_SETVAR, CON_SETVAR_ACTOR },
768 #ifdef CON_DISCRETE_VAR_ACCESS
769 { CON_IFVARA, CON_IFVARA_ACTOR },
770 { CON_IFVARAE, CON_IFVARAE_ACTOR },
771 { CON_IFVARAND, CON_IFVARAND_ACTOR },
772 { CON_IFVARB, CON_IFVARB_ACTOR },
773 { CON_IFVARBE, CON_IFVARBE_ACTOR },
774 { CON_IFVARBOTH, CON_IFVARBOTH_ACTOR },
775 { CON_IFVARE, CON_IFVARE_ACTOR },
776 { CON_IFVAREITHER, CON_IFVAREITHER_ACTOR },
777 { CON_IFVARG, CON_IFVARG_ACTOR },
778 { CON_IFVARGE, CON_IFVARGE_ACTOR },
779 { CON_IFVARL, CON_IFVARL_ACTOR },
780 { CON_IFVARLE, CON_IFVARLE_ACTOR },
781 { CON_IFVARN, CON_IFVARN_ACTOR },
782 { CON_IFVAROR, CON_IFVAROR_ACTOR },
783 { CON_IFVARXOR, CON_IFVARXOR_ACTOR },
784 { CON_WHILEVARL, CON_WHILEVARL_ACTOR },
785 { CON_WHILEVARN, CON_WHILEVARN_ACTOR },
786
787 { CON_ADDVAR, CON_ADDVAR_ACTOR },
788 { CON_ANDVAR, CON_ANDVAR_ACTOR },
789 { CON_DIVVAR, CON_DIVVAR_ACTOR },
790 { CON_MODVAR, CON_MODVAR_ACTOR },
791 { CON_MULVAR, CON_MULVAR_ACTOR },
792 { CON_ORVAR, CON_ORVAR_ACTOR },
793 { CON_RANDVAR, CON_RANDVAR_ACTOR },
794 { CON_SHIFTVARL, CON_SHIFTVARL_ACTOR },
795 { CON_SHIFTVARR, CON_SHIFTVARR_ACTOR },
796 { CON_SUBVAR, CON_SUBVAR_ACTOR },
797 { CON_XORVAR, CON_XORVAR_ACTOR },
798 #endif
799 };
800
801 static inthashtable_t h_varvar = { NULL, INTHASH_SIZE(ARRAY_SIZE(varvartable)) };
802 static inthashtable_t h_globalvar = { NULL, INTHASH_SIZE(ARRAY_SIZE(globalvartable)) };
803 static inthashtable_t h_playervar = { NULL, INTHASH_SIZE(ARRAY_SIZE(playervartable)) };
804 static inthashtable_t h_actorvar = { NULL, INTHASH_SIZE(ARRAY_SIZE(actorvartable)) };
805
806 static inthashtable_t *const inttables[] = {
807 &h_varvar,
808 &h_globalvar,
809 &h_playervar,
810 &h_actorvar,
811 };
812
813
814 const tokenmap_t iter_tokens [] =
815 {
816 { "allsprites", ITER_ALLSPRITES },
817 { "allspritesbystat", ITER_ALLSPRITESBYSTAT },
818 { "allspritesbysect", ITER_ALLSPRITESBYSECT },
819 { "allsectors", ITER_ALLSECTORS },
820 { "allwalls", ITER_ALLWALLS },
821 { "activelights", ITER_ACTIVELIGHTS },
822 { "drawnsprites", ITER_DRAWNSPRITES },
823 { "spritesofsector", ITER_SPRITESOFSECTOR },
824 { "spritesofstatus", ITER_SPRITESOFSTATUS },
825 { "loopofwall", ITER_LOOPOFWALL },
826 { "wallsofsector", ITER_WALLSOFSECTOR },
827 { "range", ITER_RANGE },
828 // vvv alternatives go here vvv
829 { "lights", ITER_ACTIVELIGHTS },
830 { "sprofsec", ITER_SPRITESOFSECTOR },
831 { "sprofstat", ITER_SPRITESOFSTATUS },
832 { "walofsec", ITER_WALLSOFSECTOR },
833 };
834
835 // some keywords generate different opcodes depending on the context the keyword is used in
836 // keywords_for_private_opcodes[] resolves those opcodes to the publicly facing keyword that can generate them
837 static const tokenmap_t keywords_for_private_opcodes[] =
838 {
839 { "getactor", CON_GETSPRITEEXT },
840 { "getactor", CON_GETACTORSTRUCT },
841 { "getactor", CON_GETSPRITESTRUCT },
842
843 { "setactor", CON_SETSPRITEEXT },
844 { "setactor", CON_SETACTORSTRUCT },
845 { "setactor", CON_SETSPRITESTRUCT },
846
847 { "getwall", CON_GETWALLSTRUCT },
848 { "setwall", CON_SETWALLSTRUCT },
849
850 { "getsector", CON_GETSECTORSTRUCT },
851 { "setsector", CON_SETSECTORSTRUCT },
852
853 { "getplayer", CON_GETPLAYERSTRUCT },
854 { "setplayer", CON_SETPLAYERSTRUCT },
855 };
856
VM_GetKeywordForID(int32_t id)857 char const *VM_GetKeywordForID(int32_t id)
858 {
859 // could be better, but this is used strictly for diagnostic warning and error messages
860 for (tokenmap_t const & keyword : vm_keywords)
861 if (keyword.val == id)
862 return keyword.token;
863
864 for (tokenmap_t const & keyword : keywords_for_private_opcodes)
865 if (keyword.val == id)
866 return keyword.token;
867
868 return "<unknown instruction>";
869 }
870
871 // KEEPINSYNC with enum GameEvent_t
872 const char *EventNames[MAXEVENTS] =
873 {
874 "EVENT_INIT",
875 "EVENT_ENTERLEVEL",
876 "EVENT_RESETWEAPONS",
877 "EVENT_RESETINVENTORY",
878 "EVENT_HOLSTER",
879 "EVENT_LOOKLEFT",
880 "EVENT_LOOKRIGHT",
881 "EVENT_SOARUP",
882 "EVENT_SOARDOWN",
883 "EVENT_CROUCH",
884 "EVENT_JUMP",
885 "EVENT_RETURNTOCENTER",
886 "EVENT_LOOKUP",
887 "EVENT_LOOKDOWN",
888 "EVENT_AIMUP",
889 "EVENT_FIRE",
890 "EVENT_CHANGEWEAPON",
891 "EVENT_GETSHOTRANGE",
892 "EVENT_GETAUTOAIMANGLE",
893 "EVENT_GETLOADTILE",
894 "EVENT_CHEATGETSTEROIDS",
895 "EVENT_CHEATGETHEAT",
896 "EVENT_CHEATGETBOOT",
897 "EVENT_CHEATGETSHIELD",
898 "EVENT_CHEATGETSCUBA",
899 "EVENT_CHEATGETHOLODUKE",
900 "EVENT_CHEATGETJETPACK",
901 "EVENT_CHEATGETFIRSTAID",
902 "EVENT_QUICKKICK",
903 "EVENT_INVENTORY",
904 "EVENT_USENIGHTVISION",
905 "EVENT_USESTEROIDS",
906 "EVENT_INVENTORYLEFT",
907 "EVENT_INVENTORYRIGHT",
908 "EVENT_HOLODUKEON",
909 "EVENT_HOLODUKEOFF",
910 "EVENT_USEMEDKIT",
911 "EVENT_USEJETPACK",
912 "EVENT_TURNAROUND",
913 "EVENT_DISPLAYWEAPON",
914 "EVENT_FIREWEAPON",
915 "EVENT_SELECTWEAPON",
916 "EVENT_MOVEFORWARD",
917 "EVENT_MOVEBACKWARD",
918 "EVENT_TURNLEFT",
919 "EVENT_TURNRIGHT",
920 "EVENT_STRAFELEFT",
921 "EVENT_STRAFERIGHT",
922 "EVENT_WEAPKEY1",
923 "EVENT_WEAPKEY2",
924 "EVENT_WEAPKEY3",
925 "EVENT_WEAPKEY4",
926 "EVENT_WEAPKEY5",
927 "EVENT_WEAPKEY6",
928 "EVENT_WEAPKEY7",
929 "EVENT_WEAPKEY8",
930 "EVENT_WEAPKEY9",
931 "EVENT_WEAPKEY10",
932 "EVENT_DRAWWEAPON",
933 "EVENT_DISPLAYCROSSHAIR",
934 "EVENT_DISPLAYREST",
935 "EVENT_DISPLAYSBAR",
936 "EVENT_RESETPLAYER",
937 "EVENT_INCURDAMAGE",
938 "EVENT_AIMDOWN",
939 "EVENT_GAME",
940 "EVENT_PREVIOUSWEAPON",
941 "EVENT_NEXTWEAPON",
942 "EVENT_SWIMUP",
943 "EVENT_SWIMDOWN",
944 "EVENT_GETMENUTILE",
945 "EVENT_SPAWN",
946 "EVENT_LOGO",
947 "EVENT_EGS",
948 "EVENT_DOFIRE",
949 "EVENT_PRESSEDFIRE",
950 "EVENT_USE",
951 "EVENT_PROCESSINPUT",
952 "EVENT_FAKEDOMOVETHINGS",
953 "EVENT_DISPLAYROOMS",
954 "EVENT_KILLIT",
955 "EVENT_LOADACTOR",
956 "EVENT_DISPLAYBONUSSCREEN",
957 "EVENT_DISPLAYMENU",
958 "EVENT_DISPLAYMENUREST",
959 "EVENT_DISPLAYLOADINGSCREEN",
960 "EVENT_ANIMATESPRITES",
961 "EVENT_NEWGAME",
962 "EVENT_SOUND",
963 "EVENT_CHECKTOUCHDAMAGE",
964 "EVENT_CHECKFLOORDAMAGE",
965 "EVENT_LOADGAME",
966 "EVENT_SAVEGAME",
967 "EVENT_PREGAME",
968 "EVENT_CHANGEMENU",
969 "EVENT_DAMAGEHPLANE",
970 "EVENT_ACTIVATECHEAT",
971 "EVENT_DISPLAYINACTIVEMENU",
972 "EVENT_DISPLAYINACTIVEMENUREST",
973 "EVENT_CUTSCENE",
974 "EVENT_DISPLAYCURSOR",
975 "EVENT_DISPLAYLEVELSTATS",
976 "EVENT_DISPLAYCAMERAOSD",
977 "EVENT_DISPLAYROOMSCAMERA",
978 "EVENT_DISPLAYSTART",
979 "EVENT_WORLD",
980 "EVENT_PREWORLD",
981 "EVENT_PRELEVEL",
982 "EVENT_DISPLAYSPIT",
983 "EVENT_DISPLAYFIST",
984 "EVENT_DISPLAYKNEE",
985 "EVENT_DISPLAYKNUCKLES",
986 "EVENT_DISPLAYSCUBA",
987 "EVENT_DISPLAYTIP",
988 "EVENT_DISPLAYACCESS",
989 "EVENT_MOVESECTOR",
990 "EVENT_MOVEEFFECTORS",
991 "EVENT_DISPLAYOVERHEADMAPTEXT",
992 "EVENT_PRELOADGAME",
993 "EVENT_POSTSAVEGAME",
994 "EVENT_PRECUTSCENE",
995 "EVENT_SKIPCUTSCENE",
996 "EVENT_SCREEN",
997 "EVENT_DISPLAYROOMSEND",
998 "EVENT_DISPLAYEND",
999 "EVENT_OPENMENUSOUND",
1000 "EVENT_RECOGSOUND",
1001 "EVENT_UPDATESCREENAREA",
1002 "EVENT_DISPLAYBORDER",
1003 "EVENT_SETDEFAULTS",
1004 "EVENT_MAINMENUSCREEN",
1005 "EVENT_NEWGAMESCREEN",
1006 "EVENT_ENDLEVELSCREEN",
1007 "EVENT_EXITGAMESCREEN",
1008 "EVENT_EXITPROGRAMSCREEN",
1009 "EVENT_ALTFIRE",
1010 "EVENT_ALTWEAPON",
1011 "EVENT_DISPLAYOVERHEADMAPPLAYER",
1012 "EVENT_MENUCURSORLEFT",
1013 "EVENT_MENUCURSORRIGHT",
1014 "EVENT_MENUCURSORSHADE",
1015 "EVENT_MENUSHADESELECTED",
1016 "EVENT_PLAYLEVELMUSICSLOT",
1017 "EVENT_CONTINUELEVELMUSICSLOT",
1018 "EVENT_DISPLAYPOINTER",
1019 "EVENT_LASTWEAPON",
1020 "EVENT_DAMAGESPRITE",
1021 "EVENT_POSTDAMAGESPRITE",
1022 "EVENT_DAMAGEWALL",
1023 "EVENT_DAMAGEFLOOR",
1024 "EVENT_DAMAGECEILING",
1025 "EVENT_DISPLAYROOMSCAMERATILE",
1026 "EVENT_RESETGOTPICS",
1027 "EVENT_VALIDATESTART",
1028 "EVENT_NEWGAMECUSTOM",
1029 "EVENT_INITCOMPLETE",
1030 "EVENT_CAPIR",
1031 };
1032
1033 uint8_t *bitptr; // pointer to bitmap of which bytecode positions contain pointers
1034
1035 #define BITPTR_SET(x) bitmap_set(bitptr, x)
1036 #define BITPTR_CLEAR(x) bitmap_clear(bitptr, x)
1037 #define BITPTR_IS_POINTER(x) bitmap_test(bitptr, x)
1038
1039 hashtable_t h_arrays = { MAXGAMEARRAYS >> 1, NULL };
1040 hashtable_t h_gamevars = { MAXGAMEVARS >> 1, NULL };
1041 hashtable_t h_labels = { MAXLABELS >> 1, NULL };
1042
C_SetScriptSize(int32_t newsize)1043 static void C_SetScriptSize(int32_t newsize)
1044 {
1045 for (int i = 0; i < g_scriptSize - 1; ++i)
1046 {
1047 if (BITPTR_IS_POINTER(i))
1048 {
1049 if (EDUKE32_PREDICT_FALSE(apScript[i] < (intptr_t)apScript || apScript[i] > (intptr_t)g_scriptPtr))
1050 {
1051 g_errorCnt++;
1052 buildprint("Internal compiler error at ", i, " (0x", hex(i), ")\n");
1053 VM_ScriptInfo(&apScript[i], 16);
1054 }
1055 else
1056 apScript[i] -= (intptr_t)apScript;
1057 }
1058 }
1059
1060 G_Util_PtrToIdx2(&g_tile[0].execPtr, MAXTILES, sizeof(tiledata_t), apScript, P2I_FWD_NON0);
1061 G_Util_PtrToIdx2(&g_tile[0].loadPtr, MAXTILES, sizeof(tiledata_t), apScript, P2I_FWD_NON0);
1062
1063 size_t old_bitptr_size = (((g_scriptSize + 7) >> 3) + 1) * sizeof(uint8_t);
1064 size_t new_bitptr_size = (((newsize + 7) >> 3) + 1) * sizeof(uint8_t);
1065
1066 auto newscript = (intptr_t *)Xrealloc(apScript, newsize * sizeof(intptr_t));
1067 bitptr = (uint8_t *)Xrealloc(bitptr, new_bitptr_size);
1068
1069 if (newsize > g_scriptSize)
1070 {
1071 Bmemset(&newscript[g_scriptSize], 0, (newsize - g_scriptSize) * sizeof(intptr_t));
1072 Bmemset(&bitptr[old_bitptr_size], 0, new_bitptr_size - old_bitptr_size);
1073 }
1074
1075 if (apScript != newscript)
1076 {
1077 buildprint("Relocated compiled code from 0x", hex((intptr_t)apScript), " to 0x", hex((intptr_t)newscript), "\n");
1078 g_scriptPtr = g_scriptPtr - apScript + newscript;
1079 apScript = newscript;
1080 }
1081
1082 int const smallestSize = min(g_scriptSize, newsize);
1083
1084 for (int i = 0; i < smallestSize - 1; ++i)
1085 {
1086 if (BITPTR_IS_POINTER(i))
1087 apScript[i] += (intptr_t)apScript;
1088 }
1089
1090 g_scriptSize = newsize;
1091
1092 G_Util_PtrToIdx2(&g_tile[0].execPtr, MAXTILES, sizeof(tiledata_t), apScript, P2I_BACK_NON0);
1093 G_Util_PtrToIdx2(&g_tile[0].loadPtr, MAXTILES, sizeof(tiledata_t), apScript, P2I_BACK_NON0);
1094 }
1095
ispecial(const char c)1096 static inline bool ispecial(const char c)
1097 {
1098 return (c == ' ' || c == 0x0d || c == '(' || c == ')' ||
1099 c == ',' || c == ';' || (c == 0x0a /*&& ++g_lineNumber*/));
1100 }
1101
scriptSkipLine(void)1102 static inline void scriptSkipLine(void)
1103 {
1104 while (*textptr != 0x0a && *textptr != 0x0d && *textptr != 0)
1105 textptr++;
1106 }
1107
scriptSkipSpaces(void)1108 static inline void scriptSkipSpaces(void)
1109 {
1110 while (*textptr == ' ' || *textptr == '\t')
1111 textptr++;
1112 }
1113
C_SkipComments(void)1114 static void C_SkipComments(void)
1115 {
1116 do
1117 {
1118 switch (*textptr)
1119 {
1120 case '\n':
1121 g_lineNumber++;
1122 fallthrough__;
1123 case ' ':
1124 case '\t':
1125 case '\r':
1126 case 0x1a:
1127 textptr++;
1128 break;
1129 case '/':
1130 switch (textptr[1])
1131 {
1132 case '/': // C++ style comment
1133 if (g_scriptDebug > 1 && !g_errorCnt && !g_warningCnt)
1134 initprintf("%s:%d: debug: got comment.\n",g_scriptFileName,g_lineNumber);
1135 scriptSkipLine();
1136 continue;
1137 case '*': // beginning of a C style comment
1138 if (g_scriptDebug > 1 && !g_errorCnt && !g_warningCnt)
1139 initprintf("%s:%d: debug: got start of comment block.\n",g_scriptFileName,g_lineNumber);
1140 do
1141 {
1142 if (*textptr == '\n')
1143 g_lineNumber++;
1144 textptr++;
1145 }
1146 while (*textptr && (textptr[0] != '*' || textptr[1] != '/'));
1147
1148 if (EDUKE32_PREDICT_FALSE(!*textptr))
1149 {
1150 if (!(g_errorCnt || g_warningCnt) && g_scriptDebug)
1151 initprintf("%s:%d: debug: EOF in comment!\n",g_scriptFileName,g_lineNumber);
1152 C_ReportError(-1);
1153 initprintf("%s:%d: error: found `/*' with no `*/'.\n",g_scriptFileName,g_lineNumber);
1154 g_scriptActorOffset = g_numBraces = g_processingState = 0;
1155 g_errorCnt++;
1156 continue;
1157 }
1158
1159 if (g_scriptDebug > 1 && !g_errorCnt && !g_warningCnt)
1160 initprintf("%s:%d: debug: got end of comment block.\n",g_scriptFileName,g_lineNumber);
1161
1162 textptr+=2;
1163 continue;
1164 default:
1165 C_ReportError(-1);
1166 initprintf("%s:%d: error: malformed comment.\n", g_scriptFileName, g_lineNumber);
1167 scriptSkipLine();
1168 g_errorCnt++;
1169 continue;
1170 }
1171 break;
1172
1173 default:
1174 if (ispecial(*textptr))
1175 {
1176 textptr++;
1177 continue;
1178 }
1179 fallthrough__;
1180 case 0: // EOF
1181 return;
1182 }
1183 }
1184 while (1);
1185 }
1186
GetDefID(char const * label)1187 static inline int GetDefID(char const *label) { return hash_find(&h_gamevars, label); }
GetADefID(char const * label)1188 static inline int GetADefID(char const *label) { return hash_find(&h_arrays, label); }
1189
1190 #define LAST_LABEL (label+(g_labelCnt<<6))
isaltok(const char c)1191 static inline bool isaltok(const char c)
1192 {
1193 return (isalnum(c) || c == '{' || c == '}' || c == '/' || c == '\\' || c == '*' || c == '-' || c == '_' ||
1194 c == '.');
1195 }
1196
C_IsLabelChar(const char c,int32_t const i)1197 static inline bool C_IsLabelChar(const char c, int32_t const i)
1198 {
1199 return (isalnum(c) || c == '_' || c == '*' || c == '?' || (i > 0 && (c == '+' || c == '-')));
1200 }
1201
C_GetLabelNameID(memberlabel_t const * pLabel,hashtable_t const * const table,const char * psz)1202 static inline int32_t C_GetLabelNameID(memberlabel_t const *pLabel, hashtable_t const * const table, const char *psz)
1203 {
1204 // find the label psz in the table pLabel.
1205 // returns the ID for the label, or -1
1206
1207 int const l = hash_findcase(table, psz);
1208 return (l >= 0) ? pLabel[l].lId : -1;
1209 }
1210
C_GetLabelNameOffset(hashtable_t const * const table,const char * psz)1211 static inline int32_t C_GetLabelNameOffset(hashtable_t const * const table, const char *psz)
1212 {
1213 // find the label psz in the table pLabel.
1214 // returns the offset in the array for the label, or -1
1215
1216 return hash_findcase(table, psz);
1217 }
1218
C_GetNextLabelName(void)1219 static void C_GetNextLabelName(void)
1220 {
1221 int32_t i = 0;
1222
1223 if (EDUKE32_PREDICT_FALSE(g_labelCnt >= MAXLABELS))
1224 {
1225 g_errorCnt++;
1226 C_ReportError(ERROR_TOOMANYLABELS);
1227 G_GameExit("Error: too many labels defined!");
1228 return;
1229 }
1230
1231 C_SkipComments();
1232
1233 // while (ispecial(*textptr) == 0 && *textptr!='['&& *textptr!=']' && *textptr!='\t' && *textptr!='\n' && *textptr!='\r')
1234 while (C_IsLabelChar(*textptr, i))
1235 {
1236 if (i < (1<<6)-1)
1237 label[(g_labelCnt<<6) + (i++)] = *textptr;
1238 textptr++;
1239 }
1240
1241 label[(g_labelCnt<<6)+i] = 0;
1242
1243 if (!(g_errorCnt|g_warningCnt) && g_scriptDebug > 1)
1244 initprintf("%s:%d: debug: label `%s'.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
1245 }
1246
scriptWriteValue(int32_t const value)1247 static inline void scriptWriteValue(int32_t const value)
1248 {
1249 BITPTR_CLEAR(g_scriptPtr-apScript);
1250 *g_scriptPtr++ = value;
1251 }
1252
1253 // addresses passed to these functions must be within the block of memory pointed to by apScript
scriptWriteAtOffset(int32_t const value,intptr_t * const addr)1254 static inline void scriptWriteAtOffset(int32_t const value, intptr_t * const addr)
1255 {
1256 BITPTR_CLEAR(addr-apScript);
1257 *(addr) = value;
1258 }
1259
scriptWritePointer(intptr_t const value,intptr_t * const addr)1260 static inline void scriptWritePointer(intptr_t const value, intptr_t * const addr)
1261 {
1262 BITPTR_SET(addr-apScript);
1263 *(addr) = value;
1264 }
1265
C_GetNextGameArrayName(void)1266 static int32_t C_GetNextGameArrayName(void)
1267 {
1268 C_GetNextLabelName();
1269 int32_t const i = GetADefID(LAST_LABEL);
1270 if (EDUKE32_PREDICT_FALSE(i < 0))
1271 {
1272 g_errorCnt++;
1273 C_ReportError(ERROR_NOTAGAMEARRAY);
1274 return -1;
1275 }
1276
1277 scriptWriteValue(i);
1278 return i;
1279 }
1280
C_GetKeyword(void)1281 static int C_GetKeyword(void)
1282 {
1283 C_SkipComments();
1284
1285 char *temptextptr = textptr;
1286
1287 if (*temptextptr == 0) // EOF
1288 return -2;
1289
1290 while (isaltok(*temptextptr) == 0)
1291 {
1292 temptextptr++;
1293 if (*temptextptr == 0)
1294 return 0;
1295 }
1296
1297 int i = 0;
1298
1299 while (isaltok(*temptextptr))
1300 tempbuf[i++] = *(temptextptr++);
1301 tempbuf[i] = 0;
1302
1303 return hash_find(&h_keywords,tempbuf);
1304 }
1305
C_GetNextKeyword(void)1306 static int C_GetNextKeyword(void) //Returns its code #
1307 {
1308 C_SkipComments();
1309
1310 if (*textptr == 0) // EOF
1311 return -2;
1312
1313 int l = 0;
1314 while (isaltok(*(textptr+l)))
1315 {
1316 tempbuf[l] = textptr[l];
1317 l++;
1318 }
1319 tempbuf[l] = 0;
1320
1321 int i;
1322 if (EDUKE32_PREDICT_TRUE((i = hash_find(&h_keywords,tempbuf)) >= 0))
1323 {
1324 if (i == CON_LEFTBRACE || i == CON_RIGHTBRACE || i == CON_NULLOP)
1325 scriptWriteValue(i | (VM_IFELSE_MAGIC<<12));
1326 else scriptWriteValue(i | LINE_NUMBER);
1327
1328 textptr += l;
1329 if (!(g_errorCnt || g_warningCnt) && g_scriptDebug)
1330 initprintf("%s:%d: debug: keyword `%s'.\n", g_scriptFileName, g_lineNumber, tempbuf);
1331 return i;
1332 }
1333
1334 textptr += l;
1335 g_errorCnt++;
1336
1337 if (EDUKE32_PREDICT_FALSE((tempbuf[0] == '{' || tempbuf[0] == '}') && tempbuf[1] != 0))
1338 {
1339 C_ReportError(-1);
1340 initprintf("%s:%d: error: expected whitespace between `%c' and `%s'.\n",g_scriptFileName,g_lineNumber,tempbuf[0],tempbuf+1);
1341 }
1342 else C_ReportError(ERROR_EXPECTEDKEYWORD);
1343
1344 return -1;
1345 }
1346
parse_decimal_number(void)1347 static int32_t parse_decimal_number(void) // (textptr)
1348 {
1349 // decimal constants -- this is finicky business
1350 int64_t num = strtoll(textptr, NULL, 10); // assume long long to be int64_t
1351
1352 if (EDUKE32_PREDICT_TRUE(num >= INT32_MIN && num <= INT32_MAX))
1353 {
1354 // all OK
1355 }
1356 else if (EDUKE32_PREDICT_FALSE(num > INT32_MAX && num <= UINT32_MAX))
1357 {
1358 // Number interpreted as uint32, but packed as int32 (on 32-bit archs)
1359 // (CON code in the wild exists that does this). Note that such conversion
1360 // is implementation-defined (C99 6.3.1.3) but GCC does the 'expected' thing.
1361 #if 0
1362 initprintf("%s:%d: warning: number greater than INT32_MAX converted to a negative one.\n",
1363 g_szScriptFileName,g_lineNumber);
1364 g_numCompilerWarnings++;
1365 #endif
1366 }
1367 else
1368 {
1369 // out of range, this is arguably worse
1370
1371 initprintf("%s:%d: warning: number out of the range of a 32-bit integer encountered.\n",
1372 g_scriptFileName,g_lineNumber);
1373 g_warningCnt++;
1374 }
1375
1376 return (int32_t)num;
1377 }
1378
parse_hex_constant(const char * hexnum)1379 static int32_t parse_hex_constant(const char *hexnum)
1380 {
1381 uint64_t x;
1382 sscanf(hexnum, "%" PRIx64 "", &x);
1383
1384 if (EDUKE32_PREDICT_FALSE(x > UINT32_MAX))
1385 {
1386 initprintf(g_scriptFileName, ":", g_lineNumber, ": warning: number 0x", hex(x), " truncated to 32 bits.\n");
1387 g_warningCnt++;
1388 }
1389
1390 return x;
1391 }
1392
C_GetNextVarType(int32_t type)1393 static void C_GetNextVarType(int32_t type)
1394 {
1395 int32_t id = 0;
1396 int32_t flags = 0;
1397
1398 auto varptr = g_scriptPtr;
1399
1400 C_SkipComments();
1401
1402 if (!type && !g_labelsOnly && (isdigit(*textptr) || ((*textptr == '-') && (isdigit(*(textptr+1))))))
1403 {
1404 scriptWriteValue(GV_FLAG_CONSTANT);
1405
1406 if (tolower(textptr[1])=='x') // hex constants
1407 scriptWriteValue(parse_hex_constant(textptr+2));
1408 else
1409 scriptWriteValue(parse_decimal_number());
1410
1411 if (!(g_errorCnt || g_warningCnt) && g_scriptDebug)
1412 initprintf("%s:%d: debug: constant %ld in place of gamevar.\n", g_scriptFileName, g_lineNumber, (long)(g_scriptPtr[-1]));
1413 #if 1
1414 while (!ispecial(*textptr) && *textptr != ']') textptr++;
1415 #else
1416 C_GetNextLabelName();
1417 #endif
1418 return;
1419 }
1420 else if (*textptr == '-'/* && !isdigit(*(textptr+1))*/)
1421 {
1422 if (EDUKE32_PREDICT_FALSE(type))
1423 {
1424 g_errorCnt++;
1425 C_ReportError(ERROR_SYNTAXERROR);
1426 C_GetNextLabelName();
1427 return;
1428 }
1429
1430 if (!(g_errorCnt || g_warningCnt) && g_scriptDebug)
1431 initprintf("%s:%d: debug: flagging gamevar as negative.\n", g_scriptFileName, g_lineNumber); //,Batol(textptr));
1432
1433 flags = GV_FLAG_NEGATIVE;
1434 textptr++;
1435 }
1436
1437 C_GetNextLabelName();
1438
1439 if (EDUKE32_PREDICT_FALSE(hash_find(&h_keywords,LAST_LABEL)>=0))
1440 {
1441 g_errorCnt++;
1442 C_ReportError(ERROR_ISAKEYWORD);
1443 return;
1444 }
1445
1446 C_SkipComments();
1447
1448 if (*textptr == '[' || *textptr == '.') //read of array as a gamevar
1449 {
1450 flags |= GV_FLAG_ARRAY;
1451 if (*textptr != '.') textptr++;
1452 id=GetADefID(LAST_LABEL);
1453
1454 if (id < 0)
1455 {
1456 id=GetDefID(LAST_LABEL);
1457 if ((unsigned) (id - g_structVarIDs) >= NUMQUICKSTRUCTS)
1458 id = -1;
1459
1460 if (EDUKE32_PREDICT_FALSE(id < 0))
1461 {
1462 g_errorCnt++;
1463 C_ReportError(ERROR_NOTAGAMEARRAY);
1464 return;
1465 }
1466
1467 flags &= ~GV_FLAG_ARRAY; // not an array
1468 flags |= GV_FLAG_STRUCT;
1469 }
1470
1471 scriptWriteValue(id|flags);
1472
1473 if ((flags & GV_FLAG_STRUCT) && id - g_structVarIDs == STRUCT_USERDEF)
1474 {
1475 // userdef doesn't really have an array index
1476 while (*textptr != '.')
1477 {
1478 if (*textptr == 0xa || *textptr == 0)
1479 break;
1480
1481 textptr++;
1482 }
1483
1484 scriptWriteValue(0); // help out the VM by inserting a dummy index
1485 }
1486 else
1487 {
1488 // allow "[]" or "." but not "[."
1489 if (*textptr == ']' || (*textptr == '.' && textptr[-1] != '['))
1490 {
1491 scriptWriteValue(g_thisActorVarID);
1492 }
1493 else
1494 C_GetNextVarType(0);
1495
1496 C_SkipComments();
1497 }
1498
1499 if (EDUKE32_PREDICT_FALSE(*textptr != ']' && *textptr != '.'))
1500 {
1501 g_errorCnt++;
1502 C_ReportError(ERROR_GAMEARRAYBNC);
1503 return;
1504 }
1505
1506 if (*textptr != '.') textptr++;
1507
1508 //writing arrays in this way is not supported because it would require too many changes to other code
1509
1510 if (EDUKE32_PREDICT_FALSE(type))
1511 {
1512 g_errorCnt++;
1513 C_ReportError(ERROR_INVALIDARRAYWRITE);
1514 return;
1515 }
1516
1517 if (flags & GV_FLAG_STRUCT)
1518 {
1519 while (*textptr != '.')
1520 {
1521 if (*textptr == 0xa || !*textptr)
1522 break;
1523
1524 textptr++;
1525 }
1526
1527 if (EDUKE32_PREDICT_FALSE(*textptr != '.'))
1528 {
1529 g_errorCnt++;
1530 C_ReportError(ERROR_SYNTAXERROR);
1531 return;
1532 }
1533 textptr++;
1534 /// now pointing at 'xxx'
1535 C_GetNextLabelName();
1536 /*initprintf("found xxx label of \"%s\"\n", label+(g_numLabels<<6));*/
1537
1538 int32_t labelNum = -1;
1539
1540 switch (id - g_structVarIDs)
1541 {
1542 case STRUCT_SPRITE: labelNum = C_GetLabelNameOffset(&h_actor, Bstrtolower(LAST_LABEL)); break;
1543 case STRUCT_SECTOR: labelNum = C_GetLabelNameOffset(&h_sector, Bstrtolower(LAST_LABEL)); break;
1544 case STRUCT_WALL: labelNum = C_GetLabelNameOffset(&h_wall, Bstrtolower(LAST_LABEL)); break;
1545 case STRUCT_PLAYER: labelNum = C_GetLabelNameOffset(&h_player, Bstrtolower(LAST_LABEL)); break;
1546 case STRUCT_TSPR: labelNum = C_GetLabelNameOffset(&h_tsprite, Bstrtolower(LAST_LABEL)); break;
1547 case STRUCT_PROJECTILE:
1548 case STRUCT_THISPROJECTILE: labelNum = C_GetLabelNameOffset(&h_projectile, Bstrtolower(LAST_LABEL)); break;
1549 case STRUCT_USERDEF: labelNum = C_GetLabelNameOffset(&h_userdef, Bstrtolower(LAST_LABEL)); break;
1550 case STRUCT_INPUT: labelNum = C_GetLabelNameOffset(&h_input, Bstrtolower(LAST_LABEL)); break;
1551 case STRUCT_TILEDATA: labelNum = C_GetLabelNameOffset(&h_tiledata, Bstrtolower(LAST_LABEL)); break;
1552 case STRUCT_PALDATA: labelNum = C_GetLabelNameOffset(&h_paldata, Bstrtolower(LAST_LABEL)); break;
1553
1554 case STRUCT_ACTORVAR:
1555 case STRUCT_PLAYERVAR: labelNum = GetDefID(LAST_LABEL); break;
1556 }
1557
1558 if (labelNum == -1)
1559 {
1560 g_errorCnt++;
1561 C_ReportError(ERROR_NOTAMEMBER);
1562 return;
1563 }
1564
1565 switch (id - g_structVarIDs)
1566 {
1567 case STRUCT_SPRITE:
1568 {
1569 auto const &label = ActorLabels[labelNum];
1570
1571 scriptWriteValue(label.lId);
1572
1573 Bassert((*varptr & (MAXGAMEVARS-1)) == g_structVarIDs + STRUCT_SPRITE);
1574
1575 if (label.flags & LABEL_HASPARM2)
1576 C_GetNextVarType(0);
1577 else if (label.offset != -1 && (label.flags & LABEL_READFUNC) == 0)
1578 {
1579 if (labelNum >= ACTOR_SPRITEEXT_BEGIN)
1580 *varptr = (*varptr & ~(MAXGAMEVARS-1)) + g_structVarIDs + STRUCT_SPRITEEXT_INTERNAL__;
1581 else if (labelNum >= ACTOR_STRUCT_BEGIN)
1582 *varptr = (*varptr & ~(MAXGAMEVARS-1)) + g_structVarIDs + STRUCT_ACTOR_INTERNAL__;
1583 else
1584 *varptr = (*varptr & ~(MAXGAMEVARS-1)) + g_structVarIDs + STRUCT_SPRITE_INTERNAL__;
1585 }
1586 }
1587
1588 break;
1589 case STRUCT_SECTOR:
1590 {
1591 auto const &label = SectorLabels[labelNum];
1592
1593 scriptWriteValue(label.lId);
1594
1595 Bassert((*varptr & (MAXGAMEVARS-1)) == g_structVarIDs + STRUCT_SECTOR);
1596
1597 if (label.offset != -1 && (label.flags & LABEL_READFUNC) == 0)
1598 *varptr = (*varptr & ~(MAXGAMEVARS-1)) + g_structVarIDs + STRUCT_SECTOR_INTERNAL__;
1599 }
1600 break;
1601 case STRUCT_WALL:
1602 {
1603 auto const &label = WallLabels[labelNum];
1604
1605 scriptWriteValue(label.lId);
1606
1607 Bassert((*varptr & (MAXGAMEVARS-1)) == g_structVarIDs + STRUCT_WALL);
1608
1609 if (label.offset != -1 && (label.flags & LABEL_READFUNC) == 0)
1610 *varptr = (*varptr & ~(MAXGAMEVARS-1)) + g_structVarIDs + STRUCT_WALL_INTERNAL__;
1611 }
1612 break;
1613 case STRUCT_PLAYER:
1614 {
1615 auto const &label = PlayerLabels[labelNum];
1616
1617 scriptWriteValue(label.lId);
1618
1619 Bassert((*varptr & (MAXGAMEVARS-1)) == g_structVarIDs + STRUCT_PLAYER);
1620
1621 if (label.flags & LABEL_HASPARM2)
1622 C_GetNextVarType(0);
1623 else if (label.offset != -1 && (label.flags & LABEL_READFUNC) == 0)
1624 *varptr = (*varptr & ~(MAXGAMEVARS-1)) + g_structVarIDs + STRUCT_PLAYER_INTERNAL__;
1625 }
1626 break;
1627 case STRUCT_ACTORVAR:
1628 case STRUCT_PLAYERVAR:
1629 scriptWriteValue(labelNum);
1630 break;
1631 case STRUCT_TSPR:
1632 scriptWriteValue(TsprLabels[labelNum].lId);
1633 break;
1634 case STRUCT_PROJECTILE:
1635 case STRUCT_THISPROJECTILE:
1636 scriptWriteValue(ProjectileLabels[labelNum].lId);
1637 break;
1638 case STRUCT_USERDEF:
1639 scriptWriteValue(UserdefsLabels[labelNum].lId);
1640
1641 if (UserdefsLabels[labelNum].flags & LABEL_HASPARM2)
1642 C_GetNextVarType(0);
1643 break;
1644 case STRUCT_INPUT:
1645 scriptWriteValue(InputLabels[labelNum].lId);
1646 break;
1647 case STRUCT_TILEDATA:
1648 scriptWriteValue(TileDataLabels[labelNum].lId);
1649 break;
1650 case STRUCT_PALDATA:
1651 scriptWriteValue(PalDataLabels[labelNum].lId);
1652 break;
1653 }
1654 }
1655 return;
1656 }
1657
1658 id=GetDefID(LAST_LABEL);
1659 if (id<0) //gamevar not found
1660 {
1661 if (EDUKE32_PREDICT_TRUE(!type && !g_labelsOnly))
1662 {
1663 //try looking for a define instead
1664 Bstrcpy(tempbuf,LAST_LABEL);
1665 id = hash_find(&h_labels,tempbuf);
1666
1667 if (EDUKE32_PREDICT_TRUE(id>=0 && labeltype[id] & LABEL_DEFINE))
1668 {
1669 if (!(g_errorCnt || g_warningCnt) && g_scriptDebug)
1670 initprintf("%s:%d: debug: label `%s' in place of gamevar.\n",g_scriptFileName,g_lineNumber,label+(id<<6));
1671
1672 scriptWriteValue(GV_FLAG_CONSTANT);
1673 scriptWriteValue(labelcode[id]);
1674 return;
1675 }
1676 }
1677
1678 g_errorCnt++;
1679 C_ReportError(ERROR_NOTAGAMEVAR);
1680 return;
1681 }
1682
1683 if (EDUKE32_PREDICT_FALSE(type == GAMEVAR_READONLY && aGameVars[id].flags & GAMEVAR_READONLY))
1684 {
1685 g_errorCnt++;
1686 C_ReportError(ERROR_VARREADONLY);
1687 return;
1688 }
1689 else if (EDUKE32_PREDICT_FALSE(aGameVars[id].flags & type))
1690 {
1691 g_errorCnt++;
1692 C_ReportError(ERROR_VARTYPEMISMATCH);
1693 return;
1694 }
1695
1696 if (g_scriptDebug > 1 && !g_errorCnt && !g_warningCnt)
1697 initprintf("%s:%d: debug: gamevar `%s'.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
1698
1699 scriptWriteValue(id|flags);
1700 }
1701
1702 #define C_GetNextVar() C_GetNextVarType(0)
1703
C_GetManyVarsType(int32_t type,int num)1704 static FORCE_INLINE void C_GetManyVarsType(int32_t type, int num)
1705 {
1706 for (; num>0; --num)
1707 C_GetNextVarType(type);
1708 }
1709
1710 #define C_GetManyVars(num) C_GetManyVarsType(0,num)
1711
1712 // returns:
1713 // -1 on EOF or wrong type or error
1714 // 0 if literal value
1715 // LABEL_* (>0) if that type and matched
1716 //
1717 // *g_scriptPtr will contain the value OR 0 if wrong type or error
C_GetNextValue(int32_t type)1718 static int32_t C_GetNextValue(int32_t type)
1719 {
1720 C_SkipComments();
1721
1722 if (*textptr == 0) // EOF
1723 return -1;
1724
1725 int32_t l = 0;
1726
1727 while (isaltok(*(textptr+l)))
1728 {
1729 tempbuf[l] = textptr[l];
1730 l++;
1731 }
1732 tempbuf[l] = 0;
1733
1734 if (EDUKE32_PREDICT_FALSE(hash_find(&h_keywords,tempbuf /*label+(g_numLabels<<6)*/)>=0))
1735 {
1736 g_errorCnt++;
1737 C_ReportError(ERROR_ISAKEYWORD);
1738 textptr+=l;
1739 }
1740
1741 int32_t i = hash_find(&h_labels,tempbuf);
1742
1743 if (i>=0)
1744 {
1745 if (EDUKE32_PREDICT_TRUE(labeltype[i] & type))
1746 {
1747 if (g_scriptDebug > 1 && !g_errorCnt && !g_warningCnt)
1748 {
1749 char *gl = C_GetLabelType(labeltype[i]);
1750 initprintf("%s:%d: debug: %s label `%s'.\n",g_scriptFileName,g_lineNumber,gl,label+(i<<6));
1751 Xfree(gl);
1752 }
1753
1754 scriptWriteValue(labelcode[i]);
1755
1756 textptr += l;
1757 return labeltype[i];
1758 }
1759
1760 scriptWriteValue(0);
1761 textptr += l;
1762 char * const el = C_GetLabelType(type);
1763 char * const gl = C_GetLabelType(labeltype[i]);
1764 C_ReportError(-1);
1765 initprintf("%s:%d: warning: expected %s, found %s.\n",g_scriptFileName,g_lineNumber,el,gl);
1766 g_warningCnt++;
1767 Xfree(el);
1768 Xfree(gl);
1769 return -1; // valid label name, but wrong type
1770 }
1771
1772 if (EDUKE32_PREDICT_FALSE(isdigit(*textptr) == 0 && *textptr != '-'))
1773 {
1774 C_ReportError(ERROR_PARAMUNDEFINED);
1775 g_errorCnt++;
1776 scriptWriteValue(0);
1777 textptr+=l;
1778 if (!l) textptr++;
1779 return -1; // error!
1780 }
1781
1782 if (EDUKE32_PREDICT_FALSE(isdigit(*textptr) && g_labelsOnly))
1783 {
1784 C_ReportError(WARNING_LABELSONLY);
1785 g_warningCnt++;
1786 }
1787
1788 i = l-1;
1789 do
1790 {
1791 // FIXME: check for 0-9 A-F for hex
1792 if (textptr[0] == '0' && textptr[1] == 'x') break; // kill the warning for hex
1793 if (EDUKE32_PREDICT_FALSE(!isdigit(textptr[i--])))
1794 {
1795 C_ReportError(-1);
1796 initprintf("%s:%d: warning: invalid character `%c' in definition!\n",g_scriptFileName,g_lineNumber,textptr[i+1]);
1797 g_warningCnt++;
1798 break;
1799 }
1800 }
1801 while (i > 0);
1802
1803 if (textptr[0] == '0' && tolower(textptr[1])=='x')
1804 scriptWriteValue(parse_hex_constant(textptr+2));
1805 else
1806 scriptWriteValue(parse_decimal_number());
1807
1808 if (g_scriptDebug > 1 && !g_errorCnt && !g_warningCnt)
1809 initprintf("%s:%d: debug: constant %ld.\n", g_scriptFileName, g_lineNumber, (long)g_scriptPtr[-1]);
1810
1811 textptr += l;
1812
1813 return 0; // literal value
1814 }
1815
C_GetStructureIndexes(bool const labelsonly,hashtable_t const * const table)1816 static int C_GetStructureIndexes(bool const labelsonly, hashtable_t const * const table)
1817 {
1818 C_SkipComments();
1819
1820 if (EDUKE32_PREDICT_FALSE(*textptr != '[' && *textptr != '.'))
1821 {
1822 g_errorCnt++;
1823 C_ReportError(ERROR_SYNTAXERROR);
1824 return -1;
1825 }
1826
1827 if (*textptr != '.') textptr++;
1828
1829 C_SkipComments();
1830
1831 if (*textptr == ']' || *textptr == '.')
1832 {
1833 scriptWriteValue(g_thisActorVarID);
1834 }
1835 else
1836 {
1837 g_labelsOnly = labelsonly;
1838 C_GetNextVar();
1839 g_labelsOnly = 0;
1840 }
1841
1842 if (*textptr != '.') textptr++;
1843
1844 C_SkipComments();
1845
1846 // now get name of .xxx
1847
1848 if (EDUKE32_PREDICT_FALSE(*textptr++ != '.'))
1849 {
1850 g_errorCnt++;
1851 C_ReportError(ERROR_SYNTAXERROR);
1852 return -1;
1853 }
1854
1855 if (!table)
1856 return 0;
1857
1858 // .xxx
1859
1860 C_GetNextLabelName();
1861
1862 int const labelNum = C_GetLabelNameOffset(table, Bstrtolower(LAST_LABEL));
1863
1864 if (EDUKE32_PREDICT_FALSE(labelNum == -1))
1865 {
1866 g_errorCnt++;
1867 C_ReportError(ERROR_NOTAMEMBER);
1868 return -1;
1869 }
1870
1871 return labelNum;
1872 }
1873
1874 #ifdef CURRENTLY_UNUSED
C_IntPow2(int32_t const v)1875 static FORCE_INLINE bool C_IntPow2(int32_t const v)
1876 {
1877 return ((v!=0) && (v&(v-1))==0);
1878 }
1879
C_Pow2IntLogBase2(int32_t const v)1880 static inline uint32_t C_Pow2IntLogBase2(int32_t const v)
1881 {
1882 static constexpr uint32_t b[] = { 0xAAAAAAAA, 0xCCCCCCCC, 0xF0F0F0F0, 0xFF00FF00, 0xFFFF0000 };
1883
1884 uint32_t r = (v & b[0]) != 0;
1885
1886 for (int i = 0; i < ARRAY_SSIZE(b); ++i)
1887 r |= ((v & b[i]) != 0) << i;
1888
1889 return r;
1890 }
1891 #endif
1892
C_CheckMalformedBranch(intptr_t lastScriptPtr)1893 static bool C_CheckMalformedBranch(intptr_t lastScriptPtr)
1894 {
1895 switch (C_GetKeyword())
1896 {
1897 case CON_RIGHTBRACE:
1898 case CON_ENDA:
1899 case CON_ENDEVENT:
1900 case CON_ENDS:
1901 case CON_ELSE:
1902 g_scriptPtr = lastScriptPtr + apScript;
1903 g_skipBranch = true;
1904 C_ReportError(-1);
1905 g_warningCnt++;
1906 initprintf("%s:%d: warning: malformed `%s' branch\n",g_scriptFileName,g_lineNumber,
1907 VM_GetKeywordForID(*(g_scriptPtr) & VM_INSTMASK));
1908 return true;
1909 }
1910 return false;
1911 }
1912
C_CheckEmptyBranch(int tw,intptr_t lastScriptPtr)1913 static bool C_CheckEmptyBranch(int tw, intptr_t lastScriptPtr)
1914 {
1915 // ifrnd and the others actually do something when the condition is executed
1916 if ((Bstrncmp(VM_GetKeywordForID(tw), "if", 2) && tw != CON_ELSE) ||
1917 tw == CON_IFRND || tw == CON_IFHITWEAPON || tw == CON_IFCANSEE || tw == CON_IFCANSEETARGET ||
1918 tw == CON_IFPDISTL || tw == CON_IFPDISTG || tw == CON_IFGOTWEAPONCE)
1919 {
1920 g_skipBranch = false;
1921 return false;
1922 }
1923
1924 if ((*(g_scriptPtr) & VM_INSTMASK) != CON_NULLOP || *(g_scriptPtr)>>12 != VM_IFELSE_MAGIC)
1925 g_skipBranch = false;
1926
1927 if (EDUKE32_PREDICT_FALSE(g_skipBranch))
1928 {
1929 C_ReportError(-1);
1930 g_warningCnt++;
1931 g_scriptPtr = lastScriptPtr + apScript;
1932 initprintf("%s:%d: warning: empty `%s' branch\n",g_scriptFileName,g_lineNumber,
1933 VM_GetKeywordForID(*(g_scriptPtr) & VM_INSTMASK));
1934 scriptWriteAtOffset(CON_NULLOP | (VM_IFELSE_MAGIC<<12), g_scriptPtr);
1935 return true;
1936 }
1937
1938 return false;
1939 }
1940
C_CountCaseStatements()1941 static int C_CountCaseStatements()
1942 {
1943 char *const temptextptr = textptr;
1944 int const backupLineNumber = g_lineNumber;
1945 int const backupNumCases = g_numCases;
1946 intptr_t const casePtrOffset = g_caseTablePtr - apScript;
1947 intptr_t const scriptPtrOffset = g_scriptPtr - apScript;
1948
1949 g_numCases = 0;
1950 g_caseTablePtr = NULL;
1951 C_ParseCommand(true);
1952
1953 // since we processed the endswitch, we need to re-increment g_checkingSwitch
1954 g_checkingSwitch++;
1955
1956 int const numCases = g_numCases;
1957
1958 textptr = temptextptr;
1959 g_lineNumber = backupLineNumber;
1960 g_numCases = backupNumCases;
1961 g_caseTablePtr = apScript + casePtrOffset;
1962 g_scriptPtr = apScript + scriptPtrOffset;
1963
1964 return numCases;
1965 }
1966
C_Include(const char * confile)1967 static void C_Include(const char *confile)
1968 {
1969 buildvfs_kfd fp = kopen4loadfrommod(confile, g_loadFromGroupOnly);
1970
1971 if (EDUKE32_PREDICT_FALSE(fp == buildvfs_kfd_invalid))
1972 {
1973 g_errorCnt++;
1974 initprintf("%s:%d: error: could not find file `%s'.\n",g_scriptFileName,g_lineNumber,confile);
1975 return;
1976 }
1977
1978 int32_t const len = kfilelength(fp);
1979 char *mptr = (char *)Xmalloc(len+1);
1980
1981 initprintf("Including: %s (%d bytes)\n",confile, len);
1982
1983 kread(fp, mptr, len);
1984 kclose(fp);
1985
1986 mptr[len] = 0;
1987
1988 if (*textptr == '"') // skip past the closing quote if it's there so we don't screw up the next line
1989 textptr++;
1990
1991 char * const origtptr = textptr;
1992 char parentScriptFileName[BMAX_PATH];
1993
1994 Bstrcpy(parentScriptFileName, g_scriptFileName);
1995 Bstrcpy(g_scriptFileName, confile);
1996
1997 int const temp_ScriptLineNumber = g_lineNumber;
1998 g_lineNumber = 1;
1999
2000 int const temp_ifelse_check = g_checkingIfElse;
2001 g_checkingIfElse = 0;
2002
2003 textptr = mptr;
2004
2005 C_SkipComments();
2006 C_ParseCommand(true);
2007
2008 Bstrcpy(g_scriptFileName, parentScriptFileName);
2009
2010 g_totalLines += g_lineNumber;
2011 g_lineNumber = temp_ScriptLineNumber;
2012 g_checkingIfElse = temp_ifelse_check;
2013
2014 textptr = origtptr;
2015
2016 Xfree(mptr);
2017 }
2018
2019 #ifdef _WIN32
check_filename_case(const char * fn)2020 static void check_filename_case(const char *fn)
2021 {
2022 static char buf[BMAX_PATH];
2023
2024 // .zip isn't case sensitive, and calling kopen4load on files in .zips is slow
2025 Bstrcpy(buf, fn);
2026 kzfindfilestart(buf);
2027
2028 if (!kzfindfile(buf))
2029 {
2030 buildvfs_kfd fp;
2031 if ((fp = kopen4loadfrommod(fn, g_loadFromGroupOnly)) != buildvfs_kfd_invalid)
2032 kclose(fp);
2033 }
2034 }
2035 #else
check_filename_case(const char * fn)2036 static void check_filename_case(const char *fn) { UNREFERENCED_PARAMETER(fn); }
2037 #endif
2038
G_DoGameStartup(const int32_t * params)2039 void G_DoGameStartup(const int32_t *params)
2040 {
2041 auto &p0 = *g_player[0].ps;
2042 int j = 0;
2043
2044 ud.const_visibility = params[j++];
2045 g_impactDamage = params[j++];
2046
2047 p0.max_shield_amount = params[j];
2048 p0.max_player_health = params[j];
2049 g_maxPlayerHealth = params[j++];
2050
2051 g_startArmorAmount = params[j++];
2052 g_actorRespawnTime = params[j++];
2053 g_itemRespawnTime = (g_scriptVersion >= 11) ? params[j++] : g_actorRespawnTime;
2054
2055 if (g_scriptVersion >= 11)
2056 g_playerFriction = params[j++];
2057
2058 if (g_scriptVersion >= 14)
2059 g_spriteGravity = params[j++];
2060
2061 if (g_scriptVersion >= 11)
2062 {
2063 g_rpgRadius = params[j++];
2064 g_pipebombRadius = params[j++];
2065 g_shrinkerRadius = params[j++];
2066 g_tripbombRadius = params[j++];
2067 g_morterRadius = params[j++];
2068 g_bouncemineRadius = params[j++];
2069 g_seenineRadius = params[j++];
2070 }
2071
2072 p0.max_ammo_amount[PISTOL_WEAPON] = params[j++];
2073 p0.max_ammo_amount[SHOTGUN_WEAPON] = params[j++];
2074 p0.max_ammo_amount[CHAINGUN_WEAPON] = params[j++];
2075 p0.max_ammo_amount[RPG_WEAPON] = params[j++];
2076 p0.max_ammo_amount[HANDBOMB_WEAPON] = params[j++];
2077 p0.max_ammo_amount[SHRINKER_WEAPON] = params[j++];
2078 p0.max_ammo_amount[DEVISTATOR_WEAPON] = params[j++];
2079 p0.max_ammo_amount[TRIPBOMB_WEAPON] = params[j++];
2080
2081 if (g_scriptVersion >= 13)
2082 {
2083 p0.max_ammo_amount[FREEZE_WEAPON] = params[j++];
2084
2085 if (g_scriptVersion >= 14)
2086 p0.max_ammo_amount[GROW_WEAPON] = params[j++];
2087
2088 g_damageCameras = params[j++];
2089 g_numFreezeBounces = params[j++];
2090 g_freezerSelfDamage = params[j++];
2091
2092 if (g_scriptVersion >= 14)
2093 {
2094 g_deleteQueueSize = clamp(params[j++], 0, ARRAY_SSIZE(SpriteDeletionQueue));
2095 g_tripbombLaserMode = params[j++];
2096 }
2097
2098 if (g_scriptVersion >= 16)
2099 p0.max_ammo_amount[FLAMETHROWER_WEAPON] = params[j++];
2100 }
2101 }
2102
C_DefineMusic(int volumeNum,int levelNum,const char * fileName)2103 void C_DefineMusic(int volumeNum, int levelNum, const char *fileName)
2104 {
2105 Bassert((unsigned)volumeNum < MAXVOLUMES+1);
2106 Bassert((unsigned)levelNum < MAXLEVELS);
2107
2108 if (strcmp(fileName, "/.") == 0)
2109 return;
2110
2111 map_t *const pMapInfo = &g_mapInfo[(MAXLEVELS*volumeNum)+levelNum];
2112
2113 Xfree(pMapInfo->musicfn);
2114 pMapInfo->musicfn = dup_filename(fileName);
2115 check_filename_case(pMapInfo->musicfn);
2116 }
2117
C_DefineVolumeFlags(int32_t vol,int32_t flags)2118 void C_DefineVolumeFlags(int32_t vol, int32_t flags)
2119 {
2120 Bassert((unsigned)vol < MAXVOLUMES);
2121
2122 g_volumeFlags[vol] = flags;
2123 }
2124
C_UndefineVolume(int32_t vol)2125 void C_UndefineVolume(int32_t vol)
2126 {
2127 Bassert((unsigned)vol < MAXVOLUMES);
2128
2129 for (bssize_t i = 0; i < MAXLEVELS; i++)
2130 C_UndefineLevel(vol, i);
2131
2132 g_volumeNames[vol][0] = '\0';
2133
2134 g_volumeCnt = 0;
2135 for (bssize_t i = MAXVOLUMES-1; i >= 0; i--)
2136 {
2137 if (g_volumeNames[i][0])
2138 {
2139 g_volumeCnt = i+1;
2140 break;
2141 }
2142 }
2143 }
2144
C_UndefineSkill(int32_t skill)2145 void C_UndefineSkill(int32_t skill)
2146 {
2147 Bassert((unsigned)skill < MAXSKILLS);
2148
2149 g_skillNames[skill][0] = '\0';
2150
2151 g_skillCnt = 0;
2152 for (bssize_t i = MAXSKILLS-1; i >= 0; i--)
2153 {
2154 if (g_skillNames[i][0])
2155 {
2156 g_skillCnt = i+1;
2157 break;
2158 }
2159 }
2160 }
2161
C_UndefineLevel(int32_t vol,int32_t lev)2162 void C_UndefineLevel(int32_t vol, int32_t lev)
2163 {
2164 Bassert((unsigned)vol < MAXVOLUMES);
2165 Bassert((unsigned)lev < MAXLEVELS);
2166
2167 map_t *const map = &g_mapInfo[(MAXLEVELS*vol)+lev];
2168
2169 DO_FREE_AND_NULL(map->filename);
2170 DO_FREE_AND_NULL(map->name);
2171 map->partime = 0;
2172 map->designertime = 0;
2173 }
2174
C_SetDefName(const char * name)2175 static int32_t C_SetDefName(const char *name)
2176 {
2177 clearDefNamePtr();
2178 g_defNamePtr = dup_filename(name);
2179 if (g_defNamePtr)
2180 initprintf("Using DEF file: %s.\n", g_defNamePtr);
2181 return (g_defNamePtr==NULL);
2182 }
2183
2184 defaultprojectile_t DefaultProjectile;
2185
2186 EDUKE32_STATIC_ASSERT(sizeof(projectile_t) == sizeof(DefaultProjectile));
2187
C_AllocProjectile(int32_t j)2188 void C_AllocProjectile(int32_t j)
2189 {
2190 g_tile[j].proj = (projectile_t *)Xrealloc(g_tile[j].proj, 2 * sizeof(projectile_t));
2191 g_tile[j].defproj = g_tile[j].proj + 1;
2192 }
2193
C_FreeProjectile(int32_t j)2194 void C_FreeProjectile(int32_t j)
2195 {
2196 DO_FREE_AND_NULL(g_tile[j].proj);
2197 g_tile[j].defproj = NULL;
2198 }
2199
2200
C_DefineProjectile(int32_t j,int32_t what,int32_t val)2201 static void C_DefineProjectile(int32_t j, int32_t what, int32_t val)
2202 {
2203 if (g_tile[j].proj == NULL)
2204 {
2205 C_AllocProjectile(j);
2206 *g_tile[j].proj = DefaultProjectile;
2207 }
2208
2209 projectile_t * const proj = g_tile[j].proj;
2210
2211 switch (what)
2212 {
2213 case PROJ_WORKSLIKE: proj->workslike = val; break;
2214 case PROJ_SPAWNS: proj->spawns = val; break;
2215 case PROJ_SXREPEAT: proj->sxrepeat = val; break;
2216 case PROJ_SYREPEAT: proj->syrepeat = val; break;
2217 case PROJ_SOUND: proj->sound = val; break;
2218 case PROJ_ISOUND: proj->isound = val; break;
2219 case PROJ_VEL: proj->vel = val; break;
2220 case PROJ_EXTRA: proj->extra = val; break;
2221 case PROJ_DECAL: proj->decal = val; break;
2222 case PROJ_TRAIL: proj->trail = val; break;
2223 case PROJ_TXREPEAT: proj->txrepeat = val; break;
2224 case PROJ_TYREPEAT: proj->tyrepeat = val; break;
2225 case PROJ_TOFFSET: proj->toffset = val; break;
2226 case PROJ_TNUM: proj->tnum = val; break;
2227 case PROJ_DROP: proj->drop = val; break;
2228 case PROJ_CSTAT: proj->cstat = val; break;
2229 case PROJ_CLIPDIST: proj->clipdist = val; break;
2230 case PROJ_SHADE: proj->shade = val; break;
2231 case PROJ_XREPEAT: proj->xrepeat = val; break;
2232 case PROJ_YREPEAT: proj->yrepeat = val; break;
2233 case PROJ_PAL: proj->pal = val; break;
2234 case PROJ_EXTRA_RAND: proj->extra_rand = val; break;
2235 case PROJ_HITRADIUS: proj->hitradius = val; break;
2236 case PROJ_MOVECNT: proj->movecnt = val; break;
2237 case PROJ_OFFSET: proj->offset = val; break;
2238 case PROJ_BOUNCES: proj->bounces = val; break;
2239 case PROJ_BSOUND: proj->bsound = val; break;
2240 case PROJ_RANGE: proj->range = val; break;
2241 case PROJ_FLASH_COLOR: proj->flashcolor = val; break;
2242 case PROJ_USERDATA: proj->userdata = val; break;
2243 default: break;
2244 }
2245
2246 *g_tile[j].defproj = *proj;
2247
2248 g_tile[j].flags |= SFLAG_PROJECTILE;
2249 }
2250
C_AllocQuote(int32_t qnum)2251 int32_t C_AllocQuote(int32_t qnum)
2252 {
2253 Bassert((unsigned)qnum < MAXQUOTES);
2254
2255 if (apStrings[qnum] == NULL)
2256 {
2257 apStrings[qnum] = (char *)Xcalloc(MAXQUOTELEN,sizeof(uint8_t));
2258 return 1;
2259 }
2260
2261 return 0;
2262 }
2263
2264 #ifndef EDUKE32_TOUCH_DEVICES
C_ReplaceQuoteSubstring(const size_t q,char const * const query,char const * const replacement)2265 static void C_ReplaceQuoteSubstring(const size_t q, char const * const query, char const * const replacement)
2266 {
2267 size_t querylength = Bstrlen(query);
2268
2269 for (bssize_t i = MAXQUOTELEN - querylength - 2; i >= 0; i--)
2270 if (Bstrncmp(&apStrings[q][i], query, querylength) == 0)
2271 {
2272 Bmemset(tempbuf, 0, sizeof(tempbuf));
2273 Bstrncpy(tempbuf, apStrings[q], i);
2274 Bstrcat(tempbuf, replacement);
2275 Bstrcat(tempbuf, &apStrings[q][i + querylength]);
2276 Bstrncpy(apStrings[q], tempbuf, MAXQUOTELEN - 1);
2277 i = MAXQUOTELEN - querylength - 2;
2278 }
2279 }
2280 #endif
2281
C_InitQuotes(void)2282 void C_InitQuotes(void)
2283 {
2284 for (int i = 0; i < 128; i++) C_AllocQuote(i);
2285
2286 #ifdef EDUKE32_TOUCH_DEVICES
2287 apStrings[QUOTE_DEAD] = 0;
2288 #else
2289 char const * const OpenGameFunc = gamefunctions[gamefunc_Open];
2290 C_ReplaceQuoteSubstring(QUOTE_DEAD, "SPACE", OpenGameFunc);
2291 C_ReplaceQuoteSubstring(QUOTE_DEAD, "OPEN", OpenGameFunc);
2292 C_ReplaceQuoteSubstring(QUOTE_DEAD, "USE", OpenGameFunc);
2293 #endif
2294
2295 // most of these are based on Blood, obviously
2296 const char *PlayerObituaries[] =
2297 {
2298 "^02%s^02 beat %s^02 like a cur",
2299 "^02%s^02 broke %s",
2300 "^02%s^02 body bagged %s",
2301 "^02%s^02 boned %s^02 like a fish",
2302 "^02%s^02 castrated %s",
2303 "^02%s^02 creamed %s",
2304 "^02%s^02 crushed %s",
2305 "^02%s^02 destroyed %s",
2306 "^02%s^02 diced %s",
2307 "^02%s^02 disemboweled %s",
2308 "^02%s^02 erased %s",
2309 "^02%s^02 eviscerated %s",
2310 "^02%s^02 flailed %s",
2311 "^02%s^02 flattened %s",
2312 "^02%s^02 gave AnAl MaDnEsS to %s",
2313 "^02%s^02 gave %s^02 Anal Justice",
2314 "^02%s^02 hosed %s",
2315 "^02%s^02 hurt %s^02 real bad",
2316 "^02%s^02 killed %s",
2317 "^02%s^02 made dog meat out of %s",
2318 "^02%s^02 made mincemeat out of %s",
2319 "^02%s^02 manhandled %s",
2320 "^02%s^02 massacred %s",
2321 "^02%s^02 mutilated %s",
2322 "^02%s^02 murdered %s",
2323 "^02%s^02 neutered %s",
2324 "^02%s^02 punted %s",
2325 "^02%s^02 reamed %s",
2326 "^02%s^02 ripped %s^02 a new orifice",
2327 "^02%s^02 rocked %s",
2328 "^02%s^02 sent %s^02 to hell",
2329 "^02%s^02 shredded %s",
2330 "^02%s^02 slashed %s",
2331 "^02%s^02 slaughtered %s",
2332 "^02%s^02 sliced %s",
2333 "^02%s^02 smacked %s around",
2334 "^02%s^02 smashed %s",
2335 "^02%s^02 snuffed %s",
2336 "^02%s^02 sodomized %s",
2337 "^02%s^02 splattered %s",
2338 "^02%s^02 sprayed %s",
2339 "^02%s^02 squashed %s",
2340 "^02%s^02 throttled %s",
2341 "^02%s^02 toasted %s",
2342 "^02%s^02 vented %s",
2343 "^02%s^02 ventilated %s",
2344 "^02%s^02 wasted %s",
2345 "^02%s^02 wrecked %s",
2346 };
2347
2348 const char *PlayerSelfObituaries[] =
2349 {
2350 "^02%s^02 is excrement",
2351 "^02%s^02 is hamburger",
2352 "^02%s^02 suffered scrotum separation",
2353 "^02%s^02 volunteered for population control",
2354 "^02%s^02 has suicided",
2355 "^02%s^02 bled out",
2356 };
2357
2358 EDUKE32_STATIC_ASSERT(OBITQUOTEINDEX + ARRAY_SIZE(PlayerObituaries)-1 < MAXQUOTES);
2359 EDUKE32_STATIC_ASSERT(SUICIDEQUOTEINDEX + ARRAY_SIZE(PlayerSelfObituaries)-1 < MAXQUOTES);
2360
2361 g_numObituaries = ARRAY_SIZE(PlayerObituaries);
2362 for (bssize_t i = g_numObituaries - 1; i >= 0; i--)
2363 {
2364 if (C_AllocQuote(i + OBITQUOTEINDEX))
2365 Bstrcpy(apStrings[i + OBITQUOTEINDEX], PlayerObituaries[i]);
2366 }
2367
2368 g_numSelfObituaries = ARRAY_SIZE(PlayerSelfObituaries);
2369 for (bssize_t i = g_numSelfObituaries - 1; i >= 0; i--)
2370 {
2371 if (C_AllocQuote(i + SUICIDEQUOTEINDEX))
2372 Bstrcpy(apStrings[i + SUICIDEQUOTEINDEX], PlayerSelfObituaries[i]);
2373 }
2374 }
2375
C_SetCfgName(const char * cfgname)2376 static void C_SetCfgName(const char *cfgname)
2377 {
2378 if (Bstrcmp(g_setupFileName, cfgname) == 0) // no need to do anything if name is the same
2379 return;
2380
2381 if (Bstrcmp(g_setupFileName, SETUPFILENAME) != 0) // set to something else via -cfg
2382 return;
2383
2384 ud_setup_t const config = ud.setup;
2385 #ifdef POLYMER
2386 int const renderMode = glrendmode;
2387 #endif
2388
2389 if (!buildvfs_isdir(g_modDir))
2390 {
2391 if (buildvfs_mkdir(g_modDir, S_IRWXU) != 0)
2392 {
2393 OSD_Printf("Failed to create directory \"%s\"!\n", g_modDir);
2394 return;
2395 }
2396 else
2397 OSD_Printf("Created configuration file directory %s\n", g_modDir);
2398 }
2399
2400 // XXX: Back up 'cfgname' as it may be the global 'tempbuf'.
2401 char *temp = Xstrdup(cfgname);
2402
2403 CONFIG_WriteSetup(1);
2404
2405 if (g_modDir[0] != '/')
2406 Bsnprintf(g_setupFileName, sizeof(g_setupFileName), "%s/%s", g_modDir, temp);
2407 else
2408 Bstrncpyz(g_setupFileName, temp, sizeof(g_setupFileName));
2409
2410 DO_FREE_AND_NULL(temp);
2411
2412 initprintf("Using config file \"%s\".\n", g_setupFileName);
2413
2414 CONFIG_ReadSetup();
2415
2416 ud.setup = config;
2417 #ifdef POLYMER
2418 glrendmode = renderMode;
2419 #endif
2420 }
2421
C_BitOrNextValue(int32_t * valptr)2422 static inline void C_BitOrNextValue(int32_t *valptr)
2423 {
2424 C_GetNextValue(LABEL_DEFINE);
2425 g_scriptPtr--;
2426 *valptr |= *g_scriptPtr;
2427 }
2428
C_FinishBitOr(int32_t value)2429 static inline void C_FinishBitOr(int32_t value)
2430 {
2431 scriptWriteValue(value);
2432 }
2433
C_FillEventBreakStackWithJump(intptr_t * breakPtr,intptr_t destination)2434 static void C_FillEventBreakStackWithJump(intptr_t *breakPtr, intptr_t destination)
2435 {
2436 while (breakPtr)
2437 {
2438 breakPtr = apScript + (intptr_t)breakPtr;
2439 intptr_t const tempPtr = *breakPtr;
2440 scriptWriteAtOffset(destination, breakPtr);
2441 breakPtr = (intptr_t *)tempPtr;
2442 }
2443 }
2444
scriptUpdateOpcodeForVariableType(intptr_t * ins)2445 static void scriptUpdateOpcodeForVariableType(intptr_t *ins)
2446 {
2447 int opcode = -1;
2448
2449 if (ins[1] < MAXGAMEVARS)
2450 {
2451 switch (aGameVars[ins[1] & (MAXGAMEVARS - 1)].flags & (GAMEVAR_USER_MASK | GAMEVAR_PTR_MASK))
2452 {
2453 case 0:
2454 opcode = inthash_find(&h_globalvar, *ins & VM_INSTMASK);
2455 break;
2456 case GAMEVAR_PERACTOR:
2457 opcode = inthash_find(&h_actorvar, *ins & VM_INSTMASK);
2458 break;
2459 case GAMEVAR_PERPLAYER:
2460 opcode = inthash_find(&h_playervar, *ins & VM_INSTMASK);
2461 break;
2462 }
2463 }
2464
2465 if (opcode != -1)
2466 {
2467 if (g_scriptDebug > 1 && !g_errorCnt && !g_warningCnt)
2468 {
2469 initprintf("%s:%d: %s -> %s for var %s\n", g_scriptFileName, g_lineNumber,
2470 VM_GetKeywordForID(*ins & VM_INSTMASK), VM_GetKeywordForID(opcode), aGameVars[ins[1] & (MAXGAMEVARS-1)].szLabel);
2471 }
2472
2473 scriptWriteAtOffset(opcode | LINE_NUMBER, ins);
2474 }
2475 }
2476
C_ParseCommand(bool loop)2477 static bool C_ParseCommand(bool loop /*= false*/)
2478 {
2479 int32_t i, j=0, k=0, tw;
2480
2481 do
2482 {
2483 if (EDUKE32_PREDICT_FALSE(g_errorCnt > 63 || (*textptr == '\0') || (*(textptr+1) == '\0')))
2484 return 1;
2485
2486 if ((g_scriptPtr - apScript) > (g_scriptSize - 4096) && g_caseTablePtr == NULL)
2487 C_SetScriptSize(g_scriptSize << 1);
2488
2489 if (EDUKE32_PREDICT_FALSE(g_scriptDebug))
2490 C_ReportError(-1);
2491
2492 int const otw = g_lastKeyword;
2493
2494 C_SkipComments();
2495
2496 switch ((g_lastKeyword = tw = C_GetNextKeyword()))
2497 {
2498 default:
2499 case -1:
2500 case -2:
2501 return 1; //End
2502 case CON_DEFSTATE:
2503 if (EDUKE32_PREDICT_FALSE(g_processingState || g_scriptActorOffset))
2504 {
2505 C_ReportError(ERROR_FOUNDWITHIN);
2506 g_errorCnt++;
2507 continue;
2508 }
2509 goto DO_DEFSTATE;
2510 case CON_STATE:
2511 if (!g_scriptActorOffset && g_processingState == 0)
2512 {
2513 DO_DEFSTATE:
2514 C_GetNextLabelName();
2515 g_scriptPtr--;
2516 labelcode[g_labelCnt] = g_scriptPtr-apScript;
2517 labeltype[g_labelCnt] = LABEL_STATE;
2518
2519 g_processingState = 1;
2520 Bsprintf(g_szCurrentBlockName,"%s",LAST_LABEL);
2521
2522 if (EDUKE32_PREDICT_FALSE(hash_find(&h_keywords,LAST_LABEL)>=0))
2523 {
2524 g_errorCnt++;
2525 C_ReportError(ERROR_ISAKEYWORD);
2526 continue;
2527 }
2528
2529 if (EDUKE32_PREDICT_FALSE(hash_find(&h_gamevars,LAST_LABEL)>=0))
2530 {
2531 g_warningCnt++;
2532 C_ReportError(WARNING_NAMEMATCHESVAR);
2533 }
2534
2535 hash_add(&h_labels,LAST_LABEL,g_labelCnt,0);
2536 g_labelCnt++;
2537 continue;
2538 }
2539
2540 C_GetNextLabelName();
2541
2542 if (EDUKE32_PREDICT_FALSE((j = hash_find(&h_labels,LAST_LABEL)) < 0))
2543 {
2544 C_ReportError(-1);
2545 initprintf("%s:%d: error: state `%s' not found.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
2546 g_errorCnt++;
2547 g_scriptPtr++;
2548 continue;
2549 }
2550
2551 if (EDUKE32_PREDICT_FALSE((labeltype[j] & LABEL_STATE) != LABEL_STATE))
2552 {
2553 char *gl = (char *) C_GetLabelType(labeltype[j]);
2554 C_ReportError(-1);
2555 initprintf("%s:%d: warning: expected state, found %s.\n", g_scriptFileName, g_lineNumber, gl);
2556 g_warningCnt++;
2557 Xfree(gl);
2558 scriptWriteAtOffset(CON_NULLOP, &g_scriptPtr[-1]); // get rid of the state, leaving a nullop to satisfy if conditions
2559 continue; // valid label name, but wrong type
2560 }
2561
2562 if (g_scriptDebug > 1 && !g_errorCnt && !g_warningCnt)
2563 initprintf("%s:%d: debug: state label `%s'.\n", g_scriptFileName, g_lineNumber, label+(j<<6));
2564
2565 // 'state' type labels are always script addresses, as far as I can see
2566 scriptWritePointer((intptr_t)(apScript+labelcode[j]), g_scriptPtr++);
2567 continue;
2568
2569 case CON_ENDS:
2570 if (EDUKE32_PREDICT_FALSE(g_processingState == 0))
2571 {
2572 C_ReportError(-1);
2573 initprintf("%s:%d: error: found `ends' without open `state'.\n",g_scriptFileName,g_lineNumber);
2574 g_errorCnt++;
2575 }
2576
2577 if (EDUKE32_PREDICT_FALSE(g_numBraces > 0))
2578 {
2579 C_ReportError(ERROR_NOTTOPLEVEL);
2580 g_errorCnt++;
2581 }
2582
2583 if (EDUKE32_PREDICT_FALSE(g_checkingSwitch > 0))
2584 {
2585 C_ReportError(ERROR_NOENDSWITCH);
2586 g_errorCnt++;
2587
2588 g_checkingSwitch = 0; // can't be checking anymore...
2589 }
2590
2591 g_processingState = 0;
2592 Bsprintf(g_szCurrentBlockName,"(none)");
2593 continue;
2594
2595 case CON_GETPROJECTILE:
2596 case CON_GETTHISPROJECTILE:
2597 case CON_SETPROJECTILE:
2598 case CON_SETTHISPROJECTILE:
2599 {
2600 int const labelNum = C_GetStructureIndexes(tw == CON_SETTHISPROJECTILE || tw == CON_GETTHISPROJECTILE, &h_projectile);
2601
2602 if (labelNum == -1)
2603 continue;
2604
2605 scriptWriteValue(ProjectileLabels[labelNum].lId);
2606
2607 switch (tw)
2608 {
2609 case CON_SETPROJECTILE:
2610 case CON_SETTHISPROJECTILE:
2611 C_GetNextVar();
2612 break;
2613 default:
2614 C_GetNextVarType(GAMEVAR_READONLY);
2615 break;
2616 }
2617 continue;
2618 }
2619
2620 case CON_GAMEVAR:
2621 {
2622 // syntax: gamevar <var1> <initial value> <flags>
2623 // defines var1 and sets initial value.
2624 // flags are used to define usage
2625 // (see top of this files for flags)
2626
2627 //Skip comments before calling the check in order to align the textptr onto the label
2628 C_SkipComments();
2629 if (EDUKE32_PREDICT_FALSE(isdigit(*textptr) || (*textptr == '-')))
2630 {
2631 g_errorCnt++;
2632 C_ReportError(ERROR_SYNTAXERROR);
2633 scriptSkipLine();
2634 continue;
2635 }
2636
2637 g_scriptPtr--;
2638
2639 C_GetNextLabelName();
2640
2641 if (EDUKE32_PREDICT_FALSE(hash_find(&h_keywords, LAST_LABEL)>=0))
2642 {
2643 g_warningCnt++;
2644 C_ReportError(WARNING_VARMASKSKEYWORD);
2645 hash_delete(&h_keywords, LAST_LABEL);
2646 }
2647
2648 int32_t defaultValue = 0;
2649 int32_t varFlags = 0;
2650
2651 if (C_GetKeyword() == -1)
2652 {
2653 C_GetNextValue(LABEL_DEFINE); // get initial value
2654 defaultValue = *(--g_scriptPtr);
2655
2656 j = 0;
2657
2658 while (C_GetKeyword() == -1)
2659 C_BitOrNextValue(&j);
2660
2661 C_FinishBitOr(j);
2662 varFlags = *(--g_scriptPtr);
2663
2664 if (EDUKE32_PREDICT_FALSE((*(g_scriptPtr)&GAMEVAR_USER_MASK)==(GAMEVAR_PERPLAYER|GAMEVAR_PERACTOR)))
2665 {
2666 g_warningCnt++;
2667 varFlags ^= GAMEVAR_PERPLAYER;
2668 C_ReportError(WARNING_BADGAMEVAR);
2669 }
2670 }
2671
2672 Gv_NewVar(LAST_LABEL, defaultValue, varFlags);
2673 continue;
2674 }
2675
2676 case CON_GAMEARRAY:
2677 {
2678 //Skip comments before calling the check in order to align the textptr onto the label
2679 C_SkipComments();
2680 if (EDUKE32_PREDICT_FALSE(isdigit(*textptr) || (*textptr == '-')))
2681 {
2682 g_errorCnt++;
2683 C_ReportError(ERROR_SYNTAXERROR);
2684 scriptSkipLine();
2685 continue;
2686 }
2687 C_GetNextLabelName();
2688
2689 if (EDUKE32_PREDICT_FALSE(hash_find(&h_keywords,LAST_LABEL)>=0))
2690 {
2691 g_warningCnt++;
2692 C_ReportError(WARNING_ARRAYMASKSKEYWORD);
2693 hash_delete(&h_keywords, LAST_LABEL);
2694 }
2695
2696 i = hash_find(&h_gamevars,LAST_LABEL);
2697 if (EDUKE32_PREDICT_FALSE(i>=0))
2698 {
2699 g_warningCnt++;
2700 C_ReportError(WARNING_NAMEMATCHESVAR);
2701 }
2702
2703 C_GetNextValue(LABEL_DEFINE);
2704
2705 char const * const arrayName = LAST_LABEL;
2706 int32_t arrayFlags = 0;
2707
2708 while (C_GetKeyword() == -1)
2709 C_BitOrNextValue(&arrayFlags);
2710
2711 C_FinishBitOr(arrayFlags);
2712
2713 arrayFlags = g_scriptPtr[-1];
2714 g_scriptPtr--;
2715
2716 Gv_NewArray(arrayName, NULL, g_scriptPtr[-1], arrayFlags);
2717
2718 g_scriptPtr -= 2; // no need to save in script...
2719 continue;
2720 }
2721
2722 case CON_DEFINE:
2723 {
2724 C_GetNextLabelName();
2725
2726 if (EDUKE32_PREDICT_FALSE(hash_find(&h_keywords,LAST_LABEL)>=0))
2727 {
2728 g_errorCnt++;
2729 C_ReportError(ERROR_ISAKEYWORD);
2730 continue;
2731 }
2732
2733 i = hash_find(&h_gamevars,LAST_LABEL);
2734 if (EDUKE32_PREDICT_FALSE(i>=0))
2735 {
2736 g_warningCnt++;
2737 C_ReportError(WARNING_NAMEMATCHESVAR);
2738 }
2739
2740 C_GetNextValue(LABEL_DEFINE);
2741
2742 i = hash_find(&h_labels,LAST_LABEL);
2743 if (i>=0)
2744 {
2745 // if (i >= g_numDefaultLabels)
2746
2747 if (EDUKE32_PREDICT_FALSE(labelcode[i] != g_scriptPtr[-1]))
2748 {
2749 g_warningCnt++;
2750 initprintf("%s:%d: warning: ignored redefinition of `%s' to %d (old: %d).\n",g_scriptFileName,
2751 g_lineNumber,LAST_LABEL, (int32_t)(g_scriptPtr[-1]), labelcode[i]);
2752 }
2753 }
2754 else
2755 {
2756 hash_add(&h_labels,LAST_LABEL,g_labelCnt,0);
2757 labeltype[g_labelCnt] = LABEL_DEFINE;
2758 labelcode[g_labelCnt++] = g_scriptPtr[-1];
2759 if (g_scriptPtr[-1] >= 0 && g_scriptPtr[-1] < MAXTILES && g_dynamicTileMapping)
2760 G_ProcessDynamicTileMapping(label+((g_labelCnt-1)<<6),g_scriptPtr[-1]);
2761 }
2762 g_scriptPtr -= 2;
2763 continue;
2764 }
2765
2766 case CON_PALFROM:
2767 for (j=3; j>=0; j--)
2768 {
2769 if (C_GetKeyword() == -1)
2770 C_GetNextValue(LABEL_DEFINE);
2771 else break;
2772 }
2773
2774 while (j>-1)
2775 {
2776 scriptWriteValue(0);
2777 j--;
2778 }
2779 continue;
2780
2781 case CON_MOVE:
2782 if (g_scriptActorOffset || g_processingState)
2783 {
2784 if (EDUKE32_PREDICT_FALSE((C_GetNextValue(LABEL_MOVE|LABEL_DEFINE) == 0) && (g_scriptPtr[-1] != 0) && (g_scriptPtr[-1] != 1)))
2785 {
2786 C_ReportError(-1);
2787 scriptWriteAtOffset(0, &g_scriptPtr[-1]);
2788 initprintf("%s:%d: warning: expected a move, found a constant.\n",g_scriptFileName,g_lineNumber);
2789 g_warningCnt++;
2790 }
2791
2792 j = 0;
2793 while (C_GetKeyword() == -1)
2794 C_BitOrNextValue(&j);
2795
2796 C_FinishBitOr(j);
2797 }
2798 else
2799 {
2800 g_scriptPtr--;
2801 scriptWriteValue(CON_MOVE);
2802
2803 C_GetNextLabelName();
2804 // Check to see it's already defined
2805
2806 if (EDUKE32_PREDICT_FALSE(hash_find(&h_keywords,LAST_LABEL)>=0))
2807 {
2808 g_errorCnt++;
2809 C_ReportError(ERROR_ISAKEYWORD);
2810 continue;
2811 }
2812
2813 if (EDUKE32_PREDICT_FALSE(hash_find(&h_gamevars,LAST_LABEL)>=0))
2814 {
2815 g_warningCnt++;
2816 C_ReportError(WARNING_NAMEMATCHESVAR);
2817 }
2818
2819 if (EDUKE32_PREDICT_FALSE((i = hash_find(&h_labels,LAST_LABEL)) >= 0))
2820 {
2821 g_warningCnt++;
2822 initprintf("%s:%d: warning: duplicate move `%s' ignored.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
2823 }
2824 else
2825 {
2826 hash_add(&h_labels,LAST_LABEL,g_labelCnt,0);
2827 labeltype[g_labelCnt] = LABEL_MOVE;
2828 labelcode[g_labelCnt++] = g_scriptPtr-apScript;
2829 }
2830
2831 for (j=1; j>=0; j--)
2832 {
2833 if (C_GetKeyword() != -1) break;
2834 C_GetNextValue(LABEL_DEFINE);
2835 }
2836
2837 for (k=j; k>=0; k--)
2838 scriptWriteValue(0);
2839
2840 scriptWriteValue(CON_END);
2841 }
2842 continue;
2843
2844 case CON_MUSIC:
2845 {
2846 // NOTE: this doesn't get stored in the PCode...
2847
2848 // music 1 stalker.mid dethtoll.mid streets.mid watrwld1.mid snake1.mid
2849 // thecall.mid ahgeez.mid dethtoll.mid streets.mid watrwld1.mid snake1.mid
2850 g_scriptPtr--;
2851 C_GetNextValue(LABEL_DEFINE); // Volume Number (0/4)
2852 g_scriptPtr--;
2853
2854 k = *g_scriptPtr-1; // 0-based volume number. -1 or MAXVOLUMES: "special"
2855 if (k == -1)
2856 k = MAXVOLUMES;
2857
2858 if (EDUKE32_PREDICT_FALSE((unsigned)k >= MAXVOLUMES+1)) // if it's not background or special music
2859 {
2860 g_errorCnt++;
2861 C_ReportError(-1);
2862 initprintf("%s:%d: error: volume number must be between 0 and MAXVOLUMES+1=%d.\n",
2863 g_scriptFileName, g_lineNumber, MAXVOLUMES+1);
2864 continue;
2865
2866 }
2867
2868 i = 0;
2869 // get the file name...
2870 while (C_GetKeyword() == -1)
2871 {
2872 C_SkipComments();
2873
2874 j = 0;
2875 tempbuf[j] = '/';
2876 while (isaltok(*(textptr+j)))
2877 {
2878 tempbuf[j+1] = textptr[j];
2879 j++;
2880 }
2881 tempbuf[j+1] = '\0';
2882
2883 C_DefineMusic(k, i, tempbuf);
2884
2885 textptr += j;
2886
2887 if (i >= MAXLEVELS)
2888 break;
2889 i++;
2890 }
2891 }
2892 continue;
2893
2894 case CON_INCLUDE:
2895 g_scriptPtr--;
2896
2897 C_SkipComments();
2898
2899 j = 0;
2900 while (isaltok(*textptr))
2901 {
2902 tempbuf[j] = *(textptr++);
2903 j++;
2904 }
2905 tempbuf[j] = '\0';
2906
2907 C_Include(tempbuf);
2908 continue;
2909
2910 case CON_INCLUDEDEFAULT:
2911 C_SkipComments();
2912 C_Include(G_DefaultConFile());
2913 continue;
2914
2915 case CON_AI:
2916 if (g_scriptActorOffset || g_processingState)
2917 {
2918 C_GetNextValue(LABEL_AI);
2919 }
2920 else
2921 {
2922 g_scriptPtr--;
2923 scriptWriteValue(CON_AI);
2924
2925 C_GetNextLabelName();
2926
2927 if (EDUKE32_PREDICT_FALSE(hash_find(&h_keywords,LAST_LABEL)>=0))
2928 {
2929 g_errorCnt++;
2930 C_ReportError(ERROR_ISAKEYWORD);
2931 continue;
2932 }
2933
2934 i = hash_find(&h_gamevars,LAST_LABEL);
2935 if (EDUKE32_PREDICT_FALSE(i>=0))
2936 {
2937 g_warningCnt++;
2938 C_ReportError(WARNING_NAMEMATCHESVAR);
2939 }
2940
2941 i = hash_find(&h_labels,LAST_LABEL);
2942 if (EDUKE32_PREDICT_FALSE(i>=0))
2943 {
2944 g_warningCnt++;
2945 initprintf("%s:%d: warning: duplicate ai `%s' ignored.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
2946 }
2947 else
2948 {
2949 labeltype[g_labelCnt] = LABEL_AI;
2950 hash_add(&h_labels,LAST_LABEL,g_labelCnt,0);
2951 labelcode[g_labelCnt++] = g_scriptPtr-apScript;
2952 }
2953
2954 for (j=0; j<3; j++)
2955 {
2956 if (C_GetKeyword() != -1) break;
2957 if (j == 1)
2958 C_GetNextValue(LABEL_ACTION);
2959 else if (j == 2)
2960 {
2961 if (EDUKE32_PREDICT_FALSE((C_GetNextValue(LABEL_MOVE|LABEL_DEFINE) == 0) &&
2962 (g_scriptPtr[-1] != 0) && (g_scriptPtr[-1] != 1)))
2963 {
2964 C_ReportError(-1);
2965 scriptWriteAtOffset(0, &g_scriptPtr[-1]);
2966 initprintf("%s:%d: warning: expected a move, found a constant.\n",g_scriptFileName,g_lineNumber);
2967 g_warningCnt++;
2968 }
2969
2970 k = 0;
2971 while (C_GetKeyword() == -1)
2972 C_BitOrNextValue(&k);
2973
2974 C_FinishBitOr(k);
2975 }
2976 }
2977
2978 for (k=j; k<3; k++)
2979 scriptWriteValue(0);
2980
2981 scriptWriteValue(CON_END);
2982 }
2983 continue;
2984
2985 case CON_ACTION:
2986 if (g_scriptActorOffset || g_processingState)
2987 {
2988 C_GetNextValue(LABEL_ACTION);
2989 }
2990 else
2991 {
2992 g_scriptPtr--;
2993 scriptWriteValue(CON_ACTION);
2994
2995 C_GetNextLabelName();
2996 // Check to see it's already defined
2997
2998 if (EDUKE32_PREDICT_FALSE(hash_find(&h_keywords,LAST_LABEL)>=0))
2999 {
3000 g_errorCnt++;
3001 C_ReportError(ERROR_ISAKEYWORD);
3002 continue;
3003 }
3004
3005 i = hash_find(&h_gamevars,LAST_LABEL);
3006 if (EDUKE32_PREDICT_FALSE(i>=0))
3007 {
3008 g_warningCnt++;
3009 C_ReportError(WARNING_NAMEMATCHESVAR);
3010 }
3011
3012 i = hash_find(&h_labels,LAST_LABEL);
3013 if (EDUKE32_PREDICT_FALSE(i>=0))
3014 {
3015 g_warningCnt++;
3016 initprintf("%s:%d: warning: duplicate action `%s' ignored.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
3017 }
3018 else
3019 {
3020 labeltype[g_labelCnt] = LABEL_ACTION;
3021 labelcode[g_labelCnt] = g_scriptPtr-apScript;
3022 hash_add(&h_labels,LAST_LABEL,g_labelCnt,0);
3023 g_labelCnt++;
3024 }
3025
3026 for (j=ACTION_PARAM_COUNT-1; j>=0; j--)
3027 {
3028 if (C_GetKeyword() != -1) break;
3029 C_GetNextValue(LABEL_DEFINE);
3030 }
3031 for (k=j; k>=0; k--)
3032 scriptWriteValue(0);
3033
3034 scriptWriteValue(CON_END);
3035 }
3036 continue;
3037
3038 case CON_ACTOR:
3039 case CON_USERACTOR:
3040 case CON_EVENTLOADACTOR:
3041 if (EDUKE32_PREDICT_FALSE(g_processingState || g_scriptActorOffset))
3042 {
3043 C_ReportError(ERROR_FOUNDWITHIN);
3044 g_errorCnt++;
3045 }
3046
3047 g_numBraces = 0;
3048 g_scriptPtr--;
3049 g_scriptActorOffset = g_scriptPtr - apScript;
3050
3051 if (tw == CON_USERACTOR)
3052 {
3053 C_GetNextValue(LABEL_DEFINE);
3054 g_scriptPtr--;
3055 }
3056
3057 // save the actor name w/o consuming it
3058 C_SkipComments();
3059 j = 0;
3060 while (isaltok(*(textptr+j)))
3061 {
3062 g_szCurrentBlockName[j] = textptr[j];
3063 j++;
3064 }
3065 g_szCurrentBlockName[j] = 0;
3066
3067 j = hash_find(&h_labels, g_szCurrentBlockName);
3068
3069 if (j != -1)
3070 labeltype[j] |= LABEL_ACTOR;
3071
3072 if (tw == CON_USERACTOR)
3073 {
3074 j = *g_scriptPtr;
3075
3076 if (EDUKE32_PREDICT_FALSE(j > 6 || (j&3)==3))
3077 {
3078 C_ReportError(-1);
3079 initprintf("%s:%d: warning: invalid useractor type. Must be 0, 1, 2"
3080 " (notenemy, enemy, enemystayput) or have 4 added (\"doesn't move\").\n",
3081 g_scriptFileName,g_lineNumber);
3082 g_warningCnt++;
3083 j = 0;
3084 }
3085 }
3086
3087 C_GetNextValue(LABEL_ACTOR);
3088 g_scriptPtr--;
3089
3090 if (EDUKE32_PREDICT_FALSE((unsigned)*g_scriptPtr >= MAXTILES))
3091 {
3092 C_ReportError(ERROR_EXCEEDSMAXTILES);
3093 g_errorCnt++;
3094 continue;
3095 }
3096
3097 if (tw == CON_EVENTLOADACTOR)
3098 {
3099 g_tile[*g_scriptPtr].loadPtr = apScript + g_scriptActorOffset;
3100 g_checkingIfElse = 0;
3101 continue;
3102 }
3103
3104 g_tile[*g_scriptPtr].execPtr = apScript + g_scriptActorOffset;
3105
3106 if (tw == CON_USERACTOR)
3107 {
3108 if (j & 1) g_tile[*g_scriptPtr].flags |= SFLAG_BADGUY;
3109 if (j & 2) g_tile[*g_scriptPtr].flags |= (SFLAG_BADGUY|SFLAG_BADGUYSTAYPUT);
3110 if (j & 4) g_tile[*g_scriptPtr].flags |= SFLAG_ROTFIXED;
3111 }
3112
3113 for (j=0; j<4; j++)
3114 {
3115 scriptWriteAtOffset(0, apScript+g_scriptActorOffset+j);
3116 if (j == 3)
3117 {
3118 j = 0;
3119 while (C_GetKeyword() == -1)
3120 C_BitOrNextValue(&j);
3121
3122 C_FinishBitOr(j);
3123 break;
3124 }
3125 else
3126 {
3127 if (C_GetKeyword() != -1)
3128 {
3129 for (i=4-j; i; i--)
3130 {
3131 scriptWriteValue(0);
3132 }
3133 break;
3134 }
3135 switch (j)
3136 {
3137 case 0:
3138 C_GetNextValue(LABEL_DEFINE);
3139 break;
3140 case 1:
3141 C_GetNextValue(LABEL_ACTION);
3142 break;
3143 case 2:
3144 // XXX: LABEL_MOVE|LABEL_DEFINE, what is this shit? compatibility?
3145 // yep, it sure is :(
3146 if (EDUKE32_PREDICT_FALSE((C_GetNextValue(LABEL_MOVE|LABEL_DEFINE) == 0) && (g_scriptPtr[-1] != 0) && (g_scriptPtr[-1] != 1)))
3147 {
3148 C_ReportError(-1);
3149 scriptWriteAtOffset(0, &g_scriptPtr[-1]);
3150 initprintf("%s:%d: warning: expected a move, found a constant.\n",g_scriptFileName,g_lineNumber);
3151 g_warningCnt++;
3152 }
3153 break;
3154 }
3155
3156 if (g_scriptPtr[-1] >= (intptr_t)apScript && g_scriptPtr[-1] < (intptr_t)&apScript[g_scriptSize])
3157 scriptWritePointer(g_scriptPtr[-1], apScript + g_scriptActorOffset + j);
3158 else
3159 scriptWriteAtOffset(g_scriptPtr[-1], apScript + g_scriptActorOffset + j);
3160 }
3161 }
3162 g_checkingIfElse = 0;
3163 continue;
3164
3165 case CON_ONEVENT:
3166 case CON_APPENDEVENT:
3167 if (EDUKE32_PREDICT_FALSE(g_processingState || g_scriptActorOffset))
3168 {
3169 C_ReportError(ERROR_FOUNDWITHIN);
3170 g_errorCnt++;
3171 }
3172
3173 g_numBraces = 0;
3174 g_scriptPtr--;
3175 g_scriptEventOffset = g_scriptActorOffset = g_scriptPtr - apScript;
3176
3177 C_SkipComments();
3178 j = 0;
3179 while (isaltok(*(textptr+j)))
3180 {
3181 g_szCurrentBlockName[j] = textptr[j];
3182 j++;
3183 }
3184 g_szCurrentBlockName[j] = 0;
3185 // g_labelsOnly = 1;
3186 C_GetNextValue(LABEL_EVENT);
3187 g_labelsOnly = 0;
3188 g_scriptPtr--;
3189 j= *g_scriptPtr; // type of event
3190 g_currentEvent = j;
3191 //Bsprintf(g_szBuf,"Adding Event for %d at %lX",j, g_parsingEventPtr);
3192 //AddLog(g_szBuf);
3193 if (EDUKE32_PREDICT_FALSE((unsigned)j > MAXEVENTS-1))
3194 {
3195 initprintf("%s:%d: error: invalid event ID.\n",g_scriptFileName,g_lineNumber);
3196 g_errorCnt++;
3197 continue;
3198 }
3199 // if event has already been declared then store previous script location
3200 if (!apScriptEvents[j])
3201 {
3202 apScriptEvents[j] = g_scriptEventOffset;
3203 }
3204 else if (tw == CON_ONEVENT)
3205 {
3206 g_scriptEventChainOffset = apScriptEvents[j];
3207 apScriptEvents[j] = g_scriptEventOffset;
3208 }
3209 else // if (tw == CON_APPENDEVENT)
3210 {
3211 auto previous_event_end = apScript + apScriptGameEventEnd[j];
3212 scriptWriteAtOffset(CON_JUMP | LINE_NUMBER, previous_event_end++);
3213 scriptWriteAtOffset(GV_FLAG_CONSTANT, previous_event_end++);
3214 C_FillEventBreakStackWithJump((intptr_t *)*previous_event_end, g_scriptEventOffset);
3215 scriptWriteAtOffset(g_scriptEventOffset, previous_event_end++);
3216 }
3217
3218 g_checkingIfElse = 0;
3219
3220 continue;
3221
3222 case CON_QSPRINTF:
3223 C_GetManyVars(2);
3224
3225 j = 0;
3226
3227 while (C_GetKeyword() == -1 && j < 32)
3228 C_GetNextVar(), j++;
3229
3230 scriptWriteValue(CON_NULLOP | LINE_NUMBER);
3231 continue;
3232
3233 case CON_CSTAT:
3234 C_GetNextValue(LABEL_DEFINE);
3235
3236 if (EDUKE32_PREDICT_FALSE(g_scriptPtr[-1] == 32767))
3237 {
3238 g_scriptPtr[-1] = 32768;
3239 C_ReportError(-1);
3240 initprintf("%s:%d: warning: tried to set cstat 32767, using 32768 instead.\n",g_scriptFileName,g_lineNumber);
3241 g_warningCnt++;
3242 }
3243 else if (EDUKE32_PREDICT_FALSE((g_scriptPtr[-1] & 48) == 48))
3244 {
3245 i = g_scriptPtr[-1];
3246 g_scriptPtr[-1] ^= 48;
3247 C_ReportError(-1);
3248 initprintf("%s:%d: warning: tried to set cstat %d, using %d instead.\n",g_scriptFileName,g_lineNumber,i,(int32_t)(g_scriptPtr[-1]));
3249 g_warningCnt++;
3250 }
3251 continue;
3252
3253 case CON_SCREENPAL:
3254 C_GetManyVars(4);
3255 continue;
3256
3257 case CON_HITRADIUS:
3258 case CON_DRAWLINE256:
3259 C_GetManyVars(5);
3260 continue;
3261
3262 case CON_DRAWLINERGB:
3263 C_GetManyVars(6);
3264 continue;
3265
3266 case CON_ADDAMMO:
3267 case CON_ADDINVENTORY:
3268 case CON_DEBRIS:
3269 case CON_GUTS:
3270 case CON_SIZEAT:
3271 case CON_SIZETO:
3272 C_GetNextValue(LABEL_DEFINE);
3273 fallthrough__;
3274 case CON_ADDKILLS:
3275 case CON_ADDPHEALTH:
3276 case CON_ADDSTRENGTH:
3277 case CON_CACTOR:
3278 case CON_CLIPDIST:
3279 case CON_COUNT:
3280 case CON_CSTATOR:
3281 case CON_DEBUG:
3282 case CON_ENDOFGAME:
3283 case CON_ENDOFLEVEL:
3284 case CON_LOTSOFGLASS:
3285 case CON_MAIL:
3286 case CON_MONEY:
3287 case CON_PAPER:
3288 case CON_SAVE:
3289 case CON_SAVENN:
3290 case CON_SLEEPTIME:
3291 case CON_SPAWN:
3292 case CON_SPRITEPAL:
3293 case CON_STRENGTH:
3294 C_GetNextValue(LABEL_DEFINE);
3295 continue;
3296
3297 case CON_QUOTE:
3298 C_GetNextValue(LABEL_DEFINE);
3299 if (EDUKE32_PREDICT_FALSE(((unsigned)g_scriptPtr[-1] >= MAXQUOTES) || apStrings[g_scriptPtr[-1]] == NULL))
3300 {
3301 g_errorCnt++;
3302 C_ReportError(-1);
3303 initprintf("%s:%d: error: invalid quote\n", g_scriptFileName, g_lineNumber);
3304 }
3305 continue;
3306
3307 case CON_ELSE:
3308 {
3309 if (EDUKE32_PREDICT_FALSE(!g_checkingIfElse))
3310 {
3311 g_scriptPtr--;
3312 auto const tempscrptr = g_scriptPtr;
3313 g_warningCnt++;
3314 C_ReportError(-1);
3315
3316 initprintf("%s:%d: warning: found `else' with no `if'\n", g_scriptFileName, g_lineNumber);
3317
3318 if (C_GetKeyword() == CON_LEFTBRACE)
3319 {
3320 C_GetNextKeyword();
3321 g_numBraces++;
3322
3323 C_ParseCommand(true);
3324 }
3325 else C_ParseCommand();
3326
3327 g_scriptPtr = tempscrptr;
3328
3329 continue;
3330 }
3331
3332 intptr_t const lastScriptPtr = &g_scriptPtr[-1] - apScript;
3333
3334 g_skipBranch = false;
3335 g_checkingIfElse--;
3336
3337 if (C_CheckMalformedBranch(lastScriptPtr))
3338 continue;
3339
3340 intptr_t const offset = (unsigned) (g_scriptPtr-apScript);
3341
3342 g_scriptPtr++; //Leave a spot for the fail location
3343
3344 C_ParseCommand();
3345
3346 if (C_CheckEmptyBranch(tw, lastScriptPtr))
3347 continue;
3348
3349 auto const tempscrptr = (intptr_t *) apScript+offset;
3350 scriptWritePointer((intptr_t)g_scriptPtr, tempscrptr);
3351
3352 continue;
3353 }
3354
3355 case CON_SETSECTOR:
3356 {
3357 intptr_t * const ins = &g_scriptPtr[-1];
3358 int const labelNum = C_GetStructureIndexes(1, &h_sector);
3359
3360 if (labelNum == -1)
3361 continue;
3362
3363 Bassert((*ins & VM_INSTMASK) == CON_SETSECTOR);
3364
3365 auto const &label = SectorLabels[labelNum];
3366
3367 if (label.offset != -1 && (label.flags & LABEL_WRITEFUNC) == 0)
3368 *ins = CON_SETSECTORSTRUCT | LINE_NUMBER;
3369
3370 scriptWriteValue(label.lId);
3371
3372 C_GetNextVar();
3373 continue;
3374 }
3375
3376 case CON_GETSECTOR:
3377 {
3378 intptr_t * const ins = &g_scriptPtr[-1];
3379 int const labelNum = C_GetStructureIndexes(1, &h_sector);
3380
3381 if (labelNum == -1)
3382 continue;
3383
3384 Bassert((*ins & VM_INSTMASK) == CON_GETSECTOR);
3385
3386 auto const &label = SectorLabels[labelNum];
3387
3388 if (label.offset != -1 && (label.flags & LABEL_READFUNC) == 0)
3389 *ins = CON_GETSECTORSTRUCT | LINE_NUMBER;
3390
3391 scriptWriteValue(label.lId);
3392
3393 C_GetNextVarType(GAMEVAR_READONLY);
3394 continue;
3395 }
3396
3397
3398 case CON_FINDNEARACTOR3D:
3399 case CON_FINDNEARACTOR:
3400 case CON_FINDNEARACTORZ:
3401 case CON_FINDNEARSPRITE3D:
3402 case CON_FINDNEARSPRITE:
3403 case CON_FINDNEARSPRITEZ:
3404 {
3405 C_GetNextValue(LABEL_DEFINE); // get <type>
3406
3407 // get the ID of the DEF
3408 C_GetNextVar();
3409 switch (tw)
3410 {
3411 case CON_FINDNEARACTORZ:
3412 case CON_FINDNEARSPRITEZ:
3413 C_GetNextVar();
3414 default:
3415 break;
3416 }
3417 // target var
3418 // get the ID of the DEF
3419 C_GetNextVarType(GAMEVAR_READONLY);
3420 continue;
3421 }
3422
3423 case CON_SETWALL:
3424 {
3425 intptr_t * const ins = &g_scriptPtr[-1];
3426 int const labelNum = C_GetStructureIndexes(1, &h_wall);
3427
3428 if (labelNum == -1)
3429 continue;
3430
3431 Bassert((*ins & VM_INSTMASK) == CON_SETWALL);
3432
3433 auto const &label = WallLabels[labelNum];
3434
3435 if (label.offset != -1 && (label.flags & LABEL_WRITEFUNC) == 0)
3436 *ins = CON_SETWALLSTRUCT | LINE_NUMBER;
3437
3438 scriptWriteValue(label.lId);
3439
3440 C_GetNextVar();
3441 continue;
3442 }
3443
3444 case CON_GETWALL:
3445 {
3446 intptr_t * const ins = &g_scriptPtr[-1];
3447 int const labelNum = C_GetStructureIndexes(1, &h_wall);
3448
3449 if (labelNum == -1)
3450 continue;
3451
3452 Bassert((*ins & VM_INSTMASK) == CON_GETWALL);
3453
3454 auto const &label = WallLabels[labelNum];
3455
3456 if (label.offset != -1 && (label.flags & LABEL_READFUNC) == 0)
3457 *ins = CON_GETWALLSTRUCT | LINE_NUMBER;
3458
3459 scriptWriteValue(label.lId);
3460
3461 C_GetNextVarType(GAMEVAR_READONLY);
3462 continue;
3463 }
3464
3465 case CON_SETPLAYER:
3466 {
3467 intptr_t * const ins = &g_scriptPtr[-1];
3468 int const labelNum = C_GetStructureIndexes(1, &h_player);
3469
3470 if (labelNum == -1)
3471 continue;
3472
3473 Bassert((*ins & VM_INSTMASK) == CON_SETPLAYER);
3474
3475 auto const &label = PlayerLabels[labelNum];
3476
3477 if (label.offset != -1 && (label.flags & (LABEL_WRITEFUNC|LABEL_HASPARM2)) == 0)
3478 *ins = CON_SETPLAYERSTRUCT | LINE_NUMBER;
3479
3480 scriptWriteValue(label.lId);
3481
3482 if (label.flags & LABEL_HASPARM2)
3483 C_GetNextVar();
3484
3485 C_GetNextVar();
3486 continue;
3487 }
3488
3489 case CON_GETPLAYER:
3490 {
3491 intptr_t * const ins = &g_scriptPtr[-1];
3492 int const labelNum = C_GetStructureIndexes(1, &h_player);
3493
3494 if (labelNum == -1)
3495 continue;
3496
3497 Bassert((*ins & VM_INSTMASK) == CON_GETPLAYER);
3498
3499 auto const &label = PlayerLabels[labelNum];
3500
3501 if (label.offset != -1 && (label.flags & (LABEL_READFUNC|LABEL_HASPARM2)) == 0)
3502 *ins = CON_GETPLAYERSTRUCT | LINE_NUMBER;
3503
3504 scriptWriteValue(label.lId);
3505
3506 if (label.flags & LABEL_HASPARM2)
3507 C_GetNextVar();
3508
3509 C_GetNextVarType(GAMEVAR_READONLY);
3510 continue;
3511 }
3512
3513 case CON_SETINPUT:
3514 case CON_GETINPUT:
3515 {
3516 int const labelNum = C_GetStructureIndexes(1, &h_input);
3517
3518 if (labelNum == -1)
3519 continue;
3520
3521 scriptWriteValue(InputLabels[labelNum].lId);
3522
3523 C_GetNextVarType(tw == CON_GETINPUT ? GAMEVAR_READONLY : 0);
3524 continue;
3525 }
3526
3527 case CON_SETTILEDATA:
3528 case CON_GETTILEDATA:
3529 {
3530 int const labelNum = C_GetStructureIndexes(0, &h_tiledata);
3531
3532 if (labelNum == -1)
3533 continue;
3534
3535 scriptWriteValue(TileDataLabels[labelNum].lId);
3536
3537 C_GetNextVarType((tw == CON_GETTILEDATA) ? GAMEVAR_READONLY : 0);
3538 continue;
3539 }
3540
3541 case CON_SETUSERDEF:
3542 case CON_GETUSERDEF:
3543 {
3544 // now get name of .xxx
3545 while (*textptr != '.')
3546 {
3547 if (*textptr == 0xa || !*textptr)
3548 break;
3549
3550 textptr++;
3551 }
3552
3553 if (EDUKE32_PREDICT_FALSE(*textptr!='.'))
3554 {
3555 g_errorCnt++;
3556 C_ReportError(ERROR_SYNTAXERROR);
3557 continue;
3558 }
3559 textptr++;
3560 C_GetNextLabelName();
3561
3562 int const labelNum=C_GetLabelNameID(UserdefsLabels,&h_userdef,Bstrtolower(LAST_LABEL));
3563
3564 if (EDUKE32_PREDICT_FALSE(labelNum == -1))
3565 {
3566 g_errorCnt++;
3567 C_ReportError(ERROR_NOTAMEMBER);
3568 continue;
3569 }
3570 scriptWriteValue(labelNum);
3571
3572 if (UserdefsLabels[labelNum].flags & LABEL_HASPARM2)
3573 C_GetNextVar();
3574
3575 C_GetNextVarType((tw == CON_GETUSERDEF) ? GAMEVAR_READONLY : 0);
3576 continue;
3577 }
3578
3579 case CON_SETACTOR:
3580 {
3581 intptr_t * const ins = &g_scriptPtr[-1];
3582 int const labelNum = C_GetStructureIndexes(1, &h_actor);
3583
3584 if (labelNum == -1)
3585 continue;
3586
3587 Bassert((*ins & VM_INSTMASK) == CON_SETACTOR);
3588
3589 auto const &label = ActorLabels[labelNum];
3590
3591 if (label.offset != -1 && (label.flags & (LABEL_WRITEFUNC|LABEL_HASPARM2)) == 0)
3592 {
3593 if (labelNum >= ACTOR_SPRITEEXT_BEGIN)
3594 *ins = CON_SETSPRITEEXT | LINE_NUMBER;
3595 else if (labelNum >= ACTOR_STRUCT_BEGIN)
3596 *ins = CON_SETACTORSTRUCT | LINE_NUMBER;
3597 else
3598 *ins = CON_SETSPRITESTRUCT | LINE_NUMBER;
3599 }
3600
3601 scriptWriteValue(label.lId);
3602
3603 if (label.flags & LABEL_HASPARM2)
3604 C_GetNextVar();
3605
3606 C_GetNextVar();
3607 continue;
3608 }
3609
3610 case CON_GETACTOR:
3611 {
3612 intptr_t * const ins = &g_scriptPtr[-1];
3613 int const labelNum = C_GetStructureIndexes(1, &h_actor);
3614
3615 if (labelNum == -1)
3616 continue;
3617
3618 Bassert((*ins & VM_INSTMASK) == CON_GETACTOR);
3619
3620 auto const &label = ActorLabels[labelNum];
3621
3622 if (label.offset != -1 && (label.flags & (LABEL_READFUNC|LABEL_HASPARM2)) == 0)
3623 {
3624 if (labelNum >= ACTOR_SPRITEEXT_BEGIN)
3625 *ins = CON_GETSPRITEEXT | LINE_NUMBER;
3626 else if (labelNum >= ACTOR_STRUCT_BEGIN)
3627 *ins = CON_GETACTORSTRUCT | LINE_NUMBER;
3628 else
3629 *ins = CON_GETSPRITESTRUCT | LINE_NUMBER;
3630 }
3631
3632 scriptWriteValue(label.lId);
3633
3634 if (label.flags & LABEL_HASPARM2)
3635 C_GetNextVar();
3636
3637 C_GetNextVarType(GAMEVAR_READONLY);
3638 continue;
3639 }
3640
3641 case CON_GETTSPR:
3642 case CON_SETTSPR:
3643 {
3644 #if 0
3645 if (unlikely(g_currentEvent != EVENT_ANIMATESPRITES))
3646 {
3647 C_ReportError(-1);
3648 initprintf("%s:%d: warning: found `%s' outside of EVENT_ANIMATESPRITES\n",g_szScriptFileName,g_lineNumber,tempbuf);
3649 g_numCompilerWarnings++;
3650 }
3651 #endif
3652 int const labelNum = C_GetStructureIndexes(1, &h_tsprite);
3653
3654 if (labelNum == -1)
3655 continue;
3656
3657 scriptWriteValue(TsprLabels[labelNum].lId);
3658
3659 C_GetNextVarType((tw == CON_GETTSPR) ? GAMEVAR_READONLY : 0);
3660 continue;
3661 }
3662 case CON_ADDLOGVAR:
3663 g_labelsOnly = 1;
3664 C_GetNextVar();
3665 g_labelsOnly = 0;
3666 continue;
3667
3668 case CON_COS:
3669 case CON_DIVR:
3670 case CON_DIVRU:
3671 case CON_HEADSPRITESECT:
3672 case CON_HEADSPRITESTAT:
3673 case CON_NEXTSPRITESECT:
3674 case CON_NEXTSPRITESTAT:
3675 case CON_PREVSPRITESECT:
3676 case CON_PREVSPRITESTAT:
3677 case CON_QSTRLEN:
3678 case CON_SECTOROFWALL:
3679 case CON_SIN:
3680 C_GetNextVarType(GAMEVAR_READONLY);
3681 fallthrough__;
3682 case CON_ACTIVATECHEAT:
3683 case CON_ANGOFF:
3684 case CON_CAPIA:
3685 case CON_CHECKACTIVATORMOTION:
3686 case CON_CHECKAVAILINVEN:
3687 case CON_CHECKAVAILWEAPON:
3688 case CON_CLEARMAPSTATE:
3689 case CON_CMENU:
3690 case CON_ECHO:
3691 case CON_EQSPAWN:
3692 case CON_ESHOOT:
3693 case CON_ESPAWN:
3694 case CON_GLOBALSOUND:
3695 case CON_GUNIQHUDID:
3696 case CON_INITTIMER:
3697 case CON_JUMP:
3698 case CON_LOCKPLAYER:
3699 case CON_MOVESECTOR:
3700 case CON_OPERATEMASTERSWITCHES:
3701 case CON_OPERATERESPAWNS:
3702 case CON_QSPAWN:
3703 case CON_QUAKE:
3704 case CON_RESETPLAYERFLAGS:
3705 case CON_SAVEGAMEVAR:
3706 case CON_SCREENSOUND:
3707 case CON_SECTCLEARINTERPOLATION:
3708 case CON_SECTSETINTERPOLATION:
3709 case CON_SETACTORANGLE:
3710 case CON_SETGAMEPALETTE:
3711 case CON_SETMUSICPOSITION:
3712 case CON_SETPLAYERANGLE:
3713 case CON_SHOOT:
3714 case CON_SOUNDONCE:
3715 case CON_SOUND:
3716 case CON_STARTCUTSCENE:
3717 case CON_STARTTRACK:
3718 case CON_STOPSOUND:
3719 case CON_TIME:
3720 case CON_USERQUOTE:
3721 C_GetNextVar();
3722 continue;
3723
3724 case CON_SQRT:
3725 C_GetNextVar();
3726 fallthrough__;
3727 case CON_DISPLAYRAND:
3728 case CON_FINDOTHERPLAYER:
3729 case CON_FINDPLAYER:
3730 case CON_GETACTORANGLE:
3731 case CON_GETANGLETOTARGET:
3732 case CON_GETCURRADDRESS:
3733 case CON_GETMUSICPOSITION:
3734 case CON_GETPLAYERANGLE:
3735 case CON_GETTICKS:
3736 case CON_INV:
3737 case CON_KLABS:
3738 case CON_READGAMEVAR:
3739 C_GetNextVarType(GAMEVAR_READONLY);
3740 continue;
3741
3742 case CON_CALCHYPOTENUSE:
3743 case CON_CLAMP:
3744 case CON_GETCLOSESTCOL:
3745 C_GetNextVarType(GAMEVAR_READONLY);
3746 fallthrough__;
3747 case CON_ACTORSOUND:
3748 case CON_CAPIS:
3749 case CON_CHANGESPRITESECT:
3750 case CON_CHANGESPRITESTAT:
3751 case CON_EZSHOOT:
3752 case CON_GETPNAME:
3753 case CON_PRELOADTRACKSLOTFORSWAP:
3754 case CON_QGETSYSSTR:
3755 case CON_QSTRCAT:
3756 case CON_QSTRCPY:
3757 case CON_SPAWNCEILINGGLASS:
3758 case CON_SPAWNWALLGLASS:
3759 case CON_SPAWNWALLSTAINEDGLASS:
3760 case CON_STARTLEVEL:
3761 case CON_STARTTRACKSLOT:
3762 case CON_STOPACTORSOUND:
3763 case CON_SWAPTRACKSLOT:
3764 case CON_ZSHOOT:
3765 case CON_GETGAMEFUNCBIND:
3766 C_GetManyVars(2);
3767 continue;
3768
3769 case CON_ENHANCED:
3770 g_scriptPtr--;
3771 C_GetNextValue(LABEL_DEFINE);
3772 g_scriptPtr--;
3773 if (EDUKE32_PREDICT_FALSE(*g_scriptPtr > BYTEVERSION_EDUKE32))
3774 {
3775 g_warningCnt++;
3776 initprintf("%s:%d: warning: need build %d, found build %d\n",g_scriptFileName,g_lineNumber,k,BYTEVERSION_EDUKE32);
3777 }
3778 continue;
3779
3780 case CON_DYNAMICREMAP:
3781 g_scriptPtr--;
3782 if (EDUKE32_PREDICT_FALSE(g_dynamicTileMapping))
3783 {
3784 initprintf("%s:%d: warning: duplicate dynamicremap statement\n",g_scriptFileName,g_lineNumber);
3785 g_warningCnt++;
3786 }
3787 #ifdef DYNTILEREMAP_ENABLE
3788 #ifdef DEBUGGINGAIDS
3789 else
3790 initprintf("Using dynamic tile remapping\n");
3791 #endif
3792 g_dynamicTileMapping = 1;
3793 #else
3794 else
3795 {
3796 initprintf("%s:%d: warning: dynamic tile remapping is disabled in this build\n",g_scriptFileName,g_lineNumber);
3797 g_warningCnt++;
3798 }
3799 #endif
3800 continue;
3801
3802 case CON_DYNAMICSOUNDREMAP:
3803 g_scriptPtr--;
3804 if (EDUKE32_PREDICT_FALSE(g_dynamicSoundMapping))
3805 {
3806 initprintf("%s:%d: warning: duplicate dynamicsoundremap statement\n",g_scriptFileName,g_lineNumber);
3807 g_warningCnt++;
3808 }
3809 else
3810 #ifdef DYNSOUNDREMAP_ENABLE
3811 #ifdef DEBUGGINGAIDS
3812 initprintf("Using dynamic sound remapping\n");
3813 #endif
3814
3815 g_dynamicSoundMapping = 1;
3816 #else
3817 {
3818 initprintf("%s:%d: warning: dynamic sound remapping is disabled in this build\n",g_scriptFileName,g_lineNumber);
3819 g_warningCnt++;
3820 }
3821 #endif
3822 continue;
3823
3824 case CON_ADDVAR:
3825 case CON_ANDVAR:
3826 case CON_DISPLAYRANDVAR:
3827 case CON_DIVVAR:
3828 case CON_MODVAR:
3829 case CON_MULVAR:
3830 case CON_ORVAR:
3831 case CON_RANDVAR:
3832 case CON_SETVAR:
3833 case CON_SHIFTVARL:
3834 case CON_SHIFTVARR:
3835 case CON_SUBVAR:
3836 case CON_XORVAR:
3837 setvar:
3838 {
3839 auto ins = &g_scriptPtr[-1];
3840
3841 C_GetNextVarType(GAMEVAR_READONLY);
3842 C_GetNextValue(LABEL_DEFINE);
3843
3844 // replace divides and multiplies by 0 with an error asking if the user is stupid
3845 if (ins[2] == 0 && (tw == CON_MODVAR || tw == CON_MULVAR || tw == CON_DIVVAR))
3846 {
3847 g_errorCnt++;
3848 C_ReportError(-1);
3849 initprintf("%s:%d: error: divide or multiply by zero! What are you doing?\n", g_scriptFileName, g_lineNumber);
3850 continue;
3851 }
3852 else if (tw == CON_DIVVAR || tw == CON_MULVAR)
3853 {
3854 auto const i = ins[2];
3855 // replace multiplies or divides by 1 with nullop
3856 if (i == 1)
3857 {
3858 int constexpr const opcode = CON_NULLOP;
3859
3860 if (!g_errorCnt && !g_warningCnt && g_scriptDebug > 1)
3861 {
3862 initprintf("%s:%d: %s -> %s\n", g_scriptFileName, g_lineNumber,
3863 VM_GetKeywordForID(tw), VM_GetKeywordForID(opcode));
3864 }
3865
3866 scriptWriteAtOffset(opcode | LINE_NUMBER, ins);
3867 g_scriptPtr = &ins[1];
3868 }
3869 // replace multiplies or divides by -1 with inversion
3870 else if (i == -1)
3871 {
3872 int constexpr const opcode = CON_INV;
3873
3874 if (g_scriptDebug > 1 && !g_errorCnt && !g_warningCnt)
3875 {
3876 initprintf("%s:%d: %s -> %s\n", g_scriptFileName, g_lineNumber,
3877 VM_GetKeywordForID(tw), VM_GetKeywordForID(opcode));
3878 }
3879
3880 scriptWriteAtOffset(opcode | LINE_NUMBER, ins);
3881 g_scriptPtr--;
3882 }
3883 }
3884 // replace instructions with special versions for specific var types
3885 scriptUpdateOpcodeForVariableType(ins);
3886 continue;
3887 }
3888
3889 case CON_ADDVARVAR:
3890 case CON_ANDVARVAR:
3891 case CON_DISPLAYRANDVARVAR:
3892 case CON_DIVVARVAR:
3893 case CON_MODVARVAR:
3894 case CON_MULVARVAR:
3895 case CON_ORVARVAR:
3896 case CON_RANDVARVAR:
3897 case CON_SETVARVAR:
3898 case CON_SHIFTVARVARL:
3899 case CON_SHIFTVARVARR:
3900 case CON_SUBVARVAR:
3901 case CON_XORVARVAR:
3902 {
3903 setvarvar:
3904 auto ins = &g_scriptPtr[-1];
3905 auto tptr = textptr;
3906 int const lnum = g_lineNumber;
3907
3908 C_GetNextVarType(GAMEVAR_READONLY);
3909 C_GetNextVar();
3910
3911 int const opcode = inthash_find(&h_varvar, *ins & VM_INSTMASK);
3912
3913 if (ins[2] == GV_FLAG_CONSTANT && opcode != -1)
3914 {
3915 if (g_scriptDebug > 1 && !g_errorCnt && !g_warningCnt)
3916 {
3917 initprintf("%s:%d: %s -> %s\n", g_scriptFileName, g_lineNumber,
3918 VM_GetKeywordForID(*ins & VM_INSTMASK), VM_GetKeywordForID(opcode));
3919 }
3920
3921 tw = opcode;
3922 scriptWriteAtOffset(opcode | LINE_NUMBER, ins);
3923 g_scriptPtr = &ins[1];
3924 textptr = tptr;
3925 g_lineNumber = lnum;
3926 goto setvar;
3927 }
3928
3929 continue;
3930 }
3931
3932 case CON_GETACTORVAR:
3933 case CON_GETPLAYERVAR:
3934 case CON_SETACTORVAR:
3935 case CON_SETPLAYERVAR:
3936 {
3937 // syntax [gs]etactorvar[<var>].<varx> <VAR>
3938 // gets the value of the per-actor variable varx into VAR
3939
3940 if (C_GetStructureIndexes(1, NULL) == -1)
3941 continue;
3942
3943 if (g_scriptPtr[-1] == g_thisActorVarID) // convert to "setvarvar"
3944 {
3945 g_scriptPtr--;
3946 g_scriptPtr[-1]=CON_SETVARVAR;
3947 if (tw == CON_SETACTORVAR || tw == CON_SETPLAYERVAR)
3948 {
3949 tw = inthash_find(&h_varvar, tw);
3950 goto setvarvar;
3951 }
3952 else
3953 {
3954 g_scriptPtr++;
3955 C_GetNextVar();
3956 g_scriptPtr-=2;
3957 C_GetNextVarType(GAMEVAR_READONLY);
3958 g_scriptPtr++;
3959 }
3960 continue;
3961 }
3962
3963 /// now pointing at 'xxx'
3964
3965 C_GetNextLabelName();
3966
3967 if (EDUKE32_PREDICT_FALSE(hash_find(&h_keywords,LAST_LABEL)>=0))
3968 {
3969 g_errorCnt++;
3970 C_ReportError(ERROR_ISAKEYWORD);
3971 continue;
3972 }
3973
3974 i=GetDefID(LAST_LABEL);
3975
3976 if (EDUKE32_PREDICT_FALSE(i<0))
3977 {
3978 g_errorCnt++;
3979 C_ReportError(ERROR_NOTAGAMEVAR);
3980 continue;
3981 }
3982 if (EDUKE32_PREDICT_FALSE(aGameVars[i].flags & GAMEVAR_READONLY))
3983 {
3984 g_errorCnt++;
3985 C_ReportError(ERROR_VARREADONLY);
3986 continue;
3987 }
3988
3989 switch (tw)
3990 {
3991 case CON_SETACTORVAR:
3992 if (EDUKE32_PREDICT_FALSE(!(aGameVars[i].flags & GAMEVAR_PERACTOR)))
3993 {
3994 g_errorCnt++;
3995 C_ReportError(-1);
3996 initprintf("%s:%d: error: variable `%s' is not per-actor.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
3997 continue;
3998 }
3999 break;
4000 case CON_SETPLAYERVAR:
4001 if (EDUKE32_PREDICT_FALSE(!(aGameVars[i].flags & GAMEVAR_PERPLAYER)))
4002 {
4003 g_errorCnt++;
4004 C_ReportError(-1);
4005 initprintf("%s:%d: error: variable `%s' is not per-player.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
4006 continue;
4007 }
4008 break;
4009 }
4010
4011 scriptWriteValue(i); // the ID of the DEF (offset into array...)
4012
4013 switch (tw)
4014 {
4015 case CON_GETACTORVAR:
4016 case CON_GETPLAYERVAR:
4017 C_GetNextVarType(GAMEVAR_READONLY);
4018 break;
4019 default:
4020 C_GetNextVar();
4021 break;
4022 }
4023 continue;
4024 }
4025
4026 case CON_WRITEARRAYTOFILE:
4027 case CON_READARRAYFROMFILE:
4028 i = C_GetNextGameArrayName();
4029 if (EDUKE32_PREDICT_FALSE(i < 0))
4030 return 1;
4031
4032 C_GetNextValue(LABEL_DEFINE);
4033 continue;
4034
4035 case CON_COPY:
4036 i = C_GetNextGameArrayName();
4037 if (EDUKE32_PREDICT_FALSE(i < 0))
4038 return 1;
4039
4040 C_SkipComments();
4041
4042 if (EDUKE32_PREDICT_FALSE(*textptr != '['))
4043 {
4044 g_errorCnt++;
4045 C_ReportError(ERROR_GAMEARRAYBNO);
4046 return 1;
4047 }
4048 textptr++;
4049 C_GetNextVar();
4050 C_SkipComments();
4051 if (EDUKE32_PREDICT_FALSE(*textptr != ']'))
4052 {
4053 g_errorCnt++;
4054 C_ReportError(ERROR_GAMEARRAYBNC);
4055 return 1;
4056 }
4057 textptr++;
4058 fallthrough__;
4059 case CON_SETARRAY:
4060 i = C_GetNextGameArrayName();
4061 if (EDUKE32_PREDICT_FALSE(i < 0))
4062 return 1;
4063
4064 if (EDUKE32_PREDICT_FALSE(aGameArrays[i].flags & GAMEARRAY_READONLY))
4065 {
4066 C_ReportError(ERROR_ARRAYREADONLY);
4067 g_errorCnt++;
4068 return 1;
4069 }
4070
4071 C_SkipComments();
4072 if (EDUKE32_PREDICT_FALSE(*textptr != '['))
4073 {
4074 g_errorCnt++;
4075 C_ReportError(ERROR_GAMEARRAYBNO);
4076 return 1;
4077 }
4078 textptr++;
4079 C_GetNextVar();
4080 C_SkipComments();
4081 if (EDUKE32_PREDICT_FALSE(*textptr != ']'))
4082 {
4083 g_errorCnt++;
4084 C_ReportError(ERROR_GAMEARRAYBNC);
4085 return 1;
4086 }
4087 textptr++;
4088 C_GetNextVar();
4089 continue;
4090
4091 case CON_GETARRAYSIZE:
4092 i = C_GetNextGameArrayName();
4093 if (EDUKE32_PREDICT_FALSE(i < 0))
4094 return 1;
4095 C_SkipComments();
4096 C_GetNextVarType(GAMEVAR_READONLY);
4097 continue;
4098
4099 case CON_GETARRAYSEQUENCE:
4100 case CON_SETARRAYSEQUENCE:
4101 {
4102 i = C_GetNextGameArrayName();
4103 if (EDUKE32_PREDICT_FALSE(i < 0))
4104 return 1;
4105 C_SkipComments();
4106
4107 auto pSize = g_scriptPtr++;
4108
4109 for (j = 0; j < MAX_ARRAYRANGE_VALUES; ++j)
4110 {
4111 if (C_GetKeyword() != -1)
4112 break;
4113
4114 C_GetNextVarType(tw == CON_GETARRAYSEQUENCE ? GAMEVAR_READONLY : 0);
4115 }
4116
4117 scriptWriteAtOffset(j, pSize);
4118 continue;
4119 }
4120
4121 case CON_RESIZEARRAY:
4122 i = C_GetNextGameArrayName();
4123 if (EDUKE32_PREDICT_FALSE(i < 0))
4124 return 1;
4125
4126 if (aGameArrays[i].flags & (GAMEARRAY_READONLY|GAMEARRAY_SYSTEM))
4127 {
4128 g_errorCnt++;
4129 C_ReportError(-1);
4130 initprintf("%s:%d: error: can't resize system array `%s'.\n", g_scriptFileName, g_lineNumber, LAST_LABEL);
4131 return 1;
4132 }
4133
4134 C_SkipComments();
4135 C_GetNextVarType(0);
4136 continue;
4137
4138 case CON_SWAPARRAYS:
4139 i = C_GetNextGameArrayName();
4140 if (EDUKE32_PREDICT_FALSE(i < 0))
4141 return 1;
4142
4143 if (aGameArrays[i].flags & (GAMEARRAY_READONLY|GAMEARRAY_SYSTEM|GAMEARRAY_VARSIZE))
4144 {
4145 g_errorCnt++;
4146 C_ReportError(-1);
4147 initprintf("%s:%d: error: can't swap system array `%s'.\n", g_scriptFileName, g_lineNumber, LAST_LABEL);
4148 return 1;
4149 }
4150
4151 C_SkipComments();
4152
4153 tw = C_GetNextGameArrayName();
4154 if (EDUKE32_PREDICT_FALSE(tw < 0))
4155 return 1;
4156
4157 if (aGameArrays[tw].flags & (GAMEARRAY_READONLY|GAMEARRAY_SYSTEM|GAMEARRAY_VARSIZE))
4158 {
4159 g_errorCnt++;
4160 C_ReportError(-1);
4161 initprintf("%s:%d: error: can't swap system array `%s'.\n", g_scriptFileName, g_lineNumber, LAST_LABEL);
4162 return 1;
4163 }
4164
4165 if ((aGameArrays[i].flags & GAMEARRAY_STORAGE_MASK) != (aGameArrays[tw].flags & GAMEARRAY_STORAGE_MASK))
4166 {
4167 g_errorCnt++;
4168 C_ReportError(-1);
4169 initprintf("%s:%d: error: can't swap arrays of different storage classes.\n", g_scriptFileName, g_lineNumber);
4170 return 1;
4171 }
4172
4173 continue;
4174
4175 case CON_ACTIVATEBYSECTOR:
4176 case CON_ADDWEAPON:
4177 case CON_DIST:
4178 case CON_DIVSCALE:
4179 case CON_GETANGLE:
4180 case CON_GETINCANGLE:
4181 case CON_GMAXAMMO:
4182 case CON_LDIST:
4183 case CON_MULSCALE:
4184 case CON_OPERATEACTIVATORS:
4185 case CON_OPERATESECTORS:
4186 case CON_SCALEVAR:
4187 case CON_SETASPECT:
4188 case CON_SMAXAMMO:
4189 case CON_SSP:
4190 // get the ID of the DEF
4191 switch (tw)
4192 {
4193 case CON_DIST:
4194 case CON_DIVSCALE:
4195 case CON_GETANGLE:
4196 case CON_GETINCANGLE:
4197 case CON_LDIST:
4198 case CON_MULSCALE:
4199 case CON_SCALEVAR:
4200 C_GetNextVarType(GAMEVAR_READONLY);
4201 break;
4202 default:
4203 C_GetNextVar();
4204 break;
4205 }
4206
4207 // get the ID of the DEF
4208 if (tw == CON_GMAXAMMO)
4209 C_GetNextVarType(GAMEVAR_READONLY);
4210 else C_GetNextVar();
4211
4212 switch (tw)
4213 {
4214 case CON_DIST:
4215 case CON_GETANGLE:
4216 case CON_GETINCANGLE:
4217 case CON_LDIST:
4218 C_GetNextVar();
4219 break;
4220 case CON_DIVSCALE:
4221 case CON_MULSCALE:
4222 case CON_SCALEVAR:
4223 C_GetManyVars(2);
4224 break;
4225 }
4226 continue;
4227
4228 case CON_FLASH:
4229 case CON_SAVEMAPSTATE:
4230 case CON_LOADMAPSTATE:
4231 if (tw != CON_FLASH)
4232 {
4233 if (EDUKE32_PREDICT_FALSE(g_currentEvent == EVENT_ANIMATESPRITES))
4234 {
4235 initprintf("%s:%d: warning: found `%s' inside EVENT_ANIMATESPRITES\n",
4236 g_scriptFileName,g_lineNumber,tempbuf);
4237 g_warningCnt++;
4238 }
4239 }
4240 continue;
4241
4242 case CON_ACTIVATE:
4243 g_scriptPtr[-1] = CON_OPERATEACTIVATORS | LINE_NUMBER;
4244 C_GetNextValue(LABEL_DEFINE);
4245 scriptWriteValue(0);
4246 continue;
4247
4248 case CON_GETFLORZOFSLOPE:
4249 case CON_GETCEILZOFSLOPE:
4250 case CON_UPDATESECTORZ:
4251 case CON_UPDATESECTORNEIGHBORZ:
4252 C_GetManyVars(3);
4253 C_GetNextVarType(GAMEVAR_READONLY);
4254 continue;
4255
4256 case CON_DEFINEPROJECTILE:
4257 {
4258 int32_t y, z;
4259
4260 if (EDUKE32_PREDICT_FALSE(g_processingState || g_scriptActorOffset))
4261 {
4262 C_ReportError(ERROR_FOUNDWITHIN);
4263 g_errorCnt++;
4264 }
4265
4266 g_scriptPtr--;
4267
4268 C_GetNextValue(LABEL_DEFINE);
4269 j = g_scriptPtr[-1];
4270 g_scriptPtr--;
4271
4272 C_GetNextValue(LABEL_DEFINE);
4273 y = g_scriptPtr[-1];
4274 g_scriptPtr--;
4275
4276 C_GetNextValue(LABEL_DEFINE);
4277 z = g_scriptPtr[-1];
4278 g_scriptPtr--;
4279
4280 if (EDUKE32_PREDICT_FALSE((unsigned)j >= MAXTILES))
4281 {
4282 C_ReportError(ERROR_EXCEEDSMAXTILES);
4283 g_errorCnt++;
4284 continue;
4285 }
4286
4287 C_DefineProjectile(j, y, z);
4288 continue;
4289 }
4290
4291 case CON_DAMAGEEVENTTILE:
4292 {
4293 if (EDUKE32_PREDICT_FALSE(g_processingState || g_scriptActorOffset))
4294 {
4295 C_ReportError(ERROR_FOUNDWITHIN);
4296 g_errorCnt++;
4297 }
4298
4299 g_scriptPtr--;
4300
4301 C_GetNextValue(LABEL_DEFINE);
4302 j = g_scriptPtr[-1];
4303 g_scriptPtr--;
4304
4305 if (EDUKE32_PREDICT_FALSE((unsigned)j >= MAXTILES))
4306 {
4307 C_ReportError(ERROR_EXCEEDSMAXTILES);
4308 g_errorCnt++;
4309 continue;
4310 }
4311
4312 g_tile[j].flags |= SFLAG_DAMAGEEVENT;
4313
4314 continue;
4315 }
4316
4317 case CON_DAMAGEEVENTTILERANGE:
4318 {
4319 if (EDUKE32_PREDICT_FALSE(g_processingState || g_scriptActorOffset))
4320 {
4321 C_ReportError(ERROR_FOUNDWITHIN);
4322 g_errorCnt++;
4323 }
4324
4325 g_scriptPtr--;
4326
4327 C_GetNextValue(LABEL_DEFINE);
4328 i = g_scriptPtr[-1];
4329 g_scriptPtr--;
4330
4331 C_GetNextValue(LABEL_DEFINE);
4332 j = g_scriptPtr[-1];
4333 g_scriptPtr--;
4334
4335 if (EDUKE32_PREDICT_FALSE((unsigned)i >= MAXTILES || (unsigned)j >= MAXTILES))
4336 {
4337 C_ReportError(ERROR_EXCEEDSMAXTILES);
4338 g_errorCnt++;
4339 continue;
4340 }
4341
4342 for (tiledata_t * t = g_tile + i, * t_end = g_tile + j; t <= t_end; ++t)
4343 t->flags |= SFLAG_DAMAGEEVENT;
4344
4345 continue;
4346 }
4347
4348 case CON_SPRITEFLAGS:
4349 if (!g_scriptActorOffset && g_processingState == 0)
4350 {
4351 g_scriptPtr--;
4352 auto tmpscrptr = g_scriptPtr;
4353
4354 C_GetNextValue(LABEL_DEFINE);
4355 j = g_scriptPtr[-1];
4356
4357 int32_t flags = 0;
4358 do
4359 C_BitOrNextValue(&flags);
4360 while (C_GetKeyword() == -1);
4361
4362 g_scriptPtr = tmpscrptr;
4363
4364 if (EDUKE32_PREDICT_FALSE((unsigned)j >= MAXTILES))
4365 {
4366 C_ReportError(ERROR_EXCEEDSMAXTILES);
4367 g_errorCnt++;
4368 continue;
4369 }
4370
4371 g_tile[j].flags = flags;
4372 }
4373 else C_GetNextVar();
4374 continue;
4375
4376 case CON_PRECACHE:
4377 case CON_SPRITENOPAL:
4378 case CON_SPRITENOSHADE:
4379 case CON_SPRITENVG:
4380 case CON_SPRITESHADOW:
4381 if (EDUKE32_PREDICT_FALSE(g_processingState || g_scriptActorOffset))
4382 {
4383 C_ReportError(ERROR_FOUNDWITHIN);
4384 g_errorCnt++;
4385 scriptSkipLine();
4386 continue;
4387 }
4388
4389 g_scriptPtr--;
4390
4391 C_GetNextValue(LABEL_DEFINE);
4392 g_scriptPtr--;
4393 j = *g_scriptPtr;
4394
4395 if (EDUKE32_PREDICT_FALSE((unsigned)j >= MAXTILES))
4396 {
4397 C_ReportError(ERROR_EXCEEDSMAXTILES);
4398 g_errorCnt++;
4399 scriptSkipLine();
4400 continue;
4401 }
4402
4403 switch (tw)
4404 {
4405 case CON_SPRITESHADOW:
4406 g_tile[*g_scriptPtr].flags |= SFLAG_SHADOW;
4407 break;
4408 case CON_SPRITENVG:
4409 g_tile[*g_scriptPtr].flags |= SFLAG_NVG;
4410 break;
4411 case CON_SPRITENOSHADE:
4412 g_tile[*g_scriptPtr].flags |= SFLAG_NOSHADE;
4413 break;
4414 case CON_SPRITENOPAL:
4415 g_tile[*g_scriptPtr].flags |= SFLAG_NOPAL;
4416 break;
4417 case CON_PRECACHE:
4418 C_GetNextValue(LABEL_DEFINE);
4419 g_scriptPtr--;
4420 i = *g_scriptPtr;
4421 if (EDUKE32_PREDICT_FALSE((unsigned)i >= MAXTILES))
4422 {
4423 C_ReportError(ERROR_EXCEEDSMAXTILES);
4424 g_errorCnt++;
4425 scriptSkipLine();
4426 continue;
4427 }
4428 g_tile[j].cacherange = i;
4429
4430 C_GetNextValue(LABEL_DEFINE);
4431 g_scriptPtr--;
4432 if (*g_scriptPtr)
4433 g_tile[j].flags |= SFLAG_CACHE;
4434
4435 break;
4436 }
4437 continue;
4438
4439 case CON_IFACTORSOUND:
4440 case CON_IFVARVARA:
4441 case CON_IFVARVARAE:
4442 case CON_IFVARVARAND:
4443 case CON_IFVARVARB:
4444 case CON_IFVARVARBE:
4445 case CON_IFVARVARBOTH:
4446 case CON_IFVARVARE:
4447 case CON_IFVARVAREITHER:
4448 case CON_IFVARVARG:
4449 case CON_IFVARVARGE:
4450 case CON_IFVARVARL:
4451 case CON_IFVARVARLE:
4452 case CON_IFVARVARN:
4453 case CON_IFVARVAROR:
4454 case CON_IFVARVARXOR:
4455 case CON_WHILEVARVARL:
4456 case CON_WHILEVARVARN:
4457 {
4458 auto const ins = &g_scriptPtr[-1];
4459 auto const lastScriptPtr = &g_scriptPtr[-1] - apScript;
4460 auto const lasttextptr = textptr;
4461 int const lnum = g_lineNumber;
4462
4463 g_skipBranch = false;
4464
4465 C_GetNextVar();
4466 auto const var = g_scriptPtr;
4467 C_GetNextVar();
4468
4469 if (*var == GV_FLAG_CONSTANT)
4470 {
4471 int const opcode = inthash_find(&h_varvar, tw);
4472
4473 if (opcode != -1)
4474 {
4475 if (g_scriptDebug > 1 && !g_errorCnt && !g_warningCnt)
4476 {
4477 initprintf("%s:%d: replacing %s with %s\n", g_scriptFileName, g_lineNumber,
4478 VM_GetKeywordForID(*ins & VM_INSTMASK), VM_GetKeywordForID(opcode));
4479 }
4480
4481 scriptWriteAtOffset(opcode | LINE_NUMBER, ins);
4482 tw = opcode;
4483 g_scriptPtr = &ins[1];
4484 textptr = lasttextptr;
4485 g_lineNumber = lnum;
4486 goto ifvar;
4487 }
4488 }
4489
4490 if (C_CheckMalformedBranch(lastScriptPtr))
4491 continue;
4492
4493 auto const offset = g_scriptPtr - apScript;
4494 g_scriptPtr++; // Leave a spot for the fail location
4495
4496 C_ParseCommand();
4497
4498 if (C_CheckEmptyBranch(tw, lastScriptPtr))
4499 continue;
4500
4501 auto const tempscrptr = apScript + offset;
4502 scriptWritePointer((intptr_t)g_scriptPtr, tempscrptr);
4503
4504 if (tw != CON_WHILEVARVARN && tw != CON_WHILEVARVARL)
4505 {
4506 j = C_GetKeyword();
4507
4508 if (j == CON_ELSE)
4509 g_checkingIfElse++;
4510 }
4511 continue;
4512 }
4513
4514 case CON_IFVARA:
4515 case CON_IFVARAE:
4516 case CON_IFVARAND:
4517 case CON_IFVARB:
4518 case CON_IFVARBE:
4519 case CON_IFVARBOTH:
4520 case CON_IFVARE:
4521 case CON_IFVAREITHER:
4522 case CON_IFVARG:
4523 case CON_IFVARGE:
4524 case CON_IFVARL:
4525 case CON_IFVARLE:
4526 case CON_IFVARN:
4527 case CON_IFVAROR:
4528 case CON_IFVARXOR:
4529 case CON_WHILEVARL:
4530 case CON_WHILEVARN:
4531 {
4532 ifvar:
4533 auto const ins = &g_scriptPtr[-1];
4534 auto const lastScriptPtr = &g_scriptPtr[-1] - apScript;
4535
4536 g_skipBranch = false;
4537
4538 C_GetNextVar();
4539 C_GetNextValue(LABEL_DEFINE);
4540
4541 if (C_CheckMalformedBranch(lastScriptPtr))
4542 continue;
4543
4544 scriptUpdateOpcodeForVariableType(ins);
4545
4546 auto const offset = g_scriptPtr - apScript;
4547 g_scriptPtr++; //Leave a spot for the fail location
4548
4549 C_ParseCommand();
4550
4551 if (C_CheckEmptyBranch(tw, lastScriptPtr))
4552 continue;
4553
4554 auto const tempscrptr = apScript + offset;
4555 scriptWritePointer((intptr_t)g_scriptPtr, tempscrptr);
4556
4557 if (tw != CON_WHILEVARN && tw != CON_WHILEVARL)
4558 {
4559 j = C_GetKeyword();
4560
4561 if (j == CON_ELSE)
4562 g_checkingIfElse++;
4563 }
4564
4565 continue;
4566 }
4567
4568 case CON_FOR: // special-purpose iteration
4569 {
4570 C_GetNextVarType(GAMEVAR_READONLY);
4571 C_GetNextLabelName();
4572
4573 int const iterType = hash_find(&h_iter, LAST_LABEL);
4574
4575 if (EDUKE32_PREDICT_FALSE(iterType < 0))
4576 {
4577 C_CUSTOMERROR("unknown iteration type `%s'.", LAST_LABEL);
4578 return 1;
4579 }
4580
4581 scriptWriteValue(iterType);
4582
4583 if (iterType >= ITER_SPRITESOFSECTOR)
4584 C_GetNextVar();
4585
4586 intptr_t const offset = g_scriptPtr-apScript;
4587 g_scriptPtr++; //Leave a spot for the location to jump to after completion
4588
4589 C_ParseCommand();
4590
4591 // write relative offset
4592 auto const tscrptr = (intptr_t *) apScript+offset;
4593 scriptWriteAtOffset((g_scriptPtr-apScript)-offset, tscrptr);
4594 continue;
4595 }
4596
4597 case CON_ROTATESPRITE16:
4598 case CON_ROTATESPRITE:
4599 if (EDUKE32_PREDICT_FALSE(!g_scriptEventOffset && g_processingState == 0))
4600 {
4601 C_ReportError(ERROR_EVENTONLY);
4602 g_errorCnt++;
4603 }
4604
4605 // syntax:
4606 // int32_t x, int32_t y, int32_t z, short a, short tilenum, int8_t shade, char orientation, x1, y1, x2, y2
4607 // myospal adds char pal
4608
4609 // get the ID of the DEFs
4610
4611 C_GetManyVars(12);
4612 continue;
4613
4614 case CON_ROTATESPRITEA:
4615 if (EDUKE32_PREDICT_FALSE(!g_scriptEventOffset && g_processingState == 0))
4616 {
4617 C_ReportError(ERROR_EVENTONLY);
4618 g_errorCnt++;
4619 }
4620
4621 C_GetManyVars(13);
4622 continue;
4623
4624 case CON_SHOWVIEW:
4625 case CON_SHOWVIEWUNBIASED:
4626 case CON_SHOWVIEWQ16:
4627 case CON_SHOWVIEWQ16UNBIASED:
4628 if (EDUKE32_PREDICT_FALSE(!g_scriptEventOffset && g_processingState == 0))
4629 {
4630 C_ReportError(ERROR_EVENTONLY);
4631 g_errorCnt++;
4632 }
4633
4634 C_GetManyVars(10);
4635 continue;
4636
4637 case CON_GETZRANGE:
4638 C_GetManyVars(4);
4639 C_GetManyVarsType(GAMEVAR_READONLY,4);
4640 C_GetManyVars(2);
4641 continue;
4642
4643 case CON_CLIPMOVE:
4644 case CON_CLIPMOVENOSLIDE:
4645 // <retvar>,<x>,<y>,z,<sectnum>, xvect,yvect,walldist,floordist,ceildist,clipmask
4646 C_GetManyVarsType(GAMEVAR_READONLY,3);
4647 C_GetNextVar();
4648 C_GetNextVarType(GAMEVAR_READONLY);
4649 C_GetManyVars(6);
4650 continue;
4651
4652 case CON_LINEINTERSECT:
4653 case CON_RAYINTERSECT:
4654 // lineintersect x y z x y z x y x y <intx> <inty> <intz> <ret>
4655 // rayintersect x y z vx vy vz x y x y <intx> <inty> <intz> <ret>
4656 C_GetManyVars(10);
4657 C_GetManyVarsType(GAMEVAR_READONLY,4);
4658 continue;
4659
4660 case CON_HITSCAN:
4661 case CON_CANSEE:
4662 // get the ID of the DEF
4663 C_GetManyVars(tw==CON_CANSEE?8:7);
4664 C_GetManyVarsType(GAMEVAR_READONLY,tw==CON_CANSEE?1:6);
4665 if (tw==CON_HITSCAN) C_GetNextVar();
4666 continue;
4667
4668 case CON_CANSEESPR:
4669 case CON_UPDATESECTOR:
4670 case CON_UPDATESECTORNEIGHBOR:
4671 case CON_QSTRCMP:
4672 C_GetManyVars(2);
4673 C_GetNextVarType(GAMEVAR_READONLY);
4674 continue;
4675
4676 case CON_NEARTAG:
4677 C_GetManyVars(5);
4678 C_GetManyVarsType(GAMEVAR_READONLY,4);
4679 C_GetManyVars(2);
4680 continue;
4681
4682 case CON_ROTATEPOINT:
4683 C_GetManyVars(5);
4684 C_GetManyVarsType(GAMEVAR_READONLY,2);
4685 continue;
4686
4687 case CON_GETTIMEDATE:
4688 C_GetManyVarsType(GAMEVAR_READONLY,8);
4689 continue;
4690
4691 case CON_MOVESPRITE:
4692 C_GetManyVars(5);
4693 C_GetNextVarType(GAMEVAR_READONLY);
4694 continue;
4695
4696 case CON_DIGITALNUMBER:
4697 case CON_DIGITALNUMBERZ:
4698 case CON_GAMETEXT:
4699 case CON_GAMETEXTZ:
4700 case CON_MINITEXT:
4701 case CON_SCREENTEXT:
4702 if (EDUKE32_PREDICT_FALSE(!g_scriptEventOffset && g_processingState == 0))
4703 {
4704 C_ReportError(ERROR_EVENTONLY);
4705 g_errorCnt++;
4706 }
4707
4708 switch (tw)
4709 {
4710 case CON_SCREENTEXT:
4711 C_GetManyVars(8);
4712 fallthrough__;
4713 case CON_GAMETEXTZ:
4714 case CON_DIGITALNUMBERZ:
4715 C_GetManyVars(1);
4716 fallthrough__;
4717 case CON_GAMETEXT:
4718 case CON_DIGITALNUMBER:
4719 C_GetManyVars(6);
4720 fallthrough__;
4721 default:
4722 C_GetManyVars(5);
4723 break;
4724 }
4725 continue;
4726
4727 case CON_MYOS:
4728 case CON_MYOSPAL:
4729 case CON_MYOSX:
4730 case CON_MYOSPALX:
4731 if (EDUKE32_PREDICT_FALSE(!g_scriptEventOffset && g_processingState == 0))
4732 {
4733 C_ReportError(ERROR_EVENTONLY);
4734 g_errorCnt++;
4735 }
4736
4737 // syntax:
4738 // int32_t x, int32_t y, short tilenum, int8_t shade, char orientation
4739 // myospal adds char pal
4740
4741 C_GetManyVars(5);
4742 if (tw==CON_MYOSPAL || tw==CON_MYOSPALX)
4743 {
4744 // Parse: pal
4745
4746 // get the ID of the DEF
4747 C_GetNextVar();
4748 }
4749 continue;
4750
4751 case CON_SWITCH:
4752 {
4753 g_checkingSwitch++; // allow nesting (if other things work)
4754 C_GetNextVar();
4755
4756 intptr_t const tempoffset = (unsigned)(g_scriptPtr-apScript);
4757
4758 scriptWriteValue(0); // leave spot for end location (for after processing)
4759 scriptWriteValue(0); // count of case statements
4760
4761 auto const backupCaseScriptPtr = g_caseTablePtr;
4762 g_caseTablePtr=g_scriptPtr; // the first case's pointer.
4763
4764 int const backupNumCases = g_numCases;
4765
4766 scriptWriteValue(0); // leave spot for 'default' location (null if none)
4767
4768 // temptextptr=textptr;
4769 // probably does not allow nesting...
4770
4771 j=C_CountCaseStatements();
4772 // initprintf("Done Counting Case Statements for switch %d: found %d.\n", g_checkingSwitch,j);
4773 g_scriptPtr+=j*2;
4774 C_SkipComments();
4775 g_scriptPtr-=j*2; // allocate buffer for the table
4776 auto tempscrptr = (intptr_t *)(apScript+tempoffset);
4777
4778 //AddLog(g_szBuf);
4779
4780 if (j<0)
4781 {
4782 return 1;
4783 }
4784
4785 if (tempscrptr)
4786 {
4787 // save count of cases
4788 scriptWriteAtOffset(j, &tempscrptr[1]);
4789 }
4790 else
4791 {
4792 //Bsprintf(g_szBuf,"ERROR::%s %d",__FILE__,__LINE__);
4793 //AddLog(g_szBuf);
4794 }
4795
4796 while (j--)
4797 {
4798 // leave room for statements
4799
4800 scriptWriteValue(0); // value check
4801 scriptWriteValue(0); // code offset
4802 C_SkipComments();
4803 }
4804
4805 g_numCases=0;
4806 C_ParseCommand(true);
4807 tempscrptr = (intptr_t *)(apScript+tempoffset);
4808
4809 //Bsprintf(g_szBuf,"SWITCHXX: '%.22s'",textptr);
4810 //AddLog(g_szBuf);
4811 // done processing switch. clean up.
4812 if (g_checkingSwitch<1)
4813 {
4814 // Bsprintf(g_szBuf,"ERROR::%s %d: g_checkingSwitch=%d",__FILE__,__LINE__, g_checkingSwitch);
4815 // AddLog(g_szBuf);
4816 }
4817 g_numCases=0;
4818
4819 if (tempscrptr)
4820 {
4821 for (i = 3; i < 3 + tempscrptr[1] * 2 - 2; i += 2) // sort them
4822 {
4823 intptr_t t = tempscrptr[i];
4824 int n = i;
4825
4826 for (j = i + 2; j < 3 + tempscrptr[1] * 2; j += 2)
4827 {
4828 if (tempscrptr[j] < t)
4829 {
4830 t = tempscrptr[j];
4831 n = j;
4832 }
4833 }
4834
4835 if (n != i)
4836 {
4837 swapptr(&tempscrptr[i], &tempscrptr[n]);
4838 swapptr(&tempscrptr[i+1], &tempscrptr[n+1]);
4839 }
4840 }
4841 // for (j=3;j<3+tempscrptr[1]*2;j+=2)initprintf("%5d %8x\n",tempscrptr[j],tempscrptr[j+1]);
4842
4843 // save 'end' location
4844 scriptWriteAtOffset((intptr_t)g_scriptPtr - (intptr_t)apScript, tempscrptr);
4845 }
4846 else
4847 {
4848 //Bsprintf(g_szBuf,"ERROR::%s %d",__FILE__,__LINE__);
4849 //AddLog(g_szBuf);
4850 }
4851 g_caseTablePtr=backupCaseScriptPtr;
4852 g_numCases=backupNumCases;
4853 //AddLog("End of Switch statement");
4854 }
4855 continue;
4856
4857 case CON_CASE:
4858 case CON_DEFAULT:
4859 {
4860 if (EDUKE32_PREDICT_FALSE(g_checkingSwitch < 1))
4861 {
4862 g_errorCnt++;
4863 C_ReportError(-1);
4864 initprintf("%s:%d: error: found `%s' statement when not in switch\n", g_scriptFileName,
4865 g_lineNumber, tw == CON_CASE ? "case" : "default");
4866 g_scriptPtr--;
4867 return 1;
4868 }
4869
4870 intptr_t tempoffset = 0;
4871 intptr_t *tempscrptr = g_scriptPtr;
4872
4873 g_checkingCase = true;
4874 repeatcase:
4875 g_scriptPtr--;
4876
4877 C_SkipComments();
4878
4879 if (tw == CON_CASE)
4880 {
4881 g_numCases++;
4882 C_GetNextValue(LABEL_ANY);
4883 j= *(--g_scriptPtr);
4884 }
4885
4886 C_SkipComments();
4887
4888 if (*textptr == ':')
4889 textptr++;
4890
4891 C_SkipComments();
4892
4893 if (g_caseTablePtr)
4894 {
4895 if (tw == CON_DEFAULT)
4896 {
4897 if (EDUKE32_PREDICT_FALSE(g_caseTablePtr[0] != 0))
4898 {
4899 // duplicate default statement
4900 g_errorCnt++;
4901 C_ReportError(-1);
4902 initprintf("%s:%d: error: multiple `default' statements found in switch\n", g_scriptFileName, g_lineNumber);
4903 }
4904 g_caseTablePtr[0]=(intptr_t) (g_scriptPtr-apScript); // save offset
4905 }
4906 else
4907 {
4908 for (i=(g_numCases/2)-1; i>=0; i--)
4909 if (EDUKE32_PREDICT_FALSE(g_caseTablePtr[i*2+1]==j))
4910 {
4911 g_warningCnt++;
4912 C_ReportError(WARNING_DUPLICATECASE);
4913 break;
4914 }
4915 g_caseTablePtr[g_numCases++]=j;
4916 g_caseTablePtr[g_numCases]=(intptr_t) ((intptr_t *) g_scriptPtr-apScript);
4917 }
4918 }
4919
4920 j = C_GetKeyword();
4921
4922 if (j == CON_CASE || j == CON_DEFAULT)
4923 {
4924 //AddLog("Found Repeat Case");
4925 C_GetNextKeyword(); // eat keyword
4926 tw = j;
4927 goto repeatcase;
4928 }
4929
4930 tempoffset = (unsigned)(tempscrptr-apScript);
4931
4932 while (C_ParseCommand() == 0)
4933 {
4934 j = C_GetKeyword();
4935
4936 if (j == CON_CASE || j == CON_DEFAULT)
4937 {
4938 C_GetNextKeyword(); // eat keyword
4939 tempscrptr = (intptr_t *)(apScript+tempoffset);
4940 tw = j;
4941 goto repeatcase;
4942 }
4943 }
4944
4945 continue;
4946 }
4947
4948 case CON_ENDSWITCH:
4949 //AddLog("End Switch");
4950 if (g_caseTablePtr)
4951 {
4952 if (EDUKE32_PREDICT_FALSE(g_checkingCase))
4953 {
4954 g_errorCnt++;
4955 C_ReportError(-1);
4956 initprintf("%s:%d: error: found `endswitch' before `break' or `return'\n", g_scriptFileName, g_lineNumber);
4957 }
4958 }
4959
4960 if (EDUKE32_PREDICT_FALSE(--g_checkingSwitch < 0))
4961 {
4962 g_errorCnt++;
4963 C_ReportError(-1);
4964 initprintf("%s:%d: error: found `endswitch' without matching `switch'\n", g_scriptFileName, g_lineNumber);
4965 }
4966 return 1; // end of block
4967
4968 case CON_DRAGPOINT:
4969 case CON_GETKEYNAME:
4970 case CON_QSTRNCAT:
4971 case CON_SETACTORSOUNDPITCH:
4972 C_GetManyVars(3);
4973 continue;
4974
4975 case CON_QSTRDIM:
4976 C_GetManyVarsType(GAMEVAR_READONLY, 2);
4977 C_GetManyVars(16);
4978 continue;
4979
4980 case CON_QSUBSTR:
4981 case CON_SETSPRITE:
4982 case CON_NEXTSECTORNEIGHBORZ:
4983 C_GetManyVars(4);
4984 continue;
4985
4986 case CON_IFACTION:
4987 case CON_IFACTIONCOUNT:
4988 case CON_IFACTOR:
4989 case CON_IFAI:
4990 case CON_IFANGDIFFL:
4991 case CON_IFCEILINGDISTL:
4992 case CON_IFCOUNT:
4993 case CON_IFCUTSCENE:
4994 case CON_IFFLOORDISTL:
4995 case CON_IFGAPZL:
4996 case CON_IFGOTWEAPONCE:
4997 case CON_IFMOVE:
4998 case CON_IFP:
4999 case CON_IFPDISTG:
5000 case CON_IFPDISTL:
5001 case CON_IFPHEALTHL:
5002 case CON_IFPINVENTORY:
5003 case CON_IFPLAYERSL:
5004 case CON_IFRND:
5005 case CON_IFSOUND:
5006 case CON_IFSPAWNEDBY:
5007 case CON_IFSPRITEPAL:
5008 case CON_IFSTRENGTH:
5009 case CON_IFWASWEAPON:
5010 {
5011 auto const lastScriptPtr = &g_scriptPtr[-1] - apScript;
5012
5013 g_skipBranch = false;
5014
5015 switch (tw)
5016 {
5017 case CON_IFCUTSCENE:
5018 C_GetNextVar();
5019 break;
5020 case CON_IFAI:
5021 C_GetNextValue(LABEL_AI);
5022 break;
5023 case CON_IFACTION:
5024 C_GetNextValue(LABEL_ACTION);
5025 break;
5026 case CON_IFMOVE:
5027 if (EDUKE32_PREDICT_FALSE((C_GetNextValue(LABEL_MOVE|LABEL_DEFINE) == 0) && (g_scriptPtr[-1] != 0) && (g_scriptPtr[-1] != 1)))
5028 {
5029 C_ReportError(-1);
5030 g_scriptPtr[-1] = 0;
5031 initprintf("%s:%d: warning: expected a move, found a constant.\n",g_scriptFileName,g_lineNumber);
5032 g_warningCnt++;
5033 }
5034 break;
5035 case CON_IFPINVENTORY:
5036 C_GetNextValue(LABEL_DEFINE);
5037 C_GetNextValue(LABEL_DEFINE);
5038 break;
5039 case CON_IFP:
5040 j = 0;
5041 do
5042 C_BitOrNextValue(&j);
5043 while (C_GetKeyword() == -1);
5044 C_FinishBitOr(j);
5045 break;
5046 case CON_IFSOUND:
5047 case CON_IFACTORSOUND:
5048 default:
5049 C_GetNextValue(LABEL_DEFINE);
5050 break;
5051 }
5052
5053 if (C_CheckMalformedBranch(lastScriptPtr))
5054 continue;
5055
5056 intptr_t const offset = (unsigned)(g_scriptPtr-apScript);
5057
5058 g_scriptPtr++; //Leave a spot for the fail location
5059
5060 C_ParseCommand();
5061
5062 if (C_CheckEmptyBranch(tw, lastScriptPtr))
5063 continue;
5064
5065 auto const tempscrptr = (intptr_t *)apScript+offset;
5066 scriptWritePointer((intptr_t)g_scriptPtr, tempscrptr);
5067
5068 j = C_GetKeyword();
5069
5070 if (j == CON_ELSE)
5071 g_checkingIfElse++;
5072
5073 continue;
5074 }
5075
5076 case CON_IFACTORNOTSTAYPUT:
5077 case CON_IFAWAYFROMWALL:
5078 case CON_IFBULLETNEAR:
5079 case CON_IFCANSEE:
5080 case CON_IFCANSEETARGET:
5081 case CON_IFCANSHOOTTARGET:
5082 case CON_IFCLIENT:
5083 case CON_IFDEAD:
5084 case CON_IFHITSPACE:
5085 case CON_IFHITWEAPON:
5086 case CON_IFINOUTERSPACE:
5087 case CON_IFINSPACE:
5088 case CON_IFINWATER:
5089 case CON_IFMULTIPLAYER:
5090 case CON_IFNOSOUNDS:
5091 case CON_IFNOTMOVING:
5092 case CON_IFONWATER:
5093 case CON_IFOUTSIDE:
5094 case CON_IFPLAYBACKON:
5095 case CON_IFRESPAWN:
5096 case CON_IFSERVER:
5097 case CON_IFSQUISHED:
5098 {
5099 auto const lastScriptPtr = &g_scriptPtr[-1] - apScript;
5100
5101 g_skipBranch = false;
5102
5103 if (C_CheckMalformedBranch(lastScriptPtr))
5104 continue;
5105
5106 intptr_t const offset = (unsigned)(g_scriptPtr-apScript);
5107
5108 g_scriptPtr++; //Leave a spot for the fail location
5109
5110 C_ParseCommand();
5111
5112 if (C_CheckEmptyBranch(tw, lastScriptPtr))
5113 continue;
5114
5115 auto const tempscrptr = (intptr_t *)apScript+offset;
5116 scriptWritePointer((intptr_t)g_scriptPtr, tempscrptr);
5117
5118 j = C_GetKeyword();
5119
5120 if (j == CON_ELSE)
5121 g_checkingIfElse++;
5122
5123 continue;
5124 }
5125
5126 case CON_LEFTBRACE:
5127 if (EDUKE32_PREDICT_FALSE(!(g_processingState || g_scriptActorOffset || g_scriptEventOffset)))
5128 {
5129 g_errorCnt++;
5130 C_ReportError(ERROR_SYNTAXERROR);
5131 }
5132 g_numBraces++;
5133
5134 C_ParseCommand(true);
5135 continue;
5136
5137 case CON_RIGHTBRACE:
5138 g_numBraces--;
5139
5140 if ((g_scriptPtr[-2]>>12) == (VM_IFELSE_MAGIC) &&
5141 ((g_scriptPtr[-2] & VM_INSTMASK) == CON_LEFTBRACE)) // rewrite "{ }" into "nullop"
5142 {
5143 // initprintf("%s:%d: rewriting empty braces '{ }' as 'nullop' from right\n",g_szScriptFileName,g_lineNumber);
5144 g_scriptPtr[-2] = CON_NULLOP | (VM_IFELSE_MAGIC<<12);
5145 g_scriptPtr -= 2;
5146
5147 if (C_GetKeyword() != CON_ELSE && (g_scriptPtr[-2] & VM_INSTMASK) != CON_ELSE)
5148 g_skipBranch = true;
5149 else g_skipBranch = false;
5150
5151 j = C_GetKeyword();
5152
5153 if (g_checkingIfElse && j != CON_ELSE)
5154 g_checkingIfElse--;
5155
5156 return 1;
5157 }
5158
5159 if (EDUKE32_PREDICT_FALSE(g_numBraces < 0))
5160 {
5161 if (g_checkingSwitch)
5162 {
5163 C_ReportError(ERROR_NOENDSWITCH);
5164 }
5165
5166 C_ReportError(-1);
5167 initprintf("%s:%d: error: found more `}' than `{'.\n",g_scriptFileName,g_lineNumber);
5168 g_errorCnt++;
5169 }
5170
5171 if (g_checkingIfElse && j != CON_ELSE)
5172 g_checkingIfElse--;
5173
5174 return 1;
5175
5176 case CON_BETANAME:
5177 g_scriptPtr--;
5178 j = 0;
5179 scriptSkipLine();
5180 continue;
5181
5182
5183 case CON_UNDEFINELEVEL:
5184 g_scriptPtr--;
5185 C_GetNextValue(LABEL_DEFINE);
5186 g_scriptPtr--;
5187 j = *g_scriptPtr;
5188 C_GetNextValue(LABEL_DEFINE);
5189 g_scriptPtr--;
5190 k = *g_scriptPtr;
5191
5192 if (EDUKE32_PREDICT_FALSE((unsigned)j > MAXVOLUMES-1))
5193 {
5194 initprintf("%s:%d: error: volume number exceeds maximum volume count.\n",g_scriptFileName,g_lineNumber);
5195 g_errorCnt++;
5196 scriptSkipLine();
5197 continue;
5198 }
5199 if (EDUKE32_PREDICT_FALSE((unsigned)k > MAXLEVELS-1))
5200 {
5201 initprintf("%s:%d: error: level number exceeds maximum number of levels per episode.\n",g_scriptFileName,g_lineNumber);
5202 g_errorCnt++;
5203 scriptSkipLine();
5204 continue;
5205 }
5206
5207 C_UndefineLevel(j, k);
5208 continue;
5209
5210 case CON_UNDEFINESKILL:
5211 g_scriptPtr--;
5212
5213 C_GetNextValue(LABEL_DEFINE);
5214 g_scriptPtr--;
5215 j = *g_scriptPtr;
5216
5217 if (EDUKE32_PREDICT_FALSE((unsigned)j >= MAXSKILLS))
5218 {
5219 initprintf("%s:%d: error: skill number exceeds maximum skill count %d.\n",
5220 g_scriptFileName,g_lineNumber, MAXSKILLS);
5221 g_errorCnt++;
5222 scriptSkipLine();
5223 continue;
5224 }
5225
5226 C_UndefineSkill(j);
5227 continue;
5228
5229 case CON_UNDEFINEVOLUME:
5230 g_scriptPtr--;
5231
5232 C_GetNextValue(LABEL_DEFINE);
5233 g_scriptPtr--;
5234 j = *g_scriptPtr;
5235
5236 if (EDUKE32_PREDICT_FALSE((unsigned)j > MAXVOLUMES-1))
5237 {
5238 initprintf("%s:%d: error: volume number exceeds maximum volume count.\n",
5239 g_scriptFileName,g_lineNumber);
5240 g_errorCnt++;
5241 scriptSkipLine();
5242 continue;
5243 }
5244
5245 C_UndefineVolume(j);
5246 continue;
5247
5248 case CON_DEFINEVOLUMENAME:
5249 g_scriptPtr--;
5250
5251 C_GetNextValue(LABEL_DEFINE);
5252 g_scriptPtr--;
5253 j = *g_scriptPtr;
5254
5255 scriptSkipSpaces();
5256
5257 if (EDUKE32_PREDICT_FALSE((unsigned)j > MAXVOLUMES-1))
5258 {
5259 initprintf("%s:%d: error: volume number exceeds maximum volume count.\n",
5260 g_scriptFileName,g_lineNumber);
5261 g_errorCnt++;
5262 scriptSkipLine();
5263 continue;
5264 }
5265
5266 i = 0;
5267
5268 while (*textptr != 0x0a && *textptr != 0x0d && *textptr != 0)
5269 {
5270 g_volumeNames[j][i] = *textptr;
5271 textptr++,i++;
5272 if (EDUKE32_PREDICT_FALSE(i >= (signed)sizeof(g_volumeNames[j])))
5273 {
5274 initprintf("%s:%d: warning: truncating volume name to %d characters.\n",
5275 g_scriptFileName,g_lineNumber,(int32_t)sizeof(g_volumeNames[j])-1);
5276 i--;
5277 g_warningCnt++;
5278 scriptSkipLine();
5279 break;
5280 }
5281 }
5282 g_volumeCnt = j+1;
5283 g_volumeNames[j][i] = '\0';
5284 continue;
5285
5286 case CON_DEFINEVOLUMEFLAGS:
5287 g_scriptPtr--;
5288 C_GetNextValue(LABEL_DEFINE);
5289 g_scriptPtr--;
5290 j = *g_scriptPtr;
5291 C_GetNextValue(LABEL_DEFINE);
5292 g_scriptPtr--;
5293 k = *g_scriptPtr;
5294
5295 if (EDUKE32_PREDICT_FALSE((unsigned)j > MAXVOLUMES-1))
5296 {
5297 initprintf("%s:%d: error: volume number exceeds maximum volume count.\n",g_scriptFileName,g_lineNumber);
5298 g_errorCnt++;
5299 scriptSkipLine();
5300 continue;
5301 }
5302
5303 C_DefineVolumeFlags(j, k);
5304 continue;
5305
5306 case CON_DEFINEGAMEFUNCNAME:
5307 g_scriptPtr--;
5308 C_GetNextValue(LABEL_DEFINE);
5309 g_scriptPtr--;
5310 j = *g_scriptPtr;
5311
5312 scriptSkipSpaces();
5313
5314 if (EDUKE32_PREDICT_FALSE((unsigned)j > NUMGAMEFUNCTIONS-1))
5315 {
5316 initprintf("%s:%d: error: function number exceeds number of game functions.\n",
5317 g_scriptFileName,g_lineNumber);
5318 g_errorCnt++;
5319 scriptSkipLine();
5320 continue;
5321 }
5322
5323 i = 0;
5324
5325 hash_delete(&h_gamefuncs, gamefunctions[j]);
5326
5327 while (*textptr != 0x0a && *textptr != 0x0d && *textptr != 0)
5328 {
5329 gamefunctions[j][i] = *textptr;
5330 textptr++,i++;
5331 if (EDUKE32_PREDICT_FALSE(i >= MAXGAMEFUNCLEN))
5332 {
5333 initprintf("%s:%d: warning: truncating function name to %d characters.\n",
5334 g_scriptFileName,g_lineNumber, MAXGAMEFUNCLEN-1);
5335 i--;
5336 g_warningCnt++;
5337 scriptSkipLine();
5338 break;
5339 }
5340 if (EDUKE32_PREDICT_FALSE(*textptr != 0x0a && *textptr != 0x0d && ispecial(*textptr)))
5341 {
5342 initprintf("%s:%d: warning: invalid character in function name.\n",
5343 g_scriptFileName,g_lineNumber);
5344 g_warningCnt++;
5345 scriptSkipLine();
5346 break;
5347 }
5348 }
5349 gamefunctions[j][i] = '\0';
5350 hash_add(&h_gamefuncs,gamefunctions[j],j,0);
5351
5352 continue;
5353
5354 case CON_UNDEFINEGAMEFUNC:
5355 g_scriptPtr--;
5356 C_GetNextValue(LABEL_DEFINE);
5357 g_scriptPtr--;
5358 j = *g_scriptPtr;
5359
5360 if (EDUKE32_PREDICT_FALSE((unsigned)j > NUMGAMEFUNCTIONS-1))
5361 {
5362 initprintf("%s:%d: error: function number exceeds number of game functions.\n",
5363 g_scriptFileName,g_lineNumber);
5364 g_errorCnt++;
5365 scriptSkipLine();
5366 continue;
5367 }
5368
5369 hash_delete(&h_gamefuncs, gamefunctions[j]);
5370
5371 gamefunctions[j][0] = '\0';
5372
5373 continue;
5374
5375 case CON_DEFINESKILLNAME:
5376 g_scriptPtr--;
5377
5378 C_GetNextValue(LABEL_DEFINE);
5379 g_scriptPtr--;
5380 j = *g_scriptPtr;
5381
5382 scriptSkipSpaces();
5383
5384 if (EDUKE32_PREDICT_FALSE((unsigned)j >= MAXSKILLS))
5385 {
5386 initprintf("%s:%d: error: skill number exceeds maximum skill count %d.\n",
5387 g_scriptFileName,g_lineNumber, MAXSKILLS);
5388 g_errorCnt++;
5389 scriptSkipLine();
5390 continue;
5391 }
5392
5393 i = 0;
5394
5395 while (*textptr != 0x0a && *textptr != 0x0d && *textptr != 0)
5396 {
5397 g_skillNames[j][i] = *textptr;
5398 textptr++,i++;
5399 if (EDUKE32_PREDICT_FALSE(i >= (signed)sizeof(g_skillNames[j])))
5400 {
5401 initprintf("%s:%d: warning: truncating skill name to %d characters.\n",
5402 g_scriptFileName,g_lineNumber,(int32_t)sizeof(g_skillNames[j])-1);
5403 i--;
5404 g_warningCnt++;
5405 scriptSkipLine();
5406 break;
5407 }
5408 }
5409
5410 if (EDUKE32_PREDICT_FALSE(i == 0))
5411 {
5412 initprintf("%s:%d: warning: empty skill name.\n",
5413 g_scriptFileName,g_lineNumber);
5414 g_skillNames[j][i++] = ' ';
5415 }
5416
5417 g_skillNames[j][i] = '\0';
5418
5419 for (i=0; i<MAXSKILLS; i++)
5420 if (g_skillNames[i][0] == 0)
5421 break;
5422 g_skillCnt = i;
5423
5424 continue;
5425
5426 case CON_SETGAMENAME:
5427 {
5428 char gamename[32];
5429 g_scriptPtr--;
5430
5431 C_SkipComments();
5432
5433 i = 0;
5434
5435 while (*textptr != 0x0a && *textptr != 0x0d && *textptr != 0)
5436 {
5437 gamename[i] = *textptr;
5438 textptr++,i++;
5439 if (EDUKE32_PREDICT_FALSE(i >= (signed)sizeof(gamename)))
5440 {
5441 initprintf("%s:%d: warning: truncating game name to %d characters.\n",
5442 g_scriptFileName,g_lineNumber,(int32_t)sizeof(gamename)-1);
5443 i--;
5444 g_warningCnt++;
5445 scriptSkipLine();
5446 break;
5447 }
5448 }
5449 gamename[i] = '\0';
5450 g_gameNamePtr = Xstrdup(gamename);
5451 G_UpdateAppTitle();
5452 }
5453 continue;
5454
5455 case CON_SETDEFNAME:
5456 {
5457 g_scriptPtr--;
5458 C_SkipComments();
5459
5460 j = 0;
5461 while (isaltok(*textptr))
5462 {
5463 tempbuf[j] = *(textptr++);
5464 j++;
5465 }
5466 tempbuf[j] = '\0';
5467
5468 C_SetDefName(tempbuf);
5469 }
5470 continue;
5471
5472 case CON_SETCFGNAME:
5473 {
5474 g_scriptPtr--;
5475 C_SkipComments();
5476
5477 j = 0;
5478 while (isaltok(*textptr))
5479 {
5480 tempbuf[j] = *(textptr++);
5481 j++;
5482 }
5483 tempbuf[j] = '\0';
5484
5485 C_SetCfgName(tempbuf);
5486 }
5487 continue;
5488
5489 case CON_DEFINEGAMETYPE:
5490 g_scriptPtr--;
5491 C_GetNextValue(LABEL_DEFINE);
5492 g_scriptPtr--;
5493 j = *g_scriptPtr;
5494
5495 C_GetNextValue(LABEL_DEFINE);
5496 g_scriptPtr--;
5497 g_gametypeFlags[j] = *g_scriptPtr;
5498
5499 C_SkipComments();
5500
5501 if (EDUKE32_PREDICT_FALSE((unsigned)j > MAXGAMETYPES-1))
5502 {
5503 initprintf("%s:%d: error: gametype number exceeds maximum gametype count.\n",g_scriptFileName,g_lineNumber);
5504 g_errorCnt++;
5505 scriptSkipLine();
5506 continue;
5507 }
5508 g_gametypeCnt = j+1;
5509
5510 i = 0;
5511
5512 while (*textptr != 0x0a && *textptr != 0x0d && *textptr != 0)
5513 {
5514 g_gametypeNames[j][i] = *textptr;
5515 textptr++,i++;
5516 if (EDUKE32_PREDICT_FALSE(i >= (signed)sizeof(g_gametypeNames[j])))
5517 {
5518 initprintf("%s:%d: warning: truncating gametype name to %d characters.\n",
5519 g_scriptFileName,g_lineNumber,(int32_t)sizeof(g_gametypeNames[j])-1);
5520 i--;
5521 g_warningCnt++;
5522 scriptSkipLine();
5523 break;
5524 }
5525 }
5526 g_gametypeNames[j][i] = '\0';
5527 continue;
5528
5529 case CON_DEFINELEVELNAME:
5530 g_scriptPtr--;
5531 C_GetNextValue(LABEL_DEFINE);
5532 g_scriptPtr--;
5533 j = *g_scriptPtr;
5534 C_GetNextValue(LABEL_DEFINE);
5535 g_scriptPtr--;
5536 k = *g_scriptPtr;
5537 C_SkipComments();
5538
5539 if (EDUKE32_PREDICT_FALSE((unsigned)j > MAXVOLUMES-1))
5540 {
5541 initprintf("%s:%d: error: volume number exceeds maximum volume count.\n",g_scriptFileName,g_lineNumber);
5542 g_errorCnt++;
5543 scriptSkipLine();
5544 continue;
5545 }
5546 if (EDUKE32_PREDICT_FALSE((unsigned)k > MAXLEVELS-1))
5547 {
5548 initprintf("%s:%d: error: level number exceeds maximum number of levels per episode.\n",g_scriptFileName,g_lineNumber);
5549 g_errorCnt++;
5550 scriptSkipLine();
5551 continue;
5552 }
5553
5554 i = 0;
5555
5556 tempbuf[i] = '/';
5557
5558 while (*textptr != ' ' && *textptr != '\t' && *textptr != 0x0a)
5559 {
5560 tempbuf[i+1] = *textptr;
5561 textptr++,i++;
5562 if (EDUKE32_PREDICT_FALSE(i >= BMAX_PATH))
5563 {
5564 initprintf("%s:%d: error: level file name exceeds limit of %d characters.\n",g_scriptFileName,g_lineNumber,BMAX_PATH);
5565 g_errorCnt++;
5566 scriptSkipSpaces();
5567 break;
5568 }
5569 }
5570 tempbuf[i+1] = '\0';
5571
5572 Bcorrectfilename(tempbuf,0);
5573
5574 if (g_mapInfo[j *MAXLEVELS+k].filename == NULL)
5575 g_mapInfo[j *MAXLEVELS+k].filename = (char *)Xcalloc(Bstrlen(tempbuf)+1,sizeof(uint8_t));
5576 else if ((Bstrlen(tempbuf)+1) > sizeof(g_mapInfo[j*MAXLEVELS+k].filename))
5577 g_mapInfo[j *MAXLEVELS+k].filename = (char *)Xrealloc(g_mapInfo[j*MAXLEVELS+k].filename,(Bstrlen(tempbuf)+1));
5578
5579 Bstrcpy(g_mapInfo[j*MAXLEVELS+k].filename,tempbuf);
5580
5581 C_SkipComments();
5582
5583 g_mapInfo[j *MAXLEVELS+k].partime =
5584 (((*(textptr+0)-'0')*10+(*(textptr+1)-'0'))*REALGAMETICSPERSEC*60)+
5585 (((*(textptr+3)-'0')*10+(*(textptr+4)-'0'))*REALGAMETICSPERSEC);
5586
5587 textptr += 5;
5588 scriptSkipSpaces();
5589
5590 // cheap hack, 0.99 doesn't have the 3D Realms time
5591 if (*(textptr+2) == ':')
5592 {
5593 g_mapInfo[j *MAXLEVELS+k].designertime =
5594 (((*(textptr+0)-'0')*10+(*(textptr+1)-'0'))*REALGAMETICSPERSEC*60)+
5595 (((*(textptr+3)-'0')*10+(*(textptr+4)-'0'))*REALGAMETICSPERSEC);
5596
5597 textptr += 5;
5598 scriptSkipSpaces();
5599 }
5600 else if (g_scriptVersion == 10) g_scriptVersion = 9;
5601
5602 i = 0;
5603
5604 while (*textptr != 0x0a && *textptr != 0x0d && *textptr != 0)
5605 {
5606 tempbuf[i] = *textptr;
5607 textptr++,i++;
5608 if (EDUKE32_PREDICT_FALSE(i >= 32))
5609 {
5610 initprintf("%s:%d: warning: truncating level name to %d characters.\n",
5611 g_scriptFileName,g_lineNumber,31);
5612 i--;
5613 g_warningCnt++;
5614 scriptSkipLine();
5615 break;
5616 }
5617 }
5618
5619 tempbuf[i] = '\0';
5620
5621 if (g_mapInfo[j*MAXLEVELS+k].name == NULL)
5622 g_mapInfo[j*MAXLEVELS+k].name = (char *)Xcalloc(Bstrlen(tempbuf)+1,sizeof(uint8_t));
5623 else if ((Bstrlen(tempbuf)+1) > sizeof(g_mapInfo[j*MAXLEVELS+k].name))
5624 g_mapInfo[j *MAXLEVELS+k].name = (char *)Xrealloc(g_mapInfo[j*MAXLEVELS+k].name,(Bstrlen(tempbuf)+1));
5625
5626 /* initprintf("level name string len: %d\n",Bstrlen(tempbuf)); */
5627
5628 Bstrcpy(g_mapInfo[j*MAXLEVELS+k].name,tempbuf);
5629
5630 continue;
5631
5632 case CON_DEFINEQUOTE:
5633 case CON_REDEFINEQUOTE:
5634 if (tw == CON_DEFINEQUOTE)
5635 {
5636 g_scriptPtr--;
5637 }
5638
5639 C_GetNextValue(LABEL_DEFINE);
5640
5641 k = g_scriptPtr[-1];
5642
5643 if (EDUKE32_PREDICT_FALSE((unsigned)k >= MAXQUOTES))
5644 {
5645 initprintf("%s:%d: error: quote number exceeds limit of %d.\n",g_scriptFileName,g_lineNumber,MAXQUOTES);
5646 g_errorCnt++;
5647 scriptSkipLine();
5648 continue;
5649 }
5650 else
5651 {
5652 C_AllocQuote(k);
5653 }
5654
5655 if (tw == CON_DEFINEQUOTE)
5656 g_scriptPtr--;
5657
5658 i = 0;
5659
5660 scriptSkipSpaces();
5661
5662 if (tw == CON_REDEFINEQUOTE)
5663 {
5664 if (apXStrings[g_numXStrings] == NULL)
5665 apXStrings[g_numXStrings] = (char *)Xcalloc(MAXQUOTELEN,sizeof(uint8_t));
5666 }
5667
5668 while (*textptr != 0x0a && *textptr != 0x0d && *textptr != 0)
5669 {
5670 /*
5671 if (*textptr == '%' && *(textptr+1) == 's')
5672 {
5673 initprintf("%s:%d: error: quote text contains string identifier.\n",g_szScriptFileName,g_lineNumber);
5674 g_numCompilerErrors++;
5675 while (*textptr != 0x0a && *textptr != 0x0d && *textptr != 0) textptr++;
5676 break;
5677 }
5678 */
5679 if (tw == CON_DEFINEQUOTE)
5680 *(apStrings[k]+i) = *textptr;
5681 else
5682 *(apXStrings[g_numXStrings]+i) = *textptr;
5683 textptr++,i++;
5684 if (EDUKE32_PREDICT_FALSE(i >= MAXQUOTELEN))
5685 {
5686 initprintf("%s:%d: warning: truncating quote text to %d characters.\n",g_scriptFileName,g_lineNumber,MAXQUOTELEN-1);
5687 i--;
5688 g_warningCnt++;
5689 scriptSkipLine();
5690 break;
5691 }
5692 }
5693
5694 if (tw == CON_DEFINEQUOTE)
5695 {
5696 if ((unsigned)k < MAXQUOTES)
5697 *(apStrings[k]+i) = '\0';
5698 }
5699 else
5700 {
5701 *(apXStrings[g_numXStrings]+i) = '\0';
5702 scriptWriteValue(g_numXStrings++);
5703 }
5704 continue;
5705
5706 case CON_DEFINECHEATDESCRIPTION:
5707 g_scriptPtr--;
5708
5709 C_GetNextValue(LABEL_DEFINE);
5710
5711 k = g_scriptPtr[-1];
5712
5713 if (EDUKE32_PREDICT_FALSE((unsigned)k >= NUMCHEATS))
5714 {
5715 initprintf("%s:%d: error: cheat number exceeds limit of %d.\n",g_scriptFileName,g_lineNumber,NUMCHEATS);
5716 g_errorCnt++;
5717 scriptSkipLine();
5718 continue;
5719 }
5720
5721 g_scriptPtr--;
5722
5723 i = 0;
5724
5725 scriptSkipSpaces();
5726
5727 while (*textptr != 0x0a && *textptr != 0x0d && *textptr != 0)
5728 {
5729 *(CheatDescriptions[k]+i) = *textptr;
5730 textptr++,i++;
5731 if (EDUKE32_PREDICT_FALSE(i >= MAXCHEATDESC))
5732 {
5733 initprintf("%s:%d: warning: truncating cheat text to %d characters.\n",g_scriptFileName,g_lineNumber,MAXCHEATDESC-1);
5734 i--;
5735 g_warningCnt++;
5736 scriptSkipLine();
5737 break;
5738 }
5739 }
5740
5741 *(CheatDescriptions[k]+i) = '\0';
5742 continue;
5743
5744 case CON_CHEATKEYS:
5745 g_scriptPtr--;
5746 C_GetNextValue(LABEL_DEFINE);
5747 CheatKeys[0] = g_scriptPtr[-1];
5748 C_GetNextValue(LABEL_DEFINE);
5749 CheatKeys[1] = g_scriptPtr[-1];
5750 g_scriptPtr -= 2;
5751 continue;
5752
5753 case CON_UNDEFINECHEAT:
5754 g_scriptPtr--;
5755
5756 C_GetNextValue(LABEL_DEFINE);
5757 g_scriptPtr--;
5758 j = *g_scriptPtr;
5759
5760 if (EDUKE32_PREDICT_FALSE((unsigned)j >= NUMCHEATS))
5761 {
5762 initprintf("%s:%d: error: cheat undefinition attempts to undefine nonexistent cheat.\n",g_scriptFileName,g_lineNumber);
5763 g_errorCnt++;
5764 scriptSkipLine();
5765 continue;
5766 }
5767
5768 CheatStrings[j][0] = '\0';
5769 continue;
5770
5771 case CON_DEFINECHEAT:
5772 g_scriptPtr--;
5773 C_GetNextValue(LABEL_DEFINE);
5774 k = g_scriptPtr[-1];
5775
5776 if (EDUKE32_PREDICT_FALSE((unsigned)k >= NUMCHEATS))
5777 {
5778 initprintf("%s:%d: error: cheat redefinition attempts to redefine nonexistent cheat.\n",g_scriptFileName,g_lineNumber);
5779 g_errorCnt++;
5780 scriptSkipLine();
5781 continue;
5782 }
5783 g_scriptPtr--;
5784 i = 0;
5785 scriptSkipSpaces();
5786 while (*textptr != 0x0a && *textptr != 0x0d && *textptr != 0 && *textptr != ' ')
5787 {
5788 CheatStrings[k][i] = Btolower(*textptr);
5789 textptr++,i++;
5790 if (EDUKE32_PREDICT_FALSE(i >= (signed)sizeof(CheatStrings[k])))
5791 {
5792 initprintf("%s:%d: warning: truncating cheat string to %d characters.\n",
5793 g_scriptFileName,g_lineNumber,(signed)sizeof(CheatStrings[k])-1);
5794 i--;
5795 g_warningCnt++;
5796 scriptSkipLine();
5797 break;
5798 }
5799 }
5800 CheatStrings[k][i] = '\0';
5801 continue;
5802
5803 case CON_DEFINESOUND:
5804 g_scriptPtr--;
5805 C_GetNextValue(LABEL_DEFINE);
5806
5807 // Ideally we could keep the value of i from C_GetNextValue() instead of having to hash_find() again.
5808 // This depends on tempbuf remaining in place after C_GetNextValue():
5809 j = hash_find(&h_labels,tempbuf);
5810
5811 k = g_scriptPtr[-1];
5812 if (EDUKE32_PREDICT_FALSE((unsigned)k >= MAXSOUNDS-1))
5813 {
5814 initprintf("%s:%d: error: sound index exceeds limit of %d.\n",g_scriptFileName,g_lineNumber, MAXSOUNDS-1);
5815 g_errorCnt++;
5816 k = MAXSOUNDS-1;
5817 }
5818 else if (EDUKE32_PREDICT_FALSE(g_sounds[k].filename != NULL))
5819 {
5820 initprintf("%s:%d: warning: sound %d already defined (%s)\n",g_scriptFileName,g_lineNumber,k,g_sounds[k].filename);
5821 g_warningCnt++;
5822 }
5823
5824 g_scriptPtr--;
5825 i = 0;
5826 C_SkipComments();
5827
5828 if (g_sounds[k].filename == NULL)
5829 g_sounds[k].filename = (char *)Xcalloc(BMAX_PATH,sizeof(uint8_t));
5830
5831 if (*textptr == '\"')
5832 {
5833 textptr++;
5834 while (*textptr && *textptr != '\"')
5835 {
5836 g_sounds[k].filename[i++] = *textptr++;
5837 if (EDUKE32_PREDICT_FALSE(i >= BMAX_PATH-1))
5838 {
5839 initprintf("%s:%d: error: sound filename exceeds limit of %d characters.\n",g_scriptFileName,g_lineNumber,BMAX_PATH-1);
5840 g_errorCnt++;
5841 C_SkipComments();
5842 break;
5843 }
5844 }
5845 textptr++;
5846 }
5847 else while (*textptr != ' ' && *textptr != '\t' && *textptr != '\r' && *textptr != '\n')
5848 {
5849 g_sounds[k].filename[i++] = *textptr++;
5850 if (EDUKE32_PREDICT_FALSE(i >= BMAX_PATH-1))
5851 {
5852 initprintf("%s:%d: error: sound filename exceeds limit of %d characters.\n",g_scriptFileName,g_lineNumber,BMAX_PATH-1);
5853 g_errorCnt++;
5854 C_SkipComments();
5855 break;
5856 }
5857 }
5858 g_sounds[k].filename[i] = '\0';
5859
5860 check_filename_case(g_sounds[k].filename);
5861
5862 C_GetNextValue(LABEL_DEFINE);
5863 g_sounds[k].ps = g_scriptPtr[-1];
5864 C_GetNextValue(LABEL_DEFINE);
5865 g_sounds[k].pe = g_scriptPtr[-1];
5866 C_GetNextValue(LABEL_DEFINE);
5867 g_sounds[k].pr = g_scriptPtr[-1];
5868
5869 C_GetNextValue(LABEL_DEFINE);
5870 g_sounds[k].m = g_scriptPtr[-1] & ~SF_ONEINST_INTERNAL;
5871 if (g_scriptPtr[-1] & SF_LOOP)
5872 g_sounds[k].m |= SF_ONEINST_INTERNAL;
5873
5874 C_GetNextValue(LABEL_DEFINE);
5875 g_sounds[k].vo = g_scriptPtr[-1];
5876 g_scriptPtr -= 5;
5877
5878 g_sounds[k].volume = fix16_one;
5879
5880 if (k > g_highestSoundIdx)
5881 g_highestSoundIdx = k;
5882
5883 if (g_dynamicSoundMapping && j >= 0 && (labeltype[j] & LABEL_DEFINE))
5884 G_ProcessDynamicSoundMapping(label+(j<<6), k);
5885 continue;
5886
5887 case CON_ENDEVENT:
5888
5889 if (EDUKE32_PREDICT_FALSE(!g_scriptEventOffset))
5890 {
5891 C_ReportError(-1);
5892 initprintf("%s:%d: error: found `endevent' without open `onevent'.\n",g_scriptFileName,g_lineNumber);
5893 g_errorCnt++;
5894 }
5895 if (EDUKE32_PREDICT_FALSE(g_numBraces > 0))
5896 {
5897 C_ReportError(ERROR_NOTTOPLEVEL);
5898 g_errorCnt++;
5899 }
5900 // if event has already been declared then put a jump in instead
5901 if (g_scriptEventChainOffset)
5902 {
5903 g_scriptPtr--;
5904 scriptWriteValue(CON_JUMP | LINE_NUMBER);
5905 scriptWriteValue(GV_FLAG_CONSTANT);
5906 scriptWriteValue(g_scriptEventChainOffset);
5907 scriptWriteValue(CON_ENDEVENT | LINE_NUMBER);
5908
5909 C_FillEventBreakStackWithJump((intptr_t *)g_scriptEventBreakOffset, g_scriptEventChainOffset);
5910
5911 g_scriptEventChainOffset = 0;
5912 }
5913 else
5914 {
5915 // pad space for the next potential appendevent
5916 apScriptGameEventEnd[g_currentEvent] = &g_scriptPtr[-1] - apScript;
5917 scriptWriteValue(CON_ENDEVENT | LINE_NUMBER);
5918 scriptWriteValue(g_scriptEventBreakOffset);
5919 scriptWriteValue(CON_ENDEVENT | LINE_NUMBER);
5920 }
5921
5922 g_scriptEventBreakOffset = g_scriptEventOffset = g_scriptActorOffset = 0;
5923 g_currentEvent = -1;
5924 Bsprintf(g_szCurrentBlockName,"(none)");
5925 continue;
5926
5927 case CON_ENDA:
5928 if (EDUKE32_PREDICT_FALSE(!g_scriptActorOffset || g_scriptEventOffset))
5929 {
5930 C_ReportError(-1);
5931 initprintf("%s:%d: error: found `enda' without open `actor'.\n",g_scriptFileName,g_lineNumber);
5932 g_errorCnt++;
5933 g_scriptEventOffset = 0;
5934 }
5935 if (EDUKE32_PREDICT_FALSE(g_numBraces > 0))
5936 {
5937 C_ReportError(ERROR_NOTTOPLEVEL);
5938 g_errorCnt++;
5939 }
5940 g_scriptActorOffset = 0;
5941 Bsprintf(g_szCurrentBlockName,"(none)");
5942 continue;
5943
5944 case CON_RETURN:
5945 if (g_checkingSwitch)
5946 {
5947 g_checkingCase = false;
5948 return 1;
5949 }
5950 continue;
5951
5952 case CON_BREAK:
5953 if (g_checkingSwitch)
5954 {
5955 if (EDUKE32_PREDICT_FALSE(otw == CON_BREAK))
5956 {
5957 C_ReportError(-1);
5958 initprintf("%s:%d: warning: duplicate `break'.\n",g_scriptFileName, g_lineNumber);
5959 g_warningCnt++;
5960 g_scriptPtr--;
5961 continue;
5962 }
5963
5964 g_checkingCase = false;
5965 return 1;
5966 }
5967 else if (g_scriptEventOffset)
5968 {
5969 g_scriptPtr--;
5970 scriptWriteValue(CON_JUMP | LINE_NUMBER);
5971 scriptWriteValue(GV_FLAG_CONSTANT);
5972 scriptWriteValue(g_scriptEventBreakOffset);
5973 g_scriptEventBreakOffset = &g_scriptPtr[-1] - apScript;
5974 }
5975 continue;
5976
5977 case CON_SCRIPTSIZE:
5978 g_scriptPtr--;
5979 C_GetNextValue(LABEL_DEFINE);
5980 j = g_scriptPtr[-1];
5981 g_scriptPtr--;
5982 C_SkipComments();
5983 C_SetScriptSize(j);
5984 continue;
5985
5986 case CON_SHADETO:
5987 g_scriptPtr--;
5988 C_GetNextValue(LABEL_DEFINE);
5989 g_scriptPtr--;
5990 continue;
5991
5992 case CON_FALL:
5993 case CON_GETLASTPAL:
5994 case CON_GETTEXTURECEILING:
5995 case CON_GETTEXTUREFLOOR:
5996 case CON_INSERTSPRITEQ:
5997 case CON_KILLIT:
5998 case CON_MIKESND:
5999 case CON_OPERATE:
6000 case CON_PKICK:
6001 case CON_PSTOMP:
6002 case CON_RESETACTIONCOUNT:
6003 case CON_RESETCOUNT:
6004 case CON_RESETPLAYER:
6005 case CON_RESPAWNHITAG:
6006 case CON_SECTGETHITAG:
6007 case CON_SECTGETLOTAG:
6008 case CON_SPGETHITAG:
6009 case CON_SPGETLOTAG:
6010 case CON_STARTSCREEN:
6011 case CON_STOPALLMUSIC:
6012 case CON_STOPALLSOUNDS:
6013 case CON_TIP:
6014 case CON_TOSSWEAPON:
6015 case CON_WACKPLAYER:
6016 continue;
6017
6018 case CON_NULLOP:
6019 {
6020 auto const kw = C_GetKeyword();
6021 if (EDUKE32_PREDICT_FALSE(kw != CON_ELSE && kw != CON_RIGHTBRACE))
6022 {
6023 C_ReportError(-1);
6024 g_warningCnt++;
6025 initprintf("%s:%d: warning: `nullop' found without accompanying branch.\n",g_scriptFileName,g_lineNumber);
6026 g_scriptPtr--;
6027 g_skipBranch = true;
6028 }
6029 continue;
6030 }
6031
6032 case CON_GAMESTARTUP:
6033 {
6034 int32_t params[31];
6035
6036 g_scriptPtr--;
6037 for (j = 0; j < 31; j++)
6038 {
6039 C_GetNextValue(LABEL_DEFINE);
6040 g_scriptPtr--;
6041 params[j] = *g_scriptPtr;
6042
6043 if (j != 12 && j != 21 && j != 25 && j != 29) continue;
6044
6045 if (C_GetKeyword() != -1)
6046 {
6047 if (j == 12)
6048 g_scriptVersion = 10;
6049 else if (j == 21)
6050 g_scriptVersion = 11;
6051 else if (j == 25)
6052 g_scriptVersion = 13;
6053 else if (j == 29)
6054 g_scriptVersion = 14;
6055 break;
6056 }
6057 else
6058 g_scriptVersion = 16;
6059 }
6060
6061 /*
6062 v1.3d v1.5
6063 DEFAULTVISIBILITY DEFAULTVISIBILITY
6064 GENERICIMPACTDAMAGE GENERICIMPACTDAMAGE
6065 MAXPLAYERHEALTH MAXPLAYERHEALTH
6066 STARTARMORHEALTH STARTARMORHEALTH
6067 RESPAWNACTORTIME RESPAWNACTORTIME
6068 RESPAWNITEMTIME RESPAWNITEMTIME
6069 RUNNINGSPEED RUNNINGSPEED
6070 RPGBLASTRADIUS GRAVITATIONALCONSTANT
6071 PIPEBOMBRADIUS RPGBLASTRADIUS
6072 SHRINKERBLASTRADIUS PIPEBOMBRADIUS
6073 TRIPBOMBBLASTRADIUS SHRINKERBLASTRADIUS
6074 MORTERBLASTRADIUS TRIPBOMBBLASTRADIUS
6075 BOUNCEMINEBLASTRADIUS MORTERBLASTRADIUS
6076 SEENINEBLASTRADIUS BOUNCEMINEBLASTRADIUS
6077 MAXPISTOLAMMO SEENINEBLASTRADIUS
6078 MAXSHOTGUNAMMO MAXPISTOLAMMO
6079 MAXCHAINGUNAMMO MAXSHOTGUNAMMO
6080 MAXRPGAMMO MAXCHAINGUNAMMO
6081 MAXHANDBOMBAMMO MAXRPGAMMO
6082 MAXSHRINKERAMMO MAXHANDBOMBAMMO
6083 MAXDEVISTATORAMMO MAXSHRINKERAMMO
6084 MAXTRIPBOMBAMMO MAXDEVISTATORAMMO
6085 MAXFREEZEAMMO MAXTRIPBOMBAMMO
6086 CAMERASDESTRUCTABLE MAXFREEZEAMMO
6087 NUMFREEZEBOUNCES MAXGROWAMMO
6088 FREEZERHURTOWNER CAMERASDESTRUCTABLE
6089 NUMFREEZEBOUNCES
6090 FREEZERHURTOWNER
6091 QSIZE
6092 TRIPBOMBLASERMODE
6093 */
6094
6095 G_DoGameStartup(params);
6096 }
6097 continue;
6098 }
6099 }
6100 while (loop);
6101
6102 return 0;
6103 }
6104
6105 /* Anything added with C_AddDefinition() cannot be overwritten in the CONs */
C_AddDefinition(const char * lLabel,int32_t lValue,int32_t lType)6106 static void C_AddDefinition(const char *lLabel,int32_t lValue,int32_t lType)
6107 {
6108 Bstrcpy(LAST_LABEL,lLabel);
6109 labeltype[g_labelCnt] = lType;
6110 hash_add(&h_labels,LAST_LABEL,g_labelCnt,0);
6111 labelcode[g_labelCnt++] = lValue;
6112 }
6113
C_AddDefaultDefinitions(void)6114 static void C_AddDefaultDefinitions(void)
6115 {
6116 for (int i=0; i<MAXEVENTS; i++)
6117 C_AddDefinition(EventNames[i], i, LABEL_DEFINE|LABEL_EVENT);
6118
6119 #if 0
6120 for (int i=0; i<NUMGAMEFUNCTIONS; i++)
6121 {
6122 int32_t j;
6123
6124 if (gamefunctions[i][0] == '\0')
6125 continue;
6126
6127 // if (!Bstrcmp(gamefunctions[i],"Show_Console")) continue;
6128
6129 j = Bsprintf(tempbuf,"GAMEFUNC_%s", gamefunctions[i]);
6130
6131 for (; j>=0; j--)
6132 tempbuf[j] = Btoupper(tempbuf[j]);
6133
6134 C_AddDefinition(tempbuf, i, LABEL_DEFINE);
6135 }
6136 #endif
6137
6138 static tokenmap_t predefined[] =
6139 {
6140 { "CLIPMASK0", CLIPMASK0 },
6141 { "CLIPMASK1", CLIPMASK1 },
6142
6143 { "GAMEARRAY_BOOLEAN", GAMEARRAY_BITMAP },
6144 { "GAMEARRAY_INT16", GAMEARRAY_INT16 },
6145 { "GAMEARRAY_INT8", GAMEARRAY_INT8 },
6146 { "GAMEARRAY_RESTORE", GAMEARRAY_RESTORE },
6147 { "GAMEARRAY_UINT16", GAMEARRAY_UINT16 },
6148 { "GAMEARRAY_UINT8", GAMEARRAY_UINT8 },
6149
6150 { "GAMEVAR_NODEFAULT", GAMEVAR_NODEFAULT },
6151 { "GAMEVAR_NOMULTI", GAMEVAR_NOMULTI },
6152 { "GAMEVAR_NORESET", GAMEVAR_NORESET },
6153 { "GAMEVAR_PERACTOR", GAMEVAR_PERACTOR },
6154 { "GAMEVAR_PERPLAYER", GAMEVAR_PERPLAYER },
6155 { "GAMEVAR_SERIALIZE", GAMEVAR_SERIALIZE },
6156
6157 { "MAX_WEAPONS", MAX_WEAPONS },
6158 { "MAXSPRITES", MAXSPRITES },
6159 { "MAXSPRITESONSCREEN", MAXSPRITESONSCREEN },
6160 { "MAXSTATUS", MAXSTATUS },
6161 { "MAXTILES", MAXTILES },
6162
6163 { "PROJ_BOUNCES", PROJ_BOUNCES },
6164 { "PROJ_BSOUND", PROJ_BSOUND },
6165 { "PROJ_CLIPDIST", PROJ_CLIPDIST },
6166 { "PROJ_CSTAT", PROJ_CSTAT },
6167 { "PROJ_DECAL", PROJ_DECAL },
6168 { "PROJ_DROP", PROJ_DROP },
6169 { "PROJ_EXTRA", PROJ_EXTRA },
6170 { "PROJ_EXTRA_RAND", PROJ_EXTRA_RAND },
6171 { "PROJ_FLASH_COLOR", PROJ_FLASH_COLOR },
6172 { "PROJ_HITRADIUS", PROJ_HITRADIUS },
6173 { "PROJ_ISOUND", PROJ_ISOUND },
6174 { "PROJ_OFFSET", PROJ_OFFSET },
6175 { "PROJ_PAL", PROJ_PAL },
6176 { "PROJ_RANGE", PROJ_RANGE },
6177 { "PROJ_SHADE", PROJ_SHADE },
6178 { "PROJ_SOUND", PROJ_SOUND },
6179 { "PROJ_SPAWNS", PROJ_SPAWNS },
6180 { "PROJ_SXREPEAT", PROJ_SXREPEAT },
6181 { "PROJ_SYREPEAT", PROJ_SYREPEAT },
6182 { "PROJ_TNUM", PROJ_TNUM },
6183 { "PROJ_TOFFSET", PROJ_TOFFSET },
6184 { "PROJ_TRAIL", PROJ_TRAIL },
6185 { "PROJ_TXREPEAT", PROJ_TXREPEAT },
6186 { "PROJ_TYREPEAT", PROJ_TYREPEAT },
6187 { "PROJ_USERDATA", PROJ_USERDATA },
6188 { "PROJ_VEL", PROJ_VEL },
6189 { "PROJ_VEL_MULT", PROJ_MOVECNT },
6190 { "PROJ_WORKSLIKE", PROJ_WORKSLIKE },
6191 { "PROJ_XREPEAT", PROJ_XREPEAT },
6192 { "PROJ_YREPEAT", PROJ_YREPEAT },
6193
6194 { "SFLAG_BADGUY", SFLAG_BADGUY },
6195 { "SFLAG_DAMAGEEVENT", SFLAG_DAMAGEEVENT },
6196 { "SFLAG_GREENSLIMEFOOD", SFLAG_GREENSLIMEFOOD },
6197 { "SFLAG_HURTSPAWNBLOOD", SFLAG_HURTSPAWNBLOOD },
6198 { "SFLAG_NOCLIP", SFLAG_NOCLIP },
6199 { "SFLAG_NODAMAGEPUSH", SFLAG_NODAMAGEPUSH },
6200 { "SFLAG_NOEVENTS", SFLAG_NOEVENTCODE },
6201 { "SFLAG_NOLIGHT", SFLAG_NOLIGHT },
6202 { "SFLAG_NOPAL", SFLAG_NOPAL },
6203 { "SFLAG_NOSHADE", SFLAG_NOSHADE },
6204 { "SFLAG_NOTELEPORT", SFLAG_NOTELEPORT },
6205 { "SFLAG_NOWATERDIP", SFLAG_NOWATERDIP },
6206 { "SFLAG_NVG", SFLAG_NVG },
6207 { "SFLAG_REALCLIPDIST", SFLAG_REALCLIPDIST },
6208 { "SFLAG_SHADOW", SFLAG_SHADOW },
6209 { "SFLAG_SMOOTHMOVE", SFLAG_SMOOTHMOVE },
6210 { "SFLAG_USEACTIVATOR", SFLAG_USEACTIVATOR },
6211 { "SFLAG_WAKEUPBADGUYS", SFLAG_WAKEUPBADGUYS },
6212 { "SFLAG_NOWATERSECTOR", SFLAG_NOWATERSECTOR },
6213 { "SFLAG_QUEUEDFORDELETE", SFLAG_QUEUEDFORDELETE },
6214
6215 { "STAT_ACTIVATOR", STAT_ACTIVATOR },
6216 { "STAT_ACTOR", STAT_ACTOR },
6217 { "STAT_DEFAULT", STAT_DEFAULT },
6218 { "STAT_DUMMYPLAYER", STAT_DUMMYPLAYER },
6219 { "STAT_EFFECTOR", STAT_EFFECTOR },
6220 { "STAT_FALLER", STAT_FALLER },
6221 { "STAT_FX", STAT_FX },
6222 { "STAT_LIGHT", STAT_LIGHT },
6223 { "STAT_LOCATOR", STAT_LOCATOR },
6224 { "STAT_MISC", STAT_MISC },
6225 { "STAT_PLAYER", STAT_PLAYER },
6226 { "STAT_PROJECTILE", STAT_PROJECTILE },
6227 { "STAT_STANDABLE", STAT_STANDABLE },
6228 { "STAT_TRANSPORT", STAT_TRANSPORT },
6229 { "STAT_ZOMBIEACTOR", STAT_ZOMBIEACTOR },
6230
6231 { "STR_BESTTIME", STR_BESTTIME },
6232 { "STR_DESIGNERTIME", STR_DESIGNERTIME },
6233 { "STR_GAMETYPE", STR_GAMETYPE },
6234 { "STR_MAPFILENAME", STR_MAPFILENAME },
6235 { "STR_MAPNAME", STR_MAPNAME },
6236 { "STR_PARTIME", STR_PARTIME },
6237 { "STR_PLAYERNAME", STR_PLAYERNAME },
6238 { "STR_REVISION", STR_REVISION },
6239 { "STR_USERMAPFILENAME", STR_USERMAPFILENAME },
6240 { "STR_VERSION", STR_VERSION },
6241 { "STR_VOLUMENAME", STR_VOLUMENAME },
6242 { "STR_YOURTIME", STR_YOURTIME },
6243 };
6244
6245 for (auto & def : predefined)
6246 C_AddDefinition(def.token, def.val, LABEL_DEFINE);
6247
6248 C_AddDefinition("NO", 0, LABEL_DEFINE | LABEL_ACTION | LABEL_AI | LABEL_MOVE);
6249 }
6250
C_InitProjectiles(void)6251 void C_InitProjectiles(void)
6252 {
6253 defaultprojectile_t const Projectile =
6254 {
6255 // workslike, cstat, hitradius, range, flashcolor;
6256 // spawns, sound, isound, vel, decal, trail, tnum, drop;
6257 // offset, bounces, bsound, toffset, extra, extra_rand;
6258 // sxrepeat, syrepeat, txrepeat, tyrepeat;
6259 // shade, xrepeat, yrepeat, pal;
6260 // movecnt, clipdist, filler[2], userdata;
6261
6262 // XXX: The default projectie seems to mimic a union of hard-coded ones.
6263
6264 1, -1, 2048, 0, 0,
6265 (int16_t)SMALLSMOKE, -1, -1, 600, (int16_t)BULLETHOLE, -1, 0, 0,
6266 448, (int16_t)g_numFreezeBounces, (int16_t)PIPEBOMB_BOUNCE, 1, 100, -1,
6267 -1, -1, -1, -1,
6268 -96, 18, 18, 0,
6269 1, 32, { 0, 0 }, 0,
6270 };
6271
6272 DefaultProjectile = Projectile;
6273
6274 for (auto & tile : g_tile)
6275 {
6276 if (tile.proj)
6277 *tile.proj = DefaultProjectile;
6278
6279 if (tile.defproj)
6280 *tile.defproj = DefaultProjectile;
6281 }
6282 }
6283
C_ScriptVersionString(int32_t version)6284 static char const * C_ScriptVersionString(int32_t version)
6285 {
6286 #ifdef EDUKE32_STANDALONE
6287 UNREFERENCED_PARAMETER(version);
6288 #else
6289 switch (version)
6290 {
6291 case 9:
6292 return ", v0.99 compatibility mode";
6293 case 10:
6294 return ", v1.0 compatibility mode";
6295 case 11:
6296 return ", v1.1 compatibility mode";
6297 case 13:
6298 return ", v1.3D compatibility mode";
6299 }
6300 #endif
6301 return "";
6302 }
6303
C_PrintStats(void)6304 void C_PrintStats(void)
6305 {
6306 initprintf("%d/%d labels, %d/%d variables, %d/%d arrays\n", g_labelCnt, MAXLABELS,
6307 g_gameVarCount, MAXGAMEVARS, g_gameArrayCount, MAXGAMEARRAYS);
6308
6309 int cnt = g_numXStrings;
6310
6311 for (auto &ptr : apStrings)
6312 if (ptr)
6313 cnt++;
6314
6315 if (cnt) initprintf("%d strings, ", cnt);
6316 cnt = 0;
6317
6318 for (auto & apScriptEvent : apScriptEvents)
6319 if (apScriptEvent)
6320 cnt++;
6321
6322 if (cnt) initprintf("%d events, ", cnt);
6323 cnt = 0;
6324
6325 for (auto & tile : g_tile)
6326 if (tile.execPtr)
6327 cnt++;
6328
6329 if (cnt) initprintf("%d actors", cnt);
6330 initprintf("\n");
6331 }
6332
6333 // TODO: add some kind of mapping between the table and the struct holding the tokens
scriptInitTables()6334 void scriptInitTables()
6335 {
6336 for (auto table : tables)
6337 hash_init(table);
6338
6339 for (auto table : inttables)
6340 inthash_init(table);
6341
6342 for (auto &keyword : vm_keywords)
6343 hash_add(&h_keywords, keyword.token, keyword.val, 0);
6344
6345 for (auto &iter_token : iter_tokens)
6346 hash_add(&h_iter, iter_token.token, iter_token.val, 0);
6347
6348 for (auto &varvar : varvartable)
6349 inthash_add(&h_varvar, varvar.x, varvar.y, 0);
6350
6351 for (auto &globalvar : globalvartable)
6352 inthash_add(&h_globalvar, globalvar.x, globalvar.y, 0);
6353
6354 for (auto &playervar : playervartable)
6355 inthash_add(&h_playervar, playervar.x, playervar.y, 0);
6356
6357 for (auto &actorvar : actorvartable)
6358 inthash_add(&h_actorvar, actorvar.x, actorvar.y, 0);
6359 }
6360
6361 #if MICROPROFILE_ENABLED != 0
C_GetLabelIndex(int32_t val,int type)6362 static int C_GetLabelIndex(int32_t val, int type)
6363 {
6364 for (int i=0;i<g_labelCnt;i++)
6365 if (labelcode[i] == val && (labeltype[i] & type) != 0)
6366 return i;
6367
6368 for (int i=0;i<g_labelCnt;i++)
6369 if (labelcode[i] == val)
6370 return i;
6371
6372 return -1;
6373 }
6374 #endif
6375
C_Compile(const char * fileName)6376 void C_Compile(const char *fileName)
6377 {
6378 Bmemset(apScriptEvents, 0, sizeof(apScriptEvents));
6379 Bmemset(apScriptGameEventEnd, 0, sizeof(apScriptGameEventEnd));
6380
6381 for (auto & i : g_tile)
6382 Bmemset(&i, 0, sizeof(tiledata_t));
6383
6384 scriptInitTables();
6385 VM_InitHashTables();
6386
6387 Gv_Init();
6388 C_InitProjectiles();
6389
6390 buildvfs_kfd kFile = kopen4loadfrommod(fileName, g_loadFromGroupOnly);
6391
6392 if (kFile == buildvfs_kfd_invalid) // JBF: was 0
6393 {
6394 if (g_loadFromGroupOnly == 1 || numgroupfiles == 0)
6395 {
6396 #ifndef EDUKE32_STANDALONE
6397 char const *gf = G_GrpFile();
6398 Bsprintf(tempbuf,"Required game data was not found. A valid copy of \"%s\" or other compatible data is needed to run EDuke32.\n\n"
6399 "You must copy \"%s\" to your game directory before continuing!", gf, gf);
6400 G_GameExit(tempbuf);
6401 #else
6402 G_GameExit(" ");
6403 #endif
6404 }
6405 else
6406 {
6407 Bsprintf(tempbuf,"CON file `%s' missing.", fileName);
6408 G_GameExit(tempbuf);
6409 }
6410
6411 //g_loadFromGroupOnly = 1;
6412 return; //Not there
6413 }
6414
6415 int const kFileLen = kfilelength(kFile);
6416
6417 initprintf("Compiling: %s (%d bytes)\n", fileName, kFileLen);
6418
6419 g_logFlushWindow = 0;
6420
6421 uint32_t const startcompiletime = timerGetTicks();
6422
6423 char * mptr = (char *)Xmalloc(kFileLen+1);
6424 mptr[kFileLen] = 0;
6425
6426 textptr = (char *)mptr;
6427 kread(kFile, (char *)textptr, kFileLen);
6428 kclose(kFile);
6429
6430 Xfree(apScript);
6431
6432 apScript = (intptr_t *)Xcalloc(1, g_scriptSize * sizeof(intptr_t));
6433 bitptr = (uint8_t *)Xcalloc(1, (((g_scriptSize + 7) >> 3) + 1) * sizeof(uint8_t));
6434
6435 g_errorCnt = 0;
6436 g_labelCnt = 0;
6437 g_lineNumber = 1;
6438 g_scriptPtr = apScript + 3; // move permits constants 0 and 1; moveptr[1] would be script[2] (reachable?)
6439 g_totalLines = 0;
6440 g_warningCnt = 0;
6441
6442 Bstrcpy(g_scriptFileName, fileName);
6443
6444 C_AddDefaultDefinitions();
6445 C_ParseCommand(true);
6446
6447 for (char * m : g_scriptModules)
6448 {
6449 C_Include(m);
6450 Bfree(m);
6451 }
6452 g_scriptModules.clear();
6453
6454 g_logFlushWindow = 1;
6455
6456 if (g_errorCnt > 63)
6457 initprintf("fatal error: too many errors: Aborted\n");
6458
6459 //*script = (intptr_t) g_scriptPtr;
6460
6461 DO_FREE_AND_NULL(mptr);
6462
6463 if (g_warningCnt || g_errorCnt)
6464 {
6465 initprintf("Found %d warning(s), %d error(s).\n", g_warningCnt, g_errorCnt);
6466
6467 if (g_errorCnt)
6468 {
6469 Bsprintf(buf, "Error compiling CON files.");
6470 G_GameExit(buf);
6471 }
6472 }
6473
6474 for (intptr_t i : apScriptGameEventEnd)
6475 {
6476 if (!i)
6477 continue;
6478
6479 auto const eventEnd = apScript + i;
6480 auto breakPtr = (intptr_t*)*(eventEnd + 2);
6481
6482 while (breakPtr)
6483 {
6484 breakPtr = apScript + (intptr_t)breakPtr;
6485 scriptWriteAtOffset(CON_ENDEVENT | LINE_NUMBER, breakPtr-2);
6486 breakPtr = (intptr_t*)*breakPtr;
6487 }
6488 }
6489
6490 g_totalLines += g_lineNumber;
6491
6492 C_SetScriptSize(g_scriptPtr-apScript+8);
6493
6494 initprintf("Compiled %d bytes in %ums%s\n", (int)((intptr_t)g_scriptPtr - (intptr_t)apScript),
6495 timerGetTicks() - startcompiletime, C_ScriptVersionString(g_scriptVersion));
6496
6497 for (auto i : tables_free)
6498 hash_free(i);
6499
6500 for (auto i : inttables)
6501 inthash_free(i);
6502
6503 freehashnames();
6504 freesoundhashnames();
6505
6506 if (g_scriptDebug)
6507 C_PrintStats();
6508
6509 C_InitQuotes();
6510
6511 #if MICROPROFILE_ENABLED != 0
6512 for (int i=0; i<MAXEVENTS; i++)
6513 {
6514 if (VM_HaveEvent(i))
6515 {
6516 g_eventTokens[i] = MicroProfileGetToken("CON VM Events", EventNames[i], MP_AUTO, MicroProfileTokenTypeCpu);
6517 g_eventCounterTokens[i] = MicroProfileGetCounterToken(EventNames[i]);
6518 }
6519 }
6520
6521 #if 0
6522 for (int i=0; i<CON_END; i++)
6523 {
6524 Bassert(VM_GetKeywordForID(i) != nullptr);
6525 g_instTokens[i] = MicroProfileGetToken("CON VM Instructions", VM_GetKeywordForID(i), MP_AUTO, MicroProfileTokenTypeCpu);
6526 }
6527 #endif
6528
6529 for (int i=0; i<MAXTILES; i++)
6530 {
6531 if (G_TileHasActor(i))
6532 {
6533 int const index = C_GetLabelIndex(i, LABEL_ACTOR);
6534
6535 if (index != -1)
6536 Bsprintf(tempbuf,"%s (%d)", label+(index<<6), i);
6537 else Bsprintf(tempbuf,"unnamed (%d)", i);
6538
6539 g_actorTokens[i] = MicroProfileGetToken("CON VM Actors", tempbuf, MP_AUTO, MicroProfileTokenTypeCpu);
6540 }
6541 }
6542
6543 for (int i=0; i<MAXSTATUS; i++)
6544 {
6545 Bsprintf(tempbuf,"statnum%d", i);
6546 g_statnumTokens[i] = MicroProfileGetToken("CON VM Actors", tempbuf, MP_AUTO, MicroProfileTokenTypeCpu);
6547 }
6548 #endif
6549 }
6550
C_ReportError(int error)6551 void C_ReportError(int error)
6552 {
6553 if (Bstrcmp(g_szCurrentBlockName,g_szLastBlockName))
6554 {
6555 if (g_scriptEventOffset || g_processingState || g_scriptActorOffset)
6556 initprintf("%s: In %s `%s':\n",g_scriptFileName,g_scriptEventOffset?"event":g_scriptActorOffset?"actor":"state",g_szCurrentBlockName);
6557 else initprintf("%s: At top level:\n",g_scriptFileName);
6558 Bstrcpy(g_szLastBlockName,g_szCurrentBlockName);
6559 }
6560 switch (error)
6561 {
6562 case ERROR_NOTTOPLEVEL:
6563 initprintf("%s:%d: error: `%s' not at top level within script.\n",g_scriptFileName,g_lineNumber,tempbuf);
6564 break;
6565 case ERROR_EVENTONLY:
6566 initprintf("%s:%d: error: keyword `%s' only available during events.\n",g_scriptFileName,g_lineNumber,tempbuf);
6567 break;
6568 case ERROR_EXCEEDSMAXTILES:
6569 initprintf("%s:%d: error: `%s' value exceeds MAXTILES. Maximum is %d.\n",g_scriptFileName,g_lineNumber,tempbuf,MAXTILES-1);
6570 break;
6571 case ERROR_EXPECTEDKEYWORD:
6572 initprintf("%s:%d: error: expected a keyword but found `%s'.\n",g_scriptFileName,g_lineNumber,tempbuf);
6573 break;
6574 case ERROR_FOUNDWITHIN:
6575 initprintf("%s:%d: error: found `%s' within %s.\n",g_scriptFileName,g_lineNumber,tempbuf,g_scriptEventOffset?"an event":g_scriptActorOffset?"an actor":"a state");
6576 break;
6577 case ERROR_ISAKEYWORD:
6578 initprintf("%s:%d: error: symbol `%s' is a keyword.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
6579 break;
6580 case ERROR_NOENDSWITCH:
6581 initprintf("%s:%d: error: did not find `endswitch' before `%s'.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
6582 break;
6583 case ERROR_NOTAGAMEDEF:
6584 initprintf("%s:%d: error: symbol `%s' is not a definition.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
6585 break;
6586 case ERROR_NOTAGAMEVAR:
6587 initprintf("%s:%d: error: symbol `%s' is not a variable.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
6588 break;
6589 case ERROR_NOTAGAMEARRAY:
6590 initprintf("%s:%d: error: symbol `%s' is not an array.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
6591 break;
6592 case ERROR_GAMEARRAYBNC:
6593 initprintf("%s:%d: error: malformed array index: expected ], found %c\n",g_scriptFileName,g_lineNumber,*textptr);
6594 break;
6595 case ERROR_GAMEARRAYBNO:
6596 initprintf("%s:%d: error: malformed array index: expected [, found %c\n",g_scriptFileName,g_lineNumber,*textptr);
6597 break;
6598 case ERROR_INVALIDARRAYWRITE:
6599 initprintf("%s:%d: error: arrays can only be written to using `setarray'.\n",g_scriptFileName,g_lineNumber);
6600 break;
6601 case ERROR_PARAMUNDEFINED:
6602 initprintf("%s:%d: error: parameter `%s' is undefined.\n",g_scriptFileName,g_lineNumber,tempbuf);
6603 break;
6604 case ERROR_NOTAMEMBER:
6605 initprintf("%s:%d: error: symbol `%s' is not a valid structure member.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
6606 break;
6607 case ERROR_SYNTAXERROR:
6608 initprintf("%s:%d: error: syntax error.\n",g_scriptFileName,g_lineNumber);
6609 break;
6610 case ERROR_VARREADONLY:
6611 initprintf("%s:%d: error: variable `%s' is read-only.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
6612 break;
6613 case ERROR_ARRAYREADONLY:
6614 initprintf("%s:%d: error: array `%s' is read-only.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
6615 break;
6616 case ERROR_VARTYPEMISMATCH:
6617 initprintf("%s:%d: error: variable `%s' is of the wrong type.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
6618 break;
6619 case ERROR_TOOMANYLABELS:
6620 initprintf("%s:%d: error: too many labels defined! Maximum is %d\n.",g_scriptFileName,g_lineNumber, MAXLABELS);
6621 break;
6622 case WARNING_BADGAMEVAR:
6623 initprintf("%s:%d: warning: variable `%s' should be either per-player OR per-actor, not both.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
6624 break;
6625 case WARNING_DUPLICATECASE:
6626 initprintf("%s:%d: warning: duplicate case ignored.\n",g_scriptFileName,g_lineNumber);
6627 break;
6628 case WARNING_DUPLICATEDEFINITION:
6629 initprintf("%s:%d: warning: duplicate definition `%s' ignored.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
6630 break;
6631 case WARNING_EVENTSYNC:
6632 initprintf("%s:%d: warning: found `%s' within a local event.\n",g_scriptFileName,g_lineNumber,tempbuf);
6633 break;
6634 case WARNING_LABELSONLY:
6635 initprintf("%s:%d: warning: expected a label, found a constant.\n",g_scriptFileName,g_lineNumber);
6636 break;
6637 case WARNING_NAMEMATCHESVAR:
6638 initprintf("%s:%d: warning: symbol `%s' already used for variable.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
6639 break;
6640 case WARNING_VARMASKSKEYWORD:
6641 initprintf("%s:%d: warning: variable `%s' masks keyword.\n", g_scriptFileName, g_lineNumber, LAST_LABEL);
6642 break;
6643 case WARNING_ARRAYMASKSKEYWORD:
6644 initprintf("%s:%d: warning: array `%s' masks keyword.\n", g_scriptFileName, g_lineNumber, LAST_LABEL);
6645 break;
6646 }
6647 }
6648