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_GetVarX(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_GetVarX(*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_SetVarX(j, insptr-apScript);
459 }
460 continue;
461
462 case CON_JUMP:
463 insptr++;
464 {
465 int32_t j = Gv_GetVarX(*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_GetVarX(*insptr++);
489 const int32_t value = Gv_GetVarX(*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_SetVarX(*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_GetVarX(*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_GetVarX(*insptr++);
548 const int32_t di=*insptr++;
549 int32_t didx = Gv_GetVarX(*insptr++);
550 int32_t numelts = Gv_GetVarX(*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_SetVarX(*insptr, mulscale16(krand(), *(insptr+1)+1));
609 insptr += 2;
610 continue;
611
612 case CON_DISPLAYRANDVAR:
613 insptr++;
614 Gv_SetVarX(*insptr, mulscale15(system_15bit_rand(), *(insptr+1)+1));
615 insptr += 2;
616 continue;
617
618 case CON_SETVAR:
619 insptr++;
620 Gv_SetVarX(*insptr, *(insptr+1));
621 insptr += 2;
622 continue;
623
624 case CON_SETVARVAR:
625 insptr++;
626 {
627 int32_t j=*insptr++;
628 Gv_SetVarX(j, Gv_GetVarX(*insptr++));
629 }
630 continue;
631
632 case CON_MULVAR:
633 insptr++;
634 Gv_SetVarX(*insptr, Gv_GetVarX(*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_SetVarX(*insptr, Gv_GetVarX(*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_SetVarX(*insptr,Gv_GetVarX(*insptr)%*(insptr+1));
659 insptr += 2;
660 continue;
661
662 case CON_ANDVAR:
663 insptr++;
664 Gv_SetVarX(*insptr,Gv_GetVarX(*insptr) & *(insptr+1));
665 insptr += 2;
666 continue;
667
668 case CON_ORVAR:
669 insptr++;
670 Gv_SetVarX(*insptr,Gv_GetVarX(*insptr) | *(insptr+1));
671 insptr += 2;
672 continue;
673
674 case CON_XORVAR:
675 insptr++;
676 Gv_SetVarX(*insptr,Gv_GetVarX(*insptr) ^ *(insptr+1));
677 insptr += 2;
678 continue;
679
680 case CON_RANDVARVAR:
681 insptr++;
682 {
683 int32_t j=*insptr++;
684 Gv_SetVarX(j,mulscale16(krand(), Gv_GetVarX(*insptr++)+1));
685 }
686 continue;
687
688 case CON_DISPLAYRANDVARVAR:
689 insptr++;
690 {
691 int32_t j=*insptr++;
692 Gv_SetVarX(j,mulscale15(system_15bit_rand(), Gv_GetVarX(*insptr++)+1));
693 }
694 continue;
695
696 case CON_MULVARVAR:
697 insptr++;
698 {
699 int32_t j=*insptr++;
700 Gv_SetVarX(j, Gv_GetVarX(j)*Gv_GetVarX(*insptr++));
701 }
702 continue;
703
704 case CON_DIVVARVAR:
705 insptr++;
706 {
707 int32_t j=*insptr++;
708 int32_t l2=Gv_GetVarX(*insptr++);
709
710 if (l2==0)
711 {
712 M32_ERROR("Divide by zero.");
713 continue;
714 }
715 Gv_SetVarX(j, Gv_GetVarX(j)/l2);
716 continue;
717 }
718
719 case CON_MODVARVAR:
720 insptr++;
721 {
722 int32_t j=*insptr++;
723 int32_t l2=Gv_GetVarX(*insptr++);
724
725 if (l2==0)
726 {
727 M32_ERROR("Mod by zero.");
728 continue;
729 }
730
731 Gv_SetVarX(j, Gv_GetVarX(j) % l2);
732 continue;
733 }
734
735 case CON_ANDVARVAR:
736 insptr++;
737 {
738 int32_t j=*insptr++;
739 Gv_SetVarX(j, Gv_GetVarX(j) & Gv_GetVarX(*insptr++));
740 }
741 continue;
742
743 case CON_XORVARVAR:
744 insptr++;
745 {
746 int32_t j=*insptr++;
747 Gv_SetVarX(j, Gv_GetVarX(j) ^ Gv_GetVarX(*insptr++));
748 }
749 continue;
750
751 case CON_ORVARVAR:
752 insptr++;
753 {
754 int32_t j=*insptr++;
755 Gv_SetVarX(j, Gv_GetVarX(j) | Gv_GetVarX(*insptr++));
756 }
757 continue;
758
759 case CON_SUBVAR:
760 insptr++;
761 Gv_SetVarX(*insptr, Gv_GetVarX(*insptr) - *(insptr+1));
762 insptr += 2;
763 continue;
764
765 case CON_SUBVARVAR:
766 insptr++;
767 {
768 int32_t j=*insptr++;
769 Gv_SetVarX(j, Gv_GetVarX(j) - Gv_GetVarX(*insptr++));
770 }
771 continue;
772
773 case CON_ADDVAR:
774 insptr++;
775 Gv_SetVarX(*insptr, Gv_GetVarX(*insptr) + *(insptr+1));
776 insptr += 2;
777 continue;
778
779 case CON_ADDVARVAR:
780 insptr++;
781 {
782 int32_t j=*insptr++;
783 Gv_SetVarX(j, Gv_GetVarX(j) + Gv_GetVarX(*insptr++));
784 }
785 continue;
786
787 case CON_SHIFTVARL:
788 insptr++;
789 Gv_SetVarX(*insptr, Gv_GetVarX(*insptr) << *(insptr+1));
790 insptr += 2;
791 continue;
792
793 case CON_SHIFTVARVARL:
794 insptr++;
795 {
796 int32_t j=*insptr++;
797 Gv_SetVarX(j, Gv_GetVarX(j) << Gv_GetVarX(*insptr++));
798 }
799 continue;
800
801 case CON_SHIFTVARR:
802 insptr++;
803 Gv_SetVarX(*insptr, Gv_GetVarX(*insptr) >> *(insptr+1));
804 insptr += 2;
805 continue;
806
807 case CON_SHIFTVARVARR:
808 insptr++;
809 {
810 int32_t j=*insptr++;
811 Gv_SetVarX(j, Gv_GetVarX(j) >> Gv_GetVarX(*insptr++));
812 }
813 continue;
814
815 case CON_SIN:
816 insptr++;
817 Gv_SetVarX(*insptr, sintable[Gv_GetVarX(*(insptr+1))&2047]);
818 insptr += 2;
819 continue;
820
821 case CON_COS:
822 insptr++;
823 Gv_SetVarX(*insptr, sintable[(Gv_GetVarX(*(insptr+1))+512)&2047]);
824 insptr += 2;
825 continue;
826
827 case CON_DISPLAYRAND:
828 insptr++;
829 Gv_SetVarX(*insptr++, system_15bit_rand());
830 continue;
831
832 // *** other math
833 case CON_FTOI:
834 insptr++;
835 {
836 int32_t bits=Gv_GetVarX(*insptr), scale=*(insptr+1);
837 float fval = *((float *)&bits);
838 // rounding must absolutely be!
839 //OSD_Printf("ftoi: bits:%8x, scale=%d, fval=%f, (int32_t)(fval*scale)=%d\n", bits, scale, fval, (int32_t)(fval*scale));
840 Gv_SetVarX(*insptr, (int32_t)Blrintf(fval * scale));
841 }
842 insptr += 2;
843 continue;
844
845 case CON_ITOF:
846 insptr++;
847 {
848 int32_t scaled=Gv_GetVarX(*insptr), scale=*(insptr+1);
849 float fval = (float)scaled/(float)scale;
850 Gv_SetVarX(*insptr, *((int32_t *)&fval));
851 }
852 insptr += 2;
853 continue;
854
855 case CON_CLAMP:
856 insptr++;
857 {
858 int32_t var=*insptr++, min=Gv_GetVarX(*insptr++), max=Gv_GetVarX(*insptr++);
859 int32_t val=Gv_GetVarX(var);
860
861 if (val<min) Gv_SetVarX(var, min);
862 else if (val>max) Gv_SetVarX(var, max);
863 }
864 continue;
865
866 case CON_INV:
867 Gv_SetVarX(*(insptr+1), -Gv_GetVarX(*(insptr+1)));
868 insptr += 2;
869 continue;
870
871 case CON_SQRT:
872 insptr++;
873 {
874 // syntax sqrt <invar> <outvar>
875 int32_t lInVarID=*insptr++, lOutVarID=*insptr++;
876
877 Gv_SetVarX(lOutVarID, ksqrt((uint32_t)Gv_GetVarX(lInVarID)));
878 continue;
879 }
880
881 case CON_LDIST:
882 case CON_DIST:
883 insptr++;
884 {
885 int32_t distvar = *insptr++, xvar = Gv_GetVarX(*insptr++), yvar = Gv_GetVarX(*insptr++);
886
887 if (xvar < 0 || xvar >= MAXSPRITES || sprite[xvar].statnum==MAXSTATUS)
888 {
889 M32_ERROR("invalid sprite %d", xvar);
890 }
891 if (yvar < 0 || yvar >= MAXSPRITES || sprite[yvar].statnum==MAXSTATUS)
892 {
893 M32_ERROR("invalid sprite %d", yvar);
894 }
895 if (vm.flags&VMFLAG_ERROR) continue;
896
897 if (tw==CON_DIST)
898 Gv_SetVarX(distvar, dist(&sprite[xvar],&sprite[yvar]));
899 else
900 Gv_SetVarX(distvar, ldist(&sprite[xvar],&sprite[yvar]));
901 continue;
902 }
903
904 case CON_GETANGLE:
905 insptr++;
906 {
907 int32_t angvar = *insptr++;
908 int32_t xvar = Gv_GetVarX(*insptr++);
909 int32_t yvar = Gv_GetVarX(*insptr++);
910
911 Gv_SetVarX(angvar, getangle(xvar,yvar));
912 continue;
913 }
914
915 case CON_GETINCANGLE:
916 insptr++;
917 {
918 int32_t angvar = *insptr++;
919 int32_t xvar = Gv_GetVarX(*insptr++);
920 int32_t yvar = Gv_GetVarX(*insptr++);
921
922 Gv_SetVarX(angvar, G_GetAngleDelta(xvar,yvar));
923 continue;
924 }
925
926 case CON_A2XY:
927 case CON_AH2XYZ:
928 insptr++;
929 {
930 int32_t ang=Gv_GetVarX(*insptr++), horiz=(tw==CON_A2XY)?100:Gv_GetVarX(*insptr++);
931 int32_t xvar=*insptr++, yvar=*insptr++;
932
933 int32_t x = sintable[(ang+512)&2047];
934 int32_t y = sintable[ang&2047];
935
936 if (tw==CON_AH2XYZ)
937 {
938 int32_t zvar=*insptr++, z=0;
939
940 horiz -= 100;
941 if (horiz)
942 {
943 int32_t veclen = ksqrt(200*200 + horiz*horiz);
944 int32_t dacos = divscale14(200, veclen);
945
946 x = mulscale14(x, dacos);
947 y = mulscale14(y, dacos);
948 z = divscale14(-horiz, veclen);
949 }
950
951 Gv_SetVarX(zvar, z);
952 }
953
954 Gv_SetVarX(xvar, x);
955 Gv_SetVarX(yvar, y);
956
957 continue;
958 }
959
960 case CON_MULSCALE:
961 insptr++;
962 {
963 int32_t var1 = *insptr++, var2 = Gv_GetVarX(*insptr++);
964 int32_t var3 = Gv_GetVarX(*insptr++), var4 = Gv_GetVarX(*insptr++);
965
966 Gv_SetVarX(var1, mulscale(var2, var3, var4));
967 continue;
968 }
969 case CON_DIVSCALE:
970 insptr++;
971 {
972 int32_t var1 = *insptr++, var2 = Gv_GetVarX(*insptr++);
973 int32_t var3 = Gv_GetVarX(*insptr++), var4 = Gv_GetVarX(*insptr++);
974
975 Gv_SetVarX(var1, divscale(var2, var3, var4));
976 continue;
977 }
978 case CON_SCALEVAR:
979 insptr++;
980 {
981 int32_t var1 = *insptr++, var2 = Gv_GetVarX(*insptr++);
982 int32_t var3 = Gv_GetVarX(*insptr++), var4 = Gv_GetVarX(*insptr++);
983
984 Gv_SetVarX(var1, scale(var2, var3, var4));
985 continue;
986 }
987
988 // *** if & while
989 case CON_IFVARVARAND:
990 insptr++;
991 {
992 int32_t j = Gv_GetVarX(*insptr++);
993 j &= Gv_GetVarX(*insptr++);
994 insptr--;
995 VM_DoConditional(j);
996 }
997 continue;
998
999 case CON_IFVARVAROR:
1000 insptr++;
1001 {
1002 int32_t j = Gv_GetVarX(*insptr++);
1003 j |= Gv_GetVarX(*insptr++);
1004 insptr--;
1005 VM_DoConditional(j);
1006 }
1007 continue;
1008
1009 case CON_IFVARVARXOR:
1010 insptr++;
1011 {
1012 int32_t j = Gv_GetVarX(*insptr++);
1013 j ^= Gv_GetVarX(*insptr++);
1014 insptr--;
1015 VM_DoConditional(j);
1016 }
1017 continue;
1018
1019 case CON_IFVARVAREITHER:
1020 insptr++;
1021 {
1022 int32_t j = Gv_GetVarX(*insptr++);
1023 int32_t l = Gv_GetVarX(*insptr++);
1024 insptr--;
1025 VM_DoConditional(j || l);
1026 }
1027 continue;
1028
1029 case CON_IFVARVARBOTH:
1030 insptr++;
1031 {
1032 int32_t j = Gv_GetVarX(*insptr++);
1033 int32_t l = Gv_GetVarX(*insptr++);
1034 insptr--;
1035 VM_DoConditional(j && l);
1036 }
1037 continue;
1038
1039 case CON_IFVARVARN:
1040 insptr++;
1041 {
1042 int32_t j = Gv_GetVarX(*insptr++);
1043 j = (j != Gv_GetVarX(*insptr++));
1044 insptr--;
1045 VM_DoConditional(j);
1046 }
1047 continue;
1048
1049 case CON_IFVARVARE:
1050 insptr++;
1051 {
1052 int32_t j = Gv_GetVarX(*insptr++);
1053 j = (j == Gv_GetVarX(*insptr++));
1054 insptr--;
1055 VM_DoConditional(j);
1056 }
1057 continue;
1058
1059 case CON_IFVARVARG:
1060 insptr++;
1061 {
1062 int32_t j = Gv_GetVarX(*insptr++);
1063 j = (j > Gv_GetVarX(*insptr++));
1064 insptr--;
1065 VM_DoConditional(j);
1066 }
1067 continue;
1068
1069 case CON_IFVARVARGE:
1070 insptr++;
1071 {
1072 int32_t j = Gv_GetVarX(*insptr++);
1073 j = (j >= Gv_GetVarX(*insptr++));
1074 insptr--;
1075 VM_DoConditional(j);
1076 }
1077 continue;
1078
1079 case CON_IFVARVARL:
1080 insptr++;
1081 {
1082 int32_t j = Gv_GetVarX(*insptr++);
1083 j = (j < Gv_GetVarX(*insptr++));
1084 insptr--;
1085 VM_DoConditional(j);
1086 }
1087 continue;
1088
1089 case CON_IFVARVARLE:
1090 insptr++;
1091 {
1092 int32_t j = Gv_GetVarX(*insptr++);
1093 j = (j <= Gv_GetVarX(*insptr++));
1094 insptr--;
1095 VM_DoConditional(j);
1096 }
1097 continue;
1098
1099 case CON_IFVARVARA:
1100 insptr++;
1101 {
1102 int32_t j = Gv_GetVarX(*insptr++);
1103 j = ((uint32_t)j > (uint32_t)Gv_GetVarX(*insptr++));
1104 insptr--;
1105 VM_DoConditional(j);
1106 }
1107 continue;
1108
1109 case CON_IFVARVARAE:
1110 insptr++;
1111 {
1112 int32_t j = Gv_GetVarX(*insptr++);
1113 j = ((uint32_t)j >= (uint32_t)Gv_GetVarX(*insptr++));
1114 insptr--;
1115 VM_DoConditional(j);
1116 }
1117 continue;
1118
1119 case CON_IFVARVARB:
1120 insptr++;
1121 {
1122 int32_t j = Gv_GetVarX(*insptr++);
1123 j = ((uint32_t)j < (uint32_t)Gv_GetVarX(*insptr++));
1124 insptr--;
1125 VM_DoConditional(j);
1126 }
1127 continue;
1128
1129 case CON_IFVARVARBE:
1130 insptr++;
1131 {
1132 int32_t j = Gv_GetVarX(*insptr++);
1133 j = ((uint32_t)j <= (uint32_t)Gv_GetVarX(*insptr++));
1134 insptr--;
1135 VM_DoConditional(j);
1136 }
1137 continue;
1138
1139 case CON_IFVARE:
1140 insptr++;
1141 {
1142 int32_t j=Gv_GetVarX(*insptr++);
1143 VM_DoConditional(j == *insptr);
1144 }
1145 continue;
1146
1147 case CON_IFVARN:
1148 insptr++;
1149 {
1150 int32_t j=Gv_GetVarX(*insptr++);
1151 VM_DoConditional(j != *insptr);
1152 }
1153 continue;
1154
1155 case CON_WHILEVARN:
1156 {
1157 instype *savedinsptr=insptr+2;
1158 int32_t j;
1159 do
1160 {
1161 insptr=savedinsptr;
1162 j = (Gv_GetVarX(*(insptr-1)) != *insptr);
1163 VM_DoConditional(j);
1164 }
1165 while (j && !vm.flags);
1166 vm.flags &= ~VMFLAG_BREAK;
1167 continue;
1168 }
1169
1170 case CON_WHILEVARL:
1171 {
1172 instype *savedinsptr=insptr+2;
1173 int32_t j;
1174 do
1175 {
1176 insptr=savedinsptr;
1177 j = (Gv_GetVarX(*(insptr-1)) < *insptr);
1178 VM_DoConditional(j);
1179 }
1180 while (j && !vm.flags);
1181 vm.flags &= ~VMFLAG_BREAK;
1182 continue;
1183 }
1184
1185 case CON_WHILEVARVARN:
1186 {
1187 int32_t j;
1188 instype *savedinsptr=insptr+2;
1189 do
1190 {
1191 insptr=savedinsptr;
1192 j = Gv_GetVarX(*(insptr-1));
1193 j = (j != Gv_GetVarX(*insptr++));
1194 insptr--;
1195 VM_DoConditional(j);
1196 }
1197 while (j && !vm.flags);
1198 vm.flags &= ~VMFLAG_BREAK;
1199 continue;
1200 }
1201
1202 case CON_WHILEVARVARL:
1203 {
1204 int32_t j;
1205 instype *savedinsptr=insptr+2;
1206 do
1207 {
1208 insptr=savedinsptr;
1209 j = Gv_GetVarX(*(insptr-1));
1210 j = (j < Gv_GetVarX(*insptr++));
1211 insptr--;
1212 VM_DoConditional(j);
1213 }
1214 while (j && !vm.flags);
1215 vm.flags &= ~VMFLAG_BREAK;
1216 continue;
1217 }
1218
1219 case CON_COLLECTSECTORS:
1220 insptr++;
1221 {
1222 const int32_t aridx=*insptr++, startsectnum=Gv_GetVarX(*insptr++);
1223 const int32_t numsectsVar=*insptr++, state=*insptr++;
1224
1225 if (CheckArray(aridx))
1226 continue;
1227
1228 gamearray_t *const gar = &aGameArrays[aridx];
1229 Bassert((gar->dwFlags & (GAMEARRAY_READONLY|GAMEARRAY_VARSIZE)) == 0);
1230
1231 const int32_t o_g_st=vm.g_st, arsize = gar->size;
1232 instype *const end=insptr;
1233 int32_t sectcnt, numsects=0;
1234
1235 // XXX: relies on -fno-strict-aliasing
1236 int16_t *const sectlist = (int16_t *)gar->vals; // actually an int32_t array
1237 int32_t *const sectlist32 = (int32_t *)sectlist;
1238
1239 int32_t j, startwall, endwall, ns;
1240 static uint8_t sectbitmap[MAXSECTORS>>3];
1241
1242 X_ERROR_INVALIDSECT(startsectnum);
1243 if (arsize < numsectors)
1244 {
1245 M32_ERROR("Array size must be at least numsectors (=%d) for collecting!",
1246 numsectors);
1247 continue;
1248 }
1249
1250 // collect!
1251 bfirst_search_init(sectlist, sectbitmap, &numsects, MAXSECTORS, startsectnum);
1252
1253 for (sectcnt=0; sectcnt<numsects; sectcnt++)
1254 for (WALLS_OF_SECTOR(sectlist[sectcnt], j))
1255 if ((ns=wall[j].nextsector) >= 0 && wall[j].nextsector<numsectors)
1256 {
1257 if (sectbitmap[ns>>3]&(1<<(ns&7)))
1258 continue;
1259 vm.g_st = 1+MAXEVENTS+state;
1260 insptr = apScript + statesinfo[state].ofs;
1261 g_iReturnVar = ns;
1262 VM_Execute(0);
1263 if (g_iReturnVar)
1264 bfirst_search_try(sectlist, sectbitmap, &numsects, wall[j].nextsector);
1265 }
1266
1267 // short->int sector list
1268 for (j=numsects-1; j>=0; j--)
1269 sectlist32[j] = sectlist[j];
1270
1271 Gv_SetVarX(numsectsVar, numsects);
1272 g_iReturnVar = 0;
1273
1274 // restore some VM state
1275 vm.g_st = o_g_st;
1276 insptr = end;
1277 }
1278 continue;
1279
1280 case CON_SORT:
1281 insptr++;
1282 {
1283 const int32_t aridx=*insptr++, count=Gv_GetVarX(*insptr++), state=*insptr++;
1284 const int32_t o_g_st = vm.g_st;
1285 instype *const end = insptr;
1286
1287 if (CheckArray(aridx))
1288 continue;
1289
1290 if (count <= 0)
1291 continue;
1292
1293 gamearray_t *const gar = &aGameArrays[aridx];
1294 Bassert((gar->dwFlags & (GAMEARRAY_READONLY|GAMEARRAY_VARSIZE)) == 0);
1295
1296 if (count > gar->size)
1297 {
1298 M32_ERROR("Count of elements to sort (%d) exceeds array size (%d)!",
1299 count, gar->size);
1300 continue;
1301 }
1302
1303 if (state < 0)
1304 {
1305 qsort(gar->vals, count, sizeof(int32_t), X_DoSortDefault);
1306 }
1307 else
1308 {
1309 x_sortingstateptr = apScript + statesinfo[state].ofs;
1310 vm.g_st = 1+MAXEVENTS+state;
1311 qsort(gar->vals, count, sizeof(int32_t), X_DoSort);
1312 vm.g_st = o_g_st;
1313 insptr = end;
1314 }
1315 }
1316 continue;
1317
1318 case CON_FOR: // special-purpose iteration
1319 insptr++;
1320 {
1321 const int32_t var = *insptr++, how = *insptr++;
1322 const int32_t parm2 = how<=ITER_DRAWNSPRITES ? 0 : Gv_GetVarX(*insptr++);
1323 instype *const end = insptr + *insptr, *const beg = ++insptr;
1324 const int32_t vm_i_bak = vm.spriteNum;
1325 uspritetype *const vm_sp_bak = vm.pUSprite;
1326
1327 if (vm.flags&VMFLAG_ERROR)
1328 continue;
1329
1330 switch (how)
1331 {
1332 case ITER_ALLSPRITES:
1333 for (bssize_t jj=0; jj<MAXSPRITES && !vm.flags; jj++)
1334 {
1335 if (sprite[jj].statnum == MAXSTATUS)
1336 continue;
1337 Gv_SetVarX(var, jj);
1338 vm.spriteNum = jj;
1339 vm.pSprite = &sprite[jj];
1340 insptr = beg;
1341 VM_Execute(1);
1342 }
1343 break;
1344 case ITER_ALLSECTORS:
1345 for (bssize_t jj=0; jj<numsectors && !vm.flags; jj++)
1346 {
1347 Gv_SetVarX(var, jj);
1348 insptr = beg;
1349 VM_Execute(1);
1350 }
1351 break;
1352 case ITER_ALLWALLS:
1353 for (bssize_t jj=0; jj<numwalls && !vm.flags; jj++)
1354 {
1355 Gv_SetVarX(var, jj);
1356 insptr = beg;
1357 VM_Execute(1);
1358 }
1359 break;
1360 case ITER_ACTIVELIGHTS:
1361 #ifdef POLYMER
1362 for (bssize_t jj=0; jj<PR_MAXLIGHTS; jj++)
1363 {
1364 if (!prlights[jj].flags.active)
1365 continue;
1366
1367 Gv_SetVarX(var, jj);
1368 insptr = beg;
1369 VM_Execute(1);
1370 }
1371 #else
1372 M32_ERROR("Polymer not compiled in, iteration over lights forbidden.");
1373 #endif
1374 break;
1375
1376 case ITER_SELSPRITES:
1377 for (bssize_t ii=0; ii<highlightcnt && !vm.flags; ii++)
1378 {
1379 int jj = highlight[ii];
1380 if (jj&0xc000)
1381 {
1382 jj &= (MAXSPRITES-1);
1383 Gv_SetVarX(var, jj);
1384 vm.spriteNum = jj;
1385 vm.pSprite = &sprite[jj];
1386 insptr = beg;
1387 VM_Execute(1);
1388 }
1389 }
1390 break;
1391 case ITER_SELSECTORS:
1392 for (bssize_t ii=0; ii<highlightsectorcnt && !vm.flags; ii++)
1393 {
1394 int jj=highlightsector[ii];
1395 Gv_SetVarX(var, jj);
1396 insptr = beg;
1397 VM_Execute(1);
1398 }
1399 break;
1400 case ITER_SELWALLS:
1401 for (bssize_t ii=0; ii<highlightcnt && !vm.flags; ii++)
1402 {
1403 int jj=highlight[ii];
1404 if (jj&0xc000)
1405 continue;
1406 Gv_SetVarX(var, jj);
1407 insptr = beg;
1408 VM_Execute(1);
1409 }
1410 break;
1411 case ITER_DRAWNSPRITES:
1412 {
1413 uspritetype lastSpriteBackup;
1414 auto const lastSpritePtr = (uspritetype *)&sprite[MAXSPRITES-1];
1415
1416 // Back up sprite MAXSPRITES-1.
1417 Bmemcpy(&lastSpriteBackup, lastSpritePtr, sizeof(uspritetype));
1418
1419 EDUKE32_STATIC_ASSERT(sizeof(uspritetype) == sizeof(tspritetype)); // see TSPRITE_SIZE
1420 for (bssize_t ii=0; ii<spritesortcnt && !vm.flags; ii++)
1421 {
1422 vm.pUSprite = lastSpritePtr;
1423 Bmemcpy(lastSpritePtr, &tsprite[ii], sizeof(tspritetype));
1424
1425 Gv_SetVarX(var, ii);
1426 insptr = beg;
1427 VM_Execute(1);
1428
1429 // Copy over potentially altered tsprite.
1430 Bmemcpy(&tsprite[ii], lastSpritePtr, sizeof(tspritetype));
1431 }
1432
1433 // Restore sprite MAXSPRITES-1.
1434 Bmemcpy(lastSpritePtr, &lastSpriteBackup, sizeof(uspritetype));
1435 break;
1436 }
1437 case ITER_SPRITESOFSECTOR:
1438 if (parm2 < 0 || parm2 >= MAXSECTORS)
1439 goto badindex;
1440 for (bssize_t jj=headspritesect[parm2]; jj>=0 && !vm.flags; jj=nextspritesect[jj])
1441 {
1442 Gv_SetVarX(var, jj);
1443 vm.spriteNum = jj;
1444 vm.pSprite = &sprite[jj];
1445 insptr = beg;
1446 VM_Execute(1);
1447 }
1448 break;
1449 case ITER_WALLSOFSECTOR:
1450 if (parm2 < 0 || parm2 >= MAXSECTORS)
1451 goto badindex;
1452 for (bssize_t jj=sector[parm2].wallptr, endwall=jj+sector[parm2].wallnum-1;
1453 jj<=endwall && !vm.flags; jj++)
1454 {
1455 Gv_SetVarX(var, jj);
1456 insptr = beg;
1457 VM_Execute(1);
1458 }
1459 break;
1460 case ITER_LOOPOFWALL:
1461 if (parm2 < 0 || parm2 >= numwalls)
1462 goto badindex;
1463 {
1464 int jj = parm2;
1465 do
1466 {
1467 Gv_SetVarX(var, jj);
1468 insptr = beg;
1469 VM_Execute(1);
1470 jj = wall[jj].point2;
1471 }
1472 while (jj != parm2 && !vm.flags);
1473 }
1474 break;
1475 case ITER_RANGE:
1476 for (bssize_t jj=0; jj<parm2 && !vm.flags; jj++)
1477 {
1478 Gv_SetVarX(var, jj);
1479 insptr = beg;
1480 VM_Execute(1);
1481 }
1482 break;
1483 default:
1484 M32_ERROR("Unknown iteration type %d!", how);
1485 continue;
1486 badindex:
1487 OSD_Printf("%sLine %d, %s %s: index %d out of range!\n", osd->draw.highlight,
1488 g_errorLineNum,keyw[g_tw], iter_tokens[how].token, parm2);
1489 vm.flags |= VMFLAG_ERROR;
1490 continue;
1491 }
1492 vm.spriteNum = vm_i_bak;
1493 vm.pUSprite = vm_sp_bak;
1494 vm.flags &= ~VMFLAG_BREAK;
1495 insptr = end;
1496 }
1497 continue;
1498
1499 case CON_IFVARAND:
1500 insptr++;
1501 {
1502 int32_t j=Gv_GetVarX(*insptr++);
1503 VM_DoConditional(j & *insptr);
1504 }
1505 continue;
1506
1507 case CON_IFVAROR:
1508 insptr++;
1509 {
1510 int32_t j=Gv_GetVarX(*insptr++);
1511 VM_DoConditional(j | *insptr);
1512 }
1513 continue;
1514
1515 case CON_IFVARXOR:
1516 insptr++;
1517 {
1518 int32_t j=Gv_GetVarX(*insptr++);
1519 VM_DoConditional(j ^ *insptr);
1520 }
1521 continue;
1522
1523 case CON_IFVAREITHER:
1524 insptr++;
1525 {
1526 int32_t j=Gv_GetVarX(*insptr++);
1527 VM_DoConditional(j || *insptr);
1528 }
1529 continue;
1530
1531 case CON_IFVARBOTH:
1532 insptr++;
1533 {
1534 int32_t j=Gv_GetVarX(*insptr++);
1535 VM_DoConditional(j && *insptr);
1536 }
1537 continue;
1538
1539 case CON_IFVARG:
1540 insptr++;
1541 {
1542 int32_t j=Gv_GetVarX(*insptr++);
1543 VM_DoConditional(j > *insptr);
1544 }
1545 continue;
1546
1547 case CON_IFVARGE:
1548 insptr++;
1549 {
1550 int32_t j=Gv_GetVarX(*insptr++);
1551 VM_DoConditional(j >= *insptr);
1552 }
1553 continue;
1554
1555 case CON_IFVARL:
1556 insptr++;
1557 {
1558 int32_t j=Gv_GetVarX(*insptr++);
1559 VM_DoConditional(j < *insptr);
1560 }
1561 continue;
1562
1563 case CON_IFVARLE:
1564 insptr++;
1565 {
1566 int32_t j=Gv_GetVarX(*insptr++);
1567 VM_DoConditional(j <= *insptr);
1568 }
1569 continue;
1570
1571 case CON_IFVARA:
1572 insptr++;
1573 {
1574 int32_t j=Gv_GetVarX(*insptr++);
1575 VM_DoConditional((uint32_t)j > (uint32_t)*insptr);
1576 }
1577 continue;
1578
1579 case CON_IFVARAE:
1580 insptr++;
1581 {
1582 int32_t j=Gv_GetVarX(*insptr++);
1583 VM_DoConditional((uint32_t)j >= (uint32_t)*insptr);
1584 }
1585 continue;
1586
1587 case CON_IFVARB:
1588 insptr++;
1589 {
1590 int32_t j=Gv_GetVarX(*insptr++);
1591 VM_DoConditional((uint32_t)j < (uint32_t)*insptr);
1592 }
1593 continue;
1594
1595 case CON_IFVARBE:
1596 insptr++;
1597 {
1598 int32_t j=Gv_GetVarX(*insptr++);
1599 VM_DoConditional((uint32_t)j <= (uint32_t)*insptr);
1600 }
1601 continue;
1602
1603 case CON_IFRND:
1604 VM_DoConditional(rnd(Gv_GetVarX(*(++insptr))));
1605 continue;
1606
1607 case CON_IFHITKEY:
1608 case CON_IFHOLDKEY:
1609 case CON_RESETKEY:
1610 case CON_SETKEY:
1611 insptr++;
1612 {
1613 int32_t key=Gv_GetVarX(*insptr);
1614 if (key<0 || key >= (int32_t)ARRAY_SIZE(keystatus))
1615 {
1616 M32_ERROR("Invalid key %d!", key);
1617 continue;
1618 }
1619
1620 if (tw == CON_IFHITKEY || tw == CON_IFHOLDKEY)
1621 VM_DoConditional(keystatus[key]);
1622 else
1623 insptr++;
1624
1625 if (tw != CON_IFHOLDKEY)
1626 {
1627 if (!(key==0 || key==KEYSC_ESC || key==KEYSC_TILDE || key==KEYSC_gENTER ||
1628 key==KEYSC_LALT || key==KEYSC_RALT || key==KEYSC_LCTRL || key==KEYSC_RCTRL ||
1629 key==KEYSC_LSHIFT || key==KEYSC_RSHIFT))
1630 keystatus[key] = (tw==CON_SETKEY);
1631 }
1632 }
1633 continue;
1634
1635 case CON_IFEITHERALT:
1636 VM_DoConditional(keystatus[KEYSC_LALT]||keystatus[KEYSC_RALT]);
1637 continue;
1638
1639 case CON_IFEITHERCTRL:
1640 VM_DoConditional(keystatus[KEYSC_LCTRL]||keystatus[KEYSC_RCTRL]);
1641 continue;
1642
1643 case CON_IFEITHERSHIFT:
1644 VM_DoConditional(keystatus[KEYSC_LSHIFT]||keystatus[KEYSC_RSHIFT]);
1645 continue;
1646
1647 // vvv CURSPR
1648 case CON_IFSPRITEPAL:
1649 insptr++;
1650 X_ERROR_INVALIDSP();
1651 VM_DoConditional(vm.pSprite->pal == Gv_GetVarX(*insptr));
1652 continue;
1653
1654 case CON_IFHIGHLIGHTED:
1655 insptr++;
1656 {
1657 int32_t id=*insptr++, index=Gv_GetVarX(*insptr);
1658
1659 if (index<0 || (id==M32_SPRITE_VAR_ID && index>=MAXSPRITES) || (id==M32_WALL_VAR_ID && index>=numwalls))
1660 {
1661 M32_ERROR("%s index %d out of range!", id==M32_SPRITE_VAR_ID?"Sprite":"Wall", index);
1662 continue;
1663 }
1664
1665 if (id==M32_SPRITE_VAR_ID)
1666 VM_DoConditional(show2dsprite[index>>3]&(1<<(index&7)));
1667 else
1668 VM_DoConditional(show2dwall[index>>3]&(1<<(index&7)));
1669 }
1670 continue;
1671
1672 case CON_IFANGDIFFL:
1673 insptr++;
1674 {
1675 int32_t j;
1676 X_ERROR_INVALIDSP();
1677 j = klabs(G_GetAngleDelta(ang, vm.pSprite->ang));
1678 VM_DoConditional(j <= Gv_GetVarX(*insptr));
1679 }
1680 continue;
1681
1682 case CON_IFAWAYFROMWALL:
1683 {
1684 int16_t s1;
1685 int32_t j = 0;
1686
1687 X_ERROR_INVALIDSP();
1688 s1 = vm.pSprite->sectnum;
1689 updatesector(vm.pSprite->x+108,vm.pSprite->y+108,&s1);
1690 if (s1 == vm.pSprite->sectnum)
1691 {
1692 updatesector(vm.pSprite->x-108,vm.pSprite->y-108,&s1);
1693 if (s1 == vm.pSprite->sectnum)
1694 {
1695 updatesector(vm.pSprite->x+108,vm.pSprite->y-108,&s1);
1696 if (s1 == vm.pSprite->sectnum)
1697 {
1698 updatesector(vm.pSprite->x-108,vm.pSprite->y+108,&s1);
1699 if (s1 == vm.pSprite->sectnum)
1700 j = 1;
1701 }
1702 }
1703 }
1704 VM_DoConditional(j);
1705 }
1706 continue;
1707
1708 case CON_IFCANSEE:
1709 {
1710 int32_t j;
1711
1712 X_ERROR_INVALIDSP();
1713 j = cansee(vm.pSprite->x,vm.pSprite->y,vm.pSprite->z/*-((krand()&41)<<8)*/,vm.pSprite->sectnum,
1714 pos.x, pos.y, pos.z /*-((krand()&41)<<8)*/, cursectnum);
1715 VM_DoConditional(j);
1716 }
1717 continue;
1718
1719 case CON_IFONWATER:
1720 X_ERROR_INVALIDSP();
1721 VM_DoConditional(sector[vm.pSprite->sectnum].lotag == 1 && klabs(vm.pSprite->z-sector[vm.pSprite->sectnum].floorz) < (32<<8));
1722 continue;
1723
1724 case CON_IFINWATER:
1725 X_ERROR_INVALIDSP();
1726 VM_DoConditional(sector[vm.pSprite->sectnum].lotag == 2);
1727 continue;
1728
1729 case CON_IFACTOR:
1730 insptr++;
1731 X_ERROR_INVALIDSP();
1732 VM_DoConditional(vm.pSprite->picnum == Gv_GetVarX(*insptr));
1733 continue;
1734
1735 case CON_IFINSIDE:
1736 insptr++;
1737 {
1738 int32_t x=Gv_GetVarX(*insptr++), y=Gv_GetVarX(*insptr++), sectnum=Gv_GetVarX(*insptr++), res;
1739
1740 res = inside(x, y, sectnum);
1741 if (res == -1)
1742 {
1743 M32_ERROR("Sector index %d out of range!", sectnum);
1744 continue;
1745 }
1746 insptr--;
1747 VM_DoConditional(res);
1748 }
1749 continue;
1750
1751 case CON_IFOUTSIDE:
1752 X_ERROR_INVALIDSP();
1753 VM_DoConditional(sector[vm.pSprite->sectnum].ceilingstat&1);
1754 continue;
1755
1756 case CON_IFPDISTL:
1757 insptr++;
1758 {
1759 X_ERROR_INVALIDSP();
1760 VM_DoConditional(dist((spritetype *)&pos, vm.pSprite) < Gv_GetVarX(*insptr));
1761 }
1762 continue;
1763
1764 case CON_IFPDISTG:
1765 insptr++;
1766 {
1767 X_ERROR_INVALIDSP();
1768 VM_DoConditional(dist((spritetype *)&pos, vm.pSprite) > Gv_GetVarX(*insptr));
1769 }
1770 continue;
1771 // ^^^
1772
1773 // *** BUILD functions
1774 case CON_INSERTSPRITE:
1775 insptr++;
1776 {
1777 int32_t dasectnum = Gv_GetVarX(*insptr++), ret;
1778
1779 X_ERROR_INVALIDSECT(dasectnum);
1780 if (Numsprites >= MAXSPRITES)
1781 {
1782 M32_ERROR("Maximum number of sprites reached.");
1783 continue;
1784 }
1785
1786 ret = insertsprite(dasectnum, 0);
1787 vm.spriteNum = ret;
1788 vm.pSprite = &sprite[ret];
1789 }
1790 continue;
1791
1792 case CON_DUPSPRITE:
1793 case CON_TDUPSPRITE:
1794 insptr++;
1795 {
1796 int32_t ospritenum = Gv_GetVarX(*insptr++), nspritenum;
1797
1798 if (ospritenum<0 || ospritenum>=MAXSPRITES || sprite[ospritenum].statnum==MAXSTATUS)
1799 {
1800 M32_ERROR("Tried to duplicate nonexistent sprite %d", ospritenum);
1801 }
1802 if ((tw==CON_DUPSPRITE && Numsprites >= MAXSPRITES) ||
1803 (tw==CON_DUPSPRITE && spritesortcnt >= maxspritesonscreen))
1804 {
1805 M32_ERROR("Maximum number of sprites reached.");
1806 }
1807
1808 if (vm.flags&VMFLAG_ERROR)
1809 continue;
1810
1811 if (tw==CON_DUPSPRITE)
1812 {
1813 nspritenum = insertsprite(sprite[ospritenum].sectnum, sprite[ospritenum].statnum);
1814
1815 if (nspritenum < 0)
1816 {
1817 M32_ERROR("Internal error.");
1818 continue;
1819 }
1820
1821 Bmemcpy(&sprite[nspritenum], &sprite[ospritenum], sizeof(spritetype));
1822 vm.spriteNum = nspritenum;
1823 vm.pSprite = &sprite[nspritenum];
1824 }
1825 else
1826 {
1827 tspriteptr_t tsp = renderAddTSpriteFromSprite(ospritenum);
1828 vm.spriteNum = -1;
1829
1830 EDUKE32_STATIC_ASSERT(sizeof(uspritetype) == sizeof(tspritetype)); // see TSPRITE_SIZE
1831 vm.pUSprite = (uspriteptr_t)tsp;
1832 }
1833 }
1834 continue;
1835
1836 case CON_DELETESPRITE:
1837 insptr++;
1838 {
1839 int32_t daspritenum = Gv_GetVarX(*insptr++), ret;
1840
1841 X_ERROR_INVALIDSPRI(daspritenum);
1842 ret = deletesprite(daspritenum);
1843 g_iReturnVar = ret;
1844 }
1845 continue;
1846
1847 case CON_GETSPRITELINKTYPE:
1848 insptr++;
1849 {
1850 int32_t spritenum=Gv_GetVarX(*insptr++), resvar = *insptr++;
1851
1852 X_ERROR_INVALIDSPRI(spritenum);
1853 Gv_SetVarX(resvar, taglab_linktags(1, spritenum));
1854 }
1855 continue;
1856
1857 case CON_LASTWALL:
1858 insptr++;
1859 {
1860 int32_t dapoint = Gv_GetVarX(*insptr++), resvar=*insptr++;
1861
1862 if (dapoint<0 || dapoint>=numwalls)
1863 {
1864 M32_ERROR("Invalid wall %d", dapoint);
1865 continue;
1866 }
1867
1868 Gv_SetVarX(resvar, lastwall(dapoint));
1869 }
1870 continue;
1871
1872 case CON_GETZRANGE:
1873 insptr++;
1874 {
1875 vec3_t vect;
1876
1877 vect.x = Gv_GetVarX(*insptr++);
1878 vect.y = Gv_GetVarX(*insptr++);
1879 vect.z = Gv_GetVarX(*insptr++);
1880
1881 {
1882 int32_t sectnum=Gv_GetVarX(*insptr++);
1883 int32_t ceilzvar=*insptr++, ceilhitvar=*insptr++, florzvar=*insptr++, florhitvar=*insptr++;
1884 int32_t walldist=Gv_GetVarX(*insptr++), clipmask=Gv_GetVarX(*insptr++);
1885 int32_t ceilz, ceilhit, florz, florhit;
1886
1887 X_ERROR_INVALIDSECT(sectnum);
1888 getzrange(&vect, sectnum, &ceilz, &ceilhit, &florz, &florhit, walldist, clipmask);
1889 Gv_SetVarX(ceilzvar, ceilz);
1890 Gv_SetVarX(ceilhitvar, ceilhit);
1891 Gv_SetVarX(florzvar, florz);
1892 Gv_SetVarX(florhitvar, florhit);
1893 }
1894 continue;
1895 }
1896
1897 case CON_CALCHYPOTENUSE:
1898 insptr++;
1899 {
1900 int32_t retvar=*insptr++;
1901 int64_t dax=Gv_GetVarX(*insptr++), day=Gv_GetVarX(*insptr++);
1902 int64_t hypsq = dax*dax + day*day;
1903
1904 if (hypsq > (int64_t)INT32_MAX)
1905 Gv_SetVarX(retvar, (int32_t)sqrt((double)hypsq));
1906 else
1907 Gv_SetVarX(retvar, ksqrt((uint32_t)hypsq));
1908
1909 continue;
1910 }
1911
1912 case CON_LINEINTERSECT:
1913 case CON_RAYINTERSECT:
1914 insptr++;
1915 {
1916 int32_t x1=Gv_GetVarX(*insptr++), y1=Gv_GetVarX(*insptr++), z1=Gv_GetVarX(*insptr++);
1917 int32_t x2=Gv_GetVarX(*insptr++), y2=Gv_GetVarX(*insptr++), z2=Gv_GetVarX(*insptr++);
1918 int32_t x3=Gv_GetVarX(*insptr++), y3=Gv_GetVarX(*insptr++), x4=Gv_GetVarX(*insptr++), y4=Gv_GetVarX(*insptr++);
1919 int32_t intxvar=*insptr++, intyvar=*insptr++, intzvar=*insptr++, retvar=*insptr++;
1920 int32_t intx, inty, intz, ret;
1921
1922 if (tw==CON_LINEINTERSECT)
1923 ret = lintersect(x1, y1, z1, x2, y2, z2, x3, y3, x4, y4, &intx, &inty, &intz);
1924 else
1925 ret = rayintersect(x1, y1, z1, x2, y2, z2, x3, y3, x4, y4, &intx, &inty, &intz);
1926
1927 Gv_SetVarX(retvar, ret);
1928 if (ret)
1929 {
1930 Gv_SetVarX(intxvar, intx);
1931 Gv_SetVarX(intyvar, inty);
1932 Gv_SetVarX(intzvar, intz);
1933 }
1934
1935 continue;
1936 }
1937
1938 case CON_CLIPMOVE:
1939 insptr++;
1940 {
1941 vec3_t vect;
1942 int32_t retvar=*insptr++, xvar=*insptr++, yvar=*insptr++, z=Gv_GetVarX(*insptr++), sectnumvar=*insptr++;
1943 int32_t xvect=Gv_GetVarX(*insptr++), yvect=Gv_GetVarX(*insptr++);
1944 int32_t walldist=Gv_GetVarX(*insptr++), floordist=Gv_GetVarX(*insptr++), ceildist=Gv_GetVarX(*insptr++);
1945 int32_t clipmask=Gv_GetVarX(*insptr++);
1946 int16_t sectnum;
1947
1948 vect.x = Gv_GetVarX(xvar);
1949 vect.y = Gv_GetVarX(yvar);
1950 vect.z = z;
1951 sectnum = Gv_GetVarX(sectnumvar);
1952
1953 X_ERROR_INVALIDSECT(sectnum);
1954
1955 Gv_SetVarX(retvar, clipmove(&vect, §num, xvect, yvect, walldist, floordist, ceildist, clipmask));
1956 Gv_SetVarX(sectnumvar, sectnum);
1957 Gv_SetVarX(xvar, vect.x);
1958 Gv_SetVarX(yvar, vect.y);
1959
1960 continue;
1961 }
1962
1963 case CON_HITSCAN:
1964 insptr++;
1965 {
1966 vec3_t vect;
1967 hitdata_t hit;
1968
1969 vect.x = Gv_GetVarX(*insptr++);
1970 vect.y = Gv_GetVarX(*insptr++);
1971 vect.z = Gv_GetVarX(*insptr++);
1972
1973 {
1974 int32_t sectnum=Gv_GetVarX(*insptr++);
1975 int32_t vx=Gv_GetVarX(*insptr++), vy=Gv_GetVarX(*insptr++), vz=Gv_GetVarX(*insptr++);
1976 int32_t hitsectvar=*insptr++, hitwallvar=*insptr++, hitspritevar=*insptr++;
1977 int32_t hitxvar=*insptr++, hityvar=*insptr++, hitzvar=*insptr++, cliptype=Gv_GetVarX(*insptr++);
1978
1979 X_ERROR_INVALIDSECT(sectnum);
1980 hitscan((const vec3_t *)&vect, sectnum, vx, vy, vz, &hit, cliptype);
1981 Gv_SetVarX(hitsectvar, hit.sect);
1982 Gv_SetVarX(hitwallvar, hit.wall);
1983 Gv_SetVarX(hitspritevar, hit.sprite);
1984 Gv_SetVarX(hitxvar, hit.pos.x);
1985 Gv_SetVarX(hityvar, hit.pos.y);
1986 Gv_SetVarX(hitzvar, hit.pos.z);
1987 }
1988 continue;
1989 }
1990
1991 case CON_CANSEE:
1992 insptr++;
1993 {
1994 int32_t x1=Gv_GetVarX(*insptr++), y1=Gv_GetVarX(*insptr++), z1=Gv_GetVarX(*insptr++);
1995 int32_t sect1=Gv_GetVarX(*insptr++);
1996 int32_t x2=Gv_GetVarX(*insptr++), y2=Gv_GetVarX(*insptr++), z2=Gv_GetVarX(*insptr++);
1997 int32_t sect2=Gv_GetVarX(*insptr++), rvar=*insptr++;
1998
1999 X_ERROR_INVALIDSECT(sect1);
2000 X_ERROR_INVALIDSECT(sect2);
2001
2002 Gv_SetVarX(rvar, cansee(x1,y1,z1,sect1,x2,y2,z2,sect2));
2003 continue;
2004 }
2005
2006 case CON_ROTATEPOINT:
2007 insptr++;
2008 {
2009 vec2_t pivot = { Gv_GetVarX(*insptr), Gv_GetVarX(*(insptr+1)) };
2010 vec2_t p = { Gv_GetVarX(*(insptr+2)), Gv_GetVarX(*(insptr+3)) };
2011 insptr += 4;
2012 int32_t daang=Gv_GetVarX(*insptr++);
2013 int32_t x2var=*insptr++, y2var=*insptr++;
2014 vec2_t p2;
2015
2016 rotatepoint(pivot,p,daang,&p2);
2017 Gv_SetVarX(x2var, p2.x);
2018 Gv_SetVarX(y2var, p2.y);
2019 continue;
2020 }
2021
2022 case CON_NEARTAG:
2023 insptr++;
2024 {
2025 // neartag(int32_t x, int32_t y, int32_t z, short sectnum, short ang, //Starting position & angle
2026 // short *neartagsector, //Returns near sector if sector[].tag != 0
2027 // short *neartagwall, //Returns near wall if wall[].tag != 0
2028 // short *neartagsprite, //Returns near sprite if sprite[].tag != 0
2029 // int32_t *neartaghitdist, //Returns actual distance to object (scale: 1024=largest grid size)
2030 // int32_t neartagrange, //Choose maximum distance to scan (scale: 1024=largest grid size)
2031 // char tagsearch) //1-lotag only, 2-hitag only, 3-lotag&hitag
2032
2033 int32_t x=Gv_GetVarX(*insptr++), y=Gv_GetVarX(*insptr++), z=Gv_GetVarX(*insptr++);
2034 int32_t sectnum=Gv_GetVarX(*insptr++), ang=Gv_GetVarX(*insptr++);
2035 int32_t neartagsectorvar=*insptr++, neartagwallvar=*insptr++, neartagspritevar=*insptr++, neartaghitdistvar=*insptr++;
2036 int32_t neartagrange=Gv_GetVarX(*insptr++), tagsearch=Gv_GetVarX(*insptr++);
2037
2038 int16_t neartagsector, neartagwall, neartagsprite;
2039 int32_t neartaghitdist;
2040
2041 X_ERROR_INVALIDSECT(sectnum);
2042 neartag(x, y, z, sectnum, ang, &neartagsector, &neartagwall, &neartagsprite,
2043 &neartaghitdist, neartagrange, tagsearch, NULL);
2044
2045 Gv_SetVarX(neartagsectorvar, neartagsector);
2046 Gv_SetVarX(neartagwallvar, neartagwall);
2047 Gv_SetVarX(neartagspritevar, neartagsprite);
2048 Gv_SetVarX(neartaghitdistvar, neartaghitdist);
2049 continue;
2050 }
2051
2052 case CON_BSETSPRITE: // was CON_SETSPRITE
2053 insptr++;
2054 {
2055 int32_t spritenum = Gv_GetVarX(*insptr++);
2056 vec3_t davector;
2057
2058 davector.x = Gv_GetVarX(*insptr++);
2059 davector.y = Gv_GetVarX(*insptr++);
2060 davector.z = Gv_GetVarX(*insptr++);
2061
2062 X_ERROR_INVALIDSPRI(spritenum);
2063 setsprite(spritenum, &davector);
2064 continue;
2065 }
2066
2067 case CON_GETFLORZOFSLOPE:
2068 case CON_GETCEILZOFSLOPE:
2069 insptr++;
2070 {
2071 int32_t sectnum = Gv_GetVarX(*insptr++), x = Gv_GetVarX(*insptr++), y = Gv_GetVarX(*insptr++);
2072 int32_t var=*insptr++;
2073
2074 X_ERROR_INVALIDSECT(sectnum);
2075 if (tw == CON_GETFLORZOFSLOPE)
2076 Gv_SetVarX(var, getflorzofslope(sectnum,x,y));
2077 else
2078 Gv_SetVarX(var, getceilzofslope(sectnum,x,y));
2079 continue;
2080 }
2081
2082 case CON_ALIGNFLORSLOPE:
2083 case CON_ALIGNCEILSLOPE:
2084 insptr++;
2085 {
2086 int32_t sectnum = Gv_GetVarX(*insptr++), x = Gv_GetVarX(*insptr++), y = Gv_GetVarX(*insptr++);
2087 int32_t z=Gv_GetVarX(*insptr++);
2088
2089 X_ERROR_INVALIDSECT(sectnum);
2090 if (tw == CON_ALIGNFLORSLOPE)
2091 alignflorslope(sectnum, x,y,z);
2092 else
2093 alignceilslope(sectnum, x,y,z);
2094 continue;
2095 }
2096
2097 // CURSPR
2098 case CON_SETFIRSTWALL:
2099 insptr++;
2100 {
2101 int32_t sect=Gv_GetVarX(*insptr++), wal=Gv_GetVarX(*insptr++);
2102
2103 X_ERROR_INVALIDSECT(sect);
2104 setfirstwall(sect, wal);
2105 }
2106 continue;
2107
2108 case CON_UPDATECURSECTNUM:
2109 insptr++;
2110 updatesectorz(pos.x, pos.y, pos.z, &cursectnum);
2111 continue;
2112
2113 case CON_UPDATESECTOR:
2114 case CON_UPDATESECTORZ:
2115 insptr++;
2116 {
2117 int32_t x=Gv_GetVarX(*insptr++), y=Gv_GetVarX(*insptr++);
2118 int32_t z=(tw==CON_UPDATESECTORZ)?Gv_GetVarX(*insptr++):0;
2119 int32_t var=*insptr++;
2120 int16_t w;
2121
2122 X_ERROR_INVALIDCI();
2123 w=sprite[vm.spriteNum].sectnum;
2124
2125 if (tw==CON_UPDATESECTOR) updatesector(x,y,&w);
2126 else updatesectorz(x,y,z,&w);
2127
2128 Gv_SetVarX(var, w);
2129 continue;
2130 }
2131
2132 case CON_HEADSPRITESTAT:
2133 insptr++;
2134 {
2135 int32_t i=*insptr++;
2136 int32_t j=Gv_GetVarX(*insptr++);
2137 if (j < 0 || j > MAXSTATUS)
2138 {
2139 M32_ERROR("invalid status list %d", j);
2140 continue;
2141 }
2142 Gv_SetVarX(i,headspritestat[j]);
2143 continue;
2144 }
2145
2146 case CON_PREVSPRITESTAT:
2147 insptr++;
2148 {
2149 int32_t i=*insptr++;
2150 int32_t j=Gv_GetVarX(*insptr++);
2151
2152 X_ERROR_INVALIDSPRI(j);
2153 Gv_SetVarX(i,prevspritestat[j]);
2154 continue;
2155 }
2156
2157 case CON_NEXTSPRITESTAT:
2158 insptr++;
2159 {
2160 int32_t i=*insptr++;
2161 int32_t j=Gv_GetVarX(*insptr++);
2162
2163 X_ERROR_INVALIDSPRI(j);
2164 Gv_SetVarX(i,nextspritestat[j]);
2165 continue;
2166 }
2167
2168 case CON_HEADSPRITESECT:
2169 insptr++;
2170 {
2171 int32_t i=*insptr++;
2172 int32_t j=Gv_GetVarX(*insptr++);
2173
2174 X_ERROR_INVALIDSECT(j);
2175 Gv_SetVarX(i,headspritesect[j]);
2176 continue;
2177 }
2178
2179 case CON_PREVSPRITESECT:
2180 insptr++;
2181 {
2182 int32_t i=*insptr++;
2183 int32_t j=Gv_GetVarX(*insptr++);
2184
2185 X_ERROR_INVALIDSPRI(j);
2186 Gv_SetVarX(i,prevspritesect[j]);
2187 continue;
2188 }
2189
2190 case CON_NEXTSPRITESECT:
2191 insptr++;
2192 {
2193 int32_t i=*insptr++;
2194 int32_t j=Gv_GetVarX(*insptr++);
2195
2196 X_ERROR_INVALIDSPRI(j);
2197 Gv_SetVarX(i,nextspritesect[j]);
2198 continue;
2199 }
2200
2201 case CON_CANSEESPR:
2202 insptr++;
2203 {
2204 int32_t lVar1 = Gv_GetVarX(*insptr++), lVar2 = Gv_GetVarX(*insptr++), res;
2205
2206 if (lVar1<0 || lVar1>=MAXSPRITES || sprite[lVar1].statnum==MAXSTATUS)
2207 {
2208 M32_ERROR("Invalid sprite %d", lVar1);
2209 }
2210 if (lVar2<0 || lVar2>=MAXSPRITES || sprite[lVar2].statnum==MAXSTATUS)
2211 {
2212 M32_ERROR("Invalid sprite %d", lVar2);
2213 }
2214
2215 if (vm.flags&VMFLAG_ERROR) res=0;
2216 else res=cansee(sprite[lVar1].x,sprite[lVar1].y,sprite[lVar1].z,sprite[lVar1].sectnum,
2217 sprite[lVar2].x,sprite[lVar2].y,sprite[lVar2].z,sprite[lVar2].sectnum);
2218
2219 Gv_SetVarX(*insptr++, res);
2220 continue;
2221 }
2222
2223 case CON_CHANGESPRITESTAT:
2224 case CON_CHANGESPRITESECT:
2225 insptr++;
2226 {
2227 int32_t i = Gv_GetVarX(*insptr++);
2228 int32_t j = Gv_GetVarX(*insptr++);
2229
2230 X_ERROR_INVALIDSPRI(i);
2231 if (j<0 || j >= (tw==CON_CHANGESPRITESTAT?MAXSTATUS:numsectors))
2232 {
2233 M32_ERROR("Invalid %s: %d", tw==CON_CHANGESPRITESTAT?"statnum":"sector", j);
2234 continue;
2235 }
2236
2237 if (tw == CON_CHANGESPRITESTAT)
2238 {
2239 if (sprite[i].statnum == j) continue;
2240 changespritestat(i,j);
2241 }
2242 else
2243 {
2244 if (sprite[i].sectnum == j) continue;
2245 changespritesect(i,j);
2246 }
2247 continue;
2248 }
2249
2250 case CON_DRAGPOINT:
2251 insptr++;
2252 {
2253 int32_t wallnum = Gv_GetVarX(*insptr++), newx = Gv_GetVarX(*insptr++), newy = Gv_GetVarX(*insptr++);
2254
2255 if (wallnum<0 || wallnum>=numwalls)
2256 {
2257 M32_ERROR("Invalid wall %d", wallnum);
2258 continue;
2259 }
2260 dragpoint(wallnum,newx,newy,0);
2261 continue;
2262 }
2263
2264 case CON_SECTOROFWALL:
2265 insptr++;
2266 {
2267 int32_t j = *insptr++;
2268 Gv_SetVarX(j, sectorofwall(Gv_GetVarX(*insptr++)));
2269 }
2270 continue;
2271
2272 case CON_FIXREPEATS:
2273 insptr++;
2274 fixrepeats(Gv_GetVarX(*insptr++));
2275 continue;
2276
2277 case CON_GETCLOSESTCOL:
2278 insptr++;
2279 {
2280 int32_t r = Gv_GetVarX(*insptr++), g = Gv_GetVarX(*insptr++), b = Gv_GetVarX(*insptr++);
2281 Gv_SetVarX(*insptr++, paletteGetClosestColor(r, g, b));
2282 continue;
2283 }
2284
2285 // *** stuff
2286 case CON_UPDATEHIGHLIGHT:
2287 insptr++;
2288 update_highlight();
2289 continue;
2290
2291 case CON_UPDATEHIGHLIGHTSECTOR:
2292 insptr++;
2293 update_highlightsector();
2294 continue;
2295
2296 case CON_SETHIGHLIGHT:
2297 insptr++;
2298 {
2299 int32_t what=Gv_GetVarX(*insptr++), index=Gv_GetVarX(*insptr++), doset = Gv_GetVarX(*insptr++);
2300
2301 if (highlightsectorcnt >= 0)
2302 {
2303 M32_ERROR("sector highlight active or pending, cannot highlight sprites/walls");
2304 continue;
2305 }
2306
2307 if (what&16384)
2308 {
2309 index &= ~16384;
2310 if (index < 0 || index>=MAXSPRITES || sprite[index].statnum==MAXSTATUS)
2311 {
2312 M32_ERROR("Invalid sprite index %d", index);
2313 continue;
2314 }
2315
2316 if (doset)
2317 show2dsprite[index>>3] |= (1<<(index&7));
2318 else
2319 show2dsprite[index>>3] &= ~(1<<(index&7));
2320 }
2321 else
2322 {
2323 if (index < 0 || index>=numwalls)
2324 {
2325 M32_ERROR("Invalid wall index %d", index);
2326 continue;
2327 }
2328
2329 if (doset)
2330 show2dwall[index>>3] |= (1<<(index&7));
2331 else
2332 show2dwall[index>>3] &= ~(1<<(index&7));
2333 }
2334
2335 vm.miscflags |= VMFLAG_MISC_UPDATEHL;
2336
2337 continue;
2338 }
2339
2340 case CON_SETHIGHLIGHTSECTOR:
2341 insptr++;
2342 {
2343 int32_t index=Gv_GetVarX(*insptr++), doset = Gv_GetVarX(*insptr++);
2344
2345 if (highlightcnt >= 0)
2346 {
2347 M32_ERROR("sprite/wall highlight active or pending, cannot highlight sectors");
2348 continue;
2349 }
2350
2351 X_ERROR_INVALIDSECT(index);
2352
2353 if (doset)
2354 hlsectorbitmap[index>>3] |= (1<<(index&7));
2355 else
2356 hlsectorbitmap[index>>3] &= ~(1<<(index&7));
2357
2358 vm.miscflags |= VMFLAG_MISC_UPDATEHLSECT;
2359
2360 continue;
2361 }
2362
2363 case CON_GETTIMEDATE:
2364 insptr++;
2365 {
2366 int32_t v1=*insptr++,v2=*insptr++,v3=*insptr++,v4=*insptr++,v5=*insptr++,v6=*insptr++,v7=*insptr++,v8=*insptr++;
2367 time_t rawtime;
2368 struct tm *ti;
2369
2370 time(&rawtime);
2371 ti = localtime(&rawtime);
2372 // initprintf("Time&date: %s\n",asctime (ti));
2373
2374 Gv_SetVarX(v1, ti->tm_sec);
2375 Gv_SetVarX(v2, ti->tm_min);
2376 Gv_SetVarX(v3, ti->tm_hour);
2377 Gv_SetVarX(v4, ti->tm_mday);
2378 Gv_SetVarX(v5, ti->tm_mon);
2379 Gv_SetVarX(v6, ti->tm_year+1900);
2380 Gv_SetVarX(v7, ti->tm_wday);
2381 Gv_SetVarX(v8, ti->tm_yday);
2382 continue;
2383 }
2384
2385 case CON_ADDLOG:
2386 {
2387 insptr++;
2388
2389 OSD_Printf("L=%d\n", g_errorLineNum);
2390 continue;
2391 }
2392
2393 case CON_ADDLOGVAR:
2394 insptr++;
2395 {
2396 char buf[80] = "", buf2[80] = "";
2397 int32_t code = (int32_t)*insptr, val = Gv_GetVarX(code);
2398 int32_t negate=code&M32_FLAG_NEGATE;
2399
2400 if (code & (0xFFFFFFFF-(MAXGAMEVARS-1)))
2401 {
2402 if ((code&M32_VARTYPE_MASK)==M32_FLAG_ARRAY || (code&M32_VARTYPE_MASK)==M32_FLAG_STRUCT)
2403 {
2404 if (code&M32_FLAG_CONSTANT)
2405 Bsprintf(buf2, "%d", (code>>16)&0xffff);
2406 else
2407 {
2408 char *label = aGameVars[(code>>16)&(MAXGAMEVARS-1)].szLabel;
2409 Bsprintf(buf2, "%s", label?label:"???");
2410 }
2411 }
2412 else if ((code&M32_VARTYPE_MASK)==M32_FLAG_LOCAL)
2413 Bsprintf(buf2, "%d", code&(MAXGAMEVARS-1));
2414
2415 if ((code&0x0000FFFC) == M32_FLAG_CONSTANT) // addlogvar for a constant.. why not? :P
2416 {
2417 switch (code&3)
2418 {
2419 case 0: Bsprintf(buf, "(immediate constant)"); break;
2420 case 1: Bsprintf(buf, "(indirect constant)"); break;
2421 case 2: Bsprintf(buf, "(label constant)"); break;
2422 default: Bsprintf(buf, "(??? constant)"); break;
2423 }
2424 }
2425 else
2426 {
2427 switch (code&M32_VARTYPE_MASK)
2428 {
2429 case M32_FLAG_ARRAY:
2430 Bsnprintf(buf, sizeof(buf), "%s[%s]", aGameArrays[code&(MAXGAMEARRAYS-1)].szLabel
2431 ? aGameArrays[code&(MAXGAMEARRAYS-1)].szLabel : "???", buf2);
2432 break;
2433 case M32_FLAG_STRUCT:
2434 {
2435 int32_t memberid=(code>>2)&63, lightp = (memberid >= LIGHT_X);
2436 const char *pp1[4] = {"sprite","sector","wall","tsprite"};
2437 const memberlabel_t *pp2[4] = {SpriteLabels, SectorLabels, WallLabels, SpriteLabels};
2438 if (lightp)
2439 {
2440 pp1[3] = "light";
2441 pp2[3] = LightLabels;
2442 memberid -= LIGHT_X;
2443 }
2444
2445 Bsnprintf(buf, sizeof(buf), "%s[%s].%s", pp1[code&3], buf2, pp2[code&3][memberid].name);
2446 }
2447 break;
2448 case M32_FLAG_VAR:
2449 Bstrcpy(buf, "???");
2450 break;
2451 case M32_FLAG_LOCAL:
2452 Bsnprintf(buf, sizeof(buf), ".local[%s]", buf2);
2453 break;
2454 }
2455 }
2456 }
2457 else
2458 {
2459 if (aGameVars[code].dwFlags & GAMEVAR_PERBLOCK)
2460 {
2461 Bsprintf(buf2, "(%s", vm.g_st==0? "top-level) " : vm.g_st<=MAXEVENTS? "event" : "state");
2462 if (vm.g_st >= 1+MAXEVENTS && vm.g_st <1+MAXEVENTS+g_stateCount)
2463 Bsprintf(buf, " `%s') ", statesinfo[vm.g_st-1-MAXEVENTS].name);
2464 else if (vm.g_st > 0)
2465 Bsprintf(buf, " %d) ", vm.g_st-1);
2466 Bstrcat(buf2, buf);
2467 }
2468
2469 Bsnprintf(buf, sizeof(buf), "%s%s", buf2, aGameVars[code].szLabel ? aGameVars[code].szLabel : "???");
2470 }
2471
2472 OSD_Printf("L%d: %s%s=%d\n", g_errorLineNum, negate?"-":"", buf, val);
2473
2474 insptr++;
2475 continue;
2476 }
2477
2478 case CON_DEBUG:
2479 insptr++;
2480 initprintf("%d\n",*insptr++);
2481 continue;
2482
2483 // *** strings
2484 case CON_REDEFINEQUOTE:
2485 insptr++;
2486 {
2487 int32_t q = *insptr++, i = *insptr++;
2488 X_ERROR_INVALIDQUOTE(q, apStrings);
2489 X_ERROR_INVALIDQUOTE(i, apXStrings);
2490 Bstrcpy(apStrings[q],apXStrings[i]);
2491 continue;
2492 }
2493
2494 case CON_GETNUMBER16: /* deprecated */
2495 case CON_GETNUMBER256: /* deprecated */
2496 case CON_GETNUMBERFROMUSER:
2497 insptr++;
2498 {
2499 int32_t var=*insptr++, quote=*insptr++;
2500 const char *quotetext = GetMaybeInlineQuote(quote);
2501 if (vm.flags&VMFLAG_ERROR)
2502 continue;
2503
2504 {
2505 int32_t max=Gv_GetVarX(*insptr++);
2506 int32_t sign = (tw==CON_GETNUMBERFROMUSER) ? Gv_GetVarX(*insptr++) : (max<=0);
2507 char buf[64]; // buffers in getnumber* are 80 bytes long
2508
2509 Bstrncpyz(buf, quotetext, sizeof(buf));
2510
2511 if (max==0)
2512 max = INT32_MAX;
2513 else
2514 max = klabs(max);
2515
2516 //OSD_Printf("max:%d, sign:%d\n", max, sign);
2517 if (tw==CON_GETNUMBERFROMUSER)
2518 {
2519 Gv_SetVarX(var, in3dmode() ?
2520 getnumber256(quotetext, Gv_GetVarX(var), max, sign) :
2521 getnumber16(quotetext, Gv_GetVarX(var), max, sign));
2522 }
2523 else if (tw==CON_GETNUMBER16)
2524 Gv_SetVarX(var, getnumber16(quotetext, Gv_GetVarX(var), max, sign));
2525 else
2526 Gv_SetVarX(var, getnumber256(quotetext, Gv_GetVarX(var), max, sign));
2527 }
2528 }
2529 continue;
2530
2531 case CON_PRINT:
2532 case CON_QUOTE:
2533 case CON_ERRORINS:
2534 case CON_PRINTMESSAGE16:
2535 case CON_PRINTMESSAGE256:
2536 case CON_PRINTEXT256:
2537 case CON_PRINTEXT16:
2538 case CON_DRAWLABEL:
2539 insptr++;
2540 {
2541 int32_t i=*insptr++;
2542 const char *quotetext = GetMaybeInlineQuote(i);
2543 if (vm.flags&VMFLAG_ERROR)
2544 continue;
2545
2546 {
2547 int32_t x=(tw>=CON_PRINTMESSAGE256)?Gv_GetVarX(*insptr++):0;
2548 int32_t y=(tw>=CON_PRINTMESSAGE256)?Gv_GetVarX(*insptr++):0;
2549
2550 int32_t col=(tw>=CON_PRINTEXT256)?Gv_GetVarX(*insptr++):0;
2551 int32_t backcol=(tw>=CON_PRINTEXT256)?Gv_GetVarX(*insptr++):0;
2552 int32_t fontsize=(tw>=CON_PRINTEXT256)?Gv_GetVarX(*insptr++):0;
2553
2554 if (tw==CON_PRINT || tw==CON_ERRORINS)
2555 {
2556 OSD_Printf("%s\n", quotetext);
2557 if (tw==CON_ERRORINS)
2558 vm.flags |= VMFLAG_ERROR;
2559 }
2560 else if (tw==CON_QUOTE)
2561 {
2562 message("%s", quotetext);
2563 }
2564 else if (tw==CON_PRINTMESSAGE16)
2565 {
2566 if (!in3dmode())
2567 printmessage16("%s", quotetext);
2568 }
2569 else if (tw==CON_PRINTMESSAGE256)
2570 {
2571 if (in3dmode())
2572 printmessage256(x, y, quotetext);
2573 }
2574 else if (tw==CON_PRINTEXT256)
2575 {
2576 if (in3dmode())
2577 {
2578 if (col>=256)
2579 col=0;
2580 else if (col < 0 && col >= -255)
2581 col = editorcolors[-col];
2582
2583 if (backcol<0 || backcol>=256)
2584 backcol=-1;
2585
2586 printext256(x, y, col, backcol, quotetext, fontsize);
2587 }
2588 }
2589 else if (tw==CON_PRINTEXT16)
2590 {
2591 if (!in3dmode())
2592 printext16(x, y, editorcolors[col&255], backcol<0 ? -1 : editorcolors[backcol&255],
2593 quotetext, fontsize);
2594 }
2595 else if (tw==CON_DRAWLABEL)
2596 {
2597 if (!in3dmode())
2598 {
2599 drawsmallabel(quotetext,
2600 editorcolors[backcol&255], // col
2601 fontsize < 0 ? -1 : editorcolors[fontsize&255], editorcolors[fontsize&255] - 3, // backcol
2602 x, y, col); // x y z
2603 }
2604 }
2605 }
2606 }
2607 continue;
2608
2609 case CON_QSTRLEN:
2610 insptr++;
2611 {
2612 int32_t i=*insptr++, quote=*insptr++;
2613 const char *quotetext = GetMaybeInlineQuote(quote);
2614 if (vm.flags&VMFLAG_ERROR)
2615 continue;
2616
2617 Gv_SetVarX(i, Bstrlen(quotetext));
2618 continue;
2619 }
2620
2621 case CON_QSUBSTR:
2622 insptr++;
2623 {
2624 int32_t q1 = Gv_GetVarX(*insptr++);
2625 int32_t q2 = *insptr++;
2626 const char *q2text = GetMaybeInlineQuote(q2);
2627 if (vm.flags&VMFLAG_ERROR)
2628 continue;
2629
2630 X_ERROR_INVALIDQUOTE(q1, apStrings);
2631
2632 {
2633 int32_t st = Gv_GetVarX(*insptr++);
2634 int32_t ln = Gv_GetVarX(*insptr++);
2635 char *s1 = apStrings[q1];
2636 const char *s2 = q2text;
2637
2638 while (*s2 && st--) s2++;
2639 while ((*s1 = *s2) && ln--)
2640 {
2641 s1++;
2642 s2++;
2643 }
2644 *s1=0;
2645 }
2646 continue;
2647 }
2648
2649 case CON_QSTRNCAT:
2650 case CON_QSTRCAT:
2651 case CON_QSTRCPY:
2652 /// case CON_QGETSYSSTR:
2653 insptr++;
2654 {
2655 int32_t i = Gv_GetVarX(*insptr++);
2656 int32_t j = *insptr++;
2657
2658 const char *quotetext = GetMaybeInlineQuote(j);
2659 if (vm.flags&VMFLAG_ERROR)
2660 continue;
2661
2662 X_ERROR_INVALIDQUOTE(i, apStrings);
2663
2664 switch (tw)
2665 {
2666 case CON_QSTRCAT:
2667 Bstrncat(apStrings[i], quotetext, (MAXQUOTELEN-1)-Bstrlen(apStrings[i]));
2668 break;
2669 case CON_QSTRNCAT:
2670 Bstrncat(apStrings[i], quotetext, Gv_GetVarX(*insptr++));
2671 break;
2672 case CON_QSTRCPY:
2673 Bstrcpy(apStrings[i], quotetext);
2674 break;
2675 }
2676 continue;
2677 }
2678
2679 case CON_QSPRINTF:
2680 insptr++;
2681 {
2682 int32_t dq=Gv_GetVarX(*insptr++), sq=*insptr++;
2683 const char *sourcetext = GetMaybeInlineQuote(sq);
2684 if (vm.flags&VMFLAG_ERROR)
2685 continue;
2686
2687 X_ERROR_INVALIDQUOTE(dq, apStrings);
2688
2689 {
2690 int32_t arg[32], numvals=0, i=0, j=0, k=0;
2691 int32_t len = Bstrlen(sourcetext);
2692 char tmpbuf[MAXQUOTELEN<<1];
2693
2694 while (*insptr != -1 && numvals < 32)
2695 arg[numvals++] = Gv_GetVarX(*insptr++);
2696
2697 insptr++; // skip the NOP
2698
2699 i = 0;
2700 do
2701 {
2702 while (k < len && j < MAXQUOTELEN && sourcetext[k] != '%')
2703 tmpbuf[j++] = sourcetext[k++];
2704
2705 if (sourcetext[k] == '%')
2706 {
2707 k++;
2708
2709 if (i>=numvals) goto dodefault;
2710
2711 switch (sourcetext[k])
2712 {
2713 case 'l':
2714 if (sourcetext[k+1] != 'd')
2715 {
2716 // write the % and l
2717 tmpbuf[j++] = sourcetext[k-1];
2718 tmpbuf[j++] = sourcetext[k++];
2719 break;
2720 }
2721 k++;
2722 fallthrough__;
2723 case 'd':
2724 {
2725 char buf[16];
2726 int32_t ii = 0;
2727
2728 Bsprintf(buf, "%d", arg[i++]);
2729
2730 ii = Bstrlen(buf);
2731 Bmemcpy(&tmpbuf[j], buf, ii);
2732 j += ii;
2733 k++;
2734 }
2735 break;
2736
2737 case 'f':
2738 {
2739 char buf[64];
2740 int32_t ii = 0;
2741
2742 Bsprintf(buf, "%f", *((float *)&arg[i++]));
2743
2744 ii = Bstrlen(buf);
2745 Bmemcpy(&tmpbuf[j], buf, ii);
2746 j += ii;
2747 k++;
2748 }
2749 break;
2750
2751 case 's':
2752 {
2753 if (arg[i]>=0 && arg[i]<MAXQUOTES && apStrings[arg[i]])
2754 {
2755 int32_t ii = Bstrlen(apStrings[arg[i]]);
2756 Bmemcpy(&tmpbuf[j], apStrings[arg[i]], ii);
2757 j += ii;
2758 }
2759 k++;
2760 }
2761 break;
2762
2763 dodefault:
2764 default:
2765 tmpbuf[j++] = sourcetext[k-1];
2766 break;
2767 }
2768 }
2769 }
2770 while (k < len && j < MAXQUOTELEN);
2771
2772 tmpbuf[j] = '\0';
2773 Bmemcpy(apStrings[dq], tmpbuf, MAXQUOTELEN);
2774 apStrings[dq][MAXQUOTELEN-1] = '\0';
2775 continue;
2776 }
2777 }
2778
2779 // *** findnear*
2780 // CURSPR vvv
2781 case CON_FINDNEARSPRITE:
2782 case CON_FINDNEARSPRITE3D:
2783 case CON_FINDNEARSPRITEVAR:
2784 case CON_FINDNEARSPRITE3DVAR:
2785 insptr++;
2786 {
2787 // syntax findnearactor(var) <type> <maxdist(var)> <getvar>
2788 // gets the sprite ID of the nearest actor within max dist
2789 // that is of <type> into <getvar>
2790 // -1 for none found
2791 // <type> <maxdist(varid)> <varid>
2792 int32_t lType=*insptr++;
2793 int32_t lMaxDist = (tw==CON_FINDNEARSPRITE || tw==CON_FINDNEARSPRITE3D)?
2794 *insptr++ : Gv_GetVarX(*insptr++);
2795 int32_t lVarID=*insptr++;
2796 int32_t lFound=-1, j, k = MAXSTATUS-1;
2797
2798 X_ERROR_INVALIDCI();
2799 do
2800 {
2801 j=headspritestat[k]; // all sprites
2802 if (tw==CON_FINDNEARSPRITE3D || tw==CON_FINDNEARSPRITE3DVAR)
2803 {
2804 while (j>=0)
2805 {
2806 if (sprite[j].picnum == lType && j != vm.spriteNum && dist(&sprite[vm.spriteNum], &sprite[j]) < lMaxDist)
2807 {
2808 lFound=j;
2809 j = MAXSPRITES;
2810 break;
2811 }
2812 j = nextspritestat[j];
2813 }
2814 if (j == MAXSPRITES)
2815 break;
2816 continue;
2817 }
2818
2819 while (j>=0)
2820 {
2821 if (sprite[j].picnum == lType && j != vm.spriteNum && ldist(&sprite[vm.spriteNum], &sprite[j]) < lMaxDist)
2822 {
2823 lFound=j;
2824 j = MAXSPRITES;
2825 break;
2826 }
2827 j = nextspritestat[j];
2828 }
2829
2830 if (j == MAXSPRITES)
2831 break;
2832 }
2833 while (k--);
2834 Gv_SetVarX(lVarID, lFound);
2835 continue;
2836 }
2837
2838 case CON_FINDNEARSPRITEZVAR:
2839 case CON_FINDNEARSPRITEZ:
2840 insptr++;
2841 {
2842 // syntax findnearactor(var) <type> <maxdist(var)> <getvar>
2843 // gets the sprite ID of the nearest actor within max dist
2844 // that is of <type> into <getvar>
2845 // -1 for none found
2846 // <type> <maxdist(varid)> <varid>
2847 int32_t lType=*insptr++;
2848 int32_t lMaxDist = (tw==CON_FINDNEARSPRITEZVAR) ? Gv_GetVarX(*insptr++) : *insptr++;
2849 int32_t lMaxZDist = (tw==CON_FINDNEARSPRITEZVAR) ? Gv_GetVarX(*insptr++) : *insptr++;
2850 int32_t lVarID=*insptr++;
2851 int32_t lFound=-1, lTemp, lTemp2, j, k=MAXSTATUS-1;
2852
2853 X_ERROR_INVALIDCI();
2854 do
2855 {
2856 j=headspritestat[k]; // all sprites
2857 if (j == -1) continue;
2858 do
2859 {
2860 if (sprite[j].picnum == lType && j != vm.spriteNum)
2861 {
2862 lTemp=ldist(&sprite[vm.spriteNum], &sprite[j]);
2863 if (lTemp < lMaxDist)
2864 {
2865 lTemp2=klabs(sprite[vm.spriteNum].z-sprite[j].z);
2866 if (lTemp2 < lMaxZDist)
2867 {
2868 lFound=j;
2869 j = MAXSPRITES;
2870 break;
2871 }
2872 }
2873 }
2874 j = nextspritestat[j];
2875 }
2876 while (j>=0);
2877 if (j == MAXSPRITES)
2878 break;
2879 }
2880 while (k--);
2881 Gv_SetVarX(lVarID, lFound);
2882
2883 continue;
2884 }
2885 // ^^^
2886
2887 case CON_GETTICKS:
2888 insptr++;
2889 {
2890 int32_t j=*insptr++;
2891 Gv_SetVarX(j, timerGetTicks());
2892 }
2893 continue;
2894
2895 case CON_SETASPECT:
2896 insptr++;
2897 {
2898 int32_t daxrange = Gv_GetVarX(*insptr++), dayxaspect = Gv_GetVarX(*insptr++);
2899 if (daxrange < (1<<12)) daxrange = (1<<12);
2900 if (daxrange > (1<<20)) daxrange = (1<<20);
2901 if (dayxaspect < (1<<12)) dayxaspect = (1<<12);
2902 if (dayxaspect > (1<<20)) dayxaspect = (1<<20);
2903 renderSetAspect(daxrange, dayxaspect);
2904 continue;
2905 }
2906
2907 // vvv CURSPR
2908 case CON_SETI:
2909 {
2910 int32_t newcurspritei;
2911
2912 insptr++;
2913 newcurspritei = Gv_GetVarX(*insptr++);
2914 X_ERROR_INVALIDSPRI(newcurspritei);
2915 vm.spriteNum = newcurspritei;
2916 vm.pSprite = &sprite[vm.spriteNum];
2917 continue;
2918 }
2919
2920 case CON_SIZEAT:
2921 insptr += 3;
2922 X_ERROR_INVALIDSP();
2923 vm.pSprite->xrepeat = (uint8_t) Gv_GetVarX(*(insptr-2));
2924 vm.pSprite->yrepeat = (uint8_t) Gv_GetVarX(*(insptr-1));
2925 #ifdef STRUCT_TRACKERS_ENABLED
2926 if (vm.spriteNum != -1) spritechanged[vm.spriteNum]++;
2927 #endif
2928 continue;
2929
2930 case CON_CSTAT:
2931 insptr += 2;
2932 X_ERROR_INVALIDSP();
2933 vm.pSprite->cstat = (int16_t) *(insptr-1);
2934 #ifdef STRUCT_TRACKERS_ENABLED
2935 if (vm.spriteNum != -1) spritechanged[vm.spriteNum]++;
2936 #endif
2937 continue;
2938
2939 case CON_CSTATOR:
2940 insptr += 2;
2941 X_ERROR_INVALIDSP();
2942 vm.pSprite->cstat |= (int16_t) Gv_GetVarX(*(insptr-1));
2943 #ifdef STRUCT_TRACKERS_ENABLED
2944 if (vm.spriteNum != -1) spritechanged[vm.spriteNum]++;
2945 #endif
2946 continue;
2947
2948 case CON_CLIPDIST:
2949 insptr += 2;
2950 X_ERROR_INVALIDSP();
2951 vm.pSprite->clipdist = (uint8_t) Gv_GetVarX(*(insptr-1));
2952 #ifdef STRUCT_TRACKERS_ENABLED
2953 if (vm.spriteNum != -1) spritechanged[vm.spriteNum]++;
2954 #endif
2955 continue;
2956
2957 case CON_SPRITEPAL:
2958 insptr += 2;
2959 X_ERROR_INVALIDSP();
2960 vm.pSprite->pal = Gv_GetVarX(*(insptr-1));
2961 #ifdef STRUCT_TRACKERS_ENABLED
2962 if (vm.spriteNum != -1) spritechanged[vm.spriteNum]++;
2963 #endif
2964 continue;
2965
2966 case CON_CACTOR:
2967 insptr += 2;
2968 X_ERROR_INVALIDSP();
2969 vm.pSprite->picnum = Gv_GetVarX(*(insptr-1));
2970 #ifdef STRUCT_TRACKERS_ENABLED
2971 if (vm.spriteNum != -1) spritechanged[vm.spriteNum]++;
2972 #endif
2973 continue;
2974
2975 case CON_SPGETLOTAG:
2976 insptr++;
2977 X_ERROR_INVALIDSP();
2978 Gv_SetVarX(M32_LOTAG_VAR_ID, vm.pSprite->lotag);
2979 continue;
2980
2981 case CON_SPGETHITAG:
2982 insptr++;
2983 X_ERROR_INVALIDSP();
2984 Gv_SetVarX(M32_HITAG_VAR_ID, vm.pSprite->hitag);
2985 continue;
2986
2987 case CON_SECTGETLOTAG:
2988 insptr++;
2989 X_ERROR_INVALIDSP();
2990 Gv_SetVarX(M32_LOTAG_VAR_ID, sector[vm.pSprite->sectnum].lotag);
2991 continue;
2992
2993 case CON_SECTGETHITAG:
2994 insptr++;
2995 X_ERROR_INVALIDSP();
2996 Gv_SetVarX(M32_HITAG_VAR_ID, sector[vm.pSprite->sectnum].hitag);
2997 continue;
2998
2999 case CON_GETTEXTUREFLOOR:
3000 insptr++;
3001 X_ERROR_INVALIDSP();
3002 Gv_SetVarX(M32_TEXTURE_VAR_ID, sector[vm.pSprite->sectnum].floorpicnum);
3003 continue;
3004
3005 case CON_GETTEXTURECEILING:
3006 insptr++;
3007 X_ERROR_INVALIDSP();
3008 Gv_SetVarX(M32_TEXTURE_VAR_ID, sector[vm.pSprite->sectnum].ceilingpicnum);
3009 continue;
3010 // ^^^
3011 case CON_DRAWLINE16:
3012 case CON_DRAWLINE16B:
3013 case CON_DRAWLINE16Z:
3014 insptr++;
3015 {
3016 int32_t x1=Gv_GetVarX(*insptr++), y1=Gv_GetVarX(*insptr++);
3017 int32_t z1=tw==CON_DRAWLINE16Z?Gv_GetVarX(*insptr++):0;
3018 int32_t x2=Gv_GetVarX(*insptr++), y2=Gv_GetVarX(*insptr++);
3019 int32_t z2=tw==CON_DRAWLINE16Z?Gv_GetVarX(*insptr++):0;
3020 int32_t col=Gv_GetVarX(*insptr++), odrawlinepat=drawlinepat;
3021 int32_t xofs=0, yofs=0;
3022
3023 if (tw==CON_DRAWLINE16B || tw==CON_DRAWLINE16Z)
3024 {
3025 editorGet2dScreenCoordinates(&x1,&y1, x1-pos.x,y1-pos.y, zoom);
3026 editorGet2dScreenCoordinates(&x2,&y2, x2-pos.x,y2-pos.y, zoom);
3027
3028 if (tw==CON_DRAWLINE16Z && m32_sideview)
3029 {
3030 y1 += getscreenvdisp(z1-pos.z,zoom);
3031 y2 += getscreenvdisp(z2-pos.z,zoom);
3032 }
3033
3034 xofs = halfxdim16;
3035 yofs = midydim16;
3036 }
3037
3038 drawlinepat = m32_drawlinepat;
3039 editorDraw2dLine(xofs+x1,yofs+y1, xofs+x2,yofs+y2, col>=0?editorcolors[col&15]:((-col)&255));
3040 drawlinepat = odrawlinepat;
3041 continue;
3042 }
3043
3044 case CON_DRAWCIRCLE16:
3045 case CON_DRAWCIRCLE16B:
3046 case CON_DRAWCIRCLE16Z:
3047 insptr++;
3048 {
3049 int32_t x1=Gv_GetVarX(*insptr++), y1=Gv_GetVarX(*insptr++);
3050 int32_t z1 = tw==CON_DRAWCIRCLE16Z ? Gv_GetVarX(*insptr++) : 0;
3051 int32_t r=Gv_GetVarX(*insptr++);
3052 int32_t col=Gv_GetVarX(*insptr++), odrawlinepat=drawlinepat;
3053 int32_t xofs=0, yofs=0, eccen=16384;
3054
3055 if (tw==CON_DRAWCIRCLE16B || tw==CON_DRAWCIRCLE16Z)
3056 {
3057 editorGet2dScreenCoordinates(&x1,&y1, x1-pos.x,y1-pos.y, zoom);
3058 if (m32_sideview)
3059 y1 += getscreenvdisp(z1-pos.z, zoom);
3060 r = mulscale14(r,zoom);
3061 eccen = scalescreeny(eccen);
3062 xofs = halfxdim16;
3063 yofs = midydim16;
3064 }
3065
3066 drawlinepat = m32_drawlinepat;
3067 editorDraw2dCircle(xofs+x1, yofs+y1, r, eccen, col>=0?editorcolors[col&15]:((-col)&255));
3068 drawlinepat = odrawlinepat;
3069 continue;
3070 }
3071
3072 case CON_ROTATESPRITEA:
3073 case CON_ROTATESPRITE16:
3074 case CON_ROTATESPRITE:
3075 insptr++;
3076 {
3077 int32_t x=Gv_GetVarX(*insptr++), y=Gv_GetVarX(*insptr++), z=Gv_GetVarX(*insptr++);
3078 int32_t a=Gv_GetVarX(*insptr++), tilenum=Gv_GetVarX(*insptr++), shade=Gv_GetVarX(*insptr++);
3079 int32_t pal=Gv_GetVarX(*insptr++), orientation=Gv_GetVarX(*insptr++);
3080 int32_t alpha = (tw == CON_ROTATESPRITEA) ? Gv_GetVarX(*insptr++) : 0;
3081 int32_t x1=Gv_GetVarX(*insptr++), y1=Gv_GetVarX(*insptr++);
3082 int32_t x2=Gv_GetVarX(*insptr++), y2=Gv_GetVarX(*insptr++);
3083
3084 if (tw != CON_ROTATESPRITE16 && !(orientation&ROTATESPRITE_FULL16))
3085 {
3086 x<<=16;
3087 y<<=16;
3088 }
3089
3090 orientation &= (ROTATESPRITE_MAX-1);
3091
3092 rotatesprite_(x,y,z,a,tilenum,shade,pal,2|orientation,alpha,0,x1,y1,x2,y2);
3093 continue;
3094 }
3095
3096 case CON_SETGAMEPALETTE:
3097 insptr++;
3098 SetGamePalette(Gv_GetVarX(*insptr++));
3099 continue;
3100
3101 // *** sounds
3102 case CON_IFSOUND:
3103 insptr++;
3104 {
3105 int32_t j=Gv_GetVarX(*insptr);
3106 if (S_InvalidSound(j))
3107 {
3108 M32_ERROR("Invalid sound %d", j);
3109 insptr++;
3110 continue;
3111 }
3112 VM_DoConditional(S_CheckSoundPlaying(vm.spriteNum,j));
3113 }
3114 continue;
3115
3116 case CON_IFNOSOUNDS:
3117 VM_DoConditional(S_SoundsPlaying(vm.spriteNum) < 0);
3118 continue;
3119
3120 case CON_IFIN3DMODE:
3121 VM_DoConditional(in3dmode());
3122 continue;
3123
3124 // ifaimingsprite and -wall also work in 2d mode, but you must "and" with 16383 yourself
3125 case CON_IFAIMINGSPRITE:
3126 VM_DoConditional(AIMING_AT_SPRITE || (!in3dmode() && pointhighlight>=16384));
3127 continue;
3128 case CON_IFAIMINGWALL:
3129 VM_DoConditional(AIMING_AT_WALL_OR_MASK || (!in3dmode() && linehighlight>=0));
3130 continue;
3131 case CON_IFAIMINGSECTOR:
3132 VM_DoConditional(AIMING_AT_CEILING_OR_FLOOR);
3133 continue;
3134 case CON_IFINTERACTIVE:
3135 VM_DoConditional(vm.miscflags&VMFLAG_MISC_INTERACTIVE);
3136 continue;
3137
3138 case CON_GETSOUNDFLAGS:
3139 insptr++;
3140 {
3141 int32_t j=Gv_GetVarX(*insptr++), var=*insptr++;
3142 if (S_InvalidSound(j))
3143 {
3144 M32_ERROR("Invalid sound %d", j);
3145 insptr++;
3146 continue;
3147 }
3148
3149 Gv_SetVarX(var, S_SoundFlags(j));
3150 }
3151 continue;
3152
3153 case CON_SOUNDVAR:
3154 case CON_STOPSOUNDVAR:
3155 case CON_SOUNDONCEVAR:
3156 case CON_GLOBALSOUNDVAR:
3157 insptr++;
3158 {
3159 int32_t j=Gv_GetVarX(*insptr++);
3160
3161 if (S_InvalidSound(j))
3162 {
3163 M32_ERROR("Invalid sound %d", j);
3164 continue;
3165 }
3166
3167 switch (tw)
3168 {
3169 case CON_SOUNDONCEVAR:
3170 if (!S_CheckSoundPlaying(vm.spriteNum,j))
3171 A_PlaySound((int16_t)j,vm.spriteNum);
3172 break;
3173 case CON_GLOBALSOUNDVAR:
3174 A_PlaySound((int16_t)j,-1);
3175 break;
3176 case CON_STOPSOUNDVAR:
3177 if (S_CheckSoundPlaying(vm.spriteNum,j))
3178 S_StopSound((int16_t)j);
3179 break;
3180 case CON_SOUNDVAR:
3181 A_PlaySound((int16_t)j,vm.spriteNum);
3182 break;
3183 }
3184 }
3185 continue;
3186
3187 case CON_STOPALLSOUNDS:
3188 insptr++;
3189 S_StopAllSounds();
3190 continue;
3191
3192 default:
3193 VM_ScriptInfo();
3194
3195 OSD_Printf("\nAn error has occurred in the Mapster32 virtual machine.\n\n"
3196 "Please e-mail the file mapster32.log along with every M32 file\n"
3197 "you're using and instructions how to reproduce this error to\n"
3198 "development@voidpoint.com.\n\n"
3199 "Thank you!\n");
3200 vm.flags |= VMFLAG_ERROR;
3201 Bfflush(NULL);
3202 return 1;
3203 }
3204 }
3205
3206 return 0;
3207 }
3208