diff options
Diffstat (limited to 'engines')
69 files changed, 1578 insertions, 602 deletions
diff --git a/engines/bladerunner/actor.cpp b/engines/bladerunner/actor.cpp index 49a66d9ef6..6265a0480a 100644 --- a/engines/bladerunner/actor.cpp +++ b/engines/bladerunner/actor.cpp @@ -672,7 +672,7 @@ bool Actor::draw(Common::Rect *screenRect) { // TODO: Handle SHORTY mode - _vm->_sliceRenderer->drawInWorld(_animationId, _animationFrame, drawPosition, drawAngle, drawScale, _vm->_surface2, _vm->_zbuffer->getData()); + _vm->_sliceRenderer->drawInWorld(_animationId, _animationFrame, drawPosition, drawAngle, drawScale, _vm->_surfaceGame, _vm->_zbuffer->getData()); _vm->_sliceRenderer->getScreenRectangle(screenRect, _animationId, _animationFrame, drawPosition, drawAngle, drawScale); return !screenRect->isEmpty(); diff --git a/engines/bladerunner/bladerunner.cpp b/engines/bladerunner/bladerunner.cpp index 17e117baaf..348d5f7c1f 100644 --- a/engines/bladerunner/bladerunner.cpp +++ b/engines/bladerunner/bladerunner.cpp @@ -49,6 +49,7 @@ #include "bladerunner/shape.h" #include "bladerunner/slice_animations.h" #include "bladerunner/slice_renderer.h" +#include "bladerunner/spinner.h" #include "bladerunner/text_resource.h" #include "bladerunner/vqa_decoder.h" #include "bladerunner/waypoints.h" @@ -110,9 +111,6 @@ BladeRunnerEngine::~BladeRunnerEngine() { // delete _audioPlayer; // delete _ambientSounds; - // _surface1.free(); - // _surface2.free(); - delete _zbuffer; delete _itemPickup; @@ -154,7 +152,9 @@ Common::Error BladeRunnerEngine::run() { bool BladeRunnerEngine::startup(bool hasSavegames) { bool r; - _surface1.create(640, 480, createRGB555()); + _surfaceGame.create(640, 480, createRGB555()); + _surfaceInterface.create(640, 480, createRGB555()); + _surface4.create(640, 480, createRGB555()); r = openArchive("STARTUP.MIX"); if (!r) @@ -287,6 +287,7 @@ bool BladeRunnerEngine::startup(bool hasSavegames) { // TODO: KIA // TODO: Spinner Interface + _spinner = new Spinner(this); // TODO: Elevators @@ -506,8 +507,9 @@ void BladeRunnerEngine::shutdown() { _gameInfo = nullptr; // TODO: Delete graphics surfaces here - _surface1.free(); - _surface2.free(); + _surface4.free(); + _surfaceInterface.free(); + _surfaceGame.free(); if (isArchiveOpen("STARTUP.MIX")) closeArchive("STARTUP.MIX"); @@ -522,9 +524,9 @@ bool BladeRunnerEngine::loadSplash() { if (!img.open("SPLASH.IMG")) return false; - img.copyToSurface(&_surface1); + img.copyToSurface(&_surfaceGame); - _system->copyRectToScreen(_surface1.getPixels(), _surface1.pitch, 0, 0, _surface1.w, _surface1.h); + _system->copyRectToScreen(_surfaceGame.getPixels(), _surfaceGame.pitch, 0, 0, _surfaceGame.w, _surfaceGame.h); _system->updateScreen(); return true; @@ -534,6 +536,10 @@ bool BladeRunnerEngine::init2() { return true; } +Common::Point BladeRunnerEngine::getMousePos() { + return _eventMan->getMousePos(); +} + void BladeRunnerEngine::gameLoop() { _gameIsRunning = true; do { @@ -581,7 +587,13 @@ void BladeRunnerEngine::gameTick() { // TODO: Autosave // TODO: Kia - // TODO: Spinner + + if (_spinner->isOpen()) { + _spinner->tick(); + _ambientSounds->tick(); + return; + } + // TODO: Esper // TODO: VK // TODO: Elevators @@ -598,13 +610,13 @@ void BladeRunnerEngine::gameTick() { _ambientSounds->tick(); bool backgroundChanged = false; - int frame = _scene->advanceFrame(_surface1); + int frame = _scene->advanceFrame(); if (frame >= 0) { _sceneScript->SceneFrameAdvanced(frame); backgroundChanged = true; } (void)backgroundChanged; - _surface2.copyFrom(_surface1); + _surfaceGame.copyRectToSurface(_surfaceInterface.getPixels(), _surfaceInterface.pitch, 0, 0, 640, 480); // TODO: remove zbuffer draw //_surface2.copyRectToSurface(_zbuffer->getData(), 1280, 0, 0, 640, 480); @@ -636,9 +648,9 @@ void BladeRunnerEngine::gameTick() { // TODO: Draw dialogue menu - Common::Point p = _eventMan->getMousePos(); + Common::Point p = getMousePos(); _mouse->tick(p.x, p.y); - _mouse->draw(_surface2, p.x, p.y); + _mouse->draw(_surfaceGame, p.x, p.y); // TODO: Process AUD // TODO: Footstep sound @@ -762,7 +774,7 @@ void BladeRunnerEngine::gameTick() { } #endif - _system->copyRectToScreen((const byte *)_surface2.getBasePtr(0, 0), _surface2.pitch, 0, 0, 640, 480); + _system->copyRectToScreen(_surfaceGame.getPixels(), _surfaceGame.pitch, 0, 0, 640, 480); _system->updateScreen(); _system->delayMillis(10); } @@ -797,17 +809,32 @@ void BladeRunnerEngine::handleEvents() { switch (event.type) { case Common::EVENT_LBUTTONDOWN: case Common::EVENT_RBUTTONDOWN: - handleMouseClick(event.mouse.x, event.mouse.y); + case Common::EVENT_LBUTTONUP: + case Common::EVENT_RBUTTONUP: { + bool buttonLeft = event.type == Common::EVENT_LBUTTONDOWN || event.type == Common::EVENT_LBUTTONUP; + bool buttonDown = event.type == Common::EVENT_LBUTTONDOWN || event.type == Common::EVENT_RBUTTONDOWN; + + handleMouseAction(event.mouse.x, event.mouse.y, buttonLeft, buttonDown); + } default: ; } } } -void BladeRunnerEngine::handleMouseClick(int x, int y) { +void BladeRunnerEngine::handleMouseAction(int x, int y, bool buttonLeft, bool buttonDown) { if (!playerHasControl() || _mouse->isDisabled()) return; + if (_spinner->isOpen()) { + if (buttonDown) { + _spinner->handleMouseDown(x, y); + } else { + _spinner->handleMouseUp(x, y); + } + return; + } + Vector3 mousePosition = _mouse->getXYZ(x, y); int isClickable; diff --git a/engines/bladerunner/bladerunner.h b/engines/bladerunner/bladerunner.h index 3b0359be2e..8fd43df211 100644 --- a/engines/bladerunner/bladerunner.h +++ b/engines/bladerunner/bladerunner.h @@ -69,6 +69,7 @@ class Settings; class Shape; class SliceAnimations; class SliceRenderer; +class Spinner; class TextResource; class View; class Waypoints; @@ -105,6 +106,7 @@ public: Settings *_settings; SliceAnimations *_sliceAnimations; SliceRenderer *_sliceRenderer; + Spinner *_spinner; SuspectsDatabase *_suspectsDatabase; View *_view; Waypoints *_waypoints; @@ -125,8 +127,10 @@ public: int in_script_counter; - Graphics::Surface _surface1; - Graphics::Surface _surface2; + Graphics::Surface _surfaceGame; + Graphics::Surface _surfaceInterface; + Graphics::Surface _surface4; + ZBuffer *_zbuffer; Common::RandomSource _rnd; @@ -162,11 +166,13 @@ public: bool loadSplash(); bool init2(); + Common::Point getMousePos(); + void gameLoop(); void gameTick(); void actorsUpdate(); void handleEvents(); - void handleMouseClick(int x, int y); + void handleMouseAction(int x, int y, bool buttonLeft, bool buttonDown); void handleMouseClickExit(int x, int y, int exitIndex); void handleMouseClickRegion(int x, int y, int regionIndex); void handleMouseClickItem(int x, int y, int itemId); diff --git a/engines/bladerunner/item.cpp b/engines/bladerunner/item.cpp index 3ad2868c51..0b84aae30c 100644 --- a/engines/bladerunner/item.cpp +++ b/engines/bladerunner/item.cpp @@ -86,7 +86,7 @@ bool Item::tick(Common::Rect *screenRect, bool special) { Vector3 position(_position.x, -_position.z, _position.y); int animationId = _animationId + (special ? 1 : 0); - _vm->_sliceRenderer->drawInWorld(animationId, 0, position, M_PI - _angle, 1.0f, _vm->_surface2, _vm->_zbuffer->getData()); + _vm->_sliceRenderer->drawInWorld(animationId, 0, position, M_PI - _angle, 1.0f, _vm->_surfaceGame, _vm->_zbuffer->getData()); _vm->_sliceRenderer->getScreenRectangle(&_screenRectangle, animationId, 0, position, M_PI - _angle, 1.0f); if (!_screenRectangle.isEmpty()) { diff --git a/engines/bladerunner/item_pickup.cpp b/engines/bladerunner/item_pickup.cpp index 7549c8db01..b1f557d344 100644 --- a/engines/bladerunner/item_pickup.cpp +++ b/engines/bladerunner/item_pickup.cpp @@ -104,6 +104,6 @@ void ItemPickup::draw() { return; } - _vm->_sliceRenderer->drawOnScreen(_animationId, _animationFrame, _screenX, _screenY, _facing, _scale, _vm->_surface2, _vm->_zbuffer->getData()); + _vm->_sliceRenderer->drawOnScreen(_animationId, _animationFrame, _screenX, _screenY, _facing, _scale, _vm->_surfaceGame, _vm->_zbuffer->getData()); } } // End of namespace BladeRunner diff --git a/engines/bladerunner/module.mk b/engines/bladerunner/module.mk index 82a7c21227..9a43ef4457 100644 --- a/engines/bladerunner/module.mk +++ b/engines/bladerunner/module.mk @@ -93,6 +93,7 @@ MODULE_OBJS = \ script/scene/hf04.o \ script/scene/hf05.o \ script/scene/hf06.o \ + script/scene/hf07.o \ script/scene/kp01.o \ script/scene/kp02.o \ script/scene/kp03.o \ @@ -166,8 +167,10 @@ MODULE_OBJS = \ shape.o \ slice_animations.o \ slice_renderer.o \ + spinner.o \ suspects_database.o \ text_resource.o \ + ui_image_picker.o \ view.o \ vqa_decoder.o \ vqa_player.o \ diff --git a/engines/bladerunner/outtake.cpp b/engines/bladerunner/outtake.cpp index b81b212f52..80e4d78a1a 100644 --- a/engines/bladerunner/outtake.cpp +++ b/engines/bladerunner/outtake.cpp @@ -43,7 +43,7 @@ void OuttakePlayer::play(const Common::String &name, bool noLocalization, int co else resName = name + "_E.VQA"; - VQAPlayer vqa_player(_vm); + VQAPlayer vqa_player(_vm, &_vm->_surfaceGame); vqa_player.open(resName); @@ -59,8 +59,7 @@ void OuttakePlayer::play(const Common::String &name, bool noLocalization, int co break; if (frame >= 0) { - const Graphics::Surface *surface = vqa_player.getSurface(); - _vm->_system->copyRectToScreen((const byte *)surface->getBasePtr(0, 0), surface->pitch, 0, 0, 640, 480); + _vm->_system->copyRectToScreen(_vm->_surfaceGame.getPixels(), _vm->_surfaceGame.pitch, 0, 0, 640, 480); _vm->_system->updateScreen(); } diff --git a/engines/bladerunner/scene.cpp b/engines/bladerunner/scene.cpp index be5be7cc67..1e5297a4bf 100644 --- a/engines/bladerunner/scene.cpp +++ b/engines/bladerunner/scene.cpp @@ -33,6 +33,7 @@ #include "bladerunner/scene_objects.h" #include "bladerunner/script/scene.h" #include "bladerunner/slice_renderer.h" +#include "bladerunner/spinner.h" #include "common/str.h" @@ -75,7 +76,7 @@ bool Scene::open(int setId, int sceneId, bool isLoadingGame) { if (_vqaPlayer != nullptr) delete _vqaPlayer; - _vqaPlayer = new VQAPlayer(_vm); + _vqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceInterface); Common::String sceneName = _vm->_gameInfo->getSceneName(sceneId); if (!_vm->_sceneScript->Open(sceneName)) @@ -105,7 +106,7 @@ bool Scene::open(int setId, int sceneId, bool isLoadingGame) { _defaultLoopSet = true; _specialLoopAtEnd = false; } - _vm->_scene->advanceFrame(_vm->_surface1); + _vm->_scene->advanceFrame(); _vm->_playerActor->setAtXYZ(_actorStartPosition, _actorStartFacing); _vm->_playerActor->setSetId(setId); @@ -168,10 +169,10 @@ bool Scene::close(bool isLoadingGame) { return result; } -int Scene::advanceFrame(Graphics::Surface &surface) { +int Scene::advanceFrame() { int frame = _vqaPlayer->update(); if (frame >= 0) { - surface.copyFrom(*_vqaPlayer->getSurface()); + _vm->_surfaceGame.copyRectToSurface(_vm->_surfaceInterface.getPixels(), _vm->_surfaceInterface.pitch, 0, 0, 640, 480); _vqaPlayer->updateZBuffer(_vm->_zbuffer); _vqaPlayer->updateView(_vm->_view); _vqaPlayer->updateLights(_vm->_lights); @@ -306,8 +307,7 @@ void Scene::loopEnded(int frame, int loopId) { _playerWalkedIn = true; } if (_specialLoopMode == 3) { - //TODO: - //spinner::open(Spinner); + _vm->_spinner->setIsOpen(); } _specialLoopMode = -1; _specialLoop = -1; diff --git a/engines/bladerunner/scene.h b/engines/bladerunner/scene.h index 90cb936bf8..c90258ce53 100644 --- a/engines/bladerunner/scene.h +++ b/engines/bladerunner/scene.h @@ -89,7 +89,7 @@ public: bool open(int setId, int sceneId, bool isLoadingGame); bool close(bool isLoadingGame); - int advanceFrame(Graphics::Surface &surface); + int advanceFrame(); void setActorStart(Vector3 position, int facing); void loopSetDefault(int a); diff --git a/engines/bladerunner/script/scene.cpp b/engines/bladerunner/script/scene.cpp index 1ca6408549..646fa486af 100644 --- a/engines/bladerunner/script/scene.cpp +++ b/engines/bladerunner/script/scene.cpp @@ -27,11 +27,120 @@ namespace BladeRunner { bool SceneScript::Open(const Common::String &name) { delete _currentScript; + if (name == "AR01") { _currentScript = new SceneScriptAR01(_vm); return true; } + if (name == "AR02") { _currentScript = new SceneScriptAR02(_vm); return true; } + if (name == "BB01") { _currentScript = new SceneScriptBB01(_vm); return true; } + if (name == "BB02") { _currentScript = new SceneScriptBB02(_vm); return true; } + if (name == "BB03") { _currentScript = new SceneScriptBB03(_vm); return true; } + if (name == "BB04") { _currentScript = new SceneScriptBB04(_vm); return true; } + if (name == "BB05") { _currentScript = new SceneScriptBB05(_vm); return true; } + if (name == "BB06") { _currentScript = new SceneScriptBB06(_vm); return true; } + if (name == "BB07") { _currentScript = new SceneScriptBB07(_vm); return true; } + if (name == "BB08") { _currentScript = new SceneScriptBB08(_vm); return true; } + if (name == "BB09") { _currentScript = new SceneScriptBB09(_vm); return true; } + if (name == "BB10") { _currentScript = new SceneScriptBB10(_vm); return true; } + if (name == "BB11") { _currentScript = new SceneScriptBB11(_vm); return true; } + if (name == "BB12") { _currentScript = new SceneScriptBB12(_vm); return true; } + if (name == "BB51") { _currentScript = new SceneScriptBB51(_vm); return true; } + if (name == "CT01") { _currentScript = new SceneScriptCT01(_vm); return true; } + if (name == "CT02") { _currentScript = new SceneScriptCT02(_vm); return true; } + if (name == "CT03") { _currentScript = new SceneScriptCT03(_vm); return true; } + if (name == "CT04") { _currentScript = new SceneScriptCT04(_vm); return true; } + if (name == "CT05") { _currentScript = new SceneScriptCT05(_vm); return true; } + if (name == "CT06") { _currentScript = new SceneScriptCT06(_vm); return true; } + if (name == "CT07") { _currentScript = new SceneScriptCT07(_vm); return true; } + if (name == "CT08") { _currentScript = new SceneScriptCT08(_vm); return true; } + if (name == "CT09") { _currentScript = new SceneScriptCT09(_vm); return true; } + if (name == "CT10") { _currentScript = new SceneScriptCT10(_vm); return true; } + if (name == "CT11") { _currentScript = new SceneScriptCT11(_vm); return true; } + if (name == "CT12") { _currentScript = new SceneScriptCT12(_vm); return true; } + if (name == "CT51") { _currentScript = new SceneScriptCT51(_vm); return true; } + if (name == "DR01") { _currentScript = new SceneScriptDR01(_vm); return true; } + if (name == "DR02") { _currentScript = new SceneScriptDR02(_vm); return true; } + if (name == "DR03") { _currentScript = new SceneScriptDR03(_vm); return true; } + if (name == "DR04") { _currentScript = new SceneScriptDR04(_vm); return true; } + if (name == "DR05") { _currentScript = new SceneScriptDR05(_vm); return true; } + if (name == "DR06") { _currentScript = new SceneScriptDR06(_vm); return true; } + if (name == "HC01") { _currentScript = new SceneScriptHC01(_vm); return true; } + if (name == "HC02") { _currentScript = new SceneScriptHC02(_vm); return true; } + if (name == "HC03") { _currentScript = new SceneScriptHC03(_vm); return true; } + if (name == "HC04") { _currentScript = new SceneScriptHC04(_vm); return true; } + if (name == "HF01") { _currentScript = new SceneScriptHF01(_vm); return true; } + if (name == "HF02") { _currentScript = new SceneScriptHF02(_vm); return true; } + if (name == "HF03") { _currentScript = new SceneScriptHF03(_vm); return true; } + if (name == "HF04") { _currentScript = new SceneScriptHF04(_vm); return true; } + if (name == "HF05") { _currentScript = new SceneScriptHF05(_vm); return true; } + if (name == "HF06") { _currentScript = new SceneScriptHF06(_vm); return true; } + if (name == "HF07") { _currentScript = new SceneScriptHF07(_vm); return true; } + if (name == "KP01") { _currentScript = new SceneScriptKP01(_vm); return true; } + if (name == "KP02") { _currentScript = new SceneScriptKP02(_vm); return true; } + if (name == "KP03") { _currentScript = new SceneScriptKP03(_vm); return true; } + if (name == "KP04") { _currentScript = new SceneScriptKP04(_vm); return true; } + if (name == "KP05") { _currentScript = new SceneScriptKP05(_vm); return true; } + if (name == "KP06") { _currentScript = new SceneScriptKP06(_vm); return true; } + if (name == "KP07") { _currentScript = new SceneScriptKP07(_vm); return true; } + if (name == "MA01") { _currentScript = new SceneScriptMA01(_vm); return true; } + if (name == "MA02") { _currentScript = new SceneScriptMA02(_vm); return true; } + if (name == "MA04") { _currentScript = new SceneScriptMA04(_vm); return true; } + if (name == "MA05") { _currentScript = new SceneScriptMA05(_vm); return true; } + if (name == "MA06") { _currentScript = new SceneScriptMA06(_vm); return true; } + if (name == "MA07") { _currentScript = new SceneScriptMA07(_vm); return true; } + if (name == "MA08") { _currentScript = new SceneScriptMA08(_vm); return true; } + if (name == "NR01") { _currentScript = new SceneScriptNR01(_vm); return true; } + if (name == "NR02") { _currentScript = new SceneScriptNR02(_vm); return true; } + if (name == "NR03") { _currentScript = new SceneScriptNR03(_vm); return true; } + if (name == "NR04") { _currentScript = new SceneScriptNR04(_vm); return true; } + if (name == "NR05") { _currentScript = new SceneScriptNR05(_vm); return true; } + if (name == "NR06") { _currentScript = new SceneScriptNR06(_vm); return true; } + if (name == "NR07") { _currentScript = new SceneScriptNR07(_vm); return true; } + if (name == "NR08") { _currentScript = new SceneScriptNR08(_vm); return true; } + if (name == "NR09") { _currentScript = new SceneScriptNR09(_vm); return true; } + if (name == "NR10") { _currentScript = new SceneScriptNR10(_vm); return true; } + if (name == "NR11") { _currentScript = new SceneScriptNR11(_vm); return true; } + if (name == "PS01") { _currentScript = new SceneScriptPS01(_vm); return true; } + if (name == "PS02") { _currentScript = new SceneScriptPS02(_vm); return true; } + if (name == "PS03") { _currentScript = new SceneScriptPS03(_vm); return true; } + if (name == "PS04") { _currentScript = new SceneScriptPS04(_vm); return true; } + if (name == "PS05") { _currentScript = new SceneScriptPS05(_vm); return true; } + if (name == "PS06") { _currentScript = new SceneScriptPS06(_vm); return true; } + if (name == "PS07") { _currentScript = new SceneScriptPS07(_vm); return true; } + if (name == "PS09") { _currentScript = new SceneScriptPS09(_vm); return true; } + if (name == "PS10") { _currentScript = new SceneScriptPS10(_vm); return true; } + if (name == "PS11") { _currentScript = new SceneScriptPS11(_vm); return true; } + if (name == "PS12") { _currentScript = new SceneScriptPS12(_vm); return true; } + if (name == "PS13") { _currentScript = new SceneScriptPS13(_vm); return true; } + if (name == "PS14") { _currentScript = new SceneScriptPS14(_vm); return true; } + if (name == "PS15") { _currentScript = new SceneScriptPS15(_vm); return true; } if (name == "RC01") { _currentScript = new SceneScriptRC01(_vm); return true; } if (name == "RC02") { _currentScript = new SceneScriptRC02(_vm); return true; } if (name == "RC03") { _currentScript = new SceneScriptRC03(_vm); return true; } if (name == "RC04") { _currentScript = new SceneScriptRC04(_vm); return true; } if (name == "RC51") { _currentScript = new SceneScriptRC51(_vm); return true; } + if (name == "TB02") { _currentScript = new SceneScriptTB02(_vm); return true; } + if (name == "TB03") { _currentScript = new SceneScriptTB03(_vm); return true; } + if (name == "TB05") { _currentScript = new SceneScriptTB05(_vm); return true; } + if (name == "TB06") { _currentScript = new SceneScriptTB06(_vm); return true; } + if (name == "TB07") { _currentScript = new SceneScriptTB07(_vm); return true; } + if (name == "UG01") { _currentScript = new SceneScriptUG01(_vm); return true; } + if (name == "UG02") { _currentScript = new SceneScriptUG02(_vm); return true; } + if (name == "UG03") { _currentScript = new SceneScriptUG03(_vm); return true; } + if (name == "UG04") { _currentScript = new SceneScriptUG04(_vm); return true; } + if (name == "UG05") { _currentScript = new SceneScriptUG05(_vm); return true; } + if (name == "UG06") { _currentScript = new SceneScriptUG06(_vm); return true; } + if (name == "UG07") { _currentScript = new SceneScriptUG07(_vm); return true; } + if (name == "UG08") { _currentScript = new SceneScriptUG08(_vm); return true; } + if (name == "UG09") { _currentScript = new SceneScriptUG09(_vm); return true; } + if (name == "UG10") { _currentScript = new SceneScriptUG10(_vm); return true; } + if (name == "UG12") { _currentScript = new SceneScriptUG12(_vm); return true; } + if (name == "UG13") { _currentScript = new SceneScriptUG13(_vm); return true; } + if (name == "UG14") { _currentScript = new SceneScriptUG14(_vm); return true; } + if (name == "UG15") { _currentScript = new SceneScriptUG15(_vm); return true; } + if (name == "UG16") { _currentScript = new SceneScriptUG16(_vm); return true; } + if (name == "UG17") { _currentScript = new SceneScriptUG17(_vm); return true; } + if (name == "UG18") { _currentScript = new SceneScriptUG18(_vm); return true; } + if (name == "UG19") { _currentScript = new SceneScriptUG19(_vm); return true; } + + error("SceneScript::Open: Unknown script %s", name.c_str()); return false; } diff --git a/engines/bladerunner/script/script.cpp b/engines/bladerunner/script/script.cpp index 9fcfb252c6..ba78a42b4c 100644 --- a/engines/bladerunner/script/script.cpp +++ b/engines/bladerunner/script/script.cpp @@ -43,6 +43,7 @@ #include "bladerunner/scene_objects.h" #include "bladerunner/slice_animations.h" #include "bladerunner/slice_renderer.h" +#include "bladerunner/spinner.h" #include "bladerunner/text_resource.h" #include "bladerunner/vector.h" #include "bladerunner/waypoints.h" @@ -1071,22 +1072,15 @@ bool ScriptBase::SDB_Add_Other_Clue(int suspectId, int clueId) { } void ScriptBase::Spinner_Set_Selectable_Destination_Flag(int a1, int a2) { - //TODO - warning("Spinner_Set_Selectable_Destination_Flag(%d, %d)", a1, a2); + _vm->_spinner->setSelectableDestinationFlag(a1, a2); } // ScriptBase::Spinner_Query_Selectable_Destination_Flag int ScriptBase::Spinner_Interface_Choose_Dest(int a1, int a2) { - //TODO - warning("Spinner_Interface_Choose_Dest(%d, %d)", a1, a2); - return -1; + return _vm->_spinner->interfaceChooseDest(a1, a2); } -// ScriptBase::Spinner_Set_Selectable_Destination_Flag -// ScriptBase::Spinner_Query_Selectable_Destination_Flag -// ScriptBase::Spinner_Interface_Choose_Dest - void ScriptBase::ESPER_Flag_To_Activate() { //TODO warning("ESPER_Flag_To_Activate()"); diff --git a/engines/bladerunner/spinner.cpp b/engines/bladerunner/spinner.cpp new file mode 100644 index 0000000000..6c30a62bac --- /dev/null +++ b/engines/bladerunner/spinner.cpp @@ -0,0 +1,291 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + */ + +#include "bladerunner/spinner.h" + +#include "bladerunner/bladerunner.h" + +#include "bladerunner/scene.h" +#include "bladerunner/shape.h" +#include "bladerunner/mouse.h" +#include "bladerunner/vqa_player.h" +#include "bladerunner/text_resource.h" +#include "bladerunner/ui_image_picker.h" + +#include "common/rect.h" +#include "common/system.h" + +namespace BladeRunner { + +Spinner::Spinner(BladeRunnerEngine *vm) : _vm(vm) { + reset(); + _imagePicker = new UIImagePicker(vm, SPINNER_DESTINATIONS); +} + +Spinner::~Spinner() { + delete _imagePicker; + reset(); +} + +void Spinner::setSelectableDestinationFlag(int destination, bool selectable) { + _isDestinationSelectable[destination] = selectable; +} + +bool Spinner::querySelectableDestinationFlag(int destination) const { + return _isDestinationSelectable[destination]; +} + +SpinnerDestination SpinnerDestinationsNear[] = { + { 0, 0x0D2, 0x107, 0x107, 0x14C }, + { 1, 0x133, 0x14A, 0x169, 0x17D }, + { 2, 0x152, 0x089, 0x16A, 0x0A9 }, + { 3, 0x0F8, 0x087, 0x121, 0x0A8 }, + { 4, 0x160, 0x0DE, 0x17B, 0x0EE }, + { -1, -1, -1, -1, -1 } +}; + +SpinnerDestination SpinnerDestinationsMedium[] = { + { 0, 0x0FC, 0x0F2, 0x117, 0x11B }, + { 1, 0x12D, 0x111, 0x148, 0x130 }, + { 2, 0x13F, 0x0B6, 0x150, 0x0C8 }, + { 3, 0x10D, 0x0B5, 0x125, 0x0C8 }, + { 4, 0x145, 0x0E3, 0x159, 0x0F0 }, + { 5, 0x103, 0x04A, 0x17C, 0x077 }, + { 6, 0x0CB, 0x07C, 0x0E0, 0x088 }, + { 7, 0x0C8, 0x093, 0x0DE, 0x0AA }, + { -1, -1, -1, -1, -1 } +}; + +SpinnerDestination SpinnerDestinationsFar[] = { + { 0, 0x0DC, 0x0E3, 0x0F6, 0x106 }, + { 1, 0x104, 0x0FC, 0x11E, 0x117 }, + { 2, 0x11E, 0x0B2, 0x12E, 0x0C4 }, + { 3, 0x0F4, 0x0B2, 0x107, 0x0C3 }, + { 4, 0x120, 0x0D8, 0x132, 0x0E4 }, + { 5, 0x0F9, 0x04D, 0x161, 0x07C }, + { 6, 0x0BE, 0x07F, 0x0D0, 0x08A }, + { 7, 0x0B9, 0x095, 0x0CE, 0x0AA }, + { 8, 0x18E, 0x0F9, 0x1A3, 0x10C }, + { 9, 0x186, 0x0DA, 0x1A3, 0x0EC }, + { -1, -1, -1, -1, -1 } +}; + +static void spinner_mouseInCallback(int, void*); +static void spinner_mouseOutCallback(int, void*); +static void spinner_mouseDownCallback(int, void*); +static void spinner_mouseUpCallback(int, void*); + +int Spinner::interfaceChooseDest(int loopId, int loopFlag) { + _selectedDestination = 0; + if (!_vm->openArchive("MODE.MIX")) + return 0; + + if (loopId < 0) { + _isOpen = true; + } else { + _vm->playerLosesControl(); + _vm->_scene->loopStartSpecial(3, loopId, loopFlag); + while (!_isOpen) { + _vm->gameTick(); + } + _vm->playerGainsControl(); + } + + _vqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceInterface); + if (!_vqaPlayer->open("SPINNER.VQA")) { + return 0; + } + + _vm->_mouse->setCursor(0); + + // Determine which map we need to show to include the active destinations + uint8 mapmask = 0; + uint8 mapmaskv[SPINNER_DESTINATIONS] = { 1, 1, 1, 1, 1, 3, 3, 3, 7, 7 }; + for (int i = 0; i != SPINNER_DESTINATIONS; ++i) { + if (_isDestinationSelectable[i]) + mapmask |= mapmaskv[i]; + } + + _destinations = nullptr; + int firstShapeId = 0; + int shapeCount = 0; + int spinnerLoopId = 4; + + mapmask = 1; + + if (mapmask & 4) { + _destinations = SpinnerDestinationsFar; + firstShapeId = 26; + shapeCount = 20; + spinnerLoopId = 4; + } else if (mapmask & 2) { + _destinations = SpinnerDestinationsMedium; + firstShapeId = 10; + shapeCount = 16; + spinnerLoopId = 2; + } else if (mapmask & 1) { + _destinations = SpinnerDestinationsNear; + firstShapeId = 0; + shapeCount = 10; + spinnerLoopId = 0; + } else { + return -1; + } + + _vqaPlayer->setLoop(spinnerLoopId, -1, 2, nullptr, nullptr); + _vqaPlayer->setLoop(spinnerLoopId + 1, -1, 0, nullptr, nullptr); + + for (int j = 0; j != shapeCount; ++j) { + _shapes.push_back(new Shape(_vm)); + _shapes[j]->readFromContainer("SPINNER.SHP", firstShapeId + j); + } + + _imagePicker->resetImages(); + + for (SpinnerDestination *dest = _destinations; dest->id != -1; ++dest) { + if (!_isDestinationSelectable[dest->id]) + continue; + + const char *tooltip = _vm->_textSpinnerDestinations->getText(dest->id); + + _imagePicker->defineImage( + dest->id, + dest->left, + dest->top, + dest->right, + dest->bottom, + _shapes[dest->id], + _shapes[dest->id + _shapes.size() / 2], + _shapes[dest->id + _shapes.size() / 2], + tooltip + ); + } + + _imagePicker->setCallbacks( + spinner_mouseInCallback, + spinner_mouseOutCallback, + spinner_mouseDownCallback, + spinner_mouseUpCallback, + this + ); + + // TODO: Freeze game time + _selectedDestination = -1; + do { + _vm->gameTick(); + } while (_selectedDestination == -1); + + // TODO: Unfreeze game time + _isOpen = false; + // TODO: _vm->_scene->resume(); + + for (int i = 0; i != (int)_shapes.size(); ++i) + delete _shapes[i]; + _shapes.clear(); + + return _selectedDestination; +} + +static void spinner_mouseInCallback(int, void*) { +} + +static void spinner_mouseOutCallback(int, void*) { +} + +static void spinner_mouseDownCallback(int, void*) { +} + +static void spinner_mouseUpCallback(int image, void *data) { + if (image >= 0 && image < 10) { + Spinner *spinner = (Spinner *)data; + spinner->setSelectedDestination(image); + } +} + +void Spinner::setIsOpen() { + _isOpen = true; +} + +bool Spinner::isOpen() const { + return _isOpen; +} + +int Spinner::handleMouseUp(int x, int y) { + _imagePicker->handleMouseAction(x, y, false, true, 0); + return false; +} + +int Spinner::handleMouseDown(int x, int y) { + _imagePicker->handleMouseAction(x, y, true, false, 0); + return false; +} + +void Spinner::tick() { + if (!_vm->_gameIsRunning) + return; + + int frame = _vqaPlayer->update(); + assert(frame >= -1); + + // vqaPlayer renders to _surfaceInterface + _vm->_surfaceGame.copyRectToSurface(_vm->_surfaceInterface, 0, 0, Common::Rect(640, 480)); + + _imagePicker->draw(_vm->_surfaceInterface); + + Common::Point p = _vm->getMousePos(); + _imagePicker->handleMouseAction(p.x, p.y, false, false, false); + if (_imagePicker->hasHoveredImage()) { + _vm->_mouse->setCursor(1); + } else { + _vm->_mouse->setCursor(0); + } + _vm->_mouse->draw(_vm->_surfaceGame, p.x, p.y); + + _vm->_system->copyRectToScreen(_vm->_surfaceGame.getPixels(), _vm->_surfaceGame.pitch, 0, 0, 640, 480); + _vm->_system->updateScreen(); + _vm->_system->delayMillis(10); +} + +void Spinner::setSelectedDestination(int destination) { + _selectedDestination = destination; +} + +void Spinner::reset() { + for (int i = 0; i != SPINNER_DESTINATIONS; ++i) { + _isDestinationSelectable[i] = 0; + } + + _isOpen = false; + _destinations = nullptr; + _selectedDestination = -1; + _imagePicker = nullptr; + + for (int i = 0; i != (int)_shapes.size(); ++i) + delete _shapes[i]; + _shapes.clear(); +} + +void Spinner::resume() { + // TODO +} + +} // End of namespace BladeRunner diff --git a/engines/bladerunner/spinner.h b/engines/bladerunner/spinner.h new file mode 100644 index 0000000000..19021fac1a --- /dev/null +++ b/engines/bladerunner/spinner.h @@ -0,0 +1,77 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + */ + +#ifndef BLADERUNNER_SPINNER_H +#define BLADERUNNER_SPINNER_H + +#include "common/array.h" + +namespace BladeRunner { + +class BladeRunnerEngine; +class Shape; +class VQAPlayer; +class UIImagePicker; + +#define SPINNER_DESTINATIONS 10 + +struct SpinnerDestination { + int id; + int left; + int top; + int right; + int bottom; +}; + +class Spinner { + BladeRunnerEngine *_vm; + bool _isDestinationSelectable[SPINNER_DESTINATIONS]; + bool _isOpen; + VQAPlayer *_vqaPlayer; + SpinnerDestination *_destinations; + int _selectedDestination; + Common::Array<Shape*> _shapes; + UIImagePicker *_imagePicker; + +public: + Spinner(BladeRunnerEngine *vm); + ~Spinner(); + + void setSelectableDestinationFlag(int destination, bool selectable); + bool querySelectableDestinationFlag(int destination) const; + + int interfaceChooseDest(int vqaLoopId, int loopFlag); + + void setIsOpen(); + bool isOpen() const; + + int handleMouseUp(int x, int y); + int handleMouseDown(int x, int y); + void tick(); + void setSelectedDestination(int destination); + void reset(); + void resume(); +}; + +} // End of namespace BladeRunner + +#endif diff --git a/engines/bladerunner/ui_image_picker.cpp b/engines/bladerunner/ui_image_picker.cpp new file mode 100644 index 0000000000..654129754c --- /dev/null +++ b/engines/bladerunner/ui_image_picker.cpp @@ -0,0 +1,265 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + */ + +#include "bladerunner/ui_image_picker.h" + +#include "bladerunner/bladerunner.h" + +#include "bladerunner/shape.h" + +#include "common/rect.h" +#include "graphics/surface.h" + +namespace BladeRunner { + +struct UIImagePickerImage { + int active; + Common::Rect rect; + Shape *shapeUp; + Shape *shapeHovered; + Shape *shapeDown; + const char *tooltip; +}; + +UIImagePicker::UIImagePicker(BladeRunnerEngine *vm, int imageCount) : _vm(vm) { + reset(); + _images = new UIImagePickerImage[imageCount]; + _imageCount = imageCount; + resetImages(); +} + +UIImagePicker::~UIImagePicker() { + delete[] _images; + _images = nullptr; + reset(); +} + +void UIImagePicker::resetImages() { + for (int i = 0; i != _imageCount; i++) { + resetImage(i); + } +} + +bool UIImagePicker::defineImage(int i, int left, int top, int right, int bottom, Shape *shapeUp, Shape *shapeHovered, Shape *shapeDown, const char *tooltip) { + if (i < 0 || i >= _imageCount || _images[i].active) + return false; + + UIImagePickerImage &img = _images[i]; + + img.rect.left = left; + img.rect.top = top; + img.rect.right = right + 1; + img.rect.bottom = bottom + 1; + img.shapeUp = shapeUp; + img.shapeHovered = shapeHovered; + img.shapeDown = shapeDown; + img.active = true; + img.tooltip = tooltip; + + return true; +} + +bool UIImagePicker::setImageTop(int i, int top) { + if (i < 0 || i >= _imageCount || !_images[i].active) + return false; + + UIImagePickerImage &img = _images[i]; + + img.rect.moveTo(img.rect.left, top); + + return true; +} + +bool UIImagePicker::setImageLeft(int i, int left) { + if (i < 0 || i >= _imageCount || !_images[i].active) + return false; + + UIImagePickerImage &img = _images[i]; + + img.rect.moveTo(left, img.rect.top); + + return true; +} + +bool UIImagePicker::setImageShapeUp(int i, Shape *shapeUp) { + if (i < 0 || i >= _imageCount || !_images[i].active) + return false; + + _images[i].shapeUp = shapeUp; + + return true; +} + +bool UIImagePicker::setImageShapeHovered(int i, Shape *shapeHovered) { + if (i < 0 || i >= _imageCount || !_images[i].active) + return false; + + _images[i].shapeHovered = shapeHovered; + + return true; +} + +bool UIImagePicker::setImageShapeDown(int i, Shape *shapeDown) { + if (i < 0 || i >= _imageCount || !_images[i].active) + return false; + + _images[i].shapeDown = shapeDown; + + return true; +} + +bool UIImagePicker::setImageTooltip(int i, const char *tooltip) { + if (i < 0 || i >= _imageCount || !_images[i].active) + return false; + + _images[i].tooltip = tooltip; + + return true; +} + +bool UIImagePicker::resetActiveImage(int i) { + if (i < 0 || i >= _imageCount || !_images[i].active) + return false; + + resetImage(i); + return true; +} + +void UIImagePicker::setCallbacks(UIImagePickerCallback *mouseInCallback, + UIImagePickerCallback *mouseOutCallback, + UIImagePickerCallback *mouseDownCallback, + UIImagePickerCallback *mouseUpCallback, + void *callbackData) +{ + _isButtonDown = false; + _mouseInCallback = mouseInCallback; + _mouseOutCallback = mouseOutCallback; + _mouseDownCallback = mouseDownCallback; + _mouseUpCallback = mouseUpCallback; + _callbackData = callbackData; + _hoverStartTimestamp = 0; + _isVisible = true; + _hoveredImageIndex = -1; + _pressedImageIndex = -1; +} + +void UIImagePicker::resetCallbacks() {} + +// TODO +void UIImagePicker::drawTooltip() {} + +void UIImagePicker::draw(Graphics::Surface &surface) { + if (!_isVisible) + return; + + for (int i = 0; i != _imageCount; ++i) { + UIImagePickerImage &img = _images[i]; + if (!img.active) + continue; + + // TODO: Check interaction with Mouse::isDisabled + if (i == _hoveredImageIndex && i == _pressedImageIndex && _isButtonDown) { + if (img.shapeDown) { + img.shapeDown->draw(surface, img.rect.left, img.rect.top); + } + } else if (i == _hoveredImageIndex && !_isButtonDown) { + if (img.shapeHovered) { + img.shapeHovered->draw(surface, img.rect.left, img.rect.top); + } + } else { + if (img.shapeUp) { + img.shapeUp->draw(surface, img.rect.left, img.rect.top); + } + } + } +} + +void UIImagePicker::handleMouseAction(int x, int y, bool down, bool up, bool ignore) { + if (!_isVisible || ignore) { + return; + } + + int hoveredImageIndex = -1; + for (int i = 0; i != _imageCount; ++i) { + if (_images[i].rect.contains(x, y)) { + hoveredImageIndex = i; + break; + } + } + + // If mouse moved to a new image + if (hoveredImageIndex != _hoveredImageIndex) { + if (!_isButtonDown) { + if (hoveredImageIndex == -1) { + if (_mouseOutCallback) + _mouseOutCallback(hoveredImageIndex, _callbackData); + } else { + if (_mouseInCallback) + _mouseInCallback(hoveredImageIndex, _callbackData); + } + } + _hoveredImageIndex = hoveredImageIndex; + } + + // If mouse button changed to pressed + if (down && !_isButtonDown) { + _isButtonDown = true; + _pressedImageIndex = _hoveredImageIndex; + if (_mouseDownCallback) + _mouseDownCallback(_hoveredImageIndex, _callbackData); + } + + // If mouse button changed to released + if (up) { + if (_isButtonDown) { + if (_hoveredImageIndex == _pressedImageIndex && _pressedImageIndex != -1) { + if (_mouseUpCallback) + _mouseUpCallback(_hoveredImageIndex, _callbackData); + } + } + _isButtonDown = false; + _pressedImageIndex = -1; + } +} + +void UIImagePicker::resetImage(int i) { + assert(i >= 0 && i < _imageCount); + UIImagePickerImage &img = _images[i]; + + img.active = false; + img.rect.left = -1; + img.rect.top = -1; + img.rect.right = -1; + img.rect.bottom = -1; + img.shapeUp = nullptr; + img.shapeHovered = nullptr; + img.shapeDown = nullptr; + img.tooltip = nullptr; +} + +bool UIImagePicker::hasHoveredImage() { + return _hoveredImageIndex >= 0; +} + +void UIImagePicker::reset() {} + +} // End of namespace BladeRunner diff --git a/engines/bladerunner/ui_image_picker.h b/engines/bladerunner/ui_image_picker.h new file mode 100644 index 0000000000..c55aa48a64 --- /dev/null +++ b/engines/bladerunner/ui_image_picker.h @@ -0,0 +1,92 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + */ + +#ifndef BLADERUNNER_UI_IMAGE_PICKER_H +#define BLADERUNNER_UI_IMAGE_PICKER_H + +namespace Graphics { +struct Surface; +} + +namespace BladeRunner { + +class BladeRunnerEngine; +class Shape; +struct UIImagePickerImage; + +typedef void UIImagePickerCallback(int, void*); + +class UIImagePicker { + BladeRunnerEngine *_vm; + + int _isVisible; + int _imageCount; + int _hoveredImageIndex; + int _pressedImageIndex; + int _hoverStartTimestamp; + int _isButtonDown; + UIImagePickerImage *_images; + + UIImagePickerCallback *_mouseInCallback; + UIImagePickerCallback *_mouseOutCallback; + UIImagePickerCallback *_mouseDownCallback; + UIImagePickerCallback *_mouseUpCallback; + void *_callbackData; + +public: + UIImagePicker(BladeRunnerEngine *vm, int imageCount); + ~UIImagePicker(); + + void resetImages(); + bool defineImage(int i, int left, int top, int right, int bottom, Shape *shapeUp, Shape *shapeHovered, Shape *shapeDown, const char *tooltip); + + bool setImageTop(int i, int top); + bool setImageLeft(int i, int left); + bool setImageShapeUp(int i, Shape *shapeUp); + bool setImageShapeHovered(int i, Shape *shapeHovered); + bool setImageShapeDown(int i, Shape *shapeDown); + bool setImageTooltip(int i, const char *tooltip); + + bool resetActiveImage(int i); + + void setCallbacks(UIImagePickerCallback *mouseInCallback, + UIImagePickerCallback *mouseOutCallback, + UIImagePickerCallback *mouseDownCallback, + UIImagePickerCallback *mouseUpCallback, + void *callbackData); + + void resetCallbacks(); + + void drawTooltip(); + void draw(Graphics::Surface &surface); + + void handleMouseAction(int x, int y, bool down, bool up, bool ignore = false); + + void resetImage(int i); + bool hasHoveredImage(); + + void reset(); +}; + +} // End of namespace BladeRunner + +#endif diff --git a/engines/bladerunner/vqa_decoder.cpp b/engines/bladerunner/vqa_decoder.cpp index 01ccfd5874..c43e4c3f9d 100644 --- a/engines/bladerunner/vqa_decoder.cpp +++ b/engines/bladerunner/vqa_decoder.cpp @@ -115,7 +115,9 @@ const char *strTag(uint32 tag) { return s; } -VQADecoder::VQADecoder() : _s(nullptr), +VQADecoder::VQADecoder(Graphics::Surface *surface) : + _s(nullptr), + _surface(surface), _frameInfo(nullptr), _videoTrack(nullptr), _audioTrack(nullptr), @@ -173,7 +175,7 @@ bool VQADecoder::loadStream(Common::SeekableReadStream *s) { } } while (chd.id != kFINF); - _videoTrack = new VQAVideoTrack(this); + _videoTrack = new VQAVideoTrack(this, _surface); _audioTrack = new VQAAudioTrack(this); #if 0 @@ -188,8 +190,8 @@ bool VQADecoder::loadStream(Common::SeekableReadStream *s) { return true; } -const Graphics::Surface *VQADecoder::decodeVideoFrame() { - return _videoTrack->decodeVideoFrame(); +void VQADecoder::decodeVideoFrame() { + _videoTrack->decodeVideoFrame(); } void VQADecoder::decodeZBuffer(ZBuffer *zbuffer) { @@ -533,10 +535,10 @@ bool VQADecoder::readMFCI(Common::SeekableReadStream *s, uint32 size) { return true; } -VQADecoder::VQAVideoTrack::VQAVideoTrack(VQADecoder *vqaDecoder) { +VQADecoder::VQAVideoTrack::VQAVideoTrack(VQADecoder *vqaDecoder, Graphics::Surface *surface) { VQADecoder::Header *header = &vqaDecoder->_header; - _surface = nullptr; + _surface = surface; _hasNewFrame = false; _numFrames = header->numFrames; @@ -565,9 +567,6 @@ VQADecoder::VQAVideoTrack::VQAVideoTrack(VQADecoder *vqaDecoder) { _zbufChunk = new uint8[roundup(_maxZBUFChunkSize)]; - _surface = new Graphics::Surface(); - _surface->create(_width, _height, createRGB555()); - _viewData = nullptr; _lightsData = nullptr; } @@ -578,10 +577,6 @@ VQADecoder::VQAVideoTrack::~VQAVideoTrack() { delete[] _zbufChunk; delete[] _vpointer; - if (_surface) - _surface->free(); - delete _surface; - if (_viewData) delete[] _viewData; if (_lightsData) @@ -596,10 +591,6 @@ uint16 VQADecoder::VQAVideoTrack::getHeight() const { return _height; } -Graphics::PixelFormat VQADecoder::VQAVideoTrack::getPixelFormat() const { - return _surface->format; -} - int VQADecoder::VQAVideoTrack::getCurFrame() const { return _curFrame; } @@ -612,13 +603,12 @@ Common::Rational VQADecoder::VQAVideoTrack::getFrameRate() const { return _frameRate; } -const Graphics::Surface *VQADecoder::VQAVideoTrack::decodeVideoFrame() { +void VQADecoder::VQAVideoTrack::decodeVideoFrame() { if (_hasNewFrame) { decodeFrame((uint16*)_surface->getPixels()); _curFrame++; _hasNewFrame = false; } - return _surface; } bool VQADecoder::VQAVideoTrack::readVQFL(Common::SeekableReadStream *s, uint32 size) { diff --git a/engines/bladerunner/vqa_decoder.h b/engines/bladerunner/vqa_decoder.h index a808543bec..d7086d1b9f 100644 --- a/engines/bladerunner/vqa_decoder.h +++ b/engines/bladerunner/vqa_decoder.h @@ -44,14 +44,14 @@ class ZBuffer; class VQADecoder { public: - VQADecoder(); + VQADecoder(Graphics::Surface *surface); ~VQADecoder(); bool loadStream(Common::SeekableReadStream *s); void readFrame(int frame, int skipFlags); - const Graphics::Surface *decodeVideoFrame(); + void decodeVideoFrame(); void decodeZBuffer(ZBuffer *zbuffer); Audio::SeekableAudioStream *decodeAudioFrame(); void decodeView(View *view); @@ -126,6 +126,7 @@ private: class VQAAudioTrack; Common::SeekableReadStream *_s; + Graphics::Surface *_surface; Header _header; LoopInfo _loopInfo; @@ -153,15 +154,14 @@ private: class VQAVideoTrack { public: - VQAVideoTrack(VQADecoder *vqaDecoder); + VQAVideoTrack(VQADecoder *vqaDecoder, Graphics::Surface *surface); ~VQAVideoTrack(); uint16 getWidth() const; uint16 getHeight() const; - Graphics::PixelFormat getPixelFormat() const; int getCurFrame() const; int getFrameCount() const; - const Graphics::Surface *decodeVideoFrame(); + void decodeVideoFrame(); void decodeZBuffer(ZBuffer *zbuffer); void decodeView(View *view); void decodeLights(Lights *lights); diff --git a/engines/bladerunner/vqa_player.cpp b/engines/bladerunner/vqa_player.cpp index 845e2ee1a7..129bb77b0e 100644 --- a/engines/bladerunner/vqa_player.cpp +++ b/engines/bladerunner/vqa_player.cpp @@ -99,7 +99,7 @@ int VQAPlayer::update() { _callbackLoopEnded(_callbackData, 0, _loop); } } - _surface = nullptr; + return -1; } @@ -114,7 +114,7 @@ int VQAPlayer::update() { if (now >= _frameNextTime) { int frame = _frameNext; _decoder.readFrame(_frameNext, 0x2); - _surface = _decoder.decodeVideoFrame(); + _decoder.decodeVideoFrame(); if (_hasAudio) { if (!_audioStarted) { @@ -142,14 +142,9 @@ int VQAPlayer::update() { return frame; } - _surface = nullptr; return -1; } -const Graphics::Surface *VQAPlayer::getSurface() const { - return _surface; -} - void VQAPlayer::updateZBuffer(ZBuffer *zbuffer) { _decoder.decodeZBuffer(zbuffer); } diff --git a/engines/bladerunner/vqa_player.h b/engines/bladerunner/vqa_player.h index 8c2653ec85..b60f648d4d 100644 --- a/engines/bladerunner/vqa_player.h +++ b/engines/bladerunner/vqa_player.h @@ -48,8 +48,8 @@ class ZBuffer; class VQAPlayer { BladeRunnerEngine *_vm; Common::SeekableReadStream *_s; - VQADecoder _decoder; const Graphics::Surface *_surface; + VQADecoder _decoder; const uint16 *_zBuffer; Audio::QueuingAudioStream *_audioStream; @@ -75,10 +75,11 @@ class VQAPlayer { public: - VQAPlayer(BladeRunnerEngine *vm) + VQAPlayer(BladeRunnerEngine *vm, Graphics::Surface *surface) : _vm(vm), _s(nullptr), - _surface(nullptr), + _surface(surface), + _decoder(surface), _zBuffer(nullptr), _audioStream(nullptr), _frameNext(-1), @@ -104,7 +105,6 @@ public: void close(); int update(); - const Graphics::Surface *getSurface() const; void updateZBuffer(ZBuffer *zbuffer); void updateView(View *view); void updateLights(Lights *lights); diff --git a/engines/draci/music.cpp b/engines/draci/music.cpp index 3fa380196a..fc44402bb8 100644 --- a/engines/draci/music.cpp +++ b/engines/draci/music.cpp @@ -53,7 +53,7 @@ MusicPlayer::MusicPlayer(const char *pathMask) : _pathMask(pathMask), _isGM(fals void MusicPlayer::sendToChannel(byte channel, uint32 b) { if (!_channelsTable[channel]) { - _channelsTable[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel(); + _channelsTable[channel] = (channel == 15) ? _driver->getPercussionChannel() : _driver->allocateChannel(); // If a new channel is allocated during the playback, make sure // its volume is correctly initialized. if (_channelsTable[channel]) diff --git a/engines/hopkins/hopkins.h b/engines/hopkins/hopkins.h index 30140baa2e..3528a98d58 100644 --- a/engines/hopkins/hopkins.h +++ b/engines/hopkins/hopkins.h @@ -72,8 +72,6 @@ enum HopkinsDebugChannels { */ #define MKTAG24(a0,a1,a2) ((uint32)((a2) | (a1) << 8 | ((a0) << 16))) -#define READ_LE_INT16(x) (int16) READ_LE_UINT16(x) - struct HopkinsGameDescription; class HopkinsEngine : public Engine { diff --git a/engines/lure/luredefs.h b/engines/lure/luredefs.h index 7b39710798..c6d0afa34c 100644 --- a/engines/lure/luredefs.h +++ b/engines/lure/luredefs.h @@ -37,9 +37,6 @@ namespace Lure { #define LURE_DEBUG 1 -#define READ_LE_INT16(x) (int16) READ_LE_UINT16(x) -#define READ_LE_INT32(x) (int32) READ_LE_UINT32(x) - enum { kLureDebugScripts = 1 << 0, kLureDebugAnimations = 1 << 1, diff --git a/engines/mohawk/console.cpp b/engines/mohawk/console.cpp index 877c1acd37..f24df96b55 100644 --- a/engines/mohawk/console.cpp +++ b/engines/mohawk/console.cpp @@ -248,37 +248,27 @@ bool MystConsole::Cmd_StopSound(int argc, const char **argv) { } bool MystConsole::Cmd_PlayMovie(int argc, const char **argv) { - if (argc < 2) { - debugPrintf("Usage: playMovie <name> [<stack>] [<left> <top>]\n"); + if (argc < 3) { + debugPrintf("Usage: playMovie <name> <stack> [<left> <top>]\n"); debugPrintf("NOTE: The movie will play *once* in the background.\n"); return true; } - Common::String fileName; - if (argc == 3 || argc > 4) { - int8 stackNum = 0; - for (byte i = 1; i <= ARRAYSIZE(mystStackNames); i++) - if (!scumm_stricmp(argv[2], mystStackNames[i - 1])) { - stackNum = i; - break; - } - - if (!stackNum) { - debugPrintf("\'%s\' is not a stack name!\n", argv[2]); - return true; + Common::String fileName = argv[1]; + int8 stackNum = -1; + for (byte i = 0; i < ARRAYSIZE(mystStackNames); i++) + if (!scumm_stricmp(argv[2], mystStackNames[i])) { + stackNum = i; + break; } - fileName = _vm->wrapMovieFilename(argv[1], stackNum - 1); - } else { - fileName = argv[1]; - } - - VideoEntryPtr video = _vm->_video->playMovie(fileName); - if (!video) { - debugPrintf("Failed to open movie '%s'\n", fileName.c_str()); + if (stackNum < 0) { + debugPrintf("\'%s\' is not a stack name!\n", argv[2]); return true; } + VideoEntryPtr video = _vm->playMovie(fileName, static_cast<MystStack>(stackNum)); + if (argc == 4) { video->setX(atoi(argv[2])); video->setY(atoi(argv[3])); diff --git a/engines/mohawk/myst.cpp b/engines/mohawk/myst.cpp index 9ce38b92b5..bd4af66360 100644 --- a/engines/mohawk/myst.cpp +++ b/engines/mohawk/myst.cpp @@ -225,11 +225,27 @@ Common::String MohawkEngine_Myst::wrapMovieFilename(const Common::String &movieN return Common::String("qtw/") + prefix + movieName + ".mov"; } +VideoEntryPtr MohawkEngine_Myst::playMovie(const Common::String &name, MystStack stack) { + Common::String filename = wrapMovieFilename(name, stack); + VideoEntryPtr video = _video->playMovie(filename, Audio::Mixer::kSFXSoundType); -void MohawkEngine_Myst::playMovieBlocking(const Common::String &fileName, uint16 x, uint16 y) { - VideoEntryPtr video = _video->playMovie(fileName); if (!video) { - error("Failed to open the '%s' movie", fileName.c_str()); + error("Failed to open the '%s' movie", filename.c_str()); + } + + return video; +} + +VideoEntryPtr MohawkEngine_Myst::findVideo(const Common::String &name, MystStack stack) { + Common::String filename = wrapMovieFilename(name, stack); + return _video->findVideo(filename); +} + +void MohawkEngine_Myst::playMovieBlocking(const Common::String &name, MystStack stack, uint16 x, uint16 y) { + Common::String filename = wrapMovieFilename(name, stack); + VideoEntryPtr video = _video->playMovie(filename, Audio::Mixer::kSFXSoundType); + if (!video) { + error("Failed to open the '%s' movie", filename.c_str()); } video->moveTo(x, y); @@ -237,10 +253,11 @@ void MohawkEngine_Myst::playMovieBlocking(const Common::String &fileName, uint16 waitUntilMovieEnds(video); } -void MohawkEngine_Myst::playMovieBlockingCentered(const Common::String &fileName) { - VideoEntryPtr video = _video->playMovie(fileName); +void MohawkEngine_Myst::playFlybyMovie(const Common::String &name) { + Common::String filename = wrapMovieFilename(name, kMasterpieceOnly); + VideoEntryPtr video = _video->playMovie(filename, Audio::Mixer::kSFXSoundType); if (!video) { - error("Failed to open the '%s' movie", fileName.c_str()); + error("Failed to open the '%s' movie", filename.c_str()); } // Clear screen @@ -579,7 +596,7 @@ void MohawkEngine_Myst::changeToStack(uint16 stack, uint16 card, uint16 linkSrcS } if (flyby) { - playMovieBlockingCentered(wrapMovieFilename(flyby, kMasterpieceOnly)); + playFlybyMovie(flyby); } } diff --git a/engines/mohawk/myst.h b/engines/mohawk/myst.h index f9823e5291..3f756faee0 100644 --- a/engines/mohawk/myst.h +++ b/engines/mohawk/myst.h @@ -63,7 +63,7 @@ enum { }; // Myst Stacks -enum { +enum MystStack { kChannelwoodStack = 0, // Channelwood Age kCreditsStack, // Credits kDemoStack, // Demo Main Menu @@ -181,8 +181,6 @@ public: Common::SeekableReadStream *getResource(uint32 tag, uint16 id) override; Common::Array<uint16> getResourceIDList(uint32 type) const; - Common::String wrapMovieFilename(const Common::String &movieName, uint16 stack); - void changeToStack(uint16 stack, uint16 card, uint16 linkSrcSound, uint16 linkDstSound); void changeToCard(uint16 card, TransitionType transition); uint16 getCurCard() { return _curCard; } @@ -228,8 +226,10 @@ public: void setCacheState(bool state) { _cache.enabled = state; } bool getCacheState() { return _cache.enabled; } - void playMovieBlocking(const Common::String &filename, uint16 x, uint16 y); - void playMovieBlockingCentered(const Common::String &filename); + VideoEntryPtr playMovie(const Common::String &name, MystStack stack); + VideoEntryPtr findVideo(const Common::String &name, MystStack stack); + void playMovieBlocking(const Common::String &name, MystStack stack, uint16 x, uint16 y); + void playFlybyMovie(const Common::String &name); void waitUntilMovieEnds(const VideoEntryPtr &video); void playSoundBlocking(uint16 id); @@ -269,6 +269,9 @@ private: void loadResources(); void drawResourceRects(); void checkCurrentResource(); + void updateActiveResource(); + + Common::String wrapMovieFilename(const Common::String &movieName, uint16 stack); /** Area of type kMystAreaHover being hovered by the mouse, if any */ MystAreaHover *_hoverResource; @@ -291,8 +294,6 @@ private: uint16 _mainCursor; // Also defines the current page being held (white, blue, red, or none) void pauseEngineIntern(bool) override; - - void updateActiveResource(); }; template<class T> diff --git a/engines/mohawk/myst_areas.cpp b/engines/mohawk/myst_areas.cpp index 61b0d8796b..7cc39e97b2 100644 --- a/engines/mohawk/myst_areas.cpp +++ b/engines/mohawk/myst_areas.cpp @@ -162,7 +162,7 @@ const Common::String MystAreaAction::describe() { } // In Myst/Making of Myst, the paths are hardcoded ala Windows style without extension. Convert them. -Common::String MystAreaVideo::convertMystVideoName(Common::String name) { +Common::String MystAreaVideo::convertMystVideoName(const Common::String &name) { Common::String temp; for (uint32 i = 1; i < name.size(); i++) { @@ -217,7 +217,7 @@ VideoEntryPtr MystAreaVideo::playMovie() { // If the video is not running, play it if (!handle) { - handle = _vm->_video->playMovie(_videoFile); + handle = _vm->_video->playMovie(_videoFile, Audio::Mixer::kSFXSoundType); if (!handle) error("Failed to open '%s'", _videoFile.c_str()); @@ -256,7 +256,7 @@ VideoEntryPtr MystAreaVideo::getVideo() { VideoEntryPtr handle = _vm->_video->findVideo(_videoFile); if (!handle) { // If the video has not been loaded yet, do it but don't start playing it - handle = _vm->_video->playMovie(_videoFile); + handle = _vm->_video->playMovie(_videoFile, Audio::Mixer::kSFXSoundType); if (!handle) error("Failed to open '%s'", _videoFile.c_str()); handle->stop(); diff --git a/engines/mohawk/myst_areas.h b/engines/mohawk/myst_areas.h index 3108a197fb..32b6ca4f2f 100644 --- a/engines/mohawk/myst_areas.h +++ b/engines/mohawk/myst_areas.h @@ -117,7 +117,7 @@ public: void pauseMovie(bool pause); protected: - static Common::String convertMystVideoName(Common::String name); + static Common::String convertMystVideoName(const Common::String &name); Common::String _videoFile; int16 _left; diff --git a/engines/mohawk/myst_stacks/channelwood.cpp b/engines/mohawk/myst_stacks/channelwood.cpp index 4777e92899..17df749c74 100644 --- a/engines/mohawk/myst_stacks/channelwood.cpp +++ b/engines/mohawk/myst_stacks/channelwood.cpp @@ -296,10 +296,7 @@ bool Channelwood::pipeChangeValve(bool open, uint16 mask) { } void Channelwood::o_bridgeToggle(uint16 var, const ArgumentsArray &args) { - VideoEntryPtr bridge = _vm->_video->playMovie(_vm->wrapMovieFilename("bridge", kChannelwoodStack)); - if (!bridge) - error("Failed to open 'bridge' movie"); - + VideoEntryPtr bridge = _vm->playMovie("bridge", kChannelwoodStack); bridge->moveTo(292, 203); // Toggle bridge state @@ -316,10 +313,7 @@ void Channelwood::o_pipeExtend(uint16 var, const ArgumentsArray &args) { debugC(kDebugScript, "\tsoundId: %d", soundId); _vm->_sound->playEffect(soundId); - VideoEntryPtr pipe = _vm->_video->playMovie(_vm->wrapMovieFilename("pipebrid", kChannelwoodStack)); - if (!pipe) - error("Failed to open 'pipebrid' movie"); - + VideoEntryPtr pipe = _vm->playMovie("pipebrid", kChannelwoodStack); pipe->moveTo(267, 170); // Toggle pipe state @@ -581,27 +575,19 @@ void Channelwood::o_hologramMonitor(uint16 var, const ArgumentsArray &args) { switch (button) { case 0: - video = _vm->_video->playMovie(_vm->wrapMovieFilename("monalgh", kChannelwoodStack)); - if (!video) - error("Failed to open monalgh movie"); + video = _vm->playMovie("monalgh", kChannelwoodStack); video->moveTo(227, 70); break; case 1: - video = _vm->_video->playMovie(_vm->wrapMovieFilename("monamth", kChannelwoodStack)); - if (!video) - error("Failed to open monamth movie"); + video = _vm->playMovie("monamth", kChannelwoodStack); video->moveTo(227, 70); break; case 2: - video = _vm->_video->playMovie(_vm->wrapMovieFilename("monasirs", kChannelwoodStack)); - if (!video) - error("Failed to open monasirs movie"); + video = _vm->playMovie("monasirs", kChannelwoodStack); video->moveTo(227, 70); break; case 3: - video = _vm->_video->playMovie(_vm->wrapMovieFilename("monsmsg", kChannelwoodStack)); - if (!video) - error("Failed to open monsmsg movie"); + video = _vm->playMovie("monsmsg", kChannelwoodStack); video->moveTo(226, 68); break; default: @@ -623,16 +609,16 @@ void Channelwood::o_hologramTemple(uint16 var, const ArgumentsArray &args) { // Used on Card 3333 (Temple Hologram) switch (_state.holoprojectorSelection) { case 0: - _vm->playMovieBlocking(_vm->wrapMovieFilename("holoalgh", kChannelwoodStack), 139, 64); + _vm->playMovieBlocking("holoalgh", kChannelwoodStack, 139, 64); break; case 1: - _vm->playMovieBlocking(_vm->wrapMovieFilename("holoamth", kChannelwoodStack), 127, 73); + _vm->playMovieBlocking("holoamth", kChannelwoodStack, 127, 73); break; case 2: - _vm->playMovieBlocking(_vm->wrapMovieFilename("holoasir", kChannelwoodStack), 139, 64); + _vm->playMovieBlocking("holoasir", kChannelwoodStack, 139, 64); break; case 3: - _vm->playMovieBlocking(_vm->wrapMovieFilename("holosmsg", kChannelwoodStack), 127, 45); + _vm->playMovieBlocking("holosmsg", kChannelwoodStack, 127, 45); break; default: warning("Opcode o_hologramTemple Control Variable Out of Range"); @@ -673,32 +659,32 @@ void Channelwood::o_elevatorMovies(uint16 var, const ArgumentsArray &args) { x = 214; y = 106; if (direction == 1) - movie = _vm->wrapMovieFilename("welev1up", kChannelwoodStack); + movie = "welev1up"; else - movie = _vm->wrapMovieFilename("welev1dn", kChannelwoodStack); + movie = "welev1dn"; break; case 2: x = 215; y = 117; if (direction == 1) - movie = _vm->wrapMovieFilename("welev2up", kChannelwoodStack); + movie = "welev2up"; else - movie = _vm->wrapMovieFilename("welev2dn", kChannelwoodStack); + movie = "welev2dn"; break; case 3: x = 213; y = 98; if (direction == 1) - movie = _vm->wrapMovieFilename("welev3up", kChannelwoodStack); + movie = "welev3up"; else - movie = _vm->wrapMovieFilename("welev3dn", kChannelwoodStack); + movie = "welev3dn"; break; default: error("Unknown elevator state %d in o_elevatorMovies", elevator); } _vm->_sound->pauseBackground(); - _vm->playMovieBlocking(movie, x, y); + _vm->playMovieBlocking(movie, kChannelwoodStack, x, y); _vm->_sound->resumeBackground(); } diff --git a/engines/mohawk/myst_stacks/dni.cpp b/engines/mohawk/myst_stacks/dni.cpp index c668a8c37e..dce40c71f4 100644 --- a/engines/mohawk/myst_stacks/dni.cpp +++ b/engines/mohawk/myst_stacks/dni.cpp @@ -95,7 +95,7 @@ void Dni::o_handPage(uint16 var, const ArgumentsArray &args) { // Used in Card 5014 (Atrus) // Find Atrus movie - VideoEntryPtr atrus = _vm->_video->findVideo(_video); + VideoEntryPtr atrus = _vm->findVideo(_video, kDniStack); // Good ending and Atrus asked to give page if (_globals.ending == 1 && atrus && atrus->getTime() > (uint)Audio::Timestamp(0, 6801, 600).msecs()) { @@ -115,11 +115,8 @@ void Dni::o_handPage(uint16 var, const ArgumentsArray &args) { void Dni::atrusLeft_run() { if (_vm->_system->getMillis() > _atrusLeftTime + 63333) { - _video = _vm->wrapMovieFilename("atrus2", kDniStack); - VideoEntryPtr atrus = _vm->_video->playMovie(_video); - if (!atrus) - error("Failed to open '%s'", _video.c_str()); - + _video = "atrus2"; + VideoEntryPtr atrus = _vm->playMovie(_video, kDniStack); atrus->moveTo(215, 77); atrus->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 98000, 600)); @@ -138,10 +135,7 @@ void Dni::atrusLeft_run() { void Dni::loopVideo_run() { if (!_vm->_video->isVideoPlaying()) { - VideoEntryPtr atrus = _vm->_video->playMovie(_video); - if (!atrus) - error("Failed to open '%s'", _video.c_str()); - + VideoEntryPtr atrus = _vm->playMovie(_video, kDniStack); atrus->moveTo(215, 77); atrus->setBounds(Audio::Timestamp(0, _loopStart, 600), Audio::Timestamp(0, _loopEnd, 600)); atrus->setLooping(true); @@ -157,22 +151,16 @@ void Dni::atrus_run() { } else if (_globals.ending == 1) { // Atrus asking for page if (!_vm->_video->isVideoPlaying()) { - _video = _vm->wrapMovieFilename("atr1page", kDniStack); - VideoEntryPtr atrus = _vm->_video->playMovie(_video); - if (!atrus) - error("Failed to open '%s'", _video.c_str()); - + _video = "atr1page"; + VideoEntryPtr atrus = _vm->playMovie(_video, kDniStack); atrus->moveTo(215, 77); atrus->setLooping(true); atrus->setBounds(Audio::Timestamp(0, 7388, 600), Audio::Timestamp(0, 14700, 600)); } } else if (_globals.ending != 3 && _globals.ending != 4) { if (_globals.heldPage == 13) { - _video = _vm->wrapMovieFilename("atr1page", kDniStack); - VideoEntryPtr atrus = _vm->_video->playMovie(_video); - if (!atrus) - error("Failed to open '%s'", _video.c_str()); - + _video = "atr1page"; + VideoEntryPtr atrus = _vm->playMovie(_video, kDniStack); atrus->moveTo(215, 77); atrus->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 14700, 600)); @@ -184,11 +172,8 @@ void Dni::atrus_run() { _globals.ending = 1; } else { - _video = _vm->wrapMovieFilename("atr1nopg", kDniStack); - VideoEntryPtr atrus = _vm->_video->playMovie(_video); - if (!atrus) - error("Failed to open '%s'", _video.c_str()); - + _video = "atr1nopg"; + VideoEntryPtr atrus = _vm->playMovie(_video, kDniStack); atrus->moveTo(215, 77); atrus->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 46175, 600)); @@ -200,10 +185,7 @@ void Dni::atrus_run() { _globals.ending = 3; } } else if (!_vm->_video->isVideoPlaying()) { - VideoEntryPtr atrus = _vm->_video->playMovie(_vm->wrapMovieFilename("atrwrite", kDniStack)); - if (!atrus) - error("Failed to open atrwrite movie"); - + VideoEntryPtr atrus = _vm->playMovie("atrwrite", kDniStack); atrus->moveTo(215, 77); atrus->setLooping(true); } diff --git a/engines/mohawk/myst_stacks/intro.cpp b/engines/mohawk/myst_stacks/intro.cpp index b77fa0851d..2b431e834a 100644 --- a/engines/mohawk/myst_stacks/intro.cpp +++ b/engines/mohawk/myst_stacks/intro.cpp @@ -94,10 +94,7 @@ void Intro::introMovies_run() { switch (_introStep) { case 0: _introStep = 1; - video = _vm->_video->playMovie(_vm->wrapMovieFilename("broder", kIntroStack)); - if (!video) - error("Failed to open broder movie"); - + video = _vm->playMovie("broder", kIntroStack); video->center(); break; case 1: @@ -106,10 +103,7 @@ void Intro::introMovies_run() { break; case 2: _introStep = 3; - video = _vm->_video->playMovie(_vm->wrapMovieFilename("cyanlogo", kIntroStack)); - if (!video) - error("Failed to open cyanlogo movie"); - + video = _vm->playMovie("cyanlogo", kIntroStack); video->center(); break; case 3: @@ -120,10 +114,7 @@ void Intro::introMovies_run() { _introStep = 5; if (!(_vm->getFeatures() & GF_DEMO)) { // The demo doesn't have the intro video - video = _vm->_video->playMovie(_vm->wrapMovieFilename("intro", kIntroStack)); - if (!video) - error("Failed to open intro movie"); - + video = _vm->playMovie("intro", kIntroStack); video->center(); } break; diff --git a/engines/mohawk/myst_stacks/mechanical.cpp b/engines/mohawk/myst_stacks/mechanical.cpp index 0f07e8be29..34238f37f7 100644 --- a/engines/mohawk/myst_stacks/mechanical.cpp +++ b/engines/mohawk/myst_stacks/mechanical.cpp @@ -305,10 +305,7 @@ void Mechanical::o_snakeBoxTrigger(uint16 var, const ArgumentsArray &args) { } void Mechanical::o_fortressStaircaseMovie(uint16 var, const ArgumentsArray &args) { - VideoEntryPtr staircase = _vm->_video->playMovie(_vm->wrapMovieFilename("hhstairs", kMechanicalStack)); - if (!staircase) - error("Failed to open hhstairs movie"); - + VideoEntryPtr staircase = _vm->playMovie("hhstairs", kMechanicalStack); staircase->moveTo(174, 222); if (_state.staircaseState) { @@ -532,12 +529,10 @@ void Mechanical::o_elevatorWindowMovie(uint16 var, const ArgumentsArray &args) { uint16 startTime = args[0]; uint16 endTime = args[1]; - VideoEntryPtr window = _vm->_video->playMovie(_vm->wrapMovieFilename("ewindow", kMechanicalStack)); - if (!window) - error("Failed to open ewindow movie"); - + VideoEntryPtr window = _vm->playMovie("ewindow", kMechanicalStack); window->moveTo(253, 0); window->setBounds(Audio::Timestamp(0, startTime, 600), Audio::Timestamp(0, endTime, 600)); + _vm->waitUntilMovieEnds(window); } @@ -603,12 +598,10 @@ void Mechanical::o_elevatorTopMovie(uint16 var, const ArgumentsArray &args) { uint16 startTime = args[0]; uint16 endTime = args[1]; - VideoEntryPtr window = _vm->_video->playMovie(_vm->wrapMovieFilename("hcelev", kMechanicalStack)); - if (!window) - error("Failed to open hcelev movie"); - + VideoEntryPtr window = _vm->playMovie("hcelev", kMechanicalStack); window->moveTo(206, 38); window->setBounds(Audio::Timestamp(0, startTime, 600), Audio::Timestamp(0, endTime, 600)); + _vm->waitUntilMovieEnds(window); } @@ -625,7 +618,7 @@ void Mechanical::o_fortressRotationSetPosition(uint16 var, const ArgumentsArray } void Mechanical::o_mystStaircaseMovie(uint16 var, const ArgumentsArray &args) { - _vm->playMovieBlocking(_vm->wrapMovieFilename("sstairs", kMechanicalStack), 199, 108); + _vm->playMovieBlocking("sstairs", kMechanicalStack, 199, 108); } void Mechanical::o_elevatorWaitTimeout(uint16 var, const ArgumentsArray &args) { diff --git a/engines/mohawk/myst_stacks/myst.cpp b/engines/mohawk/myst_stacks/myst.cpp index 37b0d4fba7..e72d4e5c59 100644 --- a/engines/mohawk/myst_stacks/myst.cpp +++ b/engines/mohawk/myst_stacks/myst.cpp @@ -866,9 +866,9 @@ void Myst::o_fireplaceRotation(uint16 var, const ArgumentsArray &args) { uint16 movieNum = args[0]; if (movieNum) - _vm->playMovieBlocking(_vm->wrapMovieFilename("fpout", kMystStack), 167, 4); + _vm->playMovieBlocking("fpout", kMystStack, 167, 4); else - _vm->playMovieBlocking(_vm->wrapMovieFilename("fpin", kMystStack), 167, 4); + _vm->playMovieBlocking("fpin", kMystStack, 167, 4); } void Myst::o_courtyardBoxesCheckSolution(uint16 var, const ArgumentsArray &args) { @@ -1107,12 +1107,10 @@ void Myst::o_clockWheelsExecute(uint16 var, const ArgumentsArray &args) { _vm->wait(500); // Gears rise up - VideoEntryPtr gears = _vm->_video->playMovie(_vm->wrapMovieFilename("gears", kMystStack)); - if (!gears) - error("Failed to open gears movie"); - + VideoEntryPtr gears = _vm->playMovie("gears", kMystStack); gears->moveTo(305, 33); gears->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 650, 600)); + _vm->waitUntilMovieEnds(gears); _state.clockTowerBridgeOpen = 1; @@ -1122,12 +1120,10 @@ void Myst::o_clockWheelsExecute(uint16 var, const ArgumentsArray &args) { _vm->wait(500); // Gears sink down - VideoEntryPtr gears = _vm->_video->playMovie(_vm->wrapMovieFilename("gears", kMystStack)); - if (!gears) - error("Failed to open gears movie"); - + VideoEntryPtr gears = _vm->playMovie("gears", kMystStack); gears->moveTo(305, 33); gears->setBounds(Audio::Timestamp(0, 700, 600), Audio::Timestamp(0, 1300, 600)); + _vm->waitUntilMovieEnds(gears); _state.clockTowerBridgeOpen = 0; @@ -1166,22 +1162,16 @@ void Myst::o_imagerPlayButton(uint16 var, const ArgumentsArray &args) { case 1: // Mountain if (_state.imagerActive) { // Mountains disappearing - Common::String file = _vm->wrapMovieFilename("vltmntn", kMystStack); - VideoEntryPtr mountain = _vm->_video->playMovie(file); - if (!mountain) - error("Failed to open '%s'", file.c_str()); - + Common::String file = "vltmntn"; + VideoEntryPtr mountain = _vm->playMovie(file, kMystStack); mountain->moveTo(159, 96); mountain->setBounds(Audio::Timestamp(0, 11180, 600), Audio::Timestamp(0, 16800, 600)); _state.imagerActive = 0; } else { // Mountains appearing - Common::String file = _vm->wrapMovieFilename("vltmntn", kMystStack); - VideoEntryPtr mountain = _vm->_video->playMovie(file); - if (!mountain) - error("Failed to open '%s'", file.c_str()); - + Common::String file = "vltmntn"; + VideoEntryPtr mountain = _vm->playMovie(file, kMystStack); mountain->moveTo(159, 96); mountain->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 11180, 600)); @@ -1301,10 +1291,10 @@ void Myst::o_towerElevatorAnimation(uint16 var, const ArgumentsArray &args) { switch (args[0]) { case 0: - _vm->playMovieBlocking(_vm->wrapMovieFilename("libdown", kMystStack), 216, 78); + _vm->playMovieBlocking("libdown", kMystStack, 216, 78); break; case 1: - _vm->playMovieBlocking(_vm->wrapMovieFilename("libup", kMystStack), 216, 78); + _vm->playMovieBlocking("libup", kMystStack, 216, 78); break; default: break; @@ -1878,16 +1868,10 @@ Common::Rational Myst::boilerComputeGaugeRate(uint16 pressure, uint32 delay) { void Myst::boilerResetGauge(const Common::Rational &rate) { if (!_cabinGaugeMovie || _cabinGaugeMovie->endOfVideo()) { if (_vm->getCurCard() == 4098) { - _cabinGaugeMovie = _vm->_video->playMovie(_vm->wrapMovieFilename("cabingau", kMystStack)); - if (!_cabinGaugeMovie) - error("Failed to open cabingau movie"); - + _cabinGaugeMovie = _vm->playMovie("cabingau", kMystStack); _cabinGaugeMovie->moveTo(243, 96); } else { - _cabinGaugeMovie = _vm->_video->playMovie(_vm->wrapMovieFilename("cabcgfar", kMystStack)); - if (!_cabinGaugeMovie) - error("Failed to open cabingau movie"); - + _cabinGaugeMovie = _vm->playMovie("cabcgfar", kMystStack); _cabinGaugeMovie->moveTo(254, 136); } } @@ -2207,20 +2191,15 @@ void Myst::rocketCheckSolution() { lever->drawFrame(0); // Book appearing - Common::String movieFile = _vm->wrapMovieFilename("selenbok", kMystStack); - _rocketLinkBook = _vm->_video->playMovie(movieFile); - if (!_rocketLinkBook) - error("Failed to open '%s'", movieFile.c_str()); - + Common::String movieFile = "selenbok"; + _rocketLinkBook = _vm->playMovie(movieFile, kMystStack); _rocketLinkBook->moveTo(224, 41); _rocketLinkBook->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 660, 600)); + _vm->waitUntilMovieEnds(_rocketLinkBook); // Book looping closed - _rocketLinkBook = _vm->_video->playMovie(movieFile); - if (!_rocketLinkBook) - error("Failed to open '%s'", movieFile.c_str()); - + _rocketLinkBook = _vm->playMovie(movieFile, kMystStack); _rocketLinkBook->moveTo(224, 41); _rocketLinkBook->setLooping(true); _rocketLinkBook->setBounds(Audio::Timestamp(0, 660, 600), Audio::Timestamp(0, 3500, 600)); @@ -2804,10 +2783,7 @@ void Myst::clockGearForwardOneStep(uint16 gear) { // Set video bounds uint16 gearPosition = _clockGearsPositions[gear] - 1; - _clockGearsVideos[gear] = _vm->_video->playMovie(_vm->wrapMovieFilename(videos[gear], kMystStack)); - if (!_clockGearsVideos[gear]) - error("Failed to open %s movie", videos[gear]); - + _clockGearsVideos[gear] = _vm->playMovie(videos[gear], kMystStack); _clockGearsVideos[gear]->moveTo(x[gear], y[gear]); _clockGearsVideos[gear]->setBounds( Audio::Timestamp(0, startTime[gearPosition], 600), @@ -2821,10 +2797,7 @@ void Myst::clockWeightDownOneStep() { // Set video bounds if (updateVideo) { - _clockWeightVideo = _vm->_video->playMovie(_vm->wrapMovieFilename("cl1wlfch", kMystStack)); - if (!_clockWeightVideo) - error("Failed to open cl1wlfch movie"); - + _clockWeightVideo = _vm->playMovie("cl1wlfch", kMystStack); _clockWeightVideo->moveTo(124, 0); _clockWeightVideo->setBounds( Audio::Timestamp(0, _clockWeightPosition, 600), @@ -2852,7 +2825,7 @@ void Myst::o_clockLeverEndMove(uint16 var, const ArgumentsArray &args) { // Let movies stop playing for (uint i = 0; i < ARRAYSIZE(videos); i++) { - VideoEntryPtr handle = _vm->_video->findVideo(_vm->wrapMovieFilename(videos[i], kMystStack)); + VideoEntryPtr handle = _vm->findVideo(videos[i], kMystStack); if (handle) _vm->waitUntilMovieEnds(handle); } @@ -2878,14 +2851,12 @@ void Myst::clockGearsCheckSolution() { // Make weight go down _vm->_sound->playEffect(9113); - _clockWeightVideo = _vm->_video->playMovie(_vm->wrapMovieFilename("cl1wlfch", kMystStack)); - if (!_clockWeightVideo) - error("Failed to open cl1wlfch movie"); - + _clockWeightVideo = _vm->playMovie("cl1wlfch", kMystStack); _clockWeightVideo->moveTo(124, 0); _clockWeightVideo->setBounds( Audio::Timestamp(0, _clockWeightPosition, 600), Audio::Timestamp(0, 2214, 600)); + _vm->waitUntilMovieEnds(_clockWeightVideo); _clockWeightPosition = 2214; @@ -2894,7 +2865,7 @@ void Myst::clockGearsCheckSolution() { _vm->_sound->playEffect(7113); // Gear opening video - _vm->playMovieBlocking(_vm->wrapMovieFilename("cl1wggat", kMystStack), 195, 225); + _vm->playMovieBlocking("cl1wggat", kMystStack, 195, 225); _state.gearsOpen = 1; _vm->redrawArea(40); @@ -2932,7 +2903,7 @@ void Myst::clockReset() { // Let movies stop playing for (uint i = 0; i < ARRAYSIZE(videos); i++) { - VideoEntryPtr handle = _vm->_video->findVideo(_vm->wrapMovieFilename(videos[i], kMystStack)); + VideoEntryPtr handle = _vm->findVideo(videos[i], kMystStack); if (handle) _vm->waitUntilMovieEnds(handle); } @@ -2946,10 +2917,7 @@ void Myst::clockReset() { _vm->_sound->playEffect(7113); // Gear closing movie - VideoEntryPtr handle = _vm->_video->playMovie(_vm->wrapMovieFilename("cl1wggat", kMystStack)); - if (!handle) - error("Failed to open cl1wggat movie"); - + VideoEntryPtr handle = _vm->playMovie("cl1wggat", kMystStack); handle->moveTo(195, 225); handle->seek(handle->getDuration()); handle->setRate(-1); @@ -2966,10 +2934,7 @@ void Myst::clockReset() { void Myst::clockResetWeight() { _vm->_sound->playEffect(9113); - _clockWeightVideo = _vm->_video->playMovie(_vm->wrapMovieFilename("cl1wlfch", kMystStack)); - if (!_clockWeightVideo) - error("Failed to open cl1wlfch movie"); - + _clockWeightVideo = _vm->playMovie("cl1wlfch", kMystStack); _clockWeightVideo->moveTo(124, 0); // Play the movie backwards, weight going up @@ -2989,10 +2954,7 @@ void Myst::clockResetGear(uint16 gear) { // Set video bounds, gears going to 3 uint16 gearPosition = _clockGearsPositions[gear] - 1; if (gearPosition != 2) { - _clockGearsVideos[gear] = _vm->_video->playMovie(_vm->wrapMovieFilename(videos[gear], kMystStack)); - if (!_clockGearsVideos[gear]) - error("Failed to open gears movie"); - + _clockGearsVideos[gear] = _vm->playMovie(videos[gear], kMystStack); _clockGearsVideos[gear]->moveTo(x[gear], y[gear]); _clockGearsVideos[gear]->setBounds( Audio::Timestamp(0, time[gearPosition], 600), @@ -3319,11 +3281,9 @@ void Myst::gullsFly1_run() { else x = _vm->_rnd->getRandomNumber(160) + 260; - VideoEntryPtr handle = _vm->_video->playMovie(_vm->wrapMovieFilename(gulls[video], kMystStack)); - if (!handle) - error("Failed to open gulls movie"); - + VideoEntryPtr handle = _vm->playMovie(gulls[video], kMystStack); handle->moveTo(x, 0); + _gullsNextTime = time + _vm->_rnd->getRandomNumber(16667) + 13334; } } @@ -3460,11 +3420,9 @@ void Myst::gullsFly2_run() { if (time > _gullsNextTime) { uint16 video = _vm->_rnd->getRandomNumber(3); if (video != 3) { - VideoEntryPtr handle = _vm->_video->playMovie(_vm->wrapMovieFilename(gulls[video], kMystStack)); - if (!handle) - error("Failed to open gulls movie"); - + VideoEntryPtr handle = _vm->playMovie(gulls[video], kMystStack); handle->moveTo(424, 0); + _gullsNextTime = time + _vm->_rnd->getRandomNumber(16667) + 13334; } } @@ -3489,10 +3447,7 @@ void Myst::o_boilerMovies_init(uint16 var, const ArgumentsArray &args) { void Myst::boilerFireInit() { if (_vm->getCurCard() == 4098) { - _cabinFireMovie = _vm->_video->playMovie(_vm->wrapMovieFilename("cabfire", kMystStack)); - if (!_cabinFireMovie) - error("Failed to open cabfire movie"); - + _cabinFireMovie = _vm->playMovie("cabfire", kMystStack); _cabinFireMovie->moveTo(240, 279); _cabinFireMovie->setLooping(true); _cabinFireMovie->pause(true); @@ -3501,10 +3456,7 @@ void Myst::boilerFireInit() { boilerFireUpdate(true); } else { if (_state.cabinPilotLightLit == 1 && _state.cabinValvePosition >= 1) { - _cabinFireMovie = _vm->_video->playMovie(_vm->wrapMovieFilename("cabfirfr", kMystStack)); - if (!_cabinFireMovie) - error("Failed to open cabfirfr movie"); - + _cabinFireMovie = _vm->playMovie("cabfirfr", kMystStack); _cabinFireMovie->moveTo(254, 244); _cabinFireMovie->setLooping(true); } @@ -3531,16 +3483,10 @@ void Myst::boilerFireUpdate(bool init) { void Myst::boilerGaugeInit() { if (_vm->getCurCard() == 4098) { - _cabinGaugeMovie = _vm->_video->playMovie(_vm->wrapMovieFilename("cabingau", kMystStack)); - if (!_cabinGaugeMovie) - error("Failed to open cabingau movie"); - + _cabinGaugeMovie = _vm->playMovie("cabingau", kMystStack); _cabinGaugeMovie->moveTo(243, 96); } else { - _cabinGaugeMovie = _vm->_video->playMovie(_vm->wrapMovieFilename("cabcgfar", kMystStack)); - if (!_cabinGaugeMovie) - error("Failed to open cabcgfar movie"); - + _cabinGaugeMovie = _vm->playMovie("cabcgfar", kMystStack); _cabinGaugeMovie->moveTo(254, 136); } @@ -3589,26 +3535,23 @@ void Myst::o_greenBook_init(uint16 var, const ArgumentsArray &args) { void Myst::greenBook_run() { uint loopStart = 0; uint loopEnd = 0; - Common::String file; + Common::String videoName; if (!_state.greenBookOpenedBefore) { loopStart = 113200; loopEnd = 116400; - file = _vm->wrapMovieFilename("atrusbk1", kMystStack); + videoName = "atrusbk1"; } else { loopStart = 8800; loopEnd = 9700; - file = _vm->wrapMovieFilename("atrusbk2", kMystStack); + videoName = "atrusbk2"; } if (_tempVar == 1) { _vm->_sound->stopEffect(); _vm->_sound->pauseBackground(); - VideoEntryPtr book = _vm->_video->playMovie(file); - if (!book) - error("Failed to open '%s'", file.c_str()); - + VideoEntryPtr book = _vm->playMovie(videoName, kMystStack); book->moveTo(314, 76); if (_globals.ending != 4) { @@ -3619,13 +3562,11 @@ void Myst::greenBook_run() { _tempVar = 0; } } else if (_tempVar == 2 && !_vm->_video->isVideoPlaying()) { - VideoEntryPtr book = _vm->_video->playMovie(file); - if (!book) - error("Failed to open '%s'", file.c_str()); - + VideoEntryPtr book = _vm->playMovie(videoName, kMystStack); book->moveTo(314, 76); book->setBounds(Audio::Timestamp(0, loopStart, 600), Audio::Timestamp(0, loopEnd, 600)); book->setLooping(true); + _tempVar = 0; } } @@ -3646,11 +3587,9 @@ void Myst::gullsFly3_run() { if (video != 3) { uint16 x = _vm->_rnd->getRandomNumber(280) + 135; - VideoEntryPtr handle = _vm->_video->playMovie(_vm->wrapMovieFilename(gulls[video], kMystStack)); - if (!handle) - error("Failed to open gulls movie"); - + VideoEntryPtr handle = _vm->playMovie(gulls[video], kMystStack); handle->moveTo(x, 0); + _gullsNextTime = time + _vm->_rnd->getRandomNumber(16667) + 13334; } } diff --git a/engines/mohawk/myst_stacks/selenitic.cpp b/engines/mohawk/myst_stacks/selenitic.cpp index e9439047ff..0f1949f128 100644 --- a/engines/mohawk/myst_stacks/selenitic.cpp +++ b/engines/mohawk/myst_stacks/selenitic.cpp @@ -365,123 +365,123 @@ void Selenitic::mazeRunnerBacktrack(uint16 &oldPosition) { } void Selenitic::mazeRunnerPlayVideo(uint16 video, uint16 pos) { - Common::String file; + Common::String videoName; switch (video) { case 1: - file = _vm->wrapMovieFilename("forwa1", kSeleniticStack); + videoName = "forwa1"; break; case 2: - file = _vm->wrapMovieFilename("forwe0", kSeleniticStack); + videoName = "forwe0"; break; case 3: if (mazeRunnerForwardAllowed(_mazeRunnerPosition)) - file = _vm->wrapMovieFilename("forwf1", kSeleniticStack); + videoName = "forwf1"; else - file = _vm->wrapMovieFilename("forwf0", kSeleniticStack); + videoName = "forwf0"; break; case 4: - file = _vm->wrapMovieFilename("left00", kSeleniticStack); + videoName = "left00"; break; case 5: - file = _vm->wrapMovieFilename("left01", kSeleniticStack); + videoName = "left01"; break; case 6: - file = _vm->wrapMovieFilename("left10", kSeleniticStack); + videoName = "left10"; break; case 7: - file = _vm->wrapMovieFilename("left11", kSeleniticStack); + videoName = "left11"; break; case 8: - file = _vm->wrapMovieFilename("right00", kSeleniticStack); + videoName = "right00"; break; case 9: - file = _vm->wrapMovieFilename("right01", kSeleniticStack); + videoName = "right01"; break; case 10: - file = _vm->wrapMovieFilename("right10", kSeleniticStack); + videoName = "right10"; break; case 11: - file = _vm->wrapMovieFilename("right11", kSeleniticStack); + videoName = "right11"; break; case 12: if (mazeRunnerForwardAllowed(_mazeRunnerPosition)) - file = _vm->wrapMovieFilename("forwo1", kSeleniticStack); + videoName = "forwo1"; else - file = _vm->wrapMovieFilename("forwo0", kSeleniticStack); + videoName = "forwo0"; break; case 13: if (mazeRunnerForwardAllowed(_mazeRunnerPosition)) - file = _vm->wrapMovieFilename("forwp1", kSeleniticStack); + videoName = "forwp1"; else - file = _vm->wrapMovieFilename("forwp0", kSeleniticStack); + videoName = "forwp0"; break; case 14: if (mazeRunnerForwardAllowed(_mazeRunnerPosition)) - file = _vm->wrapMovieFilename("forws1", kSeleniticStack); + videoName = "forws1"; else - file = _vm->wrapMovieFilename("forws0", kSeleniticStack); + videoName = "forws0"; break; case 15: if (mazeRunnerForwardAllowed(_mazeRunnerPosition)) - file = _vm->wrapMovieFilename("forwr1", kSeleniticStack); + videoName = "forwr1"; else - file = _vm->wrapMovieFilename("forwr0", kSeleniticStack); + videoName = "forwr0"; break; case 16: if (mazeRunnerForwardAllowed(_mazeRunnerPosition)) - file = _vm->wrapMovieFilename("forwl1", kSeleniticStack); + videoName = "forwl1"; else - file = _vm->wrapMovieFilename("forwl0", kSeleniticStack); + videoName = "forwl0"; break; case 17: - file = _vm->wrapMovieFilename("backa1", kSeleniticStack); + videoName = "backa1"; break; case 18: - file = _vm->wrapMovieFilename("backe1", kSeleniticStack); + videoName = "backe1"; break; case 19: if (mazeRunnerForwardAllowed(pos)) - file = _vm->wrapMovieFilename("backf1", kSeleniticStack); + videoName = "backf1"; else - file = _vm->wrapMovieFilename("backf0", kSeleniticStack); + videoName = "backf0"; break; case 20: if (mazeRunnerForwardAllowed(pos)) - file = _vm->wrapMovieFilename("backo1", kSeleniticStack); + videoName = "backo1"; else - file = _vm->wrapMovieFilename("backo0", kSeleniticStack); + videoName = "backo0"; break; case 21: if (mazeRunnerForwardAllowed(pos)) - file = _vm->wrapMovieFilename("backp1", kSeleniticStack); + videoName = "backp1"; else - file = _vm->wrapMovieFilename("backp0", kSeleniticStack); + videoName = "backp0"; break; case 22: if (mazeRunnerForwardAllowed(pos)) { - file = _vm->wrapMovieFilename("backs1", kSeleniticStack); + videoName = "backs1"; } else { - file = _vm->wrapMovieFilename("backs0", kSeleniticStack); + videoName = "backs0"; } break; case 23: if (mazeRunnerForwardAllowed(pos)) - file = _vm->wrapMovieFilename("backr1", kSeleniticStack); + videoName = "backr1"; else - file = _vm->wrapMovieFilename("backr0", kSeleniticStack); + videoName = "backr0"; break; case 24: if (mazeRunnerForwardAllowed(pos)) - file = _vm->wrapMovieFilename("backl1", kSeleniticStack); + videoName = "backl1"; else - file = _vm->wrapMovieFilename("backl0", kSeleniticStack); + videoName = "backl0"; break; } - if (!file.empty()) { + if (!videoName.empty()) { const Common::Rect &dest = _mazeRunnerWindow->getRect(); - _vm->playMovieBlocking(file, dest.left, dest.top); + _vm->playMovieBlocking(videoName, kSeleniticStack, dest.left, dest.top); } } diff --git a/engines/mohawk/myst_stacks/stoneship.cpp b/engines/mohawk/myst_stacks/stoneship.cpp index f4b38305f2..534efe7197 100644 --- a/engines/mohawk/myst_stacks/stoneship.cpp +++ b/engines/mohawk/myst_stacks/stoneship.cpp @@ -417,12 +417,10 @@ void Stoneship::o_cabinBookMovie(uint16 var, const ArgumentsArray &args) { uint16 startTime = args[0]; uint16 endTime = args[1]; - VideoEntryPtr book = _vm->_video->playMovie(_vm->wrapMovieFilename("bkroom", kStoneshipStack)); - if (!book) - error("Failed to open bkroom movie"); - + VideoEntryPtr book = _vm->playMovie("bkroom", kStoneshipStack); book->moveTo(159, 99); book->setBounds(Audio::Timestamp(0, startTime, 600), Audio::Timestamp(0, endTime, 600)); + _vm->waitUntilMovieEnds(book); } @@ -642,36 +640,27 @@ void Stoneship::o_compassButton(uint16 var, const ArgumentsArray &args) { } void Stoneship::o_chestValveVideos(uint16 var, const ArgumentsArray &args) { - Common::String movie = _vm->wrapMovieFilename("ligspig", kStoneshipStack); - _vm->_sound->playEffect(2132); if (_state.chestValveState) { // Valve closing - VideoEntryPtr valve = _vm->_video->playMovie(movie); - if (!valve) - error("Failed to open '%s'", movie.c_str()); - + VideoEntryPtr valve = _vm->playMovie("ligspig", kStoneshipStack); valve->moveTo(97, 267); valve->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 350, 600)); + _vm->waitUntilMovieEnds(valve); } else if (_state.chestWaterState) { // Valve opening, spilling water - VideoEntryPtr valve = _vm->_video->playMovie(movie); - if (!valve) - error("Failed to open '%s'", movie.c_str()); - + VideoEntryPtr valve = _vm->playMovie("ligspig", kStoneshipStack); valve->moveTo(97, 267); valve->setBounds(Audio::Timestamp(0, 350, 600), Audio::Timestamp(0, 650, 600)); + _vm->waitUntilMovieEnds(valve); _vm->_sound->playEffect(3132); for (uint i = 0; i < 25; i++) { - valve = _vm->_video->playMovie(movie); - if (!valve) - error("Failed to open '%s'", movie.c_str()); - + valve = _vm->playMovie("ligspig", kStoneshipStack); valve->moveTo(97, 267); valve->setBounds(Audio::Timestamp(0, 650, 600), Audio::Timestamp(0, 750, 600)); _vm->waitUntilMovieEnds(valve); @@ -680,13 +669,11 @@ void Stoneship::o_chestValveVideos(uint16 var, const ArgumentsArray &args) { _vm->_sound->resumeBackground(); } else { // Valve opening - VideoEntryPtr valve = _vm->_video->playMovie(movie); - if (!valve) - error("Failed to open '%s'", movie.c_str()); - + VideoEntryPtr valve = _vm->playMovie("ligspig", kStoneshipStack); valve->moveTo(97, 267); valve->seek(Audio::Timestamp(0, 350, 600)); valve->setRate(-1); + _vm->waitUntilMovieEnds(valve); } } @@ -701,22 +688,14 @@ void Stoneship::o_chestDropKey(uint16 var, const ArgumentsArray &args) { } void Stoneship::o_trapLockOpen(uint16 var, const ArgumentsArray &args) { - Common::String movie = _vm->wrapMovieFilename("openloc", kStoneshipStack); - - VideoEntryPtr lock = _vm->_video->playMovie(movie); - if (!lock) - error("Failed to open '%s'", movie.c_str()); - + VideoEntryPtr lock = _vm->playMovie("openloc", kStoneshipStack); lock->moveTo(187, 71); lock->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 750, 600)); _vm->waitUntilMovieEnds(lock); _vm->_sound->playEffect(2143); - lock = _vm->_video->playMovie(movie); - if (!lock) - error("Failed to open '%s'", movie.c_str()); - + lock = _vm->playMovie("openloc", kStoneshipStack); lock->moveTo(187, 71); lock->setBounds(Audio::Timestamp(0, 750, 600), Audio::Timestamp(0, 10000, 600)); _vm->waitUntilMovieEnds(lock); @@ -735,19 +714,19 @@ void Stoneship::o_sideDoorsMovies(uint16 var, const ArgumentsArray &args) { switch (movieId) { case 0: // Card 2251 - _vm->playMovieBlocking(_vm->wrapMovieFilename("tunaup", kStoneshipStack), 149, 161); + _vm->playMovieBlocking("tunaup", kStoneshipStack, 149, 161); break; case 1: // Card 2247 - _vm->playMovieBlocking(_vm->wrapMovieFilename("tunadown", kStoneshipStack), 218, 150); + _vm->playMovieBlocking("tunadown", kStoneshipStack, 218, 150); break; case 2: // Card 2289 - _vm->playMovieBlocking(_vm->wrapMovieFilename("tuncup", kStoneshipStack), 259, 161); + _vm->playMovieBlocking("tuncup", kStoneshipStack, 259, 161); break; case 3: // Card 2285 - _vm->playMovieBlocking(_vm->wrapMovieFilename("tuncdown", kStoneshipStack), 166, 150); + _vm->playMovieBlocking("tuncdown", kStoneshipStack, 166, 150); break; default: warning("Opcode 120 MovieId Out Of Range"); diff --git a/engines/mohawk/video.cpp b/engines/mohawk/video.cpp index 4354bb5b97..994e219b03 100644 --- a/engines/mohawk/video.cpp +++ b/engines/mohawk/video.cpp @@ -164,8 +164,8 @@ void VideoManager::stopVideos() { _videos.clear(); } -VideoEntryPtr VideoManager::playMovie(const Common::String &fileName) { - VideoEntryPtr ptr = open(fileName); +VideoEntryPtr VideoManager::playMovie(const Common::String &fileName, Audio::Mixer::SoundType soundType) { + VideoEntryPtr ptr = open(fileName, soundType); if (!ptr) return VideoEntryPtr(); @@ -313,7 +313,7 @@ VideoEntryPtr VideoManager::open(uint16 id) { return entry; } -VideoEntryPtr VideoManager::open(const Common::String &fileName) { +VideoEntryPtr VideoManager::open(const Common::String &fileName, Audio::Mixer::SoundType soundType) { // If this video is already playing, return that entry VideoEntryPtr oldVideo = findVideo(fileName); if (oldVideo) @@ -325,6 +325,7 @@ VideoEntryPtr VideoManager::open(const Common::String &fileName) { return VideoEntryPtr(); Video::VideoDecoder *video = new Video::QuickTimeDecoder(); + video->setSoundType(soundType); if (!video->loadStream(stream)) { // FIXME: Better error handling delete video; diff --git a/engines/mohawk/video.h b/engines/mohawk/video.h index 07dc128641..1f8b93d467 100644 --- a/engines/mohawk/video.h +++ b/engines/mohawk/video.h @@ -23,6 +23,7 @@ #ifndef MOHAWK_VIDEO_H #define MOHAWK_VIDEO_H +#include "audio/mixer.h" #include "audio/timestamp.h" #include "common/array.h" #include "common/list.h" @@ -240,7 +241,7 @@ public: virtual ~VideoManager(); // Generic movie functions - VideoEntryPtr playMovie(const Common::String &filename); + VideoEntryPtr playMovie(const Common::String &filename, Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType); VideoEntryPtr playMovie(uint16 id); bool updateMovies(); void pauseVideos(); @@ -263,7 +264,7 @@ protected: // Utility functions for managing entries VideoEntryPtr open(uint16 id); - VideoEntryPtr open(const Common::String &fileName); + VideoEntryPtr open(const Common::String &fileName, Audio::Mixer::SoundType soundType); VideoList::iterator findEntry(VideoEntryPtr ptr); diff --git a/engines/queen/queen.h b/engines/queen/queen.h index 789025c264..3c38ccd312 100644 --- a/engines/queen/queen.h +++ b/engines/queen/queen.h @@ -30,24 +30,6 @@ namespace Common { class SeekableReadStream; } -#if defined(_WIN32_WCE) && (_WIN32_WCE <= 300) - -#include "common/endian.h" - -FORCEINLINE int16 READ_BE_INT16(const void *ptr) { - uint16 result; - char dummy[2]; - result = READ_BE_UINT16(ptr); - strcpy(dummy, "x"); // Hello, I'm a drunk optimizer. Thanks for helping me. - return result; -} - -#else - -#define READ_BE_INT16 READ_BE_UINT16 - -#endif - /** * This is the namespace of the Queen engine. * diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp index fe95b0cf2f..17a1ece3e1 100644 --- a/engines/sci/detection.cpp +++ b/engines/sci/detection.cpp @@ -126,7 +126,7 @@ static const PlainGameDescriptor s_sciGameTitles[] = { // === SCI3 games ========================================================= {"lsl7", "Leisure Suit Larry 7: Love for Sail!"}, {"lighthouse", "Lighthouse: The Dark Being"}, - {"phantasmagoria2", "Phantasmagoria II: A Puzzle of Flesh"}, + {"phantasmagoria2", "Phantasmagoria 2: A Puzzle of Flesh"}, //{"shivers2", "Shivers II: Harvest of Souls"}, // Not SCI {"rama", "RAMA"}, {0, 0} diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h index 3650de55c9..91ce6785d7 100644 --- a/engines/sci/detection_tables.h +++ b/engines/sci/detection_tables.h @@ -3124,11 +3124,13 @@ static const struct ADGameDescription SciGameDescriptions[] = { #undef GUIO_PHANTASMAGORIA #undef GUIO_PHANTASMAGORIA_MAC -// TODO: Correct GUIOs -#define GUIO_PHANTASMAGORIA2 GUIO5(GUIO_NOASPECT, \ +#define GUIO_PHANTASMAGORIA2 GUIO8(GUIO_NOSUBTITLES, \ + GUIO_LINKMUSICTOSFX, \ + GUIO_LINKSPEECHTOSFX, \ GUIO_NOMIDI, \ - GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, \ + GUIO_NOASPECT, \ GAMEOPTION_ORIGINAL_SAVELOAD, \ + GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, \ GAMEOPTION_HQ_VIDEO) // Some versions of Phantasmagoria 2 were heavily censored. @@ -3153,7 +3155,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resmap.005", 0, "8bd5ceeedcbe16dfe55d1b90dcd4be84", 1942}, {"ressci.005", 0, "05f9fe2bee749659acb3cd2c90252fc5", 67905112}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO_PHANTASMAGORIA2 }, + Common::EN_ANY, Common::kPlatformWindows, ADGF_CD | ADGF_TESTING, GUIO_PHANTASMAGORIA2 }, // Phantasmagoria 2 - English DOS (GOG version) (supplied by littleboy in patch #1360) // Note: Fully uncensored, basically the US release, but ressci.* merged into ressci.000 @@ -3164,7 +3166,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"ressci.000", 0, "c54f26d9f43f908151263254b6d97053", 108134481}, {"resmap.000", 0, "de154a223a9ef4ea7358b76adc38ef5b", 2956}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO_PHANTASMAGORIA2 }, + Common::EN_ANY, Common::kPlatformWindows, ADGF_CD | ADGF_TESTING, GUIO_PHANTASMAGORIA2 }, // Phantasmagoria 2 - German DOS/Windows (supplied by AReim1982) // Note: Fully uncensored, but one scene is missing probably because of a mastering error (Curtis + Therese meeting near water cooler) @@ -3186,7 +3188,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resmap.005", 0, "2fc48a4a5a73b726994f189da51a8b2a", 1954}, {"ressci.005", 0, "e94005890d22dd3b7f605a2a7c025803", 68232146}, AD_LISTEND}, - Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO_PHANTASMAGORIA2 }, + Common::DE_DEU, Common::kPlatformWindows, ADGF_CD | ADGF_TESTING, GUIO_PHANTASMAGORIA2 }, // Phantasmagoria 2 - French DOS/Windows (supplied by bgK) // Windows executable scanning reports "3.000.000" - "Nov 09 1996 16:03:00" @@ -3204,7 +3206,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resmap.005", 0, "7811a1801660090725ceef799b62fc72", 1954}, {"ressci.005", 0, "b6f090a2c8fc955d17b8a47085b2f890", 68231525}, AD_LISTEND}, - Common::FR_FRA, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO_PHANTASMAGORIA2 }, + Common::FR_FRA, Common::kPlatformWindows, ADGF_CD | ADGF_TESTING, GUIO_PHANTASMAGORIA2 }, // Phantasmagoria 2 - Japanese Windows (supplied by m_kiewitz) // Features English voices w/ Japanese subtitles. Background images were also localized to Japanese. @@ -3226,7 +3228,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { //{"resaud.002", 0, "3b4c5f92e5143fd3539b227e48ac2929", 8414502}, //{"ressfx.001", 0, "343a6ca9ddd614541b11b155de6368ac", 90268706}, AD_LISTEND}, - Common::JA_JPN, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO_PHANTASMAGORIA2 }, + Common::JA_JPN, Common::kPlatformWindows, ADGF_CD | ADGF_TESTING, GUIO_PHANTASMAGORIA2 }, #endif // ENABLE_SCI32 diff --git a/engines/sci/engine/features.cpp b/engines/sci/engine/features.cpp index e64cf9cf9f..03e8019753 100644 --- a/engines/sci/engine/features.cpp +++ b/engines/sci/engine/features.cpp @@ -576,6 +576,7 @@ bool GameFeatures::audioVolumeSyncUsesGlobals() const { case GID_LSL6HIRES: case GID_LSL7: case GID_PHANTASMAGORIA: + case GID_PHANTASMAGORIA2: case GID_TORIN: // TODO: SCI3 return true; diff --git a/engines/sci/engine/guest_additions.cpp b/engines/sci/engine/guest_additions.cpp index 0f4818d544..17ae74e25a 100644 --- a/engines/sci/engine/guest_additions.cpp +++ b/engines/sci/engine/guest_additions.cpp @@ -141,6 +141,8 @@ bool GuestAdditions::shouldSyncAudioToScummVM() const { objName == "dacVolDown" || objName == "dacVolUp")) { return true; + } else if (gameId == GID_PHANTASMAGORIA2 && objName == "foo2") { + return true; } else if ((gameId == GID_LSL7 || gameId == GID_TORIN) && (objName == "oMusicScroll" || objName == "oSFXScroll" || objName == "oAudioScroll")) { @@ -231,6 +233,8 @@ void GuestAdditions::instantiateScriptHook(Script &script, const bool ignoreDela script.getScriptNumber() == 64866) { patchGameSaveRestoreTorin(script); + } else if (g_sci->getGameId() == GID_PHANTASMAGORIA2 && script.getScriptNumber() == 64978) { + patchGameSaveRestorePhant2(script); } else if (script.getScriptNumber() == 64990) { // 64990 is the system script containing SRDialog. This script is used // by the main Game object, but it is not loaded immediately, so we wait @@ -257,12 +261,25 @@ bool GuestAdditions::kGetEventHook() const { } bool GuestAdditions::kWaitHook() const { - if (_state->_delayedRestoreGameId != -1) { + if (_state->_delayedRestoreGameId != -1 && + // kWait cannot be used in Phant2 for delayed restore because it is + // called during the fade-in of music in the intro room, before graphics + // are fully initialized, which causes "Click to continue" text to be + // brokenly drawn over the game and then crashes the engine on the next + // room transition + g_sci->getGameId() != GID_PHANTASMAGORIA2) { + return g_sci->_guestAdditions->restoreFromLauncher(); } return false; } +#ifdef ENABLE_SCI32 +bool GuestAdditions::kPlayDuckPlayHook() const { + return _state->_delayedRestoreGameId != -1; +} +#endif + #pragma mark - #pragma mark Integrated save & restore @@ -410,7 +427,31 @@ void GuestAdditions::patchGameSaveRestoreTorin(Script &script) const { } } +void GuestAdditions::patchGameSaveRestorePhant2(Script &script) const { + const ObjMap &objects = script.getObjectMap(); + for (ObjMap::const_iterator it = objects.begin(); it != objects.end(); ++it) { + const Object &obj = it->_value; + + if (strncmp(_segMan->derefString(obj.getNameSelector()), "srGetGame", 9) != 0) { + continue; + } + + int methodIndex = obj.funcSelectorPosition(SELECTOR(init)); + if (methodIndex == -1) { + continue; + } + + byte *scriptData = const_cast<byte *>(script.getBuf(obj.getFunction(methodIndex).getOffset())); + memcpy(scriptData, SRDialogPatch, sizeof(SRDialogPatch)); + break; + } +} + reg_t GuestAdditions::kScummVMSaveLoad(EngineState *s, int argc, reg_t *argv) const { + if (g_sci->getGameId() == GID_PHANTASMAGORIA2) { + return promptSaveRestorePhant2(s, argc, argv); + } + if (g_sci->getGameId() == GID_LSL7 || g_sci->getGameId() == GID_TORIN) { return promptSaveRestoreTorin(s, argc, argv); } @@ -419,70 +460,88 @@ reg_t GuestAdditions::kScummVMSaveLoad(EngineState *s, int argc, reg_t *argv) co } reg_t GuestAdditions::promptSaveRestoreDefault(EngineState *s, int argc, reg_t *argv) const { - const bool isSave = (argc > 0); - int saveNo; + return make_reg(0, runSaveRestore(argc > 0, argc > 0 ? argv[0] : NULL_REG, s->_delayedRestoreGameId)); +} +reg_t GuestAdditions::promptSaveRestoreTorin(EngineState *s, int argc, reg_t *argv) const { + const bool isSave = (argc > 0 && (bool)argv[0].toSint16()); + + reg_t descriptionId = NULL_REG; if (isSave) { - GUI::SaveLoadChooser dialog(_("Save game:"), _("Save"), true); - saveNo = dialog.runModalWithCurrentTarget(); - if (saveNo != -1) { - reg_t descriptionId; - if (_segMan->isObject(argv[0])) { - descriptionId = readSelector(_segMan, argv[0], SELECTOR(data)); - } else { - descriptionId = argv[0]; - } - SciArray &description = *_segMan->lookupArray(descriptionId); - Common::String descriptionString = dialog.getResultString(); - if (descriptionString.empty()) - descriptionString = dialog.createDefaultSaveDescription(saveNo - 1); - description.fromString(descriptionString); - } - } else { - if (s->_delayedRestoreGameId != -1) { - saveNo = s->_delayedRestoreGameId; - } else { - GUI::SaveLoadChooser dialog(_("Restore game:"), _("Restore"), false); - saveNo = dialog.runModalWithCurrentTarget(); - } + _segMan->allocateArray(kArrayTypeString, 0, &descriptionId); } - if (saveNo > 0) { - // The autosave slot in ScummVM takes up slot 0, but in SCI the first - // non-autosave save game number needs to be 0, so reduce the save - // number here to match what would come from the normal SCI save/restore - // dialog. There is additional special code for handling the autosave - // game inside of kRestoreGame32. - --saveNo; + const int saveNo = runSaveRestore(isSave, descriptionId, s->_delayedRestoreGameId); + + if (saveNo != -1) { + assert(s->variablesMax[VAR_LOCAL] > 2); + writeSelector(_segMan, s->variables[VAR_LOCAL][1], SELECTOR(data), descriptionId); + s->variables[VAR_LOCAL][2] = make_reg(0, saveNo); + s->variables[VAR_LOCAL][3] = make_reg(0, isSave ? 1 : 0); + } else if (isSave) { + _segMan->freeArray(descriptionId); } + return make_reg(0, saveNo != -1); +} + +reg_t GuestAdditions::promptSaveRestorePhant2(EngineState *s, int argc, reg_t *argv) const { + assert(argc == 2); + const bool isSave = argv[1].toSint16() == 0; + const int saveNo = runSaveRestore(isSave, argv[0], s->_delayedRestoreGameId); + + // Clear the highlighted state of the button so if the same control panel is + // opened again it does not appear to be opened to the save/load panels + reg_t button; + if (isSave) { + button = _segMan->findObjectByName("saveButton"); + } else { + button = _segMan->findObjectByName("loadButton"); + } + writeSelectorValue(_segMan, button, SELECTOR(cel), 0); + + // This causes the control panel to quit its internal event loop and hide + // itself + const reg_t controlPanel = s->variables[VAR_GLOBAL][kGlobalVarPhant2ControlPanel]; + writeSelector(_segMan, controlPanel, SELECTOR(scratch), TRUE_REG); + return make_reg(0, saveNo); } -reg_t GuestAdditions::promptSaveRestoreTorin(EngineState *s, int argc, reg_t *argv) const { - const bool isSave = (argc > 0 && (bool)argv[0].toSint16()); +int GuestAdditions::runSaveRestore(const bool isSave, reg_t outDescription, const int forcedSaveNo) const { int saveNo; + Common::String descriptionString; - if (isSave) { - GUI::SaveLoadChooser dialog(_("Save game:"), _("Save"), true); + if (!isSave && forcedSaveNo != -1) { + saveNo = forcedSaveNo; + } else { + const char *title; + const char *action; + if (isSave) { + title = _("Save game:"); + action = _("Save"); + } else { + title = _("Restore game:"); + action = _("Restore"); + } + + GUI::SaveLoadChooser dialog(title, action, isSave); saveNo = dialog.runModalWithCurrentTarget(); if (saveNo != -1) { - reg_t descriptionId = s->variables[VAR_LOCAL][1]; - reg_t dataId; - SciArray &description = *_segMan->allocateArray(kArrayTypeString, 0, &dataId); - Common::String descriptionString = dialog.getResultString(); - if (descriptionString.empty()) + descriptionString = dialog.getResultString(); + if (descriptionString.empty()) { descriptionString = dialog.createDefaultSaveDescription(saveNo - 1); - description.fromString(descriptionString); - writeSelector(_segMan, descriptionId, SELECTOR(data), dataId); + } } - } else { - if (s->_delayedRestoreGameId != -1) { - saveNo = s->_delayedRestoreGameId; - } else { - GUI::SaveLoadChooser dialog(_("Restore game:"), _("Restore"), false); - saveNo = dialog.runModalWithCurrentTarget(); + } + + assert(!isSave || !outDescription.isNull()); + if (!outDescription.isNull()) { + if (_segMan->isObject(outDescription)) { + outDescription = readSelector(_segMan, outDescription, SELECTOR(data)); } + SciArray &description = *_segMan->lookupArray(outDescription); + description.fromString(descriptionString); } if (saveNo > 0) { @@ -494,13 +553,7 @@ reg_t GuestAdditions::promptSaveRestoreTorin(EngineState *s, int argc, reg_t *ar --saveNo; } - if (saveNo != -1) { - assert(s->variablesMax[VAR_LOCAL] > 2); - s->variables[VAR_LOCAL][2] = make_reg(0, saveNo); - s->variables[VAR_LOCAL][3] = make_reg(0, isSave ? 1 : 0); - } - - return make_reg(0, saveNo != -1); + return saveNo; } #endif @@ -535,7 +588,19 @@ bool GuestAdditions::restoreFromLauncher() const { _restoring = true; - if (g_sci->getGameId() == GID_SHIVERS) { + // Any events queued up before the game restore can cause accidental + // input into the game if they are not flushed (this is particularly + // noticeable in Phant2, where the game will display "Click to continue" + // for one frame if the user clicked during startup) + g_sci->getEventManager()->flushEvents(); + + if (g_sci->getGameId() == GID_PHANTASMAGORIA2) { + // Phantasmagoria 2 moves the function that actually restores + // a game, and uses a property of the main game object when picking + // the save game to restore + writeSelectorValue(_segMan, g_sci->getGameObject(), SELECTOR(num), _state->_delayedRestoreGameId - kSaveIdShift); + invokeSelector(g_sci->getGameObject(), SELECTOR(reallyRestore)); + } else if (g_sci->getGameId() == GID_SHIVERS) { // Shivers accepts the save game number as a parameter to // `SHIVERS::restore` reg_t args[] = { make_reg(0, _state->_delayedRestoreGameId - kSaveIdShift) }; @@ -819,6 +884,13 @@ void GuestAdditions::syncAudioVolumeGlobalsFromScummVM() const { break; } + case GID_PHANTASMAGORIA2: { + const int16 masterVolume = (ConfMan.getInt("sfx_volume") + 1) * Audio32::kMaxVolume / Audio::Mixer::kMaxMixerVolume; + syncPhant2VolumeFromScummVM(masterVolume); + syncPhant2UI(masterVolume); + break; + } + case GID_LSL7: case GID_TORIN: { const int16 musicVolume = (ConfMan.getInt("music_volume") + 1) * 100 / Audio::Mixer::kMaxMixerVolume; @@ -917,6 +989,16 @@ void GuestAdditions::syncLSL6HiresVolumeFromScummVM(const int16 musicVolume) con g_sci->_soundCmd->setMasterVolume(ConfMan.getBool("mute") ? 0 : (musicVolume * MUSIC_MASTERVOLUME_MAX / kLSL6HiresUIVolumeMax)); } +void GuestAdditions::syncPhant2VolumeFromScummVM(const int16 musicVolume) const { + _state->variables[VAR_GLOBAL][kGlobalVarPhant2MasterVolume] = make_reg(0, musicVolume); + + const reg_t soundsId = _state->variables[VAR_GLOBAL][kGlobalVarSounds]; + if (!soundsId.isNull()) { + reg_t params[] = { make_reg(0, SELECTOR(setVol)), make_reg(0, musicVolume) }; + invokeSelector(soundsId, SELECTOR(eachElementDo), 2, params); + } +} + void GuestAdditions::syncTorinVolumeFromScummVM(const int16 musicVolume, const int16 sfxVolume, const int16 speechVolume) const { _state->variables[VAR_GLOBAL][kGlobalVarTorinMusicVolume] = make_reg(0, musicVolume); _state->variables[VAR_GLOBAL][kGlobalVarTorinSFXVolume] = make_reg(0, sfxVolume); @@ -935,7 +1017,7 @@ void GuestAdditions::syncTorinVolumeFromScummVM(const int16 musicVolume, const i const reg_t &soundObj = sound->value; if (_segMan->isHeapObject(soundObj) && lookupSelector(_segMan, soundObj, selector, nullptr, nullptr) != kSelectorNone) { - invokeSelector(sound->value, SELECTOR(reSyncVol)); + invokeSelector(sound->value, selector); } soundId = sound->succ; } @@ -969,6 +1051,13 @@ void GuestAdditions::syncAudioVolumeGlobalsToScummVM(const int index, const reg_ } break; + case GID_PHANTASMAGORIA2: + if (index == kGlobalVarPhant2MasterVolume) { + const int16 masterVolume = value.toSint16() * Audio::Mixer::kMaxMixerVolume / Audio32::kMaxVolume; + ConfMan.setInt("sfx_volume", masterVolume); + } + break; + case GID_LSL7: case GID_TORIN: if (index == kGlobalVarTorinMusicVolume || @@ -1129,6 +1218,25 @@ void GuestAdditions::syncPhant1UI(const int16 oldMusicVolume, const int16 musicV } } +void GuestAdditions::syncPhant2UI(const int16 musicVolume) const { + const reg_t musicVolumeScript = _segMan->findObjectByName("foo2"); + Common::Array<reg_t> scrollBars = _segMan->findObjectsByName("P2ScrollBar"); + for (uint i = 0; i < scrollBars.size(); ++i) { + if (readSelector(_segMan, scrollBars[i], SELECTOR(client)) == musicVolumeScript) { + // P2ScrollBar objects may exist without actually being on-screen; + // the easiest way to tell seems to be to look to see if it has + // non-null pointers to subviews. (The game will correctly set the + // position of the scrollbar when it first becomes visible, so this + // is fine.) + if (!readSelector(_segMan, scrollBars[i], SELECTOR(physicalBar)).isNull()) { + reg_t params[] = { make_reg(0, musicVolume), make_reg(0, 1) }; + invokeSelector(scrollBars[i], SELECTOR(move), 2, params); + break; + } + } + } +} + void GuestAdditions::syncMGDXUI(const int16 musicVolume) const { const reg_t sliderId = _segMan->findObjectByName("icon1"); if (!sliderId.isNull()) { diff --git a/engines/sci/engine/guest_additions.h b/engines/sci/engine/guest_additions.h index 79f498a04e..cfa1139c5f 100644 --- a/engines/sci/engine/guest_additions.h +++ b/engines/sci/engine/guest_additions.h @@ -146,6 +146,13 @@ public: */ bool kWaitHook() const; +#ifdef ENABLE_SCI32 + /** + * Guest additions hook for kPlayDuck(Play). + */ + bool kPlayDuckPlayHook() const; +#endif + #pragma mark - #pragma mark Integrated save & restore @@ -183,21 +190,43 @@ private: void patchGameSaveRestoreSCI32(Script &script) const; /** - * Patches the ScummVM save/load dialogue into Torin. + * Patches the ScummVM save/load dialogue into Torin/LSL7. */ void patchGameSaveRestoreTorin(Script &script) const; /** + * Patches the ScummVM save/load dialogue into Phant2. + */ + void patchGameSaveRestorePhant2(Script &script) const; + + /** * Prompts for a save game and returns it to game scripts using default * SRDialog game class semantics. */ reg_t promptSaveRestoreDefault(EngineState *s, int argc, reg_t *argv) const; /** - * Prompts for a save game and returns it to game scripts using Torin's + * Prompts for a save game and returns it to game scripts using Torin/LSL7's * custom NewGame class semantics. */ reg_t promptSaveRestoreTorin(EngineState *s, int argc, reg_t *argv) const; + + /** + * Prompts for a save game and returns it to game scripts using Phant2's + * custom ControlPanel class semantics. + */ + reg_t promptSaveRestorePhant2(EngineState *s, int argc, reg_t *argv) const; + + /** + * Prompts the user to save or load a game. + * + * @param isSave If true, the prompt is for saving. + * @param outDescription Will be filled with the save game description. + * Optional for loads, required for saves. + * @param forcedSaveNo During delayed restore, force the returned save game + * number to this value. + */ + int runSaveRestore(const bool isSave, const reg_t outDescription, const int forcedSaveNo = -1) const; #endif #pragma mark - @@ -321,6 +350,7 @@ private: void syncGK2VolumeFromScummVM(const int16 musicVolume) const; void syncLSL6HiresVolumeFromScummVM(const int16 musicVolume) const; + void syncPhant2VolumeFromScummVM(const int16 masterVolume) const; void syncTorinVolumeFromScummVM(const int16 musicVolume, const int16 sfxVolume, const int16 speechVolume) const; /** @@ -350,6 +380,7 @@ private: void syncLSL6HiresUI(const int16 musicVolume) const; void syncMGDXUI(const int16 musicVolume) const; void syncPhant1UI(const int16 oldMusicVolume, const int16 musicVolume, reg_t &musicGlobal, const int16 oldDacVolume, const int16 dacVolume, reg_t &dacGlobal) const; + void syncPhant2UI(const int16 masterVolume) const; void syncPQ4UI(const int16 musicVolume) const; void syncPQSWATUI() const; void syncQFG4UI(const int16 musicVolume) const; diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h index bd3184a900..c65356470a 100644 --- a/engines/sci/engine/kernel_tables.h +++ b/engines/sci/engine/kernel_tables.h @@ -779,7 +779,7 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_CALL(Said), SIG_EVERYWHERE, "[r0]", NULL, NULL }, #ifdef ENABLE_SCI32 { "SaveGame", kSaveGame32, SIG_THRU_SCI21EARLY, SIGFOR_ALL, "ri[r0][r0]", NULL, NULL }, - { MAP_CALL(ScummVMSaveLoad), SIG_SCI32, SIGFOR_ALL, "([iro])([ro0])", NULL, NULL }, + { MAP_CALL(ScummVMSaveLoad), SIG_SCI32, SIGFOR_ALL, "([iro])([iro])", NULL, NULL }, #endif { MAP_CALL(SaveGame), SIG_SCI16, SIGFOR_ALL, "[r0]i[r0](r0)", NULL, NULL }, { MAP_CALL(ScriptID), SIG_EVERYWHERE, "[io](i)", NULL, NULL }, diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp index 37e4eeeab3..feb98f2eef 100644 --- a/engines/sci/engine/kvideo.cpp +++ b/engines/sci/engine/kvideo.cpp @@ -42,6 +42,7 @@ #include "video/qt_decoder.h" #include "sci/video/seq_decoder.h" #ifdef ENABLE_SCI32 +#include "sci/engine/guest_additions.h" #include "sci/graphics/frameout.h" #include "sci/graphics/video32.h" #include "sci/video/robot_decoder.h" @@ -484,6 +485,9 @@ reg_t kPlayDuck(EngineState *s, int argc, reg_t *argv) { } reg_t kPlayDuckPlay(EngineState *s, int argc, reg_t *argv) { + if (g_sci->_guestAdditions->kPlayDuckPlayHook()) { + return NULL_REG; + } kPlayDuckOpen(s, argc, argv); g_sci->_video32->getDuckPlayer().play(-1); g_sci->_video32->getDuckPlayer().close(); diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp index 2f382f4e01..9ff628eff9 100644 --- a/engines/sci/engine/script_patches.cpp +++ b/engines/sci/engine/script_patches.cpp @@ -284,9 +284,51 @@ static const uint16 sci2VolumeResetPatch[] = { PATCH_END }; +// At least Gabriel Knight 1 and Police Quest 4 floppy have a broken Str::strip inside script 64918. +// The code never passes over the actual string to kStringTrim, so that would not work and also trigger +// a signature mismatch. +// Localized version of Police Quest 4 were also affected. +// Gabriel Knight although affected doesn't seem to ever call the code, so there is no reason to patch it. +// Police Quest 4 CD got this fixed. +static const uint16 sci2BrokenStrStripSignature[] = { + SIG_MAGICDWORD, + 0x85, 0x06, // lat temp[6] + 0x31, 0x10, // bnt [jump to code that passes 2 parameters] + 0x38, SIG_UINT16(0x00c2), // pushi 00c2 (callKernel) + 0x38, SIG_UINT16(3), // pushi 03 + 0x39, 0x0e, // pushi 0e + 0x8d, 0x0b, // lst temp[0b] + 0x36, // push + 0x54, SIG_UINT16(0x000a), // self 0a + 0x33, 0x0b, // jmp to [ret] + // 2 parameter code + 0x38, SIG_UINT16(0x00c2), // pushi 00c2 + 0x7a, // push2 + 0x39, 0x0e, // pushi 0e + 0x8d, 0x0b, // lst temp[0b] + 0x54, SIG_UINT16(0x0008), // self 08 + SIG_END +}; + +static const uint16 sci2BrokenStrStripPatch[] = { + PATCH_ADDTOOFFSET(+2), + 0x85, 0x06, // lat temp[6] (once more] + PATCH_ADDTOOFFSET(+3), // jump over pushi callKernel + 0x39, 0x04, // pushi 04 + 0x39, 0x0e, // pushi 0e + // Attention: data is 0x14 in PQ4 CD, in floppy it's 0x12 + 0x67, 0x12, // pTos data (pass actual data) + 0x8d, 0x0b, // lst temp[0b] + 0x36, // push + 0x54, PATCH_UINT16(0x000c), // self 0c + 0x48, // ret + PATCH_END +}; + + // Torin/LSL7-specific version of sci2NumSavesSignature1/2 // Applies to at least: English CD -static const uint16 torinNumSavesSignature[] = { +static const uint16 torinLarry7NumSavesSignature[] = { SIG_MAGICDWORD, 0x36, // push 0x35, 0x14, // ldi 20 @@ -294,7 +336,7 @@ static const uint16 torinNumSavesSignature[] = { SIG_END }; -static const uint16 torinNumSavesPatch[] = { +static const uint16 torinLarry7NumSavesPatch[] = { PATCH_ADDTOOFFSET(+1), // push 0x35, 0x63, // ldi 99 PATCH_END @@ -2743,7 +2785,7 @@ static const SciScriptPatcherEntry larry7Signatures[] = { { true, 540, "fix make cheese cutscene (priority)", 1, larry7SignatureMakeCheesePriority, larry7PatchMakeCheesePriority }, { true, 64000, "disable volume reset on startup 1/2", 1, larry7VolumeResetSignature1, larry7VolumeResetPatch1 }, { true, 64000, "disable volume reset on startup 2/2", 1, larry7VolumeResetSignature2, larry7VolumeResetPatch2 }, - { true, 64866, "increase number of save games", 1, torinNumSavesSignature, torinNumSavesPatch }, + { true, 64866, "increase number of save games", 1, torinLarry7NumSavesSignature, torinLarry7NumSavesPatch }, SCI_SIGNATUREENTRY_TERMINATOR }; @@ -3805,6 +3847,22 @@ static const uint16 phant2RatboyPatch[] = { PATCH_END }; +// Phant2-specific version of sci2NumSavesSignature1/2 +// Applies to at least: English CD +static const uint16 phant2NumSavesSignature[] = { + SIG_MAGICDWORD, + 0x8d, 0x01, // lst 1 + 0x35, 0x14, // ldi 20 + 0x1a, // eq? + SIG_END +}; + +static const uint16 phant2NumSavesPatch[] = { + PATCH_ADDTOOFFSET(+2), // lst 1 + 0x35, 0x63, // ldi 99 + PATCH_END +}; + // script, description, signature patch static const SciScriptPatcherEntry phantasmagoria2Signatures[] = { { true, 0, "slow interface fades", 3, phant2SlowIFadeSignature, phant2SlowIFadePatch }, @@ -3812,6 +3870,7 @@ static const SciScriptPatcherEntry phantasmagoria2Signatures[] = { { true, 4081, "non-responsive mouse after ratboy puzzle", 1, phant2RatboySignature, phant2RatboyPatch }, { true, 63016, "non-responsive mouse during music fades", 1, phant2Wait4FadeSignature, phant2Wait4FadePatch }, { true, 63019, "non-responsive mouse during computer load", 1, phant2CompSlideDoorsSignature, phant2CompSlideDoorsPatch }, + { true, 64990, "increase number of save games", 1, phant2NumSavesSignature, phant2NumSavesPatch }, SCI_SIGNATUREENTRY_TERMINATOR }; @@ -4035,6 +4094,7 @@ static const SciScriptPatcherEntry pq3Signatures[] = { // script, description, signature patch static const SciScriptPatcherEntry pq4Signatures[] = { + { true, 64918, "Str::strip fix for floppy version", 1, sci2BrokenStrStripSignature, sci2BrokenStrStripPatch }, { true, 64908, "disable video benchmarking", 1, sci2BenchmarkSignature, sci2BenchmarkPatch }, { true, 64990, "increase number of save games", 1, sci2NumSavesSignature1, sci2NumSavesPatch1 }, { true, 64990, "increase number of save games", 1, sci2NumSavesSignature2, sci2NumSavesPatch2 }, @@ -6042,7 +6102,7 @@ static const SciScriptPatcherEntry torinSignatures[] = { { true, 20700, "fix bad heap in PointSoft release", 1, torinPointSoft20700HeapSignature, torinPointSoft20700HeapPatch }, { true, 64000, "disable volume reset on startup 1/2", 1, torinVolumeResetSignature1, torinVolumeResetPatch1 }, { true, 64000, "disable volume reset on startup 2/2", 1, torinVolumeResetSignature2, torinVolumeResetPatch2 }, - { true, 64866, "increase number of save games", 1, torinNumSavesSignature, torinNumSavesPatch }, + { true, 64866, "increase number of save games", 1, torinLarry7NumSavesSignature, torinLarry7NumSavesPatch }, SCI_SIGNATUREENTRY_TERMINATOR }; diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp index 1b3f18694e..cfe0ebeb64 100644 --- a/engines/sci/engine/scriptdebug.cpp +++ b/engines/sci/engine/scriptdebug.cpp @@ -950,11 +950,21 @@ void debugPropertyAccess(Object *obj, reg_t objp, unsigned int index, reg_t curV const Object *var_container = obj; if (!obj->isClass() && getSciVersion() != SCI_VERSION_3) var_container = segMan->getObject(obj->getSuperClassSelector()); - if ((index >> 1) >= var_container->getVarCount()) { - // TODO: error, warning, debug? - return; + + uint16 varSelector; + if (getSciVersion() == SCI_VERSION_3) { + varSelector = index; + } else { + index >>= 1; + + if (index >= var_container->getVarCount()) { + // TODO: error, warning, debug? + return; + } + + varSelector = var_container->getVarSelector(index); } - uint16 varSelector = var_container->getVarSelector(index >> 1); + if (g_sci->checkSelectorBreakpoint(breakpointType, objp, varSelector)) { // checkSelectorBreakpoint has already triggered the breakpoint. // We just output the relevant data here. @@ -1184,10 +1194,22 @@ bool printObject(reg_t pos) { con->debugPrintf("\n"); } con->debugPrintf(" -- methods:\n"); - for (i = 0; i < obj->getMethodCount(); i++) { - reg_t fptr = obj->getFunction(i); - con->debugPrintf(" [%03x] %s = %04x:%04x\n", obj->getFuncSelector(i), g_sci->getKernel()->getSelectorName(obj->getFuncSelector(i)).c_str(), PRINT_REG(fptr)); - } + Common::Array<Selector> foundMethods; + const Object *protoObj = obj; + do { + for (i = 0; i < protoObj->getMethodCount(); i++) { + const Selector selector = protoObj->getFuncSelector(i); + if (Common::find(foundMethods.begin(), foundMethods.end(), selector) == foundMethods.end()) { + reg_t fptr = protoObj->getFunction(i); + con->debugPrintf(" [%03x] ", selector); + if (protoObj != obj) { + con->debugPrintf("%s::", s->_segMan->getObjectName(protoObj->getPos())); + } + con->debugPrintf("%s = %04x:%04x\n", g_sci->getKernel()->getSelectorName(selector).c_str(), PRINT_REG(fptr)); + foundMethods.push_back(selector); + } + } + } while ((protoObj = s->_segMan->getObject(protoObj->getSuperClassSelector()))); Script *scr = s->_segMan->getScriptIfLoaded(pos.getSegment()); if (scr) diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp index 3cf9d08ceb..aa70d5f838 100644 --- a/engines/sci/engine/seg_manager.cpp +++ b/engines/sci/engine/seg_manager.cpp @@ -284,12 +284,11 @@ const char *SegManager::getObjectName(reg_t pos) { return name; } -reg_t SegManager::findObjectByName(const Common::String &name, int index) { +Common::Array<reg_t> SegManager::findObjectsByName(const Common::String &name) { Common::Array<reg_t> result; - uint i; // Now all values are available; iterate over all objects. - for (i = 0; i < _heap.size(); i++) { + for (uint i = 0; i < _heap.size(); i++) { const SegmentObj *mobj = _heap[i]; if (!mobj) @@ -320,12 +319,18 @@ reg_t SegManager::findObjectByName(const Common::String &name, int index) { } } + return result; +} + +reg_t SegManager::findObjectByName(const Common::String &name, int index) { + Common::Array<reg_t> result = findObjectsByName(name); + if (result.empty()) return NULL_REG; if (result.size() > 1 && index < 0) { debug("findObjectByName(%s): multiple matches:", name.c_str()); - for (i = 0; i < result.size(); i++) + for (uint i = 0; i < result.size(); i++) debug(" %3x: [%04x:%04x]", i, PRINT_REG(result[i])); return NULL_REG; // Ambiguous } diff --git a/engines/sci/engine/seg_manager.h b/engines/sci/engine/seg_manager.h index 916b813eb5..d13edf0ef2 100644 --- a/engines/sci/engine/seg_manager.h +++ b/engines/sci/engine/seg_manager.h @@ -411,6 +411,11 @@ public: const char *getObjectName(reg_t pos); /** + * Finds the addresses of all objects with the given name. + */ + Common::Array<reg_t> findObjectsByName(const Common::String &name); + + /** * Find the address of an object by its name. In case multiple objects * with the same name occur, the optional index parameter can be used * to distinguish between them. If index is -1, then if there is a diff --git a/engines/sci/engine/selector.cpp b/engines/sci/engine/selector.cpp index 77405578ed..971802affb 100644 --- a/engines/sci/engine/selector.cpp +++ b/engines/sci/engine/selector.cpp @@ -219,6 +219,13 @@ void Kernel::mapSelectors() { FIND_SELECTOR(displayValue); FIND_SELECTOR2(new_, "new"); FIND_SELECTOR(mainCel); + FIND_SELECTOR(move); + FIND_SELECTOR(eachElementDo); + FIND_SELECTOR(physicalBar); + FIND_SELECTOR(init); + FIND_SELECTOR(scratch); + FIND_SELECTOR(num); + FIND_SELECTOR(reallyRestore); #endif } diff --git a/engines/sci/engine/selector.h b/engines/sci/engine/selector.h index b2232625f2..e2afa74c7a 100644 --- a/engines/sci/engine/selector.h +++ b/engines/sci/engine/selector.h @@ -176,6 +176,13 @@ struct SelectorCache { Selector displayValue; // for PQ:SWAT volume sync Selector new_; // for Torin/LSL7 save/load patching Selector mainCel; // for MGDX volume sync + Selector move; // for Phant2 volume sync + Selector eachElementDo; // for Phant2 volume sync + Selector physicalBar; // for Phant2 volume sync + Selector init; // for Phant2 save/load patching + Selector scratch; // for Phant2 save/load patching + Selector num; // for Phant2 restore from launcher + Selector reallyRestore; // for Phant2 restore from launcher #endif }; diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h index 1ac6fed0b6..a8ac7b180f 100644 --- a/engines/sci/engine/vm.h +++ b/engines/sci/engine/vm.h @@ -167,6 +167,10 @@ enum GlobalVar { kGlobalVarTorinMusicVolume = 227, // 0 to 100 kGlobalVarTorinSFXVolume = 228, // 0 to 100 kGlobalVarTorinSpeechVolume = 229, // 0 to 100 + // Phant2 labels its volume slider as "music volume" but it is actually + // a master volume that affects both music *and* sound effects + kGlobalVarPhant2MasterVolume = 236, // 0 to 127 + kGlobalVarPhant2ControlPanel = 250, kGlobalVarShivers1Score = 349 }; diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp index 9eab4b3aec..1bbca7559f 100644 --- a/engines/sci/engine/workarounds.cpp +++ b/engines/sci/engine/workarounds.cpp @@ -361,12 +361,14 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = { { GID_PEPPER, -1, 894, 0, "Package", "doVerb", NULL, 3, { WORKAROUND_FAKE, 0 } }, // using the hand on the book in the inventory - bug #5154 { GID_PEPPER, 150, 928, 0, "Narrator", "startText", NULL, 0, { WORKAROUND_FAKE, 0 } }, // happens during the non-interactive demo of Pepper { GID_PHANTASMAGORIA, -1, 64921, -1, "Print", "addEdit", NULL, 1, { WORKAROUND_FAKE, 0 } }, // When trying to use the game debugger's flag setting command + { GID_PHANTASMAGORIA2,-1, 64926, -1, "Thumb", "action", NULL, 1, { WORKAROUND_FAKE, 0 } }, // When dragging one of the volume sliders and releasing the mouse button over the +/- buttons { GID_PQ4, -1, 25, 0, "iconToggle", "select", NULL, 1, { WORKAROUND_FAKE, 0 } }, // when toggling the icon bar to auto-hide or not { GID_PQ4, 170, 170, -1, "hideAndSeek", "handleEvent", NULL, 1, { WORKAROUND_FAKE, 0 } }, // when clicking to move right while still moving left during the Emo shootout - bug #9847 { GID_PQ4, 275, 64964, -1, "DPath", "init", NULL, 1, { WORKAROUND_FAKE, 0 } }, // when Sherry walks out of the morgue on day 3 { GID_PQ4, 240, 64964, -1, "DPath", "init", NULL, 1, { WORKAROUND_FAKE, 0 } }, // when encountering Sherry and the reporter outside the morgue at the end of day 3 { GID_PQ4, 2010, 2010, -1, "enemyShip1", "cantBeHere", NULL, 7, { WORKAROUND_FAKE, 0 } }, // when crashing into a UFO in the asteroids minigame in the Shortstop Bar { GID_PQ4, 2010, 2010, -1, "enemyShip2", "cantBeHere", NULL, 7, { WORKAROUND_FAKE, 0 } }, // when crashing into a UFO in the asteroids minigame in the Shortstop Bar + { GID_PQ4, -1, 64950, -1, "Feature", "handleEvent", NULL, 0, { WORKAROUND_FAKE, 0 } }, // floppy: when walking within room 395 (city hall, day 3) { GID_PQSWAT, -1, 64950, 0, NULL, "handleEvent", NULL, 0, { WORKAROUND_FAKE, 0 } }, // Using any menus in-game { GID_PQSWAT, -1, 73, 0, "theLashInterface", "transmit", NULL, 0, { WORKAROUND_FAKE, 0 } }, // Clicking the transmit button in LASH { GID_PQSWAT, 2990, 2990, 0, "talkToSchienbly", "changeState", NULL, 1, { WORKAROUND_FAKE, 0 } }, // When the video of Schienbly talking for the first time ends diff --git a/engines/sci/sound/audio32.cpp b/engines/sci/sound/audio32.cpp index be3f99dcea..7622305adb 100644 --- a/engines/sci/sound/audio32.cpp +++ b/engines/sci/sound/audio32.cpp @@ -842,6 +842,9 @@ uint16 Audio32::play(int16 channelIndex, const ResourceId resourceId, const bool channel.startedAtTick = now; if (_numActiveChannels == 1) { + if (_pausedAtTick) { + _pausedAtTick = now; + } _startedAtTick = now; } @@ -868,18 +871,29 @@ bool Audio32::resume(const int16 channelIndex) { AudioChannel &channel = getChannel(i); if (!channel.pausedAtTick) { channel.startedAtTick += now - _pausedAtTick; + if (channel.startedAtTick > now) { + warning("%s is being resumed in the future", channel.id.toString().c_str()); + } } } _startedAtTick += now - _pausedAtTick; + if (_startedAtTick > now) { + warning("Audio32 is being resumed in the future"); + } _pausedAtTick = 0; return true; } else if (channelIndex == kRobotChannel) { for (int i = 0; i < _numActiveChannels; ++i) { AudioChannel &channel = getChannel(i); if (channel.robot) { - channel.startedAtTick += now - channel.pausedAtTick; - channel.pausedAtTick = 0; + if (channel.pausedAtTick) { + channel.startedAtTick += now - channel.pausedAtTick; + if (channel.startedAtTick > now) { + warning("Robot audio is being resumed in the future"); + } + channel.pausedAtTick = 0; + } return true; } } @@ -887,6 +901,9 @@ bool Audio32::resume(const int16 channelIndex) { AudioChannel &channel = getChannel(channelIndex); if (channel.pausedAtTick) { channel.startedAtTick += now - channel.pausedAtTick; + if (channel.startedAtTick > now) { + warning("%s is being resumed in the future", channel.id.toString().c_str()); + } channel.pausedAtTick = 0; return true; } diff --git a/engines/scumm/imuse/imuse.cpp b/engines/scumm/imuse/imuse.cpp index 8b892f5fda..b7b72ba181 100644 --- a/engines/scumm/imuse/imuse.cpp +++ b/engines/scumm/imuse/imuse.cpp @@ -675,6 +675,44 @@ bool IMuseInternal::startSound_internal(int sound, int offset) { if (_game_id == GID_SAMNMAX && sound == 82 && getSoundStatus_internal(81, false)) ImClearTrigger(81, 1); + // Workaround for monkey2 bug #1410 / Scabb Island + // + // Tunes involved: + // 100 - Captain Dread's map + // 101 - Woodtick + // 107 - Map of Scabb Island + // + // If you go from Woodtick to the map of Scabb Island tune 107 is added as + // trigger on 101 and 101 moves to an outro and stop (triggering start + // of 107). Then at Captain Dread tune 107 is stopped and 100 is started. + // + // If you go quickly enough, the trigger occurs not at the Scabb Island + // map but at Captain Dread causing tune 107 not to be stopped. + // So we prevent starting 107 if 100 is already running. + if (_game_id == GID_MONKEY2 && (sound == 107) && (getSoundStatus_internal(100, true) == 1)) + return false; + + // In some cases 107 is running and doesn't get killed at Dread's map + if (_game_id == GID_MONKEY2 && (sound == 100) && (getSoundStatus_internal(107, true) == 1)) + IMuseInternal::stopSound_internal(107); + + // Workaround for monkey2 bug #1410 / Booty Island + // + // Tunes involved + // 100 - Captain Dread's map + // 113 - Guard Kiosk / Mardi Grass + // 115 - Map of Booty Island / Ville de la Booty + // 118 - Ville de la Booty + // + // When you enter the Guard Kiosk tune 113 is added as trigger on song + // 115. Then if you leave, 113 is stopped and 115 is started again. + // If you leave quickly enough, the trigger occurs on the map and tune + // 113 will not stop. + // We kill 113 on entry of one of the other locations (Captain Dread + // or Ville de la Booty) because tune 115 is not always started. + if (_game_id == GID_MONKEY2 && (sound == 100 || sound == 115 || sound == 118) && (getSoundStatus_internal(113, true) == 1)) + IMuseInternal::stopSound_internal(113); + player->clear(); player->setOffsetNote(offset); return player->startSound(sound, driver); diff --git a/engines/titanic/carry/long_stick.cpp b/engines/titanic/carry/long_stick.cpp index 5eb468fbd9..cfd203a9a9 100644 --- a/engines/titanic/carry/long_stick.cpp +++ b/engines/titanic/carry/long_stick.cpp @@ -47,16 +47,16 @@ bool CLongStick::UseWithOtherMsg(CUseWithOtherMsg *msg) { if (msg->_other->isEquals("SpeechCentre")) { CPuzzleSolvedMsg puzzleMsg; puzzleMsg.execute(msg->_other); - } else if (msg->_other->isEquals("LongStickDispensor")) { + } else if (msg->_other->isEquals("LongStickDispenser")) { petDisplayMessage(1, ALREADY_HAVE_STICK); } else if (msg->_other->isEquals("Bomb")) { CActMsg actMsg("Hit"); actMsg.execute("Bomb"); - petAddToInventory(); } else { return CCarry::UseWithOtherMsg(msg); } + petAddToInventory(); return true; } diff --git a/engines/titanic/continue_save_dialog.cpp b/engines/titanic/continue_save_dialog.cpp index f4c778083c..c74e1c7634 100644 --- a/engines/titanic/continue_save_dialog.cpp +++ b/engines/titanic/continue_save_dialog.cpp @@ -176,8 +176,18 @@ void CContinueSaveDialog::mouseMove(const Point &mousePos) { } void CContinueSaveDialog::leftButtonDown(const Point &mousePos) { - _mouseDown = true; - mouseMove(mousePos); + Rect eye1(188, 190, 192, 195), eye2(209, 192, 213, 197); + + if (g_vm->_events->isSpecialPressed(MK_SHIFT) && + (eye1.contains(mousePos) || eye2.contains(mousePos))) { + // Show the Easter Egg "Evil Twin" + _evilTwinShown = true; + render(); + } else { + // Standard mouse handling + _mouseDown = true; + mouseMove(mousePos); + } } void CContinueSaveDialog::leftButtonUp(const Point &mousePos) { @@ -185,6 +195,12 @@ void CContinueSaveDialog::leftButtonUp(const Point &mousePos) { Rect startRect(START_X, START_Y, START_X + _startU.w, START_Y + _startU.h); _mouseDown = false; + if (_evilTwinShown) { + _evilTwinShown = false; + render(); + return; + } + if (restoreRect.contains(mousePos)) { // Flag to exit dialog and load highlighted slot. If no slot was // selected explicitly, then fall back on loading the first slot @@ -205,22 +221,6 @@ void CContinueSaveDialog::leftButtonUp(const Point &mousePos) { } } -void CContinueSaveDialog::rightButtonDown(const Point &mousePos) { - Rect eye1(188, 190, 192, 195), eye2(209, 192, 213, 197); - - if (eye1.contains(mousePos) || eye2.contains(mousePos)) { - _evilTwinShown = true; - render(); - } -} - -void CContinueSaveDialog::rightButtonUp(const Point &mousePos) { - if (_evilTwinShown) { - _evilTwinShown = false; - render(); - } -} - void CContinueSaveDialog::keyDown(Common::KeyState keyState) { if (keyState.keycode == Common::KEYCODE_ESCAPE) _selectedSlot = EXIT_GAME; diff --git a/engines/titanic/continue_save_dialog.h b/engines/titanic/continue_save_dialog.h index b6d9aebfac..29a4bf4f14 100644 --- a/engines/titanic/continue_save_dialog.h +++ b/engines/titanic/continue_save_dialog.h @@ -85,8 +85,6 @@ public: virtual void mouseMove(const Point &mousePos); virtual void leftButtonDown(const Point &mousePos); virtual void leftButtonUp(const Point &mousePos); - virtual void rightButtonDown(const Point &mousePos); - virtual void rightButtonUp(const Point &mousePos); virtual void keyDown(Common::KeyState keyState); /** diff --git a/engines/titanic/core/view_item.cpp b/engines/titanic/core/view_item.cpp index 4e37fd23be..243d47f3fd 100644 --- a/engines/titanic/core/view_item.cpp +++ b/engines/titanic/core/view_item.cpp @@ -27,6 +27,7 @@ #include "titanic/core/view_item.h" #include "titanic/messages/messages.h" #include "titanic/pet_control/pet_control.h" +#include "titanic/titanic.h" namespace Titanic { @@ -163,6 +164,11 @@ void CViewItem::enterView(CViewItem *newView) { petControl->enterRoom(newRoom); } } + + // WORKAROUND: Do a dummy mouse movement, to allow for the correct cursor + // to be set for the current position in the new view + CMouseMoveMsg moveMsg(g_vm->_events->getMousePos(), 0); + newView->MouseMoveMsg(&moveMsg); } } diff --git a/engines/titanic/events.cpp b/engines/titanic/events.cpp index cb46f8c42b..f554796d09 100644 --- a/engines/titanic/events.cpp +++ b/engines/titanic/events.cpp @@ -72,14 +72,14 @@ void Events::pollEvents() { eventTarget()->middleButtonUp(_mousePos); return; case Common::EVENT_RBUTTONDOWN: - _specialButtons |= MK_RBUTTON; + _specialButtons |= MK_LBUTTON | MK_SHIFT; _mousePos = event.mouse; - eventTarget()->rightButtonDown(_mousePos); + eventTarget()->leftButtonDown(_mousePos); return; case Common::EVENT_RBUTTONUP: - _specialButtons &= ~MK_RBUTTON; + _specialButtons &= ~(MK_RBUTTON | MK_SHIFT); _mousePos = event.mouse; - eventTarget()->rightButtonUp(_mousePos); + eventTarget()->leftButtonUp(_mousePos); return; case Common::EVENT_WHEELUP: case Common::EVENT_WHEELDOWN: diff --git a/engines/titanic/events.h b/engines/titanic/events.h index e14fbd8637..430702be00 100644 --- a/engines/titanic/events.h +++ b/engines/titanic/events.h @@ -63,15 +63,13 @@ public: virtual void middleButtonDown(const Point &mousePos) {} virtual void middleButtonUp(const Point &mousePos) {} virtual void middleButtonDoubleClick(const Point &mousePos) {} - virtual void rightButtonDown(const Point &mousePos) {} - virtual void rightButtonUp(const Point &mousePos) {} virtual void mouseWheel(const Point &mousePos, bool wheelUp) {} virtual void keyDown(Common::KeyState keyState) {} virtual void keyUp(Common::KeyState keyState) {} }; /** - * An eent target used for waiting for a mouse or keypress + * An event target used for waiting for a mouse or keypress */ class CPressTarget : public CEventTarget { public: @@ -81,7 +79,6 @@ public: virtual ~CPressTarget() {} virtual void leftButtonDown(const Point &mousePos) { _pressed = true; } virtual void middleButtonDown(const Point &mousePos) { _pressed = true; } - virtual void rightButtonDown(const Point &mousePos) { _pressed = true; } virtual void keyDown(Common::KeyState keyState) { _pressed = true; } }; diff --git a/engines/titanic/game/idle_summoner.cpp b/engines/titanic/game/idle_summoner.cpp index dd3aa09490..81192db0a3 100644 --- a/engines/titanic/game/idle_summoner.cpp +++ b/engines/titanic/game/idle_summoner.cpp @@ -76,12 +76,22 @@ bool CIdleSummoner::TimerMsg(CTimerMsg *msg) { uint nodesCtr = getNodeChangedCtr(); if (msg->_actionVal == 1 && !petDoorOrBellbotPresent() && nodesCtr > 0 && nodesCtr != _oldNodesCtr) { + + // They can only appear in the Top of the Well and the Embarkation Lobby if (!compareRoomNameTo("TopOfWell") && !compareRoomNameTo("EmbLobby")) return true; + // WORKAROUND: To benefit the players, don't allow the bots to turn up + // when at the Embarkation SuccUBus, in front of the Deskbot's desk, + // or when in the Gondola, since it just looks weird + CString fullName = getFullViewName(); + if (fullName == "EmbLobby.Node 2.W" || fullName == "EmbLobby.Node 4.E" || + fullName == "TopOfWell.Node 29.N") + return true; + int region = talkGetDialRegion("BellBot", 1); uint delay = region == 1 ? 15000 : 120000; - uint enterTicks = MIN(getNodeEnterTicks(), _ticks); + uint enterTicks = MAX(getNodeEnterTicks(), _ticks); CString name; uint ticks = getTicksCount() - enterTicks; diff --git a/engines/titanic/input_translator.cpp b/engines/titanic/input_translator.cpp index 0f717de37f..cd0dbc7d56 100644 --- a/engines/titanic/input_translator.cpp +++ b/engines/titanic/input_translator.cpp @@ -80,26 +80,11 @@ void CInputTranslator::middleButtonDoubleClick(int special, const Point &pt) { _inputHandler->handleMessage(msg); } -void CInputTranslator::rightButtonDown(int special, const Point &pt) { - CMouseButtonDownMsg msg(pt, MB_RIGHT); - _inputHandler->handleMessage(msg); -} - -void CInputTranslator::rightButtonUp(int special, const Point &pt) { - CMouseButtonUpMsg msg(pt, MB_RIGHT); - _inputHandler->handleMessage(msg); -} - void CInputTranslator::mouseWheel(bool wheelUp, const Point &pt) { CMouseWheelMsg msg(pt, wheelUp); _inputHandler->handleMessage(msg); } -void CInputTranslator::rightButtonDoubleClick(int special, const Point &pt) { - CMouseDoubleClickMsg msg(pt, MB_RIGHT); - _inputHandler->handleMessage(msg); -} - void CInputTranslator::keyDown(const Common::KeyState &keyState) { if (keyState.keycode >= Common::KEYCODE_F1 && keyState.keycode <= Common::KEYCODE_F5) { CVirtualKeyCharMsg msg(keyState); diff --git a/engines/titanic/input_translator.h b/engines/titanic/input_translator.h index 66dcaa1cbe..cb53a2c396 100644 --- a/engines/titanic/input_translator.h +++ b/engines/titanic/input_translator.h @@ -48,10 +48,7 @@ public: void middleButtonDown(int special, const Point &pt); void middleButtonUp(int special, const Point &pt); void middleButtonDoubleClick(int special, const Point &pt); - void rightButtonDown(int special, const Point &pt); - void rightButtonUp(int special, const Point &pt); void mouseWheel(bool wheelUp, const Point &pt); - void rightButtonDoubleClick(int special, const Point &pt); void keyDown(const Common::KeyState &keyState); /** diff --git a/engines/titanic/main_game_window.cpp b/engines/titanic/main_game_window.cpp index 6cbcba08ff..b578bb942e 100644 --- a/engines/titanic/main_game_window.cpp +++ b/engines/titanic/main_game_window.cpp @@ -32,7 +32,7 @@ namespace Titanic { CMainGameWindow::CMainGameWindow(TitanicEngine *vm): _vm(vm), - _priorLeftDownTime(0), _priorMiddleDownTime(0), _priorRightDownTime(0) { + _priorLeftDownTime(0), _priorMiddleDownTime(0) { _gameView = nullptr; _gameManager = nullptr; _project = nullptr; @@ -320,26 +320,6 @@ void CMainGameWindow::middleButtonDoubleClick(const Point &mousePos) { HANDLE_MESSAGE(middleButtonDoubleClick) } -void CMainGameWindow::rightButtonDown(const Point &mousePos) { - if (!isMouseControlEnabled()) - return; - - if ((_vm->_events->getTicksCount() - _priorRightDownTime) < DOUBLE_CLICK_TIME) { - _priorRightDownTime = 0; - rightButtonDoubleClick(mousePos); - } else { - _priorRightDownTime = _vm->_events->getTicksCount(); - HANDLE_MESSAGE(rightButtonDown) - } -} - -void CMainGameWindow::rightButtonUp(const Point &mousePos) { - if (!isMouseControlEnabled()) - return; - - HANDLE_MESSAGE(rightButtonUp) -} - void CMainGameWindow::mouseWheel(const Point &mousePos, bool wheelUp) { if (!isMouseControlEnabled()) return; @@ -348,13 +328,6 @@ void CMainGameWindow::mouseWheel(const Point &mousePos, bool wheelUp) { mouseChanged(); } -void CMainGameWindow::rightButtonDoubleClick(const Point &mousePos) { - if (!isMouseControlEnabled()) - return; - - HANDLE_MESSAGE(rightButtonDoubleClick) -} - void CMainGameWindow::keyDown(Common::KeyState keyState) { if (keyState.keycode == Common::KEYCODE_d && (keyState.flags & Common::KBD_CTRL)) { // Attach to the debugger diff --git a/engines/titanic/main_game_window.h b/engines/titanic/main_game_window.h index b29198caeb..e573217058 100644 --- a/engines/titanic/main_game_window.h +++ b/engines/titanic/main_game_window.h @@ -41,7 +41,6 @@ private: int _pendingLoadSlot; uint32 _priorLeftDownTime; uint32 _priorMiddleDownTime; - uint32 _priorRightDownTime; private: /** * Returns true if a savegame was selected to be loaded @@ -78,7 +77,6 @@ private: void leftButtonDoubleClick(const Point &mousePos); void middleButtonDoubleClick(const Point &mousePos); - void rightButtonDoubleClick(const Point &mousePos); /** * Returns true if the player can control the mouse @@ -105,8 +103,6 @@ public: virtual void leftButtonUp(const Point &mousePos); virtual void middleButtonDown(const Point &mousePos); virtual void middleButtonUp(const Point &mousePos); - virtual void rightButtonDown(const Point &mousePos); - virtual void rightButtonUp(const Point &mousePos); virtual void mouseWheel(const Point &mousePos, bool wheelUp); virtual void keyDown(Common::KeyState keyState); diff --git a/engines/titanic/support/credit_text.cpp b/engines/titanic/support/credit_text.cpp index b5b4fbe4f1..98c3d9bf1d 100644 --- a/engines/titanic/support/credit_text.cpp +++ b/engines/titanic/support/credit_text.cpp @@ -25,10 +25,12 @@ namespace Titanic { +#define FRAMES_PER_CYCLE 16 + CCreditText::CCreditText() : _screenManagerP(nullptr), _ticks(0), _fontHeight(1), _objectP(nullptr), _yOffset(0), - _priorInc(0), _textR(0), _textG(0), _textB(0), _destR(0), - _destG(0), _destB(0), _counter(0) { + _priorInc(0), _textR(0), _textG(0), _textB(0), _deltaR(0), + _deltaG(0), _deltaB(0), _counter(0) { } void CCreditText::clear() { @@ -49,9 +51,9 @@ void CCreditText::load(CGameObject *obj, CScreenManager *screenManager, _textR = 0xFF; _textG = 0xFF; _textB = 0xFF; - _destR = 0; - _destG = 0; - _destB = 0; + _deltaR = 0; + _deltaG = 0; + _deltaB = 0; _counter = 0; } @@ -153,13 +155,13 @@ bool CCreditText::draw() { if (_groupIt == _groups.end()) return false; - if (++_counter > 200) { - _textR += _destR; - _textG += _destG; - _textB += _destB; - _destR = g_vm->getRandomNumber(63) + 192 - _textR; - _destG = g_vm->getRandomNumber(63) + 192 - _textG; - _destB = g_vm->getRandomNumber(63) + 192 - _textB; + if (++_counter >= FRAMES_PER_CYCLE) { + _textR += _deltaR; + _textG += _deltaG; + _textB += _deltaB; + _deltaR = g_vm->getRandomNumber(63) + 192 - _textR; + _deltaG = g_vm->getRandomNumber(63) + 192 - _textG; + _deltaB = g_vm->getRandomNumber(63) + 192 - _textB; _counter = 0; } @@ -205,9 +207,9 @@ bool CCreditText::draw() { Point textPos; for (textPos.y = _rect.top + _yOffset - yDiff; textPos.y <= _rect.bottom; textPos.y += _fontHeight) { - int textR = _textR + _destR * _counter / 200; - int textG = _textG + _destG * _counter / 200; - int textB = _textB + _destB * _counter / 200; + int textR = _textR + _deltaR * _counter / FRAMES_PER_CYCLE; + int textG = _textG + _deltaG * _counter / FRAMES_PER_CYCLE; + int textB = _textB + _deltaB * _counter / FRAMES_PER_CYCLE; // Single iteration loop to figure out RGB values for the line do { diff --git a/engines/titanic/support/credit_text.h b/engines/titanic/support/credit_text.h index f3cc08a049..2850fe79c6 100644 --- a/engines/titanic/support/credit_text.h +++ b/engines/titanic/support/credit_text.h @@ -74,7 +74,7 @@ public: int _yOffset; int _priorInc; int _textR, _textG, _textB; - int _destR, _destG, _destB; + int _deltaR, _deltaG, _deltaB; int _counter; public: CCreditText(); diff --git a/engines/titanic/true_talk/tt_parser.cpp b/engines/titanic/true_talk/tt_parser.cpp index adf008767f..4ed970533a 100644 --- a/engines/titanic/true_talk/tt_parser.cpp +++ b/engines/titanic/true_talk/tt_parser.cpp @@ -1403,7 +1403,7 @@ int TTparser::checkForAction() { // Chain of words, so we need to find the last word of the chain, // and set the last-but-one's _nextP to nullptr to detach the last one TTword *prior = nullptr; - for (word = word->_nextP; word->_nextP; word = word->_nextP) { + for (; word->_nextP; word = word->_nextP) { prior = word; } diff --git a/engines/toon/tools.h b/engines/toon/tools.h index d80ec006b0..1ba8cebdb7 100644 --- a/engines/toon/tools.h +++ b/engines/toon/tools.h @@ -36,12 +36,6 @@ const uint32 kCompSPCN = 0x5350434E; const uint32 kCompRNC1 = 0x524E4301; const uint32 kCompRNC2 = 0x524E4302; -#define READ_LE_INT16(x) (int16) READ_LE_UINT16(x) -#define READ_LE_INT32(x) (int32) READ_LE_UINT32(x) - -#define WRITE_LE_INT16(x, y) WRITE_LE_UINT16(x, (int16)y) -#define WRITE_LE_INT32(x, y) WRITE_LE_UINT32(x, (int32)y) - uint32 decompressSPCN(byte *src, byte *dst, uint32 dstsize); uint32 decompressLZSS(byte *src, byte *dst, int dstsize); |