#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <setjmp.h>

char *buf;
int size;
int maxsize;

void clear_string(void)
{
  size = 0;
}

void add_string(int c)
{
  if (size == maxsize) {
    buf = realloc(buf, maxsize += 1024); if (!buf) { printf("oom\n"); exit(1); }
  }
  buf[size] = c;
  size++;
}

char * get_string(void)
{
  return buf;
}

#define PARAM_1 0x80
#define PARAM_2 0x40
#define PARAM_3 0x20

static int _opcode;
static int _resultVarNumber;
static int _actorToPrintStrFor;

static int script_position;

void m1(const char *f, ...)
{
  va_list l;
  printf("[%x] ", script_position);
  va_start(l, f);
  vprintf(f, l);
  va_end(l);
}

void m11(const char *f, ...)
{
  va_list l;
  va_start(l, f);
  vprintf(f, l);
  va_end(l);
}

void m2(const char *f, ...)
{
  va_list l;
  va_start(l, f);
  vprintf(f, l);
  va_end(l);
  printf("\n");
}

void m(const char *f, ...)
{
  va_list l;
  printf("[%x] ", script_position);
  va_start(l, f);
  vprintf(f, l);
  va_end(l);
  printf("\n");
}

/* to change if... */
static int GF_SMALL_HEADER = 1;
static int _game_version = 3;
static int GID_INDY3 = 1;

FILE *in;
const char *in_name;

jmp_buf err_jmp;

//#define ERR do { printf("%s:%d: ERROR (%s)\n", __FUNCTION__, __LINE__, in_name); exit(1); } while (0)
#define ERR do { longjmp(err_jmp, 1); } while(0)
#define GET(c) do { c = fgetc(in); if (c == EOF) ERR; c ^= 255; /*printf("%x\n", c);*/} while (0)
#define STOP_GET(c) do { c = fgetc(in); if (c != EOF) c ^= 255; /*printf("%x\n", c);*/} while (0)

#define fetchScriptWordSigned fetchScriptWord
unsigned int fetchScriptWord(void)
{
  int c;
  int w;
  GET(c); w = c;
  GET(c); w |= c << 8;
  return w;
}

unsigned int fetchScriptByte(void)
{
  int c;
  int w;
  GET(c); w = c;
  return w;
}

int readVar(uint var) {
        int a;

        if (var & 0x2000) {
                a = fetchScriptWord();
                if (a & 0x2000)
                        var += readVar(a & ~0x2000);
                else
                        var += a & 0xFFF;
                var &= ~0x2000;
        }

        if (!(var & 0xF000)) {
                m("[scummVar %d]", var);
                return var;
        }

        if (var & 0x8000) {
          m("[bitvar? %d]", var);
          return var;
        }

        if (var & 0x4000) {
          m("[localvar %d]", var);
          return var;
        }

  ERR;
  return 0;
}

int getVar() {
  int v = fetchScriptWord();
  v = readVar(v);
  m("[variable %d]", v);
  return v;
}

int getVarOrDirectByte(int mask) {
        if (_opcode & mask)
                return getVar();
        return fetchScriptByte();
}

int getVarOrDirectWord(int mask) {
        if (_opcode & mask)
                return getVar();
        return fetchScriptWordSigned();
}

void getResultPos() {
        int a;

        _resultVarNumber = fetchScriptWord();
        if (_resultVarNumber & 0x2000) {
                a = fetchScriptWord();
                if (a & 0x2000) {
                        _resultVarNumber += readVar(a & ~0x2000);
                } else {
                        _resultVarNumber += a & 0xFFF;
                }
                _resultVarNumber &= ~0x2000;
        }
}

void jumpRelative(const char *op, int a, int b)
{
  int offset = fetchScriptWord();
  int next = ftell(in);
  int no = offset;
  if (no & 0x8000) no |= 0xffff0000;
  m("if (%d %s %d) jmpRel(%d) [%x]", a, op, b, offset, next + no);
}

void saveVars(void)
{
        while ((_opcode = fetchScriptByte()) != 0) {
                switch (_opcode & 0x1F) {
                case 0x01: // write a range of variables
                        getResultPos();
                        getResultPos();
                        break;
                case 0x02: // write a range of string variables
                        getVarOrDirectByte(PARAM_1);
                        getVarOrDirectByte(PARAM_2);

                        break;
                case 0x03: // open file
                        /* TODO */
                        ERR;
                        break;
                case 0x04:
                        return;
                case 0x1F: // close file
                        return;
                }
        }
}

void loadVars(void)
{
        while ((_opcode = fetchScriptByte()) != 0) {
                switch (_opcode & 0x1F) {
                case 0x01: // read a range of variables
                        getResultPos();
                        getResultPos();
                        break;
                case 0x02: // read a range of string variables
                        getVarOrDirectByte(PARAM_1);
                        getVarOrDirectByte(PARAM_2);
                        break;
                case 0x03: // open file
                        /* TODO */
                        ERR;
                        break;
                case 0x04:
                        return;
                case 0x1F: // close file
                        return;
                }
        }
}

void loadPtrToResource(void)
{
  char s[2048];
  int c;
  int pos = 0;
  printf("loadPtrToResource redo\n");
  while (1) {
    c = fetchScriptByte();
    if (pos == 2047) break; s[pos] = c; pos++;
    if (c == 0) break;
    if (c == 0xff) {
      c = fetchScriptByte();
      if (c != 1 && c != 2 && c != 3 && c != 8) {
        fetchScriptByte(); fetchScriptByte();
      }
    }
  }
  s[pos] = 0;
  if (pos == 2047) { printf("bad loadPtrToResource says '%s'\n", s); ERR; }
  printf("loadPtrToResource says '%s'\n", s);
}

int getWordVararg(int *ptr) {
        int i;

        for (i = 0; i < 16; i++)
                ptr[i] = 0;

        i = 0;
        while (i < 16 && (_opcode = fetchScriptByte()) != 0xFF) {
                ptr[i++] = getVarOrDirectWord(PARAM_1);
        }
        if (_opcode != 0xFF) ERR;
        return i;
}

