aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
Diffstat (limited to 'engines')
-rw-r--r--engines/bladerunner/actor.cpp2
-rw-r--r--engines/bladerunner/bladerunner.cpp59
-rw-r--r--engines/bladerunner/bladerunner.h12
-rw-r--r--engines/bladerunner/item.cpp2
-rw-r--r--engines/bladerunner/item_pickup.cpp2
-rw-r--r--engines/bladerunner/module.mk3
-rw-r--r--engines/bladerunner/outtake.cpp5
-rw-r--r--engines/bladerunner/scene.cpp12
-rw-r--r--engines/bladerunner/scene.h2
-rw-r--r--engines/bladerunner/script/scene.cpp109
-rw-r--r--engines/bladerunner/script/script.cpp12
-rw-r--r--engines/bladerunner/spinner.cpp291
-rw-r--r--engines/bladerunner/spinner.h77
-rw-r--r--engines/bladerunner/ui_image_picker.cpp265
-rw-r--r--engines/bladerunner/ui_image_picker.h92
-rw-r--r--engines/bladerunner/vqa_decoder.cpp28
-rw-r--r--engines/bladerunner/vqa_decoder.h10
-rw-r--r--engines/bladerunner/vqa_player.cpp9
-rw-r--r--engines/bladerunner/vqa_player.h8
-rw-r--r--engines/draci/music.cpp2
-rw-r--r--engines/hopkins/hopkins.h2
-rw-r--r--engines/lure/luredefs.h3
-rw-r--r--engines/mohawk/console.cpp34
-rw-r--r--engines/mohawk/myst.cpp31
-rw-r--r--engines/mohawk/myst.h15
-rw-r--r--engines/mohawk/myst_areas.cpp6
-rw-r--r--engines/mohawk/myst_areas.h2
-rw-r--r--engines/mohawk/myst_stacks/channelwood.cpp48
-rw-r--r--engines/mohawk/myst_stacks/dni.cpp40
-rw-r--r--engines/mohawk/myst_stacks/intro.cpp15
-rw-r--r--engines/mohawk/myst_stacks/mechanical.cpp19
-rw-r--r--engines/mohawk/myst_stacks/myst.cpp149
-rw-r--r--engines/mohawk/myst_stacks/selenitic.cpp78
-rw-r--r--engines/mohawk/myst_stacks/stoneship.cpp51
-rw-r--r--engines/mohawk/video.cpp7
-rw-r--r--engines/mohawk/video.h5
-rw-r--r--engines/queen/queen.h18
-rw-r--r--engines/sci/detection.cpp2
-rw-r--r--engines/sci/detection_tables.h18
-rw-r--r--engines/sci/engine/features.cpp1
-rw-r--r--engines/sci/engine/guest_additions.cpp224
-rw-r--r--engines/sci/engine/guest_additions.h35
-rw-r--r--engines/sci/engine/kernel_tables.h2
-rw-r--r--engines/sci/engine/kvideo.cpp4
-rw-r--r--engines/sci/engine/script_patches.cpp68
-rw-r--r--engines/sci/engine/scriptdebug.cpp38
-rw-r--r--engines/sci/engine/seg_manager.cpp13
-rw-r--r--engines/sci/engine/seg_manager.h5
-rw-r--r--engines/sci/engine/selector.cpp7
-rw-r--r--engines/sci/engine/selector.h7
-rw-r--r--engines/sci/engine/vm.h4
-rw-r--r--engines/sci/engine/workarounds.cpp2
-rw-r--r--engines/sci/sound/audio32.cpp21
-rw-r--r--engines/scumm/imuse/imuse.cpp38
-rw-r--r--engines/titanic/carry/long_stick.cpp4
-rw-r--r--engines/titanic/continue_save_dialog.cpp36
-rw-r--r--engines/titanic/continue_save_dialog.h2
-rw-r--r--engines/titanic/core/view_item.cpp6
-rw-r--r--engines/titanic/events.cpp8
-rw-r--r--engines/titanic/events.h5
-rw-r--r--engines/titanic/game/idle_summoner.cpp12
-rw-r--r--engines/titanic/input_translator.cpp15
-rw-r--r--engines/titanic/input_translator.h3
-rw-r--r--engines/titanic/main_game_window.cpp29
-rw-r--r--engines/titanic/main_game_window.h4
-rw-r--r--engines/titanic/support/credit_text.cpp32
-rw-r--r--engines/titanic/support/credit_text.h2
-rw-r--r--engines/titanic/true_talk/tt_parser.cpp2
-rw-r--r--engines/toon/tools.h6
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);