aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
Diffstat (limited to 'engines')
-rw-r--r--engines/adl/adl.cpp11
-rw-r--r--engines/adl/adl.h2
-rw-r--r--engines/adl/adl_v2.cpp4
-rw-r--r--engines/bladerunner/actor_clues.cpp6
-rw-r--r--engines/bladerunner/bladerunner.cpp9
-rw-r--r--engines/bladerunner/light.cpp11
-rw-r--r--engines/bladerunner/scene.cpp116
-rw-r--r--engines/bladerunner/scene.h12
-rw-r--r--engines/bladerunner/scene_objects.cpp3
-rw-r--r--engines/bladerunner/script/script.cpp31
-rw-r--r--engines/bladerunner/set_effects.cpp4
-rw-r--r--engines/bladerunner/vqa_decoder.cpp8
-rw-r--r--engines/bladerunner/vqa_player.cpp8
-rw-r--r--engines/bladerunner/vqa_player.h10
-rw-r--r--engines/chewy/detection.cpp4
-rw-r--r--engines/composer/composer.cpp14
-rw-r--r--engines/composer/composer.h19
-rw-r--r--engines/composer/detection.cpp50
-rw-r--r--engines/composer/graphics.cpp65
-rw-r--r--engines/composer/graphics.h1
-rw-r--r--engines/composer/module.mk1
-rw-r--r--engines/composer/resource.cpp21
-rw-r--r--engines/composer/resource.h12
-rw-r--r--engines/composer/saveload.cpp428
-rw-r--r--engines/director/archive.cpp552
-rw-r--r--engines/director/archive.h (renamed from engines/director/resource.h)5
-rw-r--r--engines/director/cast.cpp136
-rw-r--r--engines/director/cast.h162
-rw-r--r--engines/director/director.cpp11
-rw-r--r--engines/director/frame.cpp118
-rw-r--r--engines/director/frame.h10
-rw-r--r--engines/director/images.cpp1
-rw-r--r--engines/director/lingo/lingo-code.cpp4
-rw-r--r--engines/director/lingo/lingo-the.cpp1
-rw-r--r--engines/director/module.mk1
-rw-r--r--engines/director/movie.cpp2
-rw-r--r--engines/director/movie.h2
-rw-r--r--engines/director/resource.cpp527
-rw-r--r--engines/director/score.cpp289
-rw-r--r--engines/director/score.h131
-rw-r--r--engines/director/sound.cpp2
-rw-r--r--engines/director/sprite.cpp3
-rw-r--r--engines/director/sprite.h28
-rw-r--r--engines/dm/group.cpp5
-rw-r--r--engines/fullpipe/statics.cpp2
-rw-r--r--engines/kyra/lol.h3
-rw-r--r--engines/kyra/scene_lol.cpp14
-rw-r--r--engines/kyra/timer.cpp2
-rw-r--r--engines/lab/console.cpp2
-rw-r--r--engines/mads/palette.cpp6
-rw-r--r--engines/mads/staticres.cpp2
-rw-r--r--engines/mohawk/POTFILES1
-rw-r--r--engines/mohawk/riven.cpp6
-rw-r--r--engines/mohawk/riven_external.cpp9
-rw-r--r--engines/sci/console.cpp125
-rw-r--r--engines/sci/console.h1
-rw-r--r--engines/sci/detection.cpp2
-rw-r--r--engines/sci/detection_tables.h2
-rw-r--r--engines/sci/engine/features.h11
-rw-r--r--engines/sci/engine/kernel.h1
-rw-r--r--engines/sci/engine/kernel_tables.h1
-rw-r--r--engines/sci/engine/kstring.cpp12
-rw-r--r--engines/sci/engine/kvideo.cpp5
-rw-r--r--engines/sci/engine/message.cpp12
-rw-r--r--engines/sci/engine/message.h2
-rw-r--r--engines/sci/engine/savegame.cpp25
-rw-r--r--engines/sci/engine/script_patches.cpp19
-rw-r--r--engines/sci/engine/segment.h13
-rw-r--r--engines/sci/engine/workarounds.cpp16
-rw-r--r--engines/sci/engine/workarounds.h1
-rw-r--r--engines/sci/graphics/celobj32.cpp28
-rw-r--r--engines/sci/graphics/lists32.h7
-rw-r--r--engines/sci/graphics/palette32.h1
-rw-r--r--engines/sci/graphics/screen.cpp5
-rw-r--r--engines/sci/graphics/text32.cpp2
-rw-r--r--engines/sci/graphics/transitions32.cpp2
-rw-r--r--engines/sci/graphics/video32.cpp161
-rw-r--r--engines/sci/graphics/video32.h18
-rw-r--r--engines/sci/parser/vocabulary.cpp2
-rw-r--r--engines/sci/resource.cpp32
-rw-r--r--engines/sci/resource.h1
-rw-r--r--engines/sci/sci.cpp4
-rw-r--r--engines/scumm/sound.cpp2
-rw-r--r--engines/titanic/carry/arm.cpp5
-rw-r--r--engines/titanic/carry/carry.cpp23
-rw-r--r--engines/titanic/carry/carry_parrot.cpp5
-rw-r--r--engines/titanic/carry/central_core.cpp2
-rw-r--r--engines/titanic/carry/chicken.cpp8
-rw-r--r--engines/titanic/carry/hose.cpp3
-rw-r--r--engines/titanic/carry/perch.cpp2
-rw-r--r--engines/titanic/carry/plug_in.cpp2
-rw-r--r--engines/titanic/continue_save_dialog.cpp7
-rw-r--r--engines/titanic/core/background.cpp2
-rw-r--r--engines/titanic/core/game_object.cpp56
-rw-r--r--engines/titanic/core/game_object.h28
-rw-r--r--engines/titanic/core/project_item.cpp17
-rw-r--r--engines/titanic/core/project_item.h2
-rw-r--r--engines/titanic/core/saveable_object.cpp14
-rw-r--r--engines/titanic/core/saveable_object.h6
-rw-r--r--engines/titanic/core/view_item.cpp2
-rw-r--r--engines/titanic/events.cpp60
-rw-r--r--engines/titanic/events.h44
-rw-r--r--engines/titanic/game/cdrom.cpp3
-rw-r--r--engines/titanic/game/cdrom_tray.cpp1
-rw-r--r--engines/titanic/game/computer.cpp2
-rw-r--r--engines/titanic/game/maitred/maitred_prod_receptor.cpp4
-rw-r--r--engines/titanic/game/pet/pet.cpp2
-rw-r--r--engines/titanic/game/pet/pet_lift.cpp4
-rw-r--r--engines/titanic/game/pet/pet_position.cpp4
-rw-r--r--engines/titanic/game/pet/pet_transport.cpp6
-rw-r--r--engines/titanic/game/pet/pet_transport.h1
-rw-r--r--engines/titanic/game/service_elevator_window.cpp41
-rw-r--r--engines/titanic/game/service_elevator_window.h8
-rw-r--r--engines/titanic/game/television.cpp4
-rw-r--r--engines/titanic/game/transport/gondolier.cpp2
-rw-r--r--engines/titanic/game/transport/lift_indicator.cpp34
-rw-r--r--engines/titanic/game/transport/lift_indicator.h6
-rw-r--r--engines/titanic/game/transport/service_elevator.cpp15
-rw-r--r--engines/titanic/game_location.h5
-rw-r--r--engines/titanic/game_manager.cpp5
-rw-r--r--engines/titanic/game_state.cpp21
-rw-r--r--engines/titanic/game_state.h4
-rw-r--r--engines/titanic/input_handler.cpp6
-rw-r--r--engines/titanic/input_translator.cpp7
-rw-r--r--engines/titanic/input_translator.h1
-rw-r--r--engines/titanic/main_game_window.cpp82
-rw-r--r--engines/titanic/main_game_window.h22
-rw-r--r--engines/titanic/messages/messages.cpp13
-rw-r--r--engines/titanic/messages/messages.h18
-rw-r--r--engines/titanic/messages/mouse_messages.h14
-rw-r--r--engines/titanic/moves/exit_lift.cpp4
-rw-r--r--engines/titanic/moves/restricted_move.cpp6
-rw-r--r--engines/titanic/npcs/barbot.cpp2
-rw-r--r--engines/titanic/npcs/bellbot.cpp22
-rw-r--r--engines/titanic/npcs/bilge_succubus.cpp2
-rw-r--r--engines/titanic/npcs/deskbot.cpp45
-rw-r--r--engines/titanic/npcs/deskbot.h2
-rw-r--r--engines/titanic/npcs/doorbot.cpp105
-rw-r--r--engines/titanic/npcs/doorbot.h2
-rw-r--r--engines/titanic/npcs/liftbot.cpp23
-rw-r--r--engines/titanic/npcs/maitre_d.cpp2
-rw-r--r--engines/titanic/npcs/parrot.cpp14
-rw-r--r--engines/titanic/npcs/succubus.cpp2
-rw-r--r--engines/titanic/npcs/titania.cpp2
-rw-r--r--engines/titanic/npcs/true_talk_npc.cpp31
-rw-r--r--engines/titanic/npcs/true_talk_npc.h6
-rw-r--r--engines/titanic/pet_control/pet_control.cpp39
-rw-r--r--engines/titanic/pet_control/pet_control.h8
-rw-r--r--engines/titanic/pet_control/pet_conversations.cpp52
-rw-r--r--engines/titanic/pet_control/pet_conversations.h1
-rw-r--r--engines/titanic/pet_control/pet_drag_chev.cpp22
-rw-r--r--engines/titanic/pet_control/pet_gfx_element.cpp6
-rw-r--r--engines/titanic/pet_control/pet_glyphs.cpp6
-rw-r--r--engines/titanic/pet_control/pet_inventory.cpp2
-rw-r--r--engines/titanic/pet_control/pet_inventory_glyphs.cpp6
-rw-r--r--engines/titanic/pet_control/pet_load_save.cpp2
-rw-r--r--engines/titanic/pet_control/pet_real_life.h5
-rw-r--r--engines/titanic/pet_control/pet_remote.cpp12
-rw-r--r--engines/titanic/pet_control/pet_remote_glyphs.cpp113
-rw-r--r--engines/titanic/pet_control/pet_remote_glyphs.h44
-rw-r--r--engines/titanic/pet_control/pet_rooms.cpp22
-rw-r--r--engines/titanic/pet_control/pet_rooms.h5
-rw-r--r--engines/titanic/pet_control/pet_rooms_glyphs.cpp90
-rw-r--r--engines/titanic/pet_control/pet_rooms_glyphs.h29
-rw-r--r--engines/titanic/pet_control/pet_save.cpp13
-rw-r--r--engines/titanic/pet_control/pet_save.h5
-rw-r--r--engines/titanic/pet_control/pet_section.cpp1
-rw-r--r--engines/titanic/pet_control/pet_section.h1
-rw-r--r--engines/titanic/pet_control/pet_text.cpp32
-rw-r--r--engines/titanic/pet_control/pet_text.h17
-rw-r--r--engines/titanic/room_flags.cpp135
-rw-r--r--engines/titanic/room_flags.h11
-rw-r--r--engines/titanic/sound/qmixer.cpp59
-rw-r--r--engines/titanic/sound/qmixer.h14
-rw-r--r--engines/titanic/sound/sound.cpp3
-rw-r--r--engines/titanic/sound/sound.h2
-rw-r--r--engines/titanic/sound/sound_manager.cpp6
-rw-r--r--engines/titanic/sound/sound_manager.h8
-rw-r--r--engines/titanic/sound/wave_file.cpp10
-rw-r--r--engines/titanic/sound/wave_file.h5
-rw-r--r--engines/titanic/star_control/star_control_sub13.cpp2
-rw-r--r--engines/titanic/support/avi_surface.cpp33
-rw-r--r--engines/titanic/support/avi_surface.h7
-rw-r--r--engines/titanic/support/font.cpp35
-rw-r--r--engines/titanic/support/mouse_cursor.cpp76
-rw-r--r--engines/titanic/support/mouse_cursor.h48
-rw-r--r--engines/titanic/support/movie.cpp9
-rw-r--r--engines/titanic/support/screen_manager.cpp5
-rw-r--r--engines/titanic/support/simple_file.cpp9
-rw-r--r--engines/titanic/support/strings.cpp2
-rw-r--r--engines/titanic/support/strings.h53
-rw-r--r--engines/titanic/support/time_event_info.cpp4
-rw-r--r--engines/titanic/support/transparency_surface.cpp15
-rw-r--r--engines/titanic/support/transparency_surface.h14
-rw-r--r--engines/titanic/support/video_surface.cpp4
-rw-r--r--engines/titanic/titanic.cpp15
-rw-r--r--engines/titanic/titanic.h1
-rw-r--r--engines/titanic/true_talk/barbot_script.cpp4
-rw-r--r--engines/titanic/true_talk/bellbot_script.cpp132
-rw-r--r--engines/titanic/true_talk/deskbot_script.cpp89
-rw-r--r--engines/titanic/true_talk/deskbot_script.h8
-rw-r--r--engines/titanic/true_talk/doorbot_script.cpp6
-rw-r--r--engines/titanic/true_talk/liftbot_script.cpp13
-rw-r--r--engines/titanic/true_talk/maitred_script.cpp22
-rw-r--r--engines/titanic/true_talk/parrot_script.cpp2
-rw-r--r--engines/titanic/true_talk/script_support.cpp4
-rw-r--r--engines/titanic/true_talk/script_support.h9
-rw-r--r--engines/titanic/true_talk/succubus_script.cpp2
-rw-r--r--engines/titanic/true_talk/title_engine.cpp3
-rw-r--r--engines/titanic/true_talk/true_talk_manager.cpp11
-rw-r--r--engines/titanic/true_talk/tt_concept.cpp14
-rw-r--r--engines/titanic/true_talk/tt_concept_node.cpp3
-rw-r--r--engines/titanic/true_talk/tt_npc_script.cpp13
-rw-r--r--engines/titanic/true_talk/tt_parser.cpp122
-rw-r--r--engines/titanic/true_talk/tt_quotes_tree.cpp2
-rw-r--r--engines/titanic/true_talk/tt_response.cpp6
-rw-r--r--engines/titanic/true_talk/tt_response.h6
-rw-r--r--engines/titanic/true_talk/tt_script_base.cpp2
-rw-r--r--engines/titanic/true_talk/tt_sentence.cpp12
-rw-r--r--engines/titanic/true_talk/tt_sentence.h4
-rw-r--r--engines/titanic/true_talk/tt_string.cpp6
-rw-r--r--engines/titanic/true_talk/tt_vocab.cpp5
222 files changed, 3863 insertions, 2048 deletions
diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp
index 62f07ad639..63b0937354 100644
--- a/engines/adl/adl.cpp
+++ b/engines/adl/adl.cpp
@@ -58,6 +58,7 @@ AdlEngine::AdlEngine(OSystem *syst, const AdlGameDescription *gd) :
_graphics(nullptr),
_isRestarting(false),
_isRestoring(false),
+ _isQuitting(false),
_skipOneCommand(false),
_gameDescription(gd),
_saveVerb(0),
@@ -553,7 +554,7 @@ Common::Error AdlEngine::run() {
_display->setMode(DISPLAY_MODE_MIXED);
- while (1) {
+ while (!_isQuitting) {
uint verb = 0, noun = 0;
_isRestarting = false;
@@ -1101,7 +1102,13 @@ int AdlEngine::o1_quit(ScriptEnv &e) {
OP_DEBUG_0("\tQUIT_GAME()");
printMessage(_messageIds.thanksForPlaying);
- quitGame();
+ // Wait for a key here to ensure that the user gets a chance
+ // to read the thank-you message
+ _display->printAsciiString("PRESS ANY KEY TO QUIT");
+ inputKey();
+
+ // We use _isRestarting to abort the current game loop iteration
+ _isQuitting = _isRestarting = true;
return -1;
}
diff --git a/engines/adl/adl.h b/engines/adl/adl.h
index 971336ef50..fc696f074f 100644
--- a/engines/adl/adl.h
+++ b/engines/adl/adl.h
@@ -359,7 +359,7 @@ protected:
// Game state
State _state;
- bool _isRestarting, _isRestoring;
+ bool _isRestarting, _isRestoring, _isQuitting;
bool _skipOneCommand;
private:
diff --git a/engines/adl/adl_v2.cpp b/engines/adl/adl_v2.cpp
index 979d794146..45810d64ca 100644
--- a/engines/adl/adl_v2.cpp
+++ b/engines/adl/adl_v2.cpp
@@ -182,8 +182,8 @@ Common::String AdlEngine_v2::loadMessage(uint idx) const {
void AdlEngine_v2::printString(const Common::String &str) {
Common::String s(str);
- byte endPos = TEXT_WIDTH - 1;
- byte pos = 0;
+ uint endPos = TEXT_WIDTH - 1;
+ uint pos = 0;
while (true) {
while (pos <= endPos && pos != s.size()) {
diff --git a/engines/bladerunner/actor_clues.cpp b/engines/bladerunner/actor_clues.cpp
index a84d54906b..f9a4389b71 100644
--- a/engines/bladerunner/actor_clues.cpp
+++ b/engines/bladerunner/actor_clues.cpp
@@ -67,9 +67,7 @@ ActorClues::ActorClues(BladeRunnerEngine *vm, int cluesType) {
}
ActorClues::~ActorClues() {
- if (_clues) {
- delete[] _clues;
- }
+ delete[] _clues;
_maxCount = 0;
_count = 0;
@@ -78,7 +76,7 @@ ActorClues::~ActorClues() {
void ActorClues::acquire(int clueId, char flag2, int fromActorId) {
int clueIndex = findClueIndex(clueId);
_clues[clueIndex]._flags |= 0x01;
- _clues[_count]._flags = (_clues[_count]._flags & ~0x02) | ((flag2 << 1) & 0x02);
+ _clues[clueIndex]._flags = (_clues[clueIndex]._flags & ~0x02) | ((flag2 << 1) & 0x02);
_clues[clueIndex]._fromActorId = fromActorId;
debug("Actor acquired clue: \"%s\" from %d", _vm->_crimesDatabase->getClueText(clueId), fromActorId);
diff --git a/engines/bladerunner/bladerunner.cpp b/engines/bladerunner/bladerunner.cpp
index 33110c07de..e60fe77d26 100644
--- a/engines/bladerunner/bladerunner.cpp
+++ b/engines/bladerunner/bladerunner.cpp
@@ -457,6 +457,8 @@ void BladeRunnerEngine::shutdown() {
// TODO: Delete sine and cosine lookup tables
// TODO: Unload AI dll
+ delete _aiScripts;
+ _aiScripts = nullptr;
delete[] _gameVars;
_gameVars = nullptr;
@@ -481,7 +483,12 @@ void BladeRunnerEngine::shutdown() {
// TODO: Delete datetime - not used
- // TODO: Delete actors
+ int actorCount = (int)_gameInfo->getActorCount();
+ for (int i = 0; i != actorCount; ++i) {
+ delete _actors[i];
+ _actors[i] = nullptr;
+ }
+ _playerActor = nullptr;
// TODO: Delete proper ZBuf class
delete[] _zBuffer1;
diff --git a/engines/bladerunner/light.cpp b/engines/bladerunner/light.cpp
index 08eb8ab5be..8be8d0112b 100644
--- a/engines/bladerunner/light.cpp
+++ b/engines/bladerunner/light.cpp
@@ -27,9 +27,13 @@
namespace BladeRunner {
Light::Light() {
+ _animationData = nullptr;
}
Light::~Light() {
+ if (_animationData != nullptr) {
+ delete[] _animationData;
+ }
}
void Light::read(Common::ReadStream *stream, int framesCount, int frame, int animated) {
@@ -43,6 +47,9 @@ void Light::read(Common::ReadStream *stream, int framesCount, int frame, int ani
_animatedParameters = stream->readUint32LE();
+ if (_animationData != nullptr) {
+ delete[] _animationData;
+ }
int floatsCount = size / 4;
_animationData = new float[floatsCount];
for (int i = 0; i < floatsCount; i++) {
@@ -80,6 +87,10 @@ void Light::readVqa(Common::ReadStream *stream, int framesCount, int frame, int
int size = stream->readUint32LE();
+ if(_animationData != nullptr) {
+ delete[] _animationData;
+ }
+
int floatsCount = size / 4;
_animationData = new float[floatsCount];
for (int i = 0; i < floatsCount; i++) {
diff --git a/engines/bladerunner/scene.cpp b/engines/bladerunner/scene.cpp
index a629b4263b..c29a6345cc 100644
--- a/engines/bladerunner/scene.cpp
+++ b/engines/bladerunner/scene.cpp
@@ -29,6 +29,7 @@
#include "bladerunner/chapters.h"
#include "bladerunner/gameinfo.h"
#include "bladerunner/items.h"
+#include "bladerunner/settings.h"
#include "bladerunner/scene_objects.h"
#include "bladerunner/script/script.h"
#include "bladerunner/slice_renderer.h"
@@ -56,8 +57,8 @@ bool Scene::open(int setId, int sceneId, bool isLoadingGame) {
// TODO: Clear regions
// TODO: Destroy all overlays
_defaultLoop = 0;
- _defaultLoopSet = 0;
- _field_20_loop_stuff = 0;
+ _defaultLoopSet = false;
+ _specialLoopAtEnd = false;
_specialLoopMode = -1;
_specialLoop = -1;
_frame = -1;
@@ -76,9 +77,6 @@ bool Scene::open(int setId, int sceneId, bool isLoadingGame) {
_vqaPlayer = new VQAPlayer(_vm);
- if (!_vqaPlayer->open(vqaName))
- return false;
-
Common::String sceneName = _vm->_gameInfo->getSceneName(sceneId);
if (!_vm->_script->open(sceneName))
return false;
@@ -99,8 +97,15 @@ bool Scene::open(int setId, int sceneId, bool isLoadingGame) {
return true;
}
- // TODO: set VQADecoder parameters
- //_vm->_scene->advanceFrame(0, 0);
+ if (!_vqaPlayer->open(vqaName))
+ return false;
+
+ if (_specialLoop == -1) {
+ _vqaPlayer->setLoop(_defaultLoop, -1, 2, nullptr, nullptr);
+ _defaultLoopSet = true;
+ _specialLoopAtEnd = false;
+ }
+ _vm->_scene->advanceFrame(_vm->_surface1, _vm->_zBuffer1);
_vm->_playerActor->setAtXYZ(_actorStartPosition, _actorStartFacing);
//_vm->_playerActor->setSetId(setId);
@@ -148,6 +153,7 @@ bool Scene::close(bool isLoadingGame) {
if (isLoadingGame) {
_vm->_script->PlayerWalkedOut();
}
+
// if (SceneScript_isLoaded() && !SceneScript_unload()) {
// result = false;
// }
@@ -171,18 +177,26 @@ int Scene::advanceFrame(Graphics::Surface &surface, uint16 *&zBuffer) {
_vqaPlayer->updateLights(_vm->_lights);
}
- if (frame < 0) {
- return frame;
+ if (_specialLoopMode && _specialLoopMode != 2 && _specialLoopMode != 3) {
+ if (_specialLoopMode == 1) {
+ if (frame == -3) { // TODO: when will this happen? bad data in/eof of vqa
+ _vm->_settings->setNewSetAndScene(_nextSetId, _nextSceneId);
+ _vm->playerGainsControl();
+ }
+ } else if (!_specialLoopAtEnd) {
+ _vqaPlayer->setLoop(_defaultLoop + 1, -1, 0, &Scene::loopEndedStatic, this);
+ _specialLoopAtEnd = true;
+ }
+ } else if (!this->_defaultLoopSet) {
+ _vqaPlayer->setLoop(_defaultLoop, -1, 1, &Scene::loopEndedStatic, this);
+ _defaultLoopSet = true;
+ if (_specialLoopMode == 0) {
+ _vm->playerLosesControl();
+ }
}
- _frame = frame;
- if (_specialLoopMode == 0 && frame == _vqaPlayer->getLoopEndFrame(_specialLoop)) {
- _playerWalkedIn = true;
- _specialLoopMode = -1;
- }
- if (_specialLoopMode == 0 && !_defaultLoopSet) {
- _vqaPlayer->setLoop(_defaultLoop + 1);
- _defaultLoopSet = true;
+ if (frame >= 0) {
+ _frame = frame;
}
return frame;
@@ -193,25 +207,32 @@ void Scene::setActorStart(Vector3 position, int facing) {
_actorStartFacing = facing;
}
-void Scene::loopSetDefault(int a) {
- // warning("\t\t\tScene::loopSetDefault(%d)", a);
- _defaultLoop = a;
+void Scene::loopSetDefault(int loopId) {
+ _defaultLoop = loopId;
}
-void Scene::loopStartSpecial(int a, int b, int c) {
- // warning("\t\t\tScene::loopStartSpecial(%d, %d, %d)", a, b, c);
- _specialLoopMode = a;
- _specialLoop = b;
+void Scene::loopStartSpecial(int specialLoopMode, int loopId, int flags) {
+ _specialLoopMode = specialLoopMode;
+ _specialLoop = loopId;
- if (_specialLoop == 1) {
- // a1->on_loop_end_switch_to_set_id = sub_42BE08_options_get_set_enter_arg_1(&unk_48E910_options);
- // a1->on_loop_end_switch_to_scene_id = sub_42BE00_options_get_set_enter_arg_2(&unk_48E910_options);
+ int unknown = -1;
+ if (_specialLoopMode == 1) {
+ unknown = 0;
}
- if (c) {
- // _field_20_loop_stuff = 1;
- // v6 = a1->_field_28_loop_special_loop_number;
- // sub_453434_scene_method_loop(a1);
+ int loopMode = 1;
+ if (flags) {
+ loopMode = 2;
+ }
+
+ _vqaPlayer->setLoop(_specialLoop, unknown, loopMode, &Scene::loopEndedStatic, this);
+ if (_specialLoopMode == 1) {
+ this->_nextSetId = _vm->_settings->getNewSet();
+ this->_nextSceneId = _vm->_settings->getNewScene();
+ }
+ if (flags) {
+ this->_specialLoopAtEnd = true;
+ loopEnded(0, _specialLoop);
}
}
@@ -265,4 +286,37 @@ const char *Scene::objectGetName(int objectId) {
return _set->objectGetName(objectId);
}
+void Scene::loopEnded(int frame, int loopId) {
+ if (_specialLoopMode && _specialLoopMode != 2 && _specialLoopMode != 3) {
+ if (_specialLoopMode == 1) {
+ _defaultLoopSet = true;
+ _specialLoopAtEnd = false;
+ _vm->playerLosesControl();
+ }
+ } else if (_specialLoopAtEnd) {
+ _vqaPlayer->setLoop(_defaultLoop, -1, 1, &Scene::loopEndedStatic, this);
+ _defaultLoopSet = true;
+ _specialLoopAtEnd = false;
+ if (_specialLoopMode == 0) {
+ _vm->playerLosesControl();
+ }
+ } else {
+ if (_specialLoopMode == 0) {
+ _vm->playerGainsControl();
+ _playerWalkedIn = true;
+ }
+ if (_specialLoopMode == 3) {
+ //TODO:
+ //spinner::open(Spinner);
+ }
+ _specialLoopMode = -1;
+ _specialLoop = -1;
+ _vqaPlayer->setLoop(_defaultLoop + 1, -1, 0, nullptr, nullptr);
+ _specialLoopAtEnd = true;
+ }
+}
+
+void Scene::loopEndedStatic(void *data, int frame, int loopId) {
+ ((Scene*)data)->loopEnded(frame, loopId);
+}
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/scene.h b/engines/bladerunner/scene.h
index 6a34fcd249..5bc25fc6fc 100644
--- a/engines/bladerunner/scene.h
+++ b/engines/bladerunner/scene.h
@@ -44,10 +44,10 @@ public:
VQAPlayer *_vqaPlayer;
int _defaultLoop;
- int _defaultLoopSet;
- int _field_20_loop_stuff;
+ bool _defaultLoopSet;
int _specialLoopMode;
int _specialLoop;
+ bool _specialLoopAtEnd;
int _introFinished;
int _nextSetId;
int _nextSceneId;
@@ -83,9 +83,7 @@ public:
delete _set;
delete _regions;
delete _exits;
- if (_vqaPlayer != nullptr) {
- delete _vqaPlayer;
- }
+ delete _vqaPlayer;
}
bool open(int setId, int sceneId, bool isLoadingGame);
@@ -109,6 +107,10 @@ public:
void objectSetIsObstacleAll(bool isObstacle, bool sceneLoaded);
void objectSetIsTarget(int objectId, bool isTarget, bool sceneLoaded);
const char *objectGetName(int objectId);
+
+private:
+ void loopEnded(int frame, int loopId);
+ static void loopEndedStatic(void* data, int frame, int loopId);
};
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/scene_objects.cpp b/engines/bladerunner/scene_objects.cpp
index 6d10edd83f..c55097358d 100644
--- a/engines/bladerunner/scene_objects.cpp
+++ b/engines/bladerunner/scene_objects.cpp
@@ -65,6 +65,7 @@ void SceneObjects::clear() {
_sceneObjects[i]._isMoving = 0;
_sceneObjects[i]._isRetired = 0;
}
+ _count = 0;
}
bool SceneObjects::addActor(int sceneObjectId, BoundingBox *boundingBox, Common::Rect *screenRectangle, uint8 isClickable, uint8 isMoving, uint8 isTarget, uint8 isRetired) {
@@ -207,7 +208,7 @@ bool SceneObjects::addSceneObject(int sceneObjectId, SceneObjectType sceneObject
break;
}
}
- for (int j = _count - 1; j >= i; --j) {
+ for (int j = _count - 2; j >= i; --j) {
_sceneObjectsSortedByDistance[j + 1] = _sceneObjectsSortedByDistance[j];
}
diff --git a/engines/bladerunner/script/script.cpp b/engines/bladerunner/script/script.cpp
index b0bb638440..45b23120d5 100644
--- a/engines/bladerunner/script/script.cpp
+++ b/engines/bladerunner/script/script.cpp
@@ -55,14 +55,12 @@ namespace BladeRunner {
bool Script::open(const Common::String &name) {
delete _currentScript;
-
if (name == "RC01") { _currentScript = new ScriptRC01(_vm); return true; }
if (name == "RC02") { _currentScript = new ScriptRC02(_vm); return true; }
if (name == "RC03") { _currentScript = new ScriptRC03(_vm); return true; }
if (name == "RC04") { _currentScript = new ScriptRC04(_vm); return true; }
if (name == "RC51") { _currentScript = new ScriptRC51(_vm); return true; }
-
return false;
}
@@ -916,18 +914,18 @@ void ScriptBase::Overlay_Remove(const char *overlay) {
warning("Overlay_Remove(%s)", overlay);
}
-void ScriptBase::Scene_Loop_Set_Default(int a) {
- // debug("Scene_Loop_Set_Default(%d)", a);
-
- _vm->_scene->loopSetDefault(a);
- // _vm->_scene->_defaultLoop = a;
+void ScriptBase::Scene_Loop_Set_Default(int loopId) {
+ _vm->_scene->loopSetDefault(loopId);
}
-void ScriptBase::Scene_Loop_Start_Special(int a, int b, int c) {
- // debug("Scene_Loop_Start_Special(%d, %d, %d)", a, b, c);
-
- _vm->_scene->loopStartSpecial(a, b, c);
- // _vm->_scene->_field_24_loop_start_special_param_1 = a;
+void ScriptBase::Scene_Loop_Start_Special(int sceneLoopMode, int loopId, int c) {
+ if (sceneLoopMode == 1) {
+ c = 1;
+ }
+ _vm->_scene->loopStartSpecial(sceneLoopMode, loopId, c);
+ if (sceneLoopMode == 1) {
+ _vm->_settings->clearNewSetAndScene();
+ }
}
void ScriptBase::Outtake_Play(int id, int noLocalization, int container) {
@@ -1427,12 +1425,19 @@ void ScriptBase::VK_Play_Speech_Line(int actorIndex, int a2, float a3) {
AIScripts::AIScripts(BladeRunnerEngine *vm) : _vm(vm), _inScriptCounter(0) {
for (int i = 0; i != 100; ++i)
- _AIScripts[i] = 0;
+ _AIScripts[i] = nullptr;
_AIScripts[0] = new AIScript_McCoy(_vm);
_AIScripts[23] = new AIScript_Officer_Leroy(_vm);
}
+AIScripts::~AIScripts() {
+ for (int i = 0; i != 100; ++i) {
+ delete _AIScripts[i];
+ _AIScripts[i] = nullptr;
+ }
+}
+
void AIScripts::Initialize(int actor) {
if (_AIScripts[actor])
_AIScripts[actor]->Initialize();
diff --git a/engines/bladerunner/set_effects.cpp b/engines/bladerunner/set_effects.cpp
index 54894e2a1c..c4038f6726 100644
--- a/engines/bladerunner/set_effects.cpp
+++ b/engines/bladerunner/set_effects.cpp
@@ -38,7 +38,7 @@ SetEffects::SetEffects(BladeRunnerEngine *vm) {
_fadeDensity = 0.0f;
_fogsCount = 0;
- _fogs = NULL;
+ _fogs = nullptr;
}
SetEffects::~SetEffects() {
@@ -55,7 +55,7 @@ void SetEffects::read(Common::ReadStream *stream, int framesCount) {
int i;
for (i = 0; i < _fogsCount; i++) {
int type = stream->readUint32LE();
- Fog *fog = NULL;
+ Fog *fog = nullptr;
switch (type) {
case 0:
fog = new FogCone();
diff --git a/engines/bladerunner/vqa_decoder.cpp b/engines/bladerunner/vqa_decoder.cpp
index 940f53ee25..fe94012c51 100644
--- a/engines/bladerunner/vqa_decoder.cpp
+++ b/engines/bladerunner/vqa_decoder.cpp
@@ -34,8 +34,6 @@
#include "common/util.h"
#include "common/memstream.h"
-
-
namespace BladeRunner {
#define kAESC 0x41455343
@@ -488,7 +486,7 @@ bool VQADecoder::readLNIN(Common::SeekableReadStream *s, uint32 size) {
if (chd.id != kLNIO || chd.size != 4u * loopNamesCount)
return false;
- uint32 *loopNameOffsets = (uint32*)alloca(loopNamesCount * sizeof(uint32));
+ uint32 *loopNameOffsets = (uint32*)malloc(loopNamesCount * sizeof(uint32));
for (int i = 0; i != loopNamesCount; ++i) {
loopNameOffsets[i] = s->readUint32LE();
}
@@ -497,7 +495,7 @@ bool VQADecoder::readLNIN(Common::SeekableReadStream *s, uint32 size) {
if (chd.id != kLNID)
return false;
- char *names = (char*)alloca(roundup(chd.size));
+ char *names = (char*)malloc(roundup(chd.size));
s->read(names, roundup(chd.size));
for (int i = 0; i != loopNamesCount; ++i) {
@@ -509,6 +507,8 @@ bool VQADecoder::readLNIN(Common::SeekableReadStream *s, uint32 size) {
// debug("%2d: %s", i, _loopInfo.loops[i].name.c_str());
}
+ free(loopNameOffsets);
+ free(names);
return true;
}
diff --git a/engines/bladerunner/vqa_player.cpp b/engines/bladerunner/vqa_player.cpp
index f875b84cce..4fb19cf561 100644
--- a/engines/bladerunner/vqa_player.cpp
+++ b/engines/bladerunner/vqa_player.cpp
@@ -121,7 +121,7 @@ void VQAPlayer::updateLights(Lights *lights) {
_decoder.decodeLights(lights);
}
-bool VQAPlayer::setLoop(int loop) {
+bool VQAPlayer::setLoop(int loop, int unknown, int loopMode, void(*callback)(void*, int, int), void *callbackData) {
int begin, end;
if (!_decoder.getLoopBeginAndEndFrame(loop, &begin, &end)) {
return false;
@@ -131,6 +131,9 @@ bool VQAPlayer::setLoop(int loop) {
_loopBegin = begin;
_loopEnd = end;
+ _callbackLoopEnded = callback;
+ _callbackData = callbackData;
+
// warning("\t\t\tActive Loop: %d - %d\n", begin, end);
return true;
@@ -158,6 +161,9 @@ int VQAPlayer::calcNextFrame(int frame) const {
if (_curLoop != -1 && frame >= _loopEnd) {
frame = _loopBegin;
+ if (_callbackLoopEnded != nullptr) {
+ _callbackLoopEnded(_callbackData, 0, _curLoop);
+ }
} else {
frame++;
}
diff --git a/engines/bladerunner/vqa_player.h b/engines/bladerunner/vqa_player.h
index f5769944cf..3a821a8323 100644
--- a/engines/bladerunner/vqa_player.h
+++ b/engines/bladerunner/vqa_player.h
@@ -55,6 +55,9 @@ class VQAPlayer {
bool _audioStarted;
Audio::SoundHandle _soundHandle;
+ void (*_callbackLoopEnded)(void*, int frame, int loopId);
+ void *_callbackData;
+
public:
VQAPlayer(BladeRunnerEngine *vm)
@@ -69,7 +72,8 @@ public:
_loopEnd(-1),
_nextFrameTime(0),
_hasAudio(false),
- _audioStarted(false) {
+ _audioStarted(false),
+ _callbackLoopEnded(nullptr) {
}
~VQAPlayer() {
@@ -85,9 +89,7 @@ public:
void updateView(View *view);
void updateLights(Lights *lights);
- bool setLoop(int loop);
- // void setLoopSpecial(int loop, bool wait);
- // void setLoopDefault(int loop);
+ bool setLoop(int loop, int unknown, int loopMode, void(*callback)(void*, int, int), void* callbackData);
int getLoopBeginFrame(int loop);
int getLoopEndFrame(int loop);
diff --git a/engines/chewy/detection.cpp b/engines/chewy/detection.cpp
index a59355f166..f6f66efba0 100644
--- a/engines/chewy/detection.cpp
+++ b/engines/chewy/detection.cpp
@@ -73,8 +73,9 @@ static const ChewyGameDescription gameDescriptions[] = {
{
// Chewy - ESC von F5 - German
+ // Master version 1.1 (CHEWY.EXE - offset 0x8AB28)
// The source CD-ROM has the Matrix code SONOPRESS R-7885 B
- // Most likely a newer re-release, it contains several demos and files from 1996
+ // The disc contains several demos and files from 1996
// Provided by rootfather
{
"chewy",
@@ -89,6 +90,7 @@ static const ChewyGameDescription gameDescriptions[] = {
{
// Chewy - ESC von F5 - German
+ // Master version 1.0 (CHEWY.EXE - offset 0x8AB10)
// The source CD-ROM has the Matrix code SONOPRESS M-2742 A
// CD-ROM has the label "CHEWY_V1_0"
// Provided by rootfather
diff --git a/engines/composer/composer.cpp b/engines/composer/composer.cpp
index 73d97e100d..13ba76191b 100644
--- a/engines/composer/composer.cpp
+++ b/engines/composer/composer.cpp
@@ -21,6 +21,7 @@
*/
#include "common/scummsys.h"
+#include "common/config-manager.h"
#include "common/events.h"
#include "common/random.h"
#include "common/keyboard.h"
@@ -120,6 +121,9 @@ Common::Error ComposerEngine::run() {
else
warning("FPS in book.ini is zero. Defaulting to 8...");
uint32 lastDrawTime = 0;
+ _lastSaveTime = _system->getMillis();
+
+ bool loadFromLauncher = ConfMan.hasKey("save_slot");
while (!shouldQuit()) {
for (uint i = 0; i < _pendingPageChanges.size(); i++) {
@@ -169,7 +173,12 @@ Common::Error ComposerEngine::run() {
} else if (_needsUpdate) {
redraw();
}
-
+ if (loadFromLauncher) {
+ loadGameState(ConfMan.getInt("save_slot"));
+ loadFromLauncher = false;
+ }
+ if (shouldPerformAutoSave(_lastSaveTime))
+ saveGameState(0, "Autosave");
while (_eventMan->pollEvent(event)) {
switch (event.type) {
case Common::EVENT_LBUTTONDOWN:
@@ -378,7 +387,7 @@ void ComposerEngine::loadLibrary(uint id) {
}
Common::String filename;
-
+ Common::String oldGroup = _bookGroup;
if (getGameType() == GType_ComposerV1) {
if (!id || _bookGroup.empty())
filename = getStringFromConfig("Common", "StartPage");
@@ -412,6 +421,7 @@ void ComposerEngine::loadLibrary(uint id) {
Library library;
library._id = id;
+ library._group = oldGroup;
library._archive = new ComposerArchive();
if (!library._archive->openFile(filename))
error("failed to open '%s'", filename.c_str());
diff --git a/engines/composer/composer.h b/engines/composer/composer.h
index d1a85e975a..a4b421bfa0 100644
--- a/engines/composer/composer.h
+++ b/engines/composer/composer.h
@@ -29,6 +29,7 @@
#include "common/debug.h"
#include "common/debug-channels.h"
#include "common/error.h"
+#include "common/serializer.h"
#include "common/textconsole.h"
#include "common/rect.h"
@@ -114,6 +115,7 @@ struct Library {
uint _id;
Archive *_archive;
+ Common::String _group;
Common::List<Button> _buttons;
Common::List<KeyboardHandler> _keyboardHandlers;
};
@@ -150,6 +152,19 @@ class ComposerEngine : public Engine {
protected:
Common::Error run();
+ template <typename T>
+ void syncArray(Common::Serializer &ser, Common::Array<T> &data, Common::Serializer::Version minVersion = 0, Common::Serializer::Version maxVersion = Common::Serializer::kLastVersion);
+ template <typename T>
+ void syncList(Common::Serializer &ser, Common::List<T> &data, Common::Serializer::Version minVersion = 0, Common::Serializer::Version maxVersion = Common::Serializer::kLastVersion);
+ template <typename T>
+ void syncListReverse(Common::Serializer &ser, Common::List<T> &data, Common::Serializer::Version minVersion = 0, Common::Serializer::Version maxVersion = Common::Serializer::kLastVersion);
+ template <typename T>
+ void sync(Common::Serializer &ser, T &data, Common::Serializer::Version minVersion, Common::Serializer::Version maxVersion);
+ bool canLoadGameStateCurrently() { return true; }
+ Common::Error loadGameState(int slot);
+ bool canSaveGameStateCurrently() { return true; }
+ Common::Error saveGameState(int slot, const Common::String &desc);
+
public:
ComposerEngine(OSystem *syst, const ComposerGameDescription *gameDesc);
virtual ~ComposerEngine();
@@ -173,7 +188,7 @@ private:
Audio::QueuingAudioStream *_audioStream;
uint16 _currSoundPriority;
- uint32 _currentTime, _lastTime;
+ uint32 _currentTime, _lastTime, _timeDelta, _lastSaveTime;
bool _needsUpdate;
Common::Array<Common::Rect> _dirtyRects;
@@ -210,6 +225,7 @@ private:
uint16 _mouseSpriteId;
Common::Point _mouseOffset;
+ Common::String makeSaveGameName(int slot);
Common::String getStringFromConfig(const Common::String &section, const Common::String &key);
Common::String getFilename(const Common::String &section, uint id);
Common::String mangleFilename(Common::String filename);
@@ -231,6 +247,7 @@ private:
void tickOldScripts();
bool tickOldScript(OldScript *script);
+ void loadAnimation(Animation *&anim, uint16 animId, int16 x, int16 y, int16 eventParam, int32 size = 0);
void playAnimation(uint16 animId, int16 param1, int16 param2, int16 param3);
void stopAnimation(Animation *anim, bool localOnly = false, bool pipesOnly = false);
void playWaveForAnim(uint16 id, uint16 priority, bool bufferingOnly);
diff --git a/engines/composer/detection.cpp b/engines/composer/detection.cpp
index 689a72a743..8de3b33134 100644
--- a/engines/composer/detection.cpp
+++ b/engines/composer/detection.cpp
@@ -21,6 +21,9 @@
*/
#include "base/plugins.h"
+#include "common/savefile.h"
+#include "common/serializer.h"
+#include "common/str-array.h"
#include "engines/advancedDetector.h"
#include "composer/composer.h"
@@ -448,6 +451,8 @@ public:
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
virtual bool hasFeature(MetaEngineFeature f) const;
+ virtual int getMaximumSaveSlot() const;
+ virtual SaveStateList listSaves(const char* target) const;
};
bool ComposerMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
@@ -459,11 +464,52 @@ bool ComposerMetaEngine::createInstance(OSystem *syst, Engine **engine, const AD
}
bool ComposerMetaEngine::hasFeature(MetaEngineFeature f) const {
- return false;
+ return ((f == kSupportsListSaves) || (f == kSupportsLoadingDuringStartup));
+}
+
+Common::String getSaveName(Common::InSaveFile *in) {
+ Common::Serializer ser(in, NULL);
+ Common::String name;
+ uint32 tmp;
+ ser.syncAsUint32LE(tmp);
+ ser.syncAsUint32LE(tmp);
+ ser.syncString(name);
+ return name;
+}
+int ComposerMetaEngine::getMaximumSaveSlot() const {
+ return 99;
+}
+SaveStateList ComposerMetaEngine::listSaves(const char *target) const {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Common::StringArray filenames;
+ Common::String saveDesc;
+ Common::String pattern = Common::String::format("%s.??", target);
+
+ filenames = saveFileMan->listSavefiles(pattern);
+ sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
+
+ SaveStateList saveList;
+ for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
+ // Obtain the last 3 digits of the filename, since they correspond to the save slot
+ int slotNum = atoi(file->c_str() + file->size() - 2);
+
+ if (slotNum >= 0 && slotNum <= 99) {
+ Common::InSaveFile *in = saveFileMan->openForLoading(*file);
+ if (in) {
+ saveDesc = getSaveName(in);
+ saveList.push_back(SaveStateDescriptor(slotNum, saveDesc));
+ delete in;
+ }
+ }
+ }
+
+ return saveList;
}
bool Composer::ComposerEngine::hasFeature(EngineFeature f) const {
- return (f == kSupportsRTL);
+ return (f == kSupportsRTL
+ || f == kSupportsSavingDuringRuntime
+ || f == kSupportsLoadingDuringRuntime);
}
#if PLUGIN_ENABLED_DYNAMIC(COMPOSER)
diff --git a/engines/composer/graphics.cpp b/engines/composer/graphics.cpp
index 87694636d8..32b9812f32 100644
--- a/engines/composer/graphics.cpp
+++ b/engines/composer/graphics.cpp
@@ -44,9 +44,9 @@ bool Sprite::contains(const Common::Point &pos) const {
}
enum {
- kAnimOpEvent = 1,
- kAnimOpPlayWave = 2,
- kAnimOpPlayAnim = 3,
+ kAnimOpEvent = 1,
+ kAnimOpPlayWave = 2,
+ kAnimOpPlayAnim = 3,
kAnimOpDrawSprite = 4
};
@@ -57,6 +57,7 @@ Animation::Animation(Common::SeekableReadStream *stream, uint16 id, Common::Poin
// probably total size?
uint32 unknown = _stream->readUint32LE();
+ _size = unknown;
debug(8, "anim: size %d, state %08x, unknown %08x", size, _state, unknown);
@@ -82,17 +83,7 @@ void Animation::seekToCurrPos() {
_stream->seek(_offset, SEEK_SET);
}
-void ComposerEngine::playAnimation(uint16 animId, int16 x, int16 y, int16 eventParam) {
- // First, we check if this animation is already playing,
- // and if it is, we sabotage that running one first.
- for (Common::List<Animation *>::iterator i = _anims.begin(); i != _anims.end(); i++) {
- Animation *anim = *i;
- if (anim->_id != animId)
- continue;
-
- stopAnimation(*i);
- }
-
+void ComposerEngine::loadAnimation(Animation *&anim, uint16 animId, int16 x, int16 y, int16 eventParam, int32 size) {
Common::SeekableReadStream *stream = NULL;
Pipe *newPipe = NULL;
@@ -102,7 +93,10 @@ void ComposerEngine::playAnimation(uint16 animId, int16 x, int16 y, int16 eventP
if (!pipe->hasResource(ID_ANIM, animId))
continue;
stream = pipe->getResource(ID_ANIM, animId, false);
- break;
+
+ // When loading from savegame, make sure we have the correct stream
+ if ((!size) || (stream->size() >= size)) break;
+ stream = NULL;
}
// If we didn't find it, try the libraries.
@@ -111,33 +105,50 @@ void ComposerEngine::playAnimation(uint16 animId, int16 x, int16 y, int16 eventP
warning("ignoring attempt to play invalid anim %d", animId);
return;
}
- stream = getResource(ID_ANIM, animId);
+ Common::List<Library>::iterator j;
+ for (j = _libraries.begin(); j != _libraries.end(); j++) {
+ stream = j->_archive->getResource(ID_ANIM, animId);
- uint32 type = 0;
- for (Common::List<Library>::iterator i = _libraries.begin(); i != _libraries.end(); i++)
- if (i->_archive->hasResource(ID_ANIM, animId)) {
- type = i->_archive->getResourceFlags(ID_ANIM, animId);
- break;
- }
+ // When loading from savegame, make sure we have the correct stream
+ if ((!size) || (stream->size() >= size)) break;
+ stream = NULL;
+ }
+
+ uint32 type = j->_archive->getResourceFlags(ID_ANIM, animId);
// If the resource is a pipe itself, then load the pipe
// and then fish the requested animation out of it.
if (type != 1) {
_pipeStreams.push_back(stream);
- newPipe = new Pipe(stream);
+ newPipe = new Pipe(stream, animId);
_pipes.push_front(newPipe);
newPipe->nextFrame();
stream = newPipe->getResource(ID_ANIM, animId, false);
}
}
- Animation *anim = new Animation(stream, animId, Common::Point(x, y), eventParam);
- _anims.push_back(anim);
- runEvent(kEventAnimStarted, animId, eventParam, 0);
+ anim = new Animation(stream, animId, Common::Point(x, y), eventParam);
if (newPipe)
newPipe->_anim = anim;
}
+void ComposerEngine::playAnimation(uint16 animId, int16 x, int16 y, int16 eventParam) {
+ // First, we check if this animation is already playing,
+ // and if it is, we sabotage that running one first.
+ for (Common::List<Animation *>::iterator i = _anims.begin(); i != _anims.end(); i++) {
+ Animation *anim = *i;
+ if (anim->_id != animId)
+ continue;
+
+ stopAnimation(*i);
+ }
+
+ Animation *anim = NULL;
+ loadAnimation(anim, animId, x, y, eventParam);
+ _anims.push_back(anim);
+ runEvent(kEventAnimStarted, animId, eventParam, 0);
+}
+
void ComposerEngine::stopAnimation(Animation *anim, bool localOnly, bool pipesOnly) {
// disable the animation
anim->_state = 0;
@@ -376,7 +387,7 @@ void ComposerEngine::playPipe(uint16 id) {
}
Common::SeekableReadStream *stream = getResource(ID_PIPE, id);
- OldPipe *pipe = new OldPipe(stream);
+ OldPipe *pipe = new OldPipe(stream, id);
_pipes.push_front(pipe);
//pipe->nextFrame();
diff --git a/engines/composer/graphics.h b/engines/composer/graphics.h
index a8f37ddf60..4805e5017d 100644
--- a/engines/composer/graphics.h
+++ b/engines/composer/graphics.h
@@ -59,6 +59,7 @@ struct Animation {
uint32 _eventParam;
uint32 _state;
+ uint32 _size;
Common::Array<AnimationEntry> _entries;
diff --git a/engines/composer/module.mk b/engines/composer/module.mk
index c879d53630..74465cf156 100644
--- a/engines/composer/module.mk
+++ b/engines/composer/module.mk
@@ -6,6 +6,7 @@ MODULE_OBJS = \
detection.o \
graphics.o \
resource.o \
+ saveload.o \
scripting.o
# This module can be built as a plugin
diff --git a/engines/composer/resource.cpp b/engines/composer/resource.cpp
index d867f734a9..fa1811c05a 100644
--- a/engines/composer/resource.cpp
+++ b/engines/composer/resource.cpp
@@ -248,10 +248,11 @@ bool ComposerArchive::openStream(Common::SeekableReadStream *stream) {
return true;
}
-Pipe::Pipe(Common::SeekableReadStream *stream) {
+Pipe::Pipe(Common::SeekableReadStream *stream, uint16 id) {
_offset = 0;
_stream = stream;
_anim = NULL;
+ _pipeId = id;
}
Pipe::~Pipe() {
@@ -312,8 +313,14 @@ Common::SeekableReadStream *Pipe::getResource(uint32 tag, uint16 id, bool buffer
if (res.entries.size() == 1) {
Common::SeekableReadStream *stream = new Common::SeekableSubReadStream(_stream,
res.entries[0].offset, res.entries[0].offset + res.entries[0].size);
- if (buffering)
+ if (buffering) {
_types[tag].erase(id);
+ bool found = false;
+ for (Common::List<uint16>::const_iterator i = _bufferedResources[tag].begin(); !found && (i != _bufferedResources[tag].end()); i++)
+ if ((*i) == id) found = true;
+ if (!found)
+ _bufferedResources[tag].push_back(id);
+ }
return stream;
}
@@ -330,12 +337,18 @@ Common::SeekableReadStream *Pipe::getResource(uint32 tag, uint16 id, bool buffer
_stream->read(buffer + offset, res.entries[i].size);
offset += res.entries[i].size;
}
- if (buffering)
+ if (buffering) {
_types[tag].erase(id);
+ bool found = false;
+ for (Common::List<uint16>::const_iterator i = _bufferedResources[tag].begin(); !found && (i != _bufferedResources[tag].end()); i++)
+ if ((*i) == id) found = true;
+ if (!found)
+ _bufferedResources[tag].push_back(id);
+ }
return new Common::MemoryReadStream(buffer, size, DisposeAfterUse::YES);
}
-OldPipe::OldPipe(Common::SeekableReadStream *stream) : Pipe(stream), _currFrame(0) {
+OldPipe::OldPipe(Common::SeekableReadStream *stream, uint16 pipeId) : Pipe(stream, pipeId), _currFrame(0) {
uint32 tag = _stream->readUint32BE();
if (tag != ID_PIPE)
error("invalid tag for pipe (%08x)", tag);
diff --git a/engines/composer/resource.h b/engines/composer/resource.h
index b624da1776..fc4e20a2cd 100644
--- a/engines/composer/resource.h
+++ b/engines/composer/resource.h
@@ -106,7 +106,7 @@ struct PipeResource {
class Pipe {
public:
- Pipe(Common::SeekableReadStream *stream);
+ Pipe(Common::SeekableReadStream *stream, uint16 id);
virtual ~Pipe();
virtual void nextFrame();
@@ -116,6 +116,11 @@ public:
Common::SeekableReadStream *getResource(uint32 tag, uint16 id, bool buffering);
virtual const Common::Array<uint16> *getScripts() { return NULL; }
+ uint16 getPipeId() const { return _pipeId; }
+ virtual uint32 getOffset() const { return _offset; }
+ virtual void setOffset(uint32 offset) { while (_offset < offset) nextFrame(); }
+ typedef Common::HashMap<uint32, Common::List<uint16> > DelMap;
+ DelMap _bufferedResources;
protected:
Common::SeekableReadStream *_stream;
@@ -123,16 +128,19 @@ protected:
typedef Common::HashMap<uint16, PipeResource> ResourceMap;
typedef Common::HashMap<uint32, ResourceMap> TypeMap;
TypeMap _types;
+ uint16 _pipeId;
uint32 _offset;
};
class OldPipe : public Pipe {
public:
- OldPipe(Common::SeekableReadStream *stream);
+ OldPipe(Common::SeekableReadStream *stream, uint16 pipeId);
void nextFrame();
const Common::Array<uint16> *getScripts() { return &_scripts; }
+ uint32 getOffset() const { return _currFrame; }
+ void setOffset(uint32 offset) { while (_currFrame < offset) nextFrame(); }
protected:
uint32 _currFrame, _numFrames;
diff --git a/engines/composer/saveload.cpp b/engines/composer/saveload.cpp
new file mode 100644
index 0000000000..ea657a9dd4
--- /dev/null
+++ b/engines/composer/saveload.cpp
@@ -0,0 +1,428 @@
+/* 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 "audio/audiostream.h"
+#include "audio/decoders/raw.h"
+#include "common/config-manager.h"
+#include "common/memstream.h"
+#include "common/savefile.h"
+#include "common/serializer.h"
+#include "common/system.h"
+#include "common/zlib.h"
+#include "graphics/palette.h"
+
+#include "composer/composer.h"
+#include "composer/graphics.h"
+
+namespace Composer {
+
+template<class T>
+void ComposerEngine::syncArray(Common::Serializer &ser, Common::Array<T> &data, Common::Serializer::Version minVersion, Common::Serializer::Version maxVersion) {
+ if (ser.isSaving()) {
+ uint32 size = data.size();
+ ser.syncAsUint32LE(size, minVersion, maxVersion);
+ for (typename Common::Array<T>::iterator i = data.begin(); i != data.end(); i++) {
+ sync<T>(ser, *i, minVersion, maxVersion);
+ }
+ } else {
+ uint32 size;
+ data.clear();
+ ser.syncAsUint32LE(size, minVersion, maxVersion);
+ for (uint32 i = 0; i < size; i++) {
+ T item;
+ sync<T>(ser, item, minVersion, maxVersion);
+ data.push_back(item);
+ }
+ }
+}
+template<class T>
+void ComposerEngine::syncList(Common::Serializer &ser, Common::List<T> &data, Common::Serializer::Version minVersion, Common::Serializer::Version maxVersion) {
+ if (ser.isSaving()) {
+ uint32 size = data.size();
+ ser.syncAsUint32LE(size, minVersion, maxVersion);
+ for (typename Common::List<T>::iterator i = data.begin(); i != data.end(); i++) {
+ sync<T>(ser, *i, minVersion, maxVersion);
+ }
+ } else {
+ uint32 size;
+ data.clear();
+ ser.syncAsUint32LE(size, minVersion, maxVersion);
+ for (uint32 i = 0; i < size; i++) {
+ T item;
+ sync<T>(ser, item, minVersion, maxVersion);
+ data.push_back(item);
+ }
+ }
+}
+template<class T>
+void ComposerEngine::syncListReverse(Common::Serializer &ser, Common::List<T> &data, Common::Serializer::Version minVersion, Common::Serializer::Version maxVersion) {
+ if (ser.isSaving()) {
+ uint32 size = data.size();
+ ser.syncAsUint32LE(size, minVersion, maxVersion);
+ for (typename Common::List<T>::iterator i = data.reverse_begin(); i != data.end(); i--) {
+ sync<T>(ser, *i, minVersion, maxVersion);
+ }
+ } else {
+ uint32 size;
+ data.clear();
+ ser.syncAsUint32LE(size, minVersion, maxVersion);
+ for (uint32 i = 0; i < size; i++) {
+ T item;
+ sync<T>(ser, item, minVersion, maxVersion);
+ data.push_front(item);
+ }
+ }
+}
+template<>
+void ComposerEngine::sync<uint16>(Common::Serializer &ser, uint16 &data, Common::Serializer::Version minVersion, Common::Serializer::Version maxVersion) {
+ ser.syncAsUint16LE(data, minVersion, maxVersion);
+}
+template<>
+void ComposerEngine::sync<uint32>(Common::Serializer &ser, uint32 &data, Common::Serializer::Version minVersion, Common::Serializer::Version maxVersion) {
+ ser.syncAsUint32LE(data, minVersion, maxVersion);
+}
+template<>
+void ComposerEngine::sync<Library>(Common::Serializer &ser, Library &data, Common::Serializer::Version minVersion, Common::Serializer::Version maxVersion) {
+ if (ser.isSaving()) {
+ ser.syncAsUint16LE(data._id, minVersion, maxVersion);
+ ser.syncString(data._group, minVersion, maxVersion);
+ } else {
+ uint16 id;
+ ser.syncAsUint16LE(id, minVersion, maxVersion);
+ ser.syncString(_bookGroup, minVersion, maxVersion);
+ loadLibrary(id);
+ }
+}
+template<>
+void ComposerEngine::syncListReverse<Library>(Common::Serializer &ser, Common::List<Library> &data, Common::Serializer::Version minVersion, Common::Serializer::Version maxVersion) {
+ if (ser.isSaving()) {
+ uint32 size = data.size();
+ ser.syncAsUint32LE(size, minVersion, maxVersion);
+ for (Common::List<Library>::iterator i = data.reverse_begin(); i != data.end(); i--) {
+ sync<Library>(ser, *i, minVersion, maxVersion);
+ }
+ } else {
+ uint32 size;
+ ser.syncAsUint32LE(size, minVersion, maxVersion);
+ for (uint32 i = 0; i < size; i++) {
+ Library item;
+ sync<Library>(ser, item, minVersion, maxVersion);
+ }
+ }
+}
+template<>
+void ComposerEngine::sync<PendingPageChange>(Common::Serializer &ser, PendingPageChange &data, Common::Serializer::Version minVersion, Common::Serializer::Version maxVersion) {
+ ser.syncAsUint16LE(data._pageId, minVersion, maxVersion);
+ ser.syncAsByte(data._remove, minVersion, maxVersion);
+}
+template<>
+void ComposerEngine::sync<OldScript *>(Common::Serializer &ser, OldScript *&data, Common::Serializer::Version minVersion, Common::Serializer::Version maxVersion) {
+ uint16 id;
+ uint32 pos, delay;
+ if (ser.isSaving()) {
+ pos = data->_stream->pos();
+ id = data->_id;
+ delay = data->_currDelay;
+ }
+ ser.syncAsUint32LE(pos);
+ ser.syncAsUint16LE(id);
+ ser.syncAsUint32LE(delay);
+ if (ser.isLoading()) {
+ data = new OldScript(id, getResource(ID_SCRP, id));
+ data->_currDelay = delay;
+ data->_stream->seek(pos, SEEK_SET);
+ }
+}
+template<>
+void ComposerEngine::sync<QueuedScript>(Common::Serializer &ser, QueuedScript &data, Common::Serializer::Version minVersion, Common::Serializer::Version maxVersion) {
+ ser.syncAsUint32LE(data._baseTime);
+ ser.syncAsUint32LE(data._duration);
+ ser.syncAsUint32LE(data._count);
+ ser.syncAsUint16LE(data._scriptId);
+ if (ser.isLoading()) data._baseTime += _timeDelta;
+}
+template<>
+void ComposerEngine::sync<Pipe *>(Common::Serializer &ser, Pipe *&data, Common::Serializer::Version minVersion, Common::Serializer::Version maxVersion) {
+ uint16 id;
+ uint32 offset, tmp;
+ if (ser.isSaving()) {
+ id = data->getPipeId();
+ offset = data->getOffset();
+ tmp = data->_bufferedResources.size();
+ }
+ ser.syncAsUint16LE(id);
+ ser.syncAsUint32LE(offset);
+
+ if (ser.isLoading()) {
+ // On load, get and initialize streams
+ Common::SeekableReadStream *stream;
+ if (getGameType() == GType_ComposerV1) {
+ stream = getResource(ID_PIPE, id);
+ data = new OldPipe(stream, id);
+ } else {
+ stream = getResource(ID_ANIM, id);
+ data = new Pipe(stream, id);
+ }
+ _pipeStreams.push_back(stream);
+ data->setOffset(offset);
+ ser.syncAsUint32LE(tmp);
+ for (uint32 j = tmp; j > 0; j--) {
+ uint32 tag;
+ ser.syncAsUint32LE(tag);
+ ser.syncAsUint32LE(tmp);
+ for (uint32 k = tmp; k > 0; k--) {
+ ser.syncAsUint16LE(id);
+ if (data->hasResource(tag, id))
+ data->getResource(tag, id, true);
+ }
+ }
+ } else {
+ ser.syncAsUint32LE(tmp);
+ for (Pipe::DelMap::iterator i = data->_bufferedResources.begin(); i != data->_bufferedResources.end(); i++) {
+ uint32 key = (*i)._key;
+ ser.syncAsUint32LE(key);
+ syncList<uint16>(ser, (*i)._value, minVersion, maxVersion);
+ }
+ }
+}
+template<>
+void ComposerEngine::sync<AnimationEntry>(Common::Serializer &ser, AnimationEntry &data, Common::Serializer::Version minVersion, Common::Serializer::Version maxVersion) {
+ ser.syncAsUint32LE(data.state);
+ ser.syncAsUint16LE(data.counter);
+ ser.syncAsUint16LE(data.prevValue);
+}
+template<>
+void ComposerEngine::sync<Animation *>(Common::Serializer &ser, Animation *&data, Common::Serializer::Version minVersion, Common::Serializer::Version maxVersion) {
+ uint16 animId, x, y;
+ uint32 offset, state, param;
+ int32 size;
+ if (ser.isSaving()) {
+ animId = data->_id;
+ offset = data->_offset;
+ x = data->_basePos.x;
+ y = data->_basePos.x;
+ state = data->_state;
+ param = data->_eventParam;
+ size = data->_size;
+ }
+ ser.syncAsUint16LE(animId);
+ ser.syncAsUint32LE(offset);
+ ser.syncAsUint16LE(x);
+ ser.syncAsUint16LE(y);
+ ser.syncAsUint32LE(state);
+ ser.syncAsUint32LE(param);
+ ser.syncAsUint32LE(size);
+ if (ser.isLoading()) {
+ // On load, get and initialize streams
+ loadAnimation(data, animId, x, y, param, size);
+ data->_offset = offset;
+ data->_state = state;
+ uint32 tmp;
+ ser.syncAsUint32LE(tmp);
+ for (uint32 i = 0; i < tmp; i++) {
+ sync<AnimationEntry>(ser, data->_entries[i], minVersion, maxVersion);
+ }
+ } else {
+ syncArray<AnimationEntry>(ser, data->_entries, minVersion, maxVersion);
+ }
+}
+template<>
+void ComposerEngine::sync<Sprite>(Common::Serializer &ser, Sprite &data, Common::Serializer::Version minVersion, Common::Serializer::Version maxVersion) {
+ ser.syncAsUint16LE(data._id);
+ ser.syncAsUint16LE(data._animId);
+ ser.syncAsSint16LE(data._pos.x);
+ ser.syncAsSint16LE(data._pos.y);
+ ser.syncAsUint16LE(data._surface.w);
+ ser.syncAsUint16LE(data._surface.h);
+ ser.syncAsUint16LE(data._surface.pitch);
+ ser.syncAsUint16LE(data._zorder);
+ if (ser.isLoading())
+ data._surface.setPixels(malloc(data._surface.h * data._surface.pitch));
+ byte *pix = static_cast<byte *>(data._surface.getPixels());
+ for (uint16 y = 0; y < data._surface.h; y++) {
+ for (uint16 x = 0; x < data._surface.w; x++) {
+ ser.syncAsByte(pix[x]);
+ }
+ pix += data._surface.pitch;
+ }
+
+}
+Common::String ComposerEngine::makeSaveGameName(int slot) {
+ return (_targetName + Common::String::format(".%02d", slot));
+}
+
+Common::Error ComposerEngine::loadGameState(int slot) {
+ Common::String filename = makeSaveGameName(slot);
+ Common::InSaveFile *in;
+ if (!(in = _saveFileMan->openForLoading(filename)))
+ return Common::kPathNotFile;
+
+ Common::Serializer ser(in, NULL);
+ byte magic[4];
+ ser.syncBytes(magic, 4);
+ if (magic[0] != 'C' || magic[1] != 'M' || magic[2] != 'P' || magic[3] != 'S')
+ return Common::kUnknownError;
+
+ ser.syncVersion(0);
+ Common::String desc;
+ ser.syncString(desc);
+ uint32 tmp;
+ ser.syncAsUint32LE(tmp);
+ _rnd->setSeed(tmp);
+ ser.syncAsUint32LE(_currentTime);
+ _timeDelta = _system->getMillis() - _currentTime;
+ _currentTime += _timeDelta;
+ ser.syncAsUint32LE(_lastTime);
+ _lastTime += _timeDelta;
+
+ // Unload all Libraries
+ Common::Array<uint16> libIds;
+ for (Common::List<Library>::iterator i = _libraries.begin(); i != _libraries.end(); i++)
+ libIds.push_back((*i)._id);
+ for (uint32 i = 0; i < libIds.size(); i++)
+ unloadLibrary(libIds[i]);
+
+ syncListReverse<Library>(ser, _libraries);
+ ser.syncString(_bookGroup);
+
+ syncArray<PendingPageChange>(ser, _pendingPageChanges);
+ syncArray<uint16>(ser, _stack);
+ syncArray<uint16>(ser, _vars);
+
+ // Free outdated pointers
+ for (Common::List<OldScript *>::iterator i = _oldScripts.begin(); i != _oldScripts.end(); i++) {
+ delete *i;
+ }
+
+ syncList<OldScript *>(ser, _oldScripts);
+ syncArray<QueuedScript>(ser, _queuedScripts);
+
+ ser.syncAsSint16LE(_lastMousePos.x);
+ ser.syncAsSint16LE(_lastMousePos.y);
+ g_system->warpMouse(_lastMousePos.x, _lastMousePos.y);
+ ser.syncAsByte(_mouseEnabled);
+ ser.syncAsByte(_mouseVisible);
+ ser.syncAsUint16LE(_mouseSpriteId);
+
+ // Free outdated pointers
+ for (Common::List<Pipe *>::iterator i = _pipes.begin(); i != _pipes.end(); i++) {
+ delete *i;
+ }
+ for (Common::Array<Common::SeekableReadStream *>::iterator i = _pipeStreams.begin(); i != _pipeStreams.end(); i++) {
+ delete *i;
+ }
+
+ _pipeStreams.clear();
+ syncListReverse<Pipe *>(ser, _pipes);
+
+ // Free outdated pointers
+ for (Common::List<Animation *>::iterator i = _anims.begin(); i != _anims.end(); i++) {
+ delete *i;
+ }
+
+ syncList<Animation *>(ser, _anims);
+ syncList<Sprite>(ser, _sprites);
+
+ _dirtyRects.clear();
+
+ // Redraw the whole screen
+ _dirtyRects.push_back(Common::Rect(0, 0, 640, 480));
+ byte palbuf[256 * 3];
+ ser.syncBytes(palbuf, 256 * 3);
+ _system->getPaletteManager()->setPalette(palbuf, 0, 256);
+ _needsUpdate = true;
+
+ _mixer->stopAll();
+ _audioStream = NULL;
+
+ // Restore the buffered audio
+ ser.syncAsSint16LE(_currSoundPriority);
+ int32 numSamples;
+ ser.syncAsSint32LE(numSamples);
+ int16 *audioBuffer = (int16 *)malloc(numSamples * 2);
+ for (int32 i = 0; i < numSamples; i++)
+ ser.syncAsSint16LE(audioBuffer[i]);
+ _audioStream = Audio::makeQueuingAudioStream(22050, false);
+ _audioStream->queueBuffer((byte *)audioBuffer, numSamples * 2, DisposeAfterUse::YES, Audio::FLAG_16BITS);
+ if (!_mixer->isSoundHandleActive(_soundHandle))
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle, _audioStream);
+
+
+ // Reset autosave duration on load
+ _lastSaveTime = _system->getMillis();
+
+ return Common::kNoError;
+}
+
+Common::Error ComposerEngine::saveGameState(int slot, const Common::String &desc) {
+ Common::String filename = makeSaveGameName(slot);
+ Common::OutSaveFile *out;
+ _lastSaveTime = _system->getMillis();
+ if (!(out = _saveFileMan->openForSaving(filename)))
+ return Common::kWritingFailed;
+
+ Common::Serializer ser(NULL, out);
+ byte magic[4] = {'C', 'M', 'P', 'S'};
+ ser.syncBytes(magic, 4);
+ ser.syncVersion(0);
+ Common::String desctmp = desc;
+ ser.syncString(desctmp);
+ uint32 tmp = _rnd->getSeed();
+ ser.syncAsUint32LE(tmp);
+ ser.syncAsUint32LE(_currentTime);
+ ser.syncAsUint32LE(_lastTime);
+
+ syncListReverse<Library>(ser, _libraries);
+ ser.syncString(_bookGroup);
+
+ syncArray<PendingPageChange>(ser, _pendingPageChanges);
+ syncArray<uint16>(ser, _stack);
+ syncArray<uint16>(ser, _vars);
+ syncList<OldScript *>(ser, _oldScripts);
+ syncArray<QueuedScript>(ser, _queuedScripts);
+
+ ser.syncAsSint16LE(_lastMousePos.x);
+ ser.syncAsSint16LE(_lastMousePos.y);
+ ser.syncAsByte(_mouseEnabled);
+ ser.syncAsByte(_mouseVisible);
+ ser.syncAsUint16LE(_mouseSpriteId);
+
+ syncListReverse<Pipe *>(ser, _pipes);
+ syncList<Animation *>(ser, _anims);
+ syncList<Sprite>(ser, _sprites);
+
+ byte paletteBuffer[256 * 3];
+ _system->getPaletteManager()->grabPalette(paletteBuffer, 0, 256);
+ ser.syncBytes(paletteBuffer, 256 * 3);
+
+ ser.syncAsSint16LE(_currSoundPriority);
+ int16 audioBuffer[22050];
+ int32 numSamples = _audioStream->readBuffer(audioBuffer, 22050);
+ if (numSamples == -1) numSamples = 0;
+ ser.syncAsSint32LE(numSamples);
+ for (int32 i = 0; i < numSamples; i++)
+ ser.syncAsSint16LE(audioBuffer[i]);
+
+ out->finalize();
+ return Common::kNoError;
+}
+} // End of namespace Composer
diff --git a/engines/director/archive.cpp b/engines/director/archive.cpp
index 1af63a81b7..ff97d3fce1 100644
--- a/engines/director/archive.cpp
+++ b/engines/director/archive.cpp
@@ -20,229 +20,455 @@
*
*/
-#include "common/macresman.h"
-
+#include "director/archive.h"
#include "director/director.h"
-#include "director/resource.h"
-#include "director/lingo/lingo.h"
+
+#include "common/debug.h"
+#include "common/macresman.h"
namespace Director {
-Archive *DirectorEngine::createArchive() {
- if (getPlatform() == Common::kPlatformMacintosh) {
- if (getVersion() < 4)
- return new MacArchive();
- else
- return new RIFXArchive();
- } else {
- return new RIFFArchive();
- }
+// Base Archive code
+
+Archive::Archive() {
+ _stream = 0;
+ _isBigEndian = true;
}
-void DirectorEngine::loadMainArchive() {
- if (getPlatform() == Common::kPlatformWindows)
- loadEXE();
- else
- loadMac();
-}
-
-void DirectorEngine::cleanupMainArchive() {
- delete _mainArchive;
- delete _macBinary;
-}
-
-void DirectorEngine::loadEXE() {
- Common::SeekableReadStream *exeStream = SearchMan.createReadStreamForMember(getEXEName());
- if (!exeStream)
- error("Failed to open EXE '%s'", getEXEName().c_str());
-
- _lingo->processEvent(kEventStart, 0);
-
- exeStream->seek(-4, SEEK_END);
- exeStream->seek(exeStream->readUint32LE());
-
- switch (getVersion()) {
- case 3:
- loadEXEv3(exeStream);
- break;
- case 4:
- loadEXEv4(exeStream);
- break;
- case 5:
- loadEXEv5(exeStream);
- break;
- case 7:
- loadEXEv7(exeStream);
- break;
- default:
- error("Unhandled Windows EXE version %d", getVersion());
+Archive::~Archive() {
+ close();
+}
+
+bool Archive::openFile(const Common::String &fileName) {
+ Common::File *file = new Common::File();
+
+ if (!file->open(fileName)) {
+ delete file;
+ return false;
+ }
+
+ if (!openStream(file)) {
+ close();
+ return false;
}
+
+ _fileName = fileName;
+
+ return true;
}
-void DirectorEngine::loadEXEv3(Common::SeekableReadStream *stream) {
- uint16 entryCount = stream->readUint16LE();
- if (entryCount != 1)
- error("Unhandled multiple entry v3 EXE");
+void Archive::close() {
+ _types.clear();
+
+ if (_stream)
+ delete _stream;
- stream->skip(5); // unknown
+ _stream = 0;
+}
+
+bool Archive::hasResource(uint32 tag, uint16 id) const {
+ if (!_types.contains(tag))
+ return false;
- stream->readUint32LE(); // Main MMM size
- Common::String mmmFileName = readPascalString(*stream);
- Common::String directoryName = readPascalString(*stream);
+ return _types[tag].contains(id);
+}
- debugC(1, kDebugLoading, "Main MMM: '%s'", mmmFileName.c_str());
- debugC(1, kDebugLoading, "Directory Name: '%s'", directoryName.c_str());
+bool Archive::hasResource(uint32 tag, const Common::String &resName) const {
+ if (!_types.contains(tag) || resName.empty())
+ return false;
- _mainArchive = new RIFFArchive();
+ const ResourceMap &resMap = _types[tag];
- if (!_mainArchive->openFile(mmmFileName))
- error("Could not open '%s'", mmmFileName.c_str());
+ for (ResourceMap::const_iterator it = resMap.begin(); it != resMap.end(); it++)
+ if (it->_value.name.matchString(resName))
+ return true;
- delete stream;
+ return false;
}
-void DirectorEngine::loadEXEv4(Common::SeekableReadStream *stream) {
- if (stream->readUint32BE() != MKTAG('P', 'J', '9', '3'))
- error("Invalid projector tag found in v4 EXE");
+Common::SeekableSubReadStreamEndian *Archive::getResource(uint32 tag, uint16 id) {
+ if (!_types.contains(tag))
+ error("Archive does not contain '%s' %04x", tag2str(tag), id);
+
+ const ResourceMap &resMap = _types[tag];
- uint32 rifxOffset = stream->readUint32LE();
- /* uint32 fontMapOffset = */ stream->readUint32LE();
- /* uint32 resourceForkOffset1 = */ stream->readUint32LE();
- /* uint32 resourceForkOffset2 = */ stream->readUint32LE();
- stream->readUint32LE(); // graphics DLL offset
- stream->readUint32LE(); // sound DLL offset
- /* uint32 rifxOffsetAlt = */ stream->readUint32LE(); // equivalent to rifxOffset
+ if (!resMap.contains(id))
+ error("Archive does not contain '%s' %04x", tag2str(tag), id);
- loadEXERIFX(stream, rifxOffset);
+ const Resource &res = resMap[id];
+
+ return new Common::SeekableSubReadStreamEndian(_stream, res.offset, res.offset + res.size, _isBigEndian, DisposeAfterUse::NO);
}
-void DirectorEngine::loadEXEv5(Common::SeekableReadStream *stream) {
- if (stream->readUint32LE() != MKTAG('P', 'J', '9', '5'))
- error("Invalid projector tag found in v5 EXE");
+uint32 Archive::getOffset(uint32 tag, uint16 id) const {
+ if (!_types.contains(tag))
+ error("Archive does not contain '%s' %04x", tag2str(tag), id);
+
+ const ResourceMap &resMap = _types[tag];
- uint32 rifxOffset = stream->readUint32LE();
- stream->readUint32LE(); // unknown
- stream->readUint32LE(); // unknown
- stream->readUint32LE(); // unknown
- /* uint16 screenWidth = */ stream->readUint16LE();
- /* uint16 screenHeight = */ stream->readUint16LE();
- stream->readUint32LE(); // unknown
- stream->readUint32LE(); // unknown
- /* uint32 fontMapOffset = */ stream->readUint32LE();
+ if (!resMap.contains(id))
+ error("Archive does not contain '%s' %04x", tag2str(tag), id);
- loadEXERIFX(stream, rifxOffset);
+ return resMap[id].offset;
}
-void DirectorEngine::loadEXEv7(Common::SeekableReadStream *stream) {
- if (stream->readUint32LE() != MKTAG('P', 'J', '0', '0'))
- error("Invalid projector tag found in v7 EXE");
+uint16 Archive::findResourceID(uint32 tag, const Common::String &resName) const {
+ if (!_types.contains(tag) || resName.empty())
+ return 0xFFFF;
- uint32 rifxOffset = stream->readUint32LE();
- stream->readUint32LE(); // unknown
- stream->readUint32LE(); // unknown
- stream->readUint32LE(); // unknown
- stream->readUint32LE(); // unknown
- stream->readUint32LE(); // some DLL offset
+ const ResourceMap &resMap = _types[tag];
- loadEXERIFX(stream, rifxOffset);
+ for (ResourceMap::const_iterator it = resMap.begin(); it != resMap.end(); it++)
+ if (it->_value.name.matchString(resName))
+ return it->_key;
+
+ return 0xFFFF;
}
-void DirectorEngine::loadEXERIFX(Common::SeekableReadStream *stream, uint32 offset) {
- _mainArchive = new RIFXArchive();
+Common::String Archive::getName(uint32 tag, uint16 id) const {
+ if (!_types.contains(tag))
+ error("Archive does not contain '%s' %04x", tag2str(tag), id);
+
+ const ResourceMap &resMap = _types[tag];
- if (!_mainArchive->openStream(stream, offset))
- error("Failed to load RIFX from EXE");
+ if (!resMap.contains(id))
+ error("Archive does not contain '%s' %04x", tag2str(tag), id);
+
+ return resMap[id].name;
}
-void DirectorEngine::loadMac() {
- if (getVersion() < 4) {
- // The data is part of the resource fork of the executable
- _mainArchive = new MacArchive();
+Common::Array<uint32> Archive::getResourceTypeList() const {
+ Common::Array<uint32> typeList;
- if (!_mainArchive->openFile(getEXEName()))
- error("Failed to open Mac binary '%s'", getEXEName().c_str());
- } else {
- // The RIFX is located in the data fork of the executable
- _macBinary = new Common::MacResManager();
+ for (TypeMap::const_iterator it = _types.begin(); it != _types.end(); it++)
+ typeList.push_back(it->_key);
- if (!_macBinary->open(getEXEName()) || !_macBinary->hasDataFork())
- error("Failed to open Mac binary '%s'", getEXEName().c_str());
+ return typeList;
+}
- Common::SeekableReadStream *dataFork = _macBinary->getDataFork();
- _mainArchive = new RIFXArchive();
+Common::Array<uint16> Archive::getResourceIDList(uint32 type) const {
+ Common::Array<uint16> idList;
- // First we need to detect PPC vs. 68k
+ if (!_types.contains(type))
+ return idList;
- uint32 tag = dataFork->readUint32BE();
- uint32 startOffset;
+ const ResourceMap &resMap = _types[type];
- if (SWAP_BYTES_32(tag) == MKTAG('P', 'J', '9', '3') || tag == MKTAG('P', 'J', '9', '5') || tag == MKTAG('P', 'J', '0', '0')) {
- // PPC: The RIFX shares the data fork with the binary
- startOffset = dataFork->readUint32BE();
- } else {
- // 68k: The RIFX is the only thing in the data fork
- startOffset = 0;
- }
+ for (ResourceMap::const_iterator it = resMap.begin(); it != resMap.end(); it++)
+ idList.push_back(it->_key);
- if (!_mainArchive->openStream(dataFork, startOffset))
- error("Failed to load RIFX from Mac binary");
- }
+ return idList;
}
-void DirectorEngine::loadSharedCastsFrom(Common::String filename) {
- Archive *shardcst = createArchive();
+uint32 Archive::convertTagToUppercase(uint32 tag) {
+ uint32 newTag = toupper(tag >> 24) << 24;
+ newTag |= toupper((tag >> 16) & 0xFF) << 16;
+ newTag |= toupper((tag >> 8) & 0xFF) << 8;
- debugC(1, kDebugLoading, "Loading Shared cast '%s'", filename.c_str());
+ return newTag | toupper(tag & 0xFF);
+}
- shardcst->openFile(filename);
+// Mac Archive code
- _sharedDIB = new Common::HashMap<int, Common::SeekableSubReadStreamEndian *>;
- _sharedSTXT = new Common::HashMap<int, Common::SeekableSubReadStreamEndian *>;
- _sharedSound = new Common::HashMap<int, Common::SeekableSubReadStreamEndian *>;
- _sharedBMP = new Common::HashMap<int, Common::SeekableSubReadStreamEndian *>;
+MacArchive::MacArchive() : Archive(), _resFork(0) {
+}
- Score *castScore = new Score(this, shardcst);
+MacArchive::~MacArchive() {
+ delete _resFork;
+}
- castScore->loadConfig(*shardcst->getResource(MKTAG('V','W','C','F'), 1024));
- castScore->loadCastData(*shardcst->getResource(MKTAG('V','W','C','R'), 1024));
+void MacArchive::close() {
+ Archive::close();
+ delete _resFork;
+ _resFork = 0;
+}
- _sharedCasts = &castScore->_casts;
+bool MacArchive::openFile(const Common::String &fileName) {
+ close();
- Common::Array<uint16> dib = shardcst->getResourceIDList(MKTAG('D','I','B',' '));
- if (dib.size() != 0) {
- debugC(3, kDebugLoading, "Loading %d DIBs", dib.size());
+ _resFork = new Common::MacResManager();
- for (Common::Array<uint16>::iterator iterator = dib.begin(); iterator != dib.end(); ++iterator) {
- debugC(3, kDebugLoading, "Shared DIB %d", *iterator);
- _sharedDIB->setVal(*iterator, shardcst->getResource(MKTAG('D','I','B',' '), *iterator));
- }
+ if (!_resFork->open(fileName) || !_resFork->hasResFork()) {
+ close();
+ return false;
+ }
+
+ _fileName = _resFork->getBaseFileName();
+ if (_fileName.hasSuffix(".bin")) {
+ for (int i = 0; i < 4; i++)
+ _fileName.deleteLastChar();
}
- Common::Array<uint16> stxt = shardcst->getResourceIDList(MKTAG('S','T','X','T'));
- if (stxt.size() != 0) {
- debugC(3, kDebugLoading, "Loading %d STXTs", stxt.size());
+ Common::MacResTagArray tagArray = _resFork->getResTagArray();
- for (Common::Array<uint16>::iterator iterator = stxt.begin(); iterator != stxt.end(); ++iterator) {
- debugC(3, kDebugLoading, "Shared STXT %d", *iterator);
- _sharedSTXT->setVal(*iterator, shardcst->getResource(MKTAG('S','T','X','T'), *iterator));
+ for (uint32 i = 0; i < tagArray.size(); i++) {
+ ResourceMap &resMap = _types[tagArray[i]];
+ Common::MacResIDArray idArray = _resFork->getResIDArray(tagArray[i]);
+
+ for (uint32 j = 0; j < idArray.size(); j++) {
+ Resource &res = resMap[idArray[j]];
+
+ res.offset = res.size = 0; // unused
+ res.name = _resFork->getResName(tagArray[i], idArray[j]);
+ debug(3, "Found MacArchive resource '%s' %d: %s", tag2str(tagArray[i]), idArray[j], res.name.c_str());
}
}
- Common::Array<uint16> bmp = shardcst->getResourceIDList(MKTAG('B','I','T','D'));
- if (bmp.size() != 0) {
- debugC(3, kDebugLoading, "Loading %d BITDs", bmp.size());
- for (Common::Array<uint16>::iterator iterator = bmp.begin(); iterator != bmp.end(); ++iterator) {
- _sharedBMP->setVal(*iterator, shardcst->getResource(MKTAG('B','I','T','D'), *iterator));
+ return true;
+}
+
+bool MacArchive::openStream(Common::SeekableReadStream *stream, uint32 startOffset) {
+ // TODO: Add support for this (v4 Windows games)
+ return false;
+}
+
+Common::SeekableSubReadStreamEndian *MacArchive::getResource(uint32 tag, uint16 id) {
+ assert(_resFork);
+ Common::SeekableReadStream *stream = _resFork->getResource(tag, id);
+ return new Common::SeekableSubReadStreamEndian(stream, 0, stream->size(), true, DisposeAfterUse::NO);
+}
+
+// RIFF Archive code
+
+bool RIFFArchive::openStream(Common::SeekableReadStream *stream, uint32 startOffset) {
+ close();
+
+ stream->seek(startOffset);
+
+ if (convertTagToUppercase(stream->readUint32BE()) != MKTAG('R', 'I', 'F', 'F'))
+ return false;
+
+ stream->readUint32LE(); // size
+
+ if (convertTagToUppercase(stream->readUint32BE()) != MKTAG('R', 'M', 'M', 'P'))
+ return false;
+
+ if (convertTagToUppercase(stream->readUint32BE()) != MKTAG('C', 'F', 'T', 'C'))
+ return false;
+
+ uint32 cftcSize = stream->readUint32LE();
+ uint32 startPos = stream->pos();
+ stream->readUint32LE(); // unknown (always 0?)
+
+ while ((uint32)stream->pos() < startPos + cftcSize) {
+ uint32 tag = convertTagToUppercase(stream->readUint32BE());
+
+ uint32 size = stream->readUint32LE();
+ uint32 id = stream->readUint32LE();
+ uint32 offset = stream->readUint32LE();
+
+ if (tag == 0)
+ break;
+
+ uint16 startResPos = stream->pos();
+ stream->seek(offset + 12);
+
+ Common::String name = "";
+ byte nameSize = stream->readByte();
+
+ if (nameSize) {
+ for (uint8 i = 0; i < nameSize; i++) {
+ name += stream->readByte();
+ }
}
+
+ stream->seek(startResPos);
+
+ debug(3, "Found RIFF resource '%s' %d: %d @ 0x%08x", tag2str(tag), id, size, offset);
+
+ ResourceMap &resMap = _types[tag];
+ Resource &res = resMap[id];
+ res.offset = offset;
+ res.size = size;
+ res.name = name;
}
- Common::Array<uint16> sound = shardcst->getResourceIDList(MKTAG('S','N','D',' '));
- if (stxt.size() != 0) {
- debugC(3, kDebugLoading, "Loading %d SNDs", sound.size());
- for (Common::Array<uint16>::iterator iterator = sound.begin(); iterator != sound.end(); ++iterator) {
- _sharedSound->setVal(*iterator, shardcst->getResource(MKTAG('S','N','D',' '), *iterator));
+ _stream = stream;
+ return true;
+}
+
+Common::SeekableSubReadStreamEndian *RIFFArchive::getResource(uint32 tag, uint16 id) {
+ if (!_types.contains(tag))
+ error("Archive does not contain '%s' %04x", tag2str(tag), id);
+
+ const ResourceMap &resMap = _types[tag];
+
+ if (!resMap.contains(id))
+ error("Archive does not contain '%s' %04x", tag2str(tag), id);
+
+ const Resource &res = resMap[id];
+
+ // Adjust to skip the resource header
+ uint32 offset = res.offset + 12;
+ uint32 size = res.size - 4;
+ // Skip the Pascal string
+ _stream->seek(offset);
+ byte stringSize = _stream->readByte(); // 1 for this byte
+
+ offset += stringSize + 1;
+ size -= stringSize + 1;
+
+ // Align to nearest word boundary
+ if (offset & 1) {
+ offset++;
+ size--;
+ }
+
+ return new Common::SeekableSubReadStreamEndian(_stream, offset, offset + size, true, DisposeAfterUse::NO);
+}
+
+// RIFX Archive code
+
+bool RIFXArchive::openStream(Common::SeekableReadStream *stream, uint32 startOffset) {
+ close();
+
+ stream->seek(startOffset);
+
+ uint32 headerTag = stream->readUint32BE();
+
+ if (headerTag == MKTAG('R', 'I', 'F', 'X'))
+ _isBigEndian = true;
+ else if (SWAP_BYTES_32(headerTag) == MKTAG('R', 'I', 'F', 'X'))
+ _isBigEndian = false;
+ else
+ return false;
+
+ Common::SeekableSubReadStreamEndian subStream(stream, startOffset + 4, stream->size(), _isBigEndian, DisposeAfterUse::NO);
+
+ subStream.readUint32(); // size
+
+ uint32 rifxType = subStream.readUint32();
+
+ if (rifxType != MKTAG('M', 'V', '9', '3') && rifxType != MKTAG('A', 'P', 'P', 'L'))
+ return false;
+
+ if (subStream.readUint32() != MKTAG('i', 'm', 'a', 'p'))
+ return false;
+
+ subStream.readUint32(); // imap length
+ subStream.readUint32(); // unknown
+ uint32 mmapOffset = subStream.readUint32() - startOffset - 4;
+ uint32 version = subStream.readUint32(); // 0 for 4.0, 0x4c1 for 5.0, 0x4c7 for 6.0, 0x708 for 8.5, 0x742 for 10.0
+ warning("RIFX: version: %x", version);
+
+ subStream.seek(mmapOffset);
+
+ if (subStream.readUint32() != MKTAG('m', 'm', 'a', 'p'))
+ return false;
+
+ subStream.readUint32(); // mmap length
+ subStream.readUint16(); // unknown
+ subStream.readUint16(); // unknown
+ subStream.readUint32(); // resCount + empty entries
+ uint32 resCount = subStream.readUint32();
+ subStream.skip(8); // all 0xFF
+ subStream.readUint32(); // unknown
+
+ Common::Array<Resource> resources;
+
+ // Need to look for these two resources
+ const Resource *keyRes = 0;
+ const Resource *casRes = 0;
+
+ for (uint32 i = 0; i < resCount; i++) {
+ uint32 tag = subStream.readUint32();
+ uint32 size = subStream.readUint32();
+ uint32 offset = subStream.readUint32();
+ uint16 flags = subStream.readUint16();
+ uint16 unk1 = subStream.readUint16();
+ uint32 unk2 = subStream.readUint32();
+
+ debug(3, "Found RIFX resource index %d: '%s', %d @ 0x%08x (%d), flags: %x unk1: %x unk2: %x",
+ i, tag2str(tag), size, offset, offset, flags, unk1, unk2);
+
+ Resource res;
+ res.offset = offset;
+ res.size = size;
+ resources.push_back(res);
+
+ // APPL is a special case; it has an embedded "normal" archive
+ if (rifxType == MKTAG('A', 'P', 'P', 'L') && tag == MKTAG('F', 'i', 'l', 'e'))
+ return openStream(stream, offset);
+
+ // Looking for two types here
+ if (tag == MKTAG('K', 'E', 'Y', '*'))
+ keyRes = &resources[resources.size() - 1];
+ else if (tag == MKTAG('C', 'A', 'S', '*'))
+ casRes = &resources[resources.size() - 1];
+ }
+
+ // We need to have found the 'File' resource already
+ if (rifxType == MKTAG('A', 'P', 'P', 'L')) {
+ warning("No 'File' resource present in APPL archive");
+ return false;
+ }
+
+ // A KEY* must be present
+ if (!keyRes) {
+ warning("No 'KEY*' resource present");
+ return false;
+ }
+
+ // Parse the CAS*, if present
+ if (casRes) {
+ Common::SeekableSubReadStreamEndian casStream(stream, casRes->offset + 8, casRes->offset + 8 + casRes->size, _isBigEndian, DisposeAfterUse::NO);
+
+ uint casSize = casRes->size / 4;
+
+ debugCN(2, kDebugLoading, "CAS*: %d [", casSize);
+
+ for (uint i = 0; i < casSize; i++) {
+ uint32 index = casStream.readUint32();
+
+ const Resource &res = resources[index];
+ _types[MKTAG('C', 'A', 'S', 't')][i + 1] = res;
+
+ debugCN(2, kDebugLoading, "%d ", index);
}
+ debugC(2, kDebugLoading, "]");
}
+
+ // Parse the KEY*
+ Common::SeekableSubReadStreamEndian keyStream(stream, keyRes->offset + 8, keyRes->offset + 8 + keyRes->size, _isBigEndian, DisposeAfterUse::NO);
+ uint16 unk1 = keyStream.readUint16();
+ uint16 unk2 = keyStream.readUint16();
+ uint32 unk3 = keyStream.readUint32();
+ uint32 keyCount = keyStream.readUint32();
+
+ debugC(2, kDebugLoading, "KEY*: unk1: %d unk2: %d unk3: %d keyCount: %d", unk1, unk2, unk3, keyCount);
+
+ for (uint32 i = 0; i < keyCount; i++) {
+ uint32 index = keyStream.readUint32();
+ uint32 id = keyStream.readUint32();
+ uint32 resTag = keyStream.readUint32();
+
+ debugC(2, kDebugLoading, "KEY*: index: %d id: %d resTag: %s", index, id, tag2str(resTag));
+
+ const Resource &res = resources[index];
+ debug(3, "Found RIFX resource: '%s' id: 0x%04x, %d @ 0x%08x (%d)", tag2str(resTag), id, res.size, res.offset, res.offset);
+ _types[resTag][id] = res;
+ }
+
+ _stream = stream;
+ return true;
+}
+
+Common::SeekableSubReadStreamEndian *RIFXArchive::getResource(uint32 tag, uint16 id) {
+ if (!_types.contains(tag))
+ error("Archive does not contain '%s' %04x", tag2str(tag), id);
+
+ const ResourceMap &resMap = _types[tag];
+
+ if (!resMap.contains(id))
+ error("Archive does not contain '%s' %04x", tag2str(tag), id);
+
+ const Resource &res = resMap[id];
+
+ uint32 offset = res.offset + 8;
+ uint32 size = res.size;
+
+ return new Common::SeekableSubReadStreamEndian(_stream, offset, offset + size, true, DisposeAfterUse::NO);
}
+
} // End of namespace Director
diff --git a/engines/director/resource.h b/engines/director/archive.h
index 1265908cba..93f4ce7ee9 100644
--- a/engines/director/resource.h
+++ b/engines/director/archive.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef DIRECTOR_RESOURCE_H
-#define DIRECTOR_RESOURCE_H
+#ifndef DIRECTOR_ARCHIVE_H
+#define DIRECTOR_ARCHIVE_H
#include "common/file.h"
#include "common/substream.h"
@@ -102,6 +102,7 @@ public:
~RIFXArchive() {}
bool openStream(Common::SeekableReadStream *stream, uint32 startOffset = 0);
+ Common::SeekableSubReadStreamEndian *getResource(uint32 tag, uint16 id);
};
} // End of namespace Director
diff --git a/engines/director/cast.cpp b/engines/director/cast.cpp
new file mode 100644
index 0000000000..667fc248ea
--- /dev/null
+++ b/engines/director/cast.cpp
@@ -0,0 +1,136 @@
+/* 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 "director/director.h"
+#include "director/cast.h"
+#include "director/score.h"
+
+namespace Director {
+
+BitmapCast::BitmapCast(Common::ReadStreamEndian &stream, uint16 version) {
+ if (version < 4) {
+ flags = stream.readByte();
+ someFlaggyThing = stream.readUint16();
+ initialRect = Score::readRect(stream);
+ boundingRect = Score::readRect(stream);
+ regY = stream.readUint16();
+ regX = stream.readUint16();
+ unk1 = unk2 = 0;
+
+ if (someFlaggyThing & 0x8000) {
+ unk1 = stream.readUint16();
+ unk2 = stream.readUint16();
+ }
+ } else {
+ initialRect = Score::readRect(stream);
+ boundingRect = Score::readRect(stream);
+ regX = stream.readUint16();
+ regY = stream.readUint16();
+ }
+ modified = 0;
+}
+
+TextCast::TextCast(Common::ReadStreamEndian &stream, uint16 version) {
+ if (version < 4) {
+ flags1 = stream.readByte();
+ borderSize = static_cast<SizeType>(stream.readByte());
+ gutterSize = static_cast<SizeType>(stream.readByte());
+ boxShadow = static_cast<SizeType>(stream.readByte());
+ textType = static_cast<TextType>(stream.readByte());
+ textAlign = static_cast<TextAlignType>(stream.readUint16());
+ palinfo1 = stream.readUint16();
+ palinfo2 = stream.readUint16();
+ palinfo3 = stream.readUint16();
+
+ int t = stream.readUint32();
+ assert(t == 0); // So far we saw only 0 here
+
+ initialRect = Score::readRect(stream);
+ textShadow = static_cast<SizeType>(stream.readByte());
+ byte flags = stream.readByte();
+ if (flags & 0x1)
+ textFlags.push_back(kTextFlagEditable);
+ if (flags & 0x2)
+ textFlags.push_back(kTextFlagAutoTab);
+ if (flags & 0x4)
+ textFlags.push_back(kTextFlagDoNotWrap);
+ if (flags & 0xf8)
+ warning("Unproxessed text cast flags: %x", flags & 0xf8);
+
+ // TODO: FIXME: guesswork
+ fontId = stream.readByte();
+ fontSize = stream.readByte();
+ } else {
+ initialRect = Score::readRect(stream);
+ boundingRect = Score::readRect(stream);
+ }
+
+ modified = 0;
+}
+
+ShapeCast::ShapeCast(Common::ReadStreamEndian &stream, uint16 version) {
+ if (version < 4) {
+ /*byte flags = */ stream.readByte();
+ /*unk1 = */ stream.readByte();
+ shapeType = static_cast<ShapeType>(stream.readByte());
+ initialRect = Score::readRect(stream);
+ pattern = stream.readUint16BE();
+ fgCol = stream.readByte();
+ bgCol = stream.readByte();
+ fillType = stream.readByte();
+ lineThickness = stream.readByte();
+ lineDirection = stream.readByte();
+ } else {
+ initialRect = Score::readRect(stream);
+ boundingRect = Score::readRect(stream);
+ }
+ modified = 0;
+}
+
+ButtonCast::ButtonCast(Common::ReadStreamEndian &stream, uint16 version) : TextCast(stream, version) {
+ if (version < 4) {
+ buttonType = static_cast<ButtonType>(stream.readUint16BE());
+ } else {
+ initialRect = Score::readRect(stream);
+ boundingRect = Score::readRect(stream);
+ }
+ modified = 0;
+}
+
+ScriptCast::ScriptCast(Common::ReadStreamEndian &stream, uint16 version) {
+ if (version < 4) {
+ error("Unhandled Script cast");
+ } else {
+ initialRect = Score::readRect(stream);
+ boundingRect = Score::readRect(stream);
+
+ id = stream.readUint32();
+
+ debugC(4, kDebugLoading, "CASt: Script id: %d", id);
+
+ stream.readByte(); // There should be no more data
+ assert(stream.eos());
+ }
+ modified = 0;
+}
+
+} // End of namespace Director
diff --git a/engines/director/cast.h b/engines/director/cast.h
new file mode 100644
index 0000000000..69edf8ce89
--- /dev/null
+++ b/engines/director/cast.h
@@ -0,0 +1,162 @@
+/* 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 DIRECTOR_CAST_H
+#define DIRECTOR_CAST_H
+
+#include "common/rect.h"
+#include "common/substream.h"
+
+namespace Director {
+
+enum CastType {
+ kCastBitmap = 1,
+ kCastFilmLoop = 2,
+ kCastText = 3,
+ kCastPalette = 4,
+ kCastPicture = 5,
+ kCastSound = 6,
+ kCastButton = 7,
+ kCastShape = 8,
+ kCastMovie = 9,
+ kCastDigitalVideo = 10,
+ kCastScript = 11
+};
+
+struct Cast {
+ CastType type;
+ Common::Rect initialRect;
+ Common::Rect boundingRect;
+
+ byte modified;
+};
+
+struct BitmapCast : Cast {
+ BitmapCast(Common::ReadStreamEndian &stream, uint16 version = 2);
+
+ uint16 regX;
+ uint16 regY;
+ uint8 flags;
+ uint16 someFlaggyThing;
+ uint16 unk1, unk2;
+};
+
+enum ShapeType {
+ kShapeRectangle,
+ kShapeRoundRect,
+ kShapeOval,
+ kShapeLine
+};
+
+struct ShapeCast : Cast {
+ ShapeCast(Common::ReadStreamEndian &stream, uint16 version = 2);
+
+ ShapeType shapeType;
+ uint16 pattern;
+ byte fgCol;
+ byte bgCol;
+ byte fillType;
+ byte lineThickness;
+ byte lineDirection;
+};
+
+enum TextType {
+ kTextTypeAdjustToFit,
+ kTextTypeScrolling,
+ kTextTypeFixed
+};
+
+enum TextAlignType {
+ kTextAlignRight = -1,
+ kTextAlignLeft,
+ kTextAlignCenter
+};
+
+enum TextFlag {
+ kTextFlagEditable,
+ kTextFlagAutoTab,
+ kTextFlagDoNotWrap
+};
+
+enum SizeType {
+ kSizeNone,
+ kSizeSmallest,
+ kSizeSmall,
+ kSizeMedium,
+ kSizeLarge,
+ kSizeLargest
+};
+
+struct TextCast : Cast {
+ TextCast(Common::ReadStreamEndian &stream, uint16 version = 2);
+
+ SizeType borderSize;
+ SizeType gutterSize;
+ SizeType boxShadow;
+
+ byte flags1;
+ uint32 fontId;
+ uint16 fontSize;
+ TextType textType;
+ TextAlignType textAlign;
+ SizeType textShadow;
+ Common::Array<TextFlag> textFlags;
+ int16 palinfo1, palinfo2, palinfo3;
+};
+
+enum ButtonType {
+ kTypeButton,
+ kTypeCheckBox,
+ kTypeRadio
+};
+
+struct ButtonCast : TextCast {
+ ButtonCast(Common::ReadStreamEndian &stream, uint16 version = 2);
+
+ ButtonType buttonType;
+};
+
+struct ScriptCast : Cast {
+ ScriptCast(Common::ReadStreamEndian &stream, uint16 version = 2);
+
+ uint32 id;
+};
+
+
+
+struct CastInfo {
+ Common::String script;
+ Common::String name;
+ Common::String directory;
+ Common::String fileName;
+ Common::String type;
+};
+
+struct Label {
+ Common::String name;
+ uint16 number;
+ Label(Common::String name1, uint16 number1) { name = name1; number = number1; }
+};
+
+} // End of namespace Director
+
+#endif
diff --git a/engines/director/director.cpp b/engines/director/director.cpp
index 8c5e456781..32358e4b6e 100644
--- a/engines/director/director.cpp
+++ b/engines/director/director.cpp
@@ -27,7 +27,7 @@
#include "graphics/macgui/macwindowmanager.h"
#include "director/director.h"
-#include "director/resource.h"
+#include "director/archive.h"
#include "director/sound.h"
#include "director/lingo/lingo.h"
@@ -120,10 +120,13 @@ Common::Error DirectorEngine::run() {
//testFont();
- _movies = scanMovies(ConfMan.get("path"));
+ if (getPlatform() == Common::kPlatformWindows)
+ _sharedCastFile = "SHARDCST.MMM";
+ else
+ _sharedCastFile = "Shared Cast*";
+
+ loadSharedCastsFrom(_sharedCastFile);
- if (!_sharedCastFile.empty())
- loadSharedCastsFrom(_sharedCastFile);
loadMainArchive();
_currentScore = new Score(this, _mainArchive);
diff --git a/engines/director/frame.cpp b/engines/director/frame.cpp
index 0ce7f2be9b..6464943d99 100644
--- a/engines/director/frame.cpp
+++ b/engines/director/frame.cpp
@@ -27,9 +27,10 @@
#include "image/bmp.h"
#include "director/director.h"
+#include "director/cast.h"
#include "director/frame.h"
#include "director/images.h"
-#include "director/resource.h"
+#include "director/archive.h"
#include "director/score.h"
#include "director/sprite.h"
@@ -54,7 +55,7 @@ Frame::Frame(DirectorEngine *vm) {
_palette = NULL;
- _sprites.resize(CHANNEL_COUNT);
+ _sprites.resize(CHANNEL_COUNT + 1);
for (uint16 i = 0; i < _sprites.size(); i++) {
Sprite *sp = new Sprite();
@@ -80,9 +81,9 @@ Frame::Frame(const Frame &frame) {
debugC(1, kDebugLoading, "Frame. action: %d transType: %d transDuration: %d", _actionId, _transType, _transDuration);
- _sprites.resize(CHANNEL_COUNT);
+ _sprites.resize(CHANNEL_COUNT + 1);
- for (uint16 i = 0; i < CHANNEL_COUNT; i++) {
+ for (uint16 i = 0; i < CHANNEL_COUNT + 1; i++) {
_sprites[i] = new Sprite(*frame._sprites[i]);
}
}
@@ -112,6 +113,105 @@ void Frame::readChannel(Common::SeekableSubReadStreamEndian &stream, uint16 offs
}
}
+void Frame::readChannels(Common::ReadStreamEndian *stream) {
+ _actionId = stream->readByte();
+ _soundType1 = stream->readByte(); // type: 0x17 for sounds (sound is cast id), 0x16 for MIDI (sound is cmd id)
+ uint8 transFlags = stream->readByte(); // 0x80 is whole stage (vs changed area), rest is duration in 1/4ths of a second
+
+ if (transFlags & 0x80)
+ _transArea = 1;
+ else
+ _transArea = 0;
+ _transDuration = transFlags & 0x7f;
+
+ _transChunkSize = stream->readByte();
+ _tempo = stream->readByte();
+ _transType = static_cast<TransitionType>(stream->readByte());
+ _sound1 = stream->readUint16();
+ if (_vm->getPlatform() == Common::kPlatformMacintosh) {
+ _sound2 = stream->readUint16();
+ _soundType2 = stream->readByte();
+ } else {
+ byte unk[3];
+ stream->read(unk, 3);
+ warning("unk1: %x unk2: %x unk3: %x", unk[0], unk[1], unk[2]);
+ }
+ _skipFrameFlag = stream->readByte();
+ _blend = stream->readByte();
+
+ if (_vm->getPlatform() != Common::kPlatformMacintosh) {
+ _sound2 = stream->readUint16();
+ _soundType2 = stream->readByte();
+ }
+
+ uint16 palette = stream->readUint16();
+
+ if (palette) {
+ warning("STUB: Palette info");
+ }
+
+ debugC(kDebugLoading, 8, "%d %d %d %d %d %d %d %d %d %d %d", _actionId, _soundType1, _transDuration, _transChunkSize, _tempo, _transType, _sound1, _skipFrameFlag, _blend, _sound2, _soundType2);
+
+ _palette = new PaletteInfo();
+ _palette->firstColor = stream->readByte(); // for cycles. note: these start at 0x80 (for pal entry 0)!
+ _palette->lastColor = stream->readByte();
+ _palette->flags = stream->readByte();
+ _palette->speed = stream->readByte();
+ _palette->frameCount = stream->readUint16();
+
+ _palette->cycleCount = stream->readUint16();
+
+ byte unk[11];
+ stream->read(unk, 6);
+
+ if (_vm->getPlatform() == Common::kPlatformMacintosh) {
+ if (_vm->getVersion() < 4) {
+ stream->read(unk, 3);
+ } else {
+ stream->read(unk, 11);
+ //Common::hexdump(unk, 11);
+
+ if (_vm->getVersion() >= 5) {
+ stream->read(unk, 7);
+ //Common::hexdump(unk, 7);
+ }
+ }
+ }
+
+ for (int i = 0; i < CHANNEL_COUNT; i++) {
+ Sprite &sprite = *_sprites[i + 1];
+
+ sprite._x1 = stream->readByte();
+ sprite._enabled = (stream->readByte() != 0);
+ sprite._x2 = stream->readUint16();
+
+ sprite._flags = stream->readUint16();
+ sprite._ink = static_cast<InkType>(sprite._flags & 0x3f);
+
+ if (sprite._flags & 0x40)
+ sprite._trails = 1;
+ else
+ sprite._trails = 0;
+
+ sprite._castId = stream->readUint16();
+ sprite._startPoint.y = stream->readUint16();
+ sprite._startPoint.x = stream->readUint16();
+ sprite._height = stream->readUint16();
+ sprite._width = stream->readUint16();
+
+ debugC(kDebugLoading, 8, "%03d(%d)[%x,%x,%04x,%d/%d/%d/%d]", sprite._castId, sprite._enabled, sprite._x1, sprite._x2, sprite._flags, sprite._startPoint.x, sprite._startPoint.y, sprite._width, sprite._height);
+
+ if (_vm->getPlatform() == Common::kPlatformMacintosh && _vm->getVersion() >= 4) {
+ sprite._scriptId = stream->readUint16();
+ sprite._flags2 = stream->readByte(); // 0x40 editable, 0x80 moveable
+ sprite._unk2 = stream->readByte();
+
+ if (_vm->getVersion() >= 5)
+ sprite._unk3 = stream->readUint32();
+ }
+ }
+}
+
void Frame::readMainChannels(Common::SeekableSubReadStreamEndian &stream, uint16 offset, uint16 size) {
uint16 finishPosition = offset + size;
@@ -179,6 +279,8 @@ void Frame::readMainChannels(Common::SeekableSubReadStreamEndian &stream, uint16
break;
}
}
+
+ warning("%d %d %d %d %d %d %d %d %d %d %d", _actionId, _soundType1, _transDuration, _transChunkSize, _tempo, _transType, _sound1, _skipFrameFlag, _blend, _sound2, _soundType2);
}
void Frame::readPaletteInfo(Common::SeekableSubReadStreamEndian &stream) {
@@ -198,11 +300,13 @@ void Frame::readSprite(Common::SeekableSubReadStreamEndian &stream, uint16 offse
uint16 finishPosition = fieldPosition + size;
Sprite &sprite = *_sprites[spritePosition];
+ int x1 = 0;
+ int x2 = 0;
while (fieldPosition < finishPosition) {
switch (fieldPosition) {
case kSpritePositionUnk1:
- /*byte x1 = */ stream.readByte();
+ x1 = stream.readByte();
fieldPosition++;
break;
case kSpritePositionEnabled:
@@ -210,7 +314,7 @@ void Frame::readSprite(Common::SeekableSubReadStreamEndian &stream, uint16 offse
fieldPosition++;
break;
case kSpritePositionUnk2:
- /*byte x2 = */ stream.readUint16();
+ x2 = stream.readUint16();
fieldPosition += 2;
break;
case kSpritePositionFlags:
@@ -251,6 +355,8 @@ void Frame::readSprite(Common::SeekableSubReadStreamEndian &stream, uint16 offse
break;
}
}
+ warning("%03d(%d)[%x,%x,%04x,%d/%d/%d/%d]", sprite._castId, sprite._enabled, x1, x2, sprite._flags, sprite._startPoint.x, sprite._startPoint.y, sprite._width, sprite._height);
+
}
void Frame::prepareFrame(Score *score) {
diff --git a/engines/director/frame.h b/engines/director/frame.h
index 68eb1e33bb..ce82fa527c 100644
--- a/engines/director/frame.h
+++ b/engines/director/frame.h
@@ -35,6 +35,10 @@ class Sprite;
#define CHANNEL_COUNT 24
+enum {
+ kChannelDataSize = (25 * 50)
+};
+
enum TransitionType {
kTransNone,
kTransWipeRight,
@@ -97,6 +101,7 @@ struct PaletteInfo {
uint8 flags;
uint8 speed;
uint16 frameCount;
+ uint16 cycleCount;
};
@@ -105,6 +110,7 @@ public:
Frame(DirectorEngine *vm);
Frame(const Frame &frame);
~Frame();
+ void readChannels(Common::ReadStreamEndian *stream);
void readChannel(Common::SeekableSubReadStreamEndian &stream, uint16 offset, uint16 size);
void prepareFrame(Score *score);
uint16 getSpriteIDFromPos(Common::Point pos);
@@ -123,7 +129,9 @@ private:
void drawMatteSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect);
void drawGhostSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect);
void drawReverseSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect);
+
public:
+ byte _channelData[kChannelDataSize];
uint8 _actionId;
uint8 _transDuration;
uint8 _transArea; //1 - Whole Stage, 0 - Changing Area
@@ -144,6 +152,6 @@ public:
DirectorEngine *_vm;
};
-} //End of namespace Director
+} // End of namespace Director
#endif
diff --git a/engines/director/images.cpp b/engines/director/images.cpp
index cd8223ae8e..0ec84af0d3 100644
--- a/engines/director/images.cpp
+++ b/engines/director/images.cpp
@@ -41,6 +41,7 @@ DIBDecoder::~DIBDecoder() {
}
void DIBDecoder::destroy() {
+ delete _surface;
_surface = 0;
delete[] _palette;
diff --git a/engines/director/lingo/lingo-code.cpp b/engines/director/lingo/lingo-code.cpp
index 37a333ba10..dd5977673e 100644
--- a/engines/director/lingo/lingo-code.cpp
+++ b/engines/director/lingo/lingo-code.cpp
@@ -729,6 +729,8 @@ void Lingo::c_repeatwithcode(void) {
if (!g_lingo->_returning)
g_lingo->_pc = end; /* next stmt */
+
+ delete counter;
}
void Lingo::c_exitRepeat(void) {
@@ -972,6 +974,8 @@ void Lingo::c_global() {
s->global = true;
g_lingo->_pc += g_lingo->calcStringAlignment(name.c_str());
+
+ delete s;
}
void Lingo::c_instance() {
diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp
index a8633f1765..270746678b 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -21,6 +21,7 @@
*/
#include "director/lingo/lingo.h"
+#include "director/cast.h"
#include "director/sprite.h"
namespace Director {
diff --git a/engines/director/module.mk b/engines/director/module.mk
index 1ea361590a..38e3cfea4a 100644
--- a/engines/director/module.mk
+++ b/engines/director/module.mk
@@ -2,6 +2,7 @@ MODULE := engines/director
MODULE_OBJS = \
archive.o \
+ cast.o \
detection.o \
director.o \
frame.o \
diff --git a/engines/director/movie.cpp b/engines/director/movie.cpp
index f952346d16..9799510c6b 100644
--- a/engines/director/movie.cpp
+++ b/engines/director/movie.cpp
@@ -79,4 +79,4 @@ Movie::~Movie() {
delete _currentVideo;
}
-} //End of namespace Director
+} // End of namespace Director
diff --git a/engines/director/movie.h b/engines/director/movie.h
index 888262a2d1..e4729a62c3 100644
--- a/engines/director/movie.h
+++ b/engines/director/movie.h
@@ -60,6 +60,6 @@ private:
Video::VideoDecoder *_currentVideo;
DirectorEngine *_vm;
};
-} //End of namespace Director
+} // End of namespace Director
#endif
diff --git a/engines/director/resource.cpp b/engines/director/resource.cpp
index 8efec141d1..54ab2198e1 100644
--- a/engines/director/resource.cpp
+++ b/engines/director/resource.cpp
@@ -20,430 +20,243 @@
*
*/
-#include "director/resource.h"
-
-#include "common/debug.h"
#include "common/macresman.h"
-namespace Director {
-
-// Base Archive code
-
-Archive::Archive() {
- _stream = 0;
- _isBigEndian = true;
-}
-
-Archive::~Archive() {
- close();
-}
-
-bool Archive::openFile(const Common::String &fileName) {
- Common::File *file = new Common::File();
+#include "director/director.h"
+#include "director/archive.h"
+#include "director/lingo/lingo.h"
- if (!file->open(fileName)) {
- delete file;
- return false;
- }
+namespace Director {
- if (!openStream(file)) {
- close();
- return false;
+Archive *DirectorEngine::createArchive() {
+ if (getPlatform() == Common::kPlatformMacintosh) {
+ if (getVersion() < 4)
+ return new MacArchive();
+ else
+ return new RIFXArchive();
+ } else {
+ return new RIFFArchive();
}
-
- _fileName = fileName;
-
- return true;
-}
-
-void Archive::close() {
- _types.clear();
-
- if (_stream)
- delete _stream;
-
- _stream = 0;
-}
-
-bool Archive::hasResource(uint32 tag, uint16 id) const {
- if (!_types.contains(tag))
- return false;
-
- return _types[tag].contains(id);
-}
-
-bool Archive::hasResource(uint32 tag, const Common::String &resName) const {
- if (!_types.contains(tag) || resName.empty())
- return false;
-
- const ResourceMap &resMap = _types[tag];
-
- for (ResourceMap::const_iterator it = resMap.begin(); it != resMap.end(); it++)
- if (it->_value.name.matchString(resName))
- return true;
-
- return false;
}
-Common::SeekableSubReadStreamEndian *Archive::getResource(uint32 tag, uint16 id) {
- if (!_types.contains(tag))
- error("Archive does not contain '%s' %04x", tag2str(tag), id);
-
- const ResourceMap &resMap = _types[tag];
-
- if (!resMap.contains(id))
- error("Archive does not contain '%s' %04x", tag2str(tag), id);
-
- const Resource &res = resMap[id];
-
- return new Common::SeekableSubReadStreamEndian(_stream, res.offset, res.offset + res.size, _isBigEndian, DisposeAfterUse::NO);
-}
-
-uint32 Archive::getOffset(uint32 tag, uint16 id) const {
- if (!_types.contains(tag))
- error("Archive does not contain '%s' %04x", tag2str(tag), id);
-
- const ResourceMap &resMap = _types[tag];
-
- if (!resMap.contains(id))
- error("Archive does not contain '%s' %04x", tag2str(tag), id);
-
- return resMap[id].offset;
-}
-
-uint16 Archive::findResourceID(uint32 tag, const Common::String &resName) const {
- if (!_types.contains(tag) || resName.empty())
- return 0xFFFF;
-
- const ResourceMap &resMap = _types[tag];
-
- for (ResourceMap::const_iterator it = resMap.begin(); it != resMap.end(); it++)
- if (it->_value.name.matchString(resName))
- return it->_key;
-
- return 0xFFFF;
+void DirectorEngine::loadMainArchive() {
+ if (getPlatform() == Common::kPlatformWindows)
+ loadEXE();
+ else
+ loadMac();
}
-Common::String Archive::getName(uint32 tag, uint16 id) const {
- if (!_types.contains(tag))
- error("Archive does not contain '%s' %04x", tag2str(tag), id);
-
- const ResourceMap &resMap = _types[tag];
-
- if (!resMap.contains(id))
- error("Archive does not contain '%s' %04x", tag2str(tag), id);
-
- return resMap[id].name;
+void DirectorEngine::cleanupMainArchive() {
+ delete _mainArchive;
+ delete _macBinary;
}
-Common::Array<uint32> Archive::getResourceTypeList() const {
- Common::Array<uint32> typeList;
-
- for (TypeMap::const_iterator it = _types.begin(); it != _types.end(); it++)
- typeList.push_back(it->_key);
-
- return typeList;
+void DirectorEngine::loadEXE() {
+ Common::SeekableReadStream *exeStream = SearchMan.createReadStreamForMember(getEXEName());
+ if (!exeStream)
+ error("Failed to open EXE '%s'", getEXEName().c_str());
+
+ _lingo->processEvent(kEventStart, 0);
+
+ exeStream->seek(-4, SEEK_END);
+ exeStream->seek(exeStream->readUint32LE());
+
+ switch (getVersion()) {
+ case 3:
+ loadEXEv3(exeStream);
+ break;
+ case 4:
+ loadEXEv4(exeStream);
+ break;
+ case 5:
+ loadEXEv5(exeStream);
+ break;
+ case 7:
+ loadEXEv7(exeStream);
+ break;
+ default:
+ error("Unhandled Windows EXE version %d", getVersion());
+ }
}
-Common::Array<uint16> Archive::getResourceIDList(uint32 type) const {
- Common::Array<uint16> idList;
+void DirectorEngine::loadEXEv3(Common::SeekableReadStream *stream) {
+ uint16 entryCount = stream->readUint16LE();
+ if (entryCount != 1)
+ error("Unhandled multiple entry v3 EXE");
- if (!_types.contains(type))
- return idList;
+ stream->skip(5); // unknown
- const ResourceMap &resMap = _types[type];
+ stream->readUint32LE(); // Main MMM size
+ Common::String mmmFileName = readPascalString(*stream);
+ Common::String directoryName = readPascalString(*stream);
- for (ResourceMap::const_iterator it = resMap.begin(); it != resMap.end(); it++)
- idList.push_back(it->_key);
+ debugC(1, kDebugLoading, "Main MMM: '%s'", mmmFileName.c_str());
+ debugC(1, kDebugLoading, "Directory Name: '%s'", directoryName.c_str());
- return idList;
-}
+ _mainArchive = new RIFFArchive();
-uint32 Archive::convertTagToUppercase(uint32 tag) {
- uint32 newTag = toupper(tag >> 24) << 24;
- newTag |= toupper((tag >> 16) & 0xFF) << 16;
- newTag |= toupper((tag >> 8) & 0xFF) << 8;
+ if (!_mainArchive->openFile(mmmFileName))
+ error("Could not open '%s'", mmmFileName.c_str());
- return newTag | toupper(tag & 0xFF);
+ delete stream;
}
-// Mac Archive code
+void DirectorEngine::loadEXEv4(Common::SeekableReadStream *stream) {
+ if (stream->readUint32BE() != MKTAG('P', 'J', '9', '3'))
+ error("Invalid projector tag found in v4 EXE");
-MacArchive::MacArchive() : Archive(), _resFork(0) {
-}
+ uint32 rifxOffset = stream->readUint32LE();
+ /* uint32 fontMapOffset = */ stream->readUint32LE();
+ /* uint32 resourceForkOffset1 = */ stream->readUint32LE();
+ /* uint32 resourceForkOffset2 = */ stream->readUint32LE();
+ stream->readUint32LE(); // graphics DLL offset
+ stream->readUint32LE(); // sound DLL offset
+ /* uint32 rifxOffsetAlt = */ stream->readUint32LE(); // equivalent to rifxOffset
-MacArchive::~MacArchive() {
- delete _resFork;
+ loadEXERIFX(stream, rifxOffset);
}
-void MacArchive::close() {
- Archive::close();
- delete _resFork;
- _resFork = 0;
+void DirectorEngine::loadEXEv5(Common::SeekableReadStream *stream) {
+ if (stream->readUint32LE() != MKTAG('P', 'J', '9', '5'))
+ error("Invalid projector tag found in v5 EXE");
+
+ uint32 rifxOffset = stream->readUint32LE();
+ stream->readUint32LE(); // unknown
+ stream->readUint32LE(); // unknown
+ stream->readUint32LE(); // unknown
+ /* uint16 screenWidth = */ stream->readUint16LE();
+ /* uint16 screenHeight = */ stream->readUint16LE();
+ stream->readUint32LE(); // unknown
+ stream->readUint32LE(); // unknown
+ /* uint32 fontMapOffset = */ stream->readUint32LE();
+
+ loadEXERIFX(stream, rifxOffset);
}
-bool MacArchive::openFile(const Common::String &fileName) {
- close();
+void DirectorEngine::loadEXEv7(Common::SeekableReadStream *stream) {
+ if (stream->readUint32LE() != MKTAG('P', 'J', '0', '0'))
+ error("Invalid projector tag found in v7 EXE");
- _resFork = new Common::MacResManager();
+ uint32 rifxOffset = stream->readUint32LE();
+ stream->readUint32LE(); // unknown
+ stream->readUint32LE(); // unknown
+ stream->readUint32LE(); // unknown
+ stream->readUint32LE(); // unknown
+ stream->readUint32LE(); // some DLL offset
- if (!_resFork->open(fileName) || !_resFork->hasResFork()) {
- close();
- return false;
- }
-
- _fileName = _resFork->getBaseFileName();
- if (_fileName.hasSuffix(".bin")) {
- for (int i = 0; i < 4; i++)
- _fileName.deleteLastChar();
- }
-
- Common::MacResTagArray tagArray = _resFork->getResTagArray();
-
- for (uint32 i = 0; i < tagArray.size(); i++) {
- ResourceMap &resMap = _types[tagArray[i]];
- Common::MacResIDArray idArray = _resFork->getResIDArray(tagArray[i]);
-
- for (uint32 j = 0; j < idArray.size(); j++) {
- Resource &res = resMap[idArray[j]];
-
- res.offset = res.size = 0; // unused
- res.name = _resFork->getResName(tagArray[i], idArray[j]);
- debug(3, "Found MacArchive resource '%s' %d: %s", tag2str(tagArray[i]), idArray[j], res.name.c_str());
- }
- }
-
- return true;
+ loadEXERIFX(stream, rifxOffset);
}
-bool MacArchive::openStream(Common::SeekableReadStream *stream, uint32 startOffset) {
- // TODO: Add support for this (v4 Windows games)
- return false;
-}
+void DirectorEngine::loadEXERIFX(Common::SeekableReadStream *stream, uint32 offset) {
+ _mainArchive = new RIFXArchive();
-Common::SeekableSubReadStreamEndian *MacArchive::getResource(uint32 tag, uint16 id) {
- assert(_resFork);
- Common::SeekableReadStream *stream = _resFork->getResource(tag, id);
- return new Common::SeekableSubReadStreamEndian(stream, 0, stream->size(), true, DisposeAfterUse::NO);
+ if (!_mainArchive->openStream(stream, offset))
+ error("Failed to load RIFX from EXE");
}
-// RIFF Archive code
-
-bool RIFFArchive::openStream(Common::SeekableReadStream *stream, uint32 startOffset) {
- close();
+void DirectorEngine::loadMac() {
+ if (getVersion() < 4) {
+ // The data is part of the resource fork of the executable
+ _mainArchive = new MacArchive();
- stream->seek(startOffset);
+ if (!_mainArchive->openFile(getEXEName()))
+ error("Failed to open Mac binary '%s'", getEXEName().c_str());
+ } else {
+ // The RIFX is located in the data fork of the executable
+ _macBinary = new Common::MacResManager();
- if (convertTagToUppercase(stream->readUint32BE()) != MKTAG('R', 'I', 'F', 'F'))
- return false;
+ if (!_macBinary->open(getEXEName()) || !_macBinary->hasDataFork())
+ error("Failed to open Mac binary '%s'", getEXEName().c_str());
- stream->readUint32LE(); // size
+ Common::SeekableReadStream *dataFork = _macBinary->getDataFork();
+ _mainArchive = new RIFXArchive();
- if (convertTagToUppercase(stream->readUint32BE()) != MKTAG('R', 'M', 'M', 'P'))
- return false;
+ // First we need to detect PPC vs. 68k
- if (convertTagToUppercase(stream->readUint32BE()) != MKTAG('C', 'F', 'T', 'C'))
- return false;
+ uint32 tag = dataFork->readUint32BE();
+ uint32 startOffset;
- uint32 cftcSize = stream->readUint32LE();
- uint32 startPos = stream->pos();
- stream->readUint32LE(); // unknown (always 0?)
-
- while ((uint32)stream->pos() < startPos + cftcSize) {
- uint32 tag = convertTagToUppercase(stream->readUint32BE());
-
- uint32 size = stream->readUint32LE();
- uint32 id = stream->readUint32LE();
- uint32 offset = stream->readUint32LE();
-
- if (tag == 0)
- break;
-
- uint16 startResPos = stream->pos();
- stream->seek(offset + 12);
-
- Common::String name = "";
- byte nameSize = stream->readByte();
-
- if (nameSize) {
- for (uint8 i = 0; i < nameSize; i++) {
- name += stream->readByte();
- }
+ if (SWAP_BYTES_32(tag) == MKTAG('P', 'J', '9', '3') || tag == MKTAG('P', 'J', '9', '5') || tag == MKTAG('P', 'J', '0', '0')) {
+ // PPC: The RIFX shares the data fork with the binary
+ startOffset = dataFork->readUint32BE();
+ } else {
+ // 68k: The RIFX is the only thing in the data fork
+ startOffset = 0;
}
- stream->seek(startResPos);
-
- debug(3, "Found RIFF resource '%s' %d: %d @ 0x%08x", tag2str(tag), id, size, offset);
-
- ResourceMap &resMap = _types[tag];
- Resource &res = resMap[id];
- res.offset = offset;
- res.size = size;
- res.name = name;
+ if (!_mainArchive->openStream(dataFork, startOffset))
+ error("Failed to load RIFX from Mac binary");
}
-
- _stream = stream;
- return true;
}
-Common::SeekableSubReadStreamEndian *RIFFArchive::getResource(uint32 tag, uint16 id) {
- if (!_types.contains(tag))
- error("Archive does not contain '%s' %04x", tag2str(tag), id);
+void DirectorEngine::loadSharedCastsFrom(Common::String filename) {
+ Archive *shardcst = createArchive();
- const ResourceMap &resMap = _types[tag];
+ debugC(1, kDebugLoading, "Loading Shared cast '%s'", filename.c_str());
- if (!resMap.contains(id))
- error("Archive does not contain '%s' %04x", tag2str(tag), id);
+ if (!shardcst->openFile(filename)) {
+ warning("No shared cast %s", filename.c_str());
- const Resource &res = resMap[id];
+ _sharedCasts = new Common::HashMap<int, Cast *>;
- // Adjust to skip the resource header
- uint32 offset = res.offset + 12;
- uint32 size = res.size - 4;
- // Skip the Pascal string
- _stream->seek(offset);
- byte stringSize = _stream->readByte(); // 1 for this byte
-
- offset += stringSize + 1;
- size -= stringSize + 1;
-
- // Align to nearest word boundary
- if (offset & 1) {
- offset++;
- size--;
+ return;
}
- return new Common::SeekableSubReadStreamEndian(_stream, offset, offset + size, true, DisposeAfterUse::NO);
-}
+ _sharedDIB = new Common::HashMap<int, Common::SeekableSubReadStreamEndian *>;
+ _sharedSTXT = new Common::HashMap<int, Common::SeekableSubReadStreamEndian *>;
+ _sharedSound = new Common::HashMap<int, Common::SeekableSubReadStreamEndian *>;
+ _sharedBMP = new Common::HashMap<int, Common::SeekableSubReadStreamEndian *>;
-// RIFX Archive code
+ Score *castScore = new Score(this, shardcst);
-bool RIFXArchive::openStream(Common::SeekableReadStream *stream, uint32 startOffset) {
- close();
+ castScore->loadConfig(*shardcst->getResource(MKTAG('V','W','C','F'), 1024));
- stream->seek(startOffset);
+ if (getVersion() < 4)
+ castScore->loadCastDataVWCR(*shardcst->getResource(MKTAG('V','W','C','R'), 1024));
- uint32 headerTag = stream->readUint32BE();
-
- if (headerTag == MKTAG('R', 'I', 'F', 'X'))
- _isBigEndian = true;
- else if (SWAP_BYTES_32(headerTag) == MKTAG('R', 'I', 'F', 'X'))
- _isBigEndian = false;
- else
- return false;
-
- Common::SeekableSubReadStreamEndian subStream(stream, startOffset + 4, stream->size(), _isBigEndian, DisposeAfterUse::NO);
-
- subStream.readUint32(); // size
-
- uint32 rifxType = subStream.readUint32();
-
- if (rifxType != MKTAG('M', 'V', '9', '3') && rifxType != MKTAG('A', 'P', 'P', 'L'))
- return false;
-
- if (subStream.readUint32() != MKTAG('i', 'm', 'a', 'p'))
- return false;
-
- subStream.readUint32(); // imap length
- subStream.readUint32(); // unknown
- uint32 mmapOffset = subStream.readUint32() - startOffset - 4;
-
- subStream.seek(mmapOffset);
-
- if (subStream.readUint32() != MKTAG('m', 'm', 'a', 'p'))
- return false;
-
- subStream.readUint32(); // mmap length
- subStream.readUint16(); // unknown
- subStream.readUint16(); // unknown
- subStream.readUint32(); // resCount + empty entries
- uint32 resCount = subStream.readUint32();
- subStream.skip(8); // all 0xFF
- subStream.readUint32(); // unknown
-
- Common::Array<Resource> resources;
-
- // Need to look for these two resources
- const Resource *keyRes = 0;
- const Resource *casRes = 0;
-
- for (uint32 i = 0; i < resCount; i++) {
- uint32 tag = subStream.readUint32();
- uint32 size = subStream.readUint32();
- uint32 offset = subStream.readUint32();
- /*uint16 flags = */ subStream.readUint16();
- /*uint16 unk1 = */ subStream.readUint16();
- /*uint32 unk2 = */ subStream.readUint32();
-
- debug(3, "Found RIFX resource index %d: '%s', %d @ 0x%08x", i, tag2str(tag), size, offset);
+ Common::Array<uint16> cast = shardcst->getResourceIDList(MKTAG('C','A','S','t'));
+ if (cast.size() > 0) {
+ for (Common::Array<uint16>::iterator iterator = cast.begin(); iterator != cast.end(); ++iterator)
+ castScore->loadCastData(*shardcst->getResource(MKTAG('C','A','S','t'), *iterator), *iterator);
+ }
- Resource res;
- res.offset = offset;
- res.size = size;
- resources.push_back(res);
+ _sharedCasts = &castScore->_casts;
- // APPL is a special case; it has an embedded "normal" archive
- if (rifxType == MKTAG('A', 'P', 'P', 'L') && tag == MKTAG('F', 'i', 'l', 'e'))
- return openStream(stream, offset);
+ Common::Array<uint16> dib = shardcst->getResourceIDList(MKTAG('D','I','B',' '));
+ if (dib.size() != 0) {
+ debugC(3, kDebugLoading, "Loading %d DIBs", dib.size());
- // Looking for two types here
- if (tag == MKTAG('K', 'E', 'Y', '*'))
- keyRes = &resources[resources.size() - 1];
- else if (tag == MKTAG('C', 'A', 'S', '*'))
- casRes = &resources[resources.size() - 1];
+ for (Common::Array<uint16>::iterator iterator = dib.begin(); iterator != dib.end(); ++iterator) {
+ debugC(3, kDebugLoading, "Shared DIB %d", *iterator);
+ _sharedDIB->setVal(*iterator, shardcst->getResource(MKTAG('D','I','B',' '), *iterator));
+ }
}
- // We need to have found the 'File' resource already
- if (rifxType == MKTAG('A', 'P', 'P', 'L')) {
- warning("No 'File' resource present in APPL archive");
- return false;
- }
+ Common::Array<uint16> stxt = shardcst->getResourceIDList(MKTAG('S','T','X','T'));
+ if (stxt.size() != 0) {
+ debugC(3, kDebugLoading, "Loading %d STXTs", stxt.size());
- // A KEY* must be present
- if (!keyRes) {
- warning("No 'KEY*' resource present");
- return false;
+ for (Common::Array<uint16>::iterator iterator = stxt.begin(); iterator != stxt.end(); ++iterator) {
+ debugC(3, kDebugLoading, "Shared STXT %d", *iterator);
+ _sharedSTXT->setVal(*iterator, shardcst->getResource(MKTAG('S','T','X','T'), *iterator));
+ }
}
- // Parse the CAS*, if present
- Common::Array<uint32> casEntries;
- if (casRes) {
- Common::SeekableSubReadStreamEndian casStream(stream, casRes->offset + 8, casRes->offset + 8 + casRes->size, _isBigEndian, DisposeAfterUse::NO);
- casEntries.resize(casRes->size / 4);
-
- for (uint32 i = 0; i < casEntries.size(); i++)
- casEntries[i] = casStream.readUint32();
+ Common::Array<uint16> bmp = shardcst->getResourceIDList(MKTAG('B','I','T','D'));
+ if (bmp.size() != 0) {
+ debugC(3, kDebugLoading, "Loading %d BITDs", bmp.size());
+ for (Common::Array<uint16>::iterator iterator = bmp.begin(); iterator != bmp.end(); ++iterator) {
+ _sharedBMP->setVal(*iterator, shardcst->getResource(MKTAG('B','I','T','D'), *iterator));
+ }
}
- // Parse the KEY*
- Common::SeekableSubReadStreamEndian keyStream(stream, keyRes->offset + 8, keyRes->offset + 8 + keyRes->size, _isBigEndian, DisposeAfterUse::NO);
- /*uint16 unk1 = */ keyStream.readUint16();
- /*uint16 unk2 = */ keyStream.readUint16();
- /*uint32 unk3 = */ keyStream.readUint32();
- uint32 keyCount = keyStream.readUint32();
-
- for (uint32 i = 0; i < keyCount; i++) {
- uint32 index = keyStream.readUint32();
- uint32 id = keyStream.readUint32();
- uint32 resTag = keyStream.readUint32();
-
- // Handle CAS*/CASt nonsense
- if (resTag == MKTAG('C', 'A', 'S', 't')) {
- for (uint32 j = 0; j < casEntries.size(); j++) {
- if (casEntries[j] == index) {
- id += j + 1;
- break;
- }
- }
+ Common::Array<uint16> sound = shardcst->getResourceIDList(MKTAG('S','N','D',' '));
+ if (stxt.size() != 0) {
+ debugC(3, kDebugLoading, "Loading %d SNDs", sound.size());
+ for (Common::Array<uint16>::iterator iterator = sound.begin(); iterator != sound.end(); ++iterator) {
+ _sharedSound->setVal(*iterator, shardcst->getResource(MKTAG('S','N','D',' '), *iterator));
}
-
- const Resource &res = resources[index];
- debug(3, "Found RIFX resource: '%s' 0x%04x, %d @ 0x%08x", tag2str(resTag), id, res.size, res.offset);
- _types[resTag][id] = res;
}
-
- _stream = stream;
- return true;
}
} // End of namespace Director
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 5c594c20fc..1c78745330 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -23,6 +23,7 @@
#include "common/system.h"
#include "common/config-manager.h"
#include "common/events.h"
+#include "common/memstream.h"
#include "engines/util.h"
#include "graphics/font.h"
@@ -30,9 +31,10 @@
#include "graphics/macgui/macfontmanager.h"
#include "graphics/macgui/macwindowmanager.h"
+#include "director/cast.h"
#include "director/score.h"
#include "director/frame.h"
-#include "director/resource.h"
+#include "director/archive.h"
#include "director/sound.h"
#include "director/sprite.h"
#include "director/lingo/lingo.h"
@@ -191,7 +193,7 @@ void Score::loadArchive() {
if (_vm->getVersion() < 4) {
assert(_movieArchive->hasResource(MKTAG('V','W','C','R'), 1024));
- loadCastData(*_movieArchive->getResource(MKTAG('V','W','C','R'), 1024));
+ loadCastDataVWCR(*_movieArchive->getResource(MKTAG('V','W','C','R'), 1024));
}
if (_movieArchive->hasResource(MKTAG('V','W','A','C'), 1024)) {
@@ -208,12 +210,16 @@ void Score::loadArchive() {
Common::Array<uint16> vwci = _movieArchive->getResourceIDList(MKTAG('V','W','C','I'));
if (vwci.size() > 0) {
- Common::Array<uint16>::iterator iterator;
-
- for (iterator = vwci.begin(); iterator != vwci.end(); ++iterator)
+ for (Common::Array<uint16>::iterator iterator = vwci.begin(); iterator != vwci.end(); ++iterator)
loadCastInfo(*_movieArchive->getResource(MKTAG('V','W','C','I'), *iterator), *iterator);
}
+ Common::Array<uint16> cast = _movieArchive->getResourceIDList(MKTAG('C','A','S','t'));
+ if (cast.size() > 0) {
+ for (Common::Array<uint16>::iterator iterator = cast.begin(); iterator != cast.end(); ++iterator)
+ loadCastData(*_movieArchive->getResource(MKTAG('C','A','S','t'), *iterator), *iterator);
+ }
+
Common::Array<uint16> stxt = _movieArchive->getResourceIDList(MKTAG('S','T','X','T'));
if (stxt.size() > 0) {
loadScriptText(*_movieArchive->getResource(MKTAG('S','T','X','T'), *stxt.begin()));
@@ -262,10 +268,16 @@ void Score::loadFrames(Common::SeekableSubReadStreamEndian &stream) {
size -= 4;
if (_vm->getVersion() > 3) {
- stream.skip(16);
+ uint32 unk1 = stream.readUint32();
+ uint32 unk2 = stream.readUint32();
+ uint16 unk3 = stream.readUint16();
+ uint16 unk4 = stream.readUint16();
+ uint16 unk5 = stream.readUint16();
+ uint16 unk6 = stream.readUint16();
+ size -= 16;
- warning("STUB: Score::loadFrames. Skipping initial bytes");
- //Unknown, some bytes - constant (refer to contuinity).
+ warning("STUB: Score::loadFrames. unk1: %x unk2: %x unk3: %x unk4: %x unk5: %x unk6: %x", unk1, unk2, unk3, unk4, unk5, unk6);
+ // Unknown, some bytes - constant (refer to contuinity).
}
uint16 channelSize;
@@ -274,11 +286,20 @@ void Score::loadFrames(Common::SeekableSubReadStreamEndian &stream) {
Frame *initial = new Frame(_vm);
_frames.push_back(initial);
+ // This is a representation of the channelData. It gets overridden
+ // partically by channels, hence we keep it and read the score from left to right
+ //
+ // TODO Merge it with shared cast
+ byte channelData[kChannelDataSize];
+ memset(channelData, 0, kChannelDataSize);
+
while (size != 0) {
uint16 frameSize = stream.readUint16();
+ debugC(kDebugLoading, 8, "++++ score frame %d (frameSize %d) size %d", _frames.size(), frameSize, size);
size -= frameSize;
frameSize -= 2;
- Frame *frame = new Frame(*_frames.back());
+
+ Frame *frame = new Frame(_vm);
while (frameSize != 0) {
if (_vm->getVersion() < 4) {
@@ -286,17 +307,25 @@ void Score::loadFrames(Common::SeekableSubReadStreamEndian &stream) {
channelOffset = stream.readByte() * 2;
frameSize -= channelSize + 2;
} else {
- channelSize = stream.readByte();
- channelOffset = stream.readByte();
+ channelSize = stream.readUint16();
+ channelOffset = stream.readUint16();
frameSize -= channelSize + 4;
}
- frame->readChannel(stream, channelOffset, channelSize);
+
+ assert(channelOffset + channelSize < kChannelDataSize);
+
+ stream.read(&channelData[channelOffset], channelSize);
}
+ Common::MemoryReadStreamEndian *str = new Common::MemoryReadStreamEndian(channelData, ARRAYSIZE(channelData), stream.isBE());
+ frame->readChannels(str);
+
+ delete str;
+
_frames.push_back(frame);
}
- //remove initial frame
+ // Remove initial frame
_frames.remove_at(0);
}
@@ -319,8 +348,8 @@ void Score::readVersion(uint32 rid) {
debug("Version: %d.%d", _versionMajor, _versionMinor);
}
-void Score::loadCastData(Common::SeekableSubReadStreamEndian &stream) {
- debugC(1, kDebugLoading, "Score::loadCastData(). start: %d, end: %d", _castArrayStart, _castArrayEnd);
+void Score::loadCastDataVWCR(Common::SeekableSubReadStreamEndian &stream) {
+ debugC(1, kDebugLoading, "Score::loadCastDataVWCR(). start: %d, end: %d", _castArrayStart, _castArrayEnd);
for (uint16 id = _castArrayStart; id <= _castArrayEnd; id++) {
byte size = stream.readByte();
@@ -347,13 +376,13 @@ void Score::loadCastData(Common::SeekableSubReadStreamEndian &stream) {
_casts[id]->type = kCastButton;
break;
default:
- warning("Unhandled cast type: %d", castType);
+ warning("Score::loadCastDataVWCR(): Unhandled cast type: %d", castType);
stream.skip(size - 1);
break;
}
}
- //Set cast pointers to sprites
+ // Set cast pointers to sprites
for (uint16 i = 0; i < _frames.size(); i++) {
for (uint16 j = 0; j < _frames[i]->_sprites.size(); j++) {
byte castId = _frames[i]->_sprites[j]->_castId;
@@ -364,6 +393,116 @@ void Score::loadCastData(Common::SeekableSubReadStreamEndian &stream) {
}
}
+void Score::loadCastData(Common::SeekableSubReadStreamEndian &stream, uint16 id) {
+ // d4+ variant
+ if (stream.size() == 0)
+ return;
+
+ if (stream.size() < 26) {
+ warning("CAST data id %d is too small", id);
+ return;
+ }
+
+ debugC(3, kDebugLoading, "CASt: id: %d", id);
+
+ if (debugChannelSet(5, kDebugLoading))
+ stream.hexdump(stream.size());
+
+ uint32 size1, size2, size3, castType;
+ byte unk1 = 0, unk2 = 0, unk3 = 0;
+
+ if (_vm->getVersion() < 5) {
+ size1 = stream.readUint16();
+ size2 = stream.readUint32();
+ size3 = 0;
+ castType = stream.readByte();
+ unk1 = stream.readByte();
+ unk2 = stream.readByte();
+ unk3 = stream.readByte();
+ } else {
+ // FIXME: only the cast type and the strings are good
+ castType = stream.readUint32();
+ size2 = stream.readUint32();
+ size3 = stream.readUint32();
+ size1 = stream.readUint32();
+ assert(size1 == 0x14);
+ size1 = 0;
+ }
+
+ debugC(3, kDebugLoading, "CASt: id: %d type: %x size1: %d size2: %d (%x) size3: %d unk1: %d unk2: %d unk3: %d",
+ id, castType, size1, size2, size2, size3, unk1, unk2, unk3);
+
+ byte *data = (byte *)calloc(size1 + 16, 1);
+ stream.read(data, size1 + 16);
+
+ Common::MemoryReadStreamEndian castStream(data, size1 + 16, stream.isBE());
+
+ switch (castType) {
+ case kCastBitmap:
+ warning("CASt: Bitmap");
+ Common::hexdump(data, size1 + 16);
+ _casts[id] = new BitmapCast(castStream, _vm->getVersion());
+ _casts[id]->type = kCastBitmap;
+ break;
+ case kCastText:
+ warning("CASt: Text");
+ Common::hexdump(data, size1 + 16);
+ _casts[id] = new TextCast(castStream, _vm->getVersion());
+ _casts[id]->type = kCastText;
+ break;
+ case kCastShape:
+ warning("CASt: Shape");
+ Common::hexdump(data, size1 + 16);
+
+ _casts[id] = new ShapeCast(castStream, _vm->getVersion());
+ _casts[id]->type = kCastShape;
+ break;
+ case kCastButton:
+ warning("CASt: Button");
+ Common::hexdump(data, size1 + 16);
+
+ _casts[id] = new ButtonCast(castStream, _vm->getVersion());
+ _casts[id]->type = kCastButton;
+ break;
+ case kCastScript:
+ _casts[id] = new ScriptCast(castStream, _vm->getVersion());
+ _casts[id]->type = kCastScript;
+ break;
+ default:
+ warning("Score::loadCastData(): Unhandled cast type: %d", castType);
+ break;
+ }
+
+ free(data);
+
+ if (size2) {
+ uint32 entryType = 0;
+ Common::Array<Common::String> castStrings = loadStrings(stream, entryType, false);
+
+ debugCN(4, kDebugLoading, "str(%d): '", castStrings.size());
+
+ for (uint i = 0; i < castStrings.size(); i++) {
+ debugCN(4, kDebugLoading, "%s'", castStrings[i].c_str());
+ if (i != castStrings.size() - 1)
+ debugCN(4, kDebugLoading, ", '");
+ }
+ debugC(4, kDebugLoading, "'");
+
+ CastInfo *ci = new CastInfo();
+
+ ci->script = castStrings[0];
+ ci->name = castStrings[1];
+ ci->directory = castStrings[2];
+ ci->fileName = castStrings[3];
+ ci->type = castStrings[4];
+
+ _castsInfo[id] = ci;
+ }
+
+ if (size3)
+ warning("size3: %x", size3);
+}
+
void Score::loadLabels(Common::SeekableSubReadStreamEndian &stream) {
_labels = new Common::SortedArray<Label *>(compareLabels);
uint16 count = stream.readUint16() + 1;
@@ -379,9 +518,11 @@ void Score::loadLabels(Common::SeekableSubReadStreamEndian &stream) {
stream.seek(stringPos);
Common::String label;
+
for (uint16 j = stringPos; j < nextStringPos; j++) {
label += stream.readByte();
}
+
_labels->insert(new Label(label, frame));
stream.seek(streamPos);
@@ -405,7 +546,7 @@ void Score::loadActions(Common::SeekableSubReadStreamEndian &stream) {
uint16 offset = count * 4 + 2;
byte id = stream.readByte();
- /*byte subId = */ stream.readByte(); //I couldn't find how it used in continuity (except print). Frame actionId = 1 byte.
+ /*byte subId = */ stream.readByte(); // I couldn't find how it used in continuity (except print). Frame actionId = 1 byte.
uint16 stringPos = stream.readUint16() + offset;
for (uint16 i = 0; i < count; i++) {
@@ -647,28 +788,31 @@ Common::Array<Common::String> Score::loadStrings(Common::SeekableSubReadStreamEn
stream.seek(offset);
}
- uint16 count = stream.readUint16();
- offset += (count + 1) * 4 + 2; // positions info + uint16 count
- uint32 startPos = stream.readUint32() + offset;
+ uint16 count = stream.readUint16() + 1;
- for (uint16 i = 0; i < count; i++) {
- Common::String entryString;
- uint32 nextPos = stream.readUint32() + offset;
- uint32 streamPos = stream.pos();
+ uint32 *entries = (uint32 *)calloc(count, sizeof(uint32));
- stream.seek(startPos);
+ for (uint i = 0; i < count; i++)
+ entries[i] = stream.readUint32();
- while (startPos != nextPos) {
- entryString += stream.readByte();
- ++startPos;
- }
+ byte *data = (byte *)malloc(entries[count - 1]);
+ stream.read(data, entries[count - 1]);
- strings.push_back(entryString);
+ for (uint i = 0; i < count - 1; i++) {
+ Common::String entryString;
- stream.seek(streamPos);
- startPos = nextPos;
+ for (uint j = entries[i]; j < entries[i + 1]; j++)
+ if (data[j] == '\r')
+ entryString += '\n';
+ else
+ entryString += data[j];
+
+ strings.push_back(entryString);
}
+ free(data);
+ free(entries);
+
return strings;
}
@@ -697,77 +841,14 @@ void Score::loadFontMap(Common::SeekableSubReadStreamEndian &stream) {
}
}
-BitmapCast::BitmapCast(Common::SeekableSubReadStreamEndian &stream) {
- flags = stream.readByte();
- someFlaggyThing = stream.readUint16();
- initialRect = Score::readRect(stream);
- boundingRect = Score::readRect(stream);
- regY = stream.readUint16();
- regX = stream.readUint16();
- unk1 = unk2 = 0;
-
- if (someFlaggyThing & 0x8000) {
- unk1 = stream.readUint16();
- unk2 = stream.readUint16();
- }
- modified = 0;
-}
-
-TextCast::TextCast(Common::SeekableSubReadStreamEndian &stream) {
- flags1 = stream.readByte();
- borderSize = static_cast<SizeType>(stream.readByte());
- gutterSize = static_cast<SizeType>(stream.readByte());
- boxShadow = static_cast<SizeType>(stream.readByte());
- textType = static_cast<TextType>(stream.readByte());
- textAlign = static_cast<TextAlignType>(stream.readUint16());
- palinfo1 = stream.readUint16();
- palinfo2 = stream.readUint16();
- palinfo3 = stream.readUint16();
-
- int t = stream.readUint32();
- assert(t == 0); // So far we saw only 0 here
-
- initialRect = Score::readRect(stream);
- textShadow = static_cast<SizeType>(stream.readByte());
- byte flags = stream.readByte();
- if (flags & 0x1)
- textFlags.push_back(kTextFlagEditable);
- if (flags & 0x2)
- textFlags.push_back(kTextFlagAutoTab);
- if (flags & 0x4)
- textFlags.push_back(kTextFlagDoNotWrap);
- if (flags & 0xf8)
- warning("Unproxessed text cast flags: %x", flags & 0xf8);
-
- // TODO: FIXME: guesswork
- fontId = stream.readByte();
- fontSize = stream.readByte();
-
- modified = 0;
-}
-
-ShapeCast::ShapeCast(Common::SeekableSubReadStreamEndian &stream) {
- /*byte flags = */ stream.readByte();
- /*unk1 = */ stream.readByte();
- shapeType = static_cast<ShapeType>(stream.readByte());
- initialRect = Score::readRect(stream);
- pattern = stream.readUint16BE();
- fgCol = stream.readByte();
- bgCol = stream.readByte();
- fillType = stream.readByte();
- lineThickness = stream.readByte();
- lineDirection = stream.readByte();
- modified = 0;
-}
-
-Common::Rect Score::readRect(Common::SeekableSubReadStreamEndian &stream) {
- Common::Rect *rect = new Common::Rect();
- rect->top = stream.readUint16();
- rect->left = stream.readUint16();
- rect->bottom = stream.readUint16();
- rect->right = stream.readUint16();
+Common::Rect Score::readRect(Common::ReadStreamEndian &stream) {
+ Common::Rect rect;
+ rect.top = stream.readUint16();
+ rect.left = stream.readUint16();
+ rect.bottom = stream.readUint16();
+ rect.right = stream.readUint16();
- return *rect;
+ return rect;
}
void Score::startLoop() {
@@ -930,4 +1011,4 @@ Sprite *Score::getSpriteById(uint16 id) {
}
}
-} //End of namespace Director
+} // End of namespace Director
diff --git a/engines/director/score.h b/engines/director/score.h
index 83f25284b1..9f6088307b 100644
--- a/engines/director/score.h
+++ b/engines/director/score.h
@@ -34,26 +34,14 @@ namespace Graphics {
namespace Director {
class Archive;
+struct CastInfo;
class DirectorEngine;
class DirectorSound;
class Frame;
+struct Label;
class Lingo;
class Sprite;
-enum CastType {
- kCastBitmap = 1,
- kCastFilmLoop,
- kCastText,
- kCastPalette,
- kCastPicture,
- kCastSound,
- kCastButton,
- kCastShape,
- kCastMovie,
- kCastDigitalVideo,
- kCastScript
-};
-
enum ScriptType {
kMovieScript = 0,
kSpriteScript = 1,
@@ -62,120 +50,12 @@ enum ScriptType {
kMaxScriptType = 2
};
-struct Cast {
- CastType type;
- Common::Rect initialRect;
- byte modified;
-};
-
-struct BitmapCast : Cast {
- BitmapCast(Common::SeekableSubReadStreamEndian &stream);
-
- Common::Rect boundingRect;
- uint16 regX;
- uint16 regY;
- uint8 flags;
- uint16 someFlaggyThing;
- uint16 unk1, unk2;
-};
-
-enum ShapeType {
- kShapeRectangle,
- kShapeRoundRect,
- kShapeOval,
- kShapeLine
-};
-
-struct ShapeCast : Cast {
- ShapeCast(Common::SeekableSubReadStreamEndian &stream);
-
- ShapeType shapeType;
- uint16 pattern;
- byte fgCol;
- byte bgCol;
- byte fillType;
- byte lineThickness;
- byte lineDirection;
-};
-
-enum TextType {
- kTextTypeAdjustToFit,
- kTextTypeScrolling,
- kTextTypeFixed
-};
-
-enum TextAlignType {
- kTextAlignRight = -1,
- kTextAlignLeft,
- kTextAlignCenter
-};
-
-enum TextFlag {
- kTextFlagEditable,
- kTextFlagAutoTab,
- kTextFlagDoNotWrap
-};
-
-enum SizeType {
- kSizeNone,
- kSizeSmallest,
- kSizeSmall,
- kSizeMedium,
- kSizeLarge,
- kSizeLargest
-};
-
-struct TextCast : Cast {
- TextCast(Common::SeekableSubReadStreamEndian &stream);
-
- SizeType borderSize;
- SizeType gutterSize;
- SizeType boxShadow;
-
- byte flags1;
- uint32 fontId;
- uint16 fontSize;
- TextType textType;
- TextAlignType textAlign;
- SizeType textShadow;
- Common::Array<TextFlag> textFlags;
- int16 palinfo1, palinfo2, palinfo3;
-};
-
-enum ButtonType {
- kTypeButton,
- kTypeCheckBox,
- kTypeRadio
-};
-
-struct ButtonCast : TextCast {
- ButtonCast(Common::SeekableSubReadStreamEndian &stream) : TextCast(stream) {
- buttonType = static_cast<ButtonType>(stream.readUint16BE());
- }
-
- ButtonType buttonType;
-};
-
-struct CastInfo {
- Common::String script;
- Common::String name;
- Common::String directory;
- Common::String fileName;
- Common::String type;
-};
-
-struct Label {
- Common::String name;
- uint16 number;
- Label(Common::String name1, uint16 number1) { name = name1; number = number1; }
-};
-
class Score {
public:
Score(DirectorEngine *vm, Archive *);
~Score();
- static Common::Rect readRect(Common::SeekableSubReadStreamEndian &stream);
+ static Common::Rect readRect(Common::ReadStreamEndian &stream);
static int compareLabels(const void *a, const void *b);
void loadArchive();
void setStartToLabel(Common::String label);
@@ -186,7 +66,8 @@ public:
void processEvents();
Archive *getArchive() const { return _movieArchive; };
void loadConfig(Common::SeekableSubReadStreamEndian &stream);
- void loadCastData(Common::SeekableSubReadStreamEndian &stream);
+ void loadCastDataVWCR(Common::SeekableSubReadStreamEndian &stream);
+ void loadCastData(Common::SeekableSubReadStreamEndian &stream, uint16 id);
void setCurrentFrame(uint16 frameId) { _currentFrame = frameId; }
int getCurrentFrame() { return _currentFrame; }
Common::String getMacName() const { return _macName; }
@@ -243,6 +124,6 @@ private:
DirectorEngine *_vm;
};
-} //End of namespace Director
+} // End of namespace Director
#endif
diff --git a/engines/director/sound.cpp b/engines/director/sound.cpp
index af08094821..1bd70d257d 100644
--- a/engines/director/sound.cpp
+++ b/engines/director/sound.cpp
@@ -102,4 +102,4 @@ void DirectorSound::stopSound() {
_mixer->stopHandle(*_sound2);
}
-} //End of namespace Director
+} // End of namespace Director
diff --git a/engines/director/sprite.cpp b/engines/director/sprite.cpp
index 24db236563..a59313ad33 100644
--- a/engines/director/sprite.cpp
+++ b/engines/director/sprite.cpp
@@ -21,6 +21,7 @@
*/
#include "director/director.h"
+#include "director/cast.h"
#include "director/score.h"
#include "director/sprite.h"
@@ -93,4 +94,4 @@ Sprite::~Sprite() {
delete _cast;
}
-} //End of namespace Director
+} // End of namespace Director
diff --git a/engines/director/sprite.h b/engines/director/sprite.h
index e879f83599..d248036693 100644
--- a/engines/director/sprite.h
+++ b/engines/director/sprite.h
@@ -51,18 +51,18 @@ enum InkType {
//Director v4
enum SpriteType {
- kInactiveSprite, //turns the sprite off
+ kInactiveSprite, // turns the sprite off
kBitmapSprite,
kRectangleSprite,
kRoundedRectangleSprite,
kOvalSprite,
- kLineTopBottomSprite, //line from top left to bottom right
- kLineBottomTopSprite, //line from bottom left to top right
+ kLineTopBottomSprite, // line from top left to bottom right
+ kLineBottomTopSprite, // line from bottom left to top right
kTextSprite,
kButtonSprite,
kCheckboxSprite,
kRadioButtonSprite,
- kUndeterminedSprite = 16 //use castType property to examine the type of cast member associated with sprite
+ kUndeterminedSprite = 16 // use castType property to examine the type of cast member associated with sprite
};
enum SpritePosition {
@@ -97,6 +97,14 @@ public:
Sprite();
Sprite(const Sprite &sprite);
~Sprite();
+
+ byte _x1;
+ uint16 _x2;
+ uint16 _scriptId;
+ byte _flags2; // x40 editable, 0x80 moveable
+ byte _unk2;
+ uint32 _unk3;
+
bool _enabled;
byte _castId;
InkType _ink;
@@ -106,8 +114,8 @@ public:
Common::Point _startPoint;
uint16 _width;
uint16 _height;
- //TODO: default constraint = 0, if turned on, sprite is constrainted to the bounding rect
- //As i know, constrainted != 0 only if sprite moveable
+ // TODO: default constraint = 0, if turned on, sprite is constrainted to the bounding rect
+ // As i know, constrainted != 0 only if sprite moveable
byte _constraint;
byte _moveable;
byte _backColor;
@@ -119,19 +127,19 @@ public:
byte _blend;
bool _visible;
SpriteType _type;
- //Using in digital movie sprites
+ // Using in digital movie sprites
byte _movieRate;
uint16 _movieTime;
uint16 _startTime;
uint16 _stopTime;
byte _volume;
byte _stretch;
- //Using in shape sprites
+ // Using in shape sprites
byte _lineSize;
- //Using in text sprites
+ // Using in text sprites
Common::String _editableText;
};
-} //End of namespace Director
+} // End of namespace Director
#endif
diff --git a/engines/dm/group.cpp b/engines/dm/group.cpp
index cf748ffa41..a72342da3d 100644
--- a/engines/dm/group.cpp
+++ b/engines/dm/group.cpp
@@ -1672,7 +1672,10 @@ int16 GroupMan::getChampionDamage(Group *group, uint16 champIndex) {
uint16 poisonAttack = creatureInfo._poisonAttack;
if (poisonAttack && _vm->getRandomNumber(2)) {
poisonAttack = championMan.getStatisticAdjustedAttack(curChampion, kDMStatVitality, poisonAttack);
- if (poisonAttack >= 0)
+
+ // Strangerke: In the original, the check was on >= 0, which is pretty useless for a unsigned variable.
+ // I changed the check to > 0 because, considering the code of championPoison, it avoids a potential bug.
+ if (poisonAttack > 0)
championMan.championPoison(champIndex, poisonAttack);
}
return damage;
diff --git a/engines/fullpipe/statics.cpp b/engines/fullpipe/statics.cpp
index 404a8edecc..bf769e2f61 100644
--- a/engines/fullpipe/statics.cpp
+++ b/engines/fullpipe/statics.cpp
@@ -547,7 +547,7 @@ void Movement::draw(bool flipFlag, int angle) {
if (flipFlag) {
bmp->flipVertical()->drawShaded(1, x, y + 30 + _currDynamicPhase->_rect->bottom, _currDynamicPhase->_paletteData, _currDynamicPhase->_alpha);
- } if (angle) {
+ } else if (angle) {
bmp->drawRotated(x, y, angle, _currDynamicPhase->_paletteData, _currDynamicPhase->_alpha);
} else {
bmp->putDib(x, y, (int32 *)_currDynamicPhase->_paletteData, _currDynamicPhase->_alpha);
diff --git a/engines/kyra/lol.h b/engines/kyra/lol.h
index af58397200..9f952e5df6 100644
--- a/engines/kyra/lol.h
+++ b/engines/kyra/lol.h
@@ -987,8 +987,7 @@ private:
uint16 _specialGuiShapeY;
uint16 _specialGuiShapeMirrorFlag;
- char _lastOverridePalFile[12];
- char *_lastOverridePalFilePtr;
+ Common::String _lastOverridePalFile;
int _lastSpecialColor;
int _lastSpecialColorWeight;
diff --git a/engines/kyra/scene_lol.cpp b/engines/kyra/scene_lol.cpp
index 391de5e49c..a746080190 100644
--- a/engines/kyra/scene_lol.cpp
+++ b/engines/kyra/scene_lol.cpp
@@ -303,12 +303,10 @@ void LoLEngine::loadLevelGraphics(const char *file, int specialColor, int weight
_lastSpecialColor = specialColor;
_lastSpecialColorWeight = weight;
strcpy(_lastBlockDataFile, file);
- if (palFile) {
- strcpy(_lastOverridePalFile, palFile);
- _lastOverridePalFilePtr = _lastOverridePalFile;
- } else {
- _lastOverridePalFilePtr = 0;
- }
+ if (palFile)
+ _lastOverridePalFile = palFile;
+ else
+ _lastOverridePalFile.clear();
}
if (_flags.use16ColorMode) {
@@ -361,8 +359,8 @@ void LoLEngine::loadLevelGraphics(const char *file, int specialColor, int weight
memcpy(_vcnColTable, v, 128);
v += 128;
- if (_lastOverridePalFilePtr) {
- _res->loadFileToBuf(_lastOverridePalFilePtr, _screen->getPalette(0).getData(), 384);
+ if (!_lastOverridePalFile.empty()) {
+ _res->loadFileToBuf(_lastOverridePalFile.c_str(), _screen->getPalette(0).getData(), 384);
} else {
_screen->getPalette(0).copy(v, 0, 128);
}
diff --git a/engines/kyra/timer.cpp b/engines/kyra/timer.cpp
index edca3ef5bf..97e989ea38 100644
--- a/engines/kyra/timer.cpp
+++ b/engines/kyra/timer.cpp
@@ -90,7 +90,7 @@ void TimerManager::reset() {
void TimerManager::addTimer(uint8 id, TimerFunc *func, int countdown, bool enabled) {
Iterator timer = Common::find_if(_timers.begin(), _timers.end(), TimerEqual(id));
if (timer != _timers.end()) {
- warning("Adding allready existing timer %d", id);
+ warning("Adding already existing timer %d", id);
return;
}
diff --git a/engines/lab/console.cpp b/engines/lab/console.cpp
index 20b1f5645b..a90c2605a7 100644
--- a/engines/lab/console.cpp
+++ b/engines/lab/console.cpp
@@ -81,7 +81,7 @@ bool Console::Cmd_DumpSceneResources(int argc, const char **argv) {
"ResetBuffer", "SpecialCmd", "CShowMessage", "PlaySoundNoWait"
};
- debugPrintf("Room mesage: %s\n", roomData->_roomMsg.c_str());
+ debugPrintf("Room message: %s\n", roomData->_roomMsg.c_str());
debugPrintf("Transition: %s (%d)\n", transitions[roomData->_transitionType], roomData->_transitionType);
debugPrintf("Script:\n");
diff --git a/engines/mads/palette.cpp b/engines/mads/palette.cpp
index 7651fe8e65..de870295a5 100644
--- a/engines/mads/palette.cpp
+++ b/engines/mads/palette.cpp
@@ -665,15 +665,15 @@ void Fader::insertionSort(int size, byte *id, byte *value) {
int moveCount = size - arrIndex - 1;
if (moveCount > 0) {
- Common::copy(idP + 1, idP + moveCount + 2, idP);
- Common::copy(valueP + 1, valueP + moveCount + 2, valueP);
+ Common::copy(idP + 1, idP + moveCount + 1, idP);
+ Common::copy(valueP + 1, valueP + moveCount + 1, valueP);
}
// Scan for insert spot
int idx = 0;
if (endIndex > 0) {
bool breakFlag = false;
- for (; idx <= endIndex && !breakFlag; ++idx) {
+ for (; idx <= endIndex - 1 && !breakFlag; ++idx) {
breakFlag = savedId < id[idx];
}
}
diff --git a/engines/mads/staticres.cpp b/engines/mads/staticres.cpp
index b659d9a27c..6cb76a1d89 100644
--- a/engines/mads/staticres.cpp
+++ b/engines/mads/staticres.cpp
@@ -43,7 +43,7 @@ const char *const kFenceStr = "fence";
const char *const kOverStr = "over";
const char *const kGameReleaseInfoStr = "ScummVM rev: 8.43 14-Sept-92";
-const char *const kGameReleaseTitleStr = "GAME RELASE VERSION INFO";
+const char *const kGameReleaseTitleStr = "GAME RELEASE VERSION INFO";
const uint32 DEFAULT_VGA_LOW_PALETTE[16] = {
0x000000, 0x0000a8, 0x00a800, 0x00a8a8, 0xa80000, 0xa800a8, 0xa85400, 0xa8a8a8,
diff --git a/engines/mohawk/POTFILES b/engines/mohawk/POTFILES
index ced02735c7..42d1d084c2 100644
--- a/engines/mohawk/POTFILES
+++ b/engines/mohawk/POTFILES
@@ -2,4 +2,5 @@ engines/mohawk/detection.cpp
engines/mohawk/dialogs.cpp
engines/mohawk/myst.cpp
engines/mohawk/riven.cpp
+engines/mohawk/riven_external.cpp
engines/mohawk/mohawk.cpp
diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp
index a1eef85a69..12b4851a9c 100644
--- a/engines/mohawk/riven.cpp
+++ b/engines/mohawk/riven.cpp
@@ -147,8 +147,8 @@ Common::Error MohawkEngine_Riven::run() {
// We need to have a cursor source, or the game won't work
if (!_cursor->hasSource()) {
- Common::String message = "You're missing a Riven executable. The Windows executable is 'riven.exe' or 'rivendmo.exe'. ";
- message += "Using the 'arcriven.z' installer file also works. In addition, you can use the Mac 'Riven' executable.";
+ Common::String message = _("You're missing a Riven executable. The Windows executable is 'riven.exe' or 'rivendmo.exe'. ");
+ message += _("Using the 'arcriven.z' installer file also works. In addition, you can use the Mac 'Riven' executable.");
GUIErrorMessage(message);
warning("%s", message.c_str());
return Common::kNoGameDataFoundError;
@@ -159,7 +159,7 @@ Common::Error MohawkEngine_Riven::run() {
// We need extras.mhk for inventory images, marble images, and credits images
if (!_extrasFile->openFile("extras.mhk")) {
- Common::String message = "You're missing 'extras.mhk'. Using the 'arcriven.z' installer file also works.";
+ Common::String message = _("You're missing 'extras.mhk'. Using the 'arcriven.z' installer file also works.");
GUIErrorMessage(message);
warning("%s", message.c_str());
return Common::kNoGameDataFoundError;
diff --git a/engines/mohawk/riven_external.cpp b/engines/mohawk/riven_external.cpp
index 125630445e..fb98145b44 100644
--- a/engines/mohawk/riven_external.cpp
+++ b/engines/mohawk/riven_external.cpp
@@ -30,6 +30,7 @@
#include "gui/message.h"
#include "common/events.h"
#include "common/system.h"
+#include "common/translation.h"
namespace Mohawk {
@@ -209,8 +210,8 @@ void RivenExternal::runCommand(uint16 argc, uint16 *argv) {
}
void RivenExternal::runDemoBoundaryDialog() {
- GUI::MessageDialog dialog("Exploration beyond this point available only within the full version of\n"
- "the game.");
+ GUI::MessageDialog dialog(_("Exploration beyond this point available only within the full version of\n"
+ "the game."));
dialog.runModal();
}
@@ -651,11 +652,11 @@ void RivenExternal::xalaunchbrowser(uint16 argc, uint16 *argv) {
//
// [YES] [NO]
- GUI::MessageDialog dialog("At this point, the Riven Demo would\n"
+ GUI::MessageDialog dialog(_("At this point, the Riven Demo would\n"
"ask if you would like to open a web browser\n"
"to bring you to the Red Orb store to buy\n"
"the game. ScummVM cannot do that and\n"
- "the site no longer exists.");
+ "the site no longer exists."));
dialog.runModal();
}
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index 8737c8b954..83f1271252 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -53,6 +53,7 @@
#ifdef ENABLE_SCI32
#include "sci/graphics/frameout.h"
#include "sci/graphics/paint32.h"
+#include "sci/graphics/palette32.h"
#include "video/coktel_decoder.h"
#endif
@@ -228,6 +229,8 @@ Console::Console(SciEngine *engine) : GUI::Debugger(),
registerCmd("view_listnode", WRAP_METHOD(Console, cmdViewListNode));
registerCmd("view_reference", WRAP_METHOD(Console, cmdViewReference));
registerCmd("vr", WRAP_METHOD(Console, cmdViewReference)); // alias
+ registerCmd("dump_reference", WRAP_METHOD(Console, cmdDumpReference));
+ registerCmd("dr", WRAP_METHOD(Console, cmdDumpReference)); // alias
registerCmd("view_object", WRAP_METHOD(Console, cmdViewObject));
registerCmd("vo", WRAP_METHOD(Console, cmdViewObject)); // alias
registerCmd("active_object", WRAP_METHOD(Console, cmdViewActiveObject));
@@ -446,6 +449,7 @@ bool Console::cmdHelp(int argc, const char **argv) {
debugPrintf(" value_type - Determines the type of a value\n");
debugPrintf(" view_listnode - Examines the list node at the given address\n");
debugPrintf(" view_reference / vr - Examines an arbitrary reference\n");
+ debugPrintf(" dump_reference / dr - Dumps an arbitrary reference to disk\n");
debugPrintf(" view_object / vo - Examines the object at the given address\n");
debugPrintf(" active_object - Shows information on the currently active object or class\n");
debugPrintf(" acc_object - Shows information on the object or class at the address indexed by the accumulator\n");
@@ -2843,6 +2847,125 @@ bool Console::cmdViewReference(int argc, const char **argv) {
return true;
}
+bool Console::cmdDumpReference(int argc, const char **argv) {
+ if (argc < 2) {
+ debugPrintf("Dumps an arbitrary reference to disk.\n");
+ debugPrintf("Usage: %s <start address> [<end address>]\n", argv[0]);
+ debugPrintf("Where <start address> is the starting address to dump\n");
+ debugPrintf("<end address>, if provided, is the address where the dump ends\n");
+ debugPrintf("Check the \"addresses\" command on how to use addresses\n");
+ return true;
+ }
+
+ reg_t reg = NULL_REG;
+ reg_t reg_end = NULL_REG;
+
+ if (parse_reg_t(_engine->_gamestate, argv[1], &reg, false)) {
+ debugPrintf("Invalid address passed.\n");
+ debugPrintf("Check the \"addresses\" command on how to use addresses\n");
+ return true;
+ }
+
+ if (argc > 2) {
+ if (parse_reg_t(_engine->_gamestate, argv[2], &reg_end, false)) {
+ debugPrintf("Invalid address passed.\n");
+ debugPrintf("Check the \"addresses\" command on how to use addresses\n");
+ return true;
+ }
+ }
+
+ if (reg.getSegment() == 0 && reg.getOffset() == 0) {
+ debugPrintf("Register is null.\n");
+ return true;
+ }
+
+ if (g_sci->getKernel()->findRegType(reg) != SIG_TYPE_REFERENCE) {
+ debugPrintf("%04x:%04x is not a reference\n", PRINT_REG(reg));
+ return true;
+ }
+
+ if (reg_end.getSegment() != reg.getSegment() && reg_end != NULL_REG) {
+ debugPrintf("Ending segment different from starting segment. Assuming no bound on dump.\n");
+ reg_end = NULL_REG;
+ }
+
+ Common::DumpFile out;
+ Common::String outFileName;
+ uint32 bytesWritten;
+
+ switch (_engine->_gamestate->_segMan->getSegmentType(reg.getSegment())) {
+#ifdef ENABLE_SCI32
+ case SEG_TYPE_BITMAP: {
+ outFileName = Common::String::format("%04x_%04x.tga", PRINT_REG(reg));
+ out.open(outFileName);
+ SciBitmap &bitmap = *_engine->_gamestate->_segMan->lookupBitmap(reg);
+ const Color *color = g_sci->_gfxPalette32->getCurrentPalette().colors;
+ const uint16 numColors = ARRAYSIZE(g_sci->_gfxPalette32->getCurrentPalette().colors);
+
+ out.writeByte(0); // image id length
+ out.writeByte(1); // color map type (present)
+ out.writeByte(1); // image type (uncompressed color-mapped)
+ out.writeSint16LE(0); // index of first color map entry
+ out.writeSint16LE(numColors); // number of color map entries
+ out.writeByte(24); // number of bits per color entry (RGB24)
+ out.writeSint16LE(0); // bottom-left x-origin
+ out.writeSint16LE(bitmap.getHeight() - 1); // bottom-left y-origin
+ out.writeSint16LE(bitmap.getWidth()); // width
+ out.writeSint16LE(bitmap.getHeight()); // height
+ out.writeByte(8); // bits per pixel
+ out.writeByte(1 << 5); // origin of pixel data (top-left)
+
+ bytesWritten = 18;
+
+ for (int i = 0; i < numColors; ++i) {
+ out.writeByte(color->b);
+ out.writeByte(color->g);
+ out.writeByte(color->r);
+ ++color;
+ }
+
+ bytesWritten += numColors * 3;
+ bytesWritten += out.write(bitmap.getPixels(), bitmap.getWidth() * bitmap.getHeight());
+ break;
+ }
+#endif
+
+ default: {
+ const SegmentRef block = _engine->_gamestate->_segMan->dereference(reg);
+ uint32 size = block.maxSize;
+
+ if (size == 0) {
+ debugPrintf("Size of reference is zero.\n");
+ return true;
+ }
+
+ if (reg_end.getSegment() != 0 && (size < reg_end.getOffset() - reg.getOffset())) {
+ debugPrintf("Block end out of bounds (size %d). Resetting.\n", size);
+ reg_end = NULL_REG;
+ }
+
+ if (reg_end.getSegment() != 0 && (size >= reg_end.getOffset() - reg.getOffset())) {
+ size = reg_end.getOffset() - reg.getOffset();
+ }
+
+ if (reg_end.getSegment() != 0) {
+ debugPrintf("Block size less than or equal to %d\n", size);
+ }
+
+ outFileName = Common::String::format("%04x_%04x.dmp", PRINT_REG(reg));
+ out.open(outFileName);
+ bytesWritten = out.write(block.raw, size);
+ break;
+ }
+ }
+
+ out.finalize();
+ out.close();
+
+ debugPrintf("Wrote %u bytes to %s\n", bytesWritten, outFileName.c_str());
+ return true;
+}
+
bool Console::cmdViewObject(int argc, const char **argv) {
if (argc != 2) {
debugPrintf("Examines the object at the given address.\n");
@@ -4530,7 +4653,7 @@ int Console::printObject(reg_t pos) {
uint i;
if (!obj) {
- debugPrintf("[%04x:%04x]: Not an object.", PRINT_REG(pos));
+ debugPrintf("[%04x:%04x]: Not an object.\n", PRINT_REG(pos));
return 1;
}
diff --git a/engines/sci/console.h b/engines/sci/console.h
index 0b87a4408b..d4b17ee802 100644
--- a/engines/sci/console.h
+++ b/engines/sci/console.h
@@ -163,6 +163,7 @@ private:
bool cmdValueType(int argc, const char **argv);
bool cmdViewListNode(int argc, const char **argv);
bool cmdViewReference(int argc, const char **argv);
+ bool cmdDumpReference(int argc, const char **argv);
bool cmdViewObject(int argc, const char **argv);
bool cmdViewActiveObject(int argc, const char **argv);
bool cmdViewAccumulatorObject(int argc, const char **argv);
diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp
index 83f1d30916..a00da7c5fd 100644
--- a/engines/sci/detection.cpp
+++ b/engines/sci/detection.cpp
@@ -556,7 +556,7 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles,
s_fallbackDesc.guiOptions = GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI);
if (allFiles.contains("resource.map") || allFiles.contains("Data1")
- || allFiles.contains("resmap.001") || allFiles.contains("resmap.001")) {
+ || allFiles.contains("resmap.000") || allFiles.contains("resmap.001")) {
foundResMap = true;
}
diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h
index 22d2b6f308..4a3d13cbed 100644
--- a/engines/sci/detection_tables.h
+++ b/engines/sci/detection_tables.h
@@ -3398,7 +3398,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformDOS, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
- // Quest for Glory 1 / Hero's Quest - English DOS 3.5" Floppy (supplied by alonzotg in bug report #3206006)
+ // Quest for Glory 1 / Hero's Quest - English DOS 3.5" Floppy v1.001 Int#0.000.566 (supplied by alonzotg in bug report #3206006)
{"qfg1", "", {
{"resource.map", 0, "85512508ed4e4ef1e3b309adabceeda9", 6486},
{"resource.000", 0, "481b034132106390cb5160fe61dd5f58", 80334},
diff --git a/engines/sci/engine/features.h b/engines/sci/engine/features.h
index 15c80a7277..36b0d06360 100644
--- a/engines/sci/engine/features.h
+++ b/engines/sci/engine/features.h
@@ -117,6 +117,17 @@ public:
inline bool hasNewPaletteCode() const {
return getSciVersion() >= SCI_VERSION_2_1_MIDDLE || g_sci->getGameId() == GID_KQ7;
}
+
+ inline bool VMDOpenStopsAudio() const {
+ // Of the games that use VMDs:
+ // Yes: Phant1, Shivers, Torin
+ // No: SQ6
+ // TODO: Optional extra flag to kPlayVMD which defaults to Yes: PQ:SWAT
+ // TODO: SCI3, GK2 (GK2's VMD code is closer to SCI3 than SCI21)
+ return getSciVersion() == SCI_VERSION_2_1_MIDDLE &&
+ g_sci->getGameId() != GID_SQ6 &&
+ g_sci->getGameId() != GID_GK2;
+ }
#endif
/**
diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index cce9a223d3..03c8a673a8 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -466,6 +466,7 @@ reg_t kPlayVMD(EngineState *s, int argc, reg_t *argv);
reg_t kPlayVMDOpen(EngineState *s, int argc, reg_t *argv);
reg_t kPlayVMDInit(EngineState *s, int argc, reg_t *argv);
reg_t kPlayVMDClose(EngineState *s, int argc, reg_t *argv);
+reg_t kPlayVMDIgnorePalettes(EngineState *s, int argc, reg_t *argv);
reg_t kPlayVMDGetStatus(EngineState *s, int argc, reg_t *argv);
reg_t kPlayVMDPlayUntilEvent(EngineState *s, int argc, reg_t *argv);
reg_t kPlayVMDShowCursor(EngineState *s, int argc, reg_t *argv);
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index 6e88112992..8093147cb4 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -466,6 +466,7 @@ static const SciKernelMapSubEntry kPlayVMD_subops[] = {
{ SIG_SINCE_SCI21, 0, MAP_CALL(PlayVMDOpen), "r(i)(i)", NULL },
{ SIG_SINCE_SCI21, 1, MAP_CALL(PlayVMDInit), "ii(i)(i)(ii)", NULL },
{ SIG_SINCE_SCI21, 6, MAP_CALL(PlayVMDClose), "", NULL },
+ { SIG_SINCE_SCI21, 7, MAP_CALL(PlayVMDIgnorePalettes), "", NULL },
{ SIG_SINCE_SCI21, 10, MAP_CALL(PlayVMDGetStatus), "", NULL },
{ SIG_SINCE_SCI21, 14, MAP_CALL(PlayVMDPlayUntilEvent), "i(i)(i)", NULL },
{ SIG_SINCE_SCI21, 16, MAP_CALL(PlayVMDShowCursor), "i", NULL },
diff --git a/engines/sci/engine/kstring.cpp b/engines/sci/engine/kstring.cpp
index 6ec61343b0..74c1f99778 100644
--- a/engines/sci/engine/kstring.cpp
+++ b/engines/sci/engine/kstring.cpp
@@ -733,11 +733,12 @@ namespace {
}
bool isSignedType(const char type) {
- return type == 'd' || type == 'i';
+ // For whatever reason, %d ends up being treated as unsigned in SSCI
+ return type == 'i';
}
bool isUnsignedType(const char type) {
- return strchr("uxXoc", type);
+ return strchr("duxXoc", type);
}
bool isStringType(const char type) {
@@ -805,8 +806,11 @@ Common::String format(const Common::String &source, int argc, const reg_t *argv)
continue;
}
- assert(argIndex < argc);
- out += readPlaceholder(in, argv[argIndex++]);
+ if (argIndex < argc) {
+ out += readPlaceholder(in, argv[argIndex++]);
+ } else {
+ out += readPlaceholder(in, NULL_REG);
+ }
} else {
out += *in++;
}
diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp
index 83a02883af..11378d7647 100644
--- a/engines/sci/engine/kvideo.cpp
+++ b/engines/sci/engine/kvideo.cpp
@@ -428,6 +428,11 @@ reg_t kPlayVMDClose(EngineState *s, int argc, reg_t *argv) {
return make_reg(0, g_sci->_video32->getVMDPlayer().close());
}
+reg_t kPlayVMDIgnorePalettes(EngineState *s, int argc, reg_t *argv) {
+ g_sci->_video32->getVMDPlayer().ignorePalettes();
+ return s->r_acc;
+}
+
reg_t kPlayVMDGetStatus(EngineState *s, int argc, reg_t *argv) {
return make_reg(0, g_sci->_video32->getVMDPlayer().getStatus());
}
diff --git a/engines/sci/engine/message.cpp b/engines/sci/engine/message.cpp
index b0615b4213..26ab9b47a5 100644
--- a/engines/sci/engine/message.cpp
+++ b/engines/sci/engine/message.cpp
@@ -333,12 +333,14 @@ void MessageState::popCursorStack() {
error("Message: attempt to pop from empty stack");
}
-int MessageState::hexDigitToInt(char h) {
+int MessageState::hexDigitToWrongInt(char h) {
+ // Hex digits above 9 are incorrectly interpreted by SSCI as 11-16 instead
+ // of 10-15 because of a never-fixed typo
if ((h >= 'A') && (h <= 'F'))
- return h - 'A' + 10;
+ return h - 'A' + 11;
if ((h >= 'a') && (h <= 'f'))
- return h - 'a' + 10;
+ return h - 'a' + 11;
if ((h >= '0') && (h <= '9'))
return h - '0';
@@ -355,8 +357,8 @@ bool MessageState::stringHex(Common::String &outStr, const Common::String &inStr
if (index + 2 >= inStr.size())
return false;
- int digit1 = hexDigitToInt(inStr[index + 1]);
- int digit2 = hexDigitToInt(inStr[index + 2]);
+ int digit1 = hexDigitToWrongInt(inStr[index + 1]);
+ int digit2 = hexDigitToWrongInt(inStr[index + 2]);
// Check for hex
if ((digit1 == -1) || (digit2 == -1))
diff --git a/engines/sci/engine/message.h b/engines/sci/engine/message.h
index ff76534d2d..5847e4767e 100644
--- a/engines/sci/engine/message.h
+++ b/engines/sci/engine/message.h
@@ -73,7 +73,7 @@ private:
bool getRecord(CursorStack &stack, bool recurse, MessageRecord &record);
void outputString(reg_t buf, const Common::String &str);
Common::String processString(const char *s);
- int hexDigitToInt(char h);
+ int hexDigitToWrongInt(char h);
bool stringHex(Common::String &outStr, const Common::String &inStr, uint &index);
bool stringLit(Common::String &outStr, const Common::String &inStr, uint &index);
bool stringStage(Common::String &outStr, const Common::String &inStr, uint &index);
diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp
index 2e4da46b70..720f6783ee 100644
--- a/engines/sci/engine/savegame.cpp
+++ b/engines/sci/engine/savegame.cpp
@@ -643,20 +643,33 @@ void SoundCommandParser::reconstructPlayList() {
_music->_mutex.unlock();
for (MusicList::iterator i = songs.begin(); i != songs.end(); ++i) {
- initSoundResource(*i);
+ MusicEntry *entry = *i;
+ initSoundResource(entry);
- if ((*i)->status == kSoundPlaying) {
+#ifdef ENABLE_SCI32
+ if (_soundVersion >= SCI_VERSION_2_1_EARLY && entry->isSample) {
+ const reg_t &soundObj = entry->soundObj;
+
+ if ((int)readSelectorValue(_segMan, soundObj, SELECTOR(loop)) != -1 &&
+ readSelector(_segMan, soundObj, SELECTOR(handle)) != NULL_REG) {
+
+ writeSelector(_segMan, soundObj, SELECTOR(handle), NULL_REG);
+ processPlaySound(soundObj, entry->playBed);
+ }
+ } else
+#endif
+ if (entry->status == kSoundPlaying) {
// WORKAROUND: PQ3 (German?) scripts can set volume negative in the
// sound object directly without going through DoSound.
// Since we re-read this selector when re-playing the sound after loading,
// this will lead to unexpected behaviour. As a workaround we
// sync the sound object's selectors here. (See bug #5501)
- writeSelectorValue(_segMan, (*i)->soundObj, SELECTOR(loop), (*i)->loop);
- writeSelectorValue(_segMan, (*i)->soundObj, SELECTOR(priority), (*i)->priority);
+ writeSelectorValue(_segMan, entry->soundObj, SELECTOR(loop), entry->loop);
+ writeSelectorValue(_segMan, entry->soundObj, SELECTOR(priority), entry->priority);
if (_soundVersion >= SCI_VERSION_1_EARLY)
- writeSelectorValue(_segMan, (*i)->soundObj, SELECTOR(vol), (*i)->volume);
+ writeSelectorValue(_segMan, entry->soundObj, SELECTOR(vol), entry->volume);
- processPlaySound((*i)->soundObj, (*i)->playBed);
+ processPlaySound(entry->soundObj, entry->playBed);
}
}
}
diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index 5ac4b758ba..5f3370bad5 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -2190,8 +2190,27 @@ static const SciScriptPatcherEntry larry6Signatures[] = {
#pragma mark -
#pragma mark Leisure Suit Larry 6 Hires
+// When entering room 270 (diving board) from room 230, a typo in the game
+// script means that `setScale` is called accidentally instead of `setScaler`.
+// In SSCI this did not do much because the first argument happened to be
+// smaller than the y-position of `ego`, but in ScummVM the first argument is
+// larger and so a debug message "y value less than vanishingY" is displayed.
+static const uint16 larry6HiresSignatureSetScale[] = {
+ SIG_MAGICDWORD,
+ 0x38, SIG_UINT16(0x14b), // pushi 014b (setScale)
+ 0x38, SIG_UINT16(0x05), // pushi 0005
+ 0x51, 0x2c, // class 2c (Scaler)
+ SIG_END
+};
+
+static const uint16 larry6HiresPatchSetScale[] = {
+ 0x38, SIG_UINT16(0x14f), // pushi 014f (setScaler)
+ PATCH_END
+};
+
// script, description, signature patch
static const SciScriptPatcherEntry larry6HiresSignatures[] = {
+ { true, 270, "fix incorrect setScale call", 1, larry6HiresSignatureSetScale, larry6HiresPatchSetScale },
{ true, 64990, "increase number of save games", 1, sci2NumSavesSignature1, sci2NumSavesPatch1 },
{ true, 64990, "increase number of save games", 1, sci2NumSavesSignature2, sci2NumSavesPatch2 },
{ true, 64990, "disable change directory button", 1, sci2ChangeDirSignature, sci2ChangeDirPatch },
diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h
index 361c1cb895..e8f0be3a79 100644
--- a/engines/sci/engine/segment.h
+++ b/engines/sci/engine/segment.h
@@ -552,8 +552,17 @@ public:
case kArrayTypeID:
return ((reg_t *)_data)[index];
case kArrayTypeByte:
- case kArrayTypeString:
- return make_reg(0, ((byte *)_data)[index]);
+ case kArrayTypeString: {
+ int16 value;
+
+ if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
+ value = ((int8 *)_data)[index];
+ } else {
+ value = ((uint8 *)_data)[index];
+ }
+
+ return make_reg(0, value);
+ }
default:
error("Invalid array type %d", _type);
}
diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp
index dabf79a54b..4e9c59b225 100644
--- a/engines/sci/engine/workarounds.cpp
+++ b/engines/sci/engine/workarounds.cpp
@@ -399,6 +399,7 @@ const SciWorkaroundEntry kAbs_workarounds[] = {
// gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround
const SciWorkaroundEntry kArraySetElements_workarounds[] = {
+ { GID_GK1, 302, 64918, 0, "Str", "callKernel", NULL, 0, { WORKAROUND_FAKE, 0 } }, // when erasing a letter on the wall in St Louis Cemetery
{ GID_PHANTASMAGORIA,902, 64918, 0, "Str", "callKernel", NULL, 0, { WORKAROUND_FAKE, 0 } }, // tries to set an element of a string array to the ego object when starting a new game and selecting a chapter above 1
SCI_WORKAROUNDENTRY_TERMINATOR
};
@@ -684,21 +685,6 @@ const SciWorkaroundEntry kNewWindow_workarounds[] = {
};
// gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround
-const SciWorkaroundEntry kNumCels_workarounds[] = {
- { GID_GK1, 460, 64998, -1, "GKEgo", "lastCel", NULL, -1, { WORKAROUND_FAKE, 5 } }, // when Gabriel clicks "ask" on the bartender from a distance
- { GID_GK1, 808, 64998, -1, "sDJEnters", "changeState", NULL, -1, { WORKAROUND_FAKE, 6 } }, //
- { GID_GK2, 470, 64998, -1, "pLookieLoos", "lastCel", NULL, -1, { WORKAROUND_FAKE, 50 } }, // random background movement in the crime scene in Munich city centre
- { GID_GK2, 470, 64998, -1, "pNewsCrew", "lastCel", NULL, -1, { WORKAROUND_FAKE, 18 } }, // random background movement in the crime scene in Munich city centre
- { GID_GK2, 470, 64998, -1, "pLeberGroup", "lastCel", NULL, -1, { WORKAROUND_FAKE, 22 } }, // random background movement in the crime scene in Munich city centre
- { GID_SQ6, 270, 64998, -1, "offWorld", "lastCel", NULL, -1, { WORKAROUND_FAKE, 3 } }, // when exiting the kidnapping room
- { GID_SQ6, 320, 64998, -1, "wandererB", "lastCel", NULL, -1, { WORKAROUND_FAKE, 8 } }, // random background movement on Polysorbate LX street 3
- { GID_SQ6, 340, 64998, -1, "wandererB", "lastCel", NULL, -1, { WORKAROUND_FAKE, 8 } }, // random background movement on Polysorbate LX street 1
- { GID_SQ6, 530, 64998, -1, "monitors", "lastCel", NULL, -1, { WORKAROUND_FAKE, 5 } }, // random background movement during cutscene
- { GID_SQ6, 680, 64998, -1, "ego", "lastCel", NULL, -1, { WORKAROUND_FAKE, 44 } }, // when double-clicking hand icon on blockage
- SCI_WORKAROUNDENTRY_TERMINATOR
-};
-
-// gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround
const SciWorkaroundEntry kPalVarySetPercent_workarounds[] = {
{ GID_GK1, 370, 370, 0, "graceComeOut", "changeState", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // there's an extra parameter in GK1, when changing chapters. This extra parameter seems to be a bug or just unimplemented functionality, as there's no visible change from the original in the chapter change room
SCI_WORKAROUNDENTRY_TERMINATOR
diff --git a/engines/sci/engine/workarounds.h b/engines/sci/engine/workarounds.h
index c50a7fb04e..2d72ae5811 100644
--- a/engines/sci/engine/workarounds.h
+++ b/engines/sci/engine/workarounds.h
@@ -85,7 +85,6 @@ extern const SciWorkaroundEntry kIsObject_workarounds[];
extern const SciWorkaroundEntry kMemory_workarounds[];
extern const SciWorkaroundEntry kMoveCursor_workarounds[];
extern const SciWorkaroundEntry kNewWindow_workarounds[];
-extern const SciWorkaroundEntry kNumCels_workarounds[];
extern const SciWorkaroundEntry kPalVarySetPercent_workarounds[];
extern const SciWorkaroundEntry kRandom_workarounds[];
extern const SciWorkaroundEntry kReadNumber_workarounds[];
diff --git a/engines/sci/graphics/celobj32.cpp b/engines/sci/graphics/celobj32.cpp
index 430500ce1e..09ea05bd59 100644
--- a/engines/sci/graphics/celobj32.cpp
+++ b/engines/sci/graphics/celobj32.cpp
@@ -800,7 +800,7 @@ int16 CelObjView::getNumLoops(const GuiResourceId viewId) {
return resource->data[2];
}
-int16 CelObjView::getNumCels(const GuiResourceId viewId, const int16 loopNo) {
+int16 CelObjView::getNumCels(const GuiResourceId viewId, int16 loopNo) {
const Resource *const resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, viewId), false);
if (!resource) {
@@ -813,25 +813,15 @@ int16 CelObjView::getNumCels(const GuiResourceId viewId, const int16 loopNo) {
// Every version of SCI32 has a logic error in this function that causes
// random memory to be read if a script requests the cel count for one
- // past the maximum loop index. At least GK1 room 800 does this, and gets
- // stuck in an infinite loop because the game script expects this method
- // to return a non-zero value.
- // The scope of this bug means it is likely to pop up in other games, so we
- // explicitly trap the bad condition here and report it so that any other
- // game scripts relying on this broken behavior can be fixed as well
+ // past the maximum loop index. For example, GK1 room 808 does this, and
+ // gets stuck in an infinite loop because the game script expects this
+ // method to return a non-zero value.
+ // This bug is triggered in basically every SCI32 game and appears to be
+ // universally fixable simply by always using the next lowest loop instead.
if (loopNo == loopCount) {
- SciCallOrigin origin;
- SciWorkaroundSolution solution = trackOriginAndFindWorkaround(0, kNumCels_workarounds, &origin);
- switch (solution.type) {
- case WORKAROUND_NONE:
- error("[CelObjView::getNumCels]: loop number %d is equal to loop count in view %u, %s", loopNo, viewId, origin.toString().c_str());
- case WORKAROUND_FAKE:
- return (int16)solution.value;
- case WORKAROUND_IGNORE:
- return 0;
- case WORKAROUND_STILLCALL:
- break;
- }
+ const SciCallOrigin origin = g_sci->getEngineState()->getCurrentCallOrigin();
+ debugC(kDebugLevelWorkarounds, "Workaround: kNumCels loop %d -> loop %d in view %u, %s", loopNo, loopNo - 1, viewId, origin.toString().c_str());
+ --loopNo;
}
if (loopNo > loopCount || loopNo < 0) {
diff --git a/engines/sci/graphics/lists32.h b/engines/sci/graphics/lists32.h
index 4f74c77325..ff0bc6ceae 100644
--- a/engines/sci/graphics/lists32.h
+++ b/engines/sci/graphics/lists32.h
@@ -170,6 +170,13 @@ public:
}
/**
+ * The maximum number of elements the container is able to hold.
+ */
+ size_type max_size() const {
+ return N;
+ }
+
+ /**
* The number of populated slots in the array. The size
* of the array will only go down once `pack` is called.
*/
diff --git a/engines/sci/graphics/palette32.h b/engines/sci/graphics/palette32.h
index 81e9bbbfd3..c4cfb35096 100644
--- a/engines/sci/graphics/palette32.h
+++ b/engines/sci/graphics/palette32.h
@@ -23,7 +23,6 @@
#ifndef SCI_GRAPHICS_PALETTE32_H
#define SCI_GRAPHICS_PALETTE32_H
-#include "sci/graphics/palette.h"
namespace Sci {
#pragma mark HunkPalette
diff --git a/engines/sci/graphics/screen.cpp b/engines/sci/graphics/screen.cpp
index 23e92ef6a9..de6df39bb9 100644
--- a/engines/sci/graphics/screen.cpp
+++ b/engines/sci/graphics/screen.cpp
@@ -84,11 +84,6 @@ GfxScreen::GfxScreen(ResourceManager *resMan) : _resMan(resMan) {
}
}
- if (_resMan->detectHires()) {
- _scriptWidth = 640;
- _scriptHeight = 480;
- }
-
// if not yet set, set those to script-width/height
if (!_width)
_width = _scriptWidth;
diff --git a/engines/sci/graphics/text32.cpp b/engines/sci/graphics/text32.cpp
index d142ff75c3..7375fdeffd 100644
--- a/engines/sci/graphics/text32.cpp
+++ b/engines/sci/graphics/text32.cpp
@@ -527,7 +527,7 @@ int16 GfxText32::getTextWidth(const uint index, uint length) const {
--length;
}
} else {
- width += font->getCharWidth(currentChar);
+ width += font->getCharWidth((unsigned char)currentChar);
}
if (length > 0) {
diff --git a/engines/sci/graphics/transitions32.cpp b/engines/sci/graphics/transitions32.cpp
index ddcb50b140..bad0185179 100644
--- a/engines/sci/graphics/transitions32.cpp
+++ b/engines/sci/graphics/transitions32.cpp
@@ -778,7 +778,7 @@ bool GfxTransitions32::processPixelDissolve21Mid(const PlaneShowStyle &showStyle
int seq = 1;
uint iteration = 0;
- const uint numIterationsPerTick = ARRAYSIZE(g_sci->_gfxFrameout->_showList);
+ const uint numIterationsPerTick = g_sci->_gfxFrameout->_showList.max_size();
clearShowRects();
diff --git a/engines/sci/graphics/video32.cpp b/engines/sci/graphics/video32.cpp
index 1db66644c8..bf0c990015 100644
--- a/engines/sci/graphics/video32.cpp
+++ b/engines/sci/graphics/video32.cpp
@@ -28,6 +28,7 @@
#include "engine.h" // for Engine, g_engine
#include "engines/util.h" // for initGraphics
#include "sci/console.h" // for Console
+#include "sci/engine/features.h" // for GameFeatures
#include "sci/engine/state.h" // for EngineState
#include "sci/engine/vm_types.h" // for reg_t
#include "sci/event.h" // for SciEvent, EventManager, SCI_...
@@ -39,10 +40,12 @@
#include "sci/graphics/plane32.h" // for Plane, PlanePictureCodes::kP...
#include "sci/graphics/screen_item32.h" // for ScaleInfo, ScreenItem, Scale...
#include "sci/sci.h" // for SciEngine, g_sci, getSciVersion
-#include "sci/graphics/video32.h"
+#include "sci/sound/audio32.h" // for Audio32
#include "sci/video/seq_decoder.h" // for SEQDecoder
#include "video/avi_decoder.h" // for AVIDecoder
#include "video/coktel_decoder.h" // for AdvancedVMDDecoder
+#include "sci/graphics/video32.h"
+
namespace Graphics { struct Surface; }
namespace Sci {
@@ -68,7 +71,8 @@ void SEQPlayer::play(const Common::String &fileName, const int16 numTicks, const
// mechanism that is very similar to that used by the VMD player, which
// allows the SEQ to be drawn into a bitmap ScreenItem and displayed using
// the normal graphics system.
- _segMan->allocateBitmap(&_bitmap, _decoder->getWidth(), _decoder->getHeight(), kDefaultSkipColor, 0, 0, kLowResX, kLowResY, 0, false, false);
+ SciBitmap &bitmap = *_segMan->allocateBitmap(&_bitmap, _decoder->getWidth(), _decoder->getHeight(), kDefaultSkipColor, 0, 0, kLowResX, kLowResY, 0, false, false);
+ bitmap.getBuffer().fillRect(Common::Rect(_decoder->getWidth(), _decoder->getHeight()), 0);
CelInfo32 celInfo;
celInfo.type = kCelTypeMem;
@@ -163,49 +167,37 @@ AVIPlayer::IOStatus AVIPlayer::init1x(const int16 x, const int16 y, int16 width,
_pixelDouble = false;
if (!width || !height) {
- width = _decoder->getWidth();
- height = _decoder->getHeight();
- } else if (getSciVersion() == SCI_VERSION_2_1_EARLY && g_sci->getGameId() == GID_KQ7) {
- // KQ7 1.51 provides an explicit width and height when it wants scaling,
- // though the width and height it provides are not scaled
- _pixelDouble = true;
- width *= 2;
- height *= 2;
- }
-
- // QFG4CD gives non-multiple-of-2 values for width and height,
- // which would normally be OK except the source video is a pixel bigger
- // in each dimension
+ const int16 screenWidth = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth;
+ const int16 screenHeight = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight;
+ const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
+ const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
+ const Ratio screenToScriptX(scriptWidth, screenWidth);
+ const Ratio screenToScriptY(scriptHeight, screenHeight);
+ width = (_decoder->getWidth() * screenToScriptX).toInt();
+ height = (_decoder->getHeight() * screenToScriptY).toInt();
+ }
+
+ // QFG4CD gives non-multiple-of-2 values for width and height of the intro
+ // video, which would normally be OK except the source video is a pixel
+ // bigger in each dimension so it just causes part of the video to get cut
+ // off
width = (width + 1) & ~1;
height = (height + 1) & ~1;
- _drawRect.left = x;
- _drawRect.top = y;
- _drawRect.right = x + width;
- _drawRect.bottom = y + height;
-
- // SCI2.1mid uses init2x to draw a pixel-doubled AVI, but SCI2 has only the
- // one play routine which automatically pixel-doubles in hi-res mode
- if (getSciVersion() == SCI_VERSION_2) {
- // This is somewhat of a hack; credits.avi from GK1 is not
- // rendered correctly in SSCI because it is a 640x480 video, but the
- // game script gives the wrong dimensions. Since this is the only
- // high-resolution AVI ever used, just set the draw rectangle to draw
- // the entire screen
- if (_decoder->getWidth() > 320) {
- _drawRect.left = 0;
- _drawRect.top = 0;
- _drawRect.right = 320;
- _drawRect.bottom = 200;
- }
-
- // In hi-res mode, video will be pixel doubled, so the origin (which
- // corresponds to the correct position without pixel doubling) needs to
- // be corrected
- if (g_sci->_gfxFrameout->_isHiRes && _decoder->getWidth() <= 320) {
- _drawRect.left /= 2;
- _drawRect.top /= 2;
- }
+ // GK1 CREDITS.AVI is not rendered correctly in SSCI because it is a 640x480
+ // video and the game script gives the wrong dimensions.
+ // Since this is the only high-resolution AVI ever used by any SCI game,
+ // just set the draw rectangle to draw across the entire screen
+ if (g_sci->getGameId() == GID_GK1 && _decoder->getWidth() > 320) {
+ _drawRect.left = 0;
+ _drawRect.top = 0;
+ _drawRect.right = 320;
+ _drawRect.bottom = 200;
+ } else {
+ _drawRect.left = x;
+ _drawRect.top = y;
+ _drawRect.right = x + width;
+ _drawRect.bottom = y + height;
}
init();
@@ -222,8 +214,8 @@ AVIPlayer::IOStatus AVIPlayer::init2x(const int16 x, const int16 y) {
_drawRect.top = y;
_drawRect.right = x + _decoder->getWidth() * 2;
_drawRect.bottom = y + _decoder->getHeight() * 2;
-
_pixelDouble = true;
+
init();
return kIOSuccess;
@@ -233,42 +225,38 @@ void AVIPlayer::init() {
int16 xRes;
int16 yRes;
- bool useScreenDimensions = false;
- if (g_sci->_gfxFrameout->_isHiRes && _decoder->getWidth() > 320) {
- useScreenDimensions = true;
- }
-
- // KQ7 1.51 gives video position in screen coordinates, not game
- // coordinates, because in SSCI they are passed to Video for Windows, which
- // renders as an overlay on the game video. Because we put the video into a
- // ScreenItem instead of rendering directly to the hardware surface, the
- // coordinates need to be converted to game script coordinates
- if (g_sci->getGameId() == GID_KQ7 && getSciVersion() == SCI_VERSION_2_1_EARLY) {
- useScreenDimensions = !_pixelDouble;
- // This y-translation is arbitrary, based on what roughly centers the
- // videos in the game window
- _drawRect.translate(-_drawRect.left / 2, -_drawRect.top * 2 / 3);
- }
-
- if (useScreenDimensions) {
+ // GK1 CREDITS.AVI or KQ7 1.51 half-size videos
+ if ((g_sci->_gfxFrameout->_isHiRes && _decoder->getWidth() > 320) ||
+ (g_sci->getGameId() == GID_KQ7 && getSciVersion() == SCI_VERSION_2_1_EARLY && _drawRect.width() <= 160)) {
xRes = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth;
yRes = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight;
} else {
xRes = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
- yRes = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
+
+ const Ratio videoRatio(_decoder->getWidth(), _decoder->getHeight());
+ const Ratio screenRatio(4, 3);
+
+ // Videos that already have a 4:3 aspect ratio should not receive any
+ // aspect ratio correction
+ if (videoRatio == screenRatio) {
+ yRes = 240;
+ } else {
+ yRes = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
+ }
}
_plane = new Plane(_drawRect);
g_sci->_gfxFrameout->addPlane(*_plane);
if (_decoder->getPixelFormat().bytesPerPixel == 1) {
- _segMan->allocateBitmap(&_bitmap, _decoder->getWidth(), _decoder->getHeight(), kDefaultSkipColor, 0, 0, xRes, yRes, 0, false, false);
+ SciBitmap &bitmap = *_segMan->allocateBitmap(&_bitmap, _decoder->getWidth(), _decoder->getHeight(), kDefaultSkipColor, 0, 0, xRes, yRes, 0, false, false);
+ bitmap.getBuffer().fillRect(Common::Rect(_decoder->getWidth(), _decoder->getHeight()), 0);
CelInfo32 celInfo;
celInfo.type = kCelTypeMem;
celInfo.bitmap = _bitmap;
- _screenItem = new ScreenItem(_plane->_object, celInfo, Common::Point(_drawRect.left, _drawRect.top), ScaleInfo());
+ _screenItem = new ScreenItem(_plane->_object, celInfo, Common::Point(), ScaleInfo());
g_sci->_gfxFrameout->addScreenItem(*_screenItem);
g_sci->_gfxFrameout->frameOut(true);
} else {
@@ -384,7 +372,7 @@ void AVIPlayer::renderFrame() const {
const uint8 *end = (const uint8 *)surface->getPixels() + surface->w * surface->h;
while (source != end) {
- uint8 value = *source++;
+ const uint8 value = *source++;
*target++ = value == 0 ? 255 : value;
}
} else {
@@ -414,12 +402,19 @@ void AVIPlayer::renderFrame() const {
} else {
assert(surface->format.bytesPerPixel == 4);
+ const int16 screenWidth = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth;
+ const int16 screenHeight = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight;
+ const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
+ const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
+
Common::Rect drawRect(_drawRect);
+ mulru(drawRect, Ratio(screenWidth, scriptWidth), Ratio(screenHeight, scriptHeight), 1);
if (_pixelDouble) {
const uint32 *source = (const uint32 *)surface->getPixels();
uint32 *target = (uint32 *)_scaleBuffer;
- // target pitch here is in uint32s, not bytes
+ // target pitch here is in uint32s, not bytes, because the surface
+ // bpp is 4
const uint16 pitch = surface->pitch / 2;
for (int y = 0; y < surface->h; ++y) {
for (int x = 0; x < surface->w; ++x) {
@@ -434,17 +429,12 @@ void AVIPlayer::renderFrame() const {
target += pitch;
}
- g_system->copyRectToScreen(_scaleBuffer, surface->pitch * 2, _drawRect.left, _drawRect.top, _drawRect.width(), _drawRect.height());
+ g_system->copyRectToScreen(_scaleBuffer, surface->pitch * 2, drawRect.left, drawRect.top, _drawRect.width(), _drawRect.height());
} else {
- const int16 screenWidth = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth;
- const int16 screenHeight = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight;
- const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
- const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
-
- mulinc(drawRect, Ratio(screenWidth, scriptWidth), Ratio(screenHeight, scriptHeight));
-
g_system->copyRectToScreen(surface->getPixels(), surface->pitch, drawRect.left, drawRect.top, surface->w, surface->h);
}
+
+ g_system->updateScreen();
}
}
@@ -500,6 +490,7 @@ VMDPlayer::VMDPlayer(SegManager *segMan, EventManager *eventMan) :
_isOpen(false),
_isInitialized(false),
+ _yieldFrame(0),
_yieldInterval(0),
_lastYieldedFrameNo(0),
@@ -512,6 +503,7 @@ VMDPlayer::VMDPlayer(SegManager *segMan, EventManager *eventMan) :
_blackLines(false),
_leaveScreenBlack(false),
_leaveLastFrame(false),
+ _ignorePalettes(false),
_blackoutPlane(nullptr),
@@ -538,6 +530,10 @@ VMDPlayer::IOStatus VMDPlayer::open(const Common::String &fileName, const OpenFl
error("Attempted to play %s, but another VMD was loaded", fileName.c_str());
}
+ if (g_sci->_features->VMDOpenStopsAudio()) {
+ g_sci->_audio32->stop(kAllChannels);
+ }
+
if (_decoder->loadFile(fileName)) {
if (flags & kOpenFlagMute) {
_decoder->setVolume(0);
@@ -571,6 +567,7 @@ VMDPlayer::IOStatus VMDPlayer::close() {
_decoder->close();
_isOpen = false;
_isInitialized = false;
+ _ignorePalettes = false;
if (!_planeIsOwned && _screenItem != nullptr) {
g_sci->_gfxFrameout->deleteScreenItem(*_screenItem);
@@ -625,12 +622,12 @@ VMDPlayer::VMDStatus VMDPlayer::getStatus() const {
VMDPlayer::EventFlags VMDPlayer::kernelPlayUntilEvent(const EventFlags flags, const int16 lastFrameNo, const int16 yieldInterval) {
assert(lastFrameNo >= -1);
- const int32 maxFrameNo = (int32)(_decoder->getFrameCount() - 1);
+ const int32 maxFrameNo = _decoder->getFrameCount() - 1;
- if ((flags & kEventFlagToFrame) && lastFrameNo > 0) {
- _decoder->setEndFrame(MIN<int32>(lastFrameNo, maxFrameNo));
+ if (flags & kEventFlagToFrame) {
+ _yieldFrame = MIN<int32>(lastFrameNo, maxFrameNo);
} else {
- _decoder->setEndFrame(maxFrameNo);
+ _yieldFrame = maxFrameNo;
}
if (flags & kEventFlagYieldToVM) {
@@ -705,6 +702,7 @@ VMDPlayer::EventFlags VMDPlayer::playUntilEvent(const EventFlags flags) {
reg_t bitmapId;
SciBitmap &vmdBitmap = *_segMan->allocateBitmap(&bitmapId, vmdRect.width(), vmdRect.height(), 255, 0, 0, screenWidth, screenHeight, 0, false, false);
+ vmdBitmap.getBuffer().fillRect(Common::Rect(vmdRect.width(), vmdRect.height()), 0);
if (screenWidth != scriptWidth || screenHeight != scriptHeight) {
mulru(vmdRect, Ratio(scriptWidth, screenWidth), Ratio(scriptHeight, screenHeight), 1);
@@ -767,6 +765,11 @@ VMDPlayer::EventFlags VMDPlayer::playUntilEvent(const EventFlags flags) {
const int currentFrameNo = _decoder->getCurFrame();
+ if (currentFrameNo == _yieldFrame) {
+ stopFlag = kEventFlagEnd;
+ break;
+ }
+
if (_yieldInterval > 0 &&
currentFrameNo != _lastYieldedFrameNo &&
(currentFrameNo % _yieldInterval) == 0
@@ -826,7 +829,7 @@ void VMDPlayer::renderFrame() const {
// we are just submitting it directly here because the decoder exposes
// this information a little bit differently than the one in SSCI
const bool dirtyPalette = _decoder->hasDirtyPalette();
- if (dirtyPalette) {
+ if (dirtyPalette && !_ignorePalettes) {
Palette palette;
palette.timestamp = g_sci->getTickCount();
for (uint16 i = 0; i < _startColor; ++i) {
diff --git a/engines/sci/graphics/video32.h b/engines/sci/graphics/video32.h
index 75b8fb2d21..4fc627e674 100644
--- a/engines/sci/graphics/video32.h
+++ b/engines/sci/graphics/video32.h
@@ -326,6 +326,12 @@ private:
bool _isInitialized;
/**
+ * For VMDs played with the `kEventFlagToFrame` flag,
+ * the target frame for yielding back to the SCI VM.
+ */
+ int32 _yieldFrame;
+
+ /**
* For VMDs played with the `kEventFlagYieldToVM` flag,
* the number of frames that should be rendered until
* yielding back to the SCI VM.
@@ -347,6 +353,13 @@ private:
#pragma mark -
#pragma mark VMDPlayer - Rendering
+public:
+ /**
+ * Causes the VMD player to ignore all palettes in
+ * the currently playing video.
+ */
+ void ignorePalettes() { _ignorePalettes = true; }
+
private:
/**
* The location of the VMD plane, in game script
@@ -408,6 +421,11 @@ private:
bool _leaveLastFrame;
/**
+ * Whether or not palettes from the VMD should be ignored.
+ */
+ bool _ignorePalettes;
+
+ /**
* Renders a frame of video to the output bitmap.
*/
void renderFrame() const;
diff --git a/engines/sci/parser/vocabulary.cpp b/engines/sci/parser/vocabulary.cpp
index a09ba8f3ce..a0f958167d 100644
--- a/engines/sci/parser/vocabulary.cpp
+++ b/engines/sci/parser/vocabulary.cpp
@@ -365,7 +365,7 @@ bool Vocabulary::checkAltInput(Common::String& text, uint16& cursorPos) {
}
}
}
- } while (changed && loopCount < 10);
+ } while (changed && loopCount++ < 10);
return ret;
}
diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp
index 8826b0625a..5b57eed123 100644
--- a/engines/sci/resource.cpp
+++ b/engines/sci/resource.cpp
@@ -2459,38 +2459,6 @@ void ResourceManager::detectSciVersion() {
}
}
-bool ResourceManager::detectHires() {
- // SCI 1.1 and prior is never hires
- if (getSciVersion() <= SCI_VERSION_1_1)
- return false;
-
-#ifdef ENABLE_SCI32
- for (int i = 0; i < 32768; i++) {
- Resource *res = findResource(ResourceId(kResourceTypePic, i), 0);
-
- if (res) {
- if (READ_SCI11ENDIAN_UINT16(res->data) == 0x0e) {
- // SCI32 picture
- uint16 width = READ_SCI11ENDIAN_UINT16(res->data + 10);
- uint16 height = READ_SCI11ENDIAN_UINT16(res->data + 12);
- // Surely lowres (e.g. QFG4CD)
- if ((width == 320) && ((height == 190) || (height == 200)))
- return false;
- // Surely hires
- if ((width >= 600) || (height >= 400))
- return true;
- }
- }
- }
-
- // We haven't been able to find hires content
-
- return false;
-#else
- error("no sci32 support");
-#endif
-}
-
bool ResourceManager::detectFontExtended() {
Resource *res = findResource(ResourceId(kResourceTypeFont, 0), 0);
diff --git a/engines/sci/resource.h b/engines/sci/resource.h
index 70db5909b7..928d571dbc 100644
--- a/engines/sci/resource.h
+++ b/engines/sci/resource.h
@@ -424,7 +424,6 @@ private:
public:
#endif
- bool detectHires();
// Detects, if standard font of current game includes extended characters (>0x80)
bool detectFontExtended();
// Detects, if SCI1.1 game uses palette merging
diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp
index 246c031c06..e89d05217c 100644
--- a/engines/sci/sci.cpp
+++ b/engines/sci/sci.cpp
@@ -1166,7 +1166,9 @@ void SciEngine::syncIngameAudioOptions() {
void SciEngine::updateScummVMAudioOptions() {
// Update ScummVM's speech/subtitles settings for SCI1.1 CD games,
// depending on the in-game settings
- if (isCD() && getSciVersion() == SCI_VERSION_1_1) {
+ if ((isCD() && getSciVersion() == SCI_VERSION_1_1) ||
+ getSciVersion() >= SCI_VERSION_2) {
+
uint16 ingameSetting = _gamestate->variables[VAR_GLOBAL][kGlobalVarMessageType].getOffset();
switch (ingameSetting) {
diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp
index a62092f493..98958a3050 100644
--- a/engines/scumm/sound.cpp
+++ b/engines/scumm/sound.cpp
@@ -359,7 +359,7 @@ void Sound::playSound(int soundID) {
_currentCDSound = soundID;
} else {
// All other sound types are ignored
- warning("Scumm::Sound::playSound: encountered audio resoure with chunk type 'SOUN' and sound type %d", type);
+ warning("Scumm::Sound::playSound: encountered audio resource with chunk type 'SOUN' and sound type %d", type);
}
}
else if ((_vm->_game.platform == Common::kPlatformMacintosh) && (_vm->_game.id == GID_INDY3) && READ_BE_UINT16(ptr + 8) == 0x1C) {
diff --git a/engines/titanic/carry/arm.cpp b/engines/titanic/carry/arm.cpp
index cbc14da477..1f77247e93 100644
--- a/engines/titanic/carry/arm.cpp
+++ b/engines/titanic/carry/arm.cpp
@@ -108,7 +108,7 @@ bool CArm::TranslateObjectMsg(CTranslateObjectMsg *msg) {
bool CArm::UseWithOtherMsg(CUseWithOtherMsg *msg) {
if (_string6 != "None") {
- CShowTextMsg textMsg("The arm is already holding something.");
+ CShowTextMsg textMsg(ARM_ALREADY_HOLDING);
textMsg.execute("PET");
return false;
} else if (msg->_other->getName() == "GondolierLeftLever") {
@@ -138,9 +138,10 @@ bool CArm::UseWithOtherMsg(CUseWithOtherMsg *msg) {
bool CArm::MouseDragStartMsg(CMouseDragStartMsg *msg) {
if (!_fieldE0) {
- CShowTextMsg textMsg("You can't get this.");
+ CShowTextMsg textMsg(YOU_CANT_GET_THIS);
textMsg.execute("PET");
} else if (checkStartDragging(msg)) {
+ hideMouse();
_tempPos = msg->_mousePos - _bounds;
setPosition(msg->_mousePos - _tempPos);
diff --git a/engines/titanic/carry/carry.cpp b/engines/titanic/carry/carry.cpp
index 03798e8713..4f8df11260 100644
--- a/engines/titanic/carry/carry.cpp
+++ b/engines/titanic/carry/carry.cpp
@@ -25,6 +25,7 @@
#include "titanic/npcs/character.h"
#include "titanic/npcs/succubus.h"
#include "titanic/pet_control/pet_control.h"
+#include "titanic/titanic.h"
namespace Titanic {
@@ -48,8 +49,8 @@ CCarry::CCarry() : CGameObject(), _fieldDC(0), _fieldE0(1),
_itemFrame(0), _enterFrame(0), _enterFrameSet(false), _visibleFrame(0),
_string1("None"),
_fullViewName("NULL"),
- _string3("That doesn't seem to do anything."),
- _string4("It doesn't seem to want this.") {
+ _string3(g_vm->_strings[DOESNT_DO_ANYTHING]),
+ _string4(g_vm->_strings[DOESNT_WANT_THIS]) {
}
void CCarry::save(SimpleFile *file, int indent) {
@@ -98,18 +99,19 @@ void CCarry::load(SimpleFile *file) {
bool CCarry::MouseDragStartMsg(CMouseDragStartMsg *msg) {
CString name = getName();
+ debugC(ERROR_BASIC, kDebugScripts, "MosueDragStartMsg - %s", name.c_str());
if (_fieldE0) {
- if (_visible) {
- CShowTextMsg textMsg("You can't get this.");
- textMsg.execute("PET");
- }
- } else {
if (checkStartDragging(msg)) {
CPassOnDragStartMsg startMsg(msg->_mousePos);
startMsg.execute(this);
return true;
}
+ } else {
+ if (_visible) {
+ CShowTextMsg textMsg(YOU_CANT_GET_THIS);
+ textMsg.execute("PET");
+ }
}
return false;
@@ -121,6 +123,9 @@ bool CCarry::MouseDragMoveMsg(CMouseDragMoveMsg *msg) {
}
bool CCarry::MouseDragEndMsg(CMouseDragEndMsg *msg) {
+ debugC(ERROR_BASIC, kDebugScripts, "MosueDragEndMsg");
+ showMouse();
+
if (msg->_dropTarget) {
if (msg->_dropTarget->isPet()) {
petAddToInventory();
@@ -224,6 +229,8 @@ bool CCarry::EnterViewMsg(CEnterViewMsg *msg) {
}
bool CCarry::PassOnDragStartMsg(CPassOnDragStartMsg *msg) {
+ hideMouse();
+
if (_visibleFrame != -1)
loadFrame(_visibleFrame);
@@ -234,7 +241,7 @@ bool CCarry::PassOnDragStartMsg(CPassOnDragStartMsg *msg) {
_tempPos = msg->_mousePos - _bounds;
}
- setPosition(_tempPos - getMousePos());
+ setPosition(getMousePos() - _tempPos);
return true;
}
diff --git a/engines/titanic/carry/carry_parrot.cpp b/engines/titanic/carry/carry_parrot.cpp
index 57d82af78a..ed86384147 100644
--- a/engines/titanic/carry/carry_parrot.cpp
+++ b/engines/titanic/carry/carry_parrot.cpp
@@ -145,6 +145,7 @@ bool CCarryParrot::MouseDragEndMsg(CMouseDragEndMsg *msg) {
}
}
+ showMouse();
return true;
}
@@ -153,8 +154,8 @@ bool CCarryParrot::PassOnDragStartMsg(CPassOnDragStartMsg *msg) {
moveToView();
setPosition(Point(0, 0));
setVisible(true);
- playClip("Pick Up", 2);
- playClip("Flapping", 1);
+ playClip("Pick Up", MOVIE_STOP_PREVIOUS);
+ playClip("Flapping", MOVIE_REPEAT);
stopTimer(_timerId);
_timerId = addTimer(1000, 1000);
diff --git a/engines/titanic/carry/central_core.cpp b/engines/titanic/carry/central_core.cpp
index e210b34cbe..afc3b85bf0 100644
--- a/engines/titanic/carry/central_core.cpp
+++ b/engines/titanic/carry/central_core.cpp
@@ -47,7 +47,7 @@ bool CCentralCore::UseWithOtherMsg(CUseWithOtherMsg *msg) {
CPuzzleSolvedMsg solvedMsg;
solvedMsg.execute("BigHammer");
} else if (name == "SpeechCentre") {
- CShowTextMsg textMsg("This does not reach.");
+ CShowTextMsg textMsg(DOES_NOT_REACH);
textMsg.execute("PET");
}
diff --git a/engines/titanic/carry/chicken.cpp b/engines/titanic/carry/chicken.cpp
index 0e8f6b3653..b80096b718 100644
--- a/engines/titanic/carry/chicken.cpp
+++ b/engines/titanic/carry/chicken.cpp
@@ -74,7 +74,7 @@ bool CChicken::UseWithOtherMsg(CUseWithOtherMsg *msg) {
actMsg.execute(this);
petAddToInventory();
} else {
- CShowTextMsg textMsg("The chicken is already clean.");
+ CShowTextMsg textMsg(CHICKEN_ALREADY_CLEAN);
textMsg.execute("PET");
}
@@ -200,10 +200,12 @@ bool CChicken::ParrotTriesChickenMsg(CParrotTriesChickenMsg *msg) {
}
bool CChicken::MouseDragEndMsg(CMouseDragEndMsg *msg) {
- if (_field13C)
+ if (_field13C) {
+ showMouse();
return true;
- else
+ } else {
return CCarry::MouseDragEndMsg(msg);
+ }
}
bool CChicken::PETObjectStateMsg(CPETObjectStateMsg *msg) {
diff --git a/engines/titanic/carry/hose.cpp b/engines/titanic/carry/hose.cpp
index e90119138a..3bfb4eae47 100644
--- a/engines/titanic/carry/hose.cpp
+++ b/engines/titanic/carry/hose.cpp
@@ -22,6 +22,7 @@
#include "titanic/carry/hose.h"
#include "titanic/npcs/succubus.h"
+#include "titanic/titanic.h"
namespace Titanic {
@@ -44,7 +45,7 @@ void CHose::deinit() {
}
CHose::CHose() : CCarry(),
- _string6("Succ-U-Bus auxiliary hose attachment incompatible with sliding glass cover.") {
+ _string6(g_vm->_strings[HOSE_INCOMPATIBLE]) {
}
void CHose::save(SimpleFile *file, int indent) {
diff --git a/engines/titanic/carry/perch.cpp b/engines/titanic/carry/perch.cpp
index 4f0e76bdb0..f432dafa85 100644
--- a/engines/titanic/carry/perch.cpp
+++ b/engines/titanic/carry/perch.cpp
@@ -40,7 +40,7 @@ void CPerch::load(SimpleFile *file) {
bool CPerch::UseWithOtherMsg(CUseWithOtherMsg *msg) {
if (msg->_other->isEquals("SpeechCentre")) {
- CShowTextMsg textMsg("This does not reach.");
+ CShowTextMsg textMsg(DOES_NOT_REACH);
textMsg.execute("PET");
}
diff --git a/engines/titanic/carry/plug_in.cpp b/engines/titanic/carry/plug_in.cpp
index 438b9a5883..55767ce9a8 100644
--- a/engines/titanic/carry/plug_in.cpp
+++ b/engines/titanic/carry/plug_in.cpp
@@ -50,7 +50,7 @@ bool CPlugIn::UseWithOtherMsg(CUseWithOtherMsg *msg) {
if (otherName == "PET") {
return CCarry::UseWithOtherMsg(msg);
} else if (isEquals("DatasideTransporter")) {
- CShowTextMsg textMsg("This item is incorrectly calibrated.");
+ CShowTextMsg textMsg(INCORRECTLY_CALIBRATED);
textMsg.execute("PET");
} else if (isEquals("DatasideTransporter")) {
error("TODO: Set msg->_other->fieldC4 = 2");
diff --git a/engines/titanic/continue_save_dialog.cpp b/engines/titanic/continue_save_dialog.cpp
index 39b7d1942a..0982cab408 100644
--- a/engines/titanic/continue_save_dialog.cpp
+++ b/engines/titanic/continue_save_dialog.cpp
@@ -54,9 +54,10 @@ CContinueSaveDialog::~CContinueSaveDialog() {
}
void CContinueSaveDialog::addSavegame(int slot, const CString &name) {
- assert(_saves.size() < SAVEGAME_SLOTS_COUNT);
- _slotNames[_saves.size()].setText(name);
- _saves.push_back(SaveEntry(slot, name));
+ if (_saves.size() < SAVEGAME_SLOTS_COUNT) {
+ _slotNames[_saves.size()].setText(name);
+ _saves.push_back(SaveEntry(slot, name));
+ }
}
Rect CContinueSaveDialog::getSlotBounds(int index) {
diff --git a/engines/titanic/core/background.cpp b/engines/titanic/core/background.cpp
index 733dfc1cf3..792cd28346 100644
--- a/engines/titanic/core/background.cpp
+++ b/engines/titanic/core/background.cpp
@@ -58,7 +58,7 @@ void CBackground::load(SimpleFile *file) {
bool CBackground::StatusChangeMsg(CStatusChangeMsg *msg) {
setVisible(true);
if (_fieldDC) {
- playMovie(_startFrame, _endFrame, 16);
+ playMovie(_startFrame, _endFrame, MOVIE_GAMESTATE);
} else {
playMovie(_startFrame, _endFrame, 0);
}
diff --git a/engines/titanic/core/game_object.cpp b/engines/titanic/core/game_object.cpp
index 8f71b3d995..76a2f2d5c0 100644
--- a/engines/titanic/core/game_object.cpp
+++ b/engines/titanic/core/game_object.cpp
@@ -403,8 +403,11 @@ void CGameObject::loadImage(const CString &name, bool pendingFlag) {
void CGameObject::loadFrame(int frameNumber) {
_frameNumber = -1;
- if (!_resource.empty())
+
+ if (!_surface && !_resource.empty()) {
loadResource(_resource);
+ _resource.clear();
+ }
if (_surface)
_surface->setMovieFrame(frameNumber);
@@ -612,9 +615,8 @@ void CGameObject::playMovie(uint flags) {
void CGameObject::playMovie(int startFrame, int endFrame, uint flags) {
_frameNumber = -1;
- if (!_surface) {
- if (!_resource.empty())
- loadResource(_resource);
+ if (!_surface && !_resource.empty()) {
+ loadResource(_resource);
_resource.clear();
}
@@ -630,9 +632,8 @@ void CGameObject::playMovie(int startFrame, int endFrame, uint flags) {
void CGameObject::playMovie(int startFrame, int endFrame, int initialFrame, uint flags) {
_frameNumber = -1;
- if (!_surface) {
- if (!_resource.empty())
- loadResource(_resource);
+ if (!_surface && !_resource.empty()) {
+ loadResource(_resource);
_resource.clear();
}
@@ -645,6 +646,8 @@ void CGameObject::playMovie(int startFrame, int endFrame, int initialFrame, uint
}
void CGameObject::playClip(const CString &name, uint flags) {
+ debugC(ERROR_DETAILED, kDebugScripts, "playClip - %s", name.c_str());
+
_frameNumber = -1;
CMovieClip *clip = _movieClips.findByName(name);
if (clip)
@@ -652,6 +655,8 @@ void CGameObject::playClip(const CString &name, uint flags) {
}
void CGameObject::playClip(uint startFrame, uint endFrame) {
+ debugC(ERROR_DETAILED, kDebugScripts, "playClip - %d to %d", startFrame, endFrame);
+
CMovieClip *clip = new CMovieClip("", startFrame, endFrame);
CGameManager *gameManager = getGameManager();
CRoomItem *room = gameManager->getRoom();
@@ -753,7 +758,7 @@ int CGameObject::playSound(const CString &name, CProximity &prox) {
if (gameManager && !name.empty()) {
g_vm->_filesManager->preload(name);
- gameManager->_sound.playSound(name, prox);
+ return gameManager->_sound.playSound(name, prox);
}
return -1;
@@ -864,7 +869,8 @@ CViewItem *CGameObject::parseView(const CString &viewString) {
if (project) {
if (room->getName() != roomName) {
// Scan for the correct room
- for (room = project->findFirstRoom(); room && room->getName() != roomName;
+ for (room = project->findFirstRoom();
+ room && room->getName() != roomName;
room = project->findNextRoom(room)) ;
}
}
@@ -912,12 +918,12 @@ Point CGameObject::getMousePos() const {
}
bool CGameObject::compareViewNameTo(const CString &name) const {
- return getViewFullName().compareToIgnoreCase(name);
+ return !getViewFullName().compareToIgnoreCase(name);
}
int CGameObject::compareRoomNameTo(const CString &name) {
CRoomItem *room = getGameManager()->getRoom();
- return room->getName().compareToIgnoreCase(name);
+ return !room->getName().compareToIgnoreCase(name);
}
CString CGameObject::getRoomName() const {
@@ -1142,11 +1148,11 @@ void CGameObject::lockMouse() {
}
void CGameObject::hideMouse() {
- CScreenManager::_screenManagerPtr->_mouseCursor->hide();
+ CScreenManager::_screenManagerPtr->_mouseCursor->incHideCounter();
}
void CGameObject::showMouse() {
- CScreenManager::_screenManagerPtr->_mouseCursor->show();
+ CScreenManager::_screenManagerPtr->_mouseCursor->decHideCounter();
}
void CGameObject::disableMouse() {
@@ -1159,12 +1165,12 @@ void CGameObject::enableMouse() {
showMouse();
}
-void CGameObject::mouseLockE4() {
- CScreenManager::_screenManagerPtr->_mouseCursor->lockE4();
+void CGameObject::mouseDisableControl() {
+ CScreenManager::_screenManagerPtr->_mouseCursor->disableControl();
}
-void CGameObject::mouseUnlockE4() {
- CScreenManager::_screenManagerPtr->_mouseCursor->unlockE4();
+void CGameObject::mouseEnableControl() {
+ CScreenManager::_screenManagerPtr->_mouseCursor->enableControl();
}
void CGameObject::mouseSetPosition(const Point &pt, double rate) {
@@ -1330,17 +1336,17 @@ CMusicRoom *CGameObject::getMusicRoom() const {
return gameManager ? &gameManager->_musicRoom : nullptr;
}
-int CGameObject::getPassengerClass() const {
+PassengerClass CGameObject::getPassengerClass() const {
CGameManager *gameManager = getGameManager();
- return gameManager ? gameManager->_gameState._passengerClass : 3;
+ return gameManager ? gameManager->_gameState._passengerClass : THIRD_CLASS;
}
-int CGameObject::getPriorClass() const {
+PassengerClass CGameObject::getPriorClass() const {
CGameManager *gameManager = getGameManager();
- return gameManager ? gameManager->_gameState._priorClass : 3;
+ return gameManager ? gameManager->_gameState._priorClass : THIRD_CLASS;
}
-void CGameObject::setPassengerClass(int newClass) {
+void CGameObject::setPassengerClass(PassengerClass newClass) {
if (newClass >= 1 && newClass <= 4) {
// Change the passenger class
CGameManager *gameMan = getGameManager();
@@ -1575,7 +1581,7 @@ void CGameObject::petMoveToHiddenRoom() {
}
}
-void CGameObject::petReassignRoom(int passClassNum) {
+void CGameObject::petReassignRoom(PassengerClass passClassNum) {
CPetControl *petControl = getPetControl();
if (petControl)
petControl->reassignRoom(passClassNum);
@@ -1607,7 +1613,7 @@ void CGameObject::petSetRooms1D4(int v) {
void CGameObject::petOnSummonBot(const CString &name, int val) {
CPetControl *pet = getPetControl();
if (pet)
- pet->summonBot(name, val);
+ pet->onSummonBot(name, val);
}
void CGameObject::petUnlockInput() {
@@ -1654,7 +1660,7 @@ void CGameObject::startTalking(CTrueTalkNPC *npc, uint id, CViewItem *view) {
}
}
-void CGameObject::endTalking(CTrueTalkNPC *npc, bool viewFlag, CViewItem *view) {
+void CGameObject::setTalking(CTrueTalkNPC *npc, bool viewFlag, CViewItem *view) {
CPetControl *pet = getPetControl();
if (pet)
pet->setActiveNPC(npc);
diff --git a/engines/titanic/core/game_object.h b/engines/titanic/core/game_object.h
index b50278cf21..ae35e2ba5b 100644
--- a/engines/titanic/core/game_object.h
+++ b/engines/titanic/core/game_object.h
@@ -165,8 +165,15 @@ protected:
*/
void enableMouse();
- void mouseLockE4();
- void mouseUnlockE4();
+ /**
+ * Disables user control of the mouse
+ */
+ void mouseDisableControl();
+
+ /**
+ * Re-enables user control of the mouse
+ */
+ void mouseEnableControl();
/**
* Sets the mouse to a new position
@@ -445,7 +452,7 @@ protected:
/**
* Set's the player's passenger class
*/
- void setPassengerClass(int newClass);
+ void setPassengerClass(PassengerClass newClass);
/**
* Overrides whether the object's movie has audio timing
@@ -705,12 +712,12 @@ public:
/**
* Return the player's passenger class
*/
- int getPassengerClass() const;
+ PassengerClass getPassengerClass() const;
/**
* Return the player's previous passenger class
*/
- int getPriorClass() const;
+ PassengerClass getPriorClass() const;
/**
* Sets the mail identifier for an object
@@ -877,7 +884,7 @@ public:
/**
* Gives the player a new assigned room in the specified passenger class
*/
- void petReassignRoom(int passClassNum);
+ void petReassignRoom(PassengerClass passClassNum);
/**
* Sets a new area in the PET
@@ -925,19 +932,20 @@ public:
/*--- CTrueTalkManager Methods ---*/
/**
- * Stop a conversation with the NPC
+ * Start a conversation with the NPC
*/
- void endTalking(CTrueTalkNPC *npc, bool viewFlag, CViewItem *view = nullptr);
+ void startTalking(CTrueTalkNPC *npc, uint id, CViewItem *view = nullptr);
/**
* Start a conversation with the NPC
*/
- void startTalking(CTrueTalkNPC *npc, uint id, CViewItem *view = nullptr);
+ void startTalking(const CString &name, uint id, CViewItem *view = nullptr);
/**
* Start a conversation with the NPC
*/
- void startTalking(const CString &name, uint id, CViewItem *view = nullptr);
+ void setTalking(CTrueTalkNPC *npc, bool viewFlag, CViewItem *view = nullptr);
+
/**
* Sets a dial region for a given NPC
diff --git a/engines/titanic/core/project_item.cpp b/engines/titanic/core/project_item.cpp
index 65e8645baa..af67f69580 100644
--- a/engines/titanic/core/project_item.cpp
+++ b/engines/titanic/core/project_item.cpp
@@ -372,15 +372,20 @@ CTreeItem *CProjectItem::findChildInstance(ClassDef *classDef) const {
}
CRoomItem *CProjectItem::findNextRoom(CRoomItem *priorRoom) const {
- return dynamic_cast<CRoomItem *>(findSiblingInstanceOf(CRoomItem::_type, priorRoom));
+ return dynamic_cast<CRoomItem *>(findSiblingChildInstanceOf(CRoomItem::_type, priorRoom));
}
-CTreeItem *CProjectItem::findSiblingInstanceOf(ClassDef *classDef, CTreeItem *startItem) const {
- CTreeItem *treeItem = startItem->getParent()->getNextSibling();
- if (treeItem == nullptr)
- return nullptr;
+CTreeItem *CProjectItem::findSiblingChildInstanceOf(ClassDef *classDef, CTreeItem *startItem) const {
+ for (CTreeItem *treeItem = startItem->getParent()->getNextSibling();
+ treeItem; treeItem = treeItem->getNextSibling()) {
+ for (CTreeItem *childItem = treeItem->getFirstChild();
+ childItem; childItem = childItem->getNextSibling()) {
+ if (childItem->isInstanceOf(classDef))
+ return childItem;
+ }
+ }
- return findChildInstance(classDef);
+ return nullptr;
}
CDontSaveFileItem *CProjectItem::getDontSaveFileItem() const {
diff --git a/engines/titanic/core/project_item.h b/engines/titanic/core/project_item.h
index 4d009dd50b..20c4a4377a 100644
--- a/engines/titanic/core/project_item.h
+++ b/engines/titanic/core/project_item.h
@@ -118,7 +118,7 @@ private:
/**
* Finds the next sibling occurance of a given class type
*/
- CTreeItem *findSiblingInstanceOf(ClassDef *classDef, CTreeItem *startItem) const;
+ CTreeItem *findSiblingChildInstanceOf(ClassDef *classDef, CTreeItem *startItem) const;
private:
/**
* Load project data from the passed file
diff --git a/engines/titanic/core/saveable_object.cpp b/engines/titanic/core/saveable_object.cpp
index 7522a34737..73b4bf861f 100644
--- a/engines/titanic/core/saveable_object.cpp
+++ b/engines/titanic/core/saveable_object.cpp
@@ -421,14 +421,14 @@ CSaveableObject *ClassDef::create() {
/*------------------------------------------------------------------------*/
-Common::HashMap<Common::String, CSaveableObject::CreateFunction> *
- CSaveableObject::_classList = nullptr;
-Common::List<ClassDef *> *CSaveableObject::_classDefs;
+CSaveableObject::ClassListMap *CSaveableObject::_classList;
+CSaveableObject::ClassDefList *CSaveableObject::_classDefs;
#define DEFFN(T) CSaveableObject *Function##T() { return new T(); } \
ClassDef *T::_type
#define ADDFN(CHILD, PARENT) \
CHILD::_type = new TypeTemplate<CHILD>(#CHILD, PARENT::_type); \
+ _classDefs->push_back(CHILD::_type); \
(*_classList)[#CHILD] = Function##CHILD
DEFFN(CArm);
@@ -835,6 +835,7 @@ DEFFN(CMouseDragMsg);
DEFFN(CMouseDragStartMsg);
DEFFN(CMouseDragMoveMsg);
DEFFN(CMouseDragEndMsg);
+DEFFN(CMouseWheelMsg);
DEFFN(CMoveToStartPosMsg);
DEFFN(CMovieEndMsg);
DEFFN(CMovieFrameMsg);
@@ -1019,8 +1020,8 @@ DEFFN(CStarControl);
DEFFN(CTimeEventInfo);
void CSaveableObject::initClassList() {
- _classDefs = new Common::List<ClassDef *>();
- _classList = new Common::HashMap<Common::String, CreateFunction>();
+ _classDefs = new ClassDefList();
+ _classList = new ClassListMap();
ADDFN(CArm, CCarry);
ADDFN(CAuditoryCentre, CBrain);
ADDFN(CBowlEar, CEar);
@@ -1426,6 +1427,7 @@ void CSaveableObject::initClassList() {
ADDFN(CMouseDragStartMsg, CMouseDragMsg);
ADDFN(CMouseDragMoveMsg, CMouseDragMsg);
ADDFN(CMouseDragEndMsg, CMouseDragMsg);
+ ADDFN(CMouseWheelMsg, CMouseMsg);
ADDFN(CMoveToStartPosMsg, CMessage);
ADDFN(CMovieEndMsg, CMessage);
ADDFN(CMovieFrameMsg, CMessage);
@@ -1615,7 +1617,7 @@ void CSaveableObject::initClassList() {
}
void CSaveableObject::freeClassList() {
- Common::List<ClassDef *>::iterator i;
+ ClassDefList::iterator i;
for (i = _classDefs->begin(); i != _classDefs->end(); ++i)
delete *i;
diff --git a/engines/titanic/core/saveable_object.h b/engines/titanic/core/saveable_object.h
index 4c7c1a7737..80525f1156 100644
--- a/engines/titanic/core/saveable_object.h
+++ b/engines/titanic/core/saveable_object.h
@@ -59,8 +59,10 @@ public:
class CSaveableObject {
typedef CSaveableObject *(*CreateFunction)();
private:
- static Common::List<ClassDef *> *_classDefs;
- static Common::HashMap<Common::String, CreateFunction> *_classList;
+ typedef Common::List<ClassDef *> ClassDefList;
+ typedef Common::HashMap<Common::String, CreateFunction> ClassListMap;
+ static ClassDefList *_classDefs;
+ static ClassListMap *_classList;
public:
/**
* Sets up the list of saveable object classes
diff --git a/engines/titanic/core/view_item.cpp b/engines/titanic/core/view_item.cpp
index 9b20860a46..aa1ff7108e 100644
--- a/engines/titanic/core/view_item.cpp
+++ b/engines/titanic/core/view_item.cpp
@@ -270,7 +270,7 @@ bool CViewItem::handleMouseMsg(CMouseMsg *msg, bool flag) {
if (gameObjects.size() == 0)
return false;
- for (int idx = (int)gameObjects.size() - 1; idx >= 0; ++idx) {
+ for (int idx = (int)gameObjects.size() - 1; idx >= 0; --idx) {
if (gameObjects[idx]->_cursorId != CURSOR_IGNORE) {
CScreenManager::_screenManagerPtr->_mouseCursor->setCursor(gameObjects[idx]->_cursorId);
break;
diff --git a/engines/titanic/events.cpp b/engines/titanic/events.cpp
index fa057de432..97f9a86eb3 100644
--- a/engines/titanic/events.cpp
+++ b/engines/titanic/events.cpp
@@ -31,7 +31,7 @@
namespace Titanic {
Events::Events(TitanicEngine *vm): _vm(vm), _frameCounter(1),
- _priorFrameTime(0) {
+ _priorFrameTime(0), _specialButtons(0) {
}
void Events::pollEvents() {
@@ -47,33 +47,46 @@ void Events::pollEvents() {
eventTarget()->mouseMove(_mousePos);
break;
case Common::EVENT_LBUTTONDOWN:
+ _specialButtons |= MK_LBUTTON;
_mousePos = event.mouse;
eventTarget()->leftButtonDown(_mousePos);
break;
case Common::EVENT_LBUTTONUP:
+ _specialButtons &= ~MK_LBUTTON;
_mousePos = event.mouse;
eventTarget()->leftButtonUp(_mousePos);
break;
case Common::EVENT_MBUTTONDOWN:
+ _specialButtons |= MK_MBUTTON;
_mousePos = event.mouse;
eventTarget()->middleButtonDown(_mousePos);
break;
case Common::EVENT_MBUTTONUP:
+ _specialButtons &= ~MK_MBUTTON;
_mousePos = event.mouse;
eventTarget()->middleButtonUp(_mousePos);
break;
case Common::EVENT_RBUTTONDOWN:
+ _specialButtons |= MK_RBUTTON;
_mousePos = event.mouse;
eventTarget()->rightButtonDown(_mousePos);
break;
case Common::EVENT_RBUTTONUP:
+ _specialButtons &= ~MK_RBUTTON;
_mousePos = event.mouse;
eventTarget()->rightButtonUp(_mousePos);
break;
+ case Common::EVENT_WHEELUP:
+ case Common::EVENT_WHEELDOWN:
+ _mousePos = event.mouse;
+ eventTarget()->mouseWheel(_mousePos, event.type == Common::EVENT_WHEELUP);
+ break;
case Common::EVENT_KEYDOWN:
+ handleKbdSpecial(event.kbd);
eventTarget()->keyDown(event.kbd);
break;
case Common::EVENT_KEYUP:
+ handleKbdSpecial(event.kbd);
eventTarget()->keyUp(event.kbd);
break;
default:
@@ -125,31 +138,34 @@ void Events::sleep(uint time) {
}
bool Events::waitForPress(uint expiry) {
- CGameManager *gameManager = g_vm->_window->_gameManager;
uint32 delayEnd = g_system->getMillis() + expiry;
+ CPressTarget pressTarget;
+ addTarget(&pressTarget);
- while (!_vm->shouldQuit() && g_system->getMillis() < delayEnd) {
- g_system->delayMillis(10);
- checkForNextFrameCounter();
-
- // Regularly update the sound mixer
- if (gameManager)
- gameManager->_sound.updateMixer();
-
- Common::Event event;
- if (g_system->getEventManager()->pollEvent(event)) {
- switch (event.type) {
- case Common::EVENT_LBUTTONDOWN:
- case Common::EVENT_MBUTTONDOWN:
- case Common::EVENT_KEYDOWN:
- return true;
- default:
- break;
- }
- }
+ while (!_vm->shouldQuit() && g_system->getMillis() < delayEnd && !pressTarget._pressed) {
+ pollEventsAndWait();
}
- return false;
+ removeTarget();
+ return pressTarget._pressed;
+}
+
+void Events::setMousePos(const Common::Point &pt) {
+ g_system->warpMouse(pt.x, pt.y);
+ _mousePos = pt;
+ eventTarget()->mouseMove(_mousePos);
+}
+
+void Events::handleKbdSpecial(Common::KeyState keyState) {
+ if (keyState.flags & Common::KBD_CTRL)
+ _specialButtons |= MK_CONTROL;
+ else
+ _specialButtons &= ~MK_CONTROL;
+
+ if (keyState.flags & Common::KBD_SHIFT)
+ _specialButtons |= MK_SHIFT;
+ else
+ _specialButtons &= ~MK_SHIFT;
}
} // End of namespace Titanic
diff --git a/engines/titanic/events.h b/engines/titanic/events.h
index 3ea9b63217..52e900c2ef 100644
--- a/engines/titanic/events.h
+++ b/engines/titanic/events.h
@@ -65,10 +65,26 @@ public:
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
+ */
+class CPressTarget : public CEventTarget {
+public:
+ bool _pressed;
+public:
+ CPressTarget() : _pressed(false) {}
+ 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; }
+};
+
class Events {
private:
TitanicEngine *_vm;
@@ -76,6 +92,7 @@ private:
uint32 _frameCounter;
uint32 _priorFrameTime;
Common::Point _mousePos;
+ uint _specialButtons;
/**
* Check whether it's time to display the next screen frame
@@ -88,6 +105,11 @@ private:
CEventTarget *eventTarget() const {
return _eventTargets.top();
}
+
+ /**
+ * Handles setting/resettings special buttons on key up/down
+ */
+ void handleKbdSpecial(Common::KeyState keyState);
public:
Events(TitanicEngine *vm);
~Events() {}
@@ -138,6 +160,28 @@ public:
* Wait for a mouse or keypress
*/
bool waitForPress(uint expiry);
+
+ /**
+ * Get the mouse position
+ */
+ Common::Point getMousePos() const { return _mousePos; }
+
+ /**
+ * Sets the mouse position
+ */
+ void setMousePos(const Common::Point &pt);
+
+ /*
+ * Return whether a given special key is currently pressed
+ */
+ bool isSpecialPressed(SpecialButtons btn) const {
+ return (_specialButtons & btn) != 0;
+ }
+
+ /**
+ * Returns the bitset of the currently pressed special buttons
+ */
+ uint getSpecialButtons() const { return _specialButtons; }
};
} // End of namespace Titanic
diff --git a/engines/titanic/game/cdrom.cpp b/engines/titanic/game/cdrom.cpp
index cd913d05f7..0d1cd3a6f2 100644
--- a/engines/titanic/game/cdrom.cpp
+++ b/engines/titanic/game/cdrom.cpp
@@ -50,6 +50,7 @@ void CCDROM::load(SimpleFile *file) {
bool CCDROM::MouseDragStartMsg(CMouseDragStartMsg *msg) {
if (checkStartDragging(msg)) {
+ hideMouse();
_tempPos = msg->_mousePos - _bounds;
setPosition(msg->_mousePos - _tempPos);
return true;
@@ -59,6 +60,8 @@ bool CCDROM::MouseDragStartMsg(CMouseDragStartMsg *msg) {
}
bool CCDROM::MouseDragEndMsg(CMouseDragEndMsg *msg) {
+ showMouse();
+
if (msg->_dropTarget && msg->_dropTarget->getName() == "newComputer") {
CCDROMTray *newTray = dynamic_cast<CCDROMTray *>(getRoom()->findByName("newTray"));
diff --git a/engines/titanic/game/cdrom_tray.cpp b/engines/titanic/game/cdrom_tray.cpp
index 505bdad319..d6aa32c702 100644
--- a/engines/titanic/game/cdrom_tray.cpp
+++ b/engines/titanic/game/cdrom_tray.cpp
@@ -95,6 +95,7 @@ bool CCDROMTray::ActMsg(CActMsg *msg) {
playSound("a#35.wav", 50, 0, 0);
} else if (msg->_action == "newSTCD") {
// Starship Titanic CD dropped on CDROM Tray
+ disableMouse();
playMovie(11, 21, MOVIE_NOTIFY_OBJECT);
playSound("a#35.wav", 50, 0, 0);
} else {
diff --git a/engines/titanic/game/computer.cpp b/engines/titanic/game/computer.cpp
index 3077b46178..9aa5db252c 100644
--- a/engines/titanic/game/computer.cpp
+++ b/engines/titanic/game/computer.cpp
@@ -54,7 +54,7 @@ bool CComputer::ActMsg(CActMsg *msg) {
else if (msg->_action == "CD2")
playMovie(50, 79, 0);
else if (msg->_action == "STCD")
- playMovie(80, 90, 4);
+ playMovie(80, 90, MOVIE_NOTIFY_OBJECT);
_currentCD = msg->_action;
_state = 0;
diff --git a/engines/titanic/game/maitred/maitred_prod_receptor.cpp b/engines/titanic/game/maitred/maitred_prod_receptor.cpp
index 95e029af44..6f64a76d7f 100644
--- a/engines/titanic/game/maitred/maitred_prod_receptor.cpp
+++ b/engines/titanic/game/maitred/maitred_prod_receptor.cpp
@@ -81,7 +81,7 @@ bool CMaitreDProdReceptor::MouseMoveMsg(CMouseMoveMsg *msg) {
prodMsg._value = 125;
CMaitreD *maitreD = dynamic_cast<CMaitreD *>(findRoomObject("MaitreD"));
- if (maitreD && maitreD->_field100 <= 0)
+ if (maitreD && maitreD->_speechCounter == 0)
prodMsg.execute(this);
return true;
@@ -90,7 +90,7 @@ bool CMaitreDProdReceptor::MouseMoveMsg(CMouseMoveMsg *msg) {
bool CMaitreDProdReceptor::ProdMaitreDMsg(CProdMaitreDMsg *msg) {
if (_fieldC4) {
CMaitreD *maitreD = static_cast<CMaitreD *>(findRoomObject("MaitreD"));
- if (maitreD->_field100 <= 0) {
+ if (maitreD->_speechCounter == 0) {
CViewItem *view = findView();
startTalking(maitreD, msg->_value, view);
diff --git a/engines/titanic/game/pet/pet.cpp b/engines/titanic/game/pet/pet.cpp
index 99c9e01eb3..235d68f242 100644
--- a/engines/titanic/game/pet/pet.cpp
+++ b/engines/titanic/game/pet/pet.cpp
@@ -62,7 +62,7 @@ void CPET::load(SimpleFile *file) {
bool CPET::ShowTextMsg(CShowTextMsg *msg) {
CPetControl *pet = getPetControl();
if (pet)
- pet->petDisplayMessage(1, msg->_value);
+ pet->petDisplayMessage(1, msg->_message);
return true;
}
diff --git a/engines/titanic/game/pet/pet_lift.cpp b/engines/titanic/game/pet/pet_lift.cpp
index a7b48853e6..75a48a6a6c 100644
--- a/engines/titanic/game/pet/pet_lift.cpp
+++ b/engines/titanic/game/pet/pet_lift.cpp
@@ -50,8 +50,8 @@ bool CPETLift::TransportMsg(CTransportMsg *msg) {
} else if (msg->_roomName == "BottomOfWell") {
floorNum = 39;
} else if (msg->_roomName == "PlayersRoom" && pet) {
- int assignedFloor = pet->getAssignedFloorNum();
- if (assignedFloor < 1 || assignedFloor > 39) {
+ floorNum = pet->getAssignedFloorNum();
+ if (floorNum < 1 || floorNum > 39) {
pet->petDisplayMessage(NO_ROOM_ASSIGNED);
floorNum = -1;
}
diff --git a/engines/titanic/game/pet/pet_position.cpp b/engines/titanic/game/pet/pet_position.cpp
index d3d030eb16..db6f9997c9 100644
--- a/engines/titanic/game/pet/pet_position.cpp
+++ b/engines/titanic/game/pet/pet_position.cpp
@@ -171,8 +171,8 @@ bool CPETPosition::EnterViewMsg(CEnterViewMsg *msg) {
bool CPETPosition::LeaveViewMsg(CLeaveViewMsg *msg) {
CPetControl *pet = getPetControl();
- CString oldView = msg->_oldView->getName();
- CString newView = msg->_newView->getName();
+ CString oldView = msg->_oldView->getFullViewName();
+ CString newView = msg->_newView->getFullViewName();
if (pet && newView == "Lift.Node 1.N") {
int elevatorNum = pet->getRoomsElevatorNum();
diff --git a/engines/titanic/game/pet/pet_transport.cpp b/engines/titanic/game/pet/pet_transport.cpp
index a48e70ed01..29dce6c1b6 100644
--- a/engines/titanic/game/pet/pet_transport.cpp
+++ b/engines/titanic/game/pet/pet_transport.cpp
@@ -26,6 +26,7 @@ namespace Titanic {
BEGIN_MESSAGE_MAP(CPETTransport, CGameObject)
ON_MESSAGE(EnterRoomMsg)
+ ON_MESSAGE(LeaveRoomMsg)
END_MESSAGE_MAP()
void CPETTransport::save(SimpleFile *file, int indent) {
@@ -39,6 +40,11 @@ void CPETTransport::load(SimpleFile *file) {
}
bool CPETTransport::EnterRoomMsg(CEnterRoomMsg *msg) {
+ petSetRemoteTarget();
+ return true;
+}
+
+bool CPETTransport::LeaveRoomMsg(CLeaveRoomMsg *msg) {
petClear();
return true;
}
diff --git a/engines/titanic/game/pet/pet_transport.h b/engines/titanic/game/pet/pet_transport.h
index 58aefe6743..6a08c4bdf3 100644
--- a/engines/titanic/game/pet/pet_transport.h
+++ b/engines/titanic/game/pet/pet_transport.h
@@ -31,6 +31,7 @@ namespace Titanic {
class CPETTransport : public CGameObject {
DECLARE_MESSAGE_MAP;
virtual bool EnterRoomMsg(CEnterRoomMsg *msg);
+ virtual bool LeaveRoomMsg(CLeaveRoomMsg *msg);
public:
CLASSDEF;
diff --git a/engines/titanic/game/service_elevator_window.cpp b/engines/titanic/game/service_elevator_window.cpp
index 13db7a26f8..d548bbf37e 100644
--- a/engines/titanic/game/service_elevator_window.cpp
+++ b/engines/titanic/game/service_elevator_window.cpp
@@ -35,25 +35,25 @@ END_MESSAGE_MAP()
static const int FACTORS[4] = { 0, 20, 100, 0 };
CServiceElevatorWindow::CServiceElevatorWindow() : CBackground(),
- _fieldE0(0), _fieldE4(0), _fieldE8(0), _fieldEC(0) {
+ _destFloor(0), _notifyFlag(false), _isIndicator(false), _intoSpace(false) {
}
void CServiceElevatorWindow::save(SimpleFile *file, int indent) {
file->writeNumberLine(1, indent);
- file->writeNumberLine(_fieldE0, indent);
- file->writeNumberLine(_fieldE4, indent);
- file->writeNumberLine(_fieldE8, indent);
- file->writeNumberLine(_fieldEC, indent);
+ file->writeNumberLine(_destFloor, indent);
+ file->writeNumberLine(_notifyFlag, indent);
+ file->writeNumberLine(_isIndicator, indent);
+ file->writeNumberLine(_intoSpace, indent);
CBackground::save(file, indent);
}
void CServiceElevatorWindow::load(SimpleFile *file) {
file->readNumber();
- _fieldE0 = file->readNumber();
- _fieldE4 = file->readNumber();
- _fieldE8 = file->readNumber();
- _fieldEC = file->readNumber();
+ _destFloor = file->readNumber();
+ _notifyFlag = file->readNumber();
+ _isIndicator = file->readNumber();
+ _intoSpace = file->readNumber();
CBackground::load(file);
}
@@ -61,39 +61,42 @@ void CServiceElevatorWindow::load(SimpleFile *file) {
bool CServiceElevatorWindow::ServiceElevatorFloorChangeMsg(CServiceElevatorFloorChangeMsg *msg) {
if (getView() == findView()) {
CDoorbot *doorbot = dynamic_cast<CDoorbot *>(findRoom()->findByName("Doorbot"));
- int val = (_fieldE8 && doorbot) ? 65 : 15;
+ int fps = (_isIndicator && doorbot) ? 65 : 15;
CMovieClip *clip = _movieClips.findByName("Going Up");
if (!clip)
return true;
- int count = _endFrame - _startFrame;
- setMovieFrameRate(1.0 * count / val);
+ int count = clip->_endFrame - clip->_startFrame;
+ setMovieFrameRate(1.0 * count / fps);
- int startFrame = clip->_startFrame + count * FACTORS[msg->_value1] / 100;
- int endFrame = clip->_startFrame + count * FACTORS[msg->_value2] / 100;
+ int startFrame = clip->_startFrame + count * FACTORS[msg->_startFloor] / 100;
+ int endFrame = clip->_startFrame + count * FACTORS[msg->_endFloor] / 100;
- if (_fieldE4) {
+ if (_notifyFlag) {
+ // Service elevator indicator
playMovie(startFrame, endFrame, MOVIE_NOTIFY_OBJECT);
} else {
+ // Background outside elevator
playMovie(startFrame, endFrame, 0);
- if (_fieldEC)
+ if (_intoSpace)
playClip("Into Space");
}
}
- _fieldE0 = msg->_value2;
+ _destFloor = msg->_endFloor;
return true;
}
bool CServiceElevatorWindow::MovieEndMsg(CMovieEndMsg *msg) {
+ // Called when indicator reaches desired destination floor
CServiceElevatorMsg elevMsg(5);
elevMsg.execute(findRoom()->findByName("Service Elevator Entity"));
return true;
}
bool CServiceElevatorWindow::EnterViewMsg(CEnterViewMsg *msg) {
- if (_fieldEC) {
+ if (_intoSpace) {
playClip("Fade Up");
playMovie(1, 2, 0);
} else {
@@ -101,7 +104,7 @@ bool CServiceElevatorWindow::EnterViewMsg(CEnterViewMsg *msg) {
if (clip) {
int frameNum = clip->_startFrame + (clip->_endFrame - clip->_startFrame)
- * FACTORS[_fieldE0] / 100;
+ * FACTORS[_destFloor] / 100;
loadFrame(frameNum);
} else {
loadFrame(0);
diff --git a/engines/titanic/game/service_elevator_window.h b/engines/titanic/game/service_elevator_window.h
index 88e1663aba..baeef5aeb8 100644
--- a/engines/titanic/game/service_elevator_window.h
+++ b/engines/titanic/game/service_elevator_window.h
@@ -33,10 +33,10 @@ class CServiceElevatorWindow : public CBackground {
bool MovieEndMsg(CMovieEndMsg *msg);
bool EnterViewMsg(CEnterViewMsg *msg);
public:
- int _fieldE0;
- int _fieldE4;
- int _fieldE8;
- int _fieldEC;
+ int _destFloor;
+ bool _notifyFlag;
+ bool _isIndicator;
+ bool _intoSpace;
public:
CLASSDEF;
CServiceElevatorWindow();
diff --git a/engines/titanic/game/television.cpp b/engines/titanic/game/television.cpp
index 571ebcd6fa..2d5a09790b 100644
--- a/engines/titanic/game/television.cpp
+++ b/engines/titanic/game/television.cpp
@@ -257,11 +257,11 @@ bool CTelevision::MovieEndMsg(CMovieEndMsg *msg) {
if (_turnOn)
loadFrame(502);
else
- warning("There is currently nothing available for your viewing pleasure on this channel.");
+ petDisplayMessage(NOTHING_ON_CHANNEL);
} else if (_fieldE0 == 5 && *CGetLiftEye2::_destObject != "NULL") {
loadFrame(393 + _v4);
} else {
- warning("There is currently nothing available for your viewing pleasure on this channel.");
+ petDisplayMessage(NOTHING_ON_CHANNEL);
}
return true;
diff --git a/engines/titanic/game/transport/gondolier.cpp b/engines/titanic/game/transport/gondolier.cpp
index 8c28ff9b66..85f3b365b5 100644
--- a/engines/titanic/game/transport/gondolier.cpp
+++ b/engines/titanic/game/transport/gondolier.cpp
@@ -46,7 +46,7 @@ void CGondolier::load(SimpleFile *file) {
}
bool CGondolier::StatusChangeMsg(CStatusChangeMsg *msg) {
- CShowTextMsg textMsg("Only First Class passengers are allowed to use the Gondoliers.");
+ CShowTextMsg textMsg(GONDOLIERS_FIRST_CLASS_ONLY);
textMsg.execute("PET");
return true;
}
diff --git a/engines/titanic/game/transport/lift_indicator.cpp b/engines/titanic/game/transport/lift_indicator.cpp
index a642451fe0..df0ff397da 100644
--- a/engines/titanic/game/transport/lift_indicator.cpp
+++ b/engines/titanic/game/transport/lift_indicator.cpp
@@ -38,31 +38,31 @@ BEGIN_MESSAGE_MAP(CLiftindicator, CLift)
END_MESSAGE_MAP()
CLiftindicator::CLiftindicator() : CLift(),
- _fieldFC(0), _start(0), _end(0) {
+ _multiplier(0), _startY(0), _endY(0) {
}
void CLiftindicator::save(SimpleFile *file, int indent) {
file->writeNumberLine(1, indent);
- file->writeNumberLine(_fieldFC, indent);
+ file->writeNumberLine(_multiplier, indent);
file->writePoint(_indicatorPos, indent);
- file->writeNumberLine(_start, indent);
- file->writeNumberLine(_end, indent);
+ file->writeNumberLine(_startY, indent);
+ file->writeNumberLine(_endY, indent);
CLift::save(file, indent);
}
void CLiftindicator::load(SimpleFile *file) {
file->readNumber();
- _fieldFC = file->readNumber();
+ _multiplier = file->readNumber();
_indicatorPos = file->readPoint();
- _start = file->readNumber();
- _end = file->readNumber();
+ _startY = file->readNumber();
+ _endY = file->readNumber();
CLift::load(file);
}
bool CLiftindicator::EnterViewMsg(CEnterViewMsg *msg) {
- double multiplier = _fieldFC * 0.037037037;
+ double multiplier = _multiplier * 0.037037037;
CPetControl *pet = getPetControl();
int floorNum = pet->getRoomsFloorNum();
debugC(kDebugScripts, "Lifts = %d,%d,%d,%d, %d",
@@ -70,7 +70,7 @@ bool CLiftindicator::EnterViewMsg(CEnterViewMsg *msg) {
CLift::_elevator3Floor, CLift::_elevator4Floor,
floorNum);
- if ((pet->petGetRoomsWellEntry() & 1) == (_fieldFC & 1)) {
+ if ((pet->petGetRoomsWellEntry() & 1) == (_liftNum & 1)) {
petSetRemoteTarget();
petSetArea(PET_REMOTE);
@@ -142,7 +142,7 @@ bool CLiftindicator::LeaveViewMsg(CLeaveViewMsg *msg) {
}
bool CLiftindicator::PETActivateMsg(CPETActivateMsg *msg) {
- double multiplier = _fieldFC * 0.037037037;
+ double multiplier = _multiplier * 0.037037037;
CPetControl *pet = getPetControl();
if (msg->_name == "Lift") {
@@ -155,8 +155,8 @@ bool CLiftindicator::PETActivateMsg(CPETActivateMsg *msg) {
&& pet->getRoomsFloorNum() != CLift::_elevator4Floor) {
petDisplayMessage(1, ELEVATOR_NON_FUNCTIONAL);
} else {
- _start = _indicatorPos.y + (int)(_startFrame * multiplier);
- _end = _indicatorPos.y + (int)(_endFrame * multiplier);
+ _startY = _indicatorPos.y + (int)(_startFrame * multiplier);
+ _endY = _indicatorPos.y + (int)(_endFrame * multiplier);
lockMouse();
addTimer(100);
@@ -213,15 +213,15 @@ bool CLiftindicator::LeaveRoomMsg(CLeaveRoomMsg *msg) {
}
bool CLiftindicator::TimerMsg(CTimerMsg *msg) {
- debugC(kDebugScripts, "Start %d, End %d", _start, _end);
+ debugC(kDebugScripts, "Start %d, End %d", _startY, _endY);
- if (_start > _end) {
+ if (_startY > _endY) {
setPosition(Point(_bounds.left, _bounds.top - 1));
- --_start;
+ --_startY;
addTimer(20);
- } else if (_start < _end) {
+ } else if (_startY < _endY) {
setPosition(Point(_bounds.left, _bounds.top + 1));
- ++_start;
+ ++_startY;
addTimer(20);
} else {
CMovieEndMsg endMsg(0, 0);
diff --git a/engines/titanic/game/transport/lift_indicator.h b/engines/titanic/game/transport/lift_indicator.h
index 5d0bc45d7b..5ff9dc6d36 100644
--- a/engines/titanic/game/transport/lift_indicator.h
+++ b/engines/titanic/game/transport/lift_indicator.h
@@ -39,10 +39,10 @@ class CLiftindicator : public CLift {
bool LeaveRoomMsg(CLeaveRoomMsg *msg);
bool TimerMsg(CTimerMsg *msg);
private:
- int _fieldFC;
+ int _multiplier;
Point _indicatorPos;
- int _start;
- int _end;
+ int _startY;
+ int _endY;
public:
CLASSDEF;
CLiftindicator();
diff --git a/engines/titanic/game/transport/service_elevator.cpp b/engines/titanic/game/transport/service_elevator.cpp
index 066a418dbb..dbd4e5d74f 100644
--- a/engines/titanic/game/transport/service_elevator.cpp
+++ b/engines/titanic/game/transport/service_elevator.cpp
@@ -116,6 +116,7 @@ bool CServiceElevator::ServiceElevatorMsg(CServiceElevatorMsg *msg) {
break;
case 5:
+ // Reaching destination floor
_fieldF8 = false;
_fieldDC = _v3;
loadSound("z#423.wav");
@@ -164,9 +165,10 @@ bool CServiceElevator::TimerMsg(CTimerMsg *msg) {
if (!isSoundActive(_soundHandle1)) {
stopAnimTimer(_timerId);
if (msg->_actionVal == 0) {
+ // Elevator in motion after pressing button
_fieldF8 = true;
CServiceElevatorFloorChangeMsg changeMsg(_fieldDC, _v3);
- changeMsg.execute(getRoom());
+ changeMsg.execute(getRoom(), nullptr, MSGFLAG_SCAN);
_soundHandle2 = playSound("z#424.wav");
if (doorbot) {
@@ -174,6 +176,7 @@ bool CServiceElevator::TimerMsg(CTimerMsg *msg) {
actMsg.execute(doorbot);
}
} else {
+ // Finished playing message for bottom/middle floor disabled
enableMouse();
if (doorbot) {
CActMsg actMsg;
@@ -207,10 +210,10 @@ bool CServiceElevator::ServiceElevatorFloorRequestMsg(CServiceElevatorFloorReque
if (doorbot && _v3 == 0) {
_soundHandle1 = playSound("z#415.wav", 50);
- addTimer(1, 1000, 500);
+ _timerId = addTimer(1, 1000, 500);
} else if (doorbot && _v3 == 1) {
_soundHandle1 = playSound("z#417.wav", 50);
- addTimer(1, 1000, 500);
+ _timerId = addTimer(1, 1000, 500);
} else if (_fieldDC == _v3) {
switch (_v3) {
case 0:
@@ -226,7 +229,7 @@ bool CServiceElevator::ServiceElevatorFloorRequestMsg(CServiceElevatorFloorReque
break;
}
- addTimer(1, 1000, 500);
+ _timerId = addTimer(1, 1000, 500);
} else {
switch (_v3) {
case 0:
@@ -236,13 +239,13 @@ bool CServiceElevator::ServiceElevatorFloorRequestMsg(CServiceElevatorFloorReque
_soundHandle1 = playSound(_fieldDC ? "z#419.wav" : "z#418.wav", 50);
break;
case 2:
- _soundHandle1 = playSound("z#414.wav", 50);
+ _soundHandle1 = playSound("z#409.wav", 50);
break;
default:
break;
}
- addTimer(0, 1000, 500);
+ _timerId = addTimer(0, 1000, 500);
}
return true;
diff --git a/engines/titanic/game_location.h b/engines/titanic/game_location.h
index f145d36340..87416f6cd7 100644
--- a/engines/titanic/game_location.h
+++ b/engines/titanic/game_location.h
@@ -30,6 +30,11 @@
namespace Titanic {
+enum PassengerClass {
+ UNCHECKED = 4, THIRD_CLASS = 3, SECOND_CLASS = 2, FIRST_CLASS = 1,
+ NO_CLASS = 0
+};
+
class CGameState;
class CGameLocation {
diff --git a/engines/titanic/game_manager.cpp b/engines/titanic/game_manager.cpp
index 6023244325..015296fb14 100644
--- a/engines/titanic/game_manager.cpp
+++ b/engines/titanic/game_manager.cpp
@@ -150,11 +150,12 @@ void CGameManager::playClip(CMovieClip *clip, CRoomItem *oldRoom, CRoomItem *new
if (clip && clip->_startFrame != clip->_endFrame && _movie) {
// Clip details specifying a sub-section of movie to play
Rect tempRect(20, 10, SCREEN_WIDTH - 20, 350);
+ CMouseCursor &mouseCursor = *CScreenManager::_screenManagerPtr->_mouseCursor;
lockInputHandler();
- CScreenManager::_screenManagerPtr->_mouseCursor->hide();
+ mouseCursor.incHideCounter();
_movie->playCutscene(tempRect, clip->_startFrame, clip->_endFrame);
- CScreenManager::_screenManagerPtr->_mouseCursor->show();
+ mouseCursor.decHideCounter();
unlockInputHandler();
}
}
diff --git a/engines/titanic/game_state.cpp b/engines/titanic/game_state.cpp
index ea94deec35..5b6d34ad76 100644
--- a/engines/titanic/game_state.cpp
+++ b/engines/titanic/game_state.cpp
@@ -35,7 +35,6 @@ bool CGameStateMovieList::clear() {
++i;
} else {
i = erase(i);
- delete movieItem;
}
}
@@ -45,10 +44,10 @@ bool CGameStateMovieList::clear() {
/*------------------------------------------------------------------------*/
CGameState::CGameState(CGameManager *gameManager) :
- _gameManager(gameManager), _gameLocation(this),
- _passengerClass(0), _priorClass(0), _mode(GSMODE_NONE),
- _seasonNum(SEASON_SUMMER), _petActive(false), _field1C(false), _quitGame(false),
- _field24(0), _nodeChangeCtr(0), _nodeEnterTicks(0), _field38(0) {
+ _gameManager(gameManager), _gameLocation(this), _passengerClass(NO_CLASS),
+ _priorClass(NO_CLASS), _mode(GSMODE_NONE), _seasonNum(SEASON_SUMMER),
+ _petActive(false), _field1C(false), _quitGame(false), _field24(0),
+ _nodeChangeCtr(0), _nodeEnterTicks(0), _field38(0) {
}
void CGameState::save(SimpleFile *file) const {
@@ -64,8 +63,8 @@ void CGameState::save(SimpleFile *file) const {
void CGameState::load(SimpleFile *file) {
_petActive = file->readNumber() != 0;
- _passengerClass = file->readNumber();
- _priorClass = file->readNumber();
+ _passengerClass = (PassengerClass)file->readNumber();
+ _priorClass = (PassengerClass)file->readNumber();
_seasonNum = (Season)file->readNumber();
_field24 = file->readNumber();
_field38 = file->readNumber();
@@ -79,14 +78,14 @@ void CGameState::load(SimpleFile *file) {
void CGameState::setMode(GameStateMode newMode) {
CScreenManager *sm = CScreenManager::_screenManagerPtr;
- if (newMode == GSMODE_CUTSCENE && newMode != _mode) {
+ if (newMode == GSMODE_CUTSCENE && _mode != GSMODE_CUTSCENE) {
if (_gameManager)
_gameManager->lockInputHandler();
if (sm && sm->_mouseCursor)
sm->_mouseCursor->hide();
- } else if (newMode != GSMODE_CUTSCENE && newMode != _mode) {
+ } else if (newMode != GSMODE_CUTSCENE && _mode == GSMODE_CUTSCENE) {
if (sm && sm->_mouseCursor)
sm->_mouseCursor->show();
@@ -130,7 +129,7 @@ void CGameState::changeView(CViewItem *newView, CMovieClip *clip) {
oldView->leaveView(newView);
// If Shift key is pressed, skip showing the transition clip
- if (g_vm->_window->isSpecialPressed(MK_SHIFT))
+ if (g_vm->_events->isSpecialPressed(MK_SHIFT))
clip = nullptr;
if (_mode == GSMODE_CUTSCENE) {
@@ -139,7 +138,7 @@ void CGameState::changeView(CViewItem *newView, CMovieClip *clip) {
} else {
oldView->preEnterView(newView);
_gameManager->_gameView->setView(newView);
- CRoomItem *oldRoom = newView->findNode()->findRoom();
+ CRoomItem *oldRoom = oldView->findNode()->findRoom();
CRoomItem *newRoom = newView->findNode()->findRoom();
// If a transition clip is defined, play it
diff --git a/engines/titanic/game_state.h b/engines/titanic/game_state.h
index 77b4ded79f..ba1dff2a45 100644
--- a/engines/titanic/game_state.h
+++ b/engines/titanic/game_state.h
@@ -64,8 +64,8 @@ public:
CGameManager *_gameManager;
CGameLocation _gameLocation;
CGameStateMovieList _movieList;
- int _passengerClass;
- int _priorClass;
+ PassengerClass _passengerClass;
+ PassengerClass _priorClass;
GameStateMode _mode;
Season _seasonNum;
bool _petActive;
diff --git a/engines/titanic/input_handler.cpp b/engines/titanic/input_handler.cpp
index 9fa2b0073c..e2d1bd7a32 100644
--- a/engines/titanic/input_handler.cpp
+++ b/engines/titanic/input_handler.cpp
@@ -49,7 +49,10 @@ void CInputHandler::incLockCount() {
}
void CInputHandler::decLockCount() {
- if (--_lockCount == 0 && _inputTranslator) {
+ --_lockCount;
+ assert(_lockCount >= 0);
+
+ if (_lockCount == 0 && _inputTranslator) {
if (_dragging && !_inputTranslator->isMousePressed()) {
CMouseButtonUpMsg upMsg(_mousePos, MK_LBUTTON);
handleMessage(upMsg);
@@ -107,6 +110,7 @@ void CInputHandler::processMessage(CMessage *msg) {
_dragging = false;
_dragItem = nullptr;
+ _gameManager->_dragItem = nullptr;
}
} else if (_buttonDown) {
if (!mouseMsg->isMouseMoveMsg()) {
diff --git a/engines/titanic/input_translator.cpp b/engines/titanic/input_translator.cpp
index ce272d152c..0f717de37f 100644
--- a/engines/titanic/input_translator.cpp
+++ b/engines/titanic/input_translator.cpp
@@ -90,6 +90,11 @@ void CInputTranslator::rightButtonUp(int special, const Point &pt) {
_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);
@@ -108,7 +113,7 @@ void CInputTranslator::keyDown(const Common::KeyState &keyState) {
}
bool CInputTranslator::isMousePressed() const {
- return g_vm->_window->getSpecialButtons() & (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON);
+ return g_vm->_events->getSpecialButtons() & (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON);
}
} // End of namespace Titanic
diff --git a/engines/titanic/input_translator.h b/engines/titanic/input_translator.h
index d92157bccc..66dcaa1cbe 100644
--- a/engines/titanic/input_translator.h
+++ b/engines/titanic/input_translator.h
@@ -50,6 +50,7 @@ public:
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 80da792e4a..de0ac715ba 100644
--- a/engines/titanic/main_game_window.cpp
+++ b/engines/titanic/main_game_window.cpp
@@ -32,8 +32,7 @@
namespace Titanic {
CMainGameWindow::CMainGameWindow(TitanicEngine *vm): _vm(vm),
- _specialButtons(0), _priorLeftDownTime(0),
- _priorMiddleDownTime(0), _priorRightDownTime(0) {
+ _priorLeftDownTime(0), _priorMiddleDownTime(0), _priorRightDownTime(0) {
_gameView = nullptr;
_gameManager = nullptr;
_project = nullptr;
@@ -150,6 +149,14 @@ void CMainGameWindow::draw() {
scrManager->clearSurface(SURFACE_BACKBUFFER, &_gameManager->_bounds);
switch (_gameManager->_gameState._mode) {
+ case GSMODE_PENDING_LOAD:
+ // Pending savegame to load
+ _gameManager->_gameState.setMode(GSMODE_INTERACTIVE);
+ _project->loadGame(_pendingLoadSlot);
+ _pendingLoadSlot = -1;
+
+ // Deliberate fall-through to draw loaded game
+
case GSMODE_INTERACTIVE:
case GSMODE_CUTSCENE:
if (_gameManager->_gameState._petActive)
@@ -165,12 +172,6 @@ void CMainGameWindow::draw() {
_vm->_filesManager->insertCD(scrManager);
break;
- case GSMODE_PENDING_LOAD:
- // Pending savegame to load
- _gameManager->_gameState.setMode(GSMODE_INTERACTIVE);
- _vm->_window->_project->loadGame(_pendingLoadSlot);
- break;
-
default:
break;
}
@@ -246,17 +247,21 @@ void CMainGameWindow::onIdle() {
}
#define HANDLE_MESSAGE(METHOD) if (_inputAllowed) { \
- _gameManager->_inputTranslator.METHOD(_specialButtons, mousePos); \
+ _gameManager->_inputTranslator.METHOD(g_vm->_events->getSpecialButtons(), mousePos); \
mouseChanged(); \
}
void CMainGameWindow::mouseMove(const Point &mousePos) {
+ if (!isMouseControlEnabled())
+ return;
+
HANDLE_MESSAGE(mouseMove)
}
void CMainGameWindow::leftButtonDown(const Point &mousePos) {
- _specialButtons |= MK_LBUTTON;
+ if (!isMouseControlEnabled())
+ return;
if ((_vm->_events->getTicksCount() - _priorLeftDownTime) < DOUBLE_CLICK_TIME) {
_priorLeftDownTime = 0;
@@ -268,16 +273,22 @@ void CMainGameWindow::leftButtonDown(const Point &mousePos) {
}
void CMainGameWindow::leftButtonUp(const Point &mousePos) {
- _specialButtons &= ~MK_LBUTTON;
+ if (!isMouseControlEnabled())
+ return;
+
HANDLE_MESSAGE(leftButtonUp)
}
void CMainGameWindow::leftButtonDoubleClick(const Point &mousePos) {
+ if (!isMouseControlEnabled())
+ return;
+
HANDLE_MESSAGE(leftButtonDoubleClick)
}
void CMainGameWindow::middleButtonDown(const Point &mousePos) {
- _specialButtons |= MK_MBUTTON;
+ if (!isMouseControlEnabled())
+ return;
if ((_vm->_events->getTicksCount() - _priorMiddleDownTime) < DOUBLE_CLICK_TIME) {
_priorMiddleDownTime = 0;
@@ -289,16 +300,22 @@ void CMainGameWindow::middleButtonDown(const Point &mousePos) {
}
void CMainGameWindow::middleButtonUp(const Point &mousePos) {
- _specialButtons &= ~MK_MBUTTON;
+ if (!isMouseControlEnabled())
+ return;
+
HANDLE_MESSAGE(middleButtonUp)
}
void CMainGameWindow::middleButtonDoubleClick(const Point &mousePos) {
+ if (!isMouseControlEnabled())
+ return;
+
HANDLE_MESSAGE(middleButtonDoubleClick)
}
void CMainGameWindow::rightButtonDown(const Point &mousePos) {
- _specialButtons |= MK_RBUTTON;
+ if (!isMouseControlEnabled())
+ return;
if ((_vm->_events->getTicksCount() - _priorRightDownTime) < DOUBLE_CLICK_TIME) {
_priorRightDownTime = 0;
@@ -310,21 +327,28 @@ void CMainGameWindow::rightButtonDown(const Point &mousePos) {
}
void CMainGameWindow::rightButtonUp(const Point &mousePos) {
- _specialButtons &= ~MK_RBUTTON;
+ if (!isMouseControlEnabled())
+ return;
+
HANDLE_MESSAGE(rightButtonUp)
}
-void CMainGameWindow::rightButtonDoubleClick(const Point &mousePos) {
- HANDLE_MESSAGE(rightButtonDoubleClick)
+void CMainGameWindow::mouseWheel(const Point &mousePos, bool wheelUp) {
+ if (!isMouseControlEnabled())
+ return;
+
+ _gameManager->_inputTranslator.mouseWheel(wheelUp, mousePos);
+ mouseChanged();
}
-void CMainGameWindow::charPress(char c) {
+void CMainGameWindow::rightButtonDoubleClick(const Point &mousePos) {
+ if (!isMouseControlEnabled())
+ return;
+ HANDLE_MESSAGE(rightButtonDoubleClick)
}
void CMainGameWindow::keyDown(Common::KeyState keyState) {
- handleKbdSpecial(keyState);
-
if (keyState.keycode == Common::KEYCODE_d && (keyState.flags & Common::KBD_CTRL)) {
// Attach to the debugger
_vm->_debugger->attach();
@@ -335,20 +359,12 @@ void CMainGameWindow::keyDown(Common::KeyState keyState) {
_gameManager->_inputTranslator.keyDown(keyState);
}
-void CMainGameWindow::keyUp(Common::KeyState keyState) {
- handleKbdSpecial(keyState);
-}
-
-void CMainGameWindow::handleKbdSpecial(Common::KeyState keyState) {
- if (keyState.flags & Common::KBD_CTRL)
- _specialButtons |= MK_CONTROL;
- else
- _specialButtons &= ~MK_CONTROL;
+bool CMainGameWindow::isMouseControlEnabled() const {
+ CScreenManager *screenMan = CScreenManager::_screenManagerPtr;
+ if (!screenMan || !screenMan->_mouseCursor)
+ return true;
- if (keyState.flags & Common::KBD_SHIFT)
- _specialButtons |= MK_SHIFT;
- else
- _specialButtons &= ~MK_SHIFT;
+ return screenMan->_mouseCursor->_inputEnabled;
}
} // End of namespace Titanic
diff --git a/engines/titanic/main_game_window.h b/engines/titanic/main_game_window.h
index 7bd918df04..52d4267c83 100644
--- a/engines/titanic/main_game_window.h
+++ b/engines/titanic/main_game_window.h
@@ -39,7 +39,6 @@ class CMainGameWindow : public CEventTarget {
private:
TitanicEngine *_vm;
int _pendingLoadSlot;
- uint _specialButtons;
uint32 _priorLeftDownTime;
uint32 _priorMiddleDownTime;
uint32 _priorRightDownTime;
@@ -74,8 +73,11 @@ private:
void leftButtonDoubleClick(const Point &mousePos);
void middleButtonDoubleClick(const Point &mousePos);
void rightButtonDoubleClick(const Point &mousePos);
- void charPress(char c);
- void handleKbdSpecial(Common::KeyState keyState);
+
+ /**
+ * Returns true if the player can control the mouse
+ */
+ bool isMouseControlEnabled() const;
public:
CGameView *_gameView;
CGameManager *_gameManager;
@@ -99,8 +101,8 @@ public:
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);
- virtual void keyUp(Common::KeyState keyState);
/**
* Called when the application starts
@@ -126,18 +128,6 @@ public:
* Schedules a savegame to be loaded
*/
void loadGame(int slotId);
-
- /*
- * Return whether a given special key is currently pressed
- */
- bool isSpecialPressed(SpecialButtons btn) const {
- return (_specialButtons & btn) != 0;
- }
-
- /**
- * Returns the bitset of the currently pressed special buttons
- */
- uint getSpecialButtons() const { return _specialButtons; }
};
} // End of namespace Titanic
diff --git a/engines/titanic/messages/messages.cpp b/engines/titanic/messages/messages.cpp
index a8507063ff..db89c3de3d 100644
--- a/engines/titanic/messages/messages.cpp
+++ b/engines/titanic/messages/messages.cpp
@@ -25,6 +25,7 @@
#include "titanic/core/game_object.h"
#include "titanic/core/message_target.h"
#include "titanic/core/tree_item.h"
+#include "titanic/pet_control/pet_control.h"
#include "titanic/titanic.h"
namespace Titanic {
@@ -163,4 +164,16 @@ bool CMessage::isLeaveViewMsg() const {
return dynamic_cast<const CLeaveViewMsg *>(this) != nullptr;
}
+/*------------------------------------------------------------------------*/
+
+CShowTextMsg::CShowTextMsg() : CMessage(), _message("NO TEXT INCLUDED!!!") {
+}
+
+CShowTextMsg::CShowTextMsg(const CString &msg) : CMessage(), _message(msg) {
+}
+
+CShowTextMsg::CShowTextMsg(StringId stringId) : CMessage() {
+ _message = g_vm->_strings[stringId];
+}
+
} // End of namespace Titanic
diff --git a/engines/titanic/messages/messages.h b/engines/titanic/messages/messages.h
index b421e8ecb8..fbe504700b 100644
--- a/engines/titanic/messages/messages.h
+++ b/engines/titanic/messages/messages.h
@@ -26,6 +26,7 @@
#include "common/keyboard.h"
#include "titanic/core/saveable_object.h"
#include "titanic/core/tree_item.h"
+#include "titanic/support/strings.h"
namespace Titanic {
@@ -182,6 +183,20 @@ public:
}
};
+class CShowTextMsg : public CMessage {
+public:
+ CString _message;
+public:
+ CLASSDEF;
+ CShowTextMsg();
+ CShowTextMsg(const CString &msg);
+ CShowTextMsg(StringId stringId);
+
+ static bool isSupportedBy(const CTreeItem *item) {
+ return supports(item, _type);
+ }
+};
+
MESSAGE1(CActMsg, CString, action, "");
MESSAGE1(CActivationmsg, CString, value, "");
MESSAGE1(CAddHeadPieceMsg, CString, value, "NULL");
@@ -286,7 +301,7 @@ MESSAGE0(CReplaceBowlAndNutsMsg);
MESSAGE1(CRestaurantMusicChanged, CString, value, "");
MESSAGE2(CSendCCarryMsg, CString, strValue, "", int, numValue, 0);
MESSAGE1(CSenseWorkingMsg, CString, value, "Not Working");
-MESSAGE2(CServiceElevatorFloorChangeMsg, int, value1, 0, int, value2, 0);
+MESSAGE2(CServiceElevatorFloorChangeMsg, int, startFloor, 0, int, endFloor, 0);
MESSAGE0(CServiceElevatorFloorRequestMsg);
MESSAGE1(CServiceElevatorMsg, int, value, 4);
MESSAGE2(CSetChevButtonImageMsg, int, value1, 0, int, value2, 0);
@@ -301,7 +316,6 @@ MESSAGE0(CSetMusicControlsMsg);
MESSAGE2(CSetVarMsg, CString, varName, "", int, value, 0);
MESSAGE2(CSetVolumeMsg, int, volume, 70, int, secondsTransition, 0);
MESSAGE2(CShipSettingMsg, int, value, 0, CString, name, "");
-MESSAGE1(CShowTextMsg, CString, value, "NO TEXT INCLUDED!!!");
MESSAGE2(CSignalObject, CString, strValue, "", int, numValue, 0);
MESSAGE1(CSpeechFallsFromTreeMsg, Point, pos, Point());
MESSAGE1(CStartMusicMsg, CMusicPlayer *, musicPlayer, (CMusicPlayer *)nullptr);
diff --git a/engines/titanic/messages/mouse_messages.h b/engines/titanic/messages/mouse_messages.h
index a10f3b42a8..05f9685c04 100644
--- a/engines/titanic/messages/mouse_messages.h
+++ b/engines/titanic/messages/mouse_messages.h
@@ -101,6 +101,20 @@ public:
static void generate();
};
+class CMouseWheelMsg : public CMouseMsg {
+public:
+ bool _wheelUp;
+public:
+ CLASSDEF;
+ CMouseWheelMsg() : CMouseMsg(), _wheelUp(false) {}
+ CMouseWheelMsg(const Point &pt, bool wheelUp) :
+ CMouseMsg(pt, 0), _wheelUp(wheelUp) {}
+
+ static bool isSupportedBy(const CTreeItem *item) {
+ return supports(item, _type);
+ }
+};
+
class CMouseDoubleClickMsg : public CMouseButtonMsg {
public:
CLASSDEF;
diff --git a/engines/titanic/moves/exit_lift.cpp b/engines/titanic/moves/exit_lift.cpp
index de9a3117af..a85af7c7a2 100644
--- a/engines/titanic/moves/exit_lift.cpp
+++ b/engines/titanic/moves/exit_lift.cpp
@@ -46,8 +46,8 @@ void CExitLift::load(SimpleFile *file) {
bool CExitLift::MouseButtonDownMsg(CMouseButtonDownMsg *msg) {
CPetControl *pet = getPetControl();
- int floorNum = pet->getRoomsFloorNum();//ebx
- int elevNum = pet->getRoomsElevatorNum(); //eax
+ int floorNum = pet->getRoomsFloorNum();
+ int elevNum = pet->getRoomsElevatorNum();
if (floorNum == 39) {
switch (elevNum) {
diff --git a/engines/titanic/moves/restricted_move.cpp b/engines/titanic/moves/restricted_move.cpp
index b1040a3554..92804d473d 100644
--- a/engines/titanic/moves/restricted_move.cpp
+++ b/engines/titanic/moves/restricted_move.cpp
@@ -51,7 +51,7 @@ bool CRestrictedMove::MouseButtonDownMsg(CMouseButtonDownMsg *msg) {
if (classNum <= _classNum) {
// Okay to change to the given destination
changeView(_destination);
- } else if (classNum != 4) {
+ } else if (classNum != UNCHECKED) {
petDisplayMessage(1, CLASS_NOT_ALLOWED_AT_DEST);
} else if (compareRoomNameTo("EmbLobby")) {
playSound("a#17.wav");
@@ -66,9 +66,9 @@ bool CRestrictedMove::MouseButtonDownMsg(CMouseButtonDownMsg *msg) {
bool CRestrictedMove::EnterViewMsg(CEnterViewMsg *msg) {
int classNum = getPassengerClass();
- bool flag = classNum > _classNum;
+ bool flag = classNum <= _classNum;
- if (classNum == 4) {
+ if (classNum == UNCHECKED) {
if (compareRoomNameTo("EmbLobby"))
flag = false;
else if (compareViewNameTo("Titania.Node 1.S"))
diff --git a/engines/titanic/npcs/barbot.cpp b/engines/titanic/npcs/barbot.cpp
index 791adaa05c..87aaea611f 100644
--- a/engines/titanic/npcs/barbot.cpp
+++ b/engines/titanic/npcs/barbot.cpp
@@ -336,7 +336,7 @@ bool CBarbot::TurnOn(CTurnOn *msg) {
_fieldC4 = 1;
++_v0;
petSetArea(PET_CONVERSATION);
- endTalking(this, true);
+ setTalking(this, true);
}
return true;
diff --git a/engines/titanic/npcs/bellbot.cpp b/engines/titanic/npcs/bellbot.cpp
index 7aa32eeef3..1326655299 100644
--- a/engines/titanic/npcs/bellbot.cpp
+++ b/engines/titanic/npcs/bellbot.cpp
@@ -79,7 +79,7 @@ bool CBellBot::OnSummonBotMsg(COnSummonBotMsg *msg) {
for (idx = 0; idx < 8; ++idx) {
if (compareRoomNameTo(ROOM_WAVES[idx][0])) {
playSound(ROOM_WAVES[idx][1]);
-
+ break;
}
}
if (idx == 8)
@@ -99,7 +99,7 @@ bool CBellBot::OnSummonBotMsg(COnSummonBotMsg *msg) {
bool CBellBot::LeaveViewMsg(CLeaveViewMsg *msg) {
if (_npcFlags & NPCFLAG_10000) {
performAction(1);
- _npcFlags &= ~NPCFLAG_4;
+ _npcFlags &= ~NPCFLAG_START_IDLING;
CDismissBotMsg dismissMsg;
dismissMsg.execute(this);
}
@@ -113,13 +113,13 @@ bool CBellBot::MovieEndMsg(CMovieEndMsg *msg) {
} else if (clipExistsByEnd("Walk On", msg->_endFrame)) {
setPosition(Point(80, 10));
loadFrame(543);
- _npcFlags |= NPCFLAG_4;
+ _npcFlags |= NPCFLAG_START_IDLING;
if (_npcFlags & NPCFLAG_40000) {
startTalking(this, 157);
_npcFlags &= ~NPCFLAG_40000;
}
- endTalking(this, true);
+ setTalking(this, true);
petSetArea(PET_CONVERSATION);
} else if (clipExistsByEnd("Walk Off", msg->_endFrame)) {
CPutBotBackInHisBoxMsg boxMsg;
@@ -142,8 +142,8 @@ bool CBellBot::Use(CUse *msg) {
bool CBellBot::DismissBotMsg(CDismissBotMsg *msg) {
if (_npcFlags & NPCFLAG_10000) {
playClip("Walk Off", MOVIE_NOTIFY_OBJECT | MOVIE_GAMESTATE);
- if (_npcFlags & NPCFLAG_4) {
- _npcFlags &= ~NPCFLAG_4;
+ if (_npcFlags & NPCFLAG_START_IDLING) {
+ _npcFlags &= ~NPCFLAG_START_IDLING;
performAction(true);
} else {
performAction(false);
@@ -160,7 +160,7 @@ bool CBellBot::TrueTalkTriggerActionMsg(CTrueTalkTriggerActionMsg *msg) {
switch (msg->_action) {
case 1:
case 28: {
- _npcFlags &= ~NPCFLAG_2;
+ _npcFlags &= ~NPCFLAG_IDLING;
CDismissBotMsg dismissMsg;
dismissMsg.execute(this);
break;
@@ -203,7 +203,7 @@ bool CBellBot::MovieFrameMsg(CMovieFrameMsg *msg) {
bool CBellBot::PutBotBackInHisBoxMsg(CPutBotBackInHisBoxMsg *msg) {
petMoveToHiddenRoom();
- _npcFlags &= ~NPCFLAG_4;
+ _npcFlags &= ~NPCFLAG_START_IDLING;
return true;
}
@@ -229,7 +229,7 @@ bool CBellBot::NPCPlayTalkingAnimationMsg(CNPCPlayTalkingAnimationMsg *msg) {
};
if (msg->_value2 == 2)
- playClip("Mother Frame", 0);
+ playClip("Mother Frame");
else
msg->_names = NAMES;
@@ -238,8 +238,6 @@ bool CBellBot::NPCPlayTalkingAnimationMsg(CNPCPlayTalkingAnimationMsg *msg) {
bool CBellBot::TimerMsg(CTimerMsg *msg) {
if (msg->_action == "SummonDoorbot") {
- CTrueTalkNPC::TimerMsg(msg);
- } else {
CRoomItem *room = getRoom();
if (room) {
CSummonBotMsg botMsg;
@@ -249,6 +247,8 @@ bool CBellBot::TimerMsg(CTimerMsg *msg) {
}
_npcFlags &= ~NPCFLAG_20000;
+ } else {
+ CTrueTalkNPC::TimerMsg(msg);
}
return true;
diff --git a/engines/titanic/npcs/bilge_succubus.cpp b/engines/titanic/npcs/bilge_succubus.cpp
index d1b89e58b4..006f532a31 100644
--- a/engines/titanic/npcs/bilge_succubus.cpp
+++ b/engines/titanic/npcs/bilge_succubus.cpp
@@ -431,7 +431,7 @@ bool CBilgeSuccUBus::TurnOn(CTurnOn *msg) {
CSUBTransition transMsg;
transMsg.execute(this);
- endTalking(this, true);
+ setTalking(this, true);
petSetArea(PET_REMOTE);
petHighlightGlyph(16);
}
diff --git a/engines/titanic/npcs/deskbot.cpp b/engines/titanic/npcs/deskbot.cpp
index c5032f1674..3a65b6f5bb 100644
--- a/engines/titanic/npcs/deskbot.cpp
+++ b/engines/titanic/npcs/deskbot.cpp
@@ -52,7 +52,8 @@ END_MESSAGE_MAP()
int CDeskbot::_v1;
int CDeskbot::_v2;
-CDeskbot::CDeskbot() : CTrueTalkNPC(), _deskbotActive(false), _classNum(0) {
+CDeskbot::CDeskbot() : CTrueTalkNPC(), _deskbotActive(false),
+ _classNum(NO_CLASS) {
}
void CDeskbot::save(SimpleFile *file, int indent) {
@@ -70,7 +71,7 @@ void CDeskbot::load(SimpleFile *file) {
_v1 = file->readNumber();
_v2 = file->readNumber();
_deskbotActive = file->readNumber();
- _classNum = file->readNumber();
+ _classNum = (PassengerClass)file->readNumber();
CTrueTalkNPC::load(file);
}
@@ -78,7 +79,9 @@ void CDeskbot::load(SimpleFile *file) {
bool CDeskbot::TurnOn(CTurnOn *msg) {
if (!_deskbotActive) {
setVisible(true);
- playClip("BellRinging", 4);
+ playClip("BellRinging");
+ playClip("Opening", MOVIE_NOTIFY_OBJECT);
+
playSound("b#69.wav");
petSetArea(PET_CONVERSATION);
@@ -114,7 +117,7 @@ bool CDeskbot::MovieEndMsg(CMovieEndMsg *msg) {
dec54();
unlockMouse();
playSound("z#47.wav");
- _classNum = false;
+ _classNum = NO_CLASS;
}
_npcFlags &= ~NPCFLAG_10000;
@@ -143,9 +146,9 @@ bool CDeskbot::MovieEndMsg(CMovieEndMsg *msg) {
if (_npcFlags & NPCFLAG_20000) {
_npcFlags &= ~(NPCFLAG_40000 | NPCFLAG_20000);
- endTalking(this, 1, findView());
+ setTalking(this, true, findView());
- _npcFlags |= NPCFLAG_4;
+ _npcFlags |= NPCFLAG_START_IDLING;
flag = true;
}
@@ -170,23 +173,23 @@ bool CDeskbot::TrueTalkTriggerActionMsg(CTrueTalkTriggerActionMsg *msg) {
inc54();
lockMouse();
petSetArea(PET_CONVERSATION);
- playClip("ReprogramPETInHand", 4);
+ playClip("ReprogramPETInHand", MOVIE_NOTIFY_OBJECT);
_npcFlags |= NPCFLAG_10000;
- _classNum = msg->_param1;
+ _classNum = (PassengerClass)msg->_param1;
switch (_classNum) {
- case 1:
+ case FIRST_CLASS:
petDisplayMessage(UPGRADED_TO_FIRST_CLASS);
setPassengerClass(_classNum);
petReassignRoom(_classNum);
break;
- case 2:
+ case SECOND_CLASS:
petDisplayMessage(UPGRADED_TO_SECOND_CLASS);
setPassengerClass(_classNum);
petReassignRoom(_classNum);
break;
- case 3:
- setPassengerClass(3);
+ case THIRD_CLASS:
+ setPassengerClass(THIRD_CLASS);
petReassignRoom(_classNum);
break;
default:
@@ -197,31 +200,31 @@ bool CDeskbot::TrueTalkTriggerActionMsg(CTrueTalkTriggerActionMsg *msg) {
if (getPassengerClass() == 1) {
CPetControl *petControl = getPetControl();
if (petControl)
- petControl->changeLocationClass(4);
+ petControl->changeLocationClass(UNCHECKED);
}
break;
case 21:
- if (getPassengerClass() == 1) {
+ if (getPassengerClass() == FIRST_CLASS) {
CPetControl *petControl = getPetControl();
if (petControl)
- petControl->changeLocationClass(3);
+ petControl->changeLocationClass(THIRD_CLASS);
}
break;
case 22:
- if (getPassengerClass() == 1) {
+ if (getPassengerClass() == FIRST_CLASS) {
CPetControl *petControl = getPetControl();
if (petControl)
- petControl->changeLocationClass(2);
+ petControl->changeLocationClass(SECOND_CLASS);
}
break;
case 23:
- if (getPassengerClass() == 1) {
+ if (getPassengerClass() == FIRST_CLASS) {
CPetControl *petControl = getPetControl();
if (petControl)
- petControl->changeLocationClass(1);
+ petControl->changeLocationClass(FIRST_CLASS);
}
break;
@@ -300,8 +303,8 @@ bool CDeskbot::TurnOff(CTurnOff *msg) {
stopMovie();
performAction(1, findView());
- _npcFlags = (_npcFlags & ~(NPCFLAG_SPEAKING | NPCFLAG_2 | NPCFLAG_4)) | NPCFLAG_40000;
- playClip("Closing", 0x14);
+ _npcFlags = (_npcFlags & ~(NPCFLAG_SPEAKING | NPCFLAG_IDLING | NPCFLAG_START_IDLING)) | NPCFLAG_40000;
+ playClip("Closing", MOVIE_GAMESTATE | MOVIE_NOTIFY_OBJECT);
}
return true;
diff --git a/engines/titanic/npcs/deskbot.h b/engines/titanic/npcs/deskbot.h
index ab48d63546..1b462f6584 100644
--- a/engines/titanic/npcs/deskbot.h
+++ b/engines/titanic/npcs/deskbot.h
@@ -45,7 +45,7 @@ private:
static int _v2;
public:
bool _deskbotActive;
- int _classNum;
+ PassengerClass _classNum;
public:
CLASSDEF;
CDeskbot();
diff --git a/engines/titanic/npcs/doorbot.cpp b/engines/titanic/npcs/doorbot.cpp
index d26f4bb828..ebab6508c2 100644
--- a/engines/titanic/npcs/doorbot.cpp
+++ b/engines/titanic/npcs/doorbot.cpp
@@ -22,6 +22,7 @@
#include "titanic/npcs/doorbot.h"
#include "titanic/core/room_item.h"
+#include "titanic/titanic.h"
namespace Titanic {
@@ -48,7 +49,7 @@ int CDoorbot::_v1;
int CDoorbot::_v2;
CDoorbot::CDoorbot() : CTrueTalkNPC() {
- _field108 = 0;
+ _introMovieNum = 0;
_timerId = 0;
_field110 = 0;
_field114 = 0;
@@ -59,7 +60,7 @@ void CDoorbot::save(SimpleFile *file, int indent) {
file->writeNumberLine(_v1, indent);
file->writeNumberLine(_v2, indent);
- file->writeNumberLine(_field108, indent);
+ file->writeNumberLine(_introMovieNum, indent);
file->writeNumberLine(_timerId, indent);
file->writeNumberLine(_field110, indent);
file->writeNumberLine(_field114, indent);
@@ -72,7 +73,7 @@ void CDoorbot::load(SimpleFile *file) {
_v1 = file->readNumber();
_v2 = file->readNumber();
- _field108 = file->readNumber();
+ _introMovieNum = file->readNumber();
_timerId = file->readNumber();
_field110 = file->readNumber();
_field114 = file->readNumber();
@@ -81,11 +82,14 @@ void CDoorbot::load(SimpleFile *file) {
}
bool CDoorbot::MovieEndMsg(CMovieEndMsg *msg) {
+ debugC(ERROR_DETAILED, kDebugScripts, "CDoorbot MovieEndMsg flags=%x v=%d, start=%d, end=%d",
+ _npcFlags, _introMovieNum, msg->_startFrame, msg->_endFrame);
+
if (_npcFlags & NPCFLAG_DOORBOT_INTRO) {
- switch (_field108) {
+ switch (_introMovieNum) {
case 3:
startTalking(this, 221482);
- _field108 = 4;
+ _introMovieNum = 4;
break;
case 6:
@@ -99,7 +103,7 @@ bool CDoorbot::MovieEndMsg(CMovieEndMsg *msg) {
case 7:
startTalking(this, 221467);
- _field108 = 8;
+ _introMovieNum = 8;
break;
case 9:
@@ -118,11 +122,11 @@ bool CDoorbot::MovieEndMsg(CMovieEndMsg *msg) {
CTrueTalkNPC::MovieEndMsg(msg);
} else if (_npcFlags & NPCFLAG_100000) {
if (clipExistsByEnd("Cloak Off", msg->_endFrame)) {
- _npcFlags = (_npcFlags & ~NPCFLAG_8) | NPCFLAG_4;
- endTalking(this, false);
+ _npcFlags = (_npcFlags & ~NPCFLAG_8) | NPCFLAG_START_IDLING;
+ setTalking(this, false);
startTalking(this, 221474);
_npcFlags |= NPCFLAG_DOORBOT_INTRO;
- _field108 = 0;
+ _introMovieNum = 0;
} else if (clipExistsByEnd("Cloak On", msg->_endFrame)) {
petShow();
setState1C(true);
@@ -135,8 +139,8 @@ bool CDoorbot::MovieEndMsg(CMovieEndMsg *msg) {
|| clipExistsByEnd("Whizz On Right", msg->_endFrame)) {
setPosition(Point((600 - _bounds.width()) / 2 + 18, 42));
loadFrame(0);
- endTalking(this, true);
- _npcFlags |= NPCFLAG_4;
+ setTalking(this, true);
+ _npcFlags |= NPCFLAG_START_IDLING;
petSetArea(PET_CONVERSATION);
} else if (clipExistsByEnd("Whizz Off Left", msg->_endFrame)
|| clipExistsByEnd("Whizz Off Right", msg->_endFrame)) {
@@ -195,12 +199,12 @@ bool CDoorbot::TrueTalkTriggerActionMsg(CTrueTalkTriggerActionMsg *msg) {
break;
case 4:
- _npcFlags = (_npcFlags & ~NPCFLAG_2) | NPCFLAG_4000000;
+ _npcFlags = (_npcFlags & ~NPCFLAG_IDLING) | NPCFLAG_4000000;
playClip("Whizz Off Left", MOVIE_NOTIFY_OBJECT | MOVIE_GAMESTATE);
break;
case 28: {
- _npcFlags &= ~(NPCFLAG_2 | NPCFLAG_4);
+ _npcFlags &= ~(NPCFLAG_IDLING | NPCFLAG_START_IDLING);
CDismissBotMsg dismissMsg;
dismissMsg.execute(this);
break;
@@ -227,13 +231,13 @@ bool CDoorbot::DoorbotNeededInElevatorMsg(CDoorbotNeededInElevatorMsg *msg) {
setPosition(Point(100, 42));
if (_npcFlags & NPCFLAG_DOORBOT_INTRO) {
- _field108 = 7;
+ _introMovieNum = 7;
_npcFlags |= NPCFLAG_200000;
loadFrame(797);
} else {
_npcFlags = 0;
if (msg->_value)
- endTalking(this, true);
+ setTalking(this, true);
}
return true;
@@ -242,7 +246,7 @@ bool CDoorbot::DoorbotNeededInElevatorMsg(CDoorbotNeededInElevatorMsg *msg) {
bool CDoorbot::LeaveViewMsg(CLeaveViewMsg *msg) {
if (!(_npcFlags & NPCFLAG_DOORBOT_INTRO) && (_npcFlags & NPCFLAG_400000)) {
performAction(true);
- _npcFlags &= ~NPCFLAG_4;
+ _npcFlags &= ~NPCFLAG_START_IDLING;
}
return true;
@@ -252,6 +256,8 @@ bool CDoorbot::TimerMsg(CTimerMsg *msg) {
if (msg->_action == "NPCIdleAnim") {
return CTrueTalkNPC::TimerMsg(msg);
} else if (_npcFlags & NPCFLAG_DOORBOT_INTRO) {
+ _timerId = 0;
+
switch (msg->_actionVal) {
case 0:
startTalking(this, 221475);
@@ -266,11 +272,11 @@ bool CDoorbot::TimerMsg(CTimerMsg *msg) {
break;
case 3:
- playClip("DoubleTake Start", 0);
- playClip("DoubleTake End", 0);
- playClip("DoubleTake Start", 0);
+ playClip("DoubleTake Start");
+ playClip("DoubleTake End");
+ playClip("DoubleTake Start");
playClip("DoubleTake End", MOVIE_NOTIFY_OBJECT);
- _field108 = 3;
+ _introMovieNum = 3;
break;
case 4:
@@ -281,21 +287,23 @@ bool CDoorbot::TimerMsg(CTimerMsg *msg) {
case 5:
lockInputHandler();
- mouseLockE4();
+ mouseDisableControl();
_field114 = true;
startTalking(this, 221485);
break;
case 6:
+ // Start dragging photograph to PET
CMouseButtonDownMsg::generate();
mouseSetPosition(Point(200, 430), 2500);
_timerId = addTimer(7, 2500, 0);
break;
case 7:
- CMouseButtonDownMsg::generate();
+ // Drop photograph in PET
+ CMouseButtonUpMsg::generate();
startTalking(this, 221486);
- mouseUnlockE4();
+ mouseEnableControl();
unlockInputHandler();
_field114 = false;
disableMouse();
@@ -334,11 +342,17 @@ bool CDoorbot::NPCPlayTalkingAnimationMsg(CNPCPlayTalkingAnimationMsg *msg) {
if (msg->_value2 != 2) {
if (_npcFlags & NPCFLAG_200000) {
- if (_field108 == 8 || _field110) {
+ switch (_introMovieNum) {
+ case 8:
+ case 10:
msg->_names = NAMES2;
- } else if (_field108 == 9) {
+ break;
+ case 9:
msg->_names = NAMES3;
- _field108 = 10;
+ _introMovieNum = 10;
+ break;
+ default:
+ break;
}
} else if (_npcFlags & (NPCFLAG_100000 | NPCFLAG_400000)) {
msg->_names = NAMES1;
@@ -362,7 +376,7 @@ bool CDoorbot::NPCPlayIdleAnimationMsg(CNPCPlayIdleAnimationMsg *msg) {
bool CDoorbot::PutBotBackInHisBoxMsg(CPutBotBackInHisBoxMsg *msg) {
petMoveToHiddenRoom();
- _npcFlags &= ~(NPCFLAG_4 | NPCFLAG_100000 | NPCFLAG_200000 | NPCFLAG_DOORBOT_INTRO);
+ _npcFlags &= ~(NPCFLAG_START_IDLING | NPCFLAG_100000 | NPCFLAG_200000 | NPCFLAG_DOORBOT_INTRO);
if (msg->_value)
performAction(true);
@@ -375,8 +389,8 @@ bool CDoorbot::DismissBotMsg(CDismissBotMsg *msg) {
MOVIE_STOP_PREVIOUS | MOVIE_NOTIFY_OBJECT | MOVIE_GAMESTATE);
movieEvent();
- if (_npcFlags & NPCFLAG_4) {
- _npcFlags &= ~NPCFLAG_4;
+ if (_npcFlags & NPCFLAG_START_IDLING) {
+ _npcFlags &= ~NPCFLAG_START_IDLING;
performAction(true);
} else {
performAction(false);
@@ -409,7 +423,7 @@ bool CDoorbot::TrueTalkNotifySpeechEndedMsg(CTrueTalkNotifySpeechEndedMsg *msg)
switch (msg->_dialogueId) {
case 10552:
playClip("SE Try Buttons", MOVIE_NOTIFY_OBJECT);
- _field108 = 9;
+ _introMovieNum = 9;
break;
case 10553:
@@ -418,7 +432,7 @@ bool CDoorbot::TrueTalkNotifySpeechEndedMsg(CTrueTalkNotifySpeechEndedMsg *msg)
case 10557:
playClip("SE Move To Right", MOVIE_NOTIFY_OBJECT);
- _field108 = 11;
+ _introMovieNum = 11;
break;
case 10559:
@@ -435,13 +449,13 @@ bool CDoorbot::TrueTalkNotifySpeechEndedMsg(CTrueTalkNotifySpeechEndedMsg *msg)
case 10561:
enableMouse();
- _field108 = 1;
+ _introMovieNum = 1;
stopAnimTimer(_timerId);
_timerId = addTimer(2, 10000, 0);
break;
case 10562:
- if (_field108 == 1) {
+ if (_introMovieNum == 1) {
stopAnimTimer(_timerId);
_timerId = addTimer(2, getRandomNumber(5000), 0);
}
@@ -462,7 +476,7 @@ bool CDoorbot::TrueTalkNotifySpeechEndedMsg(CTrueTalkNotifySpeechEndedMsg *msg)
_timerId = 0;
if (_field110 == 2) {
playClip("Cloak On", MOVIE_NOTIFY_OBJECT);
- _field108 = 6;
+ _introMovieNum = 6;
} else {
_timerId = addTimer(3, 2000, 0);
}
@@ -478,7 +492,8 @@ bool CDoorbot::TrueTalkNotifySpeechEndedMsg(CTrueTalkNotifySpeechEndedMsg *msg)
}
case 10568:
- mouseLockE4();
+ // Start moving cursor to photograph
+ mouseDisableControl();
mouseSetPosition(Point(600, 250), 2500);
_timerId = addTimer(6, 2500, 0);
break;
@@ -497,7 +512,7 @@ bool CDoorbot::TrueTalkNotifySpeechEndedMsg(CTrueTalkNotifySpeechEndedMsg *msg)
case 10571:
playClip("Cloak On", MOVIE_NOTIFY_OBJECT);
- _field108 = 6;
+ _introMovieNum = 6;
break;
default:
@@ -512,9 +527,9 @@ bool CDoorbot::TextInputMsg(CTextInputMsg *msg) {
if (!(_npcFlags & NPCFLAG_DOORBOT_INTRO))
return CTrueTalkNPC::TextInputMsg(msg);
- if (_field108 == 1) {
+ if (_introMovieNum == 1) {
stopAnimTimer(_timerId);
- _field108 = 2;
+ _introMovieNum = 2;
_timerId = 0;
if (msg->_input == "yes" || msg->_input == "yeah"
@@ -532,34 +547,36 @@ bool CDoorbot::TextInputMsg(CTextInputMsg *msg) {
}
bool CDoorbot::EnterViewMsg(CEnterViewMsg *msg) {
- if ((_npcFlags & NPCFLAG_DOORBOT_INTRO) && _field108 == 7)
+ if ((_npcFlags & NPCFLAG_DOORBOT_INTRO) && _introMovieNum == 7)
playClip("SE Move And Turn", MOVIE_NOTIFY_OBJECT);
return true;
}
bool CDoorbot::ActMsg(CActMsg *msg) {
+ debugC(ERROR_DETAILED, kDebugScripts, "CDoorbot ActMsg action=%s v108=%d v110=%d v114=%d",
+ msg->_action.c_str(), _introMovieNum, _field110, _field114);
+
if (msg->_action == "DoorbotPlayerPressedTopButton") {
disableMouse();
startTalking(this, 221471);
} else if (msg->_action == "DoorbotPlayerPressedMiddleButton") {
startTalking(this, 221470);
- }
- else if (msg->_action == "DoorbotPlayerPressedBottomButton") {
+ } else if (msg->_action == "DoorbotPlayerPressedBottomButton") {
startTalking(this, 221469);
} else if (msg->_action == "DoorbotReachedEmbLobby") {
startTalking(this, 221472);
} else if (msg->_action == "PlayerPicksUpPhoto") {
_field110 = 1;
- if (!_field114 && _field108 == 4) {
+ if (!_field114 && _introMovieNum == 4) {
stopAnimTimer(_timerId);
_timerId = 0;
- _field108 = 5;
+ _introMovieNum = 5;
startTalking(this, 221484);
}
} else if (msg->_action == "PlayerPutsPhotoInPet") {
_field110 = 2;
- if (!_field114 && _field108 == 5) {
+ if (!_field114 && _introMovieNum == 5) {
stopAnimTimer(_timerId);
_timerId = 0;
startTalking(this, 221486);
diff --git a/engines/titanic/npcs/doorbot.h b/engines/titanic/npcs/doorbot.h
index 9095ebc7e7..1cb7ec3f27 100644
--- a/engines/titanic/npcs/doorbot.h
+++ b/engines/titanic/npcs/doorbot.h
@@ -49,7 +49,7 @@ private:
static int _v1;
static int _v2;
private:
- int _field108;
+ int _introMovieNum;
int _timerId;
int _field110;
int _field114;
diff --git a/engines/titanic/npcs/liftbot.cpp b/engines/titanic/npcs/liftbot.cpp
index 64bc7c4989..bb554a104f 100644
--- a/engines/titanic/npcs/liftbot.cpp
+++ b/engines/titanic/npcs/liftbot.cpp
@@ -66,7 +66,7 @@ void CLiftBot::load(SimpleFile *file) {
bool CLiftBot::TextInputMsg(CTextInputMsg *msg) {
CPetControl *pet = getPetControl();
if (_enabled || pet->getRoomsElevatorNum() != 4) {
- if (getName() != "LiftBot") {
+ if (getName() == "LiftBot") {
CViewItem *view = findView();
processInput(msg, view);
}
@@ -79,13 +79,12 @@ bool CLiftBot::EnterViewMsg(CEnterViewMsg *msg) {
CPetControl *pet = getPetControl();
if (!_enabled && pet->getRoomsElevatorNum() == 4) {
loadFrame(700);
- } else if (!_flag) {
- if (getName() != "LiftBot") {
- CViewItem *view = findView();
- endTalking(this, true, view);
- petSetArea(PET_CONVERSATION);
- _flag = 1;
- }
+ } else if (!_flag && getName() == "LiftBot") {
+ // First time meeting the LiftBot
+ CViewItem *view = findView();
+ setTalking(this, true, view);
+ petSetArea(PET_CONVERSATION);
+ _flag = 1;
}
return true;
@@ -109,7 +108,7 @@ bool CLiftBot::TrueTalkTriggerActionMsg(CTrueTalkTriggerActionMsg *msg) {
}
bool CLiftBot::LeaveRoomMsg(CLeaveRoomMsg *msg) {
- if (getName() != "LiftBot")
+ if (getName() == "LiftBot")
performAction(false);
return true;
@@ -124,7 +123,7 @@ bool CLiftBot::TurnOn(CTurnOn *msg) {
_enabled = true;
if (!_flag) {
if (isEquals("LiftBotTalking")) {
- endTalking(this, MOVIE_REPEAT, findView());
+ setTalking(this, MOVIE_REPEAT, findView());
petSetArea(PET_CONVERSATION);
_flag = true;
}
@@ -164,7 +163,7 @@ bool CLiftBot::NPCPlayTalkingAnimationMsg(CNPCPlayTalkingAnimationMsg *msg) {
};
if (msg->_value2 == 2)
- playClip("At Rest", 0);
+ playClip("At Rest");
else
msg->_names = NAMES;
return true;
@@ -174,7 +173,7 @@ bool CLiftBot::ActMsg(CActMsg *msg) {
if (msg->_action == "ActivateLift") {
_enabled = true;
CViewItem *view = findView();
- endTalking(this, true, view);
+ setTalking(this, true, view);
startTalking(this, 155, view);
} else if (msg->_action == "LiftArrive") {
CViewItem *view = findView();
diff --git a/engines/titanic/npcs/maitre_d.cpp b/engines/titanic/npcs/maitre_d.cpp
index 658b7c7123..cbb406fffa 100644
--- a/engines/titanic/npcs/maitre_d.cpp
+++ b/engines/titanic/npcs/maitre_d.cpp
@@ -114,7 +114,7 @@ bool CMaitreD::TrueTalkTriggerActionMsg(CTrueTalkTriggerActionMsg *msg) {
}
bool CMaitreD::EnterViewMsg(CEnterViewMsg *msg) {
- endTalking(this, true, findView());
+ setTalking(this, true, findView());
_field12C = _field134;
if (_string3 == "STMusic" && (!_field11C || _string2 == _string3))
diff --git a/engines/titanic/npcs/parrot.cpp b/engines/titanic/npcs/parrot.cpp
index 97a1944fef..c3702e17d4 100644
--- a/engines/titanic/npcs/parrot.cpp
+++ b/engines/titanic/npcs/parrot.cpp
@@ -202,7 +202,7 @@ bool CParrot::ActMsg(CActMsg *msg) {
}
bool CParrot::MouseButtonDownMsg(CMouseButtonDownMsg *msg) {
- if (!(_npcFlags & NPCFLAG_2000000) && _field100 <= 0) {
+ if (!(_npcFlags & NPCFLAG_2000000) && _speechCounter == 0) {
CTrueTalkTriggerActionMsg triggerMsg(280250, 280250, 1);
triggerMsg.execute(this);
}
@@ -291,7 +291,7 @@ bool CParrot::MovieEndMsg(CMovieEndMsg *msg) {
return true;
} else if (clipExistsByEnd("Lean Over To Chicken", msg->_endFrame)) {
- playClip("Eat Chicken", 0);
+ playClip("Eat Chicken");
playClip("Eat Chicken 2", MOVIE_NOTIFY_OBJECT);
_v1 = 1;
@@ -352,9 +352,9 @@ bool CParrot::EnterViewMsg(CEnterViewMsg *msg) {
_field118 = 1;
_npcFlags &= ~(NPCFLAG_10000 | NPCFLAG_20000 | NPCFLAG_40000 | NPCFLAG_80000 | NPCFLAG_100000 | NPCFLAG_200000 | NPCFLAG_400000);
loadFrame(0);
- endTalking(this, true, findView());
+ setTalking(this, true, findView());
- if (_field100 > 0) {
+ if (_speechCounter > 0) {
playRandomClip(NAMES, MOVIE_NOTIFY_OBJECT);
} else {
startTalking(this, 280258, findView());
@@ -362,7 +362,7 @@ bool CParrot::EnterViewMsg(CEnterViewMsg *msg) {
petSetArea(PET_CONVERSATION);
_field12C = 0;
- _npcFlags |= NPCFLAG_4;
+ _npcFlags |= NPCFLAG_START_IDLING;
}
return true;
@@ -404,7 +404,7 @@ bool CParrot::MouseDragStartMsg(CMouseDragStartMsg *msg) {
bool CParrot::LeaveViewMsg(CLeaveViewMsg *msg) {
performAction(true);
- _npcFlags &= ~NPCFLAG_4;
+ _npcFlags &= ~NPCFLAG_START_IDLING;
return true;
}
@@ -425,7 +425,7 @@ bool CParrot::ParrotSpeakMsg(CParrotSpeakMsg *msg) {
}
// Don't have the parrot speak too often
- if ((getTicksCount() - _field120) < 20000 || _field100)
+ if ((getTicksCount() - _field120) < 20000 || _speechCounter)
return true;
playSound("z#475.wav", 50);
diff --git a/engines/titanic/npcs/succubus.cpp b/engines/titanic/npcs/succubus.cpp
index 6db8c8d798..bdde682c03 100644
--- a/engines/titanic/npcs/succubus.cpp
+++ b/engines/titanic/npcs/succubus.cpp
@@ -671,7 +671,7 @@ bool CSuccUBus::TurnOn(CTurnOn *msg) {
CSUBTransition transMsg;
transMsg.execute(this);
- endTalking(this, true, findView());
+ setTalking(this, true, findView());
petSetArea(PET_REMOTE);
petHighlightGlyph(16);
}
diff --git a/engines/titanic/npcs/titania.cpp b/engines/titanic/npcs/titania.cpp
index aa92ddd166..db0c85d5f5 100644
--- a/engines/titanic/npcs/titania.cpp
+++ b/engines/titanic/npcs/titania.cpp
@@ -180,7 +180,7 @@ bool CTitania::ActMsg(CActMsg *msg) {
CActMsg actMsg("Woken");
actMsg.execute("MouthSlot");
actMsg.execute("VisionCentreSlot");
- setPassengerClass(4);
+ setPassengerClass(UNCHECKED);
addTimer(1000);
} else {
diff --git a/engines/titanic/npcs/true_talk_npc.cpp b/engines/titanic/npcs/true_talk_npc.cpp
index 55666a21a9..8d08600c9b 100644
--- a/engines/titanic/npcs/true_talk_npc.cpp
+++ b/engines/titanic/npcs/true_talk_npc.cpp
@@ -24,6 +24,7 @@
#include "titanic/core/view_item.h"
#include "titanic/pet_control/pet_control.h"
#include "titanic/game_manager.h"
+#include "titanic/titanic.h"
namespace Titanic {
@@ -41,7 +42,7 @@ END_MESSAGE_MAP()
CTrueTalkNPC::CTrueTalkNPC() : _assetName("z451.dlg"),
_assetNumber(0x11170), _fieldE4(0), _npcFlags(0), _speechDuration(0), _startTicks(0),
- _fieldF4(0), _fieldF8(0), _speechTimerId(0), _field100(0), _field104(0) {
+ _fieldF4(0), _fieldF8(0), _speechTimerId(0), _speechCounter(0), _field104(0) {
}
void CTrueTalkNPC::save(SimpleFile *file, int indent) {
@@ -55,7 +56,7 @@ void CTrueTalkNPC::save(SimpleFile *file, int indent) {
file->writeNumberLine(_fieldF4, indent);
file->writeNumberLine(_fieldF8, indent);
file->writeNumberLine(_speechTimerId, indent);
- file->writeNumberLine(_field100, indent);
+ file->writeNumberLine(_speechCounter, indent);
file->writeNumberLine(_field104, indent);
CCharacter::save(file, indent);
@@ -72,7 +73,7 @@ void CTrueTalkNPC::load(SimpleFile *file) {
_fieldF4 = file->readNumber();
_fieldF8 = file->readNumber();
_speechTimerId = file->readNumber();
- _field100 = file->readNumber();
+ _speechCounter = file->readNumber();
_field104 = file->readNumber();
CCharacter::load(file);
@@ -95,8 +96,11 @@ bool CTrueTalkNPC::DismissBotMsg(CDismissBotMsg *msg) {
}
bool CTrueTalkNPC::TrueTalkNotifySpeechStartedMsg(CTrueTalkNotifySpeechStartedMsg *msg) {
+ debugC(ERROR_DETAILED, kDebugScripts, "%s TrueTalkNotifySpeechStartedMsg flags=%x dialogueId=%d",
+ getName().c_str(), _npcFlags, msg->_dialogueId);
+
_npcFlags |= NPCFLAG_SPEAKING;
- ++_field100;
+ ++_speechCounter;
if (!(_npcFlags & NPCFLAG_8)) {
// Stop any previous animation
@@ -107,8 +111,8 @@ bool CTrueTalkNPC::TrueTalkNotifySpeechStartedMsg(CTrueTalkNotifySpeechStartedMs
_speechDuration = msg->_speechDuration;
_startTicks = getTicksCount();
- if (!hasActiveMovie() || (_npcFlags & NPCFLAG_2)) {
- _npcFlags &= ~NPCFLAG_2;
+ if (!hasActiveMovie() || (_npcFlags & NPCFLAG_IDLING)) {
+ _npcFlags &= ~NPCFLAG_IDLING;
stopMovie();
CNPCPlayTalkingAnimationMsg msg1(_speechDuration, 0, nullptr);
@@ -125,12 +129,13 @@ bool CTrueTalkNPC::TrueTalkNotifySpeechStartedMsg(CTrueTalkNotifySpeechStartedMs
}
bool CTrueTalkNPC::TrueTalkNotifySpeechEndedMsg(CTrueTalkNotifySpeechEndedMsg *msg) {
+ debugC(ERROR_DETAILED, kDebugScripts, "%s TrueTalkNotifySpeechEndedMsg flags=%x dialogueId=%d", getName().c_str(), _npcFlags, msg->_dialogueId);
_npcFlags &= ~NPCFLAG_SPEAKING;
- --_field100;
+ --_speechCounter;
_speechDuration = 0;
if (!(_npcFlags & NPCFLAG_8)) {
- CNPCPlayTalkingAnimationMsg msg1(0, 2, 0);
+ CNPCPlayTalkingAnimationMsg msg1(0, 2, nullptr);
msg1.execute(this);
CNPCQueueIdleAnimMsg msg2;
msg2.execute(this);
@@ -140,8 +145,8 @@ bool CTrueTalkNPC::TrueTalkNotifySpeechEndedMsg(CTrueTalkNotifySpeechEndedMsg *m
}
bool CTrueTalkNPC::MovieEndMsg(CMovieEndMsg *msg) {
- if (_npcFlags & NPCFLAG_2) {
- _npcFlags &= ~NPCFLAG_2;
+ if (_npcFlags & NPCFLAG_IDLING) {
+ _npcFlags &= ~NPCFLAG_IDLING;
CNPCQueueIdleAnimMsg idleMsg;
idleMsg.execute(this);
return true;
@@ -170,8 +175,8 @@ bool CTrueTalkNPC::NPCQueueIdleAnimMsg(CNPCQueueIdleAnimMsg *msg) {
}
bool CTrueTalkNPC::TimerMsg(CTimerMsg *msg) {
- if (_npcFlags & NPCFLAG_4) {
- if (_field100 > 0)
+ if (_npcFlags & NPCFLAG_START_IDLING) {
+ if (_speechCounter > 0)
return false;
CNPCPlayIdleAnimationMsg idleMsg;
@@ -181,7 +186,7 @@ bool CTrueTalkNPC::TimerMsg(CTimerMsg *msg) {
animMsg.execute(this);
}
- _npcFlags &= ~NPCFLAG_2;
+ _npcFlags &= ~NPCFLAG_IDLING;
}
}
diff --git a/engines/titanic/npcs/true_talk_npc.h b/engines/titanic/npcs/true_talk_npc.h
index 3adf055449..d9ea037a72 100644
--- a/engines/titanic/npcs/true_talk_npc.h
+++ b/engines/titanic/npcs/true_talk_npc.h
@@ -30,8 +30,8 @@
namespace Titanic {
enum NpcFlag {
- NPCFLAG_SPEAKING = 1, NPCFLAG_2 = 2, NPCFLAG_4 = 4, NPCFLAG_8 = 8,
- NPCFLAG_10000 = 0x10000, NPCFLAG_20000 = 0x20000,
+ NPCFLAG_SPEAKING = 1, NPCFLAG_IDLING = 2, NPCFLAG_START_IDLING = 4,
+ NPCFLAG_8 = 8, NPCFLAG_10000 = 0x10000, NPCFLAG_20000 = 0x20000,
NPCFLAG_40000 = 0x40000, NPCFLAG_80000 = 0x80000,
NPCFLAG_100000 = 0x100000, NPCFLAG_200000 = 0x200000,
NPCFLAG_400000 = 0x400000, NPCFLAG_800000 = 0x800000,
@@ -66,7 +66,7 @@ protected:
protected:
void processInput(CTextInputMsg *msg, CViewItem *view);
public:
- int _field100;
+ int _speechCounter;
public:
CLASSDEF;
CTrueTalkNPC();
diff --git a/engines/titanic/pet_control/pet_control.cpp b/engines/titanic/pet_control/pet_control.cpp
index 4cdab24f6d..415d1e9821 100644
--- a/engines/titanic/pet_control/pet_control.cpp
+++ b/engines/titanic/pet_control/pet_control.cpp
@@ -27,6 +27,7 @@
#include "titanic/messages/pet_messages.h"
#include "titanic/game_manager.h"
#include "titanic/game_state.h"
+#include "titanic/titanic.h"
namespace Titanic {
@@ -37,6 +38,7 @@ BEGIN_MESSAGE_MAP(CPetControl, CGameObject)
ON_MESSAGE(MouseDragEndMsg)
ON_MESSAGE(MouseButtonUpMsg)
ON_MESSAGE(MouseDoubleClickMsg)
+ ON_MESSAGE(MouseWheelMsg)
ON_MESSAGE(KeyCharMsg)
ON_MESSAGE(VirtualKeyCharMsg)
ON_MESSAGE(TimerMsg)
@@ -154,7 +156,7 @@ void CPetControl::postLoad() {
if (!_remoteTargetName.empty() && root)
_remoteTarget = dynamic_cast<CGameObject *>(root->findByName(_remoteTargetName));
- setArea(_currentArea);
+ setArea(_currentArea, true);
loaded();
}
@@ -184,7 +186,9 @@ void CPetControl::resetRemoteTarget() {
}
void CPetControl::setActiveNPC(CTrueTalkNPC *npc) {
- if (_activeNPC == npc) {
+ if (_activeNPC != npc) {
+ _activeNPC = npc;
+
if (_activeNPC) {
_activeNPCName = npc->getName();
_conversations.displayNPCName(npc);
@@ -207,8 +211,8 @@ void CPetControl::resetActiveNPC() {
_activeNPCName = "";
}
-PetArea CPetControl::setArea(PetArea newArea) {
- if (newArea == _currentArea || !isAreaActive())
+PetArea CPetControl::setArea(PetArea newArea, bool forceChange) {
+ if ((!forceChange && newArea == _currentArea) || !isAreaActive())
return _currentArea;
// Signal the currently active area that it's being left
@@ -315,6 +319,13 @@ bool CPetControl::MouseDoubleClickMsg(CMouseDoubleClickMsg *msg) {
return _sections[_currentArea]->MouseDoubleClickMsg(msg);
}
+bool CPetControl::MouseWheelMsg(CMouseWheelMsg *msg) {
+ if (!containsPt(msg->_mousePos) || isInputLocked())
+ return false;
+
+ return _sections[_currentArea]->MouseWheelMsg(msg);
+}
+
bool CPetControl::KeyCharMsg(CKeyCharMsg *msg) {
if (isInputLocked())
return false;
@@ -377,7 +388,7 @@ bool CPetControl::checkDragEnd(CGameObject *item) const {
}
void CPetControl::displayMessage(StringId stringId, int param) const {
- CString msg = CString::format(_strings[stringId].c_str(), param);
+ CString msg = CString::format(g_vm->_strings[stringId].c_str(), param);
_sections[_currentArea]->displayMessage(msg);
}
@@ -388,7 +399,7 @@ void CPetControl::displayMessage(const CString &str, int param) const {
void CPetControl::addTranslation(StringId id1, StringId id2) {
setArea(PET_TRANSLATION);
- _translation.addTranslation(_strings[id1], _strings[id2]);
+ _translation.addTranslation(g_vm->_strings[id1], g_vm->_strings[id2]);
}
void CPetControl::clearTranslation() {
@@ -461,7 +472,7 @@ void CPetControl::moveToHiddenRoom(CTreeItem *item) {
CRoomItem *room = getHiddenRoom();
if (room) {
item->detach();
- room->addUnder(item);
+ item->addUnder(room);
}
}
@@ -594,6 +605,7 @@ void CPetControl::onSummonBot(const CString &name, int val) {
COnSummonBotMsg summonMsg(val);
summonMsg.execute(bot);
+ makeDirty();
}
}
@@ -609,10 +621,13 @@ bool CPetControl::dismissBot(const CString &name) {
CDismissBotMsg dismissMsg;
for (CTreeItem *treeItem = view->getFirstChild(); treeItem;
treeItem = treeItem->scan(view)) {
- if (!treeItem->getName().compareToIgnoreCase(name))
- dismissMsg.execute(treeItem);
- else
- result = true;
+ CGameObject *obj = dynamic_cast<CGameObject *>(treeItem);
+ if (obj) {
+ if (!obj->getName().compareToIgnoreCase(name))
+ result = true;
+ else
+ dismissMsg.execute(treeItem);
+ }
}
return result;
@@ -686,7 +701,7 @@ void CPetControl::resetDials0() {
int CPetControl::getMailDest(const CRoomFlags &roomFlags) const {
if (!roomFlags.isSuccUBusRoomFlags())
- return roomFlags.getPassengerClassNum();
+ return (int)roomFlags.getPassengerClassNum();
return roomFlags.getSuccUBusNum(roomFlags.getSuccUBusRoomName());
}
diff --git a/engines/titanic/pet_control/pet_control.h b/engines/titanic/pet_control/pet_control.h
index d42dff598c..34d1330b52 100644
--- a/engines/titanic/pet_control/pet_control.h
+++ b/engines/titanic/pet_control/pet_control.h
@@ -68,7 +68,6 @@ private:
CRoomItem *_hiddenRoom;
Rect _drawBounds;
PetEventInfo _timers[2];
- Strings _strings;
private:
/**
* Returns true if the control is in a valid state
@@ -116,6 +115,7 @@ protected:
bool MouseDragEndMsg(CMouseDragEndMsg *msg);
bool MouseButtonUpMsg(CMouseButtonUpMsg *msg);
bool MouseDoubleClickMsg(CMouseDoubleClickMsg *msg);
+ bool MouseWheelMsg(CMouseWheelMsg *msg);
bool KeyCharMsg(CKeyCharMsg *msg);
bool VirtualKeyCharMsg(CVirtualKeyCharMsg *msg);
bool TimerMsg(CTimerMsg *msg);
@@ -180,7 +180,7 @@ public:
/**
* Sets the currently viewed area within the PET
*/
- PetArea setArea(PetArea newSection);
+ PetArea setArea(PetArea newSection, bool forceChange = false);
/**
* Hides the text cursor in the current section, if applicable
@@ -421,14 +421,14 @@ public:
/**
* Gives the player a new assigned room in the specified passenger class
*/
- void reassignRoom(int passClassNum) {
+ void reassignRoom(PassengerClass passClassNum) {
_rooms.reassignRoom(passClassNum);
}
/**
* Change the current location passenger class
*/
- bool changeLocationClass(int newClassNum) {
+ bool changeLocationClass(PassengerClass newClassNum) {
return _rooms.changeLocationClass(newClassNum);
}
diff --git a/engines/titanic/pet_control/pet_conversations.cpp b/engines/titanic/pet_control/pet_conversations.cpp
index 58dcd57384..c2cddd9598 100644
--- a/engines/titanic/pet_control/pet_conversations.cpp
+++ b/engines/titanic/pet_control/pet_conversations.cpp
@@ -23,6 +23,7 @@
#include "titanic/pet_control/pet_conversations.h"
#include "titanic/pet_control/pet_control.h"
#include "titanic/game_manager.h"
+#include "titanic/titanic.h"
namespace Titanic {
@@ -116,11 +117,11 @@ void CPetConversations::draw(CScreenManager *screenManager) {
_textInput.draw(screenManager);
if (_logChanged) {
- int startIndex = _log.getLinesStart();
- if (startIndex >= 0) {
- int npcNum = _log.getNPCNum(1, startIndex);
+ int endIndex = _log.displayEndIndex();
+ if (endIndex >= 0) {
+ int npcNum = _log.getNPCNum(1, endIndex);
if (npcNum > 0 && npcNum < 10)
- _npcNum = npcNum;
+ _npcNum = npcNum - 1;
}
_logChanged = false;
@@ -164,7 +165,7 @@ bool CPetConversations::MouseButtonUpMsg(CMouseButtonUpMsg *msg) {
if (_doorBot.MouseButtonUpMsg(msg->_mousePos)) {
switch (canSummonBot("DoorBot")) {
case SUMMON_CANT:
- _log.addLine("Sadly, it is not possible to summon the DoorBot from this location.", getColor(1));
+ _log.addLine(g_vm->_strings[CANT_SUMMON_DOORBOT], getColor(1));
break;
case SUMMON_CAN:
summonBot("DoorBot");
@@ -181,7 +182,7 @@ bool CPetConversations::MouseButtonUpMsg(CMouseButtonUpMsg *msg) {
if (_bellBot.MouseButtonUpMsg(msg->_mousePos)) {
switch (canSummonBot("BellBot")) {
case SUMMON_CANT:
- _log.addLine("Sadly, it is not possible to summon the BellBot from this location.", getColor(1));
+ _log.addLine(g_vm->_strings[CANT_SUMMON_BELLBOT], getColor(1));
break;
case SUMMON_CAN:
summonBot("BellBot");
@@ -203,6 +204,15 @@ bool CPetConversations::MouseDoubleClickMsg(CMouseDoubleClickMsg *msg) {
|| _scrollUp.MouseDoubleClickMsg(msg->_mousePos);
}
+bool CPetConversations::MouseWheelMsg(CMouseWheelMsg *msg) {
+ if (msg->_wheelUp)
+ scrollUp();
+ else
+ scrollDown();
+
+ return true;
+}
+
bool CPetConversations::KeyCharMsg(CKeyCharMsg *msg) {
Common::KeyState keyState;
keyState.ascii = msg->_key;
@@ -268,40 +278,42 @@ void CPetConversations::timerExpired(int val) {
}
void CPetConversations::displayNPCName(CGameObject *npc) {
+ const Strings &strings = g_vm->_strings;
+
if (npc) {
displayMessage(CString());
- CString msg = "Talking to ";
+ CString msg = strings[TALKING_TO];
CString name = npc->getName();
int id = 1;
if (name.contains("Doorbot")) {
- msg += "the DoorBot";
- } else if (name.contains("DeskBot")) {
+ msg += strings[DOORBOT_NAME];
+ } else if (name.contains("Deskbot")) {
id = 2;
- msg += "the DeskBot";
+ msg += strings[DESKBOT_NAME];
} else if (name.contains("LiftBot")) {
id = 3;
- msg += "a LiftBot";
+ msg += strings[LIFTBOT_NAME];
} else if (name.contains("Parrot")) {
id = 4;
- msg += "the Parrot";
+ msg += strings[PARROT_NAME];
} else if (name.contains("BarBot")) {
id = 5;
- msg += "the BarBot";
+ msg += strings[BARBOT_NAME];
} else if (name.contains("ChatterBot")) {
id = 6;
- msg += "a ChatterBot";
+ msg += strings[CHATTERBOT_NAME];
} else if (name.contains("BellBot")) {
id = 7;
- msg += "the BellBot";
+ msg += strings[BELLBOT_NAME];
} else if (name.contains("Maitre")) {
id = 8;
- msg += "the Maitre d'Bot";
+ msg += strings[MAITRED_NAME];
} else if (name.contains("Succubus") || name.contains("Sub")) {
id = 9;
- msg += "a Succ-U-Bus";
+ msg += strings[SUCCUBUS_NAME];
} else {
- msg += "Unknown";
+ msg += strings[UNKNOWN_NAME];
}
_log.setNPC(1, id);
@@ -418,7 +430,7 @@ int CPetConversations::canSummonBot(const CString &name) {
void CPetConversations::summonBot(const CString &name) {
if (_petControl) {
- if (_petControl->getPassengerClass() >= 4) {
+ if (_petControl->getPassengerClass() >= UNCHECKED) {
_petControl->displayMessage(AT_LEAST_3RD_CLASS_FOR_HELP);
} else {
_petControl->summonBot(name, 0);
@@ -498,7 +510,7 @@ void CPetConversations::textLineEntered(const CString &textLine) {
if (!inputMsg._response.empty())
_log.addLine(inputMsg._response);
} else {
- _log.addLine("There is no one here to talk to", getColor(1));
+ _log.addLine(g_vm->_strings[NO_ONE_TO_TALK_TO], getColor(1));
}
// Clear input line and scroll log down to end to show response
diff --git a/engines/titanic/pet_control/pet_conversations.h b/engines/titanic/pet_control/pet_conversations.h
index efb7db4277..1837e5df2a 100644
--- a/engines/titanic/pet_control/pet_conversations.h
+++ b/engines/titanic/pet_control/pet_conversations.h
@@ -164,6 +164,7 @@ public:
virtual bool MouseButtonDownMsg(CMouseButtonDownMsg *msg);
virtual bool MouseButtonUpMsg(CMouseButtonUpMsg *msg);
virtual bool MouseDoubleClickMsg(CMouseDoubleClickMsg *msg);
+ virtual bool MouseWheelMsg(CMouseWheelMsg *msg);
virtual bool KeyCharMsg(CKeyCharMsg *msg);
virtual bool VirtualKeyCharMsg(CVirtualKeyCharMsg *msg);
diff --git a/engines/titanic/pet_control/pet_drag_chev.cpp b/engines/titanic/pet_control/pet_drag_chev.cpp
index 7816570a23..4fe64283ff 100644
--- a/engines/titanic/pet_control/pet_drag_chev.cpp
+++ b/engines/titanic/pet_control/pet_drag_chev.cpp
@@ -54,20 +54,16 @@ bool CPetDragChev::MouseDragMoveMsg(CMouseDragMoveMsg *msg) {
}
bool CPetDragChev::MouseDragEndMsg(CMouseDragEndMsg *msg) {
- if (msg->_dropTarget) {
- CSuccUBus *succubus = dynamic_cast<CSuccUBus *>(msg->_dropTarget);
+ CSuccUBus *succubus = dynamic_cast<CSuccUBus *>(msg->_dropTarget);
- if (succubus) {
- CSetChevRoomBits chevMsg(_id);
- chevMsg.execute(succubus);
- } else {
- CPetControl *petControl = getPetControl();
- if (petControl && petControl->contains(msg->_mousePos)
- && msg->_mousePos.x < 528) {
- if (petControl->checkDragEnd(this))
- petMoveToHiddenRoom();
- }
- }
+ if (succubus) {
+ CSetChevRoomBits chevMsg(_id);
+ chevMsg.execute(succubus);
+ } else {
+ CPetControl *petControl = getPetControl();
+ if (!petControl || !petControl->contains(msg->_mousePos)
+ || msg->_mousePos.x >= 528 || !petControl->checkDragEnd(this))
+ petMoveToHiddenRoom();
}
return true;
diff --git a/engines/titanic/pet_control/pet_gfx_element.cpp b/engines/titanic/pet_control/pet_gfx_element.cpp
index e43c847bb1..3fdfd02f3a 100644
--- a/engines/titanic/pet_control/pet_gfx_element.cpp
+++ b/engines/titanic/pet_control/pet_gfx_element.cpp
@@ -49,11 +49,11 @@ void CPetGfxElement::reset(const CString &name, CPetControl *petControl, PetElem
return;
CString numString(3);
- int classNum = petControl->getPassengerClass();
+ PassengerClass classNum = petControl->getPassengerClass();
- if (classNum >= 1 && classNum <= 3) {
+ if (classNum >= FIRST_CLASS && classNum <= THIRD_CLASS) {
numString = CString(classNum);
- } else if (classNum == 4) {
+ } else if (classNum == UNCHECKED) {
int stateC = petControl->getPriorClass();
if (stateC == 1)
numString = CString(stateC);
diff --git a/engines/titanic/pet_control/pet_glyphs.cpp b/engines/titanic/pet_control/pet_glyphs.cpp
index bd05342095..5cc428b104 100644
--- a/engines/titanic/pet_control/pet_glyphs.cpp
+++ b/engines/titanic/pet_control/pet_glyphs.cpp
@@ -101,9 +101,9 @@ void CPetGlyphs::setup(int numVisible, CPetSection *owner) {
int buttonsLeft = numVisible * 70 + 21;
_scrollLeft.setBounds(Rect(0, 0, 31, 15));
- _scrollLeft.translate(buttonsLeft, 373);
+ _scrollLeft.translate(buttonsLeft + 7, 373);
_scrollRight.setBounds(Rect(0, 0, 31, 15));
- _scrollRight.translate(buttonsLeft, 413);
+ _scrollRight.translate(buttonsLeft + 7, 413);
}
void CPetGlyphs::reset() {
@@ -155,7 +155,7 @@ void CPetGlyphs::draw(CScreenManager *screenManager) {
int itemIndex = getItemIndex(index);
if (itemIndex >= 0 && itemIndex < listSize) {
- Point pt = getPosition(itemIndex);
+ Point pt = getPosition(index);
CPetGlyph *glyph = getGlyph(itemIndex);
if (glyph)
diff --git a/engines/titanic/pet_control/pet_inventory.cpp b/engines/titanic/pet_control/pet_inventory.cpp
index be01146398..c1eb0754a2 100644
--- a/engines/titanic/pet_control/pet_inventory.cpp
+++ b/engines/titanic/pet_control/pet_inventory.cpp
@@ -242,7 +242,7 @@ void CPetInventory::playMovie(CGameObject *movie, int flag) {
if (_movie) {
if (flag)
- _movie->playMovie(0, 14, 1);
+ _movie->playMovie(0, 14, MOVIE_REPEAT);
else
_movie->playMovie(0);
}
diff --git a/engines/titanic/pet_control/pet_inventory_glyphs.cpp b/engines/titanic/pet_control/pet_inventory_glyphs.cpp
index 03293eb453..e6087b5c02 100644
--- a/engines/titanic/pet_control/pet_inventory_glyphs.cpp
+++ b/engines/titanic/pet_control/pet_inventory_glyphs.cpp
@@ -295,7 +295,7 @@ void CPetInventoryGlyph::startBackgroundMovie() {
if (_owner) {
CPetInventory *section = dynamic_cast<CPetInventory *>(_owner->getOwner());
if (section)
- section->playMovie(_background, 1);
+ section->playMovie(_background, MOVIE_REPEAT);
}
}
@@ -303,7 +303,7 @@ void CPetInventoryGlyph::startForegroundMovie() {
if (_owner) {
CPetInventory *section = dynamic_cast<CPetInventory *>(_owner->getOwner());
if (section)
- section->playMovie(_image, 1);
+ section->playMovie(_image, MOVIE_REPEAT);
}
}
@@ -311,7 +311,7 @@ void CPetInventoryGlyph::stopMovie() {
if (_owner) {
CPetInventory *section = dynamic_cast<CPetInventory *>(_owner->getOwner());
if (section)
- section->playMovie(nullptr, 1);
+ section->playMovie(nullptr, MOVIE_REPEAT);
}
}
diff --git a/engines/titanic/pet_control/pet_load_save.cpp b/engines/titanic/pet_control/pet_load_save.cpp
index 136953cab7..aa438c06d3 100644
--- a/engines/titanic/pet_control/pet_load_save.cpp
+++ b/engines/titanic/pet_control/pet_load_save.cpp
@@ -159,7 +159,7 @@ void CPetLoadSave::highlightChange() {
uint col = section ? section->getColor(3) : 0;
for (int idx = 0; idx < SAVEGAME_SLOTS_COUNT; ++idx)
- _slotNames[idx].setColor(col);
+ _slotNames[idx].setLineColor(0, col);
if (_savegameSlotNum != -1) {
col = section ? section->getColor(4) : 0;
diff --git a/engines/titanic/pet_control/pet_real_life.h b/engines/titanic/pet_control/pet_real_life.h
index b359d285c8..7c7101a84b 100644
--- a/engines/titanic/pet_control/pet_real_life.h
+++ b/engines/titanic/pet_control/pet_real_life.h
@@ -87,11 +87,6 @@ public:
virtual CGameObject *dragEnd(const Point &pt) const { return nullptr; }
/**
- * Display a message
- */
- virtual void displayMessage(const CString &msg) {}
-
- /**
* Returns true if the object is in a valid state
*/
virtual bool isValid(CPetControl *petControl);
diff --git a/engines/titanic/pet_control/pet_remote.cpp b/engines/titanic/pet_control/pet_remote.cpp
index 7e98308114..46af55c4d3 100644
--- a/engines/titanic/pet_control/pet_remote.cpp
+++ b/engines/titanic/pet_control/pet_remote.cpp
@@ -118,10 +118,10 @@ bool CPetRemote::reset() {
_right.reset("PetRight", _petControl, MODE_UNSELECTED);
_top.reset("PetTopUp", _petControl, MODE_SELECTED);
_top.reset("PetTop", _petControl, MODE_UNSELECTED);
- _bottom.reset("PetBottomUp", _petControl, MODE_SELECTED);
- _bottom.reset("PetBottom", _petControl, MODE_UNSELECTED);
- _action.reset("PetActionUp", _petControl, MODE_SELECTED);
- _action.reset("PetAction", _petControl, MODE_UNSELECTED);
+ _bottom.reset("PetBottomUp", _petControl, MODE_UNSELECTED);
+ _bottom.reset("PetBottom", _petControl, MODE_SELECTED);
+ _action.reset("PetActionUp", _petControl, MODE_UNSELECTED);
+ _action.reset("PetAction", _petControl, MODE_SELECTED);
_send.reset("PetActSend0", _petControl, MODE_UNSELECTED);
_send.reset("PetActSend1", _petControl, MODE_SELECTED);
@@ -314,8 +314,8 @@ bool CPetRemote::getRemoteData(int roomIndex, Common::Array<uint> &indexes) {
const byte *p = &REMOTE_DATA[0];
for (int idx = 0; idx < TOTAL_ROOMS; ++idx) {
if (*p == roomIndex) {
- for (int ctr = 0; ctr < *p; ++ctr)
- indexes.push_back(p[ctr + 1]);
+ for (int ctr = 0; ctr < p[1]; ++ctr)
+ indexes.push_back(p[ctr + 2]);
return true;
}
diff --git a/engines/titanic/pet_control/pet_remote_glyphs.cpp b/engines/titanic/pet_control/pet_remote_glyphs.cpp
index aa756bc941..2e69ad6bce 100644
--- a/engines/titanic/pet_control/pet_remote_glyphs.cpp
+++ b/engines/titanic/pet_control/pet_remote_glyphs.cpp
@@ -24,6 +24,7 @@
#include "titanic/pet_control/pet_remote.h"
#include "titanic/pet_control/pet_control.h"
#include "titanic/messages/pet_messages.h"
+#include "titanic/support/strings.h"
#include "titanic/titanic.h"
namespace Titanic {
@@ -58,22 +59,22 @@ bool CBasicRemoteGlyph::setup(CPetControl *petControl, CPetGlyphs *owner) {
CPetRemoteGlyph::setup(petControl, owner);
setDefaults(_gfxName, petControl);
if (owner)
- _gfxElement = getElement(18);
+ _callButton = getElement(18);
return true;
}
void CBasicRemoteGlyph::draw2(CScreenManager *screenManager) {
- if (_gfxElement)
- _gfxElement->draw(screenManager);
+ if (_callButton)
+ _callButton->draw(screenManager);
}
bool CBasicRemoteGlyph::MouseButtonDownMsg(const Point &pt) {
- return _gfxElement && _gfxElement->MouseButtonDownMsg(pt);
+ return _callButton && _callButton->MouseButtonDownMsg(pt);
}
bool CBasicRemoteGlyph::MouseButtonUpMsg(const Point &pt) {
- if (_gfxElement && _gfxElement->MouseButtonUpMsg(pt)) {
- getOwner()->generateMessage(RMSG_ACTIVATE, "Lift");
+ if (_callButton && _callButton->MouseButtonUpMsg(pt)) {
+ getOwner()->generateMessage(RMSG_ACTIVATE, _msgString);
return true;
}
@@ -124,22 +125,22 @@ bool CRemoteGotoGlyph::setup(CPetControl *petControl, CPetGlyphs *owner) {
setDefaults(_gfxName, petControl);
if (owner)
- _gfxElement = getElement(7);
+ _goButton = getElement(7);
return true;
}
void CRemoteGotoGlyph::draw2(CScreenManager *screenManager) {
- if (_gfxElement)
- _gfxElement->draw(screenManager);
+ if (_goButton)
+ _goButton->draw(screenManager);
}
bool CRemoteGotoGlyph::MouseButtonDownMsg(const Point &pt) {
- return _gfxElement && _gfxElement->MouseButtonDownMsg(pt);
+ return _goButton && _goButton->MouseButtonDownMsg(pt);
}
bool CRemoteGotoGlyph::MouseButtonUpMsg(const Point &pt) {
- if (!_gfxElement || !_gfxElement->MouseButtonUpMsg(pt))
+ if (!_goButton || !_goButton->MouseButtonUpMsg(pt))
return false;
CPetControl *petControl = getPetControl();
@@ -216,7 +217,7 @@ bool CTelevisionControlGlyph::MouseButtonUpMsg(const Point &pt) {
}
void CTelevisionControlGlyph::getTooltip(CPetText *text) {
- text->setText("Television control");
+ text->setText(TELEVISION_CONTROL);
}
/*------------------------------------------------------------------------*/
@@ -280,7 +281,7 @@ bool CEntertainmentDeviceGlyph::MouseButtonUpMsg(const Point &pt) {
}
void CEntertainmentDeviceGlyph::getTooltip(CPetText *text) {
- text->setText("Operate visual entertainment device");
+ text->setText(OPERATE_ENTERTAINMENT);
}
/*------------------------------------------------------------------------*/
@@ -334,7 +335,7 @@ bool COperateLightsGlyph::MouseButtonUpMsg(const Point &pt) {
}
void COperateLightsGlyph::getTooltip(CPetText *text) {
- text->setText("Operate the lights");
+ text->setText(OPERATE_LIGHTS);
}
/*------------------------------------------------------------------------*/
@@ -346,7 +347,7 @@ bool CDeployFloralGlyph::setup(CPetControl *petControl, CPetGlyphs *owner) {
}
void CDeployFloralGlyph::getTooltip(CPetText *text) {
- text->setText("Deploy floral enhancement");
+ text->setText(DEPLOY_FLORAL_ENHANCEMENT);
}
@@ -359,7 +360,7 @@ bool CDeployFullyRelaxationGlyph::setup(CPetControl *petControl, CPetGlyphs *own
}
void CDeployFullyRelaxationGlyph::getTooltip(CPetText *text) {
- text->setText("Deploy fully recumbent relaxation device");
+ text->setText(DEPLOY_FULLY_RELAXATION);
}
/*------------------------------------------------------------------------*/
@@ -371,7 +372,7 @@ bool CDeployComfortGlyph::setup(CPetControl *petControl, CPetGlyphs *owner) {
}
void CDeployComfortGlyph::getTooltip(CPetText *text) {
- text->setText("Deploy comfort workstation");
+ text->setText(DEPLOY_COMFORT_WORKSTATION);
}
/*------------------------------------------------------------------------*/
@@ -383,7 +384,7 @@ bool CDeployMinorStorageGlyph::setup(CPetControl *petControl, CPetGlyphs *owner)
}
void CDeployMinorStorageGlyph::getTooltip(CPetText *text) {
- text->setText("Deploy minor horizontally mobile storage compartment");
+ text->setText(DEPLOY_MINOR_STORAGE);
}
/*------------------------------------------------------------------------*/
@@ -395,7 +396,7 @@ bool CDeployMajorRelaxationGlyph::setup(CPetControl *petControl, CPetGlyphs *own
}
void CDeployMajorRelaxationGlyph::getTooltip(CPetText *text) {
- text->setText("Deploy major semi-recumbent relaxation device");
+ text->setText(DEPLOY_MAJOR_RELAXATION);
}
/*------------------------------------------------------------------------*/
@@ -407,7 +408,7 @@ bool CInflateRelaxationGlyph::setup(CPetControl *petControl, CPetGlyphs *owner)
}
void CInflateRelaxationGlyph::getTooltip(CPetText *text) {
- text->setText("Inflate fully recumbent relaxation device ");
+ text->setText(INFLATE_RELAXATION_DEVICE);
}
/*------------------------------------------------------------------------*/
@@ -419,7 +420,7 @@ bool CDeployMaintenanceGlyph::setup(CPetControl *petControl, CPetGlyphs *owner)
}
void CDeployMaintenanceGlyph::getTooltip(CPetText *text) {
- text->setText("Deploy personal maintenance hub");
+ text->setText(DEPLOY_MAINTENANCE_HUB);
}
/*------------------------------------------------------------------------*/
@@ -431,7 +432,7 @@ bool CDeployWorkSurfaceGlyph::setup(CPetControl *petControl, CPetGlyphs *owner)
}
void CDeployWorkSurfaceGlyph::getTooltip(CPetText *text) {
- text->setText("Deploy executive horizontal worksurface");
+ text->setText(DEPLOY_EXECUTIVE_SURFACE);
}
/*------------------------------------------------------------------------*/
@@ -443,7 +444,7 @@ bool CDeployMinorRelaxationGlyph::setup(CPetControl *petControl, CPetGlyphs *own
}
void CDeployMinorRelaxationGlyph::getTooltip(CPetText *text) {
- text->setText("Deploy minor semi-recumbent relaxation device");
+ text->setText(DEPLOY_MINOR_RELAXATION);
}
/*------------------------------------------------------------------------*/
@@ -455,7 +456,7 @@ bool CDeploySinkGlyph::setup(CPetControl *petControl, CPetGlyphs *owner) {
}
void CDeploySinkGlyph::getTooltip(CPetText *text) {
- text->setText("Deploy aqueous cleansing receptacle");
+ text->setText(DEPLOY_SINK);
}
/*------------------------------------------------------------------------*/
@@ -467,7 +468,7 @@ bool CDeployMajorStorageGlyph::setup(CPetControl *petControl, CPetGlyphs *owner)
}
void CDeployMajorStorageGlyph::getTooltip(CPetText *text) {
- text->setText("Deploy major horizontally mobile storage compartment");
+ text->setText(DEPLOY_MAJOR_STORAGE);
}
/*------------------------------------------------------------------------*/
@@ -515,7 +516,7 @@ bool CSuccubusDeliveryGlyph::MouseButtonUpMsg(const Point &pt) {
}
void CSuccubusDeliveryGlyph::getTooltip(CPetText *text) {
- text->setText("Succ-U-Bus delivery system control");
+ text->setText(SUCCUBUS_DELIVERY_SYSTEM);
}
/*------------------------------------------------------------------------*/
@@ -554,9 +555,67 @@ bool CNavigationControllerGlyph::MouseButtonUpMsg(const Point &pt) {
}
void CNavigationControllerGlyph::getTooltip(CPetText *text) {
- text->setText("Navigation controller");
+ text->setText(NAVIGATION_CONTROLLER);
+}
+
+/*------------------------------------------------------------------------*/
+
+CSummonElevatorGlyph::CSummonElevatorGlyph() : CBasicRemoteGlyph(
+ "3PetLift", g_vm->_strings[SUMMON_ELEVATOR], "Lift") {
+}
+
+/*------------------------------------------------------------------------*/
+
+CSummonPelleratorGlyph::CSummonPelleratorGlyph() : CBasicRemoteGlyph(
+ "3PetPellerator", g_vm->_strings[SUMMON_PELLERATOR], "Pellerator") {
+}
+
+/*------------------------------------------------------------------------*/
+
+CGotoBottomOfWellGlyph::CGotoBottomOfWellGlyph() : CRemoteGotoGlyph("3PetBotOfWell",
+ g_vm->_strings[GO_TO_BOTTOM_OF_WELL], 10) {
+}
+
+/*------------------------------------------------------------------------*/
+
+CGotoTopOfWellGlyph::CGotoTopOfWellGlyph() : CRemoteGotoGlyph("3PetTopOfWell",
+ g_vm->_strings[GO_TO_TOP_OF_WELL], 32) {
+}
+
+/*------------------------------------------------------------------------*/
+
+CGotoStateroomGlyph::CGotoStateroomGlyph() : CRemoteGotoGlyph("3PetRoom",
+ g_vm->_strings[GO_TO_STATEROOM], 33) {
+}
+
+/*------------------------------------------------------------------------*/
+
+CGotoBarGlyph::CGotoBarGlyph() : CRemoteGotoGlyph("3PetBar",
+ g_vm->_strings[GO_TO_BAR], 7) {
+}
+
+/*------------------------------------------------------------------------*/
+
+CGotoPromenadeDeckGlyph::CGotoPromenadeDeckGlyph() : CRemoteGotoGlyph("3PetPromDeck",
+ g_vm->_strings[GO_TO_PROMENADE_DECK], 23) {
}
/*------------------------------------------------------------------------*/
+CGotoArboretumGlyph::CGotoArboretumGlyph() : CRemoteGotoGlyph("3PetArboretum",
+ g_vm->_strings[GO_TO_ARBORETUM], 5) {
+}
+
+/*------------------------------------------------------------------------*/
+
+CGotoMusicRoomGlyph::CGotoMusicRoomGlyph() : CRemoteGotoGlyph("3PetMusicRoom",
+ g_vm->_strings[GO_TO_MUSIC_ROOM], 20) {
+}
+
+/*------------------------------------------------------------------------*/
+
+CGotoRestaurantGlyph::CGotoRestaurantGlyph() : CRemoteGotoGlyph("3Pet1stClassRest",
+ g_vm->_strings[GO_TO_1ST_CLASS_RESTAURANT], 1) {
+}
+
} // End of namespace Titanic
diff --git a/engines/titanic/pet_control/pet_remote_glyphs.h b/engines/titanic/pet_control/pet_remote_glyphs.h
index 6114c81a9f..c661a1e2af 100644
--- a/engines/titanic/pet_control/pet_remote_glyphs.h
+++ b/engines/titanic/pet_control/pet_remote_glyphs.h
@@ -65,9 +65,9 @@ public:
class CPetRemoteGlyph : public CPetGlyph {
protected:
- CPetGfxElement *_gfxElement;
+ CPetGfxElement *_callButton;
protected:
- CPetRemoteGlyph() : CPetGlyph(), _gfxElement(nullptr) {}
+ CPetRemoteGlyph() : CPetGlyph(), _callButton(nullptr) {}
/**
* Set defaults for the glyph
@@ -150,13 +150,13 @@ public:
class CRemoteGotoGlyph : public CPetRemoteGlyph {
protected:
int _roomIndex;
- CPetGfxElement *_gfxElement;
+ CPetGfxElement *_goButton;
CString _gfxName, _tooltip;
public:
- CRemoteGotoGlyph() : CPetRemoteGlyph(), _gfxElement(nullptr), _roomIndex(21) {}
- CRemoteGotoGlyph(const CString &gfxName, const CString &tooltip) :
- CPetRemoteGlyph(), _gfxElement(nullptr), _roomIndex(21),
- _gfxName(gfxName), _tooltip(tooltip) {}
+ CRemoteGotoGlyph() : CPetRemoteGlyph(), _goButton(nullptr), _roomIndex(21) {}
+ CRemoteGotoGlyph(const CString &gfxName, const CString &tooltip, int roomIndex) :
+ CPetRemoteGlyph(), _gfxName(gfxName), _tooltip(tooltip), _roomIndex(roomIndex),
+ _goButton(nullptr) {}
/**
* Setup the glyph
@@ -186,14 +186,12 @@ public:
class CSummonElevatorGlyph : public CBasicRemoteGlyph {
public:
- CSummonElevatorGlyph() : CBasicRemoteGlyph(
- "3PetLift", "Summon Elevator", "Lift") {}
+ CSummonElevatorGlyph();
};
class CSummonPelleratorGlyph : public CBasicRemoteGlyph {
public:
- CSummonPelleratorGlyph() : CBasicRemoteGlyph(
- "3PetPellerator", "Summon Pellerator", "Pellerator") {}
+ CSummonPelleratorGlyph();
};
class CTelevisionControlGlyph : public CPetRemoteGlyph {
@@ -664,50 +662,42 @@ public:
class CGotoBottomOfWellGlyph : public CRemoteGotoGlyph {
public:
- CGotoBottomOfWellGlyph() : CRemoteGotoGlyph("3PetBotOfWell",
- "Go to the Bottom of the Well") {}
+ CGotoBottomOfWellGlyph();
};
class CGotoTopOfWellGlyph : public CRemoteGotoGlyph {
public:
- CGotoTopOfWellGlyph() : CRemoteGotoGlyph("3PetTopOfWell",
- "Go to the Top of the Well") {}
+ CGotoTopOfWellGlyph();
};
class CGotoStateroomGlyph : public CRemoteGotoGlyph {
public:
- CGotoStateroomGlyph() : CRemoteGotoGlyph("3PetRoom",
- "Go to your stateroom") {}
+ CGotoStateroomGlyph();
};
class CGotoBarGlyph : public CRemoteGotoGlyph {
public:
- CGotoBarGlyph() : CRemoteGotoGlyph("3PetBar",
- "Go to the Bar") {}
+ CGotoBarGlyph();
};
class CGotoPromenadeDeckGlyph : public CRemoteGotoGlyph {
public:
- CGotoPromenadeDeckGlyph() : CRemoteGotoGlyph("3PetPromDeck",
- "Go to the Promenade Deck") {}
+ CGotoPromenadeDeckGlyph();
};
class CGotoArboretumGlyph : public CRemoteGotoGlyph {
public:
- CGotoArboretumGlyph() : CRemoteGotoGlyph("3PetArboretum",
- "Go to the Arboretum") {}
+ CGotoArboretumGlyph();
};
class CGotoMusicRoomGlyph : public CRemoteGotoGlyph {
public:
- CGotoMusicRoomGlyph() : CRemoteGotoGlyph("3PetMusicRoom",
- "Go to the Music Room") {}
+ CGotoMusicRoomGlyph();
};
class CGotoRestaurantGlyph : public CRemoteGotoGlyph {
public:
- CGotoRestaurantGlyph() : CRemoteGotoGlyph("3Pet1stClassRest",
- "Go to the First Class Restaurant") {}
+ CGotoRestaurantGlyph();
};
} // End of namespace Titanic
diff --git a/engines/titanic/pet_control/pet_rooms.cpp b/engines/titanic/pet_control/pet_rooms.cpp
index fb92f2692d..d32667e5f7 100644
--- a/engines/titanic/pet_control/pet_rooms.cpp
+++ b/engines/titanic/pet_control/pet_rooms.cpp
@@ -56,6 +56,7 @@ bool CPetRooms::reset() {
void CPetRooms::draw(CScreenManager *screenManager) {
_petControl->drawSquares(screenManager, 6);
_plinth.draw(screenManager);
+ _glyphs.draw(screenManager);
_glyphItem.drawAt(screenManager, getGlyphPos(), false);
_text.draw(screenManager);
}
@@ -67,7 +68,7 @@ bool CPetRooms::MouseButtonDownMsg(CMouseButtonDownMsg *msg) {
if (!_glyphItem.contains(getGlyphPos(), msg->_mousePos))
return false;
- _glyphItem.MouseButtonDownMsg(msg->_mousePos);
+ _glyphItem.selectGlyph(getGlyphPos(), msg->_mousePos);
return true;
}
@@ -165,7 +166,8 @@ void CPetRooms::enter(PetArea oldArea) {
}
void CPetRooms::enterRoom(CRoomItem *room) {
-
+ if (room)
+ resetHighlight();
}
CPetText *CPetRooms::getText() {
@@ -221,7 +223,7 @@ bool CPetRooms::setupControl(CPetControl *petControl) {
_glyphs.setup(6, this);
_glyphs.setFlags(GFLAG_16);
_glyphItem.setup(petControl, &_glyphs);
- _glyphItem.set38(1);
+ _glyphItem.setFlag(1);
return true;
}
@@ -240,17 +242,17 @@ uint CPetRooms::getRoomFlags() const {
if (flags)
return flags;
- int classNum = roomFlags.whatPassengerClass(_floorNum);
+ PassengerClass classNum = roomFlags.whatPassengerClass(_floorNum);
roomFlags.setPassengerClassBits(classNum);
roomFlags.setFloorNum(_floorNum);
switch (classNum) {
- case 1:
+ case FIRST_CLASS:
roomFlags.setElevatorNum(_elevatorNum);
roomFlags.setRoomBits(_roomNum);
break;
- case 2:
+ case SECOND_CLASS:
if (_roomNum > 0) {
if (_roomNum >= 3) {
roomFlags.setElevatorNum(_elevatorNum == 1 || _elevatorNum == 2 ? 1 : 3);
@@ -264,7 +266,7 @@ uint CPetRooms::getRoomFlags() const {
}
break;
- case 3:
+ case THIRD_CLASS:
roomFlags.setElevatorNum(_elevatorNum);
roomFlags.setRoomBits(_roomNum + _field1CC * 6 - 6);
break;
@@ -276,7 +278,7 @@ uint CPetRooms::getRoomFlags() const {
return roomFlags.get();
}
-void CPetRooms::reassignRoom(int passClassNum) {
+void CPetRooms::reassignRoom(PassengerClass passClassNum) {
CPetRoomsGlyph *glyph = _glyphs.findAssignedRoom();
if (glyph)
// Flag the old assigned room as no longer assigned
@@ -329,12 +331,12 @@ CPetRoomsGlyph *CPetRooms::addGlyph(uint roomFlags, bool highlight_) {
}
}
-bool CPetRooms::changeLocationClass(int newClassNum) {
+bool CPetRooms::changeLocationClass(PassengerClass newClassNum) {
CPetRoomsGlyph *glyph = _glyphs.findAssignedRoom();
if (!glyph)
return 0;
- glyph->changeLocation(newClassNum);
+ glyph->changeClass(newClassNum);
return true;
}
diff --git a/engines/titanic/pet_control/pet_rooms.h b/engines/titanic/pet_control/pet_rooms.h
index 28d6553a33..efc7e3c969 100644
--- a/engines/titanic/pet_control/pet_rooms.h
+++ b/engines/titanic/pet_control/pet_rooms.h
@@ -26,6 +26,7 @@
#include "titanic/pet_control/pet_section.h"
#include "titanic/pet_control/pet_text.h"
#include "titanic/pet_control/pet_rooms_glyphs.h"
+#include "titanic/game_location.h"
namespace Titanic {
@@ -155,12 +156,12 @@ public:
/**
* Gives the player a new assigned room in the specified passenger class
*/
- void reassignRoom(int passClassNum);
+ void reassignRoom(PassengerClass passClassNum);
/**
* Change the current location passenger class
*/
- bool changeLocationClass(int newClassNum);
+ bool changeLocationClass(PassengerClass newClassNum);
/**
* Returns true if a room glyph exists with the given flags
diff --git a/engines/titanic/pet_control/pet_rooms_glyphs.cpp b/engines/titanic/pet_control/pet_rooms_glyphs.cpp
index e89e8072dc..f38ed28a80 100644
--- a/engines/titanic/pet_control/pet_rooms_glyphs.cpp
+++ b/engines/titanic/pet_control/pet_rooms_glyphs.cpp
@@ -30,15 +30,15 @@
namespace Titanic {
CPetRoomsGlyph::CPetRoomsGlyph() : CPetGlyph(),
- _roomFlags(0), _field38(0), _mode(RGM_UNASSIGNED),
- _object0(nullptr), _object1(nullptr), _object2(nullptr), _object3(nullptr),
- _object4(nullptr), _object5(nullptr), _object6(nullptr), _object7(nullptr) {
+ _roomFlags(0), _mailFlag(0), _mode(RGM_UNASSIGNED),
+ _chevLeftOnDim(nullptr), _chevLeftOffDim(nullptr), _chevLeftOnLit(nullptr), _chevLeftOffLit(nullptr),
+ _chevRightOnDim(nullptr), _chevRightOffDim(nullptr), _chevRightOnLit(nullptr), _chevRightOffLit(nullptr) {
}
CPetRoomsGlyph::CPetRoomsGlyph(uint flags) : CPetGlyph(),
- _roomFlags(flags), _field38(0), _mode(RGM_UNASSIGNED),
- _object0(nullptr), _object1(nullptr), _object2(nullptr), _object3(nullptr),
- _object4(nullptr), _object5(nullptr), _object6(nullptr), _object7(nullptr) {
+ _roomFlags(flags), _mailFlag(0), _mode(RGM_UNASSIGNED),
+ _chevLeftOnDim(nullptr), _chevLeftOffDim(nullptr), _chevLeftOnLit(nullptr), _chevLeftOffLit(nullptr),
+ _chevRightOnDim(nullptr), _chevRightOffDim(nullptr), _chevRightOnLit(nullptr), _chevRightOffLit(nullptr) {
}
bool CPetRoomsGlyph::setup(CPetControl *petControl, CPetGlyphs *owner) {
@@ -46,14 +46,14 @@ bool CPetRoomsGlyph::setup(CPetControl *petControl, CPetGlyphs *owner) {
return false;
CPetSection *section = owner->getOwner();
- _object0 = section->getBackground(9);
- _object1 = section->getBackground(12);
- _object4 = section->getBackground(13);
- _object5 = section->getBackground(10);
- _object2 = section->getBackground(11);
- _object3 = section->getBackground(14);
- _object6 = section->getBackground(15);
- _object7 = _object6;
+ _chevLeftOnDim = section->getBackground(8);
+ _chevLeftOffDim = section->getBackground(9);
+ _chevRightOnDim = section->getBackground(12);
+ _chevRightOffDim = section->getBackground(13);
+ _chevLeftOnLit = section->getBackground(10);
+ _chevLeftOffLit = section->getBackground(11);
+ _chevRightOnLit = section->getBackground(14);
+ _chevRightOffLit = section->getBackground(15);
return true;
}
@@ -69,19 +69,19 @@ void CPetRoomsGlyph::drawAt(CScreenManager *screenManager, const Point &pt, bool
uint roomBits = roomFlags.getRoomBits();
// Save a copy of object pointers that may be modified
- CGameObject *obj0 = _object0;
- CGameObject *obj1 = _object1;
- CGameObject *obj4 = _object4;
- CGameObject *obj5 = _object5;
-
- if (_field38 == 1 || isHighlighted_) {
- _object0 = _object2;
- _object1 = _object3;
- _object4 = _object6;
- _object5 = _object7;
+ CGameObject *leftOnDim = _chevLeftOnDim;
+ CGameObject *leftOffDim = _chevLeftOffDim;
+ CGameObject *rightOnDim = _chevRightOnDim;
+ CGameObject *rightOffDim = _chevRightOffDim;
+
+ if (_mailFlag || isHighlighted_) {
+ _chevLeftOnDim = _chevLeftOnLit;
+ _chevLeftOffDim = _chevLeftOffLit;
+ _chevRightOnDim = _chevRightOnLit;
+ _chevRightOffDim = _chevRightOffLit;
}
- // Draw the images
+ // Draw the chevron fragments for each line
Point destPt = pt;
drawObjects(classBits + elevBits * 4, destPt, screenManager);
destPt.y += 10;
@@ -94,21 +94,21 @@ void CPetRoomsGlyph::drawAt(CScreenManager *screenManager, const Point &pt, bool
drawObjects(((roomBits & 7) << 1) + (roomFlags.getBit0() ? 1 : 0),
destPt, screenManager);
- // Restore original object pointers
- _object0 = obj0;
- _object1 = obj1;
- _object4 = obj4;
- _object5 = obj5;
+ // Restore original image pointers
+ _chevLeftOnDim = leftOnDim;
+ _chevLeftOffDim = leftOffDim;
+ _chevRightOnDim = rightOnDim;
+ _chevRightOffDim = rightOffDim;
}
void CPetRoomsGlyph::selectGlyph(const Point &topLeft, const Point &pt) {
- if (isAssigned()) {
- bool isShiftPressed = g_vm->_window->getSpecialButtons() & MK_SHIFT;
+ if (!isAssigned()) {
+ bool isShiftPressed = g_vm->_events->getSpecialButtons() & MK_SHIFT;
if (isShiftPressed) {
int selection = getSelection(topLeft, pt);
if (selection >= 0)
- _roomFlags |= 1 << selection;
+ _roomFlags ^= 1 << selection;
}
updateTooltip();
@@ -116,7 +116,7 @@ void CPetRoomsGlyph::selectGlyph(const Point &topLeft, const Point &pt) {
}
bool CPetRoomsGlyph::dragGlyph(const Point &topLeft, CMouseDragStartMsg *msg) {
- bool isShiftPressed = g_vm->_window->getSpecialButtons() & MK_SHIFT;
+ bool isShiftPressed = g_vm->_events->getSpecialButtons() & MK_SHIFT;
CPetControl *petControl = getPetControl();
if (!isShiftPressed && petControl) {
@@ -124,7 +124,7 @@ bool CPetRoomsGlyph::dragGlyph(const Point &topLeft, CMouseDragStartMsg *msg) {
if (chevron) {
chevron->_id = _roomFlags;
- chevron->_isMail = _field38;
+ chevron->_isMail = _mailFlag != 0;
petControl->removeFromInventory(chevron, false, false);
chevron->loadSurface();
@@ -133,6 +133,8 @@ bool CPetRoomsGlyph::dragGlyph(const Point &topLeft, CMouseDragStartMsg *msg) {
if (msg->execute(chevron))
return true;
+
+ petControl->moveToHiddenRoom(chevron);
}
}
@@ -148,9 +150,9 @@ void CPetRoomsGlyph::getTooltip(CPetText *text) {
msg = "Your assigned room: ";
} else if (isPreviouslyAssigned()) {
msg = "A previously assigned room: ";
- } else if (!_field38) {
+ } else if (!_mailFlag) {
msg = "Saved Chevron: ";
- } else if (_field38 == 1 && owner->getRoomFlags() == _roomFlags) {
+ } else if (_mailFlag == 1 && owner->getRoomFlags() == _roomFlags) {
msg = "Current location: ";
}
@@ -183,9 +185,9 @@ void CPetRoomsGlyph::loadFlags(SimpleFile *file, int val) {
}
}
-void CPetRoomsGlyph::changeLocation(int newClassNum) {
+void CPetRoomsGlyph::changeClass(PassengerClass newClassNum) {
CRoomFlags roomFlags(_roomFlags);
- roomFlags.changeLocation(newClassNum);
+ roomFlags.changeClass(newClassNum);
_roomFlags = roomFlags.get();
}
@@ -212,15 +214,15 @@ int CPetRoomsGlyph::getSelection(const Point &topLeft, const Point &pt) {
}
void CPetRoomsGlyph::drawObjects(uint flags, const Point &pt, CScreenManager *screenManager) {
- if (_object0 && _object1 && _object4 && _object5) {
+ if (_chevLeftOnDim && _chevLeftOffDim && _chevRightOnDim && _chevRightOffDim) {
Point destPos = pt;
- ((flags & 8) ? _object0 : _object5)->draw(screenManager, destPos);
+ ((flags & 8) ? _chevLeftOnDim : _chevLeftOffDim)->draw(screenManager, destPos);
destPos.x += 13;
- ((flags & 4) ? _object4 : _object5)->draw(screenManager, destPos);
+ ((flags & 4) ? _chevRightOnDim : _chevRightOffDim)->draw(screenManager, destPos);
destPos.x += 13;
- ((flags & 2) ? _object0 : _object1)->draw(screenManager, destPos);
+ ((flags & 2) ? _chevLeftOnDim : _chevLeftOffDim)->draw(screenManager, destPos);
destPos.x += 13;
- ((flags & 1) ? _object4 : _object5)->draw(screenManager, destPos);
+ ((flags & 1) ? _chevRightOnDim : _chevRightOffDim)->draw(screenManager, destPos);
}
}
diff --git a/engines/titanic/pet_control/pet_rooms_glyphs.h b/engines/titanic/pet_control/pet_rooms_glyphs.h
index 11de6c4a8e..6c51b6f875 100644
--- a/engines/titanic/pet_control/pet_rooms_glyphs.h
+++ b/engines/titanic/pet_control/pet_rooms_glyphs.h
@@ -25,6 +25,7 @@
#include "titanic/pet_control/pet_glyphs.h"
#include "titanic/support/simple_file.h"
+#include "titanic/game_location.h"
namespace Titanic {
@@ -35,16 +36,16 @@ enum RoomGlyphMode {
class CPetRoomsGlyph : public CPetGlyph {
private:
uint _roomFlags;
- int _field38;
+ uint _mailFlag;
RoomGlyphMode _mode;
- CGameObject *_object0;
- CGameObject *_object1;
- CGameObject *_object2;
- CGameObject *_object3;
- CGameObject *_object4;
- CGameObject *_object5;
- CGameObject *_object6;
- CGameObject *_object7;
+ CGameObject *_chevLeftOnDim;
+ CGameObject *_chevLeftOffDim;
+ CGameObject *_chevLeftOnLit;
+ CGameObject *_chevLeftOffLit;
+ CGameObject *_chevRightOnDim;
+ CGameObject *_chevRightOffDim;
+ CGameObject *_chevRightOnLit;
+ CGameObject *_chevRightOffLit;
private:
/**
* Find the selected button under the given point, based on the buttons
@@ -112,14 +113,20 @@ public:
*/
uint getRoomFlags() const { return _roomFlags; }
- void set38(int val) { _field38 = val; }
+ /**
+ * Set mail status flag
+ */
+ void setFlag(uint val) { _mailFlag = val; }
/**
* Sets the mode of the glyph
*/
void setMode(RoomGlyphMode mode) { _mode = mode; }
- void changeLocation(int newClassNum);
+ /**
+ * Change the current class
+ */
+ void changeClass(PassengerClass newClassNum);
/**
* Returns true if the room is either currently or previously assigned
diff --git a/engines/titanic/pet_control/pet_save.cpp b/engines/titanic/pet_control/pet_save.cpp
index d344c8cd14..60afa11ab4 100644
--- a/engines/titanic/pet_control/pet_save.cpp
+++ b/engines/titanic/pet_control/pet_save.cpp
@@ -49,6 +49,16 @@ bool CPetSave::MouseButtonUpMsg(const Point &pt) {
}
}
+bool CPetSave::KeyCharMsg(int key) {
+ if (CPetLoadSave::KeyCharMsg(key))
+ return true;
+
+ if (_savegameSlotNum != -1)
+ _slotNames[_savegameSlotNum].handleKey(key);
+
+ return true;
+}
+
void CPetSave::highlightCurrent(const Point &pt) {
resetSlots();
highlightSave(_savegameSlotNum);
@@ -71,11 +81,12 @@ void CPetSave::unhighlightSave(int index) {
void CPetSave::execute() {
CPetControl *pet = getPetControl();
if (_savegameSlotNum >= 0) {
+ int slotNumber = _savegameSlotNum;
highlightSlot(-1);
CProjectItem *project = pet ? pet->getRoot() : nullptr;
if (project) {
- project->saveGame(_savegameSlotNum, _slotNames[_savegameSlotNum].getText());
+ project->saveGame(slotNumber, _slotNames[slotNumber].getText());
pet->displayMessage(BLANK);
}
} else if (pet) {
diff --git a/engines/titanic/pet_control/pet_save.h b/engines/titanic/pet_control/pet_save.h
index e5e956403f..39a25eb087 100644
--- a/engines/titanic/pet_control/pet_save.h
+++ b/engines/titanic/pet_control/pet_save.h
@@ -40,6 +40,11 @@ public:
virtual bool MouseButtonUpMsg(const Point &pt);
/**
+ * Handles keypresses when the glyph is focused
+ */
+ virtual bool KeyCharMsg(int key);
+
+ /**
* Unhighlight any currently highlighted element
*/
virtual void unhighlightCurrent() { unhighlightSave(_savegameSlotNum); }
diff --git a/engines/titanic/pet_control/pet_section.cpp b/engines/titanic/pet_control/pet_section.cpp
index 50d6c7615c..aced697705 100644
--- a/engines/titanic/pet_control/pet_section.cpp
+++ b/engines/titanic/pet_control/pet_section.cpp
@@ -43,6 +43,7 @@ void CPetSection::displayMessage(const CString &msg) {
if (text) {
text->setColor(getColor(1));
+ text->setText(msg);
_petControl->makeDirty();
removeText(5000);
}
diff --git a/engines/titanic/pet_control/pet_section.h b/engines/titanic/pet_control/pet_section.h
index 9e9afe6c21..c68aa90411 100644
--- a/engines/titanic/pet_control/pet_section.h
+++ b/engines/titanic/pet_control/pet_section.h
@@ -106,6 +106,7 @@ public:
virtual bool MouseDragEndMsg(CMouseDragEndMsg *msg) { return false; }
virtual bool MouseButtonUpMsg(CMouseButtonUpMsg *msg) { return false; }
virtual bool MouseDoubleClickMsg(CMouseDoubleClickMsg *msg) { return false; }
+ virtual bool MouseWheelMsg(CMouseWheelMsg *msg) { return false; }
virtual bool KeyCharMsg(CKeyCharMsg *msg) { return false; }
virtual bool VirtualKeyCharMsg(CVirtualKeyCharMsg *msg) { return false; }
diff --git a/engines/titanic/pet_control/pet_text.cpp b/engines/titanic/pet_control/pet_text.cpp
index 1aa9b804ff..7bb0bad16e 100644
--- a/engines/titanic/pet_control/pet_text.cpp
+++ b/engines/titanic/pet_control/pet_text.cpp
@@ -21,12 +21,13 @@
*/
#include "titanic/pet_control/pet_text.h"
+#include "titanic/titanic.h"
namespace Titanic {
CPetText::CPetText(uint count) :
_stringsMerged(false), _maxCharsPerLine(-1), _lineCount(0),
- _linesStart(-1), _unused1(0), _unused2(0), _unused3(0),
+ _displayEndCharIndex(-1), _unused1(0), _unused2(0), _unused3(0),
_backR(0xff), _backG(0xff), _backB(0xff),
_textR(0), _textG(0), _textB(200),
_fontNumber(0), _npcFlag(0), _npcId(0), _hasBorder(true),
@@ -57,7 +58,7 @@ void CPetText::setup() {
}
void CPetText::setLineColor(uint lineNum, uint col) {
- setLineColor(lineNum, col & 0xff, (col >> 16) & 0xff, (col >> 8) & 0xff);
+ setLineColor(lineNum, col & 0xff, (col >> 8) & 0xff, (col >> 16) & 0xff);
}
void CPetText::setLineColor(uint lineNum, byte r, byte g, byte b) {
@@ -87,7 +88,7 @@ CString CPetText::getColorText(byte r, byte g, byte b) {
void CPetText::load(SimpleFile *file, int param) {
if (!param) {
uint numLines = file->readNumber();
- uint charsPerLine = file->readNumber();
+ int charsPerLine = file->readNumber();
uint count = file->readNumber();
_bounds = file->readRect();
_unused1 = file->readNumber();
@@ -102,8 +103,9 @@ void CPetText::load(SimpleFile *file, int param) {
_hasBorder = file->readNumber() != 0;
_scrollTop = file->readNumber();
- resize(numLines);
setMaxCharsPerLine(charsPerLine);
+ resize(numLines);
+ _lineCount = (count == 0) ? 0 : count - 1;
assert(_array.size() >= count);
for (uint idx = 0; idx < count; ++idx) {
@@ -172,7 +174,7 @@ void CPetText::draw(CScreenManager *screenManager) {
tempRect.grow(-2);
int oldFontNumber = screenManager->setFontNumber(_fontNumber);
- screenManager->writeString(SURFACE_BACKBUFFER, tempRect, _scrollTop, _lines, _textCursor);
+ _displayEndCharIndex = screenManager->writeString(SURFACE_BACKBUFFER, tempRect, _scrollTop, _lines, _textCursor);
screenManager->setFontNumber(oldFontNumber);
}
@@ -211,6 +213,10 @@ void CPetText::setText(const CString &str) {
appendText(str);
}
+void CPetText::setText(StringId stringId) {
+ setText(g_vm->_strings[stringId]);
+}
+
void CPetText::appendText(const CString &str) {
int lineSize = _array[_lineCount]._line.size();
int strSize = str.size();
@@ -295,7 +301,7 @@ int CPetText::getTextWidth(CScreenManager *screenManager) {
int CPetText::getTextHeight(CScreenManager *screenManager) {
mergeStrings();
int oldFontNumber = screenManager->setFontNumber(_fontNumber);
- int textHeight = screenManager->getTextBounds(_lines, _bounds.width());
+ int textHeight = screenManager->getTextBounds(_lines, _bounds.width() - 4);
screenManager->setFontNumber(oldFontNumber);
return textHeight;
@@ -449,7 +455,7 @@ void CPetText::hideCursor() {
}
}
-int CPetText::getNPCNum(uint npcId, uint startIndex) {
+int CPetText::getNPCNum(uint ident, uint startIndex) {
if (!_stringsMerged) {
mergeStrings();
if (!_stringsMerged)
@@ -460,18 +466,20 @@ int CPetText::getNPCNum(uint npcId, uint startIndex) {
if (startIndex < 5 || startIndex >= size)
return -1;
- // Loop through string
- for (const char *strP = _lines.c_str(); size >= 5; ++strP, --size) {
+ // Loop backwards from the starting index to find an NPC ident sequence
+ for (const char *strP = _lines.c_str() + startIndex;
+ strP >= (_lines.c_str() + 5); --strP) {
if (*strP == 26) {
byte id = *(strP - 2);
- if (id == npcId)
+ if (id == ident)
return *(strP - 1);
+ strP -= 3;
} else if (*strP == 27) {
- strP += 4;
+ strP -= 4;
}
}
- return - 1;
+ return -1;
}
void CPetText::setFontNumber(int fontNumber) {
diff --git a/engines/titanic/pet_control/pet_text.h b/engines/titanic/pet_control/pet_text.h
index 0a6bb2d03d..9b2f47274c 100644
--- a/engines/titanic/pet_control/pet_text.h
+++ b/engines/titanic/pet_control/pet_text.h
@@ -43,7 +43,7 @@ private:
Rect _bounds;
int _maxCharsPerLine;
int _lineCount;
- int _linesStart;
+ int _displayEndCharIndex;
int _unused1;
int _unused2;
int _unused3;
@@ -136,6 +136,11 @@ public:
void setText(const CString &str);
/**
+ * Set the text
+ */
+ void setText(StringId stringId);
+
+ /**
* Set text color
*/
void setColor(uint col);
@@ -176,9 +181,10 @@ public:
void setNPC(int npcFlag, int npcId);
/**
- * Get the index into _lines where on-screen text starts
+ * Returns the character index into _lines of the last
+ * character to be displayed on-screen
*/
- int getLinesStart() const { return _linesStart; }
+ int displayEndIndex() const { return _displayEndCharIndex; }
/**
* Scroll the text up
@@ -246,8 +252,11 @@ public:
/**
* Get an NPC Number embedded within on-screen text.
* Used by the PET log to encode which NPC spoke
+ * @param ident Npc Type. Always passed as 1
+ * @param startIndex Starting index to scan backwards
+ * through the log text to find an NPC ident sequence
*/
- int getNPCNum(uint npcId, uint startIndex);
+ int getNPCNum(uint ident, uint startIndex);
/**
* Replaces any occurances of line colors that appear in the
diff --git a/engines/titanic/room_flags.cpp b/engines/titanic/room_flags.cpp
index 9be8ea3d33..66519aa091 100644
--- a/engines/titanic/room_flags.cpp
+++ b/engines/titanic/room_flags.cpp
@@ -112,7 +112,7 @@ int CRoomFlags::getRoomArea() const {
uint v6 = getElevatorNum();
if (v6 >= 1 && v6 <= 4) {
- uint v7 = getPassengerClassNum() - 1;
+ uint v7 = (int)getPassengerClassNum() - 1;
if (v7) {
uint v8 = v7 - 1;
if (v8) {
@@ -148,41 +148,11 @@ CString CRoomFlags::getRoomDesc() const {
result += ", ";
result += getElevatorDesc();
result += ", ";
- result += getRoomDesc();
+ result += getRoomNumDesc();
return result;
}
case 4:
- if (isTransportRoom()) {
- switch (_data) {
- case 0x68797:
- return "The Service Elevator";
- case 0x5D3AD:
- return "The Super Galactic Leisure Lounge";
- case 0x96E45:
- return "The Elevator";
- case 0xAD171:
- return "The Dome";
- case 0xC95E9:
- return "The Pellerator";
- case 0xDF4D1:
- return "The Top of the Well";
- default:
- break;
- }
- }
-
- if (getRoomCategory() == 0) {
- return "Nowhere you're likely to want to go.";
- } else {
- CString result = getPassengerClassDesc();
- result += ", ";
- result += getFloorDesc();
- return result;
- }
- break;
-
- case 5:
switch (_data) {
case 0x1D0D9:
return "The Parrot Lobby";
@@ -215,6 +185,36 @@ CString CRoomFlags::getRoomDesc() const {
}
return "Unknown Room";
+ case 5:
+ if (isTransportRoom()) {
+ switch (_data) {
+ case 0x68797:
+ return "The Service Elevator";
+ case 0x5D3AD:
+ return "The Super Galactic Leisure Lounge";
+ case 0x96E45:
+ return "The Elevator";
+ case 0xAD171:
+ return "The Dome";
+ case 0xC95E9:
+ return "The Pellerator";
+ case 0xDF4D1:
+ return "The Top of the Well";
+ default:
+ break;
+ }
+ }
+
+ if (getRoomCategory() == 0) {
+ return "Nowhere you're likely to want to go.";
+ } else {
+ CString result = getPassengerClassDesc();
+ result += ", ";
+ result += getFloorDesc();
+ return result;
+ }
+ break;
+
default:
break;
}
@@ -241,14 +241,14 @@ uint CRoomFlags::getPassengerClassBits() const {
}
CString CRoomFlags::getPassengerClassDesc() const {
- int classNum = getPassengerClassNum();
+ PassengerClass classNum = getPassengerClassNum();
switch (classNum) {
- case 1:
+ case FIRST_CLASS:
return "1st class";
- case 2:
+ case SECOND_CLASS:
return "2nd class";
- case 3:
+ case THIRD_CLASS:
return "SGT class";
default:
return "no class";
@@ -269,21 +269,20 @@ uint CRoomFlags::decodeFloorBits(uint bits) const {
int offset = bits & 0xF;
switch ((bits >> 4) & 0xF) {
- case 1:
- case 2:
- case 3:
- base = 40;
+ case 9:
+ base = 0;
break;
- case 4:
+ case 0xD:
base = 10;
break;
- case 5:
+ case 0xE:
base = 20;
break;
- case 6:
+ case 0xF:
base = 30;
break;
default:
+ base = 40;
break;
}
@@ -369,29 +368,29 @@ CString CRoomFlags::getSuccUBusRoomName() const {
return CString();
}
-void CRoomFlags::changeLocation(int action) {
+void CRoomFlags::changeClass(PassengerClass newClassNum) {
uint floorNum = getFloorNum();
uint roomNum = getRoomNum();
uint elevatorNum = getElevatorNum();
- uint classNum = getPassengerClassNum();
+ PassengerClass classNum = getPassengerClassNum();
uint v10, v11, v12, v13;
switch (classNum) {
- case 1:
+ case FIRST_CLASS:
v10 = 2;
v11 = 19;
v12 = 1;
v13 = 3;
break;
- case 2:
+ case SECOND_CLASS:
v10 = 20;
v11 = 27;
v12 = 1;
v13 = (elevatorNum & 1) ? 3 : 4;
break;
- case 3:
+ case THIRD_CLASS:
v10 = 28;
v11 = 38;
v12 = 1;
@@ -407,25 +406,28 @@ void CRoomFlags::changeLocation(int action) {
}
// Perform action to change room or floor
- switch (action) {
- case 1:
+ switch (newClassNum) {
+ case FIRST_CLASS:
if (--roomNum < v12)
roomNum = v12;
break;
- case 2:
+ case SECOND_CLASS:
if (++roomNum > v13)
roomNum = v13;
break;
- case 3:
+ case THIRD_CLASS:
if (--floorNum < v10)
floorNum = v10;
break;
- case 4:
+ case UNCHECKED:
if (++floorNum > v11)
floorNum = v11;
+
+ default:
+ break;
}
// Set new floor and room
@@ -442,16 +444,16 @@ bool CRoomFlags::compareClassElevator(uint flags1, uint flags2) {
uint elev1 = f1.getElevatorNum();
uint elev2 = f2.getElevatorNum();
- uint class1 = f1.getPassengerClassNum();
- uint class2 = f2.getPassengerClassNum();
+ PassengerClass class1 = f1.getPassengerClassNum();
+ PassengerClass class2 = f2.getPassengerClassNum();
- if (class1 > 0 && class1 < 3) {
+ if (class1 == FIRST_CLASS || class1 == SECOND_CLASS) {
if (elev1 == 2)
elev1 = 1;
else if (elev1 == 4)
elev1 = 3;
}
- if (class2 > 0 && class2 < 3) {
+ if (class2 == FIRST_CLASS || class2 == SECOND_CLASS) {
if (elev2 == 2)
elev2 = 1;
else if (elev2 == 4)
@@ -474,12 +476,12 @@ bool CRoomFlags::isTitania(uint flags1, uint flags2) {
return flags2 == 0x8A397;
}
-void CRoomFlags::setRandomLocation(int classNum, bool flag) {
+void CRoomFlags::setRandomLocation(PassengerClass classNum, bool flag) {
uint minRoom, elevNum, maxRoom, maxFloor, minFloor;
do {
switch (classNum) {
- case 1:
+ case FIRST_CLASS:
minFloor = 2;
maxFloor = 19;
minRoom = 1;
@@ -487,7 +489,7 @@ void CRoomFlags::setRandomLocation(int classNum, bool flag) {
elevNum = g_vm->getRandomNumber(flag ? 2 : 3);
break;
- case 2:
+ case SECOND_CLASS:
minFloor = 20;
maxFloor = 27;
elevNum = g_vm->getRandomNumber(flag ? 2 : 3);
@@ -495,14 +497,12 @@ void CRoomFlags::setRandomLocation(int classNum, bool flag) {
maxRoom = ((elevNum - 1) & 1) ? 3 : 4;
break;
- case 3:
+ case THIRD_CLASS:
minRoom = 1;
minFloor = 28;
maxFloor = 38;
maxRoom = 18;
- elevNum = g_vm->getRandomNumber(1);
- if (elevNum == 1)
- elevNum = 2;
+ elevNum = g_vm->getRandomNumber(1) ? 2 : 0;
break;
default:
@@ -514,14 +514,15 @@ void CRoomFlags::setRandomLocation(int classNum, bool flag) {
setElevatorBits(elevNum);
setRoomBits(roomNum);
setFloorNum(floorNum);
+ setPassengerClassBits(classNum);
} while (_data == 0x59706);
}
-int CRoomFlags::whatPassengerClass(int floorNum) {
+PassengerClass CRoomFlags::whatPassengerClass(int floorNum) {
if (is2To19(floorNum))
- return 1;
+ return FIRST_CLASS;
- return is20To27(floorNum) ? 2 : 3;
+ return is20To27(floorNum) ? SECOND_CLASS : THIRD_CLASS;
}
} // End of namespace Titanic
diff --git a/engines/titanic/room_flags.h b/engines/titanic/room_flags.h
index f0f90f80d1..8e86bf707e 100644
--- a/engines/titanic/room_flags.h
+++ b/engines/titanic/room_flags.h
@@ -24,6 +24,7 @@
#define TITANIC_ROOM_FLAGS_H
#include "titanic/support/string.h"
+#include "titanic/game_location.h"
namespace Titanic {
@@ -142,7 +143,9 @@ public:
/**
* Gets the passenger class number
*/
- uint getPassengerClassNum() const { return getPassengerClassBits(); }
+ PassengerClass getPassengerClassNum() const {
+ return (PassengerClass)getPassengerClassBits();
+ }
/**
* Get a description for the passenger class
@@ -198,12 +201,12 @@ public:
/**
* Change the passenger class
*/
- void changeLocation(int action);
+ void changeClass(PassengerClass newClassNum);
/**
* Sets a random destination in the flags
*/
- void setRandomLocation(int classNum, bool flag);
+ void setRandomLocation(PassengerClass classNum, bool flag);
/**
* Gets the succubus number associated with a given room
@@ -218,7 +221,7 @@ public:
/**
* Returns what passenger class a particular floor number belongs to
*/
- static int whatPassengerClass(int floorNum);
+ static PassengerClass whatPassengerClass(int floorNum);
bool not5() const { return getConditionally() != 5; }
diff --git a/engines/titanic/sound/qmixer.cpp b/engines/titanic/sound/qmixer.cpp
index 733164947e..b3910f846a 100644
--- a/engines/titanic/sound/qmixer.cpp
+++ b/engines/titanic/sound/qmixer.cpp
@@ -60,7 +60,19 @@ void QMixer::qsWaveMixFreeWave(Audio::SoundHandle &handle) {
}
void QMixer::qsWaveMixFlushChannel(int iChannel, uint flags) {
- // Not currently implemented in ScummVM
+ if (flags & QMIX_OPENALL) {
+ // Ignore channel, and flush all the channels
+ for (uint idx = 0; idx < _channels.size(); ++idx)
+ qsWaveMixFlushChannel(idx, 0);
+ } else {
+ // Flush the specified channel
+ Common::List<SoundEntry>::iterator i;
+ Common::List<SoundEntry> &sounds = _channels[iChannel]._sounds;
+ for (i = sounds.begin(); i != sounds.end(); ++i)
+ _mixer->stopHandle((*i)._soundHandle);
+
+ sounds.clear();
+ }
}
void QMixer::qsWaveMixSetPanRate(int iChannel, uint flags, uint rate) {
@@ -83,11 +95,28 @@ void QMixer::qsWaveMixSetVolume(int iChannel, uint flags, uint volume) {
}
void QMixer::qsWaveMixSetSourcePosition(int iChannel, uint flags, const QSVECTOR &position) {
- // Not currently implemented in ScummVM
+ ChannelEntry &channel = _channels[iChannel];
+
+ // Flag whether distance should reset when a new sound is started
+ channel._resetDistance = (flags & QMIX_USEONCE) != 0;
+
+ // Currently, we only do a basic simulation of spatial positioning by
+ // getting the distance, and proportionately reducing the volume the
+ // further away the source is
+ channel._distance = sqrt(position.x * position.x + position.y * position.y
+ + position.z * position.z);
}
void QMixer::qsWaveMixSetPolarPosition(int iChannel, uint flags, const QSPOLAR &position) {
- // Not currently implemented in ScummVM
+ ChannelEntry &channel = _channels[iChannel];
+
+ // Flag whether distance should reset when a new sound is started
+ channel._resetDistance = (flags & QMIX_USEONCE) != 0;
+
+ // Currently, we only do a basic simulation of spatial positioning by
+ // getting the distance, and proportionately reducing the volume the
+ // further away the source is
+ channel._distance = position.range;
}
void QMixer::qsWaveMixSetListenerPosition(const QSVECTOR &position, uint flags) {
@@ -163,7 +192,8 @@ void QMixer::qsWaveMixPump() {
if (channel._volume != oldVolume && !channel._sounds.empty()
&& channel._sounds.front()._started) {
- _mixer->setChannelVolume(channel._sounds.front()._soundHandle, channel._volume);
+ _mixer->setChannelVolume(channel._sounds.front()._soundHandle,
+ channel.getRawVolume());
}
}
@@ -177,7 +207,7 @@ void QMixer::qsWaveMixPump() {
sound._waveFile->_stream->rewind();
_mixer->playStream(sound._waveFile->_soundType,
&sound._soundHandle, sound._waveFile->_stream,
- -1, channel._volume, 0, DisposeAfterUse::NO);
+ -1, channel.getRawVolume(), 0, DisposeAfterUse::NO);
} else {
// Sound is finished
if (sound._callback)
@@ -195,13 +225,30 @@ void QMixer::qsWaveMixPump() {
if (!channel._sounds.empty()) {
SoundEntry &sound = channel._sounds.front();
if (!sound._started) {
+ if (channel._resetDistance)
+ channel._distance = 0.0;
+
+ // Calculate an effective volume based on distance of source
_mixer->playStream(sound._waveFile->_soundType,
&sound._soundHandle, sound._waveFile->_stream,
- -1, channel._volume, 0, DisposeAfterUse::NO);
+ -1, channel.getRawVolume(), 0, DisposeAfterUse::NO);
sound._started = true;
}
}
}
}
+/*------------------------------------------------------------------------*/
+
+byte QMixer::ChannelEntry::getRawVolume() const {
+ // Emperically decided adjustment divisor for distances
+ const double ADJUSTMENT_FACTOR = 5.0;
+
+ double r = 1.0 + (_distance / ADJUSTMENT_FACTOR);
+ double percent = 1.0 / (r * r);
+
+ double newVolume = _volume * percent;
+ return (byte)newVolume;
+}
+
} // End of namespace Titanic
diff --git a/engines/titanic/sound/qmixer.h b/engines/titanic/sound/qmixer.h
index 9a0ea85ede..b8c7f6dae2 100644
--- a/engines/titanic/sound/qmixer.h
+++ b/engines/titanic/sound/qmixer.h
@@ -197,9 +197,19 @@ class QMixer {
uint _volumeChangeEnd;
byte _volumeStart;
byte _volumeEnd;
+ // Distance of source
+ double _distance;
+ bool _resetDistance;
ChannelEntry() : _volume(0), _panRate(0), _volumeChangeStart(0),
- _volumeChangeEnd(0), _volumeStart(0), _volumeEnd(0) {}
+ _volumeChangeEnd(0), _volumeStart(0), _volumeEnd(0),
+ _distance(0.0), _resetDistance(true) {}
+
+ /**
+ * Calculates the raw volume level to pass to ScummVM playStream, taking
+ * into the sound's volume level and distance from origin
+ */
+ byte getRawVolume() const;
};
private:
Audio::Mixer *_mixer;
@@ -290,7 +300,7 @@ public:
void qsWaveMixSetDistanceMapping(int iChannel, uint flags, const QMIX_DISTANCES &distances);
/**
- *
+ * Sets the frequency/rate of sound playback
*/
void qsWaveMixSetFrequency(int iChannel, uint flags, uint frequency);
diff --git a/engines/titanic/sound/sound.cpp b/engines/titanic/sound/sound.cpp
index e48c8760c5..c28823148e 100644
--- a/engines/titanic/sound/sound.cpp
+++ b/engines/titanic/sound/sound.cpp
@@ -57,7 +57,7 @@ void CSound::preEnterView(CViewItem *newView, bool isNewRoom) {
_soundManager.setListenerPosition(xp, yp, zp, cosVal, sinVal, 0, isNewRoom);
}
-bool CSound::isActive(int handle) const {
+bool CSound::isActive(int handle) {
if (handle != 0 && handle != -1)
return _soundManager.isActive(handle);
@@ -129,6 +129,7 @@ CWaveFile *CSound::loadSound(const CString &name) {
// Found it, so move it to the front of the list and return
_sounds.remove(soundItem);
_sounds.push_front(soundItem);
+ soundItem->_waveFile->reset();
return soundItem->_waveFile;
}
}
diff --git a/engines/titanic/sound/sound.h b/engines/titanic/sound/sound.h
index 21f2a93f24..c767a3d75f 100644
--- a/engines/titanic/sound/sound.h
+++ b/engines/titanic/sound/sound.h
@@ -115,7 +115,7 @@ public:
/**
* Returns true if a sound with the specified handle is active
*/
- bool isActive(int handle) const;
+ bool isActive(int handle);
/**
* Sets the volume for a sound
diff --git a/engines/titanic/sound/sound_manager.cpp b/engines/titanic/sound/sound_manager.cpp
index c1a46e5103..5f8e53caf3 100644
--- a/engines/titanic/sound/sound_manager.cpp
+++ b/engines/titanic/sound/sound_manager.cpp
@@ -311,7 +311,9 @@ void QSoundManager::setPolarPosition(int handle, double range, double azimuth, d
}
}
-bool QSoundManager::isActive(int handle) const {
+bool QSoundManager::isActive(int handle) {
+ resetChannel(10);
+
for (uint idx = 0; idx < _slots.size(); ++idx) {
if (_slots[idx]._handle == handle)
return true;
@@ -320,7 +322,7 @@ bool QSoundManager::isActive(int handle) const {
return false;
}
-bool QSoundManager::isActive(const CWaveFile *waveFile) const {
+bool QSoundManager::isActive(const CWaveFile *waveFile) {
return _sounds.contains(waveFile);
}
diff --git a/engines/titanic/sound/sound_manager.h b/engines/titanic/sound/sound_manager.h
index a3074a8e57..ff556346de 100644
--- a/engines/titanic/sound/sound_manager.h
+++ b/engines/titanic/sound/sound_manager.h
@@ -123,12 +123,12 @@ public:
/**
* Returns true if the given sound is currently active
*/
- virtual bool isActive(int handle) const = 0;
+ virtual bool isActive(int handle) = 0;
/**
* Returns true if the given sound is currently active
*/
- virtual bool isActive(const CWaveFile *waveFile) const { return false; }
+ virtual bool isActive(const CWaveFile *waveFile) { return false; }
/**
* Handles regularly updating the mixer
@@ -395,12 +395,12 @@ public:
/**
* Returns true if the given sound is currently active
*/
- virtual bool isActive(int handle) const;
+ virtual bool isActive(int handle);
/**
* Returns true if the given sound is currently active
*/
- virtual bool isActive(const CWaveFile *waveFile) const;
+ virtual bool isActive(const CWaveFile *waveFile);
/**
* Handles regularly updating the mixer
diff --git a/engines/titanic/sound/wave_file.cpp b/engines/titanic/sound/wave_file.cpp
index ade94aad50..f2366d1dd5 100644
--- a/engines/titanic/sound/wave_file.cpp
+++ b/engines/titanic/sound/wave_file.cpp
@@ -51,9 +51,9 @@ uint CWaveFile::getDurationTicks() const {
// a desired size. Since I have no idea how the system API
// method works, for now I'm using a simple ratio of a
// sample output to input value
- uint size = _size - 0x46;
- double newSize = (double)size * (1475712.0 / 199836.0);
- return newSize * 1000.0 / _stream->getRate();
+ uint dataSize = _size - 0x46;
+ double newSize = (double)dataSize * (1475712.0 / 199836.0);
+ return (uint)(newSize * 1000.0 / _stream->getRate());
}
bool CWaveFile::loadSound(const CString &name) {
@@ -106,4 +106,8 @@ uint CWaveFile::getFrequency() const {
return _stream->getRate();
}
+void CWaveFile::reset() {
+ _stream->rewind();
+}
+
} // End of namespace Titanic z
diff --git a/engines/titanic/sound/wave_file.h b/engines/titanic/sound/wave_file.h
index 19d367936f..e4bb71a0b6 100644
--- a/engines/titanic/sound/wave_file.h
+++ b/engines/titanic/sound/wave_file.h
@@ -81,6 +81,11 @@ public:
* Return the frequency of the loaded wave file
*/
uint getFrequency() const;
+
+ /**
+ * Resets the music stream
+ */
+ void reset();
};
} // End of namespace Titanic
diff --git a/engines/titanic/star_control/star_control_sub13.cpp b/engines/titanic/star_control/star_control_sub13.cpp
index 490e6d0630..5da6118a74 100644
--- a/engines/titanic/star_control/star_control_sub13.cpp
+++ b/engines/titanic/star_control/star_control_sub13.cpp
@@ -225,7 +225,7 @@ void CStarControlSub13::fn19(double *v1, double *v2, double *v3, double *v4) {
}
void CStarControlSub13::reset() {
- const double FACTOR = 3.1415927 * 0.0055555557;
+ //const double FACTOR = 3.1415927 * 0.0055555557;
error("TODO: CStarControlSub13::reset");
}
diff --git a/engines/titanic/support/avi_surface.cpp b/engines/titanic/support/avi_surface.cpp
index 07458812b9..525c6513dd 100644
--- a/engines/titanic/support/avi_surface.cpp
+++ b/engines/titanic/support/avi_surface.cpp
@@ -41,6 +41,7 @@ AVISurface::AVISurface(const CResourceKey &key) {
_streamCount = 0;
_movieFrameSurface[0] = _movieFrameSurface[1] = nullptr;
_framePixels = nullptr;
+ _priorFrameTime = 0;
// Reset current frame. We need to keep track of frames separately from the decoder,
// since it needs to be able to go beyond the frame count or to negative to allow
@@ -164,8 +165,8 @@ bool AVISurface::handleEvents(CMovieEventList &events) {
_currentFrame += _isReversed ? -1 : 1;
int newFrame = _currentFrame;
- if ((info->_isReversed && newFrame <= info->_endFrame) ||
- (!info->_isReversed && newFrame >= info->_endFrame)) {
+ if ((info->_isReversed && newFrame < info->_endFrame) ||
+ (!info->_isReversed && newFrame > info->_endFrame)) {
if (info->_isRepeat) {
newFrame = info->_startFrame;
} else {
@@ -180,6 +181,7 @@ bool AVISurface::handleEvents(CMovieEventList &events) {
// Not empty, so move onto new first one
info = _movieRangeInfo.front();
newFrame = info->_startFrame;
+ setReversed(info->_isReversed);
}
}
}
@@ -286,8 +288,20 @@ void AVISurface::setFrame(int frameNumber) {
renderFrame();
}
-bool AVISurface::isNextFrame() const {
- return _decoder->getTimeToNextFrame() == 0;
+bool AVISurface::isNextFrame() {
+ if (!_decoder->endOfVideo())
+ return _decoder->getTimeToNextFrame() == 0;
+
+ // We're at the end of the video, so we need to manually
+ // keep track of frame delays. Hardcoded at the moment for 15FPS
+ const uint FRAME_TIME = 1000 / 15;
+ uint32 currTime = g_system->getMillis();
+ if (currTime >= (_priorFrameTime + FRAME_TIME)) {
+ _priorFrameTime = currTime;
+ return true;
+ }
+
+ return false;
}
bool AVISurface::renderFrame() {
@@ -347,7 +361,12 @@ bool AVISurface::addEvent(int frameNumber, CGameObject *obj) {
}
void AVISurface::setFrameRate(double rate) {
- _decoder->setRate(Common::Rational((int)rate));
+ // Convert rate from fps to relative to 1.0 (normal speed)
+ const int PRECISION = 10000;
+ double playRate = rate / 15.0; // Standard 15 FPS
+ Common::Rational pRate(playRate * PRECISION, PRECISION);
+
+ _decoder->setRate(pRate);
}
Graphics::ManagedSurface *AVISurface::getSecondarySurface() {
@@ -370,10 +389,12 @@ void AVISurface::playCutscene(const Rect &r, uint startFrame, uint endFrame) {
_movieFrameSurface[0]->h != r.height();
startAtFrame(startFrame);
+ _currentFrame = startFrame;
+
while (_currentFrame < (int)endFrame && !g_vm->shouldQuit()) {
if (isNextFrame()) {
renderFrame();
- _currentFrame = _decoder->getCurFrame();
+ ++_currentFrame;
if (isDifferent) {
// Clear the destination area, and use the transBlitFrom method,
diff --git a/engines/titanic/support/avi_surface.h b/engines/titanic/support/avi_surface.h
index b4e6d420cb..2a4b321f0f 100644
--- a/engines/titanic/support/avi_surface.h
+++ b/engines/titanic/support/avi_surface.h
@@ -66,6 +66,7 @@ private:
Graphics::ManagedSurface *_framePixels;
bool _isReversed;
int _currentFrame;
+ uint32 _priorFrameTime;
private:
/**
* Render a frame to the video surface
@@ -132,7 +133,9 @@ public:
/**
* Return true if a video is currently playing
*/
- virtual bool isPlaying() const { return _decoder->isPlaying(); }
+ virtual bool isPlaying() const {
+ return _decoder->isPlaying();
+ }
/**
* Handle any movie events relevent for the frame
@@ -194,7 +197,7 @@ public:
/**
* Returns true if it's time for the next
*/
- bool isNextFrame() const;
+ bool isNextFrame();
/**
* Plays an interruptable cutscene
diff --git a/engines/titanic/support/font.cpp b/engines/titanic/support/font.cpp
index 625d03720b..f81251b10b 100644
--- a/engines/titanic/support/font.cpp
+++ b/engines/titanic/support/font.cpp
@@ -90,7 +90,7 @@ int STFont::getTextBounds(const CString &str, int maxWidth, Point *sizeOut) cons
strP += 4;
} else {
if (*strP == ' ') {
- // Check fo rline wrapping
+ // Check for line wrapping
checkLineWrap(textSize, maxWidth, strP);
}
@@ -152,7 +152,7 @@ int STFont::writeString(CVideoSurface *surface, const Rect &rect1, const Rect &d
setColor(r, g, b);
} else {
if (*srcP == ' ') {
- // Check fo rline wrapping
+ // Check for line wrapping
checkLineWrap(textSize, rect1.width(), srcP);
if (!*srcP)
return endP - str.c_str();
@@ -245,11 +245,8 @@ WriteCharacterResult STFont::writeChar(CVideoSurface *surface, unsigned char c,
if (c == 233)
c = '$';
- Rect tempRect;
- tempRect.left = _chars[c]._offset;
- tempRect.right = _chars[c]._offset + _chars[c]._width;
- tempRect.top = 0;
- tempRect.bottom = _fontHeight;
+ Rect charRect(_chars[c]._offset, 0,
+ _chars[c]._offset + _chars[c]._width, _fontHeight);
Point destPos(pt.x + destRect.left, pt.y + destRect.top);
if (srcRect->isEmpty())
@@ -257,34 +254,34 @@ WriteCharacterResult STFont::writeChar(CVideoSurface *surface, unsigned char c,
if (destPos.y > srcRect->bottom)
return WC_OUTSIDE_BOTTOM;
- if ((destPos.y + tempRect.height()) > srcRect->bottom) {
- tempRect.bottom += tempRect.top - destPos.y;
+ if ((destPos.y + charRect.height()) > srcRect->bottom) {
+ charRect.bottom += srcRect->bottom - (destPos.y + charRect.height());
}
if (destPos.y < srcRect->top) {
- if ((tempRect.height() + destPos.y) < srcRect->top)
+ if ((charRect.height() + destPos.y) < srcRect->top)
return WC_OUTSIDE_TOP;
- tempRect.top += srcRect->top - destPos.y;
+ charRect.top += srcRect->top - destPos.y;
destPos.y = srcRect->top;
}
if (destPos.x < srcRect->left) {
- if ((tempRect.width() + destPos.x) < srcRect->left)
+ if ((charRect.width() + destPos.x) < srcRect->left)
return WC_OUTSIDE_LEFT;
- tempRect.left += srcRect->left - destPos.x;
+ charRect.left += srcRect->left - destPos.x;
destPos.x = srcRect->left;
} else {
- if ((tempRect.width() + destPos.x) > srcRect->right) {
+ if ((charRect.width() + destPos.x) > srcRect->right) {
if (destPos.x > srcRect->right)
return WC_OUTSIDE_RIGHT;
- tempRect.right += srcRect->left - destPos.x;
+ charRect.right += srcRect->left - destPos.x;
}
}
- copyRect(surface, destPos, tempRect);
+ copyRect(surface, destPos, charRect);
return WC_IN_BOUNDS;
}
@@ -318,10 +315,10 @@ void STFont::extendBounds(Point &textSize, byte c, int maxWidth) const {
void STFont::checkLineWrap(Point &textSize, int maxWidth, const char *&str) const {
bool flag = false;
int totalWidth = 0;
- for (const char *srcPtr = str; *srcPtr && *srcPtr != ' '; ++srcPtr) {
- if (*srcPtr == ' ' && flag)
- break;
+ // Loop forward getting the width of the word (including preceding space)
+ // until a space is encountered following at least one character
+ for (const char *srcPtr = str; *srcPtr && (*srcPtr != ' ' || !flag); ++srcPtr) {
if (*srcPtr == TEXTCMD_NPC) {
srcPtr += 3;
} else if (*srcPtr == TEXTCMD_SET_COLOR) {
diff --git a/engines/titanic/support/mouse_cursor.cpp b/engines/titanic/support/mouse_cursor.cpp
index 4dd1ab4366..6300f65a3b 100644
--- a/engines/titanic/support/mouse_cursor.cpp
+++ b/engines/titanic/support/mouse_cursor.cpp
@@ -54,10 +54,11 @@ CMouseCursor::CursorEntry::~CursorEntry() {
}
CMouseCursor::CMouseCursor(CScreenManager *screenManager) :
- _screenManager(screenManager), _cursorId(CURSOR_HOURGLASS),
- _setCursorCount(0), _fieldE4(0), _fieldE8(0) {
+ _screenManager(screenManager), _cursorId(CURSOR_HOURGLASS), _hideCounter(0),
+ _hiddenCount(0), _cursorSuppressed(false), _setCursorCount(0), _inputEnabled(true), _fieldE8(0) {
loadCursorImages();
setCursor(CURSOR_ARROW);
+ CursorMan.showMouse(true);
}
CMouseCursor::~CMouseCursor() {
@@ -87,11 +88,38 @@ void CMouseCursor::loadCursorImages() {
}
void CMouseCursor::show() {
- CursorMan.showMouse(true);
+ assert(_hiddenCount > 0);
+
+ if (--_hiddenCount == 0)
+ CursorMan.showMouse(!_cursorSuppressed);
}
void CMouseCursor::hide() {
CursorMan.showMouse(false);
+ ++_hiddenCount;
+}
+
+void CMouseCursor::incHideCounter() {
+ if (_hideCounter++ == 0)
+ hide();
+}
+
+void CMouseCursor::decHideCounter() {
+ --_hideCounter;
+ assert(_hideCounter >= 0);
+ if (_hideCounter == 0)
+ show();
+}
+
+void CMouseCursor::suppressCursor() {
+ _cursorSuppressed = true;
+ hide();
+}
+
+void CMouseCursor::unsuppressCursor() {
+ _cursorSuppressed = false;
+ if (_hideCounter == 0)
+ show();
}
void CMouseCursor::setCursor(CursorId cursorId) {
@@ -108,7 +136,7 @@ void CMouseCursor::setCursor(CursorId cursorId) {
Graphics::ManagedSurface surface(CURSOR_SIZE, CURSOR_SIZE, g_system->getScreenFormat());
const uint16 *srcP = srcSurface.getPixels();
- CTransparencySurface transSurface(&ce._transSurface->rawSurface(), TRANS_DEFAULT);
+ CTransparencySurface transSurface(&ce._transSurface->rawSurface(), TRANS_ALPHA0);
uint16 *destP = (uint16 *)surface.getPixels();
for (int y = 0; y < CURSOR_SIZE; ++y) {
@@ -131,25 +159,45 @@ void CMouseCursor::setCursor(CursorId cursorId) {
}
void CMouseCursor::update() {
- // No implementation needed
+ if (!_inputEnabled && _moveStartTime) {
+ uint32 time = CLIP(g_system->getMillis(), _moveStartTime, _moveEndTime);
+ Common::Point pt(
+ _moveStartPos.x + (_moveDestPos.x - _moveStartPos.x) *
+ (int)(time - _moveStartTime) / (int)(_moveEndTime - _moveStartTime),
+ _moveStartPos.y + (_moveDestPos.y - _moveStartPos.y) *
+ (int)(time - _moveStartTime) / (int)(_moveEndTime - _moveStartTime)
+ );
+
+ if (pt != g_vm->_events->getMousePos()) {
+ g_vm->_events->setMousePos(pt);
+
+ CInputHandler &inputHandler = *CScreenManager::_screenManagerPtr->_inputHandler;
+ CMouseMoveMsg msg(pt, 0);
+ inputHandler.handleMessage(msg, false);
+ }
+
+ if (time == _moveEndTime)
+ _moveStartTime = _moveEndTime = 0;
+ }
}
-void CMouseCursor::lockE4() {
- _fieldE4 = 0;
+void CMouseCursor::disableControl() {
+ _inputEnabled = false;
CScreenManager::_screenManagerPtr->_inputHandler->incLockCount();
}
-void CMouseCursor::unlockE4() {
- _fieldE4 = 1;
+void CMouseCursor::enableControl() {
+ _inputEnabled = true;
_fieldE8 = 0;
CScreenManager::_screenManagerPtr->_inputHandler->decLockCount();
}
-void CMouseCursor::setPosition(const Point &pt, double rate) {
- assert(rate >= 0.0 && rate <= 1.0);
-
- // TODO: Figure out use of the rate parameter
- g_system->warpMouse(pt.x, pt.y);
+void CMouseCursor::setPosition(const Point &pt, double duration) {
+ _moveStartPos = g_vm->_events->getMousePos();
+ _moveDestPos = pt;
+ _moveStartTime = g_system->getMillis();
+ _moveEndTime = _moveStartTime + duration;
+ update();
}
} // End of namespace Titanic
diff --git a/engines/titanic/support/mouse_cursor.h b/engines/titanic/support/mouse_cursor.h
index 08de28e29d..1662ce743d 100644
--- a/engines/titanic/support/mouse_cursor.h
+++ b/engines/titanic/support/mouse_cursor.h
@@ -66,14 +66,22 @@ private:
CursorId _cursorId;
CursorEntry _cursors[NUM_CURSORS];
uint _setCursorCount;
- int _fieldE4;
+ int _hideCounter;
+ int _hiddenCount;
+ bool _cursorSuppressed;
int _fieldE8;
+ uint32 _priorMoveTime;
+ Common::Point _moveStartPos;
+ Common::Point _moveDestPos;
+ uint _moveStartTime, _moveEndTime;
/**
* Load the images for each cursor
*/
void loadCursorImages();
public:
+ bool _inputEnabled;
+public:
CMouseCursor(CScreenManager *screenManager);
~CMouseCursor();
@@ -88,6 +96,29 @@ public:
void hide();
/**
+ * Decrements the hide counter, and shows the mouse if
+ * it's reached zero
+ */
+ void incHideCounter();
+
+ /**
+ * Increments the hide counter, hiding the mouse if it's the first call
+ */
+ void decHideCounter();
+
+ /**
+ * Suppresses the cursor. When suppressed, the cursor isn't drawn,
+ * even if it's not otherwise being hidden
+ */
+ void suppressCursor();
+
+ /**
+ * Unflags the cursor as being suppressed, allowing it to be drawn
+ * again if it's enabled
+ */
+ void unsuppressCursor();
+
+ /**
* Set the cursor
*/
void setCursor(CursorId cursorId);
@@ -102,13 +133,20 @@ public:
*/
uint getChangeCount() const { return _setCursorCount; }
- void lockE4();
- void unlockE4();
+ /**
+ * Disables user control of the mouse
+ */
+ void disableControl();
+
+ /**
+ * Re-enables user control of the mouse
+ */
+ void enableControl();
/**
- * Sets the mouse to a new position
+ * Move the mouse to a new position
*/
- void setPosition(const Point &pt, double rate);
+ void setPosition(const Point &pt, double duration);
};
diff --git a/engines/titanic/support/movie.cpp b/engines/titanic/support/movie.cpp
index 2115906992..949ed62fca 100644
--- a/engines/titanic/support/movie.cpp
+++ b/engines/titanic/support/movie.cpp
@@ -126,19 +126,12 @@ void OSMovie::playCutscene(const Rect &drawRect, uint startFrame, uint endFrame)
if (!_movieSurface)
_movieSurface = CScreenManager::_screenManagerPtr->createSurface(600, 340);
- bool widthLess = _videoSurface->getWidth() < 600;
- bool heightLess = _videoSurface->getHeight() < 340;
- Rect r(drawRect.left, drawRect.top,
- drawRect.left + (widthLess ? CLIP_WIDTH_REDUCED : CLIP_WIDTH),
- drawRect.top + (heightLess ? CLIP_HEIGHT_REDUCED : CLIP_HEIGHT)
- );
-
// Set a new event target whilst the clip plays, so standard scene drawing isn't called
CEventTarget eventTarget;
g_vm->_events->addTarget(&eventTarget);
_aviSurface.setFrame(startFrame);
- _aviSurface.playCutscene(r, startFrame, endFrame);
+ _aviSurface.playCutscene(drawRect, startFrame, endFrame);
g_vm->_events->removeTarget();
}
diff --git a/engines/titanic/support/screen_manager.cpp b/engines/titanic/support/screen_manager.cpp
index 2e9bbcb6de..2a675394b5 100644
--- a/engines/titanic/support/screen_manager.cpp
+++ b/engines/titanic/support/screen_manager.cpp
@@ -308,11 +308,11 @@ CVideoSurface *OSScreenManager::createSurface(const CResourceKey &key) {
}
void OSScreenManager::showCursor() {
- CScreenManager::_screenManagerPtr->_mouseCursor->show();
+ CScreenManager::_screenManagerPtr->_mouseCursor->unsuppressCursor();
}
void OSScreenManager::hideCursor() {
- CScreenManager::_screenManagerPtr->_mouseCursor->hide();
+ CScreenManager::_screenManagerPtr->_mouseCursor->suppressCursor();
}
void OSScreenManager::destroyFrontAndBackBuffers() {
@@ -330,7 +330,6 @@ void OSScreenManager::loadCursors() {
delete _mouseCursor;
}
_mouseCursor = new CMouseCursor(this);
- showCursor();
if (!_textCursor) {
_textCursor = new CTextCursor(this);
diff --git a/engines/titanic/support/simple_file.cpp b/engines/titanic/support/simple_file.cpp
index 7e3cea35be..65d2c85273 100644
--- a/engines/titanic/support/simple_file.cpp
+++ b/engines/titanic/support/simple_file.cpp
@@ -467,7 +467,7 @@ void SimpleFile::skipSpaces() {
/*------------------------------------------------------------------------*/
bool StdCWadFile::open(const Common::String &filename) {
- File f;
+ Common::File f;
CString name = filename;
// Check for whether it is indeed a file/resource pair
@@ -476,9 +476,11 @@ bool StdCWadFile::open(const Common::String &filename) {
if (idx < 0) {
// Nope, so open up file for standard reading
assert(!name.empty());
- f.open(name);
+ if (!f.open(name))
+ return false;
SimpleFile::open(f.readStream(f.size()));
+ f.close();
return true;
}
@@ -489,7 +491,8 @@ bool StdCWadFile::open(const Common::String &filename) {
int resIndex = resStr.readInt();
// Open up the index for access
- f.open(fname);
+ if (!f.open(fname))
+ return false;
int indexSize = f.readUint32LE() / 4;
assert(resIndex < indexSize);
diff --git a/engines/titanic/support/strings.cpp b/engines/titanic/support/strings.cpp
index 7664b6849b..a8ab45800f 100644
--- a/engines/titanic/support/strings.cpp
+++ b/engines/titanic/support/strings.cpp
@@ -25,7 +25,7 @@
namespace Titanic {
-Strings::Strings() {
+void Strings::load() {
Common::SeekableReadStream *r = g_vm->_filesManager->getResource("TEXT/STRINGS");
while (r->pos() < r->size())
push_back(readStringFromStream(r));
diff --git a/engines/titanic/support/strings.h b/engines/titanic/support/strings.h
index 5164897522..30aad89697 100644
--- a/engines/titanic/support/strings.h
+++ b/engines/titanic/support/strings.h
@@ -87,6 +87,57 @@ enum StringId {
BOWL_OF_NUTS,
NOT_A_BOWL_OF_NUTS,
+ CANT_SUMMON_DOORBOT,
+ CANT_SUMMON_BELLBOT,
+ NO_ONE_TO_TALK_TO,
+ TALKING_TO,
+ DOORBOT_NAME,
+ DESKBOT_NAME,
+ LIFTBOT_NAME,
+ PARROT_NAME,
+ BARBOT_NAME,
+ CHATTERBOT_NAME,
+ BELLBOT_NAME,
+ MAITRED_NAME,
+ SUCCUBUS_NAME,
+ UNKNOWN_NAME,
+ ARM_ALREADY_HOLDING,
+ YOU_CANT_GET_THIS,
+ DOESNT_DO_ANYTHING,
+ DOESNT_WANT_THIS,
+ DOES_NOT_REACH,
+ CHICKEN_ALREADY_CLEAN,
+ HOSE_INCOMPATIBLE,
+ INCORRECTLY_CALIBRATED,
+ GONDOLIERS_FIRST_CLASS_ONLY,
+ NOTHING_ON_CHANNEL,
+ TELEVISION_CONTROL,
+ OPERATE_ENTERTAINMENT,
+ OPERATE_LIGHTS,
+ DEPLOY_FLORAL_ENHANCEMENT,
+ DEPLOY_FULLY_RELAXATION,
+ DEPLOY_COMFORT_WORKSTATION,
+ DEPLOY_MINOR_STORAGE,
+ DEPLOY_MAJOR_RELAXATION,
+ INFLATE_RELAXATION_DEVICE,
+ DEPLOY_MAINTENANCE_HUB,
+ DEPLOY_EXECUTIVE_SURFACE,
+ DEPLOY_MINOR_RELAXATION,
+ DEPLOY_SINK,
+ DEPLOY_MAJOR_STORAGE,
+ SUCCUBUS_DELIVERY_SYSTEM,
+ NAVIGATION_CONTROLLER,
+ SUMMON_ELEVATOR,
+ SUMMON_PELLERATOR,
+ GO_TO_BOTTOM_OF_WELL,
+ GO_TO_TOP_OF_WELL,
+ GO_TO_STATEROOM,
+ GO_TO_BAR,
+ GO_TO_PROMENADE_DECK,
+ GO_TO_ARBORETUM,
+ GO_TO_MUSIC_ROOM,
+ GO_TO_1ST_CLASS_RESTAURANT,
+
// German version only
DE_SUMMER,
DE_AUTUMN,
@@ -139,7 +190,7 @@ enum StringId {
class Strings : public Common::StringArray {
public:
- Strings();
+ void load();
};
} // End of namespace Titanic
diff --git a/engines/titanic/support/time_event_info.cpp b/engines/titanic/support/time_event_info.cpp
index e088a8e0c2..c61ceb29ae 100644
--- a/engines/titanic/support/time_event_info.cpp
+++ b/engines/titanic/support/time_event_info.cpp
@@ -100,8 +100,8 @@ CTimeEventInfo::CTimeEventInfo() : ListItem(), _lockCounter(0),
CTimeEventInfo::CTimeEventInfo(uint ticks, bool repeated, uint firstDuration,
uint repeatDuration, CTreeItem *target, int endVal, const CString &action) :
ListItem(), _lockCounter(0), _repeated(repeated), _firstDuration(firstDuration),
- _repeatDuration(repeatDuration), _target(target), _actionVal(endVal), _done(false),
- _timerCtr(0), _lastTimerTicks(ticks), _relativeTicks(0), _persisent(true) {
+ _repeatDuration(repeatDuration), _target(target), _actionVal(endVal), _action(action),
+ _done(false), _timerCtr(0), _lastTimerTicks(ticks), _relativeTicks(0), _persisent(true) {
_id = _nextId++;
}
diff --git a/engines/titanic/support/transparency_surface.cpp b/engines/titanic/support/transparency_surface.cpp
index 5ffa8b99b1..8b5cbecc5f 100644
--- a/engines/titanic/support/transparency_surface.cpp
+++ b/engines/titanic/support/transparency_surface.cpp
@@ -46,7 +46,7 @@ CTransparencySurface::CTransparencySurface(const Graphics::Surface *surface,
_flag1 = false;
break;
case TRANS_DEFAULT:
- if (*(byte *)surface->getPixels() < 0x80) {
+ if (*(const byte *)surface->getPixels() < 0x80) {
_flag1 = true;
_flag2 = false;
}
@@ -66,8 +66,17 @@ int CTransparencySurface::moveX() {
}
uint CTransparencySurface::getPixel() const {
- const byte *pixelP = (const byte *)_surface->getBasePtr(_pos.x, _pos.y);
- return *pixelP;
+ byte pixel = *(const byte *)_surface->getBasePtr(_pos.x, _pos.y);
+ return pixel;
+}
+
+uint CTransparencySurface::getAlpha() const {
+ byte pixel = getPixel();
+ return _flag1 ? 0xFF - pixel : pixel;
+}
+
+bool CTransparencySurface::isPixelTransparent() {
+ return getAlpha() == 0xff;
}
} // End of namespace Titanic
diff --git a/engines/titanic/support/transparency_surface.h b/engines/titanic/support/transparency_surface.h
index 0391b6d5b7..1b4587a9db 100644
--- a/engines/titanic/support/transparency_surface.h
+++ b/engines/titanic/support/transparency_surface.h
@@ -42,6 +42,11 @@ private:
bool _flag;
bool _flag1;
bool _flag2;
+private:
+ /**
+ * Returns a a pixel from the transparency surface
+ */
+ uint getPixel() const;
public:
/**
* Constructor
@@ -64,19 +69,14 @@ public:
int moveX();
/**
- * Returns a byte from the transparency surface
- */
- uint getPixel() const;
-
- /**
* Returns the alpha value for the pixel (0-31)
*/
- uint getAlpha() const { return 31 - (getPixel() >> 3); }
+ uint getAlpha() const;
/**
* Returns true if the pixel is completely transparent
*/
- bool isPixelTransparent() const { return getAlpha() == 31; }
+ bool isPixelTransparent();
};
} // End of namespace Titanic
diff --git a/engines/titanic/support/video_surface.cpp b/engines/titanic/support/video_surface.cpp
index 293232860c..52610379b5 100644
--- a/engines/titanic/support/video_surface.cpp
+++ b/engines/titanic/support/video_surface.cpp
@@ -246,9 +246,7 @@ void CVideoSurface::transBlitRect(const Rect &srcRect, const Rect &destRect, CVi
transSurface.setCol(srcRect.left);
for (int srcX = srcRect.left; srcX < srcRect.right; ++srcX) {
- if (!transSurface.isPixelTransparent()) {
- copyPixel(lineDestP, lineSrcP, transSurface.getAlpha(), srcSurface->format, isAlpha);
- }
+ copyPixel(lineDestP, lineSrcP, transSurface.getAlpha() >> 3, srcSurface->format, isAlpha);
++lineSrcP;
++lineDestP;
diff --git a/engines/titanic/titanic.cpp b/engines/titanic/titanic.cpp
index 2566a36d7c..29730c36c8 100644
--- a/engines/titanic/titanic.cpp
+++ b/engines/titanic/titanic.cpp
@@ -60,6 +60,12 @@ TitanicEngine::TitanicEngine(OSystem *syst, const TitanicGameDescription *gameDe
_scriptHandler = nullptr;
_script = nullptr;
CMusicRoom::_musicHandler = nullptr;
+
+ // Set up debug channels
+ DebugMan.addDebugChannel(kDebugCore, "core", "Core engine debug level");
+ DebugMan.addDebugChannel(kDebugScripts, "scripts", "Game scripts");
+ DebugMan.addDebugChannel(kDebugGraphics, "graphics", "Graphics handling");
+ DebugMan.addDebugChannel(kDebugSound, "sound", "Sound and Music handling");
}
TitanicEngine::~TitanicEngine() {
@@ -78,12 +84,6 @@ void TitanicEngine::initializePath(const Common::FSNode &gamePath) {
}
void TitanicEngine::initialize() {
- // Set up debug channels
- DebugMan.addDebugChannel(kDebugCore, "core", "Core engine debug level");
- DebugMan.addDebugChannel(kDebugScripts, "scripts", "Game scripts");
- DebugMan.addDebugChannel(kDebugGraphics, "graphics", "Graphics handling");
- DebugMan.addDebugChannel(kDebugSound, "sound", "Sound and Music handling");
-
_debugger = new Debugger(this);
_filesManager = new CFilesManager(this);
@@ -107,6 +107,7 @@ void TitanicEngine::initialize() {
_screen = new Graphics::Screen(0, 0);
_screenManager = new OSScreenManager(this);
_window = new CMainGameWindow(this);
+ _strings.load();
setItemNames();
setRoomNames();
@@ -149,7 +150,7 @@ void TitanicEngine::setItemNames() {
r = g_vm->_filesManager->getResource("TEXT/ITEM_DESCRIPTIONS");
while (r->pos() < r->size())
- _itemNames.push_back(readStringFromStream(r));
+ _itemDescriptions.push_back(readStringFromStream(r));
delete r;
r = g_vm->_filesManager->getResource("TEXT/ITEM_IDS");
diff --git a/engines/titanic/titanic.h b/engines/titanic/titanic.h
index b0776c55a5..d8e0f880f7 100644
--- a/engines/titanic/titanic.h
+++ b/engines/titanic/titanic.h
@@ -122,6 +122,7 @@ public:
CString _itemObjects[TOTAL_ITEMS];
StringArray _itemIds;
StringArray _roomNames;
+ Strings _strings;
public:
TitanicEngine(OSystem *syst, const TitanicGameDescription *gameDesc);
virtual ~TitanicEngine();
diff --git a/engines/titanic/true_talk/barbot_script.cpp b/engines/titanic/true_talk/barbot_script.cpp
index 76f28540ea..ad10f5a57f 100644
--- a/engines/titanic/true_talk/barbot_script.cpp
+++ b/engines/titanic/true_talk/barbot_script.cpp
@@ -167,7 +167,7 @@ int BarbotScript::process(const TTroomScript *roomScript, const TTsentence *sent
dialogueId = ARRAY2[0];
_arrIndex = 1;
} else if (getRandomNumber(100) > 60) {
- switch (sentence->_field2C) {
+ switch (sentence->_category) {
case 2:
dialogueId = 51914;
break;
@@ -209,7 +209,7 @@ int BarbotScript::process(const TTroomScript *roomScript, const TTsentence *sent
int val34 = getState();
setState(0);
- int val2C = sentence->_field2C;
+ int val2C = sentence->_category;
bool flag = val2C == 11 || val2C == 13;
bool flag2 = val2C == 12;
diff --git a/engines/titanic/true_talk/bellbot_script.cpp b/engines/titanic/true_talk/bellbot_script.cpp
index 038285ec8d..c51c918a2e 100644
--- a/engines/titanic/true_talk/bellbot_script.cpp
+++ b/engines/titanic/true_talk/bellbot_script.cpp
@@ -239,11 +239,11 @@ int BellbotScript::process(const TTroomScript *roomScript, const TTsentence *sen
if (processEntries(&_entries, _entryCount, roomScript, sentence) == 2)
return 2;
- if ((sentence->_field2C == 4 && sentence->localWord("am") && sentence->localWord("i"))
+ if ((sentence->_category == 4 && sentence->localWord("am") && sentence->localWord("i"))
|| (sentence->localWord("are") && sentence->localWord("we"))
- || (sentence->_field2C == 3 && sentence->localWord("room")
+ || (sentence->_category == 3 && sentence->localWord("room")
&& sentence->localWord("we") && sentence->localWord("in"))
- || (sentence->_field2C == 3 && sentence->localWord("rom")
+ || (sentence->_category == 3 && sentence->localWord("rom")
&& sentence->localWord("is") && sentence->localWord("this"))
) {
uint id = getRangeValue(getRoomDialogueId(roomScript));
@@ -527,7 +527,7 @@ int BellbotScript::handleQuote(const TTroomScript *roomScript, const TTsentence
int BellbotScript::updateState(uint oldId, uint newId, int index) {
if (!getValue(25)) {
- newId = 202043 - getValue(1) <= 2 ? 994 : 0;
+ newId = 202043 - (getValue(1) <= 2 ? 994 : 0);
CTrueTalkManager::setFlags(25, 1);
}
@@ -795,22 +795,22 @@ int BellbotScript::preprocess(const TTroomScript *roomScript, const TTsentence *
bool applyFlag = false, stateFlag = true;
switch (getValue(23)) {
case 1:
- if (sentence->_field2C == 11 || sentence->_field2C == 13) {
+ if (sentence->_category == 11 || sentence->_category == 13) {
addResponse(getDialogueId(200818));
applyFlag = true;
}
- if (sentence->_field2C == 12) {
+ if (sentence->_category == 12) {
addResponse(getDialogueId(200817));
applyFlag = true;
}
break;
case 2:
- if (sentence->_field2C == 11 || sentence->_field2C == 13) {
+ if (sentence->_category == 11 || sentence->_category == 13) {
addResponse(getDialogueId(200835));
addResponse(getDialogueId(200830));
applyFlag = true;
- } else if (sentence->_field2C == 12) {
+ } else if (sentence->_category == 12) {
addResponse(getDialogueId(200834));
addResponse(getDialogueId(200830));
applyFlag = true;
@@ -818,7 +818,7 @@ int BellbotScript::preprocess(const TTroomScript *roomScript, const TTsentence *
break;
case 3:
- if (sentence->_field2C >= 11 && sentence->_field2C <= 13) {
+ if (sentence->_category >= 11 && sentence->_category <= 13) {
addResponse(getDialogueId(200831));
addResponse(getDialogueId(200833));
applyFlag = true;
@@ -826,36 +826,36 @@ int BellbotScript::preprocess(const TTroomScript *roomScript, const TTsentence *
break;
case 4:
- if (sentence->_field2C == 11) {
+ if (sentence->_category == 11) {
addResponse(getDialogueId(200872));
applyFlag = true;
}
- if (sentence->_field2C == 12 || sentence->_field2C == 13) {
+ if (sentence->_category == 12 || sentence->_category == 13) {
addResponse(getDialogueId(200873));
applyFlag = true;
}
break;
case 5:
- if (sentence->_field2C == 11 || sentence->_field2C == 13) {
+ if (sentence->_category == 11 || sentence->_category == 13) {
addResponse(getDialogueId(200492));
applyFlag = true;
}
- if (sentence->_field2C == 12) {
+ if (sentence->_category == 12) {
addResponse(getDialogueId(200491));
applyFlag = true;
}
break;
case 6:
- if (sentence->_field2C == 11 || sentence->_field2C == 13) {
+ if (sentence->_category == 11 || sentence->_category == 13) {
addResponse(getDialogueId(200496));
applyResponse();
setState(0);
CTrueTalkManager::setFlags(23, 7);
return 2;
}
- if (sentence->_field2C == 12) {
+ if (sentence->_category == 12) {
addResponse(getDialogueId(200127));
applyFlag = true;
}
@@ -880,7 +880,7 @@ int BellbotScript::preprocess(const TTroomScript *roomScript, const TTsentence *
break;
case 10:
- if (sentence->_field2C == 11 || sentence->_field2C == 13) {
+ if (sentence->_category == 11 || sentence->_category == 13) {
addResponse(getDialogueId(200317));
applyResponse();
setState(0);
@@ -888,14 +888,14 @@ int BellbotScript::preprocess(const TTroomScript *roomScript, const TTsentence *
return 2;
}
- addResponse(getDialogueId(sentence->_field2C == 12 ? 200316 : 200315));
+ addResponse(getDialogueId(sentence->_category == 12 ? 200316 : 200315));
applyFlag = true;
break;
case 11:
- if (sentence->_field2C == 11 || sentence->_field2C == 13) {
+ if (sentence->_category == 11 || sentence->_category == 13) {
addResponse(getDialogueId(200055));
- } else if (sentence->_field2C == 12) {
+ } else if (sentence->_category == 12) {
addResponse(getDialogueId(200318));
} else {
addResponse(getDialogueId(200315));
@@ -905,30 +905,30 @@ int BellbotScript::preprocess(const TTroomScript *roomScript, const TTsentence *
break;
case 12:
- if (sentence->_field2C == 6) {
+ if (sentence->_category == 6) {
addResponse(getDialogueId(200259));
applyFlag = true;
}
break;
case 13:
- if (sentence->_field2C == 11 || sentence->_field2C == 13) {
+ if (sentence->_category == 11 || sentence->_category == 13) {
addResponse(getDialogueId(200207));
applyFlag = true;
- } else if (sentence->_field2C == 12) {
+ } else if (sentence->_category == 12) {
addResponse(getDialogueId(200206));
applyFlag = true;
}
break;
case 14:
- if (sentence->_field2C == 6) {
+ if (sentence->_category == 6) {
addResponse(getDialogueId(200349));
applyFlag = true;
}
case 15:
- if (sentence->_field2C == 6) {
+ if (sentence->_category == 6) {
addResponse(getDialogueId(200130));
applyResponse();
setState(0);
@@ -945,7 +945,7 @@ int BellbotScript::preprocess(const TTroomScript *roomScript, const TTsentence *
break;
case 17:
- if ((sentence->_field2C == 3 && sentence->localWord("code"))
+ if ((sentence->_category == 3 && sentence->localWord("code"))
|| (sentence->localWord("which") && sentence->localWord("is"))
|| sentence->localWord("remember")
|| sentence->localWord("know")
@@ -957,7 +957,7 @@ int BellbotScript::preprocess(const TTroomScript *roomScript, const TTsentence *
break;
case 19:
- if (sentence->_field2C == 11 || sentence->_field2C == 13) {
+ if (sentence->_category == 11 || sentence->_category == 13) {
addResponse(getDialogueId(200223));
applyFlag = true;
}
@@ -1042,12 +1042,12 @@ int BellbotScript::preprocess(const TTroomScript *roomScript, const TTsentence *
break;
case 31:
- addResponse(getDialogueId(sentence->_field2C == 11 ? 200810 : 200811));
+ addResponse(getDialogueId(sentence->_category == 11 ? 200810 : 200811));
applyFlag = true;
break;
case 32:
- addResponse(getDialogueId(sentence->_field2C == 11 ? 200810 : 200812));
+ addResponse(getDialogueId(sentence->_category == 11 ? 200810 : 200812));
applyFlag = true;
break;
@@ -1062,7 +1062,7 @@ int BellbotScript::preprocess(const TTroomScript *roomScript, const TTsentence *
break;
case 35:
- if (sentence->_field2C == 3 && sentence->localWord("it")
+ if (sentence->_category == 3 && sentence->localWord("it")
&& (sentence->localWord("for") || sentence->localWord("do"))) {
addResponse(getDialogueId(200768));
applyFlag = true;
@@ -1070,7 +1070,7 @@ int BellbotScript::preprocess(const TTroomScript *roomScript, const TTsentence *
break;
case 36:
- if (sentence->_field2C == 11) {
+ if (sentence->_category == 11) {
CTrueTalkManager::triggerAction(14, 0);
addResponse(getDialogueId(200761));
applyFlag = true;
@@ -1083,14 +1083,14 @@ int BellbotScript::preprocess(const TTroomScript *roomScript, const TTsentence *
break;
case 38:
- if (sentence->_field2C == 12) {
+ if (sentence->_category == 12) {
addResponse(getDialogueId(200631));
applyFlag = true;
}
break;
case 39:
- if (sentence->_field2C == 11 || sentence->_field2C == 13) {
+ if (sentence->_category == 11 || sentence->_category == 13) {
addResponse(getDialogueId(200632));
stateFlag = false;
} else {
@@ -1124,7 +1124,7 @@ int BellbotScript::preprocess(const TTroomScript *roomScript, const TTsentence *
break;
case 43:
- if (sentence->_field2C == 11 || sentence->_field2C == 13) {
+ if (sentence->_category == 11 || sentence->_category == 13) {
addResponse(getDialogueId(200643));
applyFlag = true;
}
@@ -1157,7 +1157,7 @@ case44:
goto case44;
case 47:
- if (sentence->_field2C == 12)
+ if (sentence->_category == 12)
addResponse(getDialogueId(200368));
addResponse(getDialogueId(200366));
applyFlag = true;
@@ -1177,7 +1177,7 @@ case44:
break;
case 49:
- if (sentence->_field2C >= 11 && sentence->_field2C <= 13) {
+ if (sentence->_category >= 11 && sentence->_category <= 13) {
addResponse(getDialogueId(200407));
applyFlag = true;
stateFlag = false;
@@ -1185,7 +1185,7 @@ case44:
break;
case 50:
- if (sentence->_field2C == 11 || sentence->_field2C == 13) {
+ if (sentence->_category == 11 || sentence->_category == 13) {
addResponse(getDialogueId(200408));
stateFlag = false;
} else {
@@ -1204,24 +1204,24 @@ case44:
break;
case 52:
- if (sentence->_field2C >= 11 && sentence->_field2C <= 13) {
+ if (sentence->_category >= 11 && sentence->_category <= 13) {
addResponse(getDialogueId(200872));
applyFlag = true;
}
break;
case 53:
- if (sentence->_field2C == 12) {
+ if (sentence->_category == 12) {
addResponse(getDialogueId(200525));
applyFlag = true;
- } else if (sentence->_field2C == 11 || sentence->_field2C == 13) {
+ } else if (sentence->_category == 11 || sentence->_category == 13) {
addResponse(getDialogueId(200526));
applyFlag = true;
}
break;
case 54:
- if (sentence->_field2C == 12) {
+ if (sentence->_category == 12) {
addResponse(getDialogueId(200095));
applyFlag = true;
stateFlag = false;
@@ -1229,7 +1229,7 @@ case44:
break;
case 55:
- if (sentence->_field2C == 6) {
+ if (sentence->_category == 6) {
addResponse(getDialogueId(200112));
applyFlag = true;
}
@@ -1258,7 +1258,7 @@ case44:
case 58:
if (sentence->localWord("more")
|| (sentence->localWord("go") && sentence->localWord("on"))
- || (sentence->_field2C == 11 && sentence->localWord("really"))) {
+ || (sentence->_category == 11 && sentence->localWord("really"))) {
addResponse(getDialogueId(200650));
applyFlag = true;
stateFlag = false;
@@ -1274,7 +1274,7 @@ case44:
break;
case 60:
- if (sentence->_field2C == 3 && sentence->localWord("they") && sentence->localWord("do")) {
+ if (sentence->_category == 3 && sentence->localWord("they") && sentence->localWord("do")) {
addResponse(getDialogueId(200652));
applyFlag = true;
stateFlag = false;
@@ -1351,7 +1351,7 @@ stateFlag = false;
break;
case 70:
- if (sentence->_field2C == 12) {
+ if (sentence->_category == 12) {
addResponse(getDialogueId(201012));
applyFlag = true;
stateFlag = false;
@@ -1366,10 +1366,10 @@ stateFlag = false;
break;
case 72:
- if (sentence->_field2C == 12) {
+ if (sentence->_category == 12) {
addResponse(getDialogueId(200921));
applyFlag = true;
- } else if (sentence->_field2C == 11 || sentence->_field2C == 13) {
+ } else if (sentence->_category == 11 || sentence->_category == 13) {
addResponse(getDialogueId(200920));
applyFlag = true;
}
@@ -1384,7 +1384,7 @@ stateFlag = false;
break;
case 74:
- if (sentence->_field2C == 6) {
+ if (sentence->_category == 6) {
addResponse(getDialogueId(201022));
applyFlag = true;
stateFlag = false;
@@ -1392,7 +1392,7 @@ stateFlag = false;
break;
case 75:
- if (sentence->_field2C == 3) {
+ if (sentence->_category == 3) {
if (sentence->localWord("that") || sentence->localWord("worb")) {
addResponse(getDialogueId(201802));
applyFlag = true;
@@ -1401,7 +1401,7 @@ stateFlag = false;
break;
case 76:
- if (sentence->_field2C == 2 && (sentence->localWord("that") || sentence->localWord("gat"))) {
+ if (sentence->_category == 2 && (sentence->localWord("that") || sentence->localWord("gat"))) {
addResponse(getDialogueId(201034));
applyFlag = true;
stateFlag = false;
@@ -1409,7 +1409,7 @@ stateFlag = false;
break;
case 77:
- if (sentence->_field2C == 4 || sentence->_field2C == 3) {
+ if (sentence->_category == 4 || sentence->_category == 3) {
if (sentence->localWord("that") || sentence->localWord("blerontis")) {
addResponse(getDialogueId(201035));
applyFlag = true;
@@ -1418,11 +1418,11 @@ stateFlag = false;
break;
case 78:
- if (sentence->_field2C == 12) {
+ if (sentence->_category == 12) {
addResponse(getDialogueId(201034));
applyFlag = true;
stateFlag = false;
- } else if (sentence->_field2C == 11) {
+ } else if (sentence->_category == 11) {
addResponse(getDialogueId(201040));
applyFlag = true;
} else if ((sentence->localWord("not") && sentence->localWord("remember"))
@@ -1438,12 +1438,12 @@ stateFlag = false;
break;
case 79:
- if (sentence->_field2C == 11 || sentence->_field2C == 13) {
+ if (sentence->_category == 11 || sentence->_category == 13) {
addResponse(getDialogueId(201052));
CTrueTalkManager::triggerAction(14, 0);
applyFlag = true;
stateFlag = false;
- } else if (sentence->_field2C == 12) {
+ } else if (sentence->_category == 12) {
addResponse(getDialogueId(202119));
addResponse(getDialogueId(200256));
applyFlag = true;
@@ -1454,7 +1454,7 @@ stateFlag = false;
if ((!sentence->localWord("what") && sentence->localWord("how"))
|| sentence->localWord("about")
|| sentence->localWord("you")) {
- if (sentence->_field2C != 3 && sentence->_field2C != 4 && sentence->_field2C != 7) {
+ if (sentence->_category != 3 && sentence->_category != 4 && sentence->_category != 7) {
addResponse(getDialogueId(201694));
applyFlag = true;
stateFlag = false;
@@ -1477,7 +1477,7 @@ stateFlag = false;
break;
case 82:
- if ((sentence->_field2C == 3 && sentence->localWord("mean"))
+ if ((sentence->_category == 3 && sentence->localWord("mean"))
|| sentence->localWord("surf")
|| (sentence->localWord("what") && sentence->localWord("talk")
&& sentence->localWord("about"))) {
@@ -1488,14 +1488,14 @@ stateFlag = false;
break;
case 83:
- if (sentence->_field2C != 3 && sentence->_field2C != 4 && sentence->_field2C != 7) {
+ if (sentence->_category != 3 && sentence->_category != 4 && sentence->_category != 7) {
addResponse(getDialogueId(201083));
applyFlag = true;
}
break;
case 84:
- if (sentence->_field2C == 12) {
+ if (sentence->_category == 12) {
addResponse(getDialogueId(202119));
switch (getValue(1)) {
@@ -1511,7 +1511,7 @@ stateFlag = false;
default:
break;
}
- } else if (sentence->_field2C == 11) {
+ } else if (sentence->_category == 11) {
addResponse(getDialogueId(201060));
addResponse(getDialogueId(201079));
applyFlag = true;
@@ -1520,22 +1520,22 @@ stateFlag = false;
break;
case 85:
- if (sentence->_field2C == 11 || sentence->_field2C == 13) {
+ if (sentence->_category == 11 || sentence->_category == 13) {
addResponse(getDialogueId(201814));
applyFlag = true;
}
- if (sentence->_field2C == 12) {
+ if (sentence->_category == 12) {
addResponse(getDialogueId(201813));
applyFlag = true;
}
break;
case 86:
- if (sentence->_field2C == 11 || sentence->_field2C == 13) {
+ if (sentence->_category == 11 || sentence->_category == 13) {
addResponse(getDialogueId(202109));
applyFlag = true;
}
- if (sentence->_field2C == 12) {
+ if (sentence->_category == 12) {
addResponse(getDialogueId(202108));
applyFlag = true;
}
@@ -1548,14 +1548,14 @@ stateFlag = false;
break;
case 88:
- if (sentence->_field2C == 6 || sentence->contains("upside down")) {
+ if (sentence->_category == 6 || sentence->contains("upside down")) {
addResponse(getDialogueId(202142));
applyFlag = true;
}
break;
case 89:
- if (sentence->_field2C == 2) {
+ if (sentence->_category == 2) {
addResponse(getDialogueId(200739));
applyFlag = true;
stateFlag = false;
@@ -1710,7 +1710,7 @@ bool BellbotScript::checkCommonWords(const TTroomScript *roomScript, const TTsen
if (!roomScript || !sentence)
return 0;
CTrueTalkManager::setFlags(23, 0);
- if (sentence->_field2C != 4)
+ if (sentence->_category != 4)
return 0;
if (sentence->localWord("garage")) {
diff --git a/engines/titanic/true_talk/deskbot_script.cpp b/engines/titanic/true_talk/deskbot_script.cpp
index 4df47e0af1..d38d53a296 100644
--- a/engines/titanic/true_talk/deskbot_script.cpp
+++ b/engines/titanic/true_talk/deskbot_script.cpp
@@ -29,6 +29,8 @@ namespace Titanic {
int DeskbotScript::_oldId;
+#define CURRENT_STATE 17
+
DeskbotScript::DeskbotScript(int val1, const char *charClass, int v2,
const char *charName, int v3, int val2) :
TTnpcScript(val1, charClass, v2, charName, v3, val2, -1, -1, -1, 0) {
@@ -73,7 +75,7 @@ int DeskbotScript::process(const TTroomScript *roomScript, const TTsentence *sen
if (preprocess(roomScript, sentence) != 1)
return 1;
- CTrueTalkManager::setFlags(17, 0);
+ CTrueTalkManager::setFlags(CURRENT_STATE, 0);
setState(0);
updateCurrentDial(false);
@@ -344,7 +346,7 @@ int DeskbotScript::updateState(uint oldId, uint newId, int index) {
exit:
_oldId = oldId;
- setFlags17(newId, index);
+ setCurrentState(newId, index);
return newId;
}
@@ -509,8 +511,8 @@ uint DeskbotScript::getStateDialogueId() const {
}
}
-void DeskbotScript::setFlags17(uint newId, uint index) {
- int newValue = getValue(17);
+void DeskbotScript::setCurrentState(uint newId, uint index) {
+ int newValue = getValue(CURRENT_STATE);
for (uint idx = 0; idx < _states.size(); ++idx) {
const TTupdateState &us = _states[idx];
@@ -528,7 +530,7 @@ void DeskbotScript::setFlags17(uint newId, uint index) {
}
}
- CTrueTalkManager::setFlags(17, newValue);
+ CTrueTalkManager::setFlags(CURRENT_STATE, newValue);
}
int DeskbotScript::preprocess(const TTroomScript *roomScript, const TTsentence *sentence) {
@@ -536,11 +538,11 @@ int DeskbotScript::preprocess(const TTroomScript *roomScript, const TTsentence *
return 1;
bool stateFlag = true, applyFlag = false;
- switch (getValue(17)) {
+ switch (getValue(CURRENT_STATE)) {
case 1:
- if (sentence->_field2C != 3 && sentence->_field2C != 4
- && sentence->_field2C != 6 && sentence->_field2C != 10
- && sentence->_field2C != 2) {
+ if (sentence->_category != 3 && sentence->_category != 4
+ && sentence->_category != 6 && sentence->_category != 10
+ && sentence->_category != 2) {
addResponse(getDialogueId(240423));
applyFlag = true;
}
@@ -554,15 +556,15 @@ int DeskbotScript::preprocess(const TTroomScript *roomScript, const TTsentence *
break;
case 3:
- if (sentence->_field2C == 11 || sentence->_field2C == 13
- || sentence->_field2C == 3 || sentence->localWord("upgrade")) {
+ if (sentence->_category == 11 || sentence->_category == 13
+ || sentence->_category == 3 || sentence->localWord("upgrade")) {
addResponse(getDialogueId(240433));
applyFlag = true;
}
break;
case 4:
- addResponse(getDialogueId(sentence->_field2C == 11 || sentence->_field2C == 13
+ addResponse(getDialogueId(sentence->_category == 11 || sentence->_category == 13
? 240495 : 240494));
applyFlag = true;
break;
@@ -594,7 +596,7 @@ int DeskbotScript::preprocess(const TTroomScript *roomScript, const TTsentence *
stateFlag = true;
} else if (sentence->localWord("name")
|| sentence->localWord("called")
- || sentence->_field2C == 11) {
+ || sentence->_category == 11) {
addResponse(getDialogueId(240448));
stateFlag = true;
} else {
@@ -605,7 +607,7 @@ int DeskbotScript::preprocess(const TTroomScript *roomScript, const TTsentence *
break;
case 7:
- if (sentence->_field2C == 11 || sentence->_field2C == 13
+ if (sentence->_category == 11 || sentence->_category == 13
|| (sentence->localWord("what") && sentence->localWord("wrong"))
|| sentence->localWord("clothes")) {
addResponse(getDialogueId(240489));
@@ -616,7 +618,7 @@ int DeskbotScript::preprocess(const TTroomScript *roomScript, const TTsentence *
case 8:
if (isDial1Low() && getValue(1) == 4) {
- if (sentence->_field2C == 12 || sentence->_field2C == 13
+ if (sentence->_category == 12 || sentence->_category == 13
|| sentence->contains("do not")) {
addResponse(getDialogueId(240447));
@@ -626,7 +628,7 @@ int DeskbotScript::preprocess(const TTroomScript *roomScript, const TTsentence *
CTrueTalkManager::triggerAction(19, 3);
CTrueTalkManager::setFlags(22, 1);
applyFlag = true;
- } else if (sentence->_field2C == 11) {
+ } else if (sentence->_category == 11) {
addResponse(getDialogueId(240746));
applyFlag = true;
stateFlag = false;
@@ -1089,7 +1091,7 @@ int DeskbotScript::preprocess(const TTroomScript *roomScript, const TTsentence *
case 74:
case 75:
- if (sentence->_field2C == 24) {
+ if (sentence->_category == 24) {
addResponse(getDialogueId(240972));
applyFlag = true;
} else if (sentence->localWord("good") || sentence->localWord("yes")
@@ -1101,7 +1103,7 @@ int DeskbotScript::preprocess(const TTroomScript *roomScript, const TTsentence *
break;
case 76:
- if (sentence->_field2C == 6) {
+ if (sentence->_category == 6) {
addResponse(getDialogueId(240767));
applyFlag = true;
stateFlag = false;
@@ -1109,21 +1111,25 @@ int DeskbotScript::preprocess(const TTroomScript *roomScript, const TTsentence *
break;
case 77:
- if (sentence->_field2C == 3) {
+ if (sentence->_category == 3) {
addResponse(getDialogueId(241109));
applyFlag = true;
stateFlag = false;
}
case 78:
- if (sentence->_field2C == 11 || sentence->_field2C == 13) {
+ // "Do you have a reservation?"
+ if (sentence->_category == 11 || sentence->_category == 13) {
+ // Player said they have a reservation
addResponse(getDialogueId(241262));
- } else if (sentence->_field2C == 12 || sentence->contains("do not")) {
+ } else if (sentence->_category == 12 || sentence->contains("do not")) {
+ // Player said they don't have a reservation
setDialRegion(0, 0);
setDialRegion(1, 0);
addResponse(getDialogueId(241268));
- add241716();
+ addAskBreakfast();
} else {
+ // Player didn't say yes or no
addResponse(getDialogueId(240745));
}
@@ -1142,27 +1148,27 @@ int DeskbotScript::preprocess(const TTroomScript *roomScript, const TTsentence *
case 3:
addAssignedRoom();
setState(0);
- CTrueTalkManager::setFlags(17, 0);
+ CTrueTalkManager::setFlags(CURRENT_STATE, 0);
return 2;
default:
addResponse(getDialogueId(241267));
break;
}
- add241716();
+ addAskBreakfast();
applyFlag = true;
stateFlag = false;
break;
case 81:
- addResponse(getDialogueId(sentence->_field2C == 12 ? 240602 : 241337));
+ addResponse(getDialogueId(sentence->_category == 12 ? 240602 : 241337));
applyResponse();
setState(0);
- CTrueTalkManager::setFlags(17, 0);
+ CTrueTalkManager::setFlags(CURRENT_STATE, 0);
return 2;
case 82:
- if (sentence->_field2C == 2) {
+ if (sentence->_category == 2) {
addResponse(getDialogueId(241339));
applyFlag = true;
}
@@ -1181,7 +1187,7 @@ int DeskbotScript::preprocess(const TTroomScript *roomScript, const TTsentence *
break;
case 84:
- if (sentence->_field2C == 12 || sentence->contains("vegetarian")
+ if (sentence->_category == 12 || sentence->contains("vegetarian")
|| sentence->contains("vegitarian")) {
addResponse(getDialogueId(241718));
addResponse(getDialogueId(241709));
@@ -1208,7 +1214,7 @@ int DeskbotScript::preprocess(const TTroomScript *roomScript, const TTsentence *
break;
case 85:
- if (sentence->_field2C == 12 || sentence->contains("bugle")
+ if (sentence->_category == 12 || sentence->contains("bugle")
|| sentence->contains("buggle") || sentence->contains("trumpet")
|| sentence->contains("saxophone") || sentence->contains("kazoo")
|| sentence->contains("blerontin 1") || sentence->contains("the 1")
@@ -1229,7 +1235,7 @@ int DeskbotScript::preprocess(const TTroomScript *roomScript, const TTsentence *
break;
case 86:
- if (sentence->_field2C == 12 || sentence->_field2C == 11 || sentence->contains("view")) {
+ if (sentence->_category == 12 || sentence->_category == 11 || sentence->contains("view")) {
addResponse(getDialogueId(241714));
addResponse(getDialogueId(241699));
} else {
@@ -1352,19 +1358,25 @@ int DeskbotScript::preprocess(const TTroomScript *roomScript, const TTsentence *
case 92:
case 93:
- if (sentence->_field2C == 11 || sentence->_field2C == 13) {
+ // "Fish?"
+ if (sentence->_category == 11 || sentence->_category == 13) {
+ // Yes
addResponse(getDialogueId(241077));
addResponse(getDialogueId(241706));
- } else if (sentence->_field2C == 12) {
+ } else if (sentence->_category == 12) {
+ // No
addAssignedRoom();
setState(0);
- CTrueTalkManager::setFlags(17, 0);
+ CTrueTalkManager::setFlags(CURRENT_STATE, 0);
return 2;
- } else if (g_vm->_trueTalkManager->_quotes.find(sentence->_normalizedLine.c_str())
+ } else if (g_vm->_trueTalkManager->_quotes.find(sentence->_initialLine.c_str())
== MKTAG('F', 'I', 'S', 'H')) {
+ // WORKAROUND: Original passed _normalizedLine, but "fish" is one of the common
+ // phrases replaced with with alternative text "completelyrandom"
addResponse(getDialogueId(240877));
addResponse(getDialogueId(241706));
}else {
+ // All other responses
if (getRandomNumber(100) < 80 && sentence2C(sentence))
addResponse(getDialogueId(241707));
@@ -1387,7 +1399,7 @@ int DeskbotScript::preprocess(const TTroomScript *roomScript, const TTsentence *
|| sentence->contains("same room")) {
addAssignedRoom();
setState(0);
- CTrueTalkManager::setFlags(17, 0);
+ CTrueTalkManager::setFlags(CURRENT_STATE, 0);
return 2;
} else {
if (getRandomNumber(100) < 80 && sentence2C(sentence))
@@ -1410,7 +1422,7 @@ int DeskbotScript::preprocess(const TTroomScript *roomScript, const TTsentence *
break;
case 96:
- if (sentence->_field2C == 2) {
+ if (sentence->_category == 2) {
addResponse(getDialogueId(241350));
applyFlag = true;
stateFlag = false;
@@ -1433,7 +1445,7 @@ int DeskbotScript::preprocess(const TTroomScript *roomScript, const TTsentence *
applyResponse();
if (stateFlag) {
setState(0);
- CTrueTalkManager::setFlags(17, 0);
+ CTrueTalkManager::setFlags(CURRENT_STATE, 0);
}
return applyFlag ? 2 : 1;
@@ -1480,7 +1492,7 @@ int DeskbotScript::checkCommonWords(const TTsentence *sentence) {
return 0;
}
-void DeskbotScript::add241716() {
+void DeskbotScript::addAskBreakfast() {
addResponse(getDialogueId(241716));
}
@@ -1497,6 +1509,7 @@ void DeskbotScript::addAssignedRoom() {
addResponse(getDialogueId(241271 + floorNum));
addResponse(getDialogueId(241317 + roomNum));
addResponse(getDialogueId(241698));
+ applyResponse();
}
} // End of namespace Titanic
diff --git a/engines/titanic/true_talk/deskbot_script.h b/engines/titanic/true_talk/deskbot_script.h
index f5978553ce..ffb6b1063c 100644
--- a/engines/titanic/true_talk/deskbot_script.h
+++ b/engines/titanic/true_talk/deskbot_script.h
@@ -61,9 +61,9 @@ private:
uint getStateDialogueId() const;
/**
- * Sets state data in flags 17
+ * Sets the current state for what the Deskbot is doing/asking
*/
- void setFlags17(uint newId, uint index);
+ void setCurrentState(uint newId, uint index);
/**
* Does preprocessing for the sentence
@@ -81,9 +81,9 @@ private:
int checkCommonWords(const TTsentence *sentence);
/**
- * Adds response dialogue 241716
+ * Adds a dialogue for asking the player what kind of breakfast they'd like
*/
- void add241716();
+ void addAskBreakfast();
/**
* Adds a dialogue description for the player's assigned room
diff --git a/engines/titanic/true_talk/doorbot_script.cpp b/engines/titanic/true_talk/doorbot_script.cpp
index 5c7403f187..b1d6a91107 100644
--- a/engines/titanic/true_talk/doorbot_script.cpp
+++ b/engines/titanic/true_talk/doorbot_script.cpp
@@ -196,13 +196,13 @@ int DoorbotScript::process(const TTroomScript *roomScript, const TTsentence *sen
return setResponse(getDialogueId(220113));
}
- if (sentence->_field2C == 6 && sentence->contains("why not")) {
+ if (sentence->_category == 6 && sentence->contains("why not")) {
return setResponse(11871, 8);
}
currState = getState();
if (currState) {
- int sentMode = sentence->_field2C;
+ int sentMode = sentence->_category;
bool flag1 = sentMode == 11 || sentMode == 13;
bool flag2 = sentMode == 12;
@@ -475,7 +475,7 @@ int DoorbotScript::process(const TTroomScript *roomScript, const TTsentence *sen
|| defaultProcess(roomScript, sentence))
return 2;
- switch (sentence->_field2C) {
+ switch (sentence->_category) {
case 11:
if (getRandomNumber(100) > 90)
return setResponse(10839, 42);
diff --git a/engines/titanic/true_talk/liftbot_script.cpp b/engines/titanic/true_talk/liftbot_script.cpp
index ab995b71b9..e52e47d99d 100644
--- a/engines/titanic/true_talk/liftbot_script.cpp
+++ b/engines/titanic/true_talk/liftbot_script.cpp
@@ -92,7 +92,7 @@ int LiftbotScript::process(const TTroomScript *roomScript, const TTsentence *sen
checkItems(roomScript, sentence);
int currState = getState();
- int sentMode = sentence->_field2C;
+ int sentMode = sentence->_category;
TTtreeResult treeResult;
if (currState) {
@@ -180,6 +180,7 @@ ScriptChangedResult LiftbotScript::scriptChanged(const TTroomScript *roomScript,
addResponse(getDialogueId(210033));
}
CTrueTalkManager::setFlags(27, 1);
+ applyResponse();
break;
case 155:
@@ -580,14 +581,14 @@ int LiftbotScript::sentence1(const TTsentence *sentence) {
return 1;
}
- int classNum = 1;
+ PassengerClass classNum = FIRST_CLASS;
bool classSet = true;
if (sentence->localWord("firstclass"))
- classNum = 1;
+ classNum = FIRST_CLASS;
else if (sentence->localWord("secondclass"))
- classNum = 2;
+ classNum = SECOND_CLASS;
else if (sentence->localWord("thirdclass"))
- classNum = 3;
+ classNum = THIRD_CLASS;
else
classSet = false;
@@ -650,7 +651,7 @@ int LiftbotScript::sentence1(const TTsentence *sentence) {
return 1;
}
- if (sentence->_field2C == 4 || sentence->localWord("find")
+ if (sentence->_category == 4 || sentence->localWord("find")
|| sentence->contains("get to")) {
if (getCurrentFloor() != diff) {
selectResponse(diff == 1 ? 210769 : 210764);
diff --git a/engines/titanic/true_talk/maitred_script.cpp b/engines/titanic/true_talk/maitred_script.cpp
index e902169ed0..cb1a3a5460 100644
--- a/engines/titanic/true_talk/maitred_script.cpp
+++ b/engines/titanic/true_talk/maitred_script.cpp
@@ -726,7 +726,7 @@ int MaitreDScript::preprocess(const TTroomScript *roomScript, const TTsentence *
break;
case 7:
- if (sentence->_field2C == 12) {
+ if (sentence->_category == 12) {
addResponse(getDialogueId(260089));
applyFlag = true;
stateFlag = false;
@@ -738,7 +738,7 @@ int MaitreDScript::preprocess(const TTroomScript *roomScript, const TTsentence *
break;
case 8:
- if (sentence->_field2C == 11 || sentence->_field2C == 13) {
+ if (sentence->_category == 11 || sentence->_category == 13) {
trigger12(false);
addResponse(getDialogueId(260094));
CTrueTalkManager::setFlags(11, 1);
@@ -819,7 +819,7 @@ int MaitreDScript::preprocess(const TTroomScript *roomScript, const TTsentence *
break;
case 16:
- addResponse(getDialogueId(sentence->_field2C == 11 ? 260209 : 260210));
+ addResponse(getDialogueId(sentence->_category == 11 ? 260209 : 260210));
applyFlag = true;
stateFlag = false;
break;
@@ -843,13 +843,13 @@ int MaitreDScript::preprocess(const TTroomScript *roomScript, const TTsentence *
break;
case 18:
- if (sentence->_field2C == 11) {
+ if (sentence->_category == 11) {
addResponse(getDialogueId(260232));
applyFlag = true;
- } else if (sentence->_field2C == 12) {
+ } else if (sentence->_category == 12) {
addResponse(getDialogueId(260231));
applyFlag = true;
- } else if (sentence->_field2C == 13) {
+ } else if (sentence->_category == 13) {
addResponse(getDialogueId(260444));
addResponse(getDialogueId(260233));
applyFlag = true;
@@ -937,7 +937,7 @@ int MaitreDScript::preprocess(const TTroomScript *roomScript, const TTsentence *
break;
case 23:
- if (sentence->_field2C == 11) {
+ if (sentence->_category == 11) {
addResponse(getDialogueId(260237));
applyFlag = true;
stateFlag = false;
@@ -992,7 +992,7 @@ int MaitreDScript::preprocess(const TTroomScript *roomScript, const TTsentence *
addResponse(getDialogueId(260256));
applyFlag = true;
stateFlag = false;
- } else if (sentence->_field2C == 12) {
+ } else if (sentence->_category == 12) {
addResponse(getDialogueId(260255));
applyFlag = true;
stateFlag = false;
@@ -1024,7 +1024,7 @@ int MaitreDScript::preprocess(const TTroomScript *roomScript, const TTsentence *
break;
case 29:
- if (sentence->_field2C == 11) {
+ if (sentence->_category == 11) {
setFlags12();
addResponse(getDialogueId(260131));
} else {
@@ -1034,10 +1034,10 @@ int MaitreDScript::preprocess(const TTroomScript *roomScript, const TTsentence *
break;
case 30:
- if (sentence->_field2C == 11 || sentence->_field2C == 13) {
+ if (sentence->_category == 11 || sentence->_category == 13) {
addResponse(getDialogueId(260695));
applyFlag = true;
- } else if (sentence->_field2C == 12) {
+ } else if (sentence->_category == 12) {
addResponse(getDialogueId(260696));
applyFlag = true;
}
diff --git a/engines/titanic/true_talk/parrot_script.cpp b/engines/titanic/true_talk/parrot_script.cpp
index b09e74505c..25b54f0715 100644
--- a/engines/titanic/true_talk/parrot_script.cpp
+++ b/engines/titanic/true_talk/parrot_script.cpp
@@ -55,7 +55,7 @@ int ParrotScript::process(const TTroomScript *roomScript, const TTsentence *sent
if (processEntries(roomScript, sentence) == 2) {
int tagId = g_vm->_trueTalkManager->_quotes.find(sentence->_normalizedLine);
if (!tagId || chooseResponse(roomScript, sentence, tagId) != 2) {
- addResponse(getDialogueId(sentence->check2C() ? 280248 : 280235));
+ addResponse(getDialogueId(sentence->checkCategory() ? 280248 : 280235));
applyResponse();
}
}
diff --git a/engines/titanic/true_talk/script_support.cpp b/engines/titanic/true_talk/script_support.cpp
index 14560e2d9f..52676139f0 100644
--- a/engines/titanic/true_talk/script_support.cpp
+++ b/engines/titanic/true_talk/script_support.cpp
@@ -38,7 +38,7 @@ int TTnpcScriptResponse::size() const {
TTscriptRange::TTscriptRange(uint id, const Common::Array<uint> &values,
bool isRandom, bool isSequential) :
- _id(id), _nextP(nullptr) {
+ _id(id), _nextP(nullptr), _priorIndex(0) {
_mode = SF_NONE;
if (isRandom)
_mode = SF_RANDOM;
@@ -57,7 +57,7 @@ bool TTsentenceEntry::load(Common::SeekableReadStream *s) {
return false;
_field0 = s->readUint32LE();
- _field4 = s->readUint32LE();
+ _category = s->readUint32LE();
_string8 = readStringFromStream(s);
_fieldC = s->readUint32LE();
_string10 = readStringFromStream(s);
diff --git a/engines/titanic/true_talk/script_support.h b/engines/titanic/true_talk/script_support.h
index bdaec6e7c9..3c5b919ccf 100644
--- a/engines/titanic/true_talk/script_support.h
+++ b/engines/titanic/true_talk/script_support.h
@@ -40,6 +40,10 @@ struct TTnpcScriptResponse {
uint _tag;
uint _values[4];
+ TTnpcScriptResponse() : _tag(0) {
+ _values[0] = _values[1] = _values[2] = _values[3] = 0;
+ }
+
/**
* Returns the size of the values list plus 1
*/
@@ -59,10 +63,9 @@ struct TTscriptRange {
bool isSequential);
};
-
struct TTsentenceEntry {
int _field0;
- int _field4;
+ int _category;
CString _string8;
int _fieldC;
CString _string10;
@@ -75,7 +78,7 @@ struct TTsentenceEntry {
int _field2C;
int _field30;
- TTsentenceEntry() : _field0(0), _field4(0), _fieldC(0),
+ TTsentenceEntry() : _field0(0), _category(0), _fieldC(0),
_field20(0), _field28(0), _field2C(0), _field30(0) {}
/**
diff --git a/engines/titanic/true_talk/succubus_script.cpp b/engines/titanic/true_talk/succubus_script.cpp
index db537c6470..888d23e17c 100644
--- a/engines/titanic/true_talk/succubus_script.cpp
+++ b/engines/titanic/true_talk/succubus_script.cpp
@@ -85,7 +85,7 @@ int SuccUBusScript::process(const TTroomScript *roomScript, const TTsentence *se
int currState = getState();
if (currState) {
- int currMode = sentence->_field2C;
+ int currMode = sentence->_category;
bool modeFlag1 = currMode == 11 || currMode == 13;
bool modeFlag2 = currMode == 12;
setState(0);
diff --git a/engines/titanic/true_talk/title_engine.cpp b/engines/titanic/true_talk/title_engine.cpp
index 079067389d..bfa97e3f92 100644
--- a/engines/titanic/true_talk/title_engine.cpp
+++ b/engines/titanic/true_talk/title_engine.cpp
@@ -40,7 +40,8 @@ void CTitleEngine::setup(int val1, int val2) {
/*------------------------------------------------------------------------*/
-STtitleEngine::STtitleEngine(): CTitleEngine(), _responseP(nullptr) {
+STtitleEngine::STtitleEngine(): CTitleEngine(),
+ _responseP(nullptr), _stream(nullptr) {
}
STtitleEngine::~STtitleEngine() {
diff --git a/engines/titanic/true_talk/true_talk_manager.cpp b/engines/titanic/true_talk/true_talk_manager.cpp
index 0e90676eef..fbb9d17407 100644
--- a/engines/titanic/true_talk/true_talk_manager.cpp
+++ b/engines/titanic/true_talk/true_talk_manager.cpp
@@ -245,7 +245,7 @@ void CTrueTalkManager::start4(CTrueTalkNPC *npc, CViewItem *view) {
TTnpcScript *CTrueTalkManager::getTalker(const CString &name) const {
if (name.contains("Doorbot"))
return _scripts.getNpcScript(104);
- else if (name.contains("DeskBot"))
+ else if (name.contains("Deskbot"))
return _scripts.getNpcScript(103);
else if (name.contains("LiftBot"))
return _scripts.getNpcScript(105);
@@ -271,6 +271,7 @@ TTnpcScript *CTrueTalkManager::getNpcScript(CTrueTalkNPC *npc) const {
if (!script) {
// Fall back on the default NPC script
+ warning("Could not find NPC script for %s, using fallback", npc->getName().c_str());
script = _scripts.getNpcScript(101);
}
@@ -513,7 +514,9 @@ void CTrueTalkManager::playSpeech(TTtalker *talker, TTroomScript *roomScript, CV
_gameManager->_sound.stopChannel(p1._channelMode);
if (view) {
p1._positioningMode = POSMODE_VECTOR;
+#if 0
view->getPosition(p1._posX, p1._posY, p1._posZ);
+#endif
}
// Loop through adding each of the speech portions in. We use the
@@ -537,12 +540,16 @@ void CTrueTalkManager::playSpeech(TTtalker *talker, TTroomScript *roomScript, CV
if (idx == 0)
g_vm->_events->sleep(milli);
-
+#if 0
+ // TODO: Figure out if these below are needed. It kinda looks like they were
+ // simply playing the same speech at different spatial co-ordinates. And since
+ // we don't support spatial processing in ScummVM yet, they're being left disabled
p3._priorSoundHandle = _gameManager->_sound.playSpeech(_dialogueFile, id - _dialogueId, p3);
if (idx == 0)
g_vm->_events->sleep(milli);
p2._priorSoundHandle = _gameManager->_sound.playSpeech(_dialogueFile, id - _dialogueId, p2);
+#endif
}
}
diff --git a/engines/titanic/true_talk/tt_concept.cpp b/engines/titanic/true_talk/tt_concept.cpp
index 9aad88722b..acb2e61e9e 100644
--- a/engines/titanic/true_talk/tt_concept.cpp
+++ b/engines/titanic/true_talk/tt_concept.cpp
@@ -131,7 +131,7 @@ void TTconcept::setScriptType(ScriptType scriptType) {
int TTconcept::initializeWordRef(TTword *word) {
delete _wordP;
- _wordP = word;
+ _wordP = word->copy();
return 0;
}
@@ -213,11 +213,9 @@ void TTconcept::copyFrom(TTconcept *src) {
}
int TTconcept::setOwner(TTconcept *src) {
- if (this) {
- if (src->_wordP) {
- TTword *newWord = src->_wordP->copy();
- return setOwner(newWord, 1);
- }
+ if (src->_wordP) {
+ TTword *newWord = src->_wordP->copy();
+ return setOwner(newWord, 1);
}
return 0;
@@ -298,11 +296,11 @@ TTconcept *TTconcept::findBy20(int val) {
}
bool TTconcept::isWordId(int id) const {
- return this && _wordP && _wordP->_id == id;
+ return _wordP && _wordP->_id == id;
}
int TTconcept::getWordId() const {
- return this && _wordP ? _wordP->_id : 0;
+ return _wordP ? _wordP->_id : 0;
}
} // End of namespace Titanic
diff --git a/engines/titanic/true_talk/tt_concept_node.cpp b/engines/titanic/true_talk/tt_concept_node.cpp
index 454ca59971..f6512b3d81 100644
--- a/engines/titanic/true_talk/tt_concept_node.cpp
+++ b/engines/titanic/true_talk/tt_concept_node.cpp
@@ -29,11 +29,14 @@ namespace Titanic {
TTconceptNode::TTconceptNode() : _concept0P(_concepts[0]), _concept1P(_concepts[1]),
_concept2P(_concepts[2]), _concept3P(_concepts[3]), _concept4P(_concepts[4]),
_concept5P(_concepts[5]), _field18(0), _field1C(0), _nextP(nullptr), _status(0) {
+ Common::fill(&_concepts[0], &_concepts[6], (TTconcept *)nullptr);
}
TTconceptNode::TTconceptNode(const TTconceptNode &src) : _concept0P(_concepts[0]), _concept1P(_concepts[1]),
_concept2P(_concepts[2]), _concept3P(_concepts[3]), _concept4P(_concepts[4]),
_concept5P(_concepts[5]), _field18(0), _field1C(0), _nextP(nullptr), _status(0) {
+ Common::fill(&_concepts[0], &_concepts[6], (TTconcept *)nullptr);
+
if (src._status) {
_status = SS_5;
} else {
diff --git a/engines/titanic/true_talk/tt_npc_script.cpp b/engines/titanic/true_talk/tt_npc_script.cpp
index 74e2f4f66b..527e33f14c 100644
--- a/engines/titanic/true_talk/tt_npc_script.cpp
+++ b/engines/titanic/true_talk/tt_npc_script.cpp
@@ -338,12 +338,13 @@ uint TTnpcScript::getRangeValue(uint id) {
case SF_RANDOM: {
uint count = range->_values.size();
- uint index = getRandomNumber(count) - 1;
+ int index = (int)getRandomNumber(count) - 1;
if (count > 1 && range->_values[index] == range->_priorIndex) {
- for (int retry = 0; retry < 8 && index != range->_priorIndex; ++retry)
- index = getRandomNumber(count) - 1;
+ for (int retry = 0; retry < 8 && index != (int)range->_priorIndex; ++retry)
+ index = (int)getRandomNumber(count) - 1;
}
+ assert(index >= 0);
range->_priorIndex = index;
return range->_values[index];
}
@@ -699,12 +700,12 @@ int TTnpcScript::processEntries(const TTsentenceEntries *entries, uint entryCoun
if (!entryCount)
// No count specified, so use entire list
entryCount = entries->size();
- int entryId = _field2C;
+ int categoryNum = sentence->_category;
for (uint loopCtr = 0; loopCtr < 2; ++loopCtr) {
for (uint entryCtr = 0; entryCtr < entryCount; ++entryCtr) {
const TTsentenceEntry &entry = (*entries)[entryCtr];
- if (entry._field4 != entryId && (loopCtr == 0 || entry._field4))
+ if (entry._category != categoryNum && (loopCtr == 0 || entry._category))
continue;
bool flag;
@@ -955,7 +956,7 @@ bool TTnpcScript::getStateValue() const {
}
bool TTnpcScript::sentence2C(const TTsentence *sentence) {
- return sentence->_field2C >= 2 && sentence->_field2C <= 7;
+ return sentence->_category >= 2 && sentence->_category <= 7;
}
void TTnpcScript::getAssignedRoom(int *roomNum, int *floorNum, int *elevatorNum) const {
diff --git a/engines/titanic/true_talk/tt_parser.cpp b/engines/titanic/true_talk/tt_parser.cpp
index d67f5235c4..e432677c7c 100644
--- a/engines/titanic/true_talk/tt_parser.cpp
+++ b/engines/titanic/true_talk/tt_parser.cpp
@@ -482,28 +482,30 @@ int TTparser::findFrames(TTsentence *sentence) {
TTstring *line = sentence->_normalizedLine.copy();
TTstring wordString;
int status = 0;
- for (int ctr = 1; !status; ++ctr) {
+ for (int ctr = 1; status <= 1; ++ctr) {
// Keep stripping words off the start of the passed input
wordString = line->tokenize(" \n");
if (wordString.empty())
break;
TTword *srcWord = nullptr;
- TTword *word = _owner->_vocab->getWord(wordString, &word);
+ TTword *word = _owner->_vocab->getWord(wordString, &srcWord);
sentence->storeVocabHit(srcWord);
if (!word && ctr == 1) {
word = new TTword(wordString, WC_UNKNOWN, 0);
}
- for (TTword *currP = word; currP && !status; currP = currP->_nextP)
+ for (TTword *currP = word; currP && status <= 1; currP = currP->_nextP)
status = processRequests(currP);
- word->deleteSiblings();
- delete word;
+ if (word) {
+ word->deleteSiblings();
+ delete word;
+ }
}
- if (!status) {
+ if (status <= 1) {
status = checkForAction();
}
@@ -514,7 +516,7 @@ int TTparser::findFrames(TTsentence *sentence) {
int TTparser::loadRequests(TTword *word) {
int status = 0;
- if (word->_tag != MKTAG('Z', 'Z', 'Z', 'T'))
+ if (word->_tag != MKTAG('Z', 'Z', 'Z', '['))
addNode(word->_tag);
switch (word->_wordClass) {
@@ -620,7 +622,7 @@ int TTparser::loadRequests(TTword *word) {
break;
case WC_CONJUNCTION:
- if (_sentence->check2C()) {
+ if (_sentence->checkCategory()) {
_sentenceConcept->_field1C = 1;
_sentenceConcept = _sentenceConcept->addSibling();
delete this;
@@ -674,7 +676,7 @@ int TTparser::loadRequests(TTword *word) {
case 901:
case 902:
case 904:
- if (_sentence->_field2C == 9) {
+ if (_sentence->_category == 9) {
_sentenceConcept->_field1C = 1;
_sentenceConcept = _sentenceConcept->addSibling();
addNode(1);
@@ -736,7 +738,7 @@ int TTparser::considerRequests(TTword *word) {
for (TTparserNode *nodeP = _nodesP; nodeP; ) {
switch (nodeP->_tag) {
case CHECK_COMMAND_FORM:
- if (_sentenceConcept->_concept1P && _sentence->_field2C == 1 &&
+ if (_sentenceConcept->_concept1P && _sentence->_category == 1 &&
!_sentenceConcept->_concept0P) {
concept = new TTconcept(_sentence->_npcScript, ST_NPC_SCRIPT);
_sentenceConcept->_concept0P = concept;
@@ -1030,7 +1032,7 @@ int TTparser::considerRequests(TTword *word) {
addNode(15);
}
- if (_sentence->check2C() && word->_id == 113)
+ if (_sentence->checkCategory() && word->_id == 113)
addNode(4);
if (word->_wordClass == WC_ACTION)
@@ -1053,10 +1055,10 @@ int TTparser::considerRequests(TTword *word) {
break;
case WORD_TYPE_IS_SENTENCE_TYPE:
- if (_sentence->_field2C == 1 || _sentence->_field2C == 10) {
+ if (_sentence->_category == 1 || _sentence->_category == 10) {
for (TTword *wordP = _currentWordP; wordP; wordP = wordP->_nextP) {
if (wordP->_id == 906) {
- _sentence->_field2C = 12;
+ _sentence->_category = 12;
flag = true;
break;
}
@@ -1066,44 +1068,44 @@ int TTparser::considerRequests(TTword *word) {
TTconcept *newConceptP;
switch (word->_id) {
case 108:
- _sentence->_field2C = 8;
+ _sentence->_category = 8;
break;
case 113:
if (!_sentenceConcept->_concept3P)
- _sentence->_field2C = 22;
+ _sentence->_category = 22;
break;
- case 304:
- _sentence->_field2C = 25;
+ case 306:
+ _sentence->_category = 7;
break;
- case 305:
- _sentence->_field2C = 24;
+ case 307:
+ _sentence->_category = 24;
break;
- case 306:
- _sentence->_field2C = 7;
+ case 308:
+ _sentence->_category = 25;
break;
case 501:
- _sentence->_field2C = 9;
+ _sentence->_category = 9;
break;
case 900:
- _sentence->_field2C = 5;
+ _sentence->_category = 5;
break;
case 901:
- _sentence->_field2C = 4;
+ _sentence->_category = 4;
break;
case 904:
- _sentence->_field2C = 6;
+ _sentence->_category = 6;
break;
case 905:
- _sentence->_field2C = 11;
+ _sentence->_category = 11;
break;
case 906:
- _sentence->_field2C = 12;
+ _sentence->_category = 12;
break;
case 907:
- _sentence->_field2C = 13;
+ _sentence->_category = 13;
break;
case 908:
- _sentence->_field2C = 2;
+ _sentence->_category = 2;
if (!_sentenceConcept->_concept0P) {
newPictP = new TTpicture(TTstring("?"), WC_THING, 0, 0, 0, 0, 0);
newConceptP = new TTconcept(newPictP);
@@ -1114,7 +1116,7 @@ int TTparser::considerRequests(TTword *word) {
}
break;
case 909:
- _sentence->_field2C = 3;
+ _sentence->_category = 3;
newPictP = new TTpicture(TTstring("?"), WC_THING, 0, 0, 0, 0, 0);
newConceptP = new TTconcept(newPictP);
@@ -1152,8 +1154,8 @@ int TTparser::considerRequests(TTword *word) {
addNode(5);
addNode(21);
- if (!_sentence->_field2C)
- _sentence->_field2C = 15;
+ if (!_sentence->_category)
+ _sentence->_category = 15;
break;
case MKTAG('C', 'U', 'R', 'S'):
@@ -1168,8 +1170,8 @@ int TTparser::considerRequests(TTword *word) {
addNode(5);
addNode(21);
- if (!_sentence->_field2C)
- _sentence->_field2C = 14;
+ if (!_sentence->_category)
+ _sentence->_category = 14;
break;
case MKTAG('F', 'A', 'R', 'R'):
@@ -1186,15 +1188,15 @@ int TTparser::considerRequests(TTword *word) {
addNode(5);
addNode(21);
- if (_sentence->_field2C == 1)
- _sentence->_field2C = 14;
+ if (_sentence->_category == 1)
+ _sentence->_category = 14;
flag = true;
break;
case MKTAG('H', 'E', 'L', 'P'):
- if (_sentence->_field2C == 1)
- _sentence->_field2C = 18;
+ if (_sentence->_category == 1)
+ _sentence->_category = 18;
flag = true;
break;
@@ -1257,8 +1259,8 @@ int TTparser::considerRequests(TTword *word) {
break;
case MKTAG('T', 'E', 'A', 'C'):
- if (_sentence->_field2C == 1)
- _sentence->_field2C = 10;
+ if (_sentence->_category == 1)
+ _sentence->_category = 10;
flag = true;
break;
@@ -1275,7 +1277,7 @@ int TTparser::considerRequests(TTword *word) {
TTparserNode *nextP = dynamic_cast<TTparserNode *>(nodeP->_nextP);
if (flag)
- delete nodeP;
+ removeNode(nodeP);
nodeP = nextP;
}
@@ -1402,8 +1404,8 @@ int TTparser::checkForAction() {
} else {
// No chain, so singular word can simply be removed
_currentWordP = nullptr;
- if (word->_id == 906 && _sentence->_field2C == 1)
- _sentence->_field2C = 12;
+ if (word->_id == 906 && _sentence->_category == 1)
+ _sentence->_category = 12;
}
if (word->_text == "do" || word->_text == "doing" || word->_text == "does" ||
@@ -1453,28 +1455,28 @@ int TTparser::checkForAction() {
if (_sentence->fn2(3, TTstring("thePlayer"), _sentenceConcept) && !flag) {
if (_sentenceConcept->concept1WordId() == 101) {
- _sentence->_field2C = 16;
- } else if (_sentence->_field2C != 18 && _sentenceConcept->concept1WordId() == 102) {
+ _sentence->_category = 16;
+ } else if (_sentence->_category != 18 && _sentenceConcept->concept1WordId() == 102) {
if (_sentence->fn2(0, TTstring("targetNpc"), _sentenceConcept))
- _sentence->_field2C = 15;
+ _sentence->_category = 15;
}
}
if (_sentence->fn2(2, TTstring("thePlayer"), _sentenceConcept) &&
_sentenceConcept->concept1WordId() == 101 && flag)
- _sentence->_field2C = 17;
+ _sentence->_category = 17;
if (!_sentenceConcept->_concept0P && !_sentenceConcept->_concept1P &&
!_sentenceConcept->_concept2P && !_sentenceConcept->_concept5P && !flag) {
if (_conceptP)
filterConcepts(5, 2);
- if (!_sentenceConcept->_concept2P && _sentence->_field2C == 1)
- _sentence->_field2C = 0;
+ if (!_sentenceConcept->_concept2P && _sentence->_category == 1)
+ _sentence->_category = 0;
}
- if (_sentence->_field58 < 5 && _sentence->_field2C == 1 && !flag)
- _sentence->_field2C = 19;
+ if (_sentence->_field58 < 5 && _sentence->_category == 1 && !flag)
+ _sentence->_category = 19;
for (TTconceptNode *nodeP = &_sentence->_sentenceConcept; nodeP; nodeP = nodeP->_nextP) {
if (nodeP->_field18 == 0 && nodeP->_concept1P) {
@@ -1490,15 +1492,15 @@ int TTparser::checkForAction() {
}
}
- if (_sentence->_field2C == 1 && _sentenceConcept->_concept5P &&
+ if (_sentence->_category == 1 && _sentenceConcept->_concept5P &&
_sentenceConcept->_concept2P) {
if (_sentence->fn4(1, 113, nullptr)) {
if (_sentence->fn2(2, TTstring("targetNpc"), nullptr)) {
- _sentence->_field2C = 20;
+ _sentence->_category = 20;
} else if (_sentence->fn2(2, TTstring("thePlayer"), nullptr)) {
- _sentence->_field2C = 21;
+ _sentence->_category = 21;
} else {
- _sentence->_field2C = 22;
+ _sentence->_category = 22;
}
}
} else if (!_sentenceConcept->_concept0P && !_sentenceConcept->_concept1P &&
@@ -1506,8 +1508,8 @@ int TTparser::checkForAction() {
if (_conceptP)
filterConcepts(5, 2);
- if (!_sentenceConcept->_concept2P && _sentence->_field2C == 1)
- _sentence->_field2C = 0;
+ if (!_sentenceConcept->_concept2P && _sentence->_category == 1)
+ _sentence->_category = 0;
}
return status;
@@ -1632,7 +1634,7 @@ int TTparser::processModifiers(int modifier, TTword *word) {
TTconcept *newConcept = new TTconcept(word, ST_UNKNOWN_SCRIPT);
// Cycles through each word
- for (TTword *currP = _currentWordP; currP != word; currP = _currentWordP) {
+ for (TTword *currP = _currentWordP; currP && currP != word; currP = _currentWordP) {
if ((modifier == 2 && currP->_wordClass == WC_ADJECTIVE) ||
(modifier == 1 && currP->_wordClass == WC_ADVERB)) {
newConcept->_string2 += ' ';
@@ -1658,8 +1660,8 @@ int TTparser::processModifiers(int modifier, TTword *word) {
case 204:
newConcept->_field34 = 1;
- if (_sentence->_field2C == 1)
- _sentence->_field2C = 12;
+ if (_sentence->_category == 1)
+ _sentence->_category = 12;
newConcept->_field14 = 1;
break;
diff --git a/engines/titanic/true_talk/tt_quotes_tree.cpp b/engines/titanic/true_talk/tt_quotes_tree.cpp
index 16453a10ae..e2293887a8 100644
--- a/engines/titanic/true_talk/tt_quotes_tree.cpp
+++ b/engines/titanic/true_talk/tt_quotes_tree.cpp
@@ -66,7 +66,7 @@ int TTquotesTree::search(const char *str, QuoteTreeNum treeNum,
return -1;
if (remainder) {
- while (*str) {
+ for (; *str; ++str) {
if (*str >= 'a' && *str != 's')
*remainder += *str;
}
diff --git a/engines/titanic/true_talk/tt_response.cpp b/engines/titanic/true_talk/tt_response.cpp
index 1c784ad320..3cb8d2c9ec 100644
--- a/engines/titanic/true_talk/tt_response.cpp
+++ b/engines/titanic/true_talk/tt_response.cpp
@@ -49,6 +49,12 @@ TTresponse::~TTresponse() {
}
}
+TTresponse *TTresponse::appendResponse(int id) {
+ TTresponse *resp = new TTresponse(id, 3);
+ _nextP = resp;
+ return resp;
+}
+
TTresponse *TTresponse::copyChain() const {
TTresponse *returnResponseP = new TTresponse(this);
diff --git a/engines/titanic/true_talk/tt_response.h b/engines/titanic/true_talk/tt_response.h
index d39d18c193..950e1cd23e 100644
--- a/engines/titanic/true_talk/tt_response.h
+++ b/engines/titanic/true_talk/tt_response.h
@@ -42,6 +42,12 @@ public:
virtual ~TTresponse();
/**
+ * Creates a new response and adds it as the current
+ * response's next response
+ */
+ TTresponse *appendResponse(int id);
+
+ /**
* Makes a copy of the chain of responses
*/
TTresponse *copyChain() const;
diff --git a/engines/titanic/true_talk/tt_script_base.cpp b/engines/titanic/true_talk/tt_script_base.cpp
index 2f58ad1400..1fa1ce3315 100644
--- a/engines/titanic/true_talk/tt_script_base.cpp
+++ b/engines/titanic/true_talk/tt_script_base.cpp
@@ -129,7 +129,7 @@ void TTscriptBase::appendResponse(int index, int *maxP, int id) {
if (id && (!maxP || index <= *maxP)) {
if (_respTailP) {
// Prior fragments already exist, so append to end of chain
- _respTailP = new TTresponse(_respTailP);
+ _respTailP = _respTailP->appendResponse(id);
} else {
// Currently no tail
_respTailP = new TTresponse(id, 3);
diff --git a/engines/titanic/true_talk/tt_sentence.cpp b/engines/titanic/true_talk/tt_sentence.cpp
index 3fae527770..451582383d 100644
--- a/engines/titanic/true_talk/tt_sentence.cpp
+++ b/engines/titanic/true_talk/tt_sentence.cpp
@@ -41,7 +41,7 @@ TTsentenceConcept *TTsentenceConcept::addSibling() {
TTsentence::TTsentence(int inputCtr, const TTstring &line, CScriptHandler *owner,
TTroomScript *roomScript, TTnpcScript *npcScript) :
- _owner(owner), _field2C(1), _inputCtr(inputCtr), _field34(0),
+ _owner(owner), _category(1), _inputCtr(inputCtr), _field34(0),
_field38(0), _initialLine(line), _nodesP(nullptr), _roomScript(roomScript),
_npcScript(npcScript), _field58(0), _field5C(0) {
_status = _initialLine.isValid() && _normalizedLine.isValid() ? SS_11: SS_VALID;
@@ -77,7 +77,7 @@ void TTsentence::copyFrom(const TTsentence &src) {
_field5C = src._field5C;
_field34 = src._field34;
_field38 = src._field38;
- _field2C = src._field2C;
+ _category = src._category;
_nodesP = nullptr;
if (src._nodesP) {
@@ -109,10 +109,10 @@ int TTsentence::storeVocabHit(TTword *word) {
bool TTsentence::fn1(const CString &str, int wordId1, const CString &str1, const CString &str2,
const CString &str3, int wordId2, int val1, int val2, const TTconceptNode *node) const {
- if (node)
+ if (!node)
node = &_sentenceConcept;
- if (!node && !node)
+ if (!node)
return false;
if (val1 && !is18(val1, node))
return false;
@@ -265,7 +265,9 @@ TTconcept *TTsentence::getFrameEntry(int slotIndex, const TTconceptNode *concept
TTconcept *TTsentence::getFrameSlot(int slotIndex, const TTconceptNode *conceptNode) const {
TTconcept *newConcept = new TTconcept();
TTconcept *concept = getFrameEntry(slotIndex, conceptNode);
- newConcept->copyFrom(concept);
+
+ if (concept)
+ newConcept->copyFrom(concept);
if (!newConcept->isValid()) {
delete newConcept;
diff --git a/engines/titanic/true_talk/tt_sentence.h b/engines/titanic/true_talk/tt_sentence.h
index 7b2c6400c5..cbaef26831 100644
--- a/engines/titanic/true_talk/tt_sentence.h
+++ b/engines/titanic/true_talk/tt_sentence.h
@@ -67,7 +67,7 @@ public:
int _field58;
TTroomScript *_roomScript;
TTnpcScript *_npcScript;
- int _field2C;
+ int _category;
public:
TTsentence(int inputCtr, const TTstring &line, CScriptHandler *owner,
TTroomScript *roomScript, TTnpcScript *npcScript);
@@ -76,7 +76,7 @@ public:
void setState(int v) { _field34 = v; }
void set38(int v) { _field38 = v; }
- bool check2C() const { return _field2C > 1 && _field2C <= 10; }
+ bool checkCategory() const { return _category > 1 && _category <= 10; }
int concept18(TTconceptNode *conceptNode) {
return conceptNode ? conceptNode->get18() : 0;
}
diff --git a/engines/titanic/true_talk/tt_string.cpp b/engines/titanic/true_talk/tt_string.cpp
index 198a8c2e80..43910fc823 100644
--- a/engines/titanic/true_talk/tt_string.cpp
+++ b/engines/titanic/true_talk/tt_string.cpp
@@ -111,7 +111,7 @@ TTstring TTstring::tokenize(const char *delim) {
const char *strP = _data->_string.c_str();
const char *splitP = nullptr, *chP;
- for (const char *d = delim; d; ++d) {
+ for (const char *d = delim; *d; ++d) {
chP = strchr(strP, *d);
if (chP && (splitP == nullptr || chP < splitP))
splitP = chP;
@@ -122,7 +122,9 @@ TTstring TTstring::tokenize(const char *delim) {
_data->_string = CString(splitP + 1);
return result;
} else {
- return TTstring();
+ TTstring result(strP);
+ _data->_string = CString();
+ return result;
}
}
diff --git a/engines/titanic/true_talk/tt_vocab.cpp b/engines/titanic/true_talk/tt_vocab.cpp
index 062a6b65c0..6748d6535b 100644
--- a/engines/titanic/true_talk/tt_vocab.cpp
+++ b/engines/titanic/true_talk/tt_vocab.cpp
@@ -196,10 +196,12 @@ TTword *TTvocab::getPrimeWord(TTstring &str, TTword **srcWord) const {
TTword *newWord = nullptr;
TTword *vocabP;
- if (!Common::isDigit(c)) {
+ if (Common::isDigit(c)) {
+ // Number
vocabP = _headP;
newWord = new TTword(str, WC_ABSTRACT, 300);
} else {
+ // Standard word
for (vocabP = _headP; vocabP && !newWord; vocabP = vocabP->_nextP) {
if (_vocabMode == 3 && !strcmp(str.c_str(), vocabP->c_str())) {
newWord = vocabP->copy();
@@ -550,7 +552,6 @@ TTword *TTvocab::getPrefixedWord(TTstring &str) const {
word->_text = str;
}
- delete tempStr;
return word;
}