Logo Search packages:      
Sourcecode: scummvm version File versions  Download package

sthread.cpp

/* ScummVM - Scumm Interpreter
 * Copyright (C) 2004-2005 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/saga/sthread.cpp,v 1.108.2.1 2005/10/18 02:11:20 sev Exp $
 *
 */

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

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

#include "saga/script.h"

#include "saga/stream.h"
#include "saga/scene.h"
#include "saga/resnames.h"

namespace Saga {

ScriptThread *Script::createThread(uint16 scriptModuleNumber, uint16 scriptEntryPointNumber) {
      ScriptThread *newThread;

      loadModule(scriptModuleNumber);
      if (_modules[scriptModuleNumber].entryPointsCount <= scriptEntryPointNumber) {
            error("Script::createThread wrong scriptEntryPointNumber");
      }

      newThread = _threadList.pushFront().operator->();
      newThread->_flags = kTFlagNone;
      newThread->_stackSize = DEFAULT_THREAD_STACK_SIZE;
      newThread->_stackBuf = (uint16 *)malloc(newThread->_stackSize * sizeof(*newThread->_stackBuf));
      newThread->_stackTopIndex = newThread->_stackSize - 2;
      newThread->_instructionOffset = _modules[scriptModuleNumber].entryPoints[scriptEntryPointNumber].offset;
      newThread->_commonBase = _commonBuffer;
      newThread->_staticBase = _commonBuffer + _modules[scriptModuleNumber].staticOffset;
      newThread->_moduleBase = _modules[scriptModuleNumber].moduleBase;
      newThread->_moduleBaseSize = _modules[scriptModuleNumber].moduleBaseSize;

      newThread->_strings = &_modules[scriptModuleNumber].strings;

      if (_vm->getGameType() == GType_IHNM)
            newThread->_voiceLUT = &_globalVoiceLUT;
      else
            newThread->_voiceLUT = &_modules[scriptModuleNumber].voiceLUT;

      return newThread;
}

void Script::wakeUpActorThread(int waitType, void *threadObj) {
      ScriptThread *thread;
      ScriptThreadList::iterator threadIterator;

      for (threadIterator = _threadList.begin(); threadIterator != _threadList.end(); ++threadIterator) {
            thread = threadIterator.operator->();
            if ((thread->_flags & kTFlagWaiting) && (thread->_waitType == waitType) && (thread->_threadObj == threadObj)) {
                  thread->_flags &= ~kTFlagWaiting;
            }
      }
}

void Script::wakeUpThreads(int waitType) {
      ScriptThread *thread;
      ScriptThreadList::iterator threadIterator;

      for (threadIterator = _threadList.begin(); threadIterator != _threadList.end(); ++threadIterator) {
            thread = threadIterator.operator->();
            if ((thread->_flags & kTFlagWaiting) && (thread->_waitType == waitType)) {
                  thread->_flags &= ~kTFlagWaiting;
            }
      }
}

void Script::wakeUpThreadsDelayed(int waitType, int sleepTime) {
      ScriptThread *thread;
      ScriptThreadList::iterator threadIterator;

      for (threadIterator = _threadList.begin(); threadIterator != _threadList.end(); ++threadIterator) {
            thread = threadIterator.operator->();
            if ((thread->_flags & kTFlagWaiting) && (thread->_waitType == waitType)) {
                  thread->_waitType = kWaitTypeDelay;
                  thread->_sleepTime = sleepTime;
            }
      }
}

void Script::executeThreads(uint msec) {
      ScriptThread *thread;
      ScriptThreadList::iterator threadIterator;

      if (_vm->_interface->_statusTextInput) {
            return;
      }

      threadIterator = _threadList.begin();

      while (threadIterator != _threadList.end()) {
            thread = threadIterator.operator->();

            if (thread->_flags & (kTFlagFinished | kTFlagAborted)) {
                  if (thread->_flags & kTFlagFinished)
                        setPointerVerb();

                  if (_vm->getGameType() == GType_IHNM) {
                        thread->_flags &= ~kTFlagFinished;
                        thread->_flags |= kTFlagAborted;
                        ++threadIterator;
                  } else {
                        threadIterator = _threadList.erase(threadIterator);
                  }
                  continue;
            }

            if (thread->_flags & kTFlagWaiting) {

                  switch (thread->_waitType) {
                  case kWaitTypeDelay:
                        if (thread->_sleepTime < msec) {
                              thread->_sleepTime = 0;
                        } else {
                              thread->_sleepTime -= msec;
                        }

                        if (thread->_sleepTime == 0)
                              thread->_flags &= ~kTFlagWaiting;
                        break;

                  case kWaitTypeWalk:
                        {
                              ActorData *actor;
                              actor = (ActorData *)thread->_threadObj;
                              if (actor->_currentAction == kActionWait) {
                                    thread->_flags &= ~kTFlagWaiting;
                              }
                        }
                        break;

                  case kWaitTypeWaitFrames: // IHNM
                        if (thread->_frameWait < _vm->_frameCount)
                              thread->_flags &= ~kTFlagWaiting;
                        break;
                  }
            }

            if (!(thread->_flags & kTFlagWaiting)) {
                  if (runThread(thread, STHREAD_TIMESLICE)) {
                        break;
                  }
            }

            ++threadIterator;
      }

}

void Script::abortAllThreads(void) {
      ScriptThread *thread;
      ScriptThreadList::iterator threadIterator;

      threadIterator = _threadList.begin();

      while (threadIterator != _threadList.end()) {
            thread = threadIterator.operator->();
            thread->_flags |= kTFlagAborted;
            ++threadIterator;
      }
      executeThreads(0);
}

void Script::completeThread(void) {
      int limit = (_vm->getGameType() == GType_IHNM) ? 100 : 40;

      for (int i = 0; i < limit && !_threadList.isEmpty(); i++)
            executeThreads(0);
}

bool Script::runThread(ScriptThread *thread, uint instructionLimit) {
      const char*operandName;
      uint instructionCount;
      uint16 savedInstructionOffset;

      byte *addr;
      byte mode;
      uint16 jmpOffset1;
      int16 iparam1;
      int16 iparam2;
      int16 iparam3;

      bool disContinue;
      byte argumentsCount;
      uint16 functionNumber;
      uint16 checkStackTopIndex;
      ScriptFunctionType scriptFunction;

      int operandChar;
      int i;

      MemoryReadStream scriptS(thread->_moduleBase, thread->_moduleBaseSize);

      scriptS.seek(thread->_instructionOffset);

      for (instructionCount = 0; instructionCount < instructionLimit; instructionCount++) {
            if (thread->_flags & (kTFlagAsleep))
                  break;

            savedInstructionOffset = thread->_instructionOffset;
            operandChar = scriptS.readByte();


#define CASEOP(opName)  case opName:                                                                        \
                                          if (operandChar == opName) {                                      \
                                                operandName = #opName;                                            \
                                                debug(2, operandName);                                            \
                                                _vm->_console->DebugPrintf("%s\n", operandName);      \
                                          }

            debug(8, "Executing thread offset: %lu (%x) stack: %d", thread->_instructionOffset, operandChar, thread->pushedSize());
            operandName="";
            switch (operandChar) {
            CASEOP(opNextBlock)
                  // Some sort of "jump to the start of the next memory
                  // page" instruction, I think.
                  thread->_instructionOffset = (((thread->_instructionOffset) >> 10) + 1) << 10;
                  break;

// STACK INSTRUCTIONS
            CASEOP(opDup)
                  thread->push(thread->stackTop());
                  break;
            CASEOP(opDrop)
                  thread->pop();
                  break;
            CASEOP(opZero)
                  thread->push(0);
                  break;
            CASEOP(opOne)
                  thread->push(1);
                  break;
            CASEOP(opConstint)
            CASEOP(opStrlit)
                  iparam1 = scriptS.readSint16LE();
                  thread->push(iparam1);
                  debug(8, "0x%X", iparam1);
                  break;

// DATA INSTRUCTIONS
            CASEOP(opGetFlag)
                  addr = thread->baseAddress(scriptS.readByte());
                  iparam1 = scriptS.readSint16LE();
                  addr += (iparam1 >> 3);
                  iparam1 = (1 << (iparam1 & 7));
                  thread->push((*addr) & iparam1 ? 1 : 0);
                  break;
            CASEOP(opGetInt)
                  mode = scriptS.readByte();
                  addr = thread->baseAddress(mode);
                  iparam1 = scriptS.readSint16LE();
                  addr += iparam1;
                  thread->push(readUint16(addr, mode));
                  debug(8, "0x%X", readUint16(addr, mode));
                  break;
            CASEOP(opPutFlag)
                  addr = thread->baseAddress(scriptS.readByte());
                  iparam1 = scriptS.readSint16LE();
                  addr += (iparam1 >> 3);
                  iparam1 = (1 << (iparam1 & 7));
                  if (thread->stackTop()) {
                        *addr |= iparam1;
                  } else {
                        *addr &= ~iparam1;
                  }
                  break;
            CASEOP(opPutInt)
                  mode = scriptS.readByte();
                  addr = thread->baseAddress(mode);
                  iparam1 = scriptS.readSint16LE();
                  addr += iparam1;
                  writeUint16(addr, thread->stackTop(), mode);
                  break;
            CASEOP(opPutFlagV)
                  addr = thread->baseAddress(scriptS.readByte());
                  iparam1 = scriptS.readSint16LE();
                  addr += (iparam1 >> 3);
                  iparam1 = (1 << (iparam1 & 7));
                  if (thread->pop()) {
                        *addr |= iparam1;
                  } else {
                        *addr &= ~iparam1;
                  }
                  break;
            CASEOP(opPutIntV)
                  mode = scriptS.readByte();
                  addr = thread->baseAddress(mode);
                  iparam1 = scriptS.readSint16LE();
                  addr += iparam1;
                  writeUint16(addr, thread->pop(), mode);
                  break;

// FUNCTION CALL INSTRUCTIONS
            CASEOP(opCall)
                  argumentsCount = scriptS.readByte();
                  iparam1 = scriptS.readByte();
                  if (iparam1 != kAddressModule) {
                        error("Script::runThread iparam1 != kAddressModule");
                  }
                  addr = thread->baseAddress(iparam1);
                  iparam1 = scriptS.readSint16LE();
                  addr += iparam1;
                  thread->push(argumentsCount);

                  jmpOffset1 = scriptS.pos();
                  // NOTE: The original pushes the program
                  // counter as a pointer here. But I don't think
                  // we will have to do that.
                  thread->push(jmpOffset1);
                  // NOTE2: program counter is 32bit - so we should "emulate" it size - because kAddressStack relies on it
                  thread->push(0);
                  thread->_instructionOffset = iparam1;

                  break;
            CASEOP(opCcall)
            CASEOP(opCcallV)
                  argumentsCount = scriptS.readByte();
                  functionNumber = scriptS.readUint16LE();
                  if (functionNumber >= ((_vm->getGameType() == GType_IHNM) ?
                                                   IHNM_SCRIPT_FUNCTION_MAX : ITE_SCRIPT_FUNCTION_MAX)) {
                        error("Script::runThread() Invalid script function number (%d)", functionNumber);
                  }

                  debug(2, "Calling #%d %s argCount=%i", functionNumber, _scriptFunctionsList[functionNumber].scriptFunctionName, argumentsCount);
                  scriptFunction = _scriptFunctionsList[functionNumber].scriptFunction;
                  checkStackTopIndex = thread->_stackTopIndex + argumentsCount;
                  disContinue = false;
                  (this->*scriptFunction)(thread, argumentsCount, disContinue);
                  if (disContinue) {
                        return true;
                  }
                  if (scriptFunction == &Saga::Script::sfScriptGotoScene ||
                        scriptFunction == &Saga::Script::sfVsetTrack) {
                        return true; // cause abortAllThreads called and _this_ thread destroyed
                  }

                  thread->_stackTopIndex = checkStackTopIndex;

                  if (operandChar == opCcall) {// CALL function
                        thread->push(thread->_returnValue);
                  }

                  if (thread->_flags & kTFlagAsleep)
                        instructionCount = instructionLimit;      // break out of loop!
                  break;
            CASEOP(opEnter)
                  thread->push(thread->_frameIndex);
                  thread->_frameIndex = thread->_stackTopIndex;
                  thread->_stackTopIndex -= (scriptS.readSint16LE() / 2);
                  break;
            CASEOP(opReturn)
                  thread->_returnValue = thread->pop();
            CASEOP(opReturnV)
                  thread->_stackTopIndex = thread->_frameIndex;
                  thread->_frameIndex = thread->pop();
                  if (thread->pushedSize() == 0) {
                        thread->_flags |= kTFlagFinished;
                        return true;
                  } else {
                        thread->pop(); //cause it 0
                        thread->_instructionOffset = thread->pop();

                        // Pop all the call parameters off the stack
                        iparam1 = thread->pop();
                        while (iparam1--) {
                              thread->pop();
                        }

                        if (operandChar == opReturn) {
                              thread->push(thread->_returnValue);
                        }
                  }
                  break;

// BRANCH INSTRUCTIONS
            CASEOP(opJmp)
                  jmpOffset1 = scriptS.readUint16LE();
                  thread->_instructionOffset = jmpOffset1;
                  break;
            CASEOP(opJmpTrueV)
                  jmpOffset1 = scriptS.readUint16LE();
                  if (thread->pop()) {
                        thread->_instructionOffset = jmpOffset1;
                  }
                  break;
            CASEOP(opJmpFalseV)
                  jmpOffset1 = scriptS.readUint16LE();
                  if (!thread->pop()) {
                        thread->_instructionOffset = jmpOffset1;
                  }
                  break;
            CASEOP(opJmpTrue)
                  jmpOffset1 = scriptS.readUint16LE();
                  if (thread->stackTop()) {
                        thread->_instructionOffset = jmpOffset1;
                  }
                  break;
            CASEOP(opJmpFalse)
                  jmpOffset1 = scriptS.readUint16LE();
                  if (!thread->stackTop()) {
                        thread->_instructionOffset = jmpOffset1;
                  }
                  break;
            CASEOP(opJmpSwitch)
                  iparam1 = scriptS.readSint16LE();
                  iparam2 = thread->pop();
                  while (iparam1--) {
                        iparam3 = scriptS.readUint16LE();
                        thread->_instructionOffset = scriptS.readUint16LE();
                        if (iparam3 == iparam2) {
                              break;
                        }
                  }
                  if (iparam1 < 0) {
                        thread->_instructionOffset = scriptS.readUint16LE();
                  }
                  break;
            CASEOP(opJmpRandom)
                  // Supposedly the number of possible branches.
                  // The original interpreter ignores it.
                  scriptS.readUint16LE();
                  iparam1 = scriptS.readSint16LE();
                  iparam1 = _vm->_rnd.getRandomNumber(iparam1 - 1);
                  while (1) {
                        iparam2 = scriptS.readSint16LE();
                        thread->_instructionOffset = scriptS.readUint16LE();

                        iparam1 -= iparam2;
                        if (iparam1 < 0) {
                              break;
                        }
                  }
                  break;

// UNARY INSTRUCTIONS
            CASEOP(opNegate)
                  thread->push(-thread->pop());
                  break;
            CASEOP(opNot)
                  thread->push(!thread->pop());
                  break;
            CASEOP(opCompl)
                  thread->push(~thread->pop());
                  break;

            CASEOP(opIncV)
                  mode = scriptS.readByte();
                  addr = thread->baseAddress(mode);
                  iparam1 = scriptS.readSint16LE();
                  addr += iparam1;
                  iparam1 = readUint16(addr, mode);
                  writeUint16(addr, iparam1 + 1, mode);
                  break;
            CASEOP(opDecV)
                  mode = scriptS.readByte();
                  addr = thread->baseAddress(mode);
                  iparam1 = scriptS.readSint16LE();
                  addr += iparam1;
                  iparam1 = readUint16(addr, mode);
                  writeUint16(addr, iparam1 - 1, mode);
                  break;
            CASEOP(opPostInc)
                  mode = scriptS.readByte();
                  addr = thread->baseAddress(mode);
                  iparam1 = scriptS.readSint16LE();
                  addr += iparam1;
                  iparam1 = readUint16(addr, mode);
                  thread->push(iparam1);
                  writeUint16(addr, iparam1 + 1, mode);
                  break;
            CASEOP(opPostDec)
                  mode = scriptS.readByte();
                  addr = thread->baseAddress(mode);
                  iparam1 = scriptS.readSint16LE();
                  addr += iparam1;
                  iparam1 = readUint16(addr, mode);
                  thread->push(iparam1);
                  writeUint16(addr, iparam1 - 1, mode);
                  break;

// ARITHMETIC INSTRUCTIONS
            CASEOP(opAdd)
                  iparam2 = thread->pop();
                  iparam1 = thread->pop();
                  iparam1 += iparam2;
                  thread->push(iparam1);
                  break;
            CASEOP(opSub)
                  iparam2 = thread->pop();
                  iparam1 = thread->pop();
                  iparam1 -= iparam2;
                  thread->push(iparam1);
                  break;
            CASEOP(opMul)
                  iparam2 = thread->pop();
                  iparam1 = thread->pop();
                  iparam1 *= iparam2;
                  thread->push(iparam1);
                  break;
            CASEOP(opDiv)
                  iparam2 = thread->pop();
                  iparam1 = thread->pop();
                  iparam1 /= iparam2;
                  thread->push(iparam1);
                  break;
            CASEOP(opMod)
                  iparam2 = thread->pop();
                  iparam1 = thread->pop();
                  iparam1 %= iparam2;
                  thread->push(iparam1);
                  break;

// COMPARISION INSTRUCTIONS
            CASEOP(opEq)
                  iparam2 = thread->pop();
                  iparam1 = thread->pop();
                  thread->push((iparam1 == iparam2) ? 1 : 0);
                  debug(8, "0x%X 0x%X", iparam1, iparam2);
                  break;
            CASEOP(opNe)
                  iparam2 = thread->pop();
                  iparam1 = thread->pop();
                  thread->push((iparam1 != iparam2) ? 1 : 0);
                  break;
            CASEOP(opGt)
                  iparam2 = thread->pop();
                  iparam1 = thread->pop();
                  thread->push((iparam1 > iparam2) ? 1 : 0);
                  break;
            CASEOP(opLt)
                  iparam2 = thread->pop();
                  iparam1 = thread->pop();
                  thread->push((iparam1 < iparam2) ? 1 : 0);
                  break;
            CASEOP(opGe)
                  iparam2 = thread->pop();
                  iparam1 = thread->pop();
                  thread->push((iparam1 >= iparam2) ? 1 : 0);
                  break;
            CASEOP(opLe)
                  iparam2 = thread->pop();
                  iparam1 = thread->pop();
                  thread->push((iparam1 <= iparam2) ? 1 : 0);
                  break;

// SHIFT INSTRUCTIONS
            CASEOP(opRsh)
                  iparam2 = thread->pop();
                  iparam1 = thread->pop();
                  iparam1 >>= iparam2;
                  thread->push(iparam1);
                  break;
            CASEOP(opLsh)
                  iparam2 = thread->pop();
                  iparam1 = thread->pop();
                  iparam1 <<= iparam2;
                  thread->push(iparam1);
                  break;

// BITWISE INSTRUCTIONS
            CASEOP(opAnd)
                  iparam2 = thread->pop();
                  iparam1 = thread->pop();
                  iparam1 &= iparam2;
                  thread->push(iparam1);
                  break;
            CASEOP(opOr)
                  iparam2 = thread->pop();
                  iparam1 = thread->pop();
                  iparam1 |= iparam2;
                  thread->push(iparam1);
                  break;
            CASEOP(opXor)
                  iparam2 = thread->pop();
                  iparam1 = thread->pop();
                  iparam1 ^= iparam2;
                  thread->push(iparam1);
                  break;

// LOGICAL INSTRUCTIONS
            CASEOP(opLAnd)
                  iparam2 = thread->pop();
                  iparam1 = thread->pop();
                  thread->push((iparam1 && iparam2) ? 1 : 0);
                  break;
            CASEOP(opLOr)
                  iparam2 = thread->pop();
                  iparam1 = thread->pop();
                  thread->push((iparam1 || iparam2) ? 1 : 0);
                  break;
            CASEOP(opLXor)
                  iparam2 = thread->pop();
                  iparam1 = thread->pop();
                  thread->push(((iparam1 && !iparam2) || (!iparam1 && iparam2)) ? 1 : 0);
                  break;

// GAME INSTRUCTIONS
            CASEOP(opSpeak) {
                        int stringsCount;
                        uint16 actorId;
                        uint16 speechFlags;
                        int sampleResourceId = -1;
                        int16 first;
                        const char *strings[ACTOR_SPEECH_STRING_MAX];

                        if (_vm->_actor->isSpeaking()) {
                              thread->wait(kWaitTypeSpeech);
                              return false;
                        }

                        stringsCount = scriptS.readByte();
                        actorId = scriptS.readUint16LE();
                        speechFlags = scriptS.readByte();
                        scriptS.readUint16LE(); // x,y skip

                        if (stringsCount == 0)
                              error("opSpeak stringsCount == 0");

                        if (stringsCount > ACTOR_SPEECH_STRING_MAX)
                              error("opSpeak stringsCount=0x%X exceed ACTOR_SPEECH_STRING_MAX", stringsCount);

                        iparam1 = first = thread->stackTop();
                        for (i = 0; i < stringsCount; i++) {
                               iparam1 = thread->pop();
                               strings[i] = thread->_strings->getString(iparam1);
                        }
                        // now data contains last string index

                        if (_vm->getGameId() == GID_ITE_DISK_G) { // special ITE dos
                              if ((_vm->_scene->currentSceneNumber() == ITE_DEFAULT_SCENE) &&
                                    (iparam1 >= 288) && (iparam1 <= (RID_SCENE1_VOICE_138 - RID_SCENE1_VOICE_009 + 288))) {
                                    sampleResourceId = RID_SCENE1_VOICE_009 + iparam1 - 288;
                              }
                        } else {
                              if (thread->_voiceLUT->voicesCount > first) {
                                    sampleResourceId = thread->_voiceLUT->voices[first];
                              }
                        }

                        if (sampleResourceId < 0 || sampleResourceId > 4000)
                              sampleResourceId = -1;

                        if (_vm->getGameType() == GType_ITE && !sampleResourceId)
                              sampleResourceId = -1;

                        _vm->_actor->actorSpeech(actorId, strings, stringsCount, sampleResourceId, speechFlags);

                        if (!(speechFlags & kSpeakAsync)) {
                              thread->wait(kWaitTypeSpeech);
                        }
                  }
                  break;
            CASEOP(opDialogBegin)
                  if (_conversingThread) {
                        thread->wait(kWaitTypeDialogBegin);
                        return false;
                  }
                  _conversingThread = thread;
                  _vm->_interface->converseClear();
                  break;
            CASEOP(opDialogEnd)
                  if (thread == _conversingThread) {
                        _vm->_interface->activate();
                        _vm->_interface->setMode(kPanelConverse);
                        thread->wait(kWaitTypeDialogEnd);
                        return false;
                  }
                  break;
            CASEOP(opReply) {
                        const char *str;
                        byte replyNum;
                        byte flags;
                        replyNum = scriptS.readByte();
                        flags = scriptS.readByte();
                        iparam1 = 0;

                        if (flags & kReplyOnce) {
                              iparam1 = scriptS.readSint16LE();
                              addr = thread->_staticBase + (iparam1 >> 3);
                              if (*addr & (1 << (iparam1 & 7))) {
                                    break;
                              }
                        }

                        str = thread->_strings->getString(thread->pop());
                        if (_vm->_interface->converseAddText(str, replyNum, flags, iparam1))
                              warning("Error adding ConverseText (%s, %d, %d, %d)", str, replyNum, flags, iparam1);
                  }
                  break;
            CASEOP(opAnimate)
                  scriptS.readUint16LE();
                  scriptS.readUint16LE();
                  jmpOffset1 = scriptS.readByte();
                  thread->_instructionOffset += jmpOffset1;
                  break;

            default:
                  error("Script::runThread() Invalid opcode encountered 0x%X", operandChar);
            }

            if (thread->_flags & (kTFlagFinished | kTFlagAborted)) {
                  error("Wrong flags %d in thread", thread->_flags);
            }

            // Set instruction offset only if a previous instruction didn't branch
            if (savedInstructionOffset == thread->_instructionOffset) {
                  thread->_instructionOffset = scriptS.pos();
            } else {
                  if (thread->_instructionOffset >= scriptS.size()) {
                        error("Script::runThread() Out of range script execution");
                  }

                  scriptS.seek(thread->_instructionOffset);
            }
      }
      return false;
}

} // End of namespace Saga


Generated by  Doxygen 1.6.0   Back to index