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 "duke3d.h"
24 #include "namesdyn.h"
25 #include "gamedef.h"
26 #include "gameexec.h"
27 #include "savegame.h"
28 #include "common.h"
29 #include "common_game.h"
30 #include "cheats.h"
31
32 #include "osd.h"
33 #include "crc32.h"
34
35 #define LINE_NUMBER (g_lineNumber << 12)
36
37 int32_t g_scriptVersion = 14; // 13 = 1.3D-style CON files, 14 = 1.4/1.5 style CON files
38
39 char g_scriptFileName[BMAX_PATH] = "(none)"; // file we're currently compiling
40
41 int32_t g_totalLines, g_lineNumber;
42 uint32_t g_scriptcrc;
43 char g_szBuf[1024];
44
45 static char g_szCurrentBlockName[256] = "(none)", g_szLastBlockName[256] = "NULL";
46 static int32_t g_checkingIfElse, g_processingState, g_lastKeyword = -1;
47
48 // The pointer to the start of the case table in a switch statement.
49 // First entry is 'default' code.
50 static intptr_t *g_caseScriptPtr;
51 static int32_t g_labelsOnly = 0;
52 static int32_t g_numBraces = 0;
53
54 static int32_t C_ParseCommand(int32_t loop);
55 static int32_t C_SetScriptSize(int32_t size);
56
57 static intptr_t apScriptGameEventEnd[MAXEVENTS];
58 static intptr_t g_parsingActorPtr;
59 static intptr_t g_scriptEventOffset;
60 static char *textptr;
61
62 int32_t g_errorCnt,g_warningCnt;
63
C_GetLabelType(int32_t type)64 static char *C_GetLabelType(int32_t type)
65 {
66 int32_t i;
67 char x[64];
68
69 const char *LabelTypeText[] =
70 {
71 "define",
72 "state",
73 "actor",
74 "action",
75 "ai",
76 "move"
77 };
78
79 x[0] = 0;
80 for (i=0; i<6; i++)
81 {
82 if (!(type & (1<<i))) continue;
83 if (x[0]) Bstrcat(x, " or ");
84 Bstrcat(x, LabelTypeText[i]);
85 }
86
87 return Xstrdup(x);
88 }
89
90 static tokenmap_t const vm_keywords[] =
91 {
92 { "action", CON_ACTION },
93 { "actor", CON_ACTOR },
94 { "addammo", CON_ADDAMMO },
95 { "addinventory", CON_ADDINVENTORY },
96 { "addkills", CON_ADDKILLS },
97 { "addlog", CON_ADDLOGVAR },
98 { "addlogvar", CON_ADDLOGVAR },
99 { "addphealth", CON_ADDPHEALTH },
100 { "addstrength", CON_ADDSTRENGTH },
101 { "addvar", CON_ADDVAR },
102 { "addvarvar", CON_ADDVARVAR },
103 { "addweapon", CON_ADDWEAPON },
104 { "ai", CON_AI },
105 { "betaname", CON_BETANAME },
106 { "break", CON_BREAK },
107 { "cactor", CON_CACTOR },
108 { "clipdist", CON_CLIPDIST },
109 { "count", CON_COUNT },
110 { "cstat", CON_CSTAT },
111 { "cstator", CON_CSTATOR },
112 { "debris", CON_DEBRIS },
113 { "debug", CON_DEBUG },
114 { "define", CON_DEFINE },
115 { "definelevelname", CON_DEFINELEVELNAME },
116 { "definequote", CON_DEFINEQUOTE },
117 { "defineskillname", CON_DEFINESKILLNAME },
118 { "definesound", CON_DEFINESOUND },
119 { "definevolumename", CON_DEFINEVOLUMENAME },
120 { "deploybias", CON_DEPLOYBIAS },
121 { "destroyit", CON_DESTROYIT },
122 { "else", CON_ELSE },
123 { "enda", CON_ENDA },
124 { "endevent", CON_ENDEVENT },
125 { "endofgame", CON_ENDOFGAME },
126 { "ends", CON_ENDS },
127 { "fakebubba", CON_FAKEBUBBA },
128 { "fall", CON_FALL },
129 { "feathers", CON_MAIL },
130 { "gamestartup", CON_GAMESTARTUP },
131 { "gamevar", CON_GAMEVAR },
132 { "garybanjo", CON_GARYBANJO },
133 { "getlastpal", CON_GETLASTPAL },
134 { "globalsound", CON_GLOBALSOUND },
135 { "guts", CON_GUTS },
136 { "hitradius", CON_HITRADIUS },
137 { "ifaction", CON_IFACTION },
138 { "ifactioncount", CON_IFACTIONCOUNT },
139 { "ifactor", CON_IFACTOR },
140 { "ifactorhealthg", CON_IFACTORHEALTHG },
141 { "ifactorhealthl", CON_IFACTORHEALTHL },
142 { "ifactornotstayput", CON_IFACTORNOTSTAYPUT },
143 { "ifai", CON_IFAI },
144 { "ifangdiffl", CON_IFANGDIFFL },
145 { "ifawayfromwall", CON_IFAWAYFROMWALL },
146 { "ifbulletnear", CON_IFBULLETNEAR },
147 { "ifcansee", CON_IFCANSEE },
148 { "ifcanseetarget", CON_IFCANSEETARGET },
149 { "ifcanshoottarget", CON_IFCANSHOOTTARGET },
150 { "ifceilingdistl", CON_IFCEILINGDISTL },
151 { "ifcount", CON_IFCOUNT },
152 { "ifdead", CON_IFDEAD },
153 { "iffindnewspot", CON_IFFINDNEWSPOT },
154 { "iffloordistl", CON_IFFLOORDISTL },
155 { "ifgapzl", CON_IFGAPZL },
156 { "ifgotweaponce", CON_IFGOTWEAPONCE },
157 { "ifhitspace", CON_IFHITSPACE },
158 { "ifhittruck", CON_IFHITTRUCK },
159 { "ifhitweapon", CON_IFHITWEAPON },
160 { "ifinouterspace", CON_IFINOUTERSPACE },
161 { "ifinspace", CON_IFINSPACE },
162 { "ifinwater", CON_IFINWATER },
163 { "ifmotofast", CON_IFMOTOFAST },
164 { "ifmove", CON_IFMOVE },
165 { "ifmultiplayer", CON_IFMULTIPLAYER },
166 { "ifnocover", CON_IFNOCOVER },
167 { "ifnosounds", CON_IFNOSOUNDS },
168 { "ifnotmoving", CON_IFNOTMOVING },
169 { "ifcoop", CON_IFCOOP },
170 { "ifonboat", CON_IFONBOAT },
171 { "ifonmoto", CON_IFONMOTO },
172 { "ifonmud", CON_IFONMUD },
173 { "ifonwater", CON_IFONWATER },
174 { "ifoutside", CON_IFOUTSIDE },
175 { "ifp", CON_IFP },
176 { "ifpdistg", CON_IFPDISTG },
177 { "ifpdistl", CON_IFPDISTL },
178 { "ifpdrunk", CON_IFPDRUNK },
179 { "ifphealthl", CON_IFPHEALTHL },
180 { "ifpinventory", CON_IFPINVENTORY },
181 { "ifrespawn", CON_IFRESPAWN },
182 { "ifrnd", CON_IFRND },
183 { "ifsizedown", CON_IFSIZEDOWN },
184 { "ifsounddist", CON_IFSOUNDDIST },
185 { "ifsoundid", CON_IFSOUNDID },
186 { "ifspawnedby", CON_IFSPAWNEDBY },
187 { "ifspritepal", CON_IFSPRITEPAL },
188 { "ifsquished", CON_IFSQUISHED },
189 { "ifstrength", CON_IFSTRENGTH },
190 { "iftipcow", CON_IFTIPCOW },
191 { "ifpupwind", CON_IFPUPWIND },
192 { "ifvare", CON_IFVARE },
193 { "ifvarg", CON_IFVARG },
194 { "ifvarl", CON_IFVARL },
195 { "ifvarvare", CON_IFVARVARE },
196 { "ifvarvarg", CON_IFVARVARG },
197 { "ifvarvarl", CON_IFVARVARL },
198 { "ifwasweapon", CON_IFWASWEAPON },
199 { "ifwind", CON_IFWIND },
200 { "include", CON_INCLUDE },
201 { "isdrunk", CON_ISDRUNK },
202 { "iseat", CON_ISEAT },
203 { "killit", CON_KILLIT },
204 { "larrybird", CON_LARRYBIRD },
205 { "leavedroppings", CON_LEAVEDROPPINGS },
206 { "leavetrax", CON_LEAVETRAX },
207 { "lotsofglass", CON_LOTSOFGLASS },
208 { "mail", CON_MAIL },
209 { "mamaend", CON_MAMAEND },
210 { "mamaquake", CON_MAMAQUAKE },
211 { "mamaspawn", CON_MAMASPAWN },
212 { "mamatrigger", CON_MAMATRIGGER },
213 { "mikesnd", CON_MIKESND },
214 { "money", CON_MONEY },
215 { "motoloopsnd", CON_MOTOLOOPSND },
216 { "move", CON_MOVE },
217 { "music", CON_MUSIC },
218 { "newpic", CON_NEWPIC },
219 { "nullop", CON_NULLOP },
220 { "onevent", CON_ONEVENT },
221 { "operate", CON_OPERATE },
222 { "palfrom", CON_PALFROM },
223 { "paper", CON_PAPER },
224 { "pkick", CON_PKICK },
225 { "pstomp", CON_PSTOMP },
226 { "quote", CON_QUOTE },
227 { "resetactioncount", CON_RESETACTIONCOUNT },
228 { "resetcount", CON_RESETCOUNT },
229 { "resetplayer", CON_RESETPLAYER },
230 { "respawnhitag", CON_RESPAWNHITAG },
231 { "rndmove", CON_RNDMOVE },
232 { "setvar", CON_SETVAR },
233 { "setvarvar", CON_SETVARVAR },
234 { "sizeat", CON_SIZEAT },
235 { "sizeto", CON_SIZETO },
236 { "slapplayer", CON_SLAPPLAYER },
237 { "sleeptime", CON_SLEEPTIME },
238 { "shoot", CON_SHOOT },
239 { "smackbubba", CON_SMACKBUBBA },
240 { "smacksprite", CON_SMACKSPRITE },
241 { "sound", CON_SOUND },
242 { "soundonce", CON_SOUNDONCE },
243 { "soundtag", CON_SOUNDTAG },
244 { "soundtagonce", CON_SOUNDTAGONCE },
245 { "spawn", CON_SPAWN },
246 { "spritepal", CON_SPRITEPAL },
247 { "state", CON_STATE },
248 { "stopsound", CON_STOPSOUND },
249 { "strafeleft", CON_STRAFELEFT },
250 { "straferight", CON_STRAFERIGHT },
251 { "strength", CON_STRENGTH },
252 { "tearitup", CON_TEARITUP },
253 { "tip", CON_TIP },
254 { "tossweapon", CON_TOSSWEAPON },
255 { "useractor", CON_USERACTOR },
256 { "wackplayer", CON_WACKPLAYER },
257 { "{", CON_LEFTBRACE },
258 { "}", CON_RIGHTBRACE },
259 };
260
261 static const vec2_t varvartable[] =
262 {
263 { CON_IFVARVARE, CON_IFVARE },
264 { CON_IFVARVARG, CON_IFVARG },
265 { CON_IFVARVARL, CON_IFVARL },
266
267 { CON_ADDVARVAR, CON_ADDVAR },
268 { CON_SETVARVAR, CON_SETVAR },
269 };
270
271 static inthashtable_t h_varvar = { NULL, INTHASH_SIZE(ARRAY_SIZE(varvartable)) };
272
273 static inthashtable_t *const inttables[] = {
274 &h_varvar,
275 };
276
VM_GetKeywordForID(int32_t id)277 char const * VM_GetKeywordForID(int32_t id)
278 {
279 // could be better but this is only called for diagnostics, ayy lmao
280 for (tokenmap_t const & keyword : vm_keywords)
281 if (keyword.val == id)
282 return keyword.token;
283
284 return "<invalid keyword>";
285 }
286
287 char *bitptr; // pointer to bitmap of which bytecode positions contain pointers
288 #define BITPTR_SET(x) (bitptr[(x)>>3] |= (1<<((x)&7)))
289 #define BITPTR_CLEAR(x) (bitptr[(x)>>3] &= ~(1<<((x)&7)))
290 #define BITPTR_IS_POINTER(x) (bitptr[(x)>>3] & (1<<((x) &7)))
291
292 hashtable_t h_gamevars = { MAXGAMEVARS >> 1, NULL };
293 hashtable_t h_labels = { 11264>>1, NULL };
294
295 static hashtable_t h_keywords = { CON_END>>1, NULL };;
296
297 static hashtable_t * const tables[] = {
298 &h_labels, &h_keywords, &h_gamevars
299 };
300
301 static hashtable_t * const tables_free [] = {
302 &h_labels, &h_keywords
303 };
304
305 #define STRUCT_HASH_SETUP(table, labels) do { for (i=0; labels[i].lId >= 0; i++) hash_add(&table, labels[i].name, i, 0); } while (0)
306
C_InitHashes()307 void C_InitHashes()
308 {
309 uint32_t i;
310
311 for (auto table : tables)
312 hash_init(table);
313
314 for (auto table : inttables)
315 inthash_init(table);
316
317 for (auto &varvar : varvartable)
318 inthash_add(&h_varvar, varvar.x, varvar.y, 0);
319
320 //inithashnames();
321 initsoundhashnames();
322
323 for (tokenmap_t const & keyword : vm_keywords)
324 hash_add(&h_keywords, keyword.token, keyword.val, 0);
325 }
326
327 #undef STRUCT_HASH_SETUP
328
329 // "magic" number for { and }, overrides line number in compiled code for later detection
330 #define IFELSE_MAGIC 31337
331 static int32_t g_skipBranch;
332
C_SetScriptSize(int32_t newsize)333 static int32_t C_SetScriptSize(int32_t newsize)
334 {
335 intptr_t const oscript = (intptr_t)apScript;
336 intptr_t *newscript;
337 intptr_t i, j;
338 int32_t osize = g_scriptSize;
339 char *scriptptrs;
340 char *newbitptr;
341
342 scriptptrs = (char *)Xcalloc(1, g_scriptSize * sizeof(uint8_t));
343
344 for (i=g_scriptSize-1; i>=0; i--)
345 {
346 if (BITPTR_IS_POINTER(i))
347 {
348 if (EDUKE32_PREDICT_FALSE((intptr_t)apScript[i] < (intptr_t)&apScript[0] || (intptr_t)apScript[i] >= (intptr_t)&apScript[g_scriptSize]))
349 {
350 g_errorCnt++;
351 buildprint("Internal compiler error at ", i, " (0x", hex(i), ")\n");
352 VM_ScriptInfo(&apScript[i], 16);
353 }
354
355 scriptptrs[i] = 1;
356 apScript[i] -= (intptr_t)&apScript[0];
357 }
358 else scriptptrs[i] = 0;
359 }
360
361 G_Util_PtrToIdx2(&g_tile[0].execPtr, MAXTILES, sizeof(tiledata_t), apScript, P2I_FWD_NON0);
362 G_Util_PtrToIdx2(&g_tile[0].loadPtr, MAXTILES, sizeof(tiledata_t), apScript, P2I_FWD_NON0);
363
364 newscript = (intptr_t *)Xrealloc(apScript, newsize * sizeof(intptr_t));
365 newbitptr = (char *)Xcalloc(1,(((newsize+7)>>3)+1) * sizeof(uint8_t));
366
367 if (newsize >= osize)
368 {
369 Bmemset(&newscript[0]+osize,0,(newsize-osize) * sizeof(uint8_t));
370 Bmemcpy(newbitptr,bitptr,sizeof(uint8_t) *((osize+7)>>3));
371 }
372 else
373 Bmemcpy(newbitptr,bitptr,sizeof(uint8_t) *((newsize+7)>>3));
374
375 Bfree(bitptr);
376 bitptr = newbitptr;
377 if (apScript != newscript)
378 {
379 buildprint("Relocating compiled code from to 0x", hex((intptr_t)apScript), " to 0x", hex((intptr_t)newscript), "\n");
380 apScript = newscript;
381 }
382
383 g_scriptSize = newsize;
384 g_scriptPtr = apScript + (intptr_t)g_scriptPtr - oscript;
385
386 if (g_caseScriptPtr)
387 g_caseScriptPtr = apScript + (intptr_t)g_caseScriptPtr - oscript;
388
389 for (i=(((newsize>=osize)?osize:newsize))-1; i>=0; i--)
390 if (scriptptrs[i])
391 {
392 j = (intptr_t)apScript[i]+(intptr_t)&apScript[0];
393 apScript[i] = j;
394 }
395
396 G_Util_PtrToIdx2(&g_tile[0].execPtr, MAXTILES, sizeof(tiledata_t), apScript, P2I_BACK_NON0);
397 G_Util_PtrToIdx2(&g_tile[0].loadPtr, MAXTILES, sizeof(tiledata_t), apScript, P2I_BACK_NON0);
398
399 Bfree(scriptptrs);
400 return 0;
401 }
402
ispecial(const char c)403 static inline int32_t ispecial(const char c)
404 {
405 return (c == ' ' || c == 0x0d || c == '(' || c == ')' ||
406 c == ',' || c == ';' || (c == 0x0a /*&& ++g_lineNumber*/));
407 }
408
C_NextLine(void)409 static inline void C_NextLine(void)
410 {
411 while (*textptr != 0x0a && *textptr != 0x0d && *textptr != 0)
412 textptr++;
413 }
414
C_SkipSpace(void)415 static inline void C_SkipSpace(void)
416 {
417 while (*textptr == ' ' || *textptr == '\t')
418 textptr++;
419 }
420
421 static int32_t g_gotComment = 0;
422
C_SkipComments(void)423 static int32_t C_SkipComments(void)
424 {
425 g_gotComment = 0;
426 do
427 {
428 switch (*textptr)
429 {
430 case '\n':
431 g_lineNumber++;
432 fallthrough__;
433 case ' ':
434 case '\t':
435 case '\r':
436 case 0x1a:
437 textptr++;
438 break;
439 case '/':
440 switch (textptr[1])
441 {
442 case '/': // C++ style comment
443 if (!(g_errorCnt || g_warningCnt) && g_scriptDebug > 1)
444 initprintf("%s:%d: debug: got comment.\n",g_scriptFileName,g_lineNumber);
445 C_NextLine();
446 g_gotComment = 1;
447 continue;
448 case '*': // beginning of a C style comment
449 if (!(g_errorCnt || g_warningCnt) && g_scriptDebug > 1)
450 initprintf("%s:%d: debug: got start of comment block.\n",g_scriptFileName,g_lineNumber);
451 do
452 {
453 if (*textptr == '\n')
454 g_lineNumber++;
455 textptr++;
456 }
457 while (*textptr && (textptr[0] != '*' || textptr[1] != '/'));
458
459 if (EDUKE32_PREDICT_FALSE(!*textptr))
460 {
461 if (!(g_errorCnt || g_warningCnt) && g_scriptDebug)
462 initprintf("%s:%d: debug: EOF in comment!\n",g_scriptFileName,g_lineNumber);
463 C_ReportError(-1);
464 initprintf("%s:%d: error: found `/*' with no `*/'.\n",g_scriptFileName,g_lineNumber);
465 g_parsingActorPtr = g_processingState = g_numBraces = 0;
466 g_errorCnt++;
467 continue;
468 }
469
470 if (!(g_errorCnt || g_warningCnt) && g_scriptDebug > 1)
471 initprintf("%s:%d: debug: got end of comment block.\n",g_scriptFileName,g_lineNumber);
472
473 textptr+=2;
474 g_gotComment = 1;
475 continue;
476 default:
477 C_ReportError(-1);
478 initprintf("%s:%d: error: malformed comment.\n", g_scriptFileName, g_lineNumber);
479 C_NextLine();
480 g_errorCnt++;
481 continue;
482 }
483 break;
484
485 default:
486 if (ispecial(*textptr))
487 {
488 textptr++;
489 continue;
490 }
491 fallthrough__;
492 case 0: // EOF
493 return ((g_scriptPtr-apScript) > (g_scriptSize-32)) ? C_SetScriptSize(g_scriptSize<<1) : 0;
494 }
495 }
496 while (1);
497 }
498
GetDefID(char const * label)499 static inline int GetDefID(char const *label) { return hash_find(&h_gamevars, label); }
500
501 #define LAST_LABEL (label+(g_labelCnt<<6))
isaltok(const char c)502 static inline int32_t isaltok(const char c)
503 {
504 return (isalnum(c) || c == '{' || c == '}' || c == '/' || c == '\\' || c == '*' || c == '-' || c == '_' ||
505 c == '.');
506 }
507
C_IsLabelChar(const char c,int32_t const i)508 static inline int32_t C_IsLabelChar(const char c, int32_t const i)
509 {
510 return (isalnum(c) || c == '_' || c == '*' || c == '?' || (i > 0 && (c == '+' || c == '-' || c == '.')));
511 }
512
C_GetLabelNameID(const memberlabel_t * pLabel,hashtable_t const * const table,const char * psz)513 static inline int32_t C_GetLabelNameID(const memberlabel_t *pLabel, hashtable_t const * const table, const char *psz)
514 {
515 // find the label psz in the table pLabel.
516 // returns the ID for the label, or -1
517
518 int32_t l = hash_findcase(table, psz);
519 return (l >= 0) ? pLabel[l].lId : -1;
520 }
521
C_GetLabelNameOffset(hashtable_t const * const table,const char * psz)522 static inline int32_t C_GetLabelNameOffset(hashtable_t const * const table, const char *psz)
523 {
524 // find the label psz in the table pLabel.
525 // returns the offset in the array for the label, or -1
526
527 return hash_findcase(table, psz);
528 }
529
C_GetNextLabelName(void)530 static void C_GetNextLabelName(void)
531 {
532 int32_t i = 0;
533
534 C_SkipComments();
535
536 // while (ispecial(*textptr) == 0 && *textptr!='['&& *textptr!=']' && *textptr!='\t' && *textptr!='\n' && *textptr!='\r')
537 while (C_IsLabelChar(*textptr, i))
538 label[(g_labelCnt<<6)+(i++)] = *(textptr++);
539
540 label[(g_labelCnt<<6)+i] = 0;
541
542 if (!(g_errorCnt|g_warningCnt) && g_scriptDebug > 1)
543 initprintf("%s:%d: debug: label `%s'.\n",g_scriptFileName,g_lineNumber,label+(g_labelCnt<<6));
544 }
545
scriptWriteValue(int32_t const value)546 static inline void scriptWriteValue(int32_t const value)
547 {
548 BITPTR_CLEAR(g_scriptPtr-apScript);
549 *g_scriptPtr++ = value;
550 }
551
552 // 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)553 static inline void scriptWriteAtOffset(int32_t const value, intptr_t * const addr)
554 {
555 BITPTR_CLEAR(addr-apScript);
556 *(addr) = value;
557 }
558
scriptWritePointer(intptr_t const value,intptr_t * const addr)559 static inline void scriptWritePointer(intptr_t const value, intptr_t * const addr)
560 {
561 BITPTR_SET(addr-apScript);
562 *(addr) = value;
563 }
564
C_GetKeyword(void)565 static int32_t C_GetKeyword(void)
566 {
567 int32_t i;
568 char *temptextptr;
569
570 C_SkipComments();
571
572 temptextptr = textptr;
573
574 if (*temptextptr == 0) // EOF
575 return -2;
576
577 while (isaltok(*temptextptr) == 0)
578 {
579 temptextptr++;
580 if (*temptextptr == 0)
581 return 0;
582 }
583
584 i = 0;
585 while (isaltok(*temptextptr))
586 tempbuf[i++] = *(temptextptr++);
587 tempbuf[i] = 0;
588
589 return hash_find(&h_keywords,tempbuf);
590 }
591
C_GetNextKeyword(void)592 static int32_t C_GetNextKeyword(void) //Returns its code #
593 {
594 int32_t i, l;
595
596 C_SkipComments();
597
598 if (*textptr == 0) // EOF
599 return -2;
600
601 l = 0;
602 while (isaltok(*(textptr+l)))
603 {
604 tempbuf[l] = textptr[l];
605 l++;
606 }
607 tempbuf[l] = 0;
608
609 if (EDUKE32_PREDICT_TRUE((i = hash_find(&h_keywords,tempbuf)) >= 0))
610 {
611 if (i == CON_LEFTBRACE || i == CON_RIGHTBRACE || i == CON_NULLOP)
612 scriptWriteValue(i | (VM_IFELSE_MAGIC<<12));
613 else scriptWriteValue(i | LINE_NUMBER);
614
615 textptr += l;
616
617 if (!(g_errorCnt || g_warningCnt) && g_scriptDebug)
618 initprintf("%s:%d: debug: keyword `%s'.\n", g_scriptFileName, g_lineNumber, tempbuf);
619 return i;
620 }
621
622 textptr += l;
623 g_errorCnt++;
624
625 if (EDUKE32_PREDICT_FALSE((tempbuf[0] == '{' || tempbuf[0] == '}') && tempbuf[1] != 0))
626 {
627 C_ReportError(-1);
628 initprintf("%s:%d: error: expected whitespace between `%c' and `%s'.\n",g_scriptFileName,g_lineNumber,tempbuf[0],tempbuf+1);
629 }
630 else C_ReportError(ERROR_EXPECTEDKEYWORD);
631
632 return -1;
633 }
634
parse_decimal_number(void)635 static int32_t parse_decimal_number(void) // (textptr)
636 {
637 // decimal constants -- this is finicky business
638 int64_t num = strtoll(textptr, NULL, 10); // assume long long to be int64_t
639
640 if (EDUKE32_PREDICT_TRUE(num >= INT32_MIN && num <= INT32_MAX))
641 {
642 // all OK
643 }
644 else if (EDUKE32_PREDICT_FALSE(num > INT32_MAX && num <= UINT32_MAX))
645 {
646 // Number interpreted as uint32, but packed as int32 (on 32-bit archs)
647 // (CON code in the wild exists that does this). Note that such conversion
648 // is implementation-defined (C99 6.3.1.3) but GCC does the 'expected' thing.
649 #if 0
650 initprintf("%s:%d: warning: number greater than INT32_MAX converted to a negative one.\n",
651 g_szScriptFileName,g_lineNumber);
652 g_numCompilerWarnings++;
653 #endif
654 }
655 else
656 {
657 // out of range, this is arguably worse
658
659 initprintf("%s:%d: warning: number out of the range of a 32-bit integer encountered.\n",
660 g_scriptFileName,g_lineNumber);
661 g_warningCnt++;
662 }
663
664 return (int32_t)num;
665 }
666
parse_hex_constant(const char * hexnum)667 static int32_t parse_hex_constant(const char *hexnum)
668 {
669 uint64_t x;
670 sscanf(hexnum, "%" PRIx64 "", &x);
671
672 if (EDUKE32_PREDICT_FALSE(x > UINT32_MAX))
673 {
674 initprintf(g_scriptFileName, ":", g_lineNumber, ": warning: number 0x", hex(x), " truncated to 32 bits.\n");
675 g_warningCnt++;
676 }
677
678 return x;
679 }
680
C_GetNextVarType(int32_t type)681 static void C_GetNextVarType(int32_t type)
682 {
683 int32_t id = 0;
684 int32_t flags = 0;
685
686 auto varptr = g_scriptPtr;
687
688 C_SkipComments();
689
690 if (!type && !g_labelsOnly && (isdigit(*textptr) || ((*textptr == '-') && (isdigit(*(textptr+1))))))
691 {
692 scriptWriteValue(GV_FLAG_CONSTANT);
693
694 if (tolower(textptr[1])=='x') // hex constants
695 scriptWriteValue(parse_hex_constant(textptr+2));
696 else
697 scriptWriteValue(parse_decimal_number());
698
699 if (!(g_errorCnt || g_warningCnt) && g_scriptDebug)
700 initprintf("%s:%d: debug: constant %ld in place of gamevar.\n", g_scriptFileName, g_lineNumber, (long)(g_scriptPtr[-1]));
701 #if 1
702 while (!ispecial(*textptr) && *textptr != ']') textptr++;
703 #else
704 C_GetNextLabelName();
705 #endif
706 return;
707 }
708 else if (*textptr == '-'/* && !isdigit(*(textptr+1))*/)
709 {
710 if (EDUKE32_PREDICT_FALSE(type))
711 {
712 g_errorCnt++;
713 C_ReportError(ERROR_SYNTAXERROR);
714 C_GetNextLabelName();
715 return;
716 }
717
718 if (!(g_errorCnt || g_warningCnt) && g_scriptDebug)
719 initprintf("%s:%d: debug: flagging gamevar as negative.\n", g_scriptFileName, g_lineNumber); //,Batol(textptr));
720
721 flags = GV_FLAG_NEGATIVE;
722 textptr++;
723 }
724
725 C_GetNextLabelName();
726
727 if (EDUKE32_PREDICT_FALSE(hash_find(&h_keywords,LAST_LABEL)>=0))
728 {
729 g_errorCnt++;
730 C_ReportError(ERROR_ISAKEYWORD);
731 return;
732 }
733
734 C_SkipComments();
735
736 id=GetDefID(LAST_LABEL);
737 if (id<0) //gamevar not found
738 {
739 if (EDUKE32_PREDICT_TRUE(!type && !g_labelsOnly))
740 {
741 //try looking for a define instead
742 Bstrcpy(tempbuf,LAST_LABEL);
743 id = hash_find(&h_labels,tempbuf);
744
745 if (EDUKE32_PREDICT_TRUE(id>=0 && labeltype[id] & LABEL_DEFINE))
746 {
747 if (!(g_errorCnt || g_warningCnt) && g_scriptDebug)
748 initprintf("%s:%d: debug: label `%s' in place of gamevar.\n",g_scriptFileName,g_lineNumber,label+(id<<6));
749
750 scriptWriteValue(GV_FLAG_CONSTANT);
751 scriptWriteValue(labelcode[id]);
752 return;
753 }
754 }
755
756 g_errorCnt++;
757 C_ReportError(ERROR_NOTAGAMEVAR);
758 return;
759 }
760
761 if (EDUKE32_PREDICT_FALSE(type == GAMEVAR_READONLY && aGameVars[id].flags & GAMEVAR_READONLY))
762 {
763 g_errorCnt++;
764 C_ReportError(ERROR_VARREADONLY);
765 return;
766 }
767 else if (EDUKE32_PREDICT_FALSE(aGameVars[id].flags & type))
768 {
769 g_errorCnt++;
770 C_ReportError(ERROR_VARTYPEMISMATCH);
771 return;
772 }
773
774 if (g_scriptDebug > 1 && !g_errorCnt && !g_warningCnt)
775 initprintf("%s:%d: debug: gamevar `%s'.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
776
777 scriptWriteValue(id|flags);
778 }
779
780 #define C_GetNextVar() C_GetNextVarType(0)
781
C_GetManyVarsType(int32_t type,int num)782 static FORCE_INLINE void C_GetManyVarsType(int32_t type, int num)
783 {
784 for (; num>0; --num)
785 C_GetNextVarType(type);
786 }
787
788 #define C_GetManyVars(num) C_GetManyVarsType(0,num)
789
790 // returns:
791 // -1 on EOF or wrong type or error
792 // 0 if literal value
793 // LABEL_* (>0) if that type and matched
794 //
795 // *g_scriptPtr will contain the value OR 0 if wrong type or error
C_GetNextValue(int32_t type)796 static int32_t C_GetNextValue(int32_t type)
797 {
798 C_SkipComments();
799
800 if (*textptr == 0) // EOF
801 return -1;
802
803 int32_t l = 0;
804
805 while (isaltok(*(textptr+l)))
806 {
807 tempbuf[l] = textptr[l];
808 l++;
809 }
810 tempbuf[l] = 0;
811
812 if (EDUKE32_PREDICT_FALSE(hash_find(&h_keywords,tempbuf /*label+(g_numLabels<<6)*/)>=0))
813 {
814 g_errorCnt++;
815 C_ReportError(ERROR_ISAKEYWORD);
816 textptr+=l;
817 }
818
819 int32_t i = hash_find(&h_labels,tempbuf);
820
821 if (i>=0)
822 {
823 if (EDUKE32_PREDICT_TRUE(labeltype[i] & type))
824 {
825 if (!(g_errorCnt || g_warningCnt) && g_scriptDebug > 1)
826 {
827 char *gl = C_GetLabelType(labeltype[i]);
828 initprintf("%s:%d: debug: %s label `%s'.\n",g_scriptFileName,g_lineNumber,gl,label+(i<<6));
829 Bfree(gl);
830 }
831
832 BITPTR_CLEAR(g_scriptPtr-apScript);
833 *(g_scriptPtr++) = labelcode[i];
834
835 textptr += l;
836 return labeltype[i];
837 }
838
839 BITPTR_CLEAR(g_scriptPtr-apScript);
840 *(g_scriptPtr++) = 0;
841 textptr += l;
842 char *el = C_GetLabelType(type);
843 char *gl = C_GetLabelType(labeltype[i]);
844 C_ReportError(-1);
845 initprintf("%s:%d: warning: expected %s, found %s.\n",g_scriptFileName,g_lineNumber,el,gl);
846 g_warningCnt++;
847 Bfree(el);
848 Bfree(gl);
849 return -1; // valid label name, but wrong type
850 }
851
852 if (EDUKE32_PREDICT_FALSE(isdigit(*textptr) == 0 && *textptr != '-'))
853 {
854 C_ReportError(ERROR_PARAMUNDEFINED);
855 g_errorCnt++;
856 BITPTR_CLEAR(g_scriptPtr-apScript);
857 *g_scriptPtr = 0;
858 g_scriptPtr++;
859 textptr+=l;
860 if (!l) textptr++;
861 return -1; // error!
862 }
863
864 if (EDUKE32_PREDICT_FALSE(isdigit(*textptr) && g_labelsOnly))
865 {
866 C_ReportError(WARNING_LABELSONLY);
867 g_warningCnt++;
868 }
869
870 i = l-1;
871 do
872 {
873 // FIXME: check for 0-9 A-F for hex
874 if (textptr[0] == '0' && textptr[1] == 'x') break; // kill the warning for hex
875 if (EDUKE32_PREDICT_FALSE(!isdigit(textptr[i--])))
876 {
877 C_ReportError(-1);
878 initprintf("%s:%d: warning: invalid character `%c' in definition!\n",g_scriptFileName,g_lineNumber,textptr[i+1]);
879 g_warningCnt++;
880 break;
881 }
882 }
883 while (i > 0);
884
885 BITPTR_CLEAR(g_scriptPtr-apScript);
886
887 if (textptr[0] == '0' && tolower(textptr[1])=='x')
888 *g_scriptPtr = parse_hex_constant(textptr+2);
889 else
890 *g_scriptPtr = parse_decimal_number();
891
892 if (!(g_errorCnt || g_warningCnt) && g_scriptDebug > 1)
893 initprintf("%s:%d: debug: constant %ld.\n",
894 g_scriptFileName,g_lineNumber,(long)*g_scriptPtr);
895
896 g_scriptPtr++;
897
898 textptr += l;
899
900 return 0; // literal value
901 }
902
C_CheckMalformedBranch(intptr_t lastScriptPtr)903 static int32_t C_CheckMalformedBranch(intptr_t lastScriptPtr)
904 {
905 switch (C_GetKeyword())
906 {
907 case CON_RIGHTBRACE:
908 case CON_ENDA:
909 case CON_ENDS:
910 case CON_ELSE:
911 g_scriptPtr = lastScriptPtr + &apScript[0];
912 g_skipBranch = 1;
913 C_ReportError(-1);
914 g_warningCnt++;
915 initprintf("%s:%d: warning: malformed `%s' branch\n",g_scriptFileName,g_lineNumber,
916 VM_GetKeywordForID(*(g_scriptPtr) & VM_INSTMASK));
917 return 1;
918 }
919 return 0;
920 }
921
C_CheckEmptyBranch(int32_t tw,intptr_t lastScriptPtr)922 static int32_t C_CheckEmptyBranch(int32_t tw, intptr_t lastScriptPtr)
923 {
924 // ifrnd and the others actually do something when the condition is executed
925 if ((Bstrncmp(VM_GetKeywordForID(tw), "if", 2) && tw != CON_ELSE) ||
926 tw == CON_IFRND || tw == CON_IFHITWEAPON || tw == CON_IFCANSEE || tw == CON_IFCANSEETARGET ||
927 tw == CON_IFPDISTL || tw == CON_IFPDISTG || tw == CON_IFGOTWEAPONCE)
928 {
929 g_skipBranch = 0;
930 return 0;
931 }
932
933 if ((*(g_scriptPtr) & VM_INSTMASK) != CON_NULLOP || *(g_scriptPtr)>>12 != IFELSE_MAGIC)
934 g_skipBranch = 0;
935
936 if (EDUKE32_PREDICT_FALSE(g_skipBranch))
937 {
938 C_ReportError(-1);
939 g_warningCnt++;
940 g_scriptPtr = lastScriptPtr + &apScript[0];
941 initprintf("%s:%d: warning: empty `%s' branch\n",g_scriptFileName,g_lineNumber,
942 VM_GetKeywordForID(*(g_scriptPtr) & VM_INSTMASK));
943 *(g_scriptPtr) = (CON_NULLOP + (IFELSE_MAGIC<<12));
944 return 1;
945 }
946 return 0;
947 }
948
C_Include(const char * confile)949 static void C_Include(const char *confile)
950 {
951 int32_t fp = kopen4loadfrommod(confile,g_loadFromGroupOnly);
952
953 if (EDUKE32_PREDICT_FALSE(fp < 0))
954 {
955 g_errorCnt++;
956 initprintf("%s:%d: error: could not find file `%s'.\n",g_scriptFileName,g_lineNumber,confile);
957 return;
958 }
959
960 int32_t j = kfilelength(fp);
961
962 char *mptr = (char *)Xmalloc(j+1);
963
964 initprintf("Including: %s (%d bytes)\n",confile, j);
965
966 kread(fp, mptr, j);
967 kclose(fp);
968 g_scriptcrc = Bcrc32(mptr, j, g_scriptcrc);
969 mptr[j] = 0;
970
971 if (*textptr == '"') // skip past the closing quote if it's there so we don't screw up the next line
972 textptr++;
973
974 char *origtptr = textptr;
975 char parentScriptFileName[255];
976
977 Bstrcpy(parentScriptFileName, g_scriptFileName);
978 Bstrcpy(g_scriptFileName, confile);
979
980 int32_t temp_ScriptLineNumber = g_lineNumber;
981 g_lineNumber = 1;
982
983 int32_t temp_ifelse_check = g_checkingIfElse;
984 g_checkingIfElse = 0;
985
986 textptr = mptr;
987
988 C_SkipComments();
989 C_ParseCommand(1);
990
991 Bstrcpy(g_scriptFileName, parentScriptFileName);
992
993 g_totalLines += g_lineNumber;
994 g_lineNumber = temp_ScriptLineNumber;
995 g_checkingIfElse = temp_ifelse_check;
996
997 textptr = origtptr;
998
999 Bfree(mptr);
1000 }
1001
1002 #ifdef _WIN32
check_filename_case(const char * fn)1003 static void check_filename_case(const char *fn)
1004 {
1005 int32_t fp;
1006 if ((fp = kopen4loadfrommod(fn, g_loadFromGroupOnly)) >= 0)
1007 kclose(fp);
1008 }
1009 #else
check_filename_case(const char * fn)1010 static void check_filename_case(const char *fn) { UNREFERENCED_PARAMETER(fn); }
1011 #endif
1012
G_DoGameStartup(const int32_t * params)1013 void G_DoGameStartup(const int32_t *params)
1014 {
1015 int j = 0;
1016
1017 ud.const_visibility = params[j++];
1018 g_impactDamage = params[j++];
1019 g_player[0].ps->max_shield_amount = params[j++];
1020 g_player[0].ps->max_player_health = g_player[0].ps->max_shield_amount;
1021 g_maxPlayerHealth = g_player[0].ps->max_player_health;
1022 g_startArmorAmount = params[j++];
1023 g_actorRespawnTime = params[j++];
1024 g_itemRespawnTime = params[j++];
1025 g_playerFriction = params[j++];
1026 g_spriteGravity = params[j++];
1027 g_rpgRadius = params[j++];
1028 g_pipebombRadius = params[j++];
1029 g_shrinkerRadius = params[j++];
1030 g_tripbombRadius = params[j++];
1031 g_morterRadius = params[j++];
1032 g_bouncemineRadius = params[j++];
1033 g_seenineRadius = params[j++];
1034
1035 g_player[0].ps->max_ammo_amount[1] = params[j++];
1036 g_player[0].ps->max_ammo_amount[2] = params[j++];
1037 g_player[0].ps->max_ammo_amount[3] = params[j++];
1038 g_player[0].ps->max_ammo_amount[4] = params[j++];
1039 g_player[0].ps->max_ammo_amount[5] = params[j++];
1040 g_player[0].ps->max_ammo_amount[6] = params[j++];
1041 g_player[0].ps->max_ammo_amount[7] = params[j++];
1042 g_player[0].ps->max_ammo_amount[8] = params[j++];
1043 g_player[0].ps->max_ammo_amount[9] = params[j++];
1044 g_player[0].ps->max_ammo_amount[11] = params[j++];
1045
1046 if (RR)
1047 g_player[0].ps->max_ammo_amount[12] = params[j++];
1048
1049 g_damageCameras = params[j++];
1050 g_numFreezeBounces = params[j++];
1051 g_freezerSelfDamage = params[j++];
1052 g_deleteQueueSize = clamp(params[j++], 0, 1024);
1053 g_tripbombLaserMode = params[j++];
1054
1055 if (RRRA)
1056 {
1057 g_player[0].ps->max_ammo_amount[13] = params[j++];
1058 g_player[0].ps->max_ammo_amount[14] = params[j++];
1059 g_player[0].ps->max_ammo_amount[16] = params[j++];
1060 }
1061 }
1062
C_DefineMusic(int volumeNum,int levelNum,const char * fileName)1063 void C_DefineMusic(int volumeNum, int levelNum, const char *fileName)
1064 {
1065 Bassert((unsigned)volumeNum < MAXVOLUMES+1);
1066 Bassert((unsigned)levelNum < MAXLEVELS);
1067
1068 map_t *const pMapInfo = &g_mapInfo[(MAXLEVELS*volumeNum)+levelNum];
1069
1070 Bfree(pMapInfo->musicfn);
1071 pMapInfo->musicfn = dup_filename(fileName);
1072 check_filename_case(pMapInfo->musicfn);
1073 }
1074
C_DefineVolumeFlags(int32_t vol,int32_t flags)1075 void C_DefineVolumeFlags(int32_t vol, int32_t flags)
1076 {
1077 Bassert((unsigned)vol < MAXVOLUMES);
1078
1079 g_volumeFlags[vol] = flags;
1080 }
1081
C_AllocQuote(int32_t qnum)1082 int32_t C_AllocQuote(int32_t qnum)
1083 {
1084 Bassert((unsigned)qnum < MAXQUOTES);
1085
1086 if (apStrings[qnum] == NULL)
1087 {
1088 apStrings[qnum] = (char *)Xcalloc(MAXQUOTELEN,sizeof(uint8_t));
1089 return 1;
1090 }
1091
1092 return 0;
1093 }
1094
1095 #ifndef EDUKE32_TOUCH_DEVICES
C_ReplaceQuoteSubstring(const size_t q,char const * const query,char const * const replacement)1096 static void C_ReplaceQuoteSubstring(const size_t q, char const * const query, char const * const replacement)
1097 {
1098 size_t querylength = Bstrlen(query);
1099
1100 for (bssize_t i = MAXQUOTELEN - querylength - 2; i >= 0; i--)
1101 if (Bstrncmp(&apStrings[q][i], query, querylength) == 0)
1102 {
1103 Bmemset(tempbuf, 0, sizeof(tempbuf));
1104 Bstrncpy(tempbuf, apStrings[q], i);
1105 Bstrcat(tempbuf, replacement);
1106 Bstrcat(tempbuf, &apStrings[q][i + querylength]);
1107 Bstrncpy(apStrings[q], tempbuf, MAXQUOTELEN - 1);
1108 i = MAXQUOTELEN - querylength - 2;
1109 }
1110 }
1111 #endif
1112
C_InitQuotes(void)1113 void C_InitQuotes(void)
1114 {
1115 for (bssize_t i = 0; i < 128; i++) C_AllocQuote(i);
1116
1117 #ifdef EDUKE32_TOUCH_DEVICES
1118 apStrings[QUOTE_DEAD] = 0;
1119 #else
1120 char const * const OpenGameFunc = gamefunctions[gamefunc_Open];
1121 C_ReplaceQuoteSubstring(QUOTE_DEAD, "SPACE", OpenGameFunc);
1122 C_ReplaceQuoteSubstring(QUOTE_DEAD, "OPEN", OpenGameFunc);
1123 C_ReplaceQuoteSubstring(QUOTE_DEAD, "USE", OpenGameFunc);
1124 #endif
1125
1126 // most of these are based on Blood, obviously
1127 const char *PlayerObituaries[] =
1128 {
1129 "^02%s^02 beat %s^02 like a cur",
1130 "^02%s^02 broke %s",
1131 "^02%s^02 body bagged %s",
1132 "^02%s^02 boned %s^02 like a fish",
1133 "^02%s^02 castrated %s",
1134 "^02%s^02 creamed %s",
1135 "^02%s^02 crushed %s",
1136 "^02%s^02 destroyed %s",
1137 "^02%s^02 diced %s",
1138 "^02%s^02 disemboweled %s",
1139 "^02%s^02 erased %s",
1140 "^02%s^02 eviscerated %s",
1141 "^02%s^02 flailed %s",
1142 "^02%s^02 flattened %s",
1143 "^02%s^02 gave AnAl MaDnEsS to %s",
1144 "^02%s^02 gave %s^02 Anal Justice",
1145 "^02%s^02 hosed %s",
1146 "^02%s^02 hurt %s^02 real bad",
1147 "^02%s^02 killed %s",
1148 "^02%s^02 made dog meat out of %s",
1149 "^02%s^02 made mincemeat out of %s",
1150 "^02%s^02 manhandled %s",
1151 "^02%s^02 massacred %s",
1152 "^02%s^02 mutilated %s",
1153 "^02%s^02 murdered %s",
1154 "^02%s^02 neutered %s",
1155 "^02%s^02 punted %s",
1156 "^02%s^02 reamed %s",
1157 "^02%s^02 ripped %s^02 a new orifice",
1158 "^02%s^02 rocked %s",
1159 "^02%s^02 sent %s^02 to hell",
1160 "^02%s^02 shredded %s",
1161 "^02%s^02 slashed %s",
1162 "^02%s^02 slaughtered %s",
1163 "^02%s^02 sliced %s",
1164 "^02%s^02 smacked %s around",
1165 "^02%s^02 smashed %s",
1166 "^02%s^02 snuffed %s",
1167 "^02%s^02 sodomized %s",
1168 "^02%s^02 splattered %s",
1169 "^02%s^02 sprayed %s",
1170 "^02%s^02 squashed %s",
1171 "^02%s^02 throttled %s",
1172 "^02%s^02 toasted %s",
1173 "^02%s^02 vented %s",
1174 "^02%s^02 ventilated %s",
1175 "^02%s^02 wasted %s",
1176 "^02%s^02 wrecked %s",
1177 };
1178
1179 const char *PlayerSelfObituaries[] =
1180 {
1181 "^02%s^02 is excrement",
1182 "^02%s^02 is hamburger",
1183 "^02%s^02 suffered scrotum separation",
1184 "^02%s^02 volunteered for population control",
1185 "^02%s^02 has suicided",
1186 "^02%s^02 bled out",
1187 };
1188
1189 EDUKE32_STATIC_ASSERT(OBITQUOTEINDEX + ARRAY_SIZE(PlayerObituaries)-1 < MAXQUOTES);
1190 EDUKE32_STATIC_ASSERT(SUICIDEQUOTEINDEX + ARRAY_SIZE(PlayerSelfObituaries)-1 < MAXQUOTES);
1191
1192 g_numObituaries = ARRAY_SIZE(PlayerObituaries);
1193 for (bssize_t i = g_numObituaries - 1; i >= 0; i--)
1194 {
1195 if (C_AllocQuote(i + OBITQUOTEINDEX))
1196 Bstrcpy(apStrings[i + OBITQUOTEINDEX], PlayerObituaries[i]);
1197 }
1198
1199 g_numSelfObituaries = ARRAY_SIZE(PlayerSelfObituaries);
1200 for (bssize_t i = g_numSelfObituaries - 1; i >= 0; i--)
1201 {
1202 if (C_AllocQuote(i + SUICIDEQUOTEINDEX))
1203 Bstrcpy(apStrings[i + SUICIDEQUOTEINDEX], PlayerSelfObituaries[i]);
1204 }
1205 }
1206
C_BitOrNextValue(int32_t * valptr)1207 static inline void C_BitOrNextValue(int32_t *valptr)
1208 {
1209 C_GetNextValue(LABEL_DEFINE);
1210 g_scriptPtr--;
1211 *valptr |= *g_scriptPtr;
1212 }
1213
C_FinishBitOr(int32_t value)1214 static inline void C_FinishBitOr(int32_t value)
1215 {
1216 BITPTR_CLEAR(g_scriptPtr-apScript);
1217 *g_scriptPtr++ = value;
1218 }
1219
scriptUpdateOpcodeForVariableType(intptr_t * ins)1220 static void scriptUpdateOpcodeForVariableType(intptr_t *ins)
1221 {
1222 int opcode = -1;
1223
1224 if (opcode != -1)
1225 {
1226 if (g_scriptDebug > 1 && !g_errorCnt && !g_warningCnt)
1227 {
1228 initprintf("%s:%d: %s -> %s for var %s\n", g_scriptFileName, g_lineNumber,
1229 VM_GetKeywordForID(*ins & VM_INSTMASK), VM_GetKeywordForID(opcode), aGameVars[ins[1] & (MAXGAMEVARS-1)].szLabel);
1230 }
1231
1232 scriptWriteAtOffset(opcode | LINE_NUMBER, ins);
1233 }
1234 }
1235
C_ParseCommand(int32_t loop)1236 static int32_t C_ParseCommand(int32_t loop)
1237 {
1238 int32_t i, j=0, k=0, tw;
1239
1240 do
1241 {
1242 if (EDUKE32_PREDICT_FALSE(g_errorCnt > 63 || (*textptr == '\0') || (*(textptr+1) == '\0') || C_SkipComments()))
1243 return 1;
1244
1245 if (EDUKE32_PREDICT_FALSE(g_scriptDebug))
1246 C_ReportError(-1);
1247
1248 switch ((g_lastKeyword = tw = C_GetNextKeyword()))
1249 {
1250 default:
1251 case -1:
1252 case -2:
1253 return 1; //End
1254 case CON_STATE:
1255 if (!g_parsingActorPtr && g_processingState == 0)
1256 {
1257 C_GetNextLabelName();
1258 g_scriptPtr--;
1259 labelcode[g_labelCnt] = g_scriptPtr-apScript;
1260 labeltype[g_labelCnt] = LABEL_STATE;
1261
1262 g_processingState = 1;
1263 Bsprintf(g_szCurrentBlockName,"%s",label+(g_labelCnt<<6));
1264
1265 if (EDUKE32_PREDICT_FALSE(hash_find(&h_keywords,label+(g_labelCnt<<6))>=0))
1266 {
1267 g_errorCnt++;
1268 C_ReportError(ERROR_ISAKEYWORD);
1269 continue;
1270 }
1271
1272 hash_add(&h_labels,label+(g_labelCnt<<6),g_labelCnt,0);
1273 g_labelCnt++;
1274 continue;
1275 }
1276
1277 C_GetNextLabelName();
1278
1279 if (EDUKE32_PREDICT_FALSE((j = hash_find(&h_labels,label+(g_labelCnt<<6))) < 0))
1280 {
1281 C_ReportError(-1);
1282 initprintf("%s:%d: error: state `%s' not found.\n",g_scriptFileName,g_lineNumber,label+(g_labelCnt<<6));
1283 g_errorCnt++;
1284 g_scriptPtr++;
1285 continue;
1286 }
1287
1288 if (EDUKE32_PREDICT_FALSE((labeltype[j] & LABEL_STATE) != LABEL_STATE))
1289 {
1290 char *gl = (char *) C_GetLabelType(labeltype[j]);
1291 C_ReportError(-1);
1292 initprintf("%s:%d: warning: expected state, found %s.\n", g_scriptFileName, g_lineNumber, gl);
1293 g_warningCnt++;
1294 Bfree(gl);
1295 *(g_scriptPtr-1) = CON_NULLOP; // get rid of the state, leaving a nullop to satisfy if conditions
1296 BITPTR_CLEAR(g_scriptPtr-apScript-1);
1297 continue; // valid label name, but wrong type
1298 }
1299
1300 if (!(g_errorCnt || g_warningCnt) && g_scriptDebug > 1)
1301 initprintf("%s:%d: debug: state label `%s'.\n", g_scriptFileName, g_lineNumber, label+(j<<6));
1302 *g_scriptPtr = (intptr_t) (apScript+labelcode[j]);
1303
1304 // 'state' type labels are always script addresses, as far as I can see
1305 BITPTR_SET(g_scriptPtr-apScript);
1306
1307 g_scriptPtr++;
1308 continue;
1309
1310 case CON_ENDS:
1311 if (EDUKE32_PREDICT_FALSE(g_processingState == 0))
1312 {
1313 C_ReportError(-1);
1314 initprintf("%s:%d: error: found `ends' without open `state'.\n",g_scriptFileName,g_lineNumber);
1315 g_errorCnt++;
1316 }
1317 // else
1318 {
1319 if (EDUKE32_PREDICT_FALSE(g_numBraces > 0))
1320 {
1321 C_ReportError(ERROR_OPENBRACKET);
1322 g_errorCnt++;
1323 }
1324 else if (EDUKE32_PREDICT_FALSE(g_numBraces < 0))
1325 {
1326 C_ReportError(ERROR_CLOSEBRACKET);
1327 g_errorCnt++;
1328 }
1329
1330 g_processingState = 0;
1331 Bsprintf(g_szCurrentBlockName,"(none)");
1332 }
1333 continue;
1334
1335 case CON_GAMEVAR:
1336 {
1337 // syntax: gamevar <var1> <initial value> <flags>
1338 // defines var1 and sets initial value.
1339 // flags are used to define usage
1340 // (see top of this files for flags)
1341
1342 if (EDUKE32_PREDICT_FALSE(isdigit(*textptr) || (*textptr == '-')))
1343 {
1344 g_errorCnt++;
1345 C_ReportError(ERROR_SYNTAXERROR);
1346 C_NextLine();
1347 continue;
1348 }
1349
1350 g_scriptPtr--;
1351
1352 C_GetNextLabelName();
1353
1354 if (EDUKE32_PREDICT_FALSE(hash_find(&h_keywords, LAST_LABEL)>=0))
1355 {
1356 g_warningCnt++;
1357 C_ReportError(WARNING_VARMASKSKEYWORD);
1358 hash_delete(&h_keywords, LAST_LABEL);
1359 }
1360
1361 int32_t defaultValue = 0;
1362 int32_t varFlags = 0;
1363
1364 if (C_GetKeyword() == -1)
1365 {
1366 C_GetNextValue(LABEL_DEFINE); // get initial value
1367 defaultValue = *(--g_scriptPtr);
1368
1369 j = 0;
1370
1371 while (C_GetKeyword() == -1)
1372 C_BitOrNextValue(&j);
1373
1374 C_FinishBitOr(j);
1375 varFlags = *(--g_scriptPtr);
1376
1377 if (EDUKE32_PREDICT_FALSE((*(g_scriptPtr)&GAMEVAR_USER_MASK)==(GAMEVAR_PERPLAYER|GAMEVAR_PERACTOR)))
1378 {
1379 g_warningCnt++;
1380 varFlags ^= GAMEVAR_PERPLAYER;
1381 C_ReportError(WARNING_BADGAMEVAR);
1382 }
1383 }
1384
1385 Gv_NewVar(LAST_LABEL, defaultValue, varFlags);
1386 continue;
1387 }
1388
1389 case CON_DEFINE:
1390 {
1391 C_GetNextLabelName();
1392
1393 if (EDUKE32_PREDICT_FALSE(hash_find(&h_keywords,label+(g_labelCnt<<6))>=0))
1394 {
1395 g_errorCnt++;
1396 C_ReportError(ERROR_ISAKEYWORD);
1397 continue;
1398 }
1399
1400 C_GetNextValue(LABEL_DEFINE);
1401
1402 i = hash_find(&h_labels,label+(g_labelCnt<<6));
1403 if (i>=0)
1404 {
1405 // if (i >= g_numDefaultLabels)
1406
1407 if (EDUKE32_PREDICT_FALSE(labelcode[i] != *(g_scriptPtr-1)))
1408 {
1409 g_warningCnt++;
1410 initprintf("%s:%d: warning: ignored redefinition of `%s' to %d (old: %d).\n",g_scriptFileName,
1411 g_lineNumber,label+(g_labelCnt<<6), (int32_t)(*(g_scriptPtr-1)), labelcode[i]);
1412 }
1413 }
1414 else
1415 {
1416 hash_add(&h_labels,label+(g_labelCnt<<6),g_labelCnt,0);
1417 labeltype[g_labelCnt] = LABEL_DEFINE;
1418 labelcode[g_labelCnt++] = *(g_scriptPtr-1);
1419 //if (*(g_scriptPtr-1) >= 0 && *(g_scriptPtr-1) < MAXTILES && g_dynamicTileMapping)
1420 // G_ProcessDynamicTileMapping(label+((g_labelCnt-1)<<6),*(g_scriptPtr-1));
1421 }
1422 g_scriptPtr -= 2;
1423 continue;
1424 }
1425
1426 case CON_PALFROM:
1427 for (j=3; j>=0; j--)
1428 {
1429 if (C_GetKeyword() == -1)
1430 C_GetNextValue(LABEL_DEFINE);
1431 else break;
1432 }
1433
1434 while (j>-1)
1435 {
1436 BITPTR_CLEAR(g_scriptPtr-apScript);
1437 *g_scriptPtr++ = 0;
1438 j--;
1439 }
1440 continue;
1441
1442 case CON_MOVE:
1443 if (g_parsingActorPtr || g_processingState)
1444 {
1445 if (EDUKE32_PREDICT_FALSE((C_GetNextValue(LABEL_MOVE|LABEL_DEFINE) == 0) && (*(g_scriptPtr-1) != 0) && (*(g_scriptPtr-1) != 1)))
1446 {
1447 C_ReportError(-1);
1448 BITPTR_CLEAR(g_scriptPtr-apScript-1);
1449 *(g_scriptPtr-1) = 0;
1450 initprintf("%s:%d: warning: expected a move, found a constant.\n",g_scriptFileName,g_lineNumber);
1451 g_warningCnt++;
1452 }
1453
1454 j = 0;
1455 while (C_GetKeyword() == -1)
1456 C_BitOrNextValue(&j);
1457
1458 C_FinishBitOr(j);
1459 }
1460 else
1461 {
1462 g_scriptPtr--;
1463 C_GetNextLabelName();
1464 // Check to see it's already defined
1465
1466 if (EDUKE32_PREDICT_FALSE(hash_find(&h_keywords,label+(g_labelCnt<<6))>=0))
1467 {
1468 g_errorCnt++;
1469 C_ReportError(ERROR_ISAKEYWORD);
1470 continue;
1471 }
1472
1473 if (EDUKE32_PREDICT_FALSE((i = hash_find(&h_labels,label+(g_labelCnt<<6))) >= 0))
1474 {
1475 g_warningCnt++;
1476 initprintf("%s:%d: warning: duplicate move `%s' ignored.\n",g_scriptFileName,g_lineNumber,label+(g_labelCnt<<6));
1477 }
1478 else
1479 {
1480 hash_add(&h_labels,label+(g_labelCnt<<6),g_labelCnt,0);
1481 labeltype[g_labelCnt] = LABEL_MOVE;
1482 labelcode[g_labelCnt++] = g_scriptPtr-apScript;
1483 }
1484
1485 for (j=1; j>=0; j--)
1486 {
1487 if (C_GetKeyword() != -1) break;
1488 C_GetNextValue(LABEL_DEFINE);
1489 }
1490
1491 for (k=j; k>=0; k--)
1492 {
1493 BITPTR_CLEAR(g_scriptPtr-apScript);
1494 *g_scriptPtr = 0;
1495 g_scriptPtr++;
1496 }
1497 }
1498 continue;
1499
1500 case CON_MUSIC:
1501 {
1502 // NOTE: this doesn't get stored in the PCode...
1503
1504 // music 1 stalker.mid dethtoll.mid streets.mid watrwld1.mid snake1.mid
1505 // thecall.mid ahgeez.mid dethtoll.mid streets.mid watrwld1.mid snake1.mid
1506 g_scriptPtr--;
1507 C_GetNextValue(LABEL_DEFINE); // Volume Number (0/4)
1508 g_scriptPtr--;
1509
1510 k = *g_scriptPtr-1; // 0-based volume number. -1 or MAXVOLUMES: "special"
1511 if (k == -1)
1512 k = MAXVOLUMES;
1513
1514 if (EDUKE32_PREDICT_FALSE((unsigned)k >= MAXVOLUMES+1)) // if it's not background or special music
1515 {
1516 g_errorCnt++;
1517 C_ReportError(-1);
1518 initprintf("%s:%d: error: volume number must be between 0 and MAXVOLUMES+1=%d.\n",
1519 g_scriptFileName, g_lineNumber, MAXVOLUMES+1);
1520 continue;
1521
1522 }
1523
1524 i = 0;
1525 // get the file name...
1526 while (C_GetKeyword() == -1)
1527 {
1528 C_SkipComments();
1529
1530 j = 0;
1531 tempbuf[j] = '/';
1532 while (isaltok(*(textptr+j)))
1533 {
1534 tempbuf[j+1] = textptr[j];
1535 j++;
1536 }
1537 tempbuf[j+1] = '\0';
1538
1539 C_DefineMusic(k, i, tempbuf);
1540
1541 textptr += j;
1542
1543 if (i >= MAXLEVELS)
1544 break;
1545 i++;
1546 }
1547 }
1548 continue;
1549
1550 case CON_INCLUDE:
1551 g_scriptPtr--;
1552
1553 C_SkipComments();
1554 while (isaltok(*textptr) == 0)
1555 {
1556 textptr++;
1557 if (*textptr == 0) break;
1558 }
1559
1560 j = 0;
1561 while (isaltok(*textptr))
1562 {
1563 tempbuf[j] = *(textptr++);
1564 j++;
1565 }
1566 tempbuf[j] = '\0';
1567
1568 C_Include(tempbuf);
1569 continue;
1570
1571 case CON_AI:
1572 if (g_parsingActorPtr || g_processingState)
1573 {
1574 C_GetNextValue(LABEL_AI);
1575 }
1576 else
1577 {
1578 g_scriptPtr--;
1579 C_GetNextLabelName();
1580
1581 if (EDUKE32_PREDICT_FALSE(hash_find(&h_keywords,label+(g_labelCnt<<6))>=0))
1582 {
1583 g_errorCnt++;
1584 C_ReportError(ERROR_ISAKEYWORD);
1585 continue;
1586 }
1587
1588 i = hash_find(&h_labels,label+(g_labelCnt<<6));
1589 if (EDUKE32_PREDICT_FALSE(i>=0))
1590 {
1591 g_warningCnt++;
1592 initprintf("%s:%d: warning: duplicate ai `%s' ignored.\n",g_scriptFileName,g_lineNumber,label+(g_labelCnt<<6));
1593 }
1594 else
1595 {
1596 labeltype[g_labelCnt] = LABEL_AI;
1597 hash_add(&h_labels,label+(g_labelCnt<<6),g_labelCnt,0);
1598 labelcode[g_labelCnt++] = g_scriptPtr-apScript;
1599 }
1600
1601 for (j=0; j<3; j++)
1602 {
1603 if (C_GetKeyword() != -1) break;
1604 if (j == 1)
1605 C_GetNextValue(LABEL_ACTION);
1606 else if (j == 2)
1607 {
1608 if (EDUKE32_PREDICT_FALSE((C_GetNextValue(LABEL_MOVE|LABEL_DEFINE) == 0) &&
1609 (*(g_scriptPtr-1) != 0) && (*(g_scriptPtr-1) != 1)))
1610 {
1611 C_ReportError(-1);
1612 BITPTR_CLEAR(g_scriptPtr-apScript-1);
1613 *(g_scriptPtr-1) = 0;
1614 initprintf("%s:%d: warning: expected a move, found a constant.\n",g_scriptFileName,g_lineNumber);
1615 g_warningCnt++;
1616 }
1617
1618 k = 0;
1619 while (C_GetKeyword() == -1)
1620 C_BitOrNextValue(&k);
1621
1622 C_FinishBitOr(k);
1623 j = 666;
1624 break;
1625 }
1626 }
1627
1628 if (j == 666)
1629 continue;
1630
1631 for (k=j; k<3; k++)
1632 {
1633 BITPTR_CLEAR(g_scriptPtr-apScript);
1634 *g_scriptPtr = 0;
1635 g_scriptPtr++;
1636 }
1637 }
1638 continue;
1639
1640 case CON_ACTION:
1641 if (g_parsingActorPtr || g_processingState)
1642 {
1643 C_GetNextValue(LABEL_ACTION);
1644 }
1645 else
1646 {
1647 g_scriptPtr--;
1648 C_GetNextLabelName();
1649 // Check to see it's already defined
1650
1651 if (EDUKE32_PREDICT_FALSE(hash_find(&h_keywords,label+(g_labelCnt<<6))>=0))
1652 {
1653 g_errorCnt++;
1654 C_ReportError(ERROR_ISAKEYWORD);
1655 continue;
1656 }
1657
1658 i = hash_find(&h_labels,label+(g_labelCnt<<6));
1659 if (EDUKE32_PREDICT_FALSE(i>=0))
1660 {
1661 g_warningCnt++;
1662 initprintf("%s:%d: warning: duplicate action `%s' ignored.\n",g_scriptFileName,g_lineNumber,label+(g_labelCnt<<6));
1663 }
1664 else
1665 {
1666 labeltype[g_labelCnt] = LABEL_ACTION;
1667 labelcode[g_labelCnt] = g_scriptPtr-apScript;
1668 hash_add(&h_labels,label+(g_labelCnt<<6),g_labelCnt,0);
1669 g_labelCnt++;
1670 }
1671
1672 for (j=ACTION_PARAM_COUNT-1; j>=0; j--)
1673 {
1674 if (C_GetKeyword() != -1) break;
1675 C_GetNextValue(LABEL_DEFINE);
1676 }
1677 for (k=j; k>=0; k--)
1678 {
1679 BITPTR_CLEAR(g_scriptPtr-apScript);
1680 *(g_scriptPtr++) = 0;
1681 }
1682 }
1683 continue;
1684
1685 case CON_ACTOR:
1686 case CON_USERACTOR:
1687 if (EDUKE32_PREDICT_FALSE(g_processingState || g_parsingActorPtr))
1688 {
1689 C_ReportError(ERROR_FOUNDWITHIN);
1690 g_errorCnt++;
1691 }
1692
1693 g_numBraces = 0;
1694 g_scriptPtr--;
1695 g_parsingActorPtr = g_scriptPtr - apScript;
1696
1697 if (tw == CON_USERACTOR)
1698 {
1699 C_GetNextValue(LABEL_DEFINE);
1700 g_scriptPtr--;
1701 }
1702
1703 // save the actor name w/o consuming it
1704 C_SkipComments();
1705 j = 0;
1706 while (isaltok(*(textptr+j)))
1707 {
1708 g_szCurrentBlockName[j] = textptr[j];
1709 j++;
1710 }
1711 g_szCurrentBlockName[j] = 0;
1712
1713 j = hash_find(&h_labels, g_szCurrentBlockName);
1714
1715 if (j != -1)
1716 labeltype[j] |= LABEL_ACTOR;
1717
1718 if (tw == CON_USERACTOR)
1719 {
1720 j = *g_scriptPtr;
1721
1722 if (EDUKE32_PREDICT_FALSE(j >= 3))
1723 {
1724 C_ReportError(-1);
1725 initprintf("%s:%d: warning: invalid useractor type. Must be 0, 1, 2"
1726 " (notenemy, enemy, enemystayput).\n",
1727 g_scriptFileName,g_lineNumber);
1728 g_warningCnt++;
1729 j = 0;
1730 }
1731 }
1732
1733 C_GetNextValue(LABEL_ACTOR);
1734 g_scriptPtr--;
1735
1736 if (EDUKE32_PREDICT_FALSE((unsigned)*g_scriptPtr >= MAXTILES))
1737 {
1738 C_ReportError(ERROR_EXCEEDSMAXTILES);
1739 g_errorCnt++;
1740 continue;
1741 }
1742
1743 g_tile[*g_scriptPtr].execPtr = apScript + g_parsingActorPtr;
1744
1745 if (tw == CON_USERACTOR)
1746 {
1747 if (j & 1)
1748 g_tile[*g_scriptPtr].flags |= SFLAG_BADGUY;
1749
1750 if (j & 2)
1751 g_tile[*g_scriptPtr].flags |= (SFLAG_BADGUY|SFLAG_BADGUYSTAYPUT);
1752 }
1753
1754 for (j=0; j<4; j++)
1755 {
1756 BITPTR_CLEAR(g_parsingActorPtr+j);
1757 *((apScript+j)+g_parsingActorPtr) = 0;
1758 if (j == 3)
1759 {
1760 j = 0;
1761 while (C_GetKeyword() == -1)
1762 C_BitOrNextValue(&j);
1763
1764 C_FinishBitOr(j);
1765 break;
1766 }
1767 else
1768 {
1769 if (C_GetKeyword() != -1)
1770 {
1771 for (i=4-j; i; i--)
1772 {
1773 BITPTR_CLEAR(g_scriptPtr-apScript);
1774 *(g_scriptPtr++) = 0;
1775 }
1776 break;
1777 }
1778 switch (j)
1779 {
1780 case 0:
1781 C_GetNextValue(LABEL_DEFINE);
1782 break;
1783 case 1:
1784 C_GetNextValue(LABEL_ACTION);
1785 break;
1786 case 2:
1787 // XXX: LABEL_MOVE|LABEL_DEFINE, what is this shit? compatibility?
1788 // yep, it sure is :(
1789 if (EDUKE32_PREDICT_FALSE((C_GetNextValue(LABEL_MOVE|LABEL_DEFINE) == 0) && (*(g_scriptPtr-1) != 0) && (*(g_scriptPtr-1) != 1)))
1790 {
1791 C_ReportError(-1);
1792 BITPTR_CLEAR(g_scriptPtr-apScript-1);
1793 *(g_scriptPtr-1) = 0;
1794 initprintf("%s:%d: warning: expected a move, found a constant.\n",g_scriptFileName,g_lineNumber);
1795 g_warningCnt++;
1796 }
1797 break;
1798 }
1799 if (*(g_scriptPtr-1) >= (intptr_t)&apScript[0] && *(g_scriptPtr-1) < (intptr_t)&apScript[g_scriptSize])
1800 BITPTR_SET(g_parsingActorPtr+j);
1801 else BITPTR_CLEAR(g_parsingActorPtr+j);
1802 *((apScript+j)+g_parsingActorPtr) = *(g_scriptPtr-1);
1803 }
1804 }
1805 g_checkingIfElse = 0;
1806 continue;
1807
1808 case CON_ONEVENT:
1809 if (EDUKE32_PREDICT_FALSE(g_processingState || g_parsingActorPtr))
1810 {
1811 C_ReportError(ERROR_FOUNDWITHIN);
1812 g_errorCnt++;
1813 }
1814
1815 g_numBraces = 0;
1816 g_scriptPtr--;
1817 g_scriptEventOffset = g_parsingActorPtr = g_scriptPtr - apScript;
1818
1819 C_SkipComments();
1820 j = 0;
1821 while (isaltok(*(textptr+j)))
1822 {
1823 g_szCurrentBlockName[j] = textptr[j];
1824 j++;
1825 }
1826 g_szCurrentBlockName[j] = 0;
1827 // g_labelsOnly = 1;
1828 C_GetNextValue(LABEL_DEFINE);
1829 g_labelsOnly = 0;
1830 g_scriptPtr--;
1831 j= *g_scriptPtr; // type of event
1832 g_currentEvent = j;
1833 //Bsprintf(g_szBuf,"Adding Event for %d at %lX",j, g_parsingEventPtr);
1834 //AddLog(g_szBuf);
1835 if (EDUKE32_PREDICT_FALSE((unsigned)j > MAXEVENTS-1))
1836 {
1837 initprintf("%s:%d: error: invalid event ID.\n",g_scriptFileName,g_lineNumber);
1838 g_errorCnt++;
1839 continue;
1840 }
1841 // if event has already been declared then store previous script location
1842 apScriptEvents[j] = g_scriptEventOffset;
1843
1844 g_checkingIfElse = 0;
1845
1846 continue;
1847
1848 case CON_CSTAT:
1849 C_GetNextValue(LABEL_DEFINE);
1850
1851 if (EDUKE32_PREDICT_FALSE(*(g_scriptPtr-1) == 32767))
1852 {
1853 *(g_scriptPtr-1) = 32768;
1854 C_ReportError(-1);
1855 initprintf("%s:%d: warning: tried to set cstat 32767, using 32768 instead.\n",g_scriptFileName,g_lineNumber);
1856 g_warningCnt++;
1857 }
1858 else if (EDUKE32_PREDICT_FALSE((*(g_scriptPtr-1) & 48) == 48))
1859 {
1860 i = *(g_scriptPtr-1);
1861 *(g_scriptPtr-1) ^= 48;
1862 C_ReportError(-1);
1863 initprintf("%s:%d: warning: tried to set cstat %d, using %d instead.\n",g_scriptFileName,g_lineNumber,i,(int32_t)(*(g_scriptPtr-1)));
1864 g_warningCnt++;
1865 }
1866 continue;
1867
1868 case CON_HITRADIUS:
1869 C_GetNextValue(LABEL_DEFINE);
1870 C_GetNextValue(LABEL_DEFINE);
1871 C_GetNextValue(LABEL_DEFINE);
1872 fallthrough__;
1873 case CON_ADDAMMO:
1874 case CON_ADDWEAPON:
1875 case CON_SIZETO:
1876 case CON_SIZEAT:
1877 case CON_DEBRIS:
1878 case CON_ADDINVENTORY:
1879 case CON_GUTS:
1880 C_GetNextValue(LABEL_DEFINE);
1881 fallthrough__;
1882 case CON_STRENGTH:
1883 case CON_SHOOT:
1884 case CON_ADDPHEALTH:
1885 case CON_SPAWN:
1886 case CON_COUNT:
1887 case CON_ENDOFGAME:
1888 case CON_SPRITEPAL:
1889 case CON_CACTOR:
1890 case CON_MONEY:
1891 case CON_ADDKILLS:
1892 case CON_DEBUG:
1893 case CON_ADDSTRENGTH:
1894 case CON_CSTATOR:
1895 case CON_MAIL:
1896 case CON_PAPER:
1897 case CON_SLEEPTIME:
1898 case CON_CLIPDIST:
1899 case CON_ISDRUNK:
1900 case CON_ISEAT:
1901 case CON_NEWPIC:
1902 case CON_LOTSOFGLASS:
1903 case CON_QUOTE:
1904 case CON_SOUND:
1905 case CON_GLOBALSOUND:
1906 case CON_SOUNDONCE:
1907 case CON_STOPSOUND:
1908 C_GetNextValue(LABEL_DEFINE);
1909 continue;
1910
1911 case CON_ELSE:
1912 {
1913 if (EDUKE32_PREDICT_FALSE(!g_checkingIfElse))
1914 {
1915 g_scriptPtr--;
1916 intptr_t *tempscrptr = g_scriptPtr;
1917 g_warningCnt++;
1918 C_ReportError(-1);
1919
1920 initprintf("%s:%d: warning: found `else' with no `if'.\n", g_scriptFileName, g_lineNumber);
1921
1922 if (C_GetKeyword() == CON_LEFTBRACE)
1923 {
1924 C_GetNextKeyword();
1925 g_numBraces++;
1926
1927 C_ParseCommand(1);
1928 }
1929 else C_ParseCommand(0);
1930
1931 g_scriptPtr = tempscrptr;
1932
1933 continue;
1934 }
1935
1936 intptr_t const lastScriptPtr = g_scriptPtr - apScript - 1;
1937
1938 g_skipBranch = 0;
1939 g_checkingIfElse--;
1940
1941 if (C_CheckMalformedBranch(lastScriptPtr))
1942 continue;
1943
1944 intptr_t const offset = (unsigned) (g_scriptPtr-apScript);
1945
1946 g_scriptPtr++; //Leave a spot for the fail location
1947
1948 if (!g_gotComment)
1949 C_ParseCommand(0);
1950
1951 if (C_CheckEmptyBranch(tw, lastScriptPtr))
1952 continue;
1953
1954 intptr_t *tempscrptr = (intptr_t *) apScript+offset;
1955 *tempscrptr = (intptr_t) g_scriptPtr;
1956 BITPTR_SET(tempscrptr-apScript);
1957
1958 continue;
1959 }
1960 case CON_ADDLOGVAR:
1961 g_labelsOnly = 1;
1962 C_GetNextVar();
1963 g_labelsOnly = 0;
1964 continue;
1965 case CON_ADDVAR:
1966 case CON_SETVAR:
1967 setvar:
1968 {
1969 auto ins = &g_scriptPtr[-1];
1970
1971 C_GetNextVarType(GAMEVAR_READONLY);
1972 C_GetNextValue(LABEL_DEFINE);
1973 // replace instructions with special versions for specific var types
1974 scriptUpdateOpcodeForVariableType(ins);
1975 continue;
1976 }
1977 case CON_ADDVARVAR:
1978 case CON_SETVARVAR:
1979 {
1980 setvarvar:
1981 auto ins = &g_scriptPtr[-1];
1982 auto tptr = textptr;
1983 int const lnum = g_lineNumber;
1984
1985 C_GetNextVarType(GAMEVAR_READONLY);
1986 C_GetNextVar();
1987
1988 int const opcode = inthash_find(&h_varvar, *ins & VM_INSTMASK);
1989
1990 if (ins[2] == GV_FLAG_CONSTANT && opcode != -1)
1991 {
1992 if (g_scriptDebug > 1 && !g_errorCnt && !g_warningCnt)
1993 {
1994 initprintf("%s:%d: %s -> %s\n", g_scriptFileName, g_lineNumber,
1995 VM_GetKeywordForID(*ins & VM_INSTMASK), VM_GetKeywordForID(opcode));
1996 }
1997
1998 tw = opcode;
1999 scriptWriteAtOffset(opcode | LINE_NUMBER, ins);
2000 g_scriptPtr = &ins[1];
2001 textptr = tptr;
2002 g_lineNumber = lnum;
2003 goto setvar;
2004 }
2005
2006 continue;
2007 }
2008
2009 case CON_IFVARVARE:
2010 case CON_IFVARVARG:
2011 case CON_IFVARVARL:
2012 {
2013 auto const ins = &g_scriptPtr[-1];
2014 auto const lastScriptPtr = &g_scriptPtr[-1] - apScript;
2015 auto const lasttextptr = textptr;
2016 int const lnum = g_lineNumber;
2017
2018 g_skipBranch = false;
2019
2020 C_GetNextVar();
2021 auto const var = g_scriptPtr;
2022 C_GetNextVar();
2023
2024 if (*var == GV_FLAG_CONSTANT)
2025 {
2026 int const opcode = inthash_find(&h_varvar, tw);
2027
2028 if (opcode != -1)
2029 {
2030 if (g_scriptDebug > 1 && !g_errorCnt && !g_warningCnt)
2031 {
2032 initprintf("%s:%d: replacing %s with %s\n", g_scriptFileName, g_lineNumber,
2033 VM_GetKeywordForID(*ins & VM_INSTMASK), VM_GetKeywordForID(opcode));
2034 }
2035
2036 scriptWriteAtOffset(opcode | LINE_NUMBER, ins);
2037 tw = opcode;
2038 g_scriptPtr = &ins[1];
2039 textptr = lasttextptr;
2040 g_lineNumber = lnum;
2041 goto ifvar;
2042 }
2043 }
2044
2045 if (C_CheckMalformedBranch(lastScriptPtr))
2046 continue;
2047
2048 auto const offset = g_scriptPtr - apScript;
2049 g_scriptPtr++; // Leave a spot for the fail location
2050
2051 C_ParseCommand(0);
2052
2053 if (C_CheckEmptyBranch(tw, lastScriptPtr))
2054 continue;
2055
2056 auto const tempscrptr = apScript + offset;
2057 scriptWritePointer((intptr_t)g_scriptPtr, tempscrptr);
2058 continue;
2059 }
2060
2061 case CON_IFVARE:
2062 case CON_IFVARG:
2063 case CON_IFVARL:
2064 {
2065 ifvar:
2066 auto const ins = &g_scriptPtr[-1];
2067 auto const lastScriptPtr = &g_scriptPtr[-1] - apScript;
2068
2069 g_skipBranch = false;
2070
2071 C_GetNextVar();
2072 C_GetNextValue(LABEL_DEFINE);
2073
2074 if (C_CheckMalformedBranch(lastScriptPtr))
2075 continue;
2076
2077 scriptUpdateOpcodeForVariableType(ins);
2078
2079 auto const offset = g_scriptPtr - apScript;
2080 g_scriptPtr++; //Leave a spot for the fail location
2081
2082 C_ParseCommand(0);
2083
2084 if (C_CheckEmptyBranch(tw, lastScriptPtr))
2085 continue;
2086
2087 auto const tempscrptr = apScript + offset;
2088 scriptWritePointer((intptr_t)g_scriptPtr, tempscrptr);
2089
2090 j = C_GetKeyword();
2091
2092 if (j == CON_ELSE)
2093 g_checkingIfElse++;
2094
2095 continue;
2096 }
2097
2098 case CON_IFRND:
2099 case CON_IFPDISTL:
2100 case CON_IFPDISTG:
2101 case CON_IFWASWEAPON:
2102 case CON_IFACTIONCOUNT:
2103 case CON_IFCOUNT:
2104 case CON_IFACTOR:
2105 case CON_IFSTRENGTH:
2106 case CON_IFSPAWNEDBY:
2107 case CON_IFGAPZL:
2108 case CON_IFFLOORDISTL:
2109 case CON_IFCEILINGDISTL:
2110 case CON_IFPHEALTHL:
2111 case CON_IFSPRITEPAL:
2112 case CON_IFGOTWEAPONCE:
2113 case CON_IFANGDIFFL:
2114 case CON_IFACTORHEALTHG:
2115 case CON_IFACTORHEALTHL:
2116 case CON_IFSOUNDID:
2117 case CON_IFSOUNDDIST:
2118 case CON_IFAI:
2119 case CON_IFACTION:
2120 case CON_IFMOVE:
2121 case CON_IFP:
2122 case CON_IFPINVENTORY:
2123 {
2124 intptr_t offset;
2125 intptr_t lastScriptPtr = (g_scriptPtr-&apScript[0]-1);
2126
2127 g_skipBranch = 0;
2128
2129 switch (tw)
2130 {
2131 case CON_IFAI:
2132 C_GetNextValue(LABEL_AI);
2133 break;
2134 case CON_IFACTION:
2135 C_GetNextValue(LABEL_ACTION);
2136 break;
2137 case CON_IFMOVE:
2138 if (EDUKE32_PREDICT_FALSE((C_GetNextValue(LABEL_MOVE|LABEL_DEFINE) == 0) && (*(g_scriptPtr-1) != 0) && (*(g_scriptPtr-1) != 1)))
2139 {
2140 C_ReportError(-1);
2141 *(g_scriptPtr-1) = 0;
2142 initprintf("%s:%d: warning: expected a move, found a constant.\n",g_scriptFileName,g_lineNumber);
2143 g_warningCnt++;
2144 }
2145 break;
2146 case CON_IFPINVENTORY:
2147 C_GetNextValue(LABEL_DEFINE);
2148 C_GetNextValue(LABEL_DEFINE);
2149 break;
2150 case CON_IFP:
2151 j = 0;
2152 do
2153 C_BitOrNextValue(&j);
2154 while (C_GetKeyword() == -1);
2155 C_FinishBitOr(j);
2156 break;
2157 default:
2158 C_GetNextValue(LABEL_DEFINE);
2159 break;
2160 }
2161
2162 if (C_CheckMalformedBranch(lastScriptPtr))
2163 continue;
2164
2165 intptr_t *tempscrptr = g_scriptPtr;
2166 offset = (unsigned)(tempscrptr-apScript);
2167
2168 g_scriptPtr++; //Leave a spot for the fail location
2169
2170 C_ParseCommand(0);
2171
2172 if (C_CheckEmptyBranch(tw, lastScriptPtr))
2173 continue;
2174
2175 tempscrptr = (intptr_t *)apScript+offset;
2176 *tempscrptr = (intptr_t) g_scriptPtr;
2177 BITPTR_SET(tempscrptr-apScript);
2178
2179 j = C_GetKeyword();
2180
2181 if (j == CON_ELSE || j == CON_LEFTBRACE)
2182 g_checkingIfElse++;
2183
2184 continue;
2185 }
2186
2187 case CON_IFONWATER:
2188 case CON_IFINWATER:
2189 case CON_IFACTORNOTSTAYPUT:
2190 case CON_IFCANSEE:
2191 case CON_IFHITWEAPON:
2192 case CON_IFSQUISHED:
2193 case CON_IFDEAD:
2194 case CON_IFCANSHOOTTARGET:
2195 case CON_IFHITSPACE:
2196 case CON_IFOUTSIDE:
2197 case CON_IFMULTIPLAYER:
2198 case CON_IFINSPACE:
2199 case CON_IFBULLETNEAR:
2200 case CON_IFRESPAWN:
2201 case CON_IFINOUTERSPACE:
2202 case CON_IFNOTMOVING:
2203 case CON_IFAWAYFROMWALL:
2204 case CON_IFCANSEETARGET:
2205 case CON_IFNOSOUNDS:
2206 case CON_IFNOCOVER:
2207 case CON_IFHITTRUCK:
2208 case CON_IFTIPCOW:
2209 case CON_IFONMUD:
2210 case CON_IFCOOP:
2211 case CON_IFMOTOFAST:
2212 case CON_IFWIND:
2213 case CON_IFONMOTO:
2214 case CON_IFONBOAT:
2215 case CON_IFSIZEDOWN:
2216 case CON_IFFINDNEWSPOT:
2217 case CON_IFPUPWIND:
2218 {
2219 intptr_t offset;
2220 intptr_t lastScriptPtr = (g_scriptPtr-&apScript[0]-1);
2221
2222 g_skipBranch = 0;
2223
2224 if (C_CheckMalformedBranch(lastScriptPtr))
2225 continue;
2226
2227 intptr_t *tempscrptr = g_scriptPtr;
2228 offset = (unsigned)(tempscrptr-apScript);
2229
2230 g_scriptPtr++; //Leave a spot for the fail location
2231
2232 C_ParseCommand(0);
2233
2234 if (C_CheckEmptyBranch(tw, lastScriptPtr))
2235 continue;
2236
2237 tempscrptr = (intptr_t *)apScript+offset;
2238 *tempscrptr = (intptr_t) g_scriptPtr;
2239 BITPTR_SET(tempscrptr-apScript);
2240
2241 j = C_GetKeyword();
2242
2243 if (j == CON_ELSE || j == CON_LEFTBRACE)
2244 g_checkingIfElse++;
2245
2246 continue;
2247 }
2248
2249 case CON_LEFTBRACE:
2250 if (EDUKE32_PREDICT_FALSE(!(g_processingState || g_parsingActorPtr || g_scriptEventOffset)))
2251 {
2252 g_errorCnt++;
2253 C_ReportError(ERROR_SYNTAXERROR);
2254 }
2255 g_numBraces++;
2256
2257 C_ParseCommand(1);
2258 continue;
2259
2260 case CON_RIGHTBRACE:
2261 g_numBraces--;
2262
2263 if ((*(g_scriptPtr-2)>>12) == (IFELSE_MAGIC) &&
2264 ((*(g_scriptPtr-2) & VM_INSTMASK) == CON_LEFTBRACE)) // rewrite "{ }" into "nullop"
2265 {
2266 // initprintf("%s:%d: rewriting empty braces '{ }' as 'nullop' from right\n",g_szScriptFileName,g_lineNumber);
2267 *(g_scriptPtr-2) = CON_NULLOP + (IFELSE_MAGIC<<12);
2268 g_scriptPtr -= 2;
2269
2270 if (C_GetKeyword() != CON_ELSE && (*(g_scriptPtr-2) & VM_INSTMASK) != CON_ELSE)
2271 g_skipBranch = 1;
2272 else g_skipBranch = 0;
2273
2274 j = C_GetKeyword();
2275
2276 if (g_checkingIfElse && j != CON_ELSE)
2277 g_checkingIfElse--;
2278
2279 return 1;
2280 }
2281
2282 if (EDUKE32_PREDICT_FALSE(g_numBraces < 0))
2283 {
2284 C_ReportError(-1);
2285 initprintf("%s:%d: error: found more `}' than `{'.\n",g_scriptFileName,g_lineNumber);
2286 g_errorCnt++;
2287 }
2288
2289 if (g_checkingIfElse && j != CON_ELSE)
2290 g_checkingIfElse--;
2291
2292 return 1;
2293
2294 case CON_BETANAME:
2295 g_scriptPtr--;
2296 j = 0;
2297 C_NextLine();
2298 continue;
2299
2300 case CON_DEFINEVOLUMENAME:
2301 g_scriptPtr--;
2302
2303 C_GetNextValue(LABEL_DEFINE);
2304 g_scriptPtr--;
2305 j = *g_scriptPtr;
2306
2307 C_SkipSpace();
2308
2309 if (EDUKE32_PREDICT_FALSE((unsigned)j > MAXVOLUMES-1))
2310 {
2311 initprintf("%s:%d: error: volume number exceeds maximum volume count.\n",
2312 g_scriptFileName,g_lineNumber);
2313 g_errorCnt++;
2314 C_NextLine();
2315 continue;
2316 }
2317
2318 i = 0;
2319
2320 while (*textptr != 0x0a && *textptr != 0x0d && *textptr != 0)
2321 {
2322 g_volumeNames[j][i] = *textptr;
2323 textptr++,i++;
2324 if (EDUKE32_PREDICT_FALSE(i >= (signed)sizeof(g_volumeNames[j])-1))
2325 {
2326 initprintf("%s:%d: warning: truncating volume name to %d characters.\n",
2327 g_scriptFileName,g_lineNumber,(int32_t)sizeof(g_volumeNames[j])-1);
2328 g_warningCnt++;
2329 C_NextLine();
2330 break;
2331 }
2332 }
2333 g_volumeCnt = j+1;
2334 g_volumeNames[j][i] = '\0';
2335 continue;
2336
2337 case CON_DEFINESKILLNAME:
2338 g_scriptPtr--;
2339
2340 C_GetNextValue(LABEL_DEFINE);
2341 g_scriptPtr--;
2342 j = *g_scriptPtr;
2343
2344 C_SkipSpace();
2345
2346 if (EDUKE32_PREDICT_FALSE((unsigned)j >= MAXSKILLS))
2347 {
2348 initprintf("%s:%d: error: skill number exceeds maximum skill count %d.\n",
2349 g_scriptFileName,g_lineNumber, MAXSKILLS);
2350 g_errorCnt++;
2351 C_NextLine();
2352 continue;
2353 }
2354
2355 i = 0;
2356
2357 while (*textptr != 0x0a && *textptr != 0x0d && *textptr != 0)
2358 {
2359 g_skillNames[j][i] = *textptr;
2360 textptr++,i++;
2361 if (EDUKE32_PREDICT_FALSE(i >= (signed)sizeof(g_skillNames[j])-1))
2362 {
2363 initprintf("%s:%d: warning: truncating skill name to %d characters.\n",
2364 g_scriptFileName,g_lineNumber,(int32_t)sizeof(g_skillNames[j])-1);
2365 g_warningCnt++;
2366 C_NextLine();
2367 break;
2368 }
2369 }
2370
2371 g_skillNames[j][i] = '\0';
2372
2373 for (i=0; i<MAXSKILLS; i++)
2374 if (g_skillNames[i][0] == 0)
2375 break;
2376 g_skillCnt = i;
2377
2378 continue;
2379
2380 case CON_DEFINELEVELNAME:
2381 g_scriptPtr--;
2382 C_GetNextValue(LABEL_DEFINE);
2383 g_scriptPtr--;
2384 j = *g_scriptPtr;
2385 C_GetNextValue(LABEL_DEFINE);
2386 g_scriptPtr--;
2387 k = *g_scriptPtr;
2388 C_SkipComments();
2389
2390 if (EDUKE32_PREDICT_FALSE((unsigned)j > MAXVOLUMES-1))
2391 {
2392 initprintf("%s:%d: error: volume number exceeds maximum volume count.\n",g_scriptFileName,g_lineNumber);
2393 g_errorCnt++;
2394 C_NextLine();
2395 continue;
2396 }
2397 if (EDUKE32_PREDICT_FALSE((unsigned)k > MAXLEVELS-1))
2398 {
2399 initprintf("%s:%d: error: level number exceeds maximum number of levels per episode.\n",g_scriptFileName,g_lineNumber);
2400 g_errorCnt++;
2401 C_NextLine();
2402 continue;
2403 }
2404
2405 i = 0;
2406
2407 tempbuf[i] = '/';
2408
2409 while (*textptr != ' ' && *textptr != '\t' && *textptr != 0x0a)
2410 {
2411 tempbuf[i+1] = *textptr;
2412 textptr++,i++;
2413 if (EDUKE32_PREDICT_FALSE(i >= BMAX_PATH))
2414 {
2415 initprintf("%s:%d: error: level file name exceeds limit of %d characters.\n",g_scriptFileName,g_lineNumber,BMAX_PATH);
2416 g_errorCnt++;
2417 C_SkipSpace();
2418 break;
2419 }
2420 }
2421 tempbuf[i+1] = '\0';
2422
2423 Bcorrectfilename(tempbuf,0);
2424
2425 if (g_mapInfo[j *MAXLEVELS+k].filename == NULL)
2426 g_mapInfo[j *MAXLEVELS+k].filename = (char *)Xcalloc(Bstrlen(tempbuf)+1,sizeof(uint8_t));
2427 else if ((Bstrlen(tempbuf)+1) > sizeof(g_mapInfo[j*MAXLEVELS+k].filename))
2428 g_mapInfo[j *MAXLEVELS+k].filename = (char *)Xrealloc(g_mapInfo[j*MAXLEVELS+k].filename,(Bstrlen(tempbuf)+1));
2429
2430 Bstrcpy(g_mapInfo[j*MAXLEVELS+k].filename,tempbuf);
2431
2432 C_SkipComments();
2433
2434 g_mapInfo[j *MAXLEVELS+k].partime =
2435 (((*(textptr+0)-'0')*10+(*(textptr+1)-'0'))*REALGAMETICSPERSEC*60)+
2436 (((*(textptr+3)-'0')*10+(*(textptr+4)-'0'))*REALGAMETICSPERSEC);
2437
2438 textptr += 5;
2439 C_SkipSpace();
2440
2441 // cheap hack, 0.99 doesn't have the 3D Realms time
2442 if (*(textptr+2) == ':')
2443 {
2444 g_mapInfo[j *MAXLEVELS+k].designertime =
2445 (((*(textptr+0)-'0')*10+(*(textptr+1)-'0'))*REALGAMETICSPERSEC*60)+
2446 (((*(textptr+3)-'0')*10+(*(textptr+4)-'0'))*REALGAMETICSPERSEC);
2447
2448 textptr += 5;
2449 C_SkipSpace();
2450 }
2451 else if (g_scriptVersion == 10) g_scriptVersion = 9;
2452
2453 i = 0;
2454
2455 while (*textptr != 0x0a && *textptr != 0x0d && *textptr != 0)
2456 {
2457 tempbuf[i] = *textptr;
2458 textptr++,i++;
2459 if (EDUKE32_PREDICT_FALSE(i >= 32))
2460 {
2461 initprintf("%s:%d: warning: truncating level name to %d characters.\n",
2462 g_scriptFileName,g_lineNumber,32);
2463 g_warningCnt++;
2464 C_NextLine();
2465 break;
2466 }
2467 }
2468
2469 tempbuf[i] = '\0';
2470
2471 if (g_mapInfo[j*MAXLEVELS+k].name == NULL)
2472 g_mapInfo[j*MAXLEVELS+k].name = (char *)Xcalloc(Bstrlen(tempbuf)+1,sizeof(uint8_t));
2473 else if ((Bstrlen(tempbuf)+1) > sizeof(g_mapInfo[j*MAXLEVELS+k].name))
2474 g_mapInfo[j *MAXLEVELS+k].name = (char *)Xrealloc(g_mapInfo[j*MAXLEVELS+k].name,(Bstrlen(tempbuf)+1));
2475
2476 /* initprintf("level name string len: %d\n",Bstrlen(tempbuf)); */
2477
2478 Bstrcpy(g_mapInfo[j*MAXLEVELS+k].name,tempbuf);
2479
2480 continue;
2481
2482 case CON_DEFINEQUOTE:
2483 g_scriptPtr--;
2484
2485 C_GetNextValue(LABEL_DEFINE);
2486
2487 k = *(g_scriptPtr-1);
2488
2489 if (EDUKE32_PREDICT_FALSE((unsigned)k >= MAXQUOTES))
2490 {
2491 initprintf("%s:%d: error: quote number exceeds limit of %d.\n",g_scriptFileName,g_lineNumber,MAXQUOTES);
2492 g_errorCnt++;
2493 }
2494 else
2495 {
2496 C_AllocQuote(k);
2497 }
2498
2499 g_scriptPtr--;
2500
2501 i = 0;
2502
2503 C_SkipSpace();
2504
2505 while (*textptr != 0x0a && *textptr != 0x0d && *textptr != 0)
2506 {
2507 /*
2508 if (*textptr == '%' && *(textptr+1) == 's')
2509 {
2510 initprintf("%s:%d: error: quote text contains string identifier.\n",g_szScriptFileName,g_lineNumber);
2511 g_numCompilerErrors++;
2512 while (*textptr != 0x0a && *textptr != 0x0d && *textptr != 0) textptr++;
2513 break;
2514 }
2515 */
2516 *(apStrings[k]+i) = *textptr;
2517
2518 textptr++,i++;
2519 if (EDUKE32_PREDICT_FALSE(i >= MAXQUOTELEN-1))
2520 {
2521 initprintf("%s:%d: warning: truncating quote text to %d characters.\n",g_scriptFileName,g_lineNumber,MAXQUOTELEN-1);
2522 g_warningCnt++;
2523 C_NextLine();
2524 break;
2525 }
2526 }
2527
2528 if ((unsigned)k < MAXQUOTES)
2529 *(apStrings[k]+i) = '\0';
2530 continue;
2531
2532 case CON_DEFINESOUND:
2533 g_scriptPtr--;
2534 C_GetNextValue(LABEL_DEFINE);
2535
2536 // Ideally we could keep the value of i from C_GetNextValue() instead of having to hash_find() again.
2537 // This depends on tempbuf remaining in place after C_GetNextValue():
2538 j = hash_find(&h_labels,tempbuf);
2539
2540 k = *(g_scriptPtr-1);
2541 if (EDUKE32_PREDICT_FALSE((unsigned)k >= MAXSOUNDS-1))
2542 {
2543 initprintf("%s:%d: error: index exceeds sound limit of %d.\n",g_scriptFileName,g_lineNumber, MAXSOUNDS-1);
2544 g_errorCnt++;
2545 k = MAXSOUNDS-1;
2546 }
2547 g_scriptPtr--;
2548 i = 0;
2549 C_SkipComments();
2550
2551 if (g_sounds[k].filename == NULL)
2552 g_sounds[k].filename = (char *)Xcalloc(BMAX_PATH,sizeof(uint8_t));
2553
2554 if (*textptr == '\"')
2555 {
2556 textptr++;
2557 while (*textptr && *textptr != '\"')
2558 {
2559 g_sounds[k].filename[i++] = *textptr++;
2560 if (EDUKE32_PREDICT_FALSE(i >= BMAX_PATH-1))
2561 {
2562 initprintf("%s:%d: error: sound filename exceeds limit of %d characters.\n",g_scriptFileName,g_lineNumber,BMAX_PATH-1);
2563 g_errorCnt++;
2564 C_SkipComments();
2565 break;
2566 }
2567 }
2568 textptr++;
2569 }
2570 else while (*textptr != ' ' && *textptr != '\t' && *textptr != '\r' && *textptr != '\n')
2571 {
2572 g_sounds[k].filename[i++] = *textptr++;
2573 if (EDUKE32_PREDICT_FALSE(i >= BMAX_PATH-1))
2574 {
2575 initprintf("%s:%d: error: sound filename exceeds limit of %d characters.\n",g_scriptFileName,g_lineNumber,BMAX_PATH-1);
2576 g_errorCnt++;
2577 C_SkipComments();
2578 break;
2579 }
2580 }
2581 g_sounds[k].filename[i] = '\0';
2582
2583 check_filename_case(g_sounds[k].filename);
2584
2585 C_GetNextValue(LABEL_DEFINE);
2586 g_sounds[k].ps = *(g_scriptPtr-1);
2587 C_GetNextValue(LABEL_DEFINE);
2588 g_sounds[k].pe = *(g_scriptPtr-1);
2589 C_GetNextValue(LABEL_DEFINE);
2590 g_sounds[k].pr = *(g_scriptPtr-1);
2591
2592 C_GetNextValue(LABEL_DEFINE);
2593 g_sounds[k].m = *(g_scriptPtr-1) & ~SF_ONEINST_INTERNAL;
2594 if (*(g_scriptPtr-1) & SF_LOOP)
2595 g_sounds[k].m |= SF_ONEINST_INTERNAL;
2596
2597 C_GetNextValue(LABEL_DEFINE);
2598 g_sounds[k].vo = *(g_scriptPtr-1);
2599 g_scriptPtr -= 5;
2600
2601 g_sounds[k].volume = fix16_one;
2602
2603 if (k > g_highestSoundIdx)
2604 g_highestSoundIdx = k;
2605 continue;
2606
2607 case CON_ENDEVENT:
2608
2609 if (EDUKE32_PREDICT_FALSE(!g_scriptEventOffset))
2610 {
2611 C_ReportError(-1);
2612 initprintf("%s:%d: error: found `endevent' without open `onevent'.\n",g_scriptFileName,g_lineNumber);
2613 g_errorCnt++;
2614 }
2615 if (EDUKE32_PREDICT_FALSE(g_numBraces != 0))
2616 {
2617 C_ReportError(g_numBraces > 0 ? ERROR_OPENBRACKET : ERROR_CLOSEBRACKET);
2618 g_errorCnt++;
2619 }
2620
2621 g_scriptEventOffset = g_parsingActorPtr = 0;
2622 g_currentEvent = -1;
2623 Bsprintf(g_szCurrentBlockName,"(none)");
2624 continue;
2625
2626 case CON_ENDA:
2627 if (EDUKE32_PREDICT_FALSE(!g_parsingActorPtr || g_scriptEventOffset))
2628 {
2629 C_ReportError(-1);
2630 initprintf("%s:%d: error: found `enda' without open `actor'.\n",g_scriptFileName,g_lineNumber);
2631 g_errorCnt++;
2632 g_scriptEventOffset = 0;
2633 }
2634 if (EDUKE32_PREDICT_FALSE(g_numBraces != 0))
2635 {
2636 C_ReportError(g_numBraces > 0 ? ERROR_OPENBRACKET : ERROR_CLOSEBRACKET);
2637 g_errorCnt++;
2638 }
2639 g_parsingActorPtr = 0;
2640 Bsprintf(g_szCurrentBlockName,"(none)");
2641 continue;
2642
2643 case CON_BREAK:
2644 continue;
2645
2646 case CON_FALL:
2647 case CON_TIP:
2648 // case 21:
2649 case CON_KILLIT:
2650 case CON_RESETACTIONCOUNT:
2651 case CON_PSTOMP:
2652 case CON_RESETPLAYER:
2653 case CON_RESETCOUNT:
2654 case CON_WACKPLAYER:
2655 case CON_OPERATE:
2656 case CON_RESPAWNHITAG:
2657 case CON_GETLASTPAL:
2658 case CON_PKICK:
2659 case CON_MIKESND:
2660 case CON_TOSSWEAPON:
2661 case CON_DESTROYIT:
2662 case CON_LARRYBIRD:
2663 case CON_STRAFELEFT:
2664 case CON_STRAFERIGHT:
2665 case CON_SLAPPLAYER:
2666 case CON_TEARITUP:
2667 case CON_SMACKBUBBA:
2668 case CON_SOUNDTAGONCE:
2669 case CON_SOUNDTAG:
2670 case CON_SMACKSPRITE:
2671 case CON_FAKEBUBBA:
2672 case CON_MAMATRIGGER:
2673 case CON_MAMASPAWN:
2674 case CON_MAMAQUAKE:
2675 case CON_MAMAEND:
2676 case CON_GARYBANJO:
2677 case CON_MOTOLOOPSND:
2678 case CON_RNDMOVE:
2679 case CON_LEAVETRAX:
2680 case CON_LEAVEDROPPINGS:
2681 case CON_DEPLOYBIAS:
2682 continue;
2683
2684 case CON_NULLOP:
2685 if (EDUKE32_PREDICT_FALSE(C_GetKeyword() != CON_ELSE))
2686 {
2687 C_ReportError(-1);
2688 g_warningCnt++;
2689 initprintf("%s:%d: warning: `nullop' found without `else'\n",g_scriptFileName,g_lineNumber);
2690 g_scriptPtr--;
2691 g_skipBranch = 1;
2692 }
2693 continue;
2694
2695 case CON_GAMESTARTUP:
2696 {
2697 int32_t params[34];
2698
2699 g_scriptPtr--;
2700 for (j = 0; j < 34; j++)
2701 {
2702 C_GetNextValue(LABEL_DEFINE);
2703 g_scriptPtr--;
2704 params[j] = *g_scriptPtr;
2705
2706 if (j != 29 && j != 30) continue;
2707
2708 if (C_GetKeyword() != -1)
2709 {
2710 /*if (j == 12)
2711 g_scriptVersion = 10;
2712 else if (j == 21)
2713 g_scriptVersion = 11;
2714 else if (j == 25)
2715 g_scriptVersion = 13;
2716 else if (j == 29)
2717 g_scriptVersion = 14;*/
2718 break;
2719 }
2720 /*else
2721 g_scriptVersion = 16;*/
2722 }
2723
2724 /*
2725 v1.3d v1.5
2726 DEFAULTVISIBILITY DEFAULTVISIBILITY
2727 GENERICIMPACTDAMAGE GENERICIMPACTDAMAGE
2728 MAXPLAYERHEALTH MAXPLAYERHEALTH
2729 STARTARMORHEALTH STARTARMORHEALTH
2730 RESPAWNACTORTIME RESPAWNACTORTIME
2731 RESPAWNITEMTIME RESPAWNITEMTIME
2732 RUNNINGSPEED RUNNINGSPEED
2733 RPGBLASTRADIUS GRAVITATIONALCONSTANT
2734 PIPEBOMBRADIUS RPGBLASTRADIUS
2735 SHRINKERBLASTRADIUS PIPEBOMBRADIUS
2736 TRIPBOMBBLASTRADIUS SHRINKERBLASTRADIUS
2737 MORTERBLASTRADIUS TRIPBOMBBLASTRADIUS
2738 BOUNCEMINEBLASTRADIUS MORTERBLASTRADIUS
2739 SEENINEBLASTRADIUS BOUNCEMINEBLASTRADIUS
2740 MAXPISTOLAMMO SEENINEBLASTRADIUS
2741 MAXSHOTGUNAMMO MAXPISTOLAMMO
2742 MAXCHAINGUNAMMO MAXSHOTGUNAMMO
2743 MAXRPGAMMO MAXCHAINGUNAMMO
2744 MAXHANDBOMBAMMO MAXRPGAMMO
2745 MAXSHRINKERAMMO MAXHANDBOMBAMMO
2746 MAXDEVISTATORAMMO MAXSHRINKERAMMO
2747 MAXTRIPBOMBAMMO MAXDEVISTATORAMMO
2748 MAXFREEZEAMMO MAXTRIPBOMBAMMO
2749 CAMERASDESTRUCTABLE MAXFREEZEAMMO
2750 NUMFREEZEBOUNCES MAXGROWAMMO
2751 FREEZERHURTOWNER CAMERASDESTRUCTABLE
2752 NUMFREEZEBOUNCES
2753 FREEZERHURTOWNER
2754 QSIZE
2755 TRIPBOMBLASERMODE
2756 */
2757
2758 G_DoGameStartup(params);
2759 }
2760 continue;
2761 }
2762 }
2763 while (loop);
2764
2765 return 0;
2766 }
2767
C_ScriptVersionString(int32_t version)2768 static char const * C_ScriptVersionString(int32_t version)
2769 {
2770 switch (version)
2771 {
2772 case 9:
2773 return ", v0.99 compatibility mode";
2774 case 10:
2775 return ", v1.0 compatibility mode";
2776 case 11:
2777 return ", v1.1 compatibility mode";
2778 case 13:
2779 return ", v1.3D compatibility mode";
2780 default:
2781 return "";
2782 }
2783 }
2784
C_PrintStats(void)2785 void C_PrintStats(void)
2786 {
2787 initprintf("%d/%d labels\n", g_labelCnt,
2788 (int32_t) min((MAXSECTORS * sizeof(sectortype)/sizeof(int32_t)),
2789 MAXSPRITES * sizeof(spritetype)/(1<<6)));
2790
2791 int i, j;
2792
2793 for (i=MAXQUOTES-1, j=0; i>=0; i--)
2794 {
2795 if (apStrings[i])
2796 j++;
2797 }
2798
2799 if (j) initprintf("%d strings, ", j);
2800
2801 for (i=MAXTILES-1, j=0; i>=0; i--)
2802 {
2803 if (g_tile[i].execPtr)
2804 j++;
2805 }
2806 if (j) initprintf("%d actors", j);
2807
2808 initprintf("\n");
2809 }
2810
C_Compile(const char * fileName)2811 void C_Compile(const char *fileName)
2812 {
2813 Bmemset(apScriptEvents, 0, sizeof(apScriptEvents));
2814 Bmemset(apScriptGameEventEnd, 0, sizeof(apScriptGameEventEnd));
2815
2816 for (int i=0; i<MAXTILES; i++)
2817 {
2818 Bmemset(&g_tile[i], 0, sizeof(tiledata_t));
2819 g_actorMinMs[i] = 1e308;
2820 }
2821
2822 C_InitHashes();
2823 Gv_Init();
2824
2825 #ifdef USE_OPENGL
2826 if (REALITY)
2827 {
2828 if (RT_PrepareScript())
2829 G_GameExit("Script error");
2830 return;
2831 }
2832 #endif
2833
2834 int kFile = kopen4loadfrommod(fileName,g_loadFromGroupOnly);
2835
2836 if (kFile == -1) // JBF: was 0
2837 {
2838 if (g_loadFromGroupOnly == 1 || numgroupfiles == 0)
2839 {
2840 char const *gf = G_GrpFile();
2841 Bsprintf(tempbuf,"Required game data was not found. A valid copy of \"%s\" or other compatible data is needed to run EDuke32.\n\n"
2842 "You must copy \"%s\" to your game directory before continuing!", gf, gf);
2843 G_GameExit(tempbuf);
2844 }
2845 else
2846 {
2847 Bsprintf(tempbuf,"CON file `%s' missing.", fileName);
2848 G_GameExit(tempbuf);
2849 }
2850
2851 //g_loadFromGroupOnly = 1;
2852 return; //Not there
2853 }
2854
2855 int const kFileLen = kfilelength(kFile);
2856
2857 initprintf("Compiling: %s (%d bytes)\n", fileName, kFileLen);
2858
2859 g_logFlushWindow = 0;
2860
2861 uint32_t const startcompiletime = timerGetTicks();
2862
2863 char * mptr = (char *)Xmalloc(kFileLen+1);
2864 mptr[kFileLen] = 0;
2865
2866 textptr = (char *) mptr;
2867 kread(kFile,(char *)textptr,kFileLen);
2868 kclose(kFile);
2869
2870 g_scriptcrc = Bcrc32(NULL, 0, 0L);
2871 g_scriptcrc = Bcrc32(textptr, kFileLen, g_scriptcrc);
2872
2873 Bfree(apScript);
2874
2875 apScript = (intptr_t *)Xcalloc(1, g_scriptSize * sizeof(intptr_t));
2876 bitptr = (char *)Xcalloc(1, (((g_scriptSize + 7) >> 3) + 1) * sizeof(uint8_t));
2877 // initprintf("script: %d, bitptr: %d\n",script,bitptr);
2878
2879 g_labelCnt = 0;
2880 g_defaultLabelCnt = 0;
2881 g_scriptPtr = apScript + 3; // move permits constants 0 and 1; moveptr[1] would be script[2] (reachable?)
2882 g_warningCnt = 0;
2883 g_errorCnt = 0;
2884 g_lineNumber = 1;
2885 g_totalLines = 0;
2886
2887 Bstrcpy(g_scriptFileName, fileName);
2888
2889 C_ParseCommand(1);
2890
2891 for (char * m : g_scriptModules)
2892 {
2893 C_Include(m);
2894 free(m);
2895 }
2896 g_scriptModules.clear();
2897
2898 g_logFlushWindow = 1;
2899
2900 if (g_errorCnt > 63)
2901 initprintf("fatal error: too many errors: Aborted\n");
2902
2903 //*script = (intptr_t) g_scriptPtr;
2904
2905 DO_FREE_AND_NULL(mptr);
2906
2907 if (g_warningCnt || g_errorCnt)
2908 initprintf("Found %d warning(s), %d error(s).\n", g_warningCnt, g_errorCnt);
2909
2910 if (g_errorCnt)
2911 {
2912 Bsprintf(buf, "Error compiling CON files.");
2913 G_GameExit(buf);
2914 }
2915
2916 g_totalLines += g_lineNumber;
2917
2918 C_SetScriptSize(g_scriptPtr-apScript+8);
2919
2920 initprintf("Script compiled in %dms, %ld bytes%s\n", timerGetTicks() - startcompiletime,
2921 (unsigned long)(g_scriptPtr-apScript), C_ScriptVersionString(g_scriptVersion));
2922
2923 for (auto *i : tables_free)
2924 hash_free(i);
2925
2926 //freehashnames();
2927 freesoundhashnames();
2928
2929 if (g_scriptDebug)
2930 C_PrintStats();
2931
2932 C_InitQuotes();
2933 }
2934
C_ReportError(int32_t iError)2935 void C_ReportError(int32_t iError)
2936 {
2937 if (Bstrcmp(g_szCurrentBlockName,g_szLastBlockName))
2938 {
2939 if (g_scriptEventOffset || g_processingState || g_parsingActorPtr)
2940 initprintf("%s: In %s `%s':\n",g_scriptFileName,g_scriptEventOffset?"event":g_parsingActorPtr?"actor":"state",g_szCurrentBlockName);
2941 else initprintf("%s: At top level:\n",g_scriptFileName);
2942 Bstrcpy(g_szLastBlockName,g_szCurrentBlockName);
2943 }
2944 switch (iError)
2945 {
2946 case ERROR_CLOSEBRACKET:
2947 initprintf("%s:%d: error: found more `}' than `{' before `%s'.\n",g_scriptFileName,g_lineNumber,tempbuf);
2948 break;
2949 case ERROR_EXCEEDSMAXTILES:
2950 initprintf("%s:%d: error: `%s' value exceeds MAXTILES. Maximum is %d.\n",g_scriptFileName,g_lineNumber,tempbuf,MAXTILES-1);
2951 break;
2952 case ERROR_EXPECTEDKEYWORD:
2953 initprintf("%s:%d: error: expected a keyword but found `%s'.\n",g_scriptFileName,g_lineNumber,tempbuf);
2954 break;
2955 case ERROR_FOUNDWITHIN:
2956 initprintf("%s:%d: error: found `%s' within %s.\n",g_scriptFileName,g_lineNumber,tempbuf,g_parsingActorPtr?"an actor":"a state");
2957 break;
2958 case ERROR_ISAKEYWORD:
2959 initprintf("%s:%d: error: symbol `%s' is a keyword.\n",g_scriptFileName,g_lineNumber,label+(g_labelCnt<<6));
2960 break;
2961 case ERROR_OPENBRACKET:
2962 initprintf("%s:%d: error: found more `{' than `}' before `%s'.\n",g_scriptFileName,g_lineNumber,tempbuf);
2963 break;
2964 case ERROR_NOTAGAMEVAR:
2965 initprintf("%s:%d: error: symbol `%s' is not a variable.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
2966 break;
2967 case ERROR_PARAMUNDEFINED:
2968 initprintf("%s:%d: error: parameter `%s' is undefined.\n",g_scriptFileName,g_lineNumber,tempbuf);
2969 break;
2970 case ERROR_SYNTAXERROR:
2971 initprintf("%s:%d: error: syntax error.\n",g_scriptFileName,g_lineNumber);
2972 break;
2973 case ERROR_VARREADONLY:
2974 initprintf("%s:%d: error: variable `%s' is read-only.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
2975 break;
2976 case ERROR_VARTYPEMISMATCH:
2977 initprintf("%s:%d: error: variable `%s' is of the wrong type.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
2978 break;
2979 case WARNING_BADGAMEVAR:
2980 initprintf("%s:%d: warning: variable `%s' should be either per-player OR per-actor, not both.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
2981 break;
2982 case WARNING_DUPLICATEDEFINITION:
2983 initprintf("%s:%d: warning: duplicate definition `%s' ignored.\n",g_scriptFileName,g_lineNumber,LAST_LABEL);
2984 break;
2985 case WARNING_LABELSONLY:
2986 initprintf("%s:%d: warning: expected a label, found a constant.\n",g_scriptFileName,g_lineNumber);
2987 break;
2988 case WARNING_VARMASKSKEYWORD:
2989 initprintf("%s:%d: warning: variable `%s' masks keyword.\n", g_scriptFileName, g_lineNumber, LAST_LABEL);
2990 break;
2991 }
2992 }
2993
2994