measuring the distance in characters for V2 games instead. Now Edna won't bring the same strange kid into the cell over and over again. If necessary, we can still fix o5_getClosestActor() to handle larger distances. It just takes a few more changes than I first thought. svn-id: r8243
2644 lines
61 KiB
C++
2644 lines
61 KiB
C++
/* ScummVM - Scumm Interpreter
|
|
* Copyright (C) 2001 Ludvig Strigeus
|
|
* Copyright (C) 2001-2003 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"
|
|
|
|
#define OPCODE(x) { &Scumm_v5::x, #x }
|
|
|
|
void Scumm_v5::setupOpcodes() {
|
|
static const OpcodeEntryV5 opcodes[256] = {
|
|
/* 00 */
|
|
OPCODE(o5_stopObjectCode),
|
|
OPCODE(o5_putActor),
|
|
OPCODE(o5_startMusic),
|
|
OPCODE(o5_getActorRoom),
|
|
/* 04 */
|
|
OPCODE(o5_isGreaterEqual),
|
|
OPCODE(o5_drawObject),
|
|
OPCODE(o5_getActorElevation),
|
|
OPCODE(o5_setState),
|
|
/* 08 */
|
|
OPCODE(o5_isNotEqual),
|
|
OPCODE(o5_faceActor),
|
|
OPCODE(o5_startScript),
|
|
OPCODE(o5_getVerbEntrypoint),
|
|
/* 0C */
|
|
OPCODE(o5_resourceRoutines),
|
|
OPCODE(o5_walkActorToActor),
|
|
OPCODE(o5_putActorAtObject),
|
|
OPCODE(o5_getObjectState),
|
|
/* 10 */
|
|
OPCODE(o5_getObjectOwner),
|
|
OPCODE(o5_animateActor),
|
|
OPCODE(o5_panCameraTo),
|
|
OPCODE(o5_actorSet),
|
|
/* 14 */
|
|
OPCODE(o5_print),
|
|
OPCODE(o5_actorFromPos),
|
|
OPCODE(o5_getRandomNr),
|
|
OPCODE(o5_and),
|
|
/* 18 */
|
|
OPCODE(o5_jumpRelative),
|
|
OPCODE(o5_doSentence),
|
|
OPCODE(o5_move),
|
|
OPCODE(o5_multiply),
|
|
/* 1C */
|
|
OPCODE(o5_startSound),
|
|
OPCODE(o5_ifClassOfIs),
|
|
OPCODE(o5_walkActorTo),
|
|
OPCODE(o5_isActorInBox),
|
|
/* 20 */
|
|
OPCODE(o5_stopMusic),
|
|
OPCODE(o5_putActor),
|
|
OPCODE(o5_getAnimCounter),
|
|
OPCODE(o5_getActorY),
|
|
/* 24 */
|
|
OPCODE(o5_loadRoomWithEgo),
|
|
OPCODE(o5_pickupObject),
|
|
OPCODE(o5_setVarRange),
|
|
OPCODE(o5_stringOps),
|
|
/* 28 */
|
|
OPCODE(o5_equalZero),
|
|
OPCODE(o5_setOwnerOf),
|
|
OPCODE(o5_startScript),
|
|
OPCODE(o5_delayVariable),
|
|
/* 2C */
|
|
OPCODE(o5_cursorCommand),
|
|
OPCODE(o5_putActorInRoom),
|
|
OPCODE(o5_delay),
|
|
OPCODE(o5_ifNotState),
|
|
/* 30 */
|
|
OPCODE(o5_matrixOps),
|
|
OPCODE(o5_getInventoryCount),
|
|
OPCODE(o5_setCameraAt),
|
|
OPCODE(o5_roomOps),
|
|
/* 34 */
|
|
OPCODE(o5_getDist),
|
|
OPCODE(o5_findObject),
|
|
OPCODE(o5_walkActorToObject),
|
|
OPCODE(o5_startObject),
|
|
/* 38 */
|
|
OPCODE(o5_lessOrEqual),
|
|
OPCODE(o5_doSentence),
|
|
OPCODE(o5_subtract),
|
|
OPCODE(o5_getActorScale),
|
|
/* 3C */
|
|
OPCODE(o5_stopSound),
|
|
OPCODE(o5_findInventory),
|
|
OPCODE(o5_walkActorTo),
|
|
OPCODE(o5_drawBox),
|
|
/* 40 */
|
|
OPCODE(o5_cutscene),
|
|
OPCODE(o5_putActor),
|
|
OPCODE(o5_chainScript),
|
|
OPCODE(o5_getActorX),
|
|
/* 44 */
|
|
OPCODE(o5_isLess),
|
|
OPCODE(o5_drawObject),
|
|
OPCODE(o5_increment),
|
|
OPCODE(o5_setState),
|
|
/* 48 */
|
|
OPCODE(o5_isEqual),
|
|
OPCODE(o5_faceActor),
|
|
OPCODE(o5_startScript),
|
|
OPCODE(o5_getVerbEntrypoint),
|
|
/* 4C */
|
|
OPCODE(o5_soundKludge),
|
|
OPCODE(o5_walkActorToActor),
|
|
OPCODE(o5_putActorAtObject),
|
|
OPCODE(o5_ifState),
|
|
/* 50 */
|
|
OPCODE(o5_pickupObjectOld),
|
|
OPCODE(o5_animateActor),
|
|
OPCODE(o5_actorFollowCamera),
|
|
OPCODE(o5_actorSet),
|
|
/* 54 */
|
|
OPCODE(o5_setObjectName),
|
|
OPCODE(o5_actorFromPos),
|
|
OPCODE(o5_getActorMoving),
|
|
OPCODE(o5_or),
|
|
/* 58 */
|
|
OPCODE(o5_beginOverride),
|
|
OPCODE(o5_doSentence),
|
|
OPCODE(o5_add),
|
|
OPCODE(o5_divide),
|
|
/* 5C */
|
|
OPCODE(o5_oldRoomEffect),
|
|
OPCODE(o5_setClass),
|
|
OPCODE(o5_walkActorTo),
|
|
OPCODE(o5_isActorInBox),
|
|
/* 60 */
|
|
OPCODE(o5_freezeScripts),
|
|
OPCODE(o5_putActor),
|
|
OPCODE(o5_stopScript),
|
|
OPCODE(o5_getActorFacing),
|
|
/* 64 */
|
|
OPCODE(o5_loadRoomWithEgo),
|
|
OPCODE(o5_pickupObject),
|
|
OPCODE(o5_getClosestObjActor),
|
|
OPCODE(o5_getStringWidth),
|
|
/* 68 */
|
|
OPCODE(o5_isScriptRunning),
|
|
OPCODE(o5_setOwnerOf),
|
|
OPCODE(o5_startScript),
|
|
OPCODE(o5_debug),
|
|
/* 6C */
|
|
OPCODE(o5_getActorWidth),
|
|
OPCODE(o5_putActorInRoom),
|
|
OPCODE(o5_stopObjectScript),
|
|
OPCODE(o5_ifNotState),
|
|
/* 70 */
|
|
OPCODE(o5_lights),
|
|
OPCODE(o5_getActorCostume),
|
|
OPCODE(o5_loadRoom),
|
|
OPCODE(o5_roomOps),
|
|
/* 74 */
|
|
OPCODE(o5_getDist),
|
|
OPCODE(o5_findObject),
|
|
OPCODE(o5_walkActorToObject),
|
|
OPCODE(o5_startObject),
|
|
/* 78 */
|
|
OPCODE(o5_isGreater),
|
|
OPCODE(o5_doSentence),
|
|
OPCODE(o5_verbOps),
|
|
OPCODE(o5_getActorWalkBox),
|
|
/* 7C */
|
|
OPCODE(o5_isSoundRunning),
|
|
OPCODE(o5_findInventory),
|
|
OPCODE(o5_walkActorTo),
|
|
OPCODE(o5_drawBox),
|
|
/* 80 */
|
|
OPCODE(o5_breakHere),
|
|
OPCODE(o5_putActor),
|
|
OPCODE(o5_startMusic),
|
|
OPCODE(o5_getActorRoom),
|
|
/* 84 */
|
|
OPCODE(o5_isGreaterEqual),
|
|
OPCODE(o5_drawObject),
|
|
OPCODE(o5_getActorElevation),
|
|
OPCODE(o5_setState),
|
|
/* 88 */
|
|
OPCODE(o5_isNotEqual),
|
|
OPCODE(o5_faceActor),
|
|
OPCODE(o5_startScript),
|
|
OPCODE(o5_getVerbEntrypoint),
|
|
/* 8C */
|
|
OPCODE(o5_resourceRoutines),
|
|
OPCODE(o5_walkActorToActor),
|
|
OPCODE(o5_putActorAtObject),
|
|
OPCODE(o5_getObjectState),
|
|
/* 90 */
|
|
OPCODE(o5_getObjectOwner),
|
|
OPCODE(o5_animateActor),
|
|
OPCODE(o5_panCameraTo),
|
|
OPCODE(o5_actorSet),
|
|
/* 94 */
|
|
OPCODE(o5_print),
|
|
OPCODE(o5_actorFromPos),
|
|
OPCODE(o5_getRandomNr),
|
|
OPCODE(o5_and),
|
|
/* 98 */
|
|
OPCODE(o5_quitPauseRestart),
|
|
OPCODE(o5_doSentence),
|
|
OPCODE(o5_move),
|
|
OPCODE(o5_multiply),
|
|
/* 9C */
|
|
OPCODE(o5_startSound),
|
|
OPCODE(o5_ifClassOfIs),
|
|
OPCODE(o5_walkActorTo),
|
|
OPCODE(o5_isActorInBox),
|
|
/* A0 */
|
|
OPCODE(o5_stopObjectCode),
|
|
OPCODE(o5_putActor),
|
|
OPCODE(o5_getAnimCounter),
|
|
OPCODE(o5_getActorY),
|
|
/* A4 */
|
|
OPCODE(o5_loadRoomWithEgo),
|
|
OPCODE(o5_pickupObject),
|
|
OPCODE(o5_setVarRange),
|
|
OPCODE(o5_saveLoadVars),
|
|
/* A8 */
|
|
OPCODE(o5_notEqualZero),
|
|
OPCODE(o5_setOwnerOf),
|
|
OPCODE(o5_startScript),
|
|
OPCODE(o5_saveRestoreVerbs),
|
|
/* AC */
|
|
OPCODE(o5_expression),
|
|
OPCODE(o5_putActorInRoom),
|
|
OPCODE(o5_wait),
|
|
OPCODE(o5_ifNotState),
|
|
/* B0 */
|
|
OPCODE(o5_matrixOps),
|
|
OPCODE(o5_getInventoryCount),
|
|
OPCODE(o5_setCameraAt),
|
|
OPCODE(o5_roomOps),
|
|
/* B4 */
|
|
OPCODE(o5_getDist),
|
|
OPCODE(o5_findObject),
|
|
OPCODE(o5_walkActorToObject),
|
|
OPCODE(o5_startObject),
|
|
/* B8 */
|
|
OPCODE(o5_lessOrEqual),
|
|
OPCODE(o5_doSentence),
|
|
OPCODE(o5_subtract),
|
|
OPCODE(o5_getActorScale),
|
|
/* BC */
|
|
OPCODE(o5_stopSound),
|
|
OPCODE(o5_findInventory),
|
|
OPCODE(o5_walkActorTo),
|
|
OPCODE(o5_drawBox),
|
|
/* C0 */
|
|
OPCODE(o5_endCutscene),
|
|
OPCODE(o5_putActor),
|
|
OPCODE(o5_chainScript),
|
|
OPCODE(o5_getActorX),
|
|
/* C4 */
|
|
OPCODE(o5_isLess),
|
|
OPCODE(o5_drawObject),
|
|
OPCODE(o5_decrement),
|
|
OPCODE(o5_setState),
|
|
/* C8 */
|
|
OPCODE(o5_isEqual),
|
|
OPCODE(o5_faceActor),
|
|
OPCODE(o5_startScript),
|
|
OPCODE(o5_getVerbEntrypoint),
|
|
/* CC */
|
|
OPCODE(o5_pseudoRoom),
|
|
OPCODE(o5_walkActorToActor),
|
|
OPCODE(o5_putActorAtObject),
|
|
OPCODE(o5_ifState),
|
|
/* D0 */
|
|
OPCODE(o5_pickupObjectOld),
|
|
OPCODE(o5_animateActor),
|
|
OPCODE(o5_actorFollowCamera),
|
|
OPCODE(o5_actorSet),
|
|
/* D4 */
|
|
OPCODE(o5_setObjectName),
|
|
OPCODE(o5_actorFromPos),
|
|
OPCODE(o5_getActorMoving),
|
|
OPCODE(o5_or),
|
|
/* D8 */
|
|
OPCODE(o5_printEgo),
|
|
OPCODE(o5_doSentence),
|
|
OPCODE(o5_add),
|
|
OPCODE(o5_divide),
|
|
/* DC */
|
|
OPCODE(o5_oldRoomEffect),
|
|
OPCODE(o5_setClass),
|
|
OPCODE(o5_walkActorTo),
|
|
OPCODE(o5_isActorInBox),
|
|
/* E0 */
|
|
OPCODE(o5_freezeScripts),
|
|
OPCODE(o5_putActor),
|
|
OPCODE(o5_stopScript),
|
|
OPCODE(o5_getActorFacing),
|
|
/* E4 */
|
|
OPCODE(o5_loadRoomWithEgo),
|
|
OPCODE(o5_pickupObject),
|
|
OPCODE(o5_getClosestObjActor),
|
|
OPCODE(o5_getStringWidth),
|
|
/* E8 */
|
|
OPCODE(o5_isScriptRunning),
|
|
OPCODE(o5_setOwnerOf),
|
|
OPCODE(o5_startScript),
|
|
OPCODE(o5_debug),
|
|
/* EC */
|
|
OPCODE(o5_getActorWidth),
|
|
OPCODE(o5_putActorInRoom),
|
|
OPCODE(o5_stopObjectScript),
|
|
OPCODE(o5_ifNotState),
|
|
/* F0 */
|
|
OPCODE(o5_lights),
|
|
OPCODE(o5_getActorCostume),
|
|
OPCODE(o5_loadRoom),
|
|
OPCODE(o5_roomOps),
|
|
/* F4 */
|
|
OPCODE(o5_getDist),
|
|
OPCODE(o5_findObject),
|
|
OPCODE(o5_walkActorToObject),
|
|
OPCODE(o5_startObject),
|
|
/* F8 */
|
|
OPCODE(o5_isGreater),
|
|
OPCODE(o5_doSentence),
|
|
OPCODE(o5_verbOps),
|
|
OPCODE(o5_getActorWalkBox),
|
|
/* FC */
|
|
OPCODE(o5_isSoundRunning),
|
|
OPCODE(o5_findInventory),
|
|
OPCODE(o5_walkActorTo),
|
|
OPCODE(o5_drawBox)
|
|
};
|
|
|
|
_opcodesV5 = opcodes;
|
|
}
|
|
|
|
void Scumm_v5::executeOpcode(byte i) {
|
|
OpcodeProcV5 op = _opcodesV5[i].proc;
|
|
(this->*op) ();
|
|
}
|
|
|
|
const char *Scumm_v5::getOpcodeDesc(byte i) {
|
|
return _opcodesV5[i].desc;
|
|
}
|
|
|
|
int Scumm_v5::getVar() {
|
|
return readVar(fetchScriptWord());
|
|
}
|
|
|
|
int Scumm_v5::getVarOrDirectByte(byte mask) {
|
|
if (_opcode & mask)
|
|
return getVar();
|
|
return fetchScriptByte();
|
|
}
|
|
|
|
int Scumm_v5::getVarOrDirectWord(byte mask) {
|
|
if (_opcode & mask)
|
|
return getVar();
|
|
return (int16)fetchScriptWord();
|
|
}
|
|
|
|
void Scumm_v5::o5_actorFollowCamera() {
|
|
actorFollowCamera(getVarOrDirectByte(0x80));
|
|
}
|
|
|
|
void Scumm_v5::o5_actorFromPos() {
|
|
int x, y;
|
|
getResultPos();
|
|
x = getVarOrDirectWord(0x80);
|
|
y = getVarOrDirectWord(0x40);
|
|
setResult(getActorFromPos(x, y));
|
|
}
|
|
|
|
void Scumm_v5::o5_actorSet() {
|
|
static const byte convertTable[20] =
|
|
{ 1, 0, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 20 };
|
|
int act = getVarOrDirectByte(0x80);
|
|
Actor *a;
|
|
int i, j;
|
|
|
|
if (act == 0) {
|
|
// This case happens in Zak256 (and maybe elsewhere, to set the default talk color (9).
|
|
// For now, we hack this to modify actor 1 instead, but clearly that's bad.
|
|
// Better might be to modify _string[0].color, or even add a new dedicated
|
|
// 'default talk color' variable.
|
|
act = 1;
|
|
ScriptSlot *ss = &vm.slot[_currentScript];
|
|
warning("o5_actorSet: act = 0, setting to 1 as a workaround (%d:%d:0x%X)", _roomResource,
|
|
ss->number, _scriptPointer - _scriptOrgPointer);
|
|
}
|
|
|
|
a = derefActor(act, "o5_actorSet");
|
|
|
|
while ((_opcode = fetchScriptByte()) != 0xFF) {
|
|
if (_features & GF_SMALL_HEADER)
|
|
_opcode = (_opcode & 0xE0) | convertTable[(_opcode & 0x1F) - 1];
|
|
|
|
switch (_opcode & 0x1F) {
|
|
case 0: /* dummy case */
|
|
getVarOrDirectByte(0x80);
|
|
break;
|
|
case 1: /* costume */
|
|
a->setActorCostume(getVarOrDirectByte(0x80));
|
|
break;
|
|
case 2: /* walkspeed */
|
|
i = getVarOrDirectByte(0x80);
|
|
j = getVarOrDirectByte(0x40);
|
|
a->setActorWalkSpeed(i, j);
|
|
break;
|
|
case 3: /* sound */
|
|
a->sound[0] = getVarOrDirectByte(0x80);
|
|
break;
|
|
case 4: /* walkanim */
|
|
a->walkFrame = getVarOrDirectByte(0x80);
|
|
break;
|
|
case 5: /* talkanim */
|
|
a->talkStartFrame = getVarOrDirectByte(0x80);
|
|
a->talkStopFrame = getVarOrDirectByte(0x40);
|
|
break;
|
|
case 6: /* standanim */
|
|
a->standFrame = getVarOrDirectByte(0x80);
|
|
break;
|
|
case 7: /* ignore */
|
|
getVarOrDirectByte(0x80);
|
|
getVarOrDirectByte(0x40);
|
|
getVarOrDirectByte(0x20);
|
|
break;
|
|
case 8: /* init */
|
|
a->initActor(0);
|
|
break;
|
|
case 9: /* elevation */
|
|
a->elevation = getVarOrDirectWord(0x80);
|
|
a->needRedraw = true;
|
|
break;
|
|
case 10: /* defaultanims */
|
|
a->initFrame = 1;
|
|
a->walkFrame = 2;
|
|
a->standFrame = 3;
|
|
a->talkStartFrame = 4;
|
|
a->talkStopFrame = 5;
|
|
break;
|
|
case 11: /* palette */
|
|
i = getVarOrDirectByte(0x80);
|
|
j = getVarOrDirectByte(0x40);
|
|
checkRange(31, 0, i, "Illegal palette slot %d");
|
|
a->palette[i] = j;
|
|
a->needRedraw = true;
|
|
break;
|
|
case 12: /* talk color */
|
|
a->talkColor = getVarOrDirectByte(0x80);
|
|
break;
|
|
case 13: /* name */
|
|
loadPtrToResource(rtActorName, a->number, NULL);
|
|
break;
|
|
case 14: /* initanim */
|
|
a->initFrame = getVarOrDirectByte(0x80);
|
|
break;
|
|
case 15: /* unk */
|
|
error("o5_actorset:unk not implemented");
|
|
#if 0
|
|
int args[16] =
|
|
{
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
};
|
|
getWordVararg(args);
|
|
for (i = 0; i < 16; i++)
|
|
if (args[i] != 0xFF)
|
|
a->palette[i] = args[i];
|
|
#endif
|
|
break;
|
|
case 16: /* width */
|
|
a->width = getVarOrDirectByte(0x80);
|
|
break;
|
|
case 17: /* scale */
|
|
if ((_gameId == GID_MONKEY_VGA) || (_gameId == GID_MONKEY_EGA)) {
|
|
a->scalex = a->scaley = getVarOrDirectByte(0x80);
|
|
} else {
|
|
a->scalex = getVarOrDirectByte(0x80);
|
|
a->scaley = getVarOrDirectByte(0x40);
|
|
}
|
|
|
|
a->needRedraw = true;
|
|
break;
|
|
case 18: /* neverzclip */
|
|
a->forceClip = 0;
|
|
break;
|
|
case 19: /* setzclip */
|
|
a->forceClip = getVarOrDirectByte(0x80);
|
|
break;
|
|
case 20: /* ignoreboxes */
|
|
case 21: /* followboxes */
|
|
a->ignoreBoxes = !(_opcode & 1);
|
|
a->forceClip = 0;
|
|
if (a->isInCurrentRoom())
|
|
a->putActor(a->x, a->y, a->room);
|
|
break;
|
|
|
|
case 22: /* animspeed */
|
|
a->animSpeed = getVarOrDirectByte(0x80);
|
|
a->animProgress = 0;
|
|
break;
|
|
case 23: /* shadow mode */
|
|
a->shadow_mode = getVarOrDirectByte(0x80);
|
|
break;
|
|
default:
|
|
warning("o5_actorSet: default case");
|
|
}
|
|
}
|
|
}
|
|
|
|
void Scumm_v5::o5_setClass() {
|
|
int obj = getVarOrDirectWord(0x80);
|
|
int newClass;
|
|
|
|
while ((_opcode = fetchScriptByte()) != 0xFF) {
|
|
newClass = getVarOrDirectWord(0x80);
|
|
if (newClass == 0) {
|
|
// Class '0' means: clean all class data
|
|
_classData[obj] = 0;
|
|
if ((_features & GF_SMALL_HEADER) && obj <= _numActors) {
|
|
Actor *a = derefActor(obj, "o5_setClass");
|
|
a->ignoreBoxes = false;
|
|
a->forceClip = 0;
|
|
}
|
|
} else
|
|
putClass(obj, newClass, (newClass & 0x80) ? true : false);
|
|
}
|
|
}
|
|
|
|
void Scumm_v5::o5_add() {
|
|
int a;
|
|
getResultPos();
|
|
a = getVarOrDirectWord(0x80);
|
|
setResult(readVar(_resultVarNumber) + a);
|
|
}
|
|
|
|
void Scumm_v5::o5_and() {
|
|
int a;
|
|
getResultPos();
|
|
a = getVarOrDirectWord(0x80);
|
|
setResult(readVar(_resultVarNumber) & a);
|
|
}
|
|
|
|
void Scumm_v5::o5_animateActor() {
|
|
int act = getVarOrDirectByte(0x80);
|
|
int anim = getVarOrDirectByte(0x40);
|
|
Actor *a = derefActor(act, "o5_animateActor");
|
|
a->animateActor(anim);
|
|
}
|
|
|
|
void Scumm_v5::o5_breakHere() {
|
|
updateScriptPtr();
|
|
_currentScript = 0xFF;
|
|
}
|
|
|
|
void Scumm_v5::o5_chainScript() {
|
|
int vars[16];
|
|
int data;
|
|
int cur;
|
|
|
|
data = getVarOrDirectByte(0x80);
|
|
|
|
getWordVararg(vars);
|
|
|
|
cur = _currentScript;
|
|
|
|
vm.slot[cur].number = 0;
|
|
vm.slot[cur].status = 0;
|
|
_currentScript = 0xFF;
|
|
|
|
runScript(data, vm.slot[cur].freezeResistant, vm.slot[cur].recursive, vars);
|
|
}
|
|
|
|
void Scumm_v5::o5_cursorCommand() {
|
|
int i, j, k;
|
|
int table[16];
|
|
switch ((_opcode = fetchScriptByte()) & 0x1F) {
|
|
case 1: /* cursor show */
|
|
_cursor.state = 1;
|
|
verbMouseOver(0);
|
|
break;
|
|
case 2: /* cursor hide */
|
|
_cursor.state = 0;
|
|
verbMouseOver(0);
|
|
break;
|
|
case 3: /* userput on */
|
|
_userPut = 1;
|
|
break;
|
|
case 4: /* userput off */
|
|
_userPut = 0;
|
|
break;
|
|
case 5: /* cursor soft on */
|
|
_cursor.state++;
|
|
verbMouseOver(0);
|
|
break;
|
|
case 6: /* cursor soft off */
|
|
_cursor.state--;
|
|
verbMouseOver(0);
|
|
break;
|
|
case 7: /* userput soft on */
|
|
_userPut++;
|
|
break;
|
|
case 8: /* userput soft off */
|
|
_userPut--;
|
|
break;
|
|
case 10: /* set cursor img */
|
|
i = getVarOrDirectByte(0x80);
|
|
j = getVarOrDirectByte(0x40);
|
|
// cursor image in both Looms is based on image from charset
|
|
// omit for now.
|
|
// FIXME: Actually: is this opcode ever called by a non-Loom game?
|
|
// Which V3-V5 game besides Loom makes use of custom cursors, ever?
|
|
if ((_gameId != GID_LOOM256) && (_gameId != GID_LOOM)) {
|
|
warning("setCursorImg called - tell Fingolfin where you saw this!");
|
|
setCursorImg(i, j, 1);
|
|
}
|
|
break;
|
|
case 11: /* set cursor hotspot */
|
|
i = getVarOrDirectByte(0x80);
|
|
j = getVarOrDirectByte(0x40);
|
|
k = getVarOrDirectByte(0x20);
|
|
setCursorHotspot(j, k);
|
|
break;
|
|
case 12: /* init cursor */
|
|
setCursor(getVarOrDirectByte(0x80));
|
|
break;
|
|
case 13: /* init charset */
|
|
initCharset(getVarOrDirectByte(0x80));
|
|
break;
|
|
case 14: /* unk */
|
|
if (_features & GF_OLD_BUNDLE || _gameId == GID_INDY3_256) {
|
|
// FIXME: What is this supposed to do? From comparing
|
|
// Indy3's script 118 to the Passport Demo's script 58
|
|
// my guess is that it's some sort of "init charset",
|
|
// but why does it need two parameters?
|
|
int a = getVarOrDirectByte(0x80);
|
|
int b = getVarOrDirectByte(0x40);
|
|
warning("o5_cursorCommand: unknown subopcode 14 (init charset?): %d, %d", a, b);
|
|
// Maybe the following is what to do (or maybe b instead of a); since I have only
|
|
// seen a = b = 1, this is not clear; still even if this is right, what's b?
|
|
// loadCharset(a);
|
|
// Assuming this is correct, we might not actually need it, as our
|
|
// initCharset automatically calls loadCharset for GF_SMALL_HEADER, if needed.
|
|
// Loom ega at least does need this and v2 has its own cursor command
|
|
// so making this for OLD_BUNDLE. Going by disassembly zak256 does not have a
|
|
// sub op for this case, not sure about loomcd
|
|
} else {
|
|
getWordVararg(table);
|
|
for (i = 0; i < 16; i++)
|
|
_charsetColorMap[i] = _charsetData[_string[1].t_charset][i] = (unsigned char)table[i];
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (!(_features & GF_OLD_BUNDLE) && _gameId != GID_INDY3_256) {
|
|
VAR(VAR_CURSORSTATE) = _cursor.state;
|
|
VAR(VAR_USERPUT) = _userPut;
|
|
}
|
|
}
|
|
|
|
void Scumm_v5::o5_cutscene() {
|
|
int args[16];
|
|
getWordVararg(args);
|
|
beginCutscene(args);
|
|
}
|
|
|
|
void Scumm_v5::o5_endCutscene() {
|
|
endCutscene();
|
|
}
|
|
|
|
void Scumm_v5::o5_debug() {
|
|
int a = getVarOrDirectWord(0x80);
|
|
debug(1, "o5_debug(%d)", a);
|
|
}
|
|
|
|
void Scumm_v5::o5_decrement() {
|
|
getResultPos();
|
|
setResult(readVar(_resultVarNumber) - 1);
|
|
}
|
|
|
|
void Scumm_v5::o5_delay() {
|
|
int delay = fetchScriptByte();
|
|
delay |= fetchScriptByte() << 8;
|
|
delay |= fetchScriptByte() << 16;
|
|
vm.slot[_currentScript].delay = delay;
|
|
vm.slot[_currentScript].status = 1;
|
|
o5_breakHere();
|
|
}
|
|
|
|
void Scumm_v5::o5_delayVariable() {
|
|
vm.slot[_currentScript].delay = getVar();
|
|
vm.slot[_currentScript].status = 1;
|
|
o5_breakHere();
|
|
}
|
|
|
|
void Scumm_v5::o5_divide() {
|
|
int a;
|
|
getResultPos();
|
|
a = getVarOrDirectWord(0x80);
|
|
if (a == 0) {
|
|
error("Divide by zero");
|
|
setResult(0);
|
|
} else
|
|
setResult(readVar(_resultVarNumber) / a);
|
|
}
|
|
|
|
void Scumm_v5::o5_doSentence() {
|
|
int verb;
|
|
SentenceTab *st;
|
|
|
|
verb = getVarOrDirectByte(0x80);
|
|
if (verb == 0xFE) {
|
|
_sentenceNum = 0;
|
|
stopScript(VAR(VAR_SENTENCE_SCRIPT));
|
|
clearClickedStatus();
|
|
return;
|
|
}
|
|
|
|
st = &_sentence[_sentenceNum++];
|
|
|
|
st->verb = verb;
|
|
st->objectA = getVarOrDirectWord(0x40);
|
|
st->objectB = getVarOrDirectWord(0x20);
|
|
st->preposition = (st->objectB != 0);
|
|
st->freezeCount = 0;
|
|
}
|
|
|
|
void Scumm_v5::o5_drawBox() {
|
|
int x, y, x2, y2, color;
|
|
|
|
x = getVarOrDirectWord(0x80);
|
|
y = getVarOrDirectWord(0x40);
|
|
|
|
_opcode = fetchScriptByte();
|
|
x2 = getVarOrDirectWord(0x80);
|
|
y2 = getVarOrDirectWord(0x40);
|
|
color = getVarOrDirectByte(0x20);
|
|
|
|
drawBox(x, y, x2, y2, color);
|
|
}
|
|
|
|
void Scumm_v5::o5_drawObject() {
|
|
int state, obj, idx, i;
|
|
ObjectData *od;
|
|
uint16 x, y, w, h;
|
|
int xpos, ypos;
|
|
|
|
state = 1;
|
|
xpos = ypos = 255;
|
|
obj = getVarOrDirectWord(0x80);
|
|
|
|
if (_features & GF_SMALL_HEADER) {
|
|
xpos = getVarOrDirectWord(0x40);
|
|
ypos = getVarOrDirectWord(0x20);
|
|
} else {
|
|
switch ((_opcode = fetchScriptByte()) & 0x1F) {
|
|
case 1: /* draw at */
|
|
xpos = getVarOrDirectWord(0x80);
|
|
ypos = getVarOrDirectWord(0x40);
|
|
break;
|
|
case 2: /* set state */
|
|
state = getVarOrDirectWord(0x80);
|
|
break;
|
|
case 0x1F: /* neither */
|
|
break;
|
|
default:
|
|
error("o5_drawObject: default case");
|
|
}
|
|
}
|
|
|
|
idx = getObjectIndex(obj);
|
|
if (idx == -1)
|
|
return;
|
|
|
|
od = &_objs[idx];
|
|
if (xpos != 0xFF) {
|
|
od->walk_x += (xpos << 3) - od->x_pos;
|
|
od->x_pos = xpos << 3;
|
|
od->walk_y += (ypos << 3) - od->y_pos;
|
|
od->y_pos = ypos << 3;
|
|
}
|
|
addObjectToDrawQue(idx);
|
|
|
|
x = od->x_pos;
|
|
y = od->y_pos;
|
|
w = od->width;
|
|
h = od->height;
|
|
|
|
i = _numLocalObjects - 1;
|
|
do {
|
|
if (_objs[i].obj_nr && _objs[i].x_pos == x && _objs[i].y_pos == y && _objs[i].width == w && _objs[i].height == h)
|
|
putState(_objs[i].obj_nr, 0);
|
|
} while (--i);
|
|
|
|
putState(obj, state);
|
|
}
|
|
|
|
void Scumm_v5::o5_getStringWidth() {
|
|
// TODO - not sure if this is correct... needs testing
|
|
int a = getVarOrDirectByte(0x80);
|
|
byte *ptr = getResourceAddress(rtString, a);
|
|
int width = 0;
|
|
|
|
if (ptr)
|
|
width = _charset->getStringWidth(0, ptr);
|
|
|
|
setResult(width);
|
|
warning("o5_getStringWidth, result %d", width);
|
|
}
|
|
|
|
void Scumm_v5::o5_saveLoadVars() {
|
|
// TODO
|
|
error("o5_saveLoadVars not yet implemented");
|
|
}
|
|
|
|
void Scumm_v5::o5_expression() {
|
|
int dst, i;
|
|
|
|
_scummStackPos = 0;
|
|
getResultPos();
|
|
dst = _resultVarNumber;
|
|
|
|
while ((_opcode = fetchScriptByte()) != 0xFF) {
|
|
switch (_opcode & 0x1F) {
|
|
case 1: /* varordirect */
|
|
push(getVarOrDirectWord(0x80));
|
|
break;
|
|
case 2: /* add */
|
|
i = pop();
|
|
push(i + pop());
|
|
break;
|
|
case 3: /* sub */
|
|
i = pop();
|
|
push(pop() - i);
|
|
break;
|
|
case 4: /* mul */
|
|
i = pop();
|
|
push(i * pop());
|
|
break;
|
|
case 5: /* div */
|
|
i = pop();
|
|
if (i == 0)
|
|
error("Divide by zero");
|
|
push(pop() / i);
|
|
break;
|
|
case 6: /* normal opcode */
|
|
_opcode = fetchScriptByte();
|
|
executeOpcode(_opcode);
|
|
push(_scummVars[0]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
_resultVarNumber = dst;
|
|
setResult(pop());
|
|
}
|
|
|
|
void Scumm_v5::o5_faceActor() {
|
|
int act = getVarOrDirectByte(0x80);
|
|
int obj = getVarOrDirectWord(0x40);
|
|
Actor *a = derefActor(act, "o5_faceActor");
|
|
a->faceToObject(obj);
|
|
}
|
|
|
|
void Scumm_v5::o5_findInventory() {
|
|
getResultPos();
|
|
int x = getVarOrDirectByte(0x80);
|
|
int y = getVarOrDirectByte(0x40);
|
|
setResult(findInventory(x, y));
|
|
}
|
|
|
|
void Scumm_v5::o5_findObject() {
|
|
getResultPos();
|
|
int x = getVarOrDirectByte(0x80);
|
|
int y = getVarOrDirectByte(0x40);
|
|
setResult(findObject(x, y));
|
|
}
|
|
|
|
void Scumm_v5::o5_freezeScripts() {
|
|
int scr = getVarOrDirectByte(0x80);
|
|
|
|
if (scr != 0)
|
|
freezeScripts(scr);
|
|
else
|
|
unfreezeScripts();
|
|
}
|
|
|
|
void Scumm_v5::o5_getActorCostume() {
|
|
getResultPos();
|
|
int act = getVarOrDirectByte(0x80);
|
|
Actor *a = derefActor(act, "o5_getActorCostume");
|
|
setResult(a->costume);
|
|
}
|
|
|
|
void Scumm_v5::o5_getActorElevation() {
|
|
getResultPos();
|
|
int act = getVarOrDirectByte(0x80);
|
|
Actor *a = derefActor(act, "o5_getActorElevation");
|
|
setResult(a->elevation);
|
|
}
|
|
|
|
void Scumm_v5::o5_getActorFacing() {
|
|
getResultPos();
|
|
int act = getVarOrDirectByte(0x80);
|
|
Actor *a = derefActor(act, "o5_getActorFacing");
|
|
setResult(newDirToOldDir(a->facing));
|
|
}
|
|
|
|
void Scumm_v5::o5_getActorMoving() {
|
|
getResultPos();
|
|
int act = getVarOrDirectByte(0x80);
|
|
Actor *a = derefActor(act, "o5_getActorMoving");
|
|
setResult(a->moving);
|
|
}
|
|
|
|
void Scumm_v5::o5_getActorRoom() {
|
|
getResultPos();
|
|
int act = getVarOrDirectByte(0x80);
|
|
// FIXME: Workaround for bug #746349. This is a really odd bu
|
|
//in either the script or in our script engine. Might be a good
|
|
// idea to investigate this further by e.g. looking at the FOA
|
|
// engine a bit closer.
|
|
if (_gameId == GID_INDY4 && _roomResource == 94 && vm.slot[_currentScript].number == 206 && act > _numActors) {
|
|
setResult(0);
|
|
return;
|
|
}
|
|
|
|
Actor *a = derefActor(act, "o5_getActorRoom");
|
|
setResult(a->room);
|
|
}
|
|
|
|
void Scumm_v5::o5_getActorScale() {
|
|
Actor *a;
|
|
|
|
// dummy opcode in the loom
|
|
if (_gameId == GID_LOOM)
|
|
return;
|
|
|
|
// INDY3 uses this opcode as a wait_for_actor();
|
|
if ((_gameId == GID_INDY3_256) || (_gameId == GID_INDY3)) {
|
|
const byte *oldaddr = _scriptPointer - 1;
|
|
a = derefActor(getVarOrDirectByte(0x80), "o5_getActorScale (wait)");
|
|
if (a->moving) {
|
|
_scriptPointer = oldaddr;
|
|
o5_breakHere();
|
|
}
|
|
return;
|
|
}
|
|
|
|
getResultPos();
|
|
int act = getVarOrDirectByte(0x80);
|
|
a = derefActor(act, "o5_getActorScale");
|
|
setResult(a->scalex);
|
|
}
|
|
|
|
void Scumm_v5::o5_getActorWalkBox() {
|
|
getResultPos();
|
|
int act = getVarOrDirectByte(0x80);
|
|
Actor *a = derefActor(act, "o5_getActorWalkBox");
|
|
setResult(a->walkbox);
|
|
}
|
|
|
|
void Scumm_v5::o5_getActorWidth() {
|
|
getResultPos();
|
|
int act = getVarOrDirectByte(0x80);
|
|
Actor *a = derefActor(act, "o5_getActorWidth");
|
|
setResult(a->width);
|
|
}
|
|
|
|
void Scumm_v5::o5_getActorX() {
|
|
int a;
|
|
getResultPos();
|
|
|
|
if (_gameId == GID_INDY3_256 || _gameId == GID_INDY3)
|
|
a = getVarOrDirectByte(0x80);
|
|
else
|
|
a = getVarOrDirectWord(0x80);
|
|
|
|
setResult(getObjX(a));
|
|
}
|
|
|
|
void Scumm_v5::o5_getActorY() {
|
|
int a;
|
|
getResultPos();
|
|
|
|
if (_gameId == GID_INDY3_256 || _gameId == GID_INDY3) {
|
|
a = getVarOrDirectByte(0x80);
|
|
|
|
// FIXME - bug 636433 workaround (can't get into Zeppelin)
|
|
if (_roomResource == 36) {
|
|
setResult(getObjY(a) - 1);
|
|
return;
|
|
}
|
|
} else
|
|
a = getVarOrDirectWord(0x80);
|
|
|
|
setResult(getObjY(a));
|
|
}
|
|
|
|
void Scumm_v5::o5_getAnimCounter() {
|
|
getResultPos();
|
|
int act = getVarOrDirectByte(0x80);
|
|
Actor *a = derefActor(act, "o5_getAnimCounter");
|
|
setResult(a->cost.animCounter1);
|
|
}
|
|
|
|
void Scumm_v5::o5_getClosestObjActor() {
|
|
int obj;
|
|
int act;
|
|
int dist;
|
|
|
|
// This is a bit odd: We can't detect any actors farther away than
|
|
// 255 units (pixels in newer games, characters in older ones.) To
|
|
// fix this, we also need to change getObjActToObjActDist(), since
|
|
// it returns 255 to indicate that it can't find the actor, and make
|
|
// sure we don't break o5_getDist() in the process.
|
|
//
|
|
// But we probably won't have to.
|
|
|
|
int closest_obj = 0xFF, closest_dist = 0xFF;
|
|
|
|
getResultPos();
|
|
|
|
act = getVarOrDirectWord(0x80);
|
|
obj = VAR(VAR_ACTOR_RANGE_MAX);
|
|
|
|
do {
|
|
dist = getObjActToObjActDist(act, obj);
|
|
if (dist < closest_dist) {
|
|
closest_dist = dist;
|
|
closest_obj = obj;
|
|
}
|
|
} while (--obj >= VAR(VAR_ACTOR_RANGE_MIN));
|
|
|
|
setResult(closest_obj);
|
|
}
|
|
|
|
void Scumm_v5::o5_getDist() {
|
|
int o1, o2;
|
|
int r;
|
|
getResultPos();
|
|
o1 = getVarOrDirectWord(0x80);
|
|
o2 = getVarOrDirectWord(0x40);
|
|
r = getObjActToObjActDist(o1, o2);
|
|
|
|
// FIXME: MI2 race workaround, see bug #597022
|
|
if (_gameId == GID_MONKEY2 && vm.slot[_currentScript].number == 40 && r < 60)
|
|
r = 60;
|
|
|
|
setResult(r);
|
|
}
|
|
|
|
void Scumm_v5::o5_getInventoryCount() {
|
|
getResultPos();
|
|
setResult(getInventoryCount(getVarOrDirectByte(0x80)));
|
|
}
|
|
|
|
void Scumm_v5::o5_getObjectOwner() {
|
|
getResultPos();
|
|
setResult(getOwner(getVarOrDirectWord(0x80)));
|
|
}
|
|
|
|
void Scumm_v5::o5_getObjectState() {
|
|
if (_features & GF_SMALL_HEADER) {
|
|
o5_ifState();
|
|
} else {
|
|
getResultPos();
|
|
setResult(getState(getVarOrDirectWord(0x80)));
|
|
}
|
|
}
|
|
|
|
void Scumm_v5::o5_ifState() {
|
|
int a = getVarOrDirectWord(0x80);
|
|
int b = getVarOrDirectByte(0x40);
|
|
|
|
if (getState(a) != b)
|
|
o5_jumpRelative();
|
|
else
|
|
ignoreScriptWord();
|
|
}
|
|
|
|
void Scumm_v5::o5_ifNotState() {
|
|
int a = getVarOrDirectWord(0x80);
|
|
int b = getVarOrDirectByte(0x40);
|
|
|
|
if (getState(a) == b)
|
|
o5_jumpRelative();
|
|
else
|
|
ignoreScriptWord();
|
|
}
|
|
|
|
void Scumm_v5::o5_getRandomNr() {
|
|
getResultPos();
|
|
setResult(_rnd.getRandomNumber(getVarOrDirectByte(0x80)));
|
|
}
|
|
|
|
void Scumm_v5::o5_isScriptRunning() {
|
|
getResultPos();
|
|
setResult(isScriptRunning(getVarOrDirectByte(0x80)));
|
|
}
|
|
|
|
void Scumm_v5::o5_getVerbEntrypoint() {
|
|
int a, b;
|
|
getResultPos();
|
|
a = getVarOrDirectWord(0x80);
|
|
b = getVarOrDirectWord(0x40);
|
|
|
|
setResult(getVerbEntrypoint(a, b));
|
|
}
|
|
|
|
void Scumm_v5::o5_ifClassOfIs() {
|
|
int act, cls, b = 0;
|
|
bool cond = true;
|
|
|
|
act = getVarOrDirectWord(0x80);
|
|
|
|
while ((_opcode = fetchScriptByte()) != 0xFF) {
|
|
cls = getVarOrDirectWord(0x80);
|
|
|
|
if (!cls) // FIXME: Ender can't remember why this is here,
|
|
b = false; // but it fixes an oddball zak256 crash
|
|
else
|
|
b = getClass(act, cls);
|
|
|
|
if (cls & 0x80 && !b || !(cls & 0x80) && b)
|
|
cond = false;
|
|
}
|
|
if (cond)
|
|
ignoreScriptWord();
|
|
else
|
|
o5_jumpRelative();
|
|
}
|
|
|
|
void Scumm_v5::o5_increment() {
|
|
getResultPos();
|
|
setResult(readVar(_resultVarNumber) + 1);
|
|
}
|
|
|
|
void Scumm_v5::o5_isActorInBox() {
|
|
int act = getVarOrDirectByte(0x80);
|
|
int box = getVarOrDirectByte(0x40);
|
|
Actor *a = derefActor(act, "o5_isActorInBox");
|
|
|
|
if (!checkXYInBoxBounds(box, a->x, a->y))
|
|
o5_jumpRelative();
|
|
else
|
|
ignoreScriptWord();
|
|
}
|
|
|
|
void Scumm_v5::o5_isEqual() {
|
|
int16 a, b;
|
|
int var;
|
|
|
|
if (_features & GF_AFTER_V2)
|
|
var = fetchScriptByte();
|
|
else
|
|
var = fetchScriptWord();
|
|
a = readVar(var);
|
|
b = getVarOrDirectWord(0x80);
|
|
|
|
// HACK: See bug report #602348. The sound effects for Largo's screams
|
|
// are only played on type 5 soundcards. However, there is at least one
|
|
// other sound effect (the bartender spitting) which is only played on
|
|
// type 3 soundcards.
|
|
|
|
if (_gameId == GID_MONKEY2 && var == VAR_SOUNDCARD && b == 5)
|
|
b = a;
|
|
|
|
if (b == a)
|
|
ignoreScriptWord();
|
|
else
|
|
o5_jumpRelative();
|
|
|
|
}
|
|
|
|
void Scumm_v5::o5_isGreater() {
|
|
int16 a = getVar();
|
|
int16 b = getVarOrDirectWord(0x80);
|
|
if (b > a)
|
|
ignoreScriptWord();
|
|
else
|
|
o5_jumpRelative();
|
|
}
|
|
|
|
void Scumm_v5::o5_isGreaterEqual() {
|
|
int16 a = getVar();
|
|
int16 b = getVarOrDirectWord(0x80);
|
|
if (b >= a)
|
|
ignoreScriptWord();
|
|
else
|
|
o5_jumpRelative();
|
|
}
|
|
|
|
void Scumm_v5::o5_isLess() {
|
|
int16 a = getVar();
|
|
int16 b = getVarOrDirectWord(0x80);
|
|
|
|
if (b < a)
|
|
ignoreScriptWord();
|
|
else
|
|
o5_jumpRelative();
|
|
}
|
|
|
|
void Scumm_v5::o5_lessOrEqual() {
|
|
int16 a = getVar();
|
|
int16 b = getVarOrDirectWord(0x80);
|
|
if (b <= a)
|
|
ignoreScriptWord();
|
|
else
|
|
o5_jumpRelative();
|
|
}
|
|
|
|
void Scumm_v5::o5_isNotEqual() {
|
|
int16 a = getVar();
|
|
int16 b = getVarOrDirectWord(0x80);
|
|
if (b != a)
|
|
ignoreScriptWord();
|
|
else
|
|
o5_jumpRelative();
|
|
}
|
|
|
|
void Scumm_v5::o5_notEqualZero() {
|
|
int a = getVar();
|
|
if (a != 0)
|
|
ignoreScriptWord();
|
|
else
|
|
o5_jumpRelative();
|
|
}
|
|
|
|
void Scumm_v5::o5_equalZero() {
|
|
int a = getVar();
|
|
if (a == 0)
|
|
ignoreScriptWord();
|
|
else
|
|
o5_jumpRelative();
|
|
}
|
|
|
|
void Scumm_v5::o5_jumpRelative() {
|
|
_scriptPointer += (int16)fetchScriptWord();
|
|
}
|
|
|
|
void Scumm_v5::o5_lights() {
|
|
int a, b, c;
|
|
|
|
a = getVarOrDirectByte(0x80);
|
|
b = fetchScriptByte();
|
|
c = fetchScriptByte();
|
|
|
|
if (c == 0)
|
|
VAR(VAR_CURRENT_LIGHTS) = a;
|
|
else if (c == 1) {
|
|
_flashlight.xStrips = a;
|
|
_flashlight.yStrips = b;
|
|
}
|
|
_fullRedraw = 1;
|
|
}
|
|
|
|
void Scumm_v5::o5_loadRoom() {
|
|
int room;
|
|
|
|
room = getVarOrDirectByte(0x80);
|
|
|
|
// For small header games, we only call startScene if the room
|
|
// actually changed. This avoid unwanted (wrong) fades in Zak256
|
|
// and others. OTOH, it seems to cause a problem in newer games.
|
|
if (!(_features & GF_SMALL_HEADER) || room != _currentRoom)
|
|
startScene(room, 0, 0);
|
|
_fullRedraw = 1;
|
|
}
|
|
|
|
void Scumm_v5::o5_loadRoomWithEgo() {
|
|
Actor *a;
|
|
int obj, room, x, y;
|
|
|
|
obj = getVarOrDirectWord(0x80);
|
|
room = getVarOrDirectByte(0x40);
|
|
|
|
a = derefActor(VAR(VAR_EGO), "o5_loadRoomWithEgo");
|
|
|
|
a->putActor(0, 0, room);
|
|
_egoPositioned = false;
|
|
|
|
x = (int16)fetchScriptWord();
|
|
y = (int16)fetchScriptWord();
|
|
|
|
VAR(VAR_WALKTO_OBJ) = obj;
|
|
startScene(a->room, a, obj);
|
|
VAR(VAR_WALKTO_OBJ) = 0;
|
|
|
|
// FIXME: Can this be removed?
|
|
camera._cur.x = a->x;
|
|
|
|
setCameraAt(a->x, a->y);
|
|
setCameraFollows(a);
|
|
|
|
_fullRedraw = 1;
|
|
|
|
if (x != -1) {
|
|
a->startWalkActor(x, y, -1);
|
|
}
|
|
}
|
|
|
|
void Scumm_v5::o5_matrixOps() {
|
|
int a, b;
|
|
|
|
if (_features & GF_AFTER_V3) {
|
|
a = getVarOrDirectByte(0x80);
|
|
b = fetchScriptByte();
|
|
setBoxFlags(a, b);
|
|
return;
|
|
}
|
|
|
|
_opcode = fetchScriptByte();
|
|
switch (_opcode & 0x1F) {
|
|
case 1:
|
|
a = getVarOrDirectByte(0x80);
|
|
b = getVarOrDirectByte(0x40);
|
|
setBoxFlags(a, b);
|
|
break;
|
|
case 2:
|
|
a = getVarOrDirectByte(0x80);
|
|
b = getVarOrDirectByte(0x40);
|
|
setBoxScale(a, b);
|
|
break;
|
|
case 3:
|
|
a = getVarOrDirectByte(0x80);
|
|
b = getVarOrDirectByte(0x40);
|
|
setBoxScale(a, (b - 1) | 0x8000);
|
|
break;
|
|
case 4:
|
|
createBoxMatrix();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Scumm_v5::o5_move() {
|
|
getResultPos();
|
|
setResult(getVarOrDirectWord(0x80));
|
|
}
|
|
|
|
void Scumm_v5::o5_multiply() {
|
|
int a;
|
|
getResultPos();
|
|
a = getVarOrDirectWord(0x80);
|
|
setResult(readVar(_resultVarNumber) * a);
|
|
}
|
|
|
|
void Scumm_v5::o5_or() {
|
|
int a;
|
|
getResultPos();
|
|
a = getVarOrDirectWord(0x80);
|
|
setResult(readVar(_resultVarNumber) | a);
|
|
}
|
|
|
|
void Scumm_v5::o5_beginOverride() {
|
|
if (fetchScriptByte() != 0)
|
|
beginOverride();
|
|
else
|
|
endOverride();
|
|
}
|
|
|
|
void Scumm_v5::o5_panCameraTo() {
|
|
panCameraTo(getVarOrDirectWord(0x80), 0);
|
|
}
|
|
|
|
void Scumm_v5::o5_pickupObject() {
|
|
int obj, room;
|
|
if (_features & GF_AFTER_V3) {
|
|
o5_drawObject();
|
|
return;
|
|
}
|
|
|
|
obj = getVarOrDirectWord(0x80);
|
|
room = getVarOrDirectByte(0x40);
|
|
if (room == 0)
|
|
room = _roomResource;
|
|
addObjectToInventory(obj, room);
|
|
putOwner(obj, VAR(VAR_EGO));
|
|
putClass(obj, kObjectClassUntouchable, 1);
|
|
putState(obj, 1);
|
|
removeObjectFromRoom(obj);
|
|
clearDrawObjectQueue();
|
|
runHook(1);
|
|
}
|
|
|
|
void Scumm_v5::o5_print() {
|
|
_actorToPrintStrFor = getVarOrDirectByte(0x80);
|
|
decodeParseString();
|
|
}
|
|
|
|
void Scumm_v5::o5_printEgo() {
|
|
_actorToPrintStrFor = (byte)VAR(VAR_EGO);
|
|
decodeParseString();
|
|
}
|
|
|
|
void Scumm_v5::o5_pseudoRoom() {
|
|
int i = fetchScriptByte(), j;
|
|
while ((j = fetchScriptByte()) != 0) {
|
|
if (j >= 0x80) {
|
|
_resourceMapper[j & 0x7F] = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Scumm_v5::o5_putActor() {
|
|
int x, y;
|
|
Actor *a;
|
|
|
|
a = derefActor(getVarOrDirectByte(0x80), "o5_putActor");
|
|
x = getVarOrDirectWord(0x40);
|
|
y = getVarOrDirectWord(0x20);
|
|
a->putActor(x, y, a->room);
|
|
}
|
|
|
|
void Scumm_v5::o5_putActorAtObject() {
|
|
int obj, x, y;
|
|
Actor *a;
|
|
|
|
a = derefActor(getVarOrDirectByte(0x80), "o5_putActorAtObject");
|
|
obj = getVarOrDirectWord(0x40);
|
|
if (whereIsObject(obj) != WIO_NOT_FOUND)
|
|
getObjectXYPos(obj, x, y);
|
|
else {
|
|
x = 240;
|
|
y = 120;
|
|
}
|
|
a->putActor(x, y, a->room);
|
|
}
|
|
|
|
void Scumm_v5::o5_putActorInRoom() {
|
|
Actor *a;
|
|
int act = getVarOrDirectByte(0x80);
|
|
int room = getVarOrDirectByte(0x40);
|
|
|
|
a = derefActor(act, "o5_putActorInRoom");
|
|
|
|
if (a->visible && _currentRoom != room && VAR(VAR_TALK_ACTOR) == a->number) {
|
|
clearMsgQueue();
|
|
}
|
|
a->room = room;
|
|
if (!room)
|
|
a->putActor(0, 0, 0);
|
|
}
|
|
|
|
void Scumm_v5::o5_quitPauseRestart() {
|
|
switch (fetchScriptByte()) {
|
|
case 1:
|
|
pauseGame(false);
|
|
break;
|
|
case 3:
|
|
shutDown(0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Scumm_v5::o5_resourceRoutines() {
|
|
const ResTypes resType[4] = { rtScript, rtSound, rtCostume, rtRoom };
|
|
int resid = 0;
|
|
int foo, bar;
|
|
|
|
_opcode = fetchScriptByte();
|
|
if (_opcode != 17)
|
|
resid = getVarOrDirectByte(0x80);
|
|
if (_gameId != GID_ZAK256) {
|
|
// FIXME - this probably can be removed eventually, I don't think the following
|
|
// check will ever be triggered, but then I could be wrong and it's better
|
|
// to play it safe.
|
|
if((_opcode & 0x3F) != (_opcode & 0x1F))
|
|
error("Oops, this shouldn't happen: o5_resourceRoutines opcode %d", _opcode);
|
|
}
|
|
|
|
int op = _opcode & 0x3F;
|
|
|
|
switch (_opcode & 0x3F) {
|
|
case 1: // load script
|
|
case 2: // load sound
|
|
case 3: // load costume
|
|
ensureResourceLoaded(resType[op-1], resid);
|
|
break;
|
|
case 4: // load room
|
|
if (_features == GF_AFTER_V3) {
|
|
ensureResourceLoaded(rtRoom, resid);
|
|
if (resid > 0x7F)
|
|
resid = _resourceMapper[resid & 0x7F];
|
|
|
|
if (_currentRoom != resid) {
|
|
res.flags[rtRoom][resid] |= 1;
|
|
}
|
|
} else
|
|
ensureResourceLoaded(rtRoom, resid);
|
|
break;
|
|
|
|
case 5: // nuke script
|
|
case 6: // nuke sound
|
|
case 7: // nuke costume
|
|
case 8: // nuke room
|
|
if (_gameId == GID_ZAK256)
|
|
warning("o5_resourceRoutines %d should not occur in Zak256", op);
|
|
else
|
|
setResourceCounter(resType[op-5], resid, 0x7F);
|
|
break;
|
|
|
|
case 9: // lock script
|
|
if (resid >= _numGlobalScripts)
|
|
break;
|
|
lock(rtScript, resid);
|
|
break;
|
|
case 10: // lock sound
|
|
lock(rtSound, resid);
|
|
break;
|
|
case 11: // lock costume
|
|
lock(rtCostume, resid);
|
|
break;
|
|
case 12: // lock room
|
|
if (resid > 0x7F)
|
|
resid = _resourceMapper[resid & 0x7F];
|
|
lock(rtRoom, resid);
|
|
break;
|
|
|
|
case 13: // unlock script
|
|
if (resid >= _numGlobalScripts)
|
|
break;
|
|
unlock(rtScript, resid);
|
|
break;
|
|
case 14: // unlock sound
|
|
unlock(rtSound, resid);
|
|
break;
|
|
case 15: // unlock costume
|
|
unlock(rtCostume, resid);
|
|
break;
|
|
case 16: // unlock room
|
|
if (resid > 0x7F)
|
|
resid = _resourceMapper[resid & 0x7F];
|
|
unlock(rtRoom, resid);
|
|
break;
|
|
|
|
case 17: // clear heap
|
|
//heapClear(0);
|
|
//unkHeapProc2(0, 0);
|
|
break;
|
|
case 18: // load charset
|
|
loadCharset(resid);
|
|
break;
|
|
case 19: // nuke charset
|
|
nukeCharset(resid);
|
|
break;
|
|
case 20: // load fl object
|
|
loadFlObject(getVarOrDirectWord(0x40), resid);
|
|
break;
|
|
|
|
case 0x1F + 1:
|
|
// TODO
|
|
warning("o5_resourceRoutines %d not yet handled (script %d)", _opcode, vm.slot[_currentScript].number);
|
|
break;
|
|
case 0x20 + 1:
|
|
// TODO
|
|
warning("o5_resourceRoutines %d not yet handled (script %d)", _opcode, vm.slot[_currentScript].number);
|
|
break;
|
|
case 0x22 + 1:
|
|
// TODO
|
|
foo = getVarOrDirectByte(0x40);
|
|
warning("o5_resourceRoutines %d not yet handled (script %d)", _opcode, vm.slot[_currentScript].number);
|
|
break;
|
|
case 0x23 + 1:
|
|
// TODO
|
|
foo = getVarOrDirectByte(0x40);
|
|
bar = fetchScriptByte();
|
|
warning("o5_resourceRoutines %d not yet handled (script %d)", _opcode, vm.slot[_currentScript].number);
|
|
break;
|
|
case 0x24 + 1:
|
|
// TODO
|
|
foo = getVarOrDirectByte(0x40);
|
|
warning("o5_resourceRoutines %d not yet handled (script %d)", _opcode, vm.slot[_currentScript].number);
|
|
break;
|
|
|
|
default:
|
|
warning("Unknown o5_resourceRoutines: %d", _opcode);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Scumm_v5::o5_roomOps() {
|
|
int a = 0, b = 0, c, d, e;
|
|
|
|
if (_features & GF_AFTER_V3) {
|
|
a = getVarOrDirectWord(0x80);
|
|
b = getVarOrDirectWord(0x40);
|
|
}
|
|
|
|
_opcode = fetchScriptByte();
|
|
switch (_opcode & 0x1F) {
|
|
case 1: /* room scroll */
|
|
if (!(_features & GF_AFTER_V3)) {
|
|
a = getVarOrDirectWord(0x80);
|
|
b = getVarOrDirectWord(0x40);
|
|
}
|
|
if (a < (_screenWidth / 2))
|
|
a = (_screenWidth / 2);
|
|
if (b < (_screenWidth / 2))
|
|
b = (_screenWidth / 2);
|
|
if (a > _roomWidth - (_screenWidth / 2))
|
|
a = _roomWidth - (_screenWidth / 2);
|
|
if (b > _roomWidth - (_screenWidth / 2))
|
|
b = _roomWidth - (_screenWidth / 2);
|
|
VAR(VAR_CAMERA_MIN_X) = a;
|
|
VAR(VAR_CAMERA_MAX_X) = b;
|
|
break;
|
|
case 2: /* room color */
|
|
if (_features & GF_SMALL_HEADER) {
|
|
if (!(_features & GF_AFTER_V3)) {
|
|
a = getVarOrDirectWord(0x80);
|
|
b = getVarOrDirectWord(0x40);
|
|
}
|
|
checkRange(256, 0, a, "o5_roomOps: 2: Illegal room color slot (%d)");
|
|
// FIXME - fingolfin thinks our whole _shadowPalette usage is weird.
|
|
// It seems very suspicious that subopcode 2 is identical to subopcode 4
|
|
// for GF_SMALL_HEADER games. Needs investigation.
|
|
// printf("copyPalColor(%d, %d)\n", a, b);
|
|
// copyPalColor(a, b);
|
|
_shadowPalette[b] = a;
|
|
setDirtyColors(b, b);
|
|
} else {
|
|
error("room-color is no longer a valid command");
|
|
}
|
|
break;
|
|
|
|
case 3: /* set screen */
|
|
if (!(_features & GF_AFTER_V3)) {
|
|
a = getVarOrDirectWord(0x80);
|
|
b = getVarOrDirectWord(0x40);
|
|
}
|
|
initScreens(0, a, _screenWidth, b);
|
|
break;
|
|
case 4: /* set palette color */
|
|
if (_features & GF_SMALL_HEADER) {
|
|
if (!(_features & GF_AFTER_V3)) {
|
|
a = getVarOrDirectWord(0x80);
|
|
b = getVarOrDirectWord(0x40);
|
|
}
|
|
checkRange(256, 0, a, "o5_roomOps: 2: Illegal room color slot (%d)");
|
|
_shadowPalette[b] = a;
|
|
setDirtyColors(b, b);
|
|
} else {
|
|
a = getVarOrDirectWord(0x80);
|
|
b = getVarOrDirectWord(0x40);
|
|
c = getVarOrDirectWord(0x20);
|
|
_opcode = fetchScriptByte();
|
|
d = getVarOrDirectByte(0x80);
|
|
setPalColor(d, a, b, c); /* index, r, g, b */
|
|
}
|
|
break;
|
|
case 5: /* shake on */
|
|
setShake(1);
|
|
break;
|
|
case 6: /* shake off */
|
|
setShake(0);
|
|
break;
|
|
case 7: /* room scale for old games */
|
|
a = getVarOrDirectByte(0x80);
|
|
b = getVarOrDirectByte(0x40);
|
|
_opcode = fetchScriptByte();
|
|
c = getVarOrDirectByte(0x80);
|
|
d = getVarOrDirectByte(0x40);
|
|
_opcode = fetchScriptByte();
|
|
e = getVarOrDirectByte(0x40);
|
|
setScaleItem(e - 1, b, a, d, c);
|
|
break;
|
|
case 8: /* room scale? */
|
|
if (_features & GF_SMALL_HEADER) {
|
|
if (!(_features & GF_AFTER_V3)) {
|
|
a = getVarOrDirectWord(0x80);
|
|
b = getVarOrDirectWord(0x40);
|
|
}
|
|
c = getVarOrDirectWord(0x20);
|
|
} else {
|
|
a = getVarOrDirectByte(0x80);
|
|
b = getVarOrDirectByte(0x40);
|
|
c = getVarOrDirectByte(0x20);
|
|
}
|
|
darkenPalette(a, a, a, b, c);
|
|
break;
|
|
case 9: /* ? */
|
|
_saveLoadFlag = getVarOrDirectByte(0x80);
|
|
_saveLoadSlot = getVarOrDirectByte(0x40);
|
|
_saveLoadSlot = 99; /* use this slot */
|
|
_saveLoadCompatible = true;
|
|
break;
|
|
case 10: /* ? */
|
|
a = getVarOrDirectWord(0x80);
|
|
if (a) {
|
|
_switchRoomEffect = (byte)a;
|
|
_switchRoomEffect2 = (byte)(a >> 8);
|
|
} else {
|
|
fadeIn(_newEffect);
|
|
}
|
|
break;
|
|
case 11: /* ? */
|
|
a = getVarOrDirectWord(0x80);
|
|
b = getVarOrDirectWord(0x40);
|
|
c = getVarOrDirectWord(0x20);
|
|
_opcode = fetchScriptByte();
|
|
d = getVarOrDirectByte(0x80);
|
|
e = getVarOrDirectByte(0x40);
|
|
darkenPalette(a, b, c, d, e);
|
|
break;
|
|
case 12: /* ? */
|
|
a = getVarOrDirectWord(0x80);
|
|
b = getVarOrDirectWord(0x40);
|
|
c = getVarOrDirectWord(0x20);
|
|
_opcode = fetchScriptByte();
|
|
d = getVarOrDirectByte(0x80);
|
|
e = getVarOrDirectByte(0x40);
|
|
setupShadowPalette(a, b, c, d, e);
|
|
break;
|
|
|
|
case 13:{ /* save-string */
|
|
// TODO - use class File instead of fopen/fwrite/fclose
|
|
char buf[256], *s;
|
|
FILE *out;
|
|
|
|
a = getVarOrDirectByte(0x80);
|
|
|
|
// FIXME - check for buffer overflow
|
|
strcpy(buf, getSavePath());
|
|
s = buf + strlen(buf);
|
|
while ((*s++ = fetchScriptByte()));
|
|
|
|
// Use buf as filename
|
|
out = fopen(buf, "wb");
|
|
if (out) {
|
|
byte *ptr;
|
|
ptr = getResourceAddress(rtString, a);
|
|
fwrite(ptr, resStrLen(ptr) + 1, 1, out);
|
|
fclose(out);
|
|
}
|
|
break;
|
|
}
|
|
case 14:{ /* load-string */
|
|
// TODO - use class File instead of fopen/fread/fclose
|
|
char buf[256], *s;
|
|
FILE *in;
|
|
|
|
a = getVarOrDirectByte(0x80);
|
|
|
|
// FIXME - check for buffer overflow
|
|
strcpy(buf, getSavePath());
|
|
s = buf + strlen(buf);
|
|
while ((*s++ = fetchScriptByte()));
|
|
|
|
// Use buf as filename
|
|
in = fopen(buf, "rb");
|
|
if (in) {
|
|
byte *ptr;
|
|
int len;
|
|
fseek(in, 0, SEEK_END);
|
|
len = ftell(in); // Determine file size
|
|
ptr = (byte *)calloc(len + 1, 1); // Create a zero terminated buffer
|
|
fseek(in, 0, SEEK_SET);
|
|
fread(ptr, len, 1, in); // Read in the data
|
|
fclose(in);
|
|
loadPtrToResource(rtString, a, ptr);
|
|
free(ptr);
|
|
}
|
|
break;
|
|
}
|
|
case 15: /* palmanip */
|
|
a = getVarOrDirectByte(0x80);
|
|
_opcode = fetchScriptByte();
|
|
b = getVarOrDirectByte(0x80);
|
|
c = getVarOrDirectByte(0x40);
|
|
_opcode = fetchScriptByte();
|
|
d = getVarOrDirectByte(0x80);
|
|
palManipulateInit(b, c, a, d);
|
|
break;
|
|
|
|
case 16:
|
|
a = getVarOrDirectByte(0x80);
|
|
b = getVarOrDirectByte(0x40);
|
|
if (a < 1)
|
|
a = 1; /* FIXME: ZAK256 */
|
|
checkRange(16, 1, a, "o5_roomOps: 16: color cycle out of range (%d)");
|
|
_colorCycle[a - 1].delay = (b != 0) ? 0x4000 / (b * 0x4C) : 0;
|
|
break;
|
|
default:
|
|
error("o5_roomOps: unknown subopcode %d\n", _opcode & 0x1F);
|
|
}
|
|
}
|
|
|
|
void Scumm_v5::o5_saveRestoreVerbs() {
|
|
int a, b, c, slot, slot2;
|
|
|
|
_opcode = fetchScriptByte();
|
|
|
|
a = getVarOrDirectByte(0x80);
|
|
b = getVarOrDirectByte(0x40);
|
|
c = getVarOrDirectByte(0x20);
|
|
|
|
switch (_opcode) {
|
|
case 1: /* hide verbs */
|
|
while (a <= b) {
|
|
slot = getVerbSlot(a, 0);
|
|
if (slot && _verbs[slot].saveid == 0) {
|
|
_verbs[slot].saveid = c;
|
|
drawVerb(slot, 0);
|
|
verbMouseOver(0);
|
|
}
|
|
a++;
|
|
}
|
|
break;
|
|
case 2: /* show verbs */
|
|
while (a <= b) {
|
|
slot = getVerbSlot(a, c);
|
|
if (slot) {
|
|
slot2 = getVerbSlot(a, 0);
|
|
if (slot2)
|
|
killVerb(slot2);
|
|
slot = getVerbSlot(a, c);
|
|
_verbs[slot].saveid = 0;
|
|
drawVerb(slot, 0);
|
|
verbMouseOver(0);
|
|
}
|
|
a++;
|
|
}
|
|
break;
|
|
case 3: /* kill verbs */
|
|
while (a <= b) {
|
|
slot = getVerbSlot(a, c);
|
|
if (slot)
|
|
killVerb(slot);
|
|
a++;
|
|
}
|
|
break;
|
|
default:
|
|
error("o5_saveRestoreVerbs: invalid opcode");
|
|
}
|
|
}
|
|
|
|
void Scumm_v5::o5_setCameraAt() {
|
|
setCameraAtEx(getVarOrDirectWord(0x80));
|
|
}
|
|
|
|
void Scumm_v5::o5_setObjectName() {
|
|
int obj = getVarOrDirectWord(0x80);
|
|
int size;
|
|
int a;
|
|
int i = 0;
|
|
byte *name = NULL;
|
|
unsigned char work[256];
|
|
|
|
// Read in new name
|
|
while ((a = fetchScriptByte()) != 0) {
|
|
work[i++] = a;
|
|
if (a == 0xFF) {
|
|
work[i++] = fetchScriptByte();
|
|
work[i++] = fetchScriptByte();
|
|
work[i++] = fetchScriptByte();
|
|
}
|
|
}
|
|
work[i] = 0;
|
|
|
|
if (obj < _numActors)
|
|
error("Can't set actor %d name with new-name-of", obj);
|
|
|
|
// TODO: Would be nice if we used rtObjectName resource for pre-V6
|
|
// games, too. The only problem with that which I can see is that this
|
|
// would break savegames. I.e. it would require yet another change to
|
|
// the save/load system.
|
|
|
|
byte *objptr;
|
|
objptr = getOBCDFromObject(obj);
|
|
if (objptr == NULL) {
|
|
// FIXME: Bug 587553. This is an odd one and looks more like
|
|
// an actual bug in the original script. Usually we would error
|
|
warning("Can't find OBCD to rename object %d to %s", obj, work);
|
|
return;
|
|
}
|
|
|
|
if (_features & GF_SMALL_HEADER) {
|
|
byte offset = 0;
|
|
|
|
if (_features & GF_OLD_BUNDLE)
|
|
offset = *(objptr + 16);
|
|
else
|
|
offset = READ_LE_UINT16(objptr + 18);
|
|
|
|
size = READ_LE_UINT16(objptr) - offset;
|
|
name = objptr + offset;
|
|
} else {
|
|
name = 0;
|
|
#if 0
|
|
name = findResourceData(MKID('OBNA'), objptr);
|
|
#else
|
|
// FIXME: we can't use findResourceData anymore, because it returns const
|
|
// data, while this function *must* return a non-const pointer. That is so
|
|
// because in o2_setObjectName / o5_setObjectName we directly modify this
|
|
// data. Now, we could add a non-const version of findResourceData, too
|
|
// (C++ makes that easy); but this here is really the *only* place in all
|
|
// of ScummVM where it wold be needed! That seems kind of a waste...
|
|
//
|
|
// So for now, I duplicate some code from findResourceData / findResource
|
|
// here. However, a much nicer solution might be (with stress on "might")
|
|
// to use the same technique as in V6 games: that is, use a seperate
|
|
// resource for changed names. That would be the cleanest solution, but
|
|
// might proof to be infeasible, as it might lead to unforseen regressions.
|
|
|
|
uint32 tag = MKID('OBNA');
|
|
byte *searchin = objptr;
|
|
uint32 curpos, totalsize;
|
|
|
|
assert(searchin);
|
|
|
|
searchin += 4;
|
|
totalsize = READ_BE_UINT32_UNALIGNED(searchin);
|
|
curpos = 8;
|
|
searchin += 4;
|
|
|
|
while (curpos < totalsize) {
|
|
if (READ_UINT32_UNALIGNED(searchin) == tag) {
|
|
name = searchin + _resourceHeaderSize;
|
|
break;
|
|
}
|
|
|
|
size = READ_BE_UINT32_UNALIGNED(searchin + 4);
|
|
if ((int32)size <= 0) {
|
|
error("(%c%c%c%c) Not found in %d... illegal block len %d",
|
|
tag & 0xFF, (tag >> 8) & 0xFF, (tag >> 16) & 0xFF, (tag >> 24) & 0xFF, 0, size);
|
|
}
|
|
|
|
curpos += size;
|
|
searchin += size;
|
|
}
|
|
#endif
|
|
size = getResourceDataSize(name);
|
|
}
|
|
|
|
if (name == 0)
|
|
return; // Silently bail out
|
|
|
|
|
|
if (i >= size) {
|
|
warning("New name of object %d too long (old *%s* new *%s*)", obj, name, work);
|
|
i = size - 1;
|
|
}
|
|
|
|
memcpy(name, work, i+1);
|
|
runHook(0);
|
|
}
|
|
|
|
void Scumm_v5::o5_setOwnerOf() {
|
|
int obj, owner;
|
|
|
|
obj = getVarOrDirectWord(0x80);
|
|
owner = getVarOrDirectByte(0x40);
|
|
|
|
setOwnerOf(obj, owner);
|
|
}
|
|
|
|
void Scumm_v5::o5_setState() {
|
|
int obj, state;
|
|
obj = getVarOrDirectWord(0x80);
|
|
state = getVarOrDirectByte(0x40);
|
|
putState(obj, state);
|
|
removeObjectFromRoom(obj);
|
|
if (_BgNeedsRedraw)
|
|
clearDrawObjectQueue();
|
|
}
|
|
|
|
void Scumm_v5::o5_setVarRange() {
|
|
int a, b;
|
|
|
|
getResultPos();
|
|
a = fetchScriptByte();
|
|
do {
|
|
if (_opcode & 0x80)
|
|
b = fetchScriptWordSigned();
|
|
else
|
|
b = fetchScriptByte();
|
|
|
|
setResult(b);
|
|
_resultVarNumber++;
|
|
} while (--a);
|
|
}
|
|
|
|
void Scumm_v5::o5_startMusic() {
|
|
_sound->addSoundToQueue(getVarOrDirectByte(0x80));
|
|
if (_gameId == GID_ZAK256) {
|
|
int a = fetchScriptByte();
|
|
int b = fetchScriptByte();
|
|
warning("Just skipped two bytes of unknown meaning: %d, %d", a, b);
|
|
}
|
|
}
|
|
|
|
void Scumm_v5::o5_startSound() {
|
|
VAR(VAR_MUSIC_TIMER) = 0;
|
|
_sound->addSoundToQueue(getVarOrDirectByte(0x80));
|
|
}
|
|
|
|
void Scumm_v5::o5_stopMusic() {
|
|
_sound->stopAllSounds();
|
|
}
|
|
|
|
void Scumm_v5::o5_stopSound() {
|
|
_sound->stopSound(getVarOrDirectByte(0x80));
|
|
}
|
|
|
|
void Scumm_v5::o5_isSoundRunning() {
|
|
int snd;
|
|
getResultPos();
|
|
snd = getVarOrDirectByte(0x80);
|
|
if (snd)
|
|
snd = _sound->isSoundRunning(snd);
|
|
setResult(snd);
|
|
}
|
|
|
|
void Scumm_v5::o5_soundKludge() {
|
|
int items[16];
|
|
int i;
|
|
|
|
if (_features & GF_SMALL_HEADER) { // Is WaitForSentence in SCUMM V3
|
|
if (_sentenceNum) {
|
|
if (_sentence[_sentenceNum - 1].freezeCount && !isScriptInUse(VAR(VAR_SENTENCE_SCRIPT)))
|
|
return;
|
|
} else if (!isScriptInUse(VAR(VAR_SENTENCE_SCRIPT)))
|
|
return;
|
|
|
|
_scriptPointer--;
|
|
o5_breakHere();
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < 16; i++)
|
|
items[i] = 0;
|
|
|
|
int num = getWordVararg(items);
|
|
|
|
_sound->soundKludge(items, num);
|
|
}
|
|
|
|
void Scumm_v5::o5_startObject() {
|
|
int obj, script;
|
|
int data[16];
|
|
|
|
obj = getVarOrDirectWord(0x80);
|
|
script = getVarOrDirectByte(0x40);
|
|
|
|
getWordVararg(data);
|
|
runObjectScript(obj, script, 0, 0, data);
|
|
}
|
|
|
|
void Scumm_v5::o5_startScript() {
|
|
int op, script;
|
|
int data[16];
|
|
|
|
op = _opcode;
|
|
script = getVarOrDirectByte(0x80);
|
|
|
|
getWordVararg(data);
|
|
|
|
runScript(script, (op & 0x20) != 0, (op & 0x40) != 0, data);
|
|
}
|
|
|
|
void Scumm_v5::o5_stopObjectCode() {
|
|
stopObjectCode();
|
|
}
|
|
|
|
void Scumm_v5::o5_stopObjectScript() {
|
|
stopObjectScript(getVarOrDirectWord(0x80));
|
|
}
|
|
|
|
void Scumm_v5::o5_stopScript() {
|
|
int script;
|
|
|
|
script = getVarOrDirectByte(0x80);
|
|
if (!script)
|
|
stopObjectCode();
|
|
else
|
|
stopScript(script);
|
|
}
|
|
|
|
void Scumm_v5::o5_stringOps() {
|
|
int a, b, c, i;
|
|
byte *ptr;
|
|
|
|
_opcode = fetchScriptByte();
|
|
switch (_opcode & 0x1F) {
|
|
case 1: /* loadstring */
|
|
loadPtrToResource(rtString, getVarOrDirectByte(0x80), NULL);
|
|
break;
|
|
case 2: /* copystring */
|
|
a = getVarOrDirectByte(0x80);
|
|
b = getVarOrDirectByte(0x40);
|
|
nukeResource(rtString, a);
|
|
ptr = getResourceAddress(rtString, b);
|
|
if (ptr)
|
|
loadPtrToResource(rtString, a, ptr);
|
|
break;
|
|
case 3: /* set string char */
|
|
a = getVarOrDirectByte(0x80);
|
|
b = getVarOrDirectByte(0x40);
|
|
c = getVarOrDirectByte(0x20);
|
|
ptr = getResourceAddress(rtString, a);
|
|
if (_gameId != GID_LOOM256) { /* FIXME - LOOM256 */
|
|
if (ptr == NULL)
|
|
error("String %d does not exist", a);
|
|
ptr[b] = c;
|
|
}
|
|
|
|
break;
|
|
|
|
case 4: /* get string char */
|
|
getResultPos();
|
|
a = getVarOrDirectByte(0x80);
|
|
b = getVarOrDirectByte(0x40);
|
|
ptr = getResourceAddress(rtString, a);
|
|
if (ptr == NULL)
|
|
error("String %d does not exist", a);
|
|
setResult(ptr[b]);
|
|
break;
|
|
|
|
case 5: /* create empty string */
|
|
a = getVarOrDirectByte(0x80);
|
|
b = getVarOrDirectByte(0x40);
|
|
nukeResource(rtString, a);
|
|
if (b) {
|
|
ptr = createResource(rtString, a, b);
|
|
if (ptr) {
|
|
for (i = 0; i < b; i++)
|
|
ptr[i] = 0;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Scumm_v5::o5_subtract() {
|
|
int a;
|
|
getResultPos();
|
|
a = getVarOrDirectWord(0x80);
|
|
setResult(readVar(_resultVarNumber) - a);
|
|
}
|
|
|
|
void Scumm_v5::o5_verbOps() {
|
|
int verb, slot;
|
|
VerbSlot *vs;
|
|
int a, b;
|
|
byte *ptr;
|
|
|
|
verb = getVarOrDirectByte(0x80);
|
|
|
|
slot = getVerbSlot(verb, 0);
|
|
checkRange(_maxVerbs - 1, 0, slot, "Illegal new verb slot %d");
|
|
|
|
vs = &_verbs[slot];
|
|
vs->verbid = verb;
|
|
|
|
while ((_opcode = fetchScriptByte()) != 0xFF) {
|
|
switch (_opcode & 0x1F) {
|
|
case 1: /* load image */
|
|
a = getVarOrDirectWord(0x80);
|
|
if (slot) {
|
|
setVerbObject(_roomResource, a, slot);
|
|
vs->type = kImageVerbType;
|
|
}
|
|
break;
|
|
case 2: /* load from code */
|
|
loadPtrToResource(rtVerb, slot, NULL);
|
|
if (slot == 0)
|
|
nukeResource(rtVerb, slot);
|
|
vs->type = kTextVerbType;
|
|
vs->imgindex = 0;
|
|
break;
|
|
case 3: /* color */
|
|
vs->color = getVarOrDirectByte(0x80);
|
|
break;
|
|
case 4: /* set hi color */
|
|
vs->hicolor = getVarOrDirectByte(0x80);
|
|
break;
|
|
case 5: /* set xy */
|
|
vs->x = getVarOrDirectWord(0x80);
|
|
vs->y = getVarOrDirectWord(0x40);
|
|
// FIXME: hack loom notes into right spot
|
|
if (_gameId == GID_LOOM256) {
|
|
if ((verb >= 90) && (verb <= 97)) { // Notes
|
|
switch (verb) {
|
|
case 90:
|
|
case 91:
|
|
vs->y -= 7;
|
|
break;
|
|
case 92:
|
|
vs->y -= 6;
|
|
break;
|
|
case 93:
|
|
vs->y -= 4;
|
|
break;
|
|
case 94:
|
|
vs->y -= 3;
|
|
break;
|
|
case 95:
|
|
vs->y -= 1;
|
|
break;
|
|
case 97:
|
|
vs->y -= 5;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 6: /* set on */
|
|
vs->curmode = 1;
|
|
break;
|
|
case 7: /* set off */
|
|
vs->curmode = 0;
|
|
break;
|
|
case 8: /* delete */
|
|
killVerb(slot);
|
|
break;
|
|
case 9: /* new */
|
|
slot = getVerbSlot(verb, 0);
|
|
if (slot == 0) {
|
|
for (slot = 1; slot < _maxVerbs; slot++) {
|
|
if (_verbs[slot].verbid == 0)
|
|
break;
|
|
}
|
|
if (slot == _maxVerbs)
|
|
error("Too many verbs");
|
|
}
|
|
vs = &_verbs[slot];
|
|
vs->verbid = verb;
|
|
vs->color = 2;
|
|
vs->hicolor = 0;
|
|
vs->dimcolor = 8;
|
|
vs->type = kTextVerbType;
|
|
vs->charset_nr = _string[0].t_charset;
|
|
vs->curmode = 0;
|
|
vs->saveid = 0;
|
|
vs->key = 0;
|
|
vs->center = 0;
|
|
vs->imgindex = 0;
|
|
break;
|
|
|
|
case 16: /* set dim color */
|
|
vs->dimcolor = getVarOrDirectByte(0x80);
|
|
break;
|
|
case 17: /* dim */
|
|
vs->curmode = 2;
|
|
break;
|
|
case 18: /* set key */
|
|
vs->key = getVarOrDirectByte(0x80);
|
|
break;
|
|
case 19: /* set center */
|
|
vs->center = 1;
|
|
break;
|
|
case 20: /* set to string */
|
|
ptr = getResourceAddress(rtString, getVarOrDirectWord(0x80));
|
|
if (!ptr)
|
|
nukeResource(rtVerb, slot);
|
|
else {
|
|
loadPtrToResource(rtVerb, slot, ptr);
|
|
}
|
|
if (slot == 0)
|
|
nukeResource(rtVerb, slot);
|
|
vs->type = kTextVerbType;
|
|
vs->imgindex = 0;
|
|
break;
|
|
case 22: /* assign object */
|
|
a = getVarOrDirectWord(0x80);
|
|
b = getVarOrDirectByte(0x40);
|
|
if (slot && vs->imgindex != a) {
|
|
setVerbObject(b, a, slot);
|
|
vs->type = kImageVerbType;
|
|
vs->imgindex = a;
|
|
}
|
|
break;
|
|
case 23: /* set back color */
|
|
vs->bkcolor = getVarOrDirectByte(0x80);
|
|
break;
|
|
}
|
|
}
|
|
drawVerb(slot, 0);
|
|
verbMouseOver(0);
|
|
}
|
|
|
|
void Scumm_v5::o5_wait() {
|
|
const byte *oldaddr = _scriptPointer - 1;
|
|
|
|
if ((_gameId == GID_INDY3_256) || (_gameId == GID_INDY3)) {
|
|
_opcode = 2;
|
|
} else
|
|
_opcode = fetchScriptByte();
|
|
|
|
switch (_opcode & 0x1F) {
|
|
case 1: { /* wait for actor */
|
|
Actor *a = derefActorSafe(getVarOrDirectByte(0x80), "o5_wait");
|
|
if (a && a->isInCurrentRoom() && a->moving)
|
|
break;
|
|
return;
|
|
}
|
|
case 2: /* wait for message */
|
|
if (VAR(VAR_HAVE_MSG))
|
|
break;
|
|
return;
|
|
case 3: /* wait for camera */
|
|
if (camera._cur.x >> 3 != camera._dest.x >> 3)
|
|
break;
|
|
return;
|
|
case 4: /* wait for sentence */
|
|
if (_sentenceNum) {
|
|
if (_sentence[_sentenceNum - 1].freezeCount && !isScriptInUse(VAR(VAR_SENTENCE_SCRIPT)))
|
|
return;
|
|
break;
|
|
}
|
|
if (!isScriptInUse(VAR(VAR_SENTENCE_SCRIPT)))
|
|
return;
|
|
break;
|
|
default:
|
|
error("o5_wait: default case");
|
|
return;
|
|
}
|
|
|
|
_scriptPointer = oldaddr;
|
|
o5_breakHere();
|
|
}
|
|
|
|
void Scumm_v5::o5_walkActorTo() {
|
|
int x, y;
|
|
Actor *a;
|
|
|
|
a = derefActor(getVarOrDirectByte(0x80), "o5_walkActorTo");
|
|
x = getVarOrDirectWord(0x40);
|
|
y = getVarOrDirectWord(0x20);
|
|
a->startWalkActor(x, y, -1);
|
|
}
|
|
|
|
void Scumm_v5::o5_walkActorToActor() {
|
|
int x;
|
|
Actor *a, *a2;
|
|
int nr = getVarOrDirectByte(0x80);
|
|
int nr2 = getVarOrDirectByte(0x40);
|
|
int dist = fetchScriptByte();
|
|
|
|
if (nr == 106 && _gameId == GID_INDY4) {
|
|
warning("Bypassing Indy4 bug");
|
|
return;
|
|
}
|
|
|
|
if (_gameId == GID_LOOM256 && nr == 1 && nr2 == 0 &&
|
|
dist == 255 && vm.slot[_currentScript].number == 98) {
|
|
// FIXME: Work around bug #743615. LoomCD script 98
|
|
// contains this: walkActorToActor(1,0,255)
|
|
// Once more this is either a script bug, or there is
|
|
// some hidden meaning in this odd walk request?
|
|
return;
|
|
}
|
|
|
|
a = derefActor(nr, "o5_walkActorToActor");
|
|
if (!a->isInCurrentRoom())
|
|
return;
|
|
|
|
a2 = derefActor(nr2, "o5_walkActorToActor(2)");
|
|
if (!a2->isInCurrentRoom())
|
|
return;
|
|
|
|
if (_features & GF_AFTER_V2)
|
|
dist *= 8;
|
|
else if (dist == 0xFF) {
|
|
dist = a2->scalex * a->width / 0xFF;
|
|
dist += dist / 2;
|
|
}
|
|
x = a2->x;
|
|
if (x < a->x)
|
|
x += dist;
|
|
else
|
|
x -= dist;
|
|
|
|
a->startWalkActor(x, a2->y, -1);
|
|
}
|
|
|
|
void Scumm_v5::o5_walkActorToObject() {
|
|
int obj;
|
|
Actor *a;
|
|
|
|
a = derefActor(getVarOrDirectByte(0x80), "o5_walkActorToObject");
|
|
obj = getVarOrDirectWord(0x40);
|
|
if (whereIsObject(obj) != WIO_NOT_FOUND) {
|
|
int x, y, dir;
|
|
getObjectXYPos(obj, x, y, dir);
|
|
a->startWalkActor(x, y, dir);
|
|
}
|
|
}
|
|
|
|
int Scumm_v5::getWordVararg(int *ptr) {
|
|
int i;
|
|
|
|
for (i = 0; i < 16; i++)
|
|
ptr[i] = 0;
|
|
|
|
i = 0;
|
|
while ((_opcode = fetchScriptByte()) != 0xFF) {
|
|
ptr[i++] = getVarOrDirectWord(0x80);
|
|
}
|
|
return i;
|
|
}
|
|
|
|
void Scumm_v5::decodeParseString() {
|
|
int textSlot;
|
|
|
|
switch (_actorToPrintStrFor) {
|
|
case 252:
|
|
textSlot = 3;
|
|
break;
|
|
case 253:
|
|
textSlot = 2;
|
|
break;
|
|
case 254:
|
|
textSlot = 1;
|
|
break;
|
|
default:
|
|
textSlot = 0;
|
|
}
|
|
|
|
setStringVars(textSlot);
|
|
|
|
while ((_opcode = fetchScriptByte()) != 0xFF) {
|
|
switch (_opcode & 0xF) {
|
|
case 0: /* set string xy */
|
|
_string[textSlot].xpos = getVarOrDirectWord(0x80);
|
|
_string[textSlot].ypos = getVarOrDirectWord(0x40);
|
|
_string[textSlot].overhead = false;
|
|
break;
|
|
case 1: /* color */
|
|
_string[textSlot].color = getVarOrDirectByte(0x80);
|
|
break;
|
|
case 2: /* clipping */
|
|
_string[textSlot].right = getVarOrDirectWord(0x80);
|
|
break;
|
|
case 3: /* erase */
|
|
{
|
|
int a = getVarOrDirectWord(0x80);
|
|
int b = getVarOrDirectWord(0x40);
|
|
warning("Scumm_v5::decodeParseString: Unhandled case 3: %d, %d", a, b);
|
|
}
|
|
break;
|
|
case 4: /* center */
|
|
_string[textSlot].center = true;
|
|
_string[textSlot].overhead = false;
|
|
break;
|
|
case 6: /* left */
|
|
// FIXME: not sure if GF_OLD_BUNDLE is the right thing to check...
|
|
// but Loom needs this, for sure.
|
|
if (_features & GF_OLD_BUNDLE) {
|
|
// FIXME: this value seems to be some kind of override
|
|
// for text spacing?!?
|
|
/* int a = */ getVarOrDirectWord(0x80);
|
|
|
|
} else {
|
|
_string[textSlot].center = false;
|
|
_string[textSlot].overhead = false;
|
|
}
|
|
break;
|
|
case 7: /* overhead */
|
|
_string[textSlot].overhead = true;
|
|
break;
|
|
case 8:{ /* play loom talkie sound - used in other games ? */
|
|
int offset = (uint16)getVarOrDirectWord(0x80);
|
|
int delay = (uint16)getVarOrDirectWord(0x40);
|
|
|
|
if (_gameId == GID_LOOM256) {
|
|
VAR(VAR_MUSIC_TIMER) = 0;
|
|
if (offset == 0 && delay == 0) {
|
|
_sound->stopCD();
|
|
} else {
|
|
// Loom specified the offset from the start of the CD;
|
|
// thus we have to subtract the lenght of the first track
|
|
// (22500 frames) plus the 2 second = 150 frame leadin.
|
|
// I.e. in total 22650 frames.
|
|
offset = (int)(offset * 7.5 - 22650);
|
|
|
|
// Slightly increase the delay (5 frames = 1/25 of a second).
|
|
// This noticably improves the experience in Loom CD.
|
|
delay = (int)(delay * 7.5 + 5);
|
|
|
|
_sound->playCDTrack(1, 0, offset, delay);
|
|
}
|
|
} else {
|
|
warning("parseString: 8");
|
|
}
|
|
}
|
|
break;
|
|
case 15:
|
|
_messagePtr = _scriptPointer;
|
|
switch (textSlot) {
|
|
case 0:
|
|
actorTalk();
|
|
break;
|
|
case 1:
|
|
drawString(1);
|
|
break;
|
|
case 2:
|
|
unkMessage1();
|
|
break;
|
|
case 3:
|
|
unkMessage2();
|
|
break;
|
|
}
|
|
|
|
// FIXME: Store positions, this is needed for Indy3 (Grail Diary)..
|
|
// I don't believe this is the correct fix, may cause other problems
|
|
// later in the game.
|
|
//
|
|
// It's also needed for Loom, or the lines Bobbin
|
|
// speaks during the intro are put at position 0,0.
|
|
// In addition, Loom needs to remember the text colour.
|
|
if (_gameId == GID_INDY3_256 || _gameId == GID_INDY3 || _gameId == GID_LOOM) {
|
|
_string[textSlot].t_xpos = _string[textSlot].xpos;
|
|
_string[textSlot].t_ypos = _string[textSlot].ypos;
|
|
_string[textSlot].t_color = _string[textSlot].color;
|
|
}
|
|
|
|
_scriptPointer = _messagePtr;
|
|
return;
|
|
default:
|
|
warning("Scumm_v5::decodeParseString: Unhandled case %d", _opcode & 0xF);
|
|
return;
|
|
}
|
|
}
|
|
|
|
_string[textSlot].t_xpos = _string[textSlot].xpos;
|
|
_string[textSlot].t_ypos = _string[textSlot].ypos;
|
|
_string[textSlot].t_center = _string[textSlot].center;
|
|
_string[textSlot].t_overhead = _string[textSlot].overhead;
|
|
_string[textSlot].t_right = _string[textSlot].right;
|
|
_string[textSlot].t_color = _string[textSlot].color;
|
|
_string[textSlot].t_charset = _string[textSlot].charset;
|
|
}
|
|
|
|
void Scumm_v5::o5_oldRoomEffect() {
|
|
int a;
|
|
|
|
_opcode = fetchScriptByte();
|
|
if ((_opcode & 0x1F) == 3) {
|
|
a = getVarOrDirectWord(0x80);
|
|
|
|
#if 1
|
|
if (_gameId == GID_ZAK256) {
|
|
// FIXME / TODO: OK the first thing to note is: at least in Zak256,
|
|
// maybe also in other games, this opcode does a bit more. I added
|
|
// some stubs here, but somebody with a full IDA or more knowledge
|
|
// about this will have to fill in the gaps. At least now we know
|
|
// that something is missing here :-)
|
|
|
|
if (a == 4) {
|
|
printf("o5_oldRoomEffect ODDBALL: _opcode = 0x%x, a = 0x%x\n", _opcode, a);
|
|
// No idea what byte_2FCCF is, but it's a globale boolean flag.
|
|
// I only add it here as a temporary hack to make the pseudo code compile.
|
|
// Maybe it is just there as a reentry protection guard, given
|
|
// how it is used?
|
|
int byte_2FCCF = 0;
|
|
|
|
if (byte_2FCCF) {
|
|
// Here now "sub_1C44" is called, which sets byte_2FCCF to 0 then
|
|
// calls yet another sub (which also reads byte_2FCCF):
|
|
|
|
byte_2FCCF = 0;
|
|
//call sub_0BB3
|
|
|
|
|
|
// Now sub_085C is called. This is quite simply: it sets
|
|
// 0xF000 bytes. starting at 0x40000 to 0. No idea what that
|
|
// buffer is, maybe a screen buffer, though. Note that
|
|
// 0xF000 = 320*192
|
|
|
|
// call sub_085C
|
|
|
|
|
|
// And then sub_1C54 is called, which is almost identical to
|
|
// the above sub_1C44, only it sets byte_2FCCF to 1:
|
|
|
|
byte_2FCCF = 1;
|
|
// call sub_0BB3
|
|
|
|
} else {
|
|
// Here only sub_085C is called (see comment above)
|
|
|
|
// call sub_085C
|
|
}
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
}
|
|
if (a) {
|
|
_switchRoomEffect = (byte)a;
|
|
_switchRoomEffect2 = (byte)(a >> 8);
|
|
} else {
|
|
fadeIn(_newEffect);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Scumm_v5::o5_pickupObjectOld() {
|
|
int obj = getVarOrDirectWord(0x80);
|
|
|
|
if (obj < 1) {
|
|
error("pickupObjectOld received invalid index %d (script %d)", obj, vm.slot[_currentScript].number);
|
|
}
|
|
|
|
if (getObjectIndex(obj) == -1)
|
|
return;
|
|
|
|
if (whereIsObject(obj) == WIO_INVENTORY) /* Don't take an */
|
|
return; /* object twice */
|
|
|
|
// warning("adding %d from %d to inventoryOld", obj, _currentRoom);
|
|
addObjectToInventory(obj, _roomResource);
|
|
removeObjectFromRoom(obj);
|
|
putOwner(obj, VAR(VAR_EGO));
|
|
putClass(obj, kObjectClassUntouchable, 1);
|
|
putState(obj, 1);
|
|
clearDrawObjectQueue();
|
|
runHook(1);
|
|
}
|