home *** CD-ROM | disk | FTP | other *** search
/ hobbes.nmsu.edu 2008 / 2008-06-02_hobbes.nmsu.edu.zip / new / scummc-0.2.0-os2.zip / ScummC / src / scvm_op.c < prev    next >
Encoding:
C/C++ Source or Header  |  2007-12-18  |  51.6 KB  |  2,097 lines

  1. /* ScummC
  2.  * Copyright (C) 2006  Alban Bedel
  3.  *
  4.  * This program is free software; you can redistribute it and/or
  5.  * modify it under the terms of the GNU General Public License
  6.  * as published by the Free Software Foundation; either version 2
  7.  * of the License, or (at your option) any later version.
  8.  
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  17.  *
  18.  */
  19.  
  20. /**
  21.  * @file scvm_op.c
  22.  * @ingroup scvm
  23.  * @brief SCVM op-code implementation
  24.  */
  25.  
  26. #include "config.h"
  27.  
  28. #include <stdlib.h>
  29. #include <stdio.h>
  30. #include <string.h>
  31. #include <inttypes.h>
  32. #include <errno.h>
  33. #include <stdarg.h>
  34. #include <sys/types.h>
  35. #include <sys/stat.h>
  36. #include <fcntl.h>
  37. #include <math.h>
  38.  
  39. #include "scc_fd.h"
  40. #include "scc_util.h"
  41. #include "scc_cost.h"
  42. #include "scc_box.h"
  43. #include "scvm_res.h"
  44. #include "scvm_thread.h"
  45. #include "scvm.h"
  46.  
  47. // Basic stack ops
  48.  
  49. int scvm_push(scvm_t* vm,int val) {
  50.   if(vm->stack_ptr + 1 >= vm->stack_size) {
  51.     scc_log(LOG_ERR,"Stack overflow!\n");
  52.     return SCVM_ERR_STACK_OVERFLOW;
  53.   }
  54.   scc_log(LOG_MSG,"Push %d\n",val);
  55.   vm->stack[vm->stack_ptr] = val;
  56.   vm->stack_ptr++;
  57.   return 0;
  58. }
  59.  
  60. int scvm_pop(scvm_t* vm,int* val) {
  61.   if(vm->stack_ptr < 1) {
  62.     scc_log(LOG_ERR,"Stack underflow!\n");
  63.     return SCVM_ERR_STACK_UNDERFLOW;
  64.   }
  65.   vm->stack_ptr--;
  66.   scc_log(LOG_MSG,"Pop %d\n",vm->stack[vm->stack_ptr]);
  67.   if(val) *val = vm->stack[vm->stack_ptr];
  68.   return 0;
  69. }
  70.  
  71. int scvm_vpop(scvm_t* vm, ...) {
  72.   va_list ap;
  73.   int* val,r;
  74.   va_start(ap,vm);
  75.   while((val = va_arg(ap,int*)))
  76.     if((r = scvm_pop(vm,val))) return r;
  77.   va_end(ap);
  78.   return 0;
  79. }
  80.  
  81. int scvm_peek(scvm_t* vm,int* val) {
  82.   if(vm->stack_ptr < 1) {
  83.     scc_log(LOG_ERR,"Stack underflow!\n");
  84.     return SCVM_ERR_STACK_UNDERFLOW;
  85.   }
  86.   if(val) *val = vm->stack[vm->stack_ptr-1];
  87.   return 0;
  88. }
  89.  
  90. int scvm_thread_read_var(scvm_t* vm, scvm_thread_t* thread,
  91.                          uint16_t addr, int* val) {
  92.   // decode the address
  93.   if(addr & 0x8000) { // bit variable
  94.     addr &= 0x7FFF;
  95.     if(addr >= vm->num_bitvar) return SCVM_ERR_BAD_ADDR;
  96.     *val = (vm->bitvar[addr>>3]>>(addr&7))&1;
  97.     scc_log(LOG_MSG,"Read bit var %d: %d\n",addr,*val);
  98.   } else if(addr & 0x4000) { // thread local variable
  99.     addr &= 0x3FFF;
  100.     if(!thread || addr >= thread->num_var) return SCVM_ERR_BAD_ADDR;
  101.     *val = thread->var[addr];
  102.     scc_log(LOG_MSG,"Read local var %d: %d\n",addr,*val);
  103.   } else { // global variable
  104.     addr &= 0x3FFF;
  105.     if(addr >= vm->num_var) return SCVM_ERR_BAD_ADDR;
  106.     if(addr < 0x100 && vm->get_var[addr])
  107.       *val = vm->get_var[addr](vm,addr);
  108.     else
  109.       *val = vm->var_mem[addr];
  110.     scc_log(LOG_MSG,"Read global var %d: %d\n",addr,*val);
  111.   }
  112.   return 0;
  113. }
  114.  
  115. int scvm_thread_write_var(scvm_t* vm, scvm_thread_t* thread,
  116.                           uint16_t addr, int val) {
  117.   // decode the address
  118.   if(addr & 0x8000) { // bit variable
  119.     addr &= 0x7FFF;
  120.     if(addr >= vm->num_bitvar) return SCVM_ERR_BAD_ADDR;
  121.     vm->bitvar[addr>>3] &= ~(1<<(addr&7));
  122.     vm->bitvar[addr>>3] |= (val&1)<<(addr&7);
  123.     scc_log(LOG_MSG,"Write bit var %d: %d\n",addr,val);
  124.   } else if(addr & 0x4000) { // thread local variable
  125.     addr &= 0x3FFF;
  126.     if(!thread || addr >= thread->num_var) return SCVM_ERR_BAD_ADDR;
  127.     thread->var[addr] = val;
  128.     scc_log(LOG_MSG,"Write local var %d: %d\n",addr,val);
  129.   } else { // global variable
  130.     addr &= 0x3FFF;
  131.     if(addr >= vm->num_var) return SCVM_ERR_BAD_ADDR;
  132.     if(addr < 0x100 && vm->set_var[addr])
  133.       vm->set_var[addr](vm,addr,val);
  134.     else
  135.       vm->var_mem[addr] = val;
  136.     scc_log(LOG_MSG,"Write global var %d: %d\n",addr,val);
  137.   }
  138.   return 0;
  139. }
  140.  
  141.  
  142. int scvm_read_array(scvm_t* vm, unsigned addr, unsigned x, unsigned y, int* val) {
  143.   unsigned idx;
  144.   if(addr >= vm->num_array) return SCVM_ERR_BAD_ADDR;
  145.   idx = x+y*vm->array[addr].line_size;
  146.   if(idx >= vm->array[addr].size)
  147.     return SCVM_ERR_ARRAY_BOUND;
  148.   switch(vm->array[addr].type) {
  149.   case SCVM_ARRAY_WORD:
  150.     *val = vm->array[addr].data.word[idx];
  151.     break;
  152.   case SCVM_ARRAY_BYTE:
  153.   //case SCVM_ARRAY_CHAR:
  154.     *val = vm->array[addr].data.byte[idx];
  155.     break;
  156.   case SCVM_ARRAY_NIBBLE:
  157.     *val = (vm->array[addr].data.byte[idx>>2]>>((idx&1)<<2))&0xF;
  158.     break;
  159.   case SCVM_ARRAY_BIT:
  160.     *val = (vm->array[addr].data.byte[idx>>3]>>(idx&7))&1;
  161.     break;
  162.   default:
  163.     return SCVM_ERR_ARRAY_TYPE;
  164.   }
  165.   scc_log(LOG_MSG,"Read array %d[%d][%d]: %d\n",addr,x,y,*val);
  166.   return 0;
  167. }
  168.  
  169. int scvm_write_array(scvm_t* vm, unsigned addr, unsigned x, unsigned y, int val) {
  170.   unsigned idx;
  171.   scc_log(LOG_MSG,"Write array %d[%d][%d]: %d\n",addr,x,y,val);
  172.   if(addr >= vm->num_array) return SCVM_ERR_BAD_ADDR;
  173.   idx = x+y*vm->array[addr].line_size;
  174.   if(idx >= vm->array[addr].size)
  175.     return SCVM_ERR_ARRAY_BOUND;
  176.   switch(vm->array[addr].type) {
  177.   case SCVM_ARRAY_WORD:
  178.     vm->array[addr].data.word[idx] = val;
  179.     break;
  180.   case SCVM_ARRAY_BYTE:
  181.   //case SCVM_ARRAY_CHAR:
  182.     val = vm->array[addr].data.byte[idx] = val;
  183.     break;
  184.   case SCVM_ARRAY_NIBBLE:
  185.     vm->array[addr].data.byte[idx>>2] &= 0xF<<((idx&1)<<2);
  186.     vm->array[addr].data.byte[idx>>2] |= (val&0xF)<<((idx&1)<<2);
  187.     break;
  188.   case SCVM_ARRAY_BIT:
  189.     vm->array[addr].data.byte[idx>>3] &= ~(1<<(idx&7));
  190.     vm->array[addr].data.byte[idx>>3] |= (val&1)<<(idx&7);
  191.     break;
  192.   default:
  193.     return SCVM_ERR_ARRAY_TYPE;
  194.   }
  195.   return 0;
  196. }
  197.  
  198.  
  199. int scvm_alloc_array(scvm_t* vm, unsigned type, unsigned x, unsigned y) {
  200.   scvm_array_t* array;
  201.   int addr;
  202.   
  203.   switch(type) {
  204.   case SCVM_ARRAY_WORD:
  205.   case SCVM_ARRAY_BYTE:
  206.     break;
  207.   case SCVM_ARRAY_NIBBLE:
  208.     x = (x+1)&~1;
  209.     break;
  210.   case SCVM_ARRAY_BIT:
  211.     x = (x+7)&~7;
  212.     break;
  213.   default:
  214.     return SCVM_ERR_ARRAY_TYPE;
  215.   }
  216.   
  217.   for(addr = 1 ; addr < vm->num_array ; addr++)
  218.       if(vm->array[addr].size == 0) break;
  219.   if(addr >= vm->num_array) return SCVM_ERR_OUT_OF_ARRAY;
  220.   array = &vm->array[addr];
  221.   array->type = type;
  222.  
  223.   if(y) {
  224.     array->line_size = x;
  225.     array->size = x*y;
  226.   } else {
  227.     array->line_size = 0;
  228.     array->size = x;
  229.   }
  230.   switch(type) {
  231.   case SCVM_ARRAY_WORD:
  232.     array->data.word = calloc(2,array->size);
  233.     break;
  234.   case SCVM_ARRAY_BYTE:
  235.     array->data.byte = calloc(1,array->size);
  236.     break;
  237.   case SCVM_ARRAY_NIBBLE:
  238.     array->data.byte = calloc(1,array->size>>1);
  239.     break;
  240.   case SCVM_ARRAY_BIT:
  241.     array->data.byte = calloc(1,array->size>>3);
  242.     break;
  243.   }
  244.   return addr;
  245. }
  246.  
  247. static int scvm_nuke_array(scvm_t* vm, unsigned addr) {
  248.   if(!addr || addr >= vm->num_array) return SCVM_ERR_BAD_ADDR;
  249.   if(vm->array[addr].data.byte) free(vm->array[addr].data.byte);
  250.   vm->array[addr].size = vm->array[addr].line_size = 0;
  251.   return 0;
  252. }
  253.  
  254. // SCUMM ops
  255.  
  256. // 0x00
  257. static int scvm_op_push_byte(scvm_t* vm, scvm_thread_t* thread) {
  258.   int r;
  259.   uint8_t byte;
  260.   if((r=scvm_thread_r8(thread,&byte))) return r;
  261.   return scvm_push(vm,byte);
  262. }
  263.  
  264. // 0x01
  265. static int scvm_op_push_word(scvm_t* vm, scvm_thread_t* thread) {
  266.   int r;
  267.   int16_t word;
  268.   if((r=scvm_thread_r16(thread,&word))) return r;
  269.   return scvm_push(vm,word);
  270. }
  271.  
  272. // 0x02
  273. static int scvm_op_var_read_byte(scvm_t* vm, scvm_thread_t* thread) {
  274.   int r,val;
  275.   uint8_t addr;
  276.   if((r=scvm_thread_r8(thread,&addr)) ||
  277.      (r=scvm_thread_read_var(vm,thread,addr,&val))) return r;
  278.   return scvm_push(vm,val);
  279. }
  280.  
  281. // 0x03
  282. static int scvm_op_var_read_word(scvm_t* vm, scvm_thread_t* thread) {
  283.   int r,val;
  284.   uint16_t addr;
  285.   if((r=scvm_thread_r16(thread,&addr)) ||
  286.      (r=scvm_thread_read_var(vm,thread,addr,&val))) return r;
  287.   return scvm_push(vm,val);
  288. }
  289.  
  290. // 0x06
  291. static int scvm_op_array_read_byte(scvm_t* vm, scvm_thread_t* thread) {
  292.   int r,val;
  293.   unsigned addr,x;
  294.   uint8_t vaddr;
  295.   if((r=scvm_thread_r8(thread,&vaddr)) ||
  296.      (r=scvm_thread_read_var(vm,thread,vaddr,&addr)) ||
  297.      (r=scvm_pop(vm,&x)) ||
  298.      (r=scvm_read_array(vm,addr,x,0,&val)))
  299.     return r;
  300.   return scvm_push(vm,val);
  301. }
  302.  
  303. // 0x07
  304. static int scvm_op_array_read_word(scvm_t* vm, scvm_thread_t* thread) {
  305.   int r,val;
  306.   unsigned addr,x;
  307.   uint16_t vaddr;
  308.   if((r=scvm_thread_r16(thread,&vaddr)) ||
  309.      (r=scvm_thread_read_var(vm,thread,vaddr,&addr)) ||
  310.      (r=scvm_pop(vm,&x)) ||
  311.      (r=scvm_read_array(vm,addr,x,0,&val)))
  312.     return r;
  313.   return scvm_push(vm,val);
  314. }
  315.  
  316. // 0x0A
  317. static int scvm_op_array2_read_byte(scvm_t* vm, scvm_thread_t* thread) {
  318.   int r,val;
  319.   unsigned addr,x,y;
  320.   uint8_t vaddr;
  321.   if((r=scvm_thread_r8(thread,&vaddr)) ||
  322.      (r=scvm_thread_read_var(vm,thread,vaddr,&addr)) ||
  323.      (r=scvm_vpop(vm,&x,&y,NULL)) ||
  324.      (r=scvm_read_array(vm,addr,x,y,&val)))
  325.     return r;
  326.   return scvm_push(vm,val);
  327. }
  328.  
  329. // 0x0B
  330. static int scvm_op_array2_read_word(scvm_t* vm, scvm_thread_t* thread) {
  331.   int r,val;
  332.   unsigned addr,x,y;
  333.   uint16_t vaddr;
  334.   if((r=scvm_thread_r16(thread,&vaddr)) ||
  335.      (r=scvm_thread_read_var(vm,thread,vaddr,&addr)) ||
  336.      (r=scvm_vpop(vm,&x,&y,NULL)) ||
  337.      (r=scvm_read_array(vm,addr,x,y,&val)))
  338.     return r;
  339.   return scvm_push(vm,val);
  340. }
  341.  
  342. // 0x0C
  343. static int scvm_op_dup(scvm_t* vm, scvm_thread_t* thread) {
  344.   int r,a;
  345.   if((r=scvm_peek(vm,&a))) return r;
  346.   return scvm_push(vm,a);
  347. }
  348.  
  349. // 0x0D
  350. static int scvm_op_not(scvm_t* vm, scvm_thread_t* thread) {
  351.   int r,a;
  352.   if((r=scvm_pop(vm,&a))) return r;
  353.   return scvm_push(vm,!a);
  354. }
  355.  
  356. #define SCVM_BIN_OP(name,op) \
  357. static int scvm_op_ ##name (scvm_t* vm, scvm_thread_t* thread) { \
  358.   int r,a,b;                                              \
  359.   if((r=scvm_vpop(vm,&b,&a,NULL)))                        \
  360.     return r;                                             \
  361.   return scvm_push(vm,(a op b));                          \
  362. }
  363.  
  364. // 0x0E ... 0x19
  365. SCVM_BIN_OP(eq,==)
  366. SCVM_BIN_OP(neq,!=)
  367. SCVM_BIN_OP(gt,>)
  368. SCVM_BIN_OP(lt,<)
  369. SCVM_BIN_OP(ge,>=)
  370. SCVM_BIN_OP(le,<=)
  371. SCVM_BIN_OP(add,+)
  372. SCVM_BIN_OP(sub,-)
  373. SCVM_BIN_OP(mul,*)
  374. SCVM_BIN_OP(div,/)
  375. SCVM_BIN_OP(land,&&)
  376. SCVM_BIN_OP(lor,||)
  377. // 0xD6 0xD7
  378. SCVM_BIN_OP(band,&)
  379. SCVM_BIN_OP(bor,|)
  380.  
  381. // 0x1A
  382. static int scvm_op_pop(scvm_t* vm, scvm_thread_t* thread) {
  383.   return scvm_pop(vm,NULL);
  384. }
  385.  
  386. // 0x42
  387. static int scvm_op_var_write_byte(scvm_t* vm, scvm_thread_t* thread) {
  388.   int r,val;
  389.   uint8_t addr;
  390.   if((r=scvm_thread_r8(thread,&addr)) ||
  391.      (r=scvm_pop(vm,&val))) return r;
  392.   return scvm_thread_write_var(vm,thread,addr,val);
  393. }
  394.  
  395. // 0x43
  396. static int scvm_op_var_write_word(scvm_t* vm, scvm_thread_t* thread) {
  397.   int r,val;
  398.   uint16_t addr;
  399.   if((r=scvm_thread_r16(thread,&addr)) ||
  400.      (r=scvm_pop(vm,&val))) return r;
  401.   return scvm_thread_write_var(vm,thread,addr,val);
  402. }
  403.  
  404. // 0x46
  405. static int scvm_op_array_write_byte(scvm_t* vm, scvm_thread_t* thread) {
  406.   int r,val;
  407.   unsigned addr,x;
  408.   uint8_t vaddr;
  409.   if((r=scvm_thread_r8(thread,&vaddr)) ||
  410.      (r=scvm_thread_read_var(vm,thread,vaddr,&addr)) ||
  411.      (r=scvm_vpop(vm,&val,&x,NULL)))
  412.     return r;
  413.   return scvm_write_array(vm,addr,x,0,val);
  414. }
  415.  
  416. // 0x47
  417. static int scvm_op_array_write_word(scvm_t* vm, scvm_thread_t* thread) {
  418.   int r,val;
  419.   unsigned addr,x;
  420.   uint16_t vaddr;
  421.   if((r=scvm_thread_r16(thread,&vaddr)) ||
  422.      (r=scvm_thread_read_var(vm,thread,vaddr,&addr)) ||
  423.      (r=scvm_vpop(vm,&val,&x,NULL)))
  424.     return r;
  425.   return scvm_write_array(vm,addr,x,0,val);
  426. }
  427.  
  428. // 0x4A
  429. static int scvm_op_array2_write_byte(scvm_t* vm, scvm_thread_t* thread) {
  430.   int r,val;
  431.   unsigned addr,x,y;
  432.   uint8_t vaddr;
  433.   if((r=scvm_thread_r8(thread,&vaddr)) ||
  434.      (r=scvm_thread_read_var(vm,thread,vaddr,&addr)) ||
  435.      (r=scvm_vpop(vm,&val,&x,&y,NULL)))
  436.     return r;
  437.   return scvm_write_array(vm,addr,x,0,val);
  438. }
  439.  
  440. // 0x4B
  441. static int scvm_op_array2_write_word(scvm_t* vm, scvm_thread_t* thread) {
  442.   int r,val;
  443.   unsigned addr,x,y;
  444.   uint16_t vaddr;
  445.   if((r=scvm_thread_r16(thread,&vaddr)) ||
  446.      (r=scvm_thread_read_var(vm,thread,vaddr,&addr)) ||
  447.      (r=scvm_vpop(vm,&val,&x,&y,NULL)))
  448.     return r;
  449.   return scvm_write_array(vm,addr,x,0,val);
  450. }
  451.  
  452. // 0x4E
  453. static int scvm_op_var_inc_byte(scvm_t* vm, scvm_thread_t* thread) {
  454.   int r,val;
  455.   uint8_t addr;
  456.   if((r=scvm_thread_r8(thread,&addr)) ||
  457.      (r=scvm_thread_read_var(vm,thread,addr,&val))) return r;
  458.   val++;
  459.   return scvm_thread_write_var(vm,thread,addr,val);
  460. }
  461.  
  462. // 0x4F
  463. static int scvm_op_var_inc_word(scvm_t* vm, scvm_thread_t* thread) {
  464.   int r,val;
  465.   uint16_t addr;
  466.   if((r=scvm_thread_r16(thread,&addr)) ||
  467.      (r=scvm_thread_read_var(vm,thread,addr,&val))) return r;
  468.   val++;
  469.   return scvm_thread_write_var(vm,thread,addr,val);
  470. }
  471.  
  472. // 0x52
  473. static int scvm_op_array_inc_byte(scvm_t* vm, scvm_thread_t* thread) {
  474.   int r,val;
  475.   unsigned addr,x;
  476.   uint8_t vaddr;
  477.   if((r=scvm_thread_r8(thread,&vaddr)) ||
  478.      (r=scvm_thread_read_var(vm,thread,vaddr,&addr)) ||
  479.      (r=scvm_pop(vm,&x)) ||
  480.      (r=scvm_read_array(vm,addr,x,0,&val)))
  481.     return r;
  482.   val++;
  483.   return scvm_write_array(vm,addr,x,0,val);
  484. }
  485.  
  486. // 0x53
  487. static int scvm_op_array_inc_word(scvm_t* vm, scvm_thread_t* thread) {
  488.   int r,val;
  489.   unsigned addr,x;
  490.   uint16_t vaddr;
  491.   if((r=scvm_thread_r16(thread,&vaddr)) ||
  492.      (r=scvm_thread_read_var(vm,thread,vaddr,&addr)) ||
  493.      (r=scvm_pop(vm,&x)) ||
  494.      (r=scvm_read_array(vm,addr,x,0,&val)))
  495.     return r;
  496.   val++;
  497.   return scvm_write_array(vm,addr,x,0,val);
  498. }
  499.  
  500. // 0x56
  501. static int scvm_op_var_dec_byte(scvm_t* vm, scvm_thread_t* thread) {
  502.   int r,val;
  503.   uint8_t addr;
  504.   if((r=scvm_thread_r8(thread,&addr)) ||
  505.      (r=scvm_thread_read_var(vm,thread,addr,&val))) return r;
  506.   val--;
  507.   return scvm_thread_write_var(vm,thread,addr,val);
  508. }
  509.  
  510. // 0x57
  511. static int scvm_op_var_dec_word(scvm_t* vm, scvm_thread_t* thread) {
  512.   int r,val;
  513.   uint16_t addr;
  514.   if((r=scvm_thread_r16(thread,&addr)) ||
  515.      (r=scvm_thread_read_var(vm,thread,addr,&val))) return r;
  516.   val--;
  517.   return scvm_thread_write_var(vm,thread,addr,val);
  518. }
  519.  
  520. // 0x5A
  521. static int scvm_op_array_dec_byte(scvm_t* vm, scvm_thread_t* thread) {
  522.   int r,val;
  523.   unsigned addr,x;
  524.   uint8_t vaddr;
  525.   if((r=scvm_thread_r8(thread,&vaddr)) ||
  526.      (r=scvm_thread_read_var(vm,thread,vaddr,&addr)) ||
  527.      (r=scvm_pop(vm,&x)) ||
  528.      (r=scvm_read_array(vm,addr,x,0,&val)))
  529.     return r;
  530.   val--;
  531.   return scvm_write_array(vm,addr,x,0,val);
  532. }
  533.  
  534. // 0x5B
  535. static int scvm_op_array_dec_word(scvm_t* vm, scvm_thread_t* thread) {
  536.   int r,val;
  537.   unsigned addr,x;
  538.   uint16_t vaddr;
  539.   if((r=scvm_thread_r16(thread,&vaddr)) ||
  540.      (r=scvm_thread_read_var(vm,thread,vaddr,&addr)) ||
  541.      (r=scvm_pop(vm,&x)) ||
  542.      (r=scvm_read_array(vm,addr,x,0,&val)))
  543.     return r;
  544.   val--;
  545.   return scvm_write_array(vm,addr,x,0,val);
  546. }
  547.  
  548. // 0x5C
  549. static int scvm_op_jmp_not_zero(scvm_t* vm, scvm_thread_t* thread) {
  550.   int r,ptr,val;
  551.   int16_t off;
  552.   if((r=scvm_thread_r16(thread,&off)) ||
  553.      (r=scvm_pop(vm,&val))) return r;
  554.   ptr = thread->code_ptr+off;
  555.   if(ptr < 0 || ptr >= thread->script->size)
  556.     return SCVM_ERR_JUMP_BOUND;
  557.   if(val) thread->code_ptr = ptr;
  558.   return 0;
  559. }
  560.  
  561. // 0x5D
  562. static int scvm_op_jmp_zero(scvm_t* vm, scvm_thread_t* thread) {
  563.   int r,ptr,val;
  564.   int16_t off;
  565.   if((r=scvm_thread_r16(thread,&off)) ||
  566.      (r=scvm_pop(vm,&val))) return r;
  567.   ptr = thread->code_ptr+off;
  568.   if(ptr < 0 || ptr >= thread->script->size)
  569.     return SCVM_ERR_JUMP_BOUND;
  570.   if(!val) thread->code_ptr = ptr;
  571.   return 0;
  572. }
  573.  
  574. // 0x5E
  575. static int scvm_op_start_script(scvm_t* vm, scvm_thread_t* thread) {
  576.   int r;
  577.   unsigned num_args,script,flags;
  578.   if((r=scvm_pop(vm,&num_args))) return r;
  579.   else {
  580.     int args[num_args+1];
  581.     args[0] = num_args;
  582.     while(num_args > 0) {
  583.       if((r=scvm_pop(vm,&args[num_args]))) return r;
  584.       num_args--;
  585.     }
  586.     if((r=scvm_vpop(vm,&script,&flags,NULL)) ||
  587.        (r=scvm_start_script(vm,flags,script,args)) < 0)
  588.       return r;
  589.     vm->next_thread = &vm->thread[r];
  590.     return SCVM_START_SCRIPT;
  591.   }    
  592. }
  593.  
  594. // 0x5F
  595. static int scvm_op_start_script0(scvm_t* vm, scvm_thread_t* thread) {
  596.   int r;
  597.   unsigned num_args,script;
  598.   if((r=scvm_pop(vm,&num_args))) return r;
  599.   else {
  600.     int args[num_args+1];
  601.     args[0] = num_args;
  602.     while(num_args > 0) {
  603.       if((r=scvm_pop(vm,&args[num_args]))) return r;
  604.       num_args--;
  605.     }
  606.     if((r=scvm_pop(vm,&script)) ||
  607.        (r=scvm_start_script(vm,0,script,args)) < 0)
  608.       return r;
  609.     vm->next_thread = &vm->thread[r];
  610.     return SCVM_START_SCRIPT;
  611.   }    
  612. }
  613.  
  614. // 0xBF
  615. static int scvm_op_start_script_recursive(scvm_t* vm, scvm_thread_t* thread) {
  616.   int r;
  617.   unsigned num_args,script;
  618.   if((r=scvm_pop(vm,&num_args))) return r;
  619.   else {
  620.     int args[num_args+1];
  621.     args[0] = num_args;
  622.     while(num_args > 0) {
  623.       if((r=scvm_pop(vm,&args[num_args]))) return r;
  624.       num_args--;
  625.     }
  626.     if((r=scvm_pop(vm,&script)) ||
  627.        (r=scvm_start_script(vm,SCVM_THREAD_RECURSIVE,script,args)) < 0)
  628.       return r;
  629.     vm->next_thread = &vm->thread[r];
  630.     return SCVM_START_SCRIPT;
  631.   }    
  632. }
  633.  
  634. // 0x61
  635. static int scvm_op_draw_object(scvm_t* vm, scvm_thread_t* thread) {
  636.   int r,obj_id,state;
  637.   if((r = scvm_vpop(vm,&state,&obj_id,NULL)))
  638.     return r;
  639.   if(!vm->room) return SCVM_ERR_NO_ROOM;
  640.   // the lower address are actors
  641.   if(obj_id < 0x10 || obj_id >= vm->num_object)
  642.     return SCVM_ERR_BAD_OBJECT;
  643.   vm->object_pdata[obj_id].state = state > 0 ? state : 1;
  644.   return 0;
  645. }
  646.  
  647. // 0x65, 0x66
  648. static int scvm_op_stop_thread(scvm_t* vm, scvm_thread_t* thread) {
  649.   scvm_stop_thread(vm,thread);
  650.   return 0;
  651. }
  652.  
  653. // 0x6C
  654. static int scvm_op_break_script(scvm_t* vm, scvm_thread_t* thread) {
  655.   thread->cycle = vm->cycle+1;
  656.   return 0;
  657. }
  658.  
  659. // 0x73
  660. static int scvm_op_jmp(scvm_t* vm, scvm_thread_t* thread) {
  661.   int r,ptr;
  662.   int16_t off;
  663.   if((r=scvm_thread_r16(thread,&off))) return r;
  664.   ptr = thread->code_ptr+off;
  665.   if(ptr < 0 || ptr >= thread->script->size)
  666.     return SCVM_ERR_JUMP_BOUND;
  667.   thread->code_ptr = ptr;
  668.   return 0;
  669. }
  670.  
  671. // 0x78
  672. static int scvm_op_pan_camera_to(scvm_t* vm, scvm_thread_t* thread) {
  673.   int r,x;
  674.   if((r=scvm_pop(vm,&x))) return r;
  675.   scvm_pan_camera_to(vm,x);
  676.   return 0;
  677. }
  678.  
  679. // 0x79
  680. static int scvm_op_camera_follow_actor(scvm_t* vm, scvm_thread_t* thread) {
  681.   unsigned a;
  682.   int r;
  683.   if((r=scvm_pop(vm,&a))) return r;
  684.   if(a >= vm->num_actor) return SCVM_ERR_BAD_ACTOR;
  685.   vm->view->follow = a;
  686.   return SCVM_CAMERA_FOLLOW_ACTOR;
  687. }
  688.  
  689. // 0x7A
  690. static int scvm_op_set_camera_at(scvm_t* vm, scvm_thread_t* thread) {
  691.   int r,x;
  692.   if((r=scvm_pop(vm,&x)) ||
  693.      (r=scvm_set_camera_at(vm,x)) < 0) return r;
  694.  
  695.   // Stop following actors and panning
  696.   vm->view->follow = 0;
  697.   vm->view->flags &= ~ SCVM_VIEW_PAN;
  698.  
  699.   if(r > 0) {
  700.     vm->next_thread = &vm->thread[r-1];
  701.     return SCVM_START_SCRIPT;
  702.   }
  703.   return 0;
  704. }
  705.  
  706. // 0x7B
  707. static int scvm_op_start_room(scvm_t* vm, scvm_thread_t* thread) {
  708.   int r;
  709.   
  710.   if((r=scvm_pop(vm,&vm->next_room))) return r;
  711.   return SCVM_OPEN_ROOM;
  712. }
  713.  
  714. // 0x7C
  715. static int scvm_op_stop_script(scvm_t* vm, scvm_thread_t* thread) {
  716.   int r,id;
  717.   if((r=scvm_pop(vm,&id))) return r;
  718.   scvm_stop_script(vm,id);
  719.   return 0;
  720. }
  721.  
  722. // 0x7E
  723. static int scvm_op_walk_actor_to(scvm_t* vm, scvm_thread_t* thread) {
  724.   int r,a,x,y;
  725.  
  726.   if((r=scvm_vpop(vm,&y,&x,&a,NULL)))
  727.     return r;
  728.  
  729.   if(a < 0 || a >= vm->num_actor) return SCVM_ERR_BAD_ACTOR;
  730.   scvm_actor_walk_to(&vm->actor[a],x,y);
  731.   return 0;
  732. }
  733.  
  734.  
  735. // 0x7F
  736. static int scvm_op_put_actor_at(scvm_t* vm, scvm_thread_t* thread) {
  737.   int r,a,x,y,room;
  738.  
  739.   if((r=scvm_vpop(vm,&room,&y,&x,&a,NULL)))
  740.     return r;
  741.   return scvm_put_actor_at(vm,a,x,y,room);
  742. }
  743.  
  744. // 0x82
  745. static int scvm_op_actor_animate(scvm_t* vm, scvm_thread_t* thread) {
  746.   int r,a,f;
  747.   if((r = scvm_vpop(vm,&f,&a,NULL)))
  748.     return r;
  749.   if(a < 0 || a >= vm->num_actor) return SCVM_ERR_BAD_ACTOR;
  750.   scvm_actor_animate(&vm->actor[a],f);
  751.   return 0;
  752. }
  753.  
  754. // 0x87
  755. static int scvm_op_get_random_number(scvm_t* vm, scvm_thread_t* thread) {
  756.   int r,max;
  757.   if((r=scvm_pop(vm,&max))) return r;
  758.   vm->var->random_num = scvm_random(vm,0,max);
  759.   return scvm_push(vm,vm->var->random_num);
  760. }
  761.  
  762. // 0x88
  763. static int scvm_op_get_random_number_range(scvm_t* vm, scvm_thread_t* thread) {
  764.   int r,min,max;
  765.   if((r=scvm_vpop(vm,&max,&min,NULL)))
  766.     return r;
  767.   vm->var->random_num = scvm_random(vm,min,max);
  768.   return scvm_push(vm,vm->var->random_num);
  769. }
  770.  
  771. // 0x8B
  772. static int scvm_op_is_script_running(scvm_t* vm, scvm_thread_t* thread) {
  773.   int r,id;
  774.   if((r=scvm_pop(vm,&id))) return r;
  775.   r = scvm_is_script_running(vm,id);
  776.   return scvm_push(vm,r);
  777. }
  778.  
  779. // 0x8C
  780. static int scvm_op_get_actor_room(scvm_t* vm, scvm_thread_t* thread) {
  781.   int r,a;
  782.   if((r=scvm_pop(vm,&a))) return r;
  783.   if(a < 0 || a >= vm->num_actor) return SCVM_ERR_BAD_ACTOR;
  784.   return scvm_push(vm,vm->actor[a].room);
  785. }
  786.  
  787. // 0x8D
  788. static int scvm_op_get_object_x(scvm_t* vm, scvm_thread_t* thread) {
  789.   int r,o,x;
  790.   if((r=scvm_pop(vm,&o)) ||
  791.      (r=scvm_get_object_position(vm,o,&x,NULL)) < 0) return r;
  792.   return scvm_push(vm,x);
  793. }
  794.  
  795. // 0x8E
  796. static int scvm_op_get_object_y(scvm_t* vm, scvm_thread_t* thread) {
  797.   int r,o,y;
  798.   if((r=scvm_pop(vm,&o)) ||
  799.      (r=scvm_get_object_position(vm,o,NULL,&y)) < 0) return r;
  800.   return scvm_push(vm,y);
  801. }
  802.  
  803. // 0x8F
  804. static int scvm_op_get_object_direction(scvm_t* vm, scvm_thread_t* thread) {
  805.   int r,a;
  806.   if((r=scvm_pop(vm,&a))) return r;
  807.   if(a < 0 || a >= vm->num_actor) return SCVM_ERR_BAD_ACTOR;
  808.   return scvm_push(vm,vm->actor[a].direction);
  809. }
  810.  
  811. // 0x90
  812. static int scvm_op_get_actor_walk_box(scvm_t* vm, scvm_thread_t* thread) {
  813.   int r;
  814.   unsigned a;
  815.   if((r=scvm_pop(vm,&a))) return r;
  816.   if(a >= vm->num_actor) return SCVM_ERR_BAD_ACTOR;
  817.   return scvm_push(vm,vm->actor[a].box);
  818. }
  819.  
  820. // 0x95
  821. static int scvm_op_begin_override(scvm_t* vm, scvm_thread_t* thread) {
  822.   int r;
  823.   // there should be a jump there
  824.   if(thread->code_ptr + 3 >= thread->script->size)
  825.     return SCVM_ERR_SCRIPT_BOUND;
  826.   if((r=scvm_thread_begin_override(vm,thread)))
  827.     return r;
  828.   // skip the jump
  829.   thread->code_ptr += 3;
  830.   return 0;
  831. }
  832.  
  833. // 0x96
  834. static int scvm_op_end_override(scvm_t* vm, scvm_thread_t* thread) {
  835.   return scvm_thread_end_override(vm,thread);
  836. }
  837.  
  838. // 0x9B
  839. static int scvm_op_resource(scvm_t* vm, scvm_thread_t* thread) {
  840.   int r,res;
  841.   uint8_t op;
  842.   
  843.   if((r=scvm_thread_r8(thread,&op)) ||
  844.      (r=scvm_pop(vm,&res))) return r;
  845.   
  846.   if(op == 0x65) return 0; // ignore sounds for now
  847.   
  848.   if(op >= 0x64 && op <= 0x67) {
  849.     if(!scvm_load_res(vm,op-0x64,res))
  850.       return SCVM_ERR_BAD_RESOURCE;
  851.     return 0;
  852.   } else if(op >= 0x6C && op <= 0x6F) {
  853.     if(!scvm_lock_res(vm,op-0x6C,res))
  854.       return SCVM_ERR_BAD_RESOURCE;
  855.     return 0;
  856.   } else if(op >= 0x70 && op <= 0x73) {
  857.     if(!scvm_unlock_res(vm,op-0x70,res))
  858.       return SCVM_ERR_BAD_RESOURCE;
  859.     return 0;
  860.   }
  861.   
  862.   switch(op) {    
  863.   case 0x75: // load charset
  864.     if(!scvm_load_res(vm,SCVM_RES_CHARSET,res))
  865.       return SCVM_ERR_BAD_RESOURCE;
  866.     return 0;
  867.   case 0x77: // load fl object
  868.     return scvm_pop(vm,NULL);
  869.   }
  870.   return SCVM_ERR_NO_OP;
  871. }
  872.  
  873. // 0x9CAC
  874. static int scvm_op_set_scrolling(scvm_t* vm, scvm_thread_t* thread) {
  875.   int r;
  876.   if((r=scvm_vpop(vm,&vm->view->scroll_right,
  877.                   &vm->view->scroll_left,NULL)))
  878.     return r;
  879.   return 0;
  880. }
  881.  
  882. // 0x9CAE
  883. static int scvm_op_set_screen(scvm_t* vm, scvm_thread_t* thread) {
  884.   int r;
  885.   if((r=scvm_vpop(vm,&vm->view->room_end,
  886.                   &vm->view->room_start,NULL)))
  887.     return r;
  888.   return 0;
  889. }
  890.  
  891. // 0x9CAF
  892. static int scvm_op_set_room_color(scvm_t* vm, scvm_thread_t* thread) {
  893.   int r,red,green,blue,color;
  894.   if((r=scvm_vpop(vm,&color,&blue,&green,&red,NULL)))
  895.     return r;
  896.   if(color < 0 || color > 0xFF) return 0;
  897.   vm->view->palette[color].r = red;
  898.   vm->view->palette[color].g = green;
  899.   vm->view->palette[color].b = blue;
  900.   vm->view->flags |= SCVM_VIEW_PALETTE_CHANGED;
  901.   return 0;
  902. }
  903.  
  904. // 0x9CB0
  905. static int scvm_op_shake_on(scvm_t* vm, scvm_thread_t* thread) {
  906.   vm->view->flags |= SCVM_VIEW_SHAKE;
  907.   return 0;
  908. }
  909.  
  910. // 0x9CB1
  911. static int scvm_op_shake_off(scvm_t* vm, scvm_thread_t* thread) {
  912.   vm->view->flags &= ~SCVM_VIEW_SHAKE;
  913.   return 0;
  914. }
  915.  
  916. // 0x9CB3
  917. static int scvm_op_set_room_intensity(scvm_t* vm, scvm_thread_t* thread) {
  918.   int r,scale,start,end;
  919.   if((r=scvm_vpop(vm,&end,&start,&scale,NULL)))
  920.     return r;
  921.   if(!vm->room) return SCVM_ERR_NO_ROOM;
  922.   scvm_view_scale_palette(vm->view,vm->room->current_palette,
  923.                           scale,scale,scale,start,end);
  924.   return 0;
  925. }
  926.  
  927. // 0x9CB5
  928. static int scvm_op_set_transition_effect(scvm_t* vm, scvm_thread_t* thread) {
  929.     return scvm_pop(vm,&vm->view->effect);
  930. }
  931.  
  932. // 0x9CB6
  933. static int scvm_op_set_rgb_intensity(scvm_t* vm, scvm_thread_t* thread) {
  934.   int r,red,green,blue,start,end;
  935.   if((r=scvm_vpop(vm,&end,&start,&blue,&green,&red,NULL)))
  936.     return r;
  937.   if(!vm->room) return SCVM_ERR_NO_ROOM;
  938.   scvm_view_scale_palette(vm->view,vm->room->current_palette,
  939.                           red,green,blue,start,end);
  940.   return 0;
  941. }
  942.  
  943. // 0x9CD5
  944. static int scvm_op_set_palette(scvm_t* vm, scvm_thread_t* thread) {
  945.   int r,p;
  946.   if((r=scvm_pop(vm,&p))) return r;
  947.   if(!vm->room) return SCVM_ERR_NO_ROOM;
  948.   if(p < 0 || p >= vm->room->num_palette)
  949.     return SCVM_ERR_BAD_PALETTE;
  950.   vm->room->current_palette = vm->room->palette[p];
  951.   memcpy(vm->view->palette,vm->room->current_palette,
  952.          sizeof(scvm_palette_t));
  953.   vm->view->flags |= SCVM_VIEW_PALETTE_CHANGED;
  954.   return 0;
  955. }
  956.  
  957.  
  958. // 0x9DC5
  959. static int scvm_op_set_current_actor(scvm_t* vm, scvm_thread_t* thread) {
  960.   int r,a;
  961.   if((r=scvm_pop(vm,&a))) return r;
  962.   if(r >= vm->num_actor) return SCVM_ERR_BAD_ACTOR;
  963.   vm->current_actor = &vm->actor[a];
  964.   return 0;
  965. }
  966.  
  967. // 0x9D4C
  968. static int scvm_op_set_actor_costume(scvm_t* vm, scvm_thread_t* thread) {
  969.   int r,a;
  970.   scc_cost_t* cost = NULL;
  971.   if((r=scvm_pop(vm,&a))) return r;
  972.   if(a && !(cost = scvm_load_res(vm,SCVM_RES_COSTUME,a)))
  973.     return SCVM_ERR_BAD_COSTUME;
  974.   if(vm->current_actor)
  975.     scvm_actor_set_costume(vm->current_actor,cost);
  976.   return 0;
  977. }
  978.  
  979. // 0x9D4D
  980. static int scvm_op_set_actor_walk_speed(scvm_t* vm, scvm_thread_t* thread) {
  981.   return scvm_vpop(vm,&vm->current_actor->walk_speed_y,
  982.                    &vm->current_actor->walk_speed_x,NULL);
  983. }
  984.  
  985. // 0x9D4F
  986. static int scvm_op_set_actor_walk_frame(scvm_t* vm, scvm_thread_t* thread) {
  987.   return scvm_pop(vm,&vm->current_actor->walk_frame);
  988. }
  989.  
  990. // 0x9D50
  991. static int scvm_op_set_actor_talk_frame(scvm_t* vm, scvm_thread_t* thread) {
  992.   return scvm_vpop(vm,&vm->current_actor->talk_end_frame,
  993.                    &vm->current_actor->talk_start_frame,NULL);
  994. }
  995.  
  996. // 0x9D51
  997. static int scvm_op_set_actor_stand_frame(scvm_t* vm, scvm_thread_t* thread) {
  998.   return scvm_pop(vm,&vm->current_actor->stand_frame);
  999. }
  1000.  
  1001. // 0x9D53
  1002. static int scvm_op_actor_init(scvm_t* vm, scvm_thread_t* thread) {
  1003.   if(vm->current_actor)
  1004.     scvm_actor_init(vm->current_actor);
  1005.   return 0;
  1006. }
  1007.  
  1008. // 0x9D54
  1009. static int scvm_op_set_actor_elevation(scvm_t* vm, scvm_thread_t* thread) {
  1010.   return scvm_pop(vm,&vm->current_actor->elevation);
  1011. }
  1012.  
  1013. // 0x9D54
  1014. static int scvm_op_set_actor_default_frames(scvm_t* vm,
  1015.                                             scvm_thread_t* thread) {
  1016.   if(vm->current_actor)
  1017.     scvm_actor_set_default_frames(vm->current_actor);
  1018.   return 0;
  1019. }
  1020.  
  1021.  
  1022. // 0x9D57
  1023. static int scvm_op_set_actor_talk_color(scvm_t* vm, scvm_thread_t* thread) {
  1024.   return scvm_pop(vm,&vm->current_actor->talk_color);
  1025. }
  1026.  
  1027. // 0x9D58
  1028. static int scvm_op_set_actor_name(scvm_t* vm, scvm_thread_t* thread) {
  1029.   int r,len;
  1030.   if((r = scvm_thread_strlen(thread,&len))) return r;
  1031.   if(vm->current_actor->name)
  1032.     free(vm->current_actor->name);
  1033.   vm->current_actor->name = malloc(len+1);
  1034.   if(len > 0)
  1035.     memcpy(vm->current_actor->name,
  1036.            &thread->script->code[thread->code_ptr],len);
  1037.   thread->code_ptr += len+1;
  1038.   vm->current_actor->name[len] = 0;
  1039.   return 0;
  1040. }
  1041.  
  1042. // 0x9D59
  1043. static int scvm_op_set_actor_init_frame(scvm_t* vm, scvm_thread_t* thread) {
  1044.   return scvm_pop(vm,&vm->current_actor->init_frame);
  1045. }
  1046.  
  1047. // 0x9D5B
  1048. static int scvm_op_set_actor_width(scvm_t* vm, scvm_thread_t* thread) {
  1049.   return scvm_pop(vm,&vm->current_actor->width);
  1050. }
  1051.  
  1052. // 0x9D5C
  1053. static int scvm_op_set_actor_scale(scvm_t* vm, scvm_thread_t* thread) {
  1054.   int r;
  1055.   if((r=scvm_pop(vm,&vm->current_actor->scale_x))) return r;
  1056.   vm->current_actor->scale_y = vm->current_actor->scale_x;
  1057.   return 0;
  1058. }
  1059.  
  1060. // 0x9D5F
  1061. static int scvm_op_set_actor_ignore_boxes(scvm_t* vm, scvm_thread_t* thread) {
  1062.   if(!vm->current_actor) return 0;
  1063.   vm->current_actor->flags |= SCVM_ACTOR_IGNORE_BOXES;
  1064.   vm->current_actor->box = 0;
  1065.   return 0;
  1066. }
  1067.  
  1068. // 0x9D60
  1069. static int scvm_op_set_actor_follow_boxes(scvm_t* vm, scvm_thread_t* thread) {
  1070.   if(!vm->current_actor) return 0;
  1071.   vm->current_actor->flags &= ~SCVM_ACTOR_IGNORE_BOXES;
  1072.   if(vm->current_actor->room == vm->room->id)
  1073.     scvm_put_actor_at(vm,vm->current_actor->id,
  1074.                       vm->current_actor->x,
  1075.                       vm->current_actor->y,
  1076.                       vm->current_actor->room);
  1077.   return 0;
  1078. }
  1079.  
  1080. // 0x9D61
  1081. static int scvm_op_set_actor_anim_speed(scvm_t* vm, scvm_thread_t* thread) {
  1082.   return scvm_pop(vm,&vm->current_actor->anim_speed);
  1083. }
  1084.  
  1085. // 0x9D63
  1086. static int scvm_op_set_actor_talk_pos(scvm_t* vm, scvm_thread_t* thread) {
  1087.   return scvm_vpop(vm,&vm->current_actor->talk_y,
  1088.                    &vm->current_actor->talk_x,NULL);
  1089. }
  1090.  
  1091.  
  1092. // 0x9DE3
  1093. static int scvm_op_set_actor_layer(scvm_t* vm, scvm_thread_t* thread) {
  1094.   return scvm_pop(vm,&vm->current_actor->layer);
  1095. }
  1096.  
  1097. // 0x9DE4
  1098. static int scvm_op_set_actor_walk_script(scvm_t* vm, scvm_thread_t* thread) {
  1099.   return scvm_pop(vm,&vm->current_actor->walk_script);
  1100. }
  1101.  
  1102. // 0x9DE6
  1103. static int scvm_op_set_actor_direction(scvm_t* vm, scvm_thread_t* thread) {
  1104.   return scvm_pop(vm,&vm->current_actor->direction);
  1105. }
  1106.  
  1107. // 0x9DEB
  1108. static int scvm_op_set_actor_talk_script(scvm_t* vm, scvm_thread_t* thread) {
  1109.   return scvm_pop(vm,&vm->current_actor->talk_script);
  1110. }
  1111.  
  1112.  
  1113. // 0xA4CD
  1114. static int scvm_op_array_write_string(scvm_t* vm, scvm_thread_t* thread) {
  1115.   int r,addr;
  1116.   uint16_t vaddr;
  1117.   unsigned len,x;
  1118.   
  1119.   if((r=scvm_pop(vm,&x)) ||
  1120.      (r=scvm_thread_r16(thread,&vaddr)) ||
  1121.      (r = scvm_thread_strlen(thread,&len))) return r;
  1122.   if((addr = scvm_alloc_array(vm,SCVM_ARRAY_BYTE,
  1123.                               x+len+1,0)) < 0)
  1124.     return addr;
  1125.   if(len > 0)
  1126.     memcpy(vm->array[addr].data.byte+x,
  1127.            thread->script->code+thread->code_ptr,len);
  1128.   thread->code_ptr += len+1;
  1129.   vm->array[addr].data.byte[len] = 0;
  1130.   return scvm_thread_write_var(vm,thread,vaddr,addr);
  1131. }
  1132.  
  1133. // 0xA4D0
  1134. static int scvm_op_array_write_list(scvm_t* vm, scvm_thread_t* thread) {
  1135.   int r,val,addr;
  1136.   uint16_t vaddr;
  1137.   unsigned len,x;
  1138.   
  1139.   if((r=scvm_pop(vm,&x)) ||
  1140.      (r=scvm_thread_r16(thread,&vaddr)) ||
  1141.      (r = scvm_thread_read_var(vm,thread,vaddr,&addr)) ||
  1142.      (r = scvm_pop(vm,&len))) return r;
  1143.   if(addr <= 0) {
  1144.     if((addr = scvm_alloc_array(vm,SCVM_ARRAY_WORD, x+len,0)) <= 0)
  1145.       return addr;
  1146.     scvm_thread_write_var(vm,thread,vaddr,addr);
  1147.   }
  1148.   while(len > 0) {
  1149.     if((r = scvm_pop(vm,&val)) ||
  1150.        (r=scvm_write_array(vm,addr,x,0,val))) return r;
  1151.     len--, x++;
  1152.   }
  1153.   return 0;
  1154. }
  1155.  
  1156. // 0xA4D4
  1157. static int scvm_op_array_write_list2(scvm_t* vm, scvm_thread_t* thread) {
  1158.   int r,addr;
  1159.   uint16_t vaddr;
  1160.   unsigned len,x,y;
  1161.   
  1162.   if((r=scvm_pop(vm,&x)) ||
  1163.      (r=scvm_thread_r16(thread,&vaddr)) ||
  1164.      (r = scvm_thread_read_var(vm,thread,vaddr,&addr)) ||
  1165.      (r = scvm_pop(vm,&len))) return r;
  1166.   if(!addr || addr >= vm->num_array) return SCVM_ERR_BAD_ADDR;
  1167.   else {
  1168.     int i,list[len];
  1169.     for(i = 0 ; i < len ; i++)
  1170.       if((r = scvm_pop(vm,list+i))) return r;
  1171.     if((r = scvm_pop(vm,&y))) return r;
  1172.     for(i = 0 ; i < len ; i++)
  1173.       if((r = scvm_write_array(vm,addr,x+i,y,list[i]))) return r;
  1174.   }
  1175.   return 0;
  1176. }
  1177.  
  1178. // 0xA9A8
  1179. static int scvm_op_wait_for_actor(scvm_t* vm, scvm_thread_t* thread) {
  1180.   int r;
  1181.   unsigned a;
  1182.   int16_t off;
  1183.   if((r=scvm_pop(vm,&a)) ||
  1184.      (r=scvm_thread_r16(thread,&off))) return r;
  1185.   if(a >= vm->num_actor) return SCVM_ERR_BAD_ACTOR;
  1186.   if(vm->actor[a].walking) {
  1187.       thread->code_ptr += off;
  1188.       return scvm_op_break_script(vm,thread);
  1189.   }
  1190.   return 0;
  1191. }
  1192.  
  1193. // 0xA9A8 A9E2 A9E8
  1194. static int scvm_op_wait_for(scvm_t* vm, scvm_thread_t* thread) {
  1195.   int r;
  1196.   unsigned x;
  1197.   uint16_t off;
  1198.   if((r=scvm_pop(vm,&x)) ||
  1199.      (r=scvm_thread_r16(thread,&off))) return r;
  1200.   return scvm_op_break_script(vm,thread);
  1201. }
  1202.  
  1203. // 0xA9A9 A9AA A9AB
  1204. static int scvm_op_wait(scvm_t* vm, scvm_thread_t* thread) {
  1205.   return scvm_op_break_script(vm,thread);  
  1206. }
  1207.  
  1208. // 0xAA
  1209. static int scvm_op_get_actor_x_scale(scvm_t* vm, scvm_thread_t* thread) {
  1210.   int r,a;
  1211.   if((r=scvm_pop(vm,&a))) return a;
  1212.   if(a >= vm->num_actor) return SCVM_ERR_BAD_ACTOR;
  1213.   return scvm_push(vm,vm->actor[a].scale_x);
  1214. }
  1215.  
  1216. // 0xAB
  1217. static int scvm_op_get_actor_anim_counter(scvm_t* vm, scvm_thread_t* thread) {
  1218.   int r,a;
  1219.   if((r=scvm_pop(vm,&a))) return r;
  1220.   if(a < 0 || a >= vm->num_actor) return SCVM_ERR_BAD_ACTOR;
  1221.   return scvm_push(vm,vm->actor[a].costdec.anim_counter);
  1222. }
  1223.  
  1224.  
  1225. // 0xAC
  1226. static int scvm_op_sound_kludge(scvm_t* vm, scvm_thread_t* thread) {
  1227.   int r;
  1228.   unsigned num;
  1229.   // drop the list for now
  1230.   r=scvm_pop(vm,&num);
  1231.   while(!r && num > 0) {
  1232.     r=scvm_pop(vm,NULL);
  1233.     num--;
  1234.   }
  1235.   return r;
  1236. }
  1237.  
  1238. // 0xAD
  1239. static int scvm_op_is_any_of(scvm_t* vm, scvm_thread_t* thread) {
  1240.   int r;
  1241.   unsigned len;
  1242.   if((r=scvm_pop(vm,&len))) return r;
  1243.   else {
  1244.     int i,val,list[len];
  1245.     for(i = len-1 ; i >= 0 ; i--)
  1246.       if((r=scvm_pop(vm,list+i))) return r;
  1247.     if((r=scvm_pop(vm,&val))) return r;
  1248.     for(i = 0 ; i < len ; i++)
  1249.       if(val == list[i])
  1250.         return scvm_push(vm,1);
  1251.   }
  1252.   return scvm_push(vm,0);
  1253. }
  1254.  
  1255. // 0xB0
  1256. static int scvm_op_delay(scvm_t* vm, scvm_thread_t* thread) {
  1257.   int r;
  1258.   unsigned d;
  1259.   if((r=scvm_pop(vm,&d))) return r;
  1260.   thread->delay = d*16;
  1261.   thread->state = SCVM_THREAD_DELAYED;
  1262.   return 0;
  1263. }
  1264.  
  1265. // 0xB1
  1266. static int scvm_op_delay_seconds(scvm_t* vm, scvm_thread_t* thread) {
  1267.   int r;
  1268.   unsigned d;
  1269.   if((r=scvm_pop(vm,&d))) return r;
  1270.   thread->delay = d*1000;
  1271.   thread->state = SCVM_THREAD_DELAYED;
  1272.   return 0;
  1273. }
  1274.  
  1275. // 0xB2
  1276. static int scvm_op_delay_minutes(scvm_t* vm, scvm_thread_t* thread) {
  1277.   int r;
  1278.   unsigned d;
  1279.   if((r=scvm_pop(vm,&d))) return r;
  1280.   thread->delay = d*60000;
  1281.   thread->state = SCVM_THREAD_DELAYED;
  1282.   return 0;
  1283. }
  1284.  
  1285. // 0xBA
  1286. static int scvm_op_actor_say(scvm_t* vm, scvm_thread_t* thread) {
  1287.     int r,len;
  1288.     int actor;
  1289.     if((r = scvm_pop(vm,&actor))) return r;
  1290.  
  1291.     if((r = scvm_thread_strlen(thread,&len))) return r;
  1292.     thread->code_ptr += len+1;
  1293.  
  1294.     return 0;
  1295. }
  1296.  
  1297. // 0xBB
  1298. static int scvm_op_ego_say(scvm_t* vm, scvm_thread_t* thread) {
  1299.     scvm_push(vm, vm->var->ego);
  1300.     return scvm_op_actor_say(vm, thread);
  1301. }
  1302.  
  1303. // 0xBC
  1304. static int scvm_op_dim(scvm_t* vm, scvm_thread_t* thread) {
  1305.   int r,addr;
  1306.   unsigned size;
  1307.   uint8_t op;
  1308.   uint16_t vaddr;
  1309.   
  1310.   if((r=scvm_thread_r8(thread,&op)) ||
  1311.      (r=scvm_thread_r16(thread,&vaddr))) return r;
  1312.   
  1313.   if(op == 0xCC) { // UNDIM
  1314.     if((r=scvm_thread_read_var(vm,thread,vaddr,&addr)) ||
  1315.        (r=scvm_nuke_array(vm,addr)))
  1316.       return r;
  1317.     return scvm_thread_write_var(vm,thread,vaddr,0);
  1318.   }
  1319.   
  1320.   if(op < 0xC7 || op > 0xCB) return SCVM_ERR_NO_OP;
  1321.   if((r=scvm_pop(vm,&size))) return r;
  1322.   
  1323.   switch(op) {
  1324.   case 0xC7:
  1325.     addr = scvm_alloc_array(vm,SCVM_ARRAY_WORD,size,0);
  1326.     break;
  1327.   case 0xC8:
  1328.     addr = scvm_alloc_array(vm,SCVM_ARRAY_BIT,size,0);
  1329.     break;
  1330.   case 0xC9:
  1331.     addr = scvm_alloc_array(vm,SCVM_ARRAY_NIBBLE,size,0);
  1332.     break;
  1333.   case 0xCA: // byte
  1334.   case 0xCB: // char
  1335.     addr = scvm_alloc_array(vm,SCVM_ARRAY_BYTE,size,0);
  1336.     break;
  1337.   }
  1338.   if(addr < 0) return addr;
  1339.   return scvm_thread_write_var(vm,thread,vaddr,addr);
  1340. }
  1341.  
  1342. // 0xC5
  1343. static int scvm_op_get_distance_obj_obj(scvm_t* vm, scvm_thread_t* thread) {
  1344.   int r;
  1345.   unsigned objA, objB;
  1346.   int ax,ay, bx,by;
  1347.  
  1348.   if((r = scvm_vpop(vm,&objB,&objA,NULL)) ||
  1349.      (r = scvm_get_object_position(vm,objA,&ax,&ay)) < 0 ||
  1350.      (r = scvm_get_object_position(vm,objB,&bx,&by)) < 0) return r;
  1351.   return scvm_push(vm,hypot(bx-ax,by-ay));
  1352. }
  1353.  
  1354. // 0xCA
  1355. static int scvm_op_break_script_n_times(scvm_t* vm, scvm_thread_t* thread) {
  1356.   int r;
  1357.   unsigned n;
  1358.   if((r=scvm_pop(vm,&n))) return r;
  1359.   thread->cycle = vm->cycle+n;
  1360.   return 0;
  1361. }
  1362.  
  1363. static int scvm_op_dummy(scvm_t* vm, scvm_thread_t* thread) {
  1364.   return 0;
  1365. }
  1366.  
  1367. static int scvm_op_dummy_v(scvm_t* vm, scvm_thread_t* thread) {
  1368.   return scvm_pop(vm,NULL);
  1369. }
  1370.  
  1371. static int scvm_op_dummy_vv(scvm_t* vm, scvm_thread_t* thread) {
  1372.   int r;
  1373.   if((r=scvm_pop(vm,NULL))) return r;
  1374.   return scvm_pop(vm,NULL);
  1375. }
  1376.  
  1377. static int scvm_op_dummy_vvv(scvm_t* vm, scvm_thread_t* thread) {
  1378.   int r;
  1379.   if((r=scvm_pop(vm,NULL)) ||
  1380.      (r=scvm_pop(vm,NULL))) return r;
  1381.   return scvm_pop(vm,NULL);
  1382. }
  1383.  
  1384. static int scvm_op_dummy_vvvv(scvm_t* vm, scvm_thread_t* thread) {
  1385.   int r;
  1386.   if((r=scvm_pop(vm,NULL)) ||
  1387.      (r=scvm_pop(vm,NULL)) ||
  1388.      (r=scvm_pop(vm,NULL))) return r;
  1389.   return scvm_pop(vm,NULL);
  1390. }
  1391.  
  1392. static int scvm_op_dummy_vvvvv(scvm_t* vm, scvm_thread_t* thread) {
  1393.   int r;
  1394.   if((r=scvm_pop(vm,NULL)) ||
  1395.      (r=scvm_pop(vm,NULL)) ||
  1396.      (r=scvm_pop(vm,NULL)) ||
  1397.      (r=scvm_pop(vm,NULL))) return r;
  1398.   return scvm_pop(vm,NULL);
  1399. }
  1400.  
  1401. static int scvm_op_dummy_l(scvm_t* vm, scvm_thread_t* thread) {
  1402.   int r,len;
  1403.   if((r=scvm_pop(vm,&len))) return r;
  1404.   while(len > 0) {
  1405.     if((r=scvm_pop(vm,NULL))) return r;
  1406.     len--;
  1407.   }
  1408.   return 0;
  1409. }
  1410.  
  1411. static int scvm_op_dummy_s(scvm_t* vm, scvm_thread_t* thread) {
  1412.   int r,len;
  1413.   if((r = scvm_thread_strlen(thread,&len))) return r;
  1414.   thread->code_ptr += len+1;
  1415.   return 0;
  1416. }
  1417.  
  1418. static int scvm_op_dummy_print(scvm_t* vm, scvm_thread_t* thread) {
  1419.   int r;
  1420.   uint8_t op;
  1421.   if((r = scvm_thread_r8(thread,&op))) return r;
  1422.   switch(op) {
  1423.   case 0x41: // at
  1424.     return scvm_op_dummy_vv(vm,thread);
  1425.   case 0x42: // color
  1426.   case 0x43: // clipped
  1427.     return scvm_op_dummy_v(vm,thread);
  1428.   case 0x45: // center
  1429.   case 0x47: // left
  1430.   case 0x48: // overhead
  1431.   case 0x4A: // mumble
  1432.   case 0xFE: // begin
  1433.   case 0xFF: // end
  1434.     return 0;
  1435.   case 0x4B:
  1436.     return scvm_op_dummy_s(vm,thread);
  1437.   }
  1438.   return SCVM_ERR_NO_OP;
  1439. }
  1440.  
  1441. static int scvm_op_dummy_get_at(scvm_t* vm, scvm_thread_t* thread) {
  1442.   int r,x,y;
  1443.   if((r = scvm_vpop(vm,&y,&x,NULL))) return r;
  1444.   return scvm_push(vm,0);
  1445. }
  1446.  
  1447.  
  1448. static int scvm_op_subop(scvm_t* vm, scvm_thread_t* thread) {
  1449.   return scvm_thread_do_op(vm,thread,vm->suboptable);
  1450. }
  1451.  
  1452. scvm_op_t scvm_optable[0x100] = {
  1453.   // 00
  1454.   { scvm_op_push_byte, "push" },
  1455.   { scvm_op_push_word, "push" },
  1456.   { scvm_op_var_read_byte, "read var" },
  1457.   { scvm_op_var_read_word, "read var" },
  1458.   // 04
  1459.   { NULL, NULL },
  1460.   { NULL, NULL },
  1461.   { scvm_op_array_read_byte, "read array" },
  1462.   { scvm_op_array_read_word, "read array" },
  1463.   // 08
  1464.   { NULL, NULL },
  1465.   { NULL, NULL },
  1466.   { scvm_op_array2_read_byte, "read array2" },
  1467.   { scvm_op_array2_read_word, "read array2" },
  1468.   // 0C
  1469.   { scvm_op_dup, "dup" },
  1470.   { scvm_op_not, "not" },
  1471.   { scvm_op_eq, "eq" },
  1472.   { scvm_op_neq, "neq" },
  1473.   // 10
  1474.   { scvm_op_gt, "gt" },
  1475.   { scvm_op_lt, "lt" },
  1476.   { scvm_op_le, "le" },
  1477.   { scvm_op_ge, "ge" },
  1478.   // 14
  1479.   { scvm_op_add, "add" },
  1480.   { scvm_op_sub, "sub" },
  1481.   { scvm_op_mul, "mul" },
  1482.   { scvm_op_div, "div" },
  1483.   // 18
  1484.   { scvm_op_land, "land" },
  1485.   { scvm_op_lor, "lor" },
  1486.   { scvm_op_pop, "pop" },
  1487.   { NULL, NULL },
  1488.   // 1C
  1489.   { NULL, NULL },
  1490.   { NULL, NULL },
  1491.   { NULL, NULL },
  1492.   { NULL, NULL },
  1493.   // 20
  1494.   { NULL, NULL },
  1495.   { NULL, NULL },
  1496.   { NULL, NULL },
  1497.   { NULL, NULL },
  1498.   // 24
  1499.   { NULL, NULL },
  1500.   { NULL, NULL },
  1501.   { NULL, NULL },
  1502.   { NULL, NULL },
  1503.   // 28
  1504.   { NULL, NULL },
  1505.   { NULL, NULL },
  1506.   { NULL, NULL },
  1507.   { NULL, NULL },
  1508.   // 2C
  1509.   { NULL, NULL },
  1510.   { NULL, NULL },
  1511.   { NULL, NULL },
  1512.   { NULL, NULL },
  1513.   // 30
  1514.   { NULL, NULL },
  1515.   { NULL, NULL },
  1516.   { NULL, NULL },
  1517.   { NULL, NULL },
  1518.   // 34
  1519.   { NULL, NULL },
  1520.   { NULL, NULL },
  1521.   { NULL, NULL },
  1522.   { NULL, NULL },
  1523.   // 38
  1524.   { NULL, NULL },
  1525.   { NULL, NULL },
  1526.   { NULL, NULL },
  1527.   { NULL, NULL },
  1528.   // 3C
  1529.   { NULL, NULL },
  1530.   { NULL, NULL },
  1531.   { NULL, NULL },
  1532.   { NULL, NULL },
  1533.   // 40
  1534.   { NULL, NULL },
  1535.   { NULL, NULL },
  1536.   { scvm_op_var_write_byte, "write var" },
  1537.   { scvm_op_var_write_word, "write var" },
  1538.   // 44
  1539.   { NULL, NULL },
  1540.   { NULL, NULL },
  1541.   { scvm_op_array_write_byte, "write array" },
  1542.   { scvm_op_array_write_word, "write array" },
  1543.   // 48
  1544.   { NULL, NULL },
  1545.   { NULL, NULL },
  1546.   { scvm_op_array2_write_byte, "write array2" },
  1547.   { scvm_op_array2_write_word, "write array2" },
  1548.   // 4C
  1549.   { NULL, NULL },
  1550.   { NULL, NULL },
  1551.   { scvm_op_var_inc_byte, "inc var" },
  1552.   { scvm_op_var_inc_word, "inc var" },
  1553.   // 50
  1554.   { NULL, NULL },
  1555.   { NULL, NULL },
  1556.   { scvm_op_array_inc_byte, "inc array" },
  1557.   { scvm_op_array_inc_word, "inc array" },
  1558.   // 54
  1559.   { NULL, NULL },
  1560.   { NULL, NULL },
  1561.   { scvm_op_var_dec_byte, "dec var" },
  1562.   { scvm_op_var_dec_word, "dec var" },
  1563.   // 58
  1564.   { NULL, NULL },
  1565.   { NULL, NULL },
  1566.   { scvm_op_array_dec_byte, "dec array" },
  1567.   { scvm_op_array_dec_word, "dec array" },
  1568.   // 5C
  1569.   { scvm_op_jmp_not_zero, "jump if not zero" },
  1570.   { scvm_op_jmp_zero, "jump if zero" },
  1571.   { scvm_op_start_script, "start script" },
  1572.   { scvm_op_start_script0, "start script0" },
  1573.   // 60
  1574.   { NULL, NULL },
  1575.   { scvm_op_draw_object, "draw object" },
  1576.   { NULL, NULL },
  1577.   { NULL, NULL },
  1578.   // 64
  1579.   { NULL, NULL },
  1580.   { scvm_op_stop_thread, "stop thread" },
  1581.   { scvm_op_stop_thread, "stop thread" },
  1582.   { NULL, NULL },
  1583.   // 68
  1584.   { NULL, NULL },
  1585.   { NULL, NULL },
  1586.   { NULL, NULL },
  1587.   { scvm_op_subop, "interface op" },
  1588.   // 6C
  1589.   { scvm_op_break_script, "break script" },
  1590.   { NULL, NULL },
  1591.   { NULL, NULL },
  1592.   { scvm_op_dummy_v, "set object state" },
  1593.   // 70
  1594.   { scvm_op_dummy_vv, "set object state" },
  1595.   { scvm_op_dummy_vv, "set object owner" },
  1596.   { scvm_op_dummy_v, "get object owner" },
  1597.   { scvm_op_jmp, "jump" },
  1598.   // 74
  1599.   { scvm_op_dummy_v, "start sound" },
  1600.   { scvm_op_dummy_v, "stop sound" },
  1601.   { scvm_op_dummy_v, "start music" },
  1602.   { NULL, NULL },
  1603.   // 78
  1604.   { scvm_op_pan_camera_to, "pan camera to" },
  1605.   { scvm_op_camera_follow_actor, "camera follow actor" },
  1606.   { scvm_op_set_camera_at, "set camera at" },
  1607.   { scvm_op_start_room, "start room" },
  1608.   // 7C
  1609.   { scvm_op_stop_script, "stop script" },
  1610.   { scvm_op_dummy_vvv, "walk actor to object" },
  1611.   { scvm_op_walk_actor_to, "walk actor to" },
  1612.   { scvm_op_put_actor_at, "put actor at" },
  1613.   // 80
  1614.   { scvm_op_dummy_vvv,  "put actor at object" },
  1615.   { scvm_op_dummy_vv, "actor face" },
  1616.   { scvm_op_actor_animate, "actor animate" },
  1617.   { scvm_op_dummy_vvvv, "do sentence" },
  1618.   // 84
  1619.   { scvm_op_dummy_vv, "pickup object" },
  1620.   { NULL, NULL },
  1621.   { NULL, NULL },
  1622.   { scvm_op_get_random_number, "get random number" },
  1623.   // 88
  1624.   { scvm_op_get_random_number_range, "get random number range" },
  1625.   { NULL, NULL },
  1626.   { NULL, NULL },
  1627.   { scvm_op_is_script_running, "is script running" },
  1628.   // 8C
  1629.   { scvm_op_get_actor_room, "get actor room" },
  1630.   { scvm_op_get_object_x, "get object x" },
  1631.   { scvm_op_get_object_y, "get object y" },
  1632.   { scvm_op_get_object_direction, "get object direction" },
  1633.   // 90
  1634.   { scvm_op_get_actor_walk_box, "get actor walk box" },
  1635.   { NULL, NULL },
  1636.   { NULL, NULL },
  1637.   { NULL, NULL },
  1638.   // 94
  1639.   { scvm_op_dummy_get_at, "get verb at" },
  1640.   { scvm_op_begin_override, "begin override" },
  1641.   { scvm_op_end_override, "end override" },
  1642.   { NULL, NULL },
  1643.   // 98
  1644.   { NULL, NULL },
  1645.   { NULL, NULL },
  1646.   { NULL, NULL },
  1647.   { scvm_op_resource, "resource op" },
  1648.   // 9C
  1649.   { scvm_op_subop, "view op" },
  1650.   { scvm_op_subop, "actor op" },
  1651.   { scvm_op_subop, "verb op" },
  1652.   { scvm_op_dummy_get_at, "get actor at" },
  1653.   // A0
  1654.   { scvm_op_dummy_get_at, "get object at" },
  1655.   { NULL, NULL },
  1656.   { NULL, NULL },
  1657.   { NULL, NULL },
  1658.   // A4
  1659.   { scvm_op_subop, "array write" },
  1660.   { NULL, NULL },
  1661.   { NULL, NULL },
  1662.   { NULL, NULL },
  1663.   // A8
  1664.   { NULL, NULL },
  1665.   { scvm_op_subop, "wait" },
  1666.   { scvm_op_get_actor_x_scale, "get actor x scale" },
  1667.   { scvm_op_get_actor_anim_counter, "get actor anim counter" },
  1668.   // AC
  1669.   { scvm_op_sound_kludge, "sound kludge" },
  1670.   { scvm_op_is_any_of, "is any of" },
  1671.   { NULL, NULL },
  1672.   { NULL, NULL },
  1673.   // B0
  1674.   { scvm_op_delay, "delay" },
  1675.   { scvm_op_delay_seconds, "delay seconds" },
  1676.   { scvm_op_delay_minutes, "delay minutes"  },
  1677.   { scvm_op_dummy, "stop sentence" },
  1678.   // B4
  1679.   { scvm_op_dummy_print, "print" },
  1680.   { scvm_op_dummy_print, "cursor print" },
  1681.   { scvm_op_dummy_print, "debug print" },
  1682.   { scvm_op_dummy_print, "sys print" },
  1683.   // B8
  1684.   { scvm_op_dummy_print, "actor print" },
  1685.   { scvm_op_dummy_print, "ego print" },
  1686.   { scvm_op_actor_say, "actor say" },
  1687.   { scvm_op_ego_say, "ego say" },
  1688.   // BC
  1689.   { scvm_op_dim, "dim" },
  1690.   { NULL, NULL },
  1691.   { NULL, NULL },
  1692.   { scvm_op_start_script_recursive, "start script recursive" },
  1693.   // C0
  1694.   { NULL, NULL },
  1695.   { NULL, NULL },
  1696.   { NULL, NULL },
  1697.   { NULL, NULL },
  1698.   // C4
  1699.   { NULL, NULL },
  1700.   { scvm_op_get_distance_obj_obj, "get dist obj obj" },
  1701.   { NULL, NULL },
  1702.   { NULL, NULL },
  1703.   // C8
  1704.   { NULL, NULL },
  1705.   { NULL, NULL },
  1706.   { scvm_op_break_script_n_times, "break script n times" },
  1707.   { NULL, NULL },
  1708.   // CC
  1709.   { NULL, NULL },
  1710.   { NULL, NULL },
  1711.   { NULL, NULL },
  1712.   { NULL, NULL },
  1713.   // D0
  1714.   { NULL, NULL },
  1715.   { NULL, NULL },
  1716.   { NULL, NULL },
  1717.   { NULL, NULL },
  1718.   // D4
  1719.   { NULL, NULL },
  1720.   { NULL, NULL },
  1721.   { scvm_op_band, "bit and" },
  1722.   { scvm_op_bor, "bit or" },
  1723.   // D8
  1724.   { NULL, NULL },
  1725.   { NULL, NULL },
  1726.   { NULL, NULL },
  1727.   { NULL, NULL },
  1728.   // DC
  1729.   { NULL, NULL },
  1730.   { NULL, NULL },
  1731.   { NULL, NULL },
  1732.   { NULL, NULL },
  1733.   // E0
  1734.   { NULL, NULL },
  1735.   { NULL, NULL },
  1736.   { NULL, NULL },
  1737.   { NULL, NULL },
  1738.   // E4
  1739.   { NULL, NULL },
  1740.   { NULL, NULL },
  1741.   { NULL, NULL },
  1742.   { NULL, NULL },
  1743.   // E8
  1744.   { NULL, NULL },
  1745.   { NULL, NULL },
  1746.   { NULL, NULL },
  1747.   { NULL, NULL },
  1748.   // EC
  1749.   { NULL, NULL },
  1750.   { NULL, NULL },
  1751.   { NULL, NULL },
  1752.   { NULL, NULL },
  1753.   // F0
  1754.   { NULL, NULL },
  1755.   { NULL, NULL },
  1756.   { NULL, NULL },
  1757.   { NULL, NULL },
  1758.   // F4
  1759.   { NULL, NULL },
  1760.   { NULL, NULL },
  1761.   { NULL, NULL },
  1762.   { NULL, NULL },
  1763.   // F8
  1764.   { NULL, NULL },
  1765.   { NULL, NULL },
  1766.   { NULL, NULL },
  1767.   { NULL, NULL },
  1768.   // FC
  1769.   { NULL, NULL },
  1770.   { NULL, NULL },
  1771.   { NULL, NULL },
  1772.   { NULL, NULL }
  1773. };
  1774.  
  1775. scvm_op_t scvm_suboptable[0x100] = {
  1776.   // 00
  1777.   { NULL, NULL },
  1778.   { NULL, NULL },
  1779.   { NULL, NULL },
  1780.   { NULL, NULL },
  1781.   // 04
  1782.   { NULL, NULL },
  1783.   { NULL, NULL },
  1784.   { NULL, NULL },
  1785.   { NULL, NULL },
  1786.   // 08
  1787.   { NULL, NULL },
  1788.   { NULL, NULL },
  1789.   { NULL, NULL },
  1790.   { NULL, NULL },
  1791.   // 0C
  1792.   { NULL, NULL },
  1793.   { NULL, NULL },
  1794.   { NULL, NULL },
  1795.   { NULL, NULL },
  1796.   // 10
  1797.   { NULL, NULL },
  1798.   { NULL, NULL },
  1799.   { NULL, NULL },
  1800.   { NULL, NULL },
  1801.   // 14
  1802.   { NULL, NULL },
  1803.   { NULL, NULL },
  1804.   { NULL, NULL },
  1805.   { NULL, NULL },
  1806.   // 18
  1807.   { NULL, NULL },
  1808.   { NULL, NULL },
  1809.   { NULL, NULL },
  1810.   { NULL, NULL },
  1811.   // 1C
  1812.   { NULL, NULL },
  1813.   { NULL, NULL },
  1814.   { NULL, NULL },
  1815.   { NULL, NULL },
  1816.   // 20
  1817.   { NULL, NULL },
  1818.   { NULL, NULL },
  1819.   { NULL, NULL },
  1820.   { NULL, NULL },
  1821.   // 24
  1822.   { NULL, NULL },
  1823.   { NULL, NULL },
  1824.   { NULL, NULL },
  1825.   { NULL, NULL },
  1826.   // 28
  1827.   { NULL, NULL },
  1828.   { NULL, NULL },
  1829.   { NULL, NULL },
  1830.   { NULL, NULL },
  1831.   // 2C
  1832.   { NULL, NULL },
  1833.   { NULL, NULL },
  1834.   { NULL, NULL },
  1835.   { NULL, NULL },
  1836.   // 30
  1837.   { NULL, NULL },
  1838.   { NULL, NULL },
  1839.   { NULL, NULL },
  1840.   { NULL, NULL },
  1841.   // 34
  1842.   { NULL, NULL },
  1843.   { NULL, NULL },
  1844.   { NULL, NULL },
  1845.   { NULL, NULL },
  1846.   // 38
  1847.   { NULL, NULL },
  1848.   { NULL, NULL },
  1849.   { NULL, NULL },
  1850.   { NULL, NULL },
  1851.   // 3C
  1852.   { NULL, NULL },
  1853.   { NULL, NULL },
  1854.   { NULL, NULL },
  1855.   { NULL, NULL },
  1856.   // 40
  1857.   { NULL, NULL },
  1858.   { NULL, NULL },
  1859.   { NULL, NULL },
  1860.   { NULL, NULL },
  1861.   // 44
  1862.   { NULL, NULL },
  1863.   { NULL, NULL },
  1864.   { NULL, NULL },
  1865.   { NULL, NULL },
  1866.   // 48
  1867.   { NULL, NULL },
  1868.   { NULL, NULL },
  1869.   { NULL, NULL },
  1870.   { NULL, NULL },
  1871.   // 4C
  1872.   { scvm_op_set_actor_costume, "set costume" },
  1873.   { scvm_op_set_actor_walk_speed, "set walk speed" },
  1874.   { scvm_op_dummy_l, "set sounds" },
  1875.   { scvm_op_set_actor_walk_frame, "set walk frame" },
  1876.   // 50
  1877.   { scvm_op_set_actor_talk_frame, "set talk frame" },
  1878.   { scvm_op_set_actor_stand_frame, "set stand frame" },
  1879.   { NULL, NULL },
  1880.   { scvm_op_actor_init, "init" },
  1881.   // 54
  1882.   { scvm_op_set_actor_elevation, "set elevation" },
  1883.   { scvm_op_set_actor_default_frames, "default frames" },
  1884.   { NULL, NULL },
  1885.   { scvm_op_set_actor_talk_color, "set talk color" },
  1886.   // 58
  1887.   { scvm_op_set_actor_name, "set name" },
  1888.   { scvm_op_set_actor_init_frame, "set init frame" },
  1889.   { NULL, NULL },
  1890.   { scvm_op_set_actor_width, "set width" },
  1891.   // 5C
  1892.   { scvm_op_set_actor_scale, "set scale" },
  1893.   { scvm_op_dummy, "never z clip" },
  1894.   { NULL, NULL },
  1895.   { scvm_op_set_actor_ignore_boxes, "ignore boxes" },
  1896.   // 60
  1897.   { scvm_op_set_actor_follow_boxes, "follow boxes" },
  1898.   { scvm_op_set_actor_anim_speed, "set anim speed" },
  1899.   { scvm_op_dummy_v, "set shadow mode" },
  1900.   { scvm_op_set_actor_talk_pos, "set talk pos" },
  1901.   // 64
  1902.   { NULL, NULL },
  1903.   { NULL, NULL },
  1904.   { NULL, NULL },
  1905.   { NULL, NULL },
  1906.   // 68
  1907.   { NULL, NULL },
  1908.   { NULL, NULL },
  1909.   { NULL, NULL },
  1910.   { NULL, NULL },
  1911.   // 6C
  1912.   { NULL, NULL },
  1913.   { NULL, NULL },
  1914.   { NULL, NULL },
  1915.   { NULL, NULL },
  1916.   // 70
  1917.   { NULL, NULL },
  1918.   { NULL, NULL },
  1919.   { NULL, NULL },
  1920.   { NULL, NULL },
  1921.   // 74
  1922.   { NULL, NULL },
  1923.   { NULL, NULL },
  1924.   { NULL, NULL },
  1925.   { NULL, NULL },
  1926.   // 78
  1927.   { NULL, NULL },
  1928.   { NULL, NULL },
  1929.   { NULL, NULL },
  1930.   { NULL, NULL },
  1931.   // 7C
  1932.   { scvm_op_dummy_v, "set image" },
  1933.   { scvm_op_dummy_s, "set name" },
  1934.   { scvm_op_dummy_v, "set color" },
  1935.   { scvm_op_dummy_v, "set hi-color" },
  1936.   // 80
  1937.   { scvm_op_dummy_vv, "set XY" },
  1938.   { scvm_op_dummy, "set on" },
  1939.   { scvm_op_dummy, "set off" },
  1940.   { scvm_op_dummy, "kill" },
  1941.   // 84
  1942.   { scvm_op_dummy, "init" },
  1943.   { scvm_op_dummy_v, "set dim-color" },
  1944.   { scvm_op_dummy, "dim" },
  1945.   { scvm_op_dummy_v, "set key" },
  1946.   // 88
  1947.   { scvm_op_dummy, "set center" },
  1948.   { scvm_op_dummy_v, "set name string" },
  1949.   { NULL, NULL },
  1950.   { scvm_op_dummy_vv, "set object" },
  1951.   // 8C
  1952.   { scvm_op_dummy_v, "set back color" },
  1953.   { NULL, NULL },
  1954.   { NULL, NULL },
  1955.   { NULL, NULL },
  1956.   // 90
  1957.   { scvm_op_dummy, "cursor on" },
  1958.   { scvm_op_dummy, "cursor off" },
  1959.   { scvm_op_dummy, "user put on" },
  1960.   { scvm_op_dummy, "user put off" },
  1961.   // 94
  1962.   { scvm_op_dummy, "soft cursor on" },
  1963.   { scvm_op_dummy, "soft curosr off" },
  1964.   { scvm_op_dummy, "soft user put on" },
  1965.   { scvm_op_dummy, "soft user put off" },
  1966.   // 98
  1967.   { NULL, NULL },
  1968.   { scvm_op_dummy_vv, "set cursor image" },
  1969.   { scvm_op_dummy_vv, "set cursor hotspot" },
  1970.   { NULL, NULL },
  1971.   // 9C
  1972.   { scvm_op_dummy_v, "init charset" },
  1973.   { scvm_op_dummy_l, "set charset colors" },
  1974.   { NULL, NULL },
  1975.   { NULL, NULL },
  1976.   // A0
  1977.   { NULL, NULL },
  1978.   { NULL, NULL },
  1979.   { NULL, NULL },
  1980.   { NULL, NULL },
  1981.   // A4
  1982.   { NULL, NULL },
  1983.   { NULL, NULL },
  1984.   { NULL, NULL },
  1985.   { NULL, NULL },
  1986.   // A8
  1987.   { scvm_op_wait_for_actor, "wait actor" },
  1988.   { scvm_op_wait, "wait msg" },
  1989.   { scvm_op_wait, "wait camera" },
  1990.   { scvm_op_wait, "wait sentence" },
  1991.   // AC
  1992.   { scvm_op_set_scrolling, "set scrolling" },
  1993.   { NULL, NULL },
  1994.   { scvm_op_set_screen, "set screen" },
  1995.   { scvm_op_set_room_color, "room color" },
  1996.   // B0
  1997.   { scvm_op_shake_on, "shake on" },
  1998.   { scvm_op_shake_off, "shake off" },
  1999.   { NULL, NULL },
  2000.   { scvm_op_set_room_intensity, "room intensity" },
  2001.   // B4
  2002.   { scvm_op_dummy_vv, "save/load thing" },
  2003.   { scvm_op_set_transition_effect, "transition effect" },
  2004.   { scvm_op_set_rgb_intensity, "rgb intensitiy" },
  2005.   { scvm_op_dummy_vvvvv, "room shadow" },
  2006.   // B8
  2007.   { NULL, NULL },
  2008.   { NULL, NULL },
  2009.   { scvm_op_dummy_vvvv, "pal manip" },
  2010.   { scvm_op_dummy_vv, "cycle delay" },
  2011.   // BC
  2012.   { NULL, NULL },
  2013.   { NULL, NULL },
  2014.   { NULL, NULL },
  2015.   { NULL, NULL },
  2016.   // C0
  2017.   { NULL, NULL },
  2018.   { NULL, NULL },
  2019.   { NULL, NULL },
  2020.   { NULL, NULL },
  2021.   // C4
  2022.   { scvm_op_dummy_v, "set current verb" },
  2023.   { scvm_op_set_current_actor, "set current actor" },
  2024.   { scvm_op_dummy_vv, "set anim var" },
  2025.   { NULL, NULL },
  2026.   // C8
  2027.   { NULL, NULL },
  2028.   { NULL, NULL },
  2029.   { NULL, NULL },
  2030.   { NULL, NULL },
  2031.   // CC
  2032.   { NULL, NULL },
  2033.   { scvm_op_array_write_string, "array write string" },
  2034.   { NULL, NULL },
  2035.   { NULL, NULL },
  2036.   // D0
  2037.   { scvm_op_array_write_list, "array write list" },
  2038.   { NULL, NULL },
  2039.   { NULL, NULL },
  2040.   { NULL, NULL },
  2041.   // D4
  2042.   { scvm_op_array_write_list2, "array write list2" },
  2043.   { scvm_op_set_palette, "set palette" },
  2044.   { NULL, NULL },
  2045.   { scvm_op_dummy_v, "set cursor transparency" },
  2046.   // D8
  2047.   { NULL, NULL },
  2048.   { NULL, NULL },
  2049.   { NULL, NULL },
  2050.   { NULL, NULL },
  2051.   // DC
  2052.   { NULL, NULL },
  2053.   { NULL, NULL },
  2054.   { NULL, NULL },
  2055.   { NULL, NULL },
  2056.   // E0
  2057.   { NULL, NULL },
  2058.   { NULL, NULL },
  2059.   { scvm_op_wait_for, "wait anim" },
  2060.   { scvm_op_set_actor_layer, "set layer" },
  2061.   // E4
  2062.   { scvm_op_set_actor_walk_script, "set walk script" },
  2063.   { scvm_op_dummy, "set standing" },
  2064.   { scvm_op_set_actor_direction, "set direction" },
  2065.   { scvm_op_dummy_v, "turn to direction" },
  2066.   // E8
  2067.   { scvm_op_wait_for, "wait turn" },
  2068.   { scvm_op_dummy, "freeze" },
  2069.   { scvm_op_dummy, "unfreeze" },
  2070.   { scvm_op_set_actor_talk_script, "set talk script" },
  2071.   // EC
  2072.   { NULL, NULL },
  2073.   { NULL, NULL },
  2074.   { NULL, NULL },
  2075.   { NULL, NULL },
  2076.   // F0
  2077.   { NULL, NULL },
  2078.   { NULL, NULL },
  2079.   { NULL, NULL },
  2080.   { NULL, NULL },
  2081.   // F4
  2082.   { NULL, NULL },
  2083.   { NULL, NULL },
  2084.   { NULL, NULL },
  2085.   { NULL, NULL },
  2086.   // F8
  2087.   { NULL, NULL },
  2088.   { NULL, NULL },
  2089.   { NULL, NULL },
  2090.   { NULL, NULL },
  2091.   // FC
  2092.   { NULL, NULL },
  2093.   { NULL, NULL },
  2094.   { NULL, NULL },
  2095.   { scvm_op_dummy, "redraw" }
  2096. };
  2097.