void decodeParseString(void)
{
        int textSlot;

        switch (_actorToPrintStrFor) {
        case 252:
                textSlot = 3;
                break;
        case 253:
                textSlot = 2;
                break;
        case 254:
                textSlot = 1;
                break;
        default:
                textSlot = 0;
        }

        while ((_opcode = fetchScriptByte()) != 0xFF) {
                switch (_opcode & 0xF) {
                case 0:         // SO_AT
                        getVarOrDirectWord(PARAM_1);
                        getVarOrDirectWord(PARAM_2);
                        break;
                case 1:         // SO_COLOR
                        getVarOrDirectByte(PARAM_1);
                        break;
                case 2:         // SO_CLIPPED
                        getVarOrDirectWord(PARAM_1);
                        break;
                case 3:         // SO_ERASE
                        {
                        getVarOrDirectWord(PARAM_1);
                        getVarOrDirectWord(PARAM_2);
                        ERR;
                        }
                        break;
                case 4:         // SO_CENTER
                        break;
                case 6:         // SO_LEFT
                        if (_game_version == 3) {
                                getVarOrDirectWord(PARAM_1);
                        } else {
                        }
                        break;
                case 7:         // SO_OVERHEAD
                        break;
                case 8:{        // SO_SAY_VOICE
                                getVarOrDirectWord(PARAM_1);
                                getVarOrDirectWord(PARAM_2);

                        }
                        break;
                case 15:{       // SO_TEXTSTRING
                        printf("SO_TEXTSTRING to REDO\n");
                        loadPtrToResource();
//     clear_string();
//     while (1) { int c = fetchScriptByte(); add_string(c); if (c==0) break;}
//     m11("'%s'", get_string());
                        }
                        return;
                default:
                        ERR;
                }
        }


}

struct {
  void (*fn)(void);
} opcodes[256];

#define OPCODE(n, f) do { opcodes[n].fn = f; } while (0)

void o5_stopObjectCode(void)
{
  m("stopObjectCode");
}

void o5_putActor(void)
{
  int a, x, y;
  a = getVarOrDirectByte(PARAM_1);
  x = getVarOrDirectWord(PARAM_2);
  y = getVarOrDirectWord(PARAM_3);
  m("o5_putActor(%d, %d, %d)", a, x, y);
}

void o5_startMusic(void)
{
  int s = getVarOrDirectByte(PARAM_1);
  m("o5_startMusic(%d)", s);
}

void o5_getActorRoom(void)
{
  int act;
  getResultPos();
  act = getVarOrDirectByte(PARAM_1);
  m("o5_getActorRoom");
}

void o5_isGreaterEqual(void)
{
  int a, b;
  a = getVar();
  b = getVarOrDirectWord(PARAM_1);
  jumpRelative(">=", b, a);
}

void o5_drawObject(void)
{
  int obj = getVarOrDirectWord(PARAM_1);
  int xpos = 255, ypos = 255;
  int state = 1;

  if (GF_SMALL_HEADER) {
                xpos = getVarOrDirectWord(PARAM_2);
                ypos = getVarOrDirectWord(PARAM_3);
  } else {
                _opcode = fetchScriptByte();
                switch (_opcode & 0x1F) {
                case 1:                                                                         /* draw at */
                        xpos = getVarOrDirectWord(PARAM_1);
                        ypos = getVarOrDirectWord(PARAM_2);
                        break;
                case 2:                                                                         /* set state */
                        state = getVarOrDirectWord(PARAM_1);
                        break;
                case 0x1F:                                                                      /* neither */
                        break;
                default:
                        ERR;
                }
  }
  m("o5_drawObject(%d, %d, %d, %d)", obj, xpos, ypos, state);
}

void o5_getActorElevation(void)
{
  getResultPos();
          int act = getVarOrDirectByte(PARAM_1);
  m("o5_getActorElevation(%d)", act);
}

void o5_setState(void)
{
        int obj, state;
        obj = getVarOrDirectWord(PARAM_1);
        state = getVarOrDirectByte(PARAM_2);
  m("o5_setState(%d, %d)", obj, state);
}

void o5_isNotEqual(void)
{
        int a = getVar();
        int b = getVarOrDirectWord(PARAM_1);
        jumpRelative("!=", b, a);
}

void o5_faceActor(void)
{
        int act = getVarOrDirectByte(PARAM_1);
        int obj = getVarOrDirectWord(PARAM_2);
  m("o5_faceActor(%d, %d)", act, obj);
}

void o5_startScript(void)
{
  int script = getVarOrDirectByte(PARAM_1);
  int data[16];
  int n;
  n = getWordVararg(data);
  m("o5_startScript(%d, %d args)", script, n);
}

void o5_getVerbEntrypoint(void)
{
        int a, b;
        getResultPos();
        a = getVarOrDirectWord(PARAM_1);
        b = getVarOrDirectWord(PARAM_2);
  m("o5_getVerbEntrypoint(%d, %d)", a, b);
}

void o5_resourceRoutines(void)
{
  int resid = 0;
  int op;
        _opcode = fetchScriptByte();
        if (_opcode != 17)
                resid = getVarOrDirectByte(PARAM_1);
  op = _opcode & 0x3f;
  switch (op) {
    case 20: getVarOrDirectWord(PARAM_2); break;
    case 35: getVarOrDirectByte(PARAM_2); break;
    case 36: getVarOrDirectByte(PARAM_2); fetchScriptByte(); break;
    case 37: getVarOrDirectByte(PARAM_2); break;
  }

  m("o5_resourceRoutines");
}

void o5_walkActorToActor(void)
{
        int nr = getVarOrDirectByte(PARAM_1);
        int nr2 = getVarOrDirectByte(PARAM_2);
        int dist = fetchScriptByte();
  m("o5_walkActorToActor(%d, %d, %d)", nr, nr2, dist);
}

void o5_putActorAtObject(void)
{
  int a = getVarOrDirectByte(PARAM_1);
  int obj = getVarOrDirectWord(PARAM_2);
  m("o5_putActorAtObject(%d, %d)", a, obj);
}

void o5_getObjectState(void)
{
        getResultPos();
        getVarOrDirectWord(PARAM_1);
  m("o5_getObjectState");
}

void o5_getObjectOwner(void)
{
        getResultPos();
        getVarOrDirectWord(PARAM_1);
  m("o5_getObjectOwner");
}

void o5_animateActor(void)
{
        int act = getVarOrDirectByte(PARAM_1);
        int anim = getVarOrDirectByte(PARAM_2);
  m("o5_animateActor(%d, %d)", act, anim);
}

void o5_panCameraTo(void)
{
  int a = getVarOrDirectWord(PARAM_1);
  m("o5_panCameraTo(%d)", a);
}

