From 82564def69af77c2c22237f90eb5a9d5b22aff35 Mon Sep 17 00:00:00 2001 From: Travis Howell Date: Sat, 7 Feb 2004 02:23:24 +0000 Subject: Add separate class for Humongous Entertainment games. svn-id: r12752 --- scumm/intern.h | 55 +++ scumm/module.mk | 1 + scumm/script_v6he.cpp | 1269 +++++++++++++++++++++++++++++++++++++++++++++++++ scumm/scummvm.cpp | 8 +- scumm/vars.cpp | 19 + 5 files changed, 1351 insertions(+), 1 deletion(-) create mode 100644 scumm/script_v6he.cpp diff --git a/scumm/intern.h b/scumm/intern.h index fa40e525bb..33b3450058 100644 --- a/scumm/intern.h +++ b/scumm/intern.h @@ -552,6 +552,61 @@ protected: byte VAR_TIMEDATE_SECOND; }; +class ScummEngine_v6he : public ScummEngine_v6 { +protected: + typedef void (ScummEngine_v6he::*OpcodeProcV6he)(); + struct OpcodeEntryV6he { + OpcodeProcV6he proc; + const char *desc; + }; + + const OpcodeEntryV6he *_opcodesV6he; + + File _hFileTable[17]; + +public: + ScummEngine_v6he(GameDetector *detector, OSystem *syst, const ScummGameSettings &gs) : ScummEngine_v6(detector, syst, gs) {} + +protected: + virtual void setupOpcodes(); + virtual void executeOpcode(byte i); + virtual const char *getOpcodeDesc(byte i); + + virtual void setupScummVars(); + virtual void decodeParseString(int a, int b); + + void unknownEA_func(int a, int b, int c, int d, int e); + int readFileToArray(int slot, int32 size); + void writeFileFromArray(int slot, int resID); + + /* Version 6 script opcodes */ + void o6_drawBlastObject(); + void o6_setBlastObjectWindow(); + void o6_roomOps(); + void o6_actorOps(); + void o6_verbOps(); + void o6_wait(); + void o6_soundKludge(); + void o6_dummy(); + void o6_kernelSetFunctions(); + void o6_kernelGetFunctions(); + void o6_stampObject(); + void o6_openFile(); + void o6_closeFile(); + void o6_deleteFile(); + void o6_readFile(); + void o6_rename(); + void o6_writeFile(); + void o6_findAllObjects(); + void o6_unknownE0(); + void o6_unknownE1(); + void o6_unknownE4(); + void o6_localizeArray(); + void o6_unknownFA(); + void o6_unknownEA(); + void o6_readINI(); +}; + class ScummEngine_v7 : public ScummEngine_v6 { public: ScummEngine_v7(GameDetector *detector, OSystem *syst, const ScummGameSettings &gs) : ScummEngine_v6(detector, syst, gs) {} diff --git a/scumm/module.mk b/scumm/module.mk index fd62437a64..9191b03813 100644 --- a/scumm/module.mk +++ b/scumm/module.mk @@ -36,6 +36,7 @@ MODULE_OBJS := \ scumm/script_v2.o \ scumm/script_v5.o \ scumm/script_v6.o \ + scumm/script_v6he.o \ scumm/script_v8.o \ scumm/scummvm.o \ scumm/sound.o \ diff --git a/scumm/script_v6he.cpp b/scumm/script_v6he.cpp new file mode 100644 index 0000000000..76455d73f8 --- /dev/null +++ b/scumm/script_v6he.cpp @@ -0,0 +1,1269 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2004 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 "common/config-manager.h" + +#include "scumm/actor.h" +#include "scumm/charset.h" +#include "scumm/imuse.h" +#include "scumm/imuse_digi/dimuse.h" +#include "scumm/intern.h" +#include "scumm/object.h" +#include "scumm/resource.h" +#include "scumm/scumm.h" +#include "scumm/sound.h" +#include "scumm/verbs.h" +#include "scumm/smush/smush_player.h" + +#include "sound/mididrv.h" +#include "sound/mixer.h" + +#include "scumm/insane/insane.h" + +namespace Scumm { + +#define OPCODE(x) { &ScummEngine_v6he::x, #x } + +void ScummEngine_v6he::setupOpcodes() { + static const OpcodeEntryV6he 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_drawBlastObject), + /* 64 */ + OPCODE(o6_setBlastObjectWindow), + 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(o6_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_createBoxMatrix), + OPCODE(o6_resourceRoutines), + /* 9C */ + OPCODE(o6_roomOps), + OPCODE(o6_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_soundKludge), + OPCODE(o6_isAnyOf), + OPCODE(o6_quitPauseRestart), + OPCODE(o6_isActorInBox), + /* B0 */ + OPCODE(o6_delay), + OPCODE(o6_delaySeconds), + OPCODE(o6_delayMinutes), + OPCODE(o6_stopSentence), + /* B4 */ + OPCODE(o6_printLine), + OPCODE(o6_printCursor), + 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_dummy), + 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(o6_kernelGetFunctions), + OPCODE(o6_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(o6_closeFile), + OPCODE(o6_openFile), + OPCODE(o6_readFile), + /* DC */ + OPCODE(o6_writeFile), + OPCODE(o6_findAllObjects), + OPCODE(o6_deleteFile), + OPCODE(o6_rename), + /* E0 */ + OPCODE(o6_unknownE0), + OPCODE(o6_unknownE1), + OPCODE(o6_localizeArray), + OPCODE(o6_pickVarRandom), + /* E4 */ + OPCODE(o6_unknownE4), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* E8 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_unknownEA), + OPCODE(o6_invalid), + /* 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_readINI), + /* F4 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + /* F8 */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_unknownFA), + OPCODE(o6_invalid), + /* FC */ + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + OPCODE(o6_invalid), + }; + + _opcodesV6he = opcodes; +} + +void ScummEngine_v6he::executeOpcode(byte i) { + OpcodeProcV6he op = _opcodesV6he[i].proc; + (this->*op) (); +} + +const char *ScummEngine_v6he::getOpcodeDesc(byte i) { + return _opcodesV6he[i].desc; +} + +void ScummEngine_v6he::o6_roomOps() { + int a, b, c, d, e; + byte op; + + op = fetchScriptByte(); + + switch (op) { + 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(); + 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(); + if (_gameId == GID_TENTACLE) + _saveSound = (_saveLoadSlot != 0); + break; + + case 181: // SO_ROOM_FADE + a = pop(); + 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(); + setupShadowPalette(a, b, c, d, e); + break; + + case 184: // SO_SAVE_STRING + error("save string not implemented"); + break; + + case 185: // SO_LOAD_STRING + error("load string not implemented"); + 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, "o6_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(); + + // This opcode is used when turning off noir mode in Sam & Max, + // but since our implementation of this feature doesn't change + // the original palette there's no need to reload it. Doing it + // this way, we avoid some graphics glitches that the original + // interpreter had. + + if (_gameId == GID_SAMNMAX && vm.slot[_currentScript].number == 64) + setDirtyColors(0, 255); + else + setPalette(a); + break; + case 220: + a = pop(); + b = pop(); + warning("o6_roomops:220 (%d, %d): unimplemented", a, b); + break; + case 221: + int len; + len = resStrLen(_scriptPointer); + _scriptPointer += len + 1; + _saveLoadFlag = pop(); + _saveLoadSlot = 99; + _saveTemporaryState = true; + break; + default: + error("o6_roomOps: default case %d", op); + } +} + +void ScummEngine_v6he::o6_actorOps() { + Actor *a; + int i, j, k; + int args[8]; + byte b; + + b = fetchScriptByte(); + if (b == 197) { + _curActor = pop(); + return; + } + + a = derefActorSafe(_curActor, "o6_actorOps"); + if (!a) + return; + + switch (b) { + 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"); + if (_gameId != GID_PUTTDEMO) + a->remapActorPaletteColor(i, j); + else + a->setPalette(i, j); + 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 225: // SO_ALWAYS_ZCLIP + case 94: // SO_ALWAYS_ZCLIP + a->forceClip = pop(); + break; + case 95: // SO_IGNORE_BOXES + a->ignoreBoxes = 1; + if (_version >= 7) + a->forceClip = 100; + else + 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; + if (_version >= 7) + a->forceClip = 100; + else + 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->shadow_mode = pop(); + break; + case 99: // SO_TEXT_OFFSET + a->talkPosY = pop(); + a->talkPosX = 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: + { + // TODO: this opcode is used in the putt-putt fun pack, in 'checkers" mini game + warning("o6_actorOps():218 partially unimplemented"); + + int top_actor = a->top; + int bottom_actor = a->bottom; + a->forceClip = 1; + a->needRedraw = true; + a->drawActorCostume(); + a->forceClip = 0; + a->needRedraw = true; + a->drawActorCostume(); + a->needRedraw = false; + + if (a->top > top_actor) + a->top = top_actor; + if (a->bottom < bottom_actor) + a->bottom = bottom_actor; + + //FIXME Trigger redraw + a->bottom = top_actor; + } + break; + default: + error("o6_actorOps: default case %d", b); + } +} + +void ScummEngine_v6he::o6_verbOps() { + int slot, a, b; + VerbSlot *vs; + byte op; + + op = fetchScriptByte(); + if (op == 196) { + _curVerb = pop(); + _curVerbSlot = getVerbSlot(_curVerb, 0); + checkRange(_numVerbs - 1, 0, _curVerbSlot, "Illegal new verb slot %d"); + return; + } + vs = &_verbs[_curVerbSlot]; + slot = _curVerbSlot; + switch (op) { + case 124: // SO_VERB_IMAGE + a = pop(); + if (_curVerbSlot) { + setVerbObject(_roomResource, a, slot); + vs->type = kImageVerbType; + vs->imgindex = a; + } + break; + case 125: // SO_VERB_NAME + loadPtrToResource(rtVerb, slot, NULL); + vs->type = kTextVerbType; + vs->imgindex = 0; + break; + case 126: // SO_VERB_COLOR + vs->color = pop(); + break; + case 127: // SO_VERB_HICOLOR + vs->hicolor = pop(); + break; + case 128: // SO_VERB_AT + vs->curRect.top = pop(); + vs->curRect.left = pop(); + break; + case 129: // SO_VERB_ON + vs->curmode = 1; + break; + case 130: // SO_VERB_OFF + vs->curmode = 0; + break; + case 131: // SO_VERB_DELETE + slot = getVerbSlot(pop(), 0); + killVerb(slot); + break; + case 132: // SO_VERB_NEW + slot = getVerbSlot(_curVerb, 0); + if (slot == 0) { + for (slot = 1; slot < _numVerbs; slot++) { + if (_verbs[slot].verbid == 0) + break; + } + if (slot == _numVerbs) + error("Too many verbs"); + _curVerbSlot = slot; + } + vs = &_verbs[slot]; + vs->verbid = _curVerb; + 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 133: // SO_VERB_DIMCOLOR + vs->dimcolor = pop(); + break; + case 134: // SO_VERB_DIM + vs->curmode = 2; + break; + case 135: // SO_VERB_KEY + vs->key = pop(); + break; + case 136: // SO_VERB_CENTER + vs->center = 1; + break; + case 137: // SO_VERB_NAME_STR + a = pop(); + if (a == 0) { + loadPtrToResource(rtVerb, slot, (const byte *)""); + } else { + loadPtrToResource(rtVerb, slot, getStringAddress(a)); + } + vs->type = kTextVerbType; + vs->imgindex = 0; + break; + case 139: // SO_VERB_IMAGE_IN_ROOM + b = pop(); + a = pop(); + if (slot && a != vs->imgindex) { + setVerbObject(b, a, slot); + vs->type = kImageVerbType; + vs->imgindex = a; + } + break; + case 140: // SO_VERB_BAKCOLOR + vs->bkcolor = pop(); + break; + case 255: + drawVerb(slot, 0); + verbMouseOver(0); + break; + default: + error("o6_verbops: default case %d", op); + } +} + +void ScummEngine_v6he::o6_wait() { + int actnum; + int offs = -2; + Actor *a; + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 168: // SO_WAIT_FOR_ACTOR Wait for actor + offs = fetchScriptWordSigned(); + actnum = pop(); + a = derefActor(actnum, "o6_wait:168"); + if (a->isInCurrentRoom() && a->moving) + break; + return; + case 169: // SO_WAIT_FOR_MESSAGE Wait for message + if (VAR(VAR_HAVE_MSG)) + break; + return; + case 170: // SO_WAIT_FOR_CAMERA Wait for camera + if (_version >= 7) { + if (camera._dest != camera._cur) + break; + } else { + if (camera._cur.x / 8 != camera._dest.x / 8) + break; + } + + return; + case 171: // SO_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("o6_wait: default case 0x%x", subOp); + } + + _scriptPointer += offs; + o6_breakHere(); +} + +void ScummEngine_v6he::o6_soundKludge() { + int list[16]; + getStackList(list, ARRAYSIZE(list)); +} + +void ScummEngine_v6he::o6_dummy() { + stopObjectCode(); +} + +void ScummEngine_v6he::o6_drawBlastObject() { + int args[16]; + getStackList(args, ARRAYSIZE(args)); + pop(); + pop(); + pop(); + pop(); + pop(); +} + +void ScummEngine_v6he::o6_setBlastObjectWindow() { + pop(); + pop(); + pop(); + pop(); +} + +void ScummEngine_v6he::o6_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 + warning("o6_kernelSetFunctions: stub1()"); + break; + default: + error("o6_kernelSetFunctions: default case %d (param count %d)", args[0], num); + break; + } +} + +void ScummEngine_v6he::o6_kernelGetFunctions() { + int args[29]; + getStackList(args, ARRAYSIZE(args)); + + switch (args[0]) { + case 1: + // Used to store images when decorating cake in + // Fatty Bear's Birthday Surprise + warning("o6_kernelGetFunctions: stub1()"); + push(0); + break; + default: + error("o6_kernelGetFunctions: default case %d", args[0]); + } +} + +void ScummEngine_v6he::o6_stampObject() { + int object, x, y, state; + + state = pop(); + if (state == 0) { + state = 1; + } + y = pop(); + x = pop(); + object = pop(); + int objnum = getObjectIndex(object); + if (objnum == -1) + return; + _objs[objnum].x_pos = x * 8; + _objs[objnum].y_pos = y * 8; + putState(object, state); + drawObject(objnum, 0); +} + +void ScummEngine_v6he::o6_openFile() { + int mode, len, slot, l, r; + byte filename[100]; + + _msgPtrToAdd = filename; + _messagePtr = _scriptPointer; + addMessageToStack(_messagePtr); + + 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) { + if (mode == 1) + _hFileTable[slot].open((char*)filename + r, getGameDataPath(), File::kFileReadMode); + else if (mode == 2) + _hFileTable[slot].open((char*)filename + r, getGameDataPath(), File::kFileWriteMode); + else + error("o6_openFile(): wrong open file mode"); + + warning("%d = o6_openFile(\"%s\", %d)", slot, filename + r, mode); + } + push(slot); +} + +void ScummEngine_v6he::o6_closeFile() { + int slot = pop(); + _hFileTable[slot].close(); + warning("o6_closeFile(%d)", slot); +} + +void ScummEngine_v6he::o6_deleteFile() { + int len, r; + byte filename[100]; + + _msgPtrToAdd = filename; + _messagePtr = _scriptPointer; + addMessageToStack(_messagePtr); + + len = resStrLen(_scriptPointer); + _scriptPointer += len + 1; + + for (r = strlen((char*)filename); r != 0; r--) { + if (filename[r - 1] == '\\') + break; + } + + warning("stub o6_deleteFile(\"%s\")", filename + r); +} + +void ScummEngine_v6he::o6_rename() { + int len, r1, r2; + byte filename[100],filename2[100]; + + _msgPtrToAdd = filename; + _messagePtr = _scriptPointer; + addMessageToStack(_messagePtr); + + len = resStrLen(_scriptPointer); + _scriptPointer += len + 1; + + for (r1 = strlen((char*)filename); r1 != 0; r1--) { + if (filename[r1 - 1] == '\\') + break; + } + + _msgPtrToAdd = filename2; + _messagePtr = _scriptPointer; + addMessageToStack(_messagePtr); + + len = resStrLen(_scriptPointer); + _scriptPointer += len + 1; + + for (r2 = strlen((char*)filename2); r2 != 0; r2--) { + if (filename2[r2 - 1] == '\\') + break; + } + + warning("stub o6_rename(\"%s\" to \"%s\")", filename + r1, filename2 + r2); +} + +int ScummEngine_v6he::readFileToArray(int slot, int32 size) { + if (size == 0) + size = _hFileTable[slot].size() - _hFileTable[slot].pos(); + writeVar(0, 0); + defineArray(0, 3, 0, size); + byte *ptr = getResourceAddress(rtString, readVar(0)); + _hFileTable[slot].read(ptr, size); + return readVar(0); +} + +void ScummEngine_v6he::o6_readFile() { + int32 size = pop(); + int slot = pop(); + + if (size == -2) { + push(_hFileTable[slot].readUint16LE()); + } else if (size == -1) { + push(_hFileTable[slot].readByte()); + } else { + push(readFileToArray(slot, size)); + } + warning("o6_readFile(%d, %d)", slot, size); +} + +void ScummEngine_v6he::writeFileFromArray(int slot, int resID) { + byte *ptr = getResourceAddress(rtString, resID); + // FIXME: hack for proper size: / 2 - 5 + int32 size = getResourceSize(rtString, resID) / 2 - 5; + _hFileTable[slot].write(ptr, size); +} + +void ScummEngine_v6he::o6_writeFile() { + int32 size = pop(); + int16 resID = pop(); + int slot = pop(); + + if (size == -2) { + _hFileTable[slot].writeUint16LE(resID); + } else if (size == -1) { + _hFileTable[slot].writeByte(resID); + } else { + writeFileFromArray(slot, resID); + } + warning("o6_writeFile(%d, %d)", slot, resID); +} + +void ScummEngine_v6he::o6_findAllObjects() { + int a = pop(); + int i = 1; + + if (a != _currentRoom) + warning("o6_findAllObjects: current room is not %d", a); + writeVar(0, 0); + defineArray(0, 5, 0, _numLocalObjects + 1); + writeArray(0, 0, 0, _numLocalObjects); + + while (i < _numLocalObjects) { + writeArray(0, 0, i, _objs[i].obj_nr); + i++; + } + + push(readVar(0)); +} + +void ScummEngine_v6he::o6_unknownE1() { + // this opcode check ground area in minigame "Asteroid Lander" in the dig + int y = pop(); + int x = pop(); + + if (x > _screenWidth - 1) { + push(-1); + return; + } + if (x < 0) { + push(-1); + return; + } + + if (y < 0) { + push(-1); + return; + } + + VirtScreen *vs = findVirtScreen(y); + + if (vs == NULL) { + push(-1); + return; + } + + int offset = (y - vs->topline) * vs->width + x + _screenLeft; + + byte area = *(vs->screenPtr + offset); + push(area); +} + +void ScummEngine_v6he::o6_unknownE0() { + int a = fetchScriptByte(); + a -= 222; + if (a != 0) { + a -= 2; + if (a != 0) + return; + warning("o6_unknownE0(%d) stub", pop()); + } else { + warning("o6_uknownE0, sound volume %d stub", pop()); + } +} + +void ScummEngine_v6he::o6_unknownE4() { + warning("o6_unknownE4(%d) stub", pop()); +} + +void ScummEngine_v6he::o6_unknownFA() { + int len, a = fetchScriptByte(); + + len = resStrLen(_scriptPointer); + warning("stub o6_unknownFA(%d, \"%s\")", a, _scriptPointer); + _scriptPointer += len + 1; +} + +void ScummEngine_v6he::o6_unknownEA() { + int edi, esi, eax; + edi = pop(); + esi = pop(); + + if (edi == 0) { + eax = esi; + esi = edi; + edi = eax; + } + + eax = fetchScriptByte(); + switch (eax) { + case 199: + unknownEA_func(5, esi, edi, fetchScriptWord(), eax); + break; + case 202: + unknownEA_func(3, esi, edi, fetchScriptWord(), eax); + break; + default: + break; + } +} + +void ScummEngine_v6he::unknownEA_func(int a, int b, int c, int d, int e) { + // Used in mini game at Cosmic Dust Diner in puttmoon + warning("unknownEA_func(%d, %d, %d, %d, %d) stub", a, b, c, d, e); +} + +void ScummEngine_v6he::o6_readINI() { + int len; + + len = resStrLen(_scriptPointer); + warning("stub o6_readINI(\"%s\")", _scriptPointer); + _scriptPointer += len + 1; + pop(); + push(0); + +} + +void ScummEngine_v6he::o6_localizeArray() { + int stringID = pop(); + + if (stringID < _numArray) { + _baseArrays[stringID][0] = (byte)_currentScript; + } else { + warning("o6_localizeArray(%d): too big scriptID", stringID); + } +} + +void ScummEngine_v6he::decodeParseString(int m, int n) { + byte b; + + 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 73: // SO_SAY_VOICE + error("decodeParseString: case 73"); + break; + case 74: // SO_MUMBLE + _string[m].no_talk_anim = true; + break; + case 75: // SO_TEXTSTRING + _messagePtr = translateTextAndPlaySpeech(_scriptPointer); + _scriptPointer += resStrLen(_scriptPointer)+ 1; + + switch (m) { + case 0: + actorTalk(); + break; + case 1: + drawString(1); + break; + case 2: + unkMessage1(); + break; + case 3: + unkMessage2(); + break; + } + return; + case 0xF9: + warning("decodeParseString case 0xF9 stub"); + return; + case 0xFE: + setStringVars(m); + if (n) + _actorToPrintStrFor = pop(); + return; + case 0xFF: + _string[m].t_xpos = _string[m].xpos; + _string[m].t_ypos = _string[m].ypos; + _string[m].t_center = _string[m].center; + _string[m].t_overhead = _string[m].overhead; + _string[m].t_no_talk_anim = _string[m].no_talk_anim; + _string[m].t_right = _string[m].right; + _string[m].t_color = _string[m].color; + _string[m].t_charset = _string[m].charset; + return; + default: + error("decodeParseString: default case 0x%x", b); + } +} + +} // End of namespace Scumm diff --git a/scumm/scummvm.cpp b/scumm/scummvm.cpp index 83d155b702..c349ac3d19 100644 --- a/scumm/scummvm.cpp +++ b/scumm/scummvm.cpp @@ -170,6 +170,9 @@ static const ScummGameSettings scumm_settings[] = { {"fbdemo", "Fatty Bear's Birthday Surprise (DOS Demo)", GID_FBEAR, 6, MDT_ADLIB | MDT_NATIVE, GF_NEW_OPCODES | GF_USE_KEY | GF_HUMONGOUS | GF_NEW_COSTUMES, 0}, + {"putter", "Putt-Putt Joins The Parade (Windows)", GID_PUTTPUTT, 6, MDT_NONE, + GF_NEW_OPCODES | GF_AFTER_HEV7 | GF_USE_KEY | GF_HUMONGOUS | GF_NEW_COSTUMES, "puttputt"}, + {"tentacle", "Day Of The Tentacle", GID_TENTACLE, 6, /*MDT_PCSPK |*/ MDT_ADLIB | MDT_NATIVE, GF_NEW_OPCODES | GF_USE_KEY, 0}, {"dottdemo", "Day Of The Tentacle (Demo)", GID_TENTACLE, 6, /*MDT_PCSPK |*/ MDT_ADLIB | MDT_NATIVE, @@ -2982,7 +2985,10 @@ Engine *Engine_SCUMM_create(GameDetector *detector, OSystem *syst) { engine = new ScummEngine_v5(detector, syst, game); break; case 6: - engine = new ScummEngine_v6(detector, syst, game); + if (game.features & GF_HUMONGOUS) + engine = new ScummEngine_v6he(detector, syst, game); + else + engine = new ScummEngine_v6(detector, syst, game); break; case 7: engine = new ScummEngine_v7(detector, syst, game); diff --git a/scumm/vars.cpp b/scumm/vars.cpp index 4fab7884de..88932c586a 100644 --- a/scumm/vars.cpp +++ b/scumm/vars.cpp @@ -161,6 +161,25 @@ void ScummEngine_v6::setupScummVars() { VAR_TIMEDATE_MINUTE = 126; } +void ScummEngine_v6he::setupScummVars() { + // Many vars are the same as in V5 & V6 games, so just call the inherited method first + ScummEngine::setupScummVars(); + + VAR_V6_SCREEN_WIDTH = 41; + VAR_V6_SCREEN_HEIGHT = 54; + VAR_V6_EMSSPACE = 76; + VAR_RANDOM_NR = 118; + + VAR_V6_SOUNDMODE = 9; + + VAR_TIMEDATE_YEAR = 119; + VAR_TIMEDATE_MONTH = 129; + VAR_TIMEDATE_DAY = 128; + VAR_TIMEDATE_HOUR = 125; + VAR_TIMEDATE_MINUTE = 126; +} + + void ScummEngine_v7::setupScummVars() { VAR_MOUSE_X = 1; VAR_MOUSE_Y = 2; -- cgit v1.2.3