scummvm/scumm/script_v8.cpp

1988 lines
48 KiB
C++

/* ScummVM - Scumm Interpreter
* Copyright (C) 2002 The ScummVM project
*
* 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$
*
*/
#include "stdafx.h"
#include "scumm.h"
#include "actor.h"
#include "charset.h"
#include "intern.h"
#include "sound.h"
#include "verbs.h"
#include "smush/player.h"
#include "smush/scumm_renderer.h"
/*
* NO, we do NOT support CMI yet :-) This file is mostly a placeholder and a place
* to grow real support in. For now, only a few opcodes are implemented, and they
* might even be wrong... so don't hold your breath.
*/
#define OPCODE(x) { &Scumm_v8::x, #x }
void Scumm_v8::setupOpcodes()
{
// TODO: any of the o6_ entries are potentially wrong and pure guesses :-)
static const OpcodeEntryV8 opcodes[256] = {
/* 00 */
OPCODE(o6_invalid),
OPCODE(o6_pushWord),
OPCODE(o6_pushWordVar),
OPCODE(o6_wordArrayRead),
/* 04 */
OPCODE(o6_wordArrayIndexedRead),
OPCODE(o6_dup),
OPCODE(o6_pop),
OPCODE(o6_not),
/* 08 */
OPCODE(o6_eq),
OPCODE(o6_neq),
OPCODE(o6_gt),
OPCODE(o6_lt),
/* 0C */
OPCODE(o6_le),
OPCODE(o6_ge),
OPCODE(o6_add),
OPCODE(o6_sub),
/* 10 */
OPCODE(o6_mul),
OPCODE(o6_div),
OPCODE(o6_land),
OPCODE(o6_lor),
/* 14 */
OPCODE(o6_band),
OPCODE(o6_bor),
OPCODE(o8_mod),
OPCODE(o6_invalid),
/* 18 */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* 1C */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* 20 */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* 24 */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* 28 */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* 2C */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* 30 */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* 34 */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* 38 */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* 3C */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* 40 */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* 44 */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* 48 */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* 4C */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* 50 */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* 54 */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* 58 */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* 5C */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* 60 */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* 64 */
OPCODE(o6_jumpTrue),
OPCODE(o6_jumpFalse),
OPCODE(o6_jump),
OPCODE(o6_breakHere),
/* 68 */
OPCODE(o6_delayFrames),
OPCODE(o8_wait),
OPCODE(o6_delay),
OPCODE(o6_delaySeconds),
/* 6C */
OPCODE(o6_delayMinutes),
OPCODE(o6_writeWordVar),
OPCODE(o6_wordVarInc),
OPCODE(o6_wordVarDec),
/* 70 */
OPCODE(o8_dim),
OPCODE(o6_wordArrayWrite),
OPCODE(o6_wordArrayInc),
OPCODE(o6_wordArrayDec),
/* 74 */
OPCODE(o8_dim2),
OPCODE(o6_wordArrayIndexedWrite),
OPCODE(o8_arrayOps),
OPCODE(o6_invalid),
/* 78 */
OPCODE(o6_invalid),
OPCODE(o6_startScriptEx),
OPCODE(o6_startScriptQuick),
OPCODE(o6_stopObjectCode),
/* 7C */
OPCODE(o6_stopScript),
OPCODE(o6_jumpToScript), // FIXME - is this right? "O_CHAIN_SCRIPT"
OPCODE(o6_dummy), // FIXME - O_RETURN ? WTF is this, why don't they use the stack?
OPCODE(o6_startObject),
/* 80 */
OPCODE(o6_stopObjectScript), // FIXME - is this right?
OPCODE(o6_cutscene),
OPCODE(o6_endCutscene),
OPCODE(o6_freezeUnfreeze),
/* 84 */
OPCODE(o6_beginOverride),
OPCODE(o6_endOverride),
OPCODE(o6_stopSentence),
OPCODE(o6_invalid),
/* 88 */
OPCODE(o6_invalid),
OPCODE(o6_setClass),
OPCODE(o6_setState),
OPCODE(o6_setOwner),
/* 8C */
OPCODE(o6_panCameraTo),
OPCODE(o6_actorFollowCamera),
OPCODE(o6_setCameraAt),
OPCODE(o6_printActor),
/* 90 */
OPCODE(o6_printEgo),
OPCODE(o6_talkActor),
OPCODE(o6_talkEgo),
OPCODE(o8_printLine),
/* 94 */
OPCODE(o8_printCursor),
OPCODE(o8_printDebug),
OPCODE(o8_printSystem),
OPCODE(o8_blastText),
/* 98 */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* 9C */
OPCODE(o8_cursorCommand),
OPCODE(o6_loadRoom),
OPCODE(o6_loadRoomWithEgo), // FIXME - this is a pure guess
OPCODE(o6_walkActorToObj),
/* A0 */
OPCODE(o6_walkActorTo),
OPCODE(o6_putActorInRoom), // FIXME - this seems to be wrong? at least we get actor indices from 31 to 79 here...
OPCODE(o6_putActorAtObject),
OPCODE(o6_faceActor),
/* A4 */
OPCODE(o6_animateActor),
OPCODE(o6_doSentence),
OPCODE(o6_pickupObject),
OPCODE(o6_setBoxFlags),
/* A8 */
OPCODE(o6_createBoxMatrix), // fixme?
OPCODE(o6_invalid),
OPCODE(o8_resourceRoutines),
OPCODE(o8_roomOps),
/* AC */
OPCODE(o8_actorOps),
OPCODE(o8_cameraOps),
OPCODE(o8_verbOps),
OPCODE(o6_startSound),
/* B0 */
OPCODE(o6_startMusic),
OPCODE(o6_stopSound),
OPCODE(o8_soundKludge),
OPCODE(o8_system),
/* B4 */
OPCODE(o6_saveRestoreVerbs),
OPCODE(o6_setObjectName),
OPCODE(o6_invalid),
OPCODE(o6_drawBox),
/* B8 */
OPCODE(o6_invalid),
OPCODE(o8_startVideo),
OPCODE(o6_kernelSetFunctions),
OPCODE(o6_invalid),
/* BC */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* C0 */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* C4 */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* C8 */
OPCODE(o6_startScript), // FIXME - this function returns something in V8 !
OPCODE(o6_startObject),
OPCODE(o6_pickOneOf),
OPCODE(o6_pickOneOfDefault),
/* CC */
OPCODE(o6_invalid),
OPCODE(o6_isAnyOf),
OPCODE(o6_getRandomNumber),
OPCODE(o6_getRandomNumberRange),
/* D0 */
OPCODE(o6_ifClassOfIs), // FIXME - this is a guess
OPCODE(o6_getState),
OPCODE(o6_getOwner),
OPCODE(o6_isScriptRunning),
/* D4 */
OPCODE(o6_invalid),
OPCODE(o6_isSoundRunning),
OPCODE(o6_abs),
OPCODE(o6_invalid),
/* D8 */
OPCODE(o6_kernelGetFunctions),
OPCODE(o6_isActorInBox),
OPCODE(o6_getVerbEntrypoint),
OPCODE(o6_getActorFromXY),
/* DC */
OPCODE(o6_findObject),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_findInventory),
/* E0 */
OPCODE(o6_getInventoryCount),
OPCODE(o6_getAnimateVariable),
OPCODE(o6_getActorRoom),
OPCODE(o6_getActorWalkBox),
/* E4 */
OPCODE(o6_getActorMoving),
OPCODE(o6_getActorCostume),
OPCODE(o6_getActorScaleX),
OPCODE(o6_getActorLayer),
/* E8 */
OPCODE(o6_getActorElevation),
OPCODE(o6_getActorWidth),
OPCODE(o6_getObjectNewDir), // FIXME: is this right?
OPCODE(o6_getObjectX),
/* EC */
OPCODE(o6_getObjectY),
OPCODE(o6_getActorAnimCounter1),
OPCODE(o6_distObjectObject),
OPCODE(o6_distPtPt),
/* F0 */
OPCODE(o8_getObjectImageX),
OPCODE(o8_getObjectImageY),
OPCODE(o8_getObjectImageWidth),
OPCODE(o8_getObjectImageHeight),
/* F4 */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* F8 */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* FC */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
};
_opcodesV8 = opcodes;
}
void Scumm_v8::executeOpcode(int i)
{
OpcodeProcV8 op = _opcodesV8[i].proc;
(this->*op) ();
}
const char *Scumm_v8::getOpcodeDesc(int i)
{
return _opcodesV8[i].desc;
}
// In V8, the word size is 4 byte, not 2 bytes as in V6/V7 games
uint Scumm_v8::fetchScriptWord()
{
int a;
if (*_lastCodePtr + sizeof(MemBlkHeader) != _scriptOrgPointer) {
uint32 oldoffs = _scriptPointer - _scriptOrgPointer;
getScriptBaseAddress();
_scriptPointer = _scriptOrgPointer + oldoffs;
}
a = READ_LE_UINT32(_scriptPointer);
_scriptPointer += 4;
return a;
}
int Scumm_v8::fetchScriptWordSigned()
{
return (int32)fetchScriptWord();
}
int Scumm_v8::readVar(uint var)
{
debug(9, "readvar(%d)", var);
if (!(var & 0xF0000000)) {
checkRange(_numVariables - 1, 0, var, "Variable %d out of range(r)");
return _vars[var];
}
if (var & 0x80000000) {
var &= 0x7FFFFFFF;
checkRange(_numBitVariables - 1, 0, var, "Bit variable %d out of range(r)");
return (_bitVars[var >> 3] & (1 << (var & 7))) ? 1 : 0;
}
if (var & 0x40000000) {
var &= 0xFFFFFFF;
checkRange(0x10, 0, var, "Local variable %d out of range(r)");
return vm.localvar[_currentScript][var];
}
error("Illegal varbits (r)");
return -1;
}
void Scumm_v8::writeVar(uint var, int value)
{
debug(9, "writeVar(%d, %d)", var, value);
if (!(var & 0xF0000000)) {
checkRange(_numVariables - 1, 0, var, "Variable %d out of range(w)");
_vars[var] = value;
if ((_varwatch == (int)var) || (_varwatch == 0)) {
if (vm.slot[_currentScript].number < 100)
debug(1, "vars[%d] = %d (via script-%d)", var, value, vm.slot[_currentScript].number);
else
debug(1, "vars[%d] = %d (via room-%d-%d)", var, value, _currentRoom, vm.slot[_currentScript].number);
}
return;
}
if (var & 0x80000000) {
var &= 0x7FFFFFFF;
checkRange(_numBitVariables - 1, 0, var, "Bit variable %d out of range(w)");
if (value)
_bitVars[var >> 3] |= (1 << (var & 7));
else
_bitVars[var >> 3] &= ~(1 << (var & 7));
return;
}
if (var & 0x40000000) {
var &= 0xFFFFFFF;
checkRange(0x10, 0, var, "Local variable %d out of range(w)");
vm.localvar[_currentScript][var] = value;
return;
}
error("Illegal varbits (w)");
}
void Scumm_v8::decodeParseString(int m, int n)
{
byte b;
b = fetchScriptByte();
switch (b) {
case 0xC8:
setStringVars(m);
if (n)
_actorToPrintStrFor = pop();
return;
case 0xC9:
_string[m].t_xpos = _string[m].xpos;
_string[m].t_ypos = _string[m].ypos;
_string[m].t_center = _string[m].center;
_string[m].t_overhead = _string[m].overhead;
_string[m].t_no_talk_anim = _string[m].no_talk_anim;
_string[m].t_right = _string[m].right;
_string[m].t_color = _string[m].color;
_string[m].t_charset = _string[m].charset;
return;
case 0xCA:
_string[m].ypos = pop();
_string[m].xpos = pop();
_string[m].overhead = false;
break;
case 0xCB:
_string[m].color = pop();
break;
case 0xCC:
_string[m].center = true;
_string[m].overhead = false;
break;
case 0xCD: { // SO_PRINT_CHARSET Set print character set
// FIXME - TODO
int charset = pop();
_string[m].charset = charset;
}
break;
case 0xCE:
_string[m].center = false;
_string[m].overhead = false;
break;
case 0xCF:
_string[m].overhead = true;
_string[m].no_talk_anim = false;
break;
case 0xD0: // SO_PRINT_MUMBLE
error("decodeParseString: SO_PRINT_MUMBLE");
break;
case 0xD1: {
#if 1
_messagePtr = _scriptPointer;
if (_messagePtr[0] == '/') {
char pointer[20];
int i, j;
_scriptPointer += resStrLen((char*)_scriptPointer)+ 1;
translateText(_messagePtr, _transText);
for (i = 0, j = 0; (_messagePtr[i] != '/' || j == 0) && j < 19; i++) {
if (_messagePtr[i] != '/')
pointer[j++] = _messagePtr[i];
}
pointer[j] = 0;
// Stop any talking that's still going on
if (_sound->_talkChannel > -1)
_mixer->stop(_sound->_talkChannel);
// _sound->_talkChannel = _sound->playBundleSound(pointer);
_messagePtr = _transText;
switch (m) {
case 0:
actorTalk();
break;
case 1:
drawString(1);
break;
case 2:
unkMessage1();
break;
case 3:
unkMessage2();
break;
}
return;
} else {
switch (m) {
case 0:
actorTalk();
break;
case 1:
drawString(1);
break;
case 2:
unkMessage1();
break;
case 3:
unkMessage2();
break;
}
_scriptPointer = _messagePtr;
return;
}
#else
char buffer[1024];
_messagePtr = _scriptPointer;
if (_messagePtr[0] == '/') {
char pointer[20];
int i, j;
// Skip over the string
_scriptPointer += resStrLen((char*)_scriptPointer) + 1;
translateText(_messagePtr, _transText);
for (i = 0, j = 0; (_messagePtr[i] != '/' || j == 0) && j < 19; i++) {
if (_messagePtr[i] != '/')
pointer[j++] = _messagePtr[i];
}
pointer[j] = 0;
// Stop any talking that's still going on
if (_sound->_talkChannel > -1)
_mixer->stop(_sound->_talkChannel);
// FIXME: no 'digvoice.bun' in COMI
_sound->_talkChannel = _sound->playBundleSound(pointer);
_messagePtr = _transText;
_msgPtrToAdd = (byte *)buffer;
_messagePtr = addMessageToStack(_messagePtr);
} else {
_msgPtrToAdd = (byte *)buffer;
_scriptPointer = _messagePtr = addMessageToStack(_messagePtr);
}
if (_fr[_string[m].charset] == NULL) // FIXME: Put this elsewhere?
loadCharset(_string[m].charset);
if (_fr[_string[m].charset] != NULL) {
int x = _string[m].xpos;
// HACK - center mode. I call this a hack because we really should
// not duplicate all the string code from string.cpp. Rather, maybe
// abstract away the code in string.cpp from using the 'charset'
// fonts, and allow it to work both with old and new fonts. To this
// end, we should seperate the parts of Charset/_charset which are
// for bookkeeping (like x_pos, center mode etc.) and those that are
// for rendering. Then let the old (think printCharOld), medium (printChar),
// new (NUT) style renderers be subclasses of a common base class (which
// defines the API). This will clean up the code, and allow us to reuse
// the string logic in string.cpp.
if (_string[m].center)
x -= _fr[_string[m].charset]->getStringWidth(buffer) / 2;
_fr[_string[m].charset]->drawString(buffer, x, _string[m].ypos, _string[m].color, 0);
}
#endif
break;
}
case 0xD2: // SO_PRINT_WRAP Set print wordwrap
error("decodeParseString: SO_PRINT_MUMBLE");
break;
default:
error("decodeParseString: default case");
}
}
void Scumm_v8::o8_mod()
{
int a = pop();
push(pop() % a);
}
void Scumm_v8::o8_wait()
{
// TODO
byte subOp = fetchScriptByte();
switch (subOp) {
case 0x1E: { // SO_WAIT_FOR_ACTOR Wait for actor (to finish current action?)
int offs = fetchScriptWordSigned();
if (derefActorSafe(pop(), "o8_wait:SO_WAIT_FOR_ACTOR")->moving) {
_scriptPointer += offs;
o6_breakHere();
}
return;
}
case 0x1F: // SO_WAIT_FOR_MESSAGE Wait for message
if (_vars[VAR_HAVE_MSG])
break;
return;
case 0x20: // SO_WAIT_FOR_CAMERA Wait for camera (to finish current action?)
if (camera._dest != camera._cur)
break;
return;
case 0x21: // SO_WAIT_FOR_SENTENCE
if (_sentenceNum) {
if (_sentence[_sentenceNum - 1].freezeCount && !isScriptInUse(_vars[VAR_SENTENCE_SCRIPT]))
return;
break;
}
if (!isScriptInUse(_vars[VAR_SENTENCE_SCRIPT]))
return;
break;
case 0x22: { // SO_WAIT_FOR_ANIMATION
int actnum = pop();
Actor *a = derefActorSafe(actnum, "o8_wait:SO_WAIT_FOR_ANIMATION");
int offs = fetchScriptWordSigned();
if (a && a->isInCurrentRoom() && a->needRedraw) {
_scriptPointer += offs;
o6_breakHere();
}
return;
}
case 0x23: { // SO_WAIT_FOR_TURN
int actnum = pop();
Actor *a = derefActorSafe(actnum, "o8_wait:SO_WAIT_FOR_TURN");
int offs = fetchScriptWordSigned();
if (a && a->isInCurrentRoom() && a->moving & MF_TURN) {
_scriptPointer += offs;
o6_breakHere();
}
return;
}
default:
error("o8_wait: default case %d", subOp);
}
_scriptPointer -= 2;
o6_breakHere();
}
void Scumm_v8::o8_dim()
{
byte subOp = fetchScriptByte();
int array = fetchScriptWord();
switch (subOp) {
case 0x0A: // SO_ARRAY_SCUMMVAR
defineArray(array, 5, 0, pop());
break;
case 0x0B: // SO_ARRAY_STRING
defineArray(array, 4, 0, pop());
break;
case 0x0C: // SO_ARRAY_UNDIM
nukeArray(array);
break;
default:
error("o8_dim: default case %d", subOp);
}
}
void Scumm_v8::o8_dim2()
{
byte subOp = fetchScriptByte();
int array = fetchScriptWord(), a, b;
switch (subOp) {
case 0x0A: // SO_ARRAY_SCUMMVAR
b = pop();
a = pop();
defineArray(array, 5, a, b);
break;
case 0x0B: // SO_ARRAY_STRING
b = pop();
a = pop();
defineArray(array, 4, a, b);
break;
case 0x0C: // SO_ARRAY_UNDIM
nukeArray(array);
break;
default:
error("o8_dim2: default case %d", subOp);
}
}
void Scumm_v8::o8_arrayOps()
{
byte subOp = fetchScriptByte();
int array = fetchScriptWord();
int b, c, d, len;
int list[128];
switch (subOp) {
case 0x14: // SO_ASSIGN_STRING
{
int idx = pop();
ArrayHeader *ah;
int r;
len = getStringLen(NULL);
r = defineArray(array, 4, 0, len);
ah = (ArrayHeader *)getResourceAddress(rtString, r);
copyString(ah->data + idx, NULL, len);
}
break;
case 0x15: // SO_ASSIGN_SCUMMVAR_LIST
// TODO / FIXME: is this right?
b = pop();
c = pop();
d = readVar(array);
if (d == 0) {
defineArray(array, 5, 0, b + c);
}
while (c--) {
writeArray(array, 0, b + c, pop());
}
break;
case 0x16: // SO_ASSIGN_2DIM_LIST
// TODO / FIXME: is this right?
b = pop();
len = getStackList(list, sizeof(list) / sizeof(list[0]));
d = readVar(array);
if (d == 0)
error("Must DIM a two dimensional array before assigning");
c = pop();
while (--len >= 0) {
writeArray(array, c, b + len, list[len]);
}
break;
default:
error("o8_arrayOps: default case %d (array %d)", subOp, array);
}
}
void Scumm_v8::o8_printLine()
{
// FIXME
decodeParseString(0, 0);
}
void Scumm_v8::o8_printCursor()
{
// FIXME
decodeParseString(1, 0);
}
void Scumm_v8::o8_printDebug()
{
// FIXME
decodeParseString(2, 0);
}
void Scumm_v8::o8_printSystem()
{
// FIXME
decodeParseString(3, 0);
}
void Scumm_v8::o8_blastText()
{
// FIXME
decodeParseString(1, 0);
}
void Scumm_v8::o8_cursorCommand()
{
// TODO
byte subOp = fetchScriptByte();
int a, i;
int args[16];
switch (subOp) {
case 0xDC: // SO_CURSOR_ON Turn cursor on
_cursor.state = 1;
verbMouseOver(0);
break;
case 0xDD: // SO_CURSOR_OFF Turn cursor off
_cursor.state = 0;
verbMouseOver(0);
break;
case 0xDE: // SO_CURSOR_SOFT_ON Turn soft cursor on
_cursor.state++;
if (_cursor.state > 1)
error("Cursor state greater than 1 in script");
verbMouseOver(0);
break;
case 0xDF: // SO_CURSOR_SOFT_OFF Turn soft cursor off
_cursor.state--;
verbMouseOver(0);
break;
case 0xE0: // SO_USERPUT_ON
_userPut = 1;
break;
case 0xE1: // SO_USERPUT_OFF
_userPut = 0;
break;
case 0xE2: // SO_USERPUT_SOFT_ON
_userPut++;
break;
case 0xE3: // SO_USERPUT_SOFT_OFF
_userPut--;
break;
case 0xE4: // SO_CURSOR_IMAGE Set cursor image
{
int idx = pop();
int room, obj;
obj = popRoomAndObj(&room);
setCursorImg(obj, room, idx);
}
break;
case 0xE5: // SO_CURSOR_HOTSPOT Set cursor hotspot
a = pop();
setCursorHotspot2(pop(), a);
break;
case 0xE6: // SO_CURSOR_TRANSPARENT Set cursor transparent color
makeCursorColorTransparent(pop());
break;
case 0xE7: { // SO_CHARSET_SET
int charset = pop();
warning("Set userface charset to %d\n", charset);
// loadCharset(charset);
break;
}
case 0xE8: // SO_CHARSET_COLOR
getStackList(args, sizeof(args) / sizeof(args[0]));
for (i = 0; i < 16; i++)
_charsetColorMap[i] = _charsetData[_string[1].t_charset][i] = (unsigned char)args[i];
break;
case 0xE9: // SO_CURSOR_PUT
default:
error("o8_cursorCommand: default case %d", subOp);
}
_vars[VAR_CURSORSTATE] = _cursor.state;
_vars[VAR_USERPUT] = _userPut;
}
void Scumm_v8::o8_resourceRoutines()
{
// TODO
byte subOp = fetchScriptByte();
int resid = pop();
switch (subOp) {
case 0x3C: // SO_HEAP_LOAD_CHARSET Load character set to heap
ensureResourceLoaded(rtCharset, resid); // FIXME - is this correct?
break;
case 0x3D: // SO_HEAP_LOAD_COSTUME Load costume to heap
ensureResourceLoaded(rtCostume, resid);
break;
case 0x3E: // SO_HEAP_LOAD_OBJECT Load object to heap
// TODO - is 'object' in COMI the same as FlObject in Sam&Max ?!?
break;
case 0x3F: // SO_HEAP_LOAD_ROOM Load room to heap
ensureResourceLoaded(rtRoom, resid);
break;
case 0x40: // SO_HEAP_LOAD_SCRIPT Load script to heap
ensureResourceLoaded(rtScript, resid);
break;
case 0x41: // SO_HEAP_LOAD_SOUND Load sound to heap
ensureResourceLoaded(rtSound, resid);
break;
case 0x42: // SO_HEAP_LOCK_COSTUME Lock costume in heap
lock(rtCostume, resid);
break;
case 0x43: // SO_HEAP_LOCK_ROOM Lock room in heap
lock(rtRoom, resid);
break;
case 0x44: // SO_HEAP_LOCK_SCRIPT Lock script in heap
lock(rtScript, resid);
break;
case 0x45: // SO_HEAP_LOCK_SOUND Lock sound in heap
lock(rtSound, resid);
break;
case 0x46: // SO_HEAP_UNLOCK_COSTUME Unlock costume
unlock(rtCostume, resid);
break;
case 0x47: // SO_HEAP_UNLOCK_ROOM Unlock room
unlock(rtRoom, resid);
break;
case 0x48: // SO_HEAP_UNLOCK_SCRIPT Unlock script
unlock(rtScript, resid);
break;
case 0x49: // SO_HEAP_UNLOCK_SOUND Unlock sound
unlock(rtSound, resid);
break;
case 0x4A: // SO_HEAP_NUKE_COSTUME Remove costume from heap
setResourceCounter(rtCostume, resid, 0x7F);
break;
case 0x4B: // SO_HEAP_NUKE_ROOM Remove room from heap
setResourceCounter(rtRoom, resid, 0x7F);
break;
case 0x4C: // SO_HEAP_NUKE_SCRIPT Remove script from heap
setResourceCounter(rtScript, resid, 0x7F);
break;
case 0x4D: // SO_HEAP_NUKE_SOUND Remove sound from heap
setResourceCounter(rtSound, resid, 0x7F);
break;
default:
error("o8_resourceRoutines: default case %d", subOp);
}
}
void Scumm_v8::o8_roomOps()
{
// TODO
byte subOp = fetchScriptByte();
int a, b, c, d, e;
switch (subOp) {
case 0x52: // SO_ROOM_PALETTE Set room palette
error("o8_roomOps: default case %d", subOp);
break;
case 0x55: // SO_ROOM_INTENSITY Set room intensity
// Not used in CMI???
c = pop();
b = pop();
a = pop();
darkenPalette(a, a, a, b, c);
break;
case 0x57: // SO_ROOM_FADE Fade room
a = pop();
if (a) {
_switchRoomEffect = (byte)(a);
_switchRoomEffect2 = (byte)(a >> 8);
} else {
fadeIn(_newEffect);
}
break;
case 0x58: // SO_ROOM_RGB_INTENSITY Set room color intensity
e = pop();
d = pop();
c = pop();
b = pop();
a = pop();
darkenPalette(a, b, c, d, e);
break;
case 0x59: // SO_ROOM_TRANSFORM Transform room
case 0x5A: // SO_ROOM_CYCLE_SPEED Set palette cycling speed
case 0x5B: // SO_ROOM_COPY_PALETTE Copy palette
case 0x5C: // SO_ROOM_NEW_PALETTE Create new palette
error("o8_roomOps: unimplemented case %d", subOp);
break;
case 0x5D: // SO_ROOM_SAVE_GAME Save game
warning("V8 Save game opcode not implemented");
break;
case 0x5E: // SO_ROOM_LOAD_GAME Load game
warning("V8 Load game opcode not implemented");
break;
case 0x5F: // SO_ROOM_SATURATION Set saturation of room colors
default:
error("o8_roomOps: default case %d", subOp);
}
}
void Scumm_v8::o8_actorOps()
{
// TODO
byte subOp = fetchScriptByte();
Actor *a;
int i, j;
if (subOp == 0x7A) {
_curActor = pop();
//printf("Setting current actor to %d\n", _curActor);
return;
}
a = derefActorSafe(_curActor, "o8_actorOps");
if (!a)
return;
switch (subOp) {
case 0x64: // SO_ACTOR_COSTUME Set actor costume
a->setActorCostume(pop());
break;
case 0x65: // SO_ACTOR_STEP_DIST Set actor width of steps
j = pop();
i = pop();
a->setActorWalkSpeed(i, j);
break;
case 0x67: // SO_ACTOR_ANIMATION_DEFAULT Set actor animation to default
a->initFrame = 1;
a->walkFrame = 2;
a->standFrame = 3;
a->talkFrame1 = 4;
a->talkFrame2 = 5;
break;
case 0x68: // SO_ACTOR_ANIMATION_INIT Initialize animation
a->initFrame = pop();
break;
case 0x69: // SO_ACTOR_ANIMATION_TALK Set actor animation to talk animation
a->talkFrame2 = pop();
a->talkFrame1 = pop();
break;
case 0x6A: // SO_ACTOR_ANIMATION_WALK Set actor animation to walk animation
a->walkFrame = pop();
break;
case 0x6B: // SO_ACTOR_ANIMATION_STAND Set actor animation to standing animation
a->standFrame = pop();
break;
case 0x6C: // SO_ACTOR_ANIMATION_SPEED Set speed of animation
a->animSpeed = pop();
a->animProgress = 0;
break;
case 0x6D: // SO_ACTOR_DEFAULT
// FIXME - is this right? Or maybe a->initActor(2) ?
a->initActor(0);
break;
case 0x6E: // SO_ACTOR_ELEVATION
a->elevation = pop();
a->needRedraw = true;
a->needBgReset = true;
break;
case 0x6F: // SO_ACTOR_PALETTE Set actor palette
j = pop();
i = pop();
checkRange(31, 0, i, "Illegal palet slot %d");
a->palette[i] = j;
a->needRedraw = true;
break;
case 0x70: // SO_ACTOR_TALK_COLOR Set actor talk color
a->talkColor = pop();
break;
case 0x71: // SO_ACTOR_NAME Set name of actor
loadPtrToResource(rtActorName, a->number, NULL);
break;
case 0x72: // SO_ACTOR_WIDTH Set width of actor
a->width = pop();
break;
case 0x73: // SO_ACTOR_SCALE Set scaling of actor
a->scalex = a->scaley = pop();
a->needRedraw = true;
a->needBgReset = true;
break;
case 0x74: // SO_ACTOR_NEVER_ZCLIP ?
a->forceClip = 0;
break;
case 0x75: // SO_ACTOR_ALWAYS_ZCLIP ?
a->forceClip = pop();
break;
case 0x76: // SO_ACTOR_IGNORE_BOXES Make actor ignore boxes
a->ignoreBoxes = true;
a->forceClip = 100;
if (a->isInCurrentRoom())
a->putActor(a->x, a->y, a->room);
break;
case 0x77: // SO_ACTOR_FOLLOW_BOXES Make actor follow boxes
a->ignoreBoxes = false;
a->forceClip = 100;
if (a->isInCurrentRoom())
a->putActor(a->x, a->y, a->room);
break;
case 0x78: // SO_ACTOR_SPECIAL_DRAW
// TODO - implement this!
i = pop();
warning("o8_actorOps: specialDraw(%d) not implemented", i);
break;
case 0x79: // SO_ACTOR_TEXT_OFFSET Set text offset relative to actor
a->talkPosX = pop();
a->talkPosY = pop();
break;
// case 0x7A: // SO_ACTOR_INIT Initialize actor
case 0x7B: // SO_ACTOR_VARIABLE Set actor variable
// FIXME - is this right??
i = pop();
a->setAnimVar(pop(), i);
break;
case 0x7C: // SO_ACTOR_IGNORE_TURNS_ON Make actor ignore turns
a->ignoreTurns = true;
break;
case 0x7D: // SO_ACTOR_IGNORE_TURNS_OFF Make actor follow turns
a->ignoreTurns = false;
break;
case 0x7E: // SO_ACTOR_NEW New actor
// FIXME - is this right? Or maybe a->initActor(0) ?
a->initActor(2);
break;
case 0x7F: // SO_ACTOR_DEPTH Set actor Z position
a->layer = pop();
break;
case 0x80: // SO_ACTOR_STOP
a->stopActorMoving();
a->startAnimActor(a->standFrame);
break;
case 0x81: // SO_ACTOR_FACE Make actor face angle
a->moving &= ~MF_TURN;
a->setDirection(pop());
break;
case 0x82: // SO_ACTOR_TURN Turn actor
a->turnToDirection(pop());
break;
case 0x83: // SO_ACTOR_WALK_SCRIPT Set walk script for actor?
a->walk_script = pop();
break;
case 0x84: // SO_ACTOR_TALK_SCRIPT Set talk script for actor?
a->talk_script = pop();
break;
case 0x85: // SO_ACTOR_WALK_PAUSE
a->moving |= 0x80;
break;
case 0x86: // SO_ACTOR_WALK_RESUME
a->moving &= ~0x7f;
break;
case 0x87: // SO_ACTOR_VOLUME Set volume of actor speech
// TODO - implement this!
i = pop();
warning("o8_actorOps: setActorVolume(%d) not implemented", i);
break;
case 0x88: // SO_ACTOR_FREQUENCY Set frequency of actor speech
// TODO - implement this!
i = pop();
warning("o8_actorOps: setActorFrequency(%d) not implemented", i);
break;
case 0x89: // SO_ACTOR_PAN
// TODO - implement this!
i = pop();
warning("o8_actorOps: setActorPan(%d) not implemented", i);
break;
default:
error("o8_actorOps: default case %d", subOp);
}
}
void Scumm_v8::o8_cameraOps()
{
// TODO
byte subOp = fetchScriptByte();
switch (subOp) {
case 0x32: // SO_CAMERA_PAUSE
warning("freezeCamera NYI");
break;
case 0x33: // SO_CAMERA_RESUME
warning("unfreezeCamera NYI");
break;
default:
error("o8_cameraOps: default case %d", subOp);
}
}
void Scumm_v8::o8_verbOps()
{
// TODO
byte subOp = fetchScriptByte();
VerbSlot *vs = NULL;
if (0 <= _curVerbSlot && _curVerbSlot < _maxVerbs)
vs = &_verbs[_curVerbSlot];
switch (subOp) {
case 0x96: // SO_VERB_INIT Choose verb number for editing
_curVerb = pop();
_curVerbSlot = getVerbSlot(_curVerb, 0);
checkRange(_maxVerbs - 1, 0, _curVerbSlot, "Illegal new verb slot %d");
break;
case 0x97: // SO_VERB_NEW New verb
case 0x98: // SO_VERB_DELETE Delete verb
case 0x99: // SO_VERB_NAME Set verb name
case 0x9A: // SO_VERB_AT Set verb (X,Y) placement
error("o8_verbops: default case %d", subOp);
break;
case 0x9B: // SO_VERB_ON Turn verb on
vs->curmode = 1;
break;
case 0x9C: // SO_VERB_OFF Turn verb off
vs->curmode = 0;
break;
case 0x9D: // SO_VERB_COLOR Set verb color
vs->color = pop();
break;
case 0x9E: // SO_VERB_HICOLOR Set verb highlighted color
vs->hicolor = pop();
break;
case 0xA0: // SO_VERB_DIMCOLOR Set verb dimmed (disabled) color
vs->dimcolor = pop();
break;
case 0xA1: // SO_VERB_DIM
vs->curmode = 2;
break;
case 0xA2: // SO_VERB_KEY Set keypress to associate with verb
vs->key = pop();
break;
case 0xA3: // SO_VERB_IMAGE Set verb image
case 0xA4: // SO_VERB_NAME_STR Set verb name
error("o8_verbops: default case %d", subOp);
break;
case 0xA5: // SO_VERB_CENTER Center verb
vs->center = 1;
break;
case 0xA6: // SO_VERB_CHARSET Choose charset for verb
// FIXME - TODO
vs->charset_nr = pop();
//printf("Set to charset %d\n", vs->charset_nr);
break;
case 0xA7: // SO_VERB_LINE_SPACING Choose linespacing for verb
// FIXME - TODO
pop();
break;
default:
error("o8_verbops: default case %d", subOp);
}
}
void Scumm_v8::o8_soundKludge()
{
int args[16];
int num = getStackList(args, sizeof(args) / sizeof(args[0]));
_sound->soundKludge(args, num);
}
void Scumm_v8::o8_system()
{
// TODO
byte subOp = fetchScriptByte();
// switch (subOp) {
// default:
error("o8_system: default case %d", subOp);
// }
}
void Scumm_v8::o8_startVideo()
{
char dirName[255];
int len = resStrLen((char*)_scriptPointer);
sprintf(dirName, "%s/resource/", getGameDataPath());
warning("o8_startVideo(%s/%s)\n", dirName, (char*)_scriptPointer);
//ScummRenderer * sr = new ScummRenderer(this, 1000/14);
//SmushPlayer * sp = new SmushPlayer(sr);
//sp->play((char*)_scriptPointer, dirName);
_scriptPointer += len + 1;
}
void Scumm_v8::o6_kernelSetFunctions()
{
// TODO
int args[30];
int len = getStackList(args, sizeof(args) / sizeof(args[0]));
switch (args[0]) {
case 11: // lockObject
warning("o6_kernelSetFunctions: lockObject(%d)", args[1]);
// getObjectIndex(args[1]);
// if (ObjData.field28 != 0) {
// ObjData.field32 = 1;
// }
break;
case 12: // unlockObject
warning("o6_kernelSetFunctions: unlockObject(%d)", args[1]);
// getObjectIndex(args[1]);
// if (ObjData.field28 != 0) {
// ObjData.field32 = 0;
// }
break;
case 13: // remapCostume
derefActorSafe(args[1], "o6_kernelSetFunctions:remapCostume")->remapActorPalette(args[2], args[3], args[4], -1);
break;
case 14: // remapCostumeInsert
derefActorSafe(args[1], "o6_kernelSetFunctions:remapCostumeInsert")->remapActorPalette(args[2], args[3], args[4], args[5]);
break;
case 15: // setVideoFrameRate
// not used anymore (was smush frame rate)
break;
case 20: // setBoxSlot
setBoxScale(args[1], args[2]);
break;
case 21: // setScaleSlot
warning("o6_kernelSetFunctions: setScaleSlot(%d, %d, %d, %d, %d, %d, %d)", args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
break;
case 22: // setBannerColors
// warning("o6_kernelSetFunctions: setBannerColors(%d, %d, %d, %d)", args[1], args[2], args[3], args[4]);
break;
case 23: // setActorChoreLimbFrame
warning("o6_kernelSetFunctions: setActorChoreLimbFrame(%d, %d, %d, %d)", args[1], args[2], args[3], args[4]);
break;
case 24: // clearTextQueue
warning("o6_kernelSetFunctions: clearTextQueue()");
break;
case 25: // saveGameWrite
warning("o6_kernelSetFunctions: saveGameWrite(%d, %d)", args[1], args[2]);
break;
case 26: // saveGameRead
warning("o6_kernelSetFunctions: saveGameRead(%d, %d)", args[1], args[2]);
break;
case 27: // saveGameReadName
warning("o6_kernelSetFunctions: saveGameReadName(%d)", args[1]);
break;
case 28: // saveGameStampScreenshot
warning("o6_kernelSetFunctions: saveGameStampScreenshot(%d, %d, %d, %d, %d, %d)", args[1], args[2], args[3], args[4], args[5], args[6]);
break;
case 29: // setKeyScript
warning("o6_kernelSetFunctions: setKeyScript(%d, %d)", args[1], args[2]);
break;
case 30: // killAllScriptsButMe
warning("o6_kernelSetFunctions: killAllScriptsButMe()");
killAllScriptsExceptCurrent();
break;
case 31: // stopAllVideo
warning("o6_kernelSetFunctions: stopAllVideo()");
break;
case 32: // writeRegistryValue
warning("o6_kernelSetFunctions: writeRegistryValue(%d, %d)", args[1], args[2]);
break;
case 33: // paletteSetIntensity
warning("o6_kernelSetFunctions: paletteSetIntensity(%d, %d)", args[1], args[2]);
break;
case 34: // queryQuit
warning("o6_kernelSetFunctions: queryQuit()");
break;
case 108:
setupShadowPalette(args[1], args[2], args[3], args[4], args[5], args[6]);
break;
case 109:
setupShadowPalette(0, args[1], args[2], args[3], args[4], args[5]);
break;
case 115: // getWalkBoxAt
// TODO
break;
case 116: // isPointInBox
// TODO
break;
case 118:
enqueueObject(args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], 3);
break;
case 119:
enqueueObject(args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], 0);
break;
default:
warning("o6_kernelSetFunctions: default case (len = %d)", len);
}
}
void Scumm_v8::o6_kernelGetFunctions()
{
// TODO
int args[30];
int len = getStackList(args, sizeof(args) / sizeof(args[0]));
switch (args[0]) {
case 0xCE: // getRGBSlot
case 0xD3: // getKeyState
case 0xD7: // getBox
case 0xD8: // findBlastObject
case 0xD9: // actorHit
case 0xDA: // lipSyncWidth
case 0xDB: // lipSyncHeight
case 0xDC: // actorTalkAnimation
// FIXME - hack!
push(0);
break;
case 0xDD: // getMasterSFXVol
push(_sound->_sound_volume_sfx / 2);
break;
case 0xDE: // getMasterVoiceVol
push(_sound->_sound_volume_sfx / 2);
break;
case 0xDF: // getMasterMusicVol
push(_sound->_sound_volume_music / 2);
break;
case 0xE0: // readRegistryValue
{
printf("readRegistryValue(%d)\n", args[1]);
int array = args[1];
// FIXME - hack: for some reasons the wrong variable ID arrives here, compared to the
// scripts. Probably a wrong push/pop somewhere. For now override to correct value.
array = 658;
ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(array));
if (!strcmp((char *)ah->data, "Saveload Page"))
push(1);
else
push(0);
}
break;
default:
error("o6_kernelGetFunctions: default case (len = %d)", len);
}
}
void Scumm_v8::o8_getObjectImageX()
{
int i = getObjectIndex(pop());
push(_objs[i].x_pos);
}
void Scumm_v8::o8_getObjectImageY()
{
int i = getObjectIndex(pop());
push(_objs[i].y_pos);
}
void Scumm_v8::o8_getObjectImageWidth()
{
int i = getObjectIndex(pop());
push(_objs[i].width);
}
void Scumm_v8::o8_getObjectImageHeight()
{
int i = getObjectIndex(pop());
push(_objs[i].height);
}
/*
From http://scummrev.mixnmojo.com/specs/CMIOpcodes.shtml
000 O_0
001 O_PUSH_NUMBER Push number onto stack.
002 O_PUSH_VARIABLE Push variable value onto stack.
003 O_PUSH_ARRAY_VALUE Push array value onto stack.
004 O_PUSH_ARRAY2_VALUE ?
005 O_DUP Duplicate stack value
006 O_POP Pop value from stack.
007 O_NOT NOT (!)
008 O_EQ Equals (==)
009 O_NEQ Does not equal (!=)
00A O_GT Greater than (>)
00B O_LT Less than (<)
00C O_LEQ Less than or equal (<=)
00D O_GEQ Greater than or equal (>=)
00E O_ADD Add (+)
00F O_SUB Subtract (-)
010 O_MUL Multiply (*)
011 O_DIV Divide (/)
012 O_LAND Logical AND
013 O_LOR Logical OR
014 O_BAND Binary AND
015 O_BOR Binary OR
016 O_MOD Modulus (%)
017 O_23
018 O_24
019 O_25
01A O_26
01B O_27
01C O_28
01D O_29
01E O_30
01F O_31
020 O_32
021 O_33
022 O_34
023 O_35
024 O_36
025 O_37
026 O_38
027 O_39
028 O_40
029 O_41
02A O_42
02B O_43
02C O_44
02D O_45
02E O_46
02F O_47
030 O_48
031 O_49
032 O_50
033 O_51
034 O_52
035 O_53
036 O_54
037 O_55
038 O_56
039 O_57
03A O_58
03B O_59
03C O_60
03D O_61
03E O_62
03F O_63
040 O_64
041 O_65
042 O_66
043 O_67
044 O_68
045 O_69
046 O_70
047 O_71
048 O_72
049 O_73
04A O_74
04B O_75
04C O_76
04D O_77
04E O_78
04F O_79
050 O_80
051 O_81
052 O_82
053 O_83
054 O_84
055 O_85
056 O_86
057 O_87
058 O_88
059 O_89
05A O_90
05B O_91
05C O_92
05D O_93
05E O_94
05F O_95
060 O_96
061 O_97
062 O_98
063 O_99
064 O_IF if ()
065 O_IF_NOT if not ()
066 O_JUMP jump/goto
067 O_BREAK_HERE Break out of script
068 O_BREAK_HERE_VAR
069 O_WAIT_FOR_STUFF Wait Sub opcodes
06A O_SLEEP_JIFFIES Sleep for jiffies (10ths of a second)
06B O_SLEEP_SECONDS Sleep for seconds
06C O_SLEEP_MINUTES Sleep for minutes
06D O_STORE_VARIABLE Assign value to variable
06E O_INC_VARIABLE Increase variable value (++)
06F O_DEC_VARIABLE Decrease variable value (--)
070 O_ARRAY_DIM Set dimension of array
071 O_STORE_ARRAY Assign value to array
072 O_INC_ARRAY Increase array value
073 O_DEC_ARRAY Decrease array value
074 O_ARRAY_DIM2 Set dimensions of 2 dimensional array
075 O_STORE_ARRAY2 Assign value to 2 dimensional array
076 O_ASSIGN_ARRAY ?
077 O_ARRAY_SHUFFLE Shuffle array
078 O_ARRAY_LOCALIZE ?
079 O_START_SCRIPT Start script
07A O_START_SCRIPT_QUICK ?
07B O_END_SCRIPT End script
07C O_STOP_SCRIPT Stop script from running
07D O_CHAIN_SCRIPT ?
07E O_RETURN Return
07F O_START_OBJECT ?
080 O_STOP_OBJECT ?
081 O_CUT_SCENE Start of cutscene (interface off)
082 O_END_CUT_SCENE End of cutscene (interface on)
083 O_FREEZE_SCRIPTS ?
084 O_OVERRIDE ?
085 O_OVERRIDE_OFF ?
086 O_STOP_SENTENCE ?
087 O_DEBUG Set debug mode
088 O_DEBUG_WINDEX Set debug mode with output to external window
089 O_CLASS_OF Set class of script
08A O_STATE_OF ?
08B O_OWNER_OF Set owner of object
08C O_CAMERA_PAN_TO Pan camera to (X,Y)
08D O_CAMERA_FOLLOW Make camera follow character/object
08E O_CAMERA_AT Place camera at specific (X,Y)
08F O_SAY_LINE Talk
090 O_SAY_LINE_DEFAULT Talk using default actor
091 O_SAY_LINE_SIMPLE Talk with less arguments
092 O_SAY_LINE_SIMPLE_DEFAULT Talk with less arguments using default actor
093 O_PRINT_LINE Print a line on screen
094 O_PRINT_CURSOR
095 O_PRINT_DEBUG
096 O_PRINT_SYSTEM
097 O_BLAST_TEXT Text to output to screen
098 O_DRAW_OBJECT Draw object
099 O_153
09A O_BLAST_OBJECT
09B O_155
09C O_USERFACE ?
09D O_CURRENT_ROOM Set current room
09E O_COME_OUT_DOOR
09F O_WALK_ACTOR_TO_OBJECT Walk to object
0A0 O_WALK_ACTOR_TO_XY Walk to coordinate
0A1 O_PUT_ACTOR_AT_XY Put at coordinate
0A2 O_PUT_ACTOR_AT_OBJECT Put at object
0A3 O_FACE_TOWARDS Change facing
0A4 O_DO_ANIMATION Animate
0A5 O_DO_SENTENCE
0A6 O_PICK_UP_OBJECT Pick up object
0A7 O_SET_BOX
0A8 O_SET_BOX_PATH
0A9 O_SET_BOX_SET
0AA O_HEAP_STUFF Heap sub opcodes
0AB O_ROOM_STUFF Room sub opcodes
0AC O_ACTOR_STUFF Actor sub opcodes
0AD O_CAMERA_STUFF Camera sub opcodes
0AE O_VERB_STUFF Verb sub opcodes
0AF O_START_SFX Start sound effect
0B0 O_START_MUSIC Start music
0B1 O_STOP_SOUND Stop sound (effect or music)
0B2 O_SOUND_KLUDGE ?
0B3 O_SYSTEM System sub opcodes
0B4 O_VERB_SETS
0B5 O_NEW_NAME_OF Set new name of object
0B6 O_GET_TIME_DATE Get time and/or date
0B7 O_DRAW_BOX
0B8 O_ACTOBJ_STAMP
0B9 O_START_VIDEO Start cutscene video
0BA O_KLUDGE
0BB O_187
0BC O_188
0BD O_189
0BE O_190
0BF O_191
0C0 O_192
0C1 O_193
0C2 O_194
0C3 O_195
0C4 O_196
0C5 O_197
0C6 O_198
0C7 O_199
0C8 F_START_SCRIPT Start script
0C9 F_START_OBJECT Start object script
0CA F_PICK
0CB F_PICK_DEFAULT
0CC F_PICK_RANDOM
0CD F_IN_SET
0CE F_RANDOM Get random number
0CF F_RANDOM_BETWEEN Get random number between two values
0D0 F_CLASS_OF Get class of script
0D1 F_STATE_OF
0D2 F_OWNER_OF Get owner of object
0D3 F_SCRIPT_RUNNING Test if script is running
0D4 F_OBJECT_RUNNING Test if object is running
0D5 F_SOUND_RUNNING Test if sound is running
0D6 F_ABS Get absolute value
0D7 F_PIXEL
0D8 F_KLUDGE
0D9 F_IN_BOX Test if object is in box
0DA F_VALID_VERB
0DB F_FIND_ACTOR
0DC F_FIND_OBJECT
0DD F_FIND_VERB
0DE F_FIND_ALL_OBJECTS
0DF F_ACTOR_INVENTORY
0E0 F_ACTOR_INVENTORY_COUNT Get number of items in inventory
0E1 F_ACTOR_VARIABLE Get actor variable (property)
0E2 F_ACTOR_ROOM Get current room for actor
0E3 F_ACTOR_BOX Get current box for actor
0E4 F_ACTOR_MOVING Test if actor is moving
0E5 F_ACTOR_COSTUME Get current costume for actor
0E6 F_ACTOR_SCALE Get current scale of actor
0E7 F_ACTOR_DEPTH Get current Z position of actor
0E8 F_ACTOR_ELEVATION Get current actor elevation
0E9 F_ACTOR_WIDTH Get current actor width
0EA F_ACTOBJ_FACING Get current actor/object facing
0EB F_ACTOBJ_X Get X position of actor/object
0EC F_ACTOBJ_Y Get Y position of actor/object
0ED F_ACTOR_CHORE
0EE F_PROXIMITY_2ACTOBJS Get distance between 2 actors/objects
0EF F_PROXIMITY_2POINTS Get distance between 2 points
0F0 F_OBJECT_IMAGE_X Get X position of object image
0F1 F_OBJECT_IMAGE_Y Get Y position of object image
0F2 F_OBJECT_IMAGE_WIDTH Get width of object image
0F3 F_OBJECT_IMAGE_HEIGHT Get height of object image
0F4 F_VERB_X Get X position of verb
0F5 F_VERB_Y Get Y position of verb
0F6 F_STRING_WIDTH
0F7 F_ACTOR_ZPLANE
0F8 O_248
0F9 O_249
0FA O_250
0FB O_251
0FC O_252
0FD O_253
0FE O_254
0FF O_255
The following are subopcodes - just strip the leading 1
100 SO_256
101 SO_257
102 SO_258
103 SO_259
104 SO_260
105 SO_261
106 SO_262
107 SO_263
108 SO_264
109 SO_265
10A SO_ARRAY_SCUMMVAR
10B SO_ARRAY_STRING
10C SO_ARRAY_UNDIM
10D SO_269
10E SO_270
10F SO_271
110 SO_272
111 SO_273
112 SO_274
113 SO_275
114 SO_ASSIGN_STRING
115 SO_ASSIGN_SCUMMVAR_LIST
116 SO_ASSIGN_2DIM_LIST
117 SO_279
118 SO_280
119 SO_281
11A SO_282
11B SO_283
11C SO_284
11D SO_285
11E SO_WAIT_FOR_ACTOR Wait for actor (to finish current action?)
11F SO_WAIT_FOR_MESSAGE Wait for message
120 SO_WAIT_FOR_CAMERA Wait for camera (to finish current action?)
121 SO_WAIT_FOR_SENTENCE
122 SO_WAIT_FOR_ANIMATION
123 SO_WAIT_FOR_TURN
124 SO_292
125 SO_293
126 SO_294
127 SO_295
128 SO_SYSTEM_RESTART Restart game
129 SO_SYSTEM_QUIT Quit game
12A SO_298
12B SO_299
12C SO_300
12D SO_301
12E SO_302
12F SO_303
130 SO_304
131 SO_305
132 SO_CAMERA_PAUSE
133 SO_CAMERA_RESUME
134 SO_308
135 SO_309
136 SO_310
137 SO_311
138 SO_312
139 SO_313
13A SO_314
13B SO_315
13C SO_HEAP_LOAD_CHARSET Load character set to heap
13D SO_HEAP_LOAD_COSTUME Load costume to heap
13E SO_HEAP_LOAD_OBJECT Load object to heap
13F SO_HEAP_LOAD_ROOM Load room to heap
140 SO_HEAP_LOAD_SCRIPT Load script to heap
141 SO_HEAP_LOAD_SOUND Load sound to heap
142 SO_HEAP_LOCK_COSTUME Lock costume in heap
143 SO_HEAP_LOCK_ROOM Lock room in heap
144 SO_HEAP_LOCK_SCRIPT Lock script in heap
145 SO_HEAP_LOCK_SOUND Lock sound in heap
146 SO_HEAP_UNLOCK_COSTUME Unlock costume
147 SO_HEAP_UNLOCK_ROOM Unlock room
148 SO_HEAP_UNLOCK_SCRIPT Unlock script
149 SO_HEAP_UNLOCK_SOUND Unlock sound
14A SO_HEAP_NUKE_COSTUME Remove costume from heap
14B SO_HEAP_NUKE_ROOM Remove room from heap
14C SO_HEAP_NUKE_SCRIPT Remove script from heap
14D SO_HEAP_NUKE_SOUND Remove sound from heap
14E SO_334
14F SO_335
150 SO_336
151 SO_337
152 SO_ROOM_PALETTE Set room palette
153 SO_339
154 SO_340
155 SO_ROOM_INTENSITY Set room intensity
156 SO_342
157 SO_ROOM_FADE Fade room
158 SO_ROOM_RGB_INTENSITY Set room color intensity
159 SO_ROOM_TRANSFORM Transform room
15A SO_ROOM_CYCLE_SPEED Set palette cycling speed
15B SO_ROOM_COPY_PALETTE Copy palette
15C SO_ROOM_NEW_PALETTE Create new palette
15D SO_ROOM_SAVE_GAME Save game
15E SO_ROOM_LOAD_GAME Load game
15F SO_ROOM_SATURATION Set saturation of room colors
160 SO_352
161 SO_353
162 SO_354
163 SO_355
164 SO_ACTOR_COSTUME Set actor costume
165 SO_ACTOR_STEP_DIST Set actor width of steps
166 SO_358
167 SO_ACTOR_ANIMATION_DEFAULT Set actor animation to default
168 SO_ACTOR_ANIMATION_INIT Initialize animation
169 SO_ACTOR_ANIMATION_TALK Set actor animation to talk animation
16A SO_ACTOR_ANIMATION_WALK Set actor animation to walk animation
16B SO_ACTOR_ANIMATION_STAND Set actor animation to standing animation
16C SO_ACTOR_ANIMATION_SPEED Set speed of animation
16D SO_ACTOR_DEFAULT
16E SO_ACTOR_ELEVATION
16F SO_ACTOR_PALETTE Set actor palette
170 SO_ACTOR_TALK_COLOR Set actor talk color
171 SO_ACTOR_NAME Set name of actor
172 SO_ACTOR_WIDTH Set width of actor
173 SO_ACTOR_SCALE Set scaling of actor
174 SO_ACTOR_NEVER_ZCLIP ?
175 SO_ACTOR_ALWAYS_ZCLIP ?
176 SO_ACTOR_IGNORE_BOXES Make actor ignore boxes
177 SO_ACTOR_FOLLOW_BOXES Make actor follow boxes
178 SO_ACTOR_SPECIAL_DRAW
179 SO_ACTOR_TEXT_OFFSET Set text offset relative to actor
17A SO_ACTOR_INIT Initialize actor
17B SO_ACTOR_VARIABLE Set actor variable
17C SO_ACTOR_IGNORE_TURNS_ON Make actor ignore turns
17D SO_ACTOR_IGNORE_TURNS_OFF Make actor follow turns
17E SO_ACTOR_NEW New actor
17F SO_ACTOR_DEPTH Set actor Z position
180 SO_ACTOR_STOP
181 SO_ACTOR_FACE Make actor face angle
182 SO_ACTOR_TURN Turn actor
183 SO_ACTOR_WALK_SCRIPT Set walk script for actor?
184 SO_ACTOR_TALK_SCRIPT Set talk script for actor?
185 SO_ACTOR_WALK_PAUSE
186 SO_ACTOR_WALK_RESUME
187 SO_ACTOR_VOLUME Set volume of actor speech
188 SO_ACTOR_FREQUENCY Set frequency of actor speech
189 SO_ACTOR_PAN
18A SO_394
18B SO_395
18C SO_396
18D SO_397
18E SO_398
18F SO_399
190 SO_400
191 SO_401
192 SO_402
193 SO_403
194 SO_404
195 SO_405
196 SO_VERB_INIT Choose verb number for editing
197 SO_VERB_NEW New verb
198 SO_VERB_DELETE Delete verb
199 SO_VERB_NAME Set verb name
19A SO_VERB_AT Set verb (X,Y) placement
19B SO_VERB_ON Turn verb on
19C SO_VERB_OFF Turn verb off
19D SO_VERB_COLOR Set verb color
19E SO_VERB_HICOLOR Set verb highlighted color
19F SO_415
1A0 SO_VERB_DIMCOLOR Set verb dimmed (disabled) color
1A1 SO_VERB_DIM
1A2 SO_VERB_KEY Set keypress to associate with verb
1A3 SO_VERB_IMAGE Set verb image
1A4 SO_VERB_NAME_STR Set verb name
1A5 SO_VERB_CENTER Center verb
1A6 SO_VERB_CHARSET Choose charset for verb
1A7 SO_VERB_LINE_SPACING Choose linespacing for verb
1A8 SO_424
1A9 SO_425
1AA SO_426
1AB SO_427
1AC SO_428
1AD SO_429
1AE SO_430
1AF SO_431
1B0 SO_432
1B1 SO_433
1B2 SO_434
1B3 SO_435
1B4 SO_VERBS_SAVE
1B5 SO_VERBS_RESTORE
1B6 SO_VERBS_DELETE
1B7 SO_439
1B8 SO_440
1B9 SO_441
1BA SO_442
1BB SO_443
1BC SO_444
1BD SO_445
1BE SO_446
1BF SO_447
1C0 SO_448
1C1 SO_449
1C2 SO_450
1C3 SO_451
1C4 SO_452
1C5 SO_453
1C6 SO_454
1C7 SO_455
1C8 SO_PRINT_BASEOP
1C9 SO_PRINT_END
1CA SO_PRINT_AT Print at coordinates (x,y)
1CB SO_PRINT_COLOR Print color
1CC SO_PRINT_CENTER Center output
1CD SO_PRINT_CHARSET Set print character set
1CE SO_PRINT_LEFT Left justify output
1CF SO_PRINT_OVERHEAD
1D0 SO_PRINT_MUMBLE
1D1 SO_PRINT_STRING Set string to print
1D2 SO_PRINT_WRAP Set print wordwrap
1D3 SO_467
1D4 SO_468
1D5 SO_469
1D6 SO_470
1D7 SO_471
1D8 SO_472
1D9 SO_473
1DA SO_474
1DB SO_475
1DC SO_CURSOR_ON Turn cursor on
1DD SO_CURSOR_OFF Turn cursor off
1DE SO_CURSOR_SOFT_ON Turn soft cursor on
1DF SO_CURSOR_SOFT_OFF Turn soft cursor off
1E0 SO_USERPUT_ON
1E1 SO_USERPUT_OFF
1E2 SO_USERPUT_SOFT_ON
1E3 SO_USERPUT_SOFT_OFF
1E4 SO_CURSOR_IMAGE Set cursor image
1E5 SO_CURSOR_HOTSPOT Set cursor hotspot
1E6 SO_CURSOR_TRANSPARENT Set cursor transparent color
1E7 SO_CHARSET_SET
1E8 SO_CHARSET_COLOR
1E9 SO_CURSOR_PUT
1EA SO_490
1EB SO_491
1EC SO_492
1ED SO_493
1EE SO_494
1EF SO_495
1F0 SO_496
1F1 SO_497
1F2 SO_498
1F3 SO_499
1F4 SO_500
1F5 SO_501
1F6 SO_502
1F7 SO_503
1F8 SO_504
1F9 SO_505
1FA SO_506
1FB SO_507
1FC SO_508
1FD SO_509
1FE SO_510
1FF SO_511
*/