void o5_actorOps(void)
{
printf("o5_actorOps %x\n", _opcode);
   static const int convertTable[20] =
     { 1, 0, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 20 };
   int act = getVarOrDirectByte(PARAM_1);
        while ((_opcode = fetchScriptByte()) != 0xFF) {
                //printf("opcode before %d\n", _opcode);
                if (GF_SMALL_HEADER) {
                        int toto = (_opcode & 0x1f) - 1;
                        if (toto < 0 || toto > 19) ERR;
                        _opcode = (_opcode & 0xE0) | convertTable[(_opcode & 0x1F) - 1];
                }
                //printf("opcode after %d\n", _opcode);

                switch (_opcode & 0x1F) {
                case 0:  
                       /* dummy case */
                        getVarOrDirectByte(PARAM_1);
                        break;
                case 1:                 // SO_COSTUME
                        getVarOrDirectByte(PARAM_1);
                        break;
                case 2:                 // SO_STEP_DIST
                        getVarOrDirectByte(PARAM_1);
                        getVarOrDirectByte(PARAM_2);
                        break;
                case 3:                 // SO_SOUND
                        getVarOrDirectByte(PARAM_1);
                        break;
                case 4:                 // SO_WALK_ANIMATION
                        getVarOrDirectByte(PARAM_1);
                        break;
                case 5:                 // SO_TALK_ANIMATION
                        getVarOrDirectByte(PARAM_1);
                        getVarOrDirectByte(PARAM_2);
                        break;
                case 6:                 // SO_STAND_ANIMATION
                        getVarOrDirectByte(PARAM_1);
                        break;
                case 7:                 // SO_ANIMATION
                        getVarOrDirectByte(PARAM_1);
                        getVarOrDirectByte(PARAM_2);
                        getVarOrDirectByte(PARAM_3);
                        break;
                case 8:                 // SO_DEFAULT
                        break;
                case 9:                 // SO_ELEVATION
                        getVarOrDirectWord(PARAM_1);
                        break;
                case 10:                // SO_ANIMATION_DEFAULT
                        break;
                case 11:                // SO_PALETTE
                        getVarOrDirectByte(PARAM_1);
                        getVarOrDirectByte(PARAM_2);
                        break;
                case 12:                // SO_TALK_COLOR
                        getVarOrDirectByte(PARAM_1);
                        break;
                case 13:                // SO_ACTOR_NAME
                        loadPtrToResource();
                        break;
                case 14:                // SO_INIT_ANIMATION
                        getVarOrDirectByte(PARAM_1);
                        break;
                case 16:                // SO_ACTOR_WIDTH
                        getVarOrDirectByte(PARAM_1);
                        break;
                case 17:                // SO_ACTOR_SCALE
                        if (_game_version == 4) {
                                getVarOrDirectByte(PARAM_1);
                        } else {
                                getVarOrDirectByte(PARAM_1);
                                getVarOrDirectByte(PARAM_2);
                        }

                        break;
                case 18:                // SO_NEVER_ZCLIP
                        break;
                case 19:                // SO_ALWAYS_ZCLIP
                        getVarOrDirectByte(PARAM_1);
                        break;
                case 20:                // SO_IGNORE_BOXES
                case 21:                // SO_FOLLOW_BOXES
                        break;

                case 22:                // SO_ANIMATION_SPEED
                        getVarOrDirectByte(PARAM_1);
                        break;
                case 23:                // SO_SHADOW
                        getVarOrDirectByte(PARAM_1);
                        break;
                default:
                        ERR;
                        break;
                }
        }
  m("o5_actorOps(%d)", act);
}

void o5_print(void)
{
        _actorToPrintStrFor = getVarOrDirectByte(PARAM_1);
  m1("o5_print(");
        decodeParseString();
  m2(")");
}

void o5_actorFromPos(void)
{
        int x, y;
        getResultPos();
        x = getVarOrDirectWord(PARAM_1);
        y = getVarOrDirectWord(PARAM_2);
  m("o5_actorFromPos(%d, %d)", x, y);
}

void o5_getRandomNr(void)
{
  int n;
        getResultPos();
  n = getVarOrDirectByte(PARAM_1);
  m("o5_getRandomNr(%d)", n);
}

void o5_and(void)
{
        int a;
        getResultPos();
        a = getVarOrDirectWord(PARAM_1);
  m("o5_and(%d)", a);
}

void o5_jumpRelative(void)
{
  jumpRelative("TRUE", 0, 0);
}

void o5_doSentence(void)
{
        int verb;

        verb = getVarOrDirectByte(PARAM_1);
  m("o5_doSentence(%d)", verb);

        if (verb == 0xFE) {
                return;
        }

        getVarOrDirectWord(PARAM_2);
        getVarOrDirectWord(PARAM_3);
}

void o5_move(void)
{
  getResultPos();
  int x = getVarOrDirectWord(PARAM_1);
  m("o5_move(to %d, from %d)", _resultVarNumber, x);
}

void o5_multiply(void)
{
  getResultPos();
  getVarOrDirectWord(PARAM_1);
  m("o5_multiply");
}

void o5_startSound(void)
{
  getVarOrDirectByte(PARAM_1);
  m("o5_startSound");
}

void o5_ifClassOfIs(void)
{
  getVarOrDirectWord(PARAM_1);
          while ((_opcode = fetchScriptByte()) != 0xFF) {
                getVarOrDirectWord(PARAM_1);
          }
  jumpRelative("TRUE from o5_ifClassOfIs", 0, 0);
}

void o5_walkActorTo(void)
{
  int a, x, y;
  a = getVarOrDirectByte(PARAM_1);
        x = getVarOrDirectWord(PARAM_2);
        y = getVarOrDirectWord(PARAM_3);
  m("o5_walkActorTo(%d, %d, %d)", a, x, y);
}

void o5_isActorInBox(void)
{
        int act = getVarOrDirectByte(PARAM_1);
        int box = getVarOrDirectByte(PARAM_2);
  jumpRelative("inbox", act, box);
}

void o5_stopMusic(void)
{
  m("o5_stopMusic");
}

void o5_getAnimCounter(void)
{
        getResultPos();
        int act = getVarOrDirectByte(PARAM_1);
  m("o5_getAnimCounter(%d)", act);
}

void o5_getActorY(void)
{
        getResultPos();
  if (GID_INDY3) {
    getVarOrDirectByte(PARAM_1);
  } else {
    getVarOrDirectWord(PARAM_1);
  }
  m("o5_getActorY");
}

void o5_loadRoomWithEgo(void)
{
  getVarOrDirectWord(PARAM_1);
  getVarOrDirectByte(PARAM_2);
  fetchScriptWordSigned();
  fetchScriptWordSigned();
  m("o5_loadRoomWithEgo");
}

void o5_pickupObject(void)
{
  getVarOrDirectWord(PARAM_1);
  getVarOrDirectByte(PARAM_2);
  m("o5_pickupObject");
}

void o5_setVarRange(void)
{
  int a, b;
        getResultPos();
        a = fetchScriptByte();
        do {
                if (_opcode & 0x80)
                        b = fetchScriptWordSigned();
                else
                        b = fetchScriptByte();

        } while (--a);
  m("o5_setVarRange");
}

