Logo Search packages:      
Sourcecode: scummvm version File versions

sthread.cpp

/* ScummVM - Scumm Interpreter
 * Copyright (C) 2004 The ScummVM project
 *
 * The ReInherit Engine is (C)2000-2003 by Daniel Balsom.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.      See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/saga/sthread.cpp,v 1.39 2004/12/03 19:15:44 eriktorbjorn Exp $
 *
 */

// Scripting module thread management component
#include "saga/saga.h"
#include "saga/yslib.h"

#include "saga/gfx.h"
#include "saga/actor.h"
#include "saga/console.h"

#include "saga/script.h"

#include "saga/sdata.h"

namespace Saga {

void Script::setFramePtr(SCRIPT_THREAD *thread, int newPtr) {
      thread->framePtr = newPtr;
      dataBuffer(3)->len = ARRAYSIZE(thread->stackBuf) - thread->framePtr;
      dataBuffer(3)->data = (SDataWord_T *) &(thread->stackBuf[newPtr]);
}

SCRIPT_THREAD *Script::SThreadCreate() {
      YS_DL_NODE *new_node;
      SCRIPT_THREAD *new_thread;

      if (!isInitialized()) {
            return NULL;
      }

      new_thread = (SCRIPT_THREAD *)calloc(1, sizeof *new_thread);
      if (new_thread == NULL) {
            return NULL;
      }

      new_node = ys_dll_add_head(threadList(), new_thread, sizeof *new_thread);
      free(new_thread);

      new_thread = (SCRIPT_THREAD *)ys_dll_get_data(new_node);

      new_thread->stackPtr = ARRAYSIZE(new_thread->stackBuf) - 1;
      setFramePtr(new_thread, new_thread->stackPtr);

      new_thread->flags = kTFlagWaiting;
      new_thread->waitType = kTWaitPause;

      dataBuffer(4)->len = ARRAYSIZE(new_thread->threadVars);
      dataBuffer(4)->data = new_thread->threadVars;

      return new_thread;
}

int Script::SThreadDestroy(SCRIPT_THREAD *thread) {
      YS_DL_NODE *walk_p;
      SCRIPT_THREAD *th;

      if (thread == NULL) {
            return FAILURE;
      }

      for (walk_p = ys_dll_head(threadList()); walk_p != NULL; walk_p = ys_dll_next(walk_p)) {
            th = (SCRIPT_THREAD *)ys_dll_get_data(walk_p);
            if (thread == th) {
                  ys_dll_delete(walk_p);
                  break;
            }
      }

      return SUCCESS;
}

int Script::SThreadExecThreads(uint msec) {
      YS_DL_NODE *walk_p, *next_p;
      SCRIPT_THREAD *thread;

      if (!isInitialized()) {
            return FAILURE;
      }

      walk_p = ys_dll_head(threadList());

      while (walk_p != NULL) {
            next_p = ys_dll_next(walk_p);

            thread = (SCRIPT_THREAD *)ys_dll_get_data(walk_p);

            if (thread->flags & (kTFlagFinished | kTFlagAborted)) {
                  //if (thread->flags & kTFlagFinished) // FIXME. Missing function

                  SThreadDestroy(thread);
                  walk_p = next_p;
                  continue;
            }

            if (thread->flags & kTFlagWaiting) {
                  switch(thread->waitType) {
                  case kTWaitDelay:
                        if (thread->sleepTime < msec) {
                              thread->sleepTime = 0;
                        } else {
                              thread->sleepTime -= msec;
                        }

                        if (thread->sleepTime == 0)
                              thread->flags &= ~kTFlagWaiting;
                        break;
                  }
            }

            if (!(thread->flags & kTFlagWaiting))
                  SThreadRun(thread, STHREAD_TIMESLICE);

            walk_p = next_p;
      }

      return SUCCESS;
}

void Script::SThreadCompleteThread(void) {
      for (int i = 0; i < 40 && (ys_dll_head(threadList()) != NULL); i++)
            SThreadExecThreads(0);
}

int Script::SThreadSetEntrypoint(SCRIPT_THREAD *thread, int ep_num) {
      SCRIPT_BYTECODE *bytecode;
      int max_entrypoint;

      assert(isInitialized());

      bytecode = currentScript()->bytecode;
      max_entrypoint = bytecode->n_entrypoints;

      if ((ep_num < 0) || (ep_num >= max_entrypoint)) {
            return FAILURE;
      }

      thread->ep_num = ep_num;
      thread->ep_offset = bytecode->entrypoints[ep_num].offset;

      return SUCCESS;
}

int Script::SThreadExecute(SCRIPT_THREAD *thread, int ep_num) {
      assert(isInitialized());

      if ((currentScript() == NULL) || (!currentScript()->loaded)) {
            return FAILURE;
      }

      SThreadSetEntrypoint(thread, ep_num);

      thread->i_offset = thread->ep_offset;
      thread->flags = kTFlagNone;

      return SUCCESS;
}

void Script::SThreadAbortAll(void) {
      // TODO: stop current speech

      if (_abortEnabled) 
            _skipSpeeches = true;

      for (int i = 0; i < 10; i++)
            _vm->_script->SThreadExecThreads(0);
}

unsigned char *Script::SThreadGetReadPtr(SCRIPT_THREAD *thread) {
      return currentScript()->bytecode->bytecode_p + thread->i_offset;
}

unsigned long Script::SThreadGetReadOffset(const byte *read_p) {
      return (unsigned long)(read_p - (unsigned char *)currentScript()->bytecode->bytecode_p);
}

size_t Script::SThreadGetReadLen(SCRIPT_THREAD *thread) {
      return currentScript()->bytecode->bytecode_len - thread->i_offset;
}


int Script::SThreadHoldSem(SEMAPHORE *sem) {
      if (sem == NULL) {
            return FAILURE;
      }

      sem->hold_count++;

      return SUCCESS;
}

int Script::SThreadReleaseSem(SEMAPHORE *sem) {
      if (sem == NULL) {
            return FAILURE;
      }

      sem->hold_count--;
      if (sem->hold_count < 0) {
            sem->hold_count = 0;
      }

      return SUCCESS;
}

int Script::SThreadDebugStep() {
      if (_dbg_singlestep) {
            _dbg_dostep = 1;
      }

      return SUCCESS;
}

int Script::SThreadRun(SCRIPT_THREAD *thread, int instr_limit) {
      int instr_count;
      uint32 saved_offset;
      SDataWord_T param1;
      SDataWord_T param2;
      long iparam1;
      long iparam2;
      long iresult;

      SDataWord_T data;
      SDataWord_T scriptRetVal = 0;
      int debug_print = 0;
      int n_buf;
      int bitstate;
      int in_char;
      int i;
      int unhandled = 0;

      // Handle debug single-stepping
      if ((thread == _dbg_thread) && _dbg_singlestep) {
            if (_dbg_dostep) {
                  debug_print = 1;
                  thread->sleepTime = 0;
                  instr_limit = 1;
                  _dbg_dostep = 0;
            } else {
                  return SUCCESS;
            }
      }

      MemoryReadStream scriptS(currentScript()->bytecode->bytecode_p, currentScript()->bytecode->bytecode_len);

      dataBuffer(2)->len = currentScript()->bytecode->bytecode_len / sizeof(SDataWord_T);
      dataBuffer(2)->data = (SDataWord_T *) currentScript()->bytecode->bytecode_p;

      scriptS.seek(thread->i_offset);

      for (instr_count = 0; instr_count < instr_limit; instr_count++) {
            if (thread->sem.hold_count)
                  break;                                                  

            saved_offset = thread->i_offset;
            in_char = scriptS.readByte();

            debug(2, "Executing thread offset: %lu (%x) stack: %d", thread->i_offset, in_char, thread->stackSize());

            switch (in_char) {
            case 0x01: // nextblock
                  // Some sort of "jump to the start of the next memory
                  // page" instruction, I think.
                  thread->i_offset = 1024 * ((thread->i_offset / 1024) + 1);
                  break;

// STACK INSTRUCTIONS
            case 0x02: // Dup top element (DUP)
                  thread->push(thread->stackTop());
                  break;
            case 0x03: // Pop nothing (POPN)
                  thread->pop();
                  break;
            case 0x04: // Push false (PSHF)
                  thread->push(0);
                  break;
            case 0x05: // Push true (PSHT)
                  thread->push(1);
                  break;
            case 0x06: // Push word (PUSH)
            case 0x08: // Push word (PSHD) (dialogue string index)
                  param1 = (SDataWord_T)scriptS.readUint16LE();
                  thread->push(param1);
                  break;

// DATA INSTRUCTIONS  

            case 0x0B: // Test flag (TSTF)
                  n_buf = scriptS.readByte();
                  param1 = (SDataWord_T)scriptS.readUint16LE();
                  _vm->_sdata->getBit(n_buf, param1, &bitstate);
                  thread->push(bitstate);
                  break;
            case 0x0C: // Get word (GETW)
                  n_buf = scriptS.readByte();
                  param1 = scriptS.readUint16LE();
                  _vm->_sdata->getWord(n_buf, param1, &data);
                  thread->push(data);
                  break;
            case 0x0F: // Modify flag (MODF)
                  n_buf = scriptS.readByte();
                  param1 = (SDataWord_T)scriptS.readUint16LE();
                  bitstate = _vm->_sdata->readWordU(param1);
                  data = thread->stackTop();
                  if (bitstate) {
                        _vm->_sdata->setBit(n_buf, data, 1);
                  } else {
                        _vm->_sdata->setBit(n_buf, data, 0);
                  }
                  break;
            case 0x10: // Put word (PUTW)
                  n_buf = scriptS.readByte();
                  param1 = (SDataWord_T)scriptS.readUint16LE();
                  data = thread->stackTop();
                  _vm->_sdata->putWord(n_buf, param1, data);
                  break;
            case 0x13: // Modify flag and pop (MDFP)
                  n_buf = scriptS.readByte();
                  param1 = (SDataWord_T)scriptS.readUint16LE();
                  param1 = thread->pop();
                  bitstate = _vm->_sdata->readWordU(param1);
                  if (bitstate) {
                        _vm->_sdata->setBit(n_buf, param1, 1);
                  } else {
                        _vm->_sdata->setBit(n_buf, param1, 0);
                  }
                  break;
            case 0x14: // Put word and pop (PTWP)
                  n_buf = scriptS.readByte();
                  param1 = (SDataWord_T)scriptS.readUint16LE();
                  data = thread->stackTop();
                  _vm->_sdata->putWord(n_buf, param1, data);
                  break;

// CONTROL INSTRUCTIONS    

            case 0x17: // (GOSB): Call subscript
                  {
                        int n_args;
                        int temp;

                        n_args = scriptS.readByte();
                        temp = scriptS.readByte();
                        if (temp != 2)
                              error("Calling dynamically generated script? Wow");
                        param1 = (SDataWord_T)scriptS.readUint16LE();
                        data = scriptS.pos();
                        thread->push(n_args);
                        // NOTE: The original pushes the program
                        // counter as a pointer here. But I don't think
                        // we will have to do that.
                        thread->push(data);
                        thread->i_offset = (unsigned long)param1;
                  }
                  break;
            case 0x18: // (CALL): Call function
            case 0x19: // (CALL_V): Call function and discard return value
                  {
                        int n_args;
                        uint16 func_num;
                        int sfuncRetVal;
                        SFunc_T sfunc;

                        n_args = scriptS.readByte();
                        func_num = scriptS.readUint16LE();
                        if (func_num >= SFUNC_NUM) {
                              _vm->_console->DebugPrintf(S_ERROR_PREFIX "Invalid script function number: (%X)\n", func_num);
                              thread->flags |= kTFlagAborted;
                              break;
                        }

                        sfunc = _SFuncList[func_num];
                        sfuncRetVal = (this->*sfunc)(thread, n_args);
                        if (sfuncRetVal != SUCCESS) {
                              _vm->_console->DebugPrintf(S_WARN_PREFIX "%X: Script function %d failed.\n", thread->i_offset, func_num);
                        }

                        if (func_num == 16) { // SF_gotoScene
                              instr_count = instr_limit; // break the loop
                              break;
                        }

                        if (in_char == 0x18) // CALL function
                              thread->push(thread->retVal);

                        if (thread->flags & kTFlagAsleep)
                              instr_count = instr_limit;    // break out of loop!
                  }
                  break;
            case 0x1A: // (ENTR) Enter the dragon
                  thread->push(thread->framePtr);
                  setFramePtr(thread, thread->stackPtr);
                  param1 = scriptS.readUint16LE();
                  thread->stackPtr -= (param1 / 2);
                  break;
            case 0x1B: // Return with value
                  scriptRetVal = thread->pop();
                  // FALL THROUGH
            case 0x1C: // Return with void
                  thread->stackPtr = thread->framePtr;
                  setFramePtr(thread, thread->pop());
                  if (thread->stackSize() == 0) {
                        _vm->_console->DebugPrintf("Script execution complete.\n");
                        thread->flags |= kTFlagFinished;
                  } else {
                        thread->i_offset = thread->pop();
                        /* int n_args = */ thread->pop();
                        if (in_char == 0x1B)
                              thread->push(scriptRetVal);
                  }
                  break;

// BRANCH INSTRUCTIONS    

                  // (JMP): Unconditional jump
            case 0x1D:
                  param1 = scriptS.readUint16LE();
                  thread->i_offset = (unsigned long)param1;
                  break;
                  // (JNZP): Jump if nonzero + POP
            case 0x1E:
                  param1 = scriptS.readUint16LE();
                  data = thread->pop();
                  if (data) {
                        thread->i_offset = (unsigned long)param1;
                  }
                  break;
                  // (JZP): Jump if zero + POP
            case 0x1F:
                  param1 = scriptS.readUint16LE();
                  data = thread->pop();
                  if (!data) {
                        thread->i_offset = (unsigned long)param1;
                  }
                  break;
                  // (JNZ): Jump if nonzero
            case 0x20:
                  param1 = scriptS.readUint16LE();
                  data = thread->stackTop();
                  if (data) {
                        thread->i_offset = (unsigned long)param1;
                  }
                  break;
                  // (JZ): Jump if zero
            case 0x21:
                  param1 = scriptS.readUint16LE();
                  data = thread->stackTop();
                  if (!data) {
                        thread->i_offset = (unsigned long)param1;
                  }
                  break;
                  // (SWCH): Switch
            case 0x22:
                  {
                        int n_switch;
                        unsigned int switch_num;
                        unsigned int switch_jmp;
                        unsigned int default_jmp;
                        int case_found = 0;

                        data = thread->pop();
                        n_switch = scriptS.readUint16LE();
                        for (i = 0; i < n_switch; i++) {
                              switch_num = scriptS.readUint16LE();
                              switch_jmp = scriptS.readUint16LE();
                              // Found the specified case
                              if (data == (SDataWord_T) switch_num) {
                                    thread->i_offset = switch_jmp;
                                    case_found = 1;
                                    break;
                              }
                        }

                        // Jump to default case
                        if (!case_found) {
                              default_jmp = scriptS.readUint16LE();
                              thread->i_offset = default_jmp;
                        }
                  }
                  break;
                  // (RJMP): Random branch
            case 0x24:
                  {
                        int n_branch;
                        unsigned int branch_wt;
                        unsigned int branch_jmp;
                        int rand_sel = 0;
                        int branch_found = 0;

                        // Ignored?
                        scriptS.readUint16LE();
                        n_branch = scriptS.readUint16LE();
                        for (i = 0; i < n_branch; i++) {
                              branch_wt = scriptS.readUint16LE();
                              branch_jmp = scriptS.readUint16LE();
                              if (rand_sel == i) {
                                    thread->i_offset = branch_jmp;
                                    branch_found = 1;
                                    break;
                              }
                        }
                        if (!branch_found) {
                              _vm->_console->DebugPrintf(S_ERROR_PREFIX "%X: Random jump target out of bounds.\n", thread->i_offset);
                        }
                  }
                  break;

// UNARY INSTRUCTIONS

                  // (NEG) Negate stack by 2's complement
            case 0x25:
                  data = thread->pop();
                  data = ~data;
                  data++;
                  thread->push(data);
                  break;
                  // (TSTZ) Test for zero
            case 0x26:
                  data = thread->pop();
                  data = data ? 0 : 1;
                  thread->push(data);
                  break;
                  // (NOT) Binary not
            case 0x27:
                  data = thread->pop();
                  data = ~data;
                  thread->push(data);
                  break;
            case 0x28: // inc_v increment, don't push
                  unhandled = 1;
                  //debug(2, "??? ");
                  scriptS.readByte();
                  scriptS.readUint16LE();
                  break;
            case 0x29: // dec_v decrement, don't push
                  unhandled = 1;
                  //debug(2, "??? ");
                  scriptS.readByte();
                  scriptS.readUint16LE();
                  break;
            case 0x2A: // postinc
                  unhandled = 1;
                  //debug(2, "??? ");
                  scriptS.readByte();
                  scriptS.readUint16LE();
                  break;
            case 0x2B: // postdec
                  unhandled = 1;
                  //debug(2, "??? ");
                  scriptS.readByte();
                  scriptS.readUint16LE();
                  break;

// ARITHMETIC INSTRUCTIONS    

                  // (ADD): Addition
            case 0x2C:
                  param2 = thread->pop();
                  param1 = thread->pop();
                  iparam2 = (long)param2;
                  iparam1 = (long)param1;
                  iresult = iparam1 + iparam2;
                  thread->push((SDataWord_T) iresult);
                  break;
                  // (SUB): Subtraction
            case 0x2D:
                  param2 = thread->pop();
                  param1 = thread->pop();
                  iparam2 = (long)param2;
                  iparam1 = (long)param1;
                  iresult = iparam1 - iparam2;
                  thread->push((SDataWord_T) iresult);
                  break;
                  // (MULT): Integer multiplication
            case 0x2E:
                  param2 = thread->pop();
                  param1 = thread->pop();
                  iparam2 = (long)param2;
                  iparam1 = (long)param1;
                  iresult = iparam1 * iparam2;
                  thread->push((SDataWord_T) iresult);
                  break;
                  // (DIV): Integer division
            case 0x2F:
                  param2 = thread->pop();
                  param1 = thread->pop();
                  iparam2 = (long)param2;
                  iparam1 = (long)param1;
                  iresult = iparam1 / iparam2;
                  thread->push((SDataWord_T) iresult);
                  break;
                  // (MOD) Modulus
            case 0x30:
                  param2 = thread->pop();
                  param1 = thread->pop();
                  iparam2 = (long)param2;
                  iparam1 = (long)param1;
                  iresult = iparam1 % iparam2;
                  thread->push((SDataWord_T) iresult);
                  break;
                  // (EQU) Test equality
            case 0x33:
                  param2 = thread->pop();
                  param1 = thread->pop();
                  iparam2 = (long)param2;
                  iparam1 = (long)param1;
                  data = (iparam1 == iparam2) ? 1 : 0;
                  thread->push(data);
                  break;
                  // (NEQU) Test inequality
            case 0x34:
                  param2 = thread->pop();
                  param1 = thread->pop();
                  iparam2 = (long)param2;
                  iparam1 = (long)param1;
                  data = (iparam1 != iparam2) ? 1 : 0;
                  thread->push(data);
                  break;
                  // (GRT) Test Greater-than
            case 0x35:
                  param2 = thread->pop();
                  param1 = thread->pop();
                  iparam2 = (long)param2;
                  iparam1 = (long)param1;
                  data = (iparam1 > iparam2) ? 1 : 0;
                  thread->push(data);
                  break;
                  // (LST) Test Less-than
            case 0x36:
                  param2 = thread->pop();
                  param1 = thread->pop();
                  iparam2 = (long)param2;
                  iparam1 = (long)param1;
                  data = (iparam1 < iparam2) ? 1 : 0;
                  thread->push(data);
                  break;
                  // (GRTE) Test Greater-than or Equal to
            case 0x37:
                  param2 = thread->pop();
                  param1 = thread->pop();
                  iparam2 = (long)param2;
                  iparam1 = (long)param1;
                  data = (iparam1 >= iparam2) ? 1 : 0;
                  thread->push(data);
                  break;
                  // (LSTE) Test Less-than or Equal to
            case 0x38:
                  param2 = thread->pop();
                  param1 = thread->pop();
                  iparam2 = (long)param2;
                  iparam1 = (long)param1;
                  data = (iparam1 <= iparam2) ? 1 : 0;
                  thread->push(data);
                  break;

// BITWISE INSTRUCTIONS   

                  // (SHR): Arithmetic binary shift right
            case 0x3F:
                  param2 = thread->pop();
                  param1 = thread->pop();
                  iparam2 = (long)param2;
                  // Preserve most significant bit
                  data = (0x01 << ((sizeof param1 * CHAR_BIT) - 1)) & param1;
                  for (i = 0; i < (int)iparam2; i++) {
                        param1 >>= 1;
                        param1 |= data;
                  }
                  thread->push(param1);
                  break;
                  // (SHL) Binary shift left
            case 0x40:
                  param2 = thread->pop();
                  param1 = thread->pop();
                  param1 <<= param2;
                  thread->push(param1);
                  break;
                  // (AND) Binary AND
            case 0x41:
                  param2 = thread->pop();
                  param1 = thread->pop();
                  param1 &= param2;
                  thread->push(param1);
                  break;
                  // (OR) Binary OR
            case 0x42:
                  param2 = thread->pop();
                  param1 = thread->pop();
                  param1 |= param2;
                  thread->push(param1);
                  break;
                  // (XOR) Binary XOR
            case 0x43:
                  param2 = thread->pop();
                  param1 = thread->pop();
                  param1 ^= param2;
                  thread->push(param1);
                  break;

// BOOLEAN LOGIC INSTRUCTIONS     

                  // (LAND): Logical AND
            case 0x44:
                  param2 = thread->pop();
                  param1 = thread->pop();
                  data = (param1 && param2) ? 1 : 0;
                  thread->push(data);
                  break;
                  // (LOR): Logical OR
            case 0x45:
                  param2 = thread->pop();
                  param1 = thread->pop();
                  data = (param1 || param2) ? 1 : 0;
                  thread->push(data);
                  break;
                  // (LXOR): Logical XOR
            case 0x46:
                  param2 = thread->pop();
                  param1 = thread->pop();
                  data = ((param1) ? !(param2) : !!(param2));
                  thread->push(data);
                  break;

// GAME INSTRUCTIONS  

                  // (DLGP): Play Character Dialogue
            case 0x53:
                  {
                        int n_voices;
                        int a_index;
                        int voice_rn;

                        n_voices = scriptS.readByte();
                        param1 = (SDataWord_T) scriptS.readUint16LE();
                        // ignored ?
                        scriptS.readByte();
                        scriptS.readUint16LE();

                        a_index = _vm->_actor->getActorIndex(param1);
                        if (a_index < 0) {
                              _vm->_console->DebugPrintf(S_WARN_PREFIX "%X: DLGP Actor id not found.\n", thread->i_offset);
                        }

                        for (i = 0; i < n_voices; i++) {
                              data = thread->pop();
                              if (a_index < 0)
                                    continue;
                              if (!isVoiceLUTPresent()) {
                                    voice_rn = -1;
                              } else {
                                    voice_rn = currentScript()->voice->voices[data];
                              }
                              _vm->_actor->speak(a_index, currentScript()->diag->str[data], voice_rn, &thread->sem);
                        }
                  }
                  break;
                  // (DLGS): Initialize dialogue interface
            case 0x54:
                  warning("dialog_begin opcode: stub");
                  break;
                  // (DLGX): Run dialogue interface
            case 0x55:
                  warning("dialog_end opcode: stub");
                  break;
                  // (DLGO): Add a dialogue option to interface
            case 0x56:
                  {
                        SDataWord_T param3 = 0;
                        param1 = scriptS.readByte();
                        param2 = scriptS.readByte();
                        if (param2 & 1) {
                              param3 = scriptS.readUint16LE();
                        }
                        debug(2, "DLGO | %02X %02X %04X", param1, param2, param3);
                  }
                  break;
            case 0x57: // animate
                  scriptS.readUint16LE();
                  scriptS.readUint16LE();
                  iparam1 = (long)scriptS.readByte();
                  thread->i_offset += iparam1;
                  break;

// End instruction list

            default:

                  _vm->_console->DebugPrintf(S_ERROR_PREFIX "%X: Invalid opcode encountered: (%X).\n", thread->i_offset, in_char);
                  thread->flags |= kTFlagAborted;
                  break;
            }

            // Set instruction offset only if a previous instruction didn't branch
            if (saved_offset == thread->i_offset) {
                  thread->i_offset = scriptS.pos();
            } else {
                  scriptS.seek(thread->i_offset);
            }
            if (unhandled) {
                  _vm->_console->DebugPrintf(S_ERROR_PREFIX "%X: Unhandled opcode.\n", thread->i_offset);
                  thread->flags |= kTFlagAborted;
            }
            if ((thread->flags == kTFlagNone) && debug_print) {
                  SDebugPrintInstr(thread);
            }
      }

      return SUCCESS;
}

} // End of namespace Saga


Generated by  Doxygen 1.6.0   Back to index