2004-04-12 21:40:49 +00:00
|
|
|
/* ScummVM - Scumm Interpreter
|
2005-01-01 16:20:17 +00:00
|
|
|
* Copyright (C) 2004-2005 The ScummVM project
|
2004-04-12 21:40:49 +00:00
|
|
|
*
|
|
|
|
* 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$
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2004-05-01 16:15:55 +00:00
|
|
|
// Scripting module thread management component
|
2004-08-02 16:20:35 +00:00
|
|
|
#include "saga/saga.h"
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-08-02 16:20:35 +00:00
|
|
|
#include "saga/gfx.h"
|
|
|
|
#include "saga/actor.h"
|
2004-08-10 18:31:33 +00:00
|
|
|
#include "saga/console.h"
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-08-12 21:39:11 +00:00
|
|
|
#include "saga/script.h"
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-12-15 00:24:12 +00:00
|
|
|
#include "saga/stream.h"
|
2004-12-21 06:49:07 +00:00
|
|
|
#include "saga/scene.h"
|
|
|
|
#include "saga/resnames.h"
|
2004-04-12 21:40:49 +00:00
|
|
|
|
|
|
|
namespace Saga {
|
|
|
|
|
2004-10-27 21:32:28 +00:00
|
|
|
void Script::setFramePtr(SCRIPT_THREAD *thread, int newPtr) {
|
2004-10-09 07:39:46 +00:00
|
|
|
thread->framePtr = newPtr;
|
2004-12-22 21:04:50 +00:00
|
|
|
dataBuffer(3)->length = ARRAYSIZE(thread->stackBuf) - thread->framePtr;
|
|
|
|
dataBuffer(3)->data = (ScriptDataWord *) &(thread->stackBuf[newPtr]);
|
2004-10-09 07:39:46 +00:00
|
|
|
}
|
|
|
|
|
2004-10-27 21:32:28 +00:00
|
|
|
SCRIPT_THREAD *Script::SThreadCreate() {
|
|
|
|
SCRIPT_THREAD *new_thread;
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-08-12 23:57:45 +00:00
|
|
|
if (!isInitialized()) {
|
2004-04-12 21:40:49 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2004-12-15 00:24:12 +00:00
|
|
|
new_thread = _threadList.pushFront().operator->();
|
2004-10-22 07:18:01 +00:00
|
|
|
|
2004-09-23 06:46:44 +00:00
|
|
|
new_thread->stackPtr = ARRAYSIZE(new_thread->stackBuf) - 1;
|
2004-10-09 07:39:46 +00:00
|
|
|
setFramePtr(new_thread, new_thread->stackPtr);
|
|
|
|
|
2004-10-27 02:27:54 +00:00
|
|
|
new_thread->flags = kTFlagWaiting;
|
2004-12-21 06:49:07 +00:00
|
|
|
new_thread->waitType = kWaitTypePause;
|
2004-10-27 02:27:54 +00:00
|
|
|
|
2004-12-22 21:04:50 +00:00
|
|
|
dataBuffer(4)->length = ARRAYSIZE(new_thread->threadVars);
|
2004-10-09 07:39:46 +00:00
|
|
|
dataBuffer(4)->data = new_thread->threadVars;
|
2004-10-22 07:18:01 +00:00
|
|
|
return new_thread;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2004-12-24 10:22:01 +00:00
|
|
|
void Script::wakeUpActorThread(int waitType, void *threadObj) {
|
|
|
|
SCRIPT_THREAD *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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-12-21 06:49:07 +00:00
|
|
|
void Script::wakeUpThreads(int waitType) {
|
|
|
|
SCRIPT_THREAD *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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-12-21 06:49:07 +00:00
|
|
|
void Script::wakeUpThreadsDelayed(int waitType, int sleepTime) {
|
2004-10-27 21:32:28 +00:00
|
|
|
SCRIPT_THREAD *thread;
|
2004-12-21 06:49:07 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int Script::executeThreads(uint msec) {
|
|
|
|
SCRIPT_THREAD *thread;
|
|
|
|
ScriptThreadList::iterator threadIterator;
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-08-12 23:57:45 +00:00
|
|
|
if (!isInitialized()) {
|
2004-10-27 21:32:28 +00:00
|
|
|
return FAILURE;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2004-12-21 06:49:07 +00:00
|
|
|
threadIterator = _threadList.begin();
|
2004-10-27 02:27:54 +00:00
|
|
|
|
2004-12-21 06:49:07 +00:00
|
|
|
while (threadIterator != _threadList.end()) {
|
|
|
|
thread = threadIterator.operator->();
|
2004-10-27 02:27:54 +00:00
|
|
|
|
|
|
|
if (thread->flags & (kTFlagFinished | kTFlagAborted)) {
|
|
|
|
//if (thread->flags & kTFlagFinished) // FIXME. Missing function
|
|
|
|
|
2004-12-15 00:24:12 +00:00
|
|
|
|
2004-12-21 06:49:07 +00:00
|
|
|
threadIterator = _threadList.erase(threadIterator);
|
2004-10-27 02:27:54 +00:00
|
|
|
continue;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
2004-10-27 02:27:54 +00:00
|
|
|
|
2004-12-24 10:22:01 +00:00
|
|
|
if (thread->flags & kTFlagWaiting) {
|
|
|
|
|
|
|
|
if (thread->waitType == kWaitTypeDelay) {
|
|
|
|
if (thread->sleepTime < msec) {
|
|
|
|
thread->sleepTime = 0;
|
|
|
|
} else {
|
|
|
|
thread->sleepTime -= msec;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (thread->sleepTime == 0)
|
|
|
|
thread->flags &= ~kTFlagWaiting;
|
2004-12-21 06:49:07 +00:00
|
|
|
} else {
|
2004-12-24 10:22:01 +00:00
|
|
|
if (thread->waitType == kWaitTypeWalk) {
|
|
|
|
ActorData *actor;
|
|
|
|
actor = (ActorData *)thread->threadObj;
|
|
|
|
if (actor->currentAction == kActionWait) {
|
|
|
|
thread->flags &= ~kTFlagWaiting;
|
|
|
|
}
|
|
|
|
}
|
2004-10-27 02:27:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(thread->flags & kTFlagWaiting))
|
2005-01-03 21:17:32 +00:00
|
|
|
runThread(thread, STHREAD_TIMESLICE);
|
2004-10-27 02:27:54 +00:00
|
|
|
|
2004-12-21 06:49:07 +00:00
|
|
|
++threadIterator;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2004-10-27 21:32:28 +00:00
|
|
|
return SUCCESS;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2004-08-12 23:57:45 +00:00
|
|
|
void Script::SThreadCompleteThread(void) {
|
2004-12-15 00:24:12 +00:00
|
|
|
for (int i = 0; i < 40 && !_threadList.isEmpty() ; i++)
|
2004-12-21 06:49:07 +00:00
|
|
|
executeThreads(0);
|
2004-08-12 01:11:11 +00:00
|
|
|
}
|
|
|
|
|
2004-10-27 21:32:28 +00:00
|
|
|
int Script::SThreadSetEntrypoint(SCRIPT_THREAD *thread, int ep_num) {
|
|
|
|
SCRIPT_BYTECODE *bytecode;
|
2004-04-12 21:40:49 +00:00
|
|
|
int max_entrypoint;
|
|
|
|
|
2004-08-12 23:57:45 +00:00
|
|
|
assert(isInitialized());
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-08-12 23:57:45 +00:00
|
|
|
bytecode = currentScript()->bytecode;
|
2004-04-12 21:40:49 +00:00
|
|
|
max_entrypoint = bytecode->n_entrypoints;
|
|
|
|
|
|
|
|
if ((ep_num < 0) || (ep_num >= max_entrypoint)) {
|
2004-10-27 21:32:28 +00:00
|
|
|
return FAILURE;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
thread->ep_num = ep_num;
|
|
|
|
thread->ep_offset = bytecode->entrypoints[ep_num].offset;
|
|
|
|
|
2004-10-27 21:32:28 +00:00
|
|
|
return SUCCESS;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2004-10-27 21:32:28 +00:00
|
|
|
int Script::SThreadExecute(SCRIPT_THREAD *thread, int ep_num) {
|
2004-08-12 23:57:45 +00:00
|
|
|
assert(isInitialized());
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-08-12 23:57:45 +00:00
|
|
|
if ((currentScript() == NULL) || (!currentScript()->loaded)) {
|
2004-10-27 21:32:28 +00:00
|
|
|
return FAILURE;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2004-08-12 23:57:45 +00:00
|
|
|
SThreadSetEntrypoint(thread, ep_num);
|
2004-04-12 21:40:49 +00:00
|
|
|
|
|
|
|
thread->i_offset = thread->ep_offset;
|
2004-10-27 02:27:54 +00:00
|
|
|
thread->flags = kTFlagNone;
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-10-27 21:32:28 +00:00
|
|
|
return SUCCESS;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2004-10-27 02:27:54 +00:00
|
|
|
|
|
|
|
|
2004-10-27 21:32:28 +00:00
|
|
|
unsigned char *Script::SThreadGetReadPtr(SCRIPT_THREAD *thread) {
|
2004-08-12 23:57:45 +00:00
|
|
|
return currentScript()->bytecode->bytecode_p + thread->i_offset;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2004-08-12 23:57:45 +00:00
|
|
|
unsigned long Script::SThreadGetReadOffset(const byte *read_p) {
|
|
|
|
return (unsigned long)(read_p - (unsigned char *)currentScript()->bytecode->bytecode_p);
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2004-10-27 21:32:28 +00:00
|
|
|
size_t Script::SThreadGetReadLen(SCRIPT_THREAD *thread) {
|
2004-08-12 23:57:45 +00:00
|
|
|
return currentScript()->bytecode->bytecode_len - thread->i_offset;
|
2004-05-04 03:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-04-12 21:40:49 +00:00
|
|
|
|
|
|
|
|
2004-08-12 23:57:45 +00:00
|
|
|
int Script::SThreadDebugStep() {
|
|
|
|
if (_dbg_singlestep) {
|
|
|
|
_dbg_dostep = 1;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2004-10-27 21:32:28 +00:00
|
|
|
return SUCCESS;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2005-01-03 21:17:32 +00:00
|
|
|
void Script::runThread(SCRIPT_THREAD *thread, int instr_limit) {
|
2004-04-12 21:40:49 +00:00
|
|
|
int instr_count;
|
2004-04-30 23:02:23 +00:00
|
|
|
uint32 saved_offset;
|
2004-12-22 21:04:50 +00:00
|
|
|
ScriptDataWord param1;
|
|
|
|
ScriptDataWord param2;
|
2004-04-12 21:40:49 +00:00
|
|
|
long iparam1;
|
|
|
|
long iparam2;
|
|
|
|
long iresult;
|
|
|
|
|
2004-12-22 21:04:50 +00:00
|
|
|
ScriptDataWord data;
|
|
|
|
ScriptDataWord scriptRetVal = 0;
|
2004-04-12 21:40:49 +00:00
|
|
|
int debug_print = 0;
|
|
|
|
int n_buf;
|
|
|
|
int bitstate;
|
2004-12-21 06:49:07 +00:00
|
|
|
int operandChar;
|
2004-04-12 21:40:49 +00:00
|
|
|
int i;
|
|
|
|
int unhandled = 0;
|
|
|
|
|
2004-05-01 16:15:55 +00:00
|
|
|
// Handle debug single-stepping
|
2004-08-12 23:57:45 +00:00
|
|
|
if ((thread == _dbg_thread) && _dbg_singlestep) {
|
|
|
|
if (_dbg_dostep) {
|
2004-04-12 21:40:49 +00:00
|
|
|
debug_print = 1;
|
2004-10-27 02:27:54 +00:00
|
|
|
thread->sleepTime = 0;
|
2004-04-12 21:40:49 +00:00
|
|
|
instr_limit = 1;
|
2004-08-12 23:57:45 +00:00
|
|
|
_dbg_dostep = 0;
|
2004-04-12 21:40:49 +00:00
|
|
|
} else {
|
2005-01-03 21:17:32 +00:00
|
|
|
return;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-12-15 00:24:12 +00:00
|
|
|
MemoryReadStream/*Endian*/ scriptS(currentScript()->bytecode->bytecode_p, currentScript()->bytecode->bytecode_len/*, IS_BIG_ENDIAN*/);
|
2004-09-19 14:49:00 +00:00
|
|
|
|
2004-12-22 21:04:50 +00:00
|
|
|
dataBuffer(2)->length = currentScript()->bytecode->bytecode_len / sizeof(ScriptDataWord);
|
|
|
|
dataBuffer(2)->data = (ScriptDataWord *) currentScript()->bytecode->bytecode_p;
|
2004-10-09 07:39:46 +00:00
|
|
|
|
2004-09-19 14:49:00 +00:00
|
|
|
scriptS.seek(thread->i_offset);
|
|
|
|
|
2004-04-12 21:40:49 +00:00
|
|
|
for (instr_count = 0; instr_count < instr_limit; instr_count++) {
|
2005-01-03 21:17:32 +00:00
|
|
|
if (thread->flags & (kTFlagAsleep))
|
2004-12-21 06:49:07 +00:00
|
|
|
break;
|
|
|
|
|
2004-04-12 21:40:49 +00:00
|
|
|
saved_offset = thread->i_offset;
|
2004-12-21 06:49:07 +00:00
|
|
|
operandChar = scriptS.readByte();
|
2005-01-03 21:17:32 +00:00
|
|
|
// debug print (opCode name etc) should be placed here
|
|
|
|
// SDebugPrintInstr(thread)
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-12-24 20:44:39 +00:00
|
|
|
// debug(2, "Executing thread offset: %lu (%x) stack: %d", thread->i_offset, operandChar, thread->stackSize());
|
2004-12-21 06:49:07 +00:00
|
|
|
switch (operandChar) {
|
2004-08-26 23:28:10 +00:00
|
|
|
case 0x01: // nextblock
|
2004-09-21 06:35:00 +00:00
|
|
|
// Some sort of "jump to the start of the next memory
|
|
|
|
// page" instruction, I think.
|
|
|
|
thread->i_offset = 1024 * ((thread->i_offset / 1024) + 1);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
|
|
|
|
2004-05-01 16:15:55 +00:00
|
|
|
// STACK INSTRUCTIONS
|
2004-08-22 18:28:42 +00:00
|
|
|
case 0x02: // Dup top element (DUP)
|
2004-09-23 06:46:44 +00:00
|
|
|
thread->push(thread->stackTop());
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-08-22 18:28:42 +00:00
|
|
|
case 0x03: // Pop nothing (POPN)
|
2004-09-23 06:46:44 +00:00
|
|
|
thread->pop();
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-08-22 18:28:42 +00:00
|
|
|
case 0x04: // Push false (PSHF)
|
2004-09-23 06:46:44 +00:00
|
|
|
thread->push(0);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-08-22 18:28:42 +00:00
|
|
|
case 0x05: // Push true (PSHT)
|
2004-09-23 06:46:44 +00:00
|
|
|
thread->push(1);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-08-22 18:28:42 +00:00
|
|
|
case 0x06: // Push word (PUSH)
|
|
|
|
case 0x08: // Push word (PSHD) (dialogue string index)
|
2004-12-22 21:04:50 +00:00
|
|
|
param1 = (ScriptDataWord)scriptS.readUint16LE();
|
2004-09-23 06:46:44 +00:00
|
|
|
thread->push(param1);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
|
|
|
|
2004-05-01 16:15:55 +00:00
|
|
|
// DATA INSTRUCTIONS
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-08-22 18:28:42 +00:00
|
|
|
case 0x0B: // Test flag (TSTF)
|
|
|
|
n_buf = scriptS.readByte();
|
2004-12-22 21:04:50 +00:00
|
|
|
param1 = (ScriptDataWord)scriptS.readUint16LE();
|
|
|
|
getBit(n_buf, param1, &bitstate);
|
2004-09-23 06:46:44 +00:00
|
|
|
thread->push(bitstate);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-08-22 18:28:42 +00:00
|
|
|
case 0x0C: // Get word (GETW)
|
|
|
|
n_buf = scriptS.readByte();
|
|
|
|
param1 = scriptS.readUint16LE();
|
2004-12-22 21:04:50 +00:00
|
|
|
getWord(n_buf, param1, &data);
|
2004-09-23 06:46:44 +00:00
|
|
|
thread->push(data);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-08-22 18:28:42 +00:00
|
|
|
case 0x0F: // Modify flag (MODF)
|
|
|
|
n_buf = scriptS.readByte();
|
2004-12-22 21:04:50 +00:00
|
|
|
param1 = (ScriptDataWord)scriptS.readUint16LE();
|
|
|
|
bitstate = getUWord(param1);
|
2004-09-23 06:46:44 +00:00
|
|
|
data = thread->stackTop();
|
2004-04-12 21:40:49 +00:00
|
|
|
if (bitstate) {
|
2004-12-22 21:04:50 +00:00
|
|
|
setBit(n_buf, data, 1);
|
2004-04-12 21:40:49 +00:00
|
|
|
} else {
|
2004-12-22 21:04:50 +00:00
|
|
|
setBit(n_buf, data, 0);
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
break;
|
2004-08-22 18:28:42 +00:00
|
|
|
case 0x10: // Put word (PUTW)
|
|
|
|
n_buf = scriptS.readByte();
|
2004-12-22 21:04:50 +00:00
|
|
|
param1 = (ScriptDataWord)scriptS.readUint16LE();
|
2004-09-23 06:46:44 +00:00
|
|
|
data = thread->stackTop();
|
2004-12-22 21:04:50 +00:00
|
|
|
putWord(n_buf, param1, data);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-08-22 18:28:42 +00:00
|
|
|
case 0x13: // Modify flag and pop (MDFP)
|
|
|
|
n_buf = scriptS.readByte();
|
2004-12-22 21:04:50 +00:00
|
|
|
param1 = (ScriptDataWord)scriptS.readUint16LE();
|
2004-09-23 06:46:44 +00:00
|
|
|
param1 = thread->pop();
|
2004-12-22 21:04:50 +00:00
|
|
|
bitstate = getUWord(param1);
|
2004-04-12 21:40:49 +00:00
|
|
|
if (bitstate) {
|
2004-12-22 21:04:50 +00:00
|
|
|
setBit(n_buf, param1, 1);
|
2004-04-12 21:40:49 +00:00
|
|
|
} else {
|
2004-12-22 21:04:50 +00:00
|
|
|
setBit(n_buf, param1, 0);
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
break;
|
2004-08-22 18:28:42 +00:00
|
|
|
case 0x14: // Put word and pop (PTWP)
|
|
|
|
n_buf = scriptS.readByte();
|
2004-12-22 21:04:50 +00:00
|
|
|
param1 = (ScriptDataWord)scriptS.readUint16LE();
|
2004-09-23 06:46:44 +00:00
|
|
|
data = thread->stackTop();
|
2004-12-22 21:04:50 +00:00
|
|
|
putWord(n_buf, param1, data);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
|
|
|
|
2004-05-01 16:15:55 +00:00
|
|
|
// CONTROL INSTRUCTIONS
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-10-03 17:11:23 +00:00
|
|
|
case 0x17: // (GOSB): Call subscript
|
2004-04-12 21:40:49 +00:00
|
|
|
{
|
2004-09-21 06:35:00 +00:00
|
|
|
int n_args;
|
2004-04-12 21:40:49 +00:00
|
|
|
int temp;
|
|
|
|
|
2004-09-21 06:35:00 +00:00
|
|
|
n_args = scriptS.readByte();
|
2004-08-22 18:28:42 +00:00
|
|
|
temp = scriptS.readByte();
|
2004-09-21 06:35:00 +00:00
|
|
|
if (temp != 2)
|
|
|
|
error("Calling dynamically generated script? Wow");
|
2004-12-22 21:04:50 +00:00
|
|
|
param1 = (ScriptDataWord)scriptS.readUint16LE();
|
2004-08-22 18:28:42 +00:00
|
|
|
data = scriptS.pos();
|
2004-09-23 06:46:44 +00:00
|
|
|
thread->push(n_args);
|
2004-09-21 06:35:00 +00:00
|
|
|
// NOTE: The original pushes the program
|
|
|
|
// counter as a pointer here. But I don't think
|
|
|
|
// we will have to do that.
|
2004-09-23 06:46:44 +00:00
|
|
|
thread->push(data);
|
2004-04-12 21:40:49 +00:00
|
|
|
thread->i_offset = (unsigned long)param1;
|
|
|
|
}
|
|
|
|
break;
|
2005-01-03 21:17:32 +00:00
|
|
|
case opCcall: // Call function
|
|
|
|
case opCcallV: { // Call function and discard return value
|
2004-12-22 21:04:50 +00:00
|
|
|
int argumentsCount;
|
|
|
|
uint16 functionNumber;
|
|
|
|
int scriptFunctionReturnValue;
|
|
|
|
ScriptFunctionType scriptFunction;
|
|
|
|
|
|
|
|
argumentsCount = scriptS.readByte();
|
|
|
|
functionNumber = scriptS.readUint16LE();
|
|
|
|
if (functionNumber >= SCRIPT_FUNCTION_MAX) {
|
2005-01-03 21:17:32 +00:00
|
|
|
scriptError(thread, "Invalid script function number");
|
|
|
|
return;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2004-12-24 11:11:01 +00:00
|
|
|
debug(9, "opCCall* Calling 0x%X %s", functionNumber, _scriptFunctionsList[functionNumber].scriptFunctionName);
|
|
|
|
scriptFunction = _scriptFunctionsList[functionNumber].scriptFunction;
|
2004-12-22 21:04:50 +00:00
|
|
|
scriptFunctionReturnValue = (this->*scriptFunction)(thread, argumentsCount);
|
|
|
|
if (scriptFunctionReturnValue != SUCCESS) {
|
|
|
|
_vm->_console->DebugPrintf(S_WARN_PREFIX "%X: Script function %d failed.\n", thread->i_offset, scriptFunctionReturnValue);
|
2004-11-06 22:33:08 +00:00
|
|
|
}
|
2004-10-03 17:11:23 +00:00
|
|
|
|
2004-12-22 21:04:50 +00:00
|
|
|
if (functionNumber == 16) { // SF_gotoScene
|
2004-11-06 22:33:08 +00:00
|
|
|
instr_count = instr_limit; // break the loop
|
|
|
|
break;
|
|
|
|
}
|
2004-10-27 02:27:54 +00:00
|
|
|
|
2005-01-03 21:17:32 +00:00
|
|
|
if (operandChar == opCcall) // CALL function
|
2004-11-06 22:33:08 +00:00
|
|
|
thread->push(thread->retVal);
|
2004-10-27 02:27:54 +00:00
|
|
|
|
2004-11-06 22:33:08 +00:00
|
|
|
if (thread->flags & kTFlagAsleep)
|
|
|
|
instr_count = instr_limit; // break out of loop!
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
break;
|
2005-01-03 21:17:32 +00:00
|
|
|
case opEnter: // Enter a function
|
2004-10-03 17:11:23 +00:00
|
|
|
thread->push(thread->framePtr);
|
2004-10-09 07:39:46 +00:00
|
|
|
setFramePtr(thread, thread->stackPtr);
|
2004-08-22 18:28:42 +00:00
|
|
|
param1 = scriptS.readUint16LE();
|
2004-10-03 17:11:23 +00:00
|
|
|
thread->stackPtr -= (param1 / 2);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2005-01-03 21:17:32 +00:00
|
|
|
case opReturn: // Return with value
|
2004-10-03 17:11:23 +00:00
|
|
|
scriptRetVal = thread->pop();
|
2005-01-03 21:17:32 +00:00
|
|
|
case opReturnV: // Return with void
|
2004-10-03 17:11:23 +00:00
|
|
|
thread->stackPtr = thread->framePtr;
|
2004-10-09 07:39:46 +00:00
|
|
|
setFramePtr(thread, thread->pop());
|
2004-09-23 06:46:44 +00:00
|
|
|
if (thread->stackSize() == 0) {
|
2004-12-03 19:15:44 +00:00
|
|
|
_vm->_console->DebugPrintf("Script execution complete.\n");
|
2004-10-27 02:27:54 +00:00
|
|
|
thread->flags |= kTFlagFinished;
|
2005-01-03 21:17:32 +00:00
|
|
|
return;
|
2004-04-12 21:40:49 +00:00
|
|
|
} else {
|
2004-10-03 17:11:23 +00:00
|
|
|
thread->i_offset = thread->pop();
|
2004-09-23 06:46:44 +00:00
|
|
|
/* int n_args = */ thread->pop();
|
2005-01-03 21:17:32 +00:00
|
|
|
if (operandChar == opReturn)
|
2004-10-03 17:11:23 +00:00
|
|
|
thread->push(scriptRetVal);
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2004-05-01 16:15:55 +00:00
|
|
|
// BRANCH INSTRUCTIONS
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-05-01 16:15:55 +00:00
|
|
|
// (JMP): Unconditional jump
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x1D:
|
2004-08-22 18:28:42 +00:00
|
|
|
param1 = scriptS.readUint16LE();
|
2004-04-12 21:40:49 +00:00
|
|
|
thread->i_offset = (unsigned long)param1;
|
|
|
|
break;
|
2004-05-01 16:15:55 +00:00
|
|
|
// (JNZP): Jump if nonzero + POP
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x1E:
|
2004-08-22 18:28:42 +00:00
|
|
|
param1 = scriptS.readUint16LE();
|
2004-09-23 06:46:44 +00:00
|
|
|
data = thread->pop();
|
2004-04-12 21:40:49 +00:00
|
|
|
if (data) {
|
|
|
|
thread->i_offset = (unsigned long)param1;
|
|
|
|
}
|
|
|
|
break;
|
2004-05-01 16:15:55 +00:00
|
|
|
// (JZP): Jump if zero + POP
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x1F:
|
2004-08-22 18:28:42 +00:00
|
|
|
param1 = scriptS.readUint16LE();
|
2004-09-23 06:46:44 +00:00
|
|
|
data = thread->pop();
|
2004-04-12 21:40:49 +00:00
|
|
|
if (!data) {
|
|
|
|
thread->i_offset = (unsigned long)param1;
|
|
|
|
}
|
|
|
|
break;
|
2004-05-01 16:15:55 +00:00
|
|
|
// (JNZ): Jump if nonzero
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x20:
|
2004-08-22 18:28:42 +00:00
|
|
|
param1 = scriptS.readUint16LE();
|
2004-09-23 06:46:44 +00:00
|
|
|
data = thread->stackTop();
|
2004-04-12 21:40:49 +00:00
|
|
|
if (data) {
|
|
|
|
thread->i_offset = (unsigned long)param1;
|
|
|
|
}
|
|
|
|
break;
|
2004-05-01 16:15:55 +00:00
|
|
|
// (JZ): Jump if zero
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x21:
|
2004-08-22 18:28:42 +00:00
|
|
|
param1 = scriptS.readUint16LE();
|
2004-09-23 06:46:44 +00:00
|
|
|
data = thread->stackTop();
|
2004-04-12 21:40:49 +00:00
|
|
|
if (!data) {
|
|
|
|
thread->i_offset = (unsigned long)param1;
|
|
|
|
}
|
|
|
|
break;
|
2004-05-01 16:15:55 +00:00
|
|
|
// (SWCH): Switch
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x22:
|
|
|
|
{
|
|
|
|
int n_switch;
|
|
|
|
unsigned int switch_num;
|
|
|
|
unsigned int switch_jmp;
|
|
|
|
unsigned int default_jmp;
|
|
|
|
int case_found = 0;
|
|
|
|
|
2004-09-23 06:46:44 +00:00
|
|
|
data = thread->pop();
|
2004-08-22 18:28:42 +00:00
|
|
|
n_switch = scriptS.readUint16LE();
|
2004-04-12 21:40:49 +00:00
|
|
|
for (i = 0; i < n_switch; i++) {
|
2004-08-22 18:28:42 +00:00
|
|
|
switch_num = scriptS.readUint16LE();
|
|
|
|
switch_jmp = scriptS.readUint16LE();
|
2004-05-01 16:15:55 +00:00
|
|
|
// Found the specified case
|
2004-12-22 21:04:50 +00:00
|
|
|
if (data == (ScriptDataWord) switch_num) {
|
2004-04-12 21:40:49 +00:00
|
|
|
thread->i_offset = switch_jmp;
|
|
|
|
case_found = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-05-01 16:15:55 +00:00
|
|
|
// Jump to default case
|
2004-04-12 21:40:49 +00:00
|
|
|
if (!case_found) {
|
2004-08-22 18:28:42 +00:00
|
|
|
default_jmp = scriptS.readUint16LE();
|
2004-04-12 21:40:49 +00:00
|
|
|
thread->i_offset = default_jmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2004-05-01 16:15:55 +00:00
|
|
|
// (RJMP): Random branch
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x24:
|
|
|
|
{
|
|
|
|
int n_branch;
|
|
|
|
unsigned int branch_wt;
|
|
|
|
unsigned int branch_jmp;
|
|
|
|
int rand_sel = 0;
|
|
|
|
int branch_found = 0;
|
|
|
|
|
2004-05-01 16:15:55 +00:00
|
|
|
// Ignored?
|
2004-08-22 18:28:42 +00:00
|
|
|
scriptS.readUint16LE();
|
|
|
|
n_branch = scriptS.readUint16LE();
|
2004-04-12 21:40:49 +00:00
|
|
|
for (i = 0; i < n_branch; i++) {
|
2004-08-22 18:28:42 +00:00
|
|
|
branch_wt = scriptS.readUint16LE();
|
|
|
|
branch_jmp = scriptS.readUint16LE();
|
2004-04-12 21:40:49 +00:00
|
|
|
if (rand_sel == i) {
|
|
|
|
thread->i_offset = branch_jmp;
|
|
|
|
branch_found = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!branch_found) {
|
2004-12-03 19:15:44 +00:00
|
|
|
_vm->_console->DebugPrintf(S_ERROR_PREFIX "%X: Random jump target out of bounds.\n", thread->i_offset);
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2004-08-26 23:28:10 +00:00
|
|
|
// UNARY INSTRUCTIONS
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-05-01 16:15:55 +00:00
|
|
|
// (NEG) Negate stack by 2's complement
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x25:
|
2004-09-23 06:46:44 +00:00
|
|
|
data = thread->pop();
|
2004-04-12 21:40:49 +00:00
|
|
|
data = ~data;
|
|
|
|
data++;
|
2004-09-23 06:46:44 +00:00
|
|
|
thread->push(data);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-05-01 16:15:55 +00:00
|
|
|
// (TSTZ) Test for zero
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x26:
|
2004-09-23 06:46:44 +00:00
|
|
|
data = thread->pop();
|
2004-04-12 21:40:49 +00:00
|
|
|
data = data ? 0 : 1;
|
2004-09-23 06:46:44 +00:00
|
|
|
thread->push(data);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-05-01 16:15:55 +00:00
|
|
|
// (NOT) Binary not
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x27:
|
2004-09-23 06:46:44 +00:00
|
|
|
data = thread->pop();
|
2004-04-12 21:40:49 +00:00
|
|
|
data = ~data;
|
2004-09-23 06:46:44 +00:00
|
|
|
thread->push(data);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-08-26 23:28:10 +00:00
|
|
|
case 0x28: // inc_v increment, don't push
|
2004-04-12 21:40:49 +00:00
|
|
|
unhandled = 1;
|
2004-10-28 06:55:50 +00:00
|
|
|
//debug(2, "??? ");
|
2004-08-22 18:28:42 +00:00
|
|
|
scriptS.readByte();
|
|
|
|
scriptS.readUint16LE();
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-08-26 23:28:10 +00:00
|
|
|
case 0x29: // dec_v decrement, don't push
|
2004-04-12 21:40:49 +00:00
|
|
|
unhandled = 1;
|
2004-10-28 06:55:50 +00:00
|
|
|
//debug(2, "??? ");
|
2004-08-22 18:28:42 +00:00
|
|
|
scriptS.readByte();
|
|
|
|
scriptS.readUint16LE();
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-08-26 23:28:10 +00:00
|
|
|
case 0x2A: // postinc
|
2004-04-12 21:40:49 +00:00
|
|
|
unhandled = 1;
|
2004-10-28 06:55:50 +00:00
|
|
|
//debug(2, "??? ");
|
2004-08-22 18:28:42 +00:00
|
|
|
scriptS.readByte();
|
|
|
|
scriptS.readUint16LE();
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-08-26 23:28:10 +00:00
|
|
|
case 0x2B: // postdec
|
2004-04-12 21:40:49 +00:00
|
|
|
unhandled = 1;
|
2004-10-28 06:55:50 +00:00
|
|
|
//debug(2, "??? ");
|
2004-08-22 18:28:42 +00:00
|
|
|
scriptS.readByte();
|
|
|
|
scriptS.readUint16LE();
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
|
|
|
|
2004-05-01 16:15:55 +00:00
|
|
|
// ARITHMETIC INSTRUCTIONS
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-05-01 16:15:55 +00:00
|
|
|
// (ADD): Addition
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x2C:
|
2004-09-23 06:46:44 +00:00
|
|
|
param2 = thread->pop();
|
|
|
|
param1 = thread->pop();
|
2004-04-12 21:40:49 +00:00
|
|
|
iparam2 = (long)param2;
|
|
|
|
iparam1 = (long)param1;
|
|
|
|
iresult = iparam1 + iparam2;
|
2004-12-22 21:04:50 +00:00
|
|
|
thread->push((ScriptDataWord) iresult);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-05-01 16:15:55 +00:00
|
|
|
// (SUB): Subtraction
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x2D:
|
2004-09-23 06:46:44 +00:00
|
|
|
param2 = thread->pop();
|
|
|
|
param1 = thread->pop();
|
2004-04-12 21:40:49 +00:00
|
|
|
iparam2 = (long)param2;
|
|
|
|
iparam1 = (long)param1;
|
|
|
|
iresult = iparam1 - iparam2;
|
2004-12-22 21:04:50 +00:00
|
|
|
thread->push((ScriptDataWord) iresult);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-05-01 16:15:55 +00:00
|
|
|
// (MULT): Integer multiplication
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x2E:
|
2004-09-23 06:46:44 +00:00
|
|
|
param2 = thread->pop();
|
|
|
|
param1 = thread->pop();
|
2004-04-12 21:40:49 +00:00
|
|
|
iparam2 = (long)param2;
|
|
|
|
iparam1 = (long)param1;
|
|
|
|
iresult = iparam1 * iparam2;
|
2004-12-22 21:04:50 +00:00
|
|
|
thread->push((ScriptDataWord) iresult);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-05-13 01:41:23 +00:00
|
|
|
// (DIV): Integer division
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x2F:
|
2004-09-23 06:46:44 +00:00
|
|
|
param2 = thread->pop();
|
|
|
|
param1 = thread->pop();
|
2004-04-12 21:40:49 +00:00
|
|
|
iparam2 = (long)param2;
|
|
|
|
iparam1 = (long)param1;
|
|
|
|
iresult = iparam1 / iparam2;
|
2004-12-22 21:04:50 +00:00
|
|
|
thread->push((ScriptDataWord) iresult);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-05-01 16:15:55 +00:00
|
|
|
// (MOD) Modulus
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x30:
|
2004-09-23 06:46:44 +00:00
|
|
|
param2 = thread->pop();
|
|
|
|
param1 = thread->pop();
|
2004-04-12 21:40:49 +00:00
|
|
|
iparam2 = (long)param2;
|
|
|
|
iparam1 = (long)param1;
|
|
|
|
iresult = iparam1 % iparam2;
|
2004-12-22 21:04:50 +00:00
|
|
|
thread->push((ScriptDataWord) iresult);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-05-01 16:15:55 +00:00
|
|
|
// (EQU) Test equality
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x33:
|
2004-09-23 06:46:44 +00:00
|
|
|
param2 = thread->pop();
|
|
|
|
param1 = thread->pop();
|
2004-04-12 21:40:49 +00:00
|
|
|
iparam2 = (long)param2;
|
|
|
|
iparam1 = (long)param1;
|
|
|
|
data = (iparam1 == iparam2) ? 1 : 0;
|
2004-09-23 06:46:44 +00:00
|
|
|
thread->push(data);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-05-01 16:15:55 +00:00
|
|
|
// (NEQU) Test inequality
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x34:
|
2004-09-23 06:46:44 +00:00
|
|
|
param2 = thread->pop();
|
|
|
|
param1 = thread->pop();
|
2004-04-12 21:40:49 +00:00
|
|
|
iparam2 = (long)param2;
|
|
|
|
iparam1 = (long)param1;
|
|
|
|
data = (iparam1 != iparam2) ? 1 : 0;
|
2004-09-23 06:46:44 +00:00
|
|
|
thread->push(data);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-05-01 16:15:55 +00:00
|
|
|
// (GRT) Test Greater-than
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x35:
|
2004-09-23 06:46:44 +00:00
|
|
|
param2 = thread->pop();
|
|
|
|
param1 = thread->pop();
|
2004-04-12 21:40:49 +00:00
|
|
|
iparam2 = (long)param2;
|
|
|
|
iparam1 = (long)param1;
|
|
|
|
data = (iparam1 > iparam2) ? 1 : 0;
|
2004-09-23 06:46:44 +00:00
|
|
|
thread->push(data);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-05-01 16:15:55 +00:00
|
|
|
// (LST) Test Less-than
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x36:
|
2004-09-23 06:46:44 +00:00
|
|
|
param2 = thread->pop();
|
|
|
|
param1 = thread->pop();
|
2004-04-12 21:40:49 +00:00
|
|
|
iparam2 = (long)param2;
|
|
|
|
iparam1 = (long)param1;
|
|
|
|
data = (iparam1 < iparam2) ? 1 : 0;
|
2004-09-23 06:46:44 +00:00
|
|
|
thread->push(data);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-05-01 16:15:55 +00:00
|
|
|
// (GRTE) Test Greater-than or Equal to
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x37:
|
2004-09-23 06:46:44 +00:00
|
|
|
param2 = thread->pop();
|
|
|
|
param1 = thread->pop();
|
2004-04-12 21:40:49 +00:00
|
|
|
iparam2 = (long)param2;
|
|
|
|
iparam1 = (long)param1;
|
|
|
|
data = (iparam1 >= iparam2) ? 1 : 0;
|
2004-09-23 06:46:44 +00:00
|
|
|
thread->push(data);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-05-01 16:15:55 +00:00
|
|
|
// (LSTE) Test Less-than or Equal to
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x38:
|
2004-09-23 06:46:44 +00:00
|
|
|
param2 = thread->pop();
|
|
|
|
param1 = thread->pop();
|
2004-04-12 21:40:49 +00:00
|
|
|
iparam2 = (long)param2;
|
|
|
|
iparam1 = (long)param1;
|
|
|
|
data = (iparam1 <= iparam2) ? 1 : 0;
|
2004-09-23 06:46:44 +00:00
|
|
|
thread->push(data);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-05-13 01:41:23 +00:00
|
|
|
|
|
|
|
// BITWISE INSTRUCTIONS
|
|
|
|
|
2004-05-01 16:15:55 +00:00
|
|
|
// (SHR): Arithmetic binary shift right
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x3F:
|
2004-09-23 06:46:44 +00:00
|
|
|
param2 = thread->pop();
|
|
|
|
param1 = thread->pop();
|
2004-04-12 21:40:49 +00:00
|
|
|
iparam2 = (long)param2;
|
2004-05-01 16:15:55 +00:00
|
|
|
// Preserve most significant bit
|
2005-01-02 14:52:11 +00:00
|
|
|
data = (0x01 << ((sizeof(param1) * CHAR_BIT) - 1)) & param1;
|
2004-04-12 21:40:49 +00:00
|
|
|
for (i = 0; i < (int)iparam2; i++) {
|
|
|
|
param1 >>= 1;
|
|
|
|
param1 |= data;
|
|
|
|
}
|
2004-09-23 06:46:44 +00:00
|
|
|
thread->push(param1);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-05-01 16:15:55 +00:00
|
|
|
// (SHL) Binary shift left
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x40:
|
2004-09-23 06:46:44 +00:00
|
|
|
param2 = thread->pop();
|
|
|
|
param1 = thread->pop();
|
2004-04-12 21:40:49 +00:00
|
|
|
param1 <<= param2;
|
2004-09-23 06:46:44 +00:00
|
|
|
thread->push(param1);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-05-01 16:15:55 +00:00
|
|
|
// (AND) Binary AND
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x41:
|
2004-09-23 06:46:44 +00:00
|
|
|
param2 = thread->pop();
|
|
|
|
param1 = thread->pop();
|
2004-04-12 21:40:49 +00:00
|
|
|
param1 &= param2;
|
2004-09-23 06:46:44 +00:00
|
|
|
thread->push(param1);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-05-01 16:15:55 +00:00
|
|
|
// (OR) Binary OR
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x42:
|
2004-09-23 06:46:44 +00:00
|
|
|
param2 = thread->pop();
|
|
|
|
param1 = thread->pop();
|
2004-04-12 21:40:49 +00:00
|
|
|
param1 |= param2;
|
2004-09-23 06:46:44 +00:00
|
|
|
thread->push(param1);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-05-01 16:15:55 +00:00
|
|
|
// (XOR) Binary XOR
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x43:
|
2004-09-23 06:46:44 +00:00
|
|
|
param2 = thread->pop();
|
|
|
|
param1 = thread->pop();
|
2004-04-12 21:40:49 +00:00
|
|
|
param1 ^= param2;
|
2004-09-23 06:46:44 +00:00
|
|
|
thread->push(param1);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
|
|
|
|
2004-05-01 16:15:55 +00:00
|
|
|
// BOOLEAN LOGIC INSTRUCTIONS
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-05-01 16:15:55 +00:00
|
|
|
// (LAND): Logical AND
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x44:
|
2004-09-23 06:46:44 +00:00
|
|
|
param2 = thread->pop();
|
|
|
|
param1 = thread->pop();
|
2004-04-12 21:40:49 +00:00
|
|
|
data = (param1 && param2) ? 1 : 0;
|
2004-09-23 06:46:44 +00:00
|
|
|
thread->push(data);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-05-01 16:15:55 +00:00
|
|
|
// (LOR): Logical OR
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x45:
|
2004-09-23 06:46:44 +00:00
|
|
|
param2 = thread->pop();
|
|
|
|
param1 = thread->pop();
|
2004-04-12 21:40:49 +00:00
|
|
|
data = (param1 || param2) ? 1 : 0;
|
2004-09-23 06:46:44 +00:00
|
|
|
thread->push(data);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-05-01 16:15:55 +00:00
|
|
|
// (LXOR): Logical XOR
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x46:
|
2004-09-23 06:46:44 +00:00
|
|
|
param2 = thread->pop();
|
|
|
|
param1 = thread->pop();
|
2004-04-12 21:40:49 +00:00
|
|
|
data = ((param1) ? !(param2) : !!(param2));
|
2004-09-23 06:46:44 +00:00
|
|
|
thread->push(data);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
|
|
|
|
2004-05-01 16:15:55 +00:00
|
|
|
// GAME INSTRUCTIONS
|
2004-12-22 21:04:50 +00:00
|
|
|
case opSpeak: { // (opSpeak): Play Character Speech
|
2004-12-21 06:49:07 +00:00
|
|
|
int stringsCount;
|
2004-12-17 11:18:56 +00:00
|
|
|
uint16 actorId;
|
2004-12-21 06:49:07 +00:00
|
|
|
int speechFlags;
|
|
|
|
int sampleResourceId = -1;
|
|
|
|
int first;
|
|
|
|
const char *strings[ACTOR_SPEECH_STRING_MAX];
|
|
|
|
|
|
|
|
if (_vm->_actor->isSpeaking()) {
|
|
|
|
thread->wait(kWaitTypeSpeech);
|
2005-01-03 21:17:32 +00:00
|
|
|
return;
|
2004-12-21 06:49:07 +00:00
|
|
|
}
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-12-21 06:49:07 +00:00
|
|
|
stringsCount = scriptS.readByte();
|
|
|
|
actorId = scriptS.readUint16LE();
|
|
|
|
speechFlags = scriptS.readByte();
|
|
|
|
scriptS.readUint16LE(); // x,y skip
|
|
|
|
|
|
|
|
if (stringsCount == 0)
|
|
|
|
error("opSpeak stringsCount == 0");
|
|
|
|
|
2004-12-22 21:04:50 +00:00
|
|
|
if (stringsCount > ACTOR_SPEECH_STRING_MAX)
|
2004-12-21 06:49:07 +00:00
|
|
|
error("opSpeak stringsCount=0x%X exceed ACTOR_SPEECH_STRING_MAX", stringsCount);
|
|
|
|
|
|
|
|
data = first = thread->stackTop();
|
|
|
|
for (i = 0; i < stringsCount; i++) {
|
|
|
|
data = thread->pop();
|
|
|
|
strings[i] = getString(data);
|
|
|
|
}
|
|
|
|
// now data contains last string index
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-12-22 19:34:41 +00:00
|
|
|
if (_vm->_gameId == GID_ITE_DISK_G) { // special ITE dos
|
2004-12-22 21:04:50 +00:00
|
|
|
if ((_vm->_scene->currentSceneNumber() == ITE_DEFAULT_SCENE) && (data >= 288) && (data <= (RID_SCENE1_VOICE_138 - RID_SCENE1_VOICE_009 + 288))) {
|
|
|
|
sampleResourceId = RID_SCENE1_VOICE_009 + data - 288;
|
2004-12-21 06:49:07 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (isVoiceLUTPresent()) {
|
|
|
|
if (currentScript()->voice->n_voices > first) {
|
|
|
|
sampleResourceId = currentScript()->voice->voices[first];
|
|
|
|
}
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
2004-12-21 06:49:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
_vm->_actor->actorSpeech(actorId, strings, stringsCount, sampleResourceId, speechFlags);
|
|
|
|
|
|
|
|
if (!(speechFlags & kSpeakAsync)) {
|
|
|
|
thread->wait(kWaitTypeSpeech);
|
2005-01-05 07:13:15 +00:00
|
|
|
thread->i_offset = scriptS.pos();
|
2005-01-03 21:17:32 +00:00
|
|
|
return;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2004-05-01 16:15:55 +00:00
|
|
|
// (DLGS): Initialize dialogue interface
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x54:
|
2004-08-26 23:28:10 +00:00
|
|
|
warning("dialog_begin opcode: stub");
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-05-01 16:15:55 +00:00
|
|
|
// (DLGX): Run dialogue interface
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x55:
|
2004-08-26 23:28:10 +00:00
|
|
|
warning("dialog_end opcode: stub");
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-05-01 16:15:55 +00:00
|
|
|
// (DLGO): Add a dialogue option to interface
|
2004-04-12 21:40:49 +00:00
|
|
|
case 0x56:
|
|
|
|
{
|
2004-12-22 21:04:50 +00:00
|
|
|
ScriptDataWord param3 = 0;
|
2004-10-03 17:11:23 +00:00
|
|
|
param1 = scriptS.readByte();
|
|
|
|
param2 = scriptS.readByte();
|
2004-11-14 13:15:26 +00:00
|
|
|
if (param2 & 1) {
|
2004-10-28 06:55:50 +00:00
|
|
|
param3 = scriptS.readUint16LE();
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
2004-10-28 06:55:50 +00:00
|
|
|
debug(2, "DLGO | %02X %02X %04X", param1, param2, param3);
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
break;
|
2004-08-26 23:28:10 +00:00
|
|
|
case 0x57: // animate
|
|
|
|
scriptS.readUint16LE();
|
|
|
|
scriptS.readUint16LE();
|
|
|
|
iparam1 = (long)scriptS.readByte();
|
|
|
|
thread->i_offset += iparam1;
|
|
|
|
break;
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-05-01 16:15:55 +00:00
|
|
|
// End instruction list
|
2004-04-12 21:40:49 +00:00
|
|
|
|
|
|
|
default:
|
2005-01-03 21:17:32 +00:00
|
|
|
scriptError(thread, "Invalid opcode encountered");
|
|
|
|
return;
|
2004-05-01 16:15:55 +00:00
|
|
|
}
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-05-01 16:15:55 +00:00
|
|
|
// Set instruction offset only if a previous instruction didn't branch
|
2004-04-12 21:40:49 +00:00
|
|
|
if (saved_offset == thread->i_offset) {
|
2004-08-22 18:28:42 +00:00
|
|
|
thread->i_offset = scriptS.pos();
|
2004-09-19 14:49:00 +00:00
|
|
|
} else {
|
2004-12-15 00:24:12 +00:00
|
|
|
if (thread->i_offset >= scriptS.size()) {
|
2005-01-03 21:17:32 +00:00
|
|
|
scriptError(thread, "Out of range script execution");
|
|
|
|
return;
|
|
|
|
} else {
|
2004-12-15 00:24:12 +00:00
|
|
|
scriptS.seek(thread->i_offset);
|
2005-01-03 21:17:32 +00:00
|
|
|
}
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
2005-01-03 21:17:32 +00:00
|
|
|
|
|
|
|
if (unhandled) { // TODO: remove it
|
|
|
|
scriptError(thread, "Unhandled opcode");
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} // End of namespace Saga
|
|
|
|
|