aboutsummaryrefslogtreecommitdiff
path: root/engines/scumm/he/script_v6he.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/scumm/he/script_v6he.cpp')
-rw-r--r--engines/scumm/he/script_v6he.cpp1276
1 files changed, 1276 insertions, 0 deletions
diff --git a/engines/scumm/he/script_v6he.cpp b/engines/scumm/he/script_v6he.cpp
new file mode 100644
index 0000000000..9d7de59450
--- /dev/null
+++ b/engines/scumm/he/script_v6he.cpp
@@ -0,0 +1,1276 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+#include "common/savefile.h"
+
+#include "scumm/actor.h"
+#include "scumm/charset.h"
+#include "scumm/imuse.h"
+#include "scumm/he/intern_he.h"
+#include "scumm/object.h"
+#include "scumm/resource.h"
+#include "scumm/scumm.h"
+#include "scumm/sound.h"
+#include "scumm/usage_bits.h"
+#include "scumm/util.h"
+#include "scumm/verbs.h"
+
+namespace Scumm {
+
+struct vsUnpackCtx {
+ uint8 size;
+ uint8 type;
+ uint8 b;
+ uint8 *ptr;
+};
+
+struct vsPackCtx {
+ int size;
+ uint8 buf[256];
+};
+
+static void virtScreenSavePackBuf(vsPackCtx *ctx, uint8 *&dst, int len);
+static void virtScreenSavePackByte(vsPackCtx *ctx, uint8 *&dst, int len, uint8 b);
+static uint8 virtScreenLoadUnpack(vsUnpackCtx *ctx, byte *data);
+static int virtScreenSavePack(byte *dst, byte *src, int len, int unk);
+
+// Compatibility notes:
+//
+// FBEAR (fbear, fbeardemo)
+// transparency in akos.cpp
+// negative size in file read/write
+
+#define OPCODE(x) _OPCODE(ScummEngine_v60he, x)
+
+void ScummEngine_v60he::setupOpcodes() {
+ static const OpcodeEntryv60he opcodes[256] = {
+ /* 00 */
+ OPCODE(o6_pushByte),
+ OPCODE(o6_pushWord),
+ OPCODE(o6_pushByteVar),
+ OPCODE(o6_pushWordVar),
+ /* 04 */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_byteArrayRead),
+ OPCODE(o6_wordArrayRead),
+ /* 08 */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_byteArrayIndexedRead),
+ OPCODE(o6_wordArrayIndexedRead),
+ /* 0C */
+ OPCODE(o6_dup),
+ OPCODE(o6_not),
+ OPCODE(o6_eq),
+ OPCODE(o6_neq),
+ /* 10 */
+ OPCODE(o6_gt),
+ OPCODE(o6_lt),
+ OPCODE(o6_le),
+ OPCODE(o6_ge),
+ /* 14 */
+ OPCODE(o6_add),
+ OPCODE(o6_sub),
+ OPCODE(o6_mul),
+ OPCODE(o6_div),
+ /* 18 */
+ OPCODE(o6_land),
+ OPCODE(o6_lor),
+ OPCODE(o6_pop),
+ 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_writeByteVar),
+ OPCODE(o6_writeWordVar),
+ /* 44 */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_byteArrayWrite),
+ OPCODE(o6_wordArrayWrite),
+ /* 48 */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_byteArrayIndexedWrite),
+ OPCODE(o6_wordArrayIndexedWrite),
+ /* 4C */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_byteVarInc),
+ OPCODE(o6_wordVarInc),
+ /* 50 */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_byteArrayInc),
+ OPCODE(o6_wordArrayInc),
+ /* 54 */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_byteVarDec),
+ OPCODE(o6_wordVarDec),
+ /* 58 */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_byteArrayDec),
+ OPCODE(o6_wordArrayDec),
+ /* 5C */
+ OPCODE(o6_if),
+ OPCODE(o6_ifNot),
+ OPCODE(o6_startScript),
+ OPCODE(o6_startScriptQuick),
+ /* 60 */
+ OPCODE(o6_startObject),
+ OPCODE(o6_drawObject),
+ OPCODE(o6_drawObjectAt),
+ OPCODE(o6_invalid),
+ /* 64 */
+ OPCODE(o6_invalid),
+ OPCODE(o6_stopObjectCode),
+ OPCODE(o6_stopObjectCode),
+ OPCODE(o6_endCutscene),
+ /* 68 */
+ OPCODE(o6_cutscene),
+ OPCODE(o6_stopMusic),
+ OPCODE(o6_freezeUnfreeze),
+ OPCODE(o6_cursorCommand),
+ /* 6C */
+ OPCODE(o6_breakHere),
+ OPCODE(o6_ifClassOfIs),
+ OPCODE(o6_setClass),
+ OPCODE(o6_getState),
+ /* 70 */
+ OPCODE(o60_setState),
+ OPCODE(o6_setOwner),
+ OPCODE(o6_getOwner),
+ OPCODE(o6_jump),
+ /* 74 */
+ OPCODE(o6_startSound),
+ OPCODE(o6_stopSound),
+ OPCODE(o6_startMusic),
+ OPCODE(o6_stopObjectScript),
+ /* 78 */
+ OPCODE(o6_panCameraTo),
+ OPCODE(o6_actorFollowCamera),
+ OPCODE(o6_setCameraAt),
+ OPCODE(o6_loadRoom),
+ /* 7C */
+ OPCODE(o6_stopScript),
+ OPCODE(o6_walkActorToObj),
+ OPCODE(o6_walkActorTo),
+ OPCODE(o6_putActorAtXY),
+ /* 80 */
+ OPCODE(o6_putActorAtObject),
+ OPCODE(o6_faceActor),
+ OPCODE(o6_animateActor),
+ OPCODE(o6_doSentence),
+ /* 84 */
+ OPCODE(o6_pickupObject),
+ OPCODE(o6_loadRoomWithEgo),
+ OPCODE(o6_invalid),
+ OPCODE(o6_getRandomNumber),
+ /* 88 */
+ OPCODE(o6_getRandomNumberRange),
+ OPCODE(o6_invalid),
+ OPCODE(o6_getActorMoving),
+ OPCODE(o6_isScriptRunning),
+ /* 8C */
+ OPCODE(o6_getActorRoom),
+ OPCODE(o6_getObjectX),
+ OPCODE(o6_getObjectY),
+ OPCODE(o6_getObjectOldDir),
+ /* 90 */
+ OPCODE(o6_getActorWalkBox),
+ OPCODE(o6_getActorCostume),
+ OPCODE(o6_findInventory),
+ OPCODE(o6_getInventoryCount),
+ /* 94 */
+ OPCODE(o6_getVerbFromXY),
+ OPCODE(o6_beginOverride),
+ OPCODE(o6_endOverride),
+ OPCODE(o6_setObjectName),
+ /* 98 */
+ OPCODE(o6_isSoundRunning),
+ OPCODE(o6_setBoxFlags),
+ OPCODE(o6_invalid),
+ OPCODE(o6_resourceRoutines),
+ /* 9C */
+ OPCODE(o60_roomOps),
+ OPCODE(o60_actorOps),
+ OPCODE(o6_verbOps),
+ OPCODE(o6_getActorFromXY),
+ /* A0 */
+ OPCODE(o6_findObject),
+ OPCODE(o6_pseudoRoom),
+ OPCODE(o6_getActorElevation),
+ OPCODE(o6_getVerbEntrypoint),
+ /* A4 */
+ OPCODE(o6_arrayOps),
+ OPCODE(o6_saveRestoreVerbs),
+ OPCODE(o6_drawBox),
+ OPCODE(o6_pop),
+ /* A8 */
+ OPCODE(o6_getActorWidth),
+ OPCODE(o6_wait),
+ OPCODE(o6_getActorScaleX),
+ OPCODE(o6_getActorAnimCounter1),
+ /* AC */
+ OPCODE(o6_invalid),
+ OPCODE(o6_isAnyOf),
+ OPCODE(o6_systemOps),
+ OPCODE(o6_isActorInBox),
+ /* B0 */
+ OPCODE(o6_delay),
+ OPCODE(o6_delaySeconds),
+ OPCODE(o6_delayMinutes),
+ OPCODE(o6_stopSentence),
+ /* B4 */
+ OPCODE(o6_printLine),
+ OPCODE(o6_printText),
+ OPCODE(o6_printDebug),
+ OPCODE(o6_printSystem),
+ /* B8 */
+ OPCODE(o6_printActor),
+ OPCODE(o6_printEgo),
+ OPCODE(o6_talkActor),
+ OPCODE(o6_talkEgo),
+ /* BC */
+ OPCODE(o6_dimArray),
+ OPCODE(o6_stopObjectCode),
+ OPCODE(o6_startObjectQuick),
+ OPCODE(o6_startScriptQuick2),
+ /* C0 */
+ OPCODE(o6_dim2dimArray),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ /* C4 */
+ OPCODE(o6_abs),
+ OPCODE(o6_distObjectObject),
+ OPCODE(o6_distObjectPt),
+ OPCODE(o6_distPtPt),
+ /* C8 */
+ OPCODE(o60_kernelGetFunctions),
+ OPCODE(o60_kernelSetFunctions),
+ OPCODE(o6_delayFrames),
+ OPCODE(o6_pickOneOf),
+ /* CC */
+ OPCODE(o6_pickOneOfDefault),
+ OPCODE(o6_stampObject),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ /* D0 */
+ OPCODE(o6_getDateTime),
+ OPCODE(o6_stopTalking),
+ OPCODE(o6_getAnimateVariable),
+ OPCODE(o6_invalid),
+ /* D4 */
+ OPCODE(o6_shuffle),
+ OPCODE(o6_jumpToScript),
+ OPCODE(o6_band),
+ OPCODE(o6_bor),
+ /* D8 */
+ OPCODE(o6_isRoomScriptRunning),
+ OPCODE(o60_closeFile),
+ OPCODE(o60_openFile),
+ OPCODE(o60_readFile),
+ /* DC */
+ OPCODE(o60_writeFile),
+ OPCODE(o6_findAllObjects),
+ OPCODE(o60_deleteFile),
+ OPCODE(o60_rename),
+ /* E0 */
+ OPCODE(o60_soundOps),
+ OPCODE(o6_getPixel),
+ OPCODE(o60_localizeArrayToScript),
+ OPCODE(o6_pickVarRandom),
+ /* E4 */
+ OPCODE(o6_setBoxSet),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ /* E8 */
+ OPCODE(o6_invalid),
+ OPCODE(o60_seekFilePos),
+ OPCODE(o60_redimArray),
+ OPCODE(o60_readFilePos),
+ /* EC */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ /* F0 */
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ OPCODE(o6_invalid),
+ /* 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),
+ };
+
+ _opcodesv60he = opcodes;
+}
+
+void ScummEngine_v60he::executeOpcode(byte i) {
+ OpcodeProcv60he op = _opcodesv60he[i].proc;
+ (this->*op) ();
+}
+
+const char *ScummEngine_v60he::getOpcodeDesc(byte i) {
+ return _opcodesv60he[i].desc;
+}
+
+void ScummEngine_v60he::o60_setState() {
+ int state = pop();
+ int obj = pop();
+
+ if (state & 0x8000) {
+ state &= 0x7FFF;
+ putState(obj, state);
+ if (_heversion >= 72)
+ removeObjectFromDrawQue(obj);
+ } else {
+ putState(obj, state);
+ markObjectRectAsDirty(obj);
+ if (_bgNeedsRedraw)
+ clearDrawObjectQueue();
+ }
+}
+
+void ScummEngine_v60he::o60_roomOps() {
+ int a, b, c, d, e;
+
+ byte subOp = fetchScriptByte();
+
+ switch (subOp) {
+ case 172: // SO_ROOM_SCROLL
+ b = pop();
+ a = pop();
+ 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 174: // SO_ROOM_SCREEN
+ b = pop();
+ a = pop();
+ if (_heversion >= 71)
+ initScreens(a, _screenHeight);
+ else
+ initScreens(a, b);
+ break;
+
+ case 175: // SO_ROOM_PALETTE
+ d = pop();
+ c = pop();
+ b = pop();
+ a = pop();
+ setPalColor(d, a, b, c);
+ break;
+
+ case 176: // SO_ROOM_SHAKE_ON
+ setShake(1);
+ break;
+
+ case 177: // SO_ROOM_SHAKE_OFF
+ setShake(0);
+ break;
+
+ case 179: // SO_ROOM_INTENSITY
+ c = pop();
+ b = pop();
+ a = pop();
+ darkenPalette(a, a, a, b, c);
+ break;
+
+ case 180: // SO_ROOM_SAVEGAME
+ _saveTemporaryState = true;
+ _saveLoadSlot = pop();
+ _saveLoadFlag = pop();
+ break;
+
+ case 181: // SO_ROOM_FADE
+ a = pop();
+ if (_heversion >= 70) {
+ // Defaults to 1 but doesn't use fade effects
+ } else if (a) {
+ _switchRoomEffect = (byte)(a & 0xFF);
+ _switchRoomEffect2 = (byte)(a >> 8);
+ } else {
+ fadeIn(_newEffect);
+ }
+ break;
+
+ case 182: // SO_RGB_ROOM_INTENSITY
+ e = pop();
+ d = pop();
+ c = pop();
+ b = pop();
+ a = pop();
+ darkenPalette(a, b, c, d, e);
+ break;
+
+ case 183: // SO_ROOM_SHADOW
+ e = pop();
+ d = pop();
+ c = pop();
+ b = pop();
+ a = pop();
+ if (_heversion == 60)
+ setupShadowPalette(a, b, c, d, e, 0, 256);
+ break;
+
+ case 186: // SO_ROOM_TRANSFORM
+ d = pop();
+ c = pop();
+ b = pop();
+ a = pop();
+ palManipulateInit(a, b, c, d);
+ break;
+
+ case 187: // SO_CYCLE_SPEED
+ b = pop();
+ a = pop();
+ checkRange(16, 1, a, "o60_roomOps: 187: color cycle out of range (%d)");
+ _colorCycle[a - 1].delay = (b != 0) ? 0x4000 / (b * 0x4C) : 0;
+ break;
+
+ case 213: // SO_ROOM_NEW_PALETTE
+ a = pop();
+ setPalette(a);
+ break;
+ case 220:
+ a = pop();
+ b = pop();
+ copyPalColor(a, b);
+ break;
+ case 221:
+ int len;
+ len = resStrLen(_scriptPointer);
+ _scriptPointer += len + 1;
+ _saveLoadFlag = pop();
+ _saveLoadSlot = 1;
+ _saveTemporaryState = true;
+ break;
+ case 234: // HE 7.2
+ b = pop();
+ a = pop();
+ swapObjects(a, b);
+ break;
+ case 236: // HE 7.2
+ b = pop();
+ a = pop();
+ setRoomPalette(a, b);
+ break;
+ default:
+ error("o60_roomOps: default case %d", subOp);
+ }
+}
+
+void ScummEngine_v60he::swapObjects(int object1, int object2) {
+ int idx1 = -1, idx2 = -1;
+
+ for (int i = 0; i < _numLocalObjects; i++) {
+ if (_objs[i].obj_nr == object1)
+ idx1 = i;
+
+ if (_objs[i].obj_nr == object2)
+ idx2 = i;
+ }
+
+ if (idx1 == -1 || idx2 == -1 || idx1 <= idx2)
+ return;
+
+ stopObjectScript(object1);
+ stopObjectScript(object2);
+
+ ObjectData tmpOd;
+
+ memcpy(&tmpOd, &_objs[idx1], sizeof(tmpOd));
+ memcpy(&_objs[idx1], &_objs[idx2], sizeof(tmpOd));
+ memcpy(&_objs[idx2], &tmpOd, sizeof(tmpOd));
+}
+
+void ScummEngine_v60he::o60_actorOps() {
+ Actor *a;
+ int i, j, k;
+ int args[8];
+
+ byte subOp = fetchScriptByte();
+ if (subOp == 197) {
+ _curActor = pop();
+ return;
+ }
+
+ a = derefActorSafe(_curActor, "o60_actorOps");
+ if (!a)
+ return;
+
+ switch (subOp) {
+ case 30:
+ // _heversion >= 70
+ _actorClipOverride.bottom = pop();
+ _actorClipOverride.right = pop();
+ _actorClipOverride.top = pop();
+ _actorClipOverride.left = pop();
+ break;
+ case 76: // SO_COSTUME
+ a->setActorCostume(pop());
+ break;
+ case 77: // SO_STEP_DIST
+ j = pop();
+ i = pop();
+ a->setActorWalkSpeed(i, j);
+ break;
+ case 78: // SO_SOUND
+ k = getStackList(args, ARRAYSIZE(args));
+ for (i = 0; i < k; i++)
+ a->_sound[i] = args[i];
+ break;
+ case 79: // SO_WALK_ANIMATION
+ a->_walkFrame = pop();
+ break;
+ case 80: // SO_TALK_ANIMATION
+ a->_talkStopFrame = pop();
+ a->_talkStartFrame = pop();
+ break;
+ case 81: // SO_STAND_ANIMATION
+ a->_standFrame = pop();
+ break;
+ case 82: // SO_ANIMATION
+ // dummy case in scumm6
+ pop();
+ pop();
+ pop();
+ break;
+ case 83: // SO_DEFAULT
+ a->initActor(0);
+ break;
+ case 84: // SO_ELEVATION
+ a->setElevation(pop());
+ break;
+ case 85: // SO_ANIMATION_DEFAULT
+ a->_initFrame = 1;
+ a->_walkFrame = 2;
+ a->_standFrame = 3;
+ a->_talkStartFrame = 4;
+ a->_talkStopFrame = 5;
+ break;
+ case 86: // SO_PALETTE
+ j = pop();
+ i = pop();
+ checkRange(255, 0, i, "Illegal palette slot %d");
+ a->remapActorPaletteColor(i, j);
+ a->_needRedraw = true;
+ break;
+ case 87: // SO_TALK_COLOR
+ a->_talkColor = pop();
+ break;
+ case 88: // SO_ACTOR_NAME
+ loadPtrToResource(rtActorName, a->_number, NULL);
+ break;
+ case 89: // SO_INIT_ANIMATION
+ a->_initFrame = pop();
+ break;
+ case 91: // SO_ACTOR_WIDTH
+ a->_width = pop();
+ break;
+ case 92: // SO_SCALE
+ i = pop();
+ a->setScale(i, i);
+ break;
+ case 93: // SO_NEVER_ZCLIP
+ a->_forceClip = 0;
+ break;
+ case 94: // SO_ALWAYS_ZCLIP
+ a->_forceClip = pop();
+ break;
+ case 95: // SO_IGNORE_BOXES
+ a->_ignoreBoxes = 1;
+ a->_forceClip = 0;
+ if (a->isInCurrentRoom())
+ a->putActor(a->_pos.x, a->_pos.y, a->_room);
+ break;
+ case 96: // SO_FOLLOW_BOXES
+ a->_ignoreBoxes = 0;
+ a->_forceClip = 0;
+ if (a->isInCurrentRoom())
+ a->putActor(a->_pos.x, a->_pos.y, a->_room);
+ break;
+ case 97: // SO_ANIMATION_SPEED
+ a->setAnimSpeed(pop());
+ break;
+ case 98: // SO_SHADOW
+ a->_shadowMode = pop();
+ a->_needRedraw = true;
+ break;
+ case 99: // SO_TEXT_OFFSET
+ a->_talkPosY = pop();
+ a->_talkPosX = pop();
+ break;
+ case 156: // HE 7.2
+ a->_charset = pop();
+ break;
+ case 198: // SO_ACTOR_VARIABLE
+ i = pop();
+ a->setAnimVar(pop(), i);
+ break;
+ case 215: // SO_ACTOR_IGNORE_TURNS_ON
+ a->_ignoreTurns = true;
+ break;
+ case 216: // SO_ACTOR_IGNORE_TURNS_OFF
+ a->_ignoreTurns = false;
+ break;
+ case 217: // SO_ACTOR_NEW
+ a->initActor(2);
+ break;
+ case 218:
+ a->drawActorToBackBuf(a->_pos.x, a->_pos.y);
+ break;
+ case 219:
+ a->_drawToBackBuf = false;
+ a->_needRedraw = true;
+ a->_needBgReset = true;
+ break;
+ case 225:
+ {
+ byte string[128];
+ copyScriptString(string);
+ int slot = pop();
+
+ int len = resStrLen(string) + 1;
+ convertMessageToString(string, a->_heTalkQueue[slot].sentence, len);
+
+ a->_heTalkQueue[slot].posX = a->_talkPosX;
+ a->_heTalkQueue[slot].posY = a->_talkPosY;
+ a->_heTalkQueue[slot].color = a->_talkColor;
+ break;
+ }
+ default:
+ error("o60_actorOps: default case %d", subOp);
+ }
+}
+
+void ScummEngine_v60he::o60_kernelSetFunctions() {
+ int args[29];
+ int num;
+
+ num = getStackList(args, ARRAYSIZE(args));
+
+ switch (args[0]) {
+ case 1:
+ // Used to restore images when decorating cake in
+ // Fatty Bear's Birthday Surprise
+ virtScreenLoad(args[1], args[2], args[3], args[4], args[5]);
+ break;
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 8:
+ //Used before mini games in 3DO versions, seems safe to ignore.
+ break;
+ default:
+ error("o60_kernelSetFunctions: default case %d (param count %d)", args[0], num);
+ }
+}
+
+void ScummEngine_v60he::virtScreenLoad(int resIdx, int x1, int y1, int x2, int y2) {
+ vsUnpackCtx ctx;
+ memset(&ctx, 0, sizeof(ctx));
+ VirtScreen &vs = virtscr[kMainVirtScreen];
+
+ ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, resIdx);
+ virtScreenLoadUnpack(&ctx, ah->data);
+ for (int j = y1; j <= y2; ++j) {
+ uint8 *p1 = vs.getPixels(x1, j - vs.topline);
+ uint8 *p2 = vs.getBackPixels(x1, j - vs.topline);
+ if (x2 >= x1) {
+ uint32 w = x2 - x1 + 1;
+ while (w--) {
+ uint8 decByte = virtScreenLoadUnpack(&ctx, 0);
+ *p1++ = decByte;
+ *p2++ = decByte;
+ }
+ }
+ }
+ markRectAsDirty(kMainVirtScreen, x1, x2, y1, y2 + 1, USAGE_BIT_RESTORED);
+}
+
+uint8 virtScreenLoadUnpack(vsUnpackCtx *ctx, byte *data) {
+ uint8 decByte;
+ if (data != 0) {
+ ctx->type = 0;
+ ctx->ptr = data;
+ decByte = 0;
+ } else {
+ uint8 a;
+ if (ctx->type == 0) {
+ a = *(ctx->ptr)++;
+ if (a & 1) {
+ ctx->type = 1;
+ ctx->b = *(ctx->ptr)++;
+ } else {
+ ctx->type = 2;
+ }
+ ctx->size = a;
+ a = (a >> 1) + 1;
+ } else {
+ a = ctx->size;
+ }
+ if (ctx->type == 2) {
+ ctx->b = *(ctx->ptr)++;
+ }
+ ctx->size = a - 1;
+ if (ctx->size == 0) {
+ ctx->type = 0;
+ }
+ decByte = ctx->b;
+ }
+ return decByte;
+}
+
+
+void ScummEngine_v60he::o60_kernelGetFunctions() {
+ int args[29];
+ ArrayHeader *ah;
+ getStackList(args, ARRAYSIZE(args));
+
+ switch (args[0]) {
+ case 1:
+ // Used to store images when decorating cake in
+ // Fatty Bear's Birthday Surprise
+ writeVar(0, 0);
+ ah = defineArray(0, kByteArray, 0, virtScreenSave(0, args[1], args[2], args[3], args[4]));
+ virtScreenSave(ah->data, args[1], args[2], args[3], args[4]);
+ push(readVar(0));
+ break;
+ default:
+ error("o60_kernelGetFunctions: default case %d", args[0]);
+ }
+}
+
+int ScummEngine_v60he::virtScreenSave(byte *dst, int x1, int y1, int x2, int y2) {
+ int packedSize = 0;
+ VirtScreen &vs = virtscr[kMainVirtScreen];
+
+ for (int j = y1; j <= y2; ++j) {
+ uint8 *p = vs.getBackPixels(x1, j - vs.topline);
+
+ int size = virtScreenSavePack(dst, p, x2 - x1 + 1, 0);
+ if (dst != 0) {
+ dst += size;
+ }
+ packedSize += size;
+ }
+ return packedSize;
+}
+
+int virtScreenSavePack(byte *dst, byte *src, int len, int unk) {
+ vsPackCtx ctx;
+ memset(&ctx, 0, sizeof(ctx));
+
+ uint8 prevByte, curByte;
+
+ ctx.buf[0] = prevByte = *src++;
+ int flag = 0;
+ int iend = 1;
+ int ibeg = 0;
+
+ for (--len; len != 0; --len, prevByte = curByte) {
+ bool pass = false;
+
+ assert(iend < 0x100);
+ ctx.buf[iend] = curByte = *src++;
+ ++iend;
+
+ if (flag == 0) {
+ if (iend > 0x80) {
+ virtScreenSavePackBuf(&ctx, dst, iend - 1);
+ ctx.buf[0] = curByte;
+ iend = 1;
+ ibeg = 0;
+ continue;
+ }
+ if (prevByte != curByte) {
+ ibeg = iend - 1;
+ continue;
+ }
+ if (iend - ibeg < 3) {
+ if (ibeg != 0) {
+ pass = true;
+ } else {
+ flag = 1;
+ }
+ } else {
+ if (ibeg > 0) {
+ virtScreenSavePackBuf(&ctx, dst, ibeg);
+ }
+ flag = 1;
+ }
+ }
+ if (flag == 1 || pass) {
+ if (prevByte != curByte || iend - ibeg > 0x80) {
+ virtScreenSavePackByte(&ctx, dst, iend - ibeg - 1, prevByte);
+ ctx.buf[0] = curByte;
+ iend = 1;
+ ibeg = 0;
+ flag = 0;
+ }
+ }
+ }
+
+ if (flag == 0) {
+ virtScreenSavePackBuf(&ctx, dst, iend);
+ } else if (flag == 1) {
+ virtScreenSavePackByte(&ctx, dst, iend - ibeg, prevByte);
+ }
+ return ctx.size;
+}
+
+void virtScreenSavePackBuf(vsPackCtx *ctx, uint8 *&dst, int len) {
+ if (dst) {
+ *dst++ = (len - 1) * 2;
+ }
+ ++ctx->size;
+ if (len > 0) {
+ ctx->size += len;
+ if (dst) {
+ memcpy(dst, ctx->buf, len);
+ dst += len;
+ }
+ }
+}
+
+void virtScreenSavePackByte(vsPackCtx *ctx, uint8 *&dst, int len, uint8 b) {
+ if (dst) {
+ *dst++ = ((len - 1) * 2) | 1;
+ }
+ ++ctx->size;
+ if (dst) {
+ *dst++ = b;
+ }
+ ++ctx->size;
+}
+
+void ScummEngine_v60he::o60_openFile() {
+ int mode, len, slot, l, r;
+ byte filename[100];
+
+ convertMessageToString(_scriptPointer, filename, sizeof(filename));
+
+ len = resStrLen(_scriptPointer);
+ _scriptPointer += len + 1;
+
+ for (r = strlen((char*)filename); r != 0; r--) {
+ if (filename[r - 1] == '\\')
+ break;
+ }
+
+ mode = pop();
+ slot = -1;
+ for (l = 0; l < 17; l++) {
+ if (_hFileTable[l].isOpen() == false) {
+ slot = l;
+ break;
+ }
+ }
+
+ if (slot != -1) {
+ switch(mode) {
+ case 1:
+ _hFileTable[slot].open((char*)filename + r, Common::File::kFileReadMode, _saveFileMan->getSavePath());
+ if (_hFileTable[slot].isOpen() == false)
+ _hFileTable[slot].open((char*)filename + r, Common::File::kFileReadMode);
+ break;
+ case 2:
+ _hFileTable[slot].open((char*)filename + r, Common::File::kFileWriteMode, _saveFileMan->getSavePath());
+ break;
+ default:
+ error("o60_openFile(): wrong open file mode %d", mode);
+ }
+
+ if (_hFileTable[slot].isOpen() == false)
+ slot = -1;
+
+ }
+ push(slot);
+}
+
+void ScummEngine_v60he::o60_closeFile() {
+ int slot = pop();
+ if (slot != -1)
+ _hFileTable[slot].close();
+}
+
+void ScummEngine_v60he::o60_deleteFile() {
+ int len, r;
+ byte filename[100];
+
+ convertMessageToString(_scriptPointer, filename, sizeof(filename));
+
+ len = resStrLen(_scriptPointer);
+ _scriptPointer += len + 1;
+
+ for (r = strlen((char*)filename); r != 0; r--) {
+ if (filename[r - 1] == '\\')
+ break;
+ }
+
+ debug(1, "stub o60_deleteFile(\"%s\")", filename + r);
+}
+
+void ScummEngine_v60he::o60_rename() {
+ int len, r1, r2;
+ byte filename[100],filename2[100];
+
+ convertMessageToString(_scriptPointer, filename, sizeof(filename));
+
+ len = resStrLen(_scriptPointer);
+ _scriptPointer += len + 1;
+
+ for (r1 = strlen((char*)filename); r1 != 0; r1--) {
+ if (filename[r1 - 1] == '\\')
+ break;
+ }
+
+ convertMessageToString(_scriptPointer, filename2, sizeof(filename2));
+
+ len = resStrLen(_scriptPointer);
+ _scriptPointer += len + 1;
+
+ for (r2 = strlen((char*)filename2); r2 != 0; r2--) {
+ if (filename2[r2 - 1] == '\\')
+ break;
+ }
+
+ debug(1, "stub o60_rename(\"%s\" to \"%s\")", filename + r1, filename2 + r2);
+}
+
+int ScummEngine_v60he::readFileToArray(int slot, int32 size) {
+ if (size == 0)
+ size = _hFileTable[slot].size() - _hFileTable[slot].pos();
+
+ writeVar(0, 0);
+
+ ArrayHeader *ah = defineArray(0, kByteArray, 0, size);
+ _hFileTable[slot].read(ah->data, size);
+
+ return readVar(0);
+}
+
+void ScummEngine_v60he::o60_readFile() {
+ int32 size = pop();
+ int slot = pop();
+ int val;
+
+ // Fatty Bear uses positive values
+ if ((_platform == Common::kPlatformPC) && (_gameId == GID_FBEAR))
+ size = -size;
+
+ if (size == -2) {
+ val = _hFileTable[slot].readUint16LE();
+ push(val);
+ } else if (size == -1) {
+ val = _hFileTable[slot].readByte();
+ push(val);
+ } else {
+ val = readFileToArray(slot, size);
+ push(val);
+ }
+}
+
+void ScummEngine_v60he::writeFileFromArray(int slot, int resID) {
+ ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, resID);
+ int32 size = FROM_LE_16(ah->dim1) * FROM_LE_16(ah->dim2);
+
+ _hFileTable[slot].write(ah->data, size);
+}
+
+void ScummEngine_v60he::o60_writeFile() {
+ int32 size = pop();
+ int16 resID = pop();
+ int slot = pop();
+
+ // Fatty Bear uses positive values
+ if ((_platform == Common::kPlatformPC) && (_gameId == GID_FBEAR))
+ size = -size;
+
+ if (size == -2) {
+ _hFileTable[slot].writeUint16LE(resID);
+ } else if (size == -1) {
+ _hFileTable[slot].writeByte(resID);
+ } else {
+ writeFileFromArray(slot, resID);
+ }
+}
+
+void ScummEngine_v60he::o60_soundOps() {
+ byte subOp = fetchScriptByte();
+ int arg = pop();
+
+ switch (subOp) {
+ case 0xde:
+ _imuse->setMusicVolume(arg);
+ break;
+ case 0xdf:
+ // Used in fbear introduction
+ break;
+ case 0xe0:
+ // Fatty Bear's Birthday surprise uses this when playing the
+ // piano, but only when using one of the digitized instruments.
+ // See also o6_startSound().
+ _sound->setOverrideFreq(arg);
+ break;
+ default:
+ error("o60_soundOps: default case 0x%x", subOp);
+ }
+}
+
+void ScummEngine_v60he::localizeArray(int slot, byte scriptSlot) {
+ if (_heversion >= 80)
+ slot &= ~0x33539000;
+
+ if (slot >= _numArray)
+ error("o60_localizeArrayToScript(%d): array slot out of range", slot);
+
+ _arraySlot[slot] = scriptSlot;
+}
+
+void ScummEngine_v60he::o60_localizeArrayToScript() {
+ int slot = pop();
+ localizeArray(slot, _currentScript);
+}
+
+void ScummEngine_v60he::o60_seekFilePos() {
+ int mode, offset, slot;
+
+ mode = pop();
+ offset = pop();
+ slot = pop();
+
+ if (slot == -1)
+ return;
+
+ switch (mode) {
+ case 1:
+ _hFileTable[slot].seek(offset, SEEK_SET);
+ break;
+ case 2:
+ _hFileTable[slot].seek(offset, SEEK_CUR);
+ break;
+ case 3:
+ _hFileTable[slot].seek(offset, SEEK_END);
+ break;
+ default:
+ error("o60_seekFilePos: default case %d", mode);
+ }
+}
+
+void ScummEngine_v60he::o60_readFilePos() {
+ int slot = pop();
+
+ if (slot == -1) {
+ push(0);
+ return;
+ }
+
+ push(_hFileTable[slot].pos());
+}
+
+void ScummEngine_v60he::o60_redimArray() {
+ int newX, newY;
+ newY = pop();
+ newX = pop();
+
+ if (newY == 0)
+ SWAP(newX, newY);
+
+ byte subOp = fetchScriptByte();
+ switch (subOp) {
+ case 199:
+ redimArray(fetchScriptWord(), newX, newY, kIntArray);
+ break;
+ case 202:
+ redimArray(fetchScriptWord(), newX, newY, kByteArray);
+ break;
+ default:
+ error("o60_redimArray: default type %d", subOp);
+ }
+}
+
+void ScummEngine_v60he::redimArray(int arrayId, int newX, int newY, int type) {
+ // Used in mini game at Cosmic Dust Diner in puttmoon
+ int newSize, oldSize;
+
+ if (readVar(arrayId) == 0)
+ error("redimArray: Reference to zeroed array pointer");
+
+ ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(arrayId));
+
+ if (!ah)
+ error("redimArray: Invalid array (%d) reference", readVar(arrayId));
+
+ newSize = (type == kIntArray) ? 2 : 1;
+ oldSize = (ah->type == kIntArray) ? 2 : 1;
+
+ newSize *= (newX + 1) * (newY + 1);
+ oldSize *= FROM_LE_16(ah->dim1) * FROM_LE_16(ah->dim2);
+
+ if (newSize != oldSize)
+ error("redimArray: array %d redim mismatch", readVar(arrayId));
+
+ ah->type = TO_LE_16(type);
+ ah->dim1 = TO_LE_16(newY + 1);
+ ah->dim2 = TO_LE_16(newX + 1);
+}
+
+void ScummEngine_v60he::decodeParseString(int m, int n) {
+ int i, colors;
+ int args[31];
+
+ byte b = fetchScriptByte();
+
+ switch (b) {
+ case 65: // SO_AT
+ _string[m].ypos = pop();
+ _string[m].xpos = pop();
+ _string[m].overhead = false;
+ break;
+ case 66: // SO_COLOR
+ _string[m].color = pop();
+ break;
+ case 67: // SO_CLIPPED
+ _string[m].right = pop();
+ break;
+ case 69: // SO_CENTER
+ _string[m].center = true;
+ _string[m].overhead = false;
+ break;
+ case 71: // SO_LEFT
+ _string[m].center = false;
+ _string[m].overhead = false;
+ break;
+ case 72: // SO_OVERHEAD
+ _string[m].overhead = true;
+ _string[m].no_talk_anim = false;
+ break;
+ case 74: // SO_MUMBLE
+ _string[m].no_talk_anim = true;
+ break;
+ case 75: // SO_TEXTSTRING
+ printString(m, _scriptPointer);
+ _scriptPointer += resStrLen(_scriptPointer) + 1;
+ break;
+ case 0xF9:
+ colors = pop();
+ if (colors == 1) {
+ _string[m].color = pop();
+ } else {
+ push(colors);
+ getStackList(args, ARRAYSIZE(args));
+ for (i = 0; i < 16; i++)
+ _charsetColorMap[i] = _charsetData[_string[1]._default.charset][i] = (unsigned char)args[i];
+ _string[m].color = _charsetColorMap[0];
+ }
+ break;
+ case 0xFE:
+ _string[m].loadDefault();
+ if (n)
+ _actorToPrintStrFor = pop();
+ break;
+ case 0xFF:
+ _string[m].saveDefault();
+ break;
+ default:
+ error("decodeParseString: default case 0x%x", b);
+ }
+}
+
+} // End of namespace Scumm