void o5_stringOps(void)
{
  unsigned char s[1024];
  int pos;
  int c;

        _opcode = fetchScriptByte();
        switch (_opcode & 0x1F) {
        case 1:
                /* loadstring */
                printf("o5_stringOps loadstring redo\n");
                getVarOrDirectByte(PARAM_1);
                loadPtrToResource();
//                for (pos = 0; pos < 1023; pos++) {
//                  GET(c);
//                  s[pos] = c;
//                  if (c == 0) break;
//                }
//                s[pos] = 0;
//                m("loaded string: '%s'", s);
                break;
        case 2:                                                                                 /* copystring */
                getVarOrDirectByte(PARAM_1);
                getVarOrDirectByte(PARAM_2);
                break;
        case 3:                                                                                 /* set string char */
                getVarOrDirectByte(PARAM_1);
                getVarOrDirectByte(PARAM_2);
                getVarOrDirectByte(PARAM_3);
                break;

        case 4:                                                                                 /* get string char */
                getResultPos();
                getVarOrDirectByte(PARAM_1);
                getVarOrDirectByte(PARAM_2);
                break;

        case 5:                                                                                 /* create empty string */
                getVarOrDirectByte(PARAM_1);
                getVarOrDirectByte(PARAM_2);
                break;
        }
  m("o5_stringOps");
}

void o5_equalZero(void)
{
        int a = getVar();
        jumpRelative("==", a, 0);
}

void o5_setOwnerOf(void)
{
  getVarOrDirectWord(PARAM_1);
  getVarOrDirectByte(PARAM_2);
  m("o5_setOwnerOf");
}

void o5_delayVariable(void)
{
  getVar();
  m("o5_delayVariable");
}

void o5_cursorCommand(void)
{
  int table[16];
  m("o5_cursorCommand");
        switch ((_opcode = fetchScriptByte()) & 0x1F) {
        case 1:                 // SO_CURSOR_ON
                break;
        case 2:                 // SO_CURSOR_OFF
                break;
        case 3:                 // SO_USERPUT_ON
                break;
        case 4:                 // SO_USERPUT_OFF
                break;
        case 5:                 // SO_CURSOR_SOFT_ON
                break;
        case 6:                 // SO_CURSOR_SOFT_OFF
                break;
        case 7:                 // SO_USERPUT_SOFT_ON
                break;
        case 8:                 // SO_USERPUT_SOFT_OFF
                break;
        case 10:                // SO_CURSOR_IMAGE
                getVarOrDirectByte(PARAM_1);        // Cursor number
                getVarOrDirectByte(PARAM_2);        // Charset letter to use
                break;
        case 11:                // SO_CURSOR_HOTSPOT
                getVarOrDirectByte(PARAM_1);
                getVarOrDirectByte(PARAM_2);
                getVarOrDirectByte(PARAM_3);
                break;
        case 12:                // SO_CURSOR_SET
                getVarOrDirectByte(PARAM_1);
                break;
        case 13:                // SO_CHARSET_SET
                getVarOrDirectByte(PARAM_1);
                break;
        case 14:                                                                                               /* unk */
                if (_game_version == 3) {
                        /*int a = */ getVarOrDirectByte(PARAM_1);
                        /*int b = */ getVarOrDirectByte(PARAM_2);
                        // This is some kind of "init charset" opcode. However, we don't have to do anything
                        // in here, as our initCharset automatically calls loadCharset for GF_SMALL_HEADER,
                        // games if needed.
                } else {
                        getWordVararg(table);
                }
                break;
        }
}

void o5_putActorInRoom(void)
{
  int a = getVarOrDirectByte(PARAM_1);
        int room = getVarOrDirectByte(PARAM_2);
  m("o5_putActorInRoom(%d, %d)", a, room);
}

void o5_delay(void)
{
  fetchScriptByte(); fetchScriptByte(); fetchScriptByte();
  m("o5_delay");
}

void o5_matrixOps(void)
{
        _opcode = fetchScriptByte();
        switch (_opcode & 0x1F) {
        case 1:
                getVarOrDirectByte(PARAM_1);
                getVarOrDirectByte(PARAM_2);
                break;
        case 2:
                getVarOrDirectByte(PARAM_1);
                getVarOrDirectByte(PARAM_2);
                break;
        case 3:
                getVarOrDirectByte(PARAM_1);
                getVarOrDirectByte(PARAM_2);
                break;
        case 4:
                break;
        }
  m("o5_matrixOps");
}

void o5_getInventoryCount(void)
{
        getResultPos();
        getVarOrDirectByte(PARAM_1);
  m("o5_getInventoryCount");
}

void o5_setCameraAt(void)
{
  getVarOrDirectWord(PARAM_1);
  m("o5_setCameraAt");
}

void o5_roomOps(void)
{
  printf("o5_roomOps: REDO?\n");
  getVarOrDirectWord(PARAM_1);
  getVarOrDirectWord(PARAM_2);
  fetchScriptByte();
  m("o5_roomOps");
}

void o5_getDist(void)
{
        getResultPos();
        getVarOrDirectWord(PARAM_1);
        getVarOrDirectWord(PARAM_2);
  m("o5_getDist");
}

void o5_findObject(void)
{
        getResultPos();
        getVarOrDirectByte(PARAM_1);
        getVarOrDirectByte(PARAM_2);
  m("o5_findObject");
}

void o5_walkActorToObject(void)
{
  int a = getVarOrDirectByte(PARAM_1);
  int o = getVarOrDirectWord(PARAM_2);
  m("o5_walkActorToObject(%d, %d)", a, o);
}

void o5_startObject(void)
{
        int obj, script;
        int data[16];

        obj = getVarOrDirectWord(PARAM_1);
        script = getVarOrDirectByte(PARAM_2);

        getWordVararg(data);
  m("o5_startObject");
}

void o5_isLessEqual(void)
{
        int a = getVar();
        int b = getVarOrDirectWord(PARAM_1);

        jumpRelative("<=", b, a);
}

void o5_subtract(void)
{
        int a;
        getResultPos();
        a = getVarOrDirectWord(PARAM_1);
  m("o5_subtract");
}

void o5_getActorScale(void)
{
  if (GID_INDY3) {
    getVarOrDirectByte(PARAM_1);
  } else {
        getResultPos();
        getVarOrDirectByte(PARAM_1);
  }
  m("o5_getActorScale");
}

void o5_stopSound(void)
{
  getVarOrDirectByte(PARAM_1);
  m("o5_stopSound");
}

void o5_findInventory(void)
{
        getResultPos();
        getVarOrDirectByte(PARAM_1);
        getVarOrDirectByte(PARAM_2);
  m("o5_findInventory");
}

void o5_drawBox(void)
{
        int x, y, x2, y2, color;

        x = getVarOrDirectWord(PARAM_1);
        y = getVarOrDirectWord(PARAM_2);

        _opcode = fetchScriptByte();
        x2 = getVarOrDirectWord(PARAM_1);
        y2 = getVarOrDirectWord(PARAM_2);
        color = getVarOrDirectByte(PARAM_3);
  m("o5_drawBox");
}

