1 //-------------------------------------------------------------------------
2 /*
3 Copyright (C) 2010 EDuke32 developers and contributors
4
5 This file is part of EDuke32.
6
7 EDuke32 is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License version 2
9 as published by the Free Software Foundation.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
15 See the GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21 //-------------------------------------------------------------------------
22
23 // This object is shared by the editors of *all* Build games!
24
25 #include "compat.h"
26
27 #include "m32script.h"
28 #include "m32def.h"
29
30 #include "sounds_mapster32.h"
31
32 #include "osd.h"
33 #include "keys.h"
34 #include "common.h"
35
36 #include "colmatch.h"
37
38 // from macros.h
39 #define rnd(X) ((krand()>>8)>=(255-(X)))
40
41 vmstate_t vm;
42 vmstate_t vm_default =
43 {
44 -1, // g_i
45 0, // g_st
46 NULL, // g_sp
47 0, // flags
48 0, // miscflags
49 };
50
51 int32_t g_errorLineNum, g_tw;
52
53 uint8_t aEventEnabled[MAXEVENTS];
54
55 uint32_t m32_drawlinepat=0xffffffff;
56 int32_t m32_script_expertmode = 0;
57
58 instype *insptr;
59
60 static instype *x_sortingstateptr;
61
62 //#include "m32structures.cpp"
63
64 #ifdef DEBUGGINGAIDS
X_Disasm(ofstype beg,int32_t size)65 void X_Disasm(ofstype beg, int32_t size)
66 {
67 instype *p;
68
69 if (!apScript) return;
70 if (beg<0 || beg+size>g_scriptSize) return;
71
72 initprintf("beg=%d, size=%d: ", beg, size);
73 for (p=apScript+beg; p<apScript+beg+size; p++)
74 {
75 if (*p>>12 && (*p&0xFFF)<CON_END)
76 initprintf("%s ", keyw[*p&0xFFF]);
77 else
78 initprintf("%d ", *p);
79 }
80 initprintf("\n");
81 }
82 #endif
83
VM_ScriptInfo(void)84 void VM_ScriptInfo(void)
85 {
86 if (apScript)
87 {
88 instype *p;
89 if (insptr)
90 for (p=max(insptr-20,apScript); p<min(insptr+20, apScript+g_scriptSize); p++)
91 {
92 if (p==insptr) initprintf("<<");
93
94 if (*p>>12 && (*p&0xFFF)<CON_END)
95 initprintf("\n%5d: L%5d: %s ",(int32_t)(p-apScript),(int32_t)(*p>>12),keyw[*p&0xFFF]);
96 else initprintf(" %d",*p);
97
98 if (p==insptr) initprintf(">>");
99 }
100 initprintf(" \n");
101 if (vm.spriteNum >= 0)
102 initprintf("current sprite: %d\n",vm.spriteNum);
103 if (g_tw>=0 && g_tw<CON_END)
104 initprintf("g_errorLineNum: %d, g_tw: %s\n",g_errorLineNum,keyw[g_tw]);
105 else
106 initprintf("g_errorLineNum: %d, g_tw: %d\n",g_errorLineNum,g_tw);
107 }
108 }
109
M32_PostScriptExec(void)110 void M32_PostScriptExec(void)
111 {
112 if (vm.miscflags&VMFLAG_MISC_UPDATEHL)
113 {
114 update_highlight();
115 vm.miscflags &= ~VMFLAG_MISC_UPDATEHL;
116 }
117
118 if (vm.miscflags&VMFLAG_MISC_UPDATEHLSECT)
119 {
120 update_highlightsector();
121 if (!in3dmode())
122 ovh_whiteoutgrab(1);
123 vm.miscflags &= ~VMFLAG_MISC_UPDATEHLSECT;
124 }
125 }
126
VM_OnEvent(int32_t iEventID,int32_t spriteNum)127 void VM_OnEvent(int32_t iEventID, int32_t spriteNum)
128 {
129 if (iEventID < 0 || iEventID >= MAXEVENTS)
130 {
131 M32_PRINTERROR("Invalid event ID");
132 return;
133 }
134
135 if (aEventOffsets[iEventID] < 0 || !aEventEnabled[iEventID])
136 {
137 //Bsprintf(g_szBuf,"No event found for %d",iEventID);
138 //AddLog(g_szBuf);
139 return;
140 }
141
142 {
143 instype *const oinsptr=insptr;
144 vmstate_t vm_backup;
145 void *const olocalvars = aGameArrays[M32_LOCAL_ARRAY_ID].vals;
146 #ifdef M32_LOCALS_VARARRAY
147 int32_t localvars[aEventNumLocals[iEventID]];
148 #else
149 int32_t localvars[M32_LOCALS_FIXEDNUM];
150 #endif
151
152 // Initialize 'state'-local variables to 0.
153 if (aEventNumLocals[iEventID] > 0)
154 Bmemset(localvars, 0, aEventNumLocals[iEventID]*sizeof(int32_t));
155
156 Bmemcpy(&vm_backup, &vm, sizeof(vmstate_t));
157
158 vm.spriteNum = spriteNum; // current sprite ID
159 if (vm.spriteNum >= 0)
160 vm.pSprite = &sprite[vm.spriteNum];
161
162 vm.g_st = 1+iEventID;
163
164 vm.flags = 0;
165
166 insptr = apScript + aEventOffsets[iEventID];
167
168 aGameArrays[M32_LOCAL_ARRAY_ID].vals = localvars;
169 VM_Execute(0);
170 aGameArrays[M32_LOCAL_ARRAY_ID].vals = olocalvars;
171
172 if (vm.flags&VMFLAG_ERROR)
173 {
174 aEventEnabled[iEventID] = 0;
175 message("ERROR executing %s. Event disabled.", label+(iEventID*MAXLABELLEN));
176 }
177
178 M32_PostScriptExec();
179
180 // restore old values...
181 Bmemcpy(&vm, &vm_backup, sizeof(vmstate_t));
182 insptr = oinsptr;
183
184 //AddLog("End of Execution");
185 }
186 }
187
G_GetAngleDelta(int32_t a,int32_t na)188 static int32_t G_GetAngleDelta(int32_t a,int32_t na)
189 {
190 a &= 2047;
191 na &= 2047;
192
193 if (klabs(a-na) < 1024)
194 {
195 // OSD_Printf("G_GetAngleDelta() returning %d\n",na-a);
196 return na-a;
197 }
198
199 if (na > 1024) na -= 2048;
200 if (a > 1024) a -= 2048;
201
202 // OSD_Printf("G_GetAngleDelta() returning %d\n",na-a);
203 return na-a;
204 }
205
VM_DoConditional(int32_t condition)206 static inline void __fastcall VM_DoConditional(int32_t condition)
207 {
208 if (condition)
209 {
210 // skip 'else' pointer.. and...
211 insptr+=2;
212 VM_Execute(1);
213 return;
214 }
215
216 insptr++;
217 insptr += *insptr;
218 if (((*insptr)&0xFFF) == CON_ELSE)
219 {
220 // else...
221 // skip 'else' and...
222 insptr+=2;
223 VM_Execute(1);
224 }
225 }
226
X_DoSortDefault(const void * lv,const void * rv)227 static int X_DoSortDefault(const void *lv, const void *rv)
228 {
229 return *(int32_t const *)rv - *(int32_t const *)lv;
230 }
231
X_DoSort(const void * lv,const void * rv)232 static int X_DoSort(const void *lv, const void *rv)
233 {
234 m32_sortvar1 = *(int32_t const *)lv;
235 m32_sortvar2 = *(int32_t const *)rv;
236 insptr = x_sortingstateptr;
237 VM_Execute(0);
238 return g_iReturnVar;
239 }
240
241 // in interactive execution, allow the current sprite index to be the aimed-at sprite (in 3d mode)
242 #define X_ERROR_INVALIDCI() \
243 if ((vm.spriteNum < 0 || vm.spriteNum >= MAXSPRITES) && \
244 (vm.g_st != 0 || searchstat != 3 || (vm.spriteNum = searchwall, vm.pSprite = &sprite[vm.spriteNum], 0))) \
245 { \
246 M32_ERROR("Current sprite index invalid!"); \
247 continue; \
248 }
249
250 #define X_ERROR_INVALIDSPRI(dasprite) \
251 if (dasprite < 0 || dasprite >= MAXSPRITES) \
252 { \
253 M32_ERROR("Invalid sprite index %d!", dasprite); \
254 continue; \
255 }
256
257 #define X_ERROR_INVALIDSECT(dasect) \
258 if (dasect < 0 || dasect >= numsectors) \
259 { \
260 M32_ERROR("Invalid sector index %d!", dasect); \
261 continue; \
262 }
263
264 #define X_ERROR_INVALIDSP() \
265 if (!vm.pSprite && (vm.g_st != 0 || searchstat != 3 || (vm.pSprite = &sprite[searchwall], 0))) \
266 { \
267 M32_ERROR("Current sprite invalid!"); \
268 continue; \
269 }
270
271 #define X_ERROR_INVALIDQUOTE(q, array) \
272 if (q < 0 || q >= MAXQUOTES) \
273 { \
274 M32_ERROR("Invalid quote number %d!", q); \
275 continue; \
276 } \
277 else if (array[q] == NULL) \
278 { \
279 M32_ERROR("Null quote %d!", q); \
280 continue; \
281 }
282
GetMaybeInlineQuote(int32_t quotei)283 static char *GetMaybeInlineQuote(int32_t quotei)
284 {
285 char *quotetext;
286 if (quotei==-1)
287 {
288 quotetext = (char *)insptr;
289 while (*insptr++) /* skip the string */;
290 }
291 else
292 {
293 quotei = Gv_GetVar(quotei);
294 do { X_ERROR_INVALIDQUOTE(quotei, apStrings) } while (0);
295 if (vm.flags&VMFLAG_ERROR)
296 return NULL;
297 quotetext = apStrings[quotei];
298 }
299
300 return quotetext;
301 }
302
CheckArray(int aidx)303 static int CheckArray(int aidx)
304 {
305 if (!(aidx >= 0 && aidx < g_gameArrayCount))
306 M32_ERROR("Invalid array %d!", aidx);
307
308 return (vm.flags&VMFLAG_ERROR);
309 }
310
VM_Execute(int32_t once)311 int32_t VM_Execute(int32_t once)
312 {
313 int32_t tw = *insptr;
314
315 // jump directly into the loop, saving us from the checks during the first iteration
316 goto skip_check;
317
318 while (!once)
319 {
320 if (vm.flags)
321 return 1;
322
323 tw = *insptr;
324
325 skip_check:
326 // Bsprintf(g_szBuf,"Parsing: %d",*insptr);
327 // AddLog(g_szBuf);
328
329 g_errorLineNum = tw>>12;
330 g_tw = (tw &= 0xFFF);
331
332 switch (tw)
333 {
334 // *** basic commands
335 case CON_NULLOP:
336 insptr++;
337 continue;
338
339 case CON_STATE:
340 {
341 instype *const tempscrptr = insptr+2;
342 const int32_t stateidx = *(insptr+1), o_g_st = vm.g_st, oret=vm.flags&VMFLAG_RETURN;
343 void *const olocalvars = aGameArrays[M32_LOCAL_ARRAY_ID].vals;
344 #ifdef M32_LOCALS_VARARRAY
345 int32_t localvars[statesinfo[stateidx].numlocals];
346 #else
347 int32_t localvars[M32_LOCALS_FIXEDNUM];
348 #endif
349
350 // needed since any read access before initialization would cause undefined behaviour
351 if (statesinfo[stateidx].numlocals > 0)
352 Bmemset(localvars, 0, statesinfo[stateidx].numlocals*sizeof(int32_t));
353
354 insptr = apScript + statesinfo[stateidx].ofs;
355 vm.g_st = 1+MAXEVENTS+stateidx;
356 aGameArrays[M32_LOCAL_ARRAY_ID].vals = localvars;
357 VM_Execute(0);
358 aGameArrays[M32_LOCAL_ARRAY_ID].vals = olocalvars;
359 vm.g_st = o_g_st;
360 vm.flags &= ~VMFLAG_RETURN;
361 vm.flags |= oret;
362 insptr = tempscrptr;
363 }
364 continue;
365
366 case CON_RETURN:
367 vm.flags |= VMFLAG_RETURN;
368 return 1;
369 case CON_BREAK:
370 vm.flags |= VMFLAG_BREAK;
371 // XXX: may not be cleared subsequently?
372 fallthrough__;
373 case CON_ENDS:
374 return 1;
375
376 case CON_ELSE:
377 insptr++;
378 insptr += *insptr;
379 continue;
380
381 case CON_ENDSWITCH:
382 vm.flags &= ~VMFLAG_BREAK;
383 fallthrough__;
384 case CON_ENDEVENT:
385 insptr++;
386 return 1;
387
388 case CON_SWITCH:
389 insptr++; // p-code
390 {
391 // command format:
392 // variable ID to check
393 // script offset to 'end'
394 // count of case statements
395 // script offset to default case (null if none)
396 // For each case: value, ptr to code
397 //AddLog("Processing Switch...");
398 int32_t lValue=Gv_GetVar(*insptr++), lEnd=*insptr++, lCases=*insptr++;
399 instype *lpDefault=insptr++, *lpCases=insptr, *lCodeInsPtr;
400 int32_t bMatched=0, lCheckCase;
401 int32_t left,right;
402
403 insptr += lCases*2;
404 lCodeInsPtr = insptr;
405 //Bsprintf(g_szBuf,"lEnd= %d *lpDefault=%d",lEnd,*lpDefault); AddLog(g_szBuf);
406 //Bsprintf(g_szBuf,"Checking %d cases for %d",lCases, lValue); AddLog(g_szBuf);
407 left = 0;
408 right = lCases-1;
409 while (!bMatched)
410 {
411 //Bsprintf(g_szBuf,"Checking #%d Value= %d",lCheckCase, lpCases[lCheckCase*2]); AddLog(g_szBuf);
412 lCheckCase=(left+right)/2;
413 // initprintf("(%2d..%2d..%2d) [%2d..%2d..%2d]==%2d\n",left,lCheckCase,right,lpCases[left*2],lpCases[lCheckCase*2],lpCases[right*2],lValue);
414 if (lpCases[lCheckCase*2] > lValue)
415 right = lCheckCase-1;
416 else if (lpCases[lCheckCase*2] < lValue)
417 left = lCheckCase+1;
418 else if (lpCases[lCheckCase*2] == lValue)
419 {
420 //AddLog("Found Case Match");
421 //Bsprintf(g_szBuf,"insptr=%d. lCheckCase=%d, offset=%d, &script[0]=%d", (int32_t)insptr,(int32_t)lCheckCase,lpCases[lCheckCase*2+1],(int32_t)&script[0]); AddLog(g_szBuf);
422 // fake a 2-d Array
423 insptr = lCodeInsPtr + lpCases[lCheckCase*2+1];
424 //Bsprintf(g_szBuf,"insptr=%d. ", (int32_t)insptr); AddLog(g_szBuf);
425 VM_Execute(0);
426 //AddLog("Done Executing Case");
427 bMatched=1;
428 }
429
430 if (right-left < 0)
431 break;
432 }
433
434 if (!bMatched)
435 {
436 if (*lpDefault >= 0)
437 {
438 //AddLog("No Matching Case: Using Default");
439 insptr = lCodeInsPtr + *lpDefault;
440 VM_Execute(0);
441 }
442 // else
443 // {
444 // //AddLog("No Matching Case: No Default to use");
445 // }
446 }
447 insptr = (instype *)(lCodeInsPtr + lEnd);
448 vm.flags &= ~VMFLAG_BREAK;
449 //Bsprintf(g_szBuf,"insptr=%d. ", (int32_t)insptr); AddLog(g_szBuf);
450 //AddLog("Done Processing Switch");
451 continue;
452 }
453
454 case CON_GETCURRADDRESS:
455 insptr++;
456 {
457 int32_t j=*insptr++;
458 Gv_SetVar(j, insptr-apScript);
459 }
460 continue;
461
462 case CON_JUMP:
463 insptr++;
464 {
465 int32_t j = Gv_GetVar(*insptr++);
466 if (j<0 || j>=(g_scriptPtr-apScript))
467 {
468 M32_ERROR("script index out of bounds (%d)", j);
469 continue;
470 }
471 insptr = (instype *)(j+apScript);
472 }
473 continue;
474
475 case CON_RIGHTBRACE:
476 insptr++;
477 return 1;
478 case CON_LEFTBRACE:
479 insptr++;
480 VM_Execute(0);
481 continue;
482
483 // *** arrays
484 case CON_SETARRAY:
485 insptr++;
486 {
487 const int32_t j=*insptr++;
488 const int32_t index = Gv_GetVar(*insptr++);
489 const int32_t value = Gv_GetVar(*insptr++);
490
491 CheckArray(j);
492
493 if (aGameArrays[j].dwFlags & GAMEARRAY_READONLY)
494 M32_ERROR("Tried to set on read-only array `%s'", aGameArrays[j].szLabel);
495
496 if (!(index >= 0 && index < aGameArrays[j].size))
497 M32_ERROR("Array index %d out of bounds", index);
498
499 if (vm.flags&VMFLAG_ERROR)
500 continue;
501
502 // NOTE: Other array types not implemented, since they're read-only.
503 ((int32_t *)aGameArrays[j].vals)[index] = value;
504 continue;
505 }
506
507 case CON_GETARRAYSIZE:
508 insptr++;
509 {
510 const int32_t j=*insptr++;
511
512 if (CheckArray(j))
513 continue;
514
515 Gv_SetVar(*insptr++, Gv_GetArraySize(j));
516 }
517 continue;
518
519 case CON_RESIZEARRAY:
520 insptr++;
521 {
522 const int32_t j=*insptr++;
523 const int32_t asize = Gv_GetVar(*insptr++);
524
525 CheckArray(j);
526
527 if (aGameArrays[j].dwFlags & GAMEARRAY_READONLY)
528 M32_ERROR("Tried to resize read-only array `%s'", aGameArrays[j].szLabel);
529
530 if (!(asize >= 1 && asize <= 65536))
531 M32_ERROR("Invalid array size %d (must be between 1 and 65536)", asize);
532
533 if (vm.flags&VMFLAG_ERROR)
534 continue;
535
536 // OSD_Printf(OSDTEXT_GREEN "CON_RESIZEARRAY: resizing array %s from %d to %d\n", aGameArrays[j].szLabel, aGameArrays[j].size, asize);
537 aGameArrays[j].vals = Xrealloc(aGameArrays[j].vals, sizeof(int32_t) * asize);
538 aGameArrays[j].size = asize;
539
540 continue;
541 }
542
543 case CON_COPY:
544 insptr++;
545 {
546 const int32_t si=*insptr++;
547 int32_t sidx = Gv_GetVar(*insptr++);
548 const int32_t di=*insptr++;
549 int32_t didx = Gv_GetVar(*insptr++);
550 int32_t numelts = Gv_GetVar(*insptr++);
551
552 CheckArray(si);
553 CheckArray(di);
554
555 if (aGameArrays[di].dwFlags & GAMEARRAY_READONLY)
556 M32_ERROR("Array %d is read-only!", di);
557 if (vm.flags&VMFLAG_ERROR)
558 continue;
559
560 const int32_t ssiz = Gv_GetArraySize(si);
561 const int32_t dsiz = Gv_GetArraySize(di);
562
563 if ((uint32_t)sidx >= (uint32_t)ssiz)
564 M32_ERROR("Invalid source index %d", sidx);
565 if ((uint32_t)didx >= (uint32_t)dsiz)
566 M32_ERROR("Invalid destination index %d", didx);
567 if (vm.flags&VMFLAG_ERROR)
568 continue;
569
570 if (numelts > ssiz-sidx)
571 numelts = ssiz-sidx;
572 if (numelts > dsiz-didx)
573 numelts = dsiz-didx;
574
575 const gamearray_t *const sar = &aGameArrays[si];
576 gamearray_t *const dar = &aGameArrays[di];
577
578 switch (sar->dwFlags & GAMEARRAY_TYPE_MASK)
579 {
580 case 0:
581 case GAMEARRAY_INT32:
582 if (sar->dwFlags & GAMEARRAY_STRIDE2)
583 {
584 for (; numelts>0; numelts--, sidx += 2)
585 ((int32_t *)dar->vals)[didx++] = ((int32_t *)sar->vals)[sidx];
586 }
587 else
588 {
589 Bmemcpy((int32_t *)dar->vals + didx, (int32_t *)sar->vals + sidx,
590 numelts * sizeof(int32_t));
591 }
592 break;
593 case GAMEARRAY_INT16:
594 for (; numelts>0; numelts--)
595 ((int32_t *)dar->vals)[didx++] = ((int16_t *)sar->vals)[sidx++];
596 break;
597 case GAMEARRAY_UINT8:
598 for (; numelts>0; numelts--)
599 ((int32_t *)dar->vals)[didx++] = ((uint8_t *)sar->vals)[sidx++];
600 break;
601 }
602 continue;
603 }
604
605 // *** var & varvar ops
606 case CON_RANDVAR:
607 insptr++;
608 Gv_SetVar(*insptr, mulscale16(krand(), *(insptr+1)+1));
609 insptr += 2;
610 continue;
611
612 case CON_DISPLAYRANDVAR:
613 insptr++;
614 Gv_SetVar(*insptr, mulscale15(system_15bit_rand(), *(insptr+1)+1));
615 insptr += 2;
616 continue;
617
618 case CON_SETVAR:
619 insptr++;
620 Gv_SetVar(*insptr, *(insptr+1));
621 insptr += 2;
622 continue;
623
624 case CON_SETVARVAR:
625 insptr++;
626 {
627 int32_t j=*insptr++;
628 Gv_SetVar(j, Gv_GetVar(*insptr++));
629 }
630 continue;
631
632 case CON_MULVAR:
633 insptr++;
634 Gv_SetVar(*insptr, Gv_GetVar(*insptr) * *(insptr+1));
635 insptr += 2;
636 continue;
637
638 case CON_DIVVAR:
639 insptr++;
640 if (*(insptr+1) == 0)
641 {
642 M32_ERROR("Divide by zero.");
643 insptr += 2;
644 continue;
645 }
646 Gv_SetVar(*insptr, Gv_GetVar(*insptr) / *(insptr+1));
647 insptr += 2;
648 continue;
649
650 case CON_MODVAR:
651 insptr++;
652 if (*(insptr+1) == 0)
653 {
654 M32_ERROR("Mod by zero.");
655 insptr += 2;
656 continue;
657 }
658 Gv_SetVar(*insptr,Gv_GetVar(*insptr)%*(insptr+1));
659 insptr += 2;
660 continue;
661
662 case CON_ANDVAR:
663 insptr++;
664 Gv_SetVar(*insptr,Gv_GetVar(*insptr) & *(insptr+1));
665 insptr += 2;
666 continue;
667
668 case CON_ORVAR:
669 insptr++;
670 Gv_SetVar(*insptr,Gv_GetVar(*insptr) | *(insptr+1));
671 insptr += 2;
672 continue;
673
674 case CON_XORVAR:
675 insptr++;
676 Gv_SetVar(*insptr,Gv_GetVar(*insptr) ^ *(insptr+1));
677 insptr += 2;
678 continue;
679
680 case CON_RANDVARVAR:
681 insptr++;
682 {
683 int32_t j=*insptr++;
684 Gv_SetVar(j,mulscale16(krand(), Gv_GetVar(*insptr++)+1));
685 }
686 continue;
687
688 case CON_DISPLAYRANDVARVAR:
689 insptr++;
690 {
691 int32_t j=*insptr++;
692 Gv_SetVar(j,mulscale15(system_15bit_rand(), Gv_GetVar(*insptr++)+1));
693 }
694 continue;
695
696 case CON_MULVARVAR:
697 insptr++;
698 {
699 int32_t j=*insptr++;
700 Gv_SetVar(j, Gv_GetVar(j)*Gv_GetVar(*insptr++));
701 }
702 continue;
703
704 case CON_DIVVARVAR:
705 insptr++;
706 {
707 int32_t j=*insptr++;
708 int32_t l2=Gv_GetVar(*insptr++);
709
710 if (l2==0)
711 {
712 M32_ERROR("Divide by zero.");
713 continue;
714 }
715 Gv_SetVar(j, Gv_GetVar(j)/l2);
716 continue;
717 }
718
719 case CON_MODVARVAR:
720 insptr++;
721 {
722 int32_t j=*insptr++;
723 int32_t l2=Gv_GetVar(*insptr++);
724
725 if (l2==0)
726 {
727 M32_ERROR("Mod by zero.");
728 continue;
729 }
730
731 Gv_SetVar(j, Gv_GetVar(j) % l2);
732 continue;
733 }
734
735 case CON_ANDVARVAR:
736 insptr++;
737 {
738 int32_t j=*insptr++;
739 Gv_SetVar(j, Gv_GetVar(j) & Gv_GetVar(*insptr++));
740 }
741 continue;
742
743 case CON_XORVARVAR:
744 insptr++;
745 {
746 int32_t j=*insptr++;
747 Gv_SetVar(j, Gv_GetVar(j) ^ Gv_GetVar(*insptr++));
748 }
749 continue;
750
751 case CON_ORVARVAR:
752 insptr++;
753 {
754 int32_t j=*insptr++;
755 Gv_SetVar(j, Gv_GetVar(j) | Gv_GetVar(*insptr++));
756 }
757 continue;
758
759 case CON_SUBVAR:
760 insptr++;
761 Gv_SetVar(*insptr, Gv_GetVar(*insptr) - *(insptr+1));
762 insptr += 2;
763 continue;
764
765 case CON_SUBVARVAR:
766 insptr++;
767 {
768 int32_t j=*insptr++;
769 Gv_SetVar(j, Gv_GetVar(j) - Gv_GetVar(*insptr++));
770 }
771 continue;
772
773 case CON_ADDVAR:
774 insptr++;
775 Gv_SetVar(*insptr, Gv_GetVar(*insptr) + *(insptr+1));
776 insptr += 2;
777 continue;
778
779 case CON_ADDVARVAR:
780 insptr++;
781 {
782 int32_t j=*insptr++;
783 Gv_SetVar(j, Gv_GetVar(j) + Gv_GetVar(*insptr++));
784 }
785 continue;
786
787 case CON_SHIFTVARL:
788 insptr++;
789 Gv_SetVar(*insptr, Gv_GetVar(*insptr) << *(insptr+1));
790 insptr += 2;
791 continue;
792
793 case CON_SHIFTVARVARL:
794 insptr++;
795 {
796 int32_t j=*insptr++;
797 Gv_SetVar(j, Gv_GetVar(j) << Gv_GetVar(*insptr++));
798 }
799 continue;
800
801 case CON_SHIFTVARR:
802 insptr++;
803 Gv_SetVar(*insptr, Gv_GetVar(*insptr) >> *(insptr+1));
804 insptr += 2;
805 continue;
806
807 case CON_SHIFTVARVARR:
808 insptr++;
809 {
810 int32_t j=*insptr++;
811 Gv_SetVar(j, Gv_GetVar(j) >> Gv_GetVar(*insptr++));
812 }
813 continue;
814
815 case CON_SIN:
816 insptr++;
817 Gv_SetVar(*insptr, sintable[Gv_GetVar(*(insptr+1))&2047]);
818 insptr += 2;
819 continue;
820
821 case CON_COS:
822 insptr++;
823 Gv_SetVar(*insptr, sintable[(Gv_GetVar(*(insptr+1))+512)&2047]);
824 insptr += 2;
825 continue;
826
827 case CON_DISPLAYRAND:
828 insptr++;
829 Gv_SetVar(*insptr++, system_15bit_rand());
830 continue;
831
832 // *** other math
833 case CON_FTOI:
834 insptr++;
835 {
836 union { int32_t ival; float fval; };
837
838 ival=Gv_GetVar(*insptr);
839 int32_t const scale=*(insptr+1);
840 // rounding must absolutely be!
841 //OSD_Printf("ftoi: bits:%8x, scale=%d, fval=%f, (int32_t)(fval*scale)=%d\n", bits, scale, fval, (int32_t)(fval*scale));
842 Gv_SetVar(*insptr, (int32_t)Blrintf(fval * scale));
843 }
844 insptr += 2;
845 continue;
846
847 case CON_ITOF:
848 insptr++;
849 {
850 union { int32_t ival; float fval; };
851
852 ival=Gv_GetVar(*insptr);
853 int32_t const scale=*(insptr+1);
854 fval = (float)ival/(float)scale;
855 Gv_SetVar(*insptr, ival);
856 }
857 insptr += 2;
858 continue;
859
860 case CON_CLAMP:
861 insptr++;
862 {
863 int32_t var=*insptr++, min=Gv_GetVar(*insptr++), max=Gv_GetVar(*insptr++);
864 int32_t val=Gv_GetVar(var);
865
866 if (val<min) Gv_SetVar(var, min);
867 else if (val>max) Gv_SetVar(var, max);
868 }
869 continue;
870
871 case CON_INV:
872 Gv_SetVar(*(insptr+1), -Gv_GetVar(*(insptr+1)));
873 insptr += 2;
874 continue;
875
876 case CON_SQRT:
877 insptr++;
878 {
879 // syntax sqrt <invar> <outvar>
880 int32_t lInVarID=*insptr++, lOutVarID=*insptr++;
881
882 Gv_SetVar(lOutVarID, ksqrt((uint32_t)Gv_GetVar(lInVarID)));
883 continue;
884 }
885
886 case CON_LDIST:
887 case CON_DIST:
888 insptr++;
889 {
890 int32_t distvar = *insptr++, xvar = Gv_GetVar(*insptr++), yvar = Gv_GetVar(*insptr++);
891
892 if (xvar < 0 || xvar >= MAXSPRITES || sprite[xvar].statnum==MAXSTATUS)
893 {
894 M32_ERROR("invalid sprite %d", xvar);
895 }
896 if (yvar < 0 || yvar >= MAXSPRITES || sprite[yvar].statnum==MAXSTATUS)
897 {
898 M32_ERROR("invalid sprite %d", yvar);
899 }
900 if (vm.flags&VMFLAG_ERROR) continue;
901
902 if (tw==CON_DIST)
903 Gv_SetVar(distvar, dist(&sprite[xvar],&sprite[yvar]));
904 else
905 Gv_SetVar(distvar, ldist(&sprite[xvar],&sprite[yvar]));
906 continue;
907 }
908
909 case CON_GETANGLE:
910 insptr++;
911 {
912 int32_t angvar = *insptr++;
913 int32_t xvar = Gv_GetVar(*insptr++);
914 int32_t yvar = Gv_GetVar(*insptr++);
915
916 Gv_SetVar(angvar, getangle(xvar,yvar));
917 continue;
918 }
919
920 case CON_GETINCANGLE:
921 insptr++;
922 {
923 int32_t angvar = *insptr++;
924 int32_t xvar = Gv_GetVar(*insptr++);
925 int32_t yvar = Gv_GetVar(*insptr++);
926
927 Gv_SetVar(angvar, G_GetAngleDelta(xvar,yvar));
928 continue;
929 }
930
931 case CON_A2XY:
932 case CON_AH2XYZ:
933 insptr++;
934 {
935 int32_t ang=Gv_GetVar(*insptr++), horiz=(tw==CON_A2XY)?100:Gv_GetVar(*insptr++);
936 int32_t xvar=*insptr++, yvar=*insptr++;
937
938 int32_t x = sintable[(ang+512)&2047];
939 int32_t y = sintable[ang&2047];
940
941 if (tw==CON_AH2XYZ)
942 {
943 int32_t zvar=*insptr++, z=0;
944
945 horiz -= 100;
946 if (horiz)
947 {
948 int32_t veclen = ksqrt(200*200 + horiz*horiz);
949 int32_t dacos = divscale14(200, veclen);
950
951 x = mulscale14(x, dacos);
952 y = mulscale14(y, dacos);
953 z = divscale14(-horiz, veclen);
954 }
955
956 Gv_SetVar(zvar, z);
957 }
958
959 Gv_SetVar(xvar, x);
960 Gv_SetVar(yvar, y);
961
962 continue;
963 }
964
965 case CON_MULSCALE:
966 insptr++;
967 {
968 int32_t var1 = *insptr++, var2 = Gv_GetVar(*insptr++);
969 int32_t var3 = Gv_GetVar(*insptr++), var4 = Gv_GetVar(*insptr++);
970
971 Gv_SetVar(var1, mulscale(var2, var3, var4));
972 continue;
973 }
974 case CON_DIVSCALE:
975 insptr++;
976 {
977 int32_t var1 = *insptr++, var2 = Gv_GetVar(*insptr++);
978 int32_t var3 = Gv_GetVar(*insptr++), var4 = Gv_GetVar(*insptr++);
979
980 Gv_SetVar(var1, divscale(var2, var3, var4));
981 continue;
982 }
983 case CON_SCALEVAR:
984 insptr++;
985 {
986 int32_t var1 = *insptr++, var2 = Gv_GetVar(*insptr++);
987 int32_t var3 = Gv_GetVar(*insptr++), var4 = Gv_GetVar(*insptr++);
988
989 Gv_SetVar(var1, scale(var2, var3, var4));
990 continue;
991 }
992
993 // *** if & while
994 case CON_IFVARVARAND:
995 insptr++;
996 {
997 int32_t j = Gv_GetVar(*insptr++);
998 j &= Gv_GetVar(*insptr++);
999 insptr--;
1000 VM_DoConditional(j);
1001 }
1002 continue;
1003
1004 case CON_IFVARVAROR:
1005 insptr++;
1006 {
1007 int32_t j = Gv_GetVar(*insptr++);
1008 j |= Gv_GetVar(*insptr++);
1009 insptr--;
1010 VM_DoConditional(j);
1011 }
1012 continue;
1013
1014 case CON_IFVARVARXOR:
1015 insptr++;
1016 {
1017 int32_t j = Gv_GetVar(*insptr++);
1018 j ^= Gv_GetVar(*insptr++);
1019 insptr--;
1020 VM_DoConditional(j);
1021 }
1022 continue;
1023
1024 case CON_IFVARVAREITHER:
1025 insptr++;
1026 {
1027 int32_t j = Gv_GetVar(*insptr++);
1028 int32_t l = Gv_GetVar(*insptr++);
1029 insptr--;
1030 VM_DoConditional(j || l);
1031 }
1032 continue;
1033
1034 case CON_IFVARVARBOTH:
1035 insptr++;
1036 {
1037 int32_t j = Gv_GetVar(*insptr++);
1038 int32_t l = Gv_GetVar(*insptr++);
1039 insptr--;
1040 VM_DoConditional(j && l);
1041 }
1042 continue;
1043
1044 case CON_IFVARVARN:
1045 insptr++;
1046 {
1047 int32_t j = Gv_GetVar(*insptr++);
1048 j = (j != Gv_GetVar(*insptr++));
1049 insptr--;
1050 VM_DoConditional(j);
1051 }
1052 continue;
1053
1054 case CON_IFVARVARE:
1055 insptr++;
1056 {
1057 int32_t j = Gv_GetVar(*insptr++);
1058 j = (j == Gv_GetVar(*insptr++));
1059 insptr--;
1060 VM_DoConditional(j);
1061 }
1062 continue;
1063
1064 case CON_IFVARVARG:
1065 insptr++;
1066 {
1067 int32_t j = Gv_GetVar(*insptr++);
1068 j = (j > Gv_GetVar(*insptr++));
1069 insptr--;
1070 VM_DoConditional(j);
1071 }
1072 continue;
1073
1074 case CON_IFVARVARGE:
1075 insptr++;
1076 {
1077 int32_t j = Gv_GetVar(*insptr++);
1078 j = (j >= Gv_GetVar(*insptr++));
1079 insptr--;
1080 VM_DoConditional(j);
1081 }
1082 continue;
1083
1084 case CON_IFVARVARL:
1085 insptr++;
1086 {
1087 int32_t j = Gv_GetVar(*insptr++);
1088 j = (j < Gv_GetVar(*insptr++));
1089 insptr--;
1090 VM_DoConditional(j);
1091 }
1092 continue;
1093
1094 case CON_IFVARVARLE:
1095 insptr++;
1096 {
1097 int32_t j = Gv_GetVar(*insptr++);
1098 j = (j <= Gv_GetVar(*insptr++));
1099 insptr--;
1100 VM_DoConditional(j);
1101 }
1102 continue;
1103
1104 case CON_IFVARVARA:
1105 insptr++;
1106 {
1107 int32_t j = Gv_GetVar(*insptr++);
1108 j = ((uint32_t)j > (uint32_t)Gv_GetVar(*insptr++));
1109 insptr--;
1110 VM_DoConditional(j);
1111 }
1112 continue;
1113
1114 case CON_IFVARVARAE:
1115 insptr++;
1116 {
1117 int32_t j = Gv_GetVar(*insptr++);
1118 j = ((uint32_t)j >= (uint32_t)Gv_GetVar(*insptr++));
1119 insptr--;
1120 VM_DoConditional(j);
1121 }
1122 continue;
1123
1124 case CON_IFVARVARB:
1125 insptr++;
1126 {
1127 int32_t j = Gv_GetVar(*insptr++);
1128 j = ((uint32_t)j < (uint32_t)Gv_GetVar(*insptr++));
1129 insptr--;
1130 VM_DoConditional(j);
1131 }
1132 continue;
1133
1134 case CON_IFVARVARBE:
1135 insptr++;
1136 {
1137 int32_t j = Gv_GetVar(*insptr++);
1138 j = ((uint32_t)j <= (uint32_t)Gv_GetVar(*insptr++));
1139 insptr--;
1140 VM_DoConditional(j);
1141 }
1142 continue;
1143
1144 case CON_IFVARE:
1145 insptr++;
1146 {
1147 int32_t j=Gv_GetVar(*insptr++);
1148 VM_DoConditional(j == *insptr);
1149 }
1150 continue;
1151
1152 case CON_IFVARN:
1153 insptr++;
1154 {
1155 int32_t j=Gv_GetVar(*insptr++);
1156 VM_DoConditional(j != *insptr);
1157 }
1158 continue;
1159
1160 case CON_WHILEVARN:
1161 {
1162 instype *savedinsptr=insptr+2;
1163 int32_t j;
1164 do
1165 {
1166 insptr=savedinsptr;
1167 j = (Gv_GetVar(*(insptr-1)) != *insptr);
1168 VM_DoConditional(j);
1169 }
1170 while (j && !vm.flags);
1171 vm.flags &= ~VMFLAG_BREAK;
1172 continue;
1173 }
1174
1175 case CON_WHILEVARL:
1176 {
1177 instype *savedinsptr=insptr+2;
1178 int32_t j;
1179 do
1180 {
1181 insptr=savedinsptr;
1182 j = (Gv_GetVar(*(insptr-1)) < *insptr);
1183 VM_DoConditional(j);
1184 }
1185 while (j && !vm.flags);
1186 vm.flags &= ~VMFLAG_BREAK;
1187 continue;
1188 }
1189
1190 case CON_WHILEVARVARN:
1191 {
1192 int32_t j;
1193 instype *savedinsptr=insptr+2;
1194 do
1195 {
1196 insptr=savedinsptr;
1197 j = Gv_GetVar(*(insptr-1));
1198 j = (j != Gv_GetVar(*insptr++));
1199 insptr--;
1200 VM_DoConditional(j);
1201 }
1202 while (j && !vm.flags);
1203 vm.flags &= ~VMFLAG_BREAK;
1204 continue;
1205 }
1206
1207 case CON_WHILEVARVARL:
1208 {
1209 int32_t j;
1210 instype *savedinsptr=insptr+2;
1211 do
1212 {
1213 insptr=savedinsptr;
1214 j = Gv_GetVar(*(insptr-1));
1215 j = (j < Gv_GetVar(*insptr++));
1216 insptr--;
1217 VM_DoConditional(j);
1218 }
1219 while (j && !vm.flags);
1220 vm.flags &= ~VMFLAG_BREAK;
1221 continue;
1222 }
1223
1224 case CON_COLLECTSECTORS:
1225 insptr++;
1226 {
1227 const int32_t aridx=*insptr++, startsectnum=Gv_GetVar(*insptr++);
1228 const int32_t numsectsVar=*insptr++, state=*insptr++;
1229
1230 if (CheckArray(aridx))
1231 continue;
1232
1233 gamearray_t *const gar = &aGameArrays[aridx];
1234 Bassert((gar->dwFlags & (GAMEARRAY_READONLY|GAMEARRAY_VARSIZE)) == 0);
1235
1236 const int32_t o_g_st=vm.g_st, arsize = gar->size;
1237 instype *const end=insptr;
1238 int16_t sectcnt, numsects=0;
1239
1240 // XXX: relies on -fno-strict-aliasing
1241 int16_t *const sectlist = (int16_t *)gar->vals; // actually an int32_t array
1242 int32_t *const sectlist32 = (int32_t *)sectlist;
1243
1244 int32_t j, startwall, endwall, ns;
1245 static uint8_t sectbitmap[(MAXSECTORS+7)>>3];
1246
1247 X_ERROR_INVALIDSECT(startsectnum);
1248 if (arsize < numsectors)
1249 {
1250 M32_ERROR("Array size must be at least numsectors (=%d) for collecting!",
1251 numsectors);
1252 continue;
1253 }
1254
1255 // collect!
1256 bfirst_search_init(sectlist, sectbitmap, &numsects, MAXSECTORS, startsectnum);
1257
1258 for (sectcnt=0; sectcnt<numsects; sectcnt++)
1259 for (WALLS_OF_SECTOR(sectlist[sectcnt], j))
1260 if ((ns=wall[j].nextsector) >= 0 && wall[j].nextsector<numsectors)
1261 {
1262 if (sectbitmap[ns>>3]&pow2char[ns&7])
1263 continue;
1264 vm.g_st = 1+MAXEVENTS+state;
1265 insptr = apScript + statesinfo[state].ofs;
1266 g_iReturnVar = ns;
1267 VM_Execute(0);
1268 if (g_iReturnVar)
1269 bfirst_search_try(sectlist, sectbitmap, &numsects, wall[j].nextsector);
1270 }
1271
1272 // short->int sector list
1273 for (j=numsects-1; j>=0; j--)
1274 sectlist32[j] = sectlist[j];
1275
1276 Gv_SetVar(numsectsVar, numsects);
1277 g_iReturnVar = 0;
1278
1279 // restore some VM state
1280 vm.g_st = o_g_st;
1281 insptr = end;
1282 }
1283 continue;
1284
1285 case CON_SORT:
1286 insptr++;
1287 {
1288 const int32_t aridx=*insptr++, count=Gv_GetVar(*insptr++), state=*insptr++;
1289 const int32_t o_g_st = vm.g_st;
1290 instype *const end = insptr;
1291
1292 if (CheckArray(aridx))
1293 continue;
1294
1295 if (count <= 0)
1296 continue;
1297
1298 gamearray_t *const gar = &aGameArrays[aridx];
1299 Bassert((gar->dwFlags & (GAMEARRAY_READONLY|GAMEARRAY_VARSIZE)) == 0);
1300
1301 if (count > gar->size)
1302 {
1303 M32_ERROR("Count of elements to sort (%d) exceeds array size (%d)!",
1304 count, gar->size);
1305 continue;
1306 }
1307
1308 if (state < 0)
1309 {
1310 qsort(gar->vals, count, sizeof(int32_t), X_DoSortDefault);
1311 }
1312 else
1313 {
1314 x_sortingstateptr = apScript + statesinfo[state].ofs;
1315 vm.g_st = 1+MAXEVENTS+state;
1316 qsort(gar->vals, count, sizeof(int32_t), X_DoSort);
1317 vm.g_st = o_g_st;
1318 insptr = end;
1319 }
1320 }
1321 continue;
1322
1323 case CON_FOR: // special-purpose iteration
1324 insptr++;
1325 {
1326 const int32_t var = *insptr++, how = *insptr++;
1327 const int32_t parm2 = how<=ITER_DRAWNSPRITES ? 0 : Gv_GetVar(*insptr++);
1328 instype *const end = insptr + *insptr, *const beg = ++insptr;
1329 const int32_t vm_i_bak = vm.spriteNum;
1330 auto const vm_sp_bak = vm.pUSprite;
1331
1332 if (vm.flags&VMFLAG_ERROR)
1333 continue;
1334
1335 switch (how)
1336 {
1337 case ITER_ALLSPRITES:
1338 for (bssize_t jj=0; jj<MAXSPRITES && !vm.flags; jj++)
1339 {
1340 if (sprite[jj].statnum == MAXSTATUS)
1341 continue;
1342 Gv_SetVar(var, jj);
1343 vm.spriteNum = jj;
1344 vm.pSprite = &sprite[jj];
1345 insptr = beg;
1346 VM_Execute(1);
1347 }
1348 break;
1349 case ITER_ALLSECTORS:
1350 for (bssize_t jj=0; jj<numsectors && !vm.flags; jj++)
1351 {
1352 Gv_SetVar(var, jj);
1353 insptr = beg;
1354 VM_Execute(1);
1355 }
1356 break;
1357 case ITER_ALLWALLS:
1358 for (bssize_t jj=0; jj<numwalls && !vm.flags; jj++)
1359 {
1360 Gv_SetVar(var, jj);
1361 insptr = beg;
1362 VM_Execute(1);
1363 }
1364 break;
1365 case ITER_ACTIVELIGHTS:
1366 #ifdef POLYMER
1367 for (bssize_t jj=0; jj<PR_MAXLIGHTS; jj++)
1368 {
1369 if (!prlights[jj].flags.active)
1370 continue;
1371
1372 Gv_SetVar(var, jj);
1373 insptr = beg;
1374 VM_Execute(1);
1375 }
1376 #else
1377 M32_ERROR("Polymer not compiled in, iteration over lights forbidden.");
1378 #endif
1379 break;
1380
1381 case ITER_SELSPRITES:
1382 for (bssize_t ii=0; ii<highlightcnt && !vm.flags; ii++)
1383 {
1384 int jj = highlight[ii];
1385 if (jj&0xc000)
1386 {
1387 jj &= (MAXSPRITES-1);
1388 Gv_SetVar(var, jj);
1389 vm.spriteNum = jj;
1390 vm.pSprite = &sprite[jj];
1391 insptr = beg;
1392 VM_Execute(1);
1393 }
1394 }
1395 break;
1396 case ITER_SELSECTORS:
1397 for (bssize_t ii=0; ii<highlightsectorcnt && !vm.flags; ii++)
1398 {
1399 int jj=highlightsector[ii];
1400 Gv_SetVar(var, jj);
1401 insptr = beg;
1402 VM_Execute(1);
1403 }
1404 break;
1405 case ITER_SELWALLS:
1406 for (bssize_t ii=0; ii<highlightcnt && !vm.flags; ii++)
1407 {
1408 int jj=highlight[ii];
1409 if (jj&0xc000)
1410 continue;
1411 Gv_SetVar(var, jj);
1412 insptr = beg;
1413 VM_Execute(1);
1414 }
1415 break;
1416 case ITER_DRAWNSPRITES:
1417 {
1418 uspritetype lastSpriteBackup;
1419 auto const lastSpritePtr = (uspritetype *)&sprite[MAXSPRITES-1];
1420
1421 // Back up sprite MAXSPRITES-1.
1422 Bmemcpy(&lastSpriteBackup, lastSpritePtr, sizeof(uspritetype));
1423
1424 EDUKE32_STATIC_ASSERT(sizeof(uspritetype) == sizeof(tspritetype)); // see TSPRITE_SIZE
1425 for (bssize_t ii=0; ii<spritesortcnt && !vm.flags; ii++)
1426 {
1427 vm.pUSprite = lastSpritePtr;
1428 Bmemcpy(lastSpritePtr, &tsprite[ii], sizeof(tspritetype));
1429
1430 Gv_SetVar(var, ii);
1431 insptr = beg;
1432 VM_Execute(1);
1433
1434 // Copy over potentially altered tsprite.
1435 Bmemcpy(&tsprite[ii], lastSpritePtr, sizeof(tspritetype));
1436 }
1437
1438 // Restore sprite MAXSPRITES-1.
1439 Bmemcpy(lastSpritePtr, &lastSpriteBackup, sizeof(uspritetype));
1440 break;
1441 }
1442 case ITER_SPRITESOFSECTOR:
1443 if (parm2 < 0 || parm2 >= MAXSECTORS)
1444 goto badindex;
1445 for (bssize_t jj=headspritesect[parm2]; jj>=0 && !vm.flags; jj=nextspritesect[jj])
1446 {
1447 Gv_SetVar(var, jj);
1448 vm.spriteNum = jj;
1449 vm.pSprite = &sprite[jj];
1450 insptr = beg;
1451 VM_Execute(1);
1452 }
1453 break;
1454 case ITER_WALLSOFSECTOR:
1455 if (parm2 < 0 || parm2 >= MAXSECTORS)
1456 goto badindex;
1457 for (bssize_t jj=sector[parm2].wallptr, endwall=jj+sector[parm2].wallnum-1;
1458 jj<=endwall && !vm.flags; jj++)
1459 {
1460 Gv_SetVar(var, jj);
1461 insptr = beg;
1462 VM_Execute(1);
1463 }
1464 break;
1465 case ITER_LOOPOFWALL:
1466 if (parm2 < 0 || parm2 >= numwalls)
1467 goto badindex;
1468 {
1469 int jj = parm2;
1470 do
1471 {
1472 Gv_SetVar(var, jj);
1473 insptr = beg;
1474 VM_Execute(1);
1475 jj = wall[jj].point2;
1476 }
1477 while (jj != parm2 && !vm.flags);
1478 }
1479 break;
1480 case ITER_RANGE:
1481 for (bssize_t jj=0; jj<parm2 && !vm.flags; jj++)
1482 {
1483 Gv_SetVar(var, jj);
1484 insptr = beg;
1485 VM_Execute(1);
1486 }
1487 break;
1488 default:
1489 M32_ERROR("Unknown iteration type %d!", how);
1490 continue;
1491 badindex:
1492 OSD_Printf("%sLine %d, %s %s: index %d out of range!\n", osd->draw.highlight,
1493 g_errorLineNum,keyw[g_tw], iter_tokens[how].token, parm2);
1494 vm.flags |= VMFLAG_ERROR;
1495 continue;
1496 }
1497 vm.spriteNum = vm_i_bak;
1498 vm.pUSprite = vm_sp_bak;
1499 vm.flags &= ~VMFLAG_BREAK;
1500 insptr = end;
1501 }
1502 continue;
1503
1504 case CON_IFVARAND:
1505 insptr++;
1506 {
1507 int32_t j=Gv_GetVar(*insptr++);
1508 VM_DoConditional(j & *insptr);
1509 }
1510 continue;
1511
1512 case CON_IFVAROR:
1513 insptr++;
1514 {
1515 int32_t j=Gv_GetVar(*insptr++);
1516 VM_DoConditional(j | *insptr);
1517 }
1518 continue;
1519
1520 case CON_IFVARXOR:
1521 insptr++;
1522 {
1523 int32_t j=Gv_GetVar(*insptr++);
1524 VM_DoConditional(j ^ *insptr);
1525 }
1526 continue;
1527
1528 case CON_IFVAREITHER:
1529 insptr++;
1530 {
1531 int32_t j=Gv_GetVar(*insptr++);
1532 VM_DoConditional(j || *insptr);
1533 }
1534 continue;
1535
1536 case CON_IFVARBOTH:
1537 insptr++;
1538 {
1539 int32_t j=Gv_GetVar(*insptr++);
1540 VM_DoConditional(j && *insptr);
1541 }
1542 continue;
1543
1544 case CON_IFVARG:
1545 insptr++;
1546 {
1547 int32_t j=Gv_GetVar(*insptr++);
1548 VM_DoConditional(j > *insptr);
1549 }
1550 continue;
1551
1552 case CON_IFVARGE:
1553 insptr++;
1554 {
1555 int32_t j=Gv_GetVar(*insptr++);
1556 VM_DoConditional(j >= *insptr);
1557 }
1558 continue;
1559
1560 case CON_IFVARL:
1561 insptr++;
1562 {
1563 int32_t j=Gv_GetVar(*insptr++);
1564 VM_DoConditional(j < *insptr);
1565 }
1566 continue;
1567
1568 case CON_IFVARLE:
1569 insptr++;
1570 {
1571 int32_t j=Gv_GetVar(*insptr++);
1572 VM_DoConditional(j <= *insptr);
1573 }
1574 continue;
1575
1576 case CON_IFVARA:
1577 insptr++;
1578 {
1579 int32_t j=Gv_GetVar(*insptr++);
1580 VM_DoConditional((uint32_t)j > (uint32_t)*insptr);
1581 }
1582 continue;
1583
1584 case CON_IFVARAE:
1585 insptr++;
1586 {
1587 int32_t j=Gv_GetVar(*insptr++);
1588 VM_DoConditional((uint32_t)j >= (uint32_t)*insptr);
1589 }
1590 continue;
1591
1592 case CON_IFVARB:
1593 insptr++;
1594 {
1595 int32_t j=Gv_GetVar(*insptr++);
1596 VM_DoConditional((uint32_t)j < (uint32_t)*insptr);
1597 }
1598 continue;
1599
1600 case CON_IFVARBE:
1601 insptr++;
1602 {
1603 int32_t j=Gv_GetVar(*insptr++);
1604 VM_DoConditional((uint32_t)j <= (uint32_t)*insptr);
1605 }
1606 continue;
1607
1608 case CON_IFRND:
1609 VM_DoConditional(rnd(Gv_GetVar(*(++insptr))));
1610 continue;
1611
1612 case CON_IFHITKEY:
1613 case CON_IFHOLDKEY:
1614 case CON_RESETKEY:
1615 case CON_SETKEY:
1616 insptr++;
1617 {
1618 int32_t key=Gv_GetVar(*insptr);
1619 if (key<0 || key >= (int32_t)ARRAY_SIZE(keystatus))
1620 {
1621 M32_ERROR("Invalid key %d!", key);
1622 continue;
1623 }
1624
1625 if (tw == CON_IFHITKEY || tw == CON_IFHOLDKEY)
1626 VM_DoConditional(keystatus[key]);
1627 else
1628 insptr++;
1629
1630 if (tw != CON_IFHOLDKEY)
1631 {
1632 if (!(key==0 || key==KEYSC_ESC || key==KEYSC_TILDE || key==KEYSC_gENTER ||
1633 key==KEYSC_LALT || key==KEYSC_RALT || key==KEYSC_LCTRL || key==KEYSC_RCTRL ||
1634 key==KEYSC_LSHIFT || key==KEYSC_RSHIFT))
1635 keystatus[key] = (tw==CON_SETKEY);
1636 }
1637 }
1638 continue;
1639
1640 case CON_IFEITHERALT:
1641 VM_DoConditional(keystatus[KEYSC_LALT]||keystatus[KEYSC_RALT]);
1642 continue;
1643
1644 case CON_IFEITHERCTRL:
1645 VM_DoConditional(keystatus[KEYSC_LCTRL]||keystatus[KEYSC_RCTRL]);
1646 continue;
1647
1648 case CON_IFEITHERSHIFT:
1649 VM_DoConditional(keystatus[KEYSC_LSHIFT]||keystatus[KEYSC_RSHIFT]);
1650 continue;
1651
1652 // vvv CURSPR
1653 case CON_IFSPRITEPAL:
1654 insptr++;
1655 X_ERROR_INVALIDSP();
1656 VM_DoConditional(vm.pSprite->pal == Gv_GetVar(*insptr));
1657 continue;
1658
1659 case CON_IFHIGHLIGHTED:
1660 insptr++;
1661 {
1662 int32_t id=*insptr++, index=Gv_GetVar(*insptr);
1663
1664 if (index<0 || (id==M32_SPRITE_VAR_ID && index>=MAXSPRITES) || (id==M32_WALL_VAR_ID && index>=numwalls))
1665 {
1666 M32_ERROR("%s index %d out of range!", id==M32_SPRITE_VAR_ID?"Sprite":"Wall", index);
1667 continue;
1668 }
1669
1670 if (id==M32_SPRITE_VAR_ID)
1671 VM_DoConditional(show2dsprite[index>>3]&pow2char[index&7]);
1672 else
1673 VM_DoConditional(show2dwall[index>>3]&pow2char[index&7]);
1674 }
1675 continue;
1676
1677 case CON_IFANGDIFFL:
1678 insptr++;
1679 {
1680 int32_t j;
1681 X_ERROR_INVALIDSP();
1682 j = klabs(G_GetAngleDelta(ang, vm.pSprite->ang));
1683 VM_DoConditional(j <= Gv_GetVar(*insptr));
1684 }
1685 continue;
1686
1687 case CON_IFAWAYFROMWALL:
1688 {
1689 int16_t s1;
1690 int32_t j = 0;
1691
1692 X_ERROR_INVALIDSP();
1693 s1 = vm.pSprite->sectnum;
1694 updatesector(vm.pSprite->x+108,vm.pSprite->y+108,&s1);
1695 if (s1 == vm.pSprite->sectnum)
1696 {
1697 updatesector(vm.pSprite->x-108,vm.pSprite->y-108,&s1);
1698 if (s1 == vm.pSprite->sectnum)
1699 {
1700 updatesector(vm.pSprite->x+108,vm.pSprite->y-108,&s1);
1701 if (s1 == vm.pSprite->sectnum)
1702 {
1703 updatesector(vm.pSprite->x-108,vm.pSprite->y+108,&s1);
1704 if (s1 == vm.pSprite->sectnum)
1705 j = 1;
1706 }
1707 }
1708 }
1709 VM_DoConditional(j);
1710 }
1711 continue;
1712
1713 case CON_IFCANSEE:
1714 {
1715 int32_t j;
1716
1717 X_ERROR_INVALIDSP();
1718 j = cansee(vm.pSprite->x,vm.pSprite->y,vm.pSprite->z/*-((krand()&41)<<8)*/,vm.pSprite->sectnum,
1719 pos.x, pos.y, pos.z /*-((krand()&41)<<8)*/, cursectnum);
1720 VM_DoConditional(j);
1721 }
1722 continue;
1723
1724 case CON_IFONWATER:
1725 X_ERROR_INVALIDSP();
1726 VM_DoConditional(sector[vm.pSprite->sectnum].lotag == 1 && klabs(vm.pSprite->z-sector[vm.pSprite->sectnum].floorz) < (32<<8));
1727 continue;
1728
1729 case CON_IFINWATER:
1730 X_ERROR_INVALIDSP();
1731 VM_DoConditional(sector[vm.pSprite->sectnum].lotag == 2);
1732 continue;
1733
1734 case CON_IFACTOR:
1735 insptr++;
1736 X_ERROR_INVALIDSP();
1737 VM_DoConditional(vm.pSprite->picnum == Gv_GetVar(*insptr));
1738 continue;
1739
1740 case CON_IFINSIDE:
1741 insptr++;
1742 {
1743 int32_t x=Gv_GetVar(*insptr++), y=Gv_GetVar(*insptr++), sectnum=Gv_GetVar(*insptr++), res;
1744
1745 res = inside(x, y, sectnum);
1746 if (res == -1)
1747 {
1748 M32_ERROR("Sector index %d out of range!", sectnum);
1749 continue;
1750 }
1751 insptr--;
1752 VM_DoConditional(res);
1753 }
1754 continue;
1755
1756 case CON_IFOUTSIDE:
1757 X_ERROR_INVALIDSP();
1758 VM_DoConditional(sector[vm.pSprite->sectnum].ceilingstat&1);
1759 continue;
1760
1761 case CON_IFPDISTL:
1762 insptr++;
1763 {
1764 X_ERROR_INVALIDSP();
1765 VM_DoConditional(dist((spritetype *)&pos, vm.pSprite) < Gv_GetVar(*insptr));
1766 }
1767 continue;
1768
1769 case CON_IFPDISTG:
1770 insptr++;
1771 {
1772 X_ERROR_INVALIDSP();
1773 VM_DoConditional(dist((spritetype *)&pos, vm.pSprite) > Gv_GetVar(*insptr));
1774 }
1775 continue;
1776 // ^^^
1777
1778 // *** BUILD functions
1779 case CON_INSERTSPRITE:
1780 insptr++;
1781 {
1782 int32_t dasectnum = Gv_GetVar(*insptr++), ret;
1783
1784 X_ERROR_INVALIDSECT(dasectnum);
1785 if (Numsprites >= MAXSPRITES)
1786 {
1787 M32_ERROR("Maximum number of sprites reached.");
1788 continue;
1789 }
1790
1791 ret = insertsprite(dasectnum, 0);
1792 vm.spriteNum = ret;
1793 vm.pSprite = &sprite[ret];
1794 }
1795 continue;
1796
1797 case CON_DUPSPRITE:
1798 case CON_TDUPSPRITE:
1799 insptr++;
1800 {
1801 int32_t ospritenum = Gv_GetVar(*insptr++), nspritenum;
1802
1803 if (ospritenum<0 || ospritenum>=MAXSPRITES || sprite[ospritenum].statnum==MAXSTATUS)
1804 {
1805 M32_ERROR("Tried to duplicate nonexistent sprite %d", ospritenum);
1806 }
1807 if ((tw==CON_DUPSPRITE && Numsprites >= MAXSPRITES) ||
1808 (tw==CON_DUPSPRITE && spritesortcnt >= maxspritesonscreen))
1809 {
1810 M32_ERROR("Maximum number of sprites reached.");
1811 }
1812
1813 if (vm.flags&VMFLAG_ERROR)
1814 continue;
1815
1816 if (tw==CON_DUPSPRITE)
1817 {
1818 nspritenum = insertsprite(sprite[ospritenum].sectnum, sprite[ospritenum].statnum);
1819
1820 if (nspritenum < 0)
1821 {
1822 M32_ERROR("Internal error.");
1823 continue;
1824 }
1825
1826 Bmemcpy(&sprite[nspritenum], &sprite[ospritenum], sizeof(spritetype));
1827 vm.spriteNum = nspritenum;
1828 vm.pSprite = &sprite[nspritenum];
1829 }
1830 else
1831 {
1832 tspriteptr_t tsp = renderAddTSpriteFromSprite(ospritenum);
1833 vm.spriteNum = -1;
1834 EDUKE32_STATIC_ASSERT(sizeof(uspritetype) == sizeof(tspritetype)); // see TSPRITE_SIZE
1835 vm.pUSprite = (uspriteptr_t)tsp;
1836 }
1837 }
1838 continue;
1839
1840 case CON_DELETESPRITE:
1841 insptr++;
1842 {
1843 int32_t daspritenum = Gv_GetVar(*insptr++), ret;
1844
1845 X_ERROR_INVALIDSPRI(daspritenum);
1846 ret = deletesprite(daspritenum);
1847 g_iReturnVar = ret;
1848 }
1849 continue;
1850
1851 case CON_GETSPRITELINKTYPE:
1852 insptr++;
1853 {
1854 int32_t spritenum=Gv_GetVar(*insptr++), resvar = *insptr++;
1855
1856 X_ERROR_INVALIDSPRI(spritenum);
1857 Gv_SetVar(resvar, taglab_linktags(1, spritenum));
1858 }
1859 continue;
1860
1861 case CON_LASTWALL:
1862 insptr++;
1863 {
1864 int32_t dapoint = Gv_GetVar(*insptr++), resvar=*insptr++;
1865
1866 if (dapoint<0 || dapoint>=numwalls)
1867 {
1868 M32_ERROR("Invalid wall %d", dapoint);
1869 continue;
1870 }
1871
1872 Gv_SetVar(resvar, lastwall(dapoint));
1873 }
1874 continue;
1875
1876 case CON_GETZRANGE:
1877 insptr++;
1878 {
1879 vec3_t vect;
1880
1881 vect.x = Gv_GetVar(*insptr++);
1882 vect.y = Gv_GetVar(*insptr++);
1883 vect.z = Gv_GetVar(*insptr++);
1884
1885 {
1886 int32_t sectnum=Gv_GetVar(*insptr++);
1887 int32_t ceilzvar=*insptr++, ceilhitvar=*insptr++, florzvar=*insptr++, florhitvar=*insptr++;
1888 int32_t walldist=Gv_GetVar(*insptr++), clipmask=Gv_GetVar(*insptr++);
1889 int32_t ceilz, ceilhit, florz, florhit;
1890
1891 X_ERROR_INVALIDSECT(sectnum);
1892 getzrange(&vect, sectnum, &ceilz, &ceilhit, &florz, &florhit, walldist, clipmask);
1893 Gv_SetVar(ceilzvar, ceilz);
1894 Gv_SetVar(ceilhitvar, ceilhit);
1895 Gv_SetVar(florzvar, florz);
1896 Gv_SetVar(florhitvar, florhit);
1897 }
1898 continue;
1899 }
1900
1901 case CON_CALCHYPOTENUSE:
1902 insptr++;
1903 {
1904 int32_t retvar=*insptr++;
1905 int64_t dax=Gv_GetVar(*insptr++), day=Gv_GetVar(*insptr++);
1906 int64_t hypsq = dax*dax + day*day;
1907
1908 if (hypsq > (int64_t)INT32_MAX)
1909 Gv_SetVar(retvar, (int32_t)sqrt((double)hypsq));
1910 else
1911 Gv_SetVar(retvar, ksqrt((uint32_t)hypsq));
1912
1913 continue;
1914 }
1915
1916 case CON_LINEINTERSECT:
1917 case CON_RAYINTERSECT:
1918 insptr++;
1919 {
1920 int32_t x1=Gv_GetVar(*insptr++), y1=Gv_GetVar(*insptr++), z1=Gv_GetVar(*insptr++);
1921 int32_t x2=Gv_GetVar(*insptr++), y2=Gv_GetVar(*insptr++), z2=Gv_GetVar(*insptr++);
1922 int32_t x3=Gv_GetVar(*insptr++), y3=Gv_GetVar(*insptr++), x4=Gv_GetVar(*insptr++), y4=Gv_GetVar(*insptr++);
1923 int32_t intxvar=*insptr++, intyvar=*insptr++, intzvar=*insptr++, retvar=*insptr++;
1924 int32_t intx, inty, intz, ret;
1925
1926 if (tw==CON_LINEINTERSECT)
1927 ret = lintersect(x1, y1, z1, x2, y2, z2, x3, y3, x4, y4, &intx, &inty, &intz);
1928 else
1929 ret = rayintersect(x1, y1, z1, x2, y2, z2, x3, y3, x4, y4, &intx, &inty, &intz);
1930
1931 Gv_SetVar(retvar, ret);
1932 if (ret)
1933 {
1934 Gv_SetVar(intxvar, intx);
1935 Gv_SetVar(intyvar, inty);
1936 Gv_SetVar(intzvar, intz);
1937 }
1938
1939 continue;
1940 }
1941
1942 case CON_CLIPMOVE:
1943 insptr++;
1944 {
1945 vec3_t vect;
1946 int32_t retvar=*insptr++, xvar=*insptr++, yvar=*insptr++, z=Gv_GetVar(*insptr++), sectnumvar=*insptr++;
1947 int32_t xvect=Gv_GetVar(*insptr++), yvect=Gv_GetVar(*insptr++);
1948 int32_t walldist=Gv_GetVar(*insptr++), floordist=Gv_GetVar(*insptr++), ceildist=Gv_GetVar(*insptr++);
1949 int32_t clipmask=Gv_GetVar(*insptr++);
1950 int16_t sectnum;
1951
1952 vect.x = Gv_GetVar(xvar);
1953 vect.y = Gv_GetVar(yvar);
1954 vect.z = z;
1955 sectnum = Gv_GetVar(sectnumvar);
1956
1957 X_ERROR_INVALIDSECT(sectnum);
1958
1959 Gv_SetVar(retvar, clipmove(&vect, §num, xvect, yvect, walldist, floordist, ceildist, clipmask));
1960 Gv_SetVar(sectnumvar, sectnum);
1961 Gv_SetVar(xvar, vect.x);
1962 Gv_SetVar(yvar, vect.y);
1963
1964 continue;
1965 }
1966
1967 case CON_HITSCAN:
1968 insptr++;
1969 {
1970 vec3_t vect;
1971 hitdata_t hit;
1972
1973 vect.x = Gv_GetVar(*insptr++);
1974 vect.y = Gv_GetVar(*insptr++);
1975 vect.z = Gv_GetVar(*insptr++);
1976
1977 {
1978 int32_t sectnum=Gv_GetVar(*insptr++);
1979 int32_t vx=Gv_GetVar(*insptr++), vy=Gv_GetVar(*insptr++), vz=Gv_GetVar(*insptr++);
1980 int32_t hitsectvar=*insptr++, hitwallvar=*insptr++, hitspritevar=*insptr++;
1981 int32_t hitxvar=*insptr++, hityvar=*insptr++, hitzvar=*insptr++, cliptype=Gv_GetVar(*insptr++);
1982
1983 X_ERROR_INVALIDSECT(sectnum);
1984 hitscan((const vec3_t *)&vect, sectnum, vx, vy, vz, &hit, cliptype);
1985 Gv_SetVar(hitsectvar, hit.sect);
1986 Gv_SetVar(hitwallvar, hit.wall);
1987 Gv_SetVar(hitspritevar, hit.sprite);
1988 Gv_SetVar(hitxvar, hit.pos.x);
1989 Gv_SetVar(hityvar, hit.pos.y);
1990 Gv_SetVar(hitzvar, hit.pos.z);
1991 }
1992 continue;
1993 }
1994
1995 case CON_CANSEE:
1996 insptr++;
1997 {
1998 int32_t x1=Gv_GetVar(*insptr++), y1=Gv_GetVar(*insptr++), z1=Gv_GetVar(*insptr++);
1999 int32_t sect1=Gv_GetVar(*insptr++);
2000 int32_t x2=Gv_GetVar(*insptr++), y2=Gv_GetVar(*insptr++), z2=Gv_GetVar(*insptr++);
2001 int32_t sect2=Gv_GetVar(*insptr++), rvar=*insptr++;
2002
2003 X_ERROR_INVALIDSECT(sect1);
2004 X_ERROR_INVALIDSECT(sect2);
2005
2006 Gv_SetVar(rvar, cansee(x1,y1,z1,sect1,x2,y2,z2,sect2));
2007 continue;
2008 }
2009
2010 case CON_ROTATEPOINT:
2011 insptr++;
2012 {
2013 vec2_t pivot = { Gv_GetVar(*insptr), Gv_GetVar(*(insptr+1)) };
2014 vec2_t p = { Gv_GetVar(*(insptr+2)), Gv_GetVar(*(insptr+3)) };
2015 insptr += 4;
2016 int32_t daang=Gv_GetVar(*insptr++);
2017 int32_t x2var=*insptr++, y2var=*insptr++;
2018 vec2_t p2;
2019
2020 rotatepoint(pivot,p,daang,&p2);
2021 Gv_SetVar(x2var, p2.x);
2022 Gv_SetVar(y2var, p2.y);
2023 continue;
2024 }
2025
2026 case CON_NEARTAG:
2027 insptr++;
2028 {
2029 // neartag(int32_t x, int32_t y, int32_t z, short sectnum, short ang, //Starting position & angle
2030 // short *neartagsector, //Returns near sector if sector[].tag != 0
2031 // short *neartagwall, //Returns near wall if wall[].tag != 0
2032 // short *neartagsprite, //Returns near sprite if sprite[].tag != 0
2033 // int32_t *neartaghitdist, //Returns actual distance to object (scale: 1024=largest grid size)
2034 // int32_t neartagrange, //Choose maximum distance to scan (scale: 1024=largest grid size)
2035 // char tagsearch) //1-lotag only, 2-hitag only, 3-lotag&hitag
2036
2037 int32_t x=Gv_GetVar(*insptr++), y=Gv_GetVar(*insptr++), z=Gv_GetVar(*insptr++);
2038 int32_t sectnum=Gv_GetVar(*insptr++), ang=Gv_GetVar(*insptr++);
2039 int32_t neartagsectorvar=*insptr++, neartagwallvar=*insptr++, neartagspritevar=*insptr++, neartaghitdistvar=*insptr++;
2040 int32_t neartagrange=Gv_GetVar(*insptr++), tagsearch=Gv_GetVar(*insptr++);
2041
2042 int16_t neartagsector, neartagwall, neartagsprite;
2043 int32_t neartaghitdist;
2044
2045 X_ERROR_INVALIDSECT(sectnum);
2046 neartag(x, y, z, sectnum, ang, &neartagsector, &neartagwall, &neartagsprite,
2047 &neartaghitdist, neartagrange, tagsearch, NULL);
2048
2049 Gv_SetVar(neartagsectorvar, neartagsector);
2050 Gv_SetVar(neartagwallvar, neartagwall);
2051 Gv_SetVar(neartagspritevar, neartagsprite);
2052 Gv_SetVar(neartaghitdistvar, neartaghitdist);
2053 continue;
2054 }
2055
2056 case CON_BSETSPRITE: // was CON_SETSPRITE
2057 insptr++;
2058 {
2059 int32_t spritenum = Gv_GetVar(*insptr++);
2060 vec3_t davector;
2061
2062 davector.x = Gv_GetVar(*insptr++);
2063 davector.y = Gv_GetVar(*insptr++);
2064 davector.z = Gv_GetVar(*insptr++);
2065
2066 X_ERROR_INVALIDSPRI(spritenum);
2067 setsprite(spritenum, &davector);
2068 continue;
2069 }
2070
2071 case CON_GETFLORZOFSLOPE:
2072 case CON_GETCEILZOFSLOPE:
2073 insptr++;
2074 {
2075 int32_t sectnum = Gv_GetVar(*insptr++), x = Gv_GetVar(*insptr++), y = Gv_GetVar(*insptr++);
2076 int32_t var=*insptr++;
2077
2078 X_ERROR_INVALIDSECT(sectnum);
2079 if (tw == CON_GETFLORZOFSLOPE)
2080 Gv_SetVar(var, getflorzofslope(sectnum,x,y));
2081 else
2082 Gv_SetVar(var, getceilzofslope(sectnum,x,y));
2083 continue;
2084 }
2085
2086 case CON_ALIGNFLORSLOPE:
2087 case CON_ALIGNCEILSLOPE:
2088 insptr++;
2089 {
2090 int32_t sectnum = Gv_GetVar(*insptr++), x = Gv_GetVar(*insptr++), y = Gv_GetVar(*insptr++);
2091 int32_t z=Gv_GetVar(*insptr++);
2092
2093 X_ERROR_INVALIDSECT(sectnum);
2094 if (tw == CON_ALIGNFLORSLOPE)
2095 alignflorslope(sectnum, x,y,z);
2096 else
2097 alignceilslope(sectnum, x,y,z);
2098 continue;
2099 }
2100
2101 // CURSPR
2102 case CON_SETFIRSTWALL:
2103 insptr++;
2104 {
2105 int32_t sect=Gv_GetVar(*insptr++), wal=Gv_GetVar(*insptr++);
2106
2107 X_ERROR_INVALIDSECT(sect);
2108 setfirstwall(sect, wal);
2109 }
2110 continue;
2111
2112 case CON_UPDATECURSECTNUM:
2113 insptr++;
2114 updatesectorz(pos.x, pos.y, pos.z, &cursectnum);
2115 continue;
2116
2117 case CON_UPDATESECTOR:
2118 case CON_UPDATESECTORZ:
2119 case CON_UPDATESECTORNEIGHBOR:
2120 case CON_UPDATESECTORNEIGHBORZ:
2121 insptr++;
2122 {
2123 int32_t x=Gv_GetVar(*insptr++), y=Gv_GetVar(*insptr++);
2124 int32_t z=(tw==CON_UPDATESECTORZ || tw==CON_UPDATESECTORNEIGHBORZ)?Gv_GetVar(*insptr++):0;
2125 int32_t var=*insptr++;
2126 int16_t w;
2127
2128 X_ERROR_INVALIDCI();
2129 w=sprite[vm.spriteNum].sectnum;
2130
2131 switch (tw)
2132 {
2133 case CON_UPDATESECTORNEIGHBORZ:
2134 updatesectorneighborz(x,y,z,&w,getsectordist({x, y}, w));
2135 continue;
2136 case CON_UPDATESECTORZ:
2137 updatesectorz(x,y,z,&w);
2138 continue;
2139 case CON_UPDATESECTORNEIGHBOR:
2140 updatesectorneighbor(x,y,&w,getsectordist({x, y}, w));
2141 continue;
2142 default:
2143 updatesector(x,y,&w);
2144 continue;
2145 }
2146
2147 Gv_SetVar(var, w);
2148 continue;
2149 }
2150
2151 case CON_HEADSPRITESTAT:
2152 insptr++;
2153 {
2154 int32_t i=*insptr++;
2155 int32_t j=Gv_GetVar(*insptr++);
2156 if (j < 0 || j > MAXSTATUS)
2157 {
2158 M32_ERROR("invalid status list %d", j);
2159 continue;
2160 }
2161 Gv_SetVar(i,headspritestat[j]);
2162 continue;
2163 }
2164
2165 case CON_PREVSPRITESTAT:
2166 insptr++;
2167 {
2168 int32_t i=*insptr++;
2169 int32_t j=Gv_GetVar(*insptr++);
2170
2171 X_ERROR_INVALIDSPRI(j);
2172 Gv_SetVar(i,prevspritestat[j]);
2173 continue;
2174 }
2175
2176 case CON_NEXTSPRITESTAT:
2177 insptr++;
2178 {
2179 int32_t i=*insptr++;
2180 int32_t j=Gv_GetVar(*insptr++);
2181
2182 X_ERROR_INVALIDSPRI(j);
2183 Gv_SetVar(i,nextspritestat[j]);
2184 continue;
2185 }
2186
2187 case CON_HEADSPRITESECT:
2188 insptr++;
2189 {
2190 int32_t i=*insptr++;
2191 int32_t j=Gv_GetVar(*insptr++);
2192
2193 X_ERROR_INVALIDSECT(j);
2194 Gv_SetVar(i,headspritesect[j]);
2195 continue;
2196 }
2197
2198 case CON_PREVSPRITESECT:
2199 insptr++;
2200 {
2201 int32_t i=*insptr++;
2202 int32_t j=Gv_GetVar(*insptr++);
2203
2204 X_ERROR_INVALIDSPRI(j);
2205 Gv_SetVar(i,prevspritesect[j]);
2206 continue;
2207 }
2208
2209 case CON_NEXTSPRITESECT:
2210 insptr++;
2211 {
2212 int32_t i=*insptr++;
2213 int32_t j=Gv_GetVar(*insptr++);
2214
2215 X_ERROR_INVALIDSPRI(j);
2216 Gv_SetVar(i,nextspritesect[j]);
2217 continue;
2218 }
2219
2220 case CON_CANSEESPR:
2221 insptr++;
2222 {
2223 int32_t lVar1 = Gv_GetVar(*insptr++), lVar2 = Gv_GetVar(*insptr++), res;
2224
2225 if (lVar1<0 || lVar1>=MAXSPRITES || sprite[lVar1].statnum==MAXSTATUS)
2226 {
2227 M32_ERROR("Invalid sprite %d", lVar1);
2228 }
2229 if (lVar2<0 || lVar2>=MAXSPRITES || sprite[lVar2].statnum==MAXSTATUS)
2230 {
2231 M32_ERROR("Invalid sprite %d", lVar2);
2232 }
2233
2234 if (vm.flags&VMFLAG_ERROR) res=0;
2235 else res=cansee(sprite[lVar1].x,sprite[lVar1].y,sprite[lVar1].z,sprite[lVar1].sectnum,
2236 sprite[lVar2].x,sprite[lVar2].y,sprite[lVar2].z,sprite[lVar2].sectnum);
2237
2238 Gv_SetVar(*insptr++, res);
2239 continue;
2240 }
2241
2242 case CON_CHANGESPRITESTAT:
2243 case CON_CHANGESPRITESECT:
2244 insptr++;
2245 {
2246 int32_t i = Gv_GetVar(*insptr++);
2247 int32_t j = Gv_GetVar(*insptr++);
2248
2249 X_ERROR_INVALIDSPRI(i);
2250 if (j<0 || j >= (tw==CON_CHANGESPRITESTAT?MAXSTATUS:numsectors))
2251 {
2252 M32_ERROR("Invalid %s: %d", tw==CON_CHANGESPRITESTAT?"statnum":"sector", j);
2253 continue;
2254 }
2255
2256 if (tw == CON_CHANGESPRITESTAT)
2257 {
2258 if (sprite[i].statnum == j) continue;
2259 changespritestat(i,j);
2260 }
2261 else
2262 {
2263 if (sprite[i].sectnum == j) continue;
2264 changespritesect(i,j);
2265 }
2266 continue;
2267 }
2268
2269 case CON_DRAGPOINT:
2270 insptr++;
2271 {
2272 int32_t wallnum = Gv_GetVar(*insptr++), newx = Gv_GetVar(*insptr++), newy = Gv_GetVar(*insptr++);
2273
2274 if (wallnum<0 || wallnum>=numwalls)
2275 {
2276 M32_ERROR("Invalid wall %d", wallnum);
2277 continue;
2278 }
2279 dragpoint(wallnum,newx,newy,0);
2280 continue;
2281 }
2282
2283 case CON_SECTOROFWALL:
2284 insptr++;
2285 {
2286 int32_t j = *insptr++;
2287 Gv_SetVar(j, sectorofwall(Gv_GetVar(*insptr++)));
2288 }
2289 continue;
2290
2291 case CON_FIXREPEATS:
2292 insptr++;
2293 fixrepeats(Gv_GetVar(*insptr++));
2294 continue;
2295
2296 case CON_GETCLOSESTCOL:
2297 insptr++;
2298 {
2299 int32_t r = Gv_GetVar(*insptr++), g = Gv_GetVar(*insptr++), b = Gv_GetVar(*insptr++);
2300 Gv_SetVar(*insptr++, paletteGetClosestColor(r, g, b));
2301 continue;
2302 }
2303
2304 // *** stuff
2305 case CON_UPDATEHIGHLIGHT:
2306 insptr++;
2307 update_highlight();
2308 continue;
2309
2310 case CON_UPDATEHIGHLIGHTSECTOR:
2311 insptr++;
2312 update_highlightsector();
2313 continue;
2314
2315 case CON_SETHIGHLIGHT:
2316 insptr++;
2317 {
2318 int32_t what=Gv_GetVar(*insptr++), index=Gv_GetVar(*insptr++), doset = Gv_GetVar(*insptr++);
2319
2320 if (highlightsectorcnt >= 0)
2321 {
2322 M32_ERROR("sector highlight active or pending, cannot highlight sprites/walls");
2323 continue;
2324 }
2325
2326 if (what&16384)
2327 {
2328 index &= ~16384;
2329 if (index < 0 || index>=MAXSPRITES || sprite[index].statnum==MAXSTATUS)
2330 {
2331 M32_ERROR("Invalid sprite index %d", index);
2332 continue;
2333 }
2334
2335 if (doset)
2336 show2dsprite[index>>3] |= pow2char[index&7];
2337 else
2338 show2dsprite[index>>3] &= ~pow2char[index&7];
2339 }
2340 else
2341 {
2342 if (index < 0 || index>=numwalls)
2343 {
2344 M32_ERROR("Invalid wall index %d", index);
2345 continue;
2346 }
2347
2348 if (doset)
2349 show2dwall[index>>3] |= pow2char[index&7];
2350 else
2351 show2dwall[index>>3] &= ~pow2char[index&7];
2352 }
2353
2354 vm.miscflags |= VMFLAG_MISC_UPDATEHL;
2355
2356 continue;
2357 }
2358
2359 case CON_SETHIGHLIGHTSECTOR:
2360 insptr++;
2361 {
2362 int32_t index=Gv_GetVar(*insptr++), doset = Gv_GetVar(*insptr++);
2363
2364 if (highlightcnt >= 0)
2365 {
2366 M32_ERROR("sprite/wall highlight active or pending, cannot highlight sectors");
2367 continue;
2368 }
2369
2370 X_ERROR_INVALIDSECT(index);
2371
2372 if (doset)
2373 hlsectorbitmap[index>>3] |= pow2char[index&7];
2374 else
2375 hlsectorbitmap[index>>3] &= ~pow2char[index&7];
2376
2377 vm.miscflags |= VMFLAG_MISC_UPDATEHLSECT;
2378
2379 continue;
2380 }
2381
2382 case CON_GETTIMEDATE:
2383 insptr++;
2384 {
2385 int32_t v1=*insptr++,v2=*insptr++,v3=*insptr++,v4=*insptr++,v5=*insptr++,v6=*insptr++,v7=*insptr++,v8=*insptr++;
2386 time_t rawtime;
2387 struct tm *ti;
2388
2389 time(&rawtime);
2390 ti = localtime(&rawtime);
2391 // initprintf("Time&date: %s\n",asctime (ti));
2392
2393 Gv_SetVar(v1, ti->tm_sec);
2394 Gv_SetVar(v2, ti->tm_min);
2395 Gv_SetVar(v3, ti->tm_hour);
2396 Gv_SetVar(v4, ti->tm_mday);
2397 Gv_SetVar(v5, ti->tm_mon);
2398 Gv_SetVar(v6, ti->tm_year+1900);
2399 Gv_SetVar(v7, ti->tm_wday);
2400 Gv_SetVar(v8, ti->tm_yday);
2401 continue;
2402 }
2403
2404 case CON_ADDLOG:
2405 {
2406 insptr++;
2407
2408 OSD_Printf("L=%d\n", g_errorLineNum);
2409 continue;
2410 }
2411
2412 case CON_ADDLOGVAR:
2413 insptr++;
2414 {
2415 char buf[80] = "", buf2[80] = "";
2416 int32_t code = (int32_t)*insptr, val = Gv_GetVar(code);
2417 int32_t negate=code&M32_FLAG_NEGATE;
2418
2419 if (code & (0xFFFFFFFF-(MAXGAMEVARS-1)))
2420 {
2421 if ((code&M32_VARTYPE_MASK)==M32_FLAG_ARRAY || (code&M32_VARTYPE_MASK)==M32_FLAG_STRUCT)
2422 {
2423 if (code&M32_FLAG_CONSTANT)
2424 Bsprintf(buf2, "%d", (code>>16)&0xffff);
2425 else
2426 {
2427 char *label = aGameVars[(code>>16)&(MAXGAMEVARS-1)].szLabel;
2428 Bsprintf(buf2, "%s", label?label:"???");
2429 }
2430 }
2431 else if ((code&M32_VARTYPE_MASK)==M32_FLAG_LOCAL)
2432 Bsprintf(buf2, "%d", code&(MAXGAMEVARS-1));
2433
2434 if ((code&0x0000FFFC) == M32_FLAG_CONSTANT) // addlogvar for a constant.. why not? :P
2435 {
2436 switch (code&3)
2437 {
2438 case 0: Bsprintf(buf, "(immediate constant)"); break;
2439 case 1: Bsprintf(buf, "(indirect constant)"); break;
2440 case 2: Bsprintf(buf, "(label constant)"); break;
2441 default: Bsprintf(buf, "(??? constant)"); break;
2442 }
2443 }
2444 else
2445 {
2446 switch (code&M32_VARTYPE_MASK)
2447 {
2448 case M32_FLAG_ARRAY:
2449 Bsnprintf(buf, sizeof(buf), "%s[%s]", aGameArrays[code&(MAXGAMEARRAYS-1)].szLabel
2450 ? aGameArrays[code&(MAXGAMEARRAYS-1)].szLabel : "???", buf2);
2451 break;
2452 case M32_FLAG_STRUCT:
2453 {
2454 int32_t memberid=(code>>2)&63, lightp = (memberid >= LIGHT_X);
2455 const char *pp1[4] = {"sprite","sector","wall","tsprite"};
2456 memberlabel_t const *pp2[4] = {SpriteLabels, SectorLabels, WallLabels, SpriteLabels};
2457 if (lightp)
2458 {
2459 pp1[3] = "light";
2460 pp2[3] = LightLabels;
2461 memberid -= LIGHT_X;
2462 }
2463
2464 Bsnprintf(buf, sizeof(buf), "%s[%s].%s", pp1[code&3], buf2, pp2[code&3][memberid].name);
2465 }
2466 break;
2467 case M32_FLAG_VAR:
2468 Bstrcpy(buf, "???");
2469 break;
2470 case M32_FLAG_LOCAL:
2471 Bsnprintf(buf, sizeof(buf), ".local[%s]", buf2);
2472 break;
2473 }
2474 }
2475 }
2476 else
2477 {
2478 if (aGameVars[code].dwFlags & GAMEVAR_PERBLOCK)
2479 {
2480 Bsprintf(buf2, "(%s", vm.g_st==0? "top-level) " : vm.g_st<=MAXEVENTS? "event" : "state");
2481 if (vm.g_st >= 1+MAXEVENTS && vm.g_st <1+MAXEVENTS+g_stateCount)
2482 Bsprintf(buf, " `%s') ", statesinfo[vm.g_st-1-MAXEVENTS].name);
2483 else if (vm.g_st > 0)
2484 Bsprintf(buf, " %d) ", vm.g_st-1);
2485 Bstrcat(buf2, buf);
2486 }
2487
2488 Bsnprintf(buf, sizeof(buf), "%s%s", buf2, aGameVars[code].szLabel ? aGameVars[code].szLabel : "???");
2489 }
2490
2491 OSD_Printf("L%d: %s%s=%d\n", g_errorLineNum, negate?"-":"", buf, val);
2492
2493 insptr++;
2494 continue;
2495 }
2496
2497 case CON_DEBUG:
2498 insptr++;
2499 initprintf("%d\n",*insptr++);
2500 continue;
2501
2502 // *** strings
2503 case CON_REDEFINEQUOTE:
2504 insptr++;
2505 {
2506 int32_t q = *insptr++, i = *insptr++;
2507 X_ERROR_INVALIDQUOTE(q, apStrings);
2508 X_ERROR_INVALIDQUOTE(i, apXStrings);
2509 Bstrcpy(apStrings[q],apXStrings[i]);
2510 continue;
2511 }
2512
2513 case CON_GETNUMBER16: /* deprecated */
2514 case CON_GETNUMBER256: /* deprecated */
2515 case CON_GETNUMBERFROMUSER:
2516 insptr++;
2517 {
2518 int32_t var=*insptr++, quote=*insptr++;
2519 const char *quotetext = GetMaybeInlineQuote(quote);
2520 if (vm.flags&VMFLAG_ERROR)
2521 continue;
2522
2523 {
2524 int32_t max=Gv_GetVar(*insptr++);
2525 int32_t sign = (tw==CON_GETNUMBERFROMUSER) ? Gv_GetVar(*insptr++) : (max<=0);
2526 char buf[64]; // buffers in getnumber* are 80 bytes long
2527
2528 Bstrncpyz(buf, quotetext, sizeof(buf));
2529
2530 if (max==0)
2531 max = INT32_MAX;
2532 else
2533 max = klabs(max);
2534
2535 //OSD_Printf("max:%d, sign:%d\n", max, sign);
2536 if (tw==CON_GETNUMBERFROMUSER)
2537 {
2538 Gv_SetVar(var, in3dmode() ?
2539 getnumber256(quotetext, Gv_GetVar(var), max, sign) :
2540 getnumber16(quotetext, Gv_GetVar(var), max, sign));
2541 }
2542 else if (tw==CON_GETNUMBER16)
2543 Gv_SetVar(var, getnumber16(quotetext, Gv_GetVar(var), max, sign));
2544 else
2545 Gv_SetVar(var, getnumber256(quotetext, Gv_GetVar(var), max, sign));
2546 }
2547 }
2548 continue;
2549
2550 case CON_PRINT:
2551 case CON_QUOTE:
2552 case CON_ERRORINS:
2553 case CON_PRINTMESSAGE16:
2554 case CON_PRINTMESSAGE256:
2555 case CON_PRINTEXT256:
2556 case CON_PRINTEXT16:
2557 case CON_DRAWLABEL:
2558 insptr++;
2559 {
2560 int32_t i=*insptr++;
2561 const char *quotetext = GetMaybeInlineQuote(i);
2562 if (vm.flags&VMFLAG_ERROR)
2563 continue;
2564
2565 {
2566 int32_t x=(tw>=CON_PRINTMESSAGE256)?Gv_GetVar(*insptr++):0;
2567 int32_t y=(tw>=CON_PRINTMESSAGE256)?Gv_GetVar(*insptr++):0;
2568
2569 int32_t col=(tw>=CON_PRINTEXT256)?Gv_GetVar(*insptr++):0;
2570 int32_t backcol=(tw>=CON_PRINTEXT256)?Gv_GetVar(*insptr++):0;
2571 int32_t fontsize=(tw>=CON_PRINTEXT256)?Gv_GetVar(*insptr++):0;
2572
2573 if (tw==CON_PRINT || tw==CON_ERRORINS)
2574 {
2575 OSD_Printf("%s\n", quotetext);
2576 if (tw==CON_ERRORINS)
2577 vm.flags |= VMFLAG_ERROR;
2578 }
2579 else if (tw==CON_QUOTE)
2580 {
2581 message("%s", quotetext);
2582 }
2583 else if (tw==CON_PRINTMESSAGE16)
2584 {
2585 if (!in3dmode())
2586 printmessage16("%s", quotetext);
2587 }
2588 else if (tw==CON_PRINTMESSAGE256)
2589 {
2590 if (in3dmode())
2591 printmessage256(x, y, quotetext);
2592 }
2593 else if (tw==CON_PRINTEXT256)
2594 {
2595 if (in3dmode())
2596 {
2597 if (col>=256)
2598 col=0;
2599 else if (col < 0 && col >= -255)
2600 col = editorcolors[-col];
2601
2602 if (backcol<0 || backcol>=256)
2603 backcol=-1;
2604
2605 printext256(x, y, col, backcol, quotetext, fontsize);
2606 }
2607 }
2608 else if (tw==CON_PRINTEXT16)
2609 {
2610 if (!in3dmode())
2611 printext16(x, y, editorcolors[col&255], backcol<0 ? -1 : editorcolors[backcol&255],
2612 quotetext, fontsize);
2613 }
2614 else if (tw==CON_DRAWLABEL)
2615 {
2616 if (!in3dmode())
2617 {
2618 drawsmallabel(quotetext,
2619 editorcolors[backcol&255], // col
2620 fontsize < 0 ? -1 : editorcolors[fontsize&255], editorcolors[fontsize&255] - 3, // backcol
2621 x, y, col); // x y z
2622 }
2623 }
2624 }
2625 }
2626 continue;
2627
2628 case CON_QSTRLEN:
2629 insptr++;
2630 {
2631 int32_t i=*insptr++, quote=*insptr++;
2632 const char *quotetext = GetMaybeInlineQuote(quote);
2633 if (vm.flags&VMFLAG_ERROR)
2634 continue;
2635
2636 Gv_SetVar(i, Bstrlen(quotetext));
2637 continue;
2638 }
2639
2640 case CON_QSUBSTR:
2641 insptr++;
2642 {
2643 int32_t q1 = Gv_GetVar(*insptr++);
2644 int32_t q2 = *insptr++;
2645 const char *q2text = GetMaybeInlineQuote(q2);
2646 if (vm.flags&VMFLAG_ERROR)
2647 continue;
2648
2649 X_ERROR_INVALIDQUOTE(q1, apStrings);
2650
2651 {
2652 int32_t st = Gv_GetVar(*insptr++);
2653 int32_t ln = Gv_GetVar(*insptr++);
2654 char *s1 = apStrings[q1];
2655 const char *s2 = q2text;
2656
2657 while (*s2 && st--) s2++;
2658 while ((*s1 = *s2) && ln--)
2659 {
2660 s1++;
2661 s2++;
2662 }
2663 *s1=0;
2664 }
2665 continue;
2666 }
2667
2668 case CON_QSTRNCAT:
2669 case CON_QSTRCAT:
2670 case CON_QSTRCPY:
2671 /// case CON_QGETSYSSTR:
2672 insptr++;
2673 {
2674 int32_t i = Gv_GetVar(*insptr++);
2675 int32_t j = *insptr++;
2676
2677 const char *quotetext = GetMaybeInlineQuote(j);
2678 if (vm.flags&VMFLAG_ERROR)
2679 continue;
2680
2681 X_ERROR_INVALIDQUOTE(i, apStrings);
2682
2683 switch (tw)
2684 {
2685 case CON_QSTRCAT:
2686 Bstrncat(apStrings[i], quotetext, (MAXQUOTELEN-1)-Bstrlen(apStrings[i]));
2687 break;
2688 case CON_QSTRNCAT:
2689 Bstrncat(apStrings[i], quotetext, Gv_GetVar(*insptr++));
2690 break;
2691 case CON_QSTRCPY:
2692 Bstrcpy(apStrings[i], quotetext);
2693 break;
2694 }
2695 continue;
2696 }
2697
2698 case CON_QSPRINTF:
2699 insptr++;
2700 {
2701 int32_t dq=Gv_GetVar(*insptr++), sq=*insptr++;
2702 const char *sourcetext = GetMaybeInlineQuote(sq);
2703 if (vm.flags&VMFLAG_ERROR)
2704 continue;
2705
2706 X_ERROR_INVALIDQUOTE(dq, apStrings);
2707
2708 {
2709 int32_t arg[32], numvals=0, i=0, j=0, k=0;
2710 int32_t len = Bstrlen(sourcetext);
2711 char tmpbuf[MAXQUOTELEN<<1];
2712
2713 while (*insptr != -1 && numvals < 32)
2714 arg[numvals++] = Gv_GetVar(*insptr++);
2715
2716 insptr++; // skip the NOP
2717
2718 i = 0;
2719 do
2720 {
2721 while (k < len && j < MAXQUOTELEN && sourcetext[k] != '%')
2722 tmpbuf[j++] = sourcetext[k++];
2723
2724 if (sourcetext[k] == '%')
2725 {
2726 k++;
2727
2728 if (i>=numvals) goto dodefault;
2729
2730 switch (sourcetext[k])
2731 {
2732 case 'l':
2733 if (sourcetext[k+1] != 'd')
2734 {
2735 // write the % and l
2736 tmpbuf[j++] = sourcetext[k-1];
2737 tmpbuf[j++] = sourcetext[k++];
2738 break;
2739 }
2740 k++;
2741 fallthrough__;
2742 case 'd':
2743 {
2744 char buf[16];
2745 int32_t ii = 0;
2746
2747 Bsprintf(buf, "%d", arg[i++]);
2748
2749 ii = Bstrlen(buf);
2750 Bmemcpy(&tmpbuf[j], buf, ii);
2751 j += ii;
2752 k++;
2753 }
2754 break;
2755
2756 case 'f':
2757 {
2758 char buf[64];
2759 int32_t ii = 0;
2760 union { int32_t ival; float fval; };
2761 ival = arg[i++];
2762
2763 Bsprintf(buf, "%f", fval);
2764
2765 ii = Bstrlen(buf);
2766 Bmemcpy(&tmpbuf[j], buf, ii);
2767 j += ii;
2768 k++;
2769 }
2770 break;
2771
2772 case 's':
2773 {
2774 if (arg[i]>=0 && arg[i]<MAXQUOTES && apStrings[arg[i]])
2775 {
2776 int32_t ii = Bstrlen(apStrings[arg[i]]);
2777 Bmemcpy(&tmpbuf[j], apStrings[arg[i]], ii);
2778 j += ii;
2779 }
2780 k++;
2781 }
2782 break;
2783
2784 dodefault:
2785 default:
2786 tmpbuf[j++] = sourcetext[k-1];
2787 break;
2788 }
2789 }
2790 }
2791 while (k < len && j < MAXQUOTELEN);
2792
2793 tmpbuf[j] = '\0';
2794 Bmemcpy(apStrings[dq], tmpbuf, MAXQUOTELEN);
2795 apStrings[dq][MAXQUOTELEN-1] = '\0';
2796 continue;
2797 }
2798 }
2799
2800 // *** findnear*
2801 // CURSPR vvv
2802 case CON_FINDNEARSPRITE:
2803 case CON_FINDNEARSPRITE3D:
2804 case CON_FINDNEARSPRITEVAR:
2805 case CON_FINDNEARSPRITE3DVAR:
2806 insptr++;
2807 {
2808 // syntax findnearactor(var) <type> <maxdist(var)> <getvar>
2809 // gets the sprite ID of the nearest actor within max dist
2810 // that is of <type> into <getvar>
2811 // -1 for none found
2812 // <type> <maxdist(varid)> <varid>
2813 int32_t lType=*insptr++;
2814 int32_t lMaxDist = (tw==CON_FINDNEARSPRITE || tw==CON_FINDNEARSPRITE3D)?
2815 *insptr++ : Gv_GetVar(*insptr++);
2816 int32_t lVarID=*insptr++;
2817 int32_t lFound=-1, j, k = MAXSTATUS-1;
2818
2819 X_ERROR_INVALIDCI();
2820 do
2821 {
2822 j=headspritestat[k]; // all sprites
2823 if (tw==CON_FINDNEARSPRITE3D || tw==CON_FINDNEARSPRITE3DVAR)
2824 {
2825 while (j>=0)
2826 {
2827 if (sprite[j].picnum == lType && j != vm.spriteNum && dist(&sprite[vm.spriteNum], &sprite[j]) < lMaxDist)
2828 {
2829 lFound=j;
2830 j = MAXSPRITES;
2831 break;
2832 }
2833 j = nextspritestat[j];
2834 }
2835 if (j == MAXSPRITES)
2836 break;
2837 continue;
2838 }
2839
2840 while (j>=0)
2841 {
2842 if (sprite[j].picnum == lType && j != vm.spriteNum && ldist(&sprite[vm.spriteNum], &sprite[j]) < lMaxDist)
2843 {
2844 lFound=j;
2845 j = MAXSPRITES;
2846 break;
2847 }
2848 j = nextspritestat[j];
2849 }
2850
2851 if (j == MAXSPRITES)
2852 break;
2853 }
2854 while (k--);
2855 Gv_SetVar(lVarID, lFound);
2856 continue;
2857 }
2858
2859 case CON_FINDNEARSPRITEZVAR:
2860 case CON_FINDNEARSPRITEZ:
2861 insptr++;
2862 {
2863 // syntax findnearactor(var) <type> <maxdist(var)> <getvar>
2864 // gets the sprite ID of the nearest actor within max dist
2865 // that is of <type> into <getvar>
2866 // -1 for none found
2867 // <type> <maxdist(varid)> <varid>
2868 int32_t lType=*insptr++;
2869 int32_t lMaxDist = (tw==CON_FINDNEARSPRITEZVAR) ? Gv_GetVar(*insptr++) : *insptr++;
2870 int32_t lMaxZDist = (tw==CON_FINDNEARSPRITEZVAR) ? Gv_GetVar(*insptr++) : *insptr++;
2871 int32_t lVarID=*insptr++;
2872 int32_t lFound=-1, lTemp, lTemp2, j, k=MAXSTATUS-1;
2873
2874 X_ERROR_INVALIDCI();
2875 do
2876 {
2877 j=headspritestat[k]; // all sprites
2878 if (j == -1) continue;
2879 do
2880 {
2881 if (sprite[j].picnum == lType && j != vm.spriteNum)
2882 {
2883 lTemp=ldist(&sprite[vm.spriteNum], &sprite[j]);
2884 if (lTemp < lMaxDist)
2885 {
2886 lTemp2=klabs(sprite[vm.spriteNum].z-sprite[j].z);
2887 if (lTemp2 < lMaxZDist)
2888 {
2889 lFound=j;
2890 j = MAXSPRITES;
2891 break;
2892 }
2893 }
2894 }
2895 j = nextspritestat[j];
2896 }
2897 while (j>=0);
2898 if (j == MAXSPRITES)
2899 break;
2900 }
2901 while (k--);
2902 Gv_SetVar(lVarID, lFound);
2903
2904 continue;
2905 }
2906 // ^^^
2907
2908 case CON_GETTICKS:
2909 insptr++;
2910 {
2911 int32_t j=*insptr++;
2912 Gv_SetVar(j, timerGetTicks());
2913 }
2914 continue;
2915
2916 case CON_SETASPECT:
2917 insptr++;
2918 {
2919 int32_t daxrange = Gv_GetVar(*insptr++), dayxaspect = Gv_GetVar(*insptr++);
2920 if (daxrange < (1<<12)) daxrange = (1<<12);
2921 if (daxrange > (1<<20)) daxrange = (1<<20);
2922 if (dayxaspect < (1<<12)) dayxaspect = (1<<12);
2923 if (dayxaspect > (1<<20)) dayxaspect = (1<<20);
2924 renderSetAspect(daxrange, dayxaspect);
2925 continue;
2926 }
2927
2928 // vvv CURSPR
2929 case CON_SETI:
2930 {
2931 int32_t newcurspritei;
2932
2933 insptr++;
2934 newcurspritei = Gv_GetVar(*insptr++);
2935 X_ERROR_INVALIDSPRI(newcurspritei);
2936 vm.spriteNum = newcurspritei;
2937 vm.pSprite = &sprite[vm.spriteNum];
2938 continue;
2939 }
2940
2941 case CON_SIZEAT:
2942 insptr += 3;
2943 X_ERROR_INVALIDSP();
2944 vm.pSprite->xrepeat = (uint8_t) Gv_GetVar(*(insptr-2));
2945 vm.pSprite->yrepeat = (uint8_t) Gv_GetVar(*(insptr-1));
2946 #ifdef USE_STRUCT_TRACKERS
2947 if (vm.spriteNum != -1) spritechanged[vm.spriteNum]++;
2948 #endif
2949 continue;
2950
2951 case CON_CSTAT:
2952 insptr += 2;
2953 X_ERROR_INVALIDSP();
2954 vm.pSprite->cstat = (int16_t) *(insptr-1);
2955 #ifdef USE_STRUCT_TRACKERS
2956 if (vm.spriteNum != -1) spritechanged[vm.spriteNum]++;
2957 #endif
2958 continue;
2959
2960 case CON_CSTATOR:
2961 insptr += 2;
2962 X_ERROR_INVALIDSP();
2963 vm.pSprite->cstat |= (int16_t) Gv_GetVar(*(insptr-1));
2964 #ifdef USE_STRUCT_TRACKERS
2965 if (vm.spriteNum != -1) spritechanged[vm.spriteNum]++;
2966 #endif
2967 continue;
2968
2969 case CON_CLIPDIST:
2970 insptr += 2;
2971 X_ERROR_INVALIDSP();
2972 vm.pSprite->clipdist = (uint8_t) Gv_GetVar(*(insptr-1));
2973 #ifdef USE_STRUCT_TRACKERS
2974 if (vm.spriteNum != -1) spritechanged[vm.spriteNum]++;
2975 #endif
2976 continue;
2977
2978 case CON_SPRITEPAL:
2979 insptr += 2;
2980 X_ERROR_INVALIDSP();
2981 vm.pSprite->pal = Gv_GetVar(*(insptr-1));
2982 #ifdef USE_STRUCT_TRACKERS
2983 if (vm.spriteNum != -1) spritechanged[vm.spriteNum]++;
2984 #endif
2985 continue;
2986
2987 case CON_CACTOR:
2988 insptr += 2;
2989 X_ERROR_INVALIDSP();
2990 vm.pSprite->picnum = Gv_GetVar(*(insptr-1));
2991 #ifdef USE_STRUCT_TRACKERS
2992 if (vm.spriteNum != -1) spritechanged[vm.spriteNum]++;
2993 #endif
2994 continue;
2995
2996 case CON_SPGETLOTAG:
2997 insptr++;
2998 X_ERROR_INVALIDSP();
2999 Gv_SetVar(M32_LOTAG_VAR_ID, vm.pSprite->lotag);
3000 continue;
3001
3002 case CON_SPGETHITAG:
3003 insptr++;
3004 X_ERROR_INVALIDSP();
3005 Gv_SetVar(M32_HITAG_VAR_ID, vm.pSprite->hitag);
3006 continue;
3007
3008 case CON_SECTGETLOTAG:
3009 insptr++;
3010 X_ERROR_INVALIDSP();
3011 Gv_SetVar(M32_LOTAG_VAR_ID, sector[vm.pSprite->sectnum].lotag);
3012 continue;
3013
3014 case CON_SECTGETHITAG:
3015 insptr++;
3016 X_ERROR_INVALIDSP();
3017 Gv_SetVar(M32_HITAG_VAR_ID, sector[vm.pSprite->sectnum].hitag);
3018 continue;
3019
3020 case CON_GETTEXTUREFLOOR:
3021 insptr++;
3022 X_ERROR_INVALIDSP();
3023 Gv_SetVar(M32_TEXTURE_VAR_ID, sector[vm.pSprite->sectnum].floorpicnum);
3024 continue;
3025
3026 case CON_GETTEXTURECEILING:
3027 insptr++;
3028 X_ERROR_INVALIDSP();
3029 Gv_SetVar(M32_TEXTURE_VAR_ID, sector[vm.pSprite->sectnum].ceilingpicnum);
3030 continue;
3031 // ^^^
3032 case CON_DRAWLINE16:
3033 case CON_DRAWLINE16B:
3034 case CON_DRAWLINE16Z:
3035 insptr++;
3036 {
3037 int32_t x1=Gv_GetVar(*insptr++), y1=Gv_GetVar(*insptr++);
3038 int32_t z1=tw==CON_DRAWLINE16Z?Gv_GetVar(*insptr++):0;
3039 int32_t x2=Gv_GetVar(*insptr++), y2=Gv_GetVar(*insptr++);
3040 int32_t z2=tw==CON_DRAWLINE16Z?Gv_GetVar(*insptr++):0;
3041 int32_t col=Gv_GetVar(*insptr++), odrawlinepat=drawlinepat;
3042 int32_t xofs=0, yofs=0;
3043
3044 if (tw==CON_DRAWLINE16B || tw==CON_DRAWLINE16Z)
3045 {
3046 editorGet2dScreenCoordinates(&x1,&y1, x1-pos.x,y1-pos.y, zoom);
3047 editorGet2dScreenCoordinates(&x2,&y2, x2-pos.x,y2-pos.y, zoom);
3048
3049 if (tw==CON_DRAWLINE16Z && m32_sideview)
3050 {
3051 y1 += getscreenvdisp(z1-pos.z,zoom);
3052 y2 += getscreenvdisp(z2-pos.z,zoom);
3053 }
3054
3055 xofs = halfxdim16;
3056 yofs = midydim16;
3057 }
3058
3059 drawlinepat = m32_drawlinepat;
3060 editorDraw2dLine(xofs+x1,yofs+y1, xofs+x2,yofs+y2, col>=0?editorcolors[col&15]:((-col)&255));
3061 drawlinepat = odrawlinepat;
3062 continue;
3063 }
3064 case CON_DRAWLINE256:
3065 insptr++;
3066 {
3067 int32_t x1=Gv_GetVar(*insptr++), y1=Gv_GetVar(*insptr++);
3068 int32_t x2=Gv_GetVar(*insptr++), y2=Gv_GetVar(*insptr++);
3069 int32_t col=Gv_GetVar(*insptr++);
3070 renderDrawLine(x1, y1, x2, y2, col);
3071 continue;
3072 }
3073 case CON_DRAWCIRCLE16:
3074 case CON_DRAWCIRCLE16B:
3075 case CON_DRAWCIRCLE16Z:
3076 insptr++;
3077 {
3078 int32_t x1=Gv_GetVar(*insptr++), y1=Gv_GetVar(*insptr++);
3079 int32_t z1 = tw==CON_DRAWCIRCLE16Z ? Gv_GetVar(*insptr++) : 0;
3080 int32_t r=Gv_GetVar(*insptr++);
3081 int32_t col=Gv_GetVar(*insptr++), odrawlinepat=drawlinepat;
3082 int32_t xofs=0, yofs=0, eccen=16384;
3083
3084 if (tw==CON_DRAWCIRCLE16B || tw==CON_DRAWCIRCLE16Z)
3085 {
3086 editorGet2dScreenCoordinates(&x1,&y1, x1-pos.x,y1-pos.y, zoom);
3087 if (m32_sideview)
3088 y1 += getscreenvdisp(z1-pos.z, zoom);
3089 r = mulscale14(r,zoom);
3090 eccen = scalescreeny(eccen);
3091 xofs = halfxdim16;
3092 yofs = midydim16;
3093 }
3094
3095 drawlinepat = m32_drawlinepat;
3096 editorDraw2dCircle(xofs+x1, yofs+y1, r, eccen, col>=0?editorcolors[col&15]:((-col)&255));
3097 drawlinepat = odrawlinepat;
3098 continue;
3099 }
3100
3101 case CON_ROTATESPRITEA:
3102 case CON_ROTATESPRITE16:
3103 case CON_ROTATESPRITE:
3104 insptr++;
3105 {
3106 int32_t x=Gv_GetVar(*insptr++), y=Gv_GetVar(*insptr++), z=Gv_GetVar(*insptr++);
3107 int32_t a=Gv_GetVar(*insptr++), tilenum=Gv_GetVar(*insptr++), shade=Gv_GetVar(*insptr++);
3108 int32_t pal=Gv_GetVar(*insptr++), orientation=Gv_GetVar(*insptr++);
3109 int32_t alpha = (tw == CON_ROTATESPRITEA) ? Gv_GetVar(*insptr++) : 0;
3110 int32_t x1=Gv_GetVar(*insptr++), y1=Gv_GetVar(*insptr++);
3111 int32_t x2=Gv_GetVar(*insptr++), y2=Gv_GetVar(*insptr++);
3112
3113 if (tw != CON_ROTATESPRITE16 && !(orientation&ROTATESPRITE_FULL16))
3114 {
3115 x<<=16;
3116 y<<=16;
3117 }
3118
3119 orientation &= (ROTATESPRITE_MAX-1);
3120
3121 rotatesprite_(x,y,z,a,tilenum,shade,pal,2|orientation,alpha,0,x1,y1,x2,y2);
3122 continue;
3123 }
3124
3125 case CON_SETGAMEPALETTE:
3126 insptr++;
3127 SetGamePalette(Gv_GetVar(*insptr++));
3128 continue;
3129
3130 // *** sounds
3131 case CON_IFSOUND:
3132 insptr++;
3133 {
3134 int32_t j=Gv_GetVar(*insptr);
3135 if (S_InvalidSound(j))
3136 {
3137 M32_ERROR("Invalid sound %d", j);
3138 insptr++;
3139 continue;
3140 }
3141 VM_DoConditional(S_CheckSoundPlaying(vm.spriteNum,j));
3142 }
3143 continue;
3144
3145 case CON_IFNOSOUNDS:
3146 VM_DoConditional(S_SoundsPlaying(vm.spriteNum) < 0);
3147 continue;
3148
3149 case CON_IFIN3DMODE:
3150 VM_DoConditional(in3dmode());
3151 continue;
3152
3153 // ifaimingsprite and -wall also work in 2d mode, but you must "and" with 16383 yourself
3154 case CON_IFAIMINGSPRITE:
3155 VM_DoConditional(AIMING_AT_SPRITE || (!in3dmode() && pointhighlight>=16384));
3156 continue;
3157 case CON_IFAIMINGWALL:
3158 VM_DoConditional(AIMING_AT_WALL_OR_MASK || (!in3dmode() && linehighlight>=0));
3159 continue;
3160 case CON_IFAIMINGSECTOR:
3161 VM_DoConditional(AIMING_AT_CEILING_OR_FLOOR);
3162 continue;
3163 case CON_IFINTERACTIVE:
3164 VM_DoConditional(vm.miscflags&VMFLAG_MISC_INTERACTIVE);
3165 continue;
3166
3167 case CON_GETSOUNDFLAGS:
3168 insptr++;
3169 {
3170 int32_t j=Gv_GetVar(*insptr++), var=*insptr++;
3171 if (S_InvalidSound(j))
3172 {
3173 M32_ERROR("Invalid sound %d", j);
3174 insptr++;
3175 continue;
3176 }
3177
3178 Gv_SetVar(var, S_SoundFlags(j));
3179 }
3180 continue;
3181
3182 case CON_SOUNDVAR:
3183 case CON_STOPSOUNDVAR:
3184 case CON_SOUNDONCEVAR:
3185 case CON_GLOBALSOUNDVAR:
3186 insptr++;
3187 {
3188 int32_t j=Gv_GetVar(*insptr++);
3189
3190 if (S_InvalidSound(j))
3191 {
3192 M32_ERROR("Invalid sound %d", j);
3193 continue;
3194 }
3195
3196 switch (tw)
3197 {
3198 case CON_SOUNDONCEVAR:
3199 if (!S_CheckSoundPlaying(vm.spriteNum,j))
3200 A_PlaySound((int16_t)j,vm.spriteNum);
3201 break;
3202 case CON_GLOBALSOUNDVAR:
3203 A_PlaySound((int16_t)j,-1);
3204 break;
3205 case CON_STOPSOUNDVAR:
3206 if (S_CheckSoundPlaying(vm.spriteNum,j))
3207 S_StopSound((int16_t)j);
3208 break;
3209 case CON_SOUNDVAR:
3210 A_PlaySound((int16_t)j,vm.spriteNum);
3211 break;
3212 }
3213 }
3214 continue;
3215
3216 case CON_STOPALLSOUNDS:
3217 insptr++;
3218 S_StopAllSounds();
3219 continue;
3220
3221 default:
3222 VM_ScriptInfo();
3223
3224 OSD_Printf("\nAn error has occurred in the Mapster32 virtual machine.\n\n"
3225 "Please e-mail the file mapster32.log along with every M32 file\n"
3226 "you're using and instructions how to reproduce this error to\n"
3227 "development@voidpoint.com.\n\n"
3228 "Thank you!\n");
3229 vm.flags |= VMFLAG_ERROR;
3230 Bfflush(NULL);
3231 return 1;
3232 }
3233 }
3234
3235 return 0;
3236 }
3237