/ source / blood / src / m32exec.cpp
m32exec.cpp
   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
  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  
  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  
 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  
 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  
 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  
 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  
 227  static int X_DoSortDefault(const void *lv, const void *rv)
 228  {
 229      return *(int32_t const *)rv - *(int32_t const *)lv;
 230  }
 231  
 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  
 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  
 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  
 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[bitmap_size(MAXSECTORS)];
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]&(1<<(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]&(1<<(index&7)));
1672                  else
1673                      VM_DoConditional(show2dwall[index>>3]&(1<<(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, &sectnum, 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] |= (1<<(index&7));
2337                      else
2338                          show2dsprite[index>>3] &= ~(1<<(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] |= (1<<(index&7));
2350                      else
2351                          show2dwall[index>>3] &= ~(1<<(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] |= (1<<(index&7));
2374                  else
2375                      hlsectorbitmap[index>>3] &= ~(1<<(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                              const memberlabel_t *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  
3065          case CON_DRAWCIRCLE16:
3066          case CON_DRAWCIRCLE16B:
3067          case CON_DRAWCIRCLE16Z:
3068              insptr++;
3069              {
3070                  int32_t x1=Gv_GetVar(*insptr++), y1=Gv_GetVar(*insptr++);
3071                  int32_t z1 = tw==CON_DRAWCIRCLE16Z ? Gv_GetVar(*insptr++) : 0;
3072                  int32_t r=Gv_GetVar(*insptr++);
3073                  int32_t col=Gv_GetVar(*insptr++), odrawlinepat=drawlinepat;
3074                  int32_t xofs=0, yofs=0, eccen=16384;
3075  
3076                  if (tw==CON_DRAWCIRCLE16B || tw==CON_DRAWCIRCLE16Z)
3077                  {
3078                      editorGet2dScreenCoordinates(&x1,&y1, x1-pos.x,y1-pos.y, zoom);
3079                      if (m32_sideview)
3080                          y1 += getscreenvdisp(z1-pos.z, zoom);
3081                      r = mulscale14(r,zoom);
3082                      eccen = scalescreeny(eccen);
3083                      xofs = halfxdim16;
3084                      yofs = midydim16;
3085                  }
3086  
3087                  drawlinepat = m32_drawlinepat;
3088                  editorDraw2dCircle(xofs+x1, yofs+y1, r, eccen, col>=0?editorcolors[col&15]:((-col)&255));
3089                  drawlinepat = odrawlinepat;
3090                  continue;
3091              }
3092  
3093          case CON_ROTATESPRITEA:
3094          case CON_ROTATESPRITE16:
3095          case CON_ROTATESPRITE:
3096              insptr++;
3097              {
3098                  int32_t x=Gv_GetVar(*insptr++),   y=Gv_GetVar(*insptr++),           z=Gv_GetVar(*insptr++);
3099                  int32_t a=Gv_GetVar(*insptr++),   tilenum=Gv_GetVar(*insptr++),     shade=Gv_GetVar(*insptr++);
3100                  int32_t pal=Gv_GetVar(*insptr++), orientation=Gv_GetVar(*insptr++);
3101                  int32_t alpha = (tw == CON_ROTATESPRITEA) ? Gv_GetVar(*insptr++) : 0;
3102                  int32_t x1=Gv_GetVar(*insptr++),  y1=Gv_GetVar(*insptr++);
3103                  int32_t x2=Gv_GetVar(*insptr++),  y2=Gv_GetVar(*insptr++);
3104  
3105                  if (tw != CON_ROTATESPRITE16 && !(orientation&ROTATESPRITE_FULL16))
3106                  {
3107                      x<<=16;
3108                      y<<=16;
3109                  }
3110  
3111                  orientation &= (ROTATESPRITE_MAX-1);
3112  
3113                  rotatesprite_(x,y,z,a,tilenum,shade,pal,2|orientation,alpha,0,x1,y1,x2,y2);
3114                  continue;
3115              }
3116  
3117          case CON_SETGAMEPALETTE:
3118              insptr++;
3119              SetGamePalette(Gv_GetVar(*insptr++));
3120              continue;
3121  
3122  // *** sounds
3123          //case CON_IFSOUND:
3124          //    insptr++;
3125          //    {
3126          //        int32_t j=Gv_GetVar(*insptr);
3127          //        if (S_InvalidSound(j))
3128          //        {
3129          //            M32_ERROR("Invalid sound %d", j);
3130          //            insptr++;
3131          //            continue;
3132          //        }
3133          //        VM_DoConditional(S_CheckSoundPlaying(vm.spriteNum,j));
3134          //    }
3135          //    continue;
3136  
3137          //case CON_IFNOSOUNDS:
3138          //    VM_DoConditional(S_SoundsPlaying(vm.spriteNum) < 0);
3139          //continue;
3140  
3141          case CON_IFIN3DMODE:
3142              VM_DoConditional(in3dmode());
3143              continue;
3144  
3145          // ifaimingsprite and -wall also work in 2d mode, but you must "and" with 16383 yourself
3146          case CON_IFAIMINGSPRITE:
3147              VM_DoConditional(AIMING_AT_SPRITE || (!in3dmode() && pointhighlight>=16384));
3148              continue;
3149          case CON_IFAIMINGWALL:
3150              VM_DoConditional(AIMING_AT_WALL_OR_MASK || (!in3dmode() && linehighlight>=0));
3151              continue;
3152          case CON_IFAIMINGSECTOR:
3153              VM_DoConditional(AIMING_AT_CEILING_OR_FLOOR);
3154              continue;
3155          case CON_IFINTERACTIVE:
3156              VM_DoConditional(vm.miscflags&VMFLAG_MISC_INTERACTIVE);
3157              continue;
3158  
3159          //case CON_GETSOUNDFLAGS:
3160          //    insptr++;
3161          //    {
3162          //        int32_t j=Gv_GetVar(*insptr++), var=*insptr++;
3163          //        if (S_InvalidSound(j))
3164          //        {
3165          //            M32_ERROR("Invalid sound %d", j);
3166          //            insptr++;
3167          //            continue;
3168          //        }
3169          //
3170          //        Gv_SetVar(var, S_SoundFlags(j));
3171          //    }
3172          //    continue;
3173          //
3174          //case CON_SOUNDVAR:
3175          //case CON_STOPSOUNDVAR:
3176          //case CON_SOUNDONCEVAR:
3177          //case CON_GLOBALSOUNDVAR:
3178          //    insptr++;
3179          //    {
3180          //        int32_t j=Gv_GetVar(*insptr++);
3181          //
3182          //        if (S_InvalidSound(j))
3183          //        {
3184          //            M32_ERROR("Invalid sound %d", j);
3185          //            continue;
3186          //        }
3187          //
3188          //        switch (tw)
3189          //        {
3190          //        case CON_SOUNDONCEVAR:
3191          //            if (!S_CheckSoundPlaying(vm.spriteNum,j))
3192          //                A_PlaySound((int16_t)j,vm.spriteNum);
3193          //            break;
3194          //        case CON_GLOBALSOUNDVAR:
3195          //            A_PlaySound((int16_t)j,-1);
3196          //            break;
3197          //        case CON_STOPSOUNDVAR:
3198          //            if (S_CheckSoundPlaying(vm.spriteNum,j))
3199          //                S_StopSound((int16_t)j);
3200          //            break;
3201          //        case CON_SOUNDVAR:
3202          //            A_PlaySound((int16_t)j,vm.spriteNum);
3203          //            break;
3204          //        }
3205          //    }
3206          //    continue;
3207          //
3208          //case CON_STOPALLSOUNDS:
3209          //    insptr++;
3210          //    S_StopAllSounds();
3211          //    continue;
3212  
3213          default:
3214              VM_ScriptInfo();
3215  
3216              OSD_Printf("\nAn error has occurred in the Mapster32 virtual machine.\n\n"
3217                         "Please e-mail the file mapster32.log along with every M32 file\n"
3218                         "you're using and instructions how to reproduce this error to\n"
3219                         "development@voidpoint.com.\n\n"
3220                         "Thank you!\n");
3221              vm.flags |= VMFLAG_ERROR;
3222              Bfflush(NULL);
3223              return 1;
3224          }
3225      }
3226  
3227      return 0;
3228  }