void o5_cutscene(void)
{
        int args[16];
        getWordVararg(args);
  m("o5_cutscene");
}

void o5_chainScript(void)
{
        int vars[16];
        int script;

        script = getVarOrDirectByte(PARAM_1);

        getWordVararg(vars);
  m("o5_chainScript");
}

void o5_getActorX(void)
{
        getResultPos();
  if (GID_INDY3) {
    getVarOrDirectByte(PARAM_1);
  } else {
    getVarOrDirectWord(PARAM_1);
  }
  m("o5_getActorX");
}

void o5_isLess(void)
{
        int a = getVar();
        int b = getVarOrDirectWord(PARAM_1);
        jumpRelative("<", b, a);
}

void o5_increment(void)
{
  printf("o5_increment redo?\n");
        getResultPos();
        readVar(_resultVarNumber);
  m("o5_increment");
}

void o5_isEqual(void)
{
        int a, b;
        int var;

        if (_game_version <= 2)
                var = fetchScriptByte();
        else
                var = fetchScriptWord();
        a = readVar(var);
        b = getVarOrDirectWord(PARAM_1);

        jumpRelative("=", b, a);
}

void o5_soundKludge(void)
{
  printf("o5_soundKludge redo?\n");
  m("o5_soundKludge");
}

void o5_actorFollowCamera(void)
{
  getVarOrDirectByte(0x80);
  m("o5_actorFollowCamera");
}

void o5_setObjectName(void)
{
  getVarOrDirectWord(PARAM_1);
  m("o5_setObjectName");
}

void o5_getActorMoving(void)
{
        getResultPos();
        int act = getVarOrDirectByte(PARAM_1);
  m("o5_getActorMoving(%d)", act);
}

void o5_or(void)
{
        int a;
        getResultPos();
        a = getVarOrDirectWord(PARAM_1);
        readVar(_resultVarNumber);
  m("o5_or");
}

void o5_beginOverride(void)
{
  printf("o5_beginOverride redo?\n");
  fetchScriptByte();
  m("o5_beginOverride");
}

void o5_add(void)
{
        int a;
        getResultPos();
        a = getVarOrDirectWord(PARAM_1);
        readVar(_resultVarNumber);
  m("o5_add");
}

void o5_divide(void)
{
        int a;
        getResultPos();
        a = getVarOrDirectWord(PARAM_1);
        readVar(_resultVarNumber);
  m("o5_divide");
}

void o5_setClass(void)
{
        int newClass;
        getVarOrDirectWord(PARAM_1);

        while ((_opcode = fetchScriptByte()) != 0xFF) {
                newClass = getVarOrDirectWord(PARAM_1);
                if (newClass == 0) {
                } else;
        }
  m("o5_setClass");
}

void o5_freezeScripts(void)
{
  getVarOrDirectByte(PARAM_1);
  m("o5_freezeScripts");
}

void o5_stopScript(void)
{
  getVarOrDirectByte(PARAM_1);
  m("o5_stopScript");
}

void o5_getActorFacing(void)
{
        getResultPos();
        getVarOrDirectByte(PARAM_1);
  m("o5_getActorFacing");
}

void o5_getClosestObjActor(void)
{
        getResultPos();

        getVarOrDirectWord(PARAM_1);
  m("o5_getClosestObjActor");
}

void o5_getStringWidth(void)
{
        getResultPos();
        getVarOrDirectByte(PARAM_1);
  m("o5_getStringWidth");
}

void o5_isScriptRunning(void)
{
        getResultPos();
        getVarOrDirectByte(PARAM_1);
  m("o5_isScriptRunning");
}

void o5_debug(void)
{
        getVarOrDirectWord(PARAM_1);
  m("o5_debug");
}

void o5_getActorWidth(void)
{
        getResultPos();
    getVarOrDirectByte(PARAM_1);
  m("o5_getActorWidth");
}

void o5_stopObjectScript(void)
{
  getVarOrDirectWord(PARAM_1);
  m("o5_stopObjectScript");
}

void o5_lights(void)
{
        getVarOrDirectByte(PARAM_1);
        fetchScriptByte();
        fetchScriptByte();
  m("o5_lights");
}

void o5_getActorCostume(void)
{
        getResultPos();
        getVarOrDirectByte(PARAM_1);
  m("o5_getActorCostume");
}

void o5_loadRoom(void)
{
  getVarOrDirectByte(PARAM_1);
  m("o5_loadRoom");
}

void o5_isGreater(void)
{
        int a = getVar();
        int b = getVarOrDirectWord(PARAM_1);
        jumpRelative(">", b, a);
}

void o5_verbOps(void)
{
        int verb;

        verb = getVarOrDirectByte(PARAM_1);

        while ((_opcode = fetchScriptByte()) != 0xFF) {
                printf("verbOps opcode = %d\n", _opcode);
                switch (_opcode & 0x1F) {
                case 1:         // SO_VERB_IMAGE
                        getVarOrDirectWord(PARAM_1);
                        break;
                case 2:         // SO_VERB_NAME
                        loadPtrToResource();
                        break;
                case 3:         // SO_VERB_COLOR
                        getVarOrDirectByte(PARAM_1);
                        break;
                case 4:         // SO_VERB_HICOLOR
                        getVarOrDirectByte(PARAM_1);
                        break;
                case 5:         // SO_VERB_AT
                        getVarOrDirectWord(PARAM_1);
                        getVarOrDirectWord(PARAM_2);
                        break;
                case 6:         // SO_VERB_ON
                        break;
                case 7:         // SO_VERB_OFF
                        break;
                case 8:         // SO_VERB_DELETE
                        break;
                case 9:         // SO_VERB_NEW
                        break;

                case 16:        // SO_VERB_DIMCOLOR
                        getVarOrDirectByte(PARAM_1);
                        break;
                case 17:        // SO_VERB_DIM
                        break;
                case 18:        // SO_VERB_KEY
                        getVarOrDirectByte(PARAM_1);
                        break;
                case 19:        // SO_VERB_CENTER
                        break;
                case 20:        // SO_VERB_NAME_STR
                        getVarOrDirectWord(PARAM_1);
                        break;
                case 22:                                                                                /* assign object */
                        getVarOrDirectWord(PARAM_1);
                        getVarOrDirectByte(PARAM_2);
                        break;
                case 23:                                                                                /* set back color */
                        break;
                default:
                    ERR;
                }
        }
  m("o5_verbOps");
}

void o5_getActorWalkBox(void)
{
        getResultPos();
        getVarOrDirectByte(PARAM_1);
  m("o5_getActorWalkBox");
}

void o5_isSoundRunning(void)
{
        getResultPos();
        getVarOrDirectByte(PARAM_1);
  m("o5_isSoundRunning");
}

void o5_breakHere(void)
{
  m("o5_breakHere");
}

void o5_systemOps(void)
{
  fetchScriptByte();
  m("o5_systemOps");
}

void o5_dummy(void)
{
  m("o5_dummy");
}

void o5_notEqualZero(void)
{
        int a = getVar();
        jumpRelative("!=", a, 0);
}

void o5_saveRestoreVerbs(void)
{
        _opcode = fetchScriptByte();

        getVarOrDirectByte(PARAM_1);
        getVarOrDirectByte(PARAM_2);
        getVarOrDirectByte(PARAM_3);
  m("o5_saveRestoreVerbs");
}

void o5_expression(void)
{
        getResultPos();

        while ((_opcode = fetchScriptByte()) != 0xFF) {
                switch (_opcode & 0x1F) {
                case 1:                                                                         /* varordirect */
                        getVarOrDirectWord(PARAM_1);
                        break;
                case 2:                                                                         /* add */
                        break;
                case 3:                                                                         /* sub */
                        break;
                case 4:                                                                         /* mul */
                        break;
                case 5:                                                                         /* div */
                        break;
                case 6:                                                                         /* normal opcode */
                        _opcode = fetchScriptByte();
                        if (opcodes[_opcode].fn) opcodes[_opcode].fn();
                        else ERR;
#if 0
                        executeOpcode(_opcode);
                        push(_scummVars[0]);
#endif
                        break;
                }
        }
}

void o5_wait(void)
{
  printf("o5_wait redo?\n");
  m("o5_wait");
}

void o5_endCutscene(void)
{
  m("o5_endCutscene");
}

void o5_decrement(void)
{
        getResultPos();
        readVar(_resultVarNumber);
  m("o5_decrement");
}

void o5_pseudoRoom(void)
{
        int i = fetchScriptByte(), j;
        while ((j = fetchScriptByte()) != 0) {
        }
i++;
  m("o5_pseudoRoom");
}

void o5_printEgo(void)
{
        decodeParseString();
  m("o5_printEgo");
}

void o4_pickupObject(void)
{
  getVarOrDirectWord(PARAM_1);
  m("o4_pickupObject");
}

void o4_oldRoomEffect(void)
{
  _opcode = fetchScriptByte();
  if ((_opcode & 0x1F) == 3) getVarOrDirectWord(PARAM_1);
  m("o4_oldRoomEffect");
}

void o4_ifState(void)
{
        int a = getVarOrDirectWord(PARAM_1);
        int b = getVarOrDirectByte(PARAM_2);

        jumpRelative("== state", a, b);
}

void o4_ifNotState(void)
{
        int a = getVarOrDirectWord(PARAM_1);
        int b = getVarOrDirectByte(PARAM_2);

        jumpRelative("!= state", a, b);
}

void o4_saveLoadVars(void)
{
  if (fetchScriptByte() == 1)
     saveVars();
        else
                loadVars();
  m("o4_saveLoadVars");
}

void o4_saveLoadGame(void)
{
        getResultPos();
        getVarOrDirectByte(PARAM_1);
  m("o4_saveLoadGame");
}

void o3_setBoxFlags(void)
{
        getVarOrDirectByte(PARAM_1);
        fetchScriptByte();
  m("o3_setBoxFlags");
}

void setup_opcodes(void)
{
  /* V5 setup */

        /* 00 */
        OPCODE(0x00, o5_stopObjectCode);
        OPCODE(0x01, o5_putActor);
        OPCODE(0x02, o5_startMusic);
        OPCODE(0x03, o5_getActorRoom);
        /* 04 */
        OPCODE(0x04, o5_isGreaterEqual);
        OPCODE(0x05, o5_drawObject);
        OPCODE(0x06, o5_getActorElevation);
        OPCODE(0x07, o5_setState);
        /* 08 */
        OPCODE(0x08, o5_isNotEqual);
        OPCODE(0x09, o5_faceActor);
        OPCODE(0x0a, o5_startScript);
        OPCODE(0x0b, o5_getVerbEntrypoint);
        /* 0C */
        OPCODE(0x0c, o5_resourceRoutines);
        OPCODE(0x0d, o5_walkActorToActor);
        OPCODE(0x0e, o5_putActorAtObject);
        OPCODE(0x0e, o5_putActorAtObject);
        OPCODE(0x0f, o5_getObjectState);
        /* 10 */
        OPCODE(0x10, o5_getObjectOwner);
        OPCODE(0x11, o5_animateActor);
        OPCODE(0x12, o5_panCameraTo);
        OPCODE(0x13, o5_actorOps);
        /* 14 */
        OPCODE(0x14, o5_print);
        OPCODE(0x15, o5_actorFromPos);
        OPCODE(0x16, o5_getRandomNr);
        OPCODE(0x17, o5_and);
        /* 18 */
        OPCODE(0x18, o5_jumpRelative);
        OPCODE(0x19, o5_doSentence);
        OPCODE(0x1a, o5_move);
        OPCODE(0x1b, o5_multiply);
        /* 1C */
        OPCODE(0x1c, o5_startSound);
        OPCODE(0x1d, o5_ifClassOfIs);
        OPCODE(0x1e, o5_walkActorTo);
        OPCODE(0x1f, o5_isActorInBox);
        /* 20 */
        OPCODE(0x20, o5_stopMusic);
        OPCODE(0x21, o5_putActor);
        OPCODE(0x22, o5_getAnimCounter);
        OPCODE(0x23, o5_getActorY);
        /* 24 */
        OPCODE(0x24, o5_loadRoomWithEgo);
        OPCODE(0x25, o5_pickupObject);
        OPCODE(0x26, o5_setVarRange);
        OPCODE(0x27, o5_stringOps);
        /* 28 */
        OPCODE(0x28, o5_equalZero);
        OPCODE(0x29, o5_setOwnerOf);
        OPCODE(0x2a, o5_startScript);
        OPCODE(0x2b, o5_delayVariable);
        /* 2C */
        OPCODE(0x2c, o5_cursorCommand);
        OPCODE(0x2d, o5_putActorInRoom);
        OPCODE(0x2e, o5_delay);
//      OPCODE(0x2f, o5_ifNotState);
        /* 30 */
        OPCODE(0x30, o5_matrixOps);
        OPCODE(0x31, o5_getInventoryCount);
        OPCODE(0x32, o5_setCameraAt);
        OPCODE(0x33, o5_roomOps);
        /* 34 */
        OPCODE(0x34, o5_getDist);
        OPCODE(0x35, o5_findObject);
        OPCODE(0x36, o5_walkActorToObject);
        OPCODE(0x37, o5_startObject);
        /* 38 */
        OPCODE(0x38, o5_isLessEqual);
        OPCODE(0x39, o5_doSentence);
        OPCODE(0x3a, o5_subtract);
        OPCODE(0x3b, o5_getActorScale);
        /* 3C */
        OPCODE(0x3c, o5_stopSound);
        OPCODE(0x3d, o5_findInventory);
        OPCODE(0x3e, o5_walkActorTo);
        OPCODE(0x3f, o5_drawBox);
        /* 40 */
        OPCODE(0x40, o5_cutscene);
        OPCODE(0x41, o5_putActor);
        OPCODE(0x42, o5_chainScript);
        OPCODE(0x43, o5_getActorX);
        /* 44 */
        OPCODE(0x44, o5_isLess);
//      OPCODE(0x45, o5_drawObject);
        OPCODE(0x46, o5_increment);
        OPCODE(0x47, o5_setState);
        /* 48 */
        OPCODE(0x48, o5_isEqual);
        OPCODE(0x49, o5_faceActor);
        OPCODE(0x4a, o5_startScript);
        OPCODE(0x4b, o5_getVerbEntrypoint);
        /* 4C */
        OPCODE(0x4c, o5_soundKludge);
        OPCODE(0x4d, o5_walkActorToActor);
        OPCODE(0x4e, o5_putActorAtObject);
//      OPCODE(0x4f, o5_ifState);
        /* 50 */
//      OPCODE(0x50, o5_pickupObjectOld);
        OPCODE(0x51, o5_animateActor);
        OPCODE(0x52, o5_actorFollowCamera);
        OPCODE(0x53, o5_actorOps);
        /* 54 */
        OPCODE(0x54, o5_setObjectName);
        OPCODE(0x55, o5_actorFromPos);
        OPCODE(0x56, o5_getActorMoving);
        OPCODE(0x57, o5_or);
        /* 58 */
        OPCODE(0x58, o5_beginOverride);
        OPCODE(0x59, o5_doSentence);
        OPCODE(0x5a, o5_add);
        OPCODE(0x5b, o5_divide);
        /* 5C */
//      OPCODE(0x5c, o5_oldRoomEffect);
        OPCODE(0x5d, o5_setClass);
        OPCODE(0x5e, o5_walkActorTo);
        OPCODE(0x5f, o5_isActorInBox);
        /* 60 */
        OPCODE(0x60, o5_freezeScripts);
        OPCODE(0x61, o5_putActor);
        OPCODE(0x62, o5_stopScript);
        OPCODE(0x63, o5_getActorFacing);
        /* 64 */
        OPCODE(0x64, o5_loadRoomWithEgo);
        OPCODE(0x65, o5_pickupObject);
        OPCODE(0x66, o5_getClosestObjActor);
        OPCODE(0x67, o5_getStringWidth);
        /* 68 */
        OPCODE(0x68, o5_isScriptRunning);
        OPCODE(0x69, o5_setOwnerOf);
        OPCODE(0x6a, o5_startScript);
        OPCODE(0x6b, o5_debug);
        /* 6C */
        OPCODE(0x6c, o5_getActorWidth);
        OPCODE(0x6d, o5_putActorInRoom);
        OPCODE(0x6e, o5_stopObjectScript);
//      OPCODE(0x6f, o5_ifNotState);
        /* 70 */
        OPCODE(0x70, o5_lights);
        OPCODE(0x71, o5_getActorCostume);
        OPCODE(0x72, o5_loadRoom);
        OPCODE(0x73, o5_roomOps);
        /* 74 */
        OPCODE(0x74, o5_getDist);
        OPCODE(0x75, o5_findObject);
        OPCODE(0x76, o5_walkActorToObject);
        OPCODE(0x77, o5_startObject);
        /* 78 */
        OPCODE(0x78, o5_isGreater);
        OPCODE(0x79, o5_doSentence);
        OPCODE(0x7a, o5_verbOps);
        OPCODE(0x7b, o5_getActorWalkBox);
        /* 7C */
        OPCODE(0x7c, o5_isSoundRunning);
        OPCODE(0x7d, o5_findInventory);
        OPCODE(0x7e, o5_walkActorTo);
        OPCODE(0x7f, o5_drawBox);
        /* 80 */
        OPCODE(0x80, o5_breakHere);
        OPCODE(0x81, o5_putActor);
        OPCODE(0x82, o5_startMusic);
        OPCODE(0x83, o5_getActorRoom);
        /* 84 */
        OPCODE(0x84, o5_isGreaterEqual);
        OPCODE(0x85, o5_drawObject);
        OPCODE(0x86, o5_getActorElevation);
        OPCODE(0x87, o5_setState);
        /* 88 */
        OPCODE(0x88, o5_isNotEqual);
        OPCODE(0x89, o5_faceActor);
        OPCODE(0x8a, o5_startScript);
        OPCODE(0x8b, o5_getVerbEntrypoint);
        /* 8C */
        OPCODE(0x8c, o5_resourceRoutines);
        OPCODE(0x8d, o5_walkActorToActor);
        OPCODE(0x8e, o5_putActorAtObject);
        OPCODE(0x8f, o5_getObjectState);
        /* 90 */
        OPCODE(0x90, o5_getObjectOwner);
        OPCODE(0x91, o5_animateActor);
        OPCODE(0x92, o5_panCameraTo);
        OPCODE(0x93, o5_actorOps);
        /* 94 */
        OPCODE(0x94, o5_print);
        OPCODE(0x95, o5_actorFromPos);
        OPCODE(0x96, o5_getRandomNr);
        OPCODE(0x97, o5_and);
        /* 98 */
        OPCODE(0x98, o5_systemOps);
        OPCODE(0x99, o5_doSentence);
        OPCODE(0x9a, o5_move);
        OPCODE(0x9b, o5_multiply);
        /* 9C */
        OPCODE(0x9c, o5_startSound);
        OPCODE(0x9d, o5_ifClassOfIs);
        OPCODE(0x9e, o5_walkActorTo);
        OPCODE(0x9f, o5_isActorInBox);
        /* A0 */
        OPCODE(0xa0, o5_stopObjectCode);
        OPCODE(0xa1, o5_putActor);
        OPCODE(0xa2, o5_getAnimCounter);
        OPCODE(0xa3, o5_getActorY);
        /* A4 */
        OPCODE(0xa4, o5_loadRoomWithEgo);
        OPCODE(0xa5, o5_pickupObject);
        OPCODE(0xa6, o5_setVarRange);
        OPCODE(0xa7, o5_dummy);
        /* A8 */
        OPCODE(0xa8, o5_notEqualZero);
        OPCODE(0xa9, o5_setOwnerOf);
        OPCODE(0xaa, o5_startScript);
        OPCODE(0xab, o5_saveRestoreVerbs);
        /* AC */
        OPCODE(0xac, o5_expression);
        OPCODE(0xad, o5_putActorInRoom);
        OPCODE(0xae, o5_wait);
//      OPCODE(0xaf, o5_ifNotState);
        /* B0 */
        OPCODE(0xb0, o5_matrixOps);
        OPCODE(0xb1, o5_getInventoryCount);
        OPCODE(0xb2, o5_setCameraAt);
        OPCODE(0xb3, o5_roomOps);
        /* B4 */
        OPCODE(0xb4, o5_getDist);
        OPCODE(0xb5, o5_findObject);
        OPCODE(0xb6, o5_walkActorToObject);
        OPCODE(0xb7, o5_startObject);
        /* B8 */
        OPCODE(0xb8, o5_isLessEqual);
        OPCODE(0xb9, o5_doSentence);
        OPCODE(0xba, o5_subtract);
        OPCODE(0xbb, o5_getActorScale);
        /* BC */
        OPCODE(0xbc, o5_stopSound);
        OPCODE(0xbd, o5_findInventory);
        OPCODE(0xbe, o5_walkActorTo);
        OPCODE(0xbf, o5_drawBox);
        /* C0 */
        OPCODE(0xc0, o5_endCutscene);
        OPCODE(0xc1, o5_putActor);
        OPCODE(0xc2, o5_chainScript);
        OPCODE(0xc3, o5_getActorX);
        /* C4 */
        OPCODE(0xc4, o5_isLess);
//      OPCODE(0xc5, o5_drawObject);
        OPCODE(0xc6, o5_decrement);
        OPCODE(0xc7, o5_setState);
        /* C8 */
        OPCODE(0xc8, o5_isEqual);
        OPCODE(0xc9, o5_faceActor);
        OPCODE(0xca, o5_startScript);
        OPCODE(0xcb, o5_getVerbEntrypoint);
        /* CC */
        OPCODE(0xcc, o5_pseudoRoom);
        OPCODE(0xcd, o5_walkActorToActor);
        OPCODE(0xce, o5_putActorAtObject);
//      OPCODE(0xcf, o5_ifState);
        /* D0 */
//      OPCODE(0xd0, o5_pickupObjectOld);
        OPCODE(0xd1, o5_animateActor);
        OPCODE(0xd2, o5_actorFollowCamera);
        OPCODE(0xd3, o5_actorOps);
        /* D4 */
        OPCODE(0xd4, o5_setObjectName);
        OPCODE(0xd5, o5_actorFromPos);
        OPCODE(0xd6, o5_getActorMoving);
        OPCODE(0xd7, o5_or);
        /* D8 */
        OPCODE(0xd8, o5_printEgo);
        OPCODE(0xd9, o5_doSentence);
        OPCODE(0xda, o5_add);
        OPCODE(0xdb, o5_divide);
        /* DC */
//      OPCODE(0xdc, o5_oldRoomEffect);
        OPCODE(0xdd, o5_setClass);
        OPCODE(0xde, o5_walkActorTo);
        OPCODE(0xdf, o5_isActorInBox);
        /* E0 */
        OPCODE(0xe0, o5_freezeScripts);
        OPCODE(0xe1, o5_putActor);
        OPCODE(0xe2, o5_stopScript);
        OPCODE(0xe3, o5_getActorFacing);
        /* E4 */
        OPCODE(0xe4, o5_loadRoomWithEgo);
        OPCODE(0xe5, o5_pickupObject);
        OPCODE(0xe6, o5_getClosestObjActor);
        OPCODE(0xe7, o5_getStringWidth);
        /* E8 */
        OPCODE(0xe8, o5_isScriptRunning);
        OPCODE(0xe9, o5_setOwnerOf);
        OPCODE(0xea, o5_startScript);
        OPCODE(0xeb, o5_debug);
        /* EC */
        OPCODE(0xec, o5_getActorWidth);
        OPCODE(0xed, o5_putActorInRoom);
        OPCODE(0xee, o5_stopObjectScript);
//      OPCODE(0xef, o5_ifNotState);
        /* F0 */
        OPCODE(0xf0, o5_lights);
        OPCODE(0xf1, o5_getActorCostume);
        OPCODE(0xf2, o5_loadRoom);
        OPCODE(0xf3, o5_roomOps);
        /* F4 */
        OPCODE(0xf4, o5_getDist);
        OPCODE(0xf5, o5_findObject);
        OPCODE(0xf6, o5_walkActorToObject);
        OPCODE(0xf7, o5_startObject);
        /* F8 */
        OPCODE(0xf8, o5_isGreater);
        OPCODE(0xf9, o5_doSentence);
        OPCODE(0xfa, o5_verbOps);
        OPCODE(0xfb, o5_getActorWalkBox);
        /* FC */
        OPCODE(0xfc, o5_isSoundRunning);
        OPCODE(0xfd, o5_findInventory);
        OPCODE(0xfe, o5_walkActorTo);
        OPCODE(0xff, o5_drawBox);

  /* v4 setup */

        OPCODE(0x25, o5_drawObject);
        OPCODE(0x45, o5_drawObject);
        OPCODE(0x65, o5_drawObject);
        OPCODE(0xa5, o5_drawObject);
        OPCODE(0xc5, o5_drawObject);
        OPCODE(0xe5, o5_drawObject);

        OPCODE(0x50, o4_pickupObject);
        OPCODE(0xd0, o4_pickupObject);

        OPCODE(0x5c, o4_oldRoomEffect);
        OPCODE(0xdc, o4_oldRoomEffect);

        OPCODE(0x0f, o4_ifState);
        OPCODE(0x4f, o4_ifState);
        OPCODE(0x8f, o4_ifState);
        OPCODE(0xcf, o4_ifState);

        OPCODE(0x2f, o4_ifNotState);
        OPCODE(0x6f, o4_ifNotState);
        OPCODE(0xaf, o4_ifNotState);
        OPCODE(0xef, o4_ifNotState);

        OPCODE(0xa7, o4_saveLoadVars);

        OPCODE(0x22, o4_saveLoadGame);
        OPCODE(0xa2, o4_saveLoadGame);

  /* v3 setup */

        OPCODE(0x30, o3_setBoxFlags);
        OPCODE(0xb0, o3_setBoxFlags);
}

int main(int n, char **v)
{
  volatile long curpos = 0;
  int c;
  if (n == 1) { printf("gimme some files\n"); return 1; }
  setup_opcodes();
  in_name = v[1];
  in = fopen(in_name, "r"); if (!in) { perror(in_name); return 1; }
//  GET(c); GET(c); GET(c); GET(c);
more:
  if (setjmp(err_jmp)) {
    fseek(in, curpos+1, SEEK_SET);
    goto more;
  }
  while (1) {
    curpos = ftell(in);
//    printf("pos in %s %ld\n", in_name, curpos);
    STOP_GET(c);
    if (c == EOF) break;
    _opcode = c;
    script_position = curpos;
    if (opcodes[c].fn) opcodes[c].fn();
    else printf("%x: unknown opcode\n", c);
  }
  fclose(in);
  return 0;
}
