[Scummvm-cvs-logs] scummvm master -> d53ed7408da6af2ac55672a38ddbea6278677957

dreammaster dreammaster at scummvm.org
Sat May 30 16:50:31 CEST 2015


This automated email contains information about 54 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
ec6e52e78e Re-factored animation code to move title and prologue arrays into Animation class, defined in scalpel.cpp and loaded at 
b1b4363788 Correct some minor spelling mistakes
bcc5a40744 Merge branch 'sherlock' of https://github.com/dreammaster/scummvm into sherlock
4865949e4d SHERLOCK: Fix to correctly increment animation variables
684f230ed2 SHERLOCK: Fix GCC compilation with correct whitespace for nested Common:Array
e745639fda SHERLOCK: Implement sound priority
1cdfeaa776 SHERLOCK: Fix buffer reference in randomTransition
1e8c297d80 SHERLOCK: Remove redundant check from mergeDirtyRects
cf229ce72c SHERLOCK: Whitespace fixes
5370b71fbf SHERLOCK: Rename object loading methods from synchronize to load
fdb39d8170 SHERLOCK: Fix speed of animations
d4b964c92b SHERLOCK: Add missing setting of _oldSelector
8432e7584c SHERLOCK: Beginnings of Rose Tattoo engine
4cbad2834c SHERLOCK: Update sound initialization for Rose Tattoo
d1d4d55074 Merge branch 'sherlock' into sherlock2
44e0904467 SHERLOCK: Move caching Scalpel sound libraries from Sound to Scalpel engine
75a6e941a0 SHERLOCK: Fix decompression for Rose Tattoo
b960736ac3 SHERLOCK: Scene loading for shapes, desc, scripts for Rose Tattoo
8c009d8941 SHERLOCK: Fix broken Scalpel scene loading
2f80df5d44 SHERLOCK: Remove accidentally committed debug info
f41b8cad2f SHERLOCK: Implement Tattoo version of image RLE compression
bfb78778a4 SHERLOCK: Update CAnim loading for Rose Tattoo
71540b7ad5 SHERLOCK: Implement remaining Rose Tattoo scene data loading
d3b86a593b SHERLOCK: Beginnings of UserInterface split for Scalpel vs Tattoo
0cc55e20f8 Merge branch 'master' into sherlock2
ad543a0423 SHERLOCK: Fix Rose Tattoo scene loading problems from merge
a66570f6be SHERLOCK: Implemented Tattoo loadWalk changes
ad008b534b SHERLOCK: Implemented initial RT palette loading
83c911c45c SHERLOCK: Implement more scene loading and setNPCPath
a09f1df8a8 SHERLOCK: Make virtual destructors for user interface classes
16490a2fe8 SHERLOCK: Create separate opcode list for Scalpel vs Tattoo
c7749f8c22 SHERLOCK: Fully implemented RT opcodes array
5a670cd024 SHERLOCK: Splitting Talk up to implement individual opcode methods
b61cccf9f8 SHERLOCK: Implement method stubs for Tattoo opcodes
69b848084b SHERLOCK: Fix script opcode table lookup
e52153d03d SHERLOCK: Implement cmdSetNPCWalkGraphics method
5b90b56c16 SHERLOCK: Implement cmdNextSong
97bb33d6f3 SHERLOCK: Fix People data initialization and general start fixes
871a4570e0 SHERLOCK: Fix display of first RT scene background
a7f7a48398 SHERLOCK: Fix palette for RT scene
c205fa6bd5 SHERLOCK: Free freeing and resetting People list
7a4d45679a SHERLOCK: Cleanup of checkBgShapes and updateBackground
8751abbbe3 SHERLOCK: Add define for fixed integer multiplier
361dc4ed8b SHERLOCK: Fix map display
57575b9068 SHERLOCK: Starting to split Scene class, implemented checkBgShapes changes
fdf1617432 SHERLOK: Beginnings of split of doBgAnim logic
1b3856b5b6 SHERLOCK: Implemented initial background clearing of RT doBgAnim
789a8b3561 SHERLOCK: Implement RT scrolling code
f759aeddcd SHERLOCK: Moving split up classes into their own files
54b3c55e82 SHERLOCK: Implement additions to updateBackground, some method stubs
074669ad45 SHERLOCK: Implemented flushScaleImage and scale calculations
c9bfc5c481 SHERLOCK: More RT doBgAnim code, interface draw
fc6320c256 Merge branch 'sherlock2'
d53ed7408d Merge branch 'master' of https://github.com/scummvm/scummvm


Commit: ec6e52e78ea3a42c0ce663892cc4cd5096965de9
    https://github.com/scummvm/scummvm/commit/ec6e52e78ea3a42c0ce663892cc4cd5096965de9
Author: sirlemonhead (sirlemonhead at outlook.com)
Date: 2015-05-12T00:45:55+01:00

Commit Message:
Re-factored animation code to move title and prologue arrays into Animation class, defined in scalpel.cpp and loaded at engine initialisation.

Changed paths:
    engines/sherlock/animation.cpp
    engines/sherlock/animation.h
    engines/sherlock/scalpel/scalpel.cpp



diff --git a/engines/sherlock/animation.cpp b/engines/sherlock/animation.cpp
index dac903a..5c11c4f 100644
--- a/engines/sherlock/animation.cpp
+++ b/engines/sherlock/animation.cpp
@@ -26,39 +26,6 @@
 
 namespace Sherlock {
 
-// The following are a list of filenames played in the prologue that have
-// special effects associated with them at specific frames
-
-#define FRAMES_END 32000
-#define PROLOGUE_NAMES_COUNT 6
-#define TITLE_NAMES_COUNT 7
-static const char *const PROLOGUE_NAMES[6] = {
-	"subway1", "subway2", "finale2", "suicid", "coff3", "coff4"
-};
-static const int PROLOGUE_FRAMES[6][9] = {
-	{ 4, 26, 54, 72, 92, 134, FRAMES_END },
-	{ 2, 80, 95, 117, 166, FRAMES_END },
-	{ 1, FRAMES_END },
-	{ 42, FRAMES_END },
-	{ FRAMES_END },
-	{ FRAMES_END }
-};
-
-// Title animations file list
-static const char *const TITLE_NAMES[7] = {
-	"27pro1", "14note", "coff1", "coff2", "coff3", "coff4", "14kick"
-};
-
-static const int TITLE_FRAMES[7][9] = {
-	{ 29, 131, FRAMES_END },
-	{ 55, 80, 95, 117, 166, FRAMES_END },
-	{ 15, FRAMES_END },
-	{ 4, 37, 92, FRAMES_END },
-	{ 2, 43, FRAMES_END },
-	{ 2, FRAMES_END },
-	{ 10, 50, FRAMES_END }
-};
-
 static const int NO_FRAMES = FRAMES_END;
 
 Animation::Animation(SherlockEngine *vm): _vm(vm) {
@@ -172,22 +139,64 @@ bool Animation::play(const Common::String &filename, int minDelay, int fade,
 }
 
 /**
+ * Load the prologue name array 
+ */
+void Animation::setPrologueNames(const char *const *names, int count) {
+	for (int idx = 0; idx < count; ++idx, names++) {
+		_prologueNames.push_back(*names);
+	}
+}
+
+/**
+ * Load the prologue frame array
+ */
+void Animation::setPrologueFrames(const int *frames, int count, int maxFrames) {
+	_prologueFrames.resize(count);
+
+	for (int idx = 0; idx < count; ++idx, frames + maxFrames) {
+		_prologueFrames[idx].resize(maxFrames);
+		Common::copy(frames, frames + maxFrames, &_prologueFrames[idx][0]);
+	}
+}
+
+/**
+ * Load the title name array
+ */
+void Animation::setTitleNames(const char *const *names, int count) {
+	for (int idx = 0; idx < count; ++idx, names++) {
+		_titleNames.push_back(*names);
+	}
+}
+
+/**
+ * Load the title frame array
+ */
+void Animation::setTitleFrames(const int *frames, int count, int maxFrames) {
+	_titleFrames.resize(count);
+
+	for (int idx = 0; idx < count; ++idx, frames + maxFrames) {
+		_titleFrames[idx].resize(maxFrames);
+		Common::copy(frames, frames + maxFrames, &_titleFrames[idx][0]);
+	}
+}
+
+/**
  * Checks for whether an animation is being played that has associated sound
  */
 const int *Animation::checkForSoundFrames(const Common::String &filename) {
 	const int *frames = &NO_FRAMES;
 
 	if (_vm->_soundOverride.empty()) {
-		for (int idx = 0; idx < PROLOGUE_NAMES_COUNT; ++idx) {
-			if (filename.equalsIgnoreCase(PROLOGUE_NAMES[idx])) {
-				frames = &PROLOGUE_FRAMES[idx][0];
+		for (Common::Array<const char *>::size_type idx = 0; idx < _prologueNames.size(); ++idx) {
+			if (filename.equalsIgnoreCase(_prologueNames[idx])) {
+				frames = &_prologueFrames[idx][0];
 				break;
 			}
 		}
 	} else {
-		for (int idx = 0; idx < TITLE_NAMES_COUNT; ++idx) {
-			if (filename.equalsIgnoreCase(TITLE_NAMES[idx])) {
-				frames = &TITLE_FRAMES[idx][0];
+		for (Common::Array<const char *>::size_type idx = 0; idx < _titleNames.size(); ++idx) {
+			if (filename.equalsIgnoreCase(_titleNames[idx])) {
+				frames = &_titleFrames[idx][0];
 				break;
 			}
 		}
diff --git a/engines/sherlock/animation.h b/engines/sherlock/animation.h
index 245d837..5802ffc 100644
--- a/engines/sherlock/animation.h
+++ b/engines/sherlock/animation.h
@@ -25,20 +25,35 @@
 
 #include "common/scummsys.h"
 #include "common/str.h"
+#include "common/array.h"
 
 namespace Sherlock {
 
+#define FRAMES_END 32000
+
 class SherlockEngine;
 
 class Animation {
 private:
 	SherlockEngine *_vm;
 
+	Common::Array<const char *> _prologueNames;
+	Common::Array<Common::Array<int>> _prologueFrames;
+
+	Common::Array<const char *> _titleNames;
+	Common::Array<Common::Array<int>> _titleFrames;
+
 	const int *checkForSoundFrames(const Common::String &filename);
 public:
 public:
 	Animation(SherlockEngine *vm);
 
+	void setPrologueNames(const char *const *names, int count);
+	void setPrologueFrames(const int *frames, int count, int maxFrames);
+
+	void setTitleNames(const char *const *names, int count);
+	void setTitleFrames(const int *frames, int count, int maxFrames);
+
 	bool play(const Common::String &filename, int minDelay, int fade, bool setPalette, int speed);
 };
 
diff --git a/engines/sherlock/scalpel/scalpel.cpp b/engines/sherlock/scalpel/scalpel.cpp
index 8dc75c0..5d84a7f 100644
--- a/engines/sherlock/scalpel/scalpel.cpp
+++ b/engines/sherlock/scalpel/scalpel.cpp
@@ -22,11 +22,46 @@
 
 #include "sherlock/scalpel/scalpel.h"
 #include "sherlock/sherlock.h"
+#include "sherlock/animation.h"
 
 namespace Sherlock {
 
 namespace Scalpel {
 
+#define PROLOGUE_NAMES_COUNT 6
+
+// The following are a list of filenames played in the prologue that have
+// special effects associated with them at specific frames
+static const char *const PROLOGUE_NAMES[PROLOGUE_NAMES_COUNT] = {
+	"subway1", "subway2", "finale2", "suicid", "coff3", "coff4"
+};
+
+static const int PROLOGUE_FRAMES[6][9] = {
+	{ 4, 26, 54, 72, 92, 134, FRAMES_END },
+	{ 2, 80, 95, 117, 166, FRAMES_END },
+	{ 1, FRAMES_END },
+	{ 42, FRAMES_END },
+	{ FRAMES_END },
+	{ FRAMES_END }
+};
+
+#define TITLE_NAMES_COUNT 7
+
+// Title animations file list
+static const char *const TITLE_NAMES[TITLE_NAMES_COUNT] = {
+	"27pro1", "14note", "coff1", "coff2", "coff3", "coff4", "14kick"
+};
+
+static const int TITLE_FRAMES[7][9] = {
+	{ 29, 131, FRAMES_END },
+	{ 55, 80, 95, 117, 166, FRAMES_END },
+	{ 15, FRAMES_END },
+	{ 4, 37, 92, FRAMES_END },
+	{ 2, 43, FRAMES_END },
+	{ 2, FRAMES_END },
+	{ 10, 50, FRAMES_END }
+};
+
 #define NUM_PLACES 100
 const int MAP_X[NUM_PLACES] = {
 	0, 368, 0, 219, 0, 282, 0, 43, 0, 0, 396, 408, 0, 0, 0, 568, 37, 325,
@@ -227,6 +262,12 @@ void ScalpelEngine::initialize() {
 	// Set up constants used by the talk system
 	_talk->setSequences(&TALK_SEQUENCES[0][0], &STILL_SEQUENCES[0][0], MAX_PEOPLE);
 
+	_animation->setPrologueNames(&PROLOGUE_NAMES[0], PROLOGUE_NAMES_COUNT);
+	_animation->setPrologueFrames(&PROLOGUE_FRAMES[0][0], 6, 9);
+
+	_animation->setTitleNames(&TITLE_NAMES[0], TITLE_NAMES_COUNT);
+	_animation->setTitleFrames(&TITLE_FRAMES[0][0], 7, 9);
+
 	// Starting scene
 	if (getIsDemo())
 		_scene->_goToScene = 3;


Commit: b1b4363788152dce18537bd278ff603bf8e7fae7
    https://github.com/scummvm/scummvm/commit/b1b4363788152dce18537bd278ff603bf8e7fae7
Author: sirlemonhead (sirlemonhead at outlook.com)
Date: 2015-05-12T00:53:51+01:00

Commit Message:
Correct some minor spelling mistakes

Changed paths:
    engines/sherlock/inventory.cpp
    engines/sherlock/talk.cpp



diff --git a/engines/sherlock/inventory.cpp b/engines/sherlock/inventory.cpp
index af2c4be..d8c0104 100644
--- a/engines/sherlock/inventory.cpp
+++ b/engines/sherlock/inventory.cpp
@@ -117,8 +117,8 @@ void Inventory::loadGraphics() {
 	Common::fill(&_invShapes[0], &_invShapes[MAX_VISIBLE_INVENTORY], (ImageFile *)nullptr);
 
 	for (int idx = _invIndex; (idx < _holdings) && (idx - _invIndex) < MAX_VISIBLE_INVENTORY; ++idx) {
-		// Get the name of the item to be dispalyed, figure out it's accompanying
-		// .VGS file with it's picture, and then load it
+		// Get the name of the item to be displayed, figure out its accompanying
+		// .VGS file with its picture, and then load it
 		int invNum = findInv((*this)[idx]._name);
 		Common::String fName = Common::String::format("item%02d.vgs", invNum + 1);
 
diff --git a/engines/sherlock/talk.cpp b/engines/sherlock/talk.cpp
index a1e124a..3520a02 100644
--- a/engines/sherlock/talk.cpp
+++ b/engines/sherlock/talk.cpp
@@ -379,7 +379,7 @@ void Talk::talkTo(const Common::String &filename) {
 
 					byte color = ui._endKeyActive ? COMMAND_FOREGROUND : COMMAND_NULL;
 
-					// If the window is alraedy open, simply draw. Otherwise, do it
+					// If the window is already open, simply draw. Otherwise, do it
 					// to the back buffer and then summon the window
 					if (ui._windowOpen) {
 						screen.buttonPrint(Common::Point(119, CONTROLS_Y), color, true, "Exit");


Commit: bcc5a40744544f31a5ac92dd85998d88e082fdec
    https://github.com/scummvm/scummvm/commit/bcc5a40744544f31a5ac92dd85998d88e082fdec
Author: sirlemonhead (sirlemonhead at outlook.com)
Date: 2015-05-12T17:44:24+01:00

Commit Message:
Merge branch 'sherlock' of https://github.com/dreammaster/scummvm into sherlock

Changed paths:





Commit: 4865949e4dc0a7d1a1f0b70e81631d15bd5a3896
    https://github.com/scummvm/scummvm/commit/4865949e4dc0a7d1a1f0b70e81631d15bd5a3896
Author: sirlemonhead (sirlemonhead at outlook.com)
Date: 2015-05-12T18:07:34+01:00

Commit Message:
SHERLOCK: Fix to correctly increment animation variables

Changed paths:
    engines/sherlock/animation.cpp



diff --git a/engines/sherlock/animation.cpp b/engines/sherlock/animation.cpp
index 5c11c4f..de72de6 100644
--- a/engines/sherlock/animation.cpp
+++ b/engines/sherlock/animation.cpp
@@ -153,7 +153,7 @@ void Animation::setPrologueNames(const char *const *names, int count) {
 void Animation::setPrologueFrames(const int *frames, int count, int maxFrames) {
 	_prologueFrames.resize(count);
 
-	for (int idx = 0; idx < count; ++idx, frames + maxFrames) {
+	for (int idx = 0; idx < count; ++idx, frames += maxFrames) {
 		_prologueFrames[idx].resize(maxFrames);
 		Common::copy(frames, frames + maxFrames, &_prologueFrames[idx][0]);
 	}
@@ -174,7 +174,7 @@ void Animation::setTitleNames(const char *const *names, int count) {
 void Animation::setTitleFrames(const int *frames, int count, int maxFrames) {
 	_titleFrames.resize(count);
 
-	for (int idx = 0; idx < count; ++idx, frames + maxFrames) {
+	for (int idx = 0; idx < count; ++idx, frames += maxFrames) {
 		_titleFrames[idx].resize(maxFrames);
 		Common::copy(frames, frames + maxFrames, &_titleFrames[idx][0]);
 	}


Commit: 684f230ed205d7dd03a309b1ba289fa04e265038
    https://github.com/scummvm/scummvm/commit/684f230ed205d7dd03a309b1ba289fa04e265038
Author: sirlemonhead (sirlemonhead at outlook.com)
Date: 2015-05-12T18:19:06+01:00

Commit Message:
SHERLOCK: Fix GCC compilation with correct whitespace for nested Common:Array

Changed paths:
    engines/sherlock/animation.h



diff --git a/engines/sherlock/animation.h b/engines/sherlock/animation.h
index 5802ffc..06614df 100644
--- a/engines/sherlock/animation.h
+++ b/engines/sherlock/animation.h
@@ -38,10 +38,10 @@ private:
 	SherlockEngine *_vm;
 
 	Common::Array<const char *> _prologueNames;
-	Common::Array<Common::Array<int>> _prologueFrames;
+	Common::Array<Common::Array<int> > _prologueFrames;
 
 	Common::Array<const char *> _titleNames;
-	Common::Array<Common::Array<int>> _titleFrames;
+	Common::Array<Common::Array<int> > _titleFrames;
 
 	const int *checkForSoundFrames(const Common::String &filename);
 public:


Commit: e745639fda44400c7ad3ffada29c638dfaf90679
    https://github.com/scummvm/scummvm/commit/e745639fda44400c7ad3ffada29c638dfaf90679
Author: Strangerke (strangerke at scummvm.org)
Date: 2015-05-12T21:34:45+02:00

Commit Message:
SHERLOCK: Implement sound priority

Changed paths:
    engines/sherlock/animation.cpp
    engines/sherlock/objects.cpp
    engines/sherlock/scene.cpp
    engines/sherlock/sound.cpp
    engines/sherlock/sound.h
    engines/sherlock/talk.cpp
    engines/sherlock/user_interface.cpp



diff --git a/engines/sherlock/animation.cpp b/engines/sherlock/animation.cpp
index de72de6..a8edf77 100644
--- a/engines/sherlock/animation.cpp
+++ b/engines/sherlock/animation.cpp
@@ -111,7 +111,7 @@ bool Animation::play(const Common::String &filename, int minDelay, int fade,
 					Common::String::format("%s%02d", filename.c_str(), soundNumber);
 
 				if (sound._voices)
-					sound.playSound(fname);
+					sound.playSound(fname, WAIT_RETURN_IMMEDIATELY);
 			}
 
 			events.wait(speed);
diff --git a/engines/sherlock/objects.cpp b/engines/sherlock/objects.cpp
index ca8ba17..acb13dd 100644
--- a/engines/sherlock/objects.cpp
+++ b/engines/sherlock/objects.cpp
@@ -613,7 +613,7 @@ void Object::checkObject() {
 
 				if (sound._soundOn && !_countCAnimFrames) {
 					if (!scene._sounds[v - 1]._name.empty() && sound._digitized)
-						sound.playLoadedSound(v - 1, 0);
+						sound.playLoadedSound(v - 1, WAIT_RETURN_IMMEDIATELY);
 				}
 			} else if (v >= FLIP_CODE && v <= (FLIP_CODE + 2)) {
 				// Flip code
diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp
index ca9f195..4b0cbee 100644
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@ -378,13 +378,8 @@ bool Scene::loadScene(const Common::String &filename) {
 		for (int idx = 0; idx < numSounds; ++idx)
 			_sounds[idx].synchronize(*rrmStream);
 
-		// If sound is turned on, load the sounds into memory
-		if (sound._soundOn) {
-			for (int idx = 0; idx < numSounds; ++idx) {
-				sound.loadSound(_sounds[idx]._name, _sounds[idx]._priority);
-				_sounds[idx]._name = "";
-			}
-		}
+		for (int idx = 0; idx < numSounds; ++idx)
+			sound.loadSound(_sounds[idx]._name, _sounds[idx]._priority);
 
 		// Read in palette
 		rrmStream->read(screen._cMap, PALETTE_SIZE);
diff --git a/engines/sherlock/sound.cpp b/engines/sherlock/sound.cpp
index 51563d1..09e55ec 100644
--- a/engines/sherlock/sound.cpp
+++ b/engines/sherlock/sound.cpp
@@ -38,6 +38,7 @@ Sound::Sound(SherlockEngine *vm, Audio::Mixer *mixer): _vm(vm), _mixer(mixer) {
 	_diskSoundPlaying = false;
 	_soundPlaying = false;
 	_soundIsOn = &_soundPlaying;
+	_curPriority = 0;
 
 	_soundOn = true;
 	_musicOn = true;
@@ -57,8 +58,7 @@ void Sound::syncSoundSettings() {
 }
 
 void Sound::loadSound(const Common::String &name, int priority) {
-	// TODO
-	warning("TODO: Sound::loadSound");
+	// No implementation required in ScummVM
 }
 
 char Sound::decodeSample(char sample, byte& prediction, int& step) {
@@ -86,8 +86,8 @@ char Sound::decodeSample(char sample, byte& prediction, int& step) {
 	return prediction;
 }
 
-bool Sound::playSound(const Common::String &name, WaitType waitType) {
-	_mixer->stopHandle(_effectsHandle);
+bool Sound::playSound(const Common::String &name, WaitType waitType, int priority) {
+	stopSound();
 
 	Common::String filename = name;
 	if (!filename.contains('.'))
@@ -103,7 +103,7 @@ bool Sound::playSound(const Common::String &name, WaitType waitType) {
 
 	byte *decoded = (byte *)malloc((size - 1) * 2);
 
-	// +127 to eliminate the pop when the sound starts (signed vs unsignded PCM). Still does not help with the pop at the end
+	// +127 to eliminate the pop when the sound starts (signed vs unsigned PCM). Still does not help with the pop at the end
 	byte prediction = (ptr[0] & 0x0f) + 127;
 	int step = 0;
 	int counter = 0;
@@ -118,6 +118,7 @@ bool Sound::playSound(const Common::String &name, WaitType waitType) {
 	Audio::AudioStream *audioStream = Audio::makeRawStream(decoded, (size - 2) * 2, rate, Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
 	_mixer->playStream(Audio::Mixer::kPlainSoundType, &_effectsHandle, audioStream, -1,  Audio::Mixer::kMaxChannelVolume);
 	_soundPlaying = true;
+	_curPriority = priority;
 
 	if (waitType == WAIT_RETURN_IMMEDIATELY) {
 		_diskSoundPlaying = true;
@@ -148,34 +149,24 @@ bool Sound::playSound(const Common::String &name, WaitType waitType) {
 	return retval;
 }
 
-void Sound::cacheSound(const Common::String &name, int index) {
-	// TODO
-	warning("TODO: Sound::cacheSound");
-}
+void Sound::playLoadedSound(int bufNum, WaitType waitType) {
+	if (_mixer->isSoundHandleActive(_effectsHandle) && (_curPriority > _vm->_scene->_sounds[bufNum]._priority))
+		return;
 
-void Sound::playLoadedSound(int bufNum, int waitMode) {
-	// TODO
-	warning("TODO: Sound::playLoadedSound");
-}
+	stopSound();
+	playSound(_vm->_scene->_sounds[bufNum]._name, waitType, _vm->_scene->_sounds[bufNum]._priority);
 
-void Sound::playCachedSound(int index) {
-	// TODO
-	warning("TODO: Sound::playCachedSound");
+	return;
 }
 
 void Sound::freeLoadedSounds() {
-	// TODO
-	warning("TODO: Sound::clearLoadedSound");
-}
-
-void Sound::clearCache() {
-	// TODO
-	warning("TODO: Sound::clearCache");
+	// As sounds are played with DisposeAfterUse::YES, stopping the sounds also
+	// frees them
+	stopSound();
 }
 
 void Sound::stopSound() {
-	// TODO
-	warning("TODO: Sound::stopSound");
+	_mixer->stopHandle(_effectsHandle);
 }
 
 void Sound::playMusic(const Common::String &name) {
diff --git a/engines/sherlock/sound.h b/engines/sherlock/sound.h
index 213a6f7..659df57 100644
--- a/engines/sherlock/sound.h
+++ b/engines/sherlock/sound.h
@@ -44,6 +44,7 @@ private:
 	SherlockEngine *_vm;
 	Audio::Mixer *_mixer;
 	Audio::SoundHandle _effectsHandle;
+	int _curPriority;
 
 	char decodeSample(char sample, byte& prediction, int& step);
 public:
@@ -63,13 +64,11 @@ public:
 
 	void syncSoundSettings();
 	void loadSound(const Common::String &name, int priority);
-	bool playSound(const Common::String &name, WaitType waitType = WAIT_RETURN_IMMEDIATELY);
-	void cacheSound(const Common::String &name, int index);
-	void playLoadedSound(int bufNum, int waitMode);
-	void playCachedSound(int index);
+	bool playSound(const Common::String &name, WaitType waitType, int priority = 100);
+	void playLoadedSound(int bufNum, WaitType waitType);
 	void freeLoadedSounds();
-	void clearCache();
 	void stopSound();
+
 	int loadSong(int songNumber);
 	void startSong();
 	void freeSong();
diff --git a/engines/sherlock/talk.cpp b/engines/sherlock/talk.cpp
index 3520a02..61f0004 100644
--- a/engines/sherlock/talk.cpp
+++ b/engines/sherlock/talk.cpp
@@ -1278,7 +1278,7 @@ void Talk::doScript(const Common::String &script) {
 				if (sound._voices) {
 					for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx)
 						tempString += str[idx];
-					sound.playSound(tempString);
+					sound.playSound(tempString, WAIT_RETURN_IMMEDIATELY);
 
 					// Set voices to wait for more
 					sound._voices = 2;
diff --git a/engines/sherlock/user_interface.cpp b/engines/sherlock/user_interface.cpp
index 8b3ee42..d65bd9c 100644
--- a/engines/sherlock/user_interface.cpp
+++ b/engines/sherlock/user_interface.cpp
@@ -1683,7 +1683,7 @@ void UserInterface::doTalkControl() {
 			people.setTalking(0);
 
 			if (!talk._statements[_selector]._voiceFile.empty() && sound._voices) {
-				sound.playSound(talk._statements[_selector]._voiceFile);
+				sound.playSound(talk._statements[_selector]._voiceFile, WAIT_RETURN_IMMEDIATELY);
 
 				// Set voices as an indicator for waiting
 				sound._voices = 2;


Commit: 1cdfeaa776b690ab092200f15d7aa02285fadb08
    https://github.com/scummvm/scummvm/commit/1cdfeaa776b690ab092200f15d7aa02285fadb08
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-12T19:14:39-04:00

Commit Message:
SHERLOCK: Fix buffer reference in randomTransition

Changed paths:
    engines/sherlock/screen.cpp



diff --git a/engines/sherlock/screen.cpp b/engines/sherlock/screen.cpp
index 2713d19..c236915 100644
--- a/engines/sherlock/screen.cpp
+++ b/engines/sherlock/screen.cpp
@@ -234,7 +234,7 @@ void Screen::randomTransition() {
 	}
 
 	// Make sure everything has been transferred
-	blitFrom(_backBuffer1);
+	blitFrom(*_backBuffer);
 }
 
 /**


Commit: 1e8c297d8043dcbfb63ea49ea47b9928f65d6dc2
    https://github.com/scummvm/scummvm/commit/1e8c297d8043dcbfb63ea49ea47b9928f65d6dc2
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-12T19:19:49-04:00

Commit Message:
SHERLOCK: Remove redundant check from mergeDirtyRects

Changed paths:
    engines/sherlock/screen.cpp



diff --git a/engines/sherlock/screen.cpp b/engines/sherlock/screen.cpp
index c236915..fb155bf 100644
--- a/engines/sherlock/screen.cpp
+++ b/engines/sherlock/screen.cpp
@@ -170,13 +170,6 @@ void Screen::addDirtyRect(const Common::Rect &r) {
 void Screen::mergeDirtyRects() {
 	Common::List<Common::Rect>::iterator rOuter, rInner;
 
-	// Ensure dirty rect list has at least two entries
-	rOuter = _dirtyRects.begin();
-	for (int i = 0; i < 2; ++i, ++rOuter) {
-		if (rOuter == _dirtyRects.end())
-			return;
-	}
-
 	// Process the dirty rect list to find any rects to merge
 	for (rOuter = _dirtyRects.begin(); rOuter != _dirtyRects.end(); ++rOuter) {
 		rInner = rOuter;


Commit: cf229ce72ca99401361659ff305faa78203675af
    https://github.com/scummvm/scummvm/commit/cf229ce72ca99401361659ff305faa78203675af
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-12T19:50:16-04:00

Commit Message:
SHERLOCK: Whitespace fixes

Changed paths:
    engines/sherlock/graphics.h
    engines/sherlock/people.h
    engines/sherlock/resources.cpp
    engines/sherlock/scalpel/scalpel.cpp
    engines/sherlock/scene.h



diff --git a/engines/sherlock/graphics.h b/engines/sherlock/graphics.h
index 91a65c8..d4a1584 100644
--- a/engines/sherlock/graphics.h
+++ b/engines/sherlock/graphics.h
@@ -37,7 +37,7 @@ private:
 protected:
 	virtual void addDirtyRect(const Common::Rect &r) {}
 public:
-    Surface(uint16 width, uint16 height);
+	Surface(uint16 width, uint16 height);
 	Surface();
 	virtual ~Surface();
 
diff --git a/engines/sherlock/people.h b/engines/sherlock/people.h
index ee16fab..f98c3db 100644
--- a/engines/sherlock/people.h
+++ b/engines/sherlock/people.h
@@ -32,11 +32,11 @@ namespace Sherlock {
 
 // People definitions
 enum PeopleId {
-	PLAYER        = 0,
-	AL            = 0,
-	PEG           = 1,
-	NUM_OF_PEOPLE = 2,		// Holmes and Watson
-	MAX_PEOPLE    = 66		// Total of all NPCs
+	PLAYER			= 0,
+	AL				= 0,
+	PEG				= 1,
+	NUM_OF_PEOPLE	= 2,		// Holmes and Watson
+	MAX_PEOPLE		= 66		// Total of all NPCs
 };
 
 // Animation sequence identifiers for characters
diff --git a/engines/sherlock/resources.cpp b/engines/sherlock/resources.cpp
index 3f74590..f50f780 100644
--- a/engines/sherlock/resources.cpp
+++ b/engines/sherlock/resources.cpp
@@ -294,7 +294,7 @@ void ImageFile::load(Common::SeekableReadStream &stream, bool skipPalette, bool
 	loadPalette(stream);
 
 	int streamSize = stream.size();
-    while (stream.pos() < streamSize) {
+	while (stream.pos() < streamSize) {
 		ImageFrame frame;
 		frame._width = stream.readUint16LE() + 1;
 		frame._height = stream.readUint16LE() + 1;
@@ -309,30 +309,30 @@ void ImageFile::load(Common::SeekableReadStream &stream, bool skipPalette, bool
 			frame._rleEncoded = stream.readByte() == 1;
 			frame._offset.x = stream.readByte();
 		}
-		frame._offset.y = stream.readByte();
 
+		frame._offset.y = stream.readByte();
 		frame._rleEncoded = !skipPalette && frame._rleEncoded;
 
 		if (frame._paletteBase) {
 			// Nibble packed frame data
 			frame._size = (frame._width * frame._height) / 2;
 		} else if (frame._rleEncoded) {
-            // this size includes the header size, which we subtract
+			// This size includes the header size, which we subtract
 			frame._size = stream.readUint16LE() - 11;
 			frame._rleMarker = stream.readByte();
-        } else {
+		} else {
 			// Uncompressed data
 			frame._size = frame._width * frame._height;
-        }
+		}
 
 		// Load data for frame and decompress it
 		byte *data = new byte[frame._size];
 		stream.read(data, frame._size);
-        decompressFrame(frame, data);
+		decompressFrame(frame, data);
 		delete[] data;
 
 		push_back(frame);
-    }
+	}
 }
 
 /**
@@ -372,17 +372,17 @@ void ImageFile::decompressFrame(ImageFrame &frame, const byte *src) {
 		}
 	} else if (frame._rleEncoded) {
 		// RLE encoded
-	    byte *dst = (byte *)frame._frame.getPixels();
+		byte *dst = (byte *)frame._frame.getPixels();
 
 		int frameSize = frame._width * frame._height;
 		while (frameSize > 0) {
 			if (*src == frame._rleMarker) {
-			    byte rleColor = src[1];
-			    byte rleCount = src[2];
-			    src += 3;
-			    frameSize -= rleCount;
-			    while (rleCount--)
-			        *dst++ = rleColor;
+				byte rleColor = src[1];
+				byte rleCount = src[2];
+				src += 3;
+				frameSize -= rleCount;
+				while (rleCount--)
+					*dst++ = rleColor;
 			} else {
 				*dst++ = *src++;
 				--frameSize;
diff --git a/engines/sherlock/scalpel/scalpel.cpp b/engines/sherlock/scalpel/scalpel.cpp
index 5d84a7f..6959e43 100644
--- a/engines/sherlock/scalpel/scalpel.cpp
+++ b/engines/sherlock/scalpel/scalpel.cpp
@@ -81,7 +81,7 @@ const int MAP_TRANSLATE[NUM_PLACES] = {
 };
 
 const byte MAP_SEQUENCES[3][MAX_FRAME] = {
-	{ 1, 1, 2, 3, 4, 0 },     // Overview Still
+	{ 1, 1, 2, 3, 4, 0 },		// Overview Still
 	{ 5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 0 },
 	{ 5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 0 }
 };
diff --git a/engines/sherlock/scene.h b/engines/sherlock/scene.h
index 8ef5d74..96714c4 100644
--- a/engines/sherlock/scene.h
+++ b/engines/sherlock/scene.h
@@ -33,8 +33,8 @@
 namespace Sherlock {
 
 #define SCENES_COUNT 63
-#define MAX_ZONES    40
-#define INFO_LINE   140
+#define MAX_ZONES	40
+#define INFO_LINE	140
 
 class SherlockEngine;
 


Commit: 5370b71fbffd80a8a75d7bf5f91573851427a0f5
    https://github.com/scummvm/scummvm/commit/5370b71fbffd80a8a75d7bf5f91573851427a0f5
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-12T19:55:53-04:00

Commit Message:
SHERLOCK: Rename object loading methods from synchronize to load

Changed paths:
    engines/sherlock/objects.cpp
    engines/sherlock/objects.h
    engines/sherlock/scene.cpp



diff --git a/engines/sherlock/objects.cpp b/engines/sherlock/objects.cpp
index acb13dd..b4371cd 100644
--- a/engines/sherlock/objects.cpp
+++ b/engines/sherlock/objects.cpp
@@ -365,9 +365,9 @@ void Sprite::checkSprite() {
 /*----------------------------------------------------------------*/
 
 /**
- * Synchronize the data for a savegame
+ * Load the data for the action
  */
-void ActionType::synchronize(Common::SeekableReadStream &s) {
+void ActionType::load(Common::SeekableReadStream &s) {
 	char buffer[12];
 
 	_cAnimNum = s.readByte();
@@ -391,9 +391,9 @@ UseType::UseType() {
 }
 
 /**
- * Synchronize the data for a savegame
+ * Load the data for the UseType
  */
-void UseType::synchronize(Common::SeekableReadStream &s) {
+void UseType::load(Common::SeekableReadStream &s) {
 	char buffer[12];
 
 	_cAnimNum = s.readByte();
@@ -459,9 +459,9 @@ Object::Object() {
 }
 
 /**
- * Load the object data from the passed stream
+ * Load the data for the object
  */
-void Object::synchronize(Common::SeekableReadStream &s) {
+void Object::load(Common::SeekableReadStream &s) {
 	char buffer[41];
 	s.read(buffer, 12);
 	_name = Common::String(buffer);
@@ -504,7 +504,7 @@ void Object::synchronize(Common::SeekableReadStream &s) {
 	_misc = s.readByte();
 	_maxFrames = s.readUint16LE();
 	_flags = s.readByte();
-	_aOpen.synchronize(s);
+	_aOpen.load(s);
 	_aType = (AType)s.readByte();
 	_lookFrames = s.readByte();
 	_seqCounter = s.readByte();
@@ -512,18 +512,18 @@ void Object::synchronize(Common::SeekableReadStream &s) {
 	_lookPosition.y = s.readByte();
 	_lookFacing = s.readByte();
 	_lookcAnim = s.readByte();
-	_aClose.synchronize(s);
+	_aClose.load(s);
 	_seqStack = s.readByte();
 	_seqTo = s.readByte();
 	_descOffset = s.readUint16LE();
 	_seqCounter2 = s.readByte();
 	_seqSize = s.readUint16LE();
 	s.skip(1);
-	_aMove.synchronize(s);
+	_aMove.load(s);
 	s.skip(8);
 
 	for (int idx = 0; idx < 4; ++idx)
-		_use[idx].synchronize(s);
+		_use[idx].load(s);
 }
 
 /**
@@ -1099,9 +1099,9 @@ const Common::Rect Object::getOldBounds() const {
 /*----------------------------------------------------------------*/
 
 /**
- * Synchronize the data for a savegame
+ * Load the data for the animation
  */
-void CAnim::synchronize(Common::SeekableReadStream &s) {
+void CAnim::load(Common::SeekableReadStream &s) {
 	char buffer[12];
 	s.read(buffer, 12);
 	_name = Common::String(buffer);
diff --git a/engines/sherlock/objects.h b/engines/sherlock/objects.h
index 52bd15c..4068973 100644
--- a/engines/sherlock/objects.h
+++ b/engines/sherlock/objects.h
@@ -148,7 +148,7 @@ struct ActionType {
 	int _cAnimSpeed;
 	Common::String _names[4];
 
-	void synchronize(Common::SeekableReadStream &s);
+	void load(Common::SeekableReadStream &s);
 };
 
 struct UseType {
@@ -161,7 +161,7 @@ struct UseType {
 	Common::String _target;
 
 	UseType();
-	void synchronize(Common::SeekableReadStream &s);
+	void load(Common::SeekableReadStream &s);
 };
 
 class Object {
@@ -222,7 +222,7 @@ public:
 
 	Object();
 
-	void synchronize(Common::SeekableReadStream &s);
+	void load(Common::SeekableReadStream &s);
 
 	void toggleHidden();
 
@@ -255,7 +255,7 @@ struct CAnim {
 	Common::Point _teleportPos;		// Location Holmes shoul teleport to after
 	int _teleportDir;					// playing canim
 
-	void synchronize(Common::SeekableReadStream &s);
+	void load(Common::SeekableReadStream &s);
 };
 
 struct SceneImage {
diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp
index 4b0cbee..f473004 100644
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@ -261,7 +261,7 @@ bool Scene::loadScene(const Common::String &filename) {
 
 		_bgShapes.resize(bgHeader._numStructs);
 		for (int idx = 0; idx < bgHeader._numStructs; ++idx)
-			_bgShapes[idx].synchronize(*infoStream);
+			_bgShapes[idx].load(*infoStream);
 
 		if (bgHeader._descSize) {
 			_descText.resize(bgHeader._descSize);
@@ -318,7 +318,7 @@ bool Scene::loadScene(const Common::String &filename) {
 
 			_cAnim.resize(bgHeader._numcAnimations);
 			for (uint idx = 0; idx < _cAnim.size(); ++idx)
-				_cAnim[idx].synchronize(*canimStream);
+				_cAnim[idx].load(*canimStream);
 
 			delete canimStream;
 		}


Commit: fdb39d8170de2796b2ae406d382e1e601f3d987c
    https://github.com/scummvm/scummvm/commit/fdb39d8170de2796b2ae406d382e1e601f3d987c
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-12T20:40:47-04:00

Commit Message:
SHERLOCK: Fix speed of animations

Changed paths:
    engines/sherlock/animation.cpp



diff --git a/engines/sherlock/animation.cpp b/engines/sherlock/animation.cpp
index a8edf77..1d6c12f 100644
--- a/engines/sherlock/animation.cpp
+++ b/engines/sherlock/animation.cpp
@@ -114,7 +114,7 @@ bool Animation::play(const Common::String &filename, int minDelay, int fade,
 					sound.playSound(fname, WAIT_RETURN_IMMEDIATELY);
 			}
 
-			events.wait(speed);
+			events.wait(speed * 3);
 		}
 
 		if (events.kbHit()) {


Commit: d4b964c92b7c725cc193298b549c68a251607763
    https://github.com/scummvm/scummvm/commit/d4b964c92b7c725cc193298b549c68a251607763
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-12T21:01:57-04:00

Commit Message:
SHERLOCK: Add missing setting of _oldSelector

Changed paths:
    engines/sherlock/user_interface.cpp



diff --git a/engines/sherlock/user_interface.cpp b/engines/sherlock/user_interface.cpp
index d65bd9c..41505b8 100644
--- a/engines/sherlock/user_interface.cpp
+++ b/engines/sherlock/user_interface.cpp
@@ -1612,6 +1612,8 @@ void UserInterface::doTalkControl() {
 		if (_selector != -1)
 			talk.talkLine(_selector, talk._statements[_selector]._talkMap, TALK_FOREGROUND,
 				talk._statements[_selector]._talkPos.top, true);
+
+		_oldSelector = _selector;
 	}
 
 	if (events._released || _keyboardInput) {


Commit: 8432e7584c95a925352a33768fff7c66f99176cf
    https://github.com/scummvm/scummvm/commit/8432e7584c95a925352a33768fff7c66f99176cf
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-12T22:02:59-04:00

Commit Message:
SHERLOCK: Beginnings of Rose Tattoo engine

Changed paths:
    engines/sherlock/decompress.cpp
    engines/sherlock/map.cpp
    engines/sherlock/objects.cpp
    engines/sherlock/objects.h
    engines/sherlock/resources.cpp
    engines/sherlock/resources.h
    engines/sherlock/scalpel/scalpel.cpp
    engines/sherlock/scene.cpp
    engines/sherlock/scene.h
    engines/sherlock/screen.cpp
    engines/sherlock/screen.h
    engines/sherlock/sherlock.cpp
    engines/sherlock/sherlock.h
    engines/sherlock/tattoo/tattoo.cpp
    engines/sherlock/tattoo/tattoo.h
    engines/sherlock/user_interface.cpp



diff --git a/engines/sherlock/decompress.cpp b/engines/sherlock/decompress.cpp
index dfa5732..8e02da3 100644
--- a/engines/sherlock/decompress.cpp
+++ b/engines/sherlock/decompress.cpp
@@ -77,4 +77,52 @@ Common::SeekableReadStream *decompressLZ(Common::SeekableReadStream &source, int
 	return outS;
 }
 
+
+/**
+ * Decompresses a Rose Tattoo resource
+ *
+Common::SeekableReadStream *decompress32(Common::SeekableReadStream &source, int32 outSize) {
+	if (outSize == -1) {
+		outSize = source.readSint32LE();
+	}
+
+	byte lzWindow[8192];
+	byte *outBuffer = new byte[outSize];
+	byte *outBufferEnd = outBuffer + outSize;
+	Common::MemoryReadStream *outS = new Common::MemoryReadStream(outBuffer, outSize, DisposeAfterUse::YES);
+
+	memset(lzWindow, 0xFF, 8192);
+	int lzWindowPos = 0xFEE;
+	int cmd = 0;
+
+	do {
+		cmd >>= 1;
+		if (!(cmd & 0x100))
+			cmd = source.readByte() | 0xFF00;
+
+		if (cmd & 1) {
+			byte literal = source.readByte();
+			*outBuffer++ = literal;
+			lzWindow[lzWindowPos] = literal;
+			lzWindowPos = (lzWindowPos + 1) & 0x0FFF;
+		} else {
+			int copyPos, copyLen;
+			copyPos = source.readByte();
+			copyLen = source.readByte();
+			copyPos = copyPos | ((copyLen & 0xF0) << 4);
+			copyLen = (copyLen & 0x0F) + 3;
+			while (copyLen--) {
+				byte literal = lzWindow[copyPos];
+				copyPos = (copyPos + 1) & 0x0FFF;
+				*outBuffer++ = literal;
+				lzWindow[lzWindowPos] = literal;
+				lzWindowPos = (lzWindowPos + 1) & 0x0FFF;
+			}
+		}
+	} while (outBuffer < outBufferEnd);
+
+	return outS;
+}
+*/
+
 } // namespace Sherlock
diff --git a/engines/sherlock/map.cpp b/engines/sherlock/map.cpp
index e178dec..c2eedd4 100644
--- a/engines/sherlock/map.cpp
+++ b/engines/sherlock/map.cpp
@@ -22,6 +22,7 @@
 
 #include "sherlock/map.h"
 #include "sherlock/sherlock.h"
+#include "common/system.h"
 
 namespace Sherlock {
 
@@ -52,7 +53,7 @@ const byte *MapPaths::getPath(int srcLocation, int destLocation) {
 
 /*----------------------------------------------------------------*/
 
-Map::Map(SherlockEngine *vm): _vm(vm), _topLine(SHERLOCK_SCREEN_WIDTH, 12) {
+Map::Map(SherlockEngine *vm): _vm(vm), _topLine(g_system->getWidth(), 12) {
 	_active = false;
 	_mapCursors = nullptr;
 	_shapes = nullptr;
@@ -94,8 +95,13 @@ void Map::loadSequences(int count, const byte *seq) {
  * Load data  needed for the map
  */
 void Map::loadData() {
+	// TODO: Remove this
+	if (_vm->getGameID() == GType_RoseTattoo)
+		return;
+
 	// Load the list of location names
-	Common::SeekableReadStream *txtStream = _vm->_res->load("chess.txt");
+	Common::SeekableReadStream *txtStream = _vm->_res->load(
+		_vm->getGameID() == GType_SerratedScalpel ? "chess.txt" : "map.txt");
 
 	int streamSize = txtStream->size();
 	while (txtStream->pos() < streamSize) {
diff --git a/engines/sherlock/objects.cpp b/engines/sherlock/objects.cpp
index b4371cd..772f9d2 100644
--- a/engines/sherlock/objects.cpp
+++ b/engines/sherlock/objects.cpp
@@ -122,8 +122,8 @@ void Sprite::adjustSprite() {
 			people.gotoStand(*this);
 		}
 	} else if (!map._active) {
-		_position.y = CLIP((int)_position.y, UPPER_LIMIT, LOWER_LIMIT);
-		_position.x = CLIP((int)_position.x, LEFT_LIMIT, RIGHT_LIMIT);
+		_position.y = CLIP((int)_position.y, (int)UPPER_LIMIT, (int)LOWER_LIMIT);
+		_position.x = CLIP((int)_position.x, (int)LEFT_LIMIT, (int)RIGHT_LIMIT);
 	}
 
 	if (!map._active || (map._frameChangeFlag = !map._frameChangeFlag))
@@ -393,9 +393,14 @@ UseType::UseType() {
 /**
  * Load the data for the UseType
  */
-void UseType::load(Common::SeekableReadStream &s) {
+void UseType::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
 	char buffer[12];
 
+	if (isRoseTattoo) {
+		s.read(buffer, 12);
+		_verb = Common::String(buffer);
+	}
+
 	_cAnimNum = s.readByte();
 	_cAnimSpeed = s.readByte();
 	if (_cAnimSpeed & 0x80)
@@ -407,9 +412,12 @@ void UseType::load(Common::SeekableReadStream &s) {
 	}
 
 	_useFlag = s.readSint16LE();
-	_dFlag[0] = s.readSint16LE();
-	_lFlag[0] = s.readSint16LE();
-	_lFlag[1] = s.readSint16LE();
+
+	if (!isRoseTattoo) {
+		_dFlag[0] = s.readSint16LE();
+		_lFlag[0] = s.readSint16LE();
+		_lFlag[1] = s.readSint16LE();
+	}
 
 	s.read(buffer, 12);
 	_target = Common::String(buffer);
@@ -456,12 +464,19 @@ Object::Object() {
 	_descOffset = 0;
 	_seqCounter2 = 0;
 	_seqSize = 0;
+
+	_quickDraw = 0;
+	_scaleVal = 0;
+	_requiredFlag1 = 0;
+	_gotoSeq = 0;
+	_talkSeq = 0;
+	_restoreSlot = 0;
 }
 
 /**
  * Load the data for the object
  */
-void Object::load(Common::SeekableReadStream &s) {
+void Object::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
 	char buffer[41];
 	s.read(buffer, 12);
 	_name = Common::String(buffer);
@@ -496,7 +511,8 @@ void Object::load(Common::SeekableReadStream &s) {
 	_pickup = s.readByte();
 	_defaultCommand = s.readByte();
 	_lookFlag = s.readUint16LE();
-	_pickupFlag = s.readUint16LE();
+	if (!isRoseTattoo)
+		_pickupFlag = s.readUint16LE();
 	_requiredFlag = s.readSint16LE();
 	_noShapeSize.x = s.readUint16LE();
 	_noShapeSize.y = s.readUint16LE();
@@ -504,26 +520,45 @@ void Object::load(Common::SeekableReadStream &s) {
 	_misc = s.readByte();
 	_maxFrames = s.readUint16LE();
 	_flags = s.readByte();
-	_aOpen.load(s);
+
+	if (!isRoseTattoo)
+		_aOpen.load(s);
+
 	_aType = (AType)s.readByte();
 	_lookFrames = s.readByte();
 	_seqCounter = s.readByte();
 	_lookPosition.x = s.readUint16LE();
-	_lookPosition.y = s.readByte();
+	_lookPosition.y = isRoseTattoo ? s.readSint16LE() : s.readByte();
 	_lookFacing = s.readByte();
 	_lookcAnim = s.readByte();
-	_aClose.load(s);
+
+	if (!isRoseTattoo)
+		_aClose.load(s);
+
 	_seqStack = s.readByte();
 	_seqTo = s.readByte();
 	_descOffset = s.readUint16LE();
 	_seqCounter2 = s.readByte();
 	_seqSize = s.readUint16LE();
-	s.skip(1);
-	_aMove.load(s);
-	s.skip(8);
 
-	for (int idx = 0; idx < 4; ++idx)
-		_use[idx].load(s);
+	if (isRoseTattoo) {
+		for (int idx = 0; idx < 6; ++idx)
+			_use[idx].load(s, true);
+
+		_quickDraw = s.readByte();
+		_scaleVal = s.readUint16LE();
+		_requiredFlag1 = s.readUint16LE();
+		_gotoSeq = s.readByte();
+		_talkSeq = s.readByte();
+		_restoreSlot = s.readByte();
+	} else {
+		s.skip(1);
+		_aMove.load(s);
+		s.skip(8);
+
+		for (int idx = 0; idx < 4; ++idx)
+			_use[idx].load(s, false);
+	}
 }
 
 /**
diff --git a/engines/sherlock/objects.h b/engines/sherlock/objects.h
index 4068973..2073f06 100644
--- a/engines/sherlock/objects.h
+++ b/engines/sherlock/objects.h
@@ -159,9 +159,10 @@ struct UseType {
 	int _dFlag[1];
 	int _lFlag[2];
 	Common::String _target;
+	Common::String _verb;
 
 	UseType();
-	void load(Common::SeekableReadStream &s);
+	void load(Common::SeekableReadStream &s, bool isRoseTattoo);
 };
 
 class Object {
@@ -197,32 +198,42 @@ public:
 	int _pickup;
 	int _defaultCommand;			// Default right-click command
 	int _lookFlag;					// Which flag LOOK   will set (if any)
-	int _pickupFlag;				// Which flag PICKUP will set (if any)
 	int _requiredFlag;				// Object will be hidden if not set
 	Common::Point _noShapeSize;		// Size of a NO_SHAPE
 	int _status;					// Status (open/closed, moved/not)
 	int8 _misc;						// Misc field -- use varies with type
 	int _maxFrames;					// Number of frames
 	int _flags;						// Tells if object can be walked behind
-	ActionType _aOpen;				// Holds data for moving object
 	AType _aType;					// Tells if this is an object, person, talk, etc.
 	int _lookFrames;				// How many frames to play of the look anim before pausing
 	int _seqCounter;				// How many times this sequence has been executed
 	Common::Point _lookPosition;	// Where to walk when examining object
 	int _lookFacing;				// Direction to face when examining object
 	int _lookcAnim;
-	ActionType _aClose;
 	int _seqStack;					// Allows gosubs to return to calling frame
 	int _seqTo;						// Allows 1-5, 8-3 type sequences encoded in 2 bytes
 	uint _descOffset;					// Tells where description starts in DescText
 	int _seqCounter2;				// Counter of calling frame sequence
 	uint _seqSize;					// Tells where description starts
+	UseType _use[6];				// Serrated Scalpel uses 4, Rose Tattoo 6
+
+	// Serrated Scalpel fields
+	int _pickupFlag;				// Which flag PICKUP will set (if any)
+	ActionType _aOpen;				// Holds data for moving object
+	ActionType _aClose;
 	ActionType _aMove;
-	UseType _use[4];
+
+	// Rose Tattoo fields
+	int _quickDraw;
+	int _scaleVal;
+	int _requiredFlag1;
+	int _gotoSeq;
+	int _talkSeq;
+	int _restoreSlot;
 
 	Object();
 
-	void load(Common::SeekableReadStream &s);
+	void load(Common::SeekableReadStream &s, bool isRoseTattoo);
 
 	void toggleHidden();
 
diff --git a/engines/sherlock/resources.cpp b/engines/sherlock/resources.cpp
index f50f780..9f2704a 100644
--- a/engines/sherlock/resources.cpp
+++ b/engines/sherlock/resources.cpp
@@ -107,9 +107,7 @@ Resources::Resources() {
 
 	addToCache("vgs.lib");
 	addToCache("talk.lib");
-	addToCache("sequence.txt");
 	addToCache("journal.txt");
-	addToCache("portrait.lib");
 }
 
 /**
@@ -122,8 +120,11 @@ void Resources::addToCache(const Common::String &filename) {
 	// Check to see if the file is a library
 	Common::SeekableReadStream *stream = load(filename);
 	uint32 header = stream->readUint32BE();
+
 	if (header == MKTAG('L', 'I', 'B', 26))
-		loadLibraryIndex(filename, stream);
+		loadLibraryIndex(filename, stream, false);
+	else if (header == MKTAG('L', 'I', 'C', 26))
+		loadLibraryIndex(filename, stream, true);
 
 	delete stream;
 }
@@ -193,7 +194,7 @@ Common::SeekableReadStream *Resources::load(const Common::String &filename, cons
 
 	// Check if the library has already had it's index read, and if not, load it
 	if (!_indexes.contains(libraryFile))
-		loadLibraryIndex(libraryFile, libStream);
+		loadLibraryIndex(libraryFile, libStream, false);
 
 	// Extract the data for the specified resource and return it
 	LibraryEntry &entry = _indexes[libraryFile][filename];
@@ -216,7 +217,7 @@ bool Resources::exists(const Common::String &filename) const {
  * Reads in the index from a library file, and caches it's index for later use
  */
 void Resources::loadLibraryIndex(const Common::String &libFilename,
-		Common::SeekableReadStream *stream) {
+		Common::SeekableReadStream *stream, bool isNewStyle) {
 	uint32 offset, nextOffset;
 
 	// Create an index entry
@@ -227,6 +228,9 @@ void Resources::loadLibraryIndex(const Common::String &libFilename,
 	stream->seek(4);
 	int count = stream->readUint16LE();
 
+	if (isNewStyle)
+		stream->seek((count + 1) * 8, SEEK_CUR);
+
 	// Loop through reading in the entries
 	for (int idx = 0; idx < count; ++idx) {
 		// Read the name of the resource
@@ -304,10 +308,12 @@ void ImageFile::load(Common::SeekableReadStream &stream, bool skipPalette, bool
 			// Animation cutscene image files use a 16-bit x offset
 			frame._offset.x = stream.readUint16LE();
 			frame._rleEncoded = (frame._offset.x & 0xff) == 1;
+			frame._offset.y = stream.readByte();
 		} else {
 			// Standard image files have a separate byte for the RLE flag, and an 8-bit X offset
 			frame._rleEncoded = stream.readByte() == 1;
 			frame._offset.x = stream.readByte();
+			frame._offset.y = stream.readByte();
 		}
 
 		frame._offset.y = stream.readByte();
diff --git a/engines/sherlock/resources.h b/engines/sherlock/resources.h
index e1f97f1..bbaac60 100644
--- a/engines/sherlock/resources.h
+++ b/engines/sherlock/resources.h
@@ -70,7 +70,8 @@ private:
 	LibraryIndexes _indexes;
 	int _resourceIndex;
 
-	void loadLibraryIndex(const Common::String &libFilename, Common::SeekableReadStream *stream);
+	void loadLibraryIndex(const Common::String &libFilename, Common::SeekableReadStream *stream,
+		bool isNewStyle);
 public:
 	Resources();
 
diff --git a/engines/sherlock/scalpel/scalpel.cpp b/engines/sherlock/scalpel/scalpel.cpp
index 6959e43..b982079 100644
--- a/engines/sherlock/scalpel/scalpel.cpp
+++ b/engines/sherlock/scalpel/scalpel.cpp
@@ -23,6 +23,7 @@
 #include "sherlock/scalpel/scalpel.h"
 #include "sherlock/sherlock.h"
 #include "sherlock/animation.h"
+#include "engines/util.h"
 
 namespace Sherlock {
 
@@ -242,6 +243,9 @@ ScalpelEngine::~ScalpelEngine() {
  * Game initialization
  */
 void ScalpelEngine::initialize() {
+	initGraphics(320, 200, false);
+
+	// Let the base engine intialize
 	SherlockEngine::initialize();
 
 	_darts = new Darts(this);
@@ -250,11 +254,13 @@ void ScalpelEngine::initialize() {
 	_flags[3] = true;		// Turn on Alley
 	_flags[39] = true;		// Turn on Baker Street
 
-	if (!getIsDemo()) {
+	// Add some more files to the cache
+	_res->addToCache("sequence.txt");
+	_res->addToCache("portrait.lib");
+
 	// Load the map co-ordinates for each scene and sequence data
 	_map->loadPoints(NUM_PLACES, &MAP_X[0], &MAP_Y[0], &MAP_TRANSLATE[0]);
 	_map->loadSequences(3, &MAP_SEQUENCES[0][0]);
-	}
 
 	// Load the inventory
 	loadInventory();
@@ -454,9 +460,9 @@ bool ScalpelEngine::scrollCredits() {
 			_screen->transBlitFrom(creditsImages[1], Common::Point(10, 400 - idx), false, 0);
 
 		// Don't show credit text on the top and bottom ten rows of the screen
-		_screen->blitFrom(_screen->_backBuffer1, Common::Point(0, 0), Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, 10));
-		_screen->blitFrom(_screen->_backBuffer1, Common::Point(0, SHERLOCK_SCREEN_HEIGHT - 10),
-			Common::Rect(0, SHERLOCK_SCREEN_HEIGHT - 10, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
+		_screen->blitFrom(_screen->_backBuffer1, Common::Point(0, 0), Common::Rect(0, 0, _screen->w, 10));
+		_screen->blitFrom(_screen->_backBuffer1, Common::Point(0, _screen->h - 10),
+			Common::Rect(0, _screen->h - 10, _screen->w, _screen->h));
 
 		_events->delay(100);
 	}
diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp
index f473004..d4662ed 100644
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@ -24,16 +24,42 @@
 #include "sherlock/sherlock.h"
 #include "sherlock/scalpel/scalpel.h"
 #include "sherlock/decompress.h"
+#include "sherlock/screen.h"
 
 namespace Sherlock {
 
-void BgFileHeader::synchronize(Common::SeekableReadStream &s) {
+BgFileHeader::BgFileHeader() {
+	_numStructs = -1;
+	_numImages = -1;
+	_numcAnimations = -1;
+	_descSize = -1;
+	_seqSize = -1;
+
+	// Serrated Scalpel
+	_fill = -1;
+
+	// Rose Tattoo
+	_scrollSize = -1;
+	_bytesWritten = -1;
+	_fadeStyle = -1;
+	Common::fill(&_palette[0], &_palette[PALETTE_SIZE], 0);
+}
+
+void BgFileHeader::synchronize(Common::SeekableReadStream &s, bool isRoseTattoo) {
 	_numStructs = s.readUint16LE();
 	_numImages = s.readUint16LE();
 	_numcAnimations = s.readUint16LE();
 	_descSize = s.readUint16LE();
 	_seqSize = s.readUint16LE();
-	_fill = s.readUint16LE();
+
+	if (isRoseTattoo) {
+		_scrollSize = s.readUint16LE();
+		_bytesWritten = s.readUint32LE();
+		_fadeStyle = s.readByte();
+	} else {
+		_fill = s.readUint16LE();
+
+	}
 }
 
 /*----------------------------------------------------------------*/
@@ -215,6 +241,7 @@ bool Scene::loadScene(const Common::String &filename) {
 	Sound &sound = *_vm->_sound;
 	UserInterface &ui = *_vm->_ui;
 	bool flag;
+	Common::Array<BgfileheaderInfo> bgInfo;
 
 	_walkedInScene = false;
 
@@ -229,7 +256,7 @@ bool Scene::loadScene(const Common::String &filename) {
 	_sequenceBuffer.clear();
 
 	//
-	// Load background shapes from <filename>.rrm
+	// Load the room resource file for the scene
 	//
 
 	Common::String rrmFile = filename + ".rrm";
@@ -238,30 +265,52 @@ bool Scene::loadScene(const Common::String &filename) {
 		Common::SeekableReadStream *rrmStream = _vm->_res->load(rrmFile);
 
 		rrmStream->seek(39);
-		_version = rrmStream->readByte();
-		_lzwMode = _version == 10;
+		if (_vm->getGameID() == GType_SerratedScalpel) {
+			_version = rrmStream->readByte();
+			_lzwMode = _version == 10;
+		} else {
+			_lzwMode = rrmStream->readByte() > 0;
+		}
 
 		// Go to header and read it in
 		rrmStream->seek(rrmStream->readUint32LE());
+
 		BgFileHeader bgHeader;
-		bgHeader.synchronize(*rrmStream);
+		bgHeader.synchronize(*rrmStream, _vm->getGameID() == GType_RoseTattoo);
 		_invGraphicItems = bgHeader._numImages + 1;
 
+		if (_vm->getGameID() == GType_RoseTattoo) {
+			screen.initPaletteFade(bgHeader._bytesWritten);
+			screen.fadeRead(*rrmStream, screen._cMap, PALETTE_SIZE);
+			screen.setupBGArea(screen._cMap);
+
+			screen.initScrollVars();
+
+			// Read in background
+			if (_lzwMode) {
+				Common::SeekableReadStream *stream = decompressLZ(*rrmStream, SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCREEN_HEIGHT);
+				stream->read(screen._backBuffer1.getPixels(), stream->size());
+				delete stream;
+			} else {
+				rrmStream->read(screen._backBuffer1.getPixels(), SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCREEN_HEIGHT);
+			}
+		} 
+
 		// Read in the shapes header info
-		Common::Array<BgfileheaderInfo> bgInfo;
 		bgInfo.resize(bgHeader._numStructs);
 
 		for (uint idx = 0; idx < bgInfo.size(); ++idx)
 			bgInfo[idx].synchronize(*rrmStream);
 
 		// Read information
+		int shapeSize = _vm->getGameID() == GType_SerratedScalpel ? 569 : 591;
 		Common::SeekableReadStream *infoStream = !_lzwMode ? rrmStream :
-			decompressLZ(*rrmStream, bgHeader._numImages * 569 +
+			decompressLZ(*rrmStream, bgHeader._numImages * shapeSize +
 				bgHeader._descSize + bgHeader._seqSize);
 
 		_bgShapes.resize(bgHeader._numStructs);
 		for (int idx = 0; idx < bgHeader._numStructs; ++idx)
-			_bgShapes[idx].load(*infoStream);
+			_bgShapes[idx].load(*infoStream, _vm->getGameID() == GType_RoseTattoo);
 
 		if (bgHeader._descSize) {
 			_descText.resize(bgHeader._descSize);
diff --git a/engines/sherlock/scene.h b/engines/sherlock/scene.h
index 96714c4..b4b88fa 100644
--- a/engines/sherlock/scene.h
+++ b/engines/sherlock/scene.h
@@ -29,6 +29,7 @@
 #include "common/serializer.h"
 #include "sherlock/objects.h"
 #include "sherlock/resources.h"
+#include "sherlock/screen.h"
 
 namespace Sherlock {
 
@@ -44,9 +45,19 @@ struct BgFileHeader {
 	int _numcAnimations;
 	int _descSize;
 	int _seqSize;
+
+	// Serrated Scalpel
 	int _fill;
 
-	void synchronize(Common::SeekableReadStream &s);
+	// Rose Tattoo
+	int _scrollSize;
+	int _bytesWritten;				// Size of the main body of the RRM
+	int _fadeStyle;					// Fade style
+	byte _palette[PALETTE_SIZE];	// Palette
+
+
+	BgFileHeader();
+	void synchronize(Common::SeekableReadStream &s, bool isRoseTattoo);
 };
 
 struct BgfileheaderInfo {
diff --git a/engines/sherlock/screen.cpp b/engines/sherlock/screen.cpp
index fb155bf..0ca10b4 100644
--- a/engines/sherlock/screen.cpp
+++ b/engines/sherlock/screen.cpp
@@ -28,9 +28,9 @@
 
 namespace Sherlock {
 
-Screen::Screen(SherlockEngine *vm) : Surface(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT), _vm(vm),
-		_backBuffer1(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT),
-		_backBuffer2(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT),
+Screen::Screen(SherlockEngine *vm) : Surface(g_system->getWidth(), g_system->getHeight()), _vm(vm),
+		_backBuffer1(g_system->getWidth(), g_system->getHeight()),
+		_backBuffer2(g_system->getWidth(), g_system->getHeight()),
 		_backBuffer(&_backBuffer1) {
 	_transitionSeed = 1;
 	_fadeStyle = false;
@@ -38,11 +38,19 @@ Screen::Screen(SherlockEngine *vm) : Surface(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCR
 	_fontHeight = 0;
 	Common::fill(&_cMap[0], &_cMap[PALETTE_SIZE], 0);
 	Common::fill(&_sMap[0], &_sMap[PALETTE_SIZE], 0);
+	Common::fill(&_tMap[0], &_tMap[PALETTE_SIZE], 0);
 	setFont(1);
 
 	// Set dummy surface used for restricted scene drawing
 	_sceneSurface.format = Graphics::PixelFormat::createFormatCLUT8();
-	_sceneSurface.pitch = SHERLOCK_SCREEN_WIDTH;
+	_sceneSurface.pitch = pitch;
+
+	// Rose Tattoo specific fields
+	_fadeBytesRead = _fadeBytesToRead = 0;
+	_oldFadePercent = 0;
+	_scrollSize = 0;
+	_currentScroll = 0;
+	_targetScroll = 0;
 }
 
 Screen::~Screen() {
@@ -213,7 +221,7 @@ void Screen::randomTransition() {
 		_transitionSeed = _transitionSeed * TRANSITION_MULTIPLIER + 1;
 		int offset = _transitionSeed & 65535;
 
-		if (offset < (SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCREEN_HEIGHT))
+		if (offset < (this->w * this->h))
 			*((byte *)getPixels() + offset) = *((const byte *)_backBuffer->getPixels() + offset);
 
 		if (idx != 0 && (idx % 100) == 0) {
@@ -236,12 +244,12 @@ void Screen::randomTransition() {
 void Screen::verticalTransition() {
 	Events &events = *_vm->_events;
 
-	byte table[SHERLOCK_SCREEN_WIDTH];
-	Common::fill(&table[0], &table[SHERLOCK_SCREEN_WIDTH], 0);
+	byte table[640];
+	Common::fill(&table[0], &table[640], 0);
 
-	for (int yp = 0; yp < SHERLOCK_SCREEN_HEIGHT; ++yp) {
-		for (int xp = 0; xp < SHERLOCK_SCREEN_WIDTH; ++xp) {
-			int temp = (table[xp] >= 197) ? SHERLOCK_SCREEN_HEIGHT - table[xp] :
+	for (int yp = 0; yp < this->h; ++yp) {
+		for (int xp = 0; xp < this->w; ++xp) {
+			int temp = (table[xp] >= (this->h - 3)) ? this->h - table[xp] :
 				_vm->getRandomNumber(3) + 1;
 
 			if (temp) {
@@ -261,7 +269,7 @@ void Screen::verticalTransition() {
 void Screen::restoreBackground(const Common::Rect &r) {
 	if (r.width() > 0 && r.height() > 0) {
 		Common::Rect tempRect = r;
-		tempRect.clip(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCENE_HEIGHT));
+		tempRect.clip(Common::Rect(0, 0, this->w, SHERLOCK_SCENE_HEIGHT));
 
 		if (tempRect.isValidRect())
 			_backBuffer1.blitFrom(_backBuffer2, Common::Point(tempRect.left, tempRect.top), tempRect);
@@ -281,7 +289,7 @@ void Screen::slamArea(int16 xp, int16 yp, int16 width, int16 height) {
 void Screen::slamRect(const Common::Rect &r) {
 	if (r.width() && r.height() > 0) {
 		Common::Rect tempRect = r;
-		tempRect.clip(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
+		tempRect.clip(Common::Rect(0, 0, this->w, this->h));
 
 		if (tempRect.isValidRect())
 			blitFrom(*_backBuffer, Common::Point(tempRect.left, tempRect.top), tempRect);
@@ -338,13 +346,13 @@ void Screen::print(const Common::Point &pt, byte color, const char *formatStr, .
 	pos.y--;		// Font is always drawing one line higher
 	if (!pos.x)
 		// Center text horizontally
-		pos.x = (SHERLOCK_SCREEN_WIDTH - width) / 2;
+		pos.x = (this->w - width) / 2;
 
 	Common::Rect textBounds(pos.x, pos.y, pos.x + width, pos.y + _fontHeight);
-	if (textBounds.right > SHERLOCK_SCREEN_WIDTH)
-		textBounds.moveTo(SHERLOCK_SCREEN_WIDTH - width, textBounds.top);
-	if (textBounds.bottom > SHERLOCK_SCREEN_HEIGHT)
-		textBounds.moveTo(textBounds.left, SHERLOCK_SCREEN_HEIGHT - _fontHeight);
+	if (textBounds.right > this->w)
+		textBounds.moveTo(this->w - width, textBounds.top);
+	if (textBounds.bottom > this->h)
+		textBounds.moveTo(textBounds.left, this->h - _fontHeight);
 
 	// Write out the string at the given position
 	writeString(str, Common::Point(textBounds.left, textBounds.top), color);
@@ -505,7 +513,7 @@ void Screen::resetDisplayBounds() {
  */
 Common::Rect Screen::getDisplayBounds() {
 	return (_backBuffer == &_sceneSurface) ? Common::Rect(0, 0, _sceneSurface.w, _sceneSurface.h) :
-		Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+		Common::Rect(0, 0, this->w, this->h);
 }
 
 /**
@@ -518,4 +526,36 @@ void Screen::synchronize(Common::Serializer &s) {
 		setFont(fontNumb);
 }
 
+void Screen::initPaletteFade(int bytesToRead) {
+	Common::copy(&_cMap[0], &_cMap[PALETTE_SIZE], &_sMap[0]);
+	Common::copy(&_cMap[0], &_cMap[PALETTE_SIZE], &_tMap[0]);
+
+	// Set how many bytes need to be read / have been read
+	_fadeBytesRead = 0;
+	_fadeBytesToRead = bytesToRead;
+	_oldFadePercent = 0;
+}
+
+int Screen::fadeRead(Common::SeekableReadStream &stream, byte *buf, int totalSize) {
+	warning("TODO: fadeRead");
+	stream.read(buf, totalSize);
+	return totalSize;
+}
+
+/**
+ * Creates a grey-scale version of the passed palette
+ */
+void Screen::setupBGArea(const byte cMap[PALETTE_SIZE]) {
+	warning("TODO");
+}
+
+/**
+ * Initializes scroll variables
+ */
+void Screen::initScrollVars() {
+	_scrollSize = 0;
+	_currentScroll = 0;
+	_targetScroll = 0;
+}
+
 } // End of namespace Sherlock
diff --git a/engines/sherlock/screen.h b/engines/sherlock/screen.h
index 501506f..2538916 100644
--- a/engines/sherlock/screen.h
+++ b/engines/sherlock/screen.h
@@ -67,6 +67,15 @@ private:
 	int _fontHeight;
 	Surface _sceneSurface;
 
+	// Rose Tattoo fields
+	int _fadeBytesRead, _fadeBytesToRead;
+	int _oldFadePercent;
+	byte _lookupTable[PALETTE_COUNT];
+	byte _lookupTable1[PALETTE_COUNT];
+	int _scrollSize;
+	int _currentScroll;
+	int _targetScroll;
+private:
 	void mergeDirtyRects();
 
 	bool unionRectangle(Common::Rect &destRect, const Common::Rect &src1, const Common::Rect &src2);
@@ -80,6 +89,7 @@ public:
 	bool _fadeStyle;
 	byte _cMap[PALETTE_SIZE];
 	byte _sMap[PALETTE_SIZE];
+	byte _tMap[PALETTE_SIZE];
 public:
 	Screen(SherlockEngine *vm);
 	virtual ~Screen();
@@ -132,6 +142,15 @@ public:
 	int fontNumber() const { return _fontNumber; }
 
 	void synchronize(Common::Serializer &s);
+
+	// Rose Tattoo specific methods
+	void initPaletteFade(int bytesToRead);
+
+	int fadeRead(Common::SeekableReadStream &stream, byte *buf, int totalSize);
+
+	void setupBGArea(const byte cMap[PALETTE_SIZE]);
+
+	void initScrollVars();
 };
 
 } // End of namespace Sherlock
diff --git a/engines/sherlock/sherlock.cpp b/engines/sherlock/sherlock.cpp
index 2a5d9ec..318267b 100644
--- a/engines/sherlock/sherlock.cpp
+++ b/engines/sherlock/sherlock.cpp
@@ -25,7 +25,6 @@
 #include "common/scummsys.h"
 #include "common/config-manager.h"
 #include "common/debug-channels.h"
-#include "engines/util.h"
 
 namespace Sherlock {
 
@@ -71,8 +70,6 @@ SherlockEngine::~SherlockEngine() {
  * Does basic initialization of the game engine
  */
 void SherlockEngine::initialize() {
-	initGraphics(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT, false);
-
 	DebugMan.addDebugChannel(kDebugScript, "scripts", "Script debug level");
 
 	ImageFile::setVm(this);
diff --git a/engines/sherlock/sherlock.h b/engines/sherlock/sherlock.h
index 501fdcb..e21ac8c 100644
--- a/engines/sherlock/sherlock.h
+++ b/engines/sherlock/sherlock.h
@@ -62,8 +62,8 @@ enum GameType {
 	GType_RoseTattoo = 1
 };
 
-#define SHERLOCK_SCREEN_WIDTH 320
-#define SHERLOCK_SCREEN_HEIGHT 200
+#define SHERLOCK_SCREEN_WIDTH _vm->_screen->w
+#define SHERLOCK_SCREEN_HEIGHT _vm->_screen->h
 #define SHERLOCK_SCENE_HEIGHT 138
 
 struct SherlockGameDescription;
diff --git a/engines/sherlock/tattoo/tattoo.cpp b/engines/sherlock/tattoo/tattoo.cpp
index d4059ac..9039e3f 100644
--- a/engines/sherlock/tattoo/tattoo.cpp
+++ b/engines/sherlock/tattoo/tattoo.cpp
@@ -21,6 +21,7 @@
  */
 
 #include "sherlock/tattoo/tattoo.h"
+#include "engines/util.h"
 
 namespace Sherlock {
 
@@ -30,6 +31,32 @@ void TattooEngine::showOpening() {
 	// TODO
 }
 
+/**
+ * Initialize the engine
+ */
+void TattooEngine::initialize() {
+	initGraphics(640, 480, true);
+
+	// Initialize the base engine
+	SherlockEngine::initialize();
+
+	_flags.resize(100 * 8);
+
+	// Add some more files to the cache
+	_res->addToCache("walk.lib");
+
+	// Starting scene
+	_scene->_goToScene = 91;
+}
+
+/**
+ * Starting a scene within the game
+ */
+void TattooEngine::startScene() {
+	// TODO
+}
+
+
 } // End of namespace Tattoo
 
 } // End of namespace Scalpel
diff --git a/engines/sherlock/tattoo/tattoo.h b/engines/sherlock/tattoo/tattoo.h
index b983955..7bdeec5 100644
--- a/engines/sherlock/tattoo/tattoo.h
+++ b/engines/sherlock/tattoo/tattoo.h
@@ -31,10 +31,15 @@ namespace Tattoo {
 
 class TattooEngine : public SherlockEngine {
 protected:
+	virtual void initialize();
+
 	virtual void showOpening();
+
+	virtual void startScene();
 public:
 	TattooEngine(OSystem *syst, const SherlockGameDescription *gameDesc) :
 		SherlockEngine(syst, gameDesc) {}
+
 	virtual ~TattooEngine() {}
 };
 
diff --git a/engines/sherlock/user_interface.cpp b/engines/sherlock/user_interface.cpp
index 41505b8..8e72540 100644
--- a/engines/sherlock/user_interface.cpp
+++ b/engines/sherlock/user_interface.cpp
@@ -81,8 +81,13 @@ const char *const MUSE[] = {
 /*----------------------------------------------------------------*/
 
 UserInterface::UserInterface(SherlockEngine *vm) : _vm(vm) {
-	_controls = new ImageFile("menu.all");
-	_controlPanel = new ImageFile("controls.vgs");
+	if (_vm->getGameID() == GType_SerratedScalpel) {
+		_controls = new ImageFile("menu.all");
+		_controlPanel = new ImageFile("controls.vgs");
+	} else {
+		_controls = nullptr;
+		_controlPanel = nullptr;
+	}
 	_bgFound = 0;
 	_oldBgFound = -1;
 	_keycode = Common::KEYCODE_INVALID;


Commit: 4cbad2834c73116bba6bdba31f8ffe918a5d18bc
    https://github.com/scummvm/scummvm/commit/4cbad2834c73116bba6bdba31f8ffe918a5d18bc
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-13T08:26:25-04:00

Commit Message:
SHERLOCK: Update sound initialization for Rose Tattoo

Changed paths:
    engines/sherlock/sound.cpp



diff --git a/engines/sherlock/sound.cpp b/engines/sherlock/sound.cpp
index 09e55ec..70451a6 100644
--- a/engines/sherlock/sound.cpp
+++ b/engines/sherlock/sound.cpp
@@ -45,7 +45,7 @@ Sound::Sound(SherlockEngine *vm, Audio::Mixer *mixer): _vm(vm), _mixer(mixer) {
 	_speechOn = true;
 
 	_vm->_res->addToCache("MUSIC.LIB");
-	_vm->_res->addToCache("SND.SND");
+	_vm->_res->addToCache(_vm->getGameID() == GType_SerratedScalpel ? "SND.SND" : "SOUND.LIB");
 }
 
 /**


Commit: d1d4d550747c1340b4030f7f2eded8d9e25d9fb5
    https://github.com/scummvm/scummvm/commit/d1d4d550747c1340b4030f7f2eded8d9e25d9fb5
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-16T09:29:40-04:00

Commit Message:
Merge branch 'sherlock' into sherlock2

Conflicts:
	engines/sherlock/decompress.cpp
	engines/sherlock/objects.cpp
	engines/sherlock/objects.h
	engines/sherlock/scene.cpp
	engines/sherlock/scene.h
	engines/sherlock/sound.cpp

Changed paths:
  A engines/sherlock/surface.cpp
  A engines/sherlock/surface.h
  R engines/sherlock/decompress.h
  R engines/sherlock/graphics.cpp
  R engines/sherlock/graphics.h
    engines/sherlock/detection.cpp
    engines/sherlock/detection_tables.h
    engines/sherlock/inventory.cpp
    engines/sherlock/inventory.h
    engines/sherlock/map.cpp
    engines/sherlock/map.h
    engines/sherlock/module.mk
    engines/sherlock/resources.cpp
    engines/sherlock/resources.h
    engines/sherlock/saveload.cpp
    engines/sherlock/scalpel/scalpel.cpp
    engines/sherlock/scene.cpp
    engines/sherlock/scene.h
    engines/sherlock/screen.cpp
    engines/sherlock/screen.h
    engines/sherlock/sherlock.cpp
    engines/sherlock/sherlock.h
    engines/sherlock/sound.cpp
    engines/sherlock/talk.cpp
    engines/sherlock/talk.h
    engines/sherlock/tattoo/tattoo.cpp
    engines/sherlock/user_interface.cpp
    engines/sherlock/user_interface.h



diff --cc engines/sherlock/resources.h
index bbaac60,d5e83a1..041f1c6
--- a/engines/sherlock/resources.h
+++ b/engines/sherlock/resources.h
@@@ -70,10 -72,9 +72,10 @@@ private
  	LibraryIndexes _indexes;
  	int _resourceIndex;
  
 -	void loadLibraryIndex(const Common::String &libFilename, Common::SeekableReadStream *stream);
 +	void loadLibraryIndex(const Common::String &libFilename, Common::SeekableReadStream *stream,
 +		bool isNewStyle);
  public:
- 	Resources();
+ 	Resources(SherlockEngine *vm);
  
  	void addToCache(const Common::String &filename);
  	void addToCache(const Common::String &filename, const Common::String &libFilename);
diff --cc engines/sherlock/scalpel/scalpel.cpp
index b982079,6959e43..521aeb3
--- a/engines/sherlock/scalpel/scalpel.cpp
+++ b/engines/sherlock/scalpel/scalpel.cpp
@@@ -254,10 -250,7 +254,11 @@@ void ScalpelEngine::initialize() 
  	_flags[3] = true;		// Turn on Alley
  	_flags[39] = true;		// Turn on Baker Street
  
 -	if (!getIsDemo()) {
 +	// Add some more files to the cache
- 	_res->addToCache("sequence.txt");
 +	_res->addToCache("portrait.lib");
++	_res->addToCache("sequence.txt");
++	_res->addToCache("snd.snd");
 +
  	// Load the map co-ordinates for each scene and sequence data
  	_map->loadPoints(NUM_PLACES, &MAP_X[0], &MAP_Y[0], &MAP_TRANSLATE[0]);
  	_map->loadSequences(3, &MAP_SEQUENCES[0][0]);
diff --cc engines/sherlock/scene.cpp
index d4662ed,9fbf25c..0a25d3d
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@@ -23,8 -23,6 +23,7 @@@
  #include "sherlock/scene.h"
  #include "sherlock/sherlock.h"
  #include "sherlock/scalpel/scalpel.h"
- #include "sherlock/decompress.h"
 +#include "sherlock/screen.h"
  
  namespace Sherlock {
  
@@@ -236,6 -227,6 +250,7 @@@ bool Scene::loadScene(const Common::Str
  	Events &events = *_vm->_events;
  	Map &map = *_vm->_map;
  	People &people = *_vm->_people;
++	Resources &res = *_vm->_res;
  	SaveManager &saves = *_vm->_saves;
  	Screen &screen = *_vm->_screen;
  	Sound &sound = *_vm->_sound;
@@@ -274,38 -260,20 +289,38 @@@
  
  		// Go to header and read it in
  		rrmStream->seek(rrmStream->readUint32LE());
 +
  		BgFileHeader bgHeader;
 -		bgHeader.load(*rrmStream);
 +		bgHeader.synchronize(*rrmStream, _vm->getGameID() == GType_RoseTattoo);
  		_invGraphicItems = bgHeader._numImages + 1;
  
 +		if (_vm->getGameID() == GType_RoseTattoo) {
 +			screen.initPaletteFade(bgHeader._bytesWritten);
 +			screen.fadeRead(*rrmStream, screen._cMap, PALETTE_SIZE);
 +			screen.setupBGArea(screen._cMap);
 +
 +			screen.initScrollVars();
 +
 +			// Read in background
 +			if (_lzwMode) {
- 				Common::SeekableReadStream *stream = decompressLZ(*rrmStream, SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCREEN_HEIGHT);
++				Common::SeekableReadStream *stream = res.decompressLZ(*rrmStream);
 +				stream->read(screen._backBuffer1.getPixels(), stream->size());
 +				delete stream;
 +			} else {
 +				rrmStream->read(screen._backBuffer1.getPixels(), SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCREEN_HEIGHT);
 +			}
 +		} 
 +
  		// Read in the shapes header info
  		bgInfo.resize(bgHeader._numStructs);
  
  		for (uint idx = 0; idx < bgInfo.size(); ++idx)
- 			bgInfo[idx].synchronize(*rrmStream);
+ 			bgInfo[idx].load(*rrmStream);
  
  		// Read information
 +		int shapeSize = _vm->getGameID() == GType_SerratedScalpel ? 569 : 591;
  		Common::SeekableReadStream *infoStream = !_lzwMode ? rrmStream :
- 			decompressLZ(*rrmStream, bgHeader._numImages * shapeSize +
 -			Resources::decompressLZ(*rrmStream, bgHeader._numImages * 569 +
++			Resources::decompressLZ(*rrmStream, bgHeader._numImages * shapeSize +
  				bgHeader._descSize + bgHeader._seqSize);
  
  		_bgShapes.resize(bgHeader._numStructs);
diff --cc engines/sherlock/screen.cpp
index 0ca10b4,cbf18f1..349bf4d
--- a/engines/sherlock/screen.cpp
+++ b/engines/sherlock/screen.cpp
@@@ -221,10 -214,10 +222,10 @@@ void Screen::randomTransition() 
  		_transitionSeed = _transitionSeed * TRANSITION_MULTIPLIER + 1;
  		int offset = _transitionSeed & 65535;
  
 -		if (offset < (SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCREEN_HEIGHT))
 +		if (offset < (this->w * this->h))
  			*((byte *)getPixels() + offset) = *((const byte *)_backBuffer->getPixels() + offset);
  
- 		if (idx != 0 && (idx % 100) == 0) {
+ 		if (idx != 0 && (idx % 300) == 0) {
  			// Ensure there's a full screen dirty rect for the next frame update
  			if (_dirtyRects.empty())
  				addDirtyRect(Common::Rect(0, 0, this->w, this->h));
diff --cc engines/sherlock/sound.cpp
index 70451a6,59098c3..0019079
--- a/engines/sherlock/sound.cpp
+++ b/engines/sherlock/sound.cpp
@@@ -45,7 -45,9 +45,8 @@@ Sound::Sound(SherlockEngine *vm, Audio:
  	_speechOn = true;
  
  	_vm->_res->addToCache("MUSIC.LIB");
- 	_vm->_res->addToCache(_vm->getGameID() == GType_SerratedScalpel ? "SND.SND" : "SOUND.LIB");
+ 	_vm->_res->addToCache("TITLE.SND");
+ 	_vm->_res->addToCache("EPILOGUE.SND");
 -	_vm->_res->addToCache("SND.SND");
  }
  
  /**
diff --cc engines/sherlock/tattoo/tattoo.cpp
index 9039e3f,d4059ac..3c684ff
--- a/engines/sherlock/tattoo/tattoo.cpp
+++ b/engines/sherlock/tattoo/tattoo.cpp
@@@ -31,32 -30,6 +31,33 @@@ void TattooEngine::showOpening() 
  	// TODO
  }
  
 +/**
 + * Initialize the engine
 + */
 +void TattooEngine::initialize() {
 +	initGraphics(640, 480, true);
 +
 +	// Initialize the base engine
 +	SherlockEngine::initialize();
 +
 +	_flags.resize(100 * 8);
 +
 +	// Add some more files to the cache
 +	_res->addToCache("walk.lib");
++	_res->addToCache("sound.lib");
 +
 +	// Starting scene
 +	_scene->_goToScene = 91;
 +}
 +
 +/**
 + * Starting a scene within the game
 + */
 +void TattooEngine::startScene() {
 +	// TODO
 +}
 +
 +
  } // End of namespace Tattoo
  
  } // End of namespace Scalpel


Commit: 44e09044674574a08dfc7a0391989d62bf3b187c
    https://github.com/scummvm/scummvm/commit/44e09044674574a08dfc7a0391989d62bf3b187c
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-16T09:33:42-04:00

Commit Message:
SHERLOCK: Move caching Scalpel sound libraries from Sound to Scalpel engine

Changed paths:
    engines/sherlock/scalpel/scalpel.cpp
    engines/sherlock/sound.cpp



diff --git a/engines/sherlock/scalpel/scalpel.cpp b/engines/sherlock/scalpel/scalpel.cpp
index 521aeb3..eff5898 100644
--- a/engines/sherlock/scalpel/scalpel.cpp
+++ b/engines/sherlock/scalpel/scalpel.cpp
@@ -257,7 +257,9 @@ void ScalpelEngine::initialize() {
 	// Add some more files to the cache
 	_res->addToCache("portrait.lib");
 	_res->addToCache("sequence.txt");
+	_res->addToCache("EPILOGUE.SND");
 	_res->addToCache("snd.snd");
+	_res->addToCache("title.snd");
 
 	// Load the map co-ordinates for each scene and sequence data
 	_map->loadPoints(NUM_PLACES, &MAP_X[0], &MAP_Y[0], &MAP_TRANSLATE[0]);
diff --git a/engines/sherlock/sound.cpp b/engines/sherlock/sound.cpp
index 0019079..3a30864 100644
--- a/engines/sherlock/sound.cpp
+++ b/engines/sherlock/sound.cpp
@@ -45,8 +45,6 @@ Sound::Sound(SherlockEngine *vm, Audio::Mixer *mixer): _vm(vm), _mixer(mixer) {
 	_speechOn = true;
 
 	_vm->_res->addToCache("MUSIC.LIB");
-	_vm->_res->addToCache("TITLE.SND");
-	_vm->_res->addToCache("EPILOGUE.SND");
 }
 
 /**


Commit: 75a6e941a06f93bf06b03d50e03e740871a1be9a
    https://github.com/scummvm/scummvm/commit/75a6e941a06f93bf06b03d50e03e740871a1be9a
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-16T10:52:38-04:00

Commit Message:
SHERLOCK: Fix decompression for Rose Tattoo

Changed paths:
    engines/sherlock/resources.cpp
    engines/sherlock/resources.h
    engines/sherlock/scene.cpp



diff --git a/engines/sherlock/resources.cpp b/engines/sherlock/resources.cpp
index bff80c2..0203011 100644
--- a/engines/sherlock/resources.cpp
+++ b/engines/sherlock/resources.cpp
@@ -76,7 +76,7 @@ void Cache::load(const Common::String &name, Common::SeekableReadStream &stream)
 	// Check whether the file is compressed
 	if (signature == MKTAG('L', 'Z', 'V', 26)) {
 		// It's compressed, so decompress the file and store it's data in the cache entry
-		Common::SeekableReadStream *decompressed = _vm->_res->decompressLZ(stream);
+		Common::SeekableReadStream *decompressed = _vm->_res->decompress(stream);
 		cacheEntry.resize(decompressed->size());
 		decompressed->read(&cacheEntry[0], decompressed->size());
 
@@ -170,7 +170,7 @@ Common::SeekableReadStream *Resources::load(const Common::String &filename) {
 			if (resStream->readUint32BE() == MKTAG('L', 'Z', 'V', 26)) {
 				resStream->seek(0);
 				// It's compressed, so decompress the sub-file and return it
-				Common::SeekableReadStream *decompressed = decompressLZ(*resStream);
+				Common::SeekableReadStream *decompressed = decompress(*resStream);
 				delete stream;
 				delete resStream;
 				return decompressed;
@@ -413,27 +413,45 @@ void ImageFile::decompressFrame(ImageFrame &frame, const byte *src) {
 /**
  * Decompress an LZW compressed resource
  */
-Common::SeekableReadStream *Resources::decompressLZ(Common::SeekableReadStream &source) {
-	if (_vm->getGameID() == GType_SerratedScalpel) {
-		uint32 id = source.readUint32BE();
-		assert(id == MKTAG('L', 'Z', 'V', 0x1A));
-	}
+Common::SeekableReadStream *Resources::decompress(Common::SeekableReadStream &source) {
+	// This variation can't be used by Rose Tattoo, since compressed resources include the input size,
+	// not the output size. Which means their decompression has to be done via passed buffers
+	assert(_vm->getGameID() == GType_SerratedScalpel);
+
+	uint32 id = source.readUint32BE();
+	assert(id == MKTAG('L', 'Z', 'V', 0x1A));
+
+	uint32 outputSize = source.readUint32LE();
+	return decompressLZ(source, outputSize);
+}
+
+/**
+ * Decompress an LZW compressed resource
+ */
+void Resources::decompress(Common::SeekableReadStream &source, byte *buffer, uint32 outSize) {
+	assert(_vm->getGameID() == GType_RoseTattoo);
 
-	uint32 size = source.readUint32LE();
-	return decompressLZ(source, size);
+	uint32 inputSize = source.readUint32LE();
+	decompressLZ(source, buffer, outSize, inputSize);
 }
 
 /**
  * Decompresses an LZW block of data with a specified output size
  */
 Common::SeekableReadStream *Resources::decompressLZ(Common::SeekableReadStream &source, uint32 outSize) {
+	byte *outBuffer = (byte *)malloc(outSize);
+	Common::MemoryReadStream *outStream = new Common::MemoryReadStream(outBuffer, outSize, DisposeAfterUse::YES);
+
+	decompressLZ(source, outSize);
+	return outStream;
+}
+
+void Resources::decompressLZ(Common::SeekableReadStream &source, byte *outBuffer, int32 outSize, int32 inSize) {
 	byte lzWindow[4096];
 	uint16 lzWindowPos;
 	uint16 cmd;
-
-	byte *outBuffer = (byte *)malloc(outSize);
 	byte *outBufferEnd = outBuffer + outSize;
-	Common::MemoryReadStream *outS = new Common::MemoryReadStream(outBuffer, outSize, DisposeAfterUse::YES);
+	uint32 endPos = source.pos() + inSize;
 
 	memset(lzWindow, 0xFF, 0xFEE);
 	lzWindowPos = 0xFEE;
@@ -463,9 +481,7 @@ Common::SeekableReadStream *Resources::decompressLZ(Common::SeekableReadStream &
 				lzWindowPos = (lzWindowPos + 1) & 0x0FFF;
 			}
 		}
-	} while (outBuffer < outBufferEnd);
-
-	return outS;
+	} while ((!outSize || outBuffer < outBufferEnd) && (!inSize || source.pos() < endPos));
 }
 
 } // End of namespace Sherlock
diff --git a/engines/sherlock/resources.h b/engines/sherlock/resources.h
index 041f1c6..0765ce4 100644
--- a/engines/sherlock/resources.h
+++ b/engines/sherlock/resources.h
@@ -90,8 +90,10 @@ public:
 
 	int resourceIndex() const;
 
+	Common::SeekableReadStream *decompress(Common::SeekableReadStream &source);
+	void decompress(Common::SeekableReadStream &source, byte *buffer, uint32 outSize);
+	static void decompressLZ(Common::SeekableReadStream &source, byte *outBuffer, int32 outSize, int32 inSize);
 	static Common::SeekableReadStream *decompressLZ(Common::SeekableReadStream &source, uint32 outSize);
-	Common::SeekableReadStream *decompressLZ(Common::SeekableReadStream &source);
 };
 
 struct ImageFrame {
diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp
index 0a25d3d..e473217 100644
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@ -303,9 +303,7 @@ bool Scene::loadScene(const Common::String &filename) {
 
 			// Read in background
 			if (_lzwMode) {
-				Common::SeekableReadStream *stream = res.decompressLZ(*rrmStream);
-				stream->read(screen._backBuffer1.getPixels(), stream->size());
-				delete stream;
+				res.decompress(*rrmStream, (byte *)screen._backBuffer1.getPixels(), SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCREEN_HEIGHT);
 			} else {
 				rrmStream->read(screen._backBuffer1.getPixels(), SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCREEN_HEIGHT);
 			}


Commit: b960736ac3eb51a07e0e4748c31c16456985f79b
    https://github.com/scummvm/scummvm/commit/b960736ac3eb51a07e0e4748c31c16456985f79b
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-16T12:27:58-04:00

Commit Message:
SHERLOCK: Scene loading for shapes, desc, scripts for Rose Tattoo

Changed paths:
    engines/sherlock/resources.cpp
    engines/sherlock/resources.h
    engines/sherlock/scene.cpp



diff --git a/engines/sherlock/resources.cpp b/engines/sherlock/resources.cpp
index 0203011..9acba0b 100644
--- a/engines/sherlock/resources.cpp
+++ b/engines/sherlock/resources.cpp
@@ -428,10 +428,22 @@ Common::SeekableReadStream *Resources::decompress(Common::SeekableReadStream &so
 /**
  * Decompress an LZW compressed resource
  */
+Common::SeekableReadStream *Resources::decompress(Common::SeekableReadStream &source, uint32 outSize) {
+	int inSize = (_vm->getGameID() == GType_RoseTattoo) ? source.readUint32LE() : -1;
+	byte *outBuffer = (byte *)malloc(outSize);
+	Common::MemoryReadStream *outStream = new Common::MemoryReadStream(outBuffer, outSize, DisposeAfterUse::YES);
+
+	decompressLZ(source, outBuffer, outSize, inSize);
+
+	return outStream;
+}
+
+/**
+ * Decompress an LZW compressed resource
+ */
 void Resources::decompress(Common::SeekableReadStream &source, byte *buffer, uint32 outSize) {
-	assert(_vm->getGameID() == GType_RoseTattoo);
+	int inputSize = (_vm->getGameID() == GType_RoseTattoo) ? source.readUint32LE() : -1;
 
-	uint32 inputSize = source.readUint32LE();
 	decompressLZ(source, buffer, outSize, inputSize);
 }
 
@@ -442,7 +454,7 @@ Common::SeekableReadStream *Resources::decompressLZ(Common::SeekableReadStream &
 	byte *outBuffer = (byte *)malloc(outSize);
 	Common::MemoryReadStream *outStream = new Common::MemoryReadStream(outBuffer, outSize, DisposeAfterUse::YES);
 
-	decompressLZ(source, outSize);
+	decompressLZ(source, outBuffer, outSize, -1);
 	return outStream;
 }
 
@@ -451,7 +463,7 @@ void Resources::decompressLZ(Common::SeekableReadStream &source, byte *outBuffer
 	uint16 lzWindowPos;
 	uint16 cmd;
 	byte *outBufferEnd = outBuffer + outSize;
-	uint32 endPos = source.pos() + inSize;
+	int32 endPos = source.pos() + inSize;
 
 	memset(lzWindow, 0xFF, 0xFEE);
 	lzWindowPos = 0xFEE;
diff --git a/engines/sherlock/resources.h b/engines/sherlock/resources.h
index 0765ce4..a320852 100644
--- a/engines/sherlock/resources.h
+++ b/engines/sherlock/resources.h
@@ -91,6 +91,7 @@ public:
 	int resourceIndex() const;
 
 	Common::SeekableReadStream *decompress(Common::SeekableReadStream &source);
+	Common::SeekableReadStream *decompress(Common::SeekableReadStream &source, uint32 outSize);
 	void decompress(Common::SeekableReadStream &source, byte *buffer, uint32 outSize);
 	static void decompressLZ(Common::SeekableReadStream &source, byte *outBuffer, int32 outSize, int32 inSize);
 	static Common::SeekableReadStream *decompressLZ(Common::SeekableReadStream &source, uint32 outSize);
diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp
index e473217..54155db 100644
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@ -316,28 +316,52 @@ bool Scene::loadScene(const Common::String &filename) {
 			bgInfo[idx].load(*rrmStream);
 
 		// Read information
-		int shapeSize = _vm->getGameID() == GType_SerratedScalpel ? 569 : 591;
-		Common::SeekableReadStream *infoStream = !_lzwMode ? rrmStream :
-			Resources::decompressLZ(*rrmStream, bgHeader._numImages * shapeSize +
-				bgHeader._descSize + bgHeader._seqSize);
+		if (_vm->getGameID() == GType_SerratedScalpel) {
+			Common::SeekableReadStream *infoStream = !_lzwMode ? rrmStream :
+				res.decompress(*rrmStream, bgHeader._numImages * 569 + bgHeader._descSize + bgHeader._seqSize);
+
+			_bgShapes.resize(bgHeader._numStructs);
+			for (int idx = 0; idx < bgHeader._numStructs; ++idx)
+				_bgShapes[idx].load(*infoStream, _vm->getGameID() == GType_RoseTattoo);
+
+			if (bgHeader._descSize) {
+				_descText.resize(bgHeader._descSize);
+				infoStream->read(&_descText[0], bgHeader._descSize);
+			}
+
+			if (bgHeader._seqSize) {
+				_sequenceBuffer.resize(bgHeader._seqSize);
+				infoStream->read(&_sequenceBuffer[0], bgHeader._seqSize);
+			}
+
+			if (_lzwMode)
+				delete infoStream;
+		} else {
+			// Load shapes
+			Common::SeekableReadStream *infoStream = !_lzwMode ? rrmStream : res.decompress(*rrmStream, bgHeader._numImages * 625);
+
+			_bgShapes.resize(bgHeader._numStructs);
+			for (int idx = 0; idx < bgHeader._numStructs; ++idx)
+				_bgShapes[idx].load(*infoStream, _vm->getGameID() == GType_RoseTattoo);
 
-		_bgShapes.resize(bgHeader._numStructs);
-		for (int idx = 0; idx < bgHeader._numStructs; ++idx)
-			_bgShapes[idx].load(*infoStream, _vm->getGameID() == GType_RoseTattoo);
+			if (_lzwMode)
+				delete infoStream;
 
-		if (bgHeader._descSize) {
+			// Load description text
 			_descText.resize(bgHeader._descSize);
-			infoStream->read(&_descText[0], bgHeader._descSize);
-		}
+			if (_lzwMode)
+				res.decompress(*rrmStream, (byte *)&_descText[0], bgHeader._descSize);
+			else
+				rrmStream->read(&_descText[0], bgHeader._descSize);
 
-		if (bgHeader._seqSize) {
+			// Load sequences
 			_sequenceBuffer.resize(bgHeader._seqSize);
-			infoStream->read(&_sequenceBuffer[0], bgHeader._seqSize);
+			if (_lzwMode)
+				res.decompress(*rrmStream, &_sequenceBuffer[0], bgHeader._seqSize);
+			else
+				rrmStream->read(&_sequenceBuffer[0], bgHeader._seqSize);
 		}
 
-		if (_lzwMode)
-			delete infoStream;
-
 		// Set up the list of images used by the scene
 		_images.resize(bgHeader._numImages + 1);
 		for (int idx = 0; idx < bgHeader._numImages; ++idx) {


Commit: 8c009d894134fc0268019009ea30c04feaf8a528
    https://github.com/scummvm/scummvm/commit/8c009d894134fc0268019009ea30c04feaf8a528
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-16T16:46:35-04:00

Commit Message:
SHERLOCK: Fix broken Scalpel scene loading

Changed paths:
    engines/sherlock/objects.cpp
    engines/sherlock/resources.cpp
    engines/sherlock/scene.cpp



diff --git a/engines/sherlock/objects.cpp b/engines/sherlock/objects.cpp
index 772f9d2..9620a01 100644
--- a/engines/sherlock/objects.cpp
+++ b/engines/sherlock/objects.cpp
@@ -477,6 +477,7 @@ Object::Object() {
  * Load the data for the object
  */
 void Object::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
+	uint32 p = s.pos(); warning("%.4x", p);
 	char buffer[41];
 	s.read(buffer, 12);
 	_name = Common::String(buffer);
@@ -508,11 +509,10 @@ void Object::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
 	_goto.x = s.readSint16LE();
 	_goto.y = s.readSint16LE();
 
-	_pickup = s.readByte();
-	_defaultCommand = s.readByte();
-	_lookFlag = s.readUint16LE();
-	if (!isRoseTattoo)
-		_pickupFlag = s.readUint16LE();
+	_pickup = isRoseTattoo ? 0 : s.readByte();
+	_defaultCommand = isRoseTattoo ? 0 : s.readByte();
+	_lookFlag = s.readSint16LE();
+	_pickupFlag = isRoseTattoo ? 0 : s.readSint16LE();
 	_requiredFlag = s.readSint16LE();
 	_noShapeSize.x = s.readUint16LE();
 	_noShapeSize.y = s.readUint16LE();
@@ -547,7 +547,7 @@ void Object::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
 
 		_quickDraw = s.readByte();
 		_scaleVal = s.readUint16LE();
-		_requiredFlag1 = s.readUint16LE();
+		_requiredFlag1 = s.readSint16LE();
 		_gotoSeq = s.readByte();
 		_talkSeq = s.readByte();
 		_restoreSlot = s.readByte();
@@ -559,6 +559,7 @@ void Object::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
 		for (int idx = 0; idx < 4; ++idx)
 			_use[idx].load(s, false);
 	}
+	warning("%.4x", s.pos() - p);
 }
 
 /**
diff --git a/engines/sherlock/resources.cpp b/engines/sherlock/resources.cpp
index 9acba0b..1c154a3 100644
--- a/engines/sherlock/resources.cpp
+++ b/engines/sherlock/resources.cpp
@@ -324,7 +324,6 @@ void ImageFile::load(Common::SeekableReadStream &stream, bool skipPalette, bool
 			frame._offset.y = stream.readByte();
 		}
 
-		frame._offset.y = stream.readByte();
 		frame._rleEncoded = !skipPalette && frame._rleEncoded;
 
 		if (frame._paletteBase) {
diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp
index 54155db..bf8d837 100644
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@ -318,11 +318,11 @@ bool Scene::loadScene(const Common::String &filename) {
 		// Read information
 		if (_vm->getGameID() == GType_SerratedScalpel) {
 			Common::SeekableReadStream *infoStream = !_lzwMode ? rrmStream :
-				res.decompress(*rrmStream, bgHeader._numImages * 569 + bgHeader._descSize + bgHeader._seqSize);
+				res.decompress(*rrmStream, bgHeader._numStructs * 569 + bgHeader._descSize + bgHeader._seqSize);
 
 			_bgShapes.resize(bgHeader._numStructs);
 			for (int idx = 0; idx < bgHeader._numStructs; ++idx)
-				_bgShapes[idx].load(*infoStream, _vm->getGameID() == GType_RoseTattoo);
+				_bgShapes[idx].load(*infoStream, false);
 
 			if (bgHeader._descSize) {
 				_descText.resize(bgHeader._descSize);
@@ -338,11 +338,11 @@ bool Scene::loadScene(const Common::String &filename) {
 				delete infoStream;
 		} else {
 			// Load shapes
-			Common::SeekableReadStream *infoStream = !_lzwMode ? rrmStream : res.decompress(*rrmStream, bgHeader._numImages * 625);
+			Common::SeekableReadStream *infoStream = !_lzwMode ? rrmStream : res.decompress(*rrmStream, bgHeader._numStructs * 625);
 
 			_bgShapes.resize(bgHeader._numStructs);
 			for (int idx = 0; idx < bgHeader._numStructs; ++idx)
-				_bgShapes[idx].load(*infoStream, _vm->getGameID() == GType_RoseTattoo);
+				_bgShapes[idx].load(*infoStream, true);
 
 			if (_lzwMode)
 				delete infoStream;


Commit: 2f80df5d44a527029c6a1ab567aa908816438710
    https://github.com/scummvm/scummvm/commit/2f80df5d44a527029c6a1ab567aa908816438710
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-16T17:01:28-04:00

Commit Message:
SHERLOCK: Remove accidentally committed debug info

Changed paths:
    engines/sherlock/objects.cpp



diff --git a/engines/sherlock/objects.cpp b/engines/sherlock/objects.cpp
index 9620a01..c6254ee 100644
--- a/engines/sherlock/objects.cpp
+++ b/engines/sherlock/objects.cpp
@@ -477,7 +477,6 @@ Object::Object() {
  * Load the data for the object
  */
 void Object::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
-	uint32 p = s.pos(); warning("%.4x", p);
 	char buffer[41];
 	s.read(buffer, 12);
 	_name = Common::String(buffer);
@@ -559,7 +558,6 @@ void Object::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
 		for (int idx = 0; idx < 4; ++idx)
 			_use[idx].load(s, false);
 	}
-	warning("%.4x", s.pos() - p);
 }
 
 /**


Commit: f41b8cad2fbf17c0989f3ad00956680afeb2b865
    https://github.com/scummvm/scummvm/commit/f41b8cad2fbf17c0989f3ad00956680afeb2b865
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-16T22:27:36-04:00

Commit Message:
SHERLOCK: Implement Tattoo version of image RLE compression

Changed paths:
    engines/sherlock/resources.cpp
    engines/sherlock/scene.cpp



diff --git a/engines/sherlock/resources.cpp b/engines/sherlock/resources.cpp
index 1c154a3..24fef3f 100644
--- a/engines/sherlock/resources.cpp
+++ b/engines/sherlock/resources.cpp
@@ -383,6 +383,28 @@ void ImageFile::decompressFrame(ImageFrame &frame, const byte *src) {
 			*pDest++ = *src & 0xF;
 			*pDest++ = (*src >> 4);
 		}
+	} else if (frame._rleEncoded && _vm->getGameID() == GType_RoseTattoo) {
+		// Rose Tattoo run length encoding doesn't use the RLE marker byte
+		byte *dst = (byte *)frame._frame.getPixels();
+
+		for (int yp = 0; yp < frame._height; ++yp) {
+			int xSize = frame._width;
+			while (xSize > 0) {
+				// Skip a given number of pixels
+				byte skip = *src++;
+				dst += skip;
+				xSize -= skip;
+				if (!xSize)
+					break;
+
+				// Get a run length, and copy the following number of pixels
+				int rleCount = *src++;
+				xSize -= rleCount;
+				while (rleCount-- > 0)
+					*dst++ = *src++;
+			}
+			assert(xSize == 0);
+		}
 	} else if (frame._rleEncoded) {
 		// RLE encoded
 		byte *dst = (byte *)frame._frame.getPixels();
diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp
index bf8d837..0348964 100644
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@ -370,7 +370,7 @@ bool Scene::loadScene(const Common::String &filename) {
 
 			// Read in the image data
 			Common::SeekableReadStream *imageStream = _lzwMode ?
-				Resources::decompressLZ(*rrmStream, bgInfo[idx]._filesize) :
+				res.decompress(*rrmStream, bgInfo[idx]._filesize) :
 				rrmStream->readStream(bgInfo[idx]._filesize);
 
 			_images[idx + 1]._images = new ImageFile(*imageStream);


Commit: bfb78778a4f11803979e355c762bad6ed5a5d4ed
    https://github.com/scummvm/scummvm/commit/bfb78778a4f11803979e355c762bad6ed5a5d4ed
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-16T22:48:24-04:00

Commit Message:
SHERLOCK: Update CAnim loading for Rose Tattoo

Changed paths:
    engines/sherlock/objects.cpp
    engines/sherlock/objects.h
    engines/sherlock/scene.cpp



diff --git a/engines/sherlock/objects.cpp b/engines/sherlock/objects.cpp
index c6254ee..2576ff0 100644
--- a/engines/sherlock/objects.cpp
+++ b/engines/sherlock/objects.cpp
@@ -1135,17 +1135,30 @@ const Common::Rect Object::getOldBounds() const {
 /**
  * Load the data for the animation
  */
-void CAnim::load(Common::SeekableReadStream &s) {
+void CAnim::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
 	char buffer[12];
 	s.read(buffer, 12);
 	_name = Common::String(buffer);
 
-	s.read(_sequences, 30);
+	if (isRoseTattoo) {
+		Common::fill(&_sequences[0], &_sequences[30], 0);
+		_size = s.readUint32LE();
+	} else {
+		s.read(_sequences, 30);
+	}
+
 	_position.x = s.readSint16LE();
 	_position.y = s.readSint16LE();
-	_size = s.readUint32LE();
-	_type = (SpriteType)s.readUint16LE();
-	_flags = s.readByte();
+	
+	if (isRoseTattoo) {
+		_flags = s.readByte();
+		_scaleVal = s.readSint16LE();
+	} else {
+		_size = s.readUint32LE();
+		_type = (SpriteType)s.readUint16LE();
+		_flags = s.readByte();
+	}
+
 	_goto.x = s.readSint16LE();
 	_goto.y = s.readSint16LE();
 	_gotoDir = s.readSint16LE();
diff --git a/engines/sherlock/objects.h b/engines/sherlock/objects.h
index 2073f06..fd4a103 100644
--- a/engines/sherlock/objects.h
+++ b/engines/sherlock/objects.h
@@ -256,17 +256,22 @@ public:
 
 struct CAnim {
 	Common::String _name;			// Name
-	byte _sequences[MAX_FRAME];		// Animation sequences
 	Common::Point _position;		// Position
 	int _size;						// Size of uncompressed animation
-	SpriteType _type;
 	int _flags;						// Tells if can be walked behind
 	Common::Point _goto;			// coords holmes should walk to before starting canim
 	int _gotoDir;
 	Common::Point _teleportPos;		// Location Holmes shoul teleport to after
 	int _teleportDir;					// playing canim
 
-	void load(Common::SeekableReadStream &s);
+	// Scalpel specific
+	byte _sequences[MAX_FRAME];		// Animation sequences
+	SpriteType _type;
+
+	// Rose Tattoo specific
+	int _scaleVal;					// How much the canim is scaled
+
+	void load(Common::SeekableReadStream &s, bool isRoseTattoo);
 };
 
 struct SceneImage {
diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp
index 0348964..0ac2eec 100644
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@ -398,13 +398,14 @@ bool Scene::loadScene(const Common::String &filename) {
 		// Load in cAnim list
 		_cAnim.clear();
 		if (bgHeader._numcAnimations) {
+			int animSize = _vm->getGameID() == GType_SerratedScalpel ? 65 : 47;
 			Common::SeekableReadStream *canimStream = _lzwMode ?
-				Resources::decompressLZ(*rrmStream, 65 * bgHeader._numcAnimations) :
-				rrmStream->readStream(65 * bgHeader._numcAnimations);
+				res.decompress(*rrmStream, animSize * bgHeader._numcAnimations) :
+				rrmStream->readStream(animSize * bgHeader._numcAnimations);
 
 			_cAnim.resize(bgHeader._numcAnimations);
 			for (uint idx = 0; idx < _cAnim.size(); ++idx)
-				_cAnim[idx].load(*canimStream);
+				_cAnim[idx].load(*canimStream, _vm->getGameID() == GType_RoseTattoo);
 
 			delete canimStream;
 		}


Commit: 71540b7ad50b975bfdb21adf5a2045ff72454222
    https://github.com/scummvm/scummvm/commit/71540b7ad50b975bfdb21adf5a2045ff72454222
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-17T07:20:06-04:00

Commit Message:
SHERLOCK: Implement remaining Rose Tattoo scene data loading

Changed paths:
    engines/sherlock/scene.cpp
    engines/sherlock/scene.h
    engines/sherlock/sherlock.h



diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp
index 0ac2eec..96cfac0 100644
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@ -80,18 +80,30 @@ void BgfileheaderInfo::load(Common::SeekableReadStream &s) {
 /**
  * Load the data for the object
  */
-void Exit::load(Common::SeekableReadStream &s) {
-	int xp = s.readSint16LE();
-	int yp = s.readSint16LE();
-	int xSize = s.readSint16LE();
-	int ySize = s.readSint16LE();
-	_bounds = Common::Rect(xp, yp, xp + xSize, yp + ySize);
+void Exit::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
+	if (isRoseTattoo) {
+		char buffer[41];
+		s.read(buffer, 41);
+		_dest = Common::String(buffer);
+	}
 
+	left = s.readSint16LE();
+	top = s.readSint16LE();
+	setWidth(s.readUint16LE());
+	setHeight(s.readUint16LE());
+
+	_image = isRoseTattoo ? s.readByte() : 0;
 	_scene = s.readSint16LE();
-	_allow = s.readSint16LE();
+
+	if (!isRoseTattoo)
+		_allow = s.readSint16LE();
+
 	_people.x = s.readSint16LE();
 	_people.y = s.readSint16LE();
 	_peopleDir = s.readUint16LE();
+
+	if (isRoseTattoo)
+		_allow = s.readSint16LE();
 }
 
 /*----------------------------------------------------------------*/
@@ -134,6 +146,21 @@ int ObjectArray::indexOf(const Object &obj) const {
 
 /*----------------------------------------------------------------*/
 
+/**
+ * Load the data for the object
+ */
+void ScaleZone::load(Common::SeekableReadStream &s) {
+	left = s.readSint16LE();
+	top = s.readSint16LE();
+	setWidth(s.readUint16LE());
+	setHeight(s.readUint16LE());
+
+	_topNumber = s.readByte();
+	_bottomNumber = s.readByte();
+}
+
+/*----------------------------------------------------------------*/
+
 Scene::Scene(SherlockEngine *vm): _vm(vm) {
 	for (int idx = 0; idx < SCENES_COUNT; ++idx)
 		Common::fill(&_sceneStats[idx][0], &_sceneStats[idx][65], false);
@@ -153,6 +180,7 @@ Scene::Scene(SherlockEngine *vm): _vm(vm) {
 	_animating = 0;
 	_doBgAnimDone = true;
 	_tempFadeStyle = 0;
+	_exitZone = -1;
 }
 
 Scene::~Scene() {
@@ -280,7 +308,7 @@ bool Scene::loadScene(const Common::String &filename) {
 		Common::SeekableReadStream *rrmStream = _vm->_res->load(rrmFile);
 
 		rrmStream->seek(39);
-		if (_vm->getGameID() == GType_SerratedScalpel) {
+		if (IS_SERRATED_SCALPEL) {
 			_version = rrmStream->readByte();
 			_lzwMode = _version == 10;
 		} else {
@@ -291,10 +319,10 @@ bool Scene::loadScene(const Common::String &filename) {
 		rrmStream->seek(rrmStream->readUint32LE());
 
 		BgFileHeader bgHeader;
-		bgHeader.synchronize(*rrmStream, _vm->getGameID() == GType_RoseTattoo);
+		bgHeader.synchronize(*rrmStream, IS_ROSE_TATTOO);
 		_invGraphicItems = bgHeader._numImages + 1;
 
-		if (_vm->getGameID() == GType_RoseTattoo) {
+		if (IS_ROSE_TATTOO) {
 			screen.initPaletteFade(bgHeader._bytesWritten);
 			screen.fadeRead(*rrmStream, screen._cMap, PALETTE_SIZE);
 			screen.setupBGArea(screen._cMap);
@@ -316,7 +344,7 @@ bool Scene::loadScene(const Common::String &filename) {
 			bgInfo[idx].load(*rrmStream);
 
 		// Read information
-		if (_vm->getGameID() == GType_SerratedScalpel) {
+		if (IS_SERRATED_SCALPEL) {
 			Common::SeekableReadStream *infoStream = !_lzwMode ? rrmStream :
 				res.decompress(*rrmStream, bgHeader._numStructs * 569 + bgHeader._descSize + bgHeader._seqSize);
 
@@ -398,14 +426,14 @@ bool Scene::loadScene(const Common::String &filename) {
 		// Load in cAnim list
 		_cAnim.clear();
 		if (bgHeader._numcAnimations) {
-			int animSize = _vm->getGameID() == GType_SerratedScalpel ? 65 : 47;
+			int animSize = IS_SERRATED_SCALPEL ? 65 : 47;
 			Common::SeekableReadStream *canimStream = _lzwMode ?
 				res.decompress(*rrmStream, animSize * bgHeader._numcAnimations) :
 				rrmStream->readStream(animSize * bgHeader._numcAnimations);
 
 			_cAnim.resize(bgHeader._numcAnimations);
 			for (uint idx = 0; idx < _cAnim.size(); ++idx)
-				_cAnim[idx].load(*canimStream, _vm->getGameID() == GType_RoseTattoo);
+				_cAnim[idx].load(*canimStream, IS_ROSE_TATTOO);
 
 			delete canimStream;
 		}
@@ -413,7 +441,7 @@ bool Scene::loadScene(const Common::String &filename) {
 		// Read in the room bounding areas
 		int size = rrmStream->readUint16LE();
 		Common::SeekableReadStream *boundsStream = !_lzwMode ? rrmStream :
-			Resources::decompressLZ(*rrmStream, size);
+			res.decompress(*rrmStream, size);
 
 		_zones.resize(size / 10);
 		for (uint idx = 0; idx < _zones.size(); ++idx) {
@@ -428,10 +456,11 @@ bool Scene::loadScene(const Common::String &filename) {
 			delete boundsStream;
 
 		// Ensure we've reached the path version byte
-		if (rrmStream->readByte() != 254)
+		if (rrmStream->readByte() != (IS_SERRATED_SCALPEL ? 254 : 251))
 			error("Invalid scene path data");
 
 		// Load the walk directory
+		assert(_zones.size() < MAX_ZONES);
 		for (uint idx1 = 0; idx1 < _zones.size(); ++idx1) {
 			for (uint idx2 = 0; idx2 < _zones.size(); ++idx2)
 				_walkDirectory[idx1][idx2] = rrmStream->readSint16LE();
@@ -440,7 +469,7 @@ bool Scene::loadScene(const Common::String &filename) {
 		// Read in the walk data
 		size = rrmStream->readUint16LE();
 		Common::SeekableReadStream *walkStream = !_lzwMode ? rrmStream :
-			Resources::decompressLZ(*rrmStream, size);
+			res.decompress(*rrmStream, size);
 
 		_walkData.resize(size);
 		walkStream->read(&_walkData[0], size);
@@ -448,15 +477,27 @@ bool Scene::loadScene(const Common::String &filename) {
 		if (_lzwMode)
 			delete walkStream;
 
+		if (IS_ROSE_TATTOO) {
+			// Read in the entrance
+			_entrance.load(*rrmStream);
+
+			// Load scale zones
+			_scaleZones.resize(rrmStream->readByte());
+			for (uint idx = 0; idx < _scaleZones.size(); ++idx)
+				_scaleZones[idx].load(*rrmStream);
+		}
+
 		// Read in the exits
+		_exitZone = -1;
 		int numExits = rrmStream->readByte();
 		_exits.resize(numExits);
 
 		for (int idx = 0; idx < numExits; ++idx)
-			_exits[idx].load(*rrmStream);
+			_exits[idx].load(*rrmStream, IS_ROSE_TATTOO);
 
-		// Read in the entrance
-		_entrance.load(*rrmStream);
+		if (IS_SERRATED_SCALPEL)
+			// Read in the entrance
+			_entrance.load(*rrmStream);
 
 		// Initialize sound list
 		int numSounds = rrmStream->readByte();
@@ -465,24 +506,34 @@ bool Scene::loadScene(const Common::String &filename) {
 		for (int idx = 0; idx < numSounds; ++idx)
 			_sounds[idx].load(*rrmStream);
 
-		for (int idx = 0; idx < numSounds; ++idx)
-			sound.loadSound(_sounds[idx]._name, _sounds[idx]._priority);
+		loadSceneSounds();
 
-		// Read in palette
-		rrmStream->read(screen._cMap, PALETTE_SIZE);
-		for (int idx = 0; idx < PALETTE_SIZE; ++idx)
-			screen._cMap[idx] = VGA_COLOR_TRANS(screen._cMap[idx]);
+		if (IS_ROSE_TATTOO) {
+			// Load the object sound list
+			char buffer[27];
+			
+			_objSoundList.resize(rrmStream->readUint16LE());
+			for (uint idx = 0; idx < _objSoundList.size(); ++idx) {
+				rrmStream->read(buffer, 27);
+				_objSoundList[idx] = Common::String(buffer);
+			}
+		} else {
+			// Read in palette
+			rrmStream->read(screen._cMap, PALETTE_SIZE);
+			for (int idx = 0; idx < PALETTE_SIZE; ++idx)
+				screen._cMap[idx] = VGA_COLOR_TRANS(screen._cMap[idx]);
 
-		Common::copy(screen._cMap, screen._cMap + PALETTE_SIZE, screen._sMap);
+			Common::copy(screen._cMap, screen._cMap + PALETTE_SIZE, screen._sMap);
 
-		// Read in the background
-		Common::SeekableReadStream *bgStream = !_lzwMode ? rrmStream :
-			Resources::decompressLZ(*rrmStream, SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCENE_HEIGHT);
+			// Read in the background
+			Common::SeekableReadStream *bgStream = !_lzwMode ? rrmStream :
+				res.decompress(*rrmStream, SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCENE_HEIGHT);
 
-		bgStream->read(screen._backBuffer1.getPixels(), SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCENE_HEIGHT);
+			bgStream->read(screen._backBuffer1.getPixels(), SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCENE_HEIGHT);
 
-		if (_lzwMode)
-			delete bgStream;
+			if (_lzwMode)
+				delete bgStream;
+		}
 
 		// Backup the image and set the palette
 		screen._backBuffer2.blitFrom(screen._backBuffer1);
@@ -551,6 +602,16 @@ bool Scene::loadScene(const Common::String &filename) {
 }
 
 /**
+ * Load all the sound effects specified for the current scene
+ */
+void Scene::loadSceneSounds() {
+	Sound &sound = *_vm->_sound;
+
+	for (uint idx = 0; idx < _sounds.size(); ++idx)
+		sound.loadSound(_sounds[idx]._name, _sounds[idx]._priority);
+}
+
+/**
  * Set objects to their current persistent state. This includes things such as
  * opening or moving them
  */
@@ -908,7 +969,7 @@ void Scene::updateBackground() {
  */
 Exit *Scene::checkForExit(const Common::Rect &r) {
 	for (uint idx = 0; idx < _exits.size(); ++idx) {
-		if (_exits[idx]._bounds.intersects(r))
+		if (_exits[idx].intersects(r))
 			return &_exits[idx];
 	}
 
@@ -1243,7 +1304,7 @@ void Scene::doBgAnim() {
 				_canimShapes[idx].checkObject();
 		}
 
-		if (_currentScene == 12 && _vm->getGameID() == GType_SerratedScalpel)
+		if (_currentScene == 12 && IS_SERRATED_SCALPEL)
 			((Scalpel::ScalpelEngine *)_vm)->eraseMirror12();
 
 		// Restore the back buffer from the back buffer 2 in the changed area
@@ -1316,7 +1377,7 @@ void Scene::doBgAnim() {
 	checkBgShapes(people[AL]._imageFrame,
 		Common::Point(people[AL]._position.x / 100, people[AL]._position.y / 100));
 
-	if (_currentScene == 12 && _vm->getGameID() == GType_SerratedScalpel)
+	if (_currentScene == 12 && IS_SERRATED_SCALPEL)
 		((Scalpel::ScalpelEngine *)_vm)->doMirror12();
 
 	// Draw all active shapes which are behind the person
@@ -1426,7 +1487,7 @@ void Scene::doBgAnim() {
 			}
 		}
 
-		if (_currentScene == 12 && _vm->getGameID() == GType_SerratedScalpel)
+		if (_currentScene == 12 && IS_SERRATED_SCALPEL)
 			((Scalpel::ScalpelEngine *)_vm)->flushMirror12();
 
 		for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
diff --git a/engines/sherlock/scene.h b/engines/sherlock/scene.h
index 86b1e3d..9454a4e 100644
--- a/engines/sherlock/scene.h
+++ b/engines/sherlock/scene.h
@@ -68,15 +68,17 @@ struct BgfileheaderInfo {
 	void load(Common::SeekableReadStream &s);
 };
 
-struct Exit {
-	Common::Rect _bounds;
-
+class Exit: public Common::Rect {
+public:
 	int _scene;
 	int _allow;
 	Common::Point _people;
 	int _peopleDir;
 
-	void load(Common::SeekableReadStream &s);
+	Common::String _dest;
+	int _image;					// Arrow image to use
+
+	void load(Common::SeekableReadStream &s, bool isRoseTattoo);
 };
 
 struct SceneEntry {
@@ -99,6 +101,14 @@ public:
 	int indexOf(const Object &obj) const;
 };
 
+class ScaleZone: public Common::Rect {
+public:
+	int _topNumber;		// Numerator of scale size at the top of the zone
+	int _bottomNumber;	// Numerator of scale size at the bottom of the zone
+
+	void load(Common::SeekableReadStream &s);
+};
+
 class Scene {
 private:
 	SherlockEngine *_vm;
@@ -109,6 +119,8 @@ private:
 
 	bool loadScene(const Common::String &filename);
 
+	void loadSceneSounds();
+
 	void checkSceneStatus();
 
 	void checkInventory();
@@ -118,6 +130,7 @@ private:
 	void checkBgShapes(ImageFrame *frame, const Common::Point &pt);
 
 	void saveSceneStatus();
+
 public:
 	int _currentScene;
 	int _goToScene;
@@ -141,9 +154,12 @@ public:
 	int _walkDirectory[MAX_ZONES][MAX_ZONES];
 	Common::Array<byte> _walkData;
 	Common::Array<Exit> _exits;
+	int _exitZone;
 	SceneEntry _entrance;
 	Common::Array<SceneSound> _sounds;
 	ObjectArray _canimShapes;
+	Common::Array<ScaleZone> _scaleZones;
+	Common::StringArray _objSoundList;
 	bool _restoreFlag;
 	int _animating;
 	bool _doBgAnimDone;
diff --git a/engines/sherlock/sherlock.h b/engines/sherlock/sherlock.h
index 9261ad5..2688b51 100644
--- a/engines/sherlock/sherlock.h
+++ b/engines/sherlock/sherlock.h
@@ -139,6 +139,9 @@ public:
 	void synchronize(Common::Serializer &s);
 };
 
+#define IS_ROSE_TATTOO (_vm->getGameID() == GType_RoseTattoo)
+#define IS_SERRATED_SCALPEL (_vm->getGameID() == GType_SerratedScalpel)
+
 } // End of namespace Sherlock
 
 #endif


Commit: d3b86a593bf8e625c162a107d122e7f915b5b81e
    https://github.com/scummvm/scummvm/commit/d3b86a593bf8e625c162a107d122e7f915b5b81e
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-17T08:09:14-04:00

Commit Message:
SHERLOCK: Beginnings of UserInterface split for Scalpel vs Tattoo

Changed paths:
    engines/sherlock/inventory.cpp
    engines/sherlock/inventory.h
    engines/sherlock/settings.cpp
    engines/sherlock/sherlock.cpp
    engines/sherlock/talk.cpp
    engines/sherlock/talk.h
    engines/sherlock/user_interface.cpp
    engines/sherlock/user_interface.h



diff --git a/engines/sherlock/inventory.cpp b/engines/sherlock/inventory.cpp
index 1997807..397575d 100644
--- a/engines/sherlock/inventory.cpp
+++ b/engines/sherlock/inventory.cpp
@@ -274,7 +274,8 @@ void Inventory::drawInventory(int flag) {
 		screen._backBuffer = &screen._backBuffer1;
 	}
 
-	ui._oldUse = -1;
+	assert(IS_SERRATED_SCALPEL);
+	((ScalpelUserInterface *)_vm->_ui)->_oldUse = -1;
 }
 
 /**
@@ -356,31 +357,6 @@ void Inventory::highlight(int index, byte color) {
 }
 
 /**
- * Support method for updating the screen
- */
-void Inventory::doInvJF() {
-	Screen &screen = *_vm->_screen;
-	Talk &talk = *_vm->_talk;
-	UserInterface &ui = *_vm->_ui;
-
-	ui._invLookFlag = true;
-	freeInv();
-
-	ui._infoFlag = true;
-	ui.clearInfo();
-
-	screen._backBuffer2.blitFrom(screen._backBuffer1, Common::Point(0, CONTROLS_Y),
-		Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
-	ui.examine();
-
-	if (!talk._talkToAbort) {
-		screen._backBuffer2.blitFrom((*ui._controlPanel)[0]._frame,
-			Common::Point(0, CONTROLS_Y));
-		loadInv();
-	}
-}
-
-/**
  * Adds a shape from the scene to the player's inventory
  */
 int Inventory::putNameInInventory(const Common::String &name) {
diff --git a/engines/sherlock/inventory.h b/engines/sherlock/inventory.h
index eb5aebd..5b9374d 100644
--- a/engines/sherlock/inventory.h
+++ b/engines/sherlock/inventory.h
@@ -95,8 +95,6 @@ public:
 
 	void highlight(int index, byte color);
 
-	void doInvJF();
-
 	int putNameInInventory(const Common::String &name);
 	int putItemInInventory(Object &obj);
 
diff --git a/engines/sherlock/settings.cpp b/engines/sherlock/settings.cpp
index ffa1f05..73c99bf 100644
--- a/engines/sherlock/settings.cpp
+++ b/engines/sherlock/settings.cpp
@@ -223,9 +223,10 @@ void Settings::show(SherlockEngine *vm) {
 	Screen &screen = *vm->_screen;
 	Sound &sound = *vm->_sound;
 	Talk &talk = *vm->_talk;
-	UserInterface &ui = *vm->_ui;
+	ScalpelUserInterface &ui = *(ScalpelUserInterface *)vm->_ui;
 	bool updateConfig = false;
 
+	assert(vm->getGameID() == GType_SerratedScalpel);
 	Settings settings(vm);
 	settings.drawInteface(false);
 
diff --git a/engines/sherlock/sherlock.cpp b/engines/sherlock/sherlock.cpp
index eea3dcb..80a4383 100644
--- a/engines/sherlock/sherlock.cpp
+++ b/engines/sherlock/sherlock.cpp
@@ -89,7 +89,7 @@ void SherlockEngine::initialize() {
 	_screen = new Screen(this);
 	_sound = new Sound(this, _mixer);
 	_talk = new Talk(this);
-	_ui = new UserInterface(this);
+	_ui = UserInterface::init(this);
 
 	// Load game settings
 	loadConfig();
diff --git a/engines/sherlock/talk.cpp b/engines/sherlock/talk.cpp
index d656431..c67b98b 100644
--- a/engines/sherlock/talk.cpp
+++ b/engines/sherlock/talk.cpp
@@ -193,9 +193,11 @@ void Talk::talkTo(const Common::String &filename) {
 	while (!_sequenceStack.empty())
 		pullSequence();
 
-	// Restore any pressed button
-	if (!ui._windowOpen && savedMode != STD_MODE)
-		ui.restoreButton(savedMode - 1);
+	if (IS_SERRATED_SCALPEL) {
+		// Restore any pressed button
+		if (!ui._windowOpen && savedMode != STD_MODE)
+			((ScalpelUserInterface *)_vm->_ui)->restoreButton(savedMode - 1);
+	}
 
 	// Clear the ui counter so that anything displayed on the info line
 	// before the window was opened isn't cleared
diff --git a/engines/sherlock/talk.h b/engines/sherlock/talk.h
index b1a7358..5c87d79 100644
--- a/engines/sherlock/talk.h
+++ b/engines/sherlock/talk.h
@@ -120,10 +120,10 @@ struct TalkSequences {
 };
 
 class SherlockEngine;
-class UserInterface;
+class ScalpelUserInterface;
 
 class Talk {
-	friend class UserInterface;
+	friend class ScalpelUserInterface;
 private:
 	Common::Array<TalkSequences> STILL_SEQUENCES;
 	Common::Array<TalkSequences> TALK_SEQUENCES;
diff --git a/engines/sherlock/user_interface.cpp b/engines/sherlock/user_interface.cpp
index 1ab8fe7..efe6c8e 100644
--- a/engines/sherlock/user_interface.cpp
+++ b/engines/sherlock/user_interface.cpp
@@ -78,45 +78,53 @@ const char *const MUSE[] = {
 	"Doors don't smoke"
 };
 
-/*----------------------------------------------------------------*/
+
+
+UserInterface *UserInterface::init(SherlockEngine *vm) {
+	if (vm->getGameID() == GType_SerratedScalpel)
+		return new ScalpelUserInterface(vm);
+	else
+		return new TattooUserInterface(vm);
+}
 
 UserInterface::UserInterface(SherlockEngine *vm) : _vm(vm) {
-	if (_vm->getGameID() == GType_SerratedScalpel) {
-		_controls = new ImageFile("menu.all");
-		_controlPanel = new ImageFile("controls.vgs");
-	} else {
-		_controls = nullptr;
-		_controlPanel = nullptr;
-	}
-	_bgFound = 0;
-	_oldBgFound = -1;
-	_keycode = Common::KEYCODE_INVALID;
-	_helpStyle = false;
-	_menuCounter = 0;
 	_menuMode = STD_MODE;
-	_help = _oldHelp = 0;
-	_lookHelp = 0;
+	_menuCounter = 0;
+	_infoFlag = false;
+	_windowOpen = false;
+	_endKeyActive = true;
+	_invLookFlag = 0;
+	_windowStyle = 1;	// Sliding windows
+	_helpStyle = false;
+	_lookScriptFlag = false;
+
 	_key = _oldKey = 0;
+	_selector = _oldSelector = -1;
 	_temp = _oldTemp = 0;
 	_temp1 = 0;
-	_invLookFlag = 0;
-	_windowOpen = false;
+	_lookHelp = 0;
+}
+
+/*----------------------------------------------------------------*/
+
+ScalpelUserInterface::ScalpelUserInterface(SherlockEngine *vm): UserInterface(vm) {
+	_controls = new ImageFile("menu.all");
+	_controlPanel = new ImageFile("controls.vgs");
+	_bgFound = 0;
+	_oldBgFound = -1;
+	_keycode = Common::KEYCODE_INVALID;
+	_help = _oldHelp = 0;
 	_oldLook = false;
 	_keyboardInput = false;
 	_pause = false;
 	_cNum = 0;
-	_selector = _oldSelector = -1;
 	_windowBounds = Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH - 1,
 		SHERLOCK_SCREEN_HEIGHT - 1);
-	_windowStyle = 1;	// Sliding windows
 	_find = 0;
 	_oldUse = 0;
-	_endKeyActive = true;
-	_lookScriptFlag = false;
-	_infoFlag = false;
 }
 
-UserInterface::~UserInterface() {
+ScalpelUserInterface::~ScalpelUserInterface() {
 	delete _controls;
 	delete _controlPanel;
 }
@@ -124,7 +132,7 @@ UserInterface::~UserInterface() {
 /**
  * Resets the user interface
  */
-void UserInterface::reset() {
+void ScalpelUserInterface::reset() {
 	_oldKey = -1;
 	_help = _oldHelp = -1;
 	_oldTemp = _temp = -1;
@@ -133,7 +141,7 @@ void UserInterface::reset() {
 /**
  * Draw the user interface onto the screen's back buffers
  */
-void UserInterface::drawInterface(int bufferNum) {
+void ScalpelUserInterface::drawInterface(int bufferNum) {
 	Screen &screen = *_vm->_screen;
 
 	if (bufferNum & 1)
@@ -147,7 +155,7 @@ void UserInterface::drawInterface(int bufferNum) {
 /**
  * Main input handler for the user interface
  */
-void UserInterface::handleInput() {
+void ScalpelUserInterface::handleInput() {
 	Events &events = *_vm->_events;
 	Inventory &inv = *_vm->_inventory;
 	People &people = *_vm->_people;
@@ -405,7 +413,7 @@ void UserInterface::handleInput() {
 /**
  * Draws the image for a user interface button in the down/pressed state.
  */
-void UserInterface::depressButton(int num) {
+void ScalpelUserInterface::depressButton(int num) {
 	Screen &screen = *_vm->_screen;
 	Common::Point pt(MENU_POINTS[num][0], MENU_POINTS[num][1]);
 
@@ -418,7 +426,7 @@ void UserInterface::depressButton(int num) {
  * Draws the image for the given user interface button in the up
  * (not selected) position
  */
-void UserInterface::restoreButton(int num) {
+void ScalpelUserInterface::restoreButton(int num) {
 	Screen &screen = *_vm->_screen;
 	Common::Point pt(MENU_POINTS[num][0], MENU_POINTS[num][1]);
 	Graphics::Surface &frame = (*_controls)[num]._frame;
@@ -437,7 +445,7 @@ void UserInterface::restoreButton(int num) {
  * If he mouse button is pressed, then calls depressButton to draw the button
  * as pressed; if not, it will show it as released with a call to "restoreButton".
  */
-void UserInterface::pushButton(int num) {
+void ScalpelUserInterface::pushButton(int num) {
 	Events &events = *_vm->_events;
 	_oldKey = -1;
 
@@ -459,7 +467,7 @@ void UserInterface::pushButton(int num) {
  * have already been drawn. This simply takes care of switching the mode around
  * accordingly
  */
-void UserInterface::toggleButton(int num) {
+void ScalpelUserInterface::toggleButton(int num) {
 	Screen &screen = *_vm->_screen;
 
 	if (_menuMode != (num + 1)) {
@@ -490,7 +498,7 @@ void UserInterface::toggleButton(int num) {
 /**
  * Clears the info line of the screen
  */
-void UserInterface::clearInfo() {
+void ScalpelUserInterface::clearInfo() {
 	if (_infoFlag) {
 		_vm->_screen->vgaBar(Common::Rect(16, INFO_LINE, SHERLOCK_SCREEN_WIDTH - 19,
 			INFO_LINE + 10), INFO_BLACK);
@@ -502,7 +510,7 @@ void UserInterface::clearInfo() {
 /**
  * Clear any active text window
  */
-void UserInterface::clearWindow() {
+void ScalpelUserInterface::clearWindow() {
 	if (_windowOpen) {
 		_vm->_screen->vgaBar(Common::Rect(3, CONTROLS_Y + 11, SHERLOCK_SCREEN_WIDTH - 2,
 			SHERLOCK_SCREEN_HEIGHT - 2), INV_BACKGROUND);
@@ -512,7 +520,7 @@ void UserInterface::clearWindow() {
 /**
  * Handles counting down whilst checking for input, then clears the info line.
  */
-void UserInterface::whileMenuCounter() {
+void ScalpelUserInterface::whileMenuCounter() {
 	if (!(--_menuCounter) || _vm->_events->checkInput()) {
 		_menuCounter = 0;
 		_infoFlag = true;
@@ -524,7 +532,7 @@ void UserInterface::whileMenuCounter() {
  * Creates a text window and uses it to display the in-depth description
  * of the highlighted object
  */
-void UserInterface::examine() {
+void ScalpelUserInterface::examine() {
 	Events &events = *_vm->_events;
 	Inventory &inv = *_vm->_inventory;
 	People &people = *_vm->_people;
@@ -578,7 +586,7 @@ void UserInterface::examine() {
 /**
  * Print the name of an object in the scene
  */
-void UserInterface::lookScreen(const Common::Point &pt) {
+void ScalpelUserInterface::lookScreen(const Common::Point &pt) {
 	Events &events = *_vm->_events;
 	Inventory &inv = *_vm->_inventory;
 	Scene &scene = *_vm->_scene;
@@ -694,7 +702,7 @@ void UserInterface::lookScreen(const Common::Point &pt) {
 /**
  * Gets the item in the inventory the mouse is on and display's it's description
  */
-void UserInterface::lookInv() {
+void ScalpelUserInterface::lookInv() {
 	Events &events = *_vm->_events;
 	Inventory &inv = *_vm->_inventory;
 	Screen &screen = *_vm->_screen;
@@ -722,7 +730,7 @@ void UserInterface::lookInv() {
 /**
  * Handles input when the file list window is being displayed
  */
-void UserInterface::doEnvControl() {
+void ScalpelUserInterface::doEnvControl() {
 	Events &events = *_vm->_events;
 	SaveManager &saves = *_vm->_saves;
 	Scene &scene = *_vm->_scene;
@@ -1028,12 +1036,13 @@ void UserInterface::doEnvControl() {
 /**
  * Handle input whilst the inventory is active
  */
-void UserInterface::doInvControl() {
+void ScalpelUserInterface::doInvControl() {
 	Events &events = *_vm->_events;
 	Inventory &inv = *_vm->_inventory;
 	Scene &scene = *_vm->_scene;
 	Screen &screen = *_vm->_screen;
 	Talk &talk = *_vm->_talk;
+	UserInterface &ui = *_vm->_ui;
 	int colors[8];
 	Common::Point mousePos = events.mousePos();
 
@@ -1197,7 +1206,7 @@ void UserInterface::doInvControl() {
 			if ((mousePos.y < CONTROLS_Y1) && (inv._invMode == 1) && (_find >= 0) && (_find < 1000)) {
 				if (!scene._bgShapes[_find]._examine.empty() &&
 						scene._bgShapes[_find]._examine[0] >= ' ')
-					inv.doInvJF();
+					ui.doInvJF();
 			} else if (_selector != -1 || _find >= 0) {
 				// Selector is the inventory object that was clicked on, or selected.
 				// If it's -1, then no inventory item is highlighted yet. Otherwise,
@@ -1205,7 +1214,7 @@ void UserInterface::doInvControl() {
 
 				if (_selector != -1 && inv._invMode == INVMODE_LOOK
 						&& mousePos.y >(CONTROLS_Y1 + 11))
-					inv.doInvJF();
+					ui.doInvJF();
 
 				if (talk._talkToAbort)
 					return;
@@ -1255,7 +1264,7 @@ void UserInterface::doInvControl() {
 /**
  * Handles waiting whilst an object's description window is open.
  */
-void UserInterface::doLookControl() {
+void ScalpelUserInterface::doLookControl() {
 	Events &events = *_vm->_events;
 	Inventory &inv = *_vm->_inventory;
 	Screen &screen = *_vm->_screen;
@@ -1319,7 +1328,7 @@ void UserInterface::doLookControl() {
 /**
  * Handles input until one of the user interface buttons/commands is selected
  */
-void UserInterface::doMainControl() {
+void ScalpelUserInterface::doMainControl() {
 	Events &events = *_vm->_events;
 	Inventory &inv = *_vm->_inventory;
 	SaveManager &saves = *_vm->_saves;
@@ -1460,7 +1469,7 @@ void UserInterface::doMainControl() {
 /**
  * Handles the input for the MOVE, OPEN, and CLOSE commands
  */
-void UserInterface::doMiscControl(int allowed) {
+void ScalpelUserInterface::doMiscControl(int allowed) {
 	Events &events = *_vm->_events;
 	Scene &scene = *_vm->_scene;
 	Talk &talk = *_vm->_talk;
@@ -1512,7 +1521,7 @@ void UserInterface::doMiscControl(int allowed) {
 /**
  * Handles input for picking up items
  */
-void UserInterface::doPickControl() {
+void ScalpelUserInterface::doPickControl() {
 	Events &events = *_vm->_events;
 	Scene &scene = *_vm->_scene;
 	Talk &talk = *_vm->_talk;
@@ -1539,7 +1548,7 @@ void UserInterface::doPickControl() {
  * Handles input when in talk mode. It highlights the buttons and available statements,
  * and handles allowing the user to click on them
  */
-void UserInterface::doTalkControl() {
+void ScalpelUserInterface::doTalkControl() {
 	Events &events = *_vm->_events;
 	Journal &journal = *_vm->_journal;
 	People &people = *_vm->_people;
@@ -1795,7 +1804,7 @@ void UserInterface::doTalkControl() {
  *		the user interface, it uses so many internal UI fields, that it sort of made some sense
  *		to put it in the UserInterface class.
  */
-void UserInterface::journalControl() {
+void ScalpelUserInterface::journalControl() {
 	Events &events = *_vm->_events;
 	Journal &journal = *_vm->_journal;
 	Scene &scene = *_vm->_scene;
@@ -1846,7 +1855,7 @@ void UserInterface::journalControl() {
 /**
 * Print the description of an object
 */
-void UserInterface::printObjectDesc(const Common::String &str, bool firstTime) {
+void ScalpelUserInterface::printObjectDesc(const Common::String &str, bool firstTime) {
 	Events &events = *_vm->_events;
 	Inventory &inv = *_vm->_inventory;
 	Screen &screen = *_vm->_screen;
@@ -2017,14 +2026,14 @@ void UserInterface::printObjectDesc(const Common::String &str, bool firstTime) {
 /**
  * Print the previously selected object's decription
  */
-void UserInterface::printObjectDesc() {
+void ScalpelUserInterface::printObjectDesc() {
 	printObjectDesc(_cAnimStr, true);
 }
 
 /**
  * Displays a passed window by gradually scrolling it vertically on-screen
  */
-void UserInterface::summonWindow(const Surface &bgSurface, bool slideUp) {
+void ScalpelUserInterface::summonWindow(const Surface &bgSurface, bool slideUp) {
 	Events &events = *_vm->_events;
 	Screen &screen = *_vm->_screen;
 
@@ -2067,7 +2076,7 @@ void UserInterface::summonWindow(const Surface &bgSurface, bool slideUp) {
 /**
  * Slide the window stored in the back buffer onto the screen
  */
-void UserInterface::summonWindow(bool slideUp, int height) {
+void ScalpelUserInterface::summonWindow(bool slideUp, int height) {
 	Screen &screen = *_vm->_screen;
 
 	// Extract the window that's been drawn on the back buffer
@@ -2088,7 +2097,7 @@ void UserInterface::summonWindow(bool slideUp, int height) {
  * Close a currently open window
  * @param flag	0 = slide old window down, 1 = slide prior UI back up
  */
-void UserInterface::banishWindow(bool slideUp) {
+void ScalpelUserInterface::banishWindow(bool slideUp) {
 	Events &events = *_vm->_events;
 	Screen &screen = *_vm->_screen;
 
@@ -2157,7 +2166,7 @@ void UserInterface::banishWindow(bool slideUp) {
 /**
  * Checks to see whether a USE action is valid on the given object
  */
-void UserInterface::checkUseAction(const UseType *use, const Common::String &invName,
+void ScalpelUserInterface::checkUseAction(const UseType *use, const Common::String &invName,
 		const char *const messages[], int objNum, int giveMode) {
 	Events &events = *_vm->_events;
 	Inventory &inv = *_vm->_inventory;
@@ -2253,7 +2262,7 @@ void UserInterface::checkUseAction(const UseType *use, const Common::String &inv
 /**
  * Called for OPEN, CLOSE, and MOVE actions are being done
  */
-void UserInterface::checkAction(ActionType &action, const char *const messages[], int objNum) {
+void ScalpelUserInterface::checkAction(ActionType &action, const char *const messages[], int objNum) {
 	Events &events = *_vm->_events;
 	People &people = *_vm->_people;
 	Scene &scene = *_vm->_scene;
@@ -2385,4 +2394,39 @@ void UserInterface::checkAction(ActionType &action, const char *const messages[]
 	events.setCursor(ARROW);
 }
 
+/**
+ * Support method for updating the screen
+ */
+void ScalpelUserInterface::doInvJF() {
+	Inventory &inv = *_vm->_inventory;
+	Screen &screen = *_vm->_screen;
+	Talk &talk = *_vm->_talk;
+
+	_invLookFlag = true;
+	inv.freeInv();
+
+	_infoFlag = true;
+	clearInfo();
+
+	screen._backBuffer2.blitFrom(screen._backBuffer1, Common::Point(0, CONTROLS_Y),
+		Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
+	examine();
+
+	if (!talk._talkToAbort) {
+		screen._backBuffer2.blitFrom((*_controlPanel)[0]._frame,
+			Common::Point(0, CONTROLS_Y));
+		inv.loadInv();
+	}
+}
+
+/*----------------------------------------------------------------*/
+
+TattooUserInterface::TattooUserInterface(SherlockEngine *vm): UserInterface(vm) {
+	//
+}
+
+void TattooUserInterface::handleInput() {
+	// TODO
+}
+
 } // End of namespace Sherlock
diff --git a/engines/sherlock/user_interface.h b/engines/sherlock/user_interface.h
index 2ff6071..acbb0c0 100644
--- a/engines/sherlock/user_interface.h
+++ b/engines/sherlock/user_interface.h
@@ -61,31 +61,64 @@ extern const char *const PRESS_KEY_TO_CONTINUE;
 class SherlockEngine;
 class Inventory;
 class Talk;
-class UserInterface;
 
 class UserInterface {
+protected:
+	SherlockEngine *_vm;
+
+	UserInterface(SherlockEngine *vm);
+public:
+	MenuMode _menuMode;
+	int _menuCounter;
+	bool _infoFlag;
+	bool _windowOpen;
+	bool _endKeyActive;
+	int _invLookFlag;
+	int _windowStyle;
+	bool _helpStyle;
+	Common::Rect _windowBounds;
+	bool _lookScriptFlag;
+
+	// TODO: Not so sure these should be in the base class. May want to refactor them to SherlockEngine, or refactor
+	// various Scalpel dialogs to keep their own private state of key/selections
+	int _key, _oldKey;
+	int _selector, _oldSelector;
+	int _temp, _oldTemp;
+	int _temp1;
+	int _lookHelp;
+public:
+	static UserInterface *init(SherlockEngine *vm);
+
+	virtual void reset() {}
+	virtual void drawInterface(int bufferNum = 3) {}
+	virtual void handleInput() {}
+
+	virtual void doInvJF() {}
+	virtual void summonWindow(const Surface &bgSurface, bool slideUp = true) {}
+	virtual void summonWindow(bool slideUp = true, int height = CONTROLS_Y) {}
+	virtual void banishWindow(bool slideUp = true) {}
+	virtual void clearInfo() {}
+	virtual void clearWindow() {}
+
+	virtual void printObjectDesc() {}
+};
+
+class ScalpelUserInterface: public UserInterface {
 	friend class Inventory;
 	friend class Settings;
 	friend class Talk;
 private:
-	SherlockEngine *_vm;
 	ImageFile *_controlPanel;
 	ImageFile *_controls;
 	int _bgFound;
 	int _oldBgFound;
 	int _keycode;
-	int _lookHelp;
 	int _help, _oldHelp;
-	int _key, _oldKey;
-	int _temp, _oldTemp;
 	int _oldLook;
 	bool _keyboardInput;
 	bool _pause;
 	int _cNum;
-	int _selector, _oldSelector;
 	Common::String _cAnimStr;
-	bool _lookScriptFlag;
-	Common::Rect _windowBounds;
 	Common::String _descStr;
 	int _find;
 	int _oldUse;
@@ -114,39 +147,38 @@ private:
 	void checkUseAction(const UseType *use, const Common::String &invName, const char *const messages[],
 		int objNum, int giveMode);
 	void checkAction(ActionType &action, const char *const messages[], int objNum);
+
+	void printObjectDesc(const Common::String &str, bool firstTime);
 public:
-	MenuMode _menuMode;
-	int _menuCounter;
-	bool _infoFlag;
-	bool _windowOpen;
-	bool _endKeyActive;
-	int _invLookFlag;
-	int _temp1;
-	int _windowStyle;
-	bool _helpStyle;
-public:
-	UserInterface(SherlockEngine *vm);
-	~UserInterface();
+	ScalpelUserInterface(SherlockEngine *vm);
+	~ScalpelUserInterface();
 
-	void reset();
+	void whileMenuCounter();
 
-	void drawInterface(int bufferNum = 3);
+	void restoreButton(int num);
+public:
+	virtual void reset();
 
-	void handleInput();
+	virtual void handleInput();
 
-	void clearInfo();
-	void clearWindow();
+	virtual void drawInterface(int bufferNum = 3);
 
-	void whileMenuCounter();
+	virtual void doInvJF();
 
-	void printObjectDesc(const Common::String &str, bool firstTime);
-	void printObjectDesc();
+	virtual void summonWindow(const Surface &bgSurface, bool slideUp = true);
+	virtual void summonWindow(bool slideUp = true, int height = CONTROLS_Y);
+	virtual void banishWindow(bool slideUp = true);
+	virtual void clearInfo();
+	virtual void clearWindow();
 
-	void summonWindow(const Surface &bgSurface, bool slideUp = true);
-	void summonWindow(bool slideUp = true, int height = CONTROLS_Y);
-	void banishWindow(bool slideUp = true);
+	virtual void printObjectDesc();
+};
 
-	void restoreButton(int num);
+class TattooUserInterface : public UserInterface {
+public:
+	TattooUserInterface(SherlockEngine *vm);
+public:
+	virtual void handleInput();
 };
 
 } // End of namespace Sherlock


Commit: 0cc55e20f8d9a63621fbabdfdc31a82194898884
    https://github.com/scummvm/scummvm/commit/0cc55e20f8d9a63621fbabdfdc31a82194898884
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-22T22:31:21-04:00

Commit Message:
Merge branch 'master' into sherlock2

Changed paths:
    NEWS
    README
    audio/mods/protracker.cpp
    backends/graphics/openglsdl/openglsdl-graphics.cpp
    backends/graphics/surfacesdl/surfacesdl-graphics.cpp
    backends/graphics/surfacesdl/surfacesdl-graphics.h
    devtools/scumm-md5.txt
    engines/agi/agi.cpp
    engines/agi/agi.h
    engines/agi/detection.cpp
    engines/agi/detection_tables.h
    engines/agi/font.h
    engines/agi/graphics.cpp
    engines/agi/graphics.h
    engines/agi/preagi.cpp
    engines/agi/sound_pcjr.cpp
    engines/agi/text.cpp
    engines/agos/rooms.cpp
    engines/agos/saveload.cpp
    engines/cine/detection_tables.h
    engines/fullpipe/scene.cpp
    engines/kyra/sound_adlib.cpp
    engines/mads/action.cpp
    engines/mads/action.h
    engines/mads/animation.cpp
    engines/mads/animation.h
    engines/mads/assets.cpp
    engines/mads/assets.h
    engines/mads/audio.cpp
    engines/mads/audio.h
    engines/mads/compression.cpp
    engines/mads/compression.h
    engines/mads/debugger.cpp
    engines/mads/debugger.h
    engines/mads/detection.cpp
    engines/mads/detection_tables.h
    engines/mads/dialogs.cpp
    engines/mads/dialogs.h
    engines/mads/dragonsphere/dragonsphere_scenes.cpp
    engines/mads/dragonsphere/dragonsphere_scenes.h
    engines/mads/dragonsphere/game_dragonsphere.cpp
    engines/mads/dragonsphere/game_dragonsphere.h
    engines/mads/events.cpp
    engines/mads/events.h
    engines/mads/font.cpp
    engines/mads/font.h
    engines/mads/game.cpp
    engines/mads/game.h
    engines/mads/game_data.cpp
    engines/mads/game_data.h
    engines/mads/globals.cpp
    engines/mads/globals.h
    engines/mads/hotspots.cpp
    engines/mads/hotspots.h
    engines/mads/inventory.cpp
    engines/mads/inventory.h
    engines/mads/mads.cpp
    engines/mads/mads.h
    engines/mads/menu_views.cpp
    engines/mads/menu_views.h
    engines/mads/messages.cpp
    engines/mads/messages.h
    engines/mads/msurface.cpp
    engines/mads/msurface.h
    engines/mads/nebular/dialogs_nebular.cpp
    engines/mads/nebular/dialogs_nebular.h
    engines/mads/nebular/game_nebular.cpp
    engines/mads/nebular/game_nebular.h
    engines/mads/nebular/globals_nebular.cpp
    engines/mads/nebular/globals_nebular.h
    engines/mads/nebular/menu_nebular.cpp
    engines/mads/nebular/menu_nebular.h
    engines/mads/nebular/nebular_scenes.cpp
    engines/mads/nebular/nebular_scenes.h
    engines/mads/nebular/nebular_scenes1.cpp
    engines/mads/nebular/nebular_scenes1.h
    engines/mads/nebular/nebular_scenes2.cpp
    engines/mads/nebular/nebular_scenes2.h
    engines/mads/nebular/nebular_scenes3.cpp
    engines/mads/nebular/nebular_scenes3.h
    engines/mads/nebular/nebular_scenes4.cpp
    engines/mads/nebular/nebular_scenes4.h
    engines/mads/nebular/nebular_scenes5.cpp
    engines/mads/nebular/nebular_scenes5.h
    engines/mads/nebular/nebular_scenes6.cpp
    engines/mads/nebular/nebular_scenes6.h
    engines/mads/nebular/nebular_scenes7.cpp
    engines/mads/nebular/nebular_scenes7.h
    engines/mads/nebular/nebular_scenes8.cpp
    engines/mads/nebular/nebular_scenes8.h
    engines/mads/nebular/sound_nebular.cpp
    engines/mads/nebular/sound_nebular.h
    engines/mads/palette.cpp
    engines/mads/palette.h
    engines/mads/phantom/game_phantom.cpp
    engines/mads/phantom/game_phantom.h
    engines/mads/phantom/phantom_scenes.cpp
    engines/mads/phantom/phantom_scenes.h
    engines/mads/player.cpp
    engines/mads/player.h
    engines/mads/rails.cpp
    engines/mads/rails.h
    engines/mads/resources.cpp
    engines/mads/resources.h
    engines/mads/scene.cpp
    engines/mads/scene.h
    engines/mads/screen.cpp
    engines/mads/screen.h
    engines/mads/sequence.cpp
    engines/mads/sequence.h
    engines/mads/sound.cpp
    engines/mads/sound.h
    engines/mads/sprites.cpp
    engines/mads/sprites.h
    engines/mads/staticres.cpp
    engines/mads/staticres.h
    engines/mads/user_interface.cpp
    engines/mads/user_interface.h
    engines/queen/walk.cpp
    engines/saga/scene.cpp
    engines/sci/console.cpp
    engines/sci/console.h
    engines/sci/detection_tables.h
    engines/sci/engine/script.cpp
    engines/sci/engine/script.h
    engines/sci/engine/script_patches.cpp
    engines/sci/engine/workarounds.cpp
    engines/scumm/scumm-md5.h
    engines/sherlock/animation.cpp
    engines/sherlock/animation.h
    engines/sherlock/debugger.cpp
    engines/sherlock/debugger.h
    engines/sherlock/detection.cpp
    engines/sherlock/detection_tables.h
    engines/sherlock/events.cpp
    engines/sherlock/events.h
    engines/sherlock/inventory.cpp
    engines/sherlock/inventory.h
    engines/sherlock/journal.cpp
    engines/sherlock/journal.h
    engines/sherlock/map.cpp
    engines/sherlock/map.h
    engines/sherlock/objects.cpp
    engines/sherlock/objects.h
    engines/sherlock/people.cpp
    engines/sherlock/people.h
    engines/sherlock/resources.cpp
    engines/sherlock/resources.h
    engines/sherlock/saveload.cpp
    engines/sherlock/saveload.h
    engines/sherlock/scalpel/darts.cpp
    engines/sherlock/scalpel/darts.h
    engines/sherlock/scalpel/scalpel.cpp
    engines/sherlock/scalpel/scalpel.h
    engines/sherlock/scene.cpp
    engines/sherlock/scene.h
    engines/sherlock/screen.cpp
    engines/sherlock/screen.h
    engines/sherlock/settings.cpp
    engines/sherlock/settings.h
    engines/sherlock/sherlock.cpp
    engines/sherlock/sherlock.h
    engines/sherlock/sound.cpp
    engines/sherlock/sound.h
    engines/sherlock/surface.cpp
    engines/sherlock/surface.h
    engines/sherlock/talk.cpp
    engines/sherlock/talk.h
    engines/sherlock/user_interface.cpp
    engines/sherlock/user_interface.h
    engines/toon/toon.cpp



diff --cc engines/sherlock/inventory.cpp
index 397575d,7f216a3..bbb7c75
--- a/engines/sherlock/inventory.cpp
+++ b/engines/sherlock/inventory.cpp
@@@ -274,14 -243,9 +243,10 @@@ void Inventory::drawInventory(InvNewMod
  		screen._backBuffer = &screen._backBuffer1;
  	}
  
 -	ui._oldUse = -1;
 +	assert(IS_SERRATED_SCALPEL);
 +	((ScalpelUserInterface *)_vm->_ui)->_oldUse = -1;
  }
  
- /**
-  * Prints the line of inventory commands at the top of an inventory window with
-  * the correct highlighting
-  */
  void Inventory::invCommands(bool slamIt) {
  	Screen &screen = *_vm->_screen;
  	UserInterface &ui = *_vm->_ui;
@@@ -356,9 -317,27 +318,30 @@@ void Inventory::highlight(int index, by
  	screen.slamArea(8 + slot * 52, 165, 44, 30);
  }
  
- /**
-  * Adds a shape from the scene to the player's inventory
-  */
+ void Inventory::refreshInv() {
++	if (IS_ROSE_TATTOO)
++		return;
++	
+ 	Screen &screen = *_vm->_screen;
+ 	Talk &talk = *_vm->_talk;
 -	UserInterface &ui = *_vm->_ui;
++	ScalpelUserInterface &ui = *(ScalpelUserInterface *)_vm->_ui;
+ 
+ 	ui._invLookFlag = true;
+ 	freeInv();
+ 
+ 	ui._infoFlag = true;
+ 	ui.clearInfo();
+ 
+ 	screen._backBuffer2.blitFrom(screen._backBuffer1, Common::Point(0, CONTROLS_Y),
+ 		Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
+ 	ui.examine();
+ 
+ 	if (!talk._talkToAbort) {
+ 		screen._backBuffer2.blitFrom((*ui._controlPanel)[0], Common::Point(0, CONTROLS_Y));
+ 		loadInv();
+ 	}
+ }
+ 
  int Inventory::putNameInInventory(const Common::String &name) {
  	Scene &scene = *_vm->_scene;
  	int matches = 0;
diff --cc engines/sherlock/map.cpp
index 46e233b,42775ae..44ca7cd
--- a/engines/sherlock/map.cpp
+++ b/engines/sherlock/map.cpp
@@@ -91,17 -82,9 +83,14 @@@ void Map::loadSequences(int count, cons
  		Common::copy(seq, seq + MAX_FRAME, &_sequences[idx][0]);
  }
  
- /**
-  * Load data  needed for the map
-  */
  void Map::loadData() {
 +	// TODO: Remove this
 +	if (_vm->getGameID() == GType_RoseTattoo)
 +		return;
 +
  	// Load the list of location names
 -	Common::SeekableReadStream *txtStream = _vm->_res->load("chess.txt");
 +	Common::SeekableReadStream *txtStream = _vm->_res->load(
 +		_vm->getGameID() == GType_SerratedScalpel ? "chess.txt" : "map.txt");
  
  	int streamSize = txtStream->size();
  	while (txtStream->pos() < streamSize) {
diff --cc engines/sherlock/objects.cpp
index 2576ff0,02f2526..f380351
--- a/engines/sherlock/objects.cpp
+++ b/engines/sherlock/objects.cpp
@@@ -386,21 -371,11 +371,16 @@@ void ActionType::load(Common::SeekableR
  UseType::UseType() {
  	_cAnimNum = _cAnimSpeed = 0;
  	_useFlag = 0;
- 	_dFlag[0] = 0;
- 	_lFlag[0] = _lFlag[1] = 0;
  }
  
- /**
-  * Load the data for the UseType
-  */
 -void UseType::load(Common::SeekableReadStream &s) {
 +void UseType::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
  	char buffer[12];
  
 +	if (isRoseTattoo) {
 +		s.read(buffer, 12);
 +		_verb = Common::String(buffer);
 +	}
 +
  	_cAnimNum = s.readByte();
  	_cAnimSpeed = s.readByte();
  	if (_cAnimSpeed & 0x80)
@@@ -412,12 -387,7 +392,9 @@@
  	}
  
  	_useFlag = s.readSint16LE();
 -	s.skip(6);
 +
- 	if (!isRoseTattoo) {
- 		_dFlag[0] = s.readSint16LE();
- 		_lFlag[0] = s.readSint16LE();
- 		_lFlag[1] = s.readSint16LE();
- 	}
++	if (!isRoseTattoo)
++		s.skip(6);
  
  	s.read(buffer, 12);
  	_target = Common::String(buffer);
@@@ -464,19 -434,9 +441,16 @@@ Object::Object() 
  	_descOffset = 0;
  	_seqCounter2 = 0;
  	_seqSize = 0;
 +
 +	_quickDraw = 0;
 +	_scaleVal = 0;
 +	_requiredFlag1 = 0;
 +	_gotoSeq = 0;
 +	_talkSeq = 0;
 +	_restoreSlot = 0;
  }
  
- /**
-  * Load the data for the object
-  */
 -void Object::load(Common::SeekableReadStream &s) {
 +void Object::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
  	char buffer[41];
  	s.read(buffer, 12);
  	_name = Common::String(buffer);
@@@ -539,30 -493,14 +513,27 @@@
  	_descOffset = s.readUint16LE();
  	_seqCounter2 = s.readByte();
  	_seqSize = s.readUint16LE();
 -	s.skip(1);
 -	_aMove.load(s);
 -	s.skip(8);
  
 -	for (int idx = 0; idx < USE_COUNT; ++idx)
 -		_use[idx].load(s);
 +	if (isRoseTattoo) {
 +		for (int idx = 0; idx < 6; ++idx)
 +			_use[idx].load(s, true);
 +
 +		_quickDraw = s.readByte();
 +		_scaleVal = s.readUint16LE();
 +		_requiredFlag1 = s.readSint16LE();
 +		_gotoSeq = s.readByte();
 +		_talkSeq = s.readByte();
 +		_restoreSlot = s.readByte();
 +	} else {
 +		s.skip(1);
 +		_aMove.load(s);
 +		s.skip(8);
 +
 +		for (int idx = 0; idx < 4; ++idx)
 +			_use[idx].load(s, false);
 +	}
  }
  
- /**
-  * Toggle the type of an object between hidden and active
-  */
  void Object::toggleHidden() {
  	if (_type != HIDDEN && _type != HIDE_SHAPE && _type != INVALID) {
  		if (_seqTo != 0)
@@@ -1132,10 -1032,7 +1065,7 @@@ const Common::Rect Object::getOldBounds
  
  /*----------------------------------------------------------------*/
  
- /**
-  * Load the data for the animation
-  */
 -void CAnim::load(Common::SeekableReadStream &s) {
 +void CAnim::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
  	char buffer[12];
  	s.read(buffer, 12);
  	_name = Common::String(buffer);
diff --cc engines/sherlock/objects.h
index fd4a103,bbd068e..b61e7e2
--- a/engines/sherlock/objects.h
+++ b/engines/sherlock/objects.h
@@@ -154,17 -176,21 +176,22 @@@ struct ActionType 
  struct UseType {
  	int _cAnimNum;
  	int _cAnimSpeed;
- 	Common::String _names[4];
+ 	Common::String _names[NAMES_COUNT];
  	int _useFlag;					// Which flag USE will set (if any)
- 	int _dFlag[1];
- 	int _lFlag[2];
  	Common::String _target;
 +	Common::String _verb;
  
  	UseType();
+ 
+ 	/**
+ 	 * Load the data for the UseType
+ 	 */
 -	void load(Common::SeekableReadStream &s);
 +	void load(Common::SeekableReadStream &s, bool isRoseTattoo);
  };
  
+ enum { OBJ_BEHIND = 1, OBJ_FLIPPED = 2, OBJ_FORWARD = 4, TURNON_OBJ = 0x20, TURNOFF_OBJ = 0x40 };
+ #define USE_COUNT 4
+ 
  class Object {
  private:
  	static SherlockEngine *_vm;
@@@ -233,24 -258,69 +269,69 @@@ public
  
  	Object();
  
+ 	/**
+ 	 * Load the data for the object
+ 	 */
 -	void load(Common::SeekableReadStream &s);
 +	void load(Common::SeekableReadStream &s, bool isRoseTattoo);
  
+ 	/**
+ 	 * Toggle the type of an object between hidden and active
+ 	 */
  	void toggleHidden();
  
+ 	/**
+ 	 * Check the state of the object
+ 	 */
  	void checkObject();
  
+ 	/**
+ 	 * Checks for codes
+ 	 * @param name		The name to check for codes
+ 	 * @param messages	Provides a lookup list of messages that can be printed
+ 	 * @returns		0 if no codes are found, 1 if codes were found
+ 	 */
  	int checkNameForCodes(const Common::String &name, const char *const messages[]);
  
+ 	/**
+ 	 * Handle setting any flags associated with the object
+ 	 */
  	void setFlagsAndToggles();
  
+ 	/**
+ 	 * Adjusts the sprite's position and animation sequence, advancing by 1 frame.
+ 	 * If the end of the sequence is reached, the appropriate action is taken.
+ 	 */
  	void adjustObject();
  
+ 	/**
+ 	 * Handles trying to pick up an object. If allowed, plays an y necessary animation for picking
+ 	 * up the item, and then adds it to the player's inventory
+ 	 */
  	int pickUpObject(const char *const messages[]);
  
+ 	/**
+ 	 * Return the frame width
+ 	 */
  	int frameWidth() const { return _imageFrame ? _imageFrame->_frame.w : 0; }
+ 	
+ 	/**
+ 	 * Return the frame height
+ 	 */
  	int frameHeight() const { return _imageFrame ? _imageFrame->_frame.h : 0; }
+ 
+ 	/**
+ 	 * Returns the current bounds for the sprite
+ 	 */
  	const Common::Rect getNewBounds() const;
+ 
+ 	/**
+ 	 * Returns the bounds for a sprite without a shape
+ 	 */
  	const Common::Rect getNoShapeBounds() const;
+ 
+ 	/**
+ 	 * Returns the old bounsd for the sprite from the previous frame
+ 	 */
  	const Common::Rect getOldBounds() const;
  };
  
@@@ -264,14 -336,10 +345,17 @@@ struct CAnim 
  	Common::Point _teleportPos;		// Location Holmes shoul teleport to after
  	int _teleportDir;					// playing canim
  
 +	// Scalpel specific
 +	byte _sequences[MAX_FRAME];		// Animation sequences
 +	SpriteType _type;
 +
 +	// Rose Tattoo specific
 +	int _scaleVal;					// How much the canim is scaled
 +
+ 	/**
+ 	 * Load the data for the animation
+ 	 */
 -	void load(Common::SeekableReadStream &s);
 +	void load(Common::SeekableReadStream &s, bool isRoseTattoo);
  };
  
  struct SceneImage {
diff --cc engines/sherlock/resources.cpp
index 24fef3f,091ef3e..864622e
--- a/engines/sherlock/resources.cpp
+++ b/engines/sherlock/resources.cpp
@@@ -193,9 -157,17 +160,19 @@@ Common::SeekableReadStream *Resources::
  	return stream;
  }
  
- /**
-  * Loads a specific resource from a given library file
-  */
+ void Resources::decompressIfNecessary(Common::SeekableReadStream *&stream) {
+ 	bool isCompressed = stream->readUint32BE() == MKTAG('L', 'Z', 'V', 26);
 -	stream->seek(-4, SEEK_CUR);
+ 
+ 	if (isCompressed) {
 -		Common::SeekableReadStream *newStream = decompressLZ(*stream);
++		int outSize = stream->readUint32LE();
++		Common::SeekableReadStream *newStream = decompressLZ(*stream, outSize);
+ 		delete stream;
+ 		stream = newStream;
++	} else {
++		stream->seek(-4, SEEK_CUR);
+ 	}
+ }
+ 
  Common::SeekableReadStream *Resources::load(const Common::String &filename, const Common::String &libraryFile) {
  	// Open up the library for access
  	Common::SeekableReadStream *libStream = load(libraryFile);
@@@ -221,11 -191,8 +196,8 @@@ bool Resources::exists(const Common::St
  	return f.exists(filename) || _cache.isCached(filename);
  }
  
- /**
-  * Reads in the index from a library file, and caches it's index for later use
-  */
  void Resources::loadLibraryIndex(const Common::String &libFilename,
 -		Common::SeekableReadStream *stream) {
 +		Common::SeekableReadStream *stream, bool isNewStyle) {
  	uint32 offset, nextOffset;
  
  	// Create an index entry
@@@ -272,6 -231,59 +239,80 @@@ int Resources::resourceIndex() const 
  	return _resourceIndex;
  }
  
 -Common::SeekableReadStream *Resources::decompressLZ(Common::SeekableReadStream &source) {
 -	if (_vm->getGameID() == GType_SerratedScalpel) {
 -		uint32 id = source.readUint32BE();
 -		assert(id == MKTAG('L', 'Z', 'V', 0x1A));
 -	}
++Common::SeekableReadStream *Resources::decompress(Common::SeekableReadStream &source) {
++	// This variation can't be used by Rose Tattoo, since compressed resources include the input size,
++	// not the output size. Which means their decompression has to be done via passed buffers
++	assert(_vm->getGameID() == GType_SerratedScalpel);
++
++	uint32 id = source.readUint32BE();
++	assert(id == MKTAG('L', 'Z', 'V', 0x1A));
++
++	uint32 outputSize = source.readUint32LE();
++	return decompressLZ(source, outputSize);
++}
++
++Common::SeekableReadStream *Resources::decompress(Common::SeekableReadStream &source, uint32 outSize) {
++	int inSize = (_vm->getGameID() == GType_RoseTattoo) ? source.readUint32LE() : -1;
++	byte *outBuffer = (byte *)malloc(outSize);
++	Common::MemoryReadStream *outStream = new Common::MemoryReadStream(outBuffer, outSize, DisposeAfterUse::YES);
++
++	decompressLZ(source, outBuffer, outSize, inSize);
++
++	return outStream;
++}
+ 
 -	uint32 size = source.readUint32LE();
 -	return decompressLZ(source, size);
++void Resources::decompress(Common::SeekableReadStream &source, byte *buffer, uint32 outSize) {
++	int inputSize = (_vm->getGameID() == GType_RoseTattoo) ? source.readUint32LE() : -1;
++
++	decompressLZ(source, buffer, outSize, inputSize);
+ }
+ 
+ Common::SeekableReadStream *Resources::decompressLZ(Common::SeekableReadStream &source, uint32 outSize) {
++	byte *dataOut = (byte *)malloc(outSize);
++	decompressLZ(source, dataOut, outSize, -1);
++
++	return new Common::MemoryReadStream(dataOut, outSize, DisposeAfterUse::YES);
++}
++
++void Resources::decompressLZ(Common::SeekableReadStream &source, byte *outBuffer, int32 outSize, int32 inSize) {
+ 	byte lzWindow[4096];
+ 	uint16 lzWindowPos;
+ 	uint16 cmd;
+ 
 -	byte *outBuffer = (byte *)malloc(outSize);
+ 	byte *outBufferEnd = outBuffer + outSize;
 -	Common::MemoryReadStream *outS = new Common::MemoryReadStream(outBuffer, outSize, DisposeAfterUse::YES);
++	int endPos = source.pos() + inSize;
+ 
+ 	memset(lzWindow, 0xFF, 0xFEE);
+ 	lzWindowPos = 0xFEE;
+ 	cmd = 0;
+ 
+ 	do {
+ 		cmd >>= 1;
+ 		if (!(cmd & 0x100))
+ 			cmd = source.readByte() | 0xFF00;
+ 
+ 		if (cmd & 1) {
+ 			byte literal = source.readByte();
+ 			*outBuffer++ = literal;
+ 			lzWindow[lzWindowPos] = literal;
+ 			lzWindowPos = (lzWindowPos + 1) & 0x0FFF;
 -		}
 -		else {
++		} else {
+ 			int copyPos, copyLen;
+ 			copyPos = source.readByte();
+ 			copyLen = source.readByte();
+ 			copyPos = copyPos | ((copyLen & 0xF0) << 4);
+ 			copyLen = (copyLen & 0x0F) + 3;
+ 			while (copyLen--) {
+ 				byte literal = lzWindow[copyPos];
+ 				copyPos = (copyPos + 1) & 0x0FFF;
+ 				*outBuffer++ = literal;
+ 				lzWindow[lzWindowPos] = literal;
+ 				lzWindowPos = (lzWindowPos + 1) & 0x0FFF;
+ 			}
+ 		}
 -	} while (outBuffer < outBufferEnd);
 -
 -	return outS;
++	} while ((outSize == -1 || outBuffer < outBufferEnd) || (inSize == -1 || source.pos() < endPos));
+ }
+ 
  /*----------------------------------------------------------------*/
  
  SherlockEngine *ImageFile::_vm;
diff --cc engines/sherlock/resources.h
index a320852,fb91b30..659ecf0
--- a/engines/sherlock/resources.h
+++ b/engines/sherlock/resources.h
@@@ -72,29 -87,67 +87,82 @@@ private
  	LibraryIndexes _indexes;
  	int _resourceIndex;
  
- 	void loadLibraryIndex(const Common::String &libFilename, Common::SeekableReadStream *stream,
- 		bool isNewStyle);
+ 	/**
+ 	 * Reads in the index from a library file, and caches it's index for later use
+ 	 */
 -	void loadLibraryIndex(const Common::String &libFilename, Common::SeekableReadStream *stream);
++	void loadLibraryIndex(const Common::String &libFilename, Common::SeekableReadStream *stream, bool isNewStyle);
  public:
  	Resources(SherlockEngine *vm);
  
+ 	/**
+ 	 * Adds the specified file to the cache. If it's a library file, takes care of
+ 	 * loading it's index for future use
+ 	 */
  	void addToCache(const Common::String &filename);
+ 	
+ 	/**
+ 	 * Adds a resource from a library file to the cache
+ 	 */
  	void addToCache(const Common::String &filename, const Common::String &libFilename);
+ 	
+ 	/**
+ 	 * Adds a given stream to the cache under the given name
+ 	 */
  	void addToCache(const Common::String &filename, Common::SeekableReadStream &stream);
+ 
  	bool isInCache(const Common::String &filename) const { return _cache.isCached(filename); }
  
+ 	/**
+ 	 * Checks the passed stream, and if is compressed, deletes it and replaces it with it's uncompressed data
+ 	 */
+ 	void decompressIfNecessary(Common::SeekableReadStream *&stream);
+ 
+ 	/**
+ 	 * Returns a stream for a given file
+ 	 */
  	Common::SeekableReadStream *load(const Common::String &filename);
  
+ 	/**
+ 	 * Loads a specific resource from a given library file
+ 	 */
  	Common::SeekableReadStream *load(const Common::String &filename, const Common::String &libraryFile);
  
+ 	/**
+ 	 * Returns true if the given file exists on disk or in the cache
+ 	 */
  	bool exists(const Common::String &filename) const;
  
+ 	/**
+ 	 * Returns the index of the last loaded resource in it's given library file.
+ 	 * This will be used primarily when loading talk files, so the engine can
+ 	 * update the given conversation number in the journal
+ 	 */
  	int resourceIndex() const;
  
+ 	/**
 -	 * Decompresses an LZW block of data with a specified output size
++	 * Decompresses LZW compressed data
++	 */
 +	Common::SeekableReadStream *decompress(Common::SeekableReadStream &source);
++
++	/**
++	 * Decompresses LZW compressed data
++	 */
 +	Common::SeekableReadStream *decompress(Common::SeekableReadStream &source, uint32 outSize);
++
++	/**
++	 * Decompresses LZW compressed data
++	 */
 +	void decompress(Common::SeekableReadStream &source, byte *buffer, uint32 outSize);
- 	static void decompressLZ(Common::SeekableReadStream &source, byte *outBuffer, int32 outSize, int32 inSize);
++
++	/**
++	 * Decompresses LZW compressed data
+ 	 */
  	static Common::SeekableReadStream *decompressLZ(Common::SeekableReadStream &source, uint32 outSize);
 -	
++
+ 	/**
 -	 * Decompress an LZW compressed resource
++	 * Decompresses LZW compressed data
+ 	 */
 -	Common::SeekableReadStream *decompressLZ(Common::SeekableReadStream &source);
++	static void decompressLZ(Common::SeekableReadStream &source, byte *outBuffer, int32 outSize, int32 inSize);
  };
  
  struct ImageFrame {
diff --cc engines/sherlock/scalpel/scalpel.cpp
index eff5898,7875f22..ccc9c8a
--- a/engines/sherlock/scalpel/scalpel.cpp
+++ b/engines/sherlock/scalpel/scalpel.cpp
@@@ -239,13 -377,7 +378,10 @@@ ScalpelEngine::~ScalpelEngine() 
  	delete _darts;
  }
  
- /**
-  * Game initialization
-  */
  void ScalpelEngine::initialize() {
 +	initGraphics(320, 200, false);
 +
 +	// Let the base engine intialize
  	SherlockEngine::initialize();
  
  	_darts = new Darts(this);
@@@ -254,16 -386,12 +390,19 @@@
  	_flags[3] = true;		// Turn on Alley
  	_flags[39] = true;		// Turn on Baker Street
  
 +	// Add some more files to the cache
 +	_res->addToCache("portrait.lib");
 +	_res->addToCache("sequence.txt");
 +	_res->addToCache("EPILOGUE.SND");
 +	_res->addToCache("snd.snd");
 +	_res->addToCache("title.snd");
 +
- 	// Load the map co-ordinates for each scene and sequence data
- 	_map->loadPoints(NUM_PLACES, &MAP_X[0], &MAP_Y[0], &MAP_TRANSLATE[0]);
- 	_map->loadSequences(3, &MAP_SEQUENCES[0][0]);
+ 	if (!isDemo()) {
+ 		// Load the map co-ordinates for each scene and sequence data
+ 		_map->loadPoints(NUM_PLACES, &MAP_X[0], &MAP_Y[0], &MAP_TRANSLATE[0]);
+ 		_map->loadSequences(3, &MAP_SEQUENCES[0][0]);
+ 		_map->_oldCharPoint = BAKER_ST_EXTERIOR;
+ 	}
  
  	// Load the inventory
  	loadInventory();
@@@ -463,9 -579,9 +590,9 @@@ bool ScalpelEngine::scrollCredits() 
  			_screen->transBlitFrom(creditsImages[1], Common::Point(10, 400 - idx), false, 0);
  
  		// Don't show credit text on the top and bottom ten rows of the screen
- 		_screen->blitFrom(_screen->_backBuffer1, Common::Point(0, 0), Common::Rect(0, 0, _screen->w, 10));
- 		_screen->blitFrom(_screen->_backBuffer1, Common::Point(0, _screen->h - 10),
- 			Common::Rect(0, _screen->h - 10, _screen->w, _screen->h));
 -		_screen->blitFrom(_screen->_backBuffer1, Common::Point(0, 0), Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, 10));
 -		_screen->blitFrom(_screen->_backBuffer1, Common::Point(0, SHERLOCK_SCREEN_HEIGHT - 10),
 -			Common::Rect(0, SHERLOCK_SCREEN_HEIGHT - 10, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
++		_screen->blitFrom(_screen->_backBuffer1, Common::Point(0, 0), Common::Rect(0, 0, _screen->w(), 10));
++		_screen->blitFrom(_screen->_backBuffer1, Common::Point(0, _screen->h() - 10),
++			Common::Rect(0, _screen->h() - 10, _screen->w(), _screen->h()));
  
  		_events->delay(100);
  	}
diff --cc engines/sherlock/scene.cpp
index 96cfac0,5ae7e25..2c80bfb
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@@ -27,24 -26,14 +27,31 @@@
  
  namespace Sherlock {
  
+ static const int FS_TRANS[8] = {
+ 	STOP_UP, STOP_UPRIGHT, STOP_RIGHT, STOP_DOWNRIGHT, STOP_DOWN,
+ 	STOP_DOWNLEFT, STOP_LEFT, STOP_UPLEFT
+ };
+ 
+ /*----------------------------------------------------------------*/
+ 
 -void BgFileHeader::load(Common::SeekableReadStream &s) {
 +BgFileHeader::BgFileHeader() {
 +	_numStructs = -1;
 +	_numImages = -1;
 +	_numcAnimations = -1;
 +	_descSize = -1;
 +	_seqSize = -1;
 +
 +	// Serrated Scalpel
 +	_fill = -1;
 +
 +	// Rose Tattoo
 +	_scrollSize = -1;
 +	_bytesWritten = -1;
 +	_fadeStyle = -1;
 +	Common::fill(&_palette[0], &_palette[PALETTE_SIZE], 0);
 +}
 +
- void BgFileHeader::synchronize(Common::SeekableReadStream &s, bool isRoseTattoo) {
++void BgFileHeader::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
  	_numStructs = s.readUint16LE();
  	_numImages = s.readUint16LE();
  	_numcAnimations = s.readUint16LE();
@@@ -77,27 -55,15 +81,24 @@@ void BgFileHeaderInfo::load(Common::See
  
  /*----------------------------------------------------------------*/
  
- /**
-  * Load the data for the object
-  */
 -void Exit::load(Common::SeekableReadStream &s) {
 -	int xp = s.readSint16LE();
 -	int yp = s.readSint16LE();
 -	int xSize = s.readSint16LE();
 -	int ySize = s.readSint16LE();
 -	_bounds = Common::Rect(xp, yp, xp + xSize, yp + ySize);
 +void Exit::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
 +	if (isRoseTattoo) {
 +		char buffer[41];
 +		s.read(buffer, 41);
 +		_dest = Common::String(buffer);
 +	}
  
 +	left = s.readSint16LE();
 +	top = s.readSint16LE();
 +	setWidth(s.readUint16LE());
 +	setHeight(s.readUint16LE());
 +
 +	_image = isRoseTattoo ? s.readByte() : 0;
  	_scene = s.readSint16LE();
 -	_allow = s.readSint16LE();
 +
 +	if (!isRoseTattoo)
 +		_allow = s.readSint16LE();
 +
  	_people.x = s.readSint16LE();
  	_people.y = s.readSint16LE();
  	_peopleDir = s.readUint16LE();
@@@ -146,22 -100,7 +138,19 @@@ int ObjectArray::indexOf(const Object &
  
  /*----------------------------------------------------------------*/
  
- /**
-  * Load the data for the object
-  */
 -Scene::Scene(SherlockEngine *vm) : _vm(vm) {
 +void ScaleZone::load(Common::SeekableReadStream &s) {
 +	left = s.readSint16LE();
 +	top = s.readSint16LE();
 +	setWidth(s.readUint16LE());
 +	setHeight(s.readUint16LE());
 +
 +	_topNumber = s.readByte();
 +	_bottomNumber = s.readByte();
 +}
 +
 +/*----------------------------------------------------------------*/
 +
 +Scene::Scene(SherlockEngine *vm): _vm(vm) {
  	for (int idx = 0; idx < SCENES_COUNT; ++idx)
  		Common::fill(&_sceneStats[idx][0], &_sceneStats[idx][65], false);
  	_currentScene = -1;
@@@ -317,77 -227,63 +283,99 @@@ bool Scene::loadScene(const Common::Str
  
  		// Go to header and read it in
  		rrmStream->seek(rrmStream->readUint32LE());
 +
  		BgFileHeader bgHeader;
- 		bgHeader.synchronize(*rrmStream, IS_ROSE_TATTOO);
 -		bgHeader.load(*rrmStream);
++		bgHeader.load(*rrmStream, IS_ROSE_TATTOO);
  		_invGraphicItems = bgHeader._numImages + 1;
  
 +		if (IS_ROSE_TATTOO) {
 +			screen.initPaletteFade(bgHeader._bytesWritten);
 +			screen.fadeRead(*rrmStream, screen._cMap, PALETTE_SIZE);
 +			screen.setupBGArea(screen._cMap);
 +
 +			screen.initScrollVars();
 +
 +			// Read in background
 +			if (_lzwMode) {
 +				res.decompress(*rrmStream, (byte *)screen._backBuffer1.getPixels(), SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCREEN_HEIGHT);
 +			} else {
 +				rrmStream->read(screen._backBuffer1.getPixels(), SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCREEN_HEIGHT);
 +			}
 +		} 
 +
  		// Read in the shapes header info
+ 		Common::Array<BgFileHeaderInfo> bgInfo;
  		bgInfo.resize(bgHeader._numStructs);
  
  		for (uint idx = 0; idx < bgInfo.size(); ++idx)
  			bgInfo[idx].load(*rrmStream);
  
  		// Read information
 -		if (!_lzwMode) {
 +		if (IS_SERRATED_SCALPEL) {
 +			Common::SeekableReadStream *infoStream = !_lzwMode ? rrmStream :
 +				res.decompress(*rrmStream, bgHeader._numStructs * 569 + bgHeader._descSize + bgHeader._seqSize);
 +
  			_bgShapes.resize(bgHeader._numStructs);
  			for (int idx = 0; idx < bgHeader._numStructs; ++idx)
 -				_bgShapes[idx].load(*rrmStream);
 +				_bgShapes[idx].load(*infoStream, false);
 +
 +			if (bgHeader._descSize) {
 +				_descText.resize(bgHeader._descSize);
 +				infoStream->read(&_descText[0], bgHeader._descSize);
 +			}
 +
 +			if (bgHeader._seqSize) {
 +				_sequenceBuffer.resize(bgHeader._seqSize);
 +				infoStream->read(&_sequenceBuffer[0], bgHeader._seqSize);
 +			}
 +
 +			if (_lzwMode)
 +				delete infoStream;
++		} else if (!_lzwMode) {
++			_bgShapes.resize(bgHeader._numStructs);
++			for (int idx = 0; idx < bgHeader._numStructs; ++idx)
++				_bgShapes[idx].load(*rrmStream, false);
+ 
+ 			if (bgHeader._descSize) {
+ 				_descText.resize(bgHeader._descSize);
+ 				rrmStream->read(&_descText[0], bgHeader._descSize);
+ 			}
+ 
+ 			if (bgHeader._seqSize) {
+ 				_sequenceBuffer.resize(bgHeader._seqSize);
+ 				rrmStream->read(&_sequenceBuffer[0], bgHeader._seqSize);
+ 			}
  		} else {
- 			// Load shapes
- 			Common::SeekableReadStream *infoStream = !_lzwMode ? rrmStream : res.decompress(*rrmStream, bgHeader._numStructs * 625);
+ 			Common::SeekableReadStream *infoStream;
+ 
+ 			// Read shapes
+ 			infoStream = Resources::decompressLZ(*rrmStream, bgHeader._numStructs * 569);
  
  			_bgShapes.resize(bgHeader._numStructs);
  			for (int idx = 0; idx < bgHeader._numStructs; ++idx)
- 				_bgShapes[idx].load(*infoStream, true);
 -				_bgShapes[idx].load(*infoStream);
++				_bgShapes[idx].load(*infoStream, false);
+ 
+ 			delete infoStream;
+ 
+ 			// Read description texts
+ 			if (bgHeader._descSize) {
+ 				infoStream = Resources::decompressLZ(*rrmStream, bgHeader._descSize);
+ 
+ 				_descText.resize(bgHeader._descSize);
+ 				infoStream->read(&_descText[0], bgHeader._descSize);
  
- 			if (_lzwMode)
  				delete infoStream;
+ 			}
  
- 			// Load description text
- 			_descText.resize(bgHeader._descSize);
- 			if (_lzwMode)
- 				res.decompress(*rrmStream, (byte *)&_descText[0], bgHeader._descSize);
- 			else
- 				rrmStream->read(&_descText[0], bgHeader._descSize);
+ 			// Read sequences
+ 			if (bgHeader._seqSize) {
+ 				infoStream = Resources::decompressLZ(*rrmStream, bgHeader._seqSize);
  
- 			// Load sequences
- 			_sequenceBuffer.resize(bgHeader._seqSize);
- 			if (_lzwMode)
- 				res.decompress(*rrmStream, &_sequenceBuffer[0], bgHeader._seqSize);
- 			else
- 				rrmStream->read(&_sequenceBuffer[0], bgHeader._seqSize);
+ 				_sequenceBuffer.resize(bgHeader._seqSize);
+ 				infoStream->read(&_sequenceBuffer[0], bgHeader._seqSize);
+ 
+ 				delete infoStream;
+ 			}
  		}
  
  		// Set up the list of images used by the scene
@@@ -601,20 -472,6 +588,13 @@@
  	return flag;
  }
  
- /**
-  * Load all the sound effects specified for the current scene
-  */
 +void Scene::loadSceneSounds() {
 +	Sound &sound = *_vm->_sound;
 +
 +	for (uint idx = 0; idx < _sounds.size(); ++idx)
 +		sound.loadSound(_sounds[idx]._name, _sounds[idx]._priority);
 +}
 +
- /**
-  * Set objects to their current persistent state. This includes things such as
-  * opening or moving them
-  */
  void Scene::checkSceneStatus() {
  	if (_sceneStats[_currentScene][64]) {
  		for (uint idx = 0; idx < 64; ++idx) {
@@@ -964,12 -791,9 +914,9 @@@ void Scene::updateBackground() 
  	screen.resetDisplayBounds();
  }
  
- /**
-  * Check whether the passed area intersects with one of the scene's exits
-  */
  Exit *Scene::checkForExit(const Common::Rect &r) {
  	for (uint idx = 0; idx < _exits.size(); ++idx) {
 -		if (_exits[idx]._bounds.intersects(r))
 +		if (_exits[idx].intersects(r))
  			return &_exits[idx];
  	}
  
diff --cc engines/sherlock/scene.h
index 9454a4e,88d12a3..0cbd775
--- a/engines/sherlock/scene.h
+++ b/engines/sherlock/scene.h
@@@ -45,22 -44,15 +45,26 @@@ struct BgFileHeader 
  	int _numcAnimations;
  	int _descSize;
  	int _seqSize;
 +
 +	// Serrated Scalpel
  	int _fill;
  
 +	// Rose Tattoo
 +	int _scrollSize;
 +	int _bytesWritten;				// Size of the main body of the RRM
 +	int _fadeStyle;					// Fade style
 +	byte _palette[PALETTE_SIZE];	// Palette
 +
 +
 +	BgFileHeader();
- 	void synchronize(Common::SeekableReadStream &s, bool isRoseTattoo);
++
+ 	/**
+ 	 * Load the data for the object
+ 	 */
 -	void load(Common::SeekableReadStream &s);
++	void load(Common::SeekableReadStream &s, bool isRoseTattoo);
  };
  
- struct BgfileheaderInfo {
+ struct BgFileHeaderInfo {
  	int _filesize;				// How long images are
  	int _maxFrames;				// How many unique frames in object
  	Common::String _filename;	// Filename of object
@@@ -75,10 -71,10 +82,13 @@@ public
  	Common::Point _people;
  	int _peopleDir;
  
 +	Common::String _dest;
 +	int _image;					// Arrow image to use
 +
+ 	/**
+ 	 * Load the data for the object
+ 	 */
 -	void load(Common::SeekableReadStream &s);
 +	void load(Common::SeekableReadStream &s, bool isRoseTattoo);
  };
  
  struct SceneEntry {
@@@ -113,24 -110,50 +132,56 @@@ class Scene 
  private:
  	SherlockEngine *_vm;
  	Common::String _rrmName;
- 	int _selector;
- 	bool _lookHelp;
  	bool _loadingSavedGame;
  
+ 	/**
+ 	 * Loads the data associated for a given scene. The .BGD file's format is:
+ 	 * BGHEADER: Holds an index for the rest of the file
+ 	 * STRUCTS:  The objects for the scene
+ 	 * IMAGES:   The graphic information for the structures
+ 	 *
+ 	 * The _misc field of the structures contains the number of the graphic image
+ 	 * that it should point to after loading; _misc is then set to 0.
+ 	 */
  	bool loadScene(const Common::String &filename);
  
+ 	/**
++	 * Loads sounds for the scene
++	 */
 +	void loadSceneSounds();
 +
++	/**
+ 	 * Set objects to their current persistent state. This includes things such as
+ 	 * opening or moving them
+ 	 */
  	void checkSceneStatus();
  
+ 	/**
+ 	 * Checks scene objects against the player's inventory items. If there are any
+ 	 * matching names, it means the given item has already been picked up, and should
+ 	 * be hidden in the scene.
+ 	 */
  	void checkInventory();
  
+ 	/**
+ 	 * Set up any entrance co-ordinates or entrance canimations, and then transition
+ 	 * in the scene
+ 	 */
  	void transitionToScene();
  
+ 	/**
+ 	 * Checks all the background shapes. If a background shape is animating,
+ 	 * it will flag it as needing to be drawn. If a non-animating shape is
+ 	 * colliding with another shape, it will also flag it as needing drawing
+ 	 */
  	void checkBgShapes(ImageFrame *frame, const Common::Point &pt);
  
+ 	/**
+ 	 * Restores objects to the correct status. This ensures that things like being opened or moved
+ 	 * will remain the same on future visits to the scene
+ 	 */
  	void saveSceneStatus();
 +
  public:
  	int _currentScene;
  	int _goToScene;
diff --cc engines/sherlock/screen.cpp
index 349bf4d,e70d061..24f7660
--- a/engines/sherlock/screen.cpp
+++ b/engines/sherlock/screen.cpp
@@@ -38,19 -38,7 +38,15 @@@ Screen::Screen(SherlockEngine *vm) : Su
  	_fontHeight = 0;
  	Common::fill(&_cMap[0], &_cMap[PALETTE_SIZE], 0);
  	Common::fill(&_sMap[0], &_sMap[PALETTE_SIZE], 0);
 +	Common::fill(&_tMap[0], &_tMap[PALETTE_SIZE], 0);
  	setFont(1);
 +
- 	// Set dummy surface used for restricted scene drawing
- 	_sceneSurface.format = Graphics::PixelFormat::createFormatCLUT8();
- 	_sceneSurface.pitch = pitch;
- 
 +	// Rose Tattoo specific fields
 +	_fadeBytesRead = _fadeBytesToRead = 0;
 +	_oldFadePercent = 0;
 +	_scrollSize = 0;
 +	_currentScroll = 0;
 +	_targetScroll = 0;
  }
  
  Screen::~Screen() {
@@@ -220,9 -177,9 +185,9 @@@ void Screen::randomTransition() 
  
  	for (int idx = 0; idx <= 65535 && !_vm->shouldQuit(); ++idx) {
  		_transitionSeed = _transitionSeed * TRANSITION_MULTIPLIER + 1;
- 		int offset = _transitionSeed & 65535;
+ 		int offset = _transitionSeed & 0xFFFF;
  
- 		if (offset < (this->w * this->h))
 -		if (offset < (SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCREEN_HEIGHT))
++		if (offset < (this->w() * this->h()))
  			*((byte *)getPixels() + offset) = *((const byte *)_backBuffer->getPixels() + offset);
  
  		if (idx != 0 && (idx % 300) == 0) {
@@@ -242,15 -199,12 +207,12 @@@
  void Screen::verticalTransition() {
  	Events &events = *_vm->_events;
  
 -	byte table[SHERLOCK_SCREEN_WIDTH];
 -	Common::fill(&table[0], &table[SHERLOCK_SCREEN_WIDTH], 0);
 +	byte table[640];
 +	Common::fill(&table[0], &table[640], 0);
  
- 	for (int yp = 0; yp < this->h; ++yp) {
- 		for (int xp = 0; xp < this->w; ++xp) {
- 			int temp = (table[xp] >= (this->h - 3)) ? this->h - table[xp] :
 -	for (int yp = 0; yp < SHERLOCK_SCREEN_HEIGHT; ++yp) {
 -		for (int xp = 0; xp < SHERLOCK_SCREEN_WIDTH; ++xp) {
 -			int temp = (table[xp] >= 197) ? SHERLOCK_SCREEN_HEIGHT - table[xp] :
++	for (int yp = 0; yp < this->h(); ++yp) {
++		for (int xp = 0; xp < this->w(); ++xp) {
++			int temp = (table[xp] >= (this->h() - 3)) ? this->h() - table[xp] :
  				_vm->getRandomNumber(3) + 1;
  
  			if (temp) {
@@@ -267,10 -221,7 +229,7 @@@
  void Screen::restoreBackground(const Common::Rect &r) {
  	if (r.width() > 0 && r.height() > 0) {
  		Common::Rect tempRect = r;
- 		tempRect.clip(Common::Rect(0, 0, this->w, SHERLOCK_SCENE_HEIGHT));
 -		tempRect.clip(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCENE_HEIGHT));
++		tempRect.clip(Common::Rect(0, 0, this->w(), SHERLOCK_SCENE_HEIGHT));
  
  		if (tempRect.isValidRect())
  			_backBuffer1.blitFrom(_backBuffer2, Common::Point(tempRect.left, tempRect.top), tempRect);
@@@ -287,10 -235,7 +243,7 @@@ void Screen::slamArea(int16 xp, int16 y
  void Screen::slamRect(const Common::Rect &r) {
  	if (r.width() && r.height() > 0) {
  		Common::Rect tempRect = r;
- 		tempRect.clip(Common::Rect(0, 0, this->w, this->h));
 -		tempRect.clip(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
++		tempRect.clip(Common::Rect(0, 0, this->w(), this->h()));
  
  		if (tempRect.isValidRect())
  			blitFrom(*_backBuffer, Common::Point(tempRect.left, tempRect.top), tempRect);
@@@ -347,13 -281,13 +289,13 @@@ void Screen::print(const Common::Point 
  	pos.y--;		// Font is always drawing one line higher
  	if (!pos.x)
  		// Center text horizontally
- 		pos.x = (this->w - width) / 2;
 -		pos.x = (SHERLOCK_SCREEN_WIDTH - width) / 2;
++		pos.x = (this->w() - width) / 2;
  
  	Common::Rect textBounds(pos.x, pos.y, pos.x + width, pos.y + _fontHeight);
- 	if (textBounds.right > this->w)
- 		textBounds.moveTo(this->w - width, textBounds.top);
- 	if (textBounds.bottom > this->h)
- 		textBounds.moveTo(textBounds.left, this->h - _fontHeight);
 -	if (textBounds.right > SHERLOCK_SCREEN_WIDTH)
 -		textBounds.moveTo(SHERLOCK_SCREEN_WIDTH - width, textBounds.top);
 -	if (textBounds.bottom > SHERLOCK_SCREEN_HEIGHT)
 -		textBounds.moveTo(textBounds.left, SHERLOCK_SCREEN_HEIGHT - _fontHeight);
++	if (textBounds.right > this->w())
++		textBounds.moveTo(this->w() - width, textBounds.top);
++	if (textBounds.bottom > this->h())
++		textBounds.moveTo(textBounds.left, this->h() - _fontHeight);
  
  	// Write out the string at the given position
  	writeString(str, Common::Point(textBounds.left, textBounds.top), color);
@@@ -509,17 -414,11 +422,11 @@@ void Screen::resetDisplayBounds() 
  	_backBuffer = &_backBuffer1;
  }
  
- /**
-  * Return the size of the current display window
-  */
  Common::Rect Screen::getDisplayBounds() {
- 	return (_backBuffer == &_sceneSurface) ? Common::Rect(0, 0, _sceneSurface.w, _sceneSurface.h) :
- 		Common::Rect(0, 0, this->w, this->h);
+ 	return (_backBuffer == &_sceneSurface) ? Common::Rect(0, 0, _sceneSurface.w(), _sceneSurface.h()) :
 -		Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
++		Common::Rect(0, 0, this->w(), this->h());
  }
  
- /**
-  * Synchronize the data for a savegame
-  */
  void Screen::synchronize(Common::Serializer &s) {
  	int fontNumb = _fontNumber;
  	s.syncAsByte(fontNumb);
diff --cc engines/sherlock/screen.h
index 8a8eca1,a2c0aa3..f4cd6fd
--- a/engines/sherlock/screen.h
+++ b/engines/sherlock/screen.h
@@@ -66,21 -66,25 +66,34 @@@ private
  	int _fontHeight;
  	Surface _sceneSurface;
  
 +	// Rose Tattoo fields
 +	int _fadeBytesRead, _fadeBytesToRead;
 +	int _oldFadePercent;
 +	byte _lookupTable[PALETTE_COUNT];
 +	byte _lookupTable1[PALETTE_COUNT];
 +	int _scrollSize;
 +	int _currentScroll;
 +	int _targetScroll;
 +private:
+ 	/**
+ 	 * Merges together overlapping dirty areas of the screen
+ 	 */
  	void mergeDirtyRects();
  
+ 	/**
+ 	 * Returns the union of two dirty area rectangles
+ 	 */
  	bool unionRectangle(Common::Rect &destRect, const Common::Rect &src1, const Common::Rect &src2);
  
+ 	/**
+ 	 * Draws the given string into the back buffer using the images stored in _font
+ 	 */
  	void writeString(const Common::String &str, const Common::Point &pt, byte color);
  protected:
+ 	/**
+ 	 * Adds a rectangle to the list of modified areas of the screen during the
+ 	 * current frame
+ 	 */
  	virtual void addDirtyRect(const Common::Rect &r);
  public:
  	Surface _backBuffer1, _backBuffer2;
@@@ -140,16 -228,10 +238,19 @@@ public
  
  	int fontNumber() const { return _fontNumber; }
  
+ 	/**
+ 	 * Synchronize the data for a savegame
+ 	 */
  	void synchronize(Common::Serializer &s);
 +
 +	// Rose Tattoo specific methods
 +	void initPaletteFade(int bytesToRead);
 +
 +	int fadeRead(Common::SeekableReadStream &stream, byte *buf, int totalSize);
 +
 +	void setupBGArea(const byte cMap[PALETTE_SIZE]);
 +
 +	void initScrollVars();
  };
  
  } // End of namespace Sherlock
diff --cc engines/sherlock/sherlock.cpp
index 80a4383,d4644d4..5973823
--- a/engines/sherlock/sherlock.cpp
+++ b/engines/sherlock/sherlock.cpp
@@@ -67,10 -69,9 +68,7 @@@ SherlockEngine::~SherlockEngine() 
  	delete _res;
  }
  
- /**
-  * Does basic initialization of the game engine
-  */
  void SherlockEngine::initialize() {
 -	initGraphics(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT, false);
 -
  	DebugMan.addDebugChannel(kDebugScript, "scripts", "Script debug level");
  
  	ImageFile::setVm(this);
diff --cc engines/sherlock/sherlock.h
index 2688b51,24a7207..bf8c0d6
--- a/engines/sherlock/sherlock.h
+++ b/engines/sherlock/sherlock.h
@@@ -62,8 -58,8 +58,8 @@@ enum GameType 
  	GType_RoseTattoo = 1
  };
  
- #define SHERLOCK_SCREEN_WIDTH _vm->_screen->w
- #define SHERLOCK_SCREEN_HEIGHT _vm->_screen->h
 -#define SHERLOCK_SCREEN_WIDTH 320
 -#define SHERLOCK_SCREEN_HEIGHT 200
++#define SHERLOCK_SCREEN_WIDTH _vm->_screen->w()
++#define SHERLOCK_SCREEN_HEIGHT _vm->_screen->h()
  #define SHERLOCK_SCENE_HEIGHT 138
  
  struct SherlockGameDescription;
diff --cc engines/sherlock/sound.cpp
index 3a30864,4f27481..06f6a0f
--- a/engines/sherlock/sound.cpp
+++ b/engines/sherlock/sound.cpp
@@@ -44,12 -63,19 +63,20 @@@ Sound::Sound(SherlockEngine *vm, Audio:
  	_musicOn = true;
  	_speechOn = true;
  
 +	_vm->_res->addToCache("MUSIC.LIB");
+ 	if (!_vm->_interactiveFl)
+ 		_vm->_res->addToCache("TITLE.SND");
+ 	else {
+ 		_vm->_res->addToCache("MUSIC.LIB");
+ 		_vm->_res->addToCache("SND.SND");
+ 
+ 		if (!_vm->isDemo()) {
+ 			_vm->_res->addToCache("TITLE.SND");
+ 			_vm->_res->addToCache("EPILOGUE.SND");
+ 		}
+ 	}
  }
  
- /**
-  * Saves sound-related settings
-  */
  void Sound::syncSoundSettings() {
  	_digitized = !ConfMan.getBool("mute");
  	_music = !ConfMan.getBool("mute") && !ConfMan.getBool("music_mute");
diff --cc engines/sherlock/talk.cpp
index c67b98b,319d1a3..1a926a5
--- a/engines/sherlock/talk.cpp
+++ b/engines/sherlock/talk.cpp
@@@ -193,11 -172,9 +172,11 @@@ void Talk::talkTo(const Common::String 
  	while (!_sequenceStack.empty())
  		pullSequence();
  
 -	// Restore any pressed button
 -	if (!ui._windowOpen && savedMode != STD_MODE)
 -		ui.restoreButton((int)(savedMode - 1));
 +	if (IS_SERRATED_SCALPEL) {
 +		// Restore any pressed button
 +		if (!ui._windowOpen && savedMode != STD_MODE)
- 			((ScalpelUserInterface *)_vm->_ui)->restoreButton(savedMode - 1);
++			((ScalpelUserInterface *)_vm->_ui)->restoreButton((int)(savedMode - 1));
 +	}
  
  	// Clear the ui counter so that anything displayed on the info line
  	// before the window was opened isn't cleared
diff --cc engines/sherlock/talk.h
index 5c87d79,d26259d..48290e9
--- a/engines/sherlock/talk.h
+++ b/engines/sherlock/talk.h
@@@ -120,14 -123,11 +123,11 @@@ struct TalkSequences 
  };
  
  class SherlockEngine;
 -class UserInterface;
 +class ScalpelUserInterface;
  
  class Talk {
 -	friend class UserInterface;
 +	friend class ScalpelUserInterface;
  private:
- 	Common::Array<TalkSequences> STILL_SEQUENCES;
- 	Common::Array<TalkSequences> TALK_SEQUENCES;
- private:
  	SherlockEngine *_vm;
  	Common::Stack<SequenceEntry> _savedSequences;
  	Common::Stack<SequenceEntry> _sequenceStack;
diff --cc engines/sherlock/user_interface.cpp
index efe6c8e,524ecf3..7a6722a
--- a/engines/sherlock/user_interface.cpp
+++ b/engines/sherlock/user_interface.cpp
@@@ -78,70 -78,57 +78,66 @@@ const char *const MUSE[] = 
  	"Doors don't smoke"
  };
  
 -/*----------------------------------------------------------------*/
 +
 +
 +UserInterface *UserInterface::init(SherlockEngine *vm) {
 +	if (vm->getGameID() == GType_SerratedScalpel)
 +		return new ScalpelUserInterface(vm);
 +	else
 +		return new TattooUserInterface(vm);
 +}
  
  UserInterface::UserInterface(SherlockEngine *vm) : _vm(vm) {
 -	if (_vm->_interactiveFl) {
 -		_controls = new ImageFile("menu.all");
 -		_controlPanel = new ImageFile("controls.vgs");
 -	} else {
 -		_controls = nullptr;
 -		_controlPanel = nullptr;
 -	}
 +	_menuMode = STD_MODE;
 +	_menuCounter = 0;
 +	_infoFlag = false;
 +	_windowOpen = false;
 +	_endKeyActive = true;
 +	_invLookFlag = 0;
- 	_windowStyle = 1;	// Sliding windows
++	_slideWindows = true;
 +	_helpStyle = false;
++	_windowBounds = Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH - 1, SHERLOCK_SCREEN_HEIGHT - 1);
 +	_lookScriptFlag = false;
 +
- 	_key = _oldKey = 0;
++	_key = _oldKey = '\0';
 +	_selector = _oldSelector = -1;
 +	_temp = _oldTemp = 0;
 +	_temp1 = 0;
 +	_lookHelp = 0;
 +}
 +
 +/*----------------------------------------------------------------*/
  
 +ScalpelUserInterface::ScalpelUserInterface(SherlockEngine *vm): UserInterface(vm) {
 +	_controls = new ImageFile("menu.all");
 +	_controlPanel = new ImageFile("controls.vgs");
++	_keyPress = '\0';
++	_lookHelp = 0;
  	_bgFound = 0;
  	_oldBgFound = -1;
- 	_keycode = Common::KEYCODE_INVALID;
 -	_keyPress = '\0';
 -	_helpStyle = false;
 -	_menuCounter = 0;
 -	_menuMode = STD_MODE;
  	_help = _oldHelp = 0;
- 	_oldLook = false;
 -	_lookHelp = 0;
+ 	_key = _oldKey = '\0';
+ 	_temp = _oldTemp = 0;
 -	_temp1 = 0;
 -	_invLookFlag = 0;
 -	_windowOpen = false;
 -	_oldLook = false;
++	_oldLook = 0;
  	_keyboardInput = false;
  	_pause = false;
  	_cNum = 0;
- 	_windowBounds = Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH - 1,
- 		SHERLOCK_SCREEN_HEIGHT - 1);
 -	_selector = _oldSelector = -1;
 -	_windowBounds = Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH - 1,
 -		SHERLOCK_SCREEN_HEIGHT - 1);
 -	_slideWindows = true;
  	_find = 0;
  	_oldUse = 0;
 -	_endKeyActive = true;
 -	_lookScriptFlag = false;
 -	_infoFlag = false;
  }
  
 -UserInterface::~UserInterface() {
 +ScalpelUserInterface::~ScalpelUserInterface() {
  	delete _controls;
  	delete _controlPanel;
  }
  
- /**
-  * Resets the user interface
-  */
 -void UserInterface::reset() {
 +void ScalpelUserInterface::reset() {
  	_oldKey = -1;
  	_help = _oldHelp = -1;
  	_oldTemp = _temp = -1;
  }
  
- /**
-  * Draw the user interface onto the screen's back buffers
-  */
 -void UserInterface::drawInterface(int bufferNum) {
 +void ScalpelUserInterface::drawInterface(int bufferNum) {
  	Screen &screen = *_vm->_screen;
  
  	if (bufferNum & 1)
@@@ -152,10 -139,7 +148,7 @@@
  		screen._backBuffer2.fillRect(0, INFO_LINE, SHERLOCK_SCREEN_WIDTH, INFO_LINE + 10, INFO_BLACK);
  }
  
- /**
-  * Main input handler for the user interface
-  */
 -void UserInterface::handleInput() {
 +void ScalpelUserInterface::handleInput() {
  	Events &events = *_vm->_events;
  	Inventory &inv = *_vm->_inventory;
  	People &people = *_vm->_people;
@@@ -410,23 -392,16 +401,16 @@@
  	}
  }
  
- /**
-  * Draws the image for a user interface button in the down/pressed state.
-  */
 -void UserInterface::depressButton(int num) {
 +void ScalpelUserInterface::depressButton(int num) {
  	Screen &screen = *_vm->_screen;
  	Common::Point pt(MENU_POINTS[num][0], MENU_POINTS[num][1]);
  
- 	Graphics::Surface &s = (*_controls)[num]._frame;
- 	screen._backBuffer1.transBlitFrom(s, pt);
- 	screen.slamArea(pt.x, pt.y, pt.x + s.w, pt.y + s.h);
+ 	ImageFrame &frame = (*_controls)[num];
+ 	screen._backBuffer1.transBlitFrom(frame, pt);
+ 	screen.slamArea(pt.x, pt.y, pt.x + frame._width, pt.y + frame._height);
  }
  
- /**
-  * Draws the image for the given user interface button in the up
-  * (not selected) position
-  */
 -void UserInterface::restoreButton(int num) {
 +void ScalpelUserInterface::restoreButton(int num) {
  	Screen &screen = *_vm->_screen;
  	Common::Point pt(MENU_POINTS[num][0], MENU_POINTS[num][1]);
  	Graphics::Surface &frame = (*_controls)[num]._frame;
@@@ -441,11 -416,7 +425,7 @@@
  	}
  }
  
- /**
-  * If he mouse button is pressed, then calls depressButton to draw the button
-  * as pressed; if not, it will show it as released with a call to "restoreButton".
-  */
 -void UserInterface::pushButton(int num) {
 +void ScalpelUserInterface::pushButton(int num) {
  	Events &events = *_vm->_events;
  	_oldKey = -1;
  
@@@ -462,15 -433,10 +442,10 @@@
  	restoreButton(num);
  }
  
- /**
-  * By the time this method has been called, the graphics for the button change
-  * have already been drawn. This simply takes care of switching the mode around
-  * accordingly
-  */
 -void UserInterface::toggleButton(int num) {
 +void ScalpelUserInterface::toggleButton(int num) {
  	Screen &screen = *_vm->_screen;
  
- 	if (_menuMode != (num + 1)) {
+ 	if (_menuMode != (MenuMode)(num + 1)) {
  		_menuMode = (MenuMode)(num + 1);
  		_oldKey = COMMANDS[num];
  		_oldTemp = num;
@@@ -495,10 -461,7 +470,7 @@@
  	}
  }
  
- /**
-  * Clears the info line of the screen
-  */
 -void UserInterface::clearInfo() {
 +void ScalpelUserInterface::clearInfo() {
  	if (_infoFlag) {
  		_vm->_screen->vgaBar(Common::Rect(16, INFO_LINE, SHERLOCK_SCREEN_WIDTH - 19,
  			INFO_LINE + 10), INFO_BLACK);
@@@ -507,20 -470,14 +479,14 @@@
  	}
  }
  
- /**
-  * Clear any active text window
-  */
 -void UserInterface::clearWindow() {
 +void ScalpelUserInterface::clearWindow() {
  	if (_windowOpen) {
  		_vm->_screen->vgaBar(Common::Rect(3, CONTROLS_Y + 11, SHERLOCK_SCREEN_WIDTH - 2,
  			SHERLOCK_SCREEN_HEIGHT - 2), INV_BACKGROUND);
  	}
  }
  
- /**
-  * Handles counting down whilst checking for input, then clears the info line.
-  */
 -void UserInterface::whileMenuCounter() {
 +void ScalpelUserInterface::whileMenuCounter() {
  	if (!(--_menuCounter) || _vm->_events->checkInput()) {
  		_menuCounter = 0;
  		_infoFlag = true;
@@@ -528,11 -485,7 +494,7 @@@
  	}
  }
  
- /**
-  * Creates a text window and uses it to display the in-depth description
-  * of the highlighted object
-  */
 -void UserInterface::examine() {
 +void ScalpelUserInterface::examine() {
  	Events &events = *_vm->_events;
  	Inventory &inv = *_vm->_inventory;
  	People &people = *_vm->_people;
@@@ -583,10 -536,7 +545,7 @@@
  	}
  }
  
- /**
-  * Print the name of an object in the scene
-  */
 -void UserInterface::lookScreen(const Common::Point &pt) {
 +void ScalpelUserInterface::lookScreen(const Common::Point &pt) {
  	Events &events = *_vm->_events;
  	Inventory &inv = *_vm->_inventory;
  	Scene &scene = *_vm->_scene;
@@@ -699,10 -649,7 +658,7 @@@
  	}
  }
  
- /**
-  * Gets the item in the inventory the mouse is on and display's it's description
-  */
 -void UserInterface::lookInv() {
 +void ScalpelUserInterface::lookInv() {
  	Events &events = *_vm->_events;
  	Inventory &inv = *_vm->_inventory;
  	Screen &screen = *_vm->_screen;
@@@ -727,10 -674,7 +683,7 @@@
  	}
  }
  
- /**
-  * Handles input when the file list window is being displayed
-  */
 -void UserInterface::doEnvControl() {
 +void ScalpelUserInterface::doEnvControl() {
  	Events &events = *_vm->_events;
  	SaveManager &saves = *_vm->_saves;
  	Scene &scene = *_vm->_scene;
@@@ -1033,10 -976,7 +985,7 @@@
  	}
  }
  
- /**
-  * Handle input whilst the inventory is active
-  */
 -void UserInterface::doInvControl() {
 +void ScalpelUserInterface::doInvControl() {
  	Events &events = *_vm->_events;
  	Inventory &inv = *_vm->_inventory;
  	Scene &scene = *_vm->_scene;
@@@ -1261,10 -1199,7 +1208,7 @@@
  	}
  }
  
- /**
-  * Handles waiting whilst an object's description window is open.
-  */
 -void UserInterface::doLookControl() {
 +void ScalpelUserInterface::doLookControl() {
  	Events &events = *_vm->_events;
  	Inventory &inv = *_vm->_inventory;
  	Screen &screen = *_vm->_screen;
@@@ -1325,10 -1260,7 +1269,7 @@@
  	}
  }
  
- /**
-  * Handles input until one of the user interface buttons/commands is selected
-  */
 -void UserInterface::doMainControl() {
 +void ScalpelUserInterface::doMainControl() {
  	Events &events = *_vm->_events;
  	Inventory &inv = *_vm->_inventory;
  	SaveManager &saves = *_vm->_saves;
@@@ -1466,10 -1398,7 +1407,7 @@@
  	}
  }
  
- /**
-  * Handles the input for the MOVE, OPEN, and CLOSE commands
-  */
 -void UserInterface::doMiscControl(int allowed) {
 +void ScalpelUserInterface::doMiscControl(int allowed) {
  	Events &events = *_vm->_events;
  	Scene &scene = *_vm->_scene;
  	Talk &talk = *_vm->_talk;
@@@ -1518,10 -1447,7 +1456,7 @@@
  	}
  }
  
- /**
-  * Handles input for picking up items
-  */
 -void UserInterface::doPickControl() {
 +void ScalpelUserInterface::doPickControl() {
  	Events &events = *_vm->_events;
  	Scene &scene = *_vm->_scene;
  	Talk &talk = *_vm->_talk;
@@@ -1544,11 -1470,7 +1479,7 @@@
  	}
  }
  
- /**
-  * Handles input when in talk mode. It highlights the buttons and available statements,
-  * and handles allowing the user to click on them
-  */
 -void UserInterface::doTalkControl() {
 +void ScalpelUserInterface::doTalkControl() {
  	Events &events = *_vm->_events;
  	Journal &journal = *_vm->_journal;
  	People &people = *_vm->_people;
@@@ -1798,13 -1720,7 +1729,7 @@@
  	}
  }
  
- /**
-  * Handles events when the Journal is active.
-  * @remarks		Whilst this would in theory be better in the Journal class, since it displays in
-  *		the user interface, it uses so many internal UI fields, that it sort of made some sense
-  *		to put it in the UserInterface class.
-  */
 -void UserInterface::journalControl() {
 +void ScalpelUserInterface::journalControl() {
  	Events &events = *_vm->_events;
  	Journal &journal = *_vm->_journal;
  	Scene &scene = *_vm->_scene;
@@@ -1852,10 -1768,7 +1777,7 @@@
  	screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
  }
  
- /**
- * Print the description of an object
- */
 -void UserInterface::printObjectDesc(const Common::String &str, bool firstTime) {
 +void ScalpelUserInterface::printObjectDesc(const Common::String &str, bool firstTime) {
  	Events &events = *_vm->_events;
  	Inventory &inv = *_vm->_inventory;
  	Screen &screen = *_vm->_screen;
@@@ -2023,17 -1936,11 +1945,11 @@@
  	}
  }
  
- /**
-  * Print the previously selected object's decription
-  */
 -void UserInterface::printObjectDesc() {
 +void ScalpelUserInterface::printObjectDesc() {
  	printObjectDesc(_cAnimStr, true);
  }
  
- /**
-  * Displays a passed window by gradually scrolling it vertically on-screen
-  */
 -void UserInterface::summonWindow(const Surface &bgSurface, bool slideUp) {
 +void ScalpelUserInterface::summonWindow(const Surface &bgSurface, bool slideUp) {
  	Events &events = *_vm->_events;
  	Screen &screen = *_vm->_screen;
  
@@@ -2073,10 -1979,7 +1988,7 @@@
  	_windowOpen = true;
  }
  
- /**
-  * Slide the window stored in the back buffer onto the screen
-  */
 -void UserInterface::summonWindow(bool slideUp, int height) {
 +void ScalpelUserInterface::summonWindow(bool slideUp, int height) {
  	Screen &screen = *_vm->_screen;
  
  	// Extract the window that's been drawn on the back buffer
@@@ -2093,11 -1996,7 +2005,7 @@@
  	summonWindow(tempSurface, slideUp);
  }
  
- /**
-  * Close a currently open window
-  * @param flag	0 = slide old window down, 1 = slide prior UI back up
-  */
 -void UserInterface::banishWindow(bool slideUp) {
 +void ScalpelUserInterface::banishWindow(bool slideUp) {
  	Events &events = *_vm->_events;
  	Screen &screen = *_vm->_screen;
  
@@@ -2163,11 -2062,8 +2071,8 @@@
  	_menuMode = STD_MODE;
  }
  
- /**
-  * Checks to see whether a USE action is valid on the given object
-  */
 -void UserInterface::checkUseAction(const UseType *use, const Common::String &invName,
 +void ScalpelUserInterface::checkUseAction(const UseType *use, const Common::String &invName,
- 		const char *const messages[], int objNum, int giveMode) {
+ 		const char *const messages[], int objNum, bool giveMode) {
  	Events &events = *_vm->_events;
  	Inventory &inv = *_vm->_inventory;
  	Scene &scene = *_vm->_scene;
@@@ -2259,10 -2155,7 +2164,7 @@@
  	events.setCursor(ARROW);
  }
  
- /**
-  * Called for OPEN, CLOSE, and MOVE actions are being done
-  */
 -void UserInterface::checkAction(ActionType &action, const char *const messages[], int objNum) {
 +void ScalpelUserInterface::checkAction(ActionType &action, const char *const messages[], int objNum) {
  	Events &events = *_vm->_events;
  	People &people = *_vm->_people;
  	Scene &scene = *_vm->_scene;
@@@ -2394,39 -2287,4 +2296,14 @@@
  	events.setCursor(ARROW);
  }
  
- /**
-  * Support method for updating the screen
-  */
- void ScalpelUserInterface::doInvJF() {
- 	Inventory &inv = *_vm->_inventory;
- 	Screen &screen = *_vm->_screen;
- 	Talk &talk = *_vm->_talk;
- 
- 	_invLookFlag = true;
- 	inv.freeInv();
- 
- 	_infoFlag = true;
- 	clearInfo();
- 
- 	screen._backBuffer2.blitFrom(screen._backBuffer1, Common::Point(0, CONTROLS_Y),
- 		Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
- 	examine();
- 
- 	if (!talk._talkToAbort) {
- 		screen._backBuffer2.blitFrom((*_controlPanel)[0]._frame,
- 			Common::Point(0, CONTROLS_Y));
- 		inv.loadInv();
- 	}
- }
- 
 +/*----------------------------------------------------------------*/
 +
 +TattooUserInterface::TattooUserInterface(SherlockEngine *vm): UserInterface(vm) {
 +	//
 +}
 +
 +void TattooUserInterface::handleInput() {
 +	// TODO
 +}
 +
  } // End of namespace Sherlock
diff --cc engines/sherlock/user_interface.h
index acbb0c0,1f7b5fe..8a0f4f5
--- a/engines/sherlock/user_interface.h
+++ b/engines/sherlock/user_interface.h
@@@ -61,59 -61,23 +61,94 @@@ extern const char *const PRESS_KEY_TO_C
  class SherlockEngine;
  class Inventory;
  class Talk;
 -class UserInterface;
  
  class UserInterface {
 +protected:
 +	SherlockEngine *_vm;
 +
 +	UserInterface(SherlockEngine *vm);
 +public:
 +	MenuMode _menuMode;
 +	int _menuCounter;
 +	bool _infoFlag;
 +	bool _windowOpen;
 +	bool _endKeyActive;
 +	int _invLookFlag;
- 	int _windowStyle;
++	bool _slideWindows;
 +	bool _helpStyle;
 +	Common::Rect _windowBounds;
 +	bool _lookScriptFlag;
 +
 +	// TODO: Not so sure these should be in the base class. May want to refactor them to SherlockEngine, or refactor
 +	// various Scalpel dialogs to keep their own private state of key/selections
- 	int _key, _oldKey;
++	char _key, _oldKey;
 +	int _selector, _oldSelector;
 +	int _temp, _oldTemp;
 +	int _temp1;
 +	int _lookHelp;
 +public:
 +	static UserInterface *init(SherlockEngine *vm);
 +
++	/**
++	 * Resets the user interface
++	 */
 +	virtual void reset() {}
++
++	/**
++	 * Draw the user interface onto the screen's back buffers
++	 */	
 +	virtual void drawInterface(int bufferNum = 3) {}
++
++	/**
++	 * Main input handler for the user interface
++	 */
 +	virtual void handleInput() {}
 +
- 	virtual void doInvJF() {}
++	/**
++	 * Displays a passed window by gradually scrolling it vertically on-screen
++	 */
 +	virtual void summonWindow(const Surface &bgSurface, bool slideUp = true) {}
++
++	/**
++	 * Slide the window stored in the back buffer onto the screen
++	 */
 +	virtual void summonWindow(bool slideUp = true, int height = CONTROLS_Y) {}
++
++	/**
++	 * Close a currently open window
++	 * @param flag	0 = slide old window down, 1 = slide prior UI back up
++	 */
 +	virtual void banishWindow(bool slideUp = true) {}
++
++	/**
++	 * Clears the info line of the screen
++	 */
 +	virtual void clearInfo() {}
++
++	/**
++	 * Clear any active text window
++	 */
 +	virtual void clearWindow() {}
 +
++	/**
++	 * Print the previously selected object's decription
++	 */
 +	virtual void printObjectDesc() {}
 +};
 +
 +class ScalpelUserInterface: public UserInterface {
  	friend class Inventory;
  	friend class Settings;
  	friend class Talk;
  private:
 -	SherlockEngine *_vm;
  	ImageFile *_controlPanel;
  	ImageFile *_controls;
--	int _bgFound;
--	int _oldBgFound;
- 	int _keycode;
+ 	char _keyPress;
+ 	int _lookHelp;
++	int _bgFound, _oldBgFound;
  	int _help, _oldHelp;
+ 	char _key, _oldKey;
+ 	int _temp, _oldTemp;
  	int _oldLook;
  	bool _keyboardInput;
  	bool _pause;
@@@ -123,62 -90,169 +158,169 @@@
  	int _find;
  	int _oldUse;
  private:
+ 	/**
+ 	 * Draws the image for a user interface button in the down/pressed state.
+ 	 */
  	void depressButton(int num);
  
+ 	/**
+ 	 * If he mouse button is pressed, then calls depressButton to draw the button
+ 	 * as pressed; if not, it will show it as released with a call to "restoreButton".
+ 	 */
  	void pushButton(int num);
  
+ 	/**
+ 	 * By the time this method has been called, the graphics for the button change
+ 	 * have already been drawn. This simply takes care of switching the mode around
+ 	 * accordingly
+ 	 */
  	void toggleButton(int num);
  
+ 	/**
+ 	 * Creates a text window and uses it to display the in-depth description
+ 	 * of the highlighted object
+ 	 */
  	void examine();
  
+ 	/**
+ 	 * Print the name of an object in the scene
+ 	 */
  	void lookScreen(const Common::Point &pt);
  
+ 	/**
+ 	 * Gets the item in the inventory the mouse is on and display's it's description
+ 	 */
  	void lookInv();
  
+ 	/**
+ 	 * Handles input when the file list window is being displayed
+ 	 */
  	void doEnvControl();
+ 	
+ 	/**
+ 	 * Handle input whilst the inventory is active
+ 	 */
  	void doInvControl();
+ 	
+ 	/**
+ 	 * Handles waiting whilst an object's description window is open.
+ 	 */
  	void doLookControl();
+ 	
+ 	/**
+ 	 * Handles input until one of the user interface buttons/commands is selected
+ 	 */
  	void doMainControl();
+ 	
+ 	/**
+ 	 * Handles the input for the MOVE, OPEN, and CLOSE commands
+ 	 */
  	void doMiscControl(int allowed);
+ 	
+ 	/**
+ 	 * Handles input for picking up items
+ 	 */
  	void doPickControl();
+ 	
+ 	/**
+ 	 * Handles input when in talk mode. It highlights the buttons and available statements,
+ 	 * and handles allowing the user to click on them
+ 	 */
  	void doTalkControl();
+ 	
+ 	/**
+ 	 * Handles events when the Journal is active.
+ 	 * @remarks		Whilst this would in theory be better in the Journal class, since it displays in
+ 	 *		the user interface, it uses so many internal UI fields, that it sort of made some sense
+ 	 *		to put it in the UserInterface class.
+ 	 */
  	void journalControl();
  
+ 	/**
+ 	 * Checks to see whether a USE action is valid on the given object
+ 	 */
  	void checkUseAction(const UseType *use, const Common::String &invName, const char *const messages[],
- 		int objNum, int giveMode);
+ 		int objNum, bool giveMode);
+ 	
+ 	/**
+ 	 * Called for OPEN, CLOSE, and MOVE actions are being done
+ 	 */
  	void checkAction(ActionType &action, const char *const messages[], int objNum);
 -public:
 -	MenuMode _menuMode;
 -	int _menuCounter;
 -	bool _infoFlag;
 -	bool _windowOpen;
 -	bool _endKeyActive;
 -	int _invLookFlag;
 -	int _temp1;
 -	bool _slideWindows;
 -	bool _helpStyle;
 -public:
 -	UserInterface(SherlockEngine *vm);
 -	~UserInterface();
  
+ 	/**
 -	 * Resets the user interface
++	 * Print the previously selected object's decription
+ 	 */
 -	void reset();
 +	void printObjectDesc(const Common::String &str, bool firstTime);
 +public:
 +	ScalpelUserInterface(SherlockEngine *vm);
 +	~ScalpelUserInterface();
  
+ 	/**
 -	 * Draw the user interface onto the screen's back buffers
++	 * Handles counting down whilst checking for input, then clears the info line.
+ 	 */
 -	void drawInterface(int bufferNum = 3);
 +	void whileMenuCounter();
  
+ 	/**
 -	 * Main input handler for the user interface
++	 * Draws the image for the given user interface button in the up
++	 * (not selected) position
+ 	 */
 -	void handleInput();
 -
 +	void restoreButton(int num);
 +public:
+ 	/**
 -	 * Clears the info line of the screen
++	 * Resets the user interface
+ 	 */
 -	void clearInfo();
 +	virtual void reset();
  
+ 	/**
 -	 * Clear any active text window
++	 * Main input handler for the user interface
+ 	 */
 -	void clearWindow();
 +	virtual void handleInput();
  
+ 	/**
 -	 * Handles counting down whilst checking for input, then clears the info line.
 -	 */
 -	void whileMenuCounter();
++	 * Draw the user interface onto the screen's back buffers
++	 */	
 +	virtual void drawInterface(int bufferNum = 3);
  
- 	virtual void doInvJF();
- 
+ 	/**
 -	 * Print the description of an object
++	 * Displays a passed window by gradually scrolling it vertically on-screen
+ 	 */
 -	void printObjectDesc(const Common::String &str, bool firstTime);
 -	
 +	virtual void summonWindow(const Surface &bgSurface, bool slideUp = true);
++
+ 	/**
 -	 * Print the previously selected object's decription
++	 * Slide the window stored in the back buffer onto the screen
+ 	 */
 -	void printObjectDesc();
 +	virtual void summonWindow(bool slideUp = true, int height = CONTROLS_Y);
+ 
+ 	/**
 -	 * Displays a passed window by gradually scrolling it vertically on-screen
++	 * Close a currently open window
++	 * @param flag	0 = slide old window down, 1 = slide prior UI back up
+ 	 */
 -	void summonWindow(const Surface &bgSurface, bool slideUp = true);
 -	
 +	virtual void banishWindow(bool slideUp = true);
++
+ 	/**
 -	 * Slide the window stored in the back buffer onto the screen
++	 * Clears the info line of the screen
+ 	 */
 -	void summonWindow(bool slideUp = true, int height = CONTROLS_Y);
 -	
 +	virtual void clearInfo();
++
+ 	/**
 -	 * Close a currently open window
 -	 * @param flag	0 = slide old window down, 1 = slide prior UI back up
++	 * Clear any active text window
+ 	 */
 -	void banishWindow(bool slideUp = true);
 +	virtual void clearWindow();
  
+ 	/**
 -	 * Draws the image for the given user interface button in the up
 -	 * (not selected) position
++	 * Print the previously selected object's decription
++	 */	
 +	virtual void printObjectDesc();
 +};
 +
 +class TattooUserInterface : public UserInterface {
 +public:
 +	TattooUserInterface(SherlockEngine *vm);
 +public:
++	/**
++	 * Main input handler for the user interface
+ 	 */
 -	void restoreButton(int num);
 +	virtual void handleInput();
  };
  
  } // End of namespace Sherlock


Commit: ad543a0423a478329149a6c2ab40fb2294ebcd0b
    https://github.com/scummvm/scummvm/commit/ad543a0423a478329149a6c2ab40fb2294ebcd0b
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-23T10:39:47-04:00

Commit Message:
SHERLOCK: Fix Rose Tattoo scene loading problems from merge

Changed paths:
    engines/sherlock/resources.cpp
    engines/sherlock/scalpel/scalpel.cpp
    engines/sherlock/scene.cpp
    engines/sherlock/sound.cpp
    engines/sherlock/tattoo/tattoo.cpp



diff --git a/engines/sherlock/resources.cpp b/engines/sherlock/resources.cpp
index 864622e..4e10ba9 100644
--- a/engines/sherlock/resources.cpp
+++ b/engines/sherlock/resources.cpp
@@ -91,9 +91,12 @@ Resources::Resources(SherlockEngine *vm) : _vm(vm), _cache(vm) {
 	if (_vm->_interactiveFl) {
 		addToCache("vgs.lib");
 		addToCache("talk.lib");
-		addToCache("sequence.txt");
 		addToCache("journal.txt");
-		addToCache("portrait.lib");
+
+		if (IS_SERRATED_SCALPEL) {
+			addToCache("sequence.txt");
+			addToCache("portrait.lib");
+		}
 	}
 }
 
@@ -310,7 +313,7 @@ void Resources::decompressLZ(Common::SeekableReadStream &source, byte *outBuffer
 				lzWindowPos = (lzWindowPos + 1) & 0x0FFF;
 			}
 		}
-	} while ((outSize == -1 || outBuffer < outBufferEnd) || (inSize == -1 || source.pos() < endPos));
+	} while ((outSize == -1 || outBuffer < outBufferEnd) && (inSize == -1 || source.pos() < endPos));
 }
 
 /*----------------------------------------------------------------*/
diff --git a/engines/sherlock/scalpel/scalpel.cpp b/engines/sherlock/scalpel/scalpel.cpp
index ccc9c8a..7209c34 100644
--- a/engines/sherlock/scalpel/scalpel.cpp
+++ b/engines/sherlock/scalpel/scalpel.cpp
@@ -390,13 +390,6 @@ void ScalpelEngine::initialize() {
 	_flags[3] = true;		// Turn on Alley
 	_flags[39] = true;		// Turn on Baker Street
 
-	// Add some more files to the cache
-	_res->addToCache("portrait.lib");
-	_res->addToCache("sequence.txt");
-	_res->addToCache("EPILOGUE.SND");
-	_res->addToCache("snd.snd");
-	_res->addToCache("title.snd");
-
 	if (!isDemo()) {
 		// Load the map co-ordinates for each scene and sequence data
 		_map->loadPoints(NUM_PLACES, &MAP_X[0], &MAP_Y[0], &MAP_TRANSLATE[0]);
diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp
index 2c80bfb..933e60d 100644
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@ -311,27 +311,32 @@ bool Scene::loadScene(const Common::String &filename) {
 			bgInfo[idx].load(*rrmStream);
 
 		// Read information
-		if (IS_SERRATED_SCALPEL) {
-			Common::SeekableReadStream *infoStream = !_lzwMode ? rrmStream :
-				res.decompress(*rrmStream, bgHeader._numStructs * 569 + bgHeader._descSize + bgHeader._seqSize);
+		if (IS_ROSE_TATTOO) {
+			// Load shapes
+			Common::SeekableReadStream *infoStream = !_lzwMode ? rrmStream : res.decompress(*rrmStream, bgHeader._numStructs * 625);
 
 			_bgShapes.resize(bgHeader._numStructs);
 			for (int idx = 0; idx < bgHeader._numStructs; ++idx)
-				_bgShapes[idx].load(*infoStream, false);
+				_bgShapes[idx].load(*infoStream, _vm->getGameID() == GType_RoseTattoo);
 
-			if (bgHeader._descSize) {
-				_descText.resize(bgHeader._descSize);
-				infoStream->read(&_descText[0], bgHeader._descSize);
-			}
+			if (_lzwMode)
+				delete infoStream;
 
-			if (bgHeader._seqSize) {
-				_sequenceBuffer.resize(bgHeader._seqSize);
-				infoStream->read(&_sequenceBuffer[0], bgHeader._seqSize);
-			}
+			// Load description text
+			_descText.resize(bgHeader._descSize);
+			if (_lzwMode)
+				res.decompress(*rrmStream, (byte *)&_descText[0], bgHeader._descSize);
+			else
+				rrmStream->read(&_descText[0], bgHeader._descSize);
 
+			// Load sequences
+			_sequenceBuffer.resize(bgHeader._seqSize);
 			if (_lzwMode)
-				delete infoStream;
+				res.decompress(*rrmStream, &_sequenceBuffer[0], bgHeader._seqSize);
+			else
+				rrmStream->read(&_sequenceBuffer[0], bgHeader._seqSize);
 		} else if (!_lzwMode) {
+			// Serrated Scalpel uncompressed info
 			_bgShapes.resize(bgHeader._numStructs);
 			for (int idx = 0; idx < bgHeader._numStructs; ++idx)
 				_bgShapes[idx].load(*rrmStream, false);
@@ -346,6 +351,7 @@ bool Scene::loadScene(const Common::String &filename) {
 				rrmStream->read(&_sequenceBuffer[0], bgHeader._seqSize);
 			}
 		} else {
+			// Serrated Scalpel compressed info
 			Common::SeekableReadStream *infoStream;
 
 			// Read shapes
diff --git a/engines/sherlock/sound.cpp b/engines/sherlock/sound.cpp
index 06f6a0f..b8fe61d 100644
--- a/engines/sherlock/sound.cpp
+++ b/engines/sherlock/sound.cpp
@@ -68,11 +68,16 @@ Sound::Sound(SherlockEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {
 		_vm->_res->addToCache("TITLE.SND");
 	else {
 		_vm->_res->addToCache("MUSIC.LIB");
-		_vm->_res->addToCache("SND.SND");
+		
+		if (IS_ROSE_TATTOO) {
+			_vm->_res->addToCache("SOUND.LIB");
+		} else {
+			_vm->_res->addToCache("SND.SND");
 
-		if (!_vm->isDemo()) {
-			_vm->_res->addToCache("TITLE.SND");
-			_vm->_res->addToCache("EPILOGUE.SND");
+			if (!_vm->isDemo()) {
+				_vm->_res->addToCache("TITLE.SND");
+				_vm->_res->addToCache("EPILOGUE.SND");
+			}
 		}
 	}
 }
diff --git a/engines/sherlock/tattoo/tattoo.cpp b/engines/sherlock/tattoo/tattoo.cpp
index 3c684ff..9039e3f 100644
--- a/engines/sherlock/tattoo/tattoo.cpp
+++ b/engines/sherlock/tattoo/tattoo.cpp
@@ -44,7 +44,6 @@ void TattooEngine::initialize() {
 
 	// Add some more files to the cache
 	_res->addToCache("walk.lib");
-	_res->addToCache("sound.lib");
 
 	// Starting scene
 	_scene->_goToScene = 91;


Commit: a66570f6be15a32dba66dac35e6b8c1771867d36
    https://github.com/scummvm/scummvm/commit/a66570f6be15a32dba66dac35e6b8c1771867d36
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-23T16:06:29-04:00

Commit Message:
SHERLOCK: Implemented Tattoo loadWalk changes

Changed paths:
    engines/sherlock/map.cpp
    engines/sherlock/map.h
    engines/sherlock/objects.cpp
    engines/sherlock/objects.h
    engines/sherlock/people.cpp
    engines/sherlock/people.h
    engines/sherlock/scalpel/scalpel.cpp
    engines/sherlock/scene.cpp



diff --git a/engines/sherlock/map.cpp b/engines/sherlock/map.cpp
index 44ca7cd..4f034d8 100644
--- a/engines/sherlock/map.cpp
+++ b/engines/sherlock/map.cpp
@@ -65,8 +65,12 @@ Map::Map(SherlockEngine *vm): _vm(vm), _topLine(g_system->getWidth(), 12) {
 	_oldCharPoint = 0;
 	_frameChangeFlag = false;
 
-	for (int idx = 0; idx < MAX_HOLMES_SEQUENCE; ++idx)
-		Common::fill(&_sequences[idx][0], &_sequences[idx][MAX_FRAME], 0);
+	// Initialise the initial walk sequence set
+	_walkSequences.resize(MAX_HOLMES_SEQUENCE);
+	for (int idx = 0; idx < MAX_HOLMES_SEQUENCE; ++idx) {
+		_walkSequences[idx]._sequences.resize(MAX_FRAME);
+		Common::fill(&_walkSequences[idx]._sequences[0], &_walkSequences[idx]._sequences[0] + MAX_FRAME, 0);
+	}
 
 	if (!_vm->isDemo())
 		loadData();
@@ -80,7 +84,7 @@ void Map::loadPoints(int count, const int *xList, const int *yList, const int *t
 
 void Map::loadSequences(int count, const byte *seq) {
 	for (int idx = 0; idx < count; ++idx, seq += MAX_FRAME)
-		Common::copy(seq, seq + MAX_FRAME, &_sequences[idx][0]);
+		Common::copy(seq, seq + MAX_FRAME, &_walkSequences[idx]._sequences[0]);
 }
 
 void Map::loadData() {
@@ -289,7 +293,7 @@ void Map::setupSprites() {
 	p._type = CHARACTER;
 	p._position = Common::Point(12400, 5000);
 	p._sequenceNumber = 0;
-	p._sequences = &_sequences;
+	p._walkSequences = _walkSequences;
 	p._images = _shapes;
 	p._imageFrame = nullptr;
 	p._frameNumber = 0;
diff --git a/engines/sherlock/map.h b/engines/sherlock/map.h
index ab70b08..198b31e 100644
--- a/engines/sherlock/map.h
+++ b/engines/sherlock/map.h
@@ -76,7 +76,7 @@ private:
 	ImageFile *_mapCursors;
 	ImageFile *_shapes;
 	ImageFile *_iconShapes;
-	byte _sequences[MAX_HOLMES_SEQUENCE][MAX_FRAME];
+	Common::Array<WalkSequence> _walkSequences;
 	Point32 _lDrawnPos;
 	int _point;
 	bool _placesShown;
diff --git a/engines/sherlock/objects.cpp b/engines/sherlock/objects.cpp
index f380351..0709f6b 100644
--- a/engines/sherlock/objects.cpp
+++ b/engines/sherlock/objects.cpp
@@ -46,7 +46,7 @@ void Sprite::clear() {
 	_description = "";
 	_examine.clear();
 	_pickUp = "";
-	_sequences = nullptr;
+	_walkSequences.clear();
 	_images = nullptr;
 	_imageFrame = nullptr;
 	_walkCount = 0;
@@ -63,12 +63,21 @@ void Sprite::clear() {
 	_status = 0;
 	_misc = 0;
 	_numFrames = 0;
+	_altImages = nullptr;
+	_altSequences = false;
+	Common::fill(&_stopFrames[0], &_stopFrames[8], (ImageFrame *)nullptr);
 }
 
 void Sprite::setImageFrame() {
-	int imageNumber = (*_sequences)[_sequenceNumber][_frameNumber] +
-		(*_sequences)[_sequenceNumber][0] - 2;
-	_imageFrame = &(*_images)[imageNumber];
+	int frameNum = MAX(_frameNumber, 0);
+	int imageNumber = _walkSequences[_sequenceNumber][frameNum];
+	
+	if (IS_SERRATED_SCALPEL)
+		imageNumber = imageNumber + +_walkSequences[_sequenceNumber][0] - 2;
+	else if (imageNumber > _numFrames)
+		imageNumber = 1;
+
+	_imageFrame = &(_altSequences ? *_altImages : *_images)[imageNumber];
 }
 
 void Sprite::adjustSprite() {
@@ -120,7 +129,7 @@ void Sprite::adjustSprite() {
 	if (!map._active || (map._frameChangeFlag = !map._frameChangeFlag))
 		++_frameNumber;
 
-	if ((*_sequences)[_sequenceNumber][_frameNumber] == 0) {
+	if (_walkSequences[_sequenceNumber][_frameNumber] == 0) {
 		switch (_sequenceNumber) {
 		case STOP_UP:
 		case STOP_DOWN:
diff --git a/engines/sherlock/objects.h b/engines/sherlock/objects.h
index b61e7e2..761c03d 100644
--- a/engines/sherlock/objects.h
+++ b/engines/sherlock/objects.h
@@ -46,7 +46,10 @@ enum SpriteType {
 	REMOVE = 5,					// Object should be removed next frame
 	NO_SHAPE = 6,				// Background object with no shape
 	HIDDEN = 7,					// Hidden backgruond object
-	HIDE_SHAPE = 8				// Object needs to be hidden
+	HIDE_SHAPE = 8,				// Object needs to be hidden
+
+	// Rose Tattoo
+	HIDDEN_CHARACTER = 128
 };
 
 enum AType {
@@ -98,16 +101,31 @@ public:
 	void operator-=(const Point32 &delta) { x -= delta.x; y -= delta.y; }
 };
 
+
+struct WalkSequence {
+	Common::String _vgsName;
+	bool _horizFlip;
+	Common::Array<byte> _sequences;
+
+	WalkSequence() : _vgsName(nullptr), _horizFlip(false) {}
+	const byte &operator[](int idx) { return _sequences[idx]; }
+
+	/**
+	 * Load data for the sequence from a stream
+	 */
+	void load(Common::SeekableReadStream &s);
+};
+
 class Sprite {
 private:
 	static SherlockEngine *_vm;
 public:
 	Common::String _name;				
 	Common::String _description;		
-	Common::StringArray _examine;		// Examine in-depth description
+	Common::String _examine;			// Examine in-depth description
 	Common::String _pickUp;				// Message for if you can't pick up object
 
-	const uint8 (*_sequences)[MAX_HOLMES_SEQUENCE][MAX_FRAME];  // Holds animation sequences
+	Common::Array<WalkSequence> _walkSequences;	// Holds animation sequences
 	ImageFile *_images;					// Sprite images
 	ImageFrame *_imageFrame;			// Pointer to shape in the images
 	int _walkCount;						// Character walk counter
@@ -124,8 +142,12 @@ public:
 	int _status;						// Status: open/closed, moved/not moved
 	int8 _misc;							// Miscellaneous use
 	int _numFrames;						// How many frames the object has
+	ImageFile *_altImages;
+	bool _altSequences;
+	ImageFrame *_stopFrames[8];			// Stop/rest frame for each direction
 public:
 	Sprite() { clear(); }
+
 	static void setVm(SherlockEngine *vm) { _vm = vm; }
 
 	/**
diff --git a/engines/sherlock/people.cpp b/engines/sherlock/people.cpp
index 3a630fd..638cbf6 100644
--- a/engines/sherlock/people.cpp
+++ b/engines/sherlock/people.cpp
@@ -50,10 +50,37 @@ static const uint8 CHARACTER_SEQUENCES[MAX_HOLMES_SEQUENCE][MAX_FRAME] = {
 	{ 52, 1, 2, 3, 4, 0 }				// Goto Stand Down Left
 };
 
+// Rose Tattoo walk image libraries
+// Walk resources within WALK.LIB
+#define NUM_IN_WALK_LIB 10            
+const char *const WALK_LIB_NAMES[10] = {
+	"SVGAWALK.VGS",
+	"COATWALK.VGS",
+	"WATSON.VGS",
+	"NOHAT.VGS",
+	"TUPRIGHT.VGS",
+	"TRIGHT.VGS",
+	"TDOWNRG.VGS",
+	"TWUPRIGH.VGS",
+	"TWRIGHT.VGS",
+	"TWDOWNRG.VGS"
+};
+
+/*----------------------------------------------------------------*/
+
+void WalkSequence::load(Common::SeekableReadStream &s) {
+	char buffer[9];
+	s.read(buffer, 9);
+	_vgsName = Common::String(buffer);
+	_horizFlip = s.readByte() != 0;
+
+	_sequences.resize(s.readUint16LE());
+	s.read(&_sequences[0], _sequences.size());
+}
+
 /*----------------------------------------------------------------*/
 
 People::People(SherlockEngine *vm) : _vm(vm), _player(_data[0]) {
-	_walkLoaded = false;
 	_holmesOn = true;
 	_oldWalkSequence = -1;
 	_allowWalkAbort = false;
@@ -68,13 +95,18 @@ People::People(SherlockEngine *vm) : _vm(vm), _player(_data[0]) {
 	_holmesQuotient = 0;
 	_hSavedPos = Common::Point(-1, -1);
 	_hSavedFacing = -1;
+	_forceWalkReload = false;
+	_useWalkLib = false;
 
 	_portrait._sequences = new byte[32];
 }
 
 People::~People() {
-	if (_walkLoaded)
-		delete _data[PLAYER]._images;
+	for (int idx = 0; idx < MAX_PLAYERS; ++idx) {
+		if (_data[idx]._walkLoaded)
+			delete _data[PLAYER]._images;
+	}
+
 	delete _talkPics;
 	delete[] _portrait._sequences;
 }
@@ -88,7 +120,6 @@ void People::reset() {
 	p._type = CHARACTER;
 	p._position = Common::Point(10000, 11000);
 	p._sequenceNumber = STOP_DOWNRIGHT;
-	p._sequences = &CHARACTER_SEQUENCES;
 	p._imageFrame = nullptr;
 	p._frameNumber = 1;
 	p._delta = Common::Point(0, 0);
@@ -102,32 +133,106 @@ void People::reset() {
 	p._goto = Common::Point(0, 0);
 	p._status = 0;
 
+	// Load the default walk sequences
+	p._walkSequences.resize(MAX_HOLMES_SEQUENCE);
+	for (int idx = 0; idx < MAX_HOLMES_SEQUENCE; ++idx) {
+		p._walkSequences[idx]._sequences.clear();
+		
+		const byte *pSrc = &CHARACTER_SEQUENCES[idx][0];
+		do {
+			p._walkSequences[idx]._sequences.push_back(*pSrc);
+		} while (*pSrc++);
+	}
+
 	// Reset any walk path in progress when Sherlock leaves scenes
 	_walkTo.clear();
 }
 
 bool People::loadWalk() {
-	if (_walkLoaded) {
-		return false;
+	Resources &res = *_vm->_res;
+	bool result = false;
+
+	if (IS_SERRATED_SCALPEL) {
+		if (_data[PLAYER]._walkLoaded) {
+			return false;
+		} else {
+			_data[PLAYER]._images = new ImageFile("walk.vgs");
+			_data[PLAYER].setImageFrame();
+			_data[PLAYER]._walkLoaded = true;
+
+			result = true;
+		}
 	} else {
-		_data[PLAYER]._images = new ImageFile("walk.vgs");
-		_data[PLAYER].setImageFrame();
-		_walkLoaded = true;
+		for (int idx = 0; idx < MAX_PLAYERS; ++idx) {
+			if (!_data[idx]._walkLoaded && (_data[idx]._type == CHARACTER || _data[idx]._type == HIDDEN_CHARACTER)) {
+				if (_data[idx]._type == HIDDEN_CHARACTER)
+					_data[idx]._type = INVALID;
+
+				// See if this is one of the more used Walk Graphics stored in WALK.LIB
+				for (int libNum = 0; libNum < NUM_IN_WALK_LIB; ++libNum) {
+					if (!_data[0]._walkVGSName.compareToIgnoreCase(WALK_LIB_NAMES[libNum])) {
+						_useWalkLib = true;
+						break;
+					}
+				}
+
+				// Load the images for the character
+				_data[idx]._images = new ImageFile(_data[idx]._walkVGSName, false);
+				_data[idx]._numFrames = _data[idx]._images->size();
+
+				// Load walk sequence data
+				Common::String fname = Common::String(_data[idx]._walkVGSName.c_str(), strchr(_data[idx]._walkVGSName.c_str(), '.'));
+				fname += ".SEQ";
+
+				// Load the walk sequence data
+				Common::SeekableReadStream *stream = res.load(fname, _useWalkLib ? "walk.lib" : "vgs.lib");
+				
+				_data[idx]._walkSequences.resize(stream->readByte());
+
+				for (uint seqNum = 0; seqNum < _data[idx]._walkSequences.size(); ++seqNum)
+					_data[idx]._walkSequences[seqNum].load(*stream);
+
+				// Close the sequences resource
+				delete stream;
+				_useWalkLib = false;
+
+				_data[idx]._frameNumber = 0;
+				_data[idx].setImageFrame();
+
+				// Set the stop Frames pointers
+				for (int dirNum = 0; dirNum < 8; ++dirNum) {
+					int count = 0;
+					while (_data[idx]._walkSequences[dirNum + 8][count] != 0)
+						++count;
+					count += 2;
+					count = _data[idx]._walkSequences[dirNum + 8][count] - 1;
+					_data[idx]._stopFrames[dirNum] = &(*_data[idx]._images)[count];
+				}
 
-		return true;
+				result = true;
+				_data[idx]._walkLoaded = true;
+			} else if (_data[idx]._type != CHARACTER) {
+				_data[idx]._walkLoaded = false;
+			}
+		}
 	}
+
+	_forceWalkReload = false;
+	return result;
 }
 
 bool People::freeWalk() {
-	if (_walkLoaded) {
-		delete _player._images;
-		_player._images = nullptr;
+	bool result = false;
 
-		_walkLoaded = false;
-		return true;
-	} else {
-		return false;
+	for (int idx = 0; idx < MAX_PLAYERS; ++idx) {
+		if (_data[idx]._walkLoaded) {
+			delete _data[idx]._images;
+			_data[idx]._images = nullptr;
+			result = true;
+		}
 	}
+
+	return result;
 }
 
 void People::setWalking() {
@@ -553,9 +658,24 @@ void People::setTalking(int speaker) {
 
 void People::synchronize(Common::Serializer &s) {
 	s.syncAsByte(_holmesOn);
-	s.syncAsSint16LE(_player._position.x);
-	s.syncAsSint16LE(_player._position.y);
-	s.syncAsSint16LE(_player._sequenceNumber);
+
+	if (IS_SERRATED_SCALPEL) {
+		s.syncAsSint16LE(_player._position.x);
+		s.syncAsSint16LE(_player._position.y);
+		s.syncAsSint16LE(_player._sequenceNumber);
+	} else {
+		for (int idx = 0; idx < MAX_PLAYERS; ++idx) {
+			Person &p = _data[idx];
+			s.syncAsSint16LE(p._position.x);
+			s.syncAsSint16LE(p._position.y);
+			s.syncAsSint16LE(p._sequenceNumber);
+			s.syncAsSint16LE(p._type);
+			s.syncString(p._walkVGSName);
+			s.syncString(p._description);
+			s.syncString(p._examine);
+		}
+	}
+
 	s.syncAsSint16LE(_holmesQuotient);
 
 	if (s.isLoading()) {
diff --git a/engines/sherlock/people.h b/engines/sherlock/people.h
index 8244fd9..f3e7950 100644
--- a/engines/sherlock/people.h
+++ b/engines/sherlock/people.h
@@ -30,13 +30,11 @@
 
 namespace Sherlock {
 
-// Player definitions. The game has theoretical support for two player characters but only the first one is used.
-// Watson is, instead, handled by a different sprite in each scene, with a very simple initial movement, if any
 enum PeopleId {
 	PLAYER			= 0,
 	AL				= 0,
 	PEG				= 1,
-	MAX_PLAYERS		= 2
+	MAX_PLAYERS		= 6
 };
 
 // Animation sequence identifiers for characters
@@ -63,20 +61,24 @@ struct PersonData {
 		_name(name), _portrait(portrait), _stillSequences(stillSequences), _talkSequences(talkSequences) {}
 };
 
-class SherlockEngine;
-
 class Person : public Sprite {
 public:
-	Person() : Sprite() {}
-
+	bool _walkLoaded;
 	Common::String _portrait;
+
+	// Rose Tattoo fields
+	Common::String _walkVGSName;		// Name of walk library person is using
+	Common::Array<WalkSequence> _walkSequences;
+public:
+	Person() : Sprite(), _walkLoaded(false) {}
 };
 
+class SherlockEngine;
+
 class People {
 private:
 	SherlockEngine *_vm;
 	Person _data[MAX_PLAYERS];
-	bool _walkLoaded;
 	int _oldWalkSequence;
 	int _srcZone, _destZone;
 public:
@@ -97,6 +99,8 @@ public:
 	bool _speakerFlip;
 	bool _holmesFlip;
 	int _holmesQuotient;
+	bool _forceWalkReload;
+	bool _useWalkLib;
 public:
 	People(SherlockEngine *vm);
 	~People();
@@ -113,7 +117,7 @@ public:
 	/**
 	 * Returns true if Sherlock is visible on the screen and enabled
 	 */
-	bool isHolmesActive() const { return _walkLoaded && _holmesOn; }
+	bool isHolmesActive() const { return _data[0]._walkLoaded && _holmesOn; }
 
 	/**
 	 * Reset the player data
diff --git a/engines/sherlock/scalpel/scalpel.cpp b/engines/sherlock/scalpel/scalpel.cpp
index 7209c34..2a107b4 100644
--- a/engines/sherlock/scalpel/scalpel.cpp
+++ b/engines/sherlock/scalpel/scalpel.cpp
@@ -837,9 +837,11 @@ void ScalpelEngine::eraseMirror12() {
 
 void ScalpelEngine::doMirror12() {
 	People &people = *_people;
+	Person &player = people._player;
+
 	Common::Point pt((*_people)[AL]._position.x / 100, (*_people)[AL]._position.y / 100);
-	int frameNum = (*people[AL]._sequences)[people[AL]._sequenceNumber][people[AL]._frameNumber] +
-		(*people[AL]._sequences)[people[AL]._sequenceNumber][0] - 2;
+	int frameNum = player._walkSequences[player._sequenceNumber][player._frameNumber] +
+		player._walkSequences[player._sequenceNumber][0] - 2;
 
 	switch ((*_people)[AL]._sequenceNumber) {
 	case WALK_DOWN:
diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp
index 933e60d..4672e3e 100644
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@ -536,7 +536,7 @@ bool Scene::loadScene(const Common::String &filename) {
 		delete rrmStream;
 	}
 
-	// Clear user interface area and draw controls
+	// Handle drawing any on-screen interface
 	ui.drawInterface();
 
 	checkSceneStatus();
@@ -568,7 +568,7 @@ bool Scene::loadScene(const Common::String &filename) {
 	checkInventory();
 
 	// Handle starting any music for the scene
-	if (sound._musicOn && sound.loadSong(_currentScene)) {
+	if (IS_SERRATED_SCALPEL && sound._musicOn && sound.loadSong(_currentScene)) {
 		if (sound._music)
 			sound.startSong();
 	}


Commit: ad008b534bfc24eb58200a676dd6190ec3d8f7ef
    https://github.com/scummvm/scummvm/commit/ad008b534bfc24eb58200a676dd6190ec3d8f7ef
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-24T07:46:25-04:00

Commit Message:
SHERLOCK: Implemented initial RT palette loading

Changed paths:
    engines/sherlock/scene.cpp
    engines/sherlock/screen.cpp
    engines/sherlock/screen.h
    engines/sherlock/tattoo/tattoo.cpp
    engines/sherlock/tattoo/tattoo.h



diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp
index 4672e3e..e625dae 100644
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@ -514,9 +514,7 @@ bool Scene::loadScene(const Common::String &filename) {
 		} else {
 			// Read in palette
 			rrmStream->read(screen._cMap, PALETTE_SIZE);
-			for (int idx = 0; idx < PALETTE_SIZE; ++idx)
-				screen._cMap[idx] = VGA_COLOR_TRANS(screen._cMap[idx]);
-
+			screen.translatePalette(screen._cMap);
 			Common::copy(screen._cMap, screen._cMap + PALETTE_SIZE, screen._sMap);
 
 			// Read in the background
diff --git a/engines/sherlock/screen.cpp b/engines/sherlock/screen.cpp
index 24f7660..bb9dbd7 100644
--- a/engines/sherlock/screen.cpp
+++ b/engines/sherlock/screen.cpp
@@ -39,7 +39,7 @@ Screen::Screen(SherlockEngine *vm) : Surface(g_system->getWidth(), g_system->get
 	Common::fill(&_cMap[0], &_cMap[PALETTE_SIZE], 0);
 	Common::fill(&_sMap[0], &_sMap[PALETTE_SIZE], 0);
 	Common::fill(&_tMap[0], &_tMap[PALETTE_SIZE], 0);
-	setFont(1);
+	setFont(IS_SERRATED_SCALPEL ? 1 : 4);
 
 	// Rose Tattoo specific fields
 	_fadeBytesRead = _fadeBytesToRead = 0;
@@ -466,4 +466,9 @@ void Screen::initScrollVars() {
 	_targetScroll = 0;
 }
 
+void Screen::translatePalette(byte palette[PALETTE_SIZE]) {
+	for (int idx = 0; idx < PALETTE_SIZE; ++idx)
+		palette[idx] = VGA_COLOR_TRANS(palette[idx]);
+}
+
 } // End of namespace Sherlock
diff --git a/engines/sherlock/screen.h b/engines/sherlock/screen.h
index f4cd6fd..58c7d8f 100644
--- a/engines/sherlock/screen.h
+++ b/engines/sherlock/screen.h
@@ -251,6 +251,12 @@ public:
 	void setupBGArea(const byte cMap[PALETTE_SIZE]);
 
 	void initScrollVars();
+
+	/**
+	 * Translate a palette from 6-bit RGB values to full 8-bit values suitable for passing
+	 * to the underlying palette manager
+	 */
+	static void translatePalette(byte palette[PALETTE_SIZE]);
 };
 
 } // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/tattoo.cpp b/engines/sherlock/tattoo/tattoo.cpp
index 9039e3f..47a7c2a 100644
--- a/engines/sherlock/tattoo/tattoo.cpp
+++ b/engines/sherlock/tattoo/tattoo.cpp
@@ -47,6 +47,9 @@ void TattooEngine::initialize() {
 
 	// Starting scene
 	_scene->_goToScene = 91;
+
+	// Load an initial palette
+	loadInitialPalette();
 }
 
 /**
@@ -56,6 +59,15 @@ void TattooEngine::startScene() {
 	// TODO
 }
 
+void TattooEngine::loadInitialPalette() {
+	byte palette[768];
+	Common::SeekableReadStream *stream = _res->load("room.pal");
+	stream->read(palette, PALETTE_SIZE);
+	_screen->translatePalette(palette);
+	_screen->setPalette(palette);
+
+	delete stream;
+}
 
 } // End of namespace Tattoo
 
diff --git a/engines/sherlock/tattoo/tattoo.h b/engines/sherlock/tattoo/tattoo.h
index 7bdeec5..b9224e0 100644
--- a/engines/sherlock/tattoo/tattoo.h
+++ b/engines/sherlock/tattoo/tattoo.h
@@ -30,6 +30,11 @@ namespace Sherlock {
 namespace Tattoo {
 
 class TattooEngine : public SherlockEngine {
+private:
+	/**
+	 * Loads the initial palette for the game
+	 */
+	void loadInitialPalette();
 protected:
 	virtual void initialize();
 


Commit: 83c911c45c3a6626d3c53971cdaa04629ecdc827
    https://github.com/scummvm/scummvm/commit/83c911c45c3a6626d3c53971cdaa04629ecdc827
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-24T10:56:22-04:00

Commit Message:
SHERLOCK: Implement more scene loading and setNPCPath

Changed paths:
    engines/sherlock/objects.h
    engines/sherlock/people.cpp
    engines/sherlock/people.h
    engines/sherlock/scene.cpp
    engines/sherlock/scene.h
    engines/sherlock/sound.cpp
    engines/sherlock/sound.h



diff --git a/engines/sherlock/objects.h b/engines/sherlock/objects.h
index 761c03d..f104762 100644
--- a/engines/sherlock/objects.h
+++ b/engines/sherlock/objects.h
@@ -107,7 +107,7 @@ struct WalkSequence {
 	bool _horizFlip;
 	Common::Array<byte> _sequences;
 
-	WalkSequence() : _vgsName(nullptr), _horizFlip(false) {}
+	WalkSequence() : _horizFlip(false) {}
 	const byte &operator[](int idx) { return _sequences[idx]; }
 
 	/**
diff --git a/engines/sherlock/people.cpp b/engines/sherlock/people.cpp
index 638cbf6..7879f29 100644
--- a/engines/sherlock/people.cpp
+++ b/engines/sherlock/people.cpp
@@ -80,6 +80,18 @@ void WalkSequence::load(Common::SeekableReadStream &s) {
 
 /*----------------------------------------------------------------*/
 
+Person::Person() : Sprite(), _walkLoaded(false), _npcIndex(0), _npcStack(0), _npcPause(false)  {
+	Common::fill(&_npcPath[0], &_npcPath[MAX_NPC_PATH], 0);
+}
+
+void Person::clearNPC() {
+	Common::fill(&_npcPath[0], &_npcPath[MAX_NPC_PATH], 0);
+	_npcIndex = _npcStack = 0;
+	_npcName = "";
+}
+
+/*----------------------------------------------------------------*/
+
 People::People(SherlockEngine *vm) : _vm(vm), _player(_data[0]) {
 	_holmesOn = true;
 	_oldWalkSequence = -1;
diff --git a/engines/sherlock/people.h b/engines/sherlock/people.h
index f3e7950..a196878 100644
--- a/engines/sherlock/people.h
+++ b/engines/sherlock/people.h
@@ -34,7 +34,9 @@ enum PeopleId {
 	PLAYER			= 0,
 	AL				= 0,
 	PEG				= 1,
-	MAX_PLAYERS		= 6
+	MAX_PLAYERS		= 6,
+	MAX_NPC			= 5,
+	MAX_NPC_PATH	= 200
 };
 
 // Animation sequence identifiers for characters
@@ -66,11 +68,23 @@ public:
 	bool _walkLoaded;
 	Common::String _portrait;
 
+	// NPC related fields
+	int _npcIndex;
+	int _npcStack;
+	bool _npcPause;
+	byte _npcPath[MAX_NPC_PATH];
+	Common::String _npcName;
+
 	// Rose Tattoo fields
 	Common::String _walkVGSName;		// Name of walk library person is using
 	Common::Array<WalkSequence> _walkSequences;
 public:
-	Person() : Sprite(), _walkLoaded(false) {}
+	Person();
+
+	/**
+	 * Clear the NPC related data
+	 */
+	void clearNPC();
 };
 
 class SherlockEngine;
diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp
index e625dae..0f679d7 100644
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@ -249,6 +249,7 @@ bool Scene::loadScene(const Common::String &filename) {
 	SaveManager &saves = *_vm->_saves;
 	Screen &screen = *_vm->_screen;
 	Sound &sound = *_vm->_sound;
+	Talk &talk = *_vm->_talk;
 	UserInterface &ui = *_vm->_ui;
 	bool flag;
 
@@ -264,6 +265,36 @@ bool Scene::loadScene(const Common::String &filename) {
 	_cAnim.clear();
 	_sequenceBuffer.clear();
 
+	// Check if it's a scene we need to keep trakc track of how many times we've visited
+	for (int idx = (int)_sceneTripCounters.size() - 1; idx >= 0; --idx) {
+		if (_sceneTripCounters[idx]._sceneNumber == _currentScene) {
+			if (--_sceneTripCounters[idx]._numTimes == 0) {
+				_vm->setFlags(_sceneTripCounters[idx]._flag);
+				_sceneTripCounters.remove_at(idx);
+			}
+		}
+	}
+
+	if (IS_ROSE_TATTOO) {
+		// Set the NPC paths for the scene
+		setNPCPath(0);
+
+		// Handle loading music for the scene
+		if (sound._midiDrvLoaded) {
+			if (talk._scriptMoreFlag != 1 && talk._scriptMoreFlag != 3)
+				sound._nextSongName = Common::String::format("res%02d", _currentScene);
+
+			// If it's a new song, then start it up
+			if (sound._currentSongName.compareToIgnoreCase(sound._nextSongName)) {
+				if (sound.loadSong(sound._nextSongName)) {
+					sound.setMIDIVolume(sound._musicVolume);
+					if (sound._musicOn)
+						sound.startSong();
+				}
+			}
+		}
+	}
+
 	//
 	// Load the room resource file for the scene
 	//
@@ -1585,4 +1616,26 @@ void Scene::synchronize(Common::Serializer &s) {
 	}
 }
 
+void Scene::setNPCPath(int npc) {
+	People &people = *_vm->_people;
+	Talk &talk = *_vm->_talk;
+	
+	people[npc].clearNPC();
+	people[npc]._name = Common::String::format("WATS%.2dA", _currentScene);
+
+	// If we're in the middle of a script that will continue once the scene is loaded,
+	// return without calling the path script
+	if (talk._scriptMoreFlag == 1 || talk._scriptMoreFlag == 3)
+		return;
+
+	// Turn off all the NPCs, since the talk script will turn them back on as needed
+	for (uint idx = 0; idx < MAX_NPC; ++idx)
+		people[idx + 1]._type = INVALID;
+
+	// Call the path script for the scene
+	Common::String pathFile = Common::String::format("PATH%.2dA", _currentScene);
+	talk.talkTo(pathFile);
+}
+
+
 } // End of namespace Sherlock
diff --git a/engines/sherlock/scene.h b/engines/sherlock/scene.h
index 0cbd775..b0b5624 100644
--- a/engines/sherlock/scene.h
+++ b/engines/sherlock/scene.h
@@ -128,6 +128,16 @@ public:
 	void load(Common::SeekableReadStream &s);
 };
 
+struct SceneTripEntry {
+	bool _flag;
+	int _sceneNumber;
+	int _numTimes;
+
+	SceneTripEntry() : _flag(false), _sceneNumber(0), _numTimes(0) {}
+	SceneTripEntry(bool flag, int sceneNumber, int numTimes) : _flag(flag),
+		_sceneNumber(sceneNumber), _numTimes(numTimes) {}
+};
+
 class Scene {
 private:
 	SherlockEngine *_vm;
@@ -212,6 +222,7 @@ public:
 	bool _doBgAnimDone;
 	int _tempFadeStyle;
 	int _cAnimFramePause;
+	Common::Array<SceneTripEntry> _sceneTripCounters;
 public:
 	Scene(SherlockEngine *vm);
 	~Scene();
@@ -291,6 +302,13 @@ public:
 	 * Synchronize the data for a savegame
 	 */
 	void synchronize(Common::Serializer &s);
+
+	/**
+	 * Resets the NPC path information when entering a new scene.
+	 * @remarks		The default talk file for the given NPC is set to WATS##A, where ## is
+	 *		the scene number being entered
+	 */
+	void setNPCPath(int npc);
 };
 
 } // End of namespace Sherlock
diff --git a/engines/sherlock/sound.cpp b/engines/sherlock/sound.cpp
index b8fe61d..279dd44 100644
--- a/engines/sherlock/sound.cpp
+++ b/engines/sherlock/sound.cpp
@@ -58,6 +58,8 @@ Sound::Sound(SherlockEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {
 	_soundPlaying = false;
 	_soundIsOn = &_soundPlaying;
 	_curPriority = 0;
+	_midiDrvLoaded = false;
+	_musicVolume = 0;
 
 	_soundOn = true;
 	_musicOn = true;
@@ -231,12 +233,19 @@ void Sound::stopMusic() {
 	warning("TODO: Sound::stopMusic");
 }
 
-int Sound::loadSong(int songNumber) {
+bool Sound::loadSong(int songNumber) {
 	// TODO
 	warning("TODO: Sound::loadSong");
-	return 0;
+	return false;
 }
 
+bool Sound::loadSong(const Common::String &name) {
+	// TODO
+	warning("TODO: Sound::loadSong");
+	return false;
+}
+
+
 void Sound::startSong() {
 	// TODO
 	warning("TODO: Sound::startSong");
@@ -264,5 +273,9 @@ void Sound::freeDigiSound() {
 	_soundPlaying = false;
 }
 
+void Sound::setMIDIVolume(int volume) {
+	// TODO
+}
+
 } // End of namespace Sherlock
 
diff --git a/engines/sherlock/sound.h b/engines/sherlock/sound.h
index 689e615..06450ff 100644
--- a/engines/sherlock/sound.h
+++ b/engines/sherlock/sound.h
@@ -58,6 +58,9 @@ public:
 	bool _soundPlaying;
 	bool *_soundIsOn;
 	byte *_digiBuf;
+	bool _midiDrvLoaded;
+	Common::String _currentSongName, _nextSongName;
+	int _musicVolume;
 public:
 	Sound(SherlockEngine *vm, Audio::Mixer *mixer);
 
@@ -94,7 +97,8 @@ public:
 	/**
 	 * Load a specified song
 	 */
-	int loadSong(int songNumber);
+	bool loadSong(int songNumber);
+	bool loadSong(const Common::String &name);
 
 	/**
 	 * Start playing a song
@@ -119,6 +123,7 @@ public:
 	void stopSndFuncPtr(int v1, int v2);
 	void waitTimerRoland(uint time);
 	void freeDigiSound();
+	void setMIDIVolume(int volume);
 };
 
 } // End of namespace Sherlock


Commit: a09f1df8a8a17b3e83190e347e0e80d4453679d6
    https://github.com/scummvm/scummvm/commit/a09f1df8a8a17b3e83190e347e0e80d4453679d6
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-24T10:58:00-04:00

Commit Message:
SHERLOCK: Make virtual destructors for user interface classes

Changed paths:
    engines/sherlock/user_interface.h



diff --git a/engines/sherlock/user_interface.h b/engines/sherlock/user_interface.h
index 8a0f4f5..2203ddf 100644
--- a/engines/sherlock/user_interface.h
+++ b/engines/sherlock/user_interface.h
@@ -88,6 +88,7 @@ public:
 	int _lookHelp;
 public:
 	static UserInterface *init(SherlockEngine *vm);
+	virtual ~UserInterface() {}
 
 	/**
 	 * Resets the user interface
@@ -253,7 +254,7 @@ private:
 	void printObjectDesc(const Common::String &str, bool firstTime);
 public:
 	ScalpelUserInterface(SherlockEngine *vm);
-	~ScalpelUserInterface();
+	virtual ~ScalpelUserInterface();
 
 	/**
 	 * Handles counting down whilst checking for input, then clears the info line.
@@ -317,6 +318,8 @@ class TattooUserInterface : public UserInterface {
 public:
 	TattooUserInterface(SherlockEngine *vm);
 public:
+	virtual ~TattooUserInterface() {}
+
 	/**
 	 * Main input handler for the user interface
 	 */


Commit: 16490a2fe843aee17bd088e59caba501aeabff8c
    https://github.com/scummvm/scummvm/commit/16490a2fe843aee17bd088e59caba501aeabff8c
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-24T12:23:25-04:00

Commit Message:
SHERLOCK: Create separate opcode list for Scalpel vs Tattoo

Changed paths:
    engines/sherlock/journal.cpp
    engines/sherlock/talk.cpp
    engines/sherlock/talk.h



diff --git a/engines/sherlock/journal.cpp b/engines/sherlock/journal.cpp
index 564db59..b4b05da 100644
--- a/engines/sherlock/journal.cpp
+++ b/engines/sherlock/journal.cpp
@@ -135,6 +135,7 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
 	Screen &screen = *_vm->_screen;
 	Talk &talk = *_vm->_talk;
 	JournalEntry &journalEntry = _journal[_index];
+	const byte *opcodes = talk._opcodes;
 
 	Common::String dirFilename = _directory[journalEntry._converseNum];
 	bool replyOnly = journalEntry._replyOnly;
@@ -243,7 +244,7 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
 		byte c = *replyP++;
 
 		// Is it a control character?
-		if (c < SWITCH_SPEAKER) {
+		if (c < opcodes[0]) {
 			// Nope. Set flag for allowing control codes to insert spaces
 			ctrlSpace = true;
 			assert(c >= ' ');
@@ -290,7 +291,7 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
 						byte v;
 						do {
 							v = *strP++;
-						} while (v && (v < SWITCH_SPEAKER) && (v != '.') && (v != '!') && (v != '?'));
+						} while (v && (v < opcodes[0]) && (v != '.') && (v != '!') && (v != '?'));
 
 						if (v == '?')
 							journalString += " asked, \"";
@@ -306,11 +307,11 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
 				journalString += c;
 				do {
 					journalString += *replyP++;
-				} while (*replyP && *replyP < SWITCH_SPEAKER && *replyP != '{' && *replyP != '}');
+				} while (*replyP && *replyP < opcodes[0] && *replyP != '{' && *replyP != '}');
 
 				commentJustPrinted = false;
 			}
-		} else if (c == SWITCH_SPEAKER) {
+		} else if (c == opcodes[OP_SWITCH_SPEAKER]) {
 			if (!startOfReply) {
 				if (!commentFlag && !commentJustPrinted)
 					journalString += "\"\n";
@@ -337,7 +338,7 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
 			byte v;
 			do {
 				v = *strP++;
-			} while (v && v < SWITCH_SPEAKER && v != '.' && v != '!' && v != '?');
+			} while (v && v < opcodes[0] && v != '.' && v != '!' && v != '?');
 
 			if (v == '?')
 				journalString += " asked, \"";
@@ -345,59 +346,42 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
 				journalString += " said, \"";
 		} else {
 			// Control code, so move past it and any parameters
-			switch (c) {
-			case RUN_CANIMATION:
-			case ASSIGN_PORTRAIT_LOCATION:
-			case PAUSE:
-			case PAUSE_WITHOUT_CONTROL:
-			case WALK_TO_CANIMATION:
+			if (c == opcodes[OP_RUN_CANIMATION] || c == opcodes[OP_ASSIGN_PORTRAIT_LOCATION] ||
+					c == opcodes[OP_PAUSE] || c == opcodes[OP_PAUSE_WITHOUT_CONTROL] ||
+					c == opcodes[OP_WALK_TO_CANIMATION]) {
 				// These commands have a single parameter
 				++replyP;
-				break;
 
-			case ADJUST_OBJ_SEQUENCE:
+			} else if (c == opcodes[OP_ADJUST_OBJ_SEQUENCE]) {
 				replyP += (replyP[0] & 127) + replyP[1] + 2;
-				break;
 
-			case WALK_TO_COORDS:
-			case MOVE_MOUSE:
+			} else if (c == opcodes[OP_WALK_TO_COORDS] || c == opcodes[OP_MOVE_MOUSE]) {
 				replyP += 4;
-				break;
-
-			case SET_FLAG:
-			case IF_STATEMENT:
+				
+			} else if (c == opcodes[OP_SET_FLAG] || c == opcodes[OP_IF_STATEMENT]) {
 				replyP += 2;
-				break;
 
-			case SFX_COMMAND:
-			case PLAY_PROLOGUE:
-			case CALL_TALK_FILE:
+			} else if (c == opcodes[OP_SFX_COMMAND] || c == opcodes[OP_PLAY_PROLOGUE] ||
+				c == opcodes[OP_CALL_TALK_FILE]) {
 				replyP += 8;
 				break;
 
-			case TOGGLE_OBJECT:
-			case ADD_ITEM_TO_INVENTORY:
-			case SET_OBJECT:
-			case DISPLAY_INFO_LINE:
-			case REMOVE_ITEM_FROM_INVENTORY:
+			} else if (c == opcodes[OP_TOGGLE_OBJECT] || c == opcodes[OP_ADD_ITEM_TO_INVENTORY] ||
+				c == opcodes[OP_SET_OBJECT] || c == opcodes[OP_DISPLAY_INFO_LINE] ||
+				c == opcodes[OP_REMOVE_ITEM_FROM_INVENTORY]) {
 				replyP += (*replyP & 127) + 1;
-				break;
 
-			case GOTO_SCENE:
+			} else if (c == opcodes[OP_GOTO_SCENE]) {
 				replyP += 5;
-				break;
 
-			case CARRIAGE_RETURN:
+			} else if (c == opcodes[OP_CARRIAGE_RETURN]) {
 				journalString += "\n";
-				break;
-
-			default:
-				break;
 			}
 
 			// Put a space in the output for a control character, unless it's
 			// immediately coming after another control character
-			if (ctrlSpace && c != ASSIGN_PORTRAIT_LOCATION && c != CARRIAGE_RETURN && !commentJustPrinted) {
+			if (ctrlSpace && c != opcodes[OP_ASSIGN_PORTRAIT_LOCATION] && c != opcodes[OP_CARRIAGE_RETURN] && 
+					!commentJustPrinted) {
 				journalString += " ";
 				ctrlSpace = false;
 			}
diff --git a/engines/sherlock/talk.cpp b/engines/sherlock/talk.cpp
index 1a926a5..7379d04 100644
--- a/engines/sherlock/talk.cpp
+++ b/engines/sherlock/talk.cpp
@@ -28,6 +28,51 @@ namespace Sherlock {
 
 #define SPEAKER_REMOVE 0x80
 
+const byte SCALPEL_OPCODES[] = {
+	128,	// OP_SWITCH_SPEAKER
+	129,	// OP_RUN_CANIMATION
+	130,	// OP_ASSIGN_PORTRAIT_LOCATION
+	131,	// OP_PAUSE
+	132,	// OP_REMOVE_PORTRAIT
+	133,	// OP_CLEAR_WINDOW
+	134,	// OP_ADJUST_OBJ_SEQUENCE
+	135,	// OP_WALK_TO_COORDS
+	136,	// OP_PAUSE_WITHOUT_CONTROL
+	137,	// OP_BANISH_WINDOW
+	138,	// OP_SUMMON_WINDOW
+	139,	// OP_SET_FLAG
+	140,	// OP_SFX_COMMAND
+	141,	// OP_TOGGLE_OBJECT
+	142,	// OP_STEALTH_MODE_ACTIVE
+	143,	// OP_IF_STATEMENT
+	144,	// OP_ELSE_STATEMENT
+	145,	// OP_END_IF_STATEMENT
+	146,	// OP_STEALTH_MODE_DEACTIVATE
+	147,	// OP_TURN_HOLMES_OFF
+	148,	// OP_TURN_HOLMES_ON
+	149,	// OP_GOTO_SCENE
+	150,	// OP_PLAY_PROLOGUE
+	151,	// OP_ADD_ITEM_TO_INVENTORY
+	152,	// OP_SET_OBJECT
+	153,	// OP_CALL_TALK_FILE
+	143,	// OP_MOVE_MOUSE
+	155,	// OP_DISPLAY_INFO_LINE
+	156,	// OP_CLEAR_INFO_LINE
+	157,	// OP_WALK_TO_CANIMATION
+	158,	// OP_REMOVE_ITEM_FROM_INVENTORY
+	159,	// OP_ENABLE_END_KEY
+	160,	// OP_DISABLE_END_KEY
+	161		// OP_CARRIAGE_RETURN
+};
+
+const byte TATTOO_OPCODES[] = {
+	170,	// OP_SWITCH_SPEAKER
+	171,	// OP_RUN_CANIMATION
+	0	// TODO reset of opcodes
+};
+
+/*----------------------------------------------------------------*/
+
 SequenceEntry::SequenceEntry() {
 	_objNum = 0;
 	_frameNumber = 0;
@@ -103,6 +148,7 @@ Talk::Talk(SherlockEngine *vm) : _vm(vm) {
 	_moreTalkDown = _moreTalkUp = false;
 	_scriptMoreFlag = 0;
 	_scriptSaveIndex = -1;
+	_opcodes = IS_SERRATED_SCALPEL ? SCALPEL_OPCODES : TATTOO_OPCODES;
 }
 
 void Talk::talkTo(const Common::String &filename) {
@@ -572,7 +618,7 @@ void Talk::stripVoiceCommands() {
 
 		// Scan for an sound effect byte, which indicates to play a sound
 		for (uint idx = 0; idx < statement._reply.size(); ++idx) {
-			if (statement._reply[idx] == (char)SFX_COMMAND) {
+			if (statement._reply[idx] == (char)_opcodes[OP_SFX_COMMAND]) {
 				// Replace instruction character with a space, and delete the
 				// rest of the name following it
 				statement._reply = Common::String(statement._reply.c_str(),
@@ -952,7 +998,7 @@ void Talk::doScript(const Common::String &script) {
 	}
 
 	// Check if the script begins with a Stealh Mode Active command
-	if (str[0] == STEALTH_MODE_ACTIVE || _talkStealth) {
+	if (str[0] == _opcodes[OP_STEALTH_MODE_ACTIVE] || _talkStealth) {
 		_talkStealth = 2;
 		_speaker |= SPEAKER_REMOVE;
 	} else {
@@ -960,7 +1006,7 @@ void Talk::doScript(const Common::String &script) {
 		ui.clearWindow();
 
 		// Need to switch speakers?
-		if (str[0] == SWITCH_SPEAKER) {
+		if (str[0] == _opcodes[OP_SWITCH_SPEAKER]) {
 			_speaker = str[1] - 1;
 			str += 2;
 			pullSequence();
@@ -971,7 +1017,7 @@ void Talk::doScript(const Common::String &script) {
 		}
 
 		// Assign portrait location?
-		if (str[0] == ASSIGN_PORTRAIT_LOCATION) {
+		if (str[0] == _opcodes[OP_ASSIGN_PORTRAIT_LOCATION]) {
 			switch (str[1] & 15) {
 			case 1:
 				people._portraitSide = 20;
@@ -993,7 +1039,7 @@ void Talk::doScript(const Common::String &script) {
 		}
 
 		// Remove portrait?
-		if (str[0] == REMOVE_PORTRAIT) {
+		if (str[0] == _opcodes[OP_REMOVE_PORTRAIT]) {
 			_speaker = 255;
 		} else {
 			// Nope, so set the first speaker
@@ -1012,10 +1058,9 @@ void Talk::doScript(const Common::String &script) {
 			// Start of comment, so skip over it
 			while (*str++ != '}')
 				;
-		} else if (c >= SWITCH_SPEAKER) {
+		} else if (c >= _opcodes[0]) {
 			// Handle control code
-			switch (c) {
-			case SWITCH_SPEAKER:
+			if (c == _opcodes[OP_SWITCH_SPEAKER]) {
 				if (!(_speaker & SPEAKER_REMOVE))
 					people.clearTalking();
 				if (_talkToAbort)
@@ -1030,20 +1075,18 @@ void Talk::doScript(const Common::String &script) {
 				pullSequence();
 				pushSequence(_speaker);
 				setSequence(_speaker);
-				break;
 
-			case RUN_CANIMATION:
+			} else if (c == _opcodes[OP_RUN_CANIMATION]) {
 				++str;
 				scene.startCAnim((str[0] - 1) & 127, (str[0] & 0x80) ? -1 : 1);
 				if (_talkToAbort)
 					return;
 
 				// Check if next character is changing side or changing portrait
-				if (charCount && (str[1] == SWITCH_SPEAKER || str[1] == ASSIGN_PORTRAIT_LOCATION))
+				if (charCount && (str[1] == _opcodes[OP_SWITCH_SPEAKER] || str[1] == _opcodes[OP_ASSIGN_PORTRAIT_LOCATION]))
 					wait = 1;
-				break;
 
-			case ASSIGN_PORTRAIT_LOCATION:
+			} else if (c == _opcodes[OP_ASSIGN_PORTRAIT_LOCATION]) {
 				++str;
 				switch (str[0] & 15) {
 				case 1:
@@ -1061,15 +1104,13 @@ void Talk::doScript(const Common::String &script) {
 
 				if (str[0] > 15)
 					people._speakerFlip = true;
-				break;
 
-			case PAUSE:
+			} else if (c == _opcodes[OP_PAUSE]) {
 				// Pause
 				charCount = *++str;
 				wait = pauseFlag = true;
-				break;
 
-			case REMOVE_PORTRAIT:
+			} else if (c == _opcodes[OP_REMOVE_PORTRAIT]) {
 				if (_speaker >= 0 && _speaker < SPEAKER_REMOVE)
 					people.clearTalking();
 				pullSequence();
@@ -1077,16 +1118,13 @@ void Talk::doScript(const Common::String &script) {
 					return;
 
 				_speaker |= SPEAKER_REMOVE;
-				break;
 
-			case CLEAR_WINDOW:
+			} else if (c == _opcodes[OP_CLEAR_WINDOW]) {
 				ui.clearWindow();
 				yp = CONTROLS_Y + 12;
 				charCount = line = 0;
-				break;
 
-			case ADJUST_OBJ_SEQUENCE:
-				{
+			} else if (c == _opcodes[OP_ADJUST_OBJ_SEQUENCE]) {
 				// Get the name of the object to adjust
 				++str;
 				for (int idx = 0; idx < (str[0] & 127); ++idx)
@@ -1123,9 +1161,8 @@ void Talk::doScript(const Common::String &script) {
 				// Reset object back to beginning of new sequence
 				scene._bgShapes[objId]._frameNumber = 0;
 				continue;
-				}
 
-			case WALK_TO_COORDS:
+			} else if (c == _opcodes[OP_WALK_TO_COORDS]) {
 				++str;
 
 				people.walkToCoords(Common::Point(((str[0] - 1) * 256 + str[1] - 1) * 100,
@@ -1134,9 +1171,8 @@ void Talk::doScript(const Common::String &script) {
 					return;
 
 				str += 3;
-				break;
-
-			case PAUSE_WITHOUT_CONTROL:
+			
+			} else if (c == _opcodes[OP_PAUSE_WITHOUT_CONTROL]) {
 				++str;
 
 				for (int idx = 0; idx < (str[0] - 1); ++idx) {
@@ -1148,9 +1184,8 @@ void Talk::doScript(const Common::String &script) {
 					events.pollEvents();
 					events.setButtonState();
 				}
-				break;
 
-			case BANISH_WINDOW:
+			} else if (c == _opcodes[OP_BANISH_WINDOW]) {
 				if (!(_speaker & SPEAKER_REMOVE))
 					people.clearTalking();
 				pullSequence();
@@ -1162,9 +1197,8 @@ void Talk::doScript(const Common::String &script) {
 				ui.banishWindow();
 				ui._menuMode = TALK_MODE;
 				noTextYet = true;
-				break;
-
-			case SUMMON_WINDOW:
+				
+			} else if (c == _opcodes[OP_SUMMON_WINDOW]) {
 				drawInterface();
 				events._pressed = events._released = false;
 				events.clearKeyboard();
@@ -1175,18 +1209,15 @@ void Talk::doScript(const Common::String &script) {
 					screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, false, "Up");
 					screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, false, "Down");
 				}
-				break;
 
-			case SET_FLAG: {
+			} else if (c == _opcodes[OP_SET_FLAG]) {
 				++str;
 				int flag1 = (str[0] - 1) * 256 + str[1] - 1 - (str[1] == 1 ? 1 : 0);
 				int flag = (flag1 & 0x3fff) * (flag1 >= 0x4000 ? -1 : 1);
 				_vm->setFlags(flag);
 				++str;
-				break;
-			}
 
-			case SFX_COMMAND:
+			} else if (c == _opcodes[OP_SFX_COMMAND]) {
 				++str;
 				if (sound._voices) {
 					for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx)
@@ -1200,22 +1231,19 @@ void Talk::doScript(const Common::String &script) {
 
 				wait = 1;
 				str += 7;
-				break;
-
-			case TOGGLE_OBJECT:
+				
+			} else if (c == _opcodes[OP_TOGGLE_OBJECT]) {
 				++str;
 				for (int idx = 0; idx < str[0]; ++idx)
 					tempString += str[idx + 1];
 
 				scene.toggleObject(tempString);
 				str += str[0];
-				break;
-
-			case STEALTH_MODE_ACTIVE:
+				
+			} else if (c == _opcodes[OP_STEALTH_MODE_ACTIVE]) {
 				_talkStealth = 2;
-				break;
 
-			case IF_STATEMENT: {
+			} else if (c == _opcodes[OP_IF_STATEMENT]) {
 				++str;
 				int flag = (str[0] - 1) * 256 + str[1] - 1 - (str[1] == 1 ? 1 : 0);
 				++str;
@@ -1225,38 +1253,32 @@ void Talk::doScript(const Common::String &script) {
 				if (_vm->readFlags(flag & 0x7fff) != result) {
 					do {
 						++str;
-					} while (str[0] && str[0] != ELSE_STATEMENT && str[0] != END_IF_STATEMENT);
+					} while (str[0] && str[0] != _opcodes[OP_ELSE_STATEMENT] && str[0] != _opcodes[OP_END_IF_STATEMENT]);
 
 					if (!str[0])
 						endStr = true;
 				}
-				break;
-			}
 
-			case ELSE_STATEMENT:
+			} else if (c == _opcodes[OP_ELSE_STATEMENT]) {
 				// If this is encountered here, it means that a preceeding IF statement was found,
 				// and evaluated to true. Now all the statements for the true block are finished,
 				// so skip over the block of code that would have executed if the result was false
 				wait = 0;
 				do {
 					++str;
-				} while (str[0] && str[0] != END_IF_STATEMENT);
-				break;
+				} while (str[0] && str[0] != _opcodes[OP_END_IF_STATEMENT]);
 
-			case STEALTH_MODE_DEACTIVATE:
+			} else if (c == _opcodes[OP_STEALTH_MODE_DEACTIVATE]) {
 				_talkStealth = 0;
 				events.clearKeyboard();
-				break;
-
-			case TURN_HOLMES_OFF:
+				
+			} else if (c == _opcodes[OP_TURN_HOLMES_OFF]) {
 				people._holmesOn = false;
-				break;
-
-			case TURN_HOLMES_ON:
+				
+			} else if (c == _opcodes[OP_TURN_HOLMES_ON]) {
 				people._holmesOn = true;
-				break;
 
-			case GOTO_SCENE:
+			} else if (c == _opcodes[OP_GOTO_SCENE]) {
 				scene._goToScene = str[1] - 1;
 
 				if (scene._goToScene != 100) {
@@ -1277,26 +1299,23 @@ void Talk::doScript(const Common::String &script) {
 				_scriptSaveIndex = str - scriptStart;
 				endStr = true;
 				wait = 0;
-				break;
-
-			case PLAY_PROLOGUE:
+				
+			} else if (c == _opcodes[OP_PLAY_PROLOGUE]) {
 				++str;
 				for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx)
 					tempString += str[idx];
 
 				anim.play(tempString, 1, 3, true, 4);
-				break;
-
-			case ADD_ITEM_TO_INVENTORY:
+				
+			} else if (c == _opcodes[OP_ADD_ITEM_TO_INVENTORY]) {
 				++str;
 				for (int idx = 0; idx < str[0]; ++idx)
 					tempString += str[idx + 1];
 				str += str[0];
 
 				inv.putNameInInventory(tempString);
-				break;
-
-			case SET_OBJECT: {
+				
+			} else if (c == _opcodes[OP_SET_OBJECT]) {
 				++str;
 				for (int idx = 0; idx < (str[0] & 127); ++idx)
 					tempString += str[idx + 1];
@@ -1313,10 +1332,8 @@ void Talk::doScript(const Common::String &script) {
 							object.toggleHidden();
 					}
 				}
-				break;
-			}
-
-			case CALL_TALK_FILE: {
+				
+			} else if (c == _opcodes[OP_CALL_TALK_FILE]) {
 				++str;
 				for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx)
 					tempString += str[idx];
@@ -1345,18 +1362,15 @@ void Talk::doScript(const Common::String &script) {
 				_scriptMoreFlag = 1;
 				endStr = true;
 				wait = 0;
-				break;
-			}
-
-			case MOVE_MOUSE:
+				
+			} else if (c == _opcodes[OP_MOVE_MOUSE]) {
 				++str;
 				events.moveMouse(Common::Point((str[0] - 1) * 256 + str[1] - 1, str[2]));
 				if (_talkToAbort)
 					return;
 				str += 3;
-				break;
-
-			case DISPLAY_INFO_LINE:
+				
+			} else if (c == _opcodes[OP_DISPLAY_INFO_LINE]) {
 				++str;
 				for (int idx = 0; idx < str[0]; ++idx)
 					tempString += str[idx + 1];
@@ -1364,42 +1378,35 @@ void Talk::doScript(const Common::String &script) {
 
 				screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", tempString.c_str());
 				ui._menuCounter = 30;
-				break;
-
-			case CLEAR_INFO_LINE:
+				
+			} else if (c == _opcodes[OP_CLEAR_INFO_LINE]) {
 				ui._infoFlag = true;
 				ui.clearInfo();
-				break;
-
-			case WALK_TO_CANIMATION: {
+				
+			} else if (c == _opcodes[OP_WALK_TO_CANIMATION]) {
 				++str;
 				CAnim &animation = scene._cAnim[str[0] - 1];
 
 				people.walkToCoords(animation._goto, animation._gotoDir);
 				if (_talkToAbort)
 					return;
-				break;
-			}
-
-			case REMOVE_ITEM_FROM_INVENTORY:
+				
+			} else if (c == _opcodes[OP_REMOVE_ITEM_FROM_INVENTORY]) {
 				++str;
 				for (int idx = 0; idx < str[0]; ++idx)
 					tempString += str[idx + 1];
 				str += str[0];
 
 				inv.deleteItemFromInventory(tempString);
-				break;
-
-			case ENABLE_END_KEY:
+				
+			} else if (c == _opcodes[OP_ENABLE_END_KEY]) {
 				ui._endKeyActive = true;
-				break;
-
-			case DISABLE_END_KEY:
+				
+			} else if (c == _opcodes[OP_DISABLE_END_KEY]) {
 				ui._endKeyActive = false;
-				break;
-
-			default:
-				break;
+				
+			} else {
+				error("Unknown opcode encountered");
 			}
 
 			++str;
@@ -1438,10 +1445,10 @@ void Talk::doScript(const Common::String &script) {
 				width += screen.charWidth(str[idx]);
 				++idx;
 				++charCount;
-			} while (width < 298 && str[idx] && str[idx] != '{' && str[idx] < SWITCH_SPEAKER);
+			} while (width < 298 && str[idx] && str[idx] != '{' && str[idx] < _opcodes[0]);
 
 			if (str[idx] || width >= 298) {
-				if (str[idx] < SWITCH_SPEAKER && str[idx] != '{') {
+				if (str[idx] < _opcodes[0] && str[idx] != '{') {
 					--idx;
 					--charCount;
 				}
@@ -1481,37 +1488,27 @@ void Talk::doScript(const Common::String &script) {
 			str += idx;
 
 			// If line wrap occurred, then move to after the separating space between the words
-			if (str[0] < SWITCH_SPEAKER && str[0] != '{')
+			if (str[0] < _opcodes[0] && str[0] != '{')
 				++str;
 
 			yp += 9;
 			++line;
 
 			// Certain different conditions require a wait
-			if ((line == 4 && str < scriptEnd && str[0] != SFX_COMMAND && str[0] != PAUSE && _speaker != -1) ||
-					(line == 5 && str < scriptEnd && str[0] != PAUSE && _speaker == -1) ||
+			if ((line == 4 && str < scriptEnd && str[0] != _opcodes[OP_SFX_COMMAND] && str[0] != _opcodes[OP_PAUSE] && _speaker != -1) ||
+					(line == 5 && str < scriptEnd && str[0] != _opcodes[OP_PAUSE] && _speaker == -1) ||
 					endStr) {
 				wait = 1;
 			}
 
-			switch (str >= scriptEnd ? 0 : str[0]) {
-			case SWITCH_SPEAKER:
-			case ASSIGN_PORTRAIT_LOCATION:
-			case BANISH_WINDOW:
-			case IF_STATEMENT:
-			case ELSE_STATEMENT:
-			case END_IF_STATEMENT:
-			case GOTO_SCENE:
-			case CALL_TALK_FILE:
-				wait = 1;
-				break;
-			default:
-				break;
-			}
+			byte v = (str >= scriptEnd ? 0 : str[0]);
+			wait = v == _opcodes[OP_SWITCH_SPEAKER] || v == _opcodes[OP_ASSIGN_PORTRAIT_LOCATION] ||
+				v == _opcodes[OP_BANISH_WINDOW] || _opcodes[OP_IF_STATEMENT] || v == _opcodes[OP_ELSE_STATEMENT] ||
+				v == _opcodes[OP_END_IF_STATEMENT] || v == _opcodes[OP_GOTO_SCENE] || v == _opcodes[OP_CALL_TALK_FILE];
 		}
 
 		// Open window if it wasn't already open, and text has already been printed
-		if ((openTalkWindow && wait) || (openTalkWindow && str[0] >= SWITCH_SPEAKER && str[0] != CARRIAGE_RETURN)) {
+		if ((openTalkWindow && wait) || (openTalkWindow && str[0] >= _opcodes[0] && str[0] != _opcodes[OP_CARRIAGE_RETURN])) {
 			if (!ui._slideWindows) {
 				screen.slamRect(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
 			} else {
@@ -1533,12 +1530,12 @@ void Talk::doScript(const Common::String &script) {
 
 			// If a key was pressed to finish the window, see if further voice files should be skipped
 			if (wait >= 0 && wait < 254) {
-				if (str[0] == SFX_COMMAND)
+				if (str[0] == _opcodes[OP_SFX_COMMAND])
 					str += 9;
 			}
 
 			// Clear the window unless the wait was due to a PAUSE command
-			if (!pauseFlag && wait != -1 && str < scriptEnd && str[0] != SFX_COMMAND) {
+			if (!pauseFlag && wait != -1 && str < scriptEnd && str[0] != _opcodes[OP_SFX_COMMAND]) {
 				if (!_talkStealth)
 					ui.clearWindow();
 				yp = CONTROLS_Y + 12;
diff --git a/engines/sherlock/talk.h b/engines/sherlock/talk.h
index 48290e9..bead679 100644
--- a/engines/sherlock/talk.h
+++ b/engines/sherlock/talk.h
@@ -36,42 +36,43 @@ namespace Sherlock {
 #define MAX_TALK_FILES 500
 
 enum {
-	SWITCH_SPEAKER				= 128,
-	RUN_CANIMATION				= 129,
-	ASSIGN_PORTRAIT_LOCATION	= 130,
-	PAUSE						= 131,
-	REMOVE_PORTRAIT				= 132,
-	CLEAR_WINDOW				= 133,
-	ADJUST_OBJ_SEQUENCE			= 134,
-	WALK_TO_COORDS				= 135,
-	PAUSE_WITHOUT_CONTROL		= 136,
-	BANISH_WINDOW				= 137,
-	SUMMON_WINDOW				= 138,
-	SET_FLAG					= 139,
-	SFX_COMMAND					= 140,
-	TOGGLE_OBJECT				= 141,
-	STEALTH_MODE_ACTIVE			= 142,
-	IF_STATEMENT				= 143,
-	ELSE_STATEMENT				= 144,
-	END_IF_STATEMENT			= 145,
-	STEALTH_MODE_DEACTIVATE		= 146,
-	TURN_HOLMES_OFF				= 147,
-	TURN_HOLMES_ON				= 148,
-	GOTO_SCENE					= 149,
-	PLAY_PROLOGUE				= 150,
-	ADD_ITEM_TO_INVENTORY		= 151,
-	SET_OBJECT					= 152,
-	CALL_TALK_FILE				= 153,
-	MOVE_MOUSE					= 154,
-	DISPLAY_INFO_LINE			= 155,
-	CLEAR_INFO_LINE				= 156,
-	WALK_TO_CANIMATION			= 157,
-	REMOVE_ITEM_FROM_INVENTORY	= 158,
-	ENABLE_END_KEY				= 159,
-	DISABLE_END_KEY				= 160,
-	CARRIAGE_RETURN				= 161
+	OP_SWITCH_SPEAKER				= 128,
+	OP_RUN_CANIMATION = 129,
+	OP_ASSIGN_PORTRAIT_LOCATION = 130,
+	OP_PAUSE = 131,
+	OP_REMOVE_PORTRAIT = 132,
+	OP_CLEAR_WINDOW = 133,
+	OP_ADJUST_OBJ_SEQUENCE = 134,
+	OP_WALK_TO_COORDS = 135,
+	OP_PAUSE_WITHOUT_CONTROL = 136,
+	OP_BANISH_WINDOW = 137,
+	OP_SUMMON_WINDOW = 138,
+	OP_SET_FLAG = 139,
+	OP_SFX_COMMAND = 140,
+	OP_TOGGLE_OBJECT = 141,
+	OP_STEALTH_MODE_ACTIVE = 142,
+	OP_IF_STATEMENT = 143,
+	OP_ELSE_STATEMENT = 144,
+	OP_END_IF_STATEMENT = 145,
+	OP_STEALTH_MODE_DEACTIVATE = 146,
+	OP_TURN_HOLMES_OFF = 147,
+	OP_TURN_HOLMES_ON = 148,
+	OP_GOTO_SCENE = 149,
+	OP_PLAY_PROLOGUE = 150,
+	OP_ADD_ITEM_TO_INVENTORY = 151,
+	OP_SET_OBJECT = 152,
+	OP_CALL_TALK_FILE = 153,
+	OP_MOVE_MOUSE = 154,
+	OP_DISPLAY_INFO_LINE = 155,
+	OP_CLEAR_INFO_LINE = 156,
+	OP_WALK_TO_CANIMATION = 157,
+	OP_REMOVE_ITEM_FROM_INVENTORY = 158,
+	OP_ENABLE_END_KEY = 159,
+	OP_DISABLE_END_KEY = 160,
+	OP_CARRIAGE_RETURN = 161
 };
 
+
 struct SequenceEntry {
 	int _objNum;
 	Common::Array<byte> _sequences;
@@ -181,6 +182,7 @@ public:
 	Common::String _scriptName;
 	bool _moreTalkUp, _moreTalkDown;
 	int _converseNum;
+	const byte *_opcodes;
 public:
 	Talk(SherlockEngine *vm);
 


Commit: c7749f8c22168560d99f7269c9428ac6e8d057eb
    https://github.com/scummvm/scummvm/commit/c7749f8c22168560d99f7269c9428ac6e8d057eb
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-24T15:17:05-04:00

Commit Message:
SHERLOCK: Fully implemented RT opcodes array

Changed paths:
    engines/sherlock/talk.cpp
    engines/sherlock/talk.h



diff --git a/engines/sherlock/talk.cpp b/engines/sherlock/talk.cpp
index 7379d04..bc473f7 100644
--- a/engines/sherlock/talk.cpp
+++ b/engines/sherlock/talk.cpp
@@ -62,13 +62,109 @@ const byte SCALPEL_OPCODES[] = {
 	158,	// OP_REMOVE_ITEM_FROM_INVENTORY
 	159,	// OP_ENABLE_END_KEY
 	160,	// OP_DISABLE_END_KEY
-	161		// OP_CARRIAGE_RETURN
+	161,	// OP_CARRIAGE_RETURN
+	0,		// OP_MOUSE_ON_OFF
+	0,		// OP_SET_WALK_CONTROL
+	0,		// OP_SET_TALK_SEQUENCE
+	0,		// OP_PLAY_SONG
+	0,		// OP_WALK_HOLMES_AND_NPC_TO_CANIM
+	0,		// OP_SET_NPC_PATH_DEST
+	0,		// OP_NEXT_SONG
+	0,		// OP_SET_NPC_PATH_PAUSE
+	0,		// OP_PASSWORD
+	0,		// OP_SET_SCENE_ENTRY_FLAG
+	0,		// OP_WALK_NPC_TO_CANIM
+	0,		// OP_WALK_HOLMES_AND_NPC_TO_COORDS
+	0,		// OP_WALK_HOLMES_AND_NPC_TO_COORDS
+	0,		// OP_SET_NPC_TALK_FILE
+	0,		// OP_TURN_NPC_OFF
+	0,		// OP_TURN_NPC_ON
+	0,		// OP_NPC_DESC_ON_OFF
+	0,		// OP_NPC_PATH_PAUSE_TAKING_NOTES
+	0,		// OP_NPC_PATH_PAUSE_LOOKING_HOLMES
+	0,		// OP_ENABLE_TALK_INTERRUPTS
+	0,		// OP_DISABLE_TALK_INTERRUPTS
+	0,		// OP_SET_NPC_INFO_LINE
+	0,		// OP_SET_NPC_POSITION
+	0,		// OP_NPC_PATH_LABEL
+	0,		// OP_PATH_GOTO_LABEL
+	0,		// OP_PATH_IF_FLAG_GOTO_LABEL
+	0,		// OP_NPC_WALK_GRAPHICS
+	0,		// OP_NPC_VERB
+	0,		// OP_NPC_VERB_CANIM
+	0,		// OP_NPC_VERB_SCRIPT
+	0,		// OP_RESTORE_PEOPLE_SEQUENCE
+	0,		// OP_NPC_VERB_TARGET
+	0		// OP_TURN_SOUNDS_OFF
 };
 
 const byte TATTOO_OPCODES[] = {
 	170,	// OP_SWITCH_SPEAKER
 	171,	// OP_RUN_CANIMATION
-	0	// TODO reset of opcodes
+	0,	// OP_ASSIGN_PORTRAIT_LOCATION
+	173,	// OP_PAUSE
+	0,	// OP_REMOVE_PORTRAIT
+	0,	// OP_CLEAR_WINDOW
+	176,	// OP_ADJUST_OBJ_SEQUENCE
+	177,	// OP_WALK_TO_COORDS
+	178,	// OP_PAUSE_WITHOUT_CONTROL
+	179,	// OP_BANISH_WINDOW
+	0,		// OP_SUMMON_WINDOW
+	181,	// OP_SET_FLAG
+	0,		// OP_SFX_COMMAND
+	183,	// OP_TOGGLE_OBJECT
+	184,	// OP_STEALTH_MODE_ACTIVE
+	0,		// OP_IF_STATEMENT
+	0,		// OP_ELSE_STATEMENT
+	0,		// OP_END_IF_STATEMENT
+	188,	// OP_STEALTH_MODE_DEACTIVATE
+	189,	// OP_TURN_HOLMES_OFF
+	190,	// OP_TURN_HOLMES_ON
+	191,	// OP_GOTO_SCENE
+	0,		// OP_PLAY_PROLOGUE
+	193,	// OP_ADD_ITEM_TO_INVENTORY
+	194,	// OP_SET_OBJECT
+	172,	// OP_CALL_TALK_FILE
+	0,		// OP_MOVE_MOUSE
+	0,		// OP_DISPLAY_INFO_LINE
+	0,		// OP_CLEAR_INFO_LINE
+	199,	// OP_WALK_TO_CANIMATION
+	200,	// OP_REMOVE_ITEM_FROM_INVENTORY
+	201,	// OP_ENABLE_END_KEY
+	202,	// OP_DISABLE_END_KEY
+	0,		// OP_CARRIAGE_RETURN
+	174,	// OP_MOUSE_ON_OFF
+	175,	// OP_SET_WALK_CONTROL
+	180,	// OP_SET_TALK_SEQUENCE
+	182,	// OP_PLAY_SONG
+	187,	// OP_WALK_HOLMES_AND_NPC_TO_CANIM
+	192,	// OP_SET_NPC_PATH_DEST
+	195,	// OP_NEXT_SONG
+	196,	// OP_SET_NPC_PATH_PAUSE
+	197,	// OP_PASSWORD
+	198,	// OP_SET_SCENE_ENTRY_FLAG
+	185,	// OP_WALK_NPC_TO_CANIM
+	204,	// OP_WALK_HOLMES_AND_NPC_TO_COORDS
+	205,	// OP_SET_NPC_TALK_FILE
+	206,	// OP_TURN_NPC_OFF
+	207,	// OP_TURN_NPC_ON
+	208,	// OP_NPC_DESC_ON_OFF
+	209,	// OP_NPC_PATH_PAUSE_TAKING_NOTES
+	210,	// OP_NPC_PATH_PAUSE_LOOKING_HOLMES
+	211,	// OP_ENABLE_TALK_INTERRUPTS
+	212,	// OP_DISABLE_TALK_INTERRUPTS
+	213,	// OP_SET_NPC_INFO_LINE
+	214,	// OP_SET_NPC_POSITION
+	215,	// OP_NPC_PATH_LABEL
+	216,	// OP_PATH_GOTO_LABEL
+	217,	// OP_PATH_IF_FLAG_GOTO_LABEL
+	218,	// OP_NPC_WALK_GRAPHICS
+	220,	// OP_NPC_VERB
+	221,	// OP_NPC_VERB_CANIM
+	222,	// OP_NPC_VERB_SCRIPT
+	224,	// OP_RESTORE_PEOPLE_SEQUENCE
+	226,	// OP_NPC_VERB_TARGET
+	227		// OP_TURN_SOUNDS_OFF
 };
 
 /*----------------------------------------------------------------*/
diff --git a/engines/sherlock/talk.h b/engines/sherlock/talk.h
index bead679..b30b4ad 100644
--- a/engines/sherlock/talk.h
+++ b/engines/sherlock/talk.h
@@ -36,40 +36,73 @@ namespace Sherlock {
 #define MAX_TALK_FILES 500
 
 enum {
-	OP_SWITCH_SPEAKER				= 128,
-	OP_RUN_CANIMATION = 129,
-	OP_ASSIGN_PORTRAIT_LOCATION = 130,
-	OP_PAUSE = 131,
-	OP_REMOVE_PORTRAIT = 132,
-	OP_CLEAR_WINDOW = 133,
-	OP_ADJUST_OBJ_SEQUENCE = 134,
-	OP_WALK_TO_COORDS = 135,
-	OP_PAUSE_WITHOUT_CONTROL = 136,
-	OP_BANISH_WINDOW = 137,
-	OP_SUMMON_WINDOW = 138,
-	OP_SET_FLAG = 139,
-	OP_SFX_COMMAND = 140,
-	OP_TOGGLE_OBJECT = 141,
-	OP_STEALTH_MODE_ACTIVE = 142,
-	OP_IF_STATEMENT = 143,
-	OP_ELSE_STATEMENT = 144,
-	OP_END_IF_STATEMENT = 145,
-	OP_STEALTH_MODE_DEACTIVATE = 146,
-	OP_TURN_HOLMES_OFF = 147,
-	OP_TURN_HOLMES_ON = 148,
-	OP_GOTO_SCENE = 149,
-	OP_PLAY_PROLOGUE = 150,
-	OP_ADD_ITEM_TO_INVENTORY = 151,
-	OP_SET_OBJECT = 152,
-	OP_CALL_TALK_FILE = 153,
-	OP_MOVE_MOUSE = 154,
-	OP_DISPLAY_INFO_LINE = 155,
-	OP_CLEAR_INFO_LINE = 156,
-	OP_WALK_TO_CANIMATION = 157,
-	OP_REMOVE_ITEM_FROM_INVENTORY = 158,
-	OP_ENABLE_END_KEY = 159,
-	OP_DISABLE_END_KEY = 160,
-	OP_CARRIAGE_RETURN = 161
+	OP_SWITCH_SPEAKER			= 0,
+	OP_RUN_CANIMATION			= 1,
+	OP_ASSIGN_PORTRAIT_LOCATION = 2,
+	OP_PAUSE					= 3,
+	OP_REMOVE_PORTRAIT			= 4,
+	OP_CLEAR_WINDOW				= 5,
+	OP_ADJUST_OBJ_SEQUENCE		= 6,
+	OP_WALK_TO_COORDS			= 7,
+	OP_PAUSE_WITHOUT_CONTROL	= 8,
+	OP_BANISH_WINDOW			= 9,
+	OP_SUMMON_WINDOW			= 10,
+	OP_SET_FLAG					= 11,
+	OP_SFX_COMMAND				= 12,
+	OP_TOGGLE_OBJECT			= 13,
+	OP_STEALTH_MODE_ACTIVE		= 14,
+	OP_IF_STATEMENT				= 15,
+	OP_ELSE_STATEMENT			= 16,
+	OP_END_IF_STATEMENT			= 17,
+	OP_STEALTH_MODE_DEACTIVATE	= 18,
+	OP_TURN_HOLMES_OFF			= 19,
+	OP_TURN_HOLMES_ON			= 20,
+	OP_GOTO_SCENE				= 21,
+	OP_PLAY_PROLOGUE			= 22,
+	OP_ADD_ITEM_TO_INVENTORY	= 23,
+	OP_SET_OBJECT				= 24,
+	OP_CALL_TALK_FILE			= 25,
+	OP_MOVE_MOUSE				= 26,
+	OP_DISPLAY_INFO_LINE		= 27,
+	OP_CLEAR_INFO_LINE			= 28,
+	OP_WALK_TO_CANIMATION		= 29,
+	OP_REMOVE_ITEM_FROM_INVENTORY = 30,
+	OP_ENABLE_END_KEY			= 31,
+	OP_DISABLE_END_KEY			= 32,
+	OP_CARRIAGE_RETURN			= 33,
+	
+	OP_MOUSE_OFF_ON				= 34,
+	OP_SET_WALK_CONTROL			= 35,
+	OP_SET_TALK_SEQUENCE		= 36,
+	OP_PLAY_SONG				= 37,
+	OP_WALK_HOLMES_AND_NPC_TO_CANIM = 38,
+	OP_SET_NPC_PATH_DEST		= 39,
+	OP_NEXT_SONG				= 40,
+	OP_SET_NPC_PATH_PAUSE		= 41,
+	OP_NEED_PASSWORD			= 42,
+	OP_SET_SCENE_ENTRY_FLAG		= 43,
+	OP_WALK_NPC_TO_CANIM		= 44,
+	OP_WALK_HOLMES_AND_NPC_TO_COORDS = 45,
+	OP_SET_NPC_TALK_FILE		= 46,
+	OP_TURN_NPC_OFF				= 47,
+	OP_TURN_NPC_ON				= 48,
+	OP_NPC_DESC_ON_OFF			= 49,
+	OP_NPC_PATH_PAUSE_TAKING_NOTES	= 50,
+	OP_NPC_PATH_PAUSE_LOOKING_HOLMES = 51,
+	OP_ENABLE_TALK_INTERRUPTS	= 52,
+	OP_DISABLE_TALK_INTERRUPTS	= 53,
+	OP_SET_NPC_INFO_LINE		= 54,
+	OP_SET_NPC_POSITION			= 54,
+	OP_NPC_PATH_LABEL			= 55,
+	OP_PATH_GOTO_LABEL			= 56,
+	OP_PATH_IF_FLAG_GOTO_LABEL	= 57,
+	OP_NPC_WALK_GRAPHICS		= 58,
+	OP_NPC_VERB					= 59,
+	OP_NPC_VERB_CANIM			= 60,
+	OP_NPC_VERB_SCRIPT			= 61,
+	OP_RESTORE_PEOPLE_SEQUENCE	= 62,
+	OP_NPC_VERB_TARGET			= 63,
+	OP_TURN_SOUNDS_OFF			= 64
 };
 
 


Commit: 5a670cd024418ef06fe9aeea6cbee43365365d1c
    https://github.com/scummvm/scummvm/commit/5a670cd024418ef06fe9aeea6cbee43365365d1c
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-24T18:59:25-04:00

Commit Message:
SHERLOCK: Splitting Talk up to implement individual opcode methods

Changed paths:
    engines/sherlock/sherlock.cpp
    engines/sherlock/talk.cpp
    engines/sherlock/talk.h



diff --git a/engines/sherlock/sherlock.cpp b/engines/sherlock/sherlock.cpp
index 5973823..14f2433 100644
--- a/engines/sherlock/sherlock.cpp
+++ b/engines/sherlock/sherlock.cpp
@@ -95,7 +95,7 @@ void SherlockEngine::initialize() {
 	_scene = new Scene(this);
 	_screen = new Screen(this);
 	_sound = new Sound(this, _mixer);
-	_talk = new Talk(this);
+	_talk = Talk::init(this);
 	_ui = UserInterface::init(this);
 
 	// Load game settings
diff --git a/engines/sherlock/talk.cpp b/engines/sherlock/talk.cpp
index bc473f7..9b22ee1 100644
--- a/engines/sherlock/talk.cpp
+++ b/engines/sherlock/talk.cpp
@@ -231,6 +231,13 @@ void TalkSequences::clear() {
 
 /*----------------------------------------------------------------*/
 
+Talk *Talk::init(SherlockEngine *vm) {
+	if (vm->getGameID() == GType_SerratedScalpel)
+		return new ScalpelTalk(vm);
+	else
+		return new TattooTalk(vm);
+}
+
 Talk::Talk(SherlockEngine *vm) : _vm(vm) {
 	_talkCounter = 0;
 	_talkToAbort = false;
@@ -245,6 +252,14 @@ Talk::Talk(SherlockEngine *vm) : _vm(vm) {
 	_scriptMoreFlag = 0;
 	_scriptSaveIndex = -1;
 	_opcodes = IS_SERRATED_SCALPEL ? SCALPEL_OPCODES : TATTOO_OPCODES;
+
+	_charCount = 0;
+	_line = 0;
+	_yp = 0;
+	_wait = 0;
+	_pauseFlag = false;
+	_seqCount = 0;
+	_scriptStart = _scriptEnd = nullptr;
 }
 
 void Talk::talkTo(const Common::String &filename) {
@@ -1063,34 +1078,29 @@ void Talk::setStillSeq(int speaker) {
 }
 
 void Talk::doScript(const Common::String &script) {
-	Animation &anim = *_vm->_animation;
-	Events &events = *_vm->_events;
-	Inventory &inv = *_vm->_inventory;
-	Map &map = *_vm->_map;
 	People &people = *_vm->_people;
 	Scene &scene = *_vm->_scene;
 	Screen &screen = *_vm->_screen;
-	Sound &sound = *_vm->_sound;
 	UserInterface &ui = *_vm->_ui;
-	int wait = 0;
-	bool pauseFlag = false;
-	bool endStr = false;
-	int yp = CONTROLS_Y + 12;
-	int charCount = 0;
-	int line = 0;
-	bool noTextYet = true;
 	bool openTalkWindow = false;
-	int seqCount;
 
 	_savedSequences.clear();
 
-	const byte *scriptStart = (const byte *)script.c_str();
-	const byte *scriptEnd = scriptStart + script.size();
-	const byte *str = scriptStart;
+	_scriptStart = (const byte *)script.c_str();
+	_scriptEnd = _scriptStart + script.size();
+	const byte *str = _scriptStart;
+	_yp = CONTROLS_Y + 12;
+	_charCount = 0;
+	_line = 0;
+	_wait = 0;
+	_pauseFlag = false;
+	_seqCount = 0;
+	_noTextYet = true;
+	_endStr = false;
 
 	if (_scriptMoreFlag) {
 		_scriptMoreFlag = 0;
-		str = scriptStart + _scriptSaveIndex;
+		str = _scriptStart + _scriptSaveIndex;
 	}
 
 	// Check if the script begins with a Stealh Mode Active command
@@ -1145,371 +1155,31 @@ void Talk::doScript(const Common::String &script) {
 
 	do {
 		Common::String tempString;
-		wait = 0;
+		_wait = 0;
 
 		byte c = str[0];
 		if (!c) {
-			endStr = true;
+			_endStr = true;
 		} else if (c == '{') {
 			// Start of comment, so skip over it
 			while (*str++ != '}')
 				;
-		} else if (c >= _opcodes[0]) {
+		} else if (_opcodeTable[c]) {
 			// Handle control code
-			if (c == _opcodes[OP_SWITCH_SPEAKER]) {
-				if (!(_speaker & SPEAKER_REMOVE))
-					people.clearTalking();
-				if (_talkToAbort)
-					return;
-
-				ui.clearWindow();
-				yp = CONTROLS_Y + 12;
-				charCount = line = 0;
-
-				_speaker = *++str - 1;
-				people.setTalking(_speaker);
-				pullSequence();
-				pushSequence(_speaker);
-				setSequence(_speaker);
-
-			} else if (c == _opcodes[OP_RUN_CANIMATION]) {
-				++str;
-				scene.startCAnim((str[0] - 1) & 127, (str[0] & 0x80) ? -1 : 1);
-				if (_talkToAbort)
-					return;
-
-				// Check if next character is changing side or changing portrait
-				if (charCount && (str[1] == _opcodes[OP_SWITCH_SPEAKER] || str[1] == _opcodes[OP_ASSIGN_PORTRAIT_LOCATION]))
-					wait = 1;
-
-			} else if (c == _opcodes[OP_ASSIGN_PORTRAIT_LOCATION]) {
-				++str;
-				switch (str[0] & 15) {
-				case 1:
-					people._portraitSide = 20;
-					break;
-				case 2:
-					people._portraitSide = 220;
-					break;
-				case 3:
-					people._portraitSide = 120;
-					break;
-				default:
-					break;
-				}
-
-				if (str[0] > 15)
-					people._speakerFlip = true;
-
-			} else if (c == _opcodes[OP_PAUSE]) {
-				// Pause
-				charCount = *++str;
-				wait = pauseFlag = true;
-
-			} else if (c == _opcodes[OP_REMOVE_PORTRAIT]) {
-				if (_speaker >= 0 && _speaker < SPEAKER_REMOVE)
-					people.clearTalking();
-				pullSequence();
-				if (_talkToAbort)
-					return;
-
-				_speaker |= SPEAKER_REMOVE;
-
-			} else if (c == _opcodes[OP_CLEAR_WINDOW]) {
-				ui.clearWindow();
-				yp = CONTROLS_Y + 12;
-				charCount = line = 0;
-
-			} else if (c == _opcodes[OP_ADJUST_OBJ_SEQUENCE]) {
-				// Get the name of the object to adjust
-				++str;
-				for (int idx = 0; idx < (str[0] & 127); ++idx)
-					tempString += str[idx + 2];
-
-				// Scan for object
-				int objId = -1;
-				for (uint idx = 0; idx < scene._bgShapes.size(); ++idx) {
-					if (tempString.equalsIgnoreCase(scene._bgShapes[idx]._name))
-						objId = idx;
-				}
-				if (objId == -1)
-					error("Could not find object %s to change", tempString.c_str());
-
-				// Should the script be overwritten?
-				if (str[0] > 0x80) {
-					// Save the current sequence
-					_savedSequences.push(SequenceEntry());
-					SequenceEntry &seqEntry = _savedSequences.top();
-					seqEntry._objNum = objId;
-					seqEntry._seqTo = scene._bgShapes[objId]._seqTo;
-					for (uint idx = 0; idx < scene._bgShapes[objId]._seqSize; ++idx)
-						seqEntry._sequences.push_back(scene._bgShapes[objId]._sequences[idx]);
-				}
-
-				// Get number of bytes to change
-				seqCount = str[1];
-				str += (str[0] & 127) + 2;
-
-				// Copy in the new sequence
-				for (int idx = 0; idx < seqCount; ++idx, ++str)
-					scene._bgShapes[objId]._sequences[idx] = str[0] - 1;
-
-				// Reset object back to beginning of new sequence
-				scene._bgShapes[objId]._frameNumber = 0;
+			switch ((this->*_opcodeTable[c - 128])(str)) {
+			case RET_EXIT:
+				return;
+			case RET_CONTINUE:
 				continue;
-
-			} else if (c == _opcodes[OP_WALK_TO_COORDS]) {
-				++str;
-
-				people.walkToCoords(Common::Point(((str[0] - 1) * 256 + str[1] - 1) * 100,
-					str[2] * 100), str[3] - 1);
-				if (_talkToAbort)
-					return;
-
-				str += 3;
-			
-			} else if (c == _opcodes[OP_PAUSE_WITHOUT_CONTROL]) {
-				++str;
-
-				for (int idx = 0; idx < (str[0] - 1); ++idx) {
-					scene.doBgAnim();
-					if (_talkToAbort)
-						return;
-
-					// Check for button press
-					events.pollEvents();
-					events.setButtonState();
-				}
-
-			} else if (c == _opcodes[OP_BANISH_WINDOW]) {
-				if (!(_speaker & SPEAKER_REMOVE))
-					people.clearTalking();
-				pullSequence();
-
-				if (_talkToAbort)
-					return;
-
-				_speaker |= SPEAKER_REMOVE;
-				ui.banishWindow();
-				ui._menuMode = TALK_MODE;
-				noTextYet = true;
-				
-			} else if (c == _opcodes[OP_SUMMON_WINDOW]) {
-				drawInterface();
-				events._pressed = events._released = false;
-				events.clearKeyboard();
-				noTextYet = false;
-
-				if (_speaker != -1) {
-					screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_NULL, false, "Exit");
-					screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, false, "Up");
-					screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, false, "Down");
-				}
-
-			} else if (c == _opcodes[OP_SET_FLAG]) {
-				++str;
-				int flag1 = (str[0] - 1) * 256 + str[1] - 1 - (str[1] == 1 ? 1 : 0);
-				int flag = (flag1 & 0x3fff) * (flag1 >= 0x4000 ? -1 : 1);
-				_vm->setFlags(flag);
-				++str;
-
-			} else if (c == _opcodes[OP_SFX_COMMAND]) {
-				++str;
-				if (sound._voices) {
-					for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx)
-						tempString += str[idx];
-					sound.playSound(tempString, WAIT_RETURN_IMMEDIATELY);
-
-					// Set voices to wait for more
-					sound._voices = 2;
-					sound._speechOn = (*sound._soundIsOn);
-				}
-
-				wait = 1;
-				str += 7;
-				
-			} else if (c == _opcodes[OP_TOGGLE_OBJECT]) {
-				++str;
-				for (int idx = 0; idx < str[0]; ++idx)
-					tempString += str[idx + 1];
-
-				scene.toggleObject(tempString);
-				str += str[0];
-				
-			} else if (c == _opcodes[OP_STEALTH_MODE_ACTIVE]) {
-				_talkStealth = 2;
-
-			} else if (c == _opcodes[OP_IF_STATEMENT]) {
-				++str;
-				int flag = (str[0] - 1) * 256 + str[1] - 1 - (str[1] == 1 ? 1 : 0);
-				++str;
-				wait = 0;
-
-				bool result = flag < 0x8000;
-				if (_vm->readFlags(flag & 0x7fff) != result) {
-					do {
-						++str;
-					} while (str[0] && str[0] != _opcodes[OP_ELSE_STATEMENT] && str[0] != _opcodes[OP_END_IF_STATEMENT]);
-
-					if (!str[0])
-						endStr = true;
-				}
-
-			} else if (c == _opcodes[OP_ELSE_STATEMENT]) {
-				// If this is encountered here, it means that a preceeding IF statement was found,
-				// and evaluated to true. Now all the statements for the true block are finished,
-				// so skip over the block of code that would have executed if the result was false
-				wait = 0;
-				do {
-					++str;
-				} while (str[0] && str[0] != _opcodes[OP_END_IF_STATEMENT]);
-
-			} else if (c == _opcodes[OP_STEALTH_MODE_DEACTIVATE]) {
-				_talkStealth = 0;
-				events.clearKeyboard();
-				
-			} else if (c == _opcodes[OP_TURN_HOLMES_OFF]) {
-				people._holmesOn = false;
-				
-			} else if (c == _opcodes[OP_TURN_HOLMES_ON]) {
-				people._holmesOn = true;
-
-			} else if (c == _opcodes[OP_GOTO_SCENE]) {
-				scene._goToScene = str[1] - 1;
-
-				if (scene._goToScene != 100) {
-					// Not going to the map overview
-					map._oldCharPoint = scene._goToScene;
-					map._overPos.x = map[scene._goToScene].x * 100 - 600;
-					map._overPos.y = map[scene._goToScene].y * 100 + 900;
-
-					// Run a canimation?
-					if (str[2] > 100) {
-						people._hSavedFacing = str[2];
-						people._hSavedPos = Common::Point(160, 100);
-					}
-				}
-				str += 6;
-
-				_scriptMoreFlag = (scene._goToScene == 100) ? 2 : 1;
-				_scriptSaveIndex = str - scriptStart;
-				endStr = true;
-				wait = 0;
-				
-			} else if (c == _opcodes[OP_PLAY_PROLOGUE]) {
-				++str;
-				for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx)
-					tempString += str[idx];
-
-				anim.play(tempString, 1, 3, true, 4);
-				
-			} else if (c == _opcodes[OP_ADD_ITEM_TO_INVENTORY]) {
-				++str;
-				for (int idx = 0; idx < str[0]; ++idx)
-					tempString += str[idx + 1];
-				str += str[0];
-
-				inv.putNameInInventory(tempString);
-				
-			} else if (c == _opcodes[OP_SET_OBJECT]) {
-				++str;
-				for (int idx = 0; idx < (str[0] & 127); ++idx)
-					tempString += str[idx + 1];
-
-				// Set comparison state according to if we want to hide or unhide
-				bool state = (str[0] >= SPEAKER_REMOVE);
-				str += str[0] & 127;
-
-				for (uint idx = 0; idx < scene._bgShapes.size(); ++idx) {
-					Object &object = scene._bgShapes[idx];
-					if (tempString.equalsIgnoreCase(object._name)) {
-						// Only toggle the object if it's not in the desired state already
-						if ((object._type == HIDDEN && state) || (object._type != HIDDEN && !state))
-							object.toggleHidden();
-					}
-				}
-				
-			} else if (c == _opcodes[OP_CALL_TALK_FILE]) {
-				++str;
-				for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx)
-					tempString += str[idx];
-				str += 8;
-
-				int scriptCurrentIndex = str - scriptStart;
-
-				// Save the current script position and new talk file
-				if (_scriptStack.size() < 9) {
-					ScriptStackEntry rec1;
-					rec1._name = _scriptName;
-					rec1._currentIndex = scriptCurrentIndex;
-					rec1._select = _scriptSelect;
-					_scriptStack.push(rec1);
-
-					// Push the new talk file onto the stack
-					ScriptStackEntry rec2;
-					rec2._name = tempString;
-					rec2._currentIndex = 0;
-					rec2._select = 100;
-					_scriptStack.push(rec2);
-				} else {
-					error("Script stack overflow");
-				}
-
-				_scriptMoreFlag = 1;
-				endStr = true;
-				wait = 0;
-				
-			} else if (c == _opcodes[OP_MOVE_MOUSE]) {
-				++str;
-				events.moveMouse(Common::Point((str[0] - 1) * 256 + str[1] - 1, str[2]));
-				if (_talkToAbort)
-					return;
-				str += 3;
-				
-			} else if (c == _opcodes[OP_DISPLAY_INFO_LINE]) {
-				++str;
-				for (int idx = 0; idx < str[0]; ++idx)
-					tempString += str[idx + 1];
-				str += str[0];
-
-				screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", tempString.c_str());
-				ui._menuCounter = 30;
-				
-			} else if (c == _opcodes[OP_CLEAR_INFO_LINE]) {
-				ui._infoFlag = true;
-				ui.clearInfo();
-				
-			} else if (c == _opcodes[OP_WALK_TO_CANIMATION]) {
-				++str;
-				CAnim &animation = scene._cAnim[str[0] - 1];
-
-				people.walkToCoords(animation._goto, animation._gotoDir);
-				if (_talkToAbort)
-					return;
-				
-			} else if (c == _opcodes[OP_REMOVE_ITEM_FROM_INVENTORY]) {
-				++str;
-				for (int idx = 0; idx < str[0]; ++idx)
-					tempString += str[idx + 1];
-				str += str[0];
-
-				inv.deleteItemFromInventory(tempString);
-				
-			} else if (c == _opcodes[OP_ENABLE_END_KEY]) {
-				ui._endKeyActive = true;
-				
-			} else if (c == _opcodes[OP_DISABLE_END_KEY]) {
-				ui._endKeyActive = false;
-				
-			} else {
-				error("Unknown opcode encountered");
+			default:
+				break;
 			}
 
 			++str;
 		} else {
 			// If the window isn't yet open, draw the window before printing starts
-			if (!ui._windowOpen && noTextYet) {
-				noTextYet = false;
+			if (!ui._windowOpen && _noTextYet) {
+				_noTextYet = false;
 				drawInterface();
 
 				if (_talkTo != -1) {
@@ -1520,19 +1190,19 @@ void Talk::doScript(const Common::String &script) {
 			}
 
 			// If it's the first line, display the speaker
-			if (!line && _speaker >= 0 && _speaker < (int)people._characters.size()) {
+			if (!_line && _speaker >= 0 && _speaker < (int)people._characters.size()) {
 				// If the window is open, display the name directly on-screen.
 				// Otherwise, simply draw it on the back buffer
 				if (ui._windowOpen) {
-					screen.print(Common::Point(16, yp), TALK_FOREGROUND, "%s",
+					screen.print(Common::Point(16, _yp), TALK_FOREGROUND, "%s",
 						people._characters[_speaker & 127]._name);
 				} else {
-					screen.gPrint(Common::Point(16, yp - 1), TALK_FOREGROUND, "%s", 
+					screen.gPrint(Common::Point(16, _yp - 1), TALK_FOREGROUND, "%s", 
 						people._characters[_speaker & 127]._name);
 					openTalkWindow = true;
 				}
 
-				yp += 9;
+				_yp += 9;
 			}
 
 			// Find amount of text that will fit on the line
@@ -1540,23 +1210,23 @@ void Talk::doScript(const Common::String &script) {
 			do {
 				width += screen.charWidth(str[idx]);
 				++idx;
-				++charCount;
+				++_charCount;
 			} while (width < 298 && str[idx] && str[idx] != '{' && str[idx] < _opcodes[0]);
 
 			if (str[idx] || width >= 298) {
 				if (str[idx] < _opcodes[0] && str[idx] != '{') {
 					--idx;
-					--charCount;
+					--_charCount;
 				}
 			} else {
-				endStr = true;
+				_endStr = true;
 			}
 
 			// If word wrap is needed, find the start of the current word
 			if (width >= 298) {
 				while (str[idx] != ' ') {
 					--idx;
-					--charCount;
+					--_charCount;
 				}
 			}
 
@@ -1566,16 +1236,16 @@ void Talk::doScript(const Common::String &script) {
 			// If the speaker indicates a description file, print it in yellow
 			if (_speaker != -1) {
 				if (ui._windowOpen) {
-					screen.print(Common::Point(16, yp), COMMAND_FOREGROUND, "%s", lineStr.c_str());
+					screen.print(Common::Point(16, _yp), COMMAND_FOREGROUND, "%s", lineStr.c_str());
 				} else {
-					screen.gPrint(Common::Point(16, yp - 1), COMMAND_FOREGROUND, "%s", lineStr.c_str());
+					screen.gPrint(Common::Point(16, _yp - 1), COMMAND_FOREGROUND, "%s", lineStr.c_str());
 					openTalkWindow = true;
 				}
 			} else {
 				if (ui._windowOpen) {
-					screen.print(Common::Point(16, yp), COMMAND_FOREGROUND, "%s", lineStr.c_str());
+					screen.print(Common::Point(16, _yp), COMMAND_FOREGROUND, "%s", lineStr.c_str());
 				} else {
-					screen.gPrint(Common::Point(16, yp - 1), COMMAND_FOREGROUND, "%s", lineStr.c_str());
+					screen.gPrint(Common::Point(16, _yp - 1), COMMAND_FOREGROUND, "%s", lineStr.c_str());
 					openTalkWindow = true;
 				}
 			}
@@ -1587,24 +1257,24 @@ void Talk::doScript(const Common::String &script) {
 			if (str[0] < _opcodes[0] && str[0] != '{')
 				++str;
 
-			yp += 9;
-			++line;
+			_yp += 9;
+			++_line;
 
 			// Certain different conditions require a wait
-			if ((line == 4 && str < scriptEnd && str[0] != _opcodes[OP_SFX_COMMAND] && str[0] != _opcodes[OP_PAUSE] && _speaker != -1) ||
-					(line == 5 && str < scriptEnd && str[0] != _opcodes[OP_PAUSE] && _speaker == -1) ||
-					endStr) {
-				wait = 1;
+			if ((_line == 4 && str < _scriptEnd && str[0] != _opcodes[OP_SFX_COMMAND] && str[0] != _opcodes[OP_PAUSE] && _speaker != -1) ||
+					(_line == 5 && str < _scriptEnd && str[0] != _opcodes[OP_PAUSE] && _speaker == -1) ||
+					_endStr) {
+				_wait = 1;
 			}
 
-			byte v = (str >= scriptEnd ? 0 : str[0]);
-			wait = v == _opcodes[OP_SWITCH_SPEAKER] || v == _opcodes[OP_ASSIGN_PORTRAIT_LOCATION] ||
+			byte v = (str >= _scriptEnd ? 0 : str[0]);
+			_wait = v == _opcodes[OP_SWITCH_SPEAKER] || v == _opcodes[OP_ASSIGN_PORTRAIT_LOCATION] ||
 				v == _opcodes[OP_BANISH_WINDOW] || _opcodes[OP_IF_STATEMENT] || v == _opcodes[OP_ELSE_STATEMENT] ||
 				v == _opcodes[OP_END_IF_STATEMENT] || v == _opcodes[OP_GOTO_SCENE] || v == _opcodes[OP_CALL_TALK_FILE];
 		}
 
 		// Open window if it wasn't already open, and text has already been printed
-		if ((openTalkWindow && wait) || (openTalkWindow && str[0] >= _opcodes[0] && str[0] != _opcodes[OP_CARRIAGE_RETURN])) {
+		if ((openTalkWindow && _wait) || (openTalkWindow && str[0] >= _opcodes[0] && str[0] != _opcodes[OP_CARRIAGE_RETURN])) {
 			if (!ui._slideWindows) {
 				screen.slamRect(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
 			} else {
@@ -1615,34 +1285,34 @@ void Talk::doScript(const Common::String &script) {
 			openTalkWindow = false;
 		}
 
-		if (wait) {
+		if (_wait) {
 			// Handling pausing
-			if (!pauseFlag && charCount < 160)
-				charCount = 160;
+			if (!_pauseFlag && _charCount < 160)
+				_charCount = 160;
 
-			wait = waitForMore(charCount);
-			if (wait == -1)
-				endStr = true;
+			_wait = waitForMore(_charCount);
+			if (_wait == -1)
+				_endStr = true;
 
 			// If a key was pressed to finish the window, see if further voice files should be skipped
-			if (wait >= 0 && wait < 254) {
+			if (_wait >= 0 && _wait < 254) {
 				if (str[0] == _opcodes[OP_SFX_COMMAND])
 					str += 9;
 			}
 
 			// Clear the window unless the wait was due to a PAUSE command
-			if (!pauseFlag && wait != -1 && str < scriptEnd && str[0] != _opcodes[OP_SFX_COMMAND]) {
+			if (!_pauseFlag && _wait != -1 && str < _scriptEnd && str[0] != _opcodes[OP_SFX_COMMAND]) {
 				if (!_talkStealth)
 					ui.clearWindow();
-				yp = CONTROLS_Y + 12;
-				charCount = line = 0;
+				_yp = CONTROLS_Y + 12;
+				_charCount = _line = 0;
 			}
 
-			pauseFlag = false;
+			_pauseFlag = false;
 		}
-	} while (!_vm->shouldQuit() && !endStr);
+	} while (!_vm->shouldQuit() && !_endStr);
 
-	if (wait != -1) {
+	if (_wait != -1) {
 		for (int ssIndex = 0; ssIndex < (int)_savedSequences.size(); ++ssIndex) {
 			SequenceEntry &seq = _savedSequences[ssIndex];
 			Object &object = scene._bgShapes[seq._objNum];
@@ -1757,4 +1427,559 @@ void Talk::synchronize(Common::Serializer &s) {
 	}
 }
 
+OpcodeReturn Talk::cmdAddItemToInventory(const byte *&str) {
+	Inventory &inv = *_vm->_inventory;
+	Common::String tempString;
+
+	++str;
+	for (int idx = 0; idx < str[0]; ++idx)
+		tempString += str[idx + 1];
+	str += str[0];
+
+	inv.putNameInInventory(tempString);
+	return RET_SUCCESS;
+}
+
+OpcodeReturn Talk::cmdAdjustObjectSequence(const byte *&str) {
+	Scene &scene = *_vm->_scene;
+	Common::String tempString;
+
+	// Get the name of the object to adjust
+	++str;
+	for (int idx = 0; idx < (str[0] & 127); ++idx)
+		tempString += str[idx + 2];
+
+	// Scan for object
+	int objId = -1;
+	for (uint idx = 0; idx < scene._bgShapes.size(); ++idx) {
+		if (tempString.equalsIgnoreCase(scene._bgShapes[idx]._name))
+			objId = idx;
+	}
+	if (objId == -1)
+		error("Could not find object %s to change", tempString.c_str());
+
+	// Should the script be overwritten?
+	if (str[0] > 0x80) {
+		// Save the current sequence
+		_savedSequences.push(SequenceEntry());
+		SequenceEntry &seqEntry = _savedSequences.top();
+		seqEntry._objNum = objId;
+		seqEntry._seqTo = scene._bgShapes[objId]._seqTo;
+		for (uint idx = 0; idx < scene._bgShapes[objId]._seqSize; ++idx)
+			seqEntry._sequences.push_back(scene._bgShapes[objId]._sequences[idx]);
+	}
+
+	// Get number of bytes to change
+	_seqCount = str[1];
+	str += (str[0] & 127) + 2;
+
+	// Copy in the new sequence
+	for (int idx = 0; idx < _seqCount; ++idx, ++str)
+		scene._bgShapes[objId]._sequences[idx] = str[0] - 1;
+
+	// Reset object back to beginning of new sequence
+	scene._bgShapes[objId]._frameNumber = 0;
+
+	return RET_CONTINUE;
+}
+
+OpcodeReturn Talk::cmdBanishWindow(const byte *&str) {
+	People &people = *_vm->_people;
+	UserInterface &ui = *_vm->_ui;
+
+	if (!(_speaker & SPEAKER_REMOVE))
+		people.clearTalking();
+	pullSequence();
+
+	if (_talkToAbort)
+		return RET_EXIT;
+
+	_speaker |= SPEAKER_REMOVE;
+	ui.banishWindow();
+	ui._menuMode = TALK_MODE;
+	_noTextYet = true;
+
+	return RET_SUCCESS;
+}
+
+OpcodeReturn Talk::cmdDisableEndKey(const byte *&str) {
+	_vm->_ui->_endKeyActive = false;
+	return RET_SUCCESS;
+}
+
+OpcodeReturn Talk::cmdEnableEndKey(const byte *&str) {
+	_vm->_ui->_endKeyActive = true;
+	return RET_SUCCESS;
+}
+
+OpcodeReturn Talk::cmdGotoScene(const byte *&str) {
+	Map &map = *_vm->_map;
+	People &people = *_vm->_people;
+	Scene &scene = *_vm->_scene;
+	scene._goToScene = str[1] - 1;
+
+	if (scene._goToScene != 100) {
+		// Not going to the map overview
+		map._oldCharPoint = scene._goToScene;
+		map._overPos.x = map[scene._goToScene].x * 100 - 600;
+		map._overPos.y = map[scene._goToScene].y * 100 + 900;
+
+		// Run a canimation?
+		if (str[2] > 100) {
+			people._hSavedFacing = str[2];
+			people._hSavedPos = Common::Point(160, 100);
+		}
+	}
+	str += 6;
+
+	_scriptMoreFlag = (scene._goToScene == 100) ? 2 : 1;
+	_scriptSaveIndex = str - _scriptStart;
+	_endStr = true;
+	_wait = 0;
+
+	return RET_SUCCESS;
+}
+
+OpcodeReturn Talk::cmdHolmesOff(const byte *&str) {
+	_vm->_people->_holmesOn = false;
+	return RET_SUCCESS;
+}
+
+OpcodeReturn Talk::cmdHolmesOn(const byte *&str) {
+	_vm->_people->_holmesOn = true;
+	return RET_SUCCESS;
+}
+
+OpcodeReturn Talk::cmdPause(const byte *&str) {
+	_charCount = *++str;
+	_wait = _pauseFlag = true;
+
+	return RET_SUCCESS;
+}
+
+OpcodeReturn Talk::cmdPauseWithoutControl(const byte *&str) {
+	Events &events = *_vm->_events;
+	Scene &scene = *_vm->_scene;
+	++str;
+
+	for (int idx = 0; idx < (str[0] - 1); ++idx) {
+		scene.doBgAnim();
+		if (_talkToAbort)
+			return RET_EXIT;
+
+		// Check for button press
+		events.pollEvents();
+		events.setButtonState();
+	}
+
+	return RET_SUCCESS;
+}
+
+OpcodeReturn Talk::cmdRemoveItemFromInventory(const byte *&str) {
+	Inventory &inv = *_vm->_inventory;
+	Common::String tempString;
+
+	++str;
+	for (int idx = 0; idx < str[0]; ++idx)
+		tempString += str[idx + 1];
+	str += str[0];
+
+	inv.deleteItemFromInventory(tempString);
+
+	return RET_SUCCESS;
+}
+
+OpcodeReturn Talk::cmdRunCAnimation(const byte *&str) {
+	Scene &scene = *_vm->_scene;
+
+	++str;
+	scene.startCAnim((str[0] - 1) & 127, (str[0] & 0x80) ? -1 : 1);
+	if (_talkToAbort)
+		return RET_EXIT;
+
+	// Check if next character is changing side or changing portrait
+	if (_charCount && (str[1] == _opcodes[OP_SWITCH_SPEAKER] || str[1] == _opcodes[OP_ASSIGN_PORTRAIT_LOCATION]))
+		_wait = 1;
+
+	return RET_SUCCESS;
+}
+
+OpcodeReturn Talk::cmdSetFlag(const byte *&str) {
+	++str;
+	int flag1 = (str[0] - 1) * 256 + str[1] - 1 - (str[1] == 1 ? 1 : 0);
+	int flag = (flag1 & 0x3fff) * (flag1 >= 0x4000 ? -1 : 1);
+	_vm->setFlags(flag);
+	++str;
+
+	return RET_SUCCESS;
+}
+
+OpcodeReturn Talk::cmdSetObject(const byte *&str) {
+	Scene &scene = *_vm->_scene;
+	Common::String tempString;
+
+	++str;
+	for (int idx = 0; idx < (str[0] & 127); ++idx)
+		tempString += str[idx + 1];
+
+	// Set comparison state according to if we want to hide or unhide
+	bool state = (str[0] >= SPEAKER_REMOVE);
+	str += str[0] & 127;
+
+	for (uint idx = 0; idx < scene._bgShapes.size(); ++idx) {
+		Object &object = scene._bgShapes[idx];
+		if (tempString.equalsIgnoreCase(object._name)) {
+			// Only toggle the object if it's not in the desired state already
+			if ((object._type == HIDDEN && state) || (object._type != HIDDEN && !state))
+				object.toggleHidden();
+		}
+	}
+
+	return RET_SUCCESS;
+}
+
+OpcodeReturn Talk::cmdStealthModeActivate(const byte *&str) {
+	_talkStealth = 2;
+	return RET_SUCCESS;
+}
+
+OpcodeReturn Talk::cmdStealthModeDeactivate(const byte *&str) {
+	Events &events = *_vm->_events;
+
+	_talkStealth = 0;
+	events.clearKeyboard();
+
+	return RET_SUCCESS;
+}
+
+OpcodeReturn Talk::cmdSwitchSpeaker(const byte *&str) {
+	People &people = *_vm->_people;
+	UserInterface &ui = *_vm->_ui;
+
+	if (!(_speaker & SPEAKER_REMOVE))
+		people.clearTalking();
+	if (_talkToAbort)
+		return RET_EXIT;
+
+	ui.clearWindow();
+	_yp = CONTROLS_Y + 12;
+	_charCount = _line = 0;
+
+	_speaker = *++str - 1;
+	people.setTalking(_speaker);
+	pullSequence();
+	pushSequence(_speaker);
+	setSequence(_speaker);
+
+	return RET_SUCCESS;
+}
+
+OpcodeReturn Talk::cmdToggleObject(const byte *&str) {
+	Scene &scene = *_vm->_scene;
+	Common::String tempString;
+
+	++str;
+	for (int idx = 0; idx < str[0]; ++idx)
+		tempString += str[idx + 1];
+
+	scene.toggleObject(tempString);
+	str += str[0];
+
+	return RET_SUCCESS;
+}
+
+OpcodeReturn Talk::cmdWalkToCAnimation(const byte *&str) {
+	People &people = *_vm->_people;
+	Scene &scene = *_vm->_scene;
+
+	++str;
+	CAnim &animation = scene._cAnim[str[0] - 1];
+	people.walkToCoords(animation._goto, animation._gotoDir);
+	
+	return _talkToAbort ? RET_EXIT : RET_SUCCESS;
+}
+
+OpcodeReturn Talk::cmdWalkToCoords(const byte *&str) {
+	People &people = *_vm->_people;
+	++str;
+
+	people.walkToCoords(Common::Point(((str[0] - 1) * 256 + str[1] - 1) * 100,
+		str[2] * 100), str[3] - 1);
+	if (_talkToAbort)
+		return RET_EXIT;
+
+	str += 3;
+	return RET_SUCCESS;
+}
+
+/*----------------------------------------------------------------*/
+
+ScalpelTalk::ScalpelTalk(SherlockEngine *vm) : Talk(vm) {
+	static OpcodeMethod OPCODE_METHODS[] = {
+		(OpcodeMethod)&ScalpelTalk::cmdSwitchSpeaker,
+		(OpcodeMethod)&ScalpelTalk::cmdRunCAnimation,
+		(OpcodeMethod)&ScalpelTalk::cmdAssignPortraitLocation,
+
+		(OpcodeMethod)&ScalpelTalk::cmdPause,
+		(OpcodeMethod)&ScalpelTalk::cmdRemovePortrait,
+		(OpcodeMethod)&ScalpelTalk::cmdClearWindow,
+		(OpcodeMethod)&ScalpelTalk::cmdAdjustObjectSequence,
+		(OpcodeMethod)&ScalpelTalk::cmdWalkToCoords,
+		(OpcodeMethod)&ScalpelTalk::cmdPauseWithoutControl,
+		(OpcodeMethod)&ScalpelTalk::cmdBanishWindow,
+		(OpcodeMethod)&ScalpelTalk::cmdSummonWindow,
+		(OpcodeMethod)&ScalpelTalk::cmdSetFlag,
+		(OpcodeMethod)&ScalpelTalk::cmdSfxCommand,
+
+		(OpcodeMethod)&ScalpelTalk::cmdToggleObject,
+		(OpcodeMethod)&ScalpelTalk::cmdStealthModeActivate,
+		(OpcodeMethod)&ScalpelTalk::cmdIf,
+		(OpcodeMethod)&ScalpelTalk::cmdElse,
+		nullptr,
+		(OpcodeMethod)&ScalpelTalk::cmdStealthModeDeactivate,
+		(OpcodeMethod)&ScalpelTalk::cmdHolmesOff,
+		(OpcodeMethod)&ScalpelTalk::cmdHolmesOn,
+		(OpcodeMethod)&ScalpelTalk::cmdGotoScene,
+		(OpcodeMethod)&ScalpelTalk::cmdPlayPrologue,
+		
+		(OpcodeMethod)&ScalpelTalk::cmdAddItemToInventory,
+		(OpcodeMethod)&ScalpelTalk::cmdSetObject,
+		(OpcodeMethod)&ScalpelTalk::cmdCallTalkFile,
+		(OpcodeMethod)&ScalpelTalk::cmdMoveMouse,
+		(OpcodeMethod)&ScalpelTalk::cmdDisplayInfoLine,
+		(OpcodeMethod)&ScalpelTalk::cmdClearInfoLine,
+		(OpcodeMethod)&ScalpelTalk::cmdWalkToCAnimation,
+		(OpcodeMethod)&ScalpelTalk::cmdRemoveItemFromInventory,
+		(OpcodeMethod)&ScalpelTalk::cmdEnableEndKey,
+		(OpcodeMethod)&ScalpelTalk::cmdDisableEndKey,
+		
+		(OpcodeMethod)&ScalpelTalk::cmdCarriageReturn
+	};
+
+	_opcodeTable = OPCODE_METHODS;
+}
+
+OpcodeReturn ScalpelTalk::cmdAssignPortraitLocation(const byte *&str) {
+	People &people = *_vm->_people;
+
+	++str;
+	switch (str[0] & 15) {
+	case 1:
+		people._portraitSide = 20;
+		break;
+	case 2:
+		people._portraitSide = 220;
+		break;
+	case 3:
+		people._portraitSide = 120;
+		break;
+	default:
+		break;
+	}
+
+	if (str[0] > 15)
+		people._speakerFlip = true;
+
+	return RET_SUCCESS;
+}
+
+OpcodeReturn ScalpelTalk::cmdCallTalkFile(const byte *&str) {
+	Common::String tempString;
+
+	++str;
+	for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx)
+		tempString += str[idx];
+	str += 8;
+
+	int scriptCurrentIndex = str - _scriptStart;
+
+	// Save the current script position and new talk file
+	if (_scriptStack.size() < 9) {
+		ScriptStackEntry rec1;
+		rec1._name = _scriptName;
+		rec1._currentIndex = scriptCurrentIndex;
+		rec1._select = _scriptSelect;
+		_scriptStack.push(rec1);
+
+		// Push the new talk file onto the stack
+		ScriptStackEntry rec2;
+		rec2._name = tempString;
+		rec2._currentIndex = 0;
+		rec2._select = 100;
+		_scriptStack.push(rec2);
+	} else {
+		error("Script stack overflow");
+	}
+
+	_scriptMoreFlag = 1;
+	_endStr = true;
+	_wait = 0;
+
+	return RET_SUCCESS;
+}
+
+OpcodeReturn ScalpelTalk::cmdClearInfoLine(const byte *&str) {
+	UserInterface &ui = *_vm->_ui;
+
+	ui._infoFlag = true;
+	ui.clearInfo();
+
+	return RET_SUCCESS;
+}
+
+OpcodeReturn ScalpelTalk::cmdClearWindow(const byte *&str) {
+	UserInterface &ui = *_vm->_ui;
+	
+	ui.clearWindow();
+	_yp = CONTROLS_Y + 12;
+	_charCount = _line = 0;
+
+	return RET_SUCCESS;
+}
+
+OpcodeReturn ScalpelTalk::cmdDisplayInfoLine(const byte *&str) {
+	Screen &screen = *_vm->_screen;
+	UserInterface &ui = *_vm->_ui;
+	Common::String tempString;
+
+	++str;
+	for (int idx = 0; idx < str[0]; ++idx)
+		tempString += str[idx + 1];
+	str += str[0];
+
+	screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", tempString.c_str());
+	ui._menuCounter = 30;
+
+	return RET_SUCCESS;
+}
+
+OpcodeReturn ScalpelTalk::cmdElse(const byte *&str) {
+	// If this is encountered here, it means that a preceeding IF statement was found,
+	// and evaluated to true. Now all the statements for the true block are finished,
+	// so skip over the block of code that would have executed if the result was false
+	_wait = 0;
+	do {
+		++str;
+	} while (str[0] && str[0] != _opcodes[OP_END_IF_STATEMENT]);
+
+	return RET_SUCCESS;
+}
+
+OpcodeReturn ScalpelTalk::cmdIf(const byte *&str) {
+	++str;
+	int flag = (str[0] - 1) * 256 + str[1] - 1 - (str[1] == 1 ? 1 : 0);
+	++str;
+	_wait = 0;
+
+	bool result = flag < 0x8000;
+	if (_vm->readFlags(flag & 0x7fff) != result) {
+		do {
+			++str;
+		} while (str[0] && str[0] != _opcodes[OP_ELSE_STATEMENT] && str[0] != _opcodes[OP_END_IF_STATEMENT]);
+
+		if (!str[0])
+			_endStr = true;
+	}
+
+	return RET_SUCCESS;
+}
+
+OpcodeReturn ScalpelTalk::cmdMoveMouse(const byte *&str) {
+	Events &events = *_vm->_events;
+
+	++str;
+	events.moveMouse(Common::Point((str[0] - 1) * 256 + str[1] - 1, str[2]));
+	if (_talkToAbort)
+		return RET_EXIT;
+	str += 3;
+	
+	return RET_SUCCESS;
+}
+
+OpcodeReturn ScalpelTalk::cmdPlayPrologue(const byte *&str) {
+	Animation &anim = *_vm->_animation;
+	Common::String tempString;
+
+	++str;
+	for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx)
+		tempString += str[idx];
+
+	anim.play(tempString, 1, 3, true, 4);
+
+	return RET_SUCCESS;
+}
+
+OpcodeReturn ScalpelTalk::cmdRemovePortrait(const byte *&str) {
+	People &people = *_vm->_people;
+
+	if (_speaker >= 0 && _speaker < SPEAKER_REMOVE)
+		people.clearTalking();
+	pullSequence();
+	if (_talkToAbort)
+		return RET_EXIT;
+
+	_speaker |= SPEAKER_REMOVE;
+	return RET_SUCCESS;
+}
+
+OpcodeReturn ScalpelTalk::cmdSfxCommand(const byte *&str) {
+	Sound &sound = *_vm->_sound;
+	Common::String tempString;
+
+	++str;
+	if (sound._voices) {
+		for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx)
+			tempString += str[idx];
+		sound.playSound(tempString, WAIT_RETURN_IMMEDIATELY);
+
+		// Set voices to wait for more
+		sound._voices = 2;
+		sound._speechOn = (*sound._soundIsOn);
+	}
+
+	_wait = 1;
+	str += 7;
+
+	return RET_SUCCESS;
+}
+
+OpcodeReturn ScalpelTalk::cmdSummonWindow(const byte *&str) {
+	Events &events = *_vm->_events;
+	Screen &screen = *_vm->_screen;
+
+	drawInterface();
+	events._pressed = events._released = false;
+	events.clearKeyboard();
+	_noTextYet = false;
+
+	if (_speaker != -1) {
+		screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_NULL, false, "Exit");
+		screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, false, "Up");
+		screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, false, "Down");
+	}
+
+	return RET_SUCCESS;
+}
+
+OpcodeReturn ScalpelTalk::cmdCarriageReturn(const byte *&str) {
+	return RET_SUCCESS;
+}
+
+/*----------------------------------------------------------------*/
+
+TattooTalk::TattooTalk(SherlockEngine *vm) : Talk(vm) {
+	static OpcodeMethod OPCODE_METHODS[] = {
+		nullptr, nullptr,
+		nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+		nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+		nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+		nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+		(OpcodeMethod)&TattooTalk::cmdSwitchSpeaker,
+		(OpcodeMethod)&TattooTalk::cmdRunCAnimation,
+		// TODO: Implement opcode methods for new Tattoo opcodes
+	};
+
+	_opcodeTable = OPCODE_METHODS;
+}
+
 } // End of namespace Sherlock
diff --git a/engines/sherlock/talk.h b/engines/sherlock/talk.h
index b30b4ad..02d141d 100644
--- a/engines/sherlock/talk.h
+++ b/engines/sherlock/talk.h
@@ -105,6 +105,13 @@ enum {
 	OP_TURN_SOUNDS_OFF			= 64
 };
 
+enum OpcodeReturn { RET_EXIT = -1, RET_SUCCESS = 0, RET_CONTINUE = 1 };
+
+class SherlockEngine;
+class ScalpelUserInterface;
+class Talk;
+
+typedef OpcodeReturn(Talk::*OpcodeMethod)(const byte *&str);
 
 struct SequenceEntry {
 	int _objNum;
@@ -156,25 +163,9 @@ struct TalkSequences {
 	void clear();
 };
 
-class SherlockEngine;
-class ScalpelUserInterface;
-
 class Talk {
 	friend class ScalpelUserInterface;
 private:
-	SherlockEngine *_vm;
-	Common::Stack<SequenceEntry> _savedSequences;
-	Common::Stack<SequenceEntry> _sequenceStack;
-	Common::Stack<ScriptStackEntry> _scriptStack;
-	Common::Array<Statement> _statements;
-	TalkHistoryEntry _talkHistory[MAX_TALK_FILES];
-	int _speaker;
-	int _talkIndex;
-	int _scriptSelect;
-	int _talkStealth;
-	int _talkToFlag;
-	int _scriptSaveIndex;
-private:
 	/**
 	 * Remove any voice commands from a loaded statement list
 	 */
@@ -207,6 +198,54 @@ private:
 	 * the amount of text that's been displayed
 	 */
 	int waitForMore(int delay);
+protected:
+	SherlockEngine *_vm;
+	OpcodeMethod *_opcodeTable;
+	Common::Stack<SequenceEntry> _savedSequences;
+	Common::Stack<SequenceEntry> _sequenceStack;
+	Common::Stack<ScriptStackEntry> _scriptStack;
+	Common::Array<Statement> _statements;
+	TalkHistoryEntry _talkHistory[MAX_TALK_FILES];
+	int _speaker;
+	int _talkIndex;
+	int _scriptSelect;
+	int _talkStealth;
+	int _talkToFlag;
+	int _scriptSaveIndex;
+
+	// These fields are used solely by doScript, but are fields because all the script opcodes are
+	// separate methods now, and need access to these fields
+	int _yp;
+	int _charCount;
+	int _line;
+	int _wait;
+	bool _pauseFlag;
+	bool _endStr, _noTextYet;
+	int _seqCount;
+	const byte *_scriptStart, *_scriptEnd;
+protected:
+	Talk(SherlockEngine *vm);
+
+	OpcodeReturn cmdAddItemToInventory(const byte *&str);
+	OpcodeReturn cmdAdjustObjectSequence(const byte *&str);
+	OpcodeReturn cmdBanishWindow(const byte *&str);
+	OpcodeReturn cmdDisableEndKey(const byte *&str);
+	OpcodeReturn cmdEnableEndKey(const byte *&str);
+	OpcodeReturn cmdGotoScene(const byte *&str);
+	OpcodeReturn cmdHolmesOff(const byte *&str);
+	OpcodeReturn cmdHolmesOn(const byte *&str);
+	OpcodeReturn cmdPause(const byte *&str);
+	OpcodeReturn cmdPauseWithoutControl(const byte *&str);
+	OpcodeReturn cmdRemoveItemFromInventory(const byte *&str);
+	OpcodeReturn cmdRunCAnimation(const byte *&str);
+	OpcodeReturn cmdSetFlag(const byte *&str);
+	OpcodeReturn cmdSetObject(const byte *&str);
+	OpcodeReturn cmdStealthModeActivate(const byte *&str);
+	OpcodeReturn cmdStealthModeDeactivate(const byte *&str);
+	OpcodeReturn cmdSwitchSpeaker(const byte *&str);
+	OpcodeReturn cmdToggleObject(const byte *&str);
+	OpcodeReturn cmdWalkToCAnimation(const byte *&str);
+	OpcodeReturn cmdWalkToCoords(const byte *&str);
 public:
 	bool _talkToAbort;
 	int _talkCounter;
@@ -216,8 +255,10 @@ public:
 	bool _moreTalkUp, _moreTalkDown;
 	int _converseNum;
 	const byte *_opcodes;
+
 public:
-	Talk(SherlockEngine *vm);
+	static Talk *init(SherlockEngine *vm);
+	virtual ~Talk() {}
 
 	/**
 	 * Return a given talk statement
@@ -302,6 +343,32 @@ public:
 	void synchronize(Common::Serializer &s);
 };
 
+class ScalpelTalk : public Talk {
+protected:
+	OpcodeReturn cmdAssignPortraitLocation(const byte *&str);
+	OpcodeReturn cmdCallTalkFile(const byte *&str);
+	OpcodeReturn cmdClearInfoLine(const byte *&str);
+	OpcodeReturn cmdClearWindow(const byte *&str);
+	OpcodeReturn cmdDisplayInfoLine(const byte *&str);
+	OpcodeReturn cmdElse(const byte *&str);
+	OpcodeReturn cmdIf(const byte *&str);
+	OpcodeReturn cmdMoveMouse(const byte *&str);
+	OpcodeReturn cmdPlayPrologue(const byte *&str);
+	OpcodeReturn cmdRemovePortrait(const byte *&str);
+	OpcodeReturn cmdSfxCommand(const byte *&str);
+	OpcodeReturn cmdSummonWindow(const byte *&str);
+	OpcodeReturn cmdCarriageReturn(const byte *&str);
+public:
+	ScalpelTalk(SherlockEngine *vm);
+	virtual ~ScalpelTalk() {}
+};
+
+class TattooTalk : public Talk {
+public:
+	TattooTalk(SherlockEngine *vm);
+	virtual ~TattooTalk() {}
+};
+
 } // End of namespace Sherlock
 
 #endif


Commit: b61cccf9f80df8411fe7e749dd94b464a96209c5
    https://github.com/scummvm/scummvm/commit/b61cccf9f80df8411fe7e749dd94b464a96209c5
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-24T20:33:14-04:00

Commit Message:
SHERLOCK: Implement method stubs for Tattoo opcodes

Changed paths:
    engines/sherlock/talk.cpp
    engines/sherlock/talk.h



diff --git a/engines/sherlock/talk.cpp b/engines/sherlock/talk.cpp
index 9b22ee1..15b6409 100644
--- a/engines/sherlock/talk.cpp
+++ b/engines/sherlock/talk.cpp
@@ -1502,6 +1502,42 @@ OpcodeReturn Talk::cmdBanishWindow(const byte *&str) {
 	return RET_SUCCESS;
 }
 
+OpcodeReturn Talk::cmdCallTalkFile(const byte *&str) {
+	Common::String tempString;
+
+	++str;
+	for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx)
+		tempString += str[idx];
+	str += 8;
+
+	int scriptCurrentIndex = str - _scriptStart;
+
+	// Save the current script position and new talk file
+	if (_scriptStack.size() < 9) {
+		ScriptStackEntry rec1;
+		rec1._name = _scriptName;
+		rec1._currentIndex = scriptCurrentIndex;
+		rec1._select = _scriptSelect;
+		_scriptStack.push(rec1);
+
+		// Push the new talk file onto the stack
+		ScriptStackEntry rec2;
+		rec2._name = tempString;
+		rec2._currentIndex = 0;
+		rec2._select = 100;
+		_scriptStack.push(rec2);
+	}
+	else {
+		error("Script stack overflow");
+	}
+
+	_scriptMoreFlag = 1;
+	_endStr = true;
+	_wait = 0;
+
+	return RET_SUCCESS;
+}
+
 OpcodeReturn Talk::cmdDisableEndKey(const byte *&str) {
 	_vm->_ui->_endKeyActive = false;
 	return RET_SUCCESS;
@@ -1783,41 +1819,6 @@ OpcodeReturn ScalpelTalk::cmdAssignPortraitLocation(const byte *&str) {
 	return RET_SUCCESS;
 }
 
-OpcodeReturn ScalpelTalk::cmdCallTalkFile(const byte *&str) {
-	Common::String tempString;
-
-	++str;
-	for (int idx = 0; idx < 8 && str[idx] != '~'; ++idx)
-		tempString += str[idx];
-	str += 8;
-
-	int scriptCurrentIndex = str - _scriptStart;
-
-	// Save the current script position and new talk file
-	if (_scriptStack.size() < 9) {
-		ScriptStackEntry rec1;
-		rec1._name = _scriptName;
-		rec1._currentIndex = scriptCurrentIndex;
-		rec1._select = _scriptSelect;
-		_scriptStack.push(rec1);
-
-		// Push the new talk file onto the stack
-		ScriptStackEntry rec2;
-		rec2._name = tempString;
-		rec2._currentIndex = 0;
-		rec2._select = 100;
-		_scriptStack.push(rec2);
-	} else {
-		error("Script stack overflow");
-	}
-
-	_scriptMoreFlag = 1;
-	_endStr = true;
-	_wait = 0;
-
-	return RET_SUCCESS;
-}
-
 OpcodeReturn ScalpelTalk::cmdClearInfoLine(const byte *&str) {
 	UserInterface &ui = *_vm->_ui;
 
@@ -1975,11 +1976,105 @@ TattooTalk::TattooTalk(SherlockEngine *vm) : Talk(vm) {
 		nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
 		nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
 		(OpcodeMethod)&TattooTalk::cmdSwitchSpeaker,
+
 		(OpcodeMethod)&TattooTalk::cmdRunCAnimation,
-		// TODO: Implement opcode methods for new Tattoo opcodes
+		(OpcodeMethod)&TattooTalk::cmdCallTalkFile,
+		(OpcodeMethod)&TattooTalk::cmdPause,
+		(OpcodeMethod)&TattooTalk::cmdMouseOnOff,
+		(OpcodeMethod)&TattooTalk::cmdSetWalkControl,
+		(OpcodeMethod)&TattooTalk::cmdAdjustObjectSequence,
+		(OpcodeMethod)&TattooTalk::cmdWalkToCoords,
+		(OpcodeMethod)&TattooTalk::cmdPauseWithoutControl,
+		(OpcodeMethod)&TattooTalk::cmdBanishWindow,
+		(OpcodeMethod)&TattooTalk::cmdSetTalkSequence,
+
+		(OpcodeMethod)&TattooTalk::cmdSetFlag,
+		(OpcodeMethod)&TattooTalk::cmdPlaySong,
+		(OpcodeMethod)&TattooTalk::cmdToggleObject,
+		(OpcodeMethod)&TattooTalk::cmdStealthModeActivate,
+		(OpcodeMethod)&TattooTalk::cmdWalkNPCToCAnimation,
+		(OpcodeMethod)&TattooTalk::cmdWalkNPCToCoords,
+		(OpcodeMethod)&TattooTalk::cmdWalkHomesAndNPCToCoords,
+		(OpcodeMethod)&TattooTalk::cmdStealthModeDeactivate,
+		(OpcodeMethod)&TattooTalk::cmdHolmesOff,
+		(OpcodeMethod)&TattooTalk::cmdHolmesOn,
+
+		(OpcodeMethod)&TattooTalk::cmdGotoScene,
+		(OpcodeMethod)&TattooTalk::cmdSetNPCPathDest,
+		(OpcodeMethod)&TattooTalk::cmdAddItemToInventory,
+		(OpcodeMethod)&TattooTalk::cmdSetObject,
+		(OpcodeMethod)&TattooTalk::cmdNextSong,
+		(OpcodeMethod)&TattooTalk::cmdSetNPCPathPause,
+		(OpcodeMethod)&TattooTalk::cmdPassword,
+		(OpcodeMethod)&TattooTalk::cmdSetSceneEntryFlag,
+		(OpcodeMethod)&TattooTalk::cmdWalkToCAnimation,
+		(OpcodeMethod)&TattooTalk::cmdRemoveItemFromInventory,
+
+		(OpcodeMethod)&TattooTalk::cmdEnableEndKey,
+		(OpcodeMethod)&TattooTalk::cmdDisableEndKey,
+		nullptr,
+		(OpcodeMethod)&TattooTalk::cmdWalkHomesAndNPCToCoords,
+		(OpcodeMethod)&TattooTalk::cmdSetNPCTalkFile,
+		(OpcodeMethod)&TattooTalk::cmdSetNPCOff,
+		(OpcodeMethod)&TattooTalk::cmdSetNPCOn,
+		(OpcodeMethod)&TattooTalk::cmdSetNPCDescOnOff,
+		(OpcodeMethod)&TattooTalk::cmdSetNPCPathPauseTakingNotes,
+		(OpcodeMethod)&TattooTalk::cmdSetNPCPathPauseLookingHolmes,
+
+		(OpcodeMethod)&TattooTalk::cmdTalkInterruptsEnable,
+		(OpcodeMethod)&TattooTalk::cmdTalkInterruptsDisable,
+		(OpcodeMethod)&TattooTalk::cmdSetNPCInfoLine,
+		(OpcodeMethod)&TattooTalk::cmdSetNPCPosition,
+		(OpcodeMethod)&TattooTalk::cmdNPCLabelSet,
+		(OpcodeMethod)&TattooTalk::cmdNPCLabelGoto,
+		(OpcodeMethod)&TattooTalk::cmdNPCLabelIfFlagGoto,
+		(OpcodeMethod)&TattooTalk::cmdSetNPCWalkGraphics,
+		nullptr,
+		(OpcodeMethod)&TattooTalk::cmdSetNPCVerb,
+
+		(OpcodeMethod)&TattooTalk::cmdSetNPCVerbCAnimation,
+		(OpcodeMethod)&TattooTalk::cmdSetNPCVerbScript,
+		nullptr,
+		(OpcodeMethod)&TattooTalk::cmdRestorePeopleSequence,
+		(OpcodeMethod)&TattooTalk::cmdSetNPCVerbTarget,
+		(OpcodeMethod)&TattooTalk::cmdTurnSoundsOff
 	};
 
 	_opcodeTable = OPCODE_METHODS;
 }
 
+OpcodeReturn TattooTalk::cmdMouseOnOff(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdNextSong(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdNPCLabelGoto(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdNPCLabelIfFlagGoto(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdNPCLabelSet(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdPassword(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdPlaySong(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdRestorePeopleSequence(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdSetNPCDescOnOff(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdSetNPCInfoLine(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdSetNPCOff(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdSetNPCOn(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdSetNPCPathDest(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdSetNPCPathPause(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdSetNPCPathPauseTakingNotes(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdSetNPCPathPauseLookingHolmes(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdSetNPCPosition(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdSetNPCTalkFile(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdSetNPCVerb(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdSetNPCVerbCAnimation(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdSetNPCVerbScript(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdSetNPCVerbTarget(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdSetNPCWalkGraphics(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdSetSceneEntryFlag(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdSetTalkSequence(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdSetWalkControl(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdTalkInterruptsDisable(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdTalkInterruptsEnable(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdTurnSoundsOff(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdWalkHolmesAndNPCToCAnimation(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdWalkNPCToCAnimation(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdWalkNPCToCoords(const byte *&str) { error("TODO: script opcode"); }
+OpcodeReturn TattooTalk::cmdWalkHomesAndNPCToCoords(const byte *&str) { error("TODO: script opcode"); }
+
 } // End of namespace Sherlock
diff --git a/engines/sherlock/talk.h b/engines/sherlock/talk.h
index 02d141d..dc6789c 100644
--- a/engines/sherlock/talk.h
+++ b/engines/sherlock/talk.h
@@ -229,6 +229,7 @@ protected:
 	OpcodeReturn cmdAddItemToInventory(const byte *&str);
 	OpcodeReturn cmdAdjustObjectSequence(const byte *&str);
 	OpcodeReturn cmdBanishWindow(const byte *&str);
+	OpcodeReturn cmdCallTalkFile(const byte *&str);
 	OpcodeReturn cmdDisableEndKey(const byte *&str);
 	OpcodeReturn cmdEnableEndKey(const byte *&str);
 	OpcodeReturn cmdGotoScene(const byte *&str);
@@ -346,7 +347,6 @@ public:
 class ScalpelTalk : public Talk {
 protected:
 	OpcodeReturn cmdAssignPortraitLocation(const byte *&str);
-	OpcodeReturn cmdCallTalkFile(const byte *&str);
 	OpcodeReturn cmdClearInfoLine(const byte *&str);
 	OpcodeReturn cmdClearWindow(const byte *&str);
 	OpcodeReturn cmdDisplayInfoLine(const byte *&str);
@@ -364,6 +364,40 @@ public:
 };
 
 class TattooTalk : public Talk {
+protected:
+	OpcodeReturn cmdMouseOnOff(const byte *&str);
+	OpcodeReturn cmdNextSong(const byte *&str);
+	OpcodeReturn cmdPassword(const byte *&str);
+	OpcodeReturn cmdPlaySong(const byte *&str);
+	OpcodeReturn cmdRestorePeopleSequence(const byte *&str);
+	OpcodeReturn cmdSetNPCDescOnOff(const byte *&str);
+	OpcodeReturn cmdSetNPCInfoLine(const byte *&str);
+	OpcodeReturn cmdNPCLabelGoto(const byte *&str);
+	OpcodeReturn cmdNPCLabelIfFlagGoto(const byte *&str);
+	OpcodeReturn cmdNPCLabelSet(const byte *&str);
+	OpcodeReturn cmdSetNPCOff(const byte *&str);
+	OpcodeReturn cmdSetNPCOn(const byte *&str);
+	OpcodeReturn cmdSetNPCPathDest(const byte *&str);
+	OpcodeReturn cmdSetNPCPathPause(const byte *&str);
+	OpcodeReturn cmdSetNPCPathPauseTakingNotes(const byte *&str);
+	OpcodeReturn cmdSetNPCPathPauseLookingHolmes(const byte *&str);
+	OpcodeReturn cmdSetNPCPosition(const byte *&str);
+	OpcodeReturn cmdSetNPCTalkFile(const byte *&str);
+	OpcodeReturn cmdSetNPCVerb(const byte *&str);
+	OpcodeReturn cmdSetNPCVerbCAnimation(const byte *&str);
+	OpcodeReturn cmdSetNPCVerbScript(const byte *&str);
+	OpcodeReturn cmdSetNPCVerbTarget(const byte *&str);
+	OpcodeReturn cmdSetNPCWalkGraphics(const byte *&str);
+	OpcodeReturn cmdSetSceneEntryFlag(const byte *&str);
+	OpcodeReturn cmdSetTalkSequence(const byte *&str);
+	OpcodeReturn cmdSetWalkControl(const byte *&str);
+	OpcodeReturn cmdTalkInterruptsDisable(const byte *&str);
+	OpcodeReturn cmdTalkInterruptsEnable(const byte *&str);
+	OpcodeReturn cmdTurnSoundsOff(const byte *&str);
+	OpcodeReturn cmdWalkHolmesAndNPCToCAnimation(const byte *&str);
+	OpcodeReturn cmdWalkNPCToCAnimation(const byte *&str);
+	OpcodeReturn cmdWalkNPCToCoords(const byte *&str);
+	OpcodeReturn cmdWalkHomesAndNPCToCoords(const byte *&str);
 public:
 	TattooTalk(SherlockEngine *vm);
 	virtual ~TattooTalk() {}


Commit: 69b848084b6d22ffb62dbe25c388203a225f3353
    https://github.com/scummvm/scummvm/commit/69b848084b6d22ffb62dbe25c388203a225f3353
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-24T21:06:21-04:00

Commit Message:
SHERLOCK: Fix script opcode table lookup

Changed paths:
    engines/sherlock/talk.cpp



diff --git a/engines/sherlock/talk.cpp b/engines/sherlock/talk.cpp
index 15b6409..8d553d6 100644
--- a/engines/sherlock/talk.cpp
+++ b/engines/sherlock/talk.cpp
@@ -1164,7 +1164,7 @@ void Talk::doScript(const Common::String &script) {
 			// Start of comment, so skip over it
 			while (*str++ != '}')
 				;
-		} else if (_opcodeTable[c]) {
+		} else if (_opcodeTable[c - 128]) {
 			// Handle control code
 			switch ((this->*_opcodeTable[c - 128])(str)) {
 			case RET_EXIT:


Commit: e52153d03da6c6a91e2c0c27128456f193407169
    https://github.com/scummvm/scummvm/commit/e52153d03da6c6a91e2c0c27128456f193407169
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-24T21:28:12-04:00

Commit Message:
SHERLOCK: Implement cmdSetNPCWalkGraphics method

Changed paths:
    engines/sherlock/talk.cpp



diff --git a/engines/sherlock/talk.cpp b/engines/sherlock/talk.cpp
index 8d553d6..3e3fcce 100644
--- a/engines/sherlock/talk.cpp
+++ b/engines/sherlock/talk.cpp
@@ -1164,7 +1164,7 @@ void Talk::doScript(const Common::String &script) {
 			// Start of comment, so skip over it
 			while (*str++ != '}')
 				;
-		} else if (_opcodeTable[c - 128]) {
+		} else if (c >= 128 && c <= 227 && _opcodeTable[c - 128]) {
 			// Handle control code
 			switch ((this->*_opcodeTable[c - 128])(str)) {
 			case RET_EXIT:
@@ -1789,7 +1789,14 @@ ScalpelTalk::ScalpelTalk(SherlockEngine *vm) : Talk(vm) {
 		(OpcodeMethod)&ScalpelTalk::cmdEnableEndKey,
 		(OpcodeMethod)&ScalpelTalk::cmdDisableEndKey,
 		
-		(OpcodeMethod)&ScalpelTalk::cmdCarriageReturn
+		(OpcodeMethod)&ScalpelTalk::cmdCarriageReturn,
+		nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+		nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+		nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+		nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+		nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+		nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+		nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr
 	};
 
 	_opcodeTable = OPCODE_METHODS;
@@ -2065,7 +2072,29 @@ OpcodeReturn TattooTalk::cmdSetNPCVerb(const byte *&str) { error("TODO: script o
 OpcodeReturn TattooTalk::cmdSetNPCVerbCAnimation(const byte *&str) { error("TODO: script opcode"); }
 OpcodeReturn TattooTalk::cmdSetNPCVerbScript(const byte *&str) { error("TODO: script opcode"); }
 OpcodeReturn TattooTalk::cmdSetNPCVerbTarget(const byte *&str) { error("TODO: script opcode"); }
-OpcodeReturn TattooTalk::cmdSetNPCWalkGraphics(const byte *&str) { error("TODO: script opcode"); }
+
+OpcodeReturn TattooTalk::cmdSetNPCWalkGraphics(const byte *&str) {
+	++str;
+	int npc = *str - 1;
+	People &people = *_vm->_people;
+	Person &person = people[npc];
+
+	// Build up walk library name for the given NPC
+	person._walkVGSName = "";
+	for (int idx = 0; idx < 8; ++idx) {
+		if (str[idx + 1] != '~')
+			person._walkVGSName += str[idx + 1];
+		else
+			break;
+	}
+	person._walkVGSName += ".VGS";
+
+	people._forceWalkReload = true;
+	str += 8;
+
+	return RET_SUCCESS;
+}
+
 OpcodeReturn TattooTalk::cmdSetSceneEntryFlag(const byte *&str) { error("TODO: script opcode"); }
 OpcodeReturn TattooTalk::cmdSetTalkSequence(const byte *&str) { error("TODO: script opcode"); }
 OpcodeReturn TattooTalk::cmdSetWalkControl(const byte *&str) { error("TODO: script opcode"); }


Commit: 5b90b56c1624752814253d2fa54d5d964da4e5e8
    https://github.com/scummvm/scummvm/commit/5b90b56c1624752814253d2fa54d5d964da4e5e8
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-24T21:34:35-04:00

Commit Message:
SHERLOCK: Implement cmdNextSong

Changed paths:
    engines/sherlock/talk.cpp



diff --git a/engines/sherlock/talk.cpp b/engines/sherlock/talk.cpp
index 3e3fcce..22e77fb 100644
--- a/engines/sherlock/talk.cpp
+++ b/engines/sherlock/talk.cpp
@@ -2051,7 +2051,24 @@ TattooTalk::TattooTalk(SherlockEngine *vm) : Talk(vm) {
 }
 
 OpcodeReturn TattooTalk::cmdMouseOnOff(const byte *&str) { error("TODO: script opcode"); }
-OpcodeReturn TattooTalk::cmdNextSong(const byte *&str) { error("TODO: script opcode"); }
+
+OpcodeReturn TattooTalk::cmdNextSong(const byte *&str) {
+	Sound &sound = *_vm->_sound;
+
+	// Get the name of the next song to play
+	++str;
+	sound._nextSongName = "";
+	for (int idx = 0; idx < 8; ++idx) {
+		if (str[idx] != '~')
+			sound._nextSongName += str[idx];
+		else
+			break;
+	}
+	str += 7;
+
+	return RET_SUCCESS;
+}
+
 OpcodeReturn TattooTalk::cmdNPCLabelGoto(const byte *&str) { error("TODO: script opcode"); }
 OpcodeReturn TattooTalk::cmdNPCLabelIfFlagGoto(const byte *&str) { error("TODO: script opcode"); }
 OpcodeReturn TattooTalk::cmdNPCLabelSet(const byte *&str) { error("TODO: script opcode"); }


Commit: 97bb33d6f3928d4e2857f06ab0dd0cc2c5d3c918
    https://github.com/scummvm/scummvm/commit/97bb33d6f3928d4e2857f06ab0dd0cc2c5d3c918
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-24T22:33:41-04:00

Commit Message:
SHERLOCK: Fix People data initialization and general start fixes

Changed paths:
    engines/sherlock/events.cpp
    engines/sherlock/objects.h
    engines/sherlock/people.cpp
    engines/sherlock/scalpel/scalpel.cpp
    engines/sherlock/talk.cpp



diff --git a/engines/sherlock/events.cpp b/engines/sherlock/events.cpp
index 94ddc9a..c201507 100644
--- a/engines/sherlock/events.cpp
+++ b/engines/sherlock/events.cpp
@@ -42,6 +42,8 @@ Events::Events(SherlockEngine *vm) {
 	_pressed = _released = false;
 	_rightPressed = _rightReleased = false;
 	_oldButtons = _oldRightButton = false;
+
+	loadCursors("rmouse.vgs");
 }
 
 Events::~Events() {
diff --git a/engines/sherlock/objects.h b/engines/sherlock/objects.h
index f104762..2a0de7f 100644
--- a/engines/sherlock/objects.h
+++ b/engines/sherlock/objects.h
@@ -116,12 +116,43 @@ struct WalkSequence {
 	void load(Common::SeekableReadStream &s);
 };
 
+enum { REVERSE_DIRECTION = 0x80 };
+#define NAMES_COUNT 4
+
+struct ActionType {
+	int _cAnimNum;
+	int _cAnimSpeed;
+	Common::String _names[NAMES_COUNT];
+
+	/**
+	 * Load the data for the action
+	 */
+	void load(Common::SeekableReadStream &s);
+};
+
+struct UseType {
+	int _cAnimNum;
+	int _cAnimSpeed;
+	Common::String _names[NAMES_COUNT];
+	int _useFlag;					// Which flag USE will set (if any)
+	Common::String _target;
+	Common::String _verb;
+
+	UseType();
+
+	/**
+	 * Load the data for the UseType
+	 */
+	void load(Common::SeekableReadStream &s, bool isRoseTattoo);
+};
+
+
 class Sprite {
 private:
 	static SherlockEngine *_vm;
 public:
-	Common::String _name;				
-	Common::String _description;		
+	Common::String _name;
+	Common::String _description;
 	Common::String _examine;			// Examine in-depth description
 	Common::String _pickUp;				// Message for if you can't pick up object
 
@@ -142,73 +173,69 @@ public:
 	int _status;						// Status: open/closed, moved/not moved
 	int8 _misc;							// Miscellaneous use
 	int _numFrames;						// How many frames the object has
-	ImageFile *_altImages;
-	bool _altSequences;
+
+	// Rose Tattoo fields
+	int _startSeq;						// Frame sequence starts at
+	int _flags;							// Flags for the sprite
+	int _aType;							// Tells if this is an object, person, talk, etc.
+	int _lookFrames;					// How many frames to play of a canim before pausing
+	int _seqCounter;					// How many times the sequence has been run
+	Common::Point _lookPosition;		// Where to look when examining object
+	int _lookFacing;					// Direction to face when examining object
+	int _lookCAnim;
+	int _seqStack;						// Allow gosubs to return to calling frame
+	int _seqTo;							// Allows 1-5, 8-3 type sequences encoded in 2 bytes
+	uint _descOffset;					// Tells where description starts in description text for scene
+	int _seqCounter2;					// Counter of calling frame sequence
+	uint _seqSize;						// Size of sequence
+	UseType _use[6];
+	int _quickDraw;						// Flag telling whether to use quick draw routine or not
+	int _scaleVal;						// Tells how to scale the sprite
+	int _requiredFlags1;				// This flag must also be set, or the sprite is hidden
+	int _gotoSeq;						// Used by Talk to tell which sequence to goto when able
+	int _talkSeq;						// Tells which talk sequence currently in use (Talk or Listen)
+	int _restoreSlot;					// Used when talk returns to the previous sequence
+
 	ImageFrame *_stopFrames[8];			// Stop/rest frame for each direction
+	ImageFile *_altImages;				// Images used for alternate NPC sequences
+	bool _altSequences;					// Which of the sequences the alt graphics apply to (0: main, 1=NPC seq)
+	int _centerWalk;					// Flag telling the walk code to offset the walk destination
+	Common::Point _adjust;				// Fine tuning adjustment to position when drawn
+	int _oldWalkSequence;
 public:
 	Sprite() { clear(); }
 
 	static void setVm(SherlockEngine *vm) { _vm = vm; }
 
 	/**
-	 * Reset the data for the sprite
-	 */
+	* Reset the data for the sprite
+	*/
 	void clear();
 
 	/**
-	 * Updates the image frame poiner for the sprite
-	 */
+	* Updates the image frame poiner for the sprite
+	*/
 	void setImageFrame();
 
 	/**
-	 * This adjusts the sprites position, as well as it's animation sequence:
-	 */
+	* This adjusts the sprites position, as well as it's animation sequence:
+	*/
 	void adjustSprite();
 
 	/**
-	 * Checks the sprite's position to see if it's collided with any special objects
-	 */
+	* Checks the sprite's position to see if it's collided with any special objects
+	*/
 	void checkSprite();
 
 	/**
-	 * Return frame width
-	 */
+	* Return frame width
+	*/
 	int frameWidth() const { return _imageFrame ? _imageFrame->_frame.w : 0; }
-	
-	/**
-	 * Return frame height
-	 */
-	int frameHeight() const { return _imageFrame ? _imageFrame->_frame.h : 0; }
-};
-
-enum { REVERSE_DIRECTION = 0x80 };
-#define NAMES_COUNT 4
-
-struct ActionType {
-	int _cAnimNum;
-	int _cAnimSpeed;
-	Common::String _names[NAMES_COUNT];
-
-	/**
-	 * Load the data for the action
-	 */
-	void load(Common::SeekableReadStream &s);
-};
-
-struct UseType {
-	int _cAnimNum;
-	int _cAnimSpeed;
-	Common::String _names[NAMES_COUNT];
-	int _useFlag;					// Which flag USE will set (if any)
-	Common::String _target;
-	Common::String _verb;
-
-	UseType();
 
 	/**
-	 * Load the data for the UseType
-	 */
-	void load(Common::SeekableReadStream &s, bool isRoseTattoo);
+	* Return frame height
+	*/
+	int frameHeight() const { return _imageFrame ? _imageFrame->_frame.h : 0; }
 };
 
 enum { OBJ_BEHIND = 1, OBJ_FLIPPED = 2, OBJ_FORWARD = 4, TURNON_OBJ = 0x20, TURNOFF_OBJ = 0x40 };
diff --git a/engines/sherlock/people.cpp b/engines/sherlock/people.cpp
index 7879f29..c03dde8 100644
--- a/engines/sherlock/people.cpp
+++ b/engines/sherlock/people.cpp
@@ -124,36 +124,55 @@ People::~People() {
 }
 
 void People::reset() {
-	// Note: The engine has theoretical support for two player characters but only the first one is used.
-	// Watson is, instead, handled by a different sprite in each scene, with a very simple initial movement, if any
-	Sprite &p = _data[PLAYER];
-
-	p._description = "Sherlock Holmes!";
-	p._type = CHARACTER;
-	p._position = Common::Point(10000, 11000);
-	p._sequenceNumber = STOP_DOWNRIGHT;
-	p._imageFrame = nullptr;
-	p._frameNumber = 1;
-	p._delta = Common::Point(0, 0);
-	p._oldPosition = Common::Point(0, 0);
-	p._oldSize = Common::Point(0, 0);
-	p._misc = 0;
-	p._walkCount = 0;
-	p._pickUp = "";
-	p._allow = 0;
-	p._noShapeSize = Common::Point(0, 0);
-	p._goto = Common::Point(0, 0);
-	p._status = 0;
-
-	// Load the default walk sequences
-	p._walkSequences.resize(MAX_HOLMES_SEQUENCE);
-	for (int idx = 0; idx < MAX_HOLMES_SEQUENCE; ++idx) {
-		p._walkSequences[idx]._sequences.clear();
-		
-		const byte *pSrc = &CHARACTER_SEQUENCES[idx][0];
-		do {
-			p._walkSequences[idx]._sequences.push_back(*pSrc);
-		} while (*pSrc++);
+	_data[0]._description = "Sherlock Holmes!";
+
+	// Note: Serrated Scalpel only uses a single Person slot for Sherlock.. Watson is handled by scene sprites
+	int count = IS_SERRATED_SCALPEL ? 1 : MAX_PLAYERS;
+	for (int idx = 0; idx < count; ++idx) {
+		Sprite &p = _data[idx];
+
+		p._type = (idx == 0) ? CHARACTER : INVALID;
+		if (IS_SERRATED_SCALPEL)
+			p._position = Point32(10000, 11000);
+		else
+			p._position = Point32(36000, 29000);
+
+		p._sequenceNumber = STOP_DOWNRIGHT;
+		p._imageFrame = nullptr;
+		p._frameNumber = 1;
+		p._delta = Common::Point(0, 0);
+		p._oldPosition = Common::Point(0, 0);
+		p._oldSize = Common::Point(0, 0);
+		p._misc = 0;
+		p._walkCount = 0;
+		p._pickUp = "";
+		p._allow = 0;
+		p._noShapeSize = Common::Point(0, 0);
+		p._goto = Common::Point(0, 0);
+		p._status = 0;
+		p._seqTo = 0;
+		p._seqCounter = p._seqCounter2 = 0;
+		p._seqStack = 0;
+		p._gotoSeq = p._talkSeq = 0;
+		p._restoreSlot = 0;
+		p._startSeq = 0;
+		p._walkSequences.clear();
+		p._altImages = nullptr;
+		p._altSequences = 0;
+		p._centerWalk = true;
+		p._adjust = Common::Point(0, 0);
+
+		// Load the default walk sequences
+		p._oldWalkSequence = -1;
+		p._walkSequences.resize(MAX_HOLMES_SEQUENCE);
+		for (int idx = 0; idx < MAX_HOLMES_SEQUENCE; ++idx) {
+			p._walkSequences[idx]._sequences.clear();
+
+			const byte *pSrc = &CHARACTER_SEQUENCES[idx][0];
+			do {
+				p._walkSequences[idx]._sequences.push_back(*pSrc);
+			} while (*pSrc++);
+		}
 	}
 
 	// Reset any walk path in progress when Sherlock leaves scenes
diff --git a/engines/sherlock/scalpel/scalpel.cpp b/engines/sherlock/scalpel/scalpel.cpp
index 2a107b4..6b72188 100644
--- a/engines/sherlock/scalpel/scalpel.cpp
+++ b/engines/sherlock/scalpel/scalpel.cpp
@@ -813,7 +813,6 @@ void ScalpelEngine::startScene() {
 		break;
 	}
 
-	_events->loadCursors("rmouse.vgs");
 	_events->setCursor(ARROW);
 
 	if (_scene->_goToScene == 99) {
diff --git a/engines/sherlock/talk.cpp b/engines/sherlock/talk.cpp
index 22e77fb..e3f8c7b 100644
--- a/engines/sherlock/talk.cpp
+++ b/engines/sherlock/talk.cpp
@@ -1577,12 +1577,20 @@ OpcodeReturn Talk::cmdGotoScene(const byte *&str) {
 }
 
 OpcodeReturn Talk::cmdHolmesOff(const byte *&str) {
-	_vm->_people->_holmesOn = false;
+	People &people = *_vm->_people;
+	people._holmesOn = false;
+	if (IS_ROSE_TATTOO)
+		people[PLAYER]._type = REMOVE;
+
 	return RET_SUCCESS;
 }
 
 OpcodeReturn Talk::cmdHolmesOn(const byte *&str) {
-	_vm->_people->_holmesOn = true;
+	People &people = *_vm->_people;
+	people._holmesOn = true;
+	if (IS_ROSE_TATTOO)
+		people[PLAYER]._type = CHARACTER;
+
 	return RET_SUCCESS;
 }
 


Commit: 871a4570e0aa11e0fc6b92c5c6bb588efc2f80ce
    https://github.com/scummvm/scummvm/commit/871a4570e0aa11e0fc6b92c5c6bb588efc2f80ce
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-24T23:15:33-04:00

Commit Message:
SHERLOCK: Fix display of first RT scene background

Changed paths:
    engines/sherlock/scene.cpp
    engines/sherlock/screen.cpp
    engines/sherlock/sherlock.cpp
    engines/sherlock/user_interface.cpp



diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp
index 0f679d7..0b4cd4e 100644
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@ -615,8 +615,12 @@ bool Scene::loadScene(const Common::String &filename) {
 	if (!_vm->isDemo()) {
 		// Reset the previous map location and position on overhead map
 		map._oldCharPoint = _currentScene;
-		map._overPos.x = map[_currentScene].x * 100 - 600;
-		map._overPos.y = map[_currentScene].y * 100 + 900;
+
+		if (IS_SERRATED_SCALPEL) {
+			map._overPos.x = map[_currentScene].x * 100 - 600;
+			map._overPos.y = map[_currentScene].y * 100 + 900;
+
+		}
 	}
 
 	events.clearEvents();
diff --git a/engines/sherlock/screen.cpp b/engines/sherlock/screen.cpp
index bb9dbd7..4dd91cf 100644
--- a/engines/sherlock/screen.cpp
+++ b/engines/sherlock/screen.cpp
@@ -182,6 +182,7 @@ void Screen::randomTransition() {
 	Events &events = *_vm->_events;
 	const int TRANSITION_MULTIPLIER = 0x15a4e35;
 	_dirtyRects.clear();
+	assert(IS_SERRATED_SCALPEL);
 
 	for (int idx = 0; idx <= 65535 && !_vm->shouldQuit(); ++idx) {
 		_transitionSeed = _transitionSeed * TRANSITION_MULTIPLIER + 1;
diff --git a/engines/sherlock/sherlock.cpp b/engines/sherlock/sherlock.cpp
index 14f2433..497841f 100644
--- a/engines/sherlock/sherlock.cpp
+++ b/engines/sherlock/sherlock.cpp
@@ -207,7 +207,9 @@ void SherlockEngine::loadConfig() {
 	ConfMan.registerDefault("font", 1);
 
 	_screen->setFont(ConfMan.getInt("font"));
-	_screen->_fadeStyle = ConfMan.getBool("fade_style");
+	if (getGameID() == GType_SerratedScalpel)
+		_screen->_fadeStyle = ConfMan.getBool("fade_style");
+
 	_ui->_helpStyle = ConfMan.getBool("help_style");
 	_ui->_slideWindows = ConfMan.getBool("window_style");
 	_people->_portraitsOn = ConfMan.getBool("portraits_on");
diff --git a/engines/sherlock/user_interface.cpp b/engines/sherlock/user_interface.cpp
index 7a6722a..4f83e91 100644
--- a/engines/sherlock/user_interface.cpp
+++ b/engines/sherlock/user_interface.cpp
@@ -2304,6 +2304,7 @@ TattooUserInterface::TattooUserInterface(SherlockEngine *vm): UserInterface(vm)
 
 void TattooUserInterface::handleInput() {
 	// TODO
+	_vm->_events->pollEventsAndWait();
 }
 
 } // End of namespace Sherlock


Commit: a7f7a4839888070331de5c8232feadfe182f332e
    https://github.com/scummvm/scummvm/commit/a7f7a4839888070331de5c8232feadfe182f332e
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-24T23:38:23-04:00

Commit Message:
SHERLOCK: Fix palette for RT scene

Changed paths:
    engines/sherlock/scene.cpp



diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp
index 0b4cd4e..989927b 100644
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@ -321,7 +321,8 @@ bool Scene::loadScene(const Common::String &filename) {
 
 		if (IS_ROSE_TATTOO) {
 			screen.initPaletteFade(bgHeader._bytesWritten);
-			screen.fadeRead(*rrmStream, screen._cMap, PALETTE_SIZE);
+			rrmStream->read(screen._cMap, PALETTE_SIZE);
+			screen.translatePalette(screen._cMap);
 			screen.setupBGArea(screen._cMap);
 
 			screen.initScrollVars();


Commit: c205fa6bd5a5dfe9c4150fd3ac5a14cbd1764e84
    https://github.com/scummvm/scummvm/commit/c205fa6bd5a5dfe9c4150fd3ac5a14cbd1764e84
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-25T08:21:57-04:00

Commit Message:
SHERLOCK: Free freeing and resetting People list

Changed paths:
    engines/sherlock/objects.cpp
    engines/sherlock/people.cpp



diff --git a/engines/sherlock/objects.cpp b/engines/sherlock/objects.cpp
index 0709f6b..31a209f 100644
--- a/engines/sherlock/objects.cpp
+++ b/engines/sherlock/objects.cpp
@@ -73,11 +73,16 @@ void Sprite::setImageFrame() {
 	int imageNumber = _walkSequences[_sequenceNumber][frameNum];
 	
 	if (IS_SERRATED_SCALPEL)
-		imageNumber = imageNumber + +_walkSequences[_sequenceNumber][0] - 2;
+		imageNumber = imageNumber + _walkSequences[_sequenceNumber][0] - 2;
 	else if (imageNumber > _numFrames)
 		imageNumber = 1;
 
-	_imageFrame = &(_altSequences ? *_altImages : *_images)[imageNumber];
+	// Get the images to use
+	ImageFile *images = _altSequences ? _altImages : _images;
+	assert(images);
+
+	// Set the frame pointer
+	_imageFrame = &(*images)[imageNumber];
 }
 
 void Sprite::adjustSprite() {
diff --git a/engines/sherlock/people.cpp b/engines/sherlock/people.cpp
index c03dde8..083e3c8 100644
--- a/engines/sherlock/people.cpp
+++ b/engines/sherlock/people.cpp
@@ -164,14 +164,17 @@ void People::reset() {
 
 		// Load the default walk sequences
 		p._oldWalkSequence = -1;
-		p._walkSequences.resize(MAX_HOLMES_SEQUENCE);
-		for (int idx = 0; idx < MAX_HOLMES_SEQUENCE; ++idx) {
-			p._walkSequences[idx]._sequences.clear();
-
-			const byte *pSrc = &CHARACTER_SEQUENCES[idx][0];
-			do {
-				p._walkSequences[idx]._sequences.push_back(*pSrc);
-			} while (*pSrc++);
+		
+		if (IS_SERRATED_SCALPEL) {
+			p._walkSequences.resize(MAX_HOLMES_SEQUENCE);
+			for (int seqIdx = 0; seqIdx < MAX_HOLMES_SEQUENCE; ++seqIdx) {
+				p._walkSequences[seqIdx]._sequences.clear();
+
+				const byte *pSrc = &CHARACTER_SEQUENCES[seqIdx][0];
+				do {
+					p._walkSequences[seqIdx]._sequences.push_back(*pSrc);
+				} while (*pSrc++);
+			}
 		}
 	}
 
@@ -259,6 +262,8 @@ bool People::freeWalk() {
 		if (_data[idx]._walkLoaded) {
 			delete _data[idx]._images;
 			_data[idx]._images = nullptr;
+			
+			_data[idx]._walkLoaded = false;
 			result = true;
 		}
 	}


Commit: 7a4d45679ab1dd5be9d59042171bd420de100b42
    https://github.com/scummvm/scummvm/commit/7a4d45679ab1dd5be9d59042171bd420de100b42
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-25T11:04:34-04:00

Commit Message:
SHERLOCK: Cleanup of checkBgShapes and updateBackground

Changed paths:
    engines/sherlock/people.cpp
    engines/sherlock/people.h
    engines/sherlock/scene.cpp
    engines/sherlock/scene.h
    engines/sherlock/sherlock.h
    engines/sherlock/talk.cpp



diff --git a/engines/sherlock/people.cpp b/engines/sherlock/people.cpp
index 083e3c8..bac147f 100644
--- a/engines/sherlock/people.cpp
+++ b/engines/sherlock/people.cpp
@@ -114,7 +114,7 @@ People::People(SherlockEngine *vm) : _vm(vm), _player(_data[0]) {
 }
 
 People::~People() {
-	for (int idx = 0; idx < MAX_PLAYERS; ++idx) {
+	for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
 		if (_data[idx]._walkLoaded)
 			delete _data[PLAYER]._images;
 	}
@@ -127,7 +127,7 @@ void People::reset() {
 	_data[0]._description = "Sherlock Holmes!";
 
 	// Note: Serrated Scalpel only uses a single Person slot for Sherlock.. Watson is handled by scene sprites
-	int count = IS_SERRATED_SCALPEL ? 1 : MAX_PLAYERS;
+	int count = IS_SERRATED_SCALPEL ? 1 : MAX_CHARACTERS;
 	for (int idx = 0; idx < count; ++idx) {
 		Sprite &p = _data[idx];
 
@@ -197,7 +197,7 @@ bool People::loadWalk() {
 			result = true;
 		}
 	} else {
-		for (int idx = 0; idx < MAX_PLAYERS; ++idx) {
+		for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
 			if (!_data[idx]._walkLoaded && (_data[idx]._type == CHARACTER || _data[idx]._type == HIDDEN_CHARACTER)) {
 				if (_data[idx]._type == HIDDEN_CHARACTER)
 					_data[idx]._type = INVALID;
@@ -258,7 +258,7 @@ bool People::loadWalk() {
 bool People::freeWalk() {
 	bool result = false;
 
-	for (int idx = 0; idx < MAX_PLAYERS; ++idx) {
+	for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
 		if (_data[idx]._walkLoaded) {
 			delete _data[idx]._images;
 			_data[idx]._images = nullptr;
@@ -700,7 +700,7 @@ void People::synchronize(Common::Serializer &s) {
 		s.syncAsSint16LE(_player._position.y);
 		s.syncAsSint16LE(_player._sequenceNumber);
 	} else {
-		for (int idx = 0; idx < MAX_PLAYERS; ++idx) {
+		for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
 			Person &p = _data[idx];
 			s.syncAsSint16LE(p._position.x);
 			s.syncAsSint16LE(p._position.y);
diff --git a/engines/sherlock/people.h b/engines/sherlock/people.h
index a196878..72bdc51 100644
--- a/engines/sherlock/people.h
+++ b/engines/sherlock/people.h
@@ -34,7 +34,7 @@ enum PeopleId {
 	PLAYER			= 0,
 	AL				= 0,
 	PEG				= 1,
-	MAX_PLAYERS		= 6,
+	MAX_CHARACTERS		= 6,
 	MAX_NPC			= 5,
 	MAX_NPC_PATH	= 200
 };
@@ -92,7 +92,7 @@ class SherlockEngine;
 class People {
 private:
 	SherlockEngine *_vm;
-	Person _data[MAX_PLAYERS];
+	Person _data[MAX_CHARACTERS];
 	int _oldWalkSequence;
 	int _srcZone, _destZone;
 public:
@@ -120,20 +120,15 @@ public:
 	~People();
 
 	Person &operator[](PeopleId id) {
-		assert(id < MAX_PLAYERS);
+		assert(id < MAX_CHARACTERS);
 		return _data[id];
 	}
 	Person &operator[](int idx) {
-		assert(idx < MAX_PLAYERS);
+		assert(idx < MAX_CHARACTERS);
 		return _data[idx];
 	}
 
 	/**
-	 * Returns true if Sherlock is visible on the screen and enabled
-	 */
-	bool isHolmesActive() const { return _data[0]._walkLoaded && _holmesOn; }
-
-	/**
 	 * Reset the player data
 	 */
 	void reset();
diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp
index 989927b..d7519d5 100644
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@ -833,11 +833,14 @@ void Scene::transitionToScene() {
 
 	updateBackground();
 
+	// Actually do the transition
 	if (screen._fadeStyle)
 		screen.randomTransition();
 	else
 		screen.blitFrom(screen._backBuffer1);
+	screen.update();
 
+	// Start any initial animation for the scene
 	if (cAnimNum != -1) {
 		CAnim &c = _cAnim[cAnimNum];
 		Common::Point pt = c._goto;
@@ -865,19 +868,26 @@ int Scene::toggleObject(const Common::String &name) {
 
 void Scene::updateBackground() {
 	People &people = *_vm->_people;
-	Screen &screen = *_vm->_screen;
-	Sprite &player = people[AL];
-
-	// Restrict drawing window
-	screen.setDisplayBounds(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCENE_HEIGHT));
 
 	// Update Holmes if he's turned on
-	if (people._holmesOn)
-		player.adjustSprite();
+	for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
+		if (people[idx]._type == CHARACTER)
+			people[idx].adjustSprite();
+	}
 
 	// Flag the bg shapes which need to be redrawn
-	checkBgShapes(player._imageFrame, Common::Point(player._position.x / 100,
-		player._position.y / 100));
+	checkBgShapes();
+
+	// Draw the shapes for the scene
+	drawAllShapes();
+}
+
+void Scene::drawAllShapes() {
+	People &people = *_vm->_people;
+	Screen &screen = *_vm->_screen;
+
+	// Restrict drawing window
+	screen.setDisplayBounds(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCENE_HEIGHT));
 
 	// Draw all active shapes which are behind the person
 	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
@@ -889,7 +899,7 @@ void Scene::updateBackground() {
 	for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
 		if (_canimShapes[idx]._type == ACTIVE_BG_SHAPE && _canimShapes[idx]._misc == BEHIND)
 			screen._backBuffer->transBlitFrom(*_canimShapes[idx]._imageFrame,
-				_canimShapes[idx]._position, _canimShapes[idx]._flags & OBJ_FLIPPED);
+			_canimShapes[idx]._position, _canimShapes[idx]._flags & OBJ_FLIPPED);
 	}
 
 	// Draw all active shapes which are normal and behind the person
@@ -902,33 +912,37 @@ void Scene::updateBackground() {
 	for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
 		if (_canimShapes[idx]._type == ACTIVE_BG_SHAPE && _canimShapes[idx]._misc == NORMAL_BEHIND)
 			screen._backBuffer->transBlitFrom(*_canimShapes[idx]._imageFrame, _canimShapes[idx]._position,
-				_canimShapes[idx]._flags & OBJ_FLIPPED);
+			_canimShapes[idx]._flags & OBJ_FLIPPED);
 	}
 
-	// Draw the player if he's active
-	if (player._type == CHARACTER && people.isHolmesActive()) {
-		bool flipped = player._sequenceNumber == WALK_LEFT || player._sequenceNumber == STOP_LEFT ||
-			player._sequenceNumber == WALK_UPLEFT || player._sequenceNumber == STOP_UPLEFT ||
-			player._sequenceNumber == WALK_DOWNRIGHT || player._sequenceNumber == STOP_DOWNRIGHT;
+	// Draw any active characters
+	for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
+		Person &p = people[idx];
+		if (p._type == CHARACTER && p._walkLoaded) {
+			bool flipped = IS_SERRATED_SCALPEL && (
+				p._sequenceNumber == WALK_LEFT || p._sequenceNumber == STOP_LEFT ||
+				p._sequenceNumber == WALK_UPLEFT || p._sequenceNumber == STOP_UPLEFT ||
+				p._sequenceNumber == WALK_DOWNRIGHT || p._sequenceNumber == STOP_DOWNRIGHT);
 
-		screen._backBuffer->transBlitFrom(*player._imageFrame, Common::Point(player._position.x / 100,
-			player._position.y / 100 - player.frameHeight()), flipped);
+			screen._backBuffer->transBlitFrom(*p._imageFrame, Common::Point(p._position.x / 100,
+				p._position.y / 100 - p.frameHeight()), flipped);
+		}
 	}
 
 	// Draw all static and active shapes that are NORMAL and are in front of the player
 	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
 		if ((_bgShapes[idx]._type == ACTIVE_BG_SHAPE || _bgShapes[idx]._type == STATIC_BG_SHAPE) &&
-				_bgShapes[idx]._misc == NORMAL_FORWARD)
+			_bgShapes[idx]._misc == NORMAL_FORWARD)
 			screen._backBuffer->transBlitFrom(*_bgShapes[idx]._imageFrame, _bgShapes[idx]._position,
-				_bgShapes[idx]._flags & OBJ_FLIPPED);
+			_bgShapes[idx]._flags & OBJ_FLIPPED);
 	}
 
 	// Draw all static and active canimations that are NORMAL and are in front of the player
 	for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
 		if ((_canimShapes[idx]._type == ACTIVE_BG_SHAPE || _canimShapes[idx]._type == STATIC_BG_SHAPE) &&
-				_canimShapes[idx]._misc == NORMAL_FORWARD)
+			_canimShapes[idx]._misc == NORMAL_FORWARD)
 			screen._backBuffer->transBlitFrom(*_canimShapes[idx]._imageFrame, _canimShapes[idx]._position,
-				_canimShapes[idx]._flags & OBJ_FLIPPED);
+			_canimShapes[idx]._flags & OBJ_FLIPPED);
 	}
 
 	// Draw all static and active shapes that are FORWARD
@@ -938,9 +952,9 @@ void Scene::updateBackground() {
 			_bgShapes[idx].frameHeight());
 
 		if ((_bgShapes[idx]._type == ACTIVE_BG_SHAPE || _bgShapes[idx]._type == STATIC_BG_SHAPE) &&
-				_bgShapes[idx]._misc == FORWARD)
+			_bgShapes[idx]._misc == FORWARD)
 			screen._backBuffer->transBlitFrom(*_bgShapes[idx]._imageFrame, _bgShapes[idx]._position,
-				_bgShapes[idx]._flags & OBJ_FLIPPED);
+			_bgShapes[idx]._flags & OBJ_FLIPPED);
 	}
 
 	// Draw all static and active canimations that are forward
@@ -948,7 +962,7 @@ void Scene::updateBackground() {
 		if ((_canimShapes[idx]._type == ACTIVE_BG_SHAPE || _canimShapes[idx]._type == STATIC_BG_SHAPE) &&
 			_canimShapes[idx]._misc == FORWARD)
 			screen._backBuffer->transBlitFrom(*_canimShapes[idx]._imageFrame, _canimShapes[idx]._position,
-				_canimShapes[idx]._flags & OBJ_FLIPPED);
+			_canimShapes[idx]._flags & OBJ_FLIPPED);
 	}
 
 	screen.resetDisplayBounds();
@@ -963,7 +977,11 @@ Exit *Scene::checkForExit(const Common::Rect &r) {
 	return nullptr;
 }
 
-void Scene::checkBgShapes(ImageFrame *frame, const Common::Point &pt) {
+void Scene::checkBgShapes() {
+	People &people = *_vm->_people;
+	Person &holmes = people._player;
+	Common::Point pt(holmes._position.x / 100, holmes._position.y / 100);
+
 	// Iterate through the shapes
 	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
 		Object &obj = _bgShapes[idx];
@@ -986,11 +1004,9 @@ void Scene::checkBgShapes(ImageFrame *frame, const Common::Point &pt) {
 			if ((obj._flags & 5) == 1) {
 				obj._misc = (pt.y < (obj._position.y + obj._imageFrame->_frame.h - 1)) ?
 				NORMAL_FORWARD : NORMAL_BEHIND;
-			}
-			else if (!(obj._flags & 1)) {
+			} else if (!(obj._flags & 1)) {
 				obj._misc = BEHIND;
-			}
-			else if (obj._flags & 4) {
+			} else if (obj._flags & 4) {
 				obj._misc = FORWARD;
 			}
 		}
@@ -1345,8 +1361,7 @@ void Scene::doBgAnim() {
 		people[AL].adjustSprite();
 
 	// Flag the bg shapes which need to be redrawn
-	checkBgShapes(people[AL]._imageFrame,
-		Common::Point(people[AL]._position.x / 100, people[AL]._position.y / 100));
+	checkBgShapes();
 
 	if (_currentScene == 12 && IS_SERRATED_SCALPEL)
 		((Scalpel::ScalpelEngine *)_vm)->doMirror12();
@@ -1382,7 +1397,7 @@ void Scene::doBgAnim() {
 	}
 
 	// Draw the person if not animating
-	if (people[AL]._type == CHARACTER && people.isHolmesActive()) {
+	if (people[AL]._type == CHARACTER && people[AL]._walkLoaded) {
 		// If Holmes is too far to the right, move him back so he's on-screen
 		int xRight = SHERLOCK_SCREEN_WIDTH - 2 - people[AL]._imageFrame->_frame.w;
 		int tempX = MIN(people[AL]._position.x / 100, xRight);
diff --git a/engines/sherlock/scene.h b/engines/sherlock/scene.h
index b0b5624..8067268 100644
--- a/engines/sherlock/scene.h
+++ b/engines/sherlock/scene.h
@@ -184,7 +184,7 @@ private:
 	 * it will flag it as needing to be drawn. If a non-animating shape is
 	 * colliding with another shape, it will also flag it as needing drawing
 	 */
-	void checkBgShapes(ImageFrame *frame, const Common::Point &pt);
+	void checkBgShapes();
 
 	/**
 	 * Restores objects to the correct status. This ensures that things like being opened or moved
@@ -192,6 +192,10 @@ private:
 	 */
 	void saveSceneStatus();
 
+	/**
+	 * Draw all the shapes, people and NPCs in the correct order
+	 */
+	void drawAllShapes();
 public:
 	int _currentScene;
 	int _goToScene;
diff --git a/engines/sherlock/sherlock.h b/engines/sherlock/sherlock.h
index bf8c0d6..467f20e 100644
--- a/engines/sherlock/sherlock.h
+++ b/engines/sherlock/sherlock.h
@@ -60,7 +60,7 @@ enum GameType {
 
 #define SHERLOCK_SCREEN_WIDTH _vm->_screen->w()
 #define SHERLOCK_SCREEN_HEIGHT _vm->_screen->h()
-#define SHERLOCK_SCENE_HEIGHT 138
+#define SHERLOCK_SCENE_HEIGHT (IS_SERRATED_SCALPEL ? 138 : 480)
 
 struct SherlockGameDescription;
 
diff --git a/engines/sherlock/talk.cpp b/engines/sherlock/talk.cpp
index e3f8c7b..b4be5ee 100644
--- a/engines/sherlock/talk.cpp
+++ b/engines/sherlock/talk.cpp
@@ -1578,18 +1578,14 @@ OpcodeReturn Talk::cmdGotoScene(const byte *&str) {
 
 OpcodeReturn Talk::cmdHolmesOff(const byte *&str) {
 	People &people = *_vm->_people;
-	people._holmesOn = false;
-	if (IS_ROSE_TATTOO)
-		people[PLAYER]._type = REMOVE;
+	people[PLAYER]._type = REMOVE;
 
 	return RET_SUCCESS;
 }
 
 OpcodeReturn Talk::cmdHolmesOn(const byte *&str) {
 	People &people = *_vm->_people;
-	people._holmesOn = true;
-	if (IS_ROSE_TATTOO)
-		people[PLAYER]._type = CHARACTER;
+	people[PLAYER]._type = CHARACTER;
 
 	return RET_SUCCESS;
 }


Commit: 8751abbbe382fb21cedcaa45464db8eba5df2bed
    https://github.com/scummvm/scummvm/commit/8751abbbe382fb21cedcaa45464db8eba5df2bed
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-25T23:07:11-04:00

Commit Message:
SHERLOCK: Add define for fixed integer multiplier

Changed paths:
    engines/sherlock/objects.h
    engines/sherlock/scene.cpp



diff --git a/engines/sherlock/objects.h b/engines/sherlock/objects.h
index 2a0de7f..7fe44c0 100644
--- a/engines/sherlock/objects.h
+++ b/engines/sherlock/objects.h
@@ -76,6 +76,7 @@ enum {
 
 #define MAX_HOLMES_SEQUENCE 16
 #define MAX_FRAME 30
+#define FIXED_INT_MULTIPLIER 100
 
 // code put into sequences to defines 1-10 type seqs
 #define SEQ_TO_CODE 67
diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp
index d7519d5..a1a165e 100644
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@ -200,8 +200,8 @@ void Scene::selectScene() {
 		_tempFadeStyle = 0;
 	}
 
-	people._walkDest = Common::Point(people[AL]._position.x / 100,
-		people[AL]._position.y / 100);
+	people._walkDest = Common::Point(people[AL]._position.x / FIXED_INT_MULTIPLIER,
+		people[AL]._position.y / FIXED_INT_MULTIPLIER);
 
 	_restoreFlag = true;
 	events.clearEvents();
@@ -618,8 +618,8 @@ bool Scene::loadScene(const Common::String &filename) {
 		map._oldCharPoint = _currentScene;
 
 		if (IS_SERRATED_SCALPEL) {
-			map._overPos.x = map[_currentScene].x * 100 - 600;
-			map._overPos.y = map[_currentScene].y * 100 + 900;
+			map._overPos.x = (map[_currentScene].x - 6) * FIXED_INT_MULTIPLIER;
+			map._overPos.y = (map[_currentScene].y + 9) * FIXED_INT_MULTIPLIER;
 
 		}
 	}
@@ -761,8 +761,8 @@ void Scene::transitionToScene() {
 		// Otherwise, this is a linked scene or entrance info, and must be translated
 		if (hSavedFacing < 8 && !saves._justLoaded) {
 			hSavedFacing = FS_TRANS[hSavedFacing];
-			hSavedPos.x *= 100;
-			hSavedPos.y *= 100;
+			hSavedPos.x *= FIXED_INT_MULTIPLIER;
+			hSavedPos.y *= FIXED_INT_MULTIPLIER;
 		}
 	}
 
@@ -802,7 +802,8 @@ void Scene::transitionToScene() {
 			}
 
 			if (Common::Rect(topLeft.x, topLeft.y, bottomRight.x, bottomRight.y).contains(
-				Common::Point(people[PLAYER]._position.x / 100, people[PLAYER]._position.y / 100))) {
+					Common::Point(people[PLAYER]._position.x / FIXED_INT_MULTIPLIER, 
+					people[PLAYER]._position.y / FIXED_INT_MULTIPLIER))) {
 				// Current point is already inside box - impact occurred on
 				// a previous call. So simply do nothing except talk until the
 				// player is clear of the box
@@ -924,8 +925,8 @@ void Scene::drawAllShapes() {
 				p._sequenceNumber == WALK_UPLEFT || p._sequenceNumber == STOP_UPLEFT ||
 				p._sequenceNumber == WALK_DOWNRIGHT || p._sequenceNumber == STOP_DOWNRIGHT);
 
-			screen._backBuffer->transBlitFrom(*p._imageFrame, Common::Point(p._position.x / 100,
-				p._position.y / 100 - p.frameHeight()), flipped);
+			screen._backBuffer->transBlitFrom(*p._imageFrame, Common::Point(p._position.x / FIXED_INT_MULTIPLIER,
+				p._position.y / FIXED_INT_MULTIPLIER - p.frameHeight()), flipped);
 		}
 	}
 
@@ -980,7 +981,7 @@ Exit *Scene::checkForExit(const Common::Rect &r) {
 void Scene::checkBgShapes() {
 	People &people = *_vm->_people;
 	Person &holmes = people._player;
-	Common::Point pt(holmes._position.x / 100, holmes._position.y / 100);
+	Common::Point pt(holmes._position.x / FIXED_INT_MULTIPLIER, holmes._position.y / FIXED_INT_MULTIPLIER);
 
 	// Iterate through the shapes
 	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
@@ -1400,13 +1401,13 @@ void Scene::doBgAnim() {
 	if (people[AL]._type == CHARACTER && people[AL]._walkLoaded) {
 		// If Holmes is too far to the right, move him back so he's on-screen
 		int xRight = SHERLOCK_SCREEN_WIDTH - 2 - people[AL]._imageFrame->_frame.w;
-		int tempX = MIN(people[AL]._position.x / 100, xRight);
+		int tempX = MIN(people[AL]._position.x / FIXED_INT_MULTIPLIER, xRight);
 
 		bool flipped = people[AL]._sequenceNumber == WALK_LEFT || people[AL]._sequenceNumber == STOP_LEFT ||
 			people[AL]._sequenceNumber == WALK_UPLEFT || people[AL]._sequenceNumber == STOP_UPLEFT ||
 			people[AL]._sequenceNumber == WALK_DOWNRIGHT || people[AL]._sequenceNumber == STOP_DOWNRIGHT;
 		screen._backBuffer->transBlitFrom(*people[AL]._imageFrame,
-			Common::Point(tempX, people[AL]._position.y / 100 - people[AL]._imageFrame->_frame.h), flipped);
+			Common::Point(tempX, people[AL]._position.y / FIXED_INT_MULTIPLIER - people[AL]._imageFrame->_frame.h), flipped);
 	}
 
 	// Draw all static and active shapes are NORMAL and are in front of the person
@@ -1466,8 +1467,8 @@ void Scene::doBgAnim() {
 				people[AL]._type = INVALID;
 			} else {
 				screen.flushImage(people[AL]._imageFrame,
-					Common::Point(people[AL]._position.x / 100,
-						people[AL]._position.y / 100 - people[AL].frameHeight()),
+					Common::Point(people[AL]._position.x / FIXED_INT_MULTIPLIER,
+						people[AL]._position.y / FIXED_INT_MULTIPLIER - people[AL].frameHeight()),
 					&people[AL]._oldPosition.x, &people[AL]._oldPosition.y,
 					&people[AL]._oldSize.x, &people[AL]._oldSize.y);
 			}


Commit: 361dc4ed8b651ff30b6e6ae6154250e3e5dbd75c
    https://github.com/scummvm/scummvm/commit/361dc4ed8b651ff30b6e6ae6154250e3e5dbd75c
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-26T08:18:50-04:00

Commit Message:
SHERLOCK: Fix map display

Changed paths:
    engines/sherlock/map.cpp
    engines/sherlock/map.h
    engines/sherlock/objects.cpp
    engines/sherlock/objects.h
    engines/sherlock/people.cpp
    engines/sherlock/people.h



diff --git a/engines/sherlock/map.cpp b/engines/sherlock/map.cpp
index 4f034d8..ffbca3f 100644
--- a/engines/sherlock/map.cpp
+++ b/engines/sherlock/map.cpp
@@ -293,7 +293,6 @@ void Map::setupSprites() {
 	p._type = CHARACTER;
 	p._position = Common::Point(12400, 5000);
 	p._sequenceNumber = 0;
-	p._walkSequences = _walkSequences;
 	p._images = _shapes;
 	p._imageFrame = nullptr;
 	p._frameNumber = 0;
@@ -306,8 +305,8 @@ void Map::setupSprites() {
 	p._noShapeSize = Common::Point(0, 0);
 	p._goto = Common::Point(28000, 15000);
 	p._status = 0;
+	p._walkSequences = _walkSequences;
 	p.setImageFrame();
-
 	scene._bgShapes.clear();
 }
 
diff --git a/engines/sherlock/map.h b/engines/sherlock/map.h
index 198b31e..e0c7d03 100644
--- a/engines/sherlock/map.h
+++ b/engines/sherlock/map.h
@@ -76,7 +76,7 @@ private:
 	ImageFile *_mapCursors;
 	ImageFile *_shapes;
 	ImageFile *_iconShapes;
-	Common::Array<WalkSequence> _walkSequences;
+	WalkSequences _walkSequences;
 	Point32 _lDrawnPos;
 	int _point;
 	bool _placesShown;
diff --git a/engines/sherlock/objects.cpp b/engines/sherlock/objects.cpp
index 31a209f..7338726 100644
--- a/engines/sherlock/objects.cpp
+++ b/engines/sherlock/objects.cpp
@@ -366,6 +366,34 @@ void Sprite::checkSprite() {
 
 /*----------------------------------------------------------------*/
 
+void WalkSequence::load(Common::SeekableReadStream &s) {
+	char buffer[9];
+	s.read(buffer, 9);
+	_vgsName = Common::String(buffer);
+	_horizFlip = s.readByte() != 0;
+
+	_sequences.resize(s.readUint16LE());
+	s.read(&_sequences[0], _sequences.size());
+}
+
+/*----------------------------------------------------------------*/
+
+WalkSequences &WalkSequences::operator=(const WalkSequences &src) {
+	resize(src.size());
+	for (uint idx = 0; idx < size(); ++idx) {
+		const WalkSequence &wSrc = src[idx];
+		WalkSequence &wDest = (*this)[idx];
+		wDest._horizFlip = wSrc._horizFlip;
+
+		wDest._sequences.resize(wSrc._sequences.size());
+		Common::copy(&wSrc._sequences[0], &wSrc._sequences[0] + wSrc._sequences.size(), &wDest._sequences[0]);
+	}
+
+	return *this;
+}
+
+/*----------------------------------------------------------------*/
+
 void ActionType::load(Common::SeekableReadStream &s) {
 	char buffer[12];
 
diff --git a/engines/sherlock/objects.h b/engines/sherlock/objects.h
index 7fe44c0..99746c9 100644
--- a/engines/sherlock/objects.h
+++ b/engines/sherlock/objects.h
@@ -117,6 +117,11 @@ struct WalkSequence {
 	void load(Common::SeekableReadStream &s);
 };
 
+class WalkSequences : public Common::Array < WalkSequence > {
+public:
+	WalkSequences &operator=(const WalkSequences &src);
+};
+
 enum { REVERSE_DIRECTION = 0x80 };
 #define NAMES_COUNT 4
 
@@ -157,7 +162,7 @@ public:
 	Common::String _examine;			// Examine in-depth description
 	Common::String _pickUp;				// Message for if you can't pick up object
 
-	Common::Array<WalkSequence> _walkSequences;	// Holds animation sequences
+	WalkSequences _walkSequences;		// Holds animation sequences
 	ImageFile *_images;					// Sprite images
 	ImageFrame *_imageFrame;			// Pointer to shape in the images
 	int _walkCount;						// Character walk counter
diff --git a/engines/sherlock/people.cpp b/engines/sherlock/people.cpp
index bac147f..6beae48 100644
--- a/engines/sherlock/people.cpp
+++ b/engines/sherlock/people.cpp
@@ -68,18 +68,6 @@ const char *const WALK_LIB_NAMES[10] = {
 
 /*----------------------------------------------------------------*/
 
-void WalkSequence::load(Common::SeekableReadStream &s) {
-	char buffer[9];
-	s.read(buffer, 9);
-	_vgsName = Common::String(buffer);
-	_horizFlip = s.readByte() != 0;
-
-	_sequences.resize(s.readUint16LE());
-	s.read(&_sequences[0], _sequences.size());
-}
-
-/*----------------------------------------------------------------*/
-
 Person::Person() : Sprite(), _walkLoaded(false), _npcIndex(0), _npcStack(0), _npcPause(false)  {
 	Common::fill(&_npcPath[0], &_npcPath[MAX_NPC_PATH], 0);
 }
@@ -156,7 +144,6 @@ void People::reset() {
 		p._gotoSeq = p._talkSeq = 0;
 		p._restoreSlot = 0;
 		p._startSeq = 0;
-		p._walkSequences.clear();
 		p._altImages = nullptr;
 		p._altSequences = 0;
 		p._centerWalk = true;
@@ -164,7 +151,7 @@ void People::reset() {
 
 		// Load the default walk sequences
 		p._oldWalkSequence = -1;
-		
+		p._walkSequences.clear();
 		if (IS_SERRATED_SCALPEL) {
 			p._walkSequences.resize(MAX_HOLMES_SEQUENCE);
 			for (int seqIdx = 0; seqIdx < MAX_HOLMES_SEQUENCE; ++seqIdx) {
diff --git a/engines/sherlock/people.h b/engines/sherlock/people.h
index 72bdc51..272c418 100644
--- a/engines/sherlock/people.h
+++ b/engines/sherlock/people.h
@@ -77,7 +77,6 @@ public:
 
 	// Rose Tattoo fields
 	Common::String _walkVGSName;		// Name of walk library person is using
-	Common::Array<WalkSequence> _walkSequences;
 public:
 	Person();
 


Commit: 57575b9068e5ec0c1229184a0404228989146fa5
    https://github.com/scummvm/scummvm/commit/57575b9068e5ec0c1229184a0404228989146fa5
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-26T21:18:45-04:00

Commit Message:
SHERLOCK: Starting to split Scene class, implemented checkBgShapes changes

Changed paths:
    engines/sherlock/objects.cpp
    engines/sherlock/objects.h
    engines/sherlock/scene.cpp
    engines/sherlock/scene.h
    engines/sherlock/sherlock.cpp



diff --git a/engines/sherlock/objects.cpp b/engines/sherlock/objects.cpp
index 7338726..3e8838c 100644
--- a/engines/sherlock/objects.cpp
+++ b/engines/sherlock/objects.cpp
@@ -1141,6 +1141,18 @@ void CAnim::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
 
 /*----------------------------------------------------------------*/
 
+CAnimStream::CAnimStream() {
+	_stream = nullptr;
+	_frameSize = 0;
+	_images = nullptr;
+	_imageFrame = nullptr;
+	_flags = 0;
+	_scaleVal = 0;
+	_zPlacement = 0;
+}
+
+/*----------------------------------------------------------------*/
+
 SceneImage::SceneImage() {
 	_images = nullptr;
 	_maxFrames = 0;
diff --git a/engines/sherlock/objects.h b/engines/sherlock/objects.h
index 99746c9..ec5c2e7 100644
--- a/engines/sherlock/objects.h
+++ b/engines/sherlock/objects.h
@@ -413,6 +413,24 @@ struct CAnim {
 	void load(Common::SeekableReadStream &s, bool isRoseTattoo);
 };
 
+struct CAnimStream {
+	Common::SeekableReadStream *_stream;	// Stream to read frames from
+	int _frameSize;					// Temporary used to store the frame size
+
+	void *_images;					// TOOD: FIgure out hwo to hook up ImageFile with streaming support
+	ImageFrame *_imageFrame;
+
+	Common::Point _position;		// Animation position
+	Common::Rect _oldBounds;		// Bounds of previous frame
+	Common::Rect _removeBounds;		// Remove area for just drawn frame
+
+	int _flags;						// Flags
+	int _scaleVal;					// Specifies the scale amount
+	int _zPlacement;				// Used by doBgAnim for determining Z order
+
+	CAnimStream();
+};
+
 struct SceneImage {
 	ImageFile *_images;				// Object images
 	int _maxFrames;					// How many frames in object
diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp
index a1a165e..63203e1 100644
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@ -150,6 +150,13 @@ void ScaleZone::load(Common::SeekableReadStream &s) {
 
 /*----------------------------------------------------------------*/
 
+Scene *Scene::init(SherlockEngine *vm) {
+	if (vm->getGameID() == GType_SerratedScalpel)
+		return new ScalpelScene(vm);
+	else
+		return new TattooScene(vm);
+}
+
 Scene::Scene(SherlockEngine *vm): _vm(vm) {
 	for (int idx = 0; idx < SCENES_COUNT; ++idx)
 		Common::fill(&_sceneStats[idx][0], &_sceneStats[idx][65], false);
@@ -978,42 +985,6 @@ Exit *Scene::checkForExit(const Common::Rect &r) {
 	return nullptr;
 }
 
-void Scene::checkBgShapes() {
-	People &people = *_vm->_people;
-	Person &holmes = people._player;
-	Common::Point pt(holmes._position.x / FIXED_INT_MULTIPLIER, holmes._position.y / FIXED_INT_MULTIPLIER);
-
-	// Iterate through the shapes
-	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
-		Object &obj = _bgShapes[idx];
-		if (obj._type == STATIC_BG_SHAPE || obj._type == ACTIVE_BG_SHAPE) {
-			if ((obj._flags & 5) == 1) {
-				obj._misc = (pt.y < (obj._position.y + obj.frameHeight() - 1)) ?
-					NORMAL_FORWARD : NORMAL_BEHIND;
-			} else if (!(obj._flags & OBJ_BEHIND)) {
-				obj._misc = BEHIND;
-			} else if (obj._flags & OBJ_FORWARD) {
-				obj._misc = FORWARD;
-			}
-		}
-	}
-
-	// Iterate through the canimshapes
-	for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
-		Object &obj = _canimShapes[idx];
-		if (obj._type == STATIC_BG_SHAPE || obj._type == ACTIVE_BG_SHAPE) {
-			if ((obj._flags & 5) == 1) {
-				obj._misc = (pt.y < (obj._position.y + obj._imageFrame->_frame.h - 1)) ?
-				NORMAL_FORWARD : NORMAL_BEHIND;
-			} else if (!(obj._flags & 1)) {
-				obj._misc = BEHIND;
-			} else if (obj._flags & 4) {
-				obj._misc = FORWARD;
-			}
-		}
-	}
-}
-
 int Scene::startCAnim(int cAnimNum, int playRate) {
 	Events &events = *_vm->_events;
 	Map &map = *_vm->_map;
@@ -1658,5 +1629,80 @@ void Scene::setNPCPath(int npc) {
 	talk.talkTo(pathFile);
 }
 
+void Scene::checkBgShapes() {
+	People &people = *_vm->_people;
+	Person &holmes = people._player;
+	Common::Point pt(holmes._position.x / FIXED_INT_MULTIPLIER, holmes._position.y / FIXED_INT_MULTIPLIER);
+
+	// Iterate through the shapes
+	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+		Object &obj = _bgShapes[idx];
+		if (obj._type == ACTIVE_BG_SHAPE || (IS_SERRATED_SCALPEL && obj._type == STATIC_BG_SHAPE)) {
+			if ((obj._flags & 5) == 1) {
+				obj._misc = (pt.y < (obj._position.y + obj.frameHeight() - 1)) ?
+					NORMAL_FORWARD : NORMAL_BEHIND;
+			} else if (!(obj._flags & OBJ_BEHIND)) {
+				obj._misc = BEHIND;
+			} else if (obj._flags & OBJ_FORWARD) {
+				obj._misc = FORWARD;
+			}
+		}
+	}
+}
+
+/*----------------------------------------------------------------*/
+
+void ScalpelScene::checkBgShapes() {
+	People &people = *_vm->_people;
+	Person &holmes = people._player;
+	Common::Point pt(holmes._position.x / FIXED_INT_MULTIPLIER, holmes._position.y / FIXED_INT_MULTIPLIER);
+
+	// Call the base scene method to handle bg shapes
+	Scene::checkBgShapes();
+
+	// Iterate through the canim list
+	for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
+		Object &obj = _canimShapes[idx];
+		if (obj._type == STATIC_BG_SHAPE || obj._type == ACTIVE_BG_SHAPE) {
+			if ((obj._flags & 5) == 1) {
+				obj._misc = (pt.y < (obj._position.y + obj._imageFrame->_frame.h - 1)) ?
+				NORMAL_FORWARD : NORMAL_BEHIND;
+			} else if (!(obj._flags & 1)) {
+				obj._misc = BEHIND;
+			} else if (obj._flags & 4) {
+				obj._misc = FORWARD;
+			}
+		}
+	}
+}
+
+/*----------------------------------------------------------------*/
+
+void TattooScene::checkBgShapes() {
+	People &people = *_vm->_people;
+	Person &holmes = people._player;
+	Common::Point pt(holmes._position.x / FIXED_INT_MULTIPLIER, holmes._position.y / FIXED_INT_MULTIPLIER);
+
+	// Call the base scene method to handle bg shapes
+	Scene::checkBgShapes();
+
+	// Check for any active playing animation
+	if (_activeCAnim._images && _activeCAnim._zPlacement != REMOVE) {
+		switch (_activeCAnim._flags & 3) {
+		case 0:
+			_activeCAnim._zPlacement = BEHIND;
+			break;
+		case 1:
+			_activeCAnim._zPlacement = ((_activeCAnim._position.y + _activeCAnim._imageFrame->_frame.h - 1)) ?
+				NORMAL_FORWARD : NORMAL_BEHIND;
+			break;
+		case 2:
+			_activeCAnim._zPlacement = FORWARD;
+			break;
+		default:
+			break;
+		}
+	}
+}
 
 } // End of namespace Sherlock
diff --git a/engines/sherlock/scene.h b/engines/sherlock/scene.h
index 8067268..50f8f07 100644
--- a/engines/sherlock/scene.h
+++ b/engines/sherlock/scene.h
@@ -140,7 +140,6 @@ struct SceneTripEntry {
 
 class Scene {
 private:
-	SherlockEngine *_vm;
 	Common::String _rrmName;
 	bool _loadingSavedGame;
 
@@ -180,13 +179,6 @@ private:
 	void transitionToScene();
 
 	/**
-	 * Checks all the background shapes. If a background shape is animating,
-	 * it will flag it as needing to be drawn. If a non-animating shape is
-	 * colliding with another shape, it will also flag it as needing drawing
-	 */
-	void checkBgShapes();
-
-	/**
 	 * Restores objects to the correct status. This ensures that things like being opened or moved
 	 * will remain the same on future visits to the scene
 	 */
@@ -196,6 +188,17 @@ private:
 	 * Draw all the shapes, people and NPCs in the correct order
 	 */
 	void drawAllShapes();
+protected:
+	SherlockEngine *_vm;
+
+	/**
+	 * Checks all the background shapes. If a background shape is animating,
+	 * it will flag it as needing to be drawn. If a non-animating shape is
+	 * colliding with another shape, it will also flag it as needing drawing
+	 */
+	virtual void checkBgShapes();
+
+	Scene(SherlockEngine *vm);
 public:
 	int _currentScene;
 	int _goToScene;
@@ -228,8 +231,8 @@ public:
 	int _cAnimFramePause;
 	Common::Array<SceneTripEntry> _sceneTripCounters;
 public:
-	Scene(SherlockEngine *vm);
-	~Scene();
+	static Scene *init(SherlockEngine *vm);
+	virtual ~Scene();
 
 	/**
 	 * Handles loading the scene specified by _goToScene
@@ -315,6 +318,32 @@ public:
 	void setNPCPath(int npc);
 };
 
+class ScalpelScene : public Scene {
+protected:
+	/**
+	 * Checks all the background shapes. If a background shape is animating,
+	 * it will flag it as needing to be drawn. If a non-animating shape is
+	 * colliding with another shape, it will also flag it as needing drawing
+	 */
+	virtual void checkBgShapes();
+public:
+	ScalpelScene(SherlockEngine *vm) : Scene(vm) {}
+};
+
+class TattooScene : public Scene {
+private:
+	CAnimStream _activeCAnim;
+protected:
+	/**
+	 * Checks all the background shapes. If a background shape is animating,
+	 * it will flag it as needing to be drawn. If a non-animating shape is
+	 * colliding with another shape, it will also flag it as needing drawing
+	 */
+	virtual void checkBgShapes();
+public:
+	TattooScene(SherlockEngine *vm) : Scene(vm) {}
+};
+
 } // End of namespace Sherlock
 
 #endif
diff --git a/engines/sherlock/sherlock.cpp b/engines/sherlock/sherlock.cpp
index 497841f..03c1055 100644
--- a/engines/sherlock/sherlock.cpp
+++ b/engines/sherlock/sherlock.cpp
@@ -92,7 +92,7 @@ void SherlockEngine::initialize() {
 	_journal = new Journal(this);
 	_people = new People(this);
 	_saves = new SaveManager(this, _targetName);
-	_scene = new Scene(this);
+	_scene = Scene::init(this);
 	_screen = new Screen(this);
 	_sound = new Sound(this, _mixer);
 	_talk = Talk::init(this);


Commit: fdf1617432f5c339728241d641e5fc2a5dc8ffa8
    https://github.com/scummvm/scummvm/commit/fdf1617432f5c339728241d641e5fc2a5dc8ffa8
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-26T22:05:27-04:00

Commit Message:
SHERLOK: Beginnings of split of doBgAnim logic

Changed paths:
    engines/sherlock/events.cpp
    engines/sherlock/events.h
    engines/sherlock/scene.cpp
    engines/sherlock/scene.h



diff --git a/engines/sherlock/events.cpp b/engines/sherlock/events.cpp
index c201507..a02a06c 100644
--- a/engines/sherlock/events.cpp
+++ b/engines/sherlock/events.cpp
@@ -75,6 +75,14 @@ void Events::setCursor(const Graphics::Surface &src) {
 	showCursor();
 }
 
+void Events::animateCursorIfNeeded() {
+	if (_cursorId >= WAIT && _cursorId < (WAIT + 3)) {
+		CursorId newId = (WAIT + 2) ? WAIT : (CursorId)((int)_cursorId + 1);
+		setCursor(newId);
+	}
+}
+
+
 void Events::showCursor() {
 	CursorMan.showMouse(true);
 }
diff --git a/engines/sherlock/events.h b/engines/sherlock/events.h
index c19a92d..b35109f 100644
--- a/engines/sherlock/events.h
+++ b/engines/sherlock/events.h
@@ -33,7 +33,7 @@ namespace Sherlock {
 #define GAME_FRAME_RATE 60
 #define GAME_FRAME_TIME (1000 / GAME_FRAME_RATE)
 
-enum CursorId { ARROW = 0, MAGNIFY = 1, WAIT = 2, INVALID_CURSOR = -1 };
+enum CursorId { ARROW = 0, MAGNIFY = 1, WAIT = 2, EXIT_ZONES_START = 5, INVALID_CURSOR = -1 };
 
 class SherlockEngine;
 
@@ -78,6 +78,11 @@ public:
 	void setCursor(const Graphics::Surface &src);
 
 	/**
+	 * Animates the mouse cursor if the Wait cursor is showing
+	 */
+	void animateCursorIfNeeded();
+
+	/**
 	 * Show the mouse cursor
 	 */
 	void showCursor();
diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp
index 63203e1..41aafff 100644
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@ -1199,53 +1199,15 @@ int Scene::startCAnim(int cAnimNum, int playRate) {
 
 void Scene::doBgAnim() {
 	Events &events = *_vm->_events;
-	Inventory &inv = *_vm->_inventory;
 	People &people = *_vm->_people;
 	Screen &screen = *_vm->_screen;
-	Sound &sound = *_vm->_sound;
 	Talk &talk = *_vm->_talk;
-	UserInterface &ui = *_vm->_ui;
-
-	screen.setDisplayBounds(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCENE_HEIGHT));
-
-	int cursorId = events.getCursor();
 	Common::Point mousePos = events.mousePos();
+	events.animateCursorIfNeeded();
 
+	screen.setDisplayBounds(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCENE_HEIGHT));
 	talk._talkToAbort = false;
 
-	// Animate the mouse cursor
-	if (cursorId >= WAIT) {
-		if (++cursorId > (WAIT + 2))
-			cursorId = WAIT;
-
-		events.setCursor((CursorId)cursorId);
-	}
-
-	if (ui._menuMode == LOOK_MODE) {
-		if (mousePos.y > CONTROLS_Y1)
-			events.setCursor(ARROW);
-		else if (mousePos.y < CONTROLS_Y)
-			events.setCursor(MAGNIFY);
-	}
-
-	// Check for setting magnifying glass cursor
-	if (ui._menuMode == INV_MODE || ui._menuMode == USE_MODE || ui._menuMode == GIVE_MODE) {
-		if (inv._invMode == INVMODE_LOOK) {
-			// Only show Magnifying glass cursor if it's not on the inventory command line
-			if (mousePos.y < CONTROLS_Y || mousePos.y >(CONTROLS_Y1 + 13))
-				events.setCursor(MAGNIFY);
-			else
-				events.setCursor(ARROW);
-		} else {
-			events.setCursor(ARROW);
-		}
-	}
-
-	if (sound._diskSoundPlaying && !*sound._soundIsOn) {
-		// Loaded sound just finished playing
-		sound.freeDigiSound();
-	}
-
 	if (_restoreFlag) {
 		if (people[AL]._type == CHARACTER)
 			people[AL].checkSprite();
@@ -1676,8 +1638,48 @@ void ScalpelScene::checkBgShapes() {
 	}
 }
 
+void ScalpelScene::doBgAnim() {
+	Inventory &inv = *_vm->_inventory;
+	Events &events = *_vm->_events;
+	Sound &sound = *_vm->_sound;
+	UserInterface &ui = *_vm->_ui;
+	Common::Point mousePos = events.mousePos();
+
+	if (ui._menuMode == LOOK_MODE) {
+		if (mousePos.y > CONTROLS_Y1)
+			events.setCursor(ARROW);
+		else if (mousePos.y < CONTROLS_Y)
+			events.setCursor(MAGNIFY);
+	}
+
+	// Check for setting magnifying glass cursor
+	if (ui._menuMode == INV_MODE || ui._menuMode == USE_MODE || ui._menuMode == GIVE_MODE) {
+		if (inv._invMode == INVMODE_LOOK) {
+			// Only show Magnifying glass cursor if it's not on the inventory command line
+			if (mousePos.y < CONTROLS_Y || mousePos.y >(CONTROLS_Y1 + 13))
+				events.setCursor(MAGNIFY);
+			else
+				events.setCursor(ARROW);
+		} else {
+			events.setCursor(ARROW);
+		}
+	}
+
+	if (sound._diskSoundPlaying && !*sound._soundIsOn) {
+		// Loaded sound just finished playing
+		sound.freeDigiSound();
+	}
+
+	// Handle doing the actual drawing
+	Scene::doBgAnim();
+}
+
 /*----------------------------------------------------------------*/
 
+TattooScene::TattooScene(SherlockEngine *vm) : Scene(vm) {
+	_arrowZone = -1;
+}
+
 void TattooScene::checkBgShapes() {
 	People &people = *_vm->_people;
 	Person &holmes = people._player;
@@ -1705,4 +1707,34 @@ void TattooScene::checkBgShapes() {
 	}
 }
 
+void TattooScene::doBgAnim() {
+	Events &events = *_vm->_events;
+	UserInterface &ui = *_vm->_ui;
+	Common::Point mousePos = events.mousePos();
+
+	// If we're in Look Mode, make sure the cursor is the magnifying glass
+	if (ui._menuMode == LOOK_MODE && events.getCursor() != MAGNIFY)
+		events.setCursor(MAGNIFY);
+
+	// See if the mouse is over any of the arrow zones, and if so, change the cursor to the correct
+	// arrow cursor indicating the direcetion of the exit
+	if (events.getCursor() == ARROW || events.getCursor() >= EXIT_ZONES_START) {
+		CursorId cursorId = ARROW;
+
+		if (ui._menuMode == STD_MODE && _arrowZone != -1 && _currentScene != 90) {
+			for (uint idx = 0; idx < _exits.size(); ++idx) {
+				Exit &exit = _exits[idx];
+				if (exit.contains(mousePos))
+					cursorId = (CursorId)(exit._image + EXIT_ZONES_START);
+			}
+		}
+
+		events.setCursor(cursorId);
+	}
+
+	// Handle doing the actual drawing
+	_restoreFlag = true;
+	Scene::doBgAnim();
+}
+
 } // End of namespace Sherlock
diff --git a/engines/sherlock/scene.h b/engines/sherlock/scene.h
index 50f8f07..2aecdfa 100644
--- a/engines/sherlock/scene.h
+++ b/engines/sherlock/scene.h
@@ -273,9 +273,9 @@ public:
 	int toggleObject(const Common::String &name);
 
 	/**
-	 * Animate all objects and people.
+	 * Draw all objects and characters.
 	 */
-	void doBgAnim();
+	virtual void doBgAnim();
 
 	/**
 	 * Attempts to find a background shape within the passed bounds. If found,
@@ -328,11 +328,17 @@ protected:
 	virtual void checkBgShapes();
 public:
 	ScalpelScene(SherlockEngine *vm) : Scene(vm) {}
+
+	/**
+	 * Draw all objects and characters.
+	 */
+	virtual void doBgAnim();
 };
 
 class TattooScene : public Scene {
 private:
 	CAnimStream _activeCAnim;
+	int _arrowZone;
 protected:
 	/**
 	 * Checks all the background shapes. If a background shape is animating,
@@ -341,7 +347,12 @@ protected:
 	 */
 	virtual void checkBgShapes();
 public:
-	TattooScene(SherlockEngine *vm) : Scene(vm) {}
+	TattooScene(SherlockEngine *vm);
+
+	/**
+	 * Draw all objects and characters.
+	 */
+	virtual void doBgAnim();
 };
 
 } // End of namespace Sherlock


Commit: 1b3856b5b6819bb493b25fc79f0ed76429dc3500
    https://github.com/scummvm/scummvm/commit/1b3856b5b6819bb493b25fc79f0ed76429dc3500
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-27T20:26:40-04:00

Commit Message:
SHERLOCK: Implemented initial background clearing of RT doBgAnim

Changed paths:
    engines/sherlock/inventory.cpp
    engines/sherlock/scene.cpp
    engines/sherlock/scene.h
    engines/sherlock/screen.h
    engines/sherlock/settings.cpp
    engines/sherlock/settings.h
    engines/sherlock/talk.cpp
    engines/sherlock/talk.h
    engines/sherlock/tattoo/tattoo.cpp
    engines/sherlock/tattoo/tattoo.h
    engines/sherlock/user_interface.cpp
    engines/sherlock/user_interface.h



diff --git a/engines/sherlock/inventory.cpp b/engines/sherlock/inventory.cpp
index bbb7c75..7ec0b64 100644
--- a/engines/sherlock/inventory.cpp
+++ b/engines/sherlock/inventory.cpp
@@ -244,7 +244,7 @@ void Inventory::drawInventory(InvNewMode mode) {
 	}
 
 	assert(IS_SERRATED_SCALPEL);
-	((ScalpelUserInterface *)_vm->_ui)->_oldUse = -1;
+	((Scalpel::ScalpelUserInterface *)_vm->_ui)->_oldUse = -1;
 }
 
 void Inventory::invCommands(bool slamIt) {
@@ -324,7 +324,7 @@ void Inventory::refreshInv() {
 	
 	Screen &screen = *_vm->_screen;
 	Talk &talk = *_vm->_talk;
-	ScalpelUserInterface &ui = *(ScalpelUserInterface *)_vm->_ui;
+	Scalpel::ScalpelUserInterface &ui = *(Scalpel::ScalpelUserInterface *)_vm->_ui;
 
 	ui._invLookFlag = true;
 	freeInv();
diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp
index 41aafff..18690fb 100644
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@ -24,6 +24,7 @@
 #include "sherlock/sherlock.h"
 #include "sherlock/scalpel/scalpel.h"
 #include "sherlock/screen.h"
+#include "sherlock/tattoo/tattoo.h"
 
 namespace Sherlock {
 
@@ -152,9 +153,9 @@ void ScaleZone::load(Common::SeekableReadStream &s) {
 
 Scene *Scene::init(SherlockEngine *vm) {
 	if (vm->getGameID() == GType_SerratedScalpel)
-		return new ScalpelScene(vm);
+		return new Scalpel::ScalpelScene(vm);
 	else
-		return new TattooScene(vm);
+		return new Tattoo::TattooScene(vm);
 }
 
 Scene::Scene(SherlockEngine *vm): _vm(vm) {
@@ -1197,20 +1198,209 @@ int Scene::startCAnim(int cAnimNum, int playRate) {
 	return 1;
 }
 
-void Scene::doBgAnim() {
+int Scene::findBgShape(const Common::Rect &r) {
+	if (!_doBgAnimDone)
+		// New frame hasn't been drawn yet
+		return -1;
+
+	for (int idx = (int)_bgShapes.size() - 1; idx >= 0; --idx) {
+		Object &o = _bgShapes[idx];
+		if (o._type != INVALID && o._type != NO_SHAPE && o._type != HIDDEN
+			&& o._aType <= PERSON) {
+			if (r.intersects(o.getNewBounds()))
+				return idx;
+		} else if (o._type == NO_SHAPE) {
+			if (r.intersects(o.getNoShapeBounds()))
+				return idx;
+		}
+	}
+
+	return -1;
+}
+
+int Scene::checkForZones(const Common::Point &pt, int zoneType) {
+	int matches = 0;
+
+	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+		Object &o = _bgShapes[idx];
+		if ((o._aType == zoneType && o._type != INVALID) && o._type != HIDDEN) {
+			Common::Rect r = o._type == NO_SHAPE ? o.getNoShapeBounds() : o.getNewBounds();
+
+			if (r.contains(pt)) {
+				++matches;
+				o.setFlagsAndToggles();
+				_vm->_talk->talkTo(o._use[0]._target);
+			}
+		}
+	}
+
+	return matches;
+}
+
+int Scene::whichZone(const Common::Point &pt) {
+	for (uint idx = 0; idx < _zones.size(); ++idx) {
+		if (_zones[idx].contains(pt))
+			return idx;
+	}
+
+	return -1;
+}
+
+int Scene::closestZone(const Common::Point &pt) {
+	int dist = 1000;
+	int zone = -1;
+
+	for (uint idx = 0; idx < _zones.size(); ++idx) {
+		Common::Point zc((_zones[idx].left + _zones[idx].right) / 2,
+			(_zones[idx].top + _zones[idx].bottom) / 2);
+		int d = ABS(zc.x - pt.x) + ABS(zc.y - pt.y);
+
+		if (d < dist) {
+			// Found a closer zone
+			dist = d;
+			zone = idx;
+		}
+	}
+
+	return zone;
+}
+
+void Scene::synchronize(Common::Serializer &s) {
+	if (s.isSaving())
+		saveSceneStatus();
+
+	if (s.isSaving()) {
+		s.syncAsSint16LE(_currentScene);
+	} else {
+		s.syncAsSint16LE(_goToScene);
+		_loadingSavedGame = true;
+	}
+
+	for (int sceneNum = 0; sceneNum < SCENES_COUNT; ++sceneNum) {
+		for (int flag = 0; flag < 65; ++flag) {
+			s.syncAsByte(_sceneStats[sceneNum][flag]);
+		}
+	}
+}
+
+void Scene::setNPCPath(int npc) {
+	People &people = *_vm->_people;
+	Talk &talk = *_vm->_talk;
+	
+	people[npc].clearNPC();
+	people[npc]._name = Common::String::format("WATS%.2dA", _currentScene);
+
+	// If we're in the middle of a script that will continue once the scene is loaded,
+	// return without calling the path script
+	if (talk._scriptMoreFlag == 1 || talk._scriptMoreFlag == 3)
+		return;
+
+	// Turn off all the NPCs, since the talk script will turn them back on as needed
+	for (uint idx = 0; idx < MAX_NPC; ++idx)
+		people[idx + 1]._type = INVALID;
+
+	// Call the path script for the scene
+	Common::String pathFile = Common::String::format("PATH%.2dA", _currentScene);
+	talk.talkTo(pathFile);
+}
+
+void Scene::checkBgShapes() {
+	People &people = *_vm->_people;
+	Person &holmes = people._player;
+	Common::Point pt(holmes._position.x / FIXED_INT_MULTIPLIER, holmes._position.y / FIXED_INT_MULTIPLIER);
+
+	// Iterate through the shapes
+	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+		Object &obj = _bgShapes[idx];
+		if (obj._type == ACTIVE_BG_SHAPE || (IS_SERRATED_SCALPEL && obj._type == STATIC_BG_SHAPE)) {
+			if ((obj._flags & 5) == 1) {
+				obj._misc = (pt.y < (obj._position.y + obj.frameHeight() - 1)) ?
+					NORMAL_FORWARD : NORMAL_BEHIND;
+			} else if (!(obj._flags & OBJ_BEHIND)) {
+				obj._misc = BEHIND;
+			} else if (obj._flags & OBJ_FORWARD) {
+				obj._misc = FORWARD;
+			}
+		}
+	}
+}
+
+/*----------------------------------------------------------------*/
+
+namespace Scalpel {
+
+void ScalpelScene::checkBgShapes() {
+	People &people = *_vm->_people;
+	Person &holmes = people._player;
+	Common::Point pt(holmes._position.x / FIXED_INT_MULTIPLIER, holmes._position.y / FIXED_INT_MULTIPLIER);
+
+	// Call the base scene method to handle bg shapes
+	Scene::checkBgShapes();
+
+	// Iterate through the canim list
+	for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
+		Object &obj = _canimShapes[idx];
+		if (obj._type == STATIC_BG_SHAPE || obj._type == ACTIVE_BG_SHAPE) {
+			if ((obj._flags & 5) == 1) {
+				obj._misc = (pt.y < (obj._position.y + obj._imageFrame->_frame.h - 1)) ?
+				NORMAL_FORWARD : NORMAL_BEHIND;
+			} else if (!(obj._flags & 1)) {
+				obj._misc = BEHIND;
+			} else if (obj._flags & 4) {
+				obj._misc = FORWARD;
+			}
+		}
+	}
+}
+
+void ScalpelScene::doBgAnimCheckCursor() {
+	Inventory &inv = *_vm->_inventory;
+	Events &events = *_vm->_events;
+	Sound &sound = *_vm->_sound;
+	UserInterface &ui = *_vm->_ui;
+	Common::Point mousePos = events.mousePos();
+
+	if (ui._menuMode == LOOK_MODE) {
+		if (mousePos.y > CONTROLS_Y1)
+			events.setCursor(ARROW);
+		else if (mousePos.y < CONTROLS_Y)
+			events.setCursor(MAGNIFY);
+	}
+
+	// Check for setting magnifying glass cursor
+	if (ui._menuMode == INV_MODE || ui._menuMode == USE_MODE || ui._menuMode == GIVE_MODE) {
+		if (inv._invMode == INVMODE_LOOK) {
+			// Only show Magnifying glass cursor if it's not on the inventory command line
+			if (mousePos.y < CONTROLS_Y || mousePos.y >(CONTROLS_Y1 + 13))
+				events.setCursor(MAGNIFY);
+			else
+				events.setCursor(ARROW);
+		} else {
+			events.setCursor(ARROW);
+		}
+	}
+
+	if (sound._diskSoundPlaying && !*sound._soundIsOn) {
+		// Loaded sound just finished playing
+		sound.freeDigiSound();
+	}
+}
+
+void ScalpelScene::doBgAnim() {
+	Scalpel::ScalpelEngine &vm = *((Scalpel::ScalpelEngine *)_vm);
 	Events &events = *_vm->_events;
 	People &people = *_vm->_people;
 	Screen &screen = *_vm->_screen;
 	Talk &talk = *_vm->_talk;
-	Common::Point mousePos = events.mousePos();
-	events.animateCursorIfNeeded();
 
 	screen.setDisplayBounds(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCENE_HEIGHT));
 	talk._talkToAbort = false;
 
 	if (_restoreFlag) {
-		if (people[AL]._type == CHARACTER)
-			people[AL].checkSprite();
+		for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
+			if (people[idx]._type == CHARACTER)
+				people[idx].checkSprite();
+		}
 
 		for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
 			if (_bgShapes[idx]._type == ACTIVE_BG_SHAPE)
@@ -1225,8 +1415,8 @@ void Scene::doBgAnim() {
 				_canimShapes[idx].checkObject();
 		}
 
-		if (_currentScene == 12 && IS_SERRATED_SCALPEL)
-			((Scalpel::ScalpelEngine *)_vm)->eraseMirror12();
+		if (_currentScene == 12)
+			vm.eraseMirror12();
 
 		// Restore the back buffer from the back buffer 2 in the changed area
 		Common::Rect bounds(people[AL]._oldPosition.x, people[AL]._oldPosition.y,
@@ -1297,8 +1487,8 @@ void Scene::doBgAnim() {
 	// Flag the bg shapes which need to be redrawn
 	checkBgShapes();
 
-	if (_currentScene == 12 && IS_SERRATED_SCALPEL)
-		((Scalpel::ScalpelEngine *)_vm)->doMirror12();
+	if (_currentScene == 12)
+		vm.doMirror12();
 
 	// Draw all active shapes which are behind the person
 	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
@@ -1407,8 +1597,8 @@ void Scene::doBgAnim() {
 			}
 		}
 
-		if (_currentScene == 12 && IS_SERRATED_SCALPEL)
-			((Scalpel::ScalpelEngine *)_vm)->flushMirror12();
+		if (_currentScene == 12)
+			vm.flushMirror12();
 
 		for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
 			Object &o = _bgShapes[idx];
@@ -1485,199 +1675,16 @@ void Scene::doBgAnim() {
 	}
 }
 
-int Scene::findBgShape(const Common::Rect &r) {
-	if (!_doBgAnimDone)
-		// New frame hasn't been drawn yet
-		return -1;
-
-	for (int idx = (int)_bgShapes.size() - 1; idx >= 0; --idx) {
-		Object &o = _bgShapes[idx];
-		if (o._type != INVALID && o._type != NO_SHAPE && o._type != HIDDEN
-			&& o._aType <= PERSON) {
-			if (r.intersects(o.getNewBounds()))
-				return idx;
-		} else if (o._type == NO_SHAPE) {
-			if (r.intersects(o.getNoShapeBounds()))
-				return idx;
-		}
-	}
-
-	return -1;
-}
-
-int Scene::checkForZones(const Common::Point &pt, int zoneType) {
-	int matches = 0;
-
-	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
-		Object &o = _bgShapes[idx];
-		if ((o._aType == zoneType && o._type != INVALID) && o._type != HIDDEN) {
-			Common::Rect r = o._type == NO_SHAPE ? o.getNoShapeBounds() : o.getNewBounds();
-
-			if (r.contains(pt)) {
-				++matches;
-				o.setFlagsAndToggles();
-				_vm->_talk->talkTo(o._use[0]._target);
-			}
-		}
-	}
-
-	return matches;
-}
-
-int Scene::whichZone(const Common::Point &pt) {
-	for (uint idx = 0; idx < _zones.size(); ++idx) {
-		if (_zones[idx].contains(pt))
-			return idx;
-	}
-
-	return -1;
-}
-
-int Scene::closestZone(const Common::Point &pt) {
-	int dist = 1000;
-	int zone = -1;
-
-	for (uint idx = 0; idx < _zones.size(); ++idx) {
-		Common::Point zc((_zones[idx].left + _zones[idx].right) / 2,
-			(_zones[idx].top + _zones[idx].bottom) / 2);
-		int d = ABS(zc.x - pt.x) + ABS(zc.y - pt.y);
-
-		if (d < dist) {
-			// Found a closer zone
-			dist = d;
-			zone = idx;
-		}
-	}
-
-	return zone;
-}
-
-void Scene::synchronize(Common::Serializer &s) {
-	if (s.isSaving())
-		saveSceneStatus();
-
-	if (s.isSaving()) {
-		s.syncAsSint16LE(_currentScene);
-	} else {
-		s.syncAsSint16LE(_goToScene);
-		_loadingSavedGame = true;
-	}
-
-	for (int sceneNum = 0; sceneNum < SCENES_COUNT; ++sceneNum) {
-		for (int flag = 0; flag < 65; ++flag) {
-			s.syncAsByte(_sceneStats[sceneNum][flag]);
-		}
-	}
-}
-
-void Scene::setNPCPath(int npc) {
-	People &people = *_vm->_people;
-	Talk &talk = *_vm->_talk;
-	
-	people[npc].clearNPC();
-	people[npc]._name = Common::String::format("WATS%.2dA", _currentScene);
-
-	// If we're in the middle of a script that will continue once the scene is loaded,
-	// return without calling the path script
-	if (talk._scriptMoreFlag == 1 || talk._scriptMoreFlag == 3)
-		return;
-
-	// Turn off all the NPCs, since the talk script will turn them back on as needed
-	for (uint idx = 0; idx < MAX_NPC; ++idx)
-		people[idx + 1]._type = INVALID;
-
-	// Call the path script for the scene
-	Common::String pathFile = Common::String::format("PATH%.2dA", _currentScene);
-	talk.talkTo(pathFile);
-}
-
-void Scene::checkBgShapes() {
-	People &people = *_vm->_people;
-	Person &holmes = people._player;
-	Common::Point pt(holmes._position.x / FIXED_INT_MULTIPLIER, holmes._position.y / FIXED_INT_MULTIPLIER);
-
-	// Iterate through the shapes
-	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
-		Object &obj = _bgShapes[idx];
-		if (obj._type == ACTIVE_BG_SHAPE || (IS_SERRATED_SCALPEL && obj._type == STATIC_BG_SHAPE)) {
-			if ((obj._flags & 5) == 1) {
-				obj._misc = (pt.y < (obj._position.y + obj.frameHeight() - 1)) ?
-					NORMAL_FORWARD : NORMAL_BEHIND;
-			} else if (!(obj._flags & OBJ_BEHIND)) {
-				obj._misc = BEHIND;
-			} else if (obj._flags & OBJ_FORWARD) {
-				obj._misc = FORWARD;
-			}
-		}
-	}
-}
+} // End of namespace Scalpel
 
 /*----------------------------------------------------------------*/
 
-void ScalpelScene::checkBgShapes() {
-	People &people = *_vm->_people;
-	Person &holmes = people._player;
-	Common::Point pt(holmes._position.x / FIXED_INT_MULTIPLIER, holmes._position.y / FIXED_INT_MULTIPLIER);
-
-	// Call the base scene method to handle bg shapes
-	Scene::checkBgShapes();
-
-	// Iterate through the canim list
-	for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
-		Object &obj = _canimShapes[idx];
-		if (obj._type == STATIC_BG_SHAPE || obj._type == ACTIVE_BG_SHAPE) {
-			if ((obj._flags & 5) == 1) {
-				obj._misc = (pt.y < (obj._position.y + obj._imageFrame->_frame.h - 1)) ?
-				NORMAL_FORWARD : NORMAL_BEHIND;
-			} else if (!(obj._flags & 1)) {
-				obj._misc = BEHIND;
-			} else if (obj._flags & 4) {
-				obj._misc = FORWARD;
-			}
-		}
-	}
-}
-
-void ScalpelScene::doBgAnim() {
-	Inventory &inv = *_vm->_inventory;
-	Events &events = *_vm->_events;
-	Sound &sound = *_vm->_sound;
-	UserInterface &ui = *_vm->_ui;
-	Common::Point mousePos = events.mousePos();
-
-	if (ui._menuMode == LOOK_MODE) {
-		if (mousePos.y > CONTROLS_Y1)
-			events.setCursor(ARROW);
-		else if (mousePos.y < CONTROLS_Y)
-			events.setCursor(MAGNIFY);
-	}
-
-	// Check for setting magnifying glass cursor
-	if (ui._menuMode == INV_MODE || ui._menuMode == USE_MODE || ui._menuMode == GIVE_MODE) {
-		if (inv._invMode == INVMODE_LOOK) {
-			// Only show Magnifying glass cursor if it's not on the inventory command line
-			if (mousePos.y < CONTROLS_Y || mousePos.y >(CONTROLS_Y1 + 13))
-				events.setCursor(MAGNIFY);
-			else
-				events.setCursor(ARROW);
-		} else {
-			events.setCursor(ARROW);
-		}
-	}
-
-	if (sound._diskSoundPlaying && !*sound._soundIsOn) {
-		// Loaded sound just finished playing
-		sound.freeDigiSound();
-	}
-
-	// Handle doing the actual drawing
-	Scene::doBgAnim();
-}
-
-/*----------------------------------------------------------------*/
+namespace Tattoo {
 
 TattooScene::TattooScene(SherlockEngine *vm) : Scene(vm) {
 	_arrowZone = -1;
+	_mask = _mask1 = nullptr;
+	_maskCounter = 0;
 }
 
 void TattooScene::checkBgShapes() {
@@ -1707,7 +1714,7 @@ void TattooScene::checkBgShapes() {
 	}
 }
 
-void TattooScene::doBgAnim() {
+void TattooScene::doBgAnimCheckCursor() {
 	Events &events = *_vm->_events;
 	UserInterface &ui = *_vm->_ui;
 	Common::Point mousePos = events.mousePos();
@@ -1731,10 +1738,106 @@ void TattooScene::doBgAnim() {
 
 		events.setCursor(cursorId);
 	}
+}
 
-	// Handle doing the actual drawing
-	_restoreFlag = true;
-	Scene::doBgAnim();
+void TattooScene::doBgAnimHandleMask() {
+	TattooEngine &vm = *((TattooEngine *)_vm);
+	People &people = *_vm->_people;
+	Screen &screen = *_vm->_screen;
+	TattooUserInterface &ui = *((TattooUserInterface *)_vm->_ui);
+	
+	static const int16 OFFSETS[16] = { -1, -2, -3, -3, -2, -1, -1, 0, 1, 2, 3, 3, 2, 1, 0, 0 };
+
+	if (_mask != nullptr) {
+		if (screen._backBuffer1.w() > screen.w())
+			screen.blitFrom(screen._backBuffer1, Common::Point(0, 0), Common::Rect(screen._currentScroll, 0,
+			screen._currentScroll + screen.w(), screen.h()));
+		else
+			screen.blitFrom(screen._backBuffer1);
+
+		switch (_currentScene) {
+		case 7:
+			if (++_maskCounter == 2) {
+				_maskCounter = 0;
+				if (--_maskOffset.x < 0)
+					_maskOffset.x = SHERLOCK_SCREEN_WIDTH - 1;
+			}
+			break;
+
+		case 8:
+			_maskOffset.x += 2;
+			if (_maskOffset.x >= SHERLOCK_SCREEN_WIDTH)
+				_maskOffset.x = 0;
+			break;
+
+		case 18:
+		case 68:
+			++_maskCounter;
+			if (_maskCounter / 4 >= 16)
+				_maskCounter = 0;
+
+			_maskOffset.x = OFFSETS[_maskCounter / 4];
+			break;
+
+		case 53:
+			if (++_maskCounter == 2) {
+				_maskCounter = 0;
+				if (++_maskOffset.x == screen._backBuffer1.w())
+					_maskOffset.x = 0;
+			}
+			break;
+
+		default:
+			break;
+		}
+	} else {
+		// Standard scene without mask, so call user interface to erase any UI elements as necessary
+		ui.doBgAnimRestoreUI();
+		
+		// Restore background for any areas covered by characters and shapes
+		for (uint idx = 0; idx < MAX_CHARACTERS; ++idx)
+			screen.restoreBackground(Common::Rect(people[idx]._oldPosition.x, people[idx]._oldPosition.y,
+				people[idx]._oldPosition.x + people[idx]._oldSize.x, people[idx]._oldPosition.y + people[idx]._oldSize.y));
+
+		for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+			Object &obj = _bgShapes[idx];
+						
+			if ((obj._type == ACTIVE_BG_SHAPE && (obj._maxFrames > 1 || obj._delta.x != 0 || obj._delta.y != 0)) || 
+					obj._type == HIDE_SHAPE || obj._type == REMOVE)
+				screen._backBuffer1.blitFrom(*obj._imageFrame, obj._oldPosition, 
+					Common::Rect(obj._oldPosition.x, obj._oldPosition.y, obj._oldPosition.x + obj._oldSize.x,
+						obj._oldPosition.y + obj._oldSize.y));
+		}
+
+		// If credits are active, erase the area they cover
+		if (vm._creditsActive)
+			vm.eraseCredits();
+	}
+}
+
+void TattooScene::doBgAnim() {
+	doBgAnimCheckCursor();
+
+//	Events &events = *_vm->_events;
+	People &people = *_vm->_people;
+//	Scene &scene = *_vm->_scene;
+	Screen &screen = *_vm->_screen;
+	Talk &talk = *_vm->_talk;
+
+	screen.setDisplayBounds(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCENE_HEIGHT));
+	talk._talkToAbort = false;
+
+	for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
+		if (people[idx]._type == CHARACTER)
+			people[idx].checkSprite();
+	}
+
+	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+		if (_bgShapes[idx]._type == ACTIVE_BG_SHAPE)
+			_bgShapes[idx].checkObject();
+	}
 }
 
+} // End of namespace Tattoo
+
 } // End of namespace Sherlock
diff --git a/engines/sherlock/scene.h b/engines/sherlock/scene.h
index 2aecdfa..1bd23fc 100644
--- a/engines/sherlock/scene.h
+++ b/engines/sherlock/scene.h
@@ -275,7 +275,7 @@ public:
 	/**
 	 * Draw all objects and characters.
 	 */
-	virtual void doBgAnim();
+	virtual void doBgAnim() = 0;
 
 	/**
 	 * Attempts to find a background shape within the passed bounds. If found,
@@ -318,7 +318,11 @@ public:
 	void setNPCPath(int npc);
 };
 
+namespace Scalpel {
+
 class ScalpelScene : public Scene {
+private:
+	void doBgAnimCheckCursor();
 protected:
 	/**
 	 * Checks all the background shapes. If a background shape is animating,
@@ -335,10 +339,19 @@ public:
 	virtual void doBgAnim();
 };
 
+} // End of namespace Scalpel
+
+namespace Tattoo {
+
 class TattooScene : public Scene {
 private:
-	CAnimStream _activeCAnim;
 	int _arrowZone;
+	int _maskCounter;
+	Common::Point _maskOffset;
+private:
+	void doBgAnimCheckCursor();
+
+	void doBgAnimHandleMask();
 protected:
 	/**
 	 * Checks all the background shapes. If a background shape is animating,
@@ -347,6 +360,9 @@ protected:
 	 */
 	virtual void checkBgShapes();
 public:
+	ImageFile *_mask, *_mask1;
+	CAnimStream _activeCAnim;
+public:
 	TattooScene(SherlockEngine *vm);
 
 	/**
@@ -355,6 +371,8 @@ public:
 	virtual void doBgAnim();
 };
 
+} // End of namespace Tattoo
+
 } // End of namespace Sherlock
 
 #endif
diff --git a/engines/sherlock/screen.h b/engines/sherlock/screen.h
index 58c7d8f..e730329 100644
--- a/engines/sherlock/screen.h
+++ b/engines/sherlock/screen.h
@@ -72,7 +72,6 @@ private:
 	byte _lookupTable[PALETTE_COUNT];
 	byte _lookupTable1[PALETTE_COUNT];
 	int _scrollSize;
-	int _currentScroll;
 	int _targetScroll;
 private:
 	/**
@@ -102,6 +101,7 @@ public:
 	byte _cMap[PALETTE_SIZE];
 	byte _sMap[PALETTE_SIZE];
 	byte _tMap[PALETTE_SIZE];
+	int _currentScroll;
 public:
 	Screen(SherlockEngine *vm);
 	virtual ~Screen();
diff --git a/engines/sherlock/settings.cpp b/engines/sherlock/settings.cpp
index cae5c6c..98a13a3 100644
--- a/engines/sherlock/settings.cpp
+++ b/engines/sherlock/settings.cpp
@@ -25,6 +25,8 @@
 
 namespace Sherlock {
 
+namespace Scalpel {
+
 static const int SETUP_POINTS[12][4]  = {
 	{ 4, 154, 101, 53 },		// Exit
 	{ 4, 165, 101, 53 },		// Music Toggle
@@ -333,4 +335,6 @@ void Settings::show(SherlockEngine *vm) {
 	ui._key = -1;
 }
 
+} // End of namespace Scalpel
+
 } // End of namespace Sherlock
diff --git a/engines/sherlock/settings.h b/engines/sherlock/settings.h
index fc5fb29..ff2e647 100644
--- a/engines/sherlock/settings.h
+++ b/engines/sherlock/settings.h
@@ -28,7 +28,8 @@
 namespace Sherlock {
 
 class SherlockEngine;
-class UserInterface;
+
+namespace Scalpel {
 
 class Settings {
 private:
@@ -55,6 +56,8 @@ public:
 	static void show(SherlockEngine *vm);
 };
 
+} // End of namespace Scalpel
+
 } // End of namespace Sherlock
 
 #endif
diff --git a/engines/sherlock/talk.cpp b/engines/sherlock/talk.cpp
index b4be5ee..5e9cb02 100644
--- a/engines/sherlock/talk.cpp
+++ b/engines/sherlock/talk.cpp
@@ -332,7 +332,7 @@ void Talk::talkTo(const Common::String &filename) {
 	if (IS_SERRATED_SCALPEL) {
 		// Restore any pressed button
 		if (!ui._windowOpen && savedMode != STD_MODE)
-			((ScalpelUserInterface *)_vm->_ui)->restoreButton((int)(savedMode - 1));
+			((Scalpel::ScalpelUserInterface *)_vm->_ui)->restoreButton((int)(savedMode - 1));
 	}
 
 	// Clear the ui counter so that anything displayed on the info line
diff --git a/engines/sherlock/talk.h b/engines/sherlock/talk.h
index dc6789c..a5f81f3 100644
--- a/engines/sherlock/talk.h
+++ b/engines/sherlock/talk.h
@@ -108,8 +108,8 @@ enum {
 enum OpcodeReturn { RET_EXIT = -1, RET_SUCCESS = 0, RET_CONTINUE = 1 };
 
 class SherlockEngine;
-class ScalpelUserInterface;
 class Talk;
+namespace Scalpel { class ScalpelUserInterface; };
 
 typedef OpcodeReturn(Talk::*OpcodeMethod)(const byte *&str);
 
@@ -164,7 +164,7 @@ struct TalkSequences {
 };
 
 class Talk {
-	friend class ScalpelUserInterface;
+	friend class Scalpel::ScalpelUserInterface;
 private:
 	/**
 	 * Remove any voice commands from a loaded statement list
diff --git a/engines/sherlock/tattoo/tattoo.cpp b/engines/sherlock/tattoo/tattoo.cpp
index 47a7c2a..6d90416 100644
--- a/engines/sherlock/tattoo/tattoo.cpp
+++ b/engines/sherlock/tattoo/tattoo.cpp
@@ -27,13 +27,15 @@ namespace Sherlock {
 
 namespace Tattoo {
 
+TattooEngine::TattooEngine(OSystem *syst, const SherlockGameDescription *gameDesc) :
+		SherlockEngine(syst, gameDesc) {
+	_creditsActive = false;
+}
+
 void TattooEngine::showOpening() {
 	// TODO
 }
 
-/**
- * Initialize the engine
- */
 void TattooEngine::initialize() {
 	initGraphics(640, 480, true);
 
@@ -52,9 +54,6 @@ void TattooEngine::initialize() {
 	loadInitialPalette();
 }
 
-/**
- * Starting a scene within the game
- */
 void TattooEngine::startScene() {
 	// TODO
 }
@@ -69,6 +68,10 @@ void TattooEngine::loadInitialPalette() {
 	delete stream;
 }
 
+void TattooEngine::eraseCredits() {
+	// TODO
+}
+
 } // End of namespace Tattoo
 
 } // End of namespace Scalpel
diff --git a/engines/sherlock/tattoo/tattoo.h b/engines/sherlock/tattoo/tattoo.h
index b9224e0..b6a8510 100644
--- a/engines/sherlock/tattoo/tattoo.h
+++ b/engines/sherlock/tattoo/tattoo.h
@@ -36,16 +36,27 @@ private:
 	 */
 	void loadInitialPalette();
 protected:
+	/**
+	 * Initialize the engine
+	 */
 	virtual void initialize();
 
 	virtual void showOpening();
 
+	/**
+	 * Starting a scene within the game
+	 */
 	virtual void startScene();
 public:
-	TattooEngine(OSystem *syst, const SherlockGameDescription *gameDesc) :
-		SherlockEngine(syst, gameDesc) {}
-
+	bool _creditsActive;
+public:
+	TattooEngine(OSystem *syst, const SherlockGameDescription *gameDesc);
 	virtual ~TattooEngine() {}
+
+	/**
+	 * Erase any area of the screen covered by credits
+	 */
+	void eraseCredits();
 };
 
 } // End of namespace Tattoo
diff --git a/engines/sherlock/user_interface.cpp b/engines/sherlock/user_interface.cpp
index 4f83e91..06ec62b 100644
--- a/engines/sherlock/user_interface.cpp
+++ b/engines/sherlock/user_interface.cpp
@@ -82,9 +82,9 @@ const char *const MUSE[] = {
 
 UserInterface *UserInterface::init(SherlockEngine *vm) {
 	if (vm->getGameID() == GType_SerratedScalpel)
-		return new ScalpelUserInterface(vm);
+		return new Scalpel::ScalpelUserInterface(vm);
 	else
-		return new TattooUserInterface(vm);
+		return new Tattoo::TattooUserInterface(vm);
 }
 
 UserInterface::UserInterface(SherlockEngine *vm) : _vm(vm) {
@@ -108,6 +108,8 @@ UserInterface::UserInterface(SherlockEngine *vm) : _vm(vm) {
 
 /*----------------------------------------------------------------*/
 
+namespace Scalpel {
+
 ScalpelUserInterface::ScalpelUserInterface(SherlockEngine *vm): UserInterface(vm) {
 	_controls = new ImageFile("menu.all");
 	_controlPanel = new ImageFile("controls.vgs");
@@ -2296,10 +2298,15 @@ void ScalpelUserInterface::checkAction(ActionType &action, const char *const mes
 	events.setCursor(ARROW);
 }
 
+}
+
 /*----------------------------------------------------------------*/
 
+namespace Tattoo {
+
 TattooUserInterface::TattooUserInterface(SherlockEngine *vm): UserInterface(vm) {
-	//
+	_menuBuffer = nullptr;
+	_invMenuBuffer = nullptr;
 }
 
 void TattooUserInterface::handleInput() {
@@ -2307,4 +2314,44 @@ void TattooUserInterface::handleInput() {
 	_vm->_events->pollEventsAndWait();
 }
 
+void TattooUserInterface::doBgAnimRestoreUI() {
+	TattooScene &scene = *((TattooScene *)_vm->_scene);
+	Screen &screen = *_vm->_screen;
+
+	// If _oldMenuBounds was set, then either a new menu has been opened or the current menu has been closed.
+	// Either way, we need to restore the area where the menu was displayed
+	if (_oldMenuBounds.width() > 0)
+		screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_oldMenuBounds.left, _oldMenuBounds.top),
+			_oldMenuBounds);
+
+	if (_oldInvMenuBounds.width() > 0)
+		screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_oldInvMenuBounds.left, _oldInvMenuBounds.top),
+			_oldInvMenuBounds);
+
+	if (_menuBuffer != nullptr)
+		screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_menuBounds.left, _menuBounds.top), _menuBounds);
+	if (_invMenuBuffer != nullptr)
+		screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_invMenuBounds.left, _invMenuBounds.top), _invMenuBounds);
+
+	// If there is a Text Tag being display, restore the area underneath it
+	if (_oldTagBounds.width() > 0)
+		screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_oldTagBounds.left, _oldTagBounds.top), 
+			_oldTagBounds);
+
+	// If there is an Inventory being shown, restore the graphics underneath it
+	if (_oldInvGraphicBounds.width() > 0)
+		screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_oldInvGraphicBounds.left, _oldInvGraphicBounds.top), 
+			_oldInvGraphicBounds);
+
+	// If a canimation is active, restore the graphics underneath it
+	if (scene._activeCAnim._images != nullptr)
+		screen.restoreBackground(scene._activeCAnim._oldBounds);
+
+	// If a canimation just ended, remove it's graphics from the backbuffer
+	if (scene._activeCAnim._removeBounds.width() > 0)
+		screen.restoreBackground(scene._activeCAnim._removeBounds);
+}
+
+} // End of namespace Tattoo
+
 } // End of namespace Sherlock
diff --git a/engines/sherlock/user_interface.h b/engines/sherlock/user_interface.h
index 2203ddf..7a640ef 100644
--- a/engines/sherlock/user_interface.h
+++ b/engines/sherlock/user_interface.h
@@ -137,6 +137,8 @@ public:
 	virtual void printObjectDesc() {}
 };
 
+namespace Scalpel {
+
 class ScalpelUserInterface: public UserInterface {
 	friend class Inventory;
 	friend class Settings;
@@ -314,9 +316,24 @@ public:
 	virtual void printObjectDesc();
 };
 
+} // End of namespace Scalpel
+
+namespace Tattoo {
+
 class TattooUserInterface : public UserInterface {
+private:
+	Common::Rect _menuBounds;
+	Common::Rect _oldMenuBounds;
+	Common::Rect _invMenuBounds;
+	Common::Rect _oldInvMenuBounds;
+	Common::Rect _oldTagBounds;
+	Common::Rect _oldInvGraphicBounds;
+	Surface *_menuBuffer;
+	Surface *_invMenuBuffer;
 public:
 	TattooUserInterface(SherlockEngine *vm);
+
+	void doBgAnimRestoreUI();
 public:
 	virtual ~TattooUserInterface() {}
 
@@ -326,6 +343,8 @@ public:
 	virtual void handleInput();
 };
 
+} // End of namespace Tattoo
+
 } // End of namespace Sherlock
 
 #endif


Commit: 789a8b35614f07ace9da51b01279c4c59a8b2253
    https://github.com/scummvm/scummvm/commit/789a8b35614f07ace9da51b01279c4c59a8b2253
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-27T22:36:51-04:00

Commit Message:
SHERLOCK: Implement RT scrolling code

Changed paths:
    engines/sherlock/people.cpp
    engines/sherlock/people.h
    engines/sherlock/scene.cpp
    engines/sherlock/scene.h
    engines/sherlock/screen.cpp
    engines/sherlock/screen.h
    engines/sherlock/user_interface.cpp
    engines/sherlock/user_interface.h



diff --git a/engines/sherlock/people.cpp b/engines/sherlock/people.cpp
index 6beae48..f8dd8e2 100644
--- a/engines/sherlock/people.cpp
+++ b/engines/sherlock/people.cpp
@@ -97,6 +97,7 @@ People::People(SherlockEngine *vm) : _vm(vm), _player(_data[0]) {
 	_hSavedFacing = -1;
 	_forceWalkReload = false;
 	_useWalkLib = false;
+	_walkControl = 0;
 
 	_portrait._sequences = new byte[32];
 }
diff --git a/engines/sherlock/people.h b/engines/sherlock/people.h
index 272c418..f4aba5a 100644
--- a/engines/sherlock/people.h
+++ b/engines/sherlock/people.h
@@ -114,6 +114,8 @@ public:
 	int _holmesQuotient;
 	bool _forceWalkReload;
 	bool _useWalkLib;
+
+	int _walkControl;
 public:
 	People(SherlockEngine *vm);
 	~People();
diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp
index 18690fb..06bbabf 100644
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@ -1740,7 +1740,7 @@ void TattooScene::doBgAnimCheckCursor() {
 	}
 }
 
-void TattooScene::doBgAnimHandleMask() {
+void TattooScene::doBgAnimEraseBackground() {
 	TattooEngine &vm = *((TattooEngine *)_vm);
 	People &people = *_vm->_people;
 	Screen &screen = *_vm->_screen;
@@ -1813,6 +1813,37 @@ void TattooScene::doBgAnimHandleMask() {
 		if (vm._creditsActive)
 			vm.eraseCredits();
 	}
+
+	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+		Object &obj = _bgShapes[idx];
+
+		if (obj._type == NO_SHAPE && (obj._flags & 1) == 0) {
+			screen._backBuffer1.blitFrom(screen._backBuffer2, obj._position, obj.getNoShapeBounds());
+
+			obj._oldPosition = obj._position;
+			obj._oldSize = obj._noShapeSize;
+		}
+	}
+
+	// Adjust the Target Scroll if needed
+	if ((people[people._walkControl]._position.x / FIXED_INT_MULTIPLIER - screen._currentScroll) < 
+			(SHERLOCK_SCREEN_WIDTH / 8) && people[people._walkControl]._delta.x < 0) {
+		
+		screen._targetScroll = (short)(people[people._walkControl]._position.x / FIXED_INT_MULTIPLIER - 
+				SHERLOCK_SCREEN_WIDTH / 8 - 250);
+		if (screen._targetScroll < 0)
+			screen._targetScroll = 0;
+	}
+
+	if ((people[people._walkControl]._position.x / FIXED_INT_MULTIPLIER - screen._currentScroll) > (SHERLOCK_SCREEN_WIDTH / 4 * 3) 
+			&& people[people._walkControl]._delta.x > 0)
+		screen._targetScroll = (short)(people[people._walkControl]._position.x / FIXED_INT_MULTIPLIER - 
+			SHERLOCK_SCREEN_WIDTH / 4 * 3 + 250);
+
+	if (screen._targetScroll > screen._scrollSize)
+		screen._targetScroll = screen._scrollSize;
+
+	ui.doScroll();
 }
 
 void TattooScene::doBgAnim() {
@@ -1827,6 +1858,7 @@ void TattooScene::doBgAnim() {
 	screen.setDisplayBounds(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCENE_HEIGHT));
 	talk._talkToAbort = false;
 
+	// Check the characters and sprites for updates
 	for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
 		if (people[idx]._type == CHARACTER)
 			people[idx].checkSprite();
@@ -1836,6 +1868,9 @@ void TattooScene::doBgAnim() {
 		if (_bgShapes[idx]._type == ACTIVE_BG_SHAPE)
 			_bgShapes[idx].checkObject();
 	}
+
+	// Erase any affected background areas
+	doBgAnimEraseBackground();
 }
 
 } // End of namespace Tattoo
diff --git a/engines/sherlock/scene.h b/engines/sherlock/scene.h
index 1bd23fc..ce07850 100644
--- a/engines/sherlock/scene.h
+++ b/engines/sherlock/scene.h
@@ -351,7 +351,7 @@ private:
 private:
 	void doBgAnimCheckCursor();
 
-	void doBgAnimHandleMask();
+	void doBgAnimEraseBackground();
 protected:
 	/**
 	 * Checks all the background shapes. If a background shape is animating,
diff --git a/engines/sherlock/screen.cpp b/engines/sherlock/screen.cpp
index 4dd91cf..350341f 100644
--- a/engines/sherlock/screen.cpp
+++ b/engines/sherlock/screen.cpp
@@ -45,8 +45,10 @@ Screen::Screen(SherlockEngine *vm) : Surface(g_system->getWidth(), g_system->get
 	_fadeBytesRead = _fadeBytesToRead = 0;
 	_oldFadePercent = 0;
 	_scrollSize = 0;
+	_scrollSpeed = 0;
 	_currentScroll = 0;
 	_targetScroll = 0;
+	_flushScreen = false;
 }
 
 Screen::~Screen() {
diff --git a/engines/sherlock/screen.h b/engines/sherlock/screen.h
index e730329..ae368cf 100644
--- a/engines/sherlock/screen.h
+++ b/engines/sherlock/screen.h
@@ -71,8 +71,6 @@ private:
 	int _oldFadePercent;
 	byte _lookupTable[PALETTE_COUNT];
 	byte _lookupTable1[PALETTE_COUNT];
-	int _scrollSize;
-	int _targetScroll;
 private:
 	/**
 	 * Merges together overlapping dirty areas of the screen
@@ -101,7 +99,9 @@ public:
 	byte _cMap[PALETTE_SIZE];
 	byte _sMap[PALETTE_SIZE];
 	byte _tMap[PALETTE_SIZE];
-	int _currentScroll;
+	int _currentScroll, _targetScroll;
+	int _scrollSize, _scrollSpeed;
+	bool _flushScreen;
 public:
 	Screen(SherlockEngine *vm);
 	virtual ~Screen();
diff --git a/engines/sherlock/user_interface.cpp b/engines/sherlock/user_interface.cpp
index 06ec62b..5858daf 100644
--- a/engines/sherlock/user_interface.cpp
+++ b/engines/sherlock/user_interface.cpp
@@ -2352,6 +2352,31 @@ void TattooUserInterface::doBgAnimRestoreUI() {
 		screen.restoreBackground(scene._activeCAnim._removeBounds);
 }
 
+void TattooUserInterface::doScroll() {
+	Screen &screen = *_vm->_screen;
+	int oldScroll = screen._currentScroll;
+
+	// If we're already at the target scroll position, nothing needs to be done
+	if (screen._targetScroll == screen._currentScroll)
+		return;
+
+	screen._flushScreen = true;
+	if (screen._targetScroll > screen._currentScroll) {
+		screen._currentScroll += screen._scrollSpeed;
+		if (screen._currentScroll > screen._targetScroll)
+			screen._currentScroll = screen._targetScroll;
+	} else if (screen._targetScroll < screen._currentScroll) {
+		screen._currentScroll -= screen._scrollSpeed;
+		if (screen._currentScroll < screen._targetScroll)
+			screen._currentScroll = screen._targetScroll;
+	}
+
+	if (_menuBuffer != nullptr)
+		_menuBounds.translate(screen._currentScroll - oldScroll, 0);
+	if (_invMenuBuffer != nullptr)
+		_invMenuBounds.translate(screen._currentScroll - oldScroll, 0);
+}
+
 } // End of namespace Tattoo
 
 } // End of namespace Sherlock
diff --git a/engines/sherlock/user_interface.h b/engines/sherlock/user_interface.h
index 7a640ef..dfd6d02 100644
--- a/engines/sherlock/user_interface.h
+++ b/engines/sherlock/user_interface.h
@@ -333,7 +333,15 @@ private:
 public:
 	TattooUserInterface(SherlockEngine *vm);
 
+	/**
+	 * Handles restoring any areas of the back buffer that were/are covered by UI elements
+	 */
 	void doBgAnimRestoreUI();
+
+	/**
+	 * Checks to see if the screen needs to be scrolled. If so, scrolls it towards the target position
+	 */
+	void doScroll();
 public:
 	virtual ~TattooUserInterface() {}
 


Commit: f759aeddcdd6a313f1ff75520d51739c6d170698
    https://github.com/scummvm/scummvm/commit/f759aeddcdd6a313f1ff75520d51739c6d170698
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-28T08:31:53-04:00

Commit Message:
SHERLOCK: Moving split up classes into their own files

Changed paths:
  A engines/sherlock/scalpel/scalpel_scene.cpp
  A engines/sherlock/scalpel/scalpel_scene.h
  A engines/sherlock/scalpel/scalpel_user_interface.cpp
  A engines/sherlock/scalpel/scalpel_user_interface.h
  A engines/sherlock/scalpel/settings.cpp
  A engines/sherlock/scalpel/settings.h
  A engines/sherlock/tattoo/tattoo_scene.cpp
  A engines/sherlock/tattoo/tattoo_scene.h
  A engines/sherlock/tattoo/tattoo_user_interface.cpp
  A engines/sherlock/tattoo/tattoo_user_interface.h
  R engines/sherlock/settings.cpp
  R engines/sherlock/settings.h
    engines/sherlock/inventory.cpp
    engines/sherlock/module.mk
    engines/sherlock/scene.cpp
    engines/sherlock/scene.h
    engines/sherlock/talk.cpp
    engines/sherlock/user_interface.cpp
    engines/sherlock/user_interface.h



diff --git a/engines/sherlock/inventory.cpp b/engines/sherlock/inventory.cpp
index 7ec0b64..a8ecb64 100644
--- a/engines/sherlock/inventory.cpp
+++ b/engines/sherlock/inventory.cpp
@@ -22,6 +22,7 @@
 
 #include "sherlock/inventory.h"
 #include "sherlock/sherlock.h"
+#include "sherlock/scalpel/scalpel_user_interface.h"
 
 namespace Sherlock {
 
@@ -200,29 +201,29 @@ void Inventory::drawInventory(InvNewMode mode) {
 		INV_BACKGROUND);
 
 	// Draw the buttons
-	screen.makeButton(Common::Rect(INVENTORY_POINTS[0][0], CONTROLS_Y1, INVENTORY_POINTS[0][1],
-		CONTROLS_Y1 + 10), INVENTORY_POINTS[0][2] - screen.stringWidth("Exit") / 2, "Exit");
-	screen.makeButton(Common::Rect(INVENTORY_POINTS[1][0], CONTROLS_Y1, INVENTORY_POINTS[1][1],
-		CONTROLS_Y1 + 10), INVENTORY_POINTS[1][2] - screen.stringWidth("Look") / 2, "Look");
-	screen.makeButton(Common::Rect(INVENTORY_POINTS[2][0], CONTROLS_Y1, INVENTORY_POINTS[2][1],
-		CONTROLS_Y1 + 10), INVENTORY_POINTS[2][2] - screen.stringWidth("Use") / 2, "Use");
-	screen.makeButton(Common::Rect(INVENTORY_POINTS[3][0], CONTROLS_Y1, INVENTORY_POINTS[3][1],
-		CONTROLS_Y1 + 10), INVENTORY_POINTS[3][2] - screen.stringWidth("Give") / 2, "Give");
-	screen.makeButton(Common::Rect(INVENTORY_POINTS[4][0], CONTROLS_Y1, INVENTORY_POINTS[4][1],
-		CONTROLS_Y1 + 10), INVENTORY_POINTS[4][2], "^^");
-	screen.makeButton(Common::Rect(INVENTORY_POINTS[5][0], CONTROLS_Y1, INVENTORY_POINTS[5][1],
-		CONTROLS_Y1 + 10), INVENTORY_POINTS[5][2], "^");
-	screen.makeButton(Common::Rect(INVENTORY_POINTS[6][0], CONTROLS_Y1, INVENTORY_POINTS[6][1],
-		CONTROLS_Y1 + 10), INVENTORY_POINTS[6][2], "_");
-	screen.makeButton(Common::Rect(INVENTORY_POINTS[7][0], CONTROLS_Y1, INVENTORY_POINTS[7][1],
-		CONTROLS_Y1 + 10), INVENTORY_POINTS[7][2], "__");
+	screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[0][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[0][1],
+		CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[0][2] - screen.stringWidth("Exit") / 2, "Exit");
+	screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[1][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[1][1],
+		CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[1][2] - screen.stringWidth("Look") / 2, "Look");
+	screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[2][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[2][1],
+		CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[2][2] - screen.stringWidth("Use") / 2, "Use");
+	screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[3][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[3][1],
+		CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[3][2] - screen.stringWidth("Give") / 2, "Give");
+	screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[4][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[4][1],
+		CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[4][2], "^^");
+	screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[5][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[5][1],
+		CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[5][2], "^");
+	screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[6][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[6][1],
+		CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[6][2], "_");
+	screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[7][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[7][1],
+		CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[7][2], "__");
 
 	if (tempMode == INVENTORY_DONT_DISPLAY)
 		mode = LOOK_INVENTORY_MODE;
 	_invMode = (InvMode)mode;
 
 	if (mode != PLAIN_INVENTORY) {
-		ui._oldKey = INVENTORY_COMMANDS[(int)mode];
+		ui._oldKey = Scalpel::INVENTORY_COMMANDS[(int)mode];
 	} else {
 		ui._oldKey = -1;
 	}
@@ -252,55 +253,55 @@ void Inventory::invCommands(bool slamIt) {
 	UserInterface &ui = *_vm->_ui;
 
 	if (slamIt) {
-		screen.buttonPrint(Common::Point(INVENTORY_POINTS[0][2], CONTROLS_Y1),
+		screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[0][2], CONTROLS_Y1),
 			_invMode == INVMODE_EXIT ? COMMAND_HIGHLIGHTED :COMMAND_FOREGROUND,
 			true, "Exit");
-		screen.buttonPrint(Common::Point(INVENTORY_POINTS[1][2], CONTROLS_Y1),
+		screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[1][2], CONTROLS_Y1),
 			_invMode == INVMODE_LOOK ? COMMAND_HIGHLIGHTED :COMMAND_FOREGROUND,
 			true, "Look");
-		screen.buttonPrint(Common::Point(INVENTORY_POINTS[2][2], CONTROLS_Y1),
+		screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[2][2], CONTROLS_Y1),
 			_invMode == INVMODE_USE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
 			true, "Use");
-		screen.buttonPrint(Common::Point(INVENTORY_POINTS[3][2], CONTROLS_Y1),
+		screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[3][2], CONTROLS_Y1),
 			_invMode == INVMODE_GIVE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
 			true, "Give");
-		screen.print(Common::Point(INVENTORY_POINTS[4][2], CONTROLS_Y1 + 1),
+		screen.print(Common::Point(Scalpel::INVENTORY_POINTS[4][2], CONTROLS_Y1 + 1),
 			_invIndex == 0 ? COMMAND_NULL : COMMAND_FOREGROUND,
 			"^^");
-		screen.print(Common::Point(INVENTORY_POINTS[5][2], CONTROLS_Y1 + 1),
+		screen.print(Common::Point(Scalpel::INVENTORY_POINTS[5][2], CONTROLS_Y1 + 1),
 			_invIndex == 0 ? COMMAND_NULL : COMMAND_FOREGROUND,
 			"^");
-		screen.print(Common::Point(INVENTORY_POINTS[6][2], CONTROLS_Y1 + 1),
+		screen.print(Common::Point(Scalpel::INVENTORY_POINTS[6][2], CONTROLS_Y1 + 1),
 			(_holdings - _invIndex <= 6) ? COMMAND_NULL : COMMAND_FOREGROUND,
 			"_");
-		screen.print(Common::Point(INVENTORY_POINTS[7][2], CONTROLS_Y1 + 1),
+		screen.print(Common::Point(Scalpel::INVENTORY_POINTS[7][2], CONTROLS_Y1 + 1),
 			(_holdings - _invIndex <= 6) ? COMMAND_NULL : COMMAND_FOREGROUND,
 			"__");
 		if (_invMode != INVMODE_LOOK)
 			ui.clearInfo();
 	} else {
-		screen.buttonPrint(Common::Point(INVENTORY_POINTS[0][2], CONTROLS_Y1),
+		screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[0][2], CONTROLS_Y1),
 			_invMode == INVMODE_EXIT ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
 			false, "Exit");
-		screen.buttonPrint(Common::Point(INVENTORY_POINTS[1][2], CONTROLS_Y1),
+		screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[1][2], CONTROLS_Y1),
 			_invMode == INVMODE_LOOK ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
 			false, "Look");
-		screen.buttonPrint(Common::Point(INVENTORY_POINTS[2][2], CONTROLS_Y1),
+		screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[2][2], CONTROLS_Y1),
 			_invMode == INVMODE_USE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
 			false, "Use");
-		screen.buttonPrint(Common::Point(INVENTORY_POINTS[3][2], CONTROLS_Y1),
+		screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[3][2], CONTROLS_Y1),
 			_invMode == INVMODE_GIVE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
 			false, "Give");
-		screen.gPrint(Common::Point(INVENTORY_POINTS[4][2], CONTROLS_Y1),
+		screen.gPrint(Common::Point(Scalpel::INVENTORY_POINTS[4][2], CONTROLS_Y1),
 			_invIndex == 0 ? COMMAND_NULL : COMMAND_FOREGROUND,
 			"^^");
-		screen.gPrint(Common::Point(INVENTORY_POINTS[5][2], CONTROLS_Y1),
+		screen.gPrint(Common::Point(Scalpel::INVENTORY_POINTS[5][2], CONTROLS_Y1),
 			_invIndex == 0 ? COMMAND_NULL : COMMAND_FOREGROUND,
 			"^");
-		screen.gPrint(Common::Point(INVENTORY_POINTS[6][2], CONTROLS_Y1),
+		screen.gPrint(Common::Point(Scalpel::INVENTORY_POINTS[6][2], CONTROLS_Y1),
 			(_holdings - _invIndex < 7) ? COMMAND_NULL : COMMAND_FOREGROUND,
 			"_");
-		screen.gPrint(Common::Point(INVENTORY_POINTS[7][2], CONTROLS_Y1),
+		screen.gPrint(Common::Point(Scalpel::INVENTORY_POINTS[7][2], CONTROLS_Y1),
 			(_holdings - _invIndex < 7) ? COMMAND_NULL : COMMAND_FOREGROUND,
 			"__");
 	}
diff --git a/engines/sherlock/module.mk b/engines/sherlock/module.mk
index 2ded999..cee48ae 100644
--- a/engines/sherlock/module.mk
+++ b/engines/sherlock/module.mk
@@ -3,7 +3,12 @@ MODULE := engines/sherlock
 MODULE_OBJS = \
 	scalpel/darts.o \
 	scalpel/scalpel.o \
+	scalpel/scalpel_scene.o \
+	scalpel/scalpel_user_interface.o \
+	scalpel/settings.o \
 	tattoo/tattoo.o \
+	tattoo/tattoo_scene.o \
+	tattoo/tattoo_user_interface.o \
 	animation.o \
 	debugger.o \
 	detection.o \
@@ -17,7 +22,6 @@ MODULE_OBJS = \
 	saveload.o \
 	scene.o \
 	screen.o \
-	settings.o \
 	sherlock.o \
 	sound.o \
 	surface.o \
diff --git a/engines/sherlock/scalpel/scalpel_scene.cpp b/engines/sherlock/scalpel/scalpel_scene.cpp
new file mode 100644
index 0000000..b6a4241
--- /dev/null
+++ b/engines/sherlock/scalpel/scalpel_scene.cpp
@@ -0,0 +1,381 @@
+/* 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 "sherlock/scalpel/scalpel_scene.h"
+#include "sherlock/scalpel/scalpel.h"
+#include "sherlock/events.h"
+#include "sherlock/people.h"
+#include "sherlock/screen.h"
+
+namespace Sherlock {
+
+namespace Scalpel {
+
+void ScalpelScene::checkBgShapes() {
+	People &people = *_vm->_people;
+	Person &holmes = people._player;
+	Common::Point pt(holmes._position.x / FIXED_INT_MULTIPLIER, holmes._position.y / FIXED_INT_MULTIPLIER);
+
+	// Call the base scene method to handle bg shapes
+	Scene::checkBgShapes();
+
+	// Iterate through the canim list
+	for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
+		Object &obj = _canimShapes[idx];
+		if (obj._type == STATIC_BG_SHAPE || obj._type == ACTIVE_BG_SHAPE) {
+			if ((obj._flags & 5) == 1) {
+				obj._misc = (pt.y < (obj._position.y + obj._imageFrame->_frame.h - 1)) ?
+				NORMAL_FORWARD : NORMAL_BEHIND;
+			} else if (!(obj._flags & 1)) {
+				obj._misc = BEHIND;
+			} else if (obj._flags & 4) {
+				obj._misc = FORWARD;
+			}
+		}
+	}
+}
+
+void ScalpelScene::doBgAnimCheckCursor() {
+	Inventory &inv = *_vm->_inventory;
+	Events &events = *_vm->_events;
+	Sound &sound = *_vm->_sound;
+	UserInterface &ui = *_vm->_ui;
+	Common::Point mousePos = events.mousePos();
+
+	if (ui._menuMode == LOOK_MODE) {
+		if (mousePos.y > CONTROLS_Y1)
+			events.setCursor(ARROW);
+		else if (mousePos.y < CONTROLS_Y)
+			events.setCursor(MAGNIFY);
+	}
+
+	// Check for setting magnifying glass cursor
+	if (ui._menuMode == INV_MODE || ui._menuMode == USE_MODE || ui._menuMode == GIVE_MODE) {
+		if (inv._invMode == INVMODE_LOOK) {
+			// Only show Magnifying glass cursor if it's not on the inventory command line
+			if (mousePos.y < CONTROLS_Y || mousePos.y >(CONTROLS_Y1 + 13))
+				events.setCursor(MAGNIFY);
+			else
+				events.setCursor(ARROW);
+		} else {
+			events.setCursor(ARROW);
+		}
+	}
+
+	if (sound._diskSoundPlaying && !*sound._soundIsOn) {
+		// Loaded sound just finished playing
+		sound.freeDigiSound();
+	}
+}
+
+void ScalpelScene::doBgAnim() {
+	ScalpelEngine &vm = *((ScalpelEngine *)_vm);
+	Events &events = *_vm->_events;
+	People &people = *_vm->_people;
+	Screen &screen = *_vm->_screen;
+	Talk &talk = *_vm->_talk;
+
+	screen.setDisplayBounds(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCENE_HEIGHT));
+	talk._talkToAbort = false;
+
+	if (_restoreFlag) {
+		for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
+			if (people[idx]._type == CHARACTER)
+				people[idx].checkSprite();
+		}
+
+		for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+			if (_bgShapes[idx]._type == ACTIVE_BG_SHAPE)
+				_bgShapes[idx].checkObject();
+		}
+
+		if (people._portraitLoaded && people._portrait._type == ACTIVE_BG_SHAPE)
+			people._portrait.checkObject();
+
+		for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
+			if (_canimShapes[idx]._type != INVALID && _canimShapes[idx]._type != REMOVE)
+				_canimShapes[idx].checkObject();
+		}
+
+		if (_currentScene == 12)
+			vm.eraseMirror12();
+
+		// Restore the back buffer from the back buffer 2 in the changed area
+		Common::Rect bounds(people[AL]._oldPosition.x, people[AL]._oldPosition.y,
+			people[AL]._oldPosition.x + people[AL]._oldSize.x,
+			people[AL]._oldPosition.y + people[AL]._oldSize.y);
+		Common::Point pt(bounds.left, bounds.top);
+
+		if (people[AL]._type == CHARACTER)
+			screen.restoreBackground(bounds);
+		else if (people[AL]._type == REMOVE)
+			screen._backBuffer->blitFrom(screen._backBuffer2, pt, bounds);
+
+		for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+			Object &o = _bgShapes[idx];
+			if (o._type == ACTIVE_BG_SHAPE || o._type == HIDE_SHAPE || o._type == REMOVE)
+				screen.restoreBackground(o.getOldBounds());
+		}
+
+		if (people._portraitLoaded)
+			screen.restoreBackground(Common::Rect(
+				people._portrait._oldPosition.x, people._portrait._oldPosition.y,
+				people._portrait._oldPosition.x + people._portrait._oldSize.x,
+				people._portrait._oldPosition.y + people._portrait._oldSize.y
+			));
+
+		for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+			Object &o = _bgShapes[idx];
+			if (o._type == NO_SHAPE && ((o._flags & OBJ_BEHIND) == 0)) {
+				// Restore screen area
+				screen._backBuffer->blitFrom(screen._backBuffer2, o._position,
+					Common::Rect(o._position.x, o._position.y,
+					o._position.x + o._noShapeSize.x, o._position.y + o._noShapeSize.y));
+
+				o._oldPosition = o._position;
+				o._oldSize = o._noShapeSize;
+			}
+		}
+
+		for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
+			Object &o = _canimShapes[idx];
+			if (o._type == ACTIVE_BG_SHAPE || o._type == HIDE_SHAPE || o._type == REMOVE)
+				screen.restoreBackground(Common::Rect(o._oldPosition.x, o._oldPosition.y,
+					o._oldPosition.x + o._oldSize.x, o._oldPosition.y + o._oldSize.y));
+		}
+	}
+
+	//
+	// Update the background objects and canimations
+	//
+
+	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+		Object &o = _bgShapes[idx];
+		if (o._type == ACTIVE_BG_SHAPE || o._type == NO_SHAPE)
+			o.adjustObject();
+	}
+
+	if (people._portraitLoaded && people._portrait._type == ACTIVE_BG_SHAPE)
+		people._portrait.adjustObject();
+
+	for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
+		if (_canimShapes[idx]._type != INVALID)
+			_canimShapes[idx].adjustObject();
+	}
+
+	if (people[AL]._type == CHARACTER && people._holmesOn)
+		people[AL].adjustSprite();
+
+	// Flag the bg shapes which need to be redrawn
+	checkBgShapes();
+
+	if (_currentScene == 12)
+		vm.doMirror12();
+
+	// Draw all active shapes which are behind the person
+	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+		Object &o = _bgShapes[idx];
+		if (o._type == ACTIVE_BG_SHAPE && o._misc == BEHIND)
+			screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
+	}
+
+	// Draw all canimations which are behind the person
+	for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
+		Object &o = _canimShapes[idx];
+		if (o._type == ACTIVE_BG_SHAPE && o._misc == BEHIND) {
+			screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
+		}
+	}
+
+	// Draw all active shapes which are HAPPEN and behind the person
+	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+		Object &o = _bgShapes[idx];
+		if (o._type == ACTIVE_BG_SHAPE && o._misc == NORMAL_BEHIND)
+			screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
+	}
+
+	// Draw all canimations which are NORMAL and behind the person
+	for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
+		Object &o = _canimShapes[idx];
+		if (o._type == ACTIVE_BG_SHAPE && o._misc == NORMAL_BEHIND) {
+			screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
+		}
+	}
+
+	// Draw the person if not animating
+	if (people[AL]._type == CHARACTER && people[AL]._walkLoaded) {
+		// If Holmes is too far to the right, move him back so he's on-screen
+		int xRight = SHERLOCK_SCREEN_WIDTH - 2 - people[AL]._imageFrame->_frame.w;
+		int tempX = MIN(people[AL]._position.x / FIXED_INT_MULTIPLIER, xRight);
+
+		bool flipped = people[AL]._sequenceNumber == WALK_LEFT || people[AL]._sequenceNumber == STOP_LEFT ||
+			people[AL]._sequenceNumber == WALK_UPLEFT || people[AL]._sequenceNumber == STOP_UPLEFT ||
+			people[AL]._sequenceNumber == WALK_DOWNRIGHT || people[AL]._sequenceNumber == STOP_DOWNRIGHT;
+		screen._backBuffer->transBlitFrom(*people[AL]._imageFrame,
+			Common::Point(tempX, people[AL]._position.y / FIXED_INT_MULTIPLIER - people[AL]._imageFrame->_frame.h), flipped);
+	}
+
+	// Draw all static and active shapes are NORMAL and are in front of the person
+	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+		Object &o = _bgShapes[idx];
+		if ((o._type == ACTIVE_BG_SHAPE || o._type == STATIC_BG_SHAPE) && o._misc == NORMAL_FORWARD)
+			screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
+	}
+
+	// Draw all static and active canimations that are NORMAL and are in front of the person
+	for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
+		Object &o = _canimShapes[idx];
+		if ((o._type == ACTIVE_BG_SHAPE || o._type == STATIC_BG_SHAPE) && o._misc == NORMAL_FORWARD) {
+			screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
+		}
+	}
+
+	// Draw all static and active shapes that are in front of the person
+	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+		Object &o = _bgShapes[idx];
+		if ((o._type == ACTIVE_BG_SHAPE || o._type == STATIC_BG_SHAPE) && o._misc == FORWARD)
+			screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
+	}
+
+	// Draw any active portrait
+	if (people._portraitLoaded && people._portrait._type == ACTIVE_BG_SHAPE)
+		screen._backBuffer->transBlitFrom(*people._portrait._imageFrame,
+			people._portrait._position, people._portrait._flags & OBJ_FLIPPED);
+
+	// Draw all static and active canimations that are in front of the person
+	for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
+		Object &o = _canimShapes[idx];
+		if ((o._type == ACTIVE_BG_SHAPE || o._type == STATIC_BG_SHAPE) && o._misc == FORWARD) {
+			screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
+		}
+	}
+
+	// Draw all NO_SHAPE shapes which have flag bit 0 clear
+	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+		Object &o = _bgShapes[idx];
+		if (o._type == NO_SHAPE && (o._flags & OBJ_BEHIND) == 0)
+			screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
+	}
+
+	// Bring the newly built picture to the screen
+	if (_animating == 2) {
+		_animating = 0;
+		screen.slamRect(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCENE_HEIGHT));
+	} else {
+		if (people[AL]._type != INVALID && ((_goToScene == -1 || _canimShapes.empty()))) {
+			if (people[AL]._type == REMOVE) {
+				screen.slamRect(Common::Rect(
+					people[AL]._oldPosition.x, people[AL]._oldPosition.y,
+					people[AL]._oldPosition.x + people[AL]._oldSize.x,
+					people[AL]._oldPosition.y + people[AL]._oldSize.y
+				));
+				people[AL]._type = INVALID;
+			} else {
+				screen.flushImage(people[AL]._imageFrame,
+					Common::Point(people[AL]._position.x / FIXED_INT_MULTIPLIER,
+						people[AL]._position.y / FIXED_INT_MULTIPLIER - people[AL].frameHeight()),
+					&people[AL]._oldPosition.x, &people[AL]._oldPosition.y,
+					&people[AL]._oldSize.x, &people[AL]._oldSize.y);
+			}
+		}
+
+		if (_currentScene == 12)
+			vm.flushMirror12();
+
+		for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+			Object &o = _bgShapes[idx];
+			if ((o._type == ACTIVE_BG_SHAPE || o._type == REMOVE) && _goToScene == -1) {
+				screen.flushImage(o._imageFrame, o._position,
+					&o._oldPosition.x, &o._oldPosition.y, &o._oldSize.x, &o._oldSize.y);
+			}
+		}
+
+		if (people._portraitLoaded) {
+			if (people._portrait._type == REMOVE)
+				screen.slamRect(Common::Rect(
+					people._portrait._position.x, people._portrait._position.y,
+					people._portrait._position.x + people._portrait._delta.x,
+					people._portrait._position.y + people._portrait._delta.y
+				));
+			else
+				screen.flushImage(people._portrait._imageFrame, people._portrait._position,
+					&people._portrait._oldPosition.x, &people._portrait._oldPosition.y,
+					&people._portrait._oldSize.x, &people._portrait._oldSize.y);
+
+			if (people._portrait._type == REMOVE)
+				people._portrait._type = INVALID;
+		}
+
+		if (_goToScene == -1) {
+			for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+				Object &o = _bgShapes[idx];
+				if (o._type == NO_SHAPE && (o._flags & OBJ_BEHIND) == 0) {
+					screen.slamArea(o._position.x, o._position.y, o._oldSize.x, o._oldSize.y);
+					screen.slamArea(o._oldPosition.x, o._oldPosition.y, o._oldSize.x, o._oldSize.y);
+				} else if (o._type == HIDE_SHAPE) {
+					// Hiding shape, so flush it out and mark it as hidden
+					screen.flushImage(o._imageFrame, o._position,
+						&o._oldPosition.x, &o._oldPosition.y, &o._oldSize.x, &o._oldSize.y);
+					o._type = HIDDEN;
+				}
+			}
+		}
+
+		for (int idx = _canimShapes.size() - 1; idx >= 0; --idx) {
+			Object &o = _canimShapes[idx];
+
+			if (o._type == INVALID) {
+				// Anim shape was invalidated by checkEndOfSequence, so at this point we can remove it
+				_canimShapes.remove_at(idx);
+			} else  if (o._type == REMOVE) {
+				if (_goToScene == -1)
+					screen.slamArea(o._position.x, o._position.y, o._delta.x, o._delta.y);
+
+				// Shape for an animation is no longer needed, so remove it completely
+				_canimShapes.remove_at(idx);
+			} else if (o._type == ACTIVE_BG_SHAPE) {
+				screen.flushImage(o._imageFrame, o._position,
+					&o._oldPosition.x, &o._oldPosition.y, &o._oldSize.x, &o._oldSize.y);
+			}
+		}
+	}
+
+	_restoreFlag = true;
+	_doBgAnimDone = true;
+
+	events.wait(3);
+	screen.resetDisplayBounds();
+
+	// Check if the method was called for calling a portrait, and a talk was
+	// interrupting it. This talk file would not have been executed at the time,
+	// since we needed to finish the 'doBgAnim' to finish clearing the portrait
+	if (people._clearingThePortrait && talk._scriptMoreFlag == 3) {
+		// Reset the flags and call to talk
+		people._clearingThePortrait = false;
+		talk._scriptMoreFlag = 0;
+		talk.talkTo(talk._scriptName);
+	}
+}
+
+} // End of namespace Scalpel
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/scalpel/scalpel_scene.h b/engines/sherlock/scalpel/scalpel_scene.h
new file mode 100644
index 0000000..e5a442f
--- /dev/null
+++ b/engines/sherlock/scalpel/scalpel_scene.h
@@ -0,0 +1,61 @@
+/* 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 SHERLOCK_SCALPEL_SCENE_H
+#define SHERLOCK_SCALPEL_SCENE_H
+
+#include "common/scummsys.h"
+#include "common/array.h"
+#include "common/rect.h"
+#include "common/serializer.h"
+#include "sherlock/objects.h"
+#include "sherlock/scene.h"
+#include "sherlock/screen.h"
+
+namespace Sherlock {
+
+namespace Scalpel {
+
+class ScalpelScene : public Scene {
+private:
+	void doBgAnimCheckCursor();
+protected:
+	/**
+	 * Checks all the background shapes. If a background shape is animating,
+	 * it will flag it as needing to be drawn. If a non-animating shape is
+	 * colliding with another shape, it will also flag it as needing drawing
+	 */
+	virtual void checkBgShapes();
+public:
+	ScalpelScene(SherlockEngine *vm) : Scene(vm) {}
+
+	/**
+	 * Draw all objects and characters.
+	 */
+	virtual void doBgAnim();
+};
+
+} // End of namespace Scalpel
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/scalpel/scalpel_user_interface.cpp b/engines/sherlock/scalpel/scalpel_user_interface.cpp
new file mode 100644
index 0000000..f9ec8bb
--- /dev/null
+++ b/engines/sherlock/scalpel/scalpel_user_interface.cpp
@@ -0,0 +1,2276 @@
+/* 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 "sherlock/scalpel/scalpel_user_interface.h"
+#include "sherlock/sherlock.h"
+#include "sherlock/scalpel/settings.h"
+
+namespace Sherlock {
+
+namespace Scalpel {
+
+// Main user interface menu control locations
+const int MENU_POINTS[12][4] = {
+	{ 13, 153, 72, 165 },
+	{ 13, 169, 72, 181 },
+	{ 13, 185, 72, 197 },
+	{ 88, 153, 152, 165 },
+	{ 88, 169, 152, 181 },
+	{ 88, 185, 152, 197 },
+	{ 165, 153, 232, 165 },
+	{ 165, 169, 232, 181 },
+	{ 165, 185, 233, 197 },
+	{ 249, 153, 305, 165 },
+	{ 249, 169, 305, 181 },
+	{ 249, 185, 305, 197 }
+};
+
+// Inventory control locations */
+const int INVENTORY_POINTS[8][3] = {
+	{ 4, 50, 29 },
+	{ 52, 99, 77 },
+	{ 101, 140, 123 },
+	{ 142, 187, 166 },
+	{ 189, 219, 198 },
+	{ 221, 251, 234 },
+	{ 253, 283, 266 },
+	{ 285, 315, 294 }
+};
+
+const char COMMANDS[13] = "LMTPOCIUGJFS";
+const char INVENTORY_COMMANDS[9] = { "ELUG-+,." };
+const char *const PRESS_KEY_FOR_MORE = "Press any Key for More.";
+const char *const PRESS_KEY_TO_CONTINUE = "Press any Key to Continue.";
+
+const char *const MOPEN[] = {
+	"This cannot be opened", "It is already open", "It is locked", "Wait for Watson", " ", "."
+};
+const char *const MCLOSE[] = {
+	"This cannot be closed", "It is already closed", "The safe door is in the way"
+};
+const char *const MMOVE[] = {
+	"This cannot be moved", "It is bolted to the floor", "It is too heavy", "The other crate is in the way"
+};
+const char *const MPICK[] = {
+	"Nothing of interest here", "It is bolted down", "It is too big to carry", "It is too heavy",
+	"I think a girl would be more your type", "Those flowers belong to Penny", "She's far too young for you!",
+	"I think a girl would be more your type!", "Government property for official use only"
+};
+const char *const MUSE[] = {
+	"You can't do that", "It had no effect", "You can't reach it", "OK, the door looks bigger! Happy?",
+	"Doors don't smoke"
+};
+
+/*----------------------------------------------------------------*/
+
+
+ScalpelUserInterface::ScalpelUserInterface(SherlockEngine *vm): UserInterface(vm) {
+	_controls = new ImageFile("menu.all");
+	_controlPanel = new ImageFile("controls.vgs");
+	_keyPress = '\0';
+	_lookHelp = 0;
+	_bgFound = 0;
+	_oldBgFound = -1;
+	_help = _oldHelp = 0;
+	_key = _oldKey = '\0';
+	_temp = _oldTemp = 0;
+	_oldLook = 0;
+	_keyboardInput = false;
+	_pause = false;
+	_cNum = 0;
+	_find = 0;
+	_oldUse = 0;
+}
+
+ScalpelUserInterface::~ScalpelUserInterface() {
+	delete _controls;
+	delete _controlPanel;
+}
+
+void ScalpelUserInterface::reset() {
+	_oldKey = -1;
+	_help = _oldHelp = -1;
+	_oldTemp = _temp = -1;
+}
+
+void ScalpelUserInterface::drawInterface(int bufferNum) {
+	Screen &screen = *_vm->_screen;
+
+	if (bufferNum & 1)
+		screen._backBuffer1.transBlitFrom((*_controlPanel)[0], Common::Point(0, CONTROLS_Y));
+	if (bufferNum & 2)
+		screen._backBuffer2.transBlitFrom((*_controlPanel)[0], Common::Point(0, CONTROLS_Y));
+	if (bufferNum == 3)
+		screen._backBuffer2.fillRect(0, INFO_LINE, SHERLOCK_SCREEN_WIDTH, INFO_LINE + 10, INFO_BLACK);
+}
+
+void ScalpelUserInterface::handleInput() {
+	Events &events = *_vm->_events;
+	Inventory &inv = *_vm->_inventory;
+	People &people = *_vm->_people;
+	Scene &scene = *_vm->_scene;
+	Screen &screen = *_vm->_screen;
+	Talk &talk = *_vm->_talk;
+
+	if (_menuCounter)
+		whileMenuCounter();
+
+	Common::Point pt = events.mousePos();
+	_bgFound = scene.findBgShape(Common::Rect(pt.x, pt.y, pt.x + 1, pt.y + 1));
+	_keyPress = '\0';
+
+	// Check kbd and set the mouse released flag if Enter or space is pressed.
+	// Otherwise, the pressed _key is stored for later use
+	if (events.kbHit()) {
+		Common::KeyState keyState = events.getKey();
+		_keyPress = keyState.ascii;
+
+		if (keyState.keycode == Common::KEYCODE_x && keyState.flags & Common::KBD_ALT) {
+			_vm->quitGame();
+			events.pollEvents();
+			return;
+		}
+	}
+
+	// Do button highlighting check
+	if (!talk._scriptMoreFlag) {	// Don't if scripts are running
+		if (((events._rightPressed || events._rightReleased) && _helpStyle) ||
+				(!_helpStyle && !_menuCounter)) {
+			// Handle any default commands if we're in STD_MODE
+			if (_menuMode == STD_MODE) {
+				if (pt.y < CONTROLS_Y &&
+					(events._rightPressed || (!_helpStyle && !events._released)) &&
+					(_bgFound != -1) && (_bgFound < 1000) &&
+					(scene._bgShapes[_bgFound]._defaultCommand ||
+					!scene._bgShapes[_bgFound]._description.empty())) {
+					// If there is no default command, so set it to Look
+					if (scene._bgShapes[_bgFound]._defaultCommand)
+						_help = scene._bgShapes[_bgFound]._defaultCommand - 1;
+					else
+						_help = 0;
+
+					// Reset 'help' if it is an invalid command
+					if (_help > 5)
+						_help = -1;
+				} else if (pt.y < CONTROLS_Y &&
+					((events._rightReleased && _helpStyle) || (events._released && !_helpStyle)) &&
+					(_bgFound != -1 && _bgFound < 1000) &&
+					(scene._bgShapes[_bgFound]._defaultCommand ||
+					!scene._bgShapes[_bgFound]._description.empty())) {
+					// If there is no default command, set it to Look
+					if (scene._bgShapes[_bgFound]._defaultCommand)
+						_menuMode = (MenuMode)scene._bgShapes[_bgFound]._defaultCommand;
+					else
+						_menuMode = LOOK_MODE;
+					events._released = true;
+					events._pressed = events._oldButtons = false;
+					_help = _oldHelp = -1;
+
+					if (_menuMode == LOOK_MODE) {
+						// Set the flag to tell the game that this was a right-click
+						// call to look and should exit without the look button being pressed
+						_lookHelp = true;
+					}
+				} else {
+					_help = -1;
+				}
+
+				// Check if highlighting a different button than last time
+				if (_help != _oldHelp) {
+					// If another button was highlighted previously, restore it
+					if (_oldHelp != -1)
+						restoreButton(_oldHelp);
+
+					// If we're highlighting a new button, then draw it pressed
+					if (_help != -1)
+						depressButton(_help);
+
+					_oldHelp = _help;
+				}
+
+				if (_bgFound != _oldBgFound || _oldBgFound == -1) {
+					_infoFlag = true;
+					clearInfo();
+
+					if (_help != -1 && !scene._bgShapes[_bgFound]._description.empty()
+							&& scene._bgShapes[_bgFound]._description[0] != ' ')
+						screen.print(Common::Point(0, INFO_LINE + 1),
+						INFO_FOREGROUND, "%s", scene._bgShapes[_bgFound]._description.c_str());
+
+					_oldBgFound = _bgFound;
+				}
+			} else {
+				// We're not in STD_MODE
+				// If there isn't a window open, then revert back to STD_MODE
+				if (!_windowOpen && events._rightReleased) {
+					// Restore all buttons
+					for (int idx = 0; idx < 12; ++idx)
+						restoreButton(idx);
+
+					_menuMode = STD_MODE;
+					_key = _oldKey = -1;
+					_temp = _oldTemp = _lookHelp = _invLookFlag = 0;
+					events.clearEvents();
+				}
+			}
+		}
+	}
+
+	// Reset the old bgshape number if the mouse button is released, so that
+	// it can e re-highlighted when we come back here
+	if ((events._rightReleased && _helpStyle) || (events._released && !_helpStyle))
+		_oldBgFound = -1;
+
+	// Do routines that should be done before input processing
+	switch (_menuMode) {
+	case LOOK_MODE:
+		if (!_windowOpen) {
+			if (events._released && _bgFound >= 0 && _bgFound < 1000) {
+				if (!scene._bgShapes[_bgFound]._examine.empty())
+					examine();
+			} else {
+				lookScreen(pt);
+			}
+		}
+		break;
+
+	case MOVE_MODE:
+	case OPEN_MODE:
+	case CLOSE_MODE:
+	case PICKUP_MODE:
+		lookScreen(pt);
+		break;
+
+	case TALK_MODE:
+		if (!_windowOpen) {
+			bool personFound;
+
+			if (_bgFound >= 1000) {
+				personFound = false;
+				if (!events._released)
+					lookScreen(pt);
+			} else {
+				personFound = _bgFound != -1 && scene._bgShapes[_bgFound]._aType == PERSON;
+			}
+
+			if (events._released && personFound)
+				talk.talk(_bgFound);
+			else if (personFound)
+				lookScreen(pt);
+			else if (_bgFound < 1000)
+				clearInfo();
+		}
+		break;
+
+	case USE_MODE:
+	case GIVE_MODE:
+	case INV_MODE:
+		if (inv._invMode == INVMODE_LOOK || inv._invMode == INVMODE_USE || inv._invMode == INVMODE_GIVE) {
+			if (pt.y > CONTROLS_Y)
+				lookInv();
+			else
+				lookScreen(pt);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	//
+	// Do input processing
+	//
+	if (events._pressed || events._released || events._rightPressed || _keyPress || _pause) {
+		if (((events._released && (_helpStyle || _help == -1)) || (events._rightReleased && !_helpStyle)) &&
+				(pt.y <= CONTROLS_Y) && (_menuMode == STD_MODE)) {
+			// The mouse was clicked in the playing area with no action buttons down.
+			// Check if the mouse was clicked in a script zone. If it was,
+			// then execute the script. Otherwise, walk to the given position
+			if (scene.checkForZones(pt, SCRIPT_ZONE) != 0 ||
+					scene.checkForZones(pt, NOWALK_ZONE) != 0) {
+				// Mouse clicked in script zone
+				events._pressed = events._released = false;
+			} else {
+				people._walkDest = pt;
+				people._allowWalkAbort = false;
+				people.goAllTheWay();
+			}
+
+			if (_oldKey != -1) {
+				restoreButton(_oldTemp);
+				_oldKey = -1;
+			}
+		}
+
+		// Handle action depending on selected mode
+		switch (_menuMode) {
+		case LOOK_MODE:
+			if (_windowOpen)
+				doLookControl();
+			break;
+
+		case MOVE_MODE:
+			doMiscControl(ALLOW_MOVE);
+			break;
+
+		case TALK_MODE:
+			if (_windowOpen)
+				doTalkControl();
+			break;
+
+		case OPEN_MODE:
+			doMiscControl(ALLOW_OPEN);
+			break;
+
+		case CLOSE_MODE:
+			doMiscControl(ALLOW_CLOSE);
+			break;
+
+		case PICKUP_MODE:
+			doPickControl();
+			break;
+
+		case USE_MODE:
+		case GIVE_MODE:
+		case INV_MODE:
+			doInvControl();
+			break;
+
+		case FILES_MODE:
+			doEnvControl();
+			break;
+
+		default:
+			break;
+		}
+
+		// As long as there isn't an open window, do main input processing.
+		// Windows are opened when in TALK, USE, INV, and GIVE modes
+		if ((!_windowOpen && !_menuCounter && pt.y > CONTROLS_Y) ||
+				_keyPress) {
+			if (events._pressed || events._released || _pause || _keyPress)
+				doMainControl();
+		}
+
+		if (pt.y < CONTROLS_Y && events._pressed && _oldTemp != (int)(_menuMode - 1) && _oldKey != -1)
+			restoreButton(_oldTemp);
+	}
+}
+
+void ScalpelUserInterface::depressButton(int num) {
+	Screen &screen = *_vm->_screen;
+	Common::Point pt(MENU_POINTS[num][0], MENU_POINTS[num][1]);
+
+	ImageFrame &frame = (*_controls)[num];
+	screen._backBuffer1.transBlitFrom(frame, pt);
+	screen.slamArea(pt.x, pt.y, pt.x + frame._width, pt.y + frame._height);
+}
+
+void ScalpelUserInterface::restoreButton(int num) {
+	Screen &screen = *_vm->_screen;
+	Common::Point pt(MENU_POINTS[num][0], MENU_POINTS[num][1]);
+	Graphics::Surface &frame = (*_controls)[num]._frame;
+
+	screen._backBuffer1.blitFrom(screen._backBuffer2, pt,
+		Common::Rect(pt.x, pt.y, pt.x + 90, pt.y + 19));
+	screen.slamArea(pt.x, pt.y, pt.x + frame.w, pt.y + frame.h);
+
+	if (!_menuCounter) {
+		_infoFlag = true;
+		clearInfo();
+	}
+}
+
+void ScalpelUserInterface::pushButton(int num) {
+	Events &events = *_vm->_events;
+	_oldKey = -1;
+
+	if (!events._released) {
+		if (_oldHelp != -1)
+			restoreButton(_oldHelp);
+		if (_help != -1)
+			restoreButton(_help);
+
+		depressButton(num);
+		events.wait(6);
+	}
+
+	restoreButton(num);
+}
+
+void ScalpelUserInterface::toggleButton(int num) {
+	Screen &screen = *_vm->_screen;
+
+	if (_menuMode != (MenuMode)(num + 1)) {
+		_menuMode = (MenuMode)(num + 1);
+		_oldKey = COMMANDS[num];
+		_oldTemp = num;
+
+		if (_keyboardInput) {
+			if (_oldHelp != -1 && _oldHelp != num)
+				restoreButton(_oldHelp);
+			if (_help != -1 && _help != num)
+				restoreButton(_help);
+
+			_keyboardInput = false;
+
+			ImageFrame &frame = (*_controls)[num];
+			Common::Point pt(MENU_POINTS[num][0], MENU_POINTS[num][1]);
+			screen._backBuffer1.transBlitFrom(frame, pt);
+			screen.slamArea(pt.x, pt.y, pt.x + frame._width, pt.y + frame._height);
+		}
+	} else {
+		_menuMode = STD_MODE;
+		_oldKey = -1;
+		restoreButton(num);
+	}
+}
+
+void ScalpelUserInterface::clearInfo() {
+	if (_infoFlag) {
+		_vm->_screen->vgaBar(Common::Rect(16, INFO_LINE, SHERLOCK_SCREEN_WIDTH - 19,
+			INFO_LINE + 10), INFO_BLACK);
+		_infoFlag = false;
+		_oldLook = -1;
+	}
+}
+
+void ScalpelUserInterface::clearWindow() {
+	if (_windowOpen) {
+		_vm->_screen->vgaBar(Common::Rect(3, CONTROLS_Y + 11, SHERLOCK_SCREEN_WIDTH - 2,
+			SHERLOCK_SCREEN_HEIGHT - 2), INV_BACKGROUND);
+	}
+}
+
+void ScalpelUserInterface::whileMenuCounter() {
+	if (!(--_menuCounter) || _vm->_events->checkInput()) {
+		_menuCounter = 0;
+		_infoFlag = true;
+		clearInfo();
+	}
+}
+
+void ScalpelUserInterface::examine() {
+	Events &events = *_vm->_events;
+	Inventory &inv = *_vm->_inventory;
+	People &people = *_vm->_people;
+	Scene &scene = *_vm->_scene;
+	Talk &talk = *_vm->_talk;
+	Common::Point pt = events.mousePos();
+
+	if (pt.y < (CONTROLS_Y + 9)) {
+		Object &obj = scene._bgShapes[_bgFound];
+
+		if (obj._lookcAnim != 0) {
+			int canimSpeed = ((obj._lookcAnim & 0xe0) >> 5) + 1;
+			scene._cAnimFramePause = obj._lookFrames;
+			_cAnimStr = obj._examine;
+			_cNum = (obj._lookcAnim & 0x1f) - 1;
+
+			scene.startCAnim(_cNum, canimSpeed);
+		} else if (obj._lookPosition.y != 0) {
+			// Need to walk to the object to be examined
+			people.walkToCoords(Common::Point(obj._lookPosition.x, obj._lookPosition.y * 100), obj._lookFacing);
+		}
+
+		if (!talk._talkToAbort) {
+			_cAnimStr = obj._examine;
+			if (obj._lookFlag)
+				_vm->setFlags(obj._lookFlag);
+		}
+	} else {
+		// Looking at an inventory item
+		_cAnimStr = inv[_selector]._examine;
+		if (inv[_selector]._lookFlag)
+			_vm->setFlags(inv[_selector]._lookFlag);
+	}
+
+	if (_invLookFlag) {
+		// Don't close the inventory window when starting an examine display, since its
+		// window will slide up to replace the inventory display
+		_windowOpen = false;
+		_menuMode = LOOK_MODE;
+	}
+
+	if (!talk._talkToAbort) {
+		if (!scene._cAnimFramePause)
+			printObjectDesc(_cAnimStr, true);
+		else
+			// description was already printed in startCAnimation
+			scene._cAnimFramePause = 0;
+	}
+}
+
+void ScalpelUserInterface::lookScreen(const Common::Point &pt) {
+	Events &events = *_vm->_events;
+	Inventory &inv = *_vm->_inventory;
+	Scene &scene = *_vm->_scene;
+	Screen &screen = *_vm->_screen;
+	Common::Point mousePos = events.mousePos();
+	int temp;
+	Common::String tempStr;
+
+	// Don't display anything for right button command
+	if ((events._rightPressed || events._rightPressed) && !events._pressed)
+		return;
+
+	if (mousePos.y < CONTROLS_Y && (temp = _bgFound) != -1) {
+		if (temp != _oldLook) {
+			_infoFlag = true;
+			clearInfo();
+
+			if (temp < 1000)
+				tempStr = scene._bgShapes[temp]._description;
+			else
+				tempStr = scene._bgShapes[temp - 1000]._description;
+
+			_infoFlag = true;
+			clearInfo();
+
+			// Only print description if there is one
+			if (!tempStr.empty() && tempStr[0] != ' ') {
+				// If inventory is active and an item is selected for a Use or Give action
+				if ((_menuMode == INV_MODE || _menuMode == USE_MODE || _menuMode == GIVE_MODE) &&
+						(inv._invMode == INVMODE_USE || inv._invMode == INVMODE_GIVE)) {
+					int width1 = 0, width2 = 0;
+					int x, width;
+					if (inv._invMode == INVMODE_USE) {
+						// Using an object
+						x = width = screen.stringWidth("Use ");
+
+						if (temp < 1000 && scene._bgShapes[temp]._aType != PERSON)
+							// It's not a person, so make it lowercase
+							tempStr.setChar(tolower(tempStr[0]), 0);
+
+						x += screen.stringWidth(tempStr);
+
+						// If we're using an inventory object, add in the width
+						// of the object name and the " on "
+						if (_selector != -1) {
+							width1 = screen.stringWidth(inv[_selector]._name);
+							x += width1;
+							width2 = screen.stringWidth(" on ");
+							x += width2;
+						}
+
+						// If the line will be too long, keep cutting off characters
+						// until the string will fit
+						while (x > 280) {
+							x -= screen.charWidth(tempStr.lastChar());
+							tempStr.deleteLastChar();
+						}
+
+						int xStart = (SHERLOCK_SCREEN_WIDTH - x) / 2;
+						screen.print(Common::Point(xStart, INFO_LINE + 1),
+							INFO_FOREGROUND, "Use ");
+
+						if (_selector != -1) {
+							screen.print(Common::Point(xStart + width, INFO_LINE + 1),
+								TALK_FOREGROUND, "%s", inv[_selector]._name.c_str());
+							screen.print(Common::Point(xStart + width + width1, INFO_LINE + 1),
+								INFO_FOREGROUND, " on ");
+							screen.print(Common::Point(xStart + width + width1 + width2, INFO_LINE + 1),
+								INFO_FOREGROUND, "%s", tempStr.c_str());
+						} else {
+							screen.print(Common::Point(xStart + width, INFO_LINE + 1),
+								INFO_FOREGROUND, "%s", tempStr.c_str());
+						}
+					} else if (temp >= 0 && temp < 1000 && _selector != -1 &&
+							scene._bgShapes[temp]._aType == PERSON) {
+						// Giving an object to a person
+						width1 = screen.stringWidth(inv[_selector]._name);
+						x = width = screen.stringWidth("Give ");
+						x += width1;
+						width2 = screen.stringWidth(" to ");
+						x += width2;
+						x += screen.stringWidth(tempStr);
+
+						// Ensure string will fit on-screen
+						while (x > 280) {
+							x -= screen.charWidth(tempStr.lastChar());
+							tempStr.deleteLastChar();
+						}
+
+						int xStart = (SHERLOCK_SCREEN_WIDTH - x) / 2;
+						screen.print(Common::Point(xStart, INFO_LINE + 1),
+							INFO_FOREGROUND, "Give ");
+						screen.print(Common::Point(xStart + width, INFO_LINE + 1),
+							TALK_FOREGROUND, "%s", inv[_selector]._name.c_str());
+						screen.print(Common::Point(xStart + width + width1, INFO_LINE + 1),
+							INFO_FOREGROUND, " to ");
+						screen.print(Common::Point(xStart + width + width1 + width2, INFO_LINE + 1),
+							INFO_FOREGROUND, "%s", tempStr.c_str());
+					}
+				} else {
+					screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", tempStr.c_str());
+				}
+
+				_infoFlag = true;
+				_oldLook = temp;
+			}
+		}
+	} else {
+		clearInfo();
+	}
+}
+
+void ScalpelUserInterface::lookInv() {
+	Events &events = *_vm->_events;
+	Inventory &inv = *_vm->_inventory;
+	Screen &screen = *_vm->_screen;
+	Common::Point mousePos = events.mousePos();
+
+	if (mousePos.x > 15 && mousePos.x < 314 && mousePos.y > (CONTROLS_Y1 + 11)
+			&& mousePos.y < (SHERLOCK_SCREEN_HEIGHT - 2)) {
+		int temp = (mousePos.x - 6) / 52 + inv._invIndex;
+		if (temp < inv._holdings) {
+			if (temp < inv._holdings) {
+				clearInfo();
+				screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND,
+					"%s", inv[temp]._description.c_str());
+				_infoFlag = true;
+				_oldLook = temp;
+			}
+		} else {
+			clearInfo();
+		}
+	} else {
+		clearInfo();
+	}
+}
+
+void ScalpelUserInterface::doEnvControl() {
+	Events &events = *_vm->_events;
+	SaveManager &saves = *_vm->_saves;
+	Scene &scene = *_vm->_scene;
+	Screen &screen = *_vm->_screen;
+	Talk &talk = *_vm->_talk;
+	Common::Point mousePos = events.mousePos();
+	static const char ENV_COMMANDS[7] = "ELSUDQ";
+
+	byte color;
+
+	_key = _oldKey = -1;
+	_keyboardInput = false;
+	int found = saves.getHighlightedButton();
+
+	if (events._pressed || events._released) {
+		events.clearKeyboard();
+
+		// Check for a filename entry being highlighted
+		if ((events._pressed || events._released) && mousePos.y > (CONTROLS_Y + 10)) {
+			int found1 = 0;
+			for (_selector = 0; (_selector < ONSCREEN_FILES_COUNT) && !found1; ++_selector)
+				if (mousePos.y > (CONTROLS_Y + 11 + _selector * 10) && mousePos.y < (CONTROLS_Y + 21 + _selector * 10))
+					found1 = 1;
+
+			if (_selector + saves._savegameIndex - 1 < MAX_SAVEGAME_SLOTS + (saves._envMode != SAVEMODE_LOAD))
+				_selector = _selector + saves._savegameIndex - 1;
+			else
+				_selector = -1;
+
+			if (!found1)
+				_selector = -1;
+		}
+
+		// Handle selecting buttons, if any
+		saves.highlightButtons(found);
+
+		if (found == 0 || found == 5)
+			saves._envMode = SAVEMODE_NONE;
+	}
+
+	if (_keyPress) {
+		_key = toupper(_keyPress);
+
+		// Escape _key will close the dialog
+		if (_key == Common::KEYCODE_ESCAPE)
+			_key = 'E';
+
+		if (_key == 'E' || _key == 'L' || _key == 'S' || _key == 'U' || _key == 'D' || _key == 'Q') {
+			const char *chP = strchr(ENV_COMMANDS, _key);
+			int btnIndex = !chP ? -1 : chP - ENV_COMMANDS;
+			saves.highlightButtons(btnIndex);
+			_keyboardInput = true;
+
+			if (_key == 'E' || _key == 'Q') {
+				saves._envMode = SAVEMODE_NONE;
+			} else if (_key >= '1' && _key <= '9') {
+				_keyboardInput = true;
+				_selector = _key - '1';
+				if (_selector >= MAX_SAVEGAME_SLOTS + (saves._envMode == SAVEMODE_LOAD ? 0 : 1))
+					_selector = -1;
+
+				if (saves.checkGameOnScreen(_selector))
+					_oldSelector = _selector;
+			} else {
+				_selector = -1;
+			}
+		}
+	}
+
+	if (_selector != _oldSelector)  {
+		if (_oldSelector != -1 && _oldSelector >= saves._savegameIndex && _oldSelector < (saves._savegameIndex + ONSCREEN_FILES_COUNT)) {
+			screen.print(Common::Point(6, CONTROLS_Y + 12 + (_oldSelector - saves._savegameIndex) * 10),
+				INV_FOREGROUND, "%d.", _oldSelector + 1);
+			screen.print(Common::Point(24, CONTROLS_Y + 12 + (_oldSelector - saves._savegameIndex) * 10),
+				INV_FOREGROUND, "%s", saves._savegames[_oldSelector].c_str());
+		}
+
+		if (_selector != -1) {
+			screen.print(Common::Point(6, CONTROLS_Y + 12 + (_selector - saves._savegameIndex) * 10),
+				TALK_FOREGROUND, "%d.", _selector + 1);
+			screen.print(Common::Point(24, CONTROLS_Y + 12 + (_selector - saves._savegameIndex) * 10),
+				TALK_FOREGROUND, "%s", saves._savegames[_selector].c_str());
+		}
+
+		_oldSelector = _selector;
+	}
+
+	if (events._released || _keyboardInput) {
+		if ((found == 0 && events._released) || _key == 'E') {
+			banishWindow();
+			_windowBounds.top = CONTROLS_Y1;
+
+			events._pressed = events._released = _keyboardInput = false;
+			_keyPress = '\0';
+		} else if ((found == 1 && events._released) || _key == 'L') {
+			saves._envMode = SAVEMODE_LOAD;
+			if (_selector != -1) {
+				saves.loadGame(_selector + 1);
+			}
+		} else if ((found == 2 && events._released) || _key == 'S') {
+			saves._envMode = SAVEMODE_SAVE;
+			if (_selector != -1) {
+				if (saves.checkGameOnScreen(_selector))
+					_oldSelector = _selector;
+
+				if (saves.promptForDescription(_selector)) {
+					saves.saveGame(_selector + 1, saves._savegames[_selector]);
+
+					banishWindow(1);
+					_windowBounds.top = CONTROLS_Y1;
+					_key = _oldKey = -1;
+					_keyPress = '\0';
+					_keyboardInput = false;
+				} else {
+					if (!talk._talkToAbort) {
+						screen._backBuffer1.fillRect(Common::Rect(6, CONTROLS_Y + 11 + (_selector - saves._savegameIndex) * 10,
+							SHERLOCK_SCREEN_WIDTH - 2, CONTROLS_Y + 20 + (_selector - saves._savegameIndex) * 10), INV_BACKGROUND);
+						screen.gPrint(Common::Point(6, CONTROLS_Y + 11 + (_selector - saves._savegameIndex) * 10), INV_FOREGROUND,
+							"%d.", _selector + 1);
+						screen.gPrint(Common::Point(24, CONTROLS_Y + 11 + (_selector - saves._savegameIndex) * 10), INV_FOREGROUND,
+							"%s", saves._savegames[_selector].c_str());
+
+						screen.slamArea(6, CONTROLS_Y + 11 + (_selector - saves._savegameIndex) * 10, 311, 10);
+						_selector = _oldSelector = -1;
+					}
+				}
+			}
+		} else if (((found == 3 && events._released) || _key == 'U') && saves._savegameIndex) {
+			bool moreKeys;
+			do {
+				saves._savegameIndex--;
+				screen._backBuffer1.fillRect(Common::Rect(3, CONTROLS_Y + 11, SHERLOCK_SCREEN_WIDTH - 2,
+					SHERLOCK_SCREEN_HEIGHT - 1), INV_BACKGROUND);
+
+				for (int idx = saves._savegameIndex; idx < (saves._savegameIndex + ONSCREEN_FILES_COUNT); ++idx) {
+					color = INV_FOREGROUND;
+					if (idx == _selector && idx >= saves._savegameIndex && idx < (saves._savegameIndex + ONSCREEN_FILES_COUNT))
+						color = TALK_FOREGROUND;
+
+					screen.gPrint(Common::Point(6, CONTROLS_Y + 11 + (idx - saves._savegameIndex) * 10), color, "%d.", idx + 1);
+					screen.gPrint(Common::Point(24, CONTROLS_Y + 11 + (idx - saves._savegameIndex) * 10), color, "%s", saves._savegames[idx].c_str());
+				}
+
+				screen.slamRect(Common::Rect(3, CONTROLS_Y + 11, SHERLOCK_SCREEN_WIDTH - 2, SHERLOCK_SCREEN_HEIGHT));
+
+				color = !saves._savegameIndex ? COMMAND_NULL : COMMAND_FOREGROUND;
+				screen.buttonPrint(Common::Point(ENV_POINTS[3][2], CONTROLS_Y), color, true, "Up");
+				color = (saves._savegameIndex == MAX_SAVEGAME_SLOTS - ONSCREEN_FILES_COUNT) ? COMMAND_NULL : COMMAND_FOREGROUND;
+				screen.buttonPrint(Common::Point(ENV_POINTS[4][2], CONTROLS_Y), color, true, "Down");
+
+				// Check whether there are more pending U keys pressed
+				moreKeys = false;
+				if (events.kbHit()) {
+					Common::KeyState keyState = events.getKey();
+
+					_key = toupper(keyState.keycode);
+					moreKeys = _key == 'U';
+				}
+			} while ((saves._savegameIndex) && moreKeys);
+		} else if (((found == 4 && events._released) || _key == 'D') && saves._savegameIndex < (MAX_SAVEGAME_SLOTS - ONSCREEN_FILES_COUNT)) {
+			bool moreKeys;
+			do {
+				saves._savegameIndex++;
+				screen._backBuffer1.fillRect(Common::Rect(3, CONTROLS_Y + 11, SHERLOCK_SCREEN_WIDTH - 2,
+					SHERLOCK_SCREEN_HEIGHT - 1), INV_BACKGROUND);
+
+				for (int idx = saves._savegameIndex; idx < (saves._savegameIndex + ONSCREEN_FILES_COUNT); ++idx) {
+					if (idx == _selector && idx >= saves._savegameIndex && idx < (saves._savegameIndex + ONSCREEN_FILES_COUNT))
+						color = TALK_FOREGROUND;
+					else
+						color = INV_FOREGROUND;
+
+					screen.gPrint(Common::Point(6, CONTROLS_Y + 11 + (idx - saves._savegameIndex) * 10), color,
+						"%d.", idx + 1);
+					screen.gPrint(Common::Point(24, CONTROLS_Y + 11 + (idx - saves._savegameIndex) * 10), color,
+						"%s", saves._savegames[idx].c_str());
+				}
+
+				screen.slamRect(Common::Rect(3, CONTROLS_Y + 11, SHERLOCK_SCREEN_WIDTH - 2, SHERLOCK_SCREEN_HEIGHT));
+
+				color = (!saves._savegameIndex) ? COMMAND_NULL : COMMAND_FOREGROUND;
+				screen.buttonPrint(Common::Point(ENV_POINTS[3][2], CONTROLS_Y), color, true, "Up");
+
+				color = (saves._savegameIndex == MAX_SAVEGAME_SLOTS - ONSCREEN_FILES_COUNT) ? COMMAND_NULL : COMMAND_FOREGROUND;
+				screen.buttonPrint(Common::Point(ENV_POINTS[4][2], CONTROLS_Y), color, true, "Down");
+
+				// Check whether there are more pending D keys pressed
+				moreKeys = false;
+				if (events.kbHit()) {
+					Common::KeyState keyState;
+					_key = toupper(keyState.keycode);
+
+					moreKeys = _key == 'D';
+				}
+			} while (saves._savegameIndex < (MAX_SAVEGAME_SLOTS - ONSCREEN_FILES_COUNT) && moreKeys);
+		} else if ((found == 5 && events._released) || _key == 'Q') {
+			clearWindow();
+			screen.print(Common::Point(0, CONTROLS_Y + 20), INV_FOREGROUND, "Are you sure you wish to Quit ?");
+			screen.vgaBar(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, CONTROLS_Y + 10), BORDER_COLOR);
+
+			screen.makeButton(Common::Rect(112, CONTROLS_Y, 160, CONTROLS_Y + 10), 136 - screen.stringWidth("Yes") / 2, "Yes");
+			screen.makeButton(Common::Rect(161, CONTROLS_Y, 209, CONTROLS_Y + 10), 184 - screen.stringWidth("No") / 2, "No");
+			screen.slamArea(112, CONTROLS_Y, 97, 10);
+
+			do {
+				scene.doBgAnim();
+
+				if (talk._talkToAbort)
+					return;
+
+				events.pollEventsAndWait();
+				events.setButtonState();
+				mousePos = events.mousePos();
+
+				if (events.kbHit()) {
+					Common::KeyState keyState = events.getKey();
+					_key = toupper(keyState.keycode);
+
+					if (_key == 'X' && (keyState.flags & Common::KBD_ALT) != 0) {
+						_vm->quitGame();
+						events.pollEvents();
+						return;
+					}
+
+					if (_key == Common::KEYCODE_ESCAPE)
+						_key = 'N';
+
+					if (_key == Common::KEYCODE_RETURN || _key == ' ') {
+						events._pressed = false;
+						events._released = true;
+						events._oldButtons = 0;
+						_keyPress = '\0';
+					}
+				}
+
+				if (events._pressed || events._released) {
+					if (mousePos.x > 112 && mousePos.x < 159 && mousePos.y > CONTROLS_Y && mousePos.y < (CONTROLS_Y + 9))
+						color = COMMAND_HIGHLIGHTED;
+					else
+						color = COMMAND_FOREGROUND;
+					screen.buttonPrint(Common::Point(136, CONTROLS_Y), color, true, "Yes");
+
+					if (mousePos.x > 161 && mousePos.x < 208 && mousePos.y > CONTROLS_Y && mousePos.y < (CONTROLS_Y + 9))
+						color = COMMAND_HIGHLIGHTED;
+					else
+						color = COMMAND_FOREGROUND;
+					screen.buttonPrint(Common::Point(184, CONTROLS_Y), color, true, "No");
+				}
+
+				if (mousePos.x > 112 && mousePos.x < 159 && mousePos.y > CONTROLS_Y && mousePos.y < (CONTROLS_Y + 9) && events._released)
+					_key = 'Y';
+
+				if (mousePos.x > 161 && mousePos.x < 208 && mousePos.y > CONTROLS_Y && mousePos.y < (CONTROLS_Y + 9) && events._released)
+					_key = 'N';
+			} while (!_vm->shouldQuit() && _key != 'Y' && _key != 'N');
+
+			if (_key == 'Y') {
+				_vm->quitGame();
+				events.pollEvents();
+				return;
+			} else {
+				screen.buttonPrint(Common::Point(184, CONTROLS_Y), COMMAND_HIGHLIGHTED, true, "No");
+				banishWindow(1);
+				_windowBounds.top = CONTROLS_Y1;
+				_key = -1;
+			}
+		} else {
+			if (_selector != -1) {
+				// Are we already in Load mode?
+				if (saves._envMode == SAVEMODE_LOAD) {
+					saves.loadGame(_selector + 1);
+				} else if (saves._envMode == SAVEMODE_SAVE || saves.isSlotEmpty(_selector)) {
+					// We're already in save mode, or pointing to an empty save slot
+					if (saves.checkGameOnScreen(_selector))
+						_oldSelector = _selector;
+
+					if (saves.promptForDescription(_selector)) {
+						saves.saveGame(_selector + 1, saves._savegames[_selector]);
+						banishWindow();
+						_windowBounds.top = CONTROLS_Y1;
+						_key = _oldKey = -1;
+						_keyPress = '\0';
+						_keyboardInput = false;
+					} else {
+						if (!talk._talkToAbort) {
+							screen._backBuffer1.fillRect(Common::Rect(6, CONTROLS_Y + 11 + (_selector - saves._savegameIndex) * 10,
+								317, CONTROLS_Y + 20 + (_selector - saves._savegameIndex) * 10), INV_BACKGROUND);
+							screen.gPrint(Common::Point(6, CONTROLS_Y + 11 + (_selector - saves._savegameIndex) * 10),
+								INV_FOREGROUND, "%d.", _selector + 1);
+							screen.gPrint(Common::Point(24, CONTROLS_Y + 11 + (_selector - saves._savegameIndex) * 10),
+								INV_FOREGROUND, "%s", saves._savegames[_selector].c_str());
+							screen.slamArea(6, CONTROLS_Y + 11 + (_selector - saves._savegameIndex) * 10, 311, 10);
+							_selector = _oldSelector = -1;
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
+void ScalpelUserInterface::doInvControl() {
+	Events &events = *_vm->_events;
+	Inventory &inv = *_vm->_inventory;
+	Scene &scene = *_vm->_scene;
+	Screen &screen = *_vm->_screen;
+	Talk &talk = *_vm->_talk;
+	int colors[8];
+	Common::Point mousePos = events.mousePos();
+
+	_key = _oldKey = -1;
+	_keyboardInput = false;
+
+	// Check whether any inventory slot is highlighted
+	int found = -1;
+	Common::fill(&colors[0], &colors[8], (int)COMMAND_FOREGROUND);
+	for (int idx = 0; idx < 8; ++idx) {
+		Common::Rect r(INVENTORY_POINTS[idx][0], CONTROLS_Y1,
+			INVENTORY_POINTS[idx][1], CONTROLS_Y1 + 10);
+		if (r.contains(mousePos)) {
+			found = idx;
+			break;
+		}
+	}
+
+	if (events._pressed || events._released) {
+		events.clearKeyboard();
+
+		if (found != -1)
+			// If a slot highlighted, set its color
+			colors[found] = COMMAND_HIGHLIGHTED;
+		screen.buttonPrint(Common::Point(INVENTORY_POINTS[0][2], CONTROLS_Y1), colors[0], true, "Exit");
+
+		if (found >= 0 && found <= 3) {
+			screen.buttonPrint(Common::Point(INVENTORY_POINTS[1][2], CONTROLS_Y1), colors[1], true, "Look");
+			screen.buttonPrint(Common::Point(INVENTORY_POINTS[2][2], CONTROLS_Y1), colors[2], true, "Use");
+			screen.buttonPrint(Common::Point(INVENTORY_POINTS[3][2], CONTROLS_Y1), colors[3], true, "Give");
+			inv._invMode = (InvMode)found;
+			_selector = -1;
+		}
+
+		if (inv._invIndex) {
+			screen.print(Common::Point(INVENTORY_POINTS[4][2], CONTROLS_Y1 + 1), colors[4], "^^");
+			screen.print(Common::Point(INVENTORY_POINTS[5][2], CONTROLS_Y1 + 1), colors[5], "^");
+		}
+
+		if ((inv._holdings - inv._invIndex) > 6) {
+			screen.print(Common::Point(INVENTORY_POINTS[6][2], CONTROLS_Y1 + 1), colors[6], "_");
+			screen.print(Common::Point(INVENTORY_POINTS[7][2], CONTROLS_Y1 + 1), colors[7], "__");
+		}
+
+		bool flag = false;
+		if (inv._invMode == INVMODE_LOOK || inv._invMode == INVMODE_USE || inv._invMode == INVMODE_GIVE) {
+			Common::Rect r(15, CONTROLS_Y1 + 11, 314, SHERLOCK_SCREEN_HEIGHT - 2);
+			if (r.contains(mousePos)) {
+				_selector = (mousePos.x - 6) / 52 + inv._invIndex;
+				if (_selector < inv._holdings)
+					flag = true;
+			}
+		}
+
+		if (!flag && mousePos.y >(CONTROLS_Y1 + 11))
+			_selector = -1;
+	}
+
+	if (_keyPress) {
+		_key = toupper(_keyPress);
+
+		if (_key == Common::KEYCODE_ESCAPE)
+			// Escape will also 'E'xit out of inventory display
+			_key = 'E';
+
+		if (_key == 'E' || _key == 'L' || _key == 'U' || _key == 'G'
+				|| _key == '-' || _key == '+') {
+			InvMode temp = inv._invMode;
+
+			const char *chP = strchr(INVENTORY_COMMANDS, _key);
+			inv._invMode = !chP ? INVMODE_INVALID : (InvMode)(chP - INVENTORY_COMMANDS);
+			inv.invCommands(true);
+
+			inv._invMode = temp;
+			_keyboardInput = true;
+			if (_key == 'E')
+				inv._invMode = INVMODE_EXIT;
+			_selector = -1;
+		} else {
+			_selector = -1;
+		}
+	}
+
+	if (_selector != _oldSelector) {
+		if (_oldSelector != -1) {
+			// Un-highlight
+			if (_oldSelector >= inv._invIndex && _oldSelector < (inv._invIndex + 6))
+				inv.highlight(_oldSelector, BUTTON_MIDDLE);
+		}
+
+		if (_selector != -1)
+			inv.highlight(_selector, 235);
+
+		_oldSelector = _selector;
+	}
+
+	if (events._released || _keyboardInput) {
+		if ((found == 0 && events._released) || _key == 'E') {
+			inv.freeInv();
+			_infoFlag = true;
+			clearInfo();
+			banishWindow(false);
+			_key = -1;
+			events.clearEvents();
+			events.setCursor(ARROW);
+		} else if ((found == 1 && events._released) || (_key == 'L')) {
+			inv._invMode = INVMODE_LOOK;
+		} else if ((found == 2 && events._released) || (_key == 'U')) {
+			inv._invMode = INVMODE_USE;
+		} else if ((found == 3 && events._released) || (_key == 'G')) {
+			inv._invMode = INVMODE_GIVE;
+		} else if (((found == 4 && events._released) || _key == ',') && inv._invIndex) {
+			if (inv._invIndex >= 6)
+				inv._invIndex -= 6;
+			else
+				inv._invIndex = 0;
+
+			screen.print(Common::Point(INVENTORY_POINTS[4][2], CONTROLS_Y1 + 1),
+				COMMAND_HIGHLIGHTED, "^^");
+			inv.freeGraphics();
+			inv.loadGraphics();
+			inv.putInv(SLAM_DISPLAY);
+			inv.invCommands(true);
+		} else if (((found == 5 && events._released) || _key == '-') && inv._invIndex > 0) {
+			--inv._invIndex;
+			screen.print(Common::Point(INVENTORY_POINTS[4][2], CONTROLS_Y1 + 1), COMMAND_HIGHLIGHTED, "^");
+			inv.freeGraphics();
+			inv.loadGraphics();
+			inv.putInv(SLAM_DISPLAY);
+			inv.invCommands(true);
+		} else if (((found == 6 && events._released) || _key == '+') &&  (inv._holdings - inv._invIndex) > 6) {
+			++inv._invIndex;
+			screen.print(Common::Point(INVENTORY_POINTS[6][2], CONTROLS_Y1 + 1), COMMAND_HIGHLIGHTED, "_");
+			inv.freeGraphics();
+			inv.loadGraphics();
+			inv.putInv(SLAM_DISPLAY);
+			inv.invCommands(true);
+		} else if (((found == 7 && events._released) || _key == '.') && (inv._holdings - inv._invIndex) > 6) {
+			inv._invIndex += 6;
+			if ((inv._holdings - 6) < inv._invIndex)
+				inv._invIndex = inv._holdings - 6;
+
+			screen.print(Common::Point(INVENTORY_POINTS[7][2], CONTROLS_Y1 + 1), COMMAND_HIGHLIGHTED, "_");
+			inv.freeGraphics();
+			inv.loadGraphics();
+			inv.putInv(SLAM_DISPLAY);
+			inv.invCommands(true);
+		} else {
+			// If something is being given, make sure it's being given to a person
+			if (inv._invMode == INVMODE_GIVE) {
+				if (_bgFound != -1 && scene._bgShapes[_bgFound]._aType == PERSON)
+					_find = _bgFound;
+				else
+					_find = -1;
+			} else {
+				_find = _bgFound;
+			}
+
+			if ((mousePos.y < CONTROLS_Y1) && (inv._invMode == INVMODE_LOOK) && (_find >= 0) && (_find < 1000)) {
+				if (!scene._bgShapes[_find]._examine.empty() &&
+						scene._bgShapes[_find]._examine[0] >= ' ')
+					inv.refreshInv();
+			} else if (_selector != -1 || _find >= 0) {
+				// Selector is the inventory object that was clicked on, or selected.
+				// If it's -1, then no inventory item is highlighted yet. Otherwise,
+				// an object in the scene has been clicked.
+
+				if (_selector != -1 && inv._invMode == INVMODE_LOOK
+						&& mousePos.y >(CONTROLS_Y1 + 11))
+					inv.refreshInv();
+
+				if (talk._talkToAbort)
+					return;
+
+				// Now check for the Use and Give actions. If inv_mode is INVMODE_GIVE,
+				// that means GIVE is in effect, _selector is the object being
+				// given, and _find is the target.
+				// The same applies to USE, except if _selector is -1, then USE
+				// is being tried on an object in the scene without an inventory
+				// object being highlighted first.
+
+				if ((inv._invMode == INVMODE_USE || (_selector != -1 && inv._invMode == INVMODE_GIVE)) && _find >= 0) {
+					events._pressed = events._released = false;
+					_infoFlag = true;
+					clearInfo();
+
+					int tempSel = _selector;	// Save the selector
+					_selector = -1;
+
+					inv.putInv(SLAM_DISPLAY);
+					_selector = tempSel;		// Restore it
+					InvMode tempMode = inv._invMode;
+					inv._invMode = INVMODE_USE55;
+					inv.invCommands(true);
+
+					_infoFlag = true;
+					clearInfo();
+					banishWindow(false);
+					_key = -1;
+
+					inv.freeInv();
+
+					bool giveFl = (tempMode >= INVMODE_GIVE);
+					if (_selector >= 0)
+						// Use/Give inv object with scene object
+						checkUseAction(&scene._bgShapes[_find]._use[0], inv[_selector]._name, MUSE, _find, giveFl);
+					else
+						// Now inv object has been highlighted
+						checkUseAction(&scene._bgShapes[_find]._use[0], "*SELF*", MUSE, _find, giveFl);
+
+					_selector = _oldSelector = -1;
+				}
+			}
+		}
+	}
+}
+
+void ScalpelUserInterface::doLookControl() {
+	Events &events = *_vm->_events;
+	Inventory &inv = *_vm->_inventory;
+	Screen &screen = *_vm->_screen;
+
+	_key = _oldKey = -1;
+	_keyboardInput = (_keyPress != '\0');
+
+	if (events._released || events._rightReleased || _keyboardInput) {
+		// Is an inventory object being looked at?
+		if (!_invLookFlag) {
+			// Is there any remaining text to display?
+			if (!_descStr.empty()) {
+				printObjectDesc(_descStr, false);
+			} else if (!_lookHelp) {
+				// Need to close the window and depress the Look button
+				Common::Point pt(MENU_POINTS[0][0], MENU_POINTS[0][1]);
+				screen._backBuffer2.blitFrom((*_controls)[0], pt);
+				banishWindow(true);
+
+				_windowBounds.top = CONTROLS_Y1;
+				_key = _oldKey = COMMANDS[LOOK_MODE - 1];
+				_temp = _oldTemp = 0;
+				_menuMode = LOOK_MODE;
+				events.clearEvents();
+
+				// Restore UI
+				drawInterface();
+			} else {
+				events.setCursor(ARROW);
+				banishWindow(true);
+				_windowBounds.top = CONTROLS_Y1;
+				_key = _oldKey = -1;
+				_temp = _oldTemp = 0;
+				_menuMode = STD_MODE;
+				events.clearEvents();
+			}
+		} else {
+			// Looking at an inventory object
+			// Backup the user interface
+			Surface tempSurface(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT - CONTROLS_Y1);
+			tempSurface.blitFrom(screen._backBuffer2, Common::Point(0, 0),
+				Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
+
+			inv.drawInventory(INVENTORY_DONT_DISPLAY);
+			banishWindow(true);
+
+			// Restore the ui
+			screen._backBuffer2.blitFrom(tempSurface, Common::Point(0, CONTROLS_Y1));
+
+			_windowBounds.top = CONTROLS_Y1;
+			_key = _oldKey = COMMANDS[LOOK_MODE - 1];
+			_temp = _oldTemp = 0;
+			events.clearEvents();
+			_invLookFlag = false;
+			_menuMode = INV_MODE;
+			_windowOpen = true;
+		}
+	}
+}
+
+void ScalpelUserInterface::doMainControl() {
+	Events &events = *_vm->_events;
+	Inventory &inv = *_vm->_inventory;
+	SaveManager &saves = *_vm->_saves;
+	Common::Point pt = events.mousePos();
+
+	if ((events._pressed || events._released) && pt.y > CONTROLS_Y) {
+		events.clearKeyboard();
+		_key = -1;
+
+		// Check whether the mouse is in any of the command areas
+		for (_temp = 0; (_temp < 12) && (_key == -1); ++_temp) {
+			Common::Rect r(MENU_POINTS[_temp][0], MENU_POINTS[_temp][1],
+				MENU_POINTS[_temp][2], MENU_POINTS[_temp][3]);
+			if (r.contains(pt))
+				_key = COMMANDS[_temp];
+		}
+		--_temp;
+	} else if (_keyPress) {
+		// Keyboard control
+		_keyboardInput = true;
+
+		if (_keyPress >= 'A' && _keyPress <= 'Z') {
+			const char *c = strchr(COMMANDS, _keyPress);
+			_temp = !c ? 12 : c - COMMANDS;
+		} else {
+			_temp = 12;
+		}
+
+		if (_temp == 12)
+			_key = -1;
+
+		if (events._rightPressed) {
+			_temp = 12;
+			_key = -1;
+		}
+	} else if (!events._released) {
+		_key = -1;
+	}
+
+	// Check if the button being pointed to has changed
+	if (_oldKey != _key && !_windowOpen) {
+		// Clear the info line
+		_infoFlag = true;
+		clearInfo();
+
+		// If there was an old button selected, restore it
+		if (_oldKey != -1) {
+			_menuMode = STD_MODE;
+			restoreButton(_oldTemp);
+		}
+
+		// If a new button is being pointed to, highlight it
+		if (_key != -1 && _temp < 12 && !_keyboardInput)
+			depressButton(_temp);
+
+		// Save the new button selection
+		_oldKey = _key;
+		_oldTemp = _temp;
+	}
+
+	if (!events._pressed && !_windowOpen) {
+		switch (_key) {
+		case 'L':
+			toggleButton(0);
+			break;
+		case 'M':
+			toggleButton(1);
+			break;
+		case 'T':
+			toggleButton(2);
+			break;
+		case 'P':
+			toggleButton(3);
+			break;
+		case 'O':
+			toggleButton(4);
+			break;
+		case 'C':
+			toggleButton(5);
+			break;
+		case 'I':
+			pushButton(6);
+			_selector = _oldSelector = -1;
+			_menuMode = INV_MODE;
+			inv.drawInventory(PLAIN_INVENTORY);
+			break;
+		case 'U':
+			pushButton(7);
+			_selector = _oldSelector = -1;
+			_menuMode = USE_MODE;
+			inv.drawInventory(USE_INVENTORY_MODE);
+			break;
+		case 'G':
+			pushButton(8);
+			_selector = _oldSelector = -1;
+			_menuMode = GIVE_MODE;
+			inv.drawInventory(GIVE_INVENTORY_MODE);
+			break;
+		case 'J':
+			pushButton(9);
+			_menuMode = JOURNAL_MODE;
+			journalControl();
+			break;
+		case 'F':
+			pushButton(10);
+
+			// Create a thumbnail of the current screen before the files dialog is shown, in case
+			// the user saves the game
+			saves.createThumbnail();
+
+			_selector = _oldSelector = -1;
+
+			if (_vm->_showOriginalSavesDialog) {
+				// Show the original dialog
+				_menuMode = FILES_MODE;
+				saves.drawInterface();
+				_windowOpen = true;
+			} else {
+				// Show the ScummVM GMM instead
+				_vm->_canLoadSave = true;
+				_vm->openMainMenuDialog();
+				_vm->_canLoadSave = false;
+			}
+			break;
+		case 'S':
+			pushButton(11);
+			_menuMode = SETUP_MODE;
+			Settings::show(_vm);
+			break;
+		default:
+			break;
+		}
+
+		_help = _oldHelp = _oldBgFound = -1;
+	}
+}
+
+void ScalpelUserInterface::doMiscControl(int allowed) {
+	Events &events = *_vm->_events;
+	Scene &scene = *_vm->_scene;
+	Talk &talk = *_vm->_talk;
+
+	if (events._released) {
+		_temp = _bgFound;
+		if (_bgFound != -1) {
+			// Only allow pointing to objects, not people
+			if (_bgFound < 1000) {
+				events.clearEvents();
+				Object &obj = scene._bgShapes[_bgFound];
+
+				switch (allowed) {
+				case ALLOW_OPEN:
+					checkAction(obj._aOpen, MOPEN, _temp);
+					if (_menuMode != TALK_MODE && !talk._talkToAbort) {
+						_menuMode = STD_MODE;
+						restoreButton(OPEN_MODE - 1);
+						_key = _oldKey = -1;
+					}
+					break;
+
+				case ALLOW_CLOSE:
+					checkAction(obj._aClose, MCLOSE, _temp);
+					if (_menuMode != TALK_MODE && !talk._talkToAbort) {
+						_menuMode = STD_MODE;
+						restoreButton(CLOSE_MODE - 1);
+						_key = _oldKey = -1;
+					}
+					break;
+
+				case ALLOW_MOVE:
+					checkAction(obj._aMove, MMOVE, _temp);
+					if (_menuMode != TALK_MODE && !talk._talkToAbort) {
+						_menuMode = STD_MODE;
+						restoreButton(MOVE_MODE - 1);
+						_key = _oldKey = -1;
+					}
+					break;
+
+				default:
+					break;
+				}
+			}
+		}
+	}
+}
+
+void ScalpelUserInterface::doPickControl() {
+	Events &events = *_vm->_events;
+	Scene &scene = *_vm->_scene;
+	Talk &talk = *_vm->_talk;
+
+	if (events._released) {
+		if ((_temp = _bgFound) != -1) {
+			events.clearEvents();
+
+			// Don't allow characters to be picked up
+			if (_bgFound < 1000) {
+				scene._bgShapes[_bgFound].pickUpObject(MPICK);
+
+				if (!talk._talkToAbort && _menuMode != TALK_MODE) {
+					_key = _oldKey = -1;
+					_menuMode = STD_MODE;
+					restoreButton(PICKUP_MODE - 1);
+				}
+			}
+		}
+	}
+}
+
+void ScalpelUserInterface::doTalkControl() {
+	Events &events = *_vm->_events;
+	Journal &journal = *_vm->_journal;
+	People &people = *_vm->_people;
+	Screen &screen = *_vm->_screen;
+	Sound &sound = *_vm->_sound;
+	Talk &talk = *_vm->_talk;
+	Common::Point mousePos = events.mousePos();
+
+	_key = _oldKey = -1;
+	_keyboardInput = false;
+
+	if (events._pressed || events._released) {
+		events.clearKeyboard();
+
+		// Handle button printing
+		if (mousePos.x > 99 && mousePos.x < 138 && mousePos.y > CONTROLS_Y && mousePos.y < (CONTROLS_Y + 10) && !_endKeyActive)
+			screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_HIGHLIGHTED, true, "Exit");
+		else if (_endKeyActive)
+			screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_FOREGROUND, true, "Exit");
+
+		if (mousePos.x > 140 && mousePos.x < 170 && mousePos.y > CONTROLS_Y && mousePos.y < (CONTROLS_Y + 10) && talk._moreTalkUp)
+			screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_HIGHLIGHTED, true, "Up");
+		else if (talk._moreTalkUp)
+			screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_FOREGROUND, true, "Up");
+
+		if (mousePos.x > 181&& mousePos.x < 220 && mousePos.y > CONTROLS_Y && mousePos.y < (CONTROLS_Y + 10) && talk._moreTalkDown)
+			screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_HIGHLIGHTED, true, "Down");
+		else if (talk._moreTalkDown)
+			screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_FOREGROUND, true, "Down");
+
+		bool found = false;
+		for (_selector = talk._talkIndex; _selector < (int)talk._statements.size() && !found; ++_selector) {
+			if (mousePos.y > talk._statements[_selector]._talkPos.top &&
+					mousePos.y < talk._statements[_selector]._talkPos.bottom)
+				found = true;
+		}
+		--_selector;
+		if (!found)
+			_selector = -1;
+	}
+
+	if (_keyPress) {
+		_key = toupper(_keyPress);
+		if (_key == Common::KEYCODE_ESCAPE)
+			_key = 'E';
+
+		// Check for number press indicating reply line
+		if (_key >= '1' && _key <= ('1' + (int)talk._statements.size() - 1)) {
+			for (uint idx = 0; idx < talk._statements.size(); ++idx) {
+				if (talk._statements[idx]._talkMap == (_key - '1')) {
+					// Found the given statement
+					_selector = idx;
+					_key = -1;
+					_keyboardInput = true;
+					break;
+				}
+			}
+		} else if (_key == 'E' || _key == 'U' || _key == 'D') {
+			_keyboardInput = true;
+		} else {
+			_selector = -1;
+		}
+	}
+
+	if (_selector != _oldSelector) {
+		// Remove highlighting from previous line, if any
+		if (_oldSelector != -1) {
+			if (!((talk._talkHistory[talk._converseNum][_oldSelector] >> (_oldSelector & 7)) & 1))
+				talk.talkLine(_oldSelector, talk._statements[_oldSelector]._talkMap, INV_FOREGROUND,
+					talk._statements[_oldSelector]._talkPos.top, true);
+			else
+				talk.talkLine(_oldSelector, talk._statements[_oldSelector]._talkMap, TALK_NULL,
+					talk._statements[_oldSelector]._talkPos.top, true);
+		}
+
+		// Add highlighting to new line, if any
+		if (_selector != -1)
+			talk.talkLine(_selector, talk._statements[_selector]._talkMap, TALK_FOREGROUND,
+				talk._statements[_selector]._talkPos.top, true);
+
+		_oldSelector = _selector;
+	}
+
+	if (events._released || _keyboardInput) {
+		if (((Common::Rect(99, CONTROLS_Y, 138, CONTROLS_Y + 10).contains(mousePos) && events._released)
+				|| _key == 'E') && _endKeyActive) {
+			talk.freeTalkVars();
+			talk.pullSequence();
+			banishWindow();
+			_windowBounds.top = CONTROLS_Y1;
+		} else if (((Common::Rect(140, CONTROLS_Y, 179, CONTROLS_Y + 10).contains(mousePos) && events._released)
+				|| _key == 'U') && talk._moreTalkUp) {
+			while (talk._statements[--talk._talkIndex]._talkMap == -1)
+				;
+			screen._backBuffer1.fillRect(Common::Rect(5, CONTROLS_Y + 11, SHERLOCK_SCREEN_WIDTH - 2,
+				SHERLOCK_SCREEN_HEIGHT - 1), INV_BACKGROUND);
+			talk.displayTalk(false);
+
+			screen.slamRect(Common::Rect(5, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH - 5, SHERLOCK_SCREEN_HEIGHT - 2));
+		} else if (((Common::Rect(181, CONTROLS_Y, 220, CONTROLS_Y + 10).contains(mousePos) && events._released)
+				|| _key == 'D') && talk._moreTalkDown) {
+			do {
+				++talk._talkIndex;
+			} while (talk._talkIndex < (int)talk._statements.size() && talk._statements[talk._talkIndex]._talkMap == -1);
+
+			screen._backBuffer1.fillRect(Common::Rect(5, CONTROLS_Y + 11, SHERLOCK_SCREEN_WIDTH - 2,
+				SHERLOCK_SCREEN_HEIGHT - 1), INV_BACKGROUND);
+			talk.displayTalk(false);
+
+			screen.slamRect(Common::Rect(5, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH - 5, SHERLOCK_SCREEN_HEIGHT - 2));
+		} else if (_selector != -1) {
+			screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_NULL, true, "Exit");
+			screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, true, "Up");
+			screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, true, "Down");
+
+			// If the reply is new, add it to the journal
+			if (!talk._talkHistory[talk._converseNum][_selector]) {
+				journal.record(talk._converseNum, _selector);
+
+				// Add any Holmes point to Holmes' total, if any
+				if (talk._statements[_selector]._quotient)
+					people._holmesQuotient += talk._statements[_selector]._quotient;
+			}
+
+			// Flag the response as having been used
+			talk._talkHistory[talk._converseNum][_selector] = true;
+
+			clearWindow();
+			screen.print(Common::Point(16, CONTROLS_Y + 12), TALK_FOREGROUND, "Sherlock Holmes");
+			talk.talkLine(_selector + 128, talk._statements[_selector]._talkMap, COMMAND_FOREGROUND, CONTROLS_Y + 21, true);
+
+			switch (talk._statements[_selector]._portraitSide & 3) {
+			case 0:
+			case 1:
+				people._portraitSide = 20;
+				break;
+			case 2:
+				people._portraitSide = 220;
+				break;
+			case 3:
+				people._portraitSide = 120;
+				break;
+			}
+
+			// Check for flipping Holmes
+			if (talk._statements[_selector]._portraitSide & REVERSE_DIRECTION)
+				people._holmesFlip = true;
+
+			talk._speaker = 0;
+			people.setTalking(0);
+
+			if (!talk._statements[_selector]._voiceFile.empty() && sound._voices) {
+				sound.playSound(talk._statements[_selector]._voiceFile, WAIT_RETURN_IMMEDIATELY);
+
+				// Set voices as an indicator for waiting
+				sound._voices = 2;
+				sound._speechOn = *sound._soundIsOn;
+			} else {
+				sound._speechOn = false;
+			}
+
+			talk.waitForMore(talk._statements[_selector]._statement.size());
+			if (talk._talkToAbort)
+				return;
+
+			people.clearTalking();
+			if (talk._talkToAbort)
+				return;
+
+			while (!_vm->shouldQuit()) {
+				talk._scriptSelect = _selector;
+				talk._speaker = talk._talkTo;
+				talk.doScript(talk._statements[_selector]._reply);
+
+				if (!talk._talkToAbort) {
+					if (!talk._talkStealth)
+						clearWindow();
+
+					if (!talk._statements[_selector]._modified.empty()) {
+						for (uint idx = 0; idx < talk._statements[_selector]._modified.size(); ++idx) {
+							_vm->setFlags(talk._statements[_selector]._modified[idx]);
+						}
+
+						talk.setTalkMap();
+					}
+
+					// Check for another linked talk file
+					Common::String linkFilename = talk._statements[_selector]._linkFile;
+					if (!linkFilename.empty() && !talk._scriptMoreFlag) {
+						talk.freeTalkVars();
+						talk.loadTalkFile(linkFilename);
+
+						// Find the first new statement
+						int select = _selector = _oldSelector = -1;
+						for (uint idx = 0; idx < talk._statements.size() && select == -1; ++idx) {
+							if (!talk._statements[idx]._talkMap)
+								select = talk._talkIndex = idx;
+						}
+
+						// See if the new statement is a stealth reply
+						talk._talkStealth = talk._statements[select]._statement.hasPrefix("^") ? 2 : 0;
+
+						// Is the new talk file a standard file, reply first file, or a stealth file
+						if (!talk._statements[select]._statement.hasPrefix("*") &&
+								!talk._statements[select]._statement.hasPrefix("^")) {
+							// Not a reply first file, so display the new selections
+							if (_endKeyActive)
+								screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_FOREGROUND, true, "Exit");
+							else
+								screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_NULL, true, "Exit");
+
+							talk.displayTalk(true);
+							events.setCursor(ARROW);
+							break;
+						} else {
+							_selector = select;
+
+							if (!talk._talkHistory[talk._converseNum][_selector])
+								journal.record(talk._converseNum, _selector);
+
+							talk._talkHistory[talk._converseNum][_selector] = true;
+						}
+					} else {
+						talk.freeTalkVars();
+						talk.pullSequence();
+						banishWindow();
+						_windowBounds.top = CONTROLS_Y1;
+						break;
+					}
+				} else {
+					break;
+				}
+			}
+
+			events._pressed = events._released = false;
+			events._oldButtons = 0;
+			talk._talkStealth = 0;
+
+			// If a script was pushed onto the script stack, restore it
+			if (!talk._scriptStack.empty()) {
+				ScriptStackEntry stackEntry = talk._scriptStack.pop();
+				talk._scriptName = stackEntry._name;
+				talk._scriptSaveIndex = stackEntry._currentIndex;
+				talk._scriptSelect = stackEntry._select;
+			}
+		}
+	}
+}
+
+void ScalpelUserInterface::journalControl() {
+	Events &events = *_vm->_events;
+	Journal &journal = *_vm->_journal;
+	Scene &scene = *_vm->_scene;
+	Screen &screen = *_vm->_screen;
+	bool doneFlag = false;
+
+	// Draw the journal screen
+	journal.drawInterface();
+
+	// Handle journal events
+	do {
+		_key = -1;
+		events.setButtonState();
+
+		// Handle keypresses
+		if (events.kbHit()) {
+			Common::KeyState keyState = events.getKey();
+			if (keyState.keycode == Common::KEYCODE_x && (keyState.flags & Common::KBD_ALT)) {
+				_vm->quitGame();
+				return;
+			} else if (keyState.keycode == Common::KEYCODE_e || keyState.keycode == Common::KEYCODE_ESCAPE) {
+				doneFlag = true;
+			} else {
+				_key = toupper(keyState.keycode);
+			}
+		}
+
+		if (!doneFlag)
+			doneFlag = journal.handleEvents(_key);
+	} while (!_vm->shouldQuit() && !doneFlag);
+
+	// Finish up
+	_infoFlag = _keyboardInput = false;
+	_keyPress = '\0';
+	_windowOpen = false;
+	_windowBounds.top = CONTROLS_Y1;
+	_key = -1;
+	_menuMode = STD_MODE;
+
+	// Reset the palette
+	screen.setPalette(screen._cMap);
+
+	screen._backBuffer1.blitFrom(screen._backBuffer2);
+	scene.updateBackground();
+	screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+}
+
+void ScalpelUserInterface::printObjectDesc(const Common::String &str, bool firstTime) {
+	Events &events = *_vm->_events;
+	Inventory &inv = *_vm->_inventory;
+	Screen &screen = *_vm->_screen;
+	Talk &talk = *_vm->_talk;
+
+	if (str.hasPrefix("_")) {
+		_lookScriptFlag = true;
+		events.setCursor(MAGNIFY);
+		int savedSelector = _selector;
+		talk.talkTo(str.c_str() + 1);
+		_lookScriptFlag = false;
+
+		if (talk._talkToAbort) {
+			events.setCursor(ARROW);
+			return;
+		}
+
+		// Check if looking at an inventory object
+		if (!_invLookFlag) {
+			// See if this look was called by a right button click or not
+			if (!_lookHelp) {
+				// If it wasn't a right button click, then we need depress
+				// the look button before we close the window. So save a copy of the
+				// menu area, and draw the controls onto it
+				Surface tempSurface((*_controls)[0]._frame.w, (*_controls)[0]._frame.h);
+				Common::Point pt(MENU_POINTS[0][0], MENU_POINTS[0][1]);
+
+				tempSurface.blitFrom(screen._backBuffer2, Common::Point(0, 0),
+					Common::Rect(pt.x, pt.y, pt.x + tempSurface.w(), pt.y + tempSurface.h()));
+				screen._backBuffer2.transBlitFrom((*_controls)[0], pt);
+
+				banishWindow(1);
+				events.setCursor(MAGNIFY);
+				_windowBounds.top = CONTROLS_Y1;
+				_key = _oldKey = COMMANDS[LOOK_MODE - 1];
+				_temp = _oldTemp = 0;
+				_menuMode = LOOK_MODE;
+				events.clearEvents();
+
+				screen._backBuffer2.blitFrom(tempSurface, pt);
+			} else {
+				events.setCursor(ARROW);
+				banishWindow(true);
+				_windowBounds.top = CONTROLS_Y1;
+				_key = _oldKey = -1;
+				_temp = _oldTemp = 0;
+				_menuMode = STD_MODE;
+				_lookHelp = 0;
+				events.clearEvents();
+			}
+		} else {
+			// Looking at an inventory object
+			_selector = _oldSelector = savedSelector;
+
+			// Reload the inventory graphics and draw the inventory
+			inv.loadInv();
+			inv.putInv(SLAM_SECONDARY_BUFFER);
+			inv.freeInv();
+			banishWindow(1);
+
+			_windowBounds.top = CONTROLS_Y1;
+			_key = _oldKey = COMMANDS[INV_MODE - 1];
+			_temp = _oldTemp = 0;
+			events.clearEvents();
+
+			_invLookFlag = 0;
+			_menuMode = INV_MODE;
+			_windowOpen = true;
+		}
+
+		return;
+	}
+
+	Surface &bb = *screen._backBuffer;
+	if (firstTime) {
+		// Only draw the border on the first call
+		_infoFlag = true;
+		clearInfo();
+
+		bb.fillRect(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH,
+			CONTROLS_Y1 + 10), BORDER_COLOR);
+		bb.fillRect(Common::Rect(0, CONTROLS_Y + 10, 1, SHERLOCK_SCREEN_HEIGHT - 1),
+			BORDER_COLOR);
+		bb.fillRect(Common::Rect(SHERLOCK_SCREEN_WIDTH - 2, CONTROLS_Y + 10,
+			SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT), BORDER_COLOR);
+		bb.fillRect(Common::Rect(0, SHERLOCK_SCREEN_HEIGHT - 1, SHERLOCK_SCREEN_WIDTH,
+			SHERLOCK_SCREEN_HEIGHT), BORDER_COLOR);
+	}
+
+	// Clear background
+	bb.fillRect(Common::Rect(2, CONTROLS_Y + 10, SHERLOCK_SCREEN_WIDTH - 2,
+		SHERLOCK_SCREEN_HEIGHT - 2), INV_BACKGROUND);
+
+	_windowBounds.top = CONTROLS_Y;
+	events.clearEvents();
+
+	// Loop through displaying up to five lines
+	bool endOfStr = false;
+	const char *msgP = str.c_str();
+	for (int lineNum = 0; lineNum < ONSCREEN_FILES_COUNT && !endOfStr; ++lineNum) {
+		int width = 0;
+		const char *lineStartP = msgP;
+
+		// Determine how much can be displayed on the line
+		do {
+			width += screen.charWidth(*msgP++);
+		} while (width < 300 && *msgP);
+
+		if (*msgP)
+			--msgP;
+		else
+			endOfStr = true;
+
+		// If the line needs to be wrapped, scan backwards to find
+		// the end of the previous word as a splitting point
+		if (width >= 300) {
+			while (*msgP != ' ')
+				--msgP;
+			endOfStr = false;
+		}
+
+		// Print out the line
+		Common::String line(lineStartP, msgP);
+		screen.gPrint(Common::Point(16, CONTROLS_Y + 12 + lineNum * 9),
+			INV_FOREGROUND, "%s", line.c_str());
+
+		if (!endOfStr)
+			// Start next line at start of the nxet word after space
+			++msgP;
+	}
+
+	// Handle display depending on whether all the message was shown
+	if (!endOfStr) {
+		screen.makeButton(Common::Rect(46, CONTROLS_Y, 272, CONTROLS_Y + 10),
+			(SHERLOCK_SCREEN_WIDTH - screen.stringWidth(PRESS_KEY_FOR_MORE)) / 2,
+			PRESS_KEY_FOR_MORE);
+		screen.gPrint(Common::Point((SHERLOCK_SCREEN_WIDTH -
+			screen.stringWidth(PRESS_KEY_FOR_MORE)) / 2, CONTROLS_Y),
+			COMMAND_FOREGROUND, "P");
+		_descStr = msgP;
+	} else {
+		screen.makeButton(Common::Rect(46, CONTROLS_Y, 272, CONTROLS_Y + 10),
+			(SHERLOCK_SCREEN_WIDTH - screen.stringWidth(PRESS_KEY_TO_CONTINUE)) / 2,
+			PRESS_KEY_TO_CONTINUE);
+		screen.gPrint(Common::Point((SHERLOCK_SCREEN_WIDTH -
+			screen.stringWidth(PRESS_KEY_TO_CONTINUE)) / 2, CONTROLS_Y),
+			COMMAND_FOREGROUND, "P");
+		_descStr = "";
+	}
+
+	if (firstTime) {
+		if (!_slideWindows) {
+			screen.slamRect(Common::Rect(0, CONTROLS_Y,
+				SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
+		} else {
+			// Display the window
+			summonWindow();
+		}
+
+		_selector = _oldSelector = -1;
+		_windowOpen = true;
+	} else {
+		screen.slamRect(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH,
+			SHERLOCK_SCREEN_HEIGHT));
+	}
+}
+
+void ScalpelUserInterface::printObjectDesc() {
+	printObjectDesc(_cAnimStr, true);
+}
+
+void ScalpelUserInterface::summonWindow(const Surface &bgSurface, bool slideUp) {
+	Events &events = *_vm->_events;
+	Screen &screen = *_vm->_screen;
+
+	if (_windowOpen)
+		// A window is already open, so can't open another one
+		return;
+
+	if (slideUp) {
+		// Gradually slide up the display of the window
+		for (int idx = 1; idx <= bgSurface.h(); idx += 2) {
+			screen._backBuffer->blitFrom(bgSurface, Common::Point(0, SHERLOCK_SCREEN_HEIGHT - idx),
+				Common::Rect(0, 0, bgSurface.w(), idx));
+			screen.slamRect(Common::Rect(0, SHERLOCK_SCREEN_HEIGHT - idx,
+				SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
+
+			events.delay(10);
+		}
+	} else {
+		// Gradually slide down the display of the window
+		for (int idx = 1; idx <= bgSurface.h(); idx += 2) {
+			screen._backBuffer->blitFrom(bgSurface,
+				Common::Point(0, SHERLOCK_SCREEN_HEIGHT - bgSurface.h()),
+				Common::Rect(0, bgSurface.h() - idx, bgSurface.w(), bgSurface.h()));
+			screen.slamRect(Common::Rect(0, SHERLOCK_SCREEN_HEIGHT - bgSurface.h(),
+				SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT - bgSurface.h() + idx));
+
+			events.delay(10);
+		}
+	}
+
+	// Final display of the entire window
+	screen._backBuffer->blitFrom(bgSurface, Common::Point(0, SHERLOCK_SCREEN_HEIGHT - bgSurface.h()),
+		Common::Rect(0, 0, bgSurface.w(), bgSurface.h()));
+	screen.slamArea(0, SHERLOCK_SCREEN_HEIGHT - bgSurface.h(), bgSurface.w(), bgSurface.h());
+
+	_windowOpen = true;
+}
+
+void ScalpelUserInterface::summonWindow(bool slideUp, int height) {
+	Screen &screen = *_vm->_screen;
+
+	// Extract the window that's been drawn on the back buffer
+	Surface tempSurface(SHERLOCK_SCREEN_WIDTH,
+		(SHERLOCK_SCREEN_HEIGHT - height));
+	Common::Rect r(0, height, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+	tempSurface.blitFrom(screen._backBuffer1, Common::Point(0, 0), r);
+
+	// Remove drawn window with original user interface
+	screen._backBuffer1.blitFrom(screen._backBuffer2,
+		Common::Point(0, height), r);
+
+	// Display the window gradually on-screen
+	summonWindow(tempSurface, slideUp);
+}
+
+void ScalpelUserInterface::banishWindow(bool slideUp) {
+	Events &events = *_vm->_events;
+	Screen &screen = *_vm->_screen;
+
+	if (_windowOpen) {
+		if (slideUp || !_slideWindows) {
+			// Slide window down
+			// Only slide the window if the window style allows it
+			if (_slideWindows) {
+				for (int idx = 2; idx < (SHERLOCK_SCREEN_HEIGHT - CONTROLS_Y); idx += 2) {
+					// Shift the window down by 2 lines
+					byte *pSrc = (byte *)screen._backBuffer1.getBasePtr(0, CONTROLS_Y + idx - 2);
+					byte *pSrcEnd = (byte *)screen._backBuffer1.getBasePtr(0, SHERLOCK_SCREEN_HEIGHT - 2);
+					byte *pDest = (byte *)screen._backBuffer1.getBasePtr(0, SHERLOCK_SCREEN_HEIGHT);
+					Common::copy_backward(pSrc, pSrcEnd, pDest);
+
+					// Restore lines from the ui in the secondary back buffer
+					screen._backBuffer1.blitFrom(screen._backBuffer2,
+						Common::Point(0, CONTROLS_Y),
+						Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, CONTROLS_Y + idx));
+
+					screen.slamArea(0, CONTROLS_Y + idx - 2, SHERLOCK_SCREEN_WIDTH,
+						SHERLOCK_SCREEN_HEIGHT - CONTROLS_Y - idx + 2);
+					events.delay(10);
+				}
+
+				// Restore final two old lines
+				screen._backBuffer1.blitFrom(screen._backBuffer2,
+					Common::Point(0, SHERLOCK_SCREEN_HEIGHT - 2),
+					Common::Rect(0, SHERLOCK_SCREEN_HEIGHT - 2,
+						SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
+				screen.slamArea(0, SHERLOCK_SCREEN_HEIGHT - 2, SHERLOCK_SCREEN_WIDTH, 2);
+			} else {
+				// Restore old area to completely erase window
+				screen._backBuffer1.blitFrom(screen._backBuffer2,
+					Common::Point(0, CONTROLS_Y),
+					Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
+				screen.slamRect(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH,
+					SHERLOCK_SCREEN_HEIGHT));
+			}
+		} else {
+			// Slide the original user interface up to cover the dialog
+			for (int idx = 1; idx < (SHERLOCK_SCREEN_HEIGHT - CONTROLS_Y1); idx += 2) {
+				byte *pSrc = (byte *)screen._backBuffer2.getBasePtr(0, CONTROLS_Y1);
+				byte *pSrcEnd = (byte *)screen._backBuffer2.getBasePtr(0, CONTROLS_Y1 + idx);
+				byte *pDest = (byte *)screen._backBuffer1.getBasePtr(0, SHERLOCK_SCREEN_HEIGHT - idx);
+				Common::copy(pSrc, pSrcEnd, pDest);
+
+				screen.slamArea(0, SHERLOCK_SCREEN_HEIGHT - idx, SHERLOCK_SCREEN_WIDTH,
+					SHERLOCK_SCREEN_HEIGHT);
+				events.delay(10);
+			}
+
+			// Show entire final area
+			screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(0, CONTROLS_Y1),
+				Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
+			screen.slamRect(Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
+		}
+
+		_infoFlag = false;
+		_windowOpen = false;
+	}
+
+	_menuMode = STD_MODE;
+}
+
+void ScalpelUserInterface::checkUseAction(const UseType *use, const Common::String &invName,
+		const char *const messages[], int objNum, bool giveMode) {
+	Events &events = *_vm->_events;
+	Inventory &inv = *_vm->_inventory;
+	Scene &scene = *_vm->_scene;
+	Screen &screen = *_vm->_screen;
+	Talk &talk = *_vm->_talk;
+	bool printed = messages == nullptr;
+
+	if (objNum >= 1000) {
+		// Holmes was specified, so do nothing
+		_infoFlag = true;
+		clearInfo();
+		_infoFlag = true;
+
+		// Display error message
+		_menuCounter = 30;
+		screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "You can't do that to yourself.");
+		return;
+	}
+
+	// Scan for target item
+	int targetNum = -1;
+	if (giveMode) {
+		for (int idx = 0; idx < USE_COUNT && targetNum == -1; ++idx) {
+			if ((use[idx]._target.equalsIgnoreCase("*GIVE*") || use[idx]._target.equalsIgnoreCase("*GIVEP*"))
+					&& use[idx]._names[0].equalsIgnoreCase(invName)) {
+				// Found a match
+				targetNum = idx;
+				if (use[idx]._target.equalsIgnoreCase("*GIVE*"))
+					inv.deleteItemFromInventory(invName);
+			}
+		}
+	} else {
+		for (int idx = 0; idx < USE_COUNT && targetNum == -1; ++idx) {
+			if (use[idx]._target.equalsIgnoreCase(invName))
+				targetNum = idx;
+		}
+	}
+
+	if (targetNum != -1) {
+		// Found a target, so do the action
+		const UseType &action = use[targetNum];
+
+		events.setCursor(WAIT);
+
+		if (action._useFlag)
+			_vm->setFlags(action._useFlag);
+
+		if (action._cAnimNum != 99) {
+			if (action._cAnimNum == 0)
+				scene.startCAnim(9, action._cAnimSpeed);
+			else
+				scene.startCAnim(action._cAnimNum - 1, action._cAnimSpeed);
+		}
+
+		if (!talk._talkToAbort) {
+			Object &obj = scene._bgShapes[objNum];
+			for (int idx = 0; idx < NAMES_COUNT && !talk._talkToAbort; ++idx) {
+				if (obj.checkNameForCodes(action._names[idx], messages)) {
+					if (!talk._talkToAbort)
+						printed = true;
+				}
+			}
+
+			// Print "Done..." as an ending, unless flagged for leaving scene or otherwise flagged
+			if (scene._goToScene != 1 && !printed && !talk._talkToAbort) {
+				_infoFlag = true;
+				clearInfo();
+				screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "Done...");
+				_menuCounter = 25;
+			}
+		}
+	} else {
+		// Couldn't find target, so print error
+		_infoFlag = true;
+		clearInfo();
+
+		if (giveMode) {
+			screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "No, thank you.");
+		} else if (messages == nullptr) {
+			screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "You can't do that.");
+		} else {
+			screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", messages[0]);
+		}
+
+		_infoFlag = true;
+		_menuCounter = 30;
+	}
+
+	events.setCursor(ARROW);
+}
+
+void ScalpelUserInterface::checkAction(ActionType &action, const char *const messages[], int objNum) {
+	Events &events = *_vm->_events;
+	People &people = *_vm->_people;
+	Scene &scene = *_vm->_scene;
+	Screen &screen = *_vm->_screen;
+	Talk &talk = *_vm->_talk;
+	Common::Point pt(-1, -1);
+
+	if (objNum >= 1000)
+		// Ignore actions done on characters
+		return;
+
+	if (!action._cAnimSpeed) {
+		// Invalid action, to print error message
+		_infoFlag = true;
+		clearInfo();
+		screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", messages[action._cAnimNum]);
+		_infoFlag = true;
+
+		// Set how long to show the message
+		_menuCounter = 30;
+	} else {
+		Object &obj = scene._bgShapes[objNum];
+
+		int cAnimNum;
+		if (action._cAnimNum == 0)
+			// Really a 10
+			cAnimNum = 9;
+		else
+			cAnimNum = action._cAnimNum - 1;
+
+		int dir = -1;
+		if (action._cAnimNum != 99) {
+			CAnim &anim = scene._cAnim[cAnimNum];
+
+			if (action._cAnimNum != 99) {
+				if (action._cAnimSpeed & REVERSE_DIRECTION) {
+					pt = anim._teleportPos;
+					dir = anim._teleportDir;
+				} else {
+					pt = anim._goto;
+					dir = anim._gotoDir;
+				}
+			}
+		} else {
+			pt = Common::Point(-1, -1);
+			dir = -1;
+		}
+
+		// Has a value, so do action
+		// Show wait cursor whilst walking to object and doing action
+		events.setCursor(WAIT);
+		bool printed = false;
+
+		for (int nameIdx = 0; nameIdx < NAMES_COUNT; ++nameIdx) {
+			if (action._names[nameIdx].hasPrefix("*") && action._names[nameIdx].size() >= 2
+					&& toupper(action._names[nameIdx][1]) == 'W') {
+				if (obj.checkNameForCodes(Common::String(action._names[nameIdx].c_str() + 2), messages)) {
+					if (!talk._talkToAbort)
+						printed = true;
+				}
+			}
+		}
+
+		bool doCAnim = true;
+		for (int nameIdx = 0; nameIdx < NAMES_COUNT; ++nameIdx) {
+			if (action._names[nameIdx].hasPrefix("*") && action._names[nameIdx].size() >= 2) {
+				char ch = toupper(action._names[nameIdx][1]);
+
+				if (ch == 'T' || ch == 'B') {
+					printed = true;
+					if (pt.x != -1)
+						// Holmes needs to walk to object before the action is done
+						people.walkToCoords(pt, dir);
+
+					if (!talk._talkToAbort) {
+						// Ensure Holmes is on the exact intended location
+						people[AL]._position = pt;
+						people[AL]._sequenceNumber = dir;
+						people.gotoStand(people[AL]);
+
+						talk.talkTo(action._names[nameIdx].c_str() + 2);
+						if (ch == 'T')
+							doCAnim = false;
+					}
+				}
+			}
+		}
+
+		if (doCAnim && !talk._talkToAbort) {
+			if (pt.x != -1)
+				// Holmes needs to walk to object before the action is done
+				people.walkToCoords(pt, dir);
+		}
+
+		for (int nameIdx = 0; nameIdx < NAMES_COUNT; ++nameIdx) {
+			if (action._names[nameIdx].hasPrefix("*") && action._names[nameIdx].size() >= 2
+					&& toupper(action._names[nameIdx][1]) == 'F') {
+				if (obj.checkNameForCodes(action._names[nameIdx].c_str() + 2, messages)) {
+					if (!talk._talkToAbort)
+						printed = true;
+				}
+			}
+		}
+
+		if (doCAnim && !talk._talkToAbort && action._cAnimNum != 99)
+			scene.startCAnim(cAnimNum, action._cAnimSpeed);
+
+		if (!talk._talkToAbort) {
+			for (int nameIdx = 0; nameIdx < NAMES_COUNT && !talk._talkToAbort; ++nameIdx) {
+				if (obj.checkNameForCodes(action._names[nameIdx], messages)) {
+					if (!talk._talkToAbort)
+						printed = true;
+				}
+			}
+
+			// Unless we're leaving the scene, print a "Done" message unless the printed flag has been set
+			if (scene._goToScene != 1 && !printed && !talk._talkToAbort) {
+				_infoFlag = true;
+				clearInfo();
+				screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "Done...");
+
+				// Set how long to show the message
+				_menuCounter = 30;
+			}
+		}
+	}
+
+	// Reset cursor back to arrow
+	events.setCursor(ARROW);
+}
+
+} // End of namespace Scalpel
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/scalpel/scalpel_user_interface.h b/engines/sherlock/scalpel/scalpel_user_interface.h
new file mode 100644
index 0000000..8ed69ac8
--- /dev/null
+++ b/engines/sherlock/scalpel/scalpel_user_interface.h
@@ -0,0 +1,227 @@
+/* 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 SHERLOCK_SCALPEL_UI_H
+#define SHERLOCK_SCALPEL_UI_H
+
+#include "common/scummsys.h"
+#include "sherlock/user_interface.h"
+
+namespace Sherlock {
+
+class Inventory;
+class Talk;
+
+namespace Scalpel {
+
+extern const char COMMANDS[13];
+extern const int MENU_POINTS[12][4];
+
+extern const int INVENTORY_POINTS[8][3];
+extern const char INVENTORY_COMMANDS[9];
+extern const char *const PRESS_KEY_FOR_MORE;
+extern const char *const PRESS_KEY_TO_CONTINUE;
+
+class Settings;
+
+class ScalpelUserInterface: public UserInterface {
+	friend class Inventory;
+	friend class Settings;
+	friend class Talk;
+private:
+	ImageFile *_controlPanel;
+	ImageFile *_controls;
+	char _keyPress;
+	int _lookHelp;
+	int _bgFound, _oldBgFound;
+	int _help, _oldHelp;
+	char _key, _oldKey;
+	int _temp, _oldTemp;
+	int _oldLook;
+	bool _keyboardInput;
+	bool _pause;
+	int _cNum;
+	Common::String _cAnimStr;
+	Common::String _descStr;
+	int _find;
+	int _oldUse;
+private:
+	/**
+	 * Draws the image for a user interface button in the down/pressed state.
+	 */
+	void depressButton(int num);
+
+	/**
+	 * If he mouse button is pressed, then calls depressButton to draw the button
+	 * as pressed; if not, it will show it as released with a call to "restoreButton".
+	 */
+	void pushButton(int num);
+
+	/**
+	 * By the time this method has been called, the graphics for the button change
+	 * have already been drawn. This simply takes care of switching the mode around
+	 * accordingly
+	 */
+	void toggleButton(int num);
+
+	/**
+	 * Creates a text window and uses it to display the in-depth description
+	 * of the highlighted object
+	 */
+	void examine();
+
+	/**
+	 * Print the name of an object in the scene
+	 */
+	void lookScreen(const Common::Point &pt);
+
+	/**
+	 * Gets the item in the inventory the mouse is on and display's it's description
+	 */
+	void lookInv();
+
+	/**
+	 * Handles input when the file list window is being displayed
+	 */
+	void doEnvControl();
+	
+	/**
+	 * Handle input whilst the inventory is active
+	 */
+	void doInvControl();
+	
+	/**
+	 * Handles waiting whilst an object's description window is open.
+	 */
+	void doLookControl();
+	
+	/**
+	 * Handles input until one of the user interface buttons/commands is selected
+	 */
+	void doMainControl();
+	
+	/**
+	 * Handles the input for the MOVE, OPEN, and CLOSE commands
+	 */
+	void doMiscControl(int allowed);
+	
+	/**
+	 * Handles input for picking up items
+	 */
+	void doPickControl();
+	
+	/**
+	 * Handles input when in talk mode. It highlights the buttons and available statements,
+	 * and handles allowing the user to click on them
+	 */
+	void doTalkControl();
+	
+	/**
+	 * Handles events when the Journal is active.
+	 * @remarks		Whilst this would in theory be better in the Journal class, since it displays in
+	 *		the user interface, it uses so many internal UI fields, that it sort of made some sense
+	 *		to put it in the UserInterface class.
+	 */
+	void journalControl();
+
+	/**
+	 * Checks to see whether a USE action is valid on the given object
+	 */
+	void checkUseAction(const UseType *use, const Common::String &invName, const char *const messages[],
+		int objNum, bool giveMode);
+	
+	/**
+	 * Called for OPEN, CLOSE, and MOVE actions are being done
+	 */
+	void checkAction(ActionType &action, const char *const messages[], int objNum);
+
+	/**
+	 * Print the previously selected object's decription
+	 */
+	void printObjectDesc(const Common::String &str, bool firstTime);
+public:
+	ScalpelUserInterface(SherlockEngine *vm);
+	virtual ~ScalpelUserInterface();
+
+	/**
+	 * Handles counting down whilst checking for input, then clears the info line.
+	 */
+	void whileMenuCounter();
+
+	/**
+	 * Draws the image for the given user interface button in the up
+	 * (not selected) position
+	 */
+	void restoreButton(int num);
+public:
+	/**
+	 * Resets the user interface
+	 */
+	virtual void reset();
+
+	/**
+	 * Main input handler for the user interface
+	 */
+	virtual void handleInput();
+
+	/**
+	 * Draw the user interface onto the screen's back buffers
+	 */	
+	virtual void drawInterface(int bufferNum = 3);
+
+	/**
+	 * Displays a passed window by gradually scrolling it vertically on-screen
+	 */
+	virtual void summonWindow(const Surface &bgSurface, bool slideUp = true);
+
+	/**
+	 * Slide the window stored in the back buffer onto the screen
+	 */
+	virtual void summonWindow(bool slideUp = true, int height = CONTROLS_Y);
+
+	/**
+	 * Close a currently open window
+	 * @param flag	0 = slide old window down, 1 = slide prior UI back up
+	 */
+	virtual void banishWindow(bool slideUp = true);
+
+	/**
+	 * Clears the info line of the screen
+	 */
+	virtual void clearInfo();
+
+	/**
+	 * Clear any active text window
+	 */
+	virtual void clearWindow();
+
+	/**
+	 * Print the previously selected object's decription
+	 */	
+	virtual void printObjectDesc();
+};
+
+} // End of namespace Scalpel
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/scalpel/settings.cpp b/engines/sherlock/scalpel/settings.cpp
new file mode 100644
index 0000000..4459786
--- /dev/null
+++ b/engines/sherlock/scalpel/settings.cpp
@@ -0,0 +1,341 @@
+/* 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 "sherlock/sherlock.h"
+#include "sherlock/scalpel/settings.h"
+#include "sherlock/scalpel/scalpel_user_interface.h"
+
+namespace Sherlock {
+
+namespace Scalpel {
+
+static const int SETUP_POINTS[12][4]  = {
+	{ 4, 154, 101, 53 },		// Exit
+	{ 4, 165, 101, 53 },		// Music Toggle
+	{ 219, 165, 316, 268 },		// Voice Toggle
+	{ 103, 165, 217, 160 },		// Sound Effects Toggle
+	{ 219, 154, 316, 268 },		// Help Button Left/Right
+	{ 103, 154, 217, 160 },		// New Font Style
+	{ 4, 187, 101, 53 },		// Joystick Toggle
+	{ 103, 187, 217, 160 },		// Calibrate Joystick
+	{ 219, 176, 316, 268 },		// Fade Style
+	{ 103, 176, 217, 160 },		// Window Open Style
+	{ 4, 176, 101, 53 }, 		// Portraits Toggle
+	{ 219, 187, 316, 268 }		// _key Pad Accel. Toggle
+};
+
+static const char *const SETUP_STRS0[2] = { "off", "on" };
+static const char *const SETUP_STRS1[2] = { "Directly", "by Pixel" };
+static const char *const SETUP_STRS2[2] = { "Left", "Right" };
+static const char *const SETUP_STRS3[2] = { "Appear", "Slide" };
+static const char *const SETUP_STRS5[2] = { "Left", "Right" };
+static const char *const SETUP_NAMES[12] = {
+	"Exit", "M", "V", "S", "B", "New Font Style", "J", "Calibrate Joystick", "F", "W", "P", "K"
+};
+
+/*----------------------------------------------------------------*/
+
+void Settings::drawInteface(bool flag) {
+	People &people = *_vm->_people;
+	Screen &screen = *_vm->_screen;
+	Sound &sound = *_vm->_sound;
+	UserInterface &ui = *_vm->_ui;
+	Common::String tempStr;
+
+	if (!flag) {
+		screen._backBuffer1.fillRect(Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH, CONTROLS_Y1 + 1), BORDER_COLOR);
+		screen._backBuffer1.fillRect(Common::Rect(0, CONTROLS_Y1 + 1, 2, SHERLOCK_SCREEN_HEIGHT), BORDER_COLOR);
+		screen._backBuffer1.fillRect(Common::Rect(SHERLOCK_SCREEN_WIDTH - 2, CONTROLS_Y1 + 1, SHERLOCK_SCREEN_WIDTH,
+			SHERLOCK_SCREEN_HEIGHT), BORDER_COLOR);
+		screen._backBuffer1.hLine(0, SHERLOCK_SCREEN_HEIGHT - 1, SHERLOCK_SCREEN_WIDTH - 1, BORDER_COLOR);
+		screen._backBuffer1.fillRect(Common::Rect(2, CONTROLS_Y1 + 1, SHERLOCK_SCREEN_WIDTH - 2,
+			SHERLOCK_SCREEN_HEIGHT - 2), INV_BACKGROUND);
+	}
+
+	screen.makeButton(Common::Rect(SETUP_POINTS[0][0], SETUP_POINTS[0][1], SETUP_POINTS[0][2], SETUP_POINTS[0][1] + 10),
+		SETUP_POINTS[0][3] - screen.stringWidth("Exit") / 2, "Exit");
+
+	tempStr = Common::String::format("Music %s", SETUP_STRS0[sound._music]);
+	screen.makeButton(Common::Rect(SETUP_POINTS[1][0], SETUP_POINTS[1][1], SETUP_POINTS[1][2], SETUP_POINTS[1][1] + 10),
+		SETUP_POINTS[1][3] - screen.stringWidth(tempStr) / 2, tempStr);
+
+	tempStr = Common::String::format("Voices %s", SETUP_STRS0[sound._voices]);
+	screen.makeButton(Common::Rect(SETUP_POINTS[2][0], SETUP_POINTS[2][1], SETUP_POINTS[2][2], SETUP_POINTS[2][1] + 10),
+		SETUP_POINTS[2][3] - screen.stringWidth(tempStr) / 2, tempStr);
+
+	tempStr = Common::String::format("Sound Effects %s", SETUP_STRS0[sound._digitized]);
+	screen.makeButton(Common::Rect(SETUP_POINTS[3][0], SETUP_POINTS[3][1], SETUP_POINTS[3][2], SETUP_POINTS[3][1] + 10),
+		SETUP_POINTS[3][3] - screen.stringWidth(tempStr) / 2, tempStr);
+
+	tempStr = Common::String::format("Auto Help %s", SETUP_STRS5[ui._helpStyle]);
+	screen.makeButton(Common::Rect(SETUP_POINTS[4][0], SETUP_POINTS[4][1], SETUP_POINTS[4][2], SETUP_POINTS[4][1] + 10),
+		SETUP_POINTS[4][3] - screen.stringWidth(tempStr) / 2, tempStr);
+	screen.makeButton(Common::Rect(SETUP_POINTS[5][0], SETUP_POINTS[5][1], SETUP_POINTS[5][2], SETUP_POINTS[5][1] + 10),
+		SETUP_POINTS[5][3] - screen.stringWidth("New Font Style") / 2, "New Font Style");
+
+	// WORKAROUND: We don't support the joystick in ScummVM, so draw the next two buttons as disabled
+	tempStr = "Joystick Off";
+	screen.makeButton(Common::Rect(SETUP_POINTS[6][0], SETUP_POINTS[6][1], SETUP_POINTS[6][2], SETUP_POINTS[6][1] + 10),
+		SETUP_POINTS[6][3] - screen.stringWidth(tempStr) / 2, tempStr);
+	screen.buttonPrint(Common::Point(SETUP_POINTS[6][3], SETUP_POINTS[6][1]), COMMAND_NULL, false, tempStr);
+
+	tempStr = "Calibrate Joystick";
+	screen.makeButton(Common::Rect(SETUP_POINTS[7][0], SETUP_POINTS[7][1], SETUP_POINTS[7][2], SETUP_POINTS[7][1] + 10),
+		SETUP_POINTS[7][3] - screen.stringWidth(tempStr) / 2, tempStr);
+	screen.buttonPrint(Common::Point(SETUP_POINTS[7][3], SETUP_POINTS[7][1]), COMMAND_NULL, false, tempStr);
+
+	tempStr = Common::String::format("Fade %s", screen._fadeStyle ? "by Pixel" : "Directly");
+	screen.makeButton(Common::Rect(SETUP_POINTS[8][0], SETUP_POINTS[8][1], SETUP_POINTS[8][2], SETUP_POINTS[8][1] + 10),
+		SETUP_POINTS[8][3] - screen.stringWidth(tempStr) / 2, tempStr);
+
+	tempStr = Common::String::format("Windows %s", ui._slideWindows ? "Slide" : "Appear");
+	screen.makeButton(Common::Rect(SETUP_POINTS[9][0], SETUP_POINTS[9][1], SETUP_POINTS[9][2], SETUP_POINTS[9][1] + 10),
+		SETUP_POINTS[9][3] - screen.stringWidth(tempStr) / 2, tempStr);
+
+	tempStr = Common::String::format("Portraits %s", SETUP_STRS0[people._portraitsOn]);
+	screen.makeButton(Common::Rect(SETUP_POINTS[10][0], SETUP_POINTS[10][1], SETUP_POINTS[10][2], SETUP_POINTS[10][1] + 10),
+		SETUP_POINTS[10][3] - screen.stringWidth(tempStr) / 2, tempStr);
+
+	tempStr = "Key Pad Slow";
+	screen.makeButton(Common::Rect(SETUP_POINTS[11][0], SETUP_POINTS[11][1], SETUP_POINTS[11][2], SETUP_POINTS[11][1] + 10),
+		SETUP_POINTS[11][3] - screen.stringWidth(tempStr) / 2, tempStr);
+	screen.buttonPrint(Common::Point(SETUP_POINTS[11][3], SETUP_POINTS[11][1]), COMMAND_NULL, false, tempStr);
+
+	// Show the window immediately, or slide it on-screen
+	if (!flag) {
+		if (!ui._slideWindows) {
+			screen.slamRect(Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
+		} else {
+			ui.summonWindow(true, CONTROLS_Y1);
+		}
+
+		ui._windowOpen = true;
+	} else {
+		screen.slamRect(Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
+	}
+}
+
+int Settings::drawButtons(const Common::Point &pt, int _key) {
+	Events &events = *_vm->_events;
+	People &people = *_vm->_people;
+	Screen &screen = *_vm->_screen;
+	Sound &sound = *_vm->_sound;
+	UserInterface &ui = *_vm->_ui;
+	int found = -1;
+	byte color;
+	Common::String tempStr;
+
+	for (int idx = 0; idx < 12; ++idx) {
+		if ((pt.x > SETUP_POINTS[idx][0] && pt.x < SETUP_POINTS[idx][2] && pt.y > SETUP_POINTS[idx][1]
+				&& pt.y < (SETUP_POINTS[idx][1] + 10) && (events._pressed || events._released))
+				|| (_key == SETUP_NAMES[idx][0])) {
+			found = idx;
+			color = COMMAND_HIGHLIGHTED;
+		} else {
+			color = COMMAND_FOREGROUND;
+		}
+
+		// Print the button text
+		switch (idx) {
+		case 1:
+			tempStr = Common::String::format("Music %s", SETUP_STRS0[sound._music]);
+			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, tempStr);
+			break;
+		case 2:
+			tempStr = Common::String::format("Voices %s", SETUP_STRS0[sound._voices]);
+			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, tempStr);
+			break;
+		case 3:
+			tempStr = Common::String::format("Sound Effects %s", SETUP_STRS0[sound._digitized]);
+			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, tempStr);
+			break;
+		case 4:
+			tempStr = Common::String::format("Auto Help %s", SETUP_STRS2[ui._helpStyle]);
+			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, tempStr);
+			break;
+		case 6:
+			tempStr = "Joystick Off";
+			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), COMMAND_NULL, true, tempStr);
+			break;
+		case 7:
+			tempStr = "Calibrate Joystick";
+			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), COMMAND_NULL, true, tempStr);
+			break;
+		case 8:
+			tempStr = Common::String::format("Fade %s", SETUP_STRS1[screen._fadeStyle]);
+			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, tempStr);
+			break;
+		case 9:
+			tempStr = Common::String::format("Windows %s", SETUP_STRS3[ui._slideWindows]);
+			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, tempStr);
+			break;
+		case 10:
+			tempStr = Common::String::format("Portraits %s", SETUP_STRS0[people._portraitsOn]);
+			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, tempStr);
+			break;
+		case 11:
+			tempStr = "Key Pad Slow";
+			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), COMMAND_NULL, true, tempStr);
+			break;
+		default:
+			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, SETUP_NAMES[idx]);
+			break;
+		}
+	}
+
+	return found;
+}
+
+void Settings::show(SherlockEngine *vm) {
+	Events &events = *vm->_events;
+	People &people = *vm->_people;
+	Scene &scene = *vm->_scene;
+	Screen &screen = *vm->_screen;
+	Sound &sound = *vm->_sound;
+	Talk &talk = *vm->_talk;
+	ScalpelUserInterface &ui = *(ScalpelUserInterface *)vm->_ui;
+	bool updateConfig = false;
+
+	assert(vm->getGameID() == GType_SerratedScalpel);
+	Settings settings(vm);
+	settings.drawInteface(false);
+
+	do {
+		if (ui._menuCounter)
+			ui.whileMenuCounter();
+
+		int found = -1;
+		ui._key = -1;
+
+		scene.doBgAnim();
+		if (talk._talkToAbort)
+			return;
+
+		events.setButtonState();
+		Common::Point pt = events.mousePos();
+
+		if (events._pressed || events._released || events.kbHit()) {
+			ui.clearInfo();
+			ui._key = -1;
+
+			if (events.kbHit()) {
+				Common::KeyState keyState = events.getKey();
+				ui._key = toupper(keyState.keycode);
+
+				if (ui._key == Common::KEYCODE_RETURN || ui._key == Common::KEYCODE_SPACE) {
+					events._pressed = false;
+					events._oldButtons = 0;
+					ui._keyPress = '\0';
+					events._released = true;
+				}
+			}
+
+			// Handle highlighting button under mouse
+			found = settings.drawButtons(pt, ui._key);
+		}
+
+		if ((found == 0 && events._released) || (ui._key == 'E' || ui._key == Common::KEYCODE_ESCAPE))
+			// Exit
+			break;
+
+		if ((found == 1 && events._released) || ui._key == 'M') {
+			// Toggle music
+			if (sound._music) {
+				sound.stopSound();
+				sound._music = false;
+			}
+			else {
+				sound._music = true;
+				sound.startSong();
+			}
+
+			updateConfig = true;
+			settings.drawInteface(true);
+		}
+
+		if ((found == 2 && events._released) || ui._key == 'V') {
+			sound._voices = !sound._voices;
+			updateConfig = true;
+			settings.drawInteface(true);
+		}
+
+		if ((found == 3 && events._released) || ui._key == 'S') {
+			// Toggle sound effects
+			sound._digitized = !sound._digitized;
+			updateConfig = true;
+			settings.drawInteface(true);
+		}
+
+		if ((found == 4 && events._released) || ui._key == 'A') {
+			// Help button style
+			ui._helpStyle = !ui._helpStyle;
+			updateConfig = true;
+			settings.drawInteface(true);
+		}
+
+		if ((found == 5 && events._released) || ui._key == 'N') {
+			// New font style
+			int fontNum = screen.fontNumber() + 1;
+			if (fontNum == 3)
+				fontNum = 0;
+
+			screen.setFont(fontNum);
+			updateConfig = true;
+			settings.drawInteface(true);
+		}
+
+		if ((found == 8 && events._released) || ui._key == 'F') {
+			// Toggle fade style
+			screen._fadeStyle = !screen._fadeStyle;
+			updateConfig = true;
+			settings.drawInteface(true);
+		}
+
+		if ((found == 9 && events._released) || ui._key == 'W') {
+			// Window style
+			ui._slideWindows = !ui._slideWindows;
+			updateConfig = true;
+			settings.drawInteface(true);
+		}
+
+		if ((found == 10 && events._released) || ui._key == 'P') {
+			// Toggle portraits being shown
+			people._portraitsOn = !people._portraitsOn;
+			updateConfig = true;
+			settings.drawInteface(true);
+		}
+	} while (!vm->shouldQuit());
+
+	ui.banishWindow();
+
+	if (updateConfig)
+		vm->saveConfig();
+
+	ui._keyPress = '\0';
+	ui._keyboardInput = false;
+	ui._windowBounds.top = CONTROLS_Y1;
+	ui._key = -1;
+}
+
+} // End of namespace Scalpel
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/scalpel/settings.h b/engines/sherlock/scalpel/settings.h
new file mode 100644
index 0000000..ff2e647
--- /dev/null
+++ b/engines/sherlock/scalpel/settings.h
@@ -0,0 +1,63 @@
+/* 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 SHERLOCK_SETTINGS_H
+#define SHERLOCK_SETTINGS_H
+
+#include "common/scummsys.h"
+
+namespace Sherlock {
+
+class SherlockEngine;
+
+namespace Scalpel {
+
+class Settings {
+private:
+	SherlockEngine *_vm;
+
+	Settings(SherlockEngine *vm) : _vm(vm) {}
+
+	/**
+	 * Draws the interface for the settings window
+	 */
+	void drawInteface(bool flag);
+
+	/**
+	 * Draws the buttons for the settings dialog
+	 */
+	int drawButtons(const Common::Point &pt, int key);
+public:
+	/**
+	 * Handles input when the settings window is being shown
+	 * @remarks		Whilst this would in theory be better in the Journal class, since it displays in
+	 *		the user interface, it uses so many internal UI fields, that it sort of made some sense
+	 *		to put it in the UserInterface class.
+	 */
+	static void show(SherlockEngine *vm);
+};
+
+} // End of namespace Scalpel
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp
index 06bbabf..0f0187e 100644
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@ -23,8 +23,10 @@
 #include "sherlock/scene.h"
 #include "sherlock/sherlock.h"
 #include "sherlock/scalpel/scalpel.h"
+#include "sherlock/scalpel/scalpel_scene.h"
 #include "sherlock/screen.h"
 #include "sherlock/tattoo/tattoo.h"
+#include "sherlock/tattoo/tattoo_scene.h"
 
 namespace Sherlock {
 
@@ -1325,554 +1327,4 @@ void Scene::checkBgShapes() {
 	}
 }
 
-/*----------------------------------------------------------------*/
-
-namespace Scalpel {
-
-void ScalpelScene::checkBgShapes() {
-	People &people = *_vm->_people;
-	Person &holmes = people._player;
-	Common::Point pt(holmes._position.x / FIXED_INT_MULTIPLIER, holmes._position.y / FIXED_INT_MULTIPLIER);
-
-	// Call the base scene method to handle bg shapes
-	Scene::checkBgShapes();
-
-	// Iterate through the canim list
-	for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
-		Object &obj = _canimShapes[idx];
-		if (obj._type == STATIC_BG_SHAPE || obj._type == ACTIVE_BG_SHAPE) {
-			if ((obj._flags & 5) == 1) {
-				obj._misc = (pt.y < (obj._position.y + obj._imageFrame->_frame.h - 1)) ?
-				NORMAL_FORWARD : NORMAL_BEHIND;
-			} else if (!(obj._flags & 1)) {
-				obj._misc = BEHIND;
-			} else if (obj._flags & 4) {
-				obj._misc = FORWARD;
-			}
-		}
-	}
-}
-
-void ScalpelScene::doBgAnimCheckCursor() {
-	Inventory &inv = *_vm->_inventory;
-	Events &events = *_vm->_events;
-	Sound &sound = *_vm->_sound;
-	UserInterface &ui = *_vm->_ui;
-	Common::Point mousePos = events.mousePos();
-
-	if (ui._menuMode == LOOK_MODE) {
-		if (mousePos.y > CONTROLS_Y1)
-			events.setCursor(ARROW);
-		else if (mousePos.y < CONTROLS_Y)
-			events.setCursor(MAGNIFY);
-	}
-
-	// Check for setting magnifying glass cursor
-	if (ui._menuMode == INV_MODE || ui._menuMode == USE_MODE || ui._menuMode == GIVE_MODE) {
-		if (inv._invMode == INVMODE_LOOK) {
-			// Only show Magnifying glass cursor if it's not on the inventory command line
-			if (mousePos.y < CONTROLS_Y || mousePos.y >(CONTROLS_Y1 + 13))
-				events.setCursor(MAGNIFY);
-			else
-				events.setCursor(ARROW);
-		} else {
-			events.setCursor(ARROW);
-		}
-	}
-
-	if (sound._diskSoundPlaying && !*sound._soundIsOn) {
-		// Loaded sound just finished playing
-		sound.freeDigiSound();
-	}
-}
-
-void ScalpelScene::doBgAnim() {
-	Scalpel::ScalpelEngine &vm = *((Scalpel::ScalpelEngine *)_vm);
-	Events &events = *_vm->_events;
-	People &people = *_vm->_people;
-	Screen &screen = *_vm->_screen;
-	Talk &talk = *_vm->_talk;
-
-	screen.setDisplayBounds(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCENE_HEIGHT));
-	talk._talkToAbort = false;
-
-	if (_restoreFlag) {
-		for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
-			if (people[idx]._type == CHARACTER)
-				people[idx].checkSprite();
-		}
-
-		for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
-			if (_bgShapes[idx]._type == ACTIVE_BG_SHAPE)
-				_bgShapes[idx].checkObject();
-		}
-
-		if (people._portraitLoaded && people._portrait._type == ACTIVE_BG_SHAPE)
-			people._portrait.checkObject();
-
-		for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
-			if (_canimShapes[idx]._type != INVALID && _canimShapes[idx]._type != REMOVE)
-				_canimShapes[idx].checkObject();
-		}
-
-		if (_currentScene == 12)
-			vm.eraseMirror12();
-
-		// Restore the back buffer from the back buffer 2 in the changed area
-		Common::Rect bounds(people[AL]._oldPosition.x, people[AL]._oldPosition.y,
-			people[AL]._oldPosition.x + people[AL]._oldSize.x,
-			people[AL]._oldPosition.y + people[AL]._oldSize.y);
-		Common::Point pt(bounds.left, bounds.top);
-
-		if (people[AL]._type == CHARACTER)
-			screen.restoreBackground(bounds);
-		else if (people[AL]._type == REMOVE)
-			screen._backBuffer->blitFrom(screen._backBuffer2, pt, bounds);
-
-		for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
-			Object &o = _bgShapes[idx];
-			if (o._type == ACTIVE_BG_SHAPE || o._type == HIDE_SHAPE || o._type == REMOVE)
-				screen.restoreBackground(o.getOldBounds());
-		}
-
-		if (people._portraitLoaded)
-			screen.restoreBackground(Common::Rect(
-				people._portrait._oldPosition.x, people._portrait._oldPosition.y,
-				people._portrait._oldPosition.x + people._portrait._oldSize.x,
-				people._portrait._oldPosition.y + people._portrait._oldSize.y
-			));
-
-		for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
-			Object &o = _bgShapes[idx];
-			if (o._type == NO_SHAPE && ((o._flags & OBJ_BEHIND) == 0)) {
-				// Restore screen area
-				screen._backBuffer->blitFrom(screen._backBuffer2, o._position,
-					Common::Rect(o._position.x, o._position.y,
-					o._position.x + o._noShapeSize.x, o._position.y + o._noShapeSize.y));
-
-				o._oldPosition = o._position;
-				o._oldSize = o._noShapeSize;
-			}
-		}
-
-		for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
-			Object &o = _canimShapes[idx];
-			if (o._type == ACTIVE_BG_SHAPE || o._type == HIDE_SHAPE || o._type == REMOVE)
-				screen.restoreBackground(Common::Rect(o._oldPosition.x, o._oldPosition.y,
-					o._oldPosition.x + o._oldSize.x, o._oldPosition.y + o._oldSize.y));
-		}
-	}
-
-	//
-	// Update the background objects and canimations
-	//
-
-	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
-		Object &o = _bgShapes[idx];
-		if (o._type == ACTIVE_BG_SHAPE || o._type == NO_SHAPE)
-			o.adjustObject();
-	}
-
-	if (people._portraitLoaded && people._portrait._type == ACTIVE_BG_SHAPE)
-		people._portrait.adjustObject();
-
-	for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
-		if (_canimShapes[idx]._type != INVALID)
-			_canimShapes[idx].adjustObject();
-	}
-
-	if (people[AL]._type == CHARACTER && people._holmesOn)
-		people[AL].adjustSprite();
-
-	// Flag the bg shapes which need to be redrawn
-	checkBgShapes();
-
-	if (_currentScene == 12)
-		vm.doMirror12();
-
-	// Draw all active shapes which are behind the person
-	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
-		Object &o = _bgShapes[idx];
-		if (o._type == ACTIVE_BG_SHAPE && o._misc == BEHIND)
-			screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
-	}
-
-	// Draw all canimations which are behind the person
-	for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
-		Object &o = _canimShapes[idx];
-		if (o._type == ACTIVE_BG_SHAPE && o._misc == BEHIND) {
-			screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
-		}
-	}
-
-	// Draw all active shapes which are HAPPEN and behind the person
-	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
-		Object &o = _bgShapes[idx];
-		if (o._type == ACTIVE_BG_SHAPE && o._misc == NORMAL_BEHIND)
-			screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
-	}
-
-	// Draw all canimations which are NORMAL and behind the person
-	for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
-		Object &o = _canimShapes[idx];
-		if (o._type == ACTIVE_BG_SHAPE && o._misc == NORMAL_BEHIND) {
-			screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
-		}
-	}
-
-	// Draw the person if not animating
-	if (people[AL]._type == CHARACTER && people[AL]._walkLoaded) {
-		// If Holmes is too far to the right, move him back so he's on-screen
-		int xRight = SHERLOCK_SCREEN_WIDTH - 2 - people[AL]._imageFrame->_frame.w;
-		int tempX = MIN(people[AL]._position.x / FIXED_INT_MULTIPLIER, xRight);
-
-		bool flipped = people[AL]._sequenceNumber == WALK_LEFT || people[AL]._sequenceNumber == STOP_LEFT ||
-			people[AL]._sequenceNumber == WALK_UPLEFT || people[AL]._sequenceNumber == STOP_UPLEFT ||
-			people[AL]._sequenceNumber == WALK_DOWNRIGHT || people[AL]._sequenceNumber == STOP_DOWNRIGHT;
-		screen._backBuffer->transBlitFrom(*people[AL]._imageFrame,
-			Common::Point(tempX, people[AL]._position.y / FIXED_INT_MULTIPLIER - people[AL]._imageFrame->_frame.h), flipped);
-	}
-
-	// Draw all static and active shapes are NORMAL and are in front of the person
-	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
-		Object &o = _bgShapes[idx];
-		if ((o._type == ACTIVE_BG_SHAPE || o._type == STATIC_BG_SHAPE) && o._misc == NORMAL_FORWARD)
-			screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
-	}
-
-	// Draw all static and active canimations that are NORMAL and are in front of the person
-	for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
-		Object &o = _canimShapes[idx];
-		if ((o._type == ACTIVE_BG_SHAPE || o._type == STATIC_BG_SHAPE) && o._misc == NORMAL_FORWARD) {
-			screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
-		}
-	}
-
-	// Draw all static and active shapes that are in front of the person
-	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
-		Object &o = _bgShapes[idx];
-		if ((o._type == ACTIVE_BG_SHAPE || o._type == STATIC_BG_SHAPE) && o._misc == FORWARD)
-			screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
-	}
-
-	// Draw any active portrait
-	if (people._portraitLoaded && people._portrait._type == ACTIVE_BG_SHAPE)
-		screen._backBuffer->transBlitFrom(*people._portrait._imageFrame,
-			people._portrait._position, people._portrait._flags & OBJ_FLIPPED);
-
-	// Draw all static and active canimations that are in front of the person
-	for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
-		Object &o = _canimShapes[idx];
-		if ((o._type == ACTIVE_BG_SHAPE || o._type == STATIC_BG_SHAPE) && o._misc == FORWARD) {
-			screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
-		}
-	}
-
-	// Draw all NO_SHAPE shapes which have flag bit 0 clear
-	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
-		Object &o = _bgShapes[idx];
-		if (o._type == NO_SHAPE && (o._flags & OBJ_BEHIND) == 0)
-			screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
-	}
-
-	// Bring the newly built picture to the screen
-	if (_animating == 2) {
-		_animating = 0;
-		screen.slamRect(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCENE_HEIGHT));
-	} else {
-		if (people[AL]._type != INVALID && ((_goToScene == -1 || _canimShapes.empty()))) {
-			if (people[AL]._type == REMOVE) {
-				screen.slamRect(Common::Rect(
-					people[AL]._oldPosition.x, people[AL]._oldPosition.y,
-					people[AL]._oldPosition.x + people[AL]._oldSize.x,
-					people[AL]._oldPosition.y + people[AL]._oldSize.y
-				));
-				people[AL]._type = INVALID;
-			} else {
-				screen.flushImage(people[AL]._imageFrame,
-					Common::Point(people[AL]._position.x / FIXED_INT_MULTIPLIER,
-						people[AL]._position.y / FIXED_INT_MULTIPLIER - people[AL].frameHeight()),
-					&people[AL]._oldPosition.x, &people[AL]._oldPosition.y,
-					&people[AL]._oldSize.x, &people[AL]._oldSize.y);
-			}
-		}
-
-		if (_currentScene == 12)
-			vm.flushMirror12();
-
-		for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
-			Object &o = _bgShapes[idx];
-			if ((o._type == ACTIVE_BG_SHAPE || o._type == REMOVE) && _goToScene == -1) {
-				screen.flushImage(o._imageFrame, o._position,
-					&o._oldPosition.x, &o._oldPosition.y, &o._oldSize.x, &o._oldSize.y);
-			}
-		}
-
-		if (people._portraitLoaded) {
-			if (people._portrait._type == REMOVE)
-				screen.slamRect(Common::Rect(
-					people._portrait._position.x, people._portrait._position.y,
-					people._portrait._position.x + people._portrait._delta.x,
-					people._portrait._position.y + people._portrait._delta.y
-				));
-			else
-				screen.flushImage(people._portrait._imageFrame, people._portrait._position,
-					&people._portrait._oldPosition.x, &people._portrait._oldPosition.y,
-					&people._portrait._oldSize.x, &people._portrait._oldSize.y);
-
-			if (people._portrait._type == REMOVE)
-				people._portrait._type = INVALID;
-		}
-
-		if (_goToScene == -1) {
-			for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
-				Object &o = _bgShapes[idx];
-				if (o._type == NO_SHAPE && (o._flags & OBJ_BEHIND) == 0) {
-					screen.slamArea(o._position.x, o._position.y, o._oldSize.x, o._oldSize.y);
-					screen.slamArea(o._oldPosition.x, o._oldPosition.y, o._oldSize.x, o._oldSize.y);
-				} else if (o._type == HIDE_SHAPE) {
-					// Hiding shape, so flush it out and mark it as hidden
-					screen.flushImage(o._imageFrame, o._position,
-						&o._oldPosition.x, &o._oldPosition.y, &o._oldSize.x, &o._oldSize.y);
-					o._type = HIDDEN;
-				}
-			}
-		}
-
-		for (int idx = _canimShapes.size() - 1; idx >= 0; --idx) {
-			Object &o = _canimShapes[idx];
-
-			if (o._type == INVALID) {
-				// Anim shape was invalidated by checkEndOfSequence, so at this point we can remove it
-				_canimShapes.remove_at(idx);
-			} else  if (o._type == REMOVE) {
-				if (_goToScene == -1)
-					screen.slamArea(o._position.x, o._position.y, o._delta.x, o._delta.y);
-
-				// Shape for an animation is no longer needed, so remove it completely
-				_canimShapes.remove_at(idx);
-			} else if (o._type == ACTIVE_BG_SHAPE) {
-				screen.flushImage(o._imageFrame, o._position,
-					&o._oldPosition.x, &o._oldPosition.y, &o._oldSize.x, &o._oldSize.y);
-			}
-		}
-	}
-
-	_restoreFlag = true;
-	_doBgAnimDone = true;
-
-	events.wait(3);
-	screen.resetDisplayBounds();
-
-	// Check if the method was called for calling a portrait, and a talk was
-	// interrupting it. This talk file would not have been executed at the time,
-	// since we needed to finish the 'doBgAnim' to finish clearing the portrait
-	if (people._clearingThePortrait && talk._scriptMoreFlag == 3) {
-		// Reset the flags and call to talk
-		people._clearingThePortrait = false;
-		talk._scriptMoreFlag = 0;
-		talk.talkTo(talk._scriptName);
-	}
-}
-
-} // End of namespace Scalpel
-
-/*----------------------------------------------------------------*/
-
-namespace Tattoo {
-
-TattooScene::TattooScene(SherlockEngine *vm) : Scene(vm) {
-	_arrowZone = -1;
-	_mask = _mask1 = nullptr;
-	_maskCounter = 0;
-}
-
-void TattooScene::checkBgShapes() {
-	People &people = *_vm->_people;
-	Person &holmes = people._player;
-	Common::Point pt(holmes._position.x / FIXED_INT_MULTIPLIER, holmes._position.y / FIXED_INT_MULTIPLIER);
-
-	// Call the base scene method to handle bg shapes
-	Scene::checkBgShapes();
-
-	// Check for any active playing animation
-	if (_activeCAnim._images && _activeCAnim._zPlacement != REMOVE) {
-		switch (_activeCAnim._flags & 3) {
-		case 0:
-			_activeCAnim._zPlacement = BEHIND;
-			break;
-		case 1:
-			_activeCAnim._zPlacement = ((_activeCAnim._position.y + _activeCAnim._imageFrame->_frame.h - 1)) ?
-				NORMAL_FORWARD : NORMAL_BEHIND;
-			break;
-		case 2:
-			_activeCAnim._zPlacement = FORWARD;
-			break;
-		default:
-			break;
-		}
-	}
-}
-
-void TattooScene::doBgAnimCheckCursor() {
-	Events &events = *_vm->_events;
-	UserInterface &ui = *_vm->_ui;
-	Common::Point mousePos = events.mousePos();
-
-	// If we're in Look Mode, make sure the cursor is the magnifying glass
-	if (ui._menuMode == LOOK_MODE && events.getCursor() != MAGNIFY)
-		events.setCursor(MAGNIFY);
-
-	// See if the mouse is over any of the arrow zones, and if so, change the cursor to the correct
-	// arrow cursor indicating the direcetion of the exit
-	if (events.getCursor() == ARROW || events.getCursor() >= EXIT_ZONES_START) {
-		CursorId cursorId = ARROW;
-
-		if (ui._menuMode == STD_MODE && _arrowZone != -1 && _currentScene != 90) {
-			for (uint idx = 0; idx < _exits.size(); ++idx) {
-				Exit &exit = _exits[idx];
-				if (exit.contains(mousePos))
-					cursorId = (CursorId)(exit._image + EXIT_ZONES_START);
-			}
-		}
-
-		events.setCursor(cursorId);
-	}
-}
-
-void TattooScene::doBgAnimEraseBackground() {
-	TattooEngine &vm = *((TattooEngine *)_vm);
-	People &people = *_vm->_people;
-	Screen &screen = *_vm->_screen;
-	TattooUserInterface &ui = *((TattooUserInterface *)_vm->_ui);
-	
-	static const int16 OFFSETS[16] = { -1, -2, -3, -3, -2, -1, -1, 0, 1, 2, 3, 3, 2, 1, 0, 0 };
-
-	if (_mask != nullptr) {
-		if (screen._backBuffer1.w() > screen.w())
-			screen.blitFrom(screen._backBuffer1, Common::Point(0, 0), Common::Rect(screen._currentScroll, 0,
-			screen._currentScroll + screen.w(), screen.h()));
-		else
-			screen.blitFrom(screen._backBuffer1);
-
-		switch (_currentScene) {
-		case 7:
-			if (++_maskCounter == 2) {
-				_maskCounter = 0;
-				if (--_maskOffset.x < 0)
-					_maskOffset.x = SHERLOCK_SCREEN_WIDTH - 1;
-			}
-			break;
-
-		case 8:
-			_maskOffset.x += 2;
-			if (_maskOffset.x >= SHERLOCK_SCREEN_WIDTH)
-				_maskOffset.x = 0;
-			break;
-
-		case 18:
-		case 68:
-			++_maskCounter;
-			if (_maskCounter / 4 >= 16)
-				_maskCounter = 0;
-
-			_maskOffset.x = OFFSETS[_maskCounter / 4];
-			break;
-
-		case 53:
-			if (++_maskCounter == 2) {
-				_maskCounter = 0;
-				if (++_maskOffset.x == screen._backBuffer1.w())
-					_maskOffset.x = 0;
-			}
-			break;
-
-		default:
-			break;
-		}
-	} else {
-		// Standard scene without mask, so call user interface to erase any UI elements as necessary
-		ui.doBgAnimRestoreUI();
-		
-		// Restore background for any areas covered by characters and shapes
-		for (uint idx = 0; idx < MAX_CHARACTERS; ++idx)
-			screen.restoreBackground(Common::Rect(people[idx]._oldPosition.x, people[idx]._oldPosition.y,
-				people[idx]._oldPosition.x + people[idx]._oldSize.x, people[idx]._oldPosition.y + people[idx]._oldSize.y));
-
-		for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
-			Object &obj = _bgShapes[idx];
-						
-			if ((obj._type == ACTIVE_BG_SHAPE && (obj._maxFrames > 1 || obj._delta.x != 0 || obj._delta.y != 0)) || 
-					obj._type == HIDE_SHAPE || obj._type == REMOVE)
-				screen._backBuffer1.blitFrom(*obj._imageFrame, obj._oldPosition, 
-					Common::Rect(obj._oldPosition.x, obj._oldPosition.y, obj._oldPosition.x + obj._oldSize.x,
-						obj._oldPosition.y + obj._oldSize.y));
-		}
-
-		// If credits are active, erase the area they cover
-		if (vm._creditsActive)
-			vm.eraseCredits();
-	}
-
-	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
-		Object &obj = _bgShapes[idx];
-
-		if (obj._type == NO_SHAPE && (obj._flags & 1) == 0) {
-			screen._backBuffer1.blitFrom(screen._backBuffer2, obj._position, obj.getNoShapeBounds());
-
-			obj._oldPosition = obj._position;
-			obj._oldSize = obj._noShapeSize;
-		}
-	}
-
-	// Adjust the Target Scroll if needed
-	if ((people[people._walkControl]._position.x / FIXED_INT_MULTIPLIER - screen._currentScroll) < 
-			(SHERLOCK_SCREEN_WIDTH / 8) && people[people._walkControl]._delta.x < 0) {
-		
-		screen._targetScroll = (short)(people[people._walkControl]._position.x / FIXED_INT_MULTIPLIER - 
-				SHERLOCK_SCREEN_WIDTH / 8 - 250);
-		if (screen._targetScroll < 0)
-			screen._targetScroll = 0;
-	}
-
-	if ((people[people._walkControl]._position.x / FIXED_INT_MULTIPLIER - screen._currentScroll) > (SHERLOCK_SCREEN_WIDTH / 4 * 3) 
-			&& people[people._walkControl]._delta.x > 0)
-		screen._targetScroll = (short)(people[people._walkControl]._position.x / FIXED_INT_MULTIPLIER - 
-			SHERLOCK_SCREEN_WIDTH / 4 * 3 + 250);
-
-	if (screen._targetScroll > screen._scrollSize)
-		screen._targetScroll = screen._scrollSize;
-
-	ui.doScroll();
-}
-
-void TattooScene::doBgAnim() {
-	doBgAnimCheckCursor();
-
-//	Events &events = *_vm->_events;
-	People &people = *_vm->_people;
-//	Scene &scene = *_vm->_scene;
-	Screen &screen = *_vm->_screen;
-	Talk &talk = *_vm->_talk;
-
-	screen.setDisplayBounds(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCENE_HEIGHT));
-	talk._talkToAbort = false;
-
-	// Check the characters and sprites for updates
-	for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
-		if (people[idx]._type == CHARACTER)
-			people[idx].checkSprite();
-	}
-
-	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
-		if (_bgShapes[idx]._type == ACTIVE_BG_SHAPE)
-			_bgShapes[idx].checkObject();
-	}
-
-	// Erase any affected background areas
-	doBgAnimEraseBackground();
-}
-
-} // End of namespace Tattoo
-
 } // End of namespace Sherlock
diff --git a/engines/sherlock/scene.h b/engines/sherlock/scene.h
index ce07850..b5e27ff 100644
--- a/engines/sherlock/scene.h
+++ b/engines/sherlock/scene.h
@@ -318,61 +318,6 @@ public:
 	void setNPCPath(int npc);
 };
 
-namespace Scalpel {
-
-class ScalpelScene : public Scene {
-private:
-	void doBgAnimCheckCursor();
-protected:
-	/**
-	 * Checks all the background shapes. If a background shape is animating,
-	 * it will flag it as needing to be drawn. If a non-animating shape is
-	 * colliding with another shape, it will also flag it as needing drawing
-	 */
-	virtual void checkBgShapes();
-public:
-	ScalpelScene(SherlockEngine *vm) : Scene(vm) {}
-
-	/**
-	 * Draw all objects and characters.
-	 */
-	virtual void doBgAnim();
-};
-
-} // End of namespace Scalpel
-
-namespace Tattoo {
-
-class TattooScene : public Scene {
-private:
-	int _arrowZone;
-	int _maskCounter;
-	Common::Point _maskOffset;
-private:
-	void doBgAnimCheckCursor();
-
-	void doBgAnimEraseBackground();
-protected:
-	/**
-	 * Checks all the background shapes. If a background shape is animating,
-	 * it will flag it as needing to be drawn. If a non-animating shape is
-	 * colliding with another shape, it will also flag it as needing drawing
-	 */
-	virtual void checkBgShapes();
-public:
-	ImageFile *_mask, *_mask1;
-	CAnimStream _activeCAnim;
-public:
-	TattooScene(SherlockEngine *vm);
-
-	/**
-	 * Draw all objects and characters.
-	 */
-	virtual void doBgAnim();
-};
-
-} // End of namespace Tattoo
-
 } // End of namespace Sherlock
 
 #endif
diff --git a/engines/sherlock/settings.cpp b/engines/sherlock/settings.cpp
deleted file mode 100644
index 98a13a3..0000000
--- a/engines/sherlock/settings.cpp
+++ /dev/null
@@ -1,340 +0,0 @@
-/* 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 "sherlock/sherlock.h"
-#include "sherlock/settings.h"
-
-namespace Sherlock {
-
-namespace Scalpel {
-
-static const int SETUP_POINTS[12][4]  = {
-	{ 4, 154, 101, 53 },		// Exit
-	{ 4, 165, 101, 53 },		// Music Toggle
-	{ 219, 165, 316, 268 },		// Voice Toggle
-	{ 103, 165, 217, 160 },		// Sound Effects Toggle
-	{ 219, 154, 316, 268 },		// Help Button Left/Right
-	{ 103, 154, 217, 160 },		// New Font Style
-	{ 4, 187, 101, 53 },		// Joystick Toggle
-	{ 103, 187, 217, 160 },		// Calibrate Joystick
-	{ 219, 176, 316, 268 },		// Fade Style
-	{ 103, 176, 217, 160 },		// Window Open Style
-	{ 4, 176, 101, 53 }, 		// Portraits Toggle
-	{ 219, 187, 316, 268 }		// _key Pad Accel. Toggle
-};
-
-static const char *const SETUP_STRS0[2] = { "off", "on" };
-static const char *const SETUP_STRS1[2] = { "Directly", "by Pixel" };
-static const char *const SETUP_STRS2[2] = { "Left", "Right" };
-static const char *const SETUP_STRS3[2] = { "Appear", "Slide" };
-static const char *const SETUP_STRS5[2] = { "Left", "Right" };
-static const char *const SETUP_NAMES[12] = {
-	"Exit", "M", "V", "S", "B", "New Font Style", "J", "Calibrate Joystick", "F", "W", "P", "K"
-};
-
-/*----------------------------------------------------------------*/
-
-void Settings::drawInteface(bool flag) {
-	People &people = *_vm->_people;
-	Screen &screen = *_vm->_screen;
-	Sound &sound = *_vm->_sound;
-	UserInterface &ui = *_vm->_ui;
-	Common::String tempStr;
-
-	if (!flag) {
-		screen._backBuffer1.fillRect(Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH, CONTROLS_Y1 + 1), BORDER_COLOR);
-		screen._backBuffer1.fillRect(Common::Rect(0, CONTROLS_Y1 + 1, 2, SHERLOCK_SCREEN_HEIGHT), BORDER_COLOR);
-		screen._backBuffer1.fillRect(Common::Rect(SHERLOCK_SCREEN_WIDTH - 2, CONTROLS_Y1 + 1, SHERLOCK_SCREEN_WIDTH,
-			SHERLOCK_SCREEN_HEIGHT), BORDER_COLOR);
-		screen._backBuffer1.hLine(0, SHERLOCK_SCREEN_HEIGHT - 1, SHERLOCK_SCREEN_WIDTH - 1, BORDER_COLOR);
-		screen._backBuffer1.fillRect(Common::Rect(2, CONTROLS_Y1 + 1, SHERLOCK_SCREEN_WIDTH - 2,
-			SHERLOCK_SCREEN_HEIGHT - 2), INV_BACKGROUND);
-	}
-
-	screen.makeButton(Common::Rect(SETUP_POINTS[0][0], SETUP_POINTS[0][1], SETUP_POINTS[0][2], SETUP_POINTS[0][1] + 10),
-		SETUP_POINTS[0][3] - screen.stringWidth("Exit") / 2, "Exit");
-
-	tempStr = Common::String::format("Music %s", SETUP_STRS0[sound._music]);
-	screen.makeButton(Common::Rect(SETUP_POINTS[1][0], SETUP_POINTS[1][1], SETUP_POINTS[1][2], SETUP_POINTS[1][1] + 10),
-		SETUP_POINTS[1][3] - screen.stringWidth(tempStr) / 2, tempStr);
-
-	tempStr = Common::String::format("Voices %s", SETUP_STRS0[sound._voices]);
-	screen.makeButton(Common::Rect(SETUP_POINTS[2][0], SETUP_POINTS[2][1], SETUP_POINTS[2][2], SETUP_POINTS[2][1] + 10),
-		SETUP_POINTS[2][3] - screen.stringWidth(tempStr) / 2, tempStr);
-
-	tempStr = Common::String::format("Sound Effects %s", SETUP_STRS0[sound._digitized]);
-	screen.makeButton(Common::Rect(SETUP_POINTS[3][0], SETUP_POINTS[3][1], SETUP_POINTS[3][2], SETUP_POINTS[3][1] + 10),
-		SETUP_POINTS[3][3] - screen.stringWidth(tempStr) / 2, tempStr);
-
-	tempStr = Common::String::format("Auto Help %s", SETUP_STRS5[ui._helpStyle]);
-	screen.makeButton(Common::Rect(SETUP_POINTS[4][0], SETUP_POINTS[4][1], SETUP_POINTS[4][2], SETUP_POINTS[4][1] + 10),
-		SETUP_POINTS[4][3] - screen.stringWidth(tempStr) / 2, tempStr);
-	screen.makeButton(Common::Rect(SETUP_POINTS[5][0], SETUP_POINTS[5][1], SETUP_POINTS[5][2], SETUP_POINTS[5][1] + 10),
-		SETUP_POINTS[5][3] - screen.stringWidth("New Font Style") / 2, "New Font Style");
-
-	// WORKAROUND: We don't support the joystick in ScummVM, so draw the next two buttons as disabled
-	tempStr = "Joystick Off";
-	screen.makeButton(Common::Rect(SETUP_POINTS[6][0], SETUP_POINTS[6][1], SETUP_POINTS[6][2], SETUP_POINTS[6][1] + 10),
-		SETUP_POINTS[6][3] - screen.stringWidth(tempStr) / 2, tempStr);
-	screen.buttonPrint(Common::Point(SETUP_POINTS[6][3], SETUP_POINTS[6][1]), COMMAND_NULL, false, tempStr);
-
-	tempStr = "Calibrate Joystick";
-	screen.makeButton(Common::Rect(SETUP_POINTS[7][0], SETUP_POINTS[7][1], SETUP_POINTS[7][2], SETUP_POINTS[7][1] + 10),
-		SETUP_POINTS[7][3] - screen.stringWidth(tempStr) / 2, tempStr);
-	screen.buttonPrint(Common::Point(SETUP_POINTS[7][3], SETUP_POINTS[7][1]), COMMAND_NULL, false, tempStr);
-
-	tempStr = Common::String::format("Fade %s", screen._fadeStyle ? "by Pixel" : "Directly");
-	screen.makeButton(Common::Rect(SETUP_POINTS[8][0], SETUP_POINTS[8][1], SETUP_POINTS[8][2], SETUP_POINTS[8][1] + 10),
-		SETUP_POINTS[8][3] - screen.stringWidth(tempStr) / 2, tempStr);
-
-	tempStr = Common::String::format("Windows %s", ui._slideWindows ? "Slide" : "Appear");
-	screen.makeButton(Common::Rect(SETUP_POINTS[9][0], SETUP_POINTS[9][1], SETUP_POINTS[9][2], SETUP_POINTS[9][1] + 10),
-		SETUP_POINTS[9][3] - screen.stringWidth(tempStr) / 2, tempStr);
-
-	tempStr = Common::String::format("Portraits %s", SETUP_STRS0[people._portraitsOn]);
-	screen.makeButton(Common::Rect(SETUP_POINTS[10][0], SETUP_POINTS[10][1], SETUP_POINTS[10][2], SETUP_POINTS[10][1] + 10),
-		SETUP_POINTS[10][3] - screen.stringWidth(tempStr) / 2, tempStr);
-
-	tempStr = "Key Pad Slow";
-	screen.makeButton(Common::Rect(SETUP_POINTS[11][0], SETUP_POINTS[11][1], SETUP_POINTS[11][2], SETUP_POINTS[11][1] + 10),
-		SETUP_POINTS[11][3] - screen.stringWidth(tempStr) / 2, tempStr);
-	screen.buttonPrint(Common::Point(SETUP_POINTS[11][3], SETUP_POINTS[11][1]), COMMAND_NULL, false, tempStr);
-
-	// Show the window immediately, or slide it on-screen
-	if (!flag) {
-		if (!ui._slideWindows) {
-			screen.slamRect(Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
-		} else {
-			ui.summonWindow(true, CONTROLS_Y1);
-		}
-
-		ui._windowOpen = true;
-	} else {
-		screen.slamRect(Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
-	}
-}
-
-int Settings::drawButtons(const Common::Point &pt, int _key) {
-	Events &events = *_vm->_events;
-	People &people = *_vm->_people;
-	Screen &screen = *_vm->_screen;
-	Sound &sound = *_vm->_sound;
-	UserInterface &ui = *_vm->_ui;
-	int found = -1;
-	byte color;
-	Common::String tempStr;
-
-	for (int idx = 0; idx < 12; ++idx) {
-		if ((pt.x > SETUP_POINTS[idx][0] && pt.x < SETUP_POINTS[idx][2] && pt.y > SETUP_POINTS[idx][1]
-				&& pt.y < (SETUP_POINTS[idx][1] + 10) && (events._pressed || events._released))
-				|| (_key == SETUP_NAMES[idx][0])) {
-			found = idx;
-			color = COMMAND_HIGHLIGHTED;
-		} else {
-			color = COMMAND_FOREGROUND;
-		}
-
-		// Print the button text
-		switch (idx) {
-		case 1:
-			tempStr = Common::String::format("Music %s", SETUP_STRS0[sound._music]);
-			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, tempStr);
-			break;
-		case 2:
-			tempStr = Common::String::format("Voices %s", SETUP_STRS0[sound._voices]);
-			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, tempStr);
-			break;
-		case 3:
-			tempStr = Common::String::format("Sound Effects %s", SETUP_STRS0[sound._digitized]);
-			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, tempStr);
-			break;
-		case 4:
-			tempStr = Common::String::format("Auto Help %s", SETUP_STRS2[ui._helpStyle]);
-			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, tempStr);
-			break;
-		case 6:
-			tempStr = "Joystick Off";
-			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), COMMAND_NULL, true, tempStr);
-			break;
-		case 7:
-			tempStr = "Calibrate Joystick";
-			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), COMMAND_NULL, true, tempStr);
-			break;
-		case 8:
-			tempStr = Common::String::format("Fade %s", SETUP_STRS1[screen._fadeStyle]);
-			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, tempStr);
-			break;
-		case 9:
-			tempStr = Common::String::format("Windows %s", SETUP_STRS3[ui._slideWindows]);
-			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, tempStr);
-			break;
-		case 10:
-			tempStr = Common::String::format("Portraits %s", SETUP_STRS0[people._portraitsOn]);
-			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, tempStr);
-			break;
-		case 11:
-			tempStr = "Key Pad Slow";
-			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), COMMAND_NULL, true, tempStr);
-			break;
-		default:
-			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, SETUP_NAMES[idx]);
-			break;
-		}
-	}
-
-	return found;
-}
-
-void Settings::show(SherlockEngine *vm) {
-	Events &events = *vm->_events;
-	People &people = *vm->_people;
-	Scene &scene = *vm->_scene;
-	Screen &screen = *vm->_screen;
-	Sound &sound = *vm->_sound;
-	Talk &talk = *vm->_talk;
-	ScalpelUserInterface &ui = *(ScalpelUserInterface *)vm->_ui;
-	bool updateConfig = false;
-
-	assert(vm->getGameID() == GType_SerratedScalpel);
-	Settings settings(vm);
-	settings.drawInteface(false);
-
-	do {
-		if (ui._menuCounter)
-			ui.whileMenuCounter();
-
-		int found = -1;
-		ui._key = -1;
-
-		scene.doBgAnim();
-		if (talk._talkToAbort)
-			return;
-
-		events.setButtonState();
-		Common::Point pt = events.mousePos();
-
-		if (events._pressed || events._released || events.kbHit()) {
-			ui.clearInfo();
-			ui._key = -1;
-
-			if (events.kbHit()) {
-				Common::KeyState keyState = events.getKey();
-				ui._key = toupper(keyState.keycode);
-
-				if (ui._key == Common::KEYCODE_RETURN || ui._key == Common::KEYCODE_SPACE) {
-					events._pressed = false;
-					events._oldButtons = 0;
-					ui._keyPress = '\0';
-					events._released = true;
-				}
-			}
-
-			// Handle highlighting button under mouse
-			found = settings.drawButtons(pt, ui._key);
-		}
-
-		if ((found == 0 && events._released) || (ui._key == 'E' || ui._key == Common::KEYCODE_ESCAPE))
-			// Exit
-			break;
-
-		if ((found == 1 && events._released) || ui._key == 'M') {
-			// Toggle music
-			if (sound._music) {
-				sound.stopSound();
-				sound._music = false;
-			}
-			else {
-				sound._music = true;
-				sound.startSong();
-			}
-
-			updateConfig = true;
-			settings.drawInteface(true);
-		}
-
-		if ((found == 2 && events._released) || ui._key == 'V') {
-			sound._voices = !sound._voices;
-			updateConfig = true;
-			settings.drawInteface(true);
-		}
-
-		if ((found == 3 && events._released) || ui._key == 'S') {
-			// Toggle sound effects
-			sound._digitized = !sound._digitized;
-			updateConfig = true;
-			settings.drawInteface(true);
-		}
-
-		if ((found == 4 && events._released) || ui._key == 'A') {
-			// Help button style
-			ui._helpStyle = !ui._helpStyle;
-			updateConfig = true;
-			settings.drawInteface(true);
-		}
-
-		if ((found == 5 && events._released) || ui._key == 'N') {
-			// New font style
-			int fontNum = screen.fontNumber() + 1;
-			if (fontNum == 3)
-				fontNum = 0;
-
-			screen.setFont(fontNum);
-			updateConfig = true;
-			settings.drawInteface(true);
-		}
-
-		if ((found == 8 && events._released) || ui._key == 'F') {
-			// Toggle fade style
-			screen._fadeStyle = !screen._fadeStyle;
-			updateConfig = true;
-			settings.drawInteface(true);
-		}
-
-		if ((found == 9 && events._released) || ui._key == 'W') {
-			// Window style
-			ui._slideWindows = !ui._slideWindows;
-			updateConfig = true;
-			settings.drawInteface(true);
-		}
-
-		if ((found == 10 && events._released) || ui._key == 'P') {
-			// Toggle portraits being shown
-			people._portraitsOn = !people._portraitsOn;
-			updateConfig = true;
-			settings.drawInteface(true);
-		}
-	} while (!vm->shouldQuit());
-
-	ui.banishWindow();
-
-	if (updateConfig)
-		vm->saveConfig();
-
-	ui._keyPress = '\0';
-	ui._keyboardInput = false;
-	ui._windowBounds.top = CONTROLS_Y1;
-	ui._key = -1;
-}
-
-} // End of namespace Scalpel
-
-} // End of namespace Sherlock
diff --git a/engines/sherlock/settings.h b/engines/sherlock/settings.h
deleted file mode 100644
index ff2e647..0000000
--- a/engines/sherlock/settings.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/* 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 SHERLOCK_SETTINGS_H
-#define SHERLOCK_SETTINGS_H
-
-#include "common/scummsys.h"
-
-namespace Sherlock {
-
-class SherlockEngine;
-
-namespace Scalpel {
-
-class Settings {
-private:
-	SherlockEngine *_vm;
-
-	Settings(SherlockEngine *vm) : _vm(vm) {}
-
-	/**
-	 * Draws the interface for the settings window
-	 */
-	void drawInteface(bool flag);
-
-	/**
-	 * Draws the buttons for the settings dialog
-	 */
-	int drawButtons(const Common::Point &pt, int key);
-public:
-	/**
-	 * Handles input when the settings window is being shown
-	 * @remarks		Whilst this would in theory be better in the Journal class, since it displays in
-	 *		the user interface, it uses so many internal UI fields, that it sort of made some sense
-	 *		to put it in the UserInterface class.
-	 */
-	static void show(SherlockEngine *vm);
-};
-
-} // End of namespace Scalpel
-
-} // End of namespace Sherlock
-
-#endif
diff --git a/engines/sherlock/talk.cpp b/engines/sherlock/talk.cpp
index 5e9cb02..dd6e776 100644
--- a/engines/sherlock/talk.cpp
+++ b/engines/sherlock/talk.cpp
@@ -23,6 +23,7 @@
 #include "sherlock/talk.h"
 #include "sherlock/sherlock.h"
 #include "sherlock/screen.h"
+#include "sherlock/scalpel/scalpel_user_interface.h"
 
 namespace Sherlock {
 
@@ -547,7 +548,7 @@ void Talk::talkTo(const Common::String &filename) {
 
 				}
 
-				ui._key = ui._oldKey = COMMANDS[TALK_MODE - 1];
+				ui._key = ui._oldKey = Scalpel::COMMANDS[TALK_MODE - 1];
 				ui._temp = ui._oldTemp = 0;
 				ui._menuMode = TALK_MODE;
 				_talkToFlag = 2;
@@ -784,9 +785,9 @@ void Talk::drawInterface() {
 		screen.makeButton(Common::Rect(181, CONTROLS_Y, 221, CONTROLS_Y + 10),
 			200 - screen.stringWidth("Down") / 2, "Down");
 	} else {
-		int strWidth = screen.stringWidth(PRESS_KEY_TO_CONTINUE);
+		int strWidth = screen.stringWidth(Scalpel::PRESS_KEY_TO_CONTINUE);
 		screen.makeButton(Common::Rect(46, CONTROLS_Y, 273, CONTROLS_Y + 10),
-			160 - strWidth / 2, PRESS_KEY_TO_CONTINUE);
+			160 - strWidth / 2, Scalpel::PRESS_KEY_TO_CONTINUE);
 		screen.gPrint(Common::Point(160 - strWidth / 2, CONTROLS_Y), COMMAND_FOREGROUND, "P");
 	}
 }
diff --git a/engines/sherlock/tattoo/tattoo_scene.cpp b/engines/sherlock/tattoo/tattoo_scene.cpp
new file mode 100644
index 0000000..f03e791
--- /dev/null
+++ b/engines/sherlock/tattoo/tattoo_scene.cpp
@@ -0,0 +1,227 @@
+/* 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 "sherlock/tattoo/tattoo_scene.h"
+#include "sherlock/tattoo/tattoo.h"
+#include "sherlock/tattoo/tattoo_user_interface.h"
+#include "sherlock/events.h"
+#include "sherlock/people.h"
+
+namespace Sherlock {
+
+namespace Tattoo {
+
+TattooScene::TattooScene(SherlockEngine *vm) : Scene(vm) {
+	_arrowZone = -1;
+	_mask = _mask1 = nullptr;
+	_maskCounter = 0;
+}
+
+void TattooScene::checkBgShapes() {
+	People &people = *_vm->_people;
+	Person &holmes = people._player;
+	Common::Point pt(holmes._position.x / FIXED_INT_MULTIPLIER, holmes._position.y / FIXED_INT_MULTIPLIER);
+
+	// Call the base scene method to handle bg shapes
+	Scene::checkBgShapes();
+
+	// Check for any active playing animation
+	if (_activeCAnim._images && _activeCAnim._zPlacement != REMOVE) {
+		switch (_activeCAnim._flags & 3) {
+		case 0:
+			_activeCAnim._zPlacement = BEHIND;
+			break;
+		case 1:
+			_activeCAnim._zPlacement = ((_activeCAnim._position.y + _activeCAnim._imageFrame->_frame.h - 1)) ?
+				NORMAL_FORWARD : NORMAL_BEHIND;
+			break;
+		case 2:
+			_activeCAnim._zPlacement = FORWARD;
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+void TattooScene::doBgAnimCheckCursor() {
+	Events &events = *_vm->_events;
+	UserInterface &ui = *_vm->_ui;
+	Common::Point mousePos = events.mousePos();
+
+	// If we're in Look Mode, make sure the cursor is the magnifying glass
+	if (ui._menuMode == LOOK_MODE && events.getCursor() != MAGNIFY)
+		events.setCursor(MAGNIFY);
+
+	// See if the mouse is over any of the arrow zones, and if so, change the cursor to the correct
+	// arrow cursor indicating the direcetion of the exit
+	if (events.getCursor() == ARROW || events.getCursor() >= EXIT_ZONES_START) {
+		CursorId cursorId = ARROW;
+
+		if (ui._menuMode == STD_MODE && _arrowZone != -1 && _currentScene != 90) {
+			for (uint idx = 0; idx < _exits.size(); ++idx) {
+				Exit &exit = _exits[idx];
+				if (exit.contains(mousePos))
+					cursorId = (CursorId)(exit._image + EXIT_ZONES_START);
+			}
+		}
+
+		events.setCursor(cursorId);
+	}
+}
+
+void TattooScene::doBgAnimEraseBackground() {
+	TattooEngine &vm = *((TattooEngine *)_vm);
+	People &people = *_vm->_people;
+	Screen &screen = *_vm->_screen;
+	TattooUserInterface &ui = *((TattooUserInterface *)_vm->_ui);
+	
+	static const int16 OFFSETS[16] = { -1, -2, -3, -3, -2, -1, -1, 0, 1, 2, 3, 3, 2, 1, 0, 0 };
+
+	if (_mask != nullptr) {
+		if (screen._backBuffer1.w() > screen.w())
+			screen.blitFrom(screen._backBuffer1, Common::Point(0, 0), Common::Rect(screen._currentScroll, 0,
+			screen._currentScroll + screen.w(), screen.h()));
+		else
+			screen.blitFrom(screen._backBuffer1);
+
+		switch (_currentScene) {
+		case 7:
+			if (++_maskCounter == 2) {
+				_maskCounter = 0;
+				if (--_maskOffset.x < 0)
+					_maskOffset.x = SHERLOCK_SCREEN_WIDTH - 1;
+			}
+			break;
+
+		case 8:
+			_maskOffset.x += 2;
+			if (_maskOffset.x >= SHERLOCK_SCREEN_WIDTH)
+				_maskOffset.x = 0;
+			break;
+
+		case 18:
+		case 68:
+			++_maskCounter;
+			if (_maskCounter / 4 >= 16)
+				_maskCounter = 0;
+
+			_maskOffset.x = OFFSETS[_maskCounter / 4];
+			break;
+
+		case 53:
+			if (++_maskCounter == 2) {
+				_maskCounter = 0;
+				if (++_maskOffset.x == screen._backBuffer1.w())
+					_maskOffset.x = 0;
+			}
+			break;
+
+		default:
+			break;
+		}
+	} else {
+		// Standard scene without mask, so call user interface to erase any UI elements as necessary
+		ui.doBgAnimRestoreUI();
+		
+		// Restore background for any areas covered by characters and shapes
+		for (uint idx = 0; idx < MAX_CHARACTERS; ++idx)
+			screen.restoreBackground(Common::Rect(people[idx]._oldPosition.x, people[idx]._oldPosition.y,
+				people[idx]._oldPosition.x + people[idx]._oldSize.x, people[idx]._oldPosition.y + people[idx]._oldSize.y));
+
+		for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+			Object &obj = _bgShapes[idx];
+						
+			if ((obj._type == ACTIVE_BG_SHAPE && (obj._maxFrames > 1 || obj._delta.x != 0 || obj._delta.y != 0)) || 
+					obj._type == HIDE_SHAPE || obj._type == REMOVE)
+				screen._backBuffer1.blitFrom(*obj._imageFrame, obj._oldPosition, 
+					Common::Rect(obj._oldPosition.x, obj._oldPosition.y, obj._oldPosition.x + obj._oldSize.x,
+						obj._oldPosition.y + obj._oldSize.y));
+		}
+
+		// If credits are active, erase the area they cover
+		if (vm._creditsActive)
+			vm.eraseCredits();
+	}
+
+	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+		Object &obj = _bgShapes[idx];
+
+		if (obj._type == NO_SHAPE && (obj._flags & 1) == 0) {
+			screen._backBuffer1.blitFrom(screen._backBuffer2, obj._position, obj.getNoShapeBounds());
+
+			obj._oldPosition = obj._position;
+			obj._oldSize = obj._noShapeSize;
+		}
+	}
+
+	// Adjust the Target Scroll if needed
+	if ((people[people._walkControl]._position.x / FIXED_INT_MULTIPLIER - screen._currentScroll) < 
+			(SHERLOCK_SCREEN_WIDTH / 8) && people[people._walkControl]._delta.x < 0) {
+		
+		screen._targetScroll = (short)(people[people._walkControl]._position.x / FIXED_INT_MULTIPLIER - 
+				SHERLOCK_SCREEN_WIDTH / 8 - 250);
+		if (screen._targetScroll < 0)
+			screen._targetScroll = 0;
+	}
+
+	if ((people[people._walkControl]._position.x / FIXED_INT_MULTIPLIER - screen._currentScroll) > (SHERLOCK_SCREEN_WIDTH / 4 * 3) 
+			&& people[people._walkControl]._delta.x > 0)
+		screen._targetScroll = (short)(people[people._walkControl]._position.x / FIXED_INT_MULTIPLIER - 
+			SHERLOCK_SCREEN_WIDTH / 4 * 3 + 250);
+
+	if (screen._targetScroll > screen._scrollSize)
+		screen._targetScroll = screen._scrollSize;
+
+	ui.doScroll();
+}
+
+void TattooScene::doBgAnim() {
+	doBgAnimCheckCursor();
+
+//	Events &events = *_vm->_events;
+	People &people = *_vm->_people;
+//	Scene &scene = *_vm->_scene;
+	Screen &screen = *_vm->_screen;
+	Talk &talk = *_vm->_talk;
+
+	screen.setDisplayBounds(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCENE_HEIGHT));
+	talk._talkToAbort = false;
+
+	// Check the characters and sprites for updates
+	for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
+		if (people[idx]._type == CHARACTER)
+			people[idx].checkSprite();
+	}
+
+	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+		if (_bgShapes[idx]._type == ACTIVE_BG_SHAPE)
+			_bgShapes[idx].checkObject();
+	}
+
+	// Erase any affected background areas
+	doBgAnimEraseBackground();
+}
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/tattoo_scene.h b/engines/sherlock/tattoo/tattoo_scene.h
new file mode 100644
index 0000000..34e87f4
--- /dev/null
+++ b/engines/sherlock/tattoo/tattoo_scene.h
@@ -0,0 +1,65 @@
+/* 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 SHERLOCK_TATTOO_SCENE_H
+#define SHERLOCK_TATTOO_SCENE_H
+
+#include "common/scummsys.h"
+#include "sherlock/scene.h"
+
+namespace Sherlock {
+
+namespace Tattoo {
+
+class TattooScene : public Scene {
+private:
+	int _arrowZone;
+	int _maskCounter;
+	Common::Point _maskOffset;
+private:
+	void doBgAnimCheckCursor();
+
+	void doBgAnimEraseBackground();
+protected:
+	/**
+	 * Checks all the background shapes. If a background shape is animating,
+	 * it will flag it as needing to be drawn. If a non-animating shape is
+	 * colliding with another shape, it will also flag it as needing drawing
+	 */
+	virtual void checkBgShapes();
+public:
+	ImageFile *_mask, *_mask1;
+	CAnimStream _activeCAnim;
+public:
+	TattooScene(SherlockEngine *vm);
+
+	/**
+	 * Draw all objects and characters.
+	 */
+	virtual void doBgAnim();
+};
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/tattoo/tattoo_user_interface.cpp b/engines/sherlock/tattoo/tattoo_user_interface.cpp
new file mode 100644
index 0000000..98ec34d
--- /dev/null
+++ b/engines/sherlock/tattoo/tattoo_user_interface.cpp
@@ -0,0 +1,106 @@
+/* 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 "sherlock/tattoo/tattoo_user_interface.h"
+#include "sherlock/tattoo/tattoo_scene.h"
+#include "sherlock/sherlock.h"
+
+namespace Sherlock {
+
+namespace Tattoo {
+
+TattooUserInterface::TattooUserInterface(SherlockEngine *vm): UserInterface(vm) {
+	_menuBuffer = nullptr;
+	_invMenuBuffer = nullptr;
+}
+
+void TattooUserInterface::handleInput() {
+	// TODO
+	_vm->_events->pollEventsAndWait();
+}
+
+void TattooUserInterface::doBgAnimRestoreUI() {
+	TattooScene &scene = *((TattooScene *)_vm->_scene);
+	Screen &screen = *_vm->_screen;
+
+	// If _oldMenuBounds was set, then either a new menu has been opened or the current menu has been closed.
+	// Either way, we need to restore the area where the menu was displayed
+	if (_oldMenuBounds.width() > 0)
+		screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_oldMenuBounds.left, _oldMenuBounds.top),
+			_oldMenuBounds);
+
+	if (_oldInvMenuBounds.width() > 0)
+		screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_oldInvMenuBounds.left, _oldInvMenuBounds.top),
+			_oldInvMenuBounds);
+
+	if (_menuBuffer != nullptr)
+		screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_menuBounds.left, _menuBounds.top), _menuBounds);
+	if (_invMenuBuffer != nullptr)
+		screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_invMenuBounds.left, _invMenuBounds.top), _invMenuBounds);
+
+	// If there is a Text Tag being display, restore the area underneath it
+	if (_oldTagBounds.width() > 0)
+		screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_oldTagBounds.left, _oldTagBounds.top), 
+			_oldTagBounds);
+
+	// If there is an Inventory being shown, restore the graphics underneath it
+	if (_oldInvGraphicBounds.width() > 0)
+		screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_oldInvGraphicBounds.left, _oldInvGraphicBounds.top), 
+			_oldInvGraphicBounds);
+
+	// If a canimation is active, restore the graphics underneath it
+	if (scene._activeCAnim._images != nullptr)
+		screen.restoreBackground(scene._activeCAnim._oldBounds);
+
+	// If a canimation just ended, remove it's graphics from the backbuffer
+	if (scene._activeCAnim._removeBounds.width() > 0)
+		screen.restoreBackground(scene._activeCAnim._removeBounds);
+}
+
+void TattooUserInterface::doScroll() {
+	Screen &screen = *_vm->_screen;
+	int oldScroll = screen._currentScroll;
+
+	// If we're already at the target scroll position, nothing needs to be done
+	if (screen._targetScroll == screen._currentScroll)
+		return;
+
+	screen._flushScreen = true;
+	if (screen._targetScroll > screen._currentScroll) {
+		screen._currentScroll += screen._scrollSpeed;
+		if (screen._currentScroll > screen._targetScroll)
+			screen._currentScroll = screen._targetScroll;
+	} else if (screen._targetScroll < screen._currentScroll) {
+		screen._currentScroll -= screen._scrollSpeed;
+		if (screen._currentScroll < screen._targetScroll)
+			screen._currentScroll = screen._targetScroll;
+	}
+
+	if (_menuBuffer != nullptr)
+		_menuBounds.translate(screen._currentScroll - oldScroll, 0);
+	if (_invMenuBuffer != nullptr)
+		_invMenuBounds.translate(screen._currentScroll - oldScroll, 0);
+}
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/tattoo_user_interface.h b/engines/sherlock/tattoo/tattoo_user_interface.h
new file mode 100644
index 0000000..c7a4c4c
--- /dev/null
+++ b/engines/sherlock/tattoo/tattoo_user_interface.h
@@ -0,0 +1,68 @@
+/* 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 SHERLOCK_TATTOO_UI_H
+#define SHERLOCK_TATTOO_UI_H
+
+#include "common/scummsys.h"
+#include "sherlock/user_interface.h"
+
+namespace Sherlock {
+
+namespace Tattoo {
+
+class TattooUserInterface : public UserInterface {
+private:
+	Common::Rect _menuBounds;
+	Common::Rect _oldMenuBounds;
+	Common::Rect _invMenuBounds;
+	Common::Rect _oldInvMenuBounds;
+	Common::Rect _oldTagBounds;
+	Common::Rect _oldInvGraphicBounds;
+	Surface *_menuBuffer;
+	Surface *_invMenuBuffer;
+public:
+	TattooUserInterface(SherlockEngine *vm);
+
+	/**
+	 * Handles restoring any areas of the back buffer that were/are covered by UI elements
+	 */
+	void doBgAnimRestoreUI();
+
+	/**
+	 * Checks to see if the screen needs to be scrolled. If so, scrolls it towards the target position
+	 */
+	void doScroll();
+public:
+	virtual ~TattooUserInterface() {}
+
+	/**
+	 * Main input handler for the user interface
+	 */
+	virtual void handleInput();
+};
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/user_interface.cpp b/engines/sherlock/user_interface.cpp
index 5858daf..9fff7cc 100644
--- a/engines/sherlock/user_interface.cpp
+++ b/engines/sherlock/user_interface.cpp
@@ -22,64 +22,11 @@
 
 #include "sherlock/user_interface.h"
 #include "sherlock/sherlock.h"
-#include "sherlock/settings.h"
+#include "sherlock/scalpel/scalpel_user_interface.h"
+#include "sherlock/tattoo/tattoo_user_interface.h"
 
 namespace Sherlock {
 
-// Main user interface menu control locations
-const int MENU_POINTS[12][4] = {
-	{ 13, 153, 72, 165 },
-	{ 13, 169, 72, 181 },
-	{ 13, 185, 72, 197 },
-	{ 88, 153, 152, 165 },
-	{ 88, 169, 152, 181 },
-	{ 88, 185, 152, 197 },
-	{ 165, 153, 232, 165 },
-	{ 165, 169, 232, 181 },
-	{ 165, 185, 233, 197 },
-	{ 249, 153, 305, 165 },
-	{ 249, 169, 305, 181 },
-	{ 249, 185, 305, 197 }
-};
-
-// Inventory control locations */
-const int INVENTORY_POINTS[8][3] = {
-	{ 4, 50, 29 },
-	{ 52, 99, 77 },
-	{ 101, 140, 123 },
-	{ 142, 187, 166 },
-	{ 189, 219, 198 },
-	{ 221, 251, 234 },
-	{ 253, 283, 266 },
-	{ 285, 315, 294 }
-};
-
-const char COMMANDS[13] = "LMTPOCIUGJFS";
-const char INVENTORY_COMMANDS[9] = { "ELUG-+,." };
-const char *const PRESS_KEY_FOR_MORE = "Press any Key for More.";
-const char *const PRESS_KEY_TO_CONTINUE = "Press any Key to Continue.";
-
-const char *const MOPEN[] = {
-	"This cannot be opened", "It is already open", "It is locked", "Wait for Watson", " ", "."
-};
-const char *const MCLOSE[] = {
-	"This cannot be closed", "It is already closed", "The safe door is in the way"
-};
-const char *const MMOVE[] = {
-	"This cannot be moved", "It is bolted to the floor", "It is too heavy", "The other crate is in the way"
-};
-const char *const MPICK[] = {
-	"Nothing of interest here", "It is bolted down", "It is too big to carry", "It is too heavy",
-	"I think a girl would be more your type", "Those flowers belong to Penny", "She's far too young for you!",
-	"I think a girl would be more your type!", "Government property for official use only"
-};
-const char *const MUSE[] = {
-	"You can't do that", "It had no effect", "You can't reach it", "OK, the door looks bigger! Happy?",
-	"Doors don't smoke"
-};
-
-
-
 UserInterface *UserInterface::init(SherlockEngine *vm) {
 	if (vm->getGameID() == GType_SerratedScalpel)
 		return new Scalpel::ScalpelUserInterface(vm);
@@ -106,2277 +53,4 @@ UserInterface::UserInterface(SherlockEngine *vm) : _vm(vm) {
 	_lookHelp = 0;
 }
 
-/*----------------------------------------------------------------*/
-
-namespace Scalpel {
-
-ScalpelUserInterface::ScalpelUserInterface(SherlockEngine *vm): UserInterface(vm) {
-	_controls = new ImageFile("menu.all");
-	_controlPanel = new ImageFile("controls.vgs");
-	_keyPress = '\0';
-	_lookHelp = 0;
-	_bgFound = 0;
-	_oldBgFound = -1;
-	_help = _oldHelp = 0;
-	_key = _oldKey = '\0';
-	_temp = _oldTemp = 0;
-	_oldLook = 0;
-	_keyboardInput = false;
-	_pause = false;
-	_cNum = 0;
-	_find = 0;
-	_oldUse = 0;
-}
-
-ScalpelUserInterface::~ScalpelUserInterface() {
-	delete _controls;
-	delete _controlPanel;
-}
-
-void ScalpelUserInterface::reset() {
-	_oldKey = -1;
-	_help = _oldHelp = -1;
-	_oldTemp = _temp = -1;
-}
-
-void ScalpelUserInterface::drawInterface(int bufferNum) {
-	Screen &screen = *_vm->_screen;
-
-	if (bufferNum & 1)
-		screen._backBuffer1.transBlitFrom((*_controlPanel)[0], Common::Point(0, CONTROLS_Y));
-	if (bufferNum & 2)
-		screen._backBuffer2.transBlitFrom((*_controlPanel)[0], Common::Point(0, CONTROLS_Y));
-	if (bufferNum == 3)
-		screen._backBuffer2.fillRect(0, INFO_LINE, SHERLOCK_SCREEN_WIDTH, INFO_LINE + 10, INFO_BLACK);
-}
-
-void ScalpelUserInterface::handleInput() {
-	Events &events = *_vm->_events;
-	Inventory &inv = *_vm->_inventory;
-	People &people = *_vm->_people;
-	Scene &scene = *_vm->_scene;
-	Screen &screen = *_vm->_screen;
-	Talk &talk = *_vm->_talk;
-
-	if (_menuCounter)
-		whileMenuCounter();
-
-	Common::Point pt = events.mousePos();
-	_bgFound = scene.findBgShape(Common::Rect(pt.x, pt.y, pt.x + 1, pt.y + 1));
-	_keyPress = '\0';
-
-	// Check kbd and set the mouse released flag if Enter or space is pressed.
-	// Otherwise, the pressed _key is stored for later use
-	if (events.kbHit()) {
-		Common::KeyState keyState = events.getKey();
-		_keyPress = keyState.ascii;
-
-		if (keyState.keycode == Common::KEYCODE_x && keyState.flags & Common::KBD_ALT) {
-			_vm->quitGame();
-			events.pollEvents();
-			return;
-		}
-	}
-
-	// Do button highlighting check
-	if (!talk._scriptMoreFlag) {	// Don't if scripts are running
-		if (((events._rightPressed || events._rightReleased) && _helpStyle) ||
-				(!_helpStyle && !_menuCounter)) {
-			// Handle any default commands if we're in STD_MODE
-			if (_menuMode == STD_MODE) {
-				if (pt.y < CONTROLS_Y &&
-					(events._rightPressed || (!_helpStyle && !events._released)) &&
-					(_bgFound != -1) && (_bgFound < 1000) &&
-					(scene._bgShapes[_bgFound]._defaultCommand ||
-					!scene._bgShapes[_bgFound]._description.empty())) {
-					// If there is no default command, so set it to Look
-					if (scene._bgShapes[_bgFound]._defaultCommand)
-						_help = scene._bgShapes[_bgFound]._defaultCommand - 1;
-					else
-						_help = 0;
-
-					// Reset 'help' if it is an invalid command
-					if (_help > 5)
-						_help = -1;
-				} else if (pt.y < CONTROLS_Y &&
-					((events._rightReleased && _helpStyle) || (events._released && !_helpStyle)) &&
-					(_bgFound != -1 && _bgFound < 1000) &&
-					(scene._bgShapes[_bgFound]._defaultCommand ||
-					!scene._bgShapes[_bgFound]._description.empty())) {
-					// If there is no default command, set it to Look
-					if (scene._bgShapes[_bgFound]._defaultCommand)
-						_menuMode = (MenuMode)scene._bgShapes[_bgFound]._defaultCommand;
-					else
-						_menuMode = LOOK_MODE;
-					events._released = true;
-					events._pressed = events._oldButtons = false;
-					_help = _oldHelp = -1;
-
-					if (_menuMode == LOOK_MODE) {
-						// Set the flag to tell the game that this was a right-click
-						// call to look and should exit without the look button being pressed
-						_lookHelp = true;
-					}
-				} else {
-					_help = -1;
-				}
-
-				// Check if highlighting a different button than last time
-				if (_help != _oldHelp) {
-					// If another button was highlighted previously, restore it
-					if (_oldHelp != -1)
-						restoreButton(_oldHelp);
-
-					// If we're highlighting a new button, then draw it pressed
-					if (_help != -1)
-						depressButton(_help);
-
-					_oldHelp = _help;
-				}
-
-				if (_bgFound != _oldBgFound || _oldBgFound == -1) {
-					_infoFlag = true;
-					clearInfo();
-
-					if (_help != -1 && !scene._bgShapes[_bgFound]._description.empty()
-							&& scene._bgShapes[_bgFound]._description[0] != ' ')
-						screen.print(Common::Point(0, INFO_LINE + 1),
-						INFO_FOREGROUND, "%s", scene._bgShapes[_bgFound]._description.c_str());
-
-					_oldBgFound = _bgFound;
-				}
-			} else {
-				// We're not in STD_MODE
-				// If there isn't a window open, then revert back to STD_MODE
-				if (!_windowOpen && events._rightReleased) {
-					// Restore all buttons
-					for (int idx = 0; idx < 12; ++idx)
-						restoreButton(idx);
-
-					_menuMode = STD_MODE;
-					_key = _oldKey = -1;
-					_temp = _oldTemp = _lookHelp = _invLookFlag = 0;
-					events.clearEvents();
-				}
-			}
-		}
-	}
-
-	// Reset the old bgshape number if the mouse button is released, so that
-	// it can e re-highlighted when we come back here
-	if ((events._rightReleased && _helpStyle) || (events._released && !_helpStyle))
-		_oldBgFound = -1;
-
-	// Do routines that should be done before input processing
-	switch (_menuMode) {
-	case LOOK_MODE:
-		if (!_windowOpen) {
-			if (events._released && _bgFound >= 0 && _bgFound < 1000) {
-				if (!scene._bgShapes[_bgFound]._examine.empty())
-					examine();
-			} else {
-				lookScreen(pt);
-			}
-		}
-		break;
-
-	case MOVE_MODE:
-	case OPEN_MODE:
-	case CLOSE_MODE:
-	case PICKUP_MODE:
-		lookScreen(pt);
-		break;
-
-	case TALK_MODE:
-		if (!_windowOpen) {
-			bool personFound;
-
-			if (_bgFound >= 1000) {
-				personFound = false;
-				if (!events._released)
-					lookScreen(pt);
-			} else {
-				personFound = _bgFound != -1 && scene._bgShapes[_bgFound]._aType == PERSON;
-			}
-
-			if (events._released && personFound)
-				talk.talk(_bgFound);
-			else if (personFound)
-				lookScreen(pt);
-			else if (_bgFound < 1000)
-				clearInfo();
-		}
-		break;
-
-	case USE_MODE:
-	case GIVE_MODE:
-	case INV_MODE:
-		if (inv._invMode == INVMODE_LOOK || inv._invMode == INVMODE_USE || inv._invMode == INVMODE_GIVE) {
-			if (pt.y > CONTROLS_Y)
-				lookInv();
-			else
-				lookScreen(pt);
-		}
-		break;
-
-	default:
-		break;
-	}
-
-	//
-	// Do input processing
-	//
-	if (events._pressed || events._released || events._rightPressed || _keyPress || _pause) {
-		if (((events._released && (_helpStyle || _help == -1)) || (events._rightReleased && !_helpStyle)) &&
-				(pt.y <= CONTROLS_Y) && (_menuMode == STD_MODE)) {
-			// The mouse was clicked in the playing area with no action buttons down.
-			// Check if the mouse was clicked in a script zone. If it was,
-			// then execute the script. Otherwise, walk to the given position
-			if (scene.checkForZones(pt, SCRIPT_ZONE) != 0 ||
-					scene.checkForZones(pt, NOWALK_ZONE) != 0) {
-				// Mouse clicked in script zone
-				events._pressed = events._released = false;
-			} else {
-				people._walkDest = pt;
-				people._allowWalkAbort = false;
-				people.goAllTheWay();
-			}
-
-			if (_oldKey != -1) {
-				restoreButton(_oldTemp);
-				_oldKey = -1;
-			}
-		}
-
-		// Handle action depending on selected mode
-		switch (_menuMode) {
-		case LOOK_MODE:
-			if (_windowOpen)
-				doLookControl();
-			break;
-
-		case MOVE_MODE:
-			doMiscControl(ALLOW_MOVE);
-			break;
-
-		case TALK_MODE:
-			if (_windowOpen)
-				doTalkControl();
-			break;
-
-		case OPEN_MODE:
-			doMiscControl(ALLOW_OPEN);
-			break;
-
-		case CLOSE_MODE:
-			doMiscControl(ALLOW_CLOSE);
-			break;
-
-		case PICKUP_MODE:
-			doPickControl();
-			break;
-
-		case USE_MODE:
-		case GIVE_MODE:
-		case INV_MODE:
-			doInvControl();
-			break;
-
-		case FILES_MODE:
-			doEnvControl();
-			break;
-
-		default:
-			break;
-		}
-
-		// As long as there isn't an open window, do main input processing.
-		// Windows are opened when in TALK, USE, INV, and GIVE modes
-		if ((!_windowOpen && !_menuCounter && pt.y > CONTROLS_Y) ||
-				_keyPress) {
-			if (events._pressed || events._released || _pause || _keyPress)
-				doMainControl();
-		}
-
-		if (pt.y < CONTROLS_Y && events._pressed && _oldTemp != (int)(_menuMode - 1) && _oldKey != -1)
-			restoreButton(_oldTemp);
-	}
-}
-
-void ScalpelUserInterface::depressButton(int num) {
-	Screen &screen = *_vm->_screen;
-	Common::Point pt(MENU_POINTS[num][0], MENU_POINTS[num][1]);
-
-	ImageFrame &frame = (*_controls)[num];
-	screen._backBuffer1.transBlitFrom(frame, pt);
-	screen.slamArea(pt.x, pt.y, pt.x + frame._width, pt.y + frame._height);
-}
-
-void ScalpelUserInterface::restoreButton(int num) {
-	Screen &screen = *_vm->_screen;
-	Common::Point pt(MENU_POINTS[num][0], MENU_POINTS[num][1]);
-	Graphics::Surface &frame = (*_controls)[num]._frame;
-
-	screen._backBuffer1.blitFrom(screen._backBuffer2, pt,
-		Common::Rect(pt.x, pt.y, pt.x + 90, pt.y + 19));
-	screen.slamArea(pt.x, pt.y, pt.x + frame.w, pt.y + frame.h);
-
-	if (!_menuCounter) {
-		_infoFlag = true;
-		clearInfo();
-	}
-}
-
-void ScalpelUserInterface::pushButton(int num) {
-	Events &events = *_vm->_events;
-	_oldKey = -1;
-
-	if (!events._released) {
-		if (_oldHelp != -1)
-			restoreButton(_oldHelp);
-		if (_help != -1)
-			restoreButton(_help);
-
-		depressButton(num);
-		events.wait(6);
-	}
-
-	restoreButton(num);
-}
-
-void ScalpelUserInterface::toggleButton(int num) {
-	Screen &screen = *_vm->_screen;
-
-	if (_menuMode != (MenuMode)(num + 1)) {
-		_menuMode = (MenuMode)(num + 1);
-		_oldKey = COMMANDS[num];
-		_oldTemp = num;
-
-		if (_keyboardInput) {
-			if (_oldHelp != -1 && _oldHelp != num)
-				restoreButton(_oldHelp);
-			if (_help != -1 && _help != num)
-				restoreButton(_help);
-
-			_keyboardInput = false;
-
-			ImageFrame &frame = (*_controls)[num];
-			Common::Point pt(MENU_POINTS[num][0], MENU_POINTS[num][1]);
-			screen._backBuffer1.transBlitFrom(frame, pt);
-			screen.slamArea(pt.x, pt.y, pt.x + frame._width, pt.y + frame._height);
-		}
-	} else {
-		_menuMode = STD_MODE;
-		_oldKey = -1;
-		restoreButton(num);
-	}
-}
-
-void ScalpelUserInterface::clearInfo() {
-	if (_infoFlag) {
-		_vm->_screen->vgaBar(Common::Rect(16, INFO_LINE, SHERLOCK_SCREEN_WIDTH - 19,
-			INFO_LINE + 10), INFO_BLACK);
-		_infoFlag = false;
-		_oldLook = -1;
-	}
-}
-
-void ScalpelUserInterface::clearWindow() {
-	if (_windowOpen) {
-		_vm->_screen->vgaBar(Common::Rect(3, CONTROLS_Y + 11, SHERLOCK_SCREEN_WIDTH - 2,
-			SHERLOCK_SCREEN_HEIGHT - 2), INV_BACKGROUND);
-	}
-}
-
-void ScalpelUserInterface::whileMenuCounter() {
-	if (!(--_menuCounter) || _vm->_events->checkInput()) {
-		_menuCounter = 0;
-		_infoFlag = true;
-		clearInfo();
-	}
-}
-
-void ScalpelUserInterface::examine() {
-	Events &events = *_vm->_events;
-	Inventory &inv = *_vm->_inventory;
-	People &people = *_vm->_people;
-	Scene &scene = *_vm->_scene;
-	Talk &talk = *_vm->_talk;
-	Common::Point pt = events.mousePos();
-
-	if (pt.y < (CONTROLS_Y + 9)) {
-		Object &obj = scene._bgShapes[_bgFound];
-
-		if (obj._lookcAnim != 0) {
-			int canimSpeed = ((obj._lookcAnim & 0xe0) >> 5) + 1;
-			scene._cAnimFramePause = obj._lookFrames;
-			_cAnimStr = obj._examine;
-			_cNum = (obj._lookcAnim & 0x1f) - 1;
-
-			scene.startCAnim(_cNum, canimSpeed);
-		} else if (obj._lookPosition.y != 0) {
-			// Need to walk to the object to be examined
-			people.walkToCoords(Common::Point(obj._lookPosition.x, obj._lookPosition.y * 100), obj._lookFacing);
-		}
-
-		if (!talk._talkToAbort) {
-			_cAnimStr = obj._examine;
-			if (obj._lookFlag)
-				_vm->setFlags(obj._lookFlag);
-		}
-	} else {
-		// Looking at an inventory item
-		_cAnimStr = inv[_selector]._examine;
-		if (inv[_selector]._lookFlag)
-			_vm->setFlags(inv[_selector]._lookFlag);
-	}
-
-	if (_invLookFlag) {
-		// Don't close the inventory window when starting an examine display, since its
-		// window will slide up to replace the inventory display
-		_windowOpen = false;
-		_menuMode = LOOK_MODE;
-	}
-
-	if (!talk._talkToAbort) {
-		if (!scene._cAnimFramePause)
-			printObjectDesc(_cAnimStr, true);
-		else
-			// description was already printed in startCAnimation
-			scene._cAnimFramePause = 0;
-	}
-}
-
-void ScalpelUserInterface::lookScreen(const Common::Point &pt) {
-	Events &events = *_vm->_events;
-	Inventory &inv = *_vm->_inventory;
-	Scene &scene = *_vm->_scene;
-	Screen &screen = *_vm->_screen;
-	Common::Point mousePos = events.mousePos();
-	int temp;
-	Common::String tempStr;
-
-	// Don't display anything for right button command
-	if ((events._rightPressed || events._rightPressed) && !events._pressed)
-		return;
-
-	if (mousePos.y < CONTROLS_Y && (temp = _bgFound) != -1) {
-		if (temp != _oldLook) {
-			_infoFlag = true;
-			clearInfo();
-
-			if (temp < 1000)
-				tempStr = scene._bgShapes[temp]._description;
-			else
-				tempStr = scene._bgShapes[temp - 1000]._description;
-
-			_infoFlag = true;
-			clearInfo();
-
-			// Only print description if there is one
-			if (!tempStr.empty() && tempStr[0] != ' ') {
-				// If inventory is active and an item is selected for a Use or Give action
-				if ((_menuMode == INV_MODE || _menuMode == USE_MODE || _menuMode == GIVE_MODE) &&
-						(inv._invMode == INVMODE_USE || inv._invMode == INVMODE_GIVE)) {
-					int width1 = 0, width2 = 0;
-					int x, width;
-					if (inv._invMode == INVMODE_USE) {
-						// Using an object
-						x = width = screen.stringWidth("Use ");
-
-						if (temp < 1000 && scene._bgShapes[temp]._aType != PERSON)
-							// It's not a person, so make it lowercase
-							tempStr.setChar(tolower(tempStr[0]), 0);
-
-						x += screen.stringWidth(tempStr);
-
-						// If we're using an inventory object, add in the width
-						// of the object name and the " on "
-						if (_selector != -1) {
-							width1 = screen.stringWidth(inv[_selector]._name);
-							x += width1;
-							width2 = screen.stringWidth(" on ");
-							x += width2;
-						}
-
-						// If the line will be too long, keep cutting off characters
-						// until the string will fit
-						while (x > 280) {
-							x -= screen.charWidth(tempStr.lastChar());
-							tempStr.deleteLastChar();
-						}
-
-						int xStart = (SHERLOCK_SCREEN_WIDTH - x) / 2;
-						screen.print(Common::Point(xStart, INFO_LINE + 1),
-							INFO_FOREGROUND, "Use ");
-
-						if (_selector != -1) {
-							screen.print(Common::Point(xStart + width, INFO_LINE + 1),
-								TALK_FOREGROUND, "%s", inv[_selector]._name.c_str());
-							screen.print(Common::Point(xStart + width + width1, INFO_LINE + 1),
-								INFO_FOREGROUND, " on ");
-							screen.print(Common::Point(xStart + width + width1 + width2, INFO_LINE + 1),
-								INFO_FOREGROUND, "%s", tempStr.c_str());
-						} else {
-							screen.print(Common::Point(xStart + width, INFO_LINE + 1),
-								INFO_FOREGROUND, "%s", tempStr.c_str());
-						}
-					} else if (temp >= 0 && temp < 1000 && _selector != -1 &&
-							scene._bgShapes[temp]._aType == PERSON) {
-						// Giving an object to a person
-						width1 = screen.stringWidth(inv[_selector]._name);
-						x = width = screen.stringWidth("Give ");
-						x += width1;
-						width2 = screen.stringWidth(" to ");
-						x += width2;
-						x += screen.stringWidth(tempStr);
-
-						// Ensure string will fit on-screen
-						while (x > 280) {
-							x -= screen.charWidth(tempStr.lastChar());
-							tempStr.deleteLastChar();
-						}
-
-						int xStart = (SHERLOCK_SCREEN_WIDTH - x) / 2;
-						screen.print(Common::Point(xStart, INFO_LINE + 1),
-							INFO_FOREGROUND, "Give ");
-						screen.print(Common::Point(xStart + width, INFO_LINE + 1),
-							TALK_FOREGROUND, "%s", inv[_selector]._name.c_str());
-						screen.print(Common::Point(xStart + width + width1, INFO_LINE + 1),
-							INFO_FOREGROUND, " to ");
-						screen.print(Common::Point(xStart + width + width1 + width2, INFO_LINE + 1),
-							INFO_FOREGROUND, "%s", tempStr.c_str());
-					}
-				} else {
-					screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", tempStr.c_str());
-				}
-
-				_infoFlag = true;
-				_oldLook = temp;
-			}
-		}
-	} else {
-		clearInfo();
-	}
-}
-
-void ScalpelUserInterface::lookInv() {
-	Events &events = *_vm->_events;
-	Inventory &inv = *_vm->_inventory;
-	Screen &screen = *_vm->_screen;
-	Common::Point mousePos = events.mousePos();
-
-	if (mousePos.x > 15 && mousePos.x < 314 && mousePos.y > (CONTROLS_Y1 + 11)
-			&& mousePos.y < (SHERLOCK_SCREEN_HEIGHT - 2)) {
-		int temp = (mousePos.x - 6) / 52 + inv._invIndex;
-		if (temp < inv._holdings) {
-			if (temp < inv._holdings) {
-				clearInfo();
-				screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND,
-					"%s", inv[temp]._description.c_str());
-				_infoFlag = true;
-				_oldLook = temp;
-			}
-		} else {
-			clearInfo();
-		}
-	} else {
-		clearInfo();
-	}
-}
-
-void ScalpelUserInterface::doEnvControl() {
-	Events &events = *_vm->_events;
-	SaveManager &saves = *_vm->_saves;
-	Scene &scene = *_vm->_scene;
-	Screen &screen = *_vm->_screen;
-	Talk &talk = *_vm->_talk;
-	Common::Point mousePos = events.mousePos();
-	static const char ENV_COMMANDS[7] = "ELSUDQ";
-
-	byte color;
-
-	_key = _oldKey = -1;
-	_keyboardInput = false;
-	int found = saves.getHighlightedButton();
-
-	if (events._pressed || events._released) {
-		events.clearKeyboard();
-
-		// Check for a filename entry being highlighted
-		if ((events._pressed || events._released) && mousePos.y > (CONTROLS_Y + 10)) {
-			int found1 = 0;
-			for (_selector = 0; (_selector < ONSCREEN_FILES_COUNT) && !found1; ++_selector)
-				if (mousePos.y > (CONTROLS_Y + 11 + _selector * 10) && mousePos.y < (CONTROLS_Y + 21 + _selector * 10))
-					found1 = 1;
-
-			if (_selector + saves._savegameIndex - 1 < MAX_SAVEGAME_SLOTS + (saves._envMode != SAVEMODE_LOAD))
-				_selector = _selector + saves._savegameIndex - 1;
-			else
-				_selector = -1;
-
-			if (!found1)
-				_selector = -1;
-		}
-
-		// Handle selecting buttons, if any
-		saves.highlightButtons(found);
-
-		if (found == 0 || found == 5)
-			saves._envMode = SAVEMODE_NONE;
-	}
-
-	if (_keyPress) {
-		_key = toupper(_keyPress);
-
-		// Escape _key will close the dialog
-		if (_key == Common::KEYCODE_ESCAPE)
-			_key = 'E';
-
-		if (_key == 'E' || _key == 'L' || _key == 'S' || _key == 'U' || _key == 'D' || _key == 'Q') {
-			const char *chP = strchr(ENV_COMMANDS, _key);
-			int btnIndex = !chP ? -1 : chP - ENV_COMMANDS;
-			saves.highlightButtons(btnIndex);
-			_keyboardInput = true;
-
-			if (_key == 'E' || _key == 'Q') {
-				saves._envMode = SAVEMODE_NONE;
-			} else if (_key >= '1' && _key <= '9') {
-				_keyboardInput = true;
-				_selector = _key - '1';
-				if (_selector >= MAX_SAVEGAME_SLOTS + (saves._envMode == SAVEMODE_LOAD ? 0 : 1))
-					_selector = -1;
-
-				if (saves.checkGameOnScreen(_selector))
-					_oldSelector = _selector;
-			} else {
-				_selector = -1;
-			}
-		}
-	}
-
-	if (_selector != _oldSelector)  {
-		if (_oldSelector != -1 && _oldSelector >= saves._savegameIndex && _oldSelector < (saves._savegameIndex + ONSCREEN_FILES_COUNT)) {
-			screen.print(Common::Point(6, CONTROLS_Y + 12 + (_oldSelector - saves._savegameIndex) * 10),
-				INV_FOREGROUND, "%d.", _oldSelector + 1);
-			screen.print(Common::Point(24, CONTROLS_Y + 12 + (_oldSelector - saves._savegameIndex) * 10),
-				INV_FOREGROUND, "%s", saves._savegames[_oldSelector].c_str());
-		}
-
-		if (_selector != -1) {
-			screen.print(Common::Point(6, CONTROLS_Y + 12 + (_selector - saves._savegameIndex) * 10),
-				TALK_FOREGROUND, "%d.", _selector + 1);
-			screen.print(Common::Point(24, CONTROLS_Y + 12 + (_selector - saves._savegameIndex) * 10),
-				TALK_FOREGROUND, "%s", saves._savegames[_selector].c_str());
-		}
-
-		_oldSelector = _selector;
-	}
-
-	if (events._released || _keyboardInput) {
-		if ((found == 0 && events._released) || _key == 'E') {
-			banishWindow();
-			_windowBounds.top = CONTROLS_Y1;
-
-			events._pressed = events._released = _keyboardInput = false;
-			_keyPress = '\0';
-		} else if ((found == 1 && events._released) || _key == 'L') {
-			saves._envMode = SAVEMODE_LOAD;
-			if (_selector != -1) {
-				saves.loadGame(_selector + 1);
-			}
-		} else if ((found == 2 && events._released) || _key == 'S') {
-			saves._envMode = SAVEMODE_SAVE;
-			if (_selector != -1) {
-				if (saves.checkGameOnScreen(_selector))
-					_oldSelector = _selector;
-
-				if (saves.promptForDescription(_selector)) {
-					saves.saveGame(_selector + 1, saves._savegames[_selector]);
-
-					banishWindow(1);
-					_windowBounds.top = CONTROLS_Y1;
-					_key = _oldKey = -1;
-					_keyPress = '\0';
-					_keyboardInput = false;
-				} else {
-					if (!talk._talkToAbort) {
-						screen._backBuffer1.fillRect(Common::Rect(6, CONTROLS_Y + 11 + (_selector - saves._savegameIndex) * 10,
-							SHERLOCK_SCREEN_WIDTH - 2, CONTROLS_Y + 20 + (_selector - saves._savegameIndex) * 10), INV_BACKGROUND);
-						screen.gPrint(Common::Point(6, CONTROLS_Y + 11 + (_selector - saves._savegameIndex) * 10), INV_FOREGROUND,
-							"%d.", _selector + 1);
-						screen.gPrint(Common::Point(24, CONTROLS_Y + 11 + (_selector - saves._savegameIndex) * 10), INV_FOREGROUND,
-							"%s", saves._savegames[_selector].c_str());
-
-						screen.slamArea(6, CONTROLS_Y + 11 + (_selector - saves._savegameIndex) * 10, 311, 10);
-						_selector = _oldSelector = -1;
-					}
-				}
-			}
-		} else if (((found == 3 && events._released) || _key == 'U') && saves._savegameIndex) {
-			bool moreKeys;
-			do {
-				saves._savegameIndex--;
-				screen._backBuffer1.fillRect(Common::Rect(3, CONTROLS_Y + 11, SHERLOCK_SCREEN_WIDTH - 2,
-					SHERLOCK_SCREEN_HEIGHT - 1), INV_BACKGROUND);
-
-				for (int idx = saves._savegameIndex; idx < (saves._savegameIndex + ONSCREEN_FILES_COUNT); ++idx) {
-					color = INV_FOREGROUND;
-					if (idx == _selector && idx >= saves._savegameIndex && idx < (saves._savegameIndex + ONSCREEN_FILES_COUNT))
-						color = TALK_FOREGROUND;
-
-					screen.gPrint(Common::Point(6, CONTROLS_Y + 11 + (idx - saves._savegameIndex) * 10), color, "%d.", idx + 1);
-					screen.gPrint(Common::Point(24, CONTROLS_Y + 11 + (idx - saves._savegameIndex) * 10), color, "%s", saves._savegames[idx].c_str());
-				}
-
-				screen.slamRect(Common::Rect(3, CONTROLS_Y + 11, SHERLOCK_SCREEN_WIDTH - 2, SHERLOCK_SCREEN_HEIGHT));
-
-				color = !saves._savegameIndex ? COMMAND_NULL : COMMAND_FOREGROUND;
-				screen.buttonPrint(Common::Point(ENV_POINTS[3][2], CONTROLS_Y), color, true, "Up");
-				color = (saves._savegameIndex == MAX_SAVEGAME_SLOTS - ONSCREEN_FILES_COUNT) ? COMMAND_NULL : COMMAND_FOREGROUND;
-				screen.buttonPrint(Common::Point(ENV_POINTS[4][2], CONTROLS_Y), color, true, "Down");
-
-				// Check whether there are more pending U keys pressed
-				moreKeys = false;
-				if (events.kbHit()) {
-					Common::KeyState keyState = events.getKey();
-
-					_key = toupper(keyState.keycode);
-					moreKeys = _key == 'U';
-				}
-			} while ((saves._savegameIndex) && moreKeys);
-		} else if (((found == 4 && events._released) || _key == 'D') && saves._savegameIndex < (MAX_SAVEGAME_SLOTS - ONSCREEN_FILES_COUNT)) {
-			bool moreKeys;
-			do {
-				saves._savegameIndex++;
-				screen._backBuffer1.fillRect(Common::Rect(3, CONTROLS_Y + 11, SHERLOCK_SCREEN_WIDTH - 2,
-					SHERLOCK_SCREEN_HEIGHT - 1), INV_BACKGROUND);
-
-				for (int idx = saves._savegameIndex; idx < (saves._savegameIndex + ONSCREEN_FILES_COUNT); ++idx) {
-					if (idx == _selector && idx >= saves._savegameIndex && idx < (saves._savegameIndex + ONSCREEN_FILES_COUNT))
-						color = TALK_FOREGROUND;
-					else
-						color = INV_FOREGROUND;
-
-					screen.gPrint(Common::Point(6, CONTROLS_Y + 11 + (idx - saves._savegameIndex) * 10), color,
-						"%d.", idx + 1);
-					screen.gPrint(Common::Point(24, CONTROLS_Y + 11 + (idx - saves._savegameIndex) * 10), color,
-						"%s", saves._savegames[idx].c_str());
-				}
-
-				screen.slamRect(Common::Rect(3, CONTROLS_Y + 11, SHERLOCK_SCREEN_WIDTH - 2, SHERLOCK_SCREEN_HEIGHT));
-
-				color = (!saves._savegameIndex) ? COMMAND_NULL : COMMAND_FOREGROUND;
-				screen.buttonPrint(Common::Point(ENV_POINTS[3][2], CONTROLS_Y), color, true, "Up");
-
-				color = (saves._savegameIndex == MAX_SAVEGAME_SLOTS - ONSCREEN_FILES_COUNT) ? COMMAND_NULL : COMMAND_FOREGROUND;
-				screen.buttonPrint(Common::Point(ENV_POINTS[4][2], CONTROLS_Y), color, true, "Down");
-
-				// Check whether there are more pending D keys pressed
-				moreKeys = false;
-				if (events.kbHit()) {
-					Common::KeyState keyState;
-					_key = toupper(keyState.keycode);
-
-					moreKeys = _key == 'D';
-				}
-			} while (saves._savegameIndex < (MAX_SAVEGAME_SLOTS - ONSCREEN_FILES_COUNT) && moreKeys);
-		} else if ((found == 5 && events._released) || _key == 'Q') {
-			clearWindow();
-			screen.print(Common::Point(0, CONTROLS_Y + 20), INV_FOREGROUND, "Are you sure you wish to Quit ?");
-			screen.vgaBar(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, CONTROLS_Y + 10), BORDER_COLOR);
-
-			screen.makeButton(Common::Rect(112, CONTROLS_Y, 160, CONTROLS_Y + 10), 136 - screen.stringWidth("Yes") / 2, "Yes");
-			screen.makeButton(Common::Rect(161, CONTROLS_Y, 209, CONTROLS_Y + 10), 184 - screen.stringWidth("No") / 2, "No");
-			screen.slamArea(112, CONTROLS_Y, 97, 10);
-
-			do {
-				scene.doBgAnim();
-
-				if (talk._talkToAbort)
-					return;
-
-				events.pollEventsAndWait();
-				events.setButtonState();
-				mousePos = events.mousePos();
-
-				if (events.kbHit()) {
-					Common::KeyState keyState = events.getKey();
-					_key = toupper(keyState.keycode);
-
-					if (_key == 'X' && (keyState.flags & Common::KBD_ALT) != 0) {
-						_vm->quitGame();
-						events.pollEvents();
-						return;
-					}
-
-					if (_key == Common::KEYCODE_ESCAPE)
-						_key = 'N';
-
-					if (_key == Common::KEYCODE_RETURN || _key == ' ') {
-						events._pressed = false;
-						events._released = true;
-						events._oldButtons = 0;
-						_keyPress = '\0';
-					}
-				}
-
-				if (events._pressed || events._released) {
-					if (mousePos.x > 112 && mousePos.x < 159 && mousePos.y > CONTROLS_Y && mousePos.y < (CONTROLS_Y + 9))
-						color = COMMAND_HIGHLIGHTED;
-					else
-						color = COMMAND_FOREGROUND;
-					screen.buttonPrint(Common::Point(136, CONTROLS_Y), color, true, "Yes");
-
-					if (mousePos.x > 161 && mousePos.x < 208 && mousePos.y > CONTROLS_Y && mousePos.y < (CONTROLS_Y + 9))
-						color = COMMAND_HIGHLIGHTED;
-					else
-						color = COMMAND_FOREGROUND;
-					screen.buttonPrint(Common::Point(184, CONTROLS_Y), color, true, "No");
-				}
-
-				if (mousePos.x > 112 && mousePos.x < 159 && mousePos.y > CONTROLS_Y && mousePos.y < (CONTROLS_Y + 9) && events._released)
-					_key = 'Y';
-
-				if (mousePos.x > 161 && mousePos.x < 208 && mousePos.y > CONTROLS_Y && mousePos.y < (CONTROLS_Y + 9) && events._released)
-					_key = 'N';
-			} while (!_vm->shouldQuit() && _key != 'Y' && _key != 'N');
-
-			if (_key == 'Y') {
-				_vm->quitGame();
-				events.pollEvents();
-				return;
-			} else {
-				screen.buttonPrint(Common::Point(184, CONTROLS_Y), COMMAND_HIGHLIGHTED, true, "No");
-				banishWindow(1);
-				_windowBounds.top = CONTROLS_Y1;
-				_key = -1;
-			}
-		} else {
-			if (_selector != -1) {
-				// Are we already in Load mode?
-				if (saves._envMode == SAVEMODE_LOAD) {
-					saves.loadGame(_selector + 1);
-				} else if (saves._envMode == SAVEMODE_SAVE || saves.isSlotEmpty(_selector)) {
-					// We're already in save mode, or pointing to an empty save slot
-					if (saves.checkGameOnScreen(_selector))
-						_oldSelector = _selector;
-
-					if (saves.promptForDescription(_selector)) {
-						saves.saveGame(_selector + 1, saves._savegames[_selector]);
-						banishWindow();
-						_windowBounds.top = CONTROLS_Y1;
-						_key = _oldKey = -1;
-						_keyPress = '\0';
-						_keyboardInput = false;
-					} else {
-						if (!talk._talkToAbort) {
-							screen._backBuffer1.fillRect(Common::Rect(6, CONTROLS_Y + 11 + (_selector - saves._savegameIndex) * 10,
-								317, CONTROLS_Y + 20 + (_selector - saves._savegameIndex) * 10), INV_BACKGROUND);
-							screen.gPrint(Common::Point(6, CONTROLS_Y + 11 + (_selector - saves._savegameIndex) * 10),
-								INV_FOREGROUND, "%d.", _selector + 1);
-							screen.gPrint(Common::Point(24, CONTROLS_Y + 11 + (_selector - saves._savegameIndex) * 10),
-								INV_FOREGROUND, "%s", saves._savegames[_selector].c_str());
-							screen.slamArea(6, CONTROLS_Y + 11 + (_selector - saves._savegameIndex) * 10, 311, 10);
-							_selector = _oldSelector = -1;
-						}
-					}
-				}
-			}
-		}
-	}
-}
-
-void ScalpelUserInterface::doInvControl() {
-	Events &events = *_vm->_events;
-	Inventory &inv = *_vm->_inventory;
-	Scene &scene = *_vm->_scene;
-	Screen &screen = *_vm->_screen;
-	Talk &talk = *_vm->_talk;
-	int colors[8];
-	Common::Point mousePos = events.mousePos();
-
-	_key = _oldKey = -1;
-	_keyboardInput = false;
-
-	// Check whether any inventory slot is highlighted
-	int found = -1;
-	Common::fill(&colors[0], &colors[8], (int)COMMAND_FOREGROUND);
-	for (int idx = 0; idx < 8; ++idx) {
-		Common::Rect r(INVENTORY_POINTS[idx][0], CONTROLS_Y1,
-			INVENTORY_POINTS[idx][1], CONTROLS_Y1 + 10);
-		if (r.contains(mousePos)) {
-			found = idx;
-			break;
-		}
-	}
-
-	if (events._pressed || events._released) {
-		events.clearKeyboard();
-
-		if (found != -1)
-			// If a slot highlighted, set its color
-			colors[found] = COMMAND_HIGHLIGHTED;
-		screen.buttonPrint(Common::Point(INVENTORY_POINTS[0][2], CONTROLS_Y1), colors[0], true, "Exit");
-
-		if (found >= 0 && found <= 3) {
-			screen.buttonPrint(Common::Point(INVENTORY_POINTS[1][2], CONTROLS_Y1), colors[1], true, "Look");
-			screen.buttonPrint(Common::Point(INVENTORY_POINTS[2][2], CONTROLS_Y1), colors[2], true, "Use");
-			screen.buttonPrint(Common::Point(INVENTORY_POINTS[3][2], CONTROLS_Y1), colors[3], true, "Give");
-			inv._invMode = (InvMode)found;
-			_selector = -1;
-		}
-
-		if (inv._invIndex) {
-			screen.print(Common::Point(INVENTORY_POINTS[4][2], CONTROLS_Y1 + 1), colors[4], "^^");
-			screen.print(Common::Point(INVENTORY_POINTS[5][2], CONTROLS_Y1 + 1), colors[5], "^");
-		}
-
-		if ((inv._holdings - inv._invIndex) > 6) {
-			screen.print(Common::Point(INVENTORY_POINTS[6][2], CONTROLS_Y1 + 1), colors[6], "_");
-			screen.print(Common::Point(INVENTORY_POINTS[7][2], CONTROLS_Y1 + 1), colors[7], "__");
-		}
-
-		bool flag = false;
-		if (inv._invMode == INVMODE_LOOK || inv._invMode == INVMODE_USE || inv._invMode == INVMODE_GIVE) {
-			Common::Rect r(15, CONTROLS_Y1 + 11, 314, SHERLOCK_SCREEN_HEIGHT - 2);
-			if (r.contains(mousePos)) {
-				_selector = (mousePos.x - 6) / 52 + inv._invIndex;
-				if (_selector < inv._holdings)
-					flag = true;
-			}
-		}
-
-		if (!flag && mousePos.y >(CONTROLS_Y1 + 11))
-			_selector = -1;
-	}
-
-	if (_keyPress) {
-		_key = toupper(_keyPress);
-
-		if (_key == Common::KEYCODE_ESCAPE)
-			// Escape will also 'E'xit out of inventory display
-			_key = 'E';
-
-		if (_key == 'E' || _key == 'L' || _key == 'U' || _key == 'G'
-				|| _key == '-' || _key == '+') {
-			InvMode temp = inv._invMode;
-
-			const char *chP = strchr(INVENTORY_COMMANDS, _key);
-			inv._invMode = !chP ? INVMODE_INVALID : (InvMode)(chP - INVENTORY_COMMANDS);
-			inv.invCommands(true);
-
-			inv._invMode = temp;
-			_keyboardInput = true;
-			if (_key == 'E')
-				inv._invMode = INVMODE_EXIT;
-			_selector = -1;
-		} else {
-			_selector = -1;
-		}
-	}
-
-	if (_selector != _oldSelector) {
-		if (_oldSelector != -1) {
-			// Un-highlight
-			if (_oldSelector >= inv._invIndex && _oldSelector < (inv._invIndex + 6))
-				inv.highlight(_oldSelector, BUTTON_MIDDLE);
-		}
-
-		if (_selector != -1)
-			inv.highlight(_selector, 235);
-
-		_oldSelector = _selector;
-	}
-
-	if (events._released || _keyboardInput) {
-		if ((found == 0 && events._released) || _key == 'E') {
-			inv.freeInv();
-			_infoFlag = true;
-			clearInfo();
-			banishWindow(false);
-			_key = -1;
-			events.clearEvents();
-			events.setCursor(ARROW);
-		} else if ((found == 1 && events._released) || (_key == 'L')) {
-			inv._invMode = INVMODE_LOOK;
-		} else if ((found == 2 && events._released) || (_key == 'U')) {
-			inv._invMode = INVMODE_USE;
-		} else if ((found == 3 && events._released) || (_key == 'G')) {
-			inv._invMode = INVMODE_GIVE;
-		} else if (((found == 4 && events._released) || _key == ',') && inv._invIndex) {
-			if (inv._invIndex >= 6)
-				inv._invIndex -= 6;
-			else
-				inv._invIndex = 0;
-
-			screen.print(Common::Point(INVENTORY_POINTS[4][2], CONTROLS_Y1 + 1),
-				COMMAND_HIGHLIGHTED, "^^");
-			inv.freeGraphics();
-			inv.loadGraphics();
-			inv.putInv(SLAM_DISPLAY);
-			inv.invCommands(true);
-		} else if (((found == 5 && events._released) || _key == '-') && inv._invIndex > 0) {
-			--inv._invIndex;
-			screen.print(Common::Point(INVENTORY_POINTS[4][2], CONTROLS_Y1 + 1), COMMAND_HIGHLIGHTED, "^");
-			inv.freeGraphics();
-			inv.loadGraphics();
-			inv.putInv(SLAM_DISPLAY);
-			inv.invCommands(true);
-		} else if (((found == 6 && events._released) || _key == '+') &&  (inv._holdings - inv._invIndex) > 6) {
-			++inv._invIndex;
-			screen.print(Common::Point(INVENTORY_POINTS[6][2], CONTROLS_Y1 + 1), COMMAND_HIGHLIGHTED, "_");
-			inv.freeGraphics();
-			inv.loadGraphics();
-			inv.putInv(SLAM_DISPLAY);
-			inv.invCommands(true);
-		} else if (((found == 7 && events._released) || _key == '.') && (inv._holdings - inv._invIndex) > 6) {
-			inv._invIndex += 6;
-			if ((inv._holdings - 6) < inv._invIndex)
-				inv._invIndex = inv._holdings - 6;
-
-			screen.print(Common::Point(INVENTORY_POINTS[7][2], CONTROLS_Y1 + 1), COMMAND_HIGHLIGHTED, "_");
-			inv.freeGraphics();
-			inv.loadGraphics();
-			inv.putInv(SLAM_DISPLAY);
-			inv.invCommands(true);
-		} else {
-			// If something is being given, make sure it's being given to a person
-			if (inv._invMode == INVMODE_GIVE) {
-				if (_bgFound != -1 && scene._bgShapes[_bgFound]._aType == PERSON)
-					_find = _bgFound;
-				else
-					_find = -1;
-			} else {
-				_find = _bgFound;
-			}
-
-			if ((mousePos.y < CONTROLS_Y1) && (inv._invMode == INVMODE_LOOK) && (_find >= 0) && (_find < 1000)) {
-				if (!scene._bgShapes[_find]._examine.empty() &&
-						scene._bgShapes[_find]._examine[0] >= ' ')
-					inv.refreshInv();
-			} else if (_selector != -1 || _find >= 0) {
-				// Selector is the inventory object that was clicked on, or selected.
-				// If it's -1, then no inventory item is highlighted yet. Otherwise,
-				// an object in the scene has been clicked.
-
-				if (_selector != -1 && inv._invMode == INVMODE_LOOK
-						&& mousePos.y >(CONTROLS_Y1 + 11))
-					inv.refreshInv();
-
-				if (talk._talkToAbort)
-					return;
-
-				// Now check for the Use and Give actions. If inv_mode is INVMODE_GIVE,
-				// that means GIVE is in effect, _selector is the object being
-				// given, and _find is the target.
-				// The same applies to USE, except if _selector is -1, then USE
-				// is being tried on an object in the scene without an inventory
-				// object being highlighted first.
-
-				if ((inv._invMode == INVMODE_USE || (_selector != -1 && inv._invMode == INVMODE_GIVE)) && _find >= 0) {
-					events._pressed = events._released = false;
-					_infoFlag = true;
-					clearInfo();
-
-					int tempSel = _selector;	// Save the selector
-					_selector = -1;
-
-					inv.putInv(SLAM_DISPLAY);
-					_selector = tempSel;		// Restore it
-					InvMode tempMode = inv._invMode;
-					inv._invMode = INVMODE_USE55;
-					inv.invCommands(true);
-
-					_infoFlag = true;
-					clearInfo();
-					banishWindow(false);
-					_key = -1;
-
-					inv.freeInv();
-
-					bool giveFl = (tempMode >= INVMODE_GIVE);
-					if (_selector >= 0)
-						// Use/Give inv object with scene object
-						checkUseAction(&scene._bgShapes[_find]._use[0], inv[_selector]._name, MUSE, _find, giveFl);
-					else
-						// Now inv object has been highlighted
-						checkUseAction(&scene._bgShapes[_find]._use[0], "*SELF*", MUSE, _find, giveFl);
-
-					_selector = _oldSelector = -1;
-				}
-			}
-		}
-	}
-}
-
-void ScalpelUserInterface::doLookControl() {
-	Events &events = *_vm->_events;
-	Inventory &inv = *_vm->_inventory;
-	Screen &screen = *_vm->_screen;
-
-	_key = _oldKey = -1;
-	_keyboardInput = (_keyPress != '\0');
-
-	if (events._released || events._rightReleased || _keyboardInput) {
-		// Is an inventory object being looked at?
-		if (!_invLookFlag) {
-			// Is there any remaining text to display?
-			if (!_descStr.empty()) {
-				printObjectDesc(_descStr, false);
-			} else if (!_lookHelp) {
-				// Need to close the window and depress the Look button
-				Common::Point pt(MENU_POINTS[0][0], MENU_POINTS[0][1]);
-				screen._backBuffer2.blitFrom((*_controls)[0], pt);
-				banishWindow(true);
-
-				_windowBounds.top = CONTROLS_Y1;
-				_key = _oldKey = COMMANDS[LOOK_MODE - 1];
-				_temp = _oldTemp = 0;
-				_menuMode = LOOK_MODE;
-				events.clearEvents();
-
-				// Restore UI
-				drawInterface();
-			} else {
-				events.setCursor(ARROW);
-				banishWindow(true);
-				_windowBounds.top = CONTROLS_Y1;
-				_key = _oldKey = -1;
-				_temp = _oldTemp = 0;
-				_menuMode = STD_MODE;
-				events.clearEvents();
-			}
-		} else {
-			// Looking at an inventory object
-			// Backup the user interface
-			Surface tempSurface(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT - CONTROLS_Y1);
-			tempSurface.blitFrom(screen._backBuffer2, Common::Point(0, 0),
-				Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
-
-			inv.drawInventory(INVENTORY_DONT_DISPLAY);
-			banishWindow(true);
-
-			// Restore the ui
-			screen._backBuffer2.blitFrom(tempSurface, Common::Point(0, CONTROLS_Y1));
-
-			_windowBounds.top = CONTROLS_Y1;
-			_key = _oldKey = COMMANDS[LOOK_MODE - 1];
-			_temp = _oldTemp = 0;
-			events.clearEvents();
-			_invLookFlag = false;
-			_menuMode = INV_MODE;
-			_windowOpen = true;
-		}
-	}
-}
-
-void ScalpelUserInterface::doMainControl() {
-	Events &events = *_vm->_events;
-	Inventory &inv = *_vm->_inventory;
-	SaveManager &saves = *_vm->_saves;
-	Common::Point pt = events.mousePos();
-
-	if ((events._pressed || events._released) && pt.y > CONTROLS_Y) {
-		events.clearKeyboard();
-		_key = -1;
-
-		// Check whether the mouse is in any of the command areas
-		for (_temp = 0; (_temp < 12) && (_key == -1); ++_temp) {
-			Common::Rect r(MENU_POINTS[_temp][0], MENU_POINTS[_temp][1],
-				MENU_POINTS[_temp][2], MENU_POINTS[_temp][3]);
-			if (r.contains(pt))
-				_key = COMMANDS[_temp];
-		}
-		--_temp;
-	} else if (_keyPress) {
-		// Keyboard control
-		_keyboardInput = true;
-
-		if (_keyPress >= 'A' && _keyPress <= 'Z') {
-			const char *c = strchr(COMMANDS, _keyPress);
-			_temp = !c ? 12 : c - COMMANDS;
-		} else {
-			_temp = 12;
-		}
-
-		if (_temp == 12)
-			_key = -1;
-
-		if (events._rightPressed) {
-			_temp = 12;
-			_key = -1;
-		}
-	} else if (!events._released) {
-		_key = -1;
-	}
-
-	// Check if the button being pointed to has changed
-	if (_oldKey != _key && !_windowOpen) {
-		// Clear the info line
-		_infoFlag = true;
-		clearInfo();
-
-		// If there was an old button selected, restore it
-		if (_oldKey != -1) {
-			_menuMode = STD_MODE;
-			restoreButton(_oldTemp);
-		}
-
-		// If a new button is being pointed to, highlight it
-		if (_key != -1 && _temp < 12 && !_keyboardInput)
-			depressButton(_temp);
-
-		// Save the new button selection
-		_oldKey = _key;
-		_oldTemp = _temp;
-	}
-
-	if (!events._pressed && !_windowOpen) {
-		switch (_key) {
-		case 'L':
-			toggleButton(0);
-			break;
-		case 'M':
-			toggleButton(1);
-			break;
-		case 'T':
-			toggleButton(2);
-			break;
-		case 'P':
-			toggleButton(3);
-			break;
-		case 'O':
-			toggleButton(4);
-			break;
-		case 'C':
-			toggleButton(5);
-			break;
-		case 'I':
-			pushButton(6);
-			_selector = _oldSelector = -1;
-			_menuMode = INV_MODE;
-			inv.drawInventory(PLAIN_INVENTORY);
-			break;
-		case 'U':
-			pushButton(7);
-			_selector = _oldSelector = -1;
-			_menuMode = USE_MODE;
-			inv.drawInventory(USE_INVENTORY_MODE);
-			break;
-		case 'G':
-			pushButton(8);
-			_selector = _oldSelector = -1;
-			_menuMode = GIVE_MODE;
-			inv.drawInventory(GIVE_INVENTORY_MODE);
-			break;
-		case 'J':
-			pushButton(9);
-			_menuMode = JOURNAL_MODE;
-			journalControl();
-			break;
-		case 'F':
-			pushButton(10);
-
-			// Create a thumbnail of the current screen before the files dialog is shown, in case
-			// the user saves the game
-			saves.createThumbnail();
-
-			_selector = _oldSelector = -1;
-
-			if (_vm->_showOriginalSavesDialog) {
-				// Show the original dialog
-				_menuMode = FILES_MODE;
-				saves.drawInterface();
-				_windowOpen = true;
-			} else {
-				// Show the ScummVM GMM instead
-				_vm->_canLoadSave = true;
-				_vm->openMainMenuDialog();
-				_vm->_canLoadSave = false;
-			}
-			break;
-		case 'S':
-			pushButton(11);
-			_menuMode = SETUP_MODE;
-			Settings::show(_vm);
-			break;
-		default:
-			break;
-		}
-
-		_help = _oldHelp = _oldBgFound = -1;
-	}
-}
-
-void ScalpelUserInterface::doMiscControl(int allowed) {
-	Events &events = *_vm->_events;
-	Scene &scene = *_vm->_scene;
-	Talk &talk = *_vm->_talk;
-
-	if (events._released) {
-		_temp = _bgFound;
-		if (_bgFound != -1) {
-			// Only allow pointing to objects, not people
-			if (_bgFound < 1000) {
-				events.clearEvents();
-				Object &obj = scene._bgShapes[_bgFound];
-
-				switch (allowed) {
-				case ALLOW_OPEN:
-					checkAction(obj._aOpen, MOPEN, _temp);
-					if (_menuMode != TALK_MODE && !talk._talkToAbort) {
-						_menuMode = STD_MODE;
-						restoreButton(OPEN_MODE - 1);
-						_key = _oldKey = -1;
-					}
-					break;
-
-				case ALLOW_CLOSE:
-					checkAction(obj._aClose, MCLOSE, _temp);
-					if (_menuMode != TALK_MODE && !talk._talkToAbort) {
-						_menuMode = STD_MODE;
-						restoreButton(CLOSE_MODE - 1);
-						_key = _oldKey = -1;
-					}
-					break;
-
-				case ALLOW_MOVE:
-					checkAction(obj._aMove, MMOVE, _temp);
-					if (_menuMode != TALK_MODE && !talk._talkToAbort) {
-						_menuMode = STD_MODE;
-						restoreButton(MOVE_MODE - 1);
-						_key = _oldKey = -1;
-					}
-					break;
-
-				default:
-					break;
-				}
-			}
-		}
-	}
-}
-
-void ScalpelUserInterface::doPickControl() {
-	Events &events = *_vm->_events;
-	Scene &scene = *_vm->_scene;
-	Talk &talk = *_vm->_talk;
-
-	if (events._released) {
-		if ((_temp = _bgFound) != -1) {
-			events.clearEvents();
-
-			// Don't allow characters to be picked up
-			if (_bgFound < 1000) {
-				scene._bgShapes[_bgFound].pickUpObject(MPICK);
-
-				if (!talk._talkToAbort && _menuMode != TALK_MODE) {
-					_key = _oldKey = -1;
-					_menuMode = STD_MODE;
-					restoreButton(PICKUP_MODE - 1);
-				}
-			}
-		}
-	}
-}
-
-void ScalpelUserInterface::doTalkControl() {
-	Events &events = *_vm->_events;
-	Journal &journal = *_vm->_journal;
-	People &people = *_vm->_people;
-	Screen &screen = *_vm->_screen;
-	Sound &sound = *_vm->_sound;
-	Talk &talk = *_vm->_talk;
-	Common::Point mousePos = events.mousePos();
-
-	_key = _oldKey = -1;
-	_keyboardInput = false;
-
-	if (events._pressed || events._released) {
-		events.clearKeyboard();
-
-		// Handle button printing
-		if (mousePos.x > 99 && mousePos.x < 138 && mousePos.y > CONTROLS_Y && mousePos.y < (CONTROLS_Y + 10) && !_endKeyActive)
-			screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_HIGHLIGHTED, true, "Exit");
-		else if (_endKeyActive)
-			screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_FOREGROUND, true, "Exit");
-
-		if (mousePos.x > 140 && mousePos.x < 170 && mousePos.y > CONTROLS_Y && mousePos.y < (CONTROLS_Y + 10) && talk._moreTalkUp)
-			screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_HIGHLIGHTED, true, "Up");
-		else if (talk._moreTalkUp)
-			screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_FOREGROUND, true, "Up");
-
-		if (mousePos.x > 181&& mousePos.x < 220 && mousePos.y > CONTROLS_Y && mousePos.y < (CONTROLS_Y + 10) && talk._moreTalkDown)
-			screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_HIGHLIGHTED, true, "Down");
-		else if (talk._moreTalkDown)
-			screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_FOREGROUND, true, "Down");
-
-		bool found = false;
-		for (_selector = talk._talkIndex; _selector < (int)talk._statements.size() && !found; ++_selector) {
-			if (mousePos.y > talk._statements[_selector]._talkPos.top &&
-					mousePos.y < talk._statements[_selector]._talkPos.bottom)
-				found = true;
-		}
-		--_selector;
-		if (!found)
-			_selector = -1;
-	}
-
-	if (_keyPress) {
-		_key = toupper(_keyPress);
-		if (_key == Common::KEYCODE_ESCAPE)
-			_key = 'E';
-
-		// Check for number press indicating reply line
-		if (_key >= '1' && _key <= ('1' + (int)talk._statements.size() - 1)) {
-			for (uint idx = 0; idx < talk._statements.size(); ++idx) {
-				if (talk._statements[idx]._talkMap == (_key - '1')) {
-					// Found the given statement
-					_selector = idx;
-					_key = -1;
-					_keyboardInput = true;
-					break;
-				}
-			}
-		} else if (_key == 'E' || _key == 'U' || _key == 'D') {
-			_keyboardInput = true;
-		} else {
-			_selector = -1;
-		}
-	}
-
-	if (_selector != _oldSelector) {
-		// Remove highlighting from previous line, if any
-		if (_oldSelector != -1) {
-			if (!((talk._talkHistory[talk._converseNum][_oldSelector] >> (_oldSelector & 7)) & 1))
-				talk.talkLine(_oldSelector, talk._statements[_oldSelector]._talkMap, INV_FOREGROUND,
-					talk._statements[_oldSelector]._talkPos.top, true);
-			else
-				talk.talkLine(_oldSelector, talk._statements[_oldSelector]._talkMap, TALK_NULL,
-					talk._statements[_oldSelector]._talkPos.top, true);
-		}
-
-		// Add highlighting to new line, if any
-		if (_selector != -1)
-			talk.talkLine(_selector, talk._statements[_selector]._talkMap, TALK_FOREGROUND,
-				talk._statements[_selector]._talkPos.top, true);
-
-		_oldSelector = _selector;
-	}
-
-	if (events._released || _keyboardInput) {
-		if (((Common::Rect(99, CONTROLS_Y, 138, CONTROLS_Y + 10).contains(mousePos) && events._released)
-				|| _key == 'E') && _endKeyActive) {
-			talk.freeTalkVars();
-			talk.pullSequence();
-			banishWindow();
-			_windowBounds.top = CONTROLS_Y1;
-		} else if (((Common::Rect(140, CONTROLS_Y, 179, CONTROLS_Y + 10).contains(mousePos) && events._released)
-				|| _key == 'U') && talk._moreTalkUp) {
-			while (talk._statements[--talk._talkIndex]._talkMap == -1)
-				;
-			screen._backBuffer1.fillRect(Common::Rect(5, CONTROLS_Y + 11, SHERLOCK_SCREEN_WIDTH - 2,
-				SHERLOCK_SCREEN_HEIGHT - 1), INV_BACKGROUND);
-			talk.displayTalk(false);
-
-			screen.slamRect(Common::Rect(5, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH - 5, SHERLOCK_SCREEN_HEIGHT - 2));
-		} else if (((Common::Rect(181, CONTROLS_Y, 220, CONTROLS_Y + 10).contains(mousePos) && events._released)
-				|| _key == 'D') && talk._moreTalkDown) {
-			do {
-				++talk._talkIndex;
-			} while (talk._talkIndex < (int)talk._statements.size() && talk._statements[talk._talkIndex]._talkMap == -1);
-
-			screen._backBuffer1.fillRect(Common::Rect(5, CONTROLS_Y + 11, SHERLOCK_SCREEN_WIDTH - 2,
-				SHERLOCK_SCREEN_HEIGHT - 1), INV_BACKGROUND);
-			talk.displayTalk(false);
-
-			screen.slamRect(Common::Rect(5, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH - 5, SHERLOCK_SCREEN_HEIGHT - 2));
-		} else if (_selector != -1) {
-			screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_NULL, true, "Exit");
-			screen.buttonPrint(Common::Point(159, CONTROLS_Y), COMMAND_NULL, true, "Up");
-			screen.buttonPrint(Common::Point(200, CONTROLS_Y), COMMAND_NULL, true, "Down");
-
-			// If the reply is new, add it to the journal
-			if (!talk._talkHistory[talk._converseNum][_selector]) {
-				journal.record(talk._converseNum, _selector);
-
-				// Add any Holmes point to Holmes' total, if any
-				if (talk._statements[_selector]._quotient)
-					people._holmesQuotient += talk._statements[_selector]._quotient;
-			}
-
-			// Flag the response as having been used
-			talk._talkHistory[talk._converseNum][_selector] = true;
-
-			clearWindow();
-			screen.print(Common::Point(16, CONTROLS_Y + 12), TALK_FOREGROUND, "Sherlock Holmes");
-			talk.talkLine(_selector + 128, talk._statements[_selector]._talkMap, COMMAND_FOREGROUND, CONTROLS_Y + 21, true);
-
-			switch (talk._statements[_selector]._portraitSide & 3) {
-			case 0:
-			case 1:
-				people._portraitSide = 20;
-				break;
-			case 2:
-				people._portraitSide = 220;
-				break;
-			case 3:
-				people._portraitSide = 120;
-				break;
-			}
-
-			// Check for flipping Holmes
-			if (talk._statements[_selector]._portraitSide & REVERSE_DIRECTION)
-				people._holmesFlip = true;
-
-			talk._speaker = 0;
-			people.setTalking(0);
-
-			if (!talk._statements[_selector]._voiceFile.empty() && sound._voices) {
-				sound.playSound(talk._statements[_selector]._voiceFile, WAIT_RETURN_IMMEDIATELY);
-
-				// Set voices as an indicator for waiting
-				sound._voices = 2;
-				sound._speechOn = *sound._soundIsOn;
-			} else {
-				sound._speechOn = false;
-			}
-
-			talk.waitForMore(talk._statements[_selector]._statement.size());
-			if (talk._talkToAbort)
-				return;
-
-			people.clearTalking();
-			if (talk._talkToAbort)
-				return;
-
-			while (!_vm->shouldQuit()) {
-				talk._scriptSelect = _selector;
-				talk._speaker = talk._talkTo;
-				talk.doScript(talk._statements[_selector]._reply);
-
-				if (!talk._talkToAbort) {
-					if (!talk._talkStealth)
-						clearWindow();
-
-					if (!talk._statements[_selector]._modified.empty()) {
-						for (uint idx = 0; idx < talk._statements[_selector]._modified.size(); ++idx) {
-							_vm->setFlags(talk._statements[_selector]._modified[idx]);
-						}
-
-						talk.setTalkMap();
-					}
-
-					// Check for another linked talk file
-					Common::String linkFilename = talk._statements[_selector]._linkFile;
-					if (!linkFilename.empty() && !talk._scriptMoreFlag) {
-						talk.freeTalkVars();
-						talk.loadTalkFile(linkFilename);
-
-						// Find the first new statement
-						int select = _selector = _oldSelector = -1;
-						for (uint idx = 0; idx < talk._statements.size() && select == -1; ++idx) {
-							if (!talk._statements[idx]._talkMap)
-								select = talk._talkIndex = idx;
-						}
-
-						// See if the new statement is a stealth reply
-						talk._talkStealth = talk._statements[select]._statement.hasPrefix("^") ? 2 : 0;
-
-						// Is the new talk file a standard file, reply first file, or a stealth file
-						if (!talk._statements[select]._statement.hasPrefix("*") &&
-								!talk._statements[select]._statement.hasPrefix("^")) {
-							// Not a reply first file, so display the new selections
-							if (_endKeyActive)
-								screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_FOREGROUND, true, "Exit");
-							else
-								screen.buttonPrint(Common::Point(119, CONTROLS_Y), COMMAND_NULL, true, "Exit");
-
-							talk.displayTalk(true);
-							events.setCursor(ARROW);
-							break;
-						} else {
-							_selector = select;
-
-							if (!talk._talkHistory[talk._converseNum][_selector])
-								journal.record(talk._converseNum, _selector);
-
-							talk._talkHistory[talk._converseNum][_selector] = true;
-						}
-					} else {
-						talk.freeTalkVars();
-						talk.pullSequence();
-						banishWindow();
-						_windowBounds.top = CONTROLS_Y1;
-						break;
-					}
-				} else {
-					break;
-				}
-			}
-
-			events._pressed = events._released = false;
-			events._oldButtons = 0;
-			talk._talkStealth = 0;
-
-			// If a script was pushed onto the script stack, restore it
-			if (!talk._scriptStack.empty()) {
-				ScriptStackEntry stackEntry = talk._scriptStack.pop();
-				talk._scriptName = stackEntry._name;
-				talk._scriptSaveIndex = stackEntry._currentIndex;
-				talk._scriptSelect = stackEntry._select;
-			}
-		}
-	}
-}
-
-void ScalpelUserInterface::journalControl() {
-	Events &events = *_vm->_events;
-	Journal &journal = *_vm->_journal;
-	Scene &scene = *_vm->_scene;
-	Screen &screen = *_vm->_screen;
-	bool doneFlag = false;
-
-	// Draw the journal screen
-	journal.drawInterface();
-
-	// Handle journal events
-	do {
-		_key = -1;
-		events.setButtonState();
-
-		// Handle keypresses
-		if (events.kbHit()) {
-			Common::KeyState keyState = events.getKey();
-			if (keyState.keycode == Common::KEYCODE_x && (keyState.flags & Common::KBD_ALT)) {
-				_vm->quitGame();
-				return;
-			} else if (keyState.keycode == Common::KEYCODE_e || keyState.keycode == Common::KEYCODE_ESCAPE) {
-				doneFlag = true;
-			} else {
-				_key = toupper(keyState.keycode);
-			}
-		}
-
-		if (!doneFlag)
-			doneFlag = journal.handleEvents(_key);
-	} while (!_vm->shouldQuit() && !doneFlag);
-
-	// Finish up
-	_infoFlag = _keyboardInput = false;
-	_keyPress = '\0';
-	_windowOpen = false;
-	_windowBounds.top = CONTROLS_Y1;
-	_key = -1;
-	_menuMode = STD_MODE;
-
-	// Reset the palette
-	screen.setPalette(screen._cMap);
-
-	screen._backBuffer1.blitFrom(screen._backBuffer2);
-	scene.updateBackground();
-	screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
-}
-
-void ScalpelUserInterface::printObjectDesc(const Common::String &str, bool firstTime) {
-	Events &events = *_vm->_events;
-	Inventory &inv = *_vm->_inventory;
-	Screen &screen = *_vm->_screen;
-	Talk &talk = *_vm->_talk;
-
-	if (str.hasPrefix("_")) {
-		_lookScriptFlag = true;
-		events.setCursor(MAGNIFY);
-		int savedSelector = _selector;
-		talk.talkTo(str.c_str() + 1);
-		_lookScriptFlag = false;
-
-		if (talk._talkToAbort) {
-			events.setCursor(ARROW);
-			return;
-		}
-
-		// Check if looking at an inventory object
-		if (!_invLookFlag) {
-			// See if this look was called by a right button click or not
-			if (!_lookHelp) {
-				// If it wasn't a right button click, then we need depress
-				// the look button before we close the window. So save a copy of the
-				// menu area, and draw the controls onto it
-				Surface tempSurface((*_controls)[0]._frame.w, (*_controls)[0]._frame.h);
-				Common::Point pt(MENU_POINTS[0][0], MENU_POINTS[0][1]);
-
-				tempSurface.blitFrom(screen._backBuffer2, Common::Point(0, 0),
-					Common::Rect(pt.x, pt.y, pt.x + tempSurface.w(), pt.y + tempSurface.h()));
-				screen._backBuffer2.transBlitFrom((*_controls)[0], pt);
-
-				banishWindow(1);
-				events.setCursor(MAGNIFY);
-				_windowBounds.top = CONTROLS_Y1;
-				_key = _oldKey = COMMANDS[LOOK_MODE - 1];
-				_temp = _oldTemp = 0;
-				_menuMode = LOOK_MODE;
-				events.clearEvents();
-
-				screen._backBuffer2.blitFrom(tempSurface, pt);
-			} else {
-				events.setCursor(ARROW);
-				banishWindow(true);
-				_windowBounds.top = CONTROLS_Y1;
-				_key = _oldKey = -1;
-				_temp = _oldTemp = 0;
-				_menuMode = STD_MODE;
-				_lookHelp = 0;
-				events.clearEvents();
-			}
-		} else {
-			// Looking at an inventory object
-			_selector = _oldSelector = savedSelector;
-
-			// Reload the inventory graphics and draw the inventory
-			inv.loadInv();
-			inv.putInv(SLAM_SECONDARY_BUFFER);
-			inv.freeInv();
-			banishWindow(1);
-
-			_windowBounds.top = CONTROLS_Y1;
-			_key = _oldKey = COMMANDS[INV_MODE - 1];
-			_temp = _oldTemp = 0;
-			events.clearEvents();
-
-			_invLookFlag = 0;
-			_menuMode = INV_MODE;
-			_windowOpen = true;
-		}
-
-		return;
-	}
-
-	Surface &bb = *screen._backBuffer;
-	if (firstTime) {
-		// Only draw the border on the first call
-		_infoFlag = true;
-		clearInfo();
-
-		bb.fillRect(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH,
-			CONTROLS_Y1 + 10), BORDER_COLOR);
-		bb.fillRect(Common::Rect(0, CONTROLS_Y + 10, 1, SHERLOCK_SCREEN_HEIGHT - 1),
-			BORDER_COLOR);
-		bb.fillRect(Common::Rect(SHERLOCK_SCREEN_WIDTH - 2, CONTROLS_Y + 10,
-			SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT), BORDER_COLOR);
-		bb.fillRect(Common::Rect(0, SHERLOCK_SCREEN_HEIGHT - 1, SHERLOCK_SCREEN_WIDTH,
-			SHERLOCK_SCREEN_HEIGHT), BORDER_COLOR);
-	}
-
-	// Clear background
-	bb.fillRect(Common::Rect(2, CONTROLS_Y + 10, SHERLOCK_SCREEN_WIDTH - 2,
-		SHERLOCK_SCREEN_HEIGHT - 2), INV_BACKGROUND);
-
-	_windowBounds.top = CONTROLS_Y;
-	events.clearEvents();
-
-	// Loop through displaying up to five lines
-	bool endOfStr = false;
-	const char *msgP = str.c_str();
-	for (int lineNum = 0; lineNum < ONSCREEN_FILES_COUNT && !endOfStr; ++lineNum) {
-		int width = 0;
-		const char *lineStartP = msgP;
-
-		// Determine how much can be displayed on the line
-		do {
-			width += screen.charWidth(*msgP++);
-		} while (width < 300 && *msgP);
-
-		if (*msgP)
-			--msgP;
-		else
-			endOfStr = true;
-
-		// If the line needs to be wrapped, scan backwards to find
-		// the end of the previous word as a splitting point
-		if (width >= 300) {
-			while (*msgP != ' ')
-				--msgP;
-			endOfStr = false;
-		}
-
-		// Print out the line
-		Common::String line(lineStartP, msgP);
-		screen.gPrint(Common::Point(16, CONTROLS_Y + 12 + lineNum * 9),
-			INV_FOREGROUND, "%s", line.c_str());
-
-		if (!endOfStr)
-			// Start next line at start of the nxet word after space
-			++msgP;
-	}
-
-	// Handle display depending on whether all the message was shown
-	if (!endOfStr) {
-		screen.makeButton(Common::Rect(46, CONTROLS_Y, 272, CONTROLS_Y + 10),
-			(SHERLOCK_SCREEN_WIDTH - screen.stringWidth(PRESS_KEY_FOR_MORE)) / 2,
-			PRESS_KEY_FOR_MORE);
-		screen.gPrint(Common::Point((SHERLOCK_SCREEN_WIDTH -
-			screen.stringWidth(PRESS_KEY_FOR_MORE)) / 2, CONTROLS_Y),
-			COMMAND_FOREGROUND, "P");
-		_descStr = msgP;
-	} else {
-		screen.makeButton(Common::Rect(46, CONTROLS_Y, 272, CONTROLS_Y + 10),
-			(SHERLOCK_SCREEN_WIDTH - screen.stringWidth(PRESS_KEY_TO_CONTINUE)) / 2,
-			PRESS_KEY_TO_CONTINUE);
-		screen.gPrint(Common::Point((SHERLOCK_SCREEN_WIDTH -
-			screen.stringWidth(PRESS_KEY_TO_CONTINUE)) / 2, CONTROLS_Y),
-			COMMAND_FOREGROUND, "P");
-		_descStr = "";
-	}
-
-	if (firstTime) {
-		if (!_slideWindows) {
-			screen.slamRect(Common::Rect(0, CONTROLS_Y,
-				SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
-		} else {
-			// Display the window
-			summonWindow();
-		}
-
-		_selector = _oldSelector = -1;
-		_windowOpen = true;
-	} else {
-		screen.slamRect(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH,
-			SHERLOCK_SCREEN_HEIGHT));
-	}
-}
-
-void ScalpelUserInterface::printObjectDesc() {
-	printObjectDesc(_cAnimStr, true);
-}
-
-void ScalpelUserInterface::summonWindow(const Surface &bgSurface, bool slideUp) {
-	Events &events = *_vm->_events;
-	Screen &screen = *_vm->_screen;
-
-	if (_windowOpen)
-		// A window is already open, so can't open another one
-		return;
-
-	if (slideUp) {
-		// Gradually slide up the display of the window
-		for (int idx = 1; idx <= bgSurface.h(); idx += 2) {
-			screen._backBuffer->blitFrom(bgSurface, Common::Point(0, SHERLOCK_SCREEN_HEIGHT - idx),
-				Common::Rect(0, 0, bgSurface.w(), idx));
-			screen.slamRect(Common::Rect(0, SHERLOCK_SCREEN_HEIGHT - idx,
-				SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
-
-			events.delay(10);
-		}
-	} else {
-		// Gradually slide down the display of the window
-		for (int idx = 1; idx <= bgSurface.h(); idx += 2) {
-			screen._backBuffer->blitFrom(bgSurface,
-				Common::Point(0, SHERLOCK_SCREEN_HEIGHT - bgSurface.h()),
-				Common::Rect(0, bgSurface.h() - idx, bgSurface.w(), bgSurface.h()));
-			screen.slamRect(Common::Rect(0, SHERLOCK_SCREEN_HEIGHT - bgSurface.h(),
-				SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT - bgSurface.h() + idx));
-
-			events.delay(10);
-		}
-	}
-
-	// Final display of the entire window
-	screen._backBuffer->blitFrom(bgSurface, Common::Point(0, SHERLOCK_SCREEN_HEIGHT - bgSurface.h()),
-		Common::Rect(0, 0, bgSurface.w(), bgSurface.h()));
-	screen.slamArea(0, SHERLOCK_SCREEN_HEIGHT - bgSurface.h(), bgSurface.w(), bgSurface.h());
-
-	_windowOpen = true;
-}
-
-void ScalpelUserInterface::summonWindow(bool slideUp, int height) {
-	Screen &screen = *_vm->_screen;
-
-	// Extract the window that's been drawn on the back buffer
-	Surface tempSurface(SHERLOCK_SCREEN_WIDTH,
-		(SHERLOCK_SCREEN_HEIGHT - height));
-	Common::Rect r(0, height, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
-	tempSurface.blitFrom(screen._backBuffer1, Common::Point(0, 0), r);
-
-	// Remove drawn window with original user interface
-	screen._backBuffer1.blitFrom(screen._backBuffer2,
-		Common::Point(0, height), r);
-
-	// Display the window gradually on-screen
-	summonWindow(tempSurface, slideUp);
-}
-
-void ScalpelUserInterface::banishWindow(bool slideUp) {
-	Events &events = *_vm->_events;
-	Screen &screen = *_vm->_screen;
-
-	if (_windowOpen) {
-		if (slideUp || !_slideWindows) {
-			// Slide window down
-			// Only slide the window if the window style allows it
-			if (_slideWindows) {
-				for (int idx = 2; idx < (SHERLOCK_SCREEN_HEIGHT - CONTROLS_Y); idx += 2) {
-					// Shift the window down by 2 lines
-					byte *pSrc = (byte *)screen._backBuffer1.getBasePtr(0, CONTROLS_Y + idx - 2);
-					byte *pSrcEnd = (byte *)screen._backBuffer1.getBasePtr(0, SHERLOCK_SCREEN_HEIGHT - 2);
-					byte *pDest = (byte *)screen._backBuffer1.getBasePtr(0, SHERLOCK_SCREEN_HEIGHT);
-					Common::copy_backward(pSrc, pSrcEnd, pDest);
-
-					// Restore lines from the ui in the secondary back buffer
-					screen._backBuffer1.blitFrom(screen._backBuffer2,
-						Common::Point(0, CONTROLS_Y),
-						Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, CONTROLS_Y + idx));
-
-					screen.slamArea(0, CONTROLS_Y + idx - 2, SHERLOCK_SCREEN_WIDTH,
-						SHERLOCK_SCREEN_HEIGHT - CONTROLS_Y - idx + 2);
-					events.delay(10);
-				}
-
-				// Restore final two old lines
-				screen._backBuffer1.blitFrom(screen._backBuffer2,
-					Common::Point(0, SHERLOCK_SCREEN_HEIGHT - 2),
-					Common::Rect(0, SHERLOCK_SCREEN_HEIGHT - 2,
-						SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
-				screen.slamArea(0, SHERLOCK_SCREEN_HEIGHT - 2, SHERLOCK_SCREEN_WIDTH, 2);
-			} else {
-				// Restore old area to completely erase window
-				screen._backBuffer1.blitFrom(screen._backBuffer2,
-					Common::Point(0, CONTROLS_Y),
-					Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
-				screen.slamRect(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH,
-					SHERLOCK_SCREEN_HEIGHT));
-			}
-		} else {
-			// Slide the original user interface up to cover the dialog
-			for (int idx = 1; idx < (SHERLOCK_SCREEN_HEIGHT - CONTROLS_Y1); idx += 2) {
-				byte *pSrc = (byte *)screen._backBuffer2.getBasePtr(0, CONTROLS_Y1);
-				byte *pSrcEnd = (byte *)screen._backBuffer2.getBasePtr(0, CONTROLS_Y1 + idx);
-				byte *pDest = (byte *)screen._backBuffer1.getBasePtr(0, SHERLOCK_SCREEN_HEIGHT - idx);
-				Common::copy(pSrc, pSrcEnd, pDest);
-
-				screen.slamArea(0, SHERLOCK_SCREEN_HEIGHT - idx, SHERLOCK_SCREEN_WIDTH,
-					SHERLOCK_SCREEN_HEIGHT);
-				events.delay(10);
-			}
-
-			// Show entire final area
-			screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(0, CONTROLS_Y1),
-				Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
-			screen.slamRect(Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
-		}
-
-		_infoFlag = false;
-		_windowOpen = false;
-	}
-
-	_menuMode = STD_MODE;
-}
-
-void ScalpelUserInterface::checkUseAction(const UseType *use, const Common::String &invName,
-		const char *const messages[], int objNum, bool giveMode) {
-	Events &events = *_vm->_events;
-	Inventory &inv = *_vm->_inventory;
-	Scene &scene = *_vm->_scene;
-	Screen &screen = *_vm->_screen;
-	Talk &talk = *_vm->_talk;
-	bool printed = messages == nullptr;
-
-	if (objNum >= 1000) {
-		// Holmes was specified, so do nothing
-		_infoFlag = true;
-		clearInfo();
-		_infoFlag = true;
-
-		// Display error message
-		_menuCounter = 30;
-		screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "You can't do that to yourself.");
-		return;
-	}
-
-	// Scan for target item
-	int targetNum = -1;
-	if (giveMode) {
-		for (int idx = 0; idx < USE_COUNT && targetNum == -1; ++idx) {
-			if ((use[idx]._target.equalsIgnoreCase("*GIVE*") || use[idx]._target.equalsIgnoreCase("*GIVEP*"))
-					&& use[idx]._names[0].equalsIgnoreCase(invName)) {
-				// Found a match
-				targetNum = idx;
-				if (use[idx]._target.equalsIgnoreCase("*GIVE*"))
-					inv.deleteItemFromInventory(invName);
-			}
-		}
-	} else {
-		for (int idx = 0; idx < USE_COUNT && targetNum == -1; ++idx) {
-			if (use[idx]._target.equalsIgnoreCase(invName))
-				targetNum = idx;
-		}
-	}
-
-	if (targetNum != -1) {
-		// Found a target, so do the action
-		const UseType &action = use[targetNum];
-
-		events.setCursor(WAIT);
-
-		if (action._useFlag)
-			_vm->setFlags(action._useFlag);
-
-		if (action._cAnimNum != 99) {
-			if (action._cAnimNum == 0)
-				scene.startCAnim(9, action._cAnimSpeed);
-			else
-				scene.startCAnim(action._cAnimNum - 1, action._cAnimSpeed);
-		}
-
-		if (!talk._talkToAbort) {
-			Object &obj = scene._bgShapes[objNum];
-			for (int idx = 0; idx < NAMES_COUNT && !talk._talkToAbort; ++idx) {
-				if (obj.checkNameForCodes(action._names[idx], messages)) {
-					if (!talk._talkToAbort)
-						printed = true;
-				}
-			}
-
-			// Print "Done..." as an ending, unless flagged for leaving scene or otherwise flagged
-			if (scene._goToScene != 1 && !printed && !talk._talkToAbort) {
-				_infoFlag = true;
-				clearInfo();
-				screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "Done...");
-				_menuCounter = 25;
-			}
-		}
-	} else {
-		// Couldn't find target, so print error
-		_infoFlag = true;
-		clearInfo();
-
-		if (giveMode) {
-			screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "No, thank you.");
-		} else if (messages == nullptr) {
-			screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "You can't do that.");
-		} else {
-			screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", messages[0]);
-		}
-
-		_infoFlag = true;
-		_menuCounter = 30;
-	}
-
-	events.setCursor(ARROW);
-}
-
-void ScalpelUserInterface::checkAction(ActionType &action, const char *const messages[], int objNum) {
-	Events &events = *_vm->_events;
-	People &people = *_vm->_people;
-	Scene &scene = *_vm->_scene;
-	Screen &screen = *_vm->_screen;
-	Talk &talk = *_vm->_talk;
-	Common::Point pt(-1, -1);
-
-	if (objNum >= 1000)
-		// Ignore actions done on characters
-		return;
-
-	if (!action._cAnimSpeed) {
-		// Invalid action, to print error message
-		_infoFlag = true;
-		clearInfo();
-		screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "%s", messages[action._cAnimNum]);
-		_infoFlag = true;
-
-		// Set how long to show the message
-		_menuCounter = 30;
-	} else {
-		Object &obj = scene._bgShapes[objNum];
-
-		int cAnimNum;
-		if (action._cAnimNum == 0)
-			// Really a 10
-			cAnimNum = 9;
-		else
-			cAnimNum = action._cAnimNum - 1;
-
-		int dir = -1;
-		if (action._cAnimNum != 99) {
-			CAnim &anim = scene._cAnim[cAnimNum];
-
-			if (action._cAnimNum != 99) {
-				if (action._cAnimSpeed & REVERSE_DIRECTION) {
-					pt = anim._teleportPos;
-					dir = anim._teleportDir;
-				} else {
-					pt = anim._goto;
-					dir = anim._gotoDir;
-				}
-			}
-		} else {
-			pt = Common::Point(-1, -1);
-			dir = -1;
-		}
-
-		// Has a value, so do action
-		// Show wait cursor whilst walking to object and doing action
-		events.setCursor(WAIT);
-		bool printed = false;
-
-		for (int nameIdx = 0; nameIdx < NAMES_COUNT; ++nameIdx) {
-			if (action._names[nameIdx].hasPrefix("*") && action._names[nameIdx].size() >= 2
-					&& toupper(action._names[nameIdx][1]) == 'W') {
-				if (obj.checkNameForCodes(Common::String(action._names[nameIdx].c_str() + 2), messages)) {
-					if (!talk._talkToAbort)
-						printed = true;
-				}
-			}
-		}
-
-		bool doCAnim = true;
-		for (int nameIdx = 0; nameIdx < NAMES_COUNT; ++nameIdx) {
-			if (action._names[nameIdx].hasPrefix("*") && action._names[nameIdx].size() >= 2) {
-				char ch = toupper(action._names[nameIdx][1]);
-
-				if (ch == 'T' || ch == 'B') {
-					printed = true;
-					if (pt.x != -1)
-						// Holmes needs to walk to object before the action is done
-						people.walkToCoords(pt, dir);
-
-					if (!talk._talkToAbort) {
-						// Ensure Holmes is on the exact intended location
-						people[AL]._position = pt;
-						people[AL]._sequenceNumber = dir;
-						people.gotoStand(people[AL]);
-
-						talk.talkTo(action._names[nameIdx].c_str() + 2);
-						if (ch == 'T')
-							doCAnim = false;
-					}
-				}
-			}
-		}
-
-		if (doCAnim && !talk._talkToAbort) {
-			if (pt.x != -1)
-				// Holmes needs to walk to object before the action is done
-				people.walkToCoords(pt, dir);
-		}
-
-		for (int nameIdx = 0; nameIdx < NAMES_COUNT; ++nameIdx) {
-			if (action._names[nameIdx].hasPrefix("*") && action._names[nameIdx].size() >= 2
-					&& toupper(action._names[nameIdx][1]) == 'F') {
-				if (obj.checkNameForCodes(action._names[nameIdx].c_str() + 2, messages)) {
-					if (!talk._talkToAbort)
-						printed = true;
-				}
-			}
-		}
-
-		if (doCAnim && !talk._talkToAbort && action._cAnimNum != 99)
-			scene.startCAnim(cAnimNum, action._cAnimSpeed);
-
-		if (!talk._talkToAbort) {
-			for (int nameIdx = 0; nameIdx < NAMES_COUNT && !talk._talkToAbort; ++nameIdx) {
-				if (obj.checkNameForCodes(action._names[nameIdx], messages)) {
-					if (!talk._talkToAbort)
-						printed = true;
-				}
-			}
-
-			// Unless we're leaving the scene, print a "Done" message unless the printed flag has been set
-			if (scene._goToScene != 1 && !printed && !talk._talkToAbort) {
-				_infoFlag = true;
-				clearInfo();
-				screen.print(Common::Point(0, INFO_LINE + 1), INFO_FOREGROUND, "Done...");
-
-				// Set how long to show the message
-				_menuCounter = 30;
-			}
-		}
-	}
-
-	// Reset cursor back to arrow
-	events.setCursor(ARROW);
-}
-
-}
-
-/*----------------------------------------------------------------*/
-
-namespace Tattoo {
-
-TattooUserInterface::TattooUserInterface(SherlockEngine *vm): UserInterface(vm) {
-	_menuBuffer = nullptr;
-	_invMenuBuffer = nullptr;
-}
-
-void TattooUserInterface::handleInput() {
-	// TODO
-	_vm->_events->pollEventsAndWait();
-}
-
-void TattooUserInterface::doBgAnimRestoreUI() {
-	TattooScene &scene = *((TattooScene *)_vm->_scene);
-	Screen &screen = *_vm->_screen;
-
-	// If _oldMenuBounds was set, then either a new menu has been opened or the current menu has been closed.
-	// Either way, we need to restore the area where the menu was displayed
-	if (_oldMenuBounds.width() > 0)
-		screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_oldMenuBounds.left, _oldMenuBounds.top),
-			_oldMenuBounds);
-
-	if (_oldInvMenuBounds.width() > 0)
-		screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_oldInvMenuBounds.left, _oldInvMenuBounds.top),
-			_oldInvMenuBounds);
-
-	if (_menuBuffer != nullptr)
-		screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_menuBounds.left, _menuBounds.top), _menuBounds);
-	if (_invMenuBuffer != nullptr)
-		screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_invMenuBounds.left, _invMenuBounds.top), _invMenuBounds);
-
-	// If there is a Text Tag being display, restore the area underneath it
-	if (_oldTagBounds.width() > 0)
-		screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_oldTagBounds.left, _oldTagBounds.top), 
-			_oldTagBounds);
-
-	// If there is an Inventory being shown, restore the graphics underneath it
-	if (_oldInvGraphicBounds.width() > 0)
-		screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_oldInvGraphicBounds.left, _oldInvGraphicBounds.top), 
-			_oldInvGraphicBounds);
-
-	// If a canimation is active, restore the graphics underneath it
-	if (scene._activeCAnim._images != nullptr)
-		screen.restoreBackground(scene._activeCAnim._oldBounds);
-
-	// If a canimation just ended, remove it's graphics from the backbuffer
-	if (scene._activeCAnim._removeBounds.width() > 0)
-		screen.restoreBackground(scene._activeCAnim._removeBounds);
-}
-
-void TattooUserInterface::doScroll() {
-	Screen &screen = *_vm->_screen;
-	int oldScroll = screen._currentScroll;
-
-	// If we're already at the target scroll position, nothing needs to be done
-	if (screen._targetScroll == screen._currentScroll)
-		return;
-
-	screen._flushScreen = true;
-	if (screen._targetScroll > screen._currentScroll) {
-		screen._currentScroll += screen._scrollSpeed;
-		if (screen._currentScroll > screen._targetScroll)
-			screen._currentScroll = screen._targetScroll;
-	} else if (screen._targetScroll < screen._currentScroll) {
-		screen._currentScroll -= screen._scrollSpeed;
-		if (screen._currentScroll < screen._targetScroll)
-			screen._currentScroll = screen._targetScroll;
-	}
-
-	if (_menuBuffer != nullptr)
-		_menuBounds.translate(screen._currentScroll - oldScroll, 0);
-	if (_invMenuBuffer != nullptr)
-		_invMenuBounds.translate(screen._currentScroll - oldScroll, 0);
-}
-
-} // End of namespace Tattoo
-
 } // End of namespace Sherlock
diff --git a/engines/sherlock/user_interface.h b/engines/sherlock/user_interface.h
index dfd6d02..042997a 100644
--- a/engines/sherlock/user_interface.h
+++ b/engines/sherlock/user_interface.h
@@ -50,18 +50,6 @@ enum MenuMode {
 	SETUP_MODE		= 12
 };
 
-extern const char COMMANDS[13];
-extern const int MENU_POINTS[12][4];
-
-extern const int INVENTORY_POINTS[8][3];
-extern const char INVENTORY_COMMANDS[9];
-extern const char *const PRESS_KEY_FOR_MORE;
-extern const char *const PRESS_KEY_TO_CONTINUE;
-
-class SherlockEngine;
-class Inventory;
-class Talk;
-
 class UserInterface {
 protected:
 	SherlockEngine *_vm;
@@ -137,222 +125,6 @@ public:
 	virtual void printObjectDesc() {}
 };
 
-namespace Scalpel {
-
-class ScalpelUserInterface: public UserInterface {
-	friend class Inventory;
-	friend class Settings;
-	friend class Talk;
-private:
-	ImageFile *_controlPanel;
-	ImageFile *_controls;
-	char _keyPress;
-	int _lookHelp;
-	int _bgFound, _oldBgFound;
-	int _help, _oldHelp;
-	char _key, _oldKey;
-	int _temp, _oldTemp;
-	int _oldLook;
-	bool _keyboardInput;
-	bool _pause;
-	int _cNum;
-	Common::String _cAnimStr;
-	Common::String _descStr;
-	int _find;
-	int _oldUse;
-private:
-	/**
-	 * Draws the image for a user interface button in the down/pressed state.
-	 */
-	void depressButton(int num);
-
-	/**
-	 * If he mouse button is pressed, then calls depressButton to draw the button
-	 * as pressed; if not, it will show it as released with a call to "restoreButton".
-	 */
-	void pushButton(int num);
-
-	/**
-	 * By the time this method has been called, the graphics for the button change
-	 * have already been drawn. This simply takes care of switching the mode around
-	 * accordingly
-	 */
-	void toggleButton(int num);
-
-	/**
-	 * Creates a text window and uses it to display the in-depth description
-	 * of the highlighted object
-	 */
-	void examine();
-
-	/**
-	 * Print the name of an object in the scene
-	 */
-	void lookScreen(const Common::Point &pt);
-
-	/**
-	 * Gets the item in the inventory the mouse is on and display's it's description
-	 */
-	void lookInv();
-
-	/**
-	 * Handles input when the file list window is being displayed
-	 */
-	void doEnvControl();
-	
-	/**
-	 * Handle input whilst the inventory is active
-	 */
-	void doInvControl();
-	
-	/**
-	 * Handles waiting whilst an object's description window is open.
-	 */
-	void doLookControl();
-	
-	/**
-	 * Handles input until one of the user interface buttons/commands is selected
-	 */
-	void doMainControl();
-	
-	/**
-	 * Handles the input for the MOVE, OPEN, and CLOSE commands
-	 */
-	void doMiscControl(int allowed);
-	
-	/**
-	 * Handles input for picking up items
-	 */
-	void doPickControl();
-	
-	/**
-	 * Handles input when in talk mode. It highlights the buttons and available statements,
-	 * and handles allowing the user to click on them
-	 */
-	void doTalkControl();
-	
-	/**
-	 * Handles events when the Journal is active.
-	 * @remarks		Whilst this would in theory be better in the Journal class, since it displays in
-	 *		the user interface, it uses so many internal UI fields, that it sort of made some sense
-	 *		to put it in the UserInterface class.
-	 */
-	void journalControl();
-
-	/**
-	 * Checks to see whether a USE action is valid on the given object
-	 */
-	void checkUseAction(const UseType *use, const Common::String &invName, const char *const messages[],
-		int objNum, bool giveMode);
-	
-	/**
-	 * Called for OPEN, CLOSE, and MOVE actions are being done
-	 */
-	void checkAction(ActionType &action, const char *const messages[], int objNum);
-
-	/**
-	 * Print the previously selected object's decription
-	 */
-	void printObjectDesc(const Common::String &str, bool firstTime);
-public:
-	ScalpelUserInterface(SherlockEngine *vm);
-	virtual ~ScalpelUserInterface();
-
-	/**
-	 * Handles counting down whilst checking for input, then clears the info line.
-	 */
-	void whileMenuCounter();
-
-	/**
-	 * Draws the image for the given user interface button in the up
-	 * (not selected) position
-	 */
-	void restoreButton(int num);
-public:
-	/**
-	 * Resets the user interface
-	 */
-	virtual void reset();
-
-	/**
-	 * Main input handler for the user interface
-	 */
-	virtual void handleInput();
-
-	/**
-	 * Draw the user interface onto the screen's back buffers
-	 */	
-	virtual void drawInterface(int bufferNum = 3);
-
-	/**
-	 * Displays a passed window by gradually scrolling it vertically on-screen
-	 */
-	virtual void summonWindow(const Surface &bgSurface, bool slideUp = true);
-
-	/**
-	 * Slide the window stored in the back buffer onto the screen
-	 */
-	virtual void summonWindow(bool slideUp = true, int height = CONTROLS_Y);
-
-	/**
-	 * Close a currently open window
-	 * @param flag	0 = slide old window down, 1 = slide prior UI back up
-	 */
-	virtual void banishWindow(bool slideUp = true);
-
-	/**
-	 * Clears the info line of the screen
-	 */
-	virtual void clearInfo();
-
-	/**
-	 * Clear any active text window
-	 */
-	virtual void clearWindow();
-
-	/**
-	 * Print the previously selected object's decription
-	 */	
-	virtual void printObjectDesc();
-};
-
-} // End of namespace Scalpel
-
-namespace Tattoo {
-
-class TattooUserInterface : public UserInterface {
-private:
-	Common::Rect _menuBounds;
-	Common::Rect _oldMenuBounds;
-	Common::Rect _invMenuBounds;
-	Common::Rect _oldInvMenuBounds;
-	Common::Rect _oldTagBounds;
-	Common::Rect _oldInvGraphicBounds;
-	Surface *_menuBuffer;
-	Surface *_invMenuBuffer;
-public:
-	TattooUserInterface(SherlockEngine *vm);
-
-	/**
-	 * Handles restoring any areas of the back buffer that were/are covered by UI elements
-	 */
-	void doBgAnimRestoreUI();
-
-	/**
-	 * Checks to see if the screen needs to be scrolled. If so, scrolls it towards the target position
-	 */
-	void doScroll();
-public:
-	virtual ~TattooUserInterface() {}
-
-	/**
-	 * Main input handler for the user interface
-	 */
-	virtual void handleInput();
-};
-
-} // End of namespace Tattoo
-
 } // End of namespace Sherlock
 
 #endif


Commit: 54b3c55e82a115fb2b6bea2539db5e0788247f7d
    https://github.com/scummvm/scummvm/commit/54b3c55e82a115fb2b6bea2539db5e0788247f7d
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-28T19:59:03-04:00

Commit Message:
SHERLOCK: Implement additions to updateBackground, some method stubs

Changed paths:
    engines/sherlock/people.cpp
    engines/sherlock/people.h
    engines/sherlock/resources.cpp
    engines/sherlock/resources.h
    engines/sherlock/scene.h
    engines/sherlock/screen.cpp
    engines/sherlock/screen.h
    engines/sherlock/surface.cpp
    engines/sherlock/surface.h
    engines/sherlock/tattoo/tattoo_scene.cpp
    engines/sherlock/tattoo/tattoo_scene.h



diff --git a/engines/sherlock/people.cpp b/engines/sherlock/people.cpp
index f8dd8e2..0ef49ff 100644
--- a/engines/sherlock/people.cpp
+++ b/engines/sherlock/people.cpp
@@ -70,6 +70,7 @@ const char *const WALK_LIB_NAMES[10] = {
 
 Person::Person() : Sprite(), _walkLoaded(false), _npcIndex(0), _npcStack(0), _npcPause(false)  {
 	Common::fill(&_npcPath[0], &_npcPath[MAX_NPC_PATH], 0);
+	_tempX = _tempScaleVal = 0;
 }
 
 void Person::clearNPC() {
diff --git a/engines/sherlock/people.h b/engines/sherlock/people.h
index f4aba5a..013727d 100644
--- a/engines/sherlock/people.h
+++ b/engines/sherlock/people.h
@@ -74,6 +74,8 @@ public:
 	bool _npcPause;
 	byte _npcPath[MAX_NPC_PATH];
 	Common::String _npcName;
+	int _tempX;
+	int _tempScaleVal;
 
 	// Rose Tattoo fields
 	Common::String _walkVGSName;		// Name of walk library person is using
diff --git a/engines/sherlock/resources.cpp b/engines/sherlock/resources.cpp
index 4e10ba9..961286f 100644
--- a/engines/sherlock/resources.cpp
+++ b/engines/sherlock/resources.cpp
@@ -466,4 +466,14 @@ void ImageFile::decompressFrame(ImageFrame &frame, const byte *src) {
 	}
 }
 
+/*----------------------------------------------------------------*/
+
+int ImageFrame::sDrawXSize(int scaleVal) const {
+	error("TODO: sDrawXSize");
+}
+
+int ImageFrame::sDrawYSize(int scaleVal) const {
+	error("TODO: sDrawYSize");
+}
+
 } // End of namespace Sherlock
diff --git a/engines/sherlock/resources.h b/engines/sherlock/resources.h
index 659ecf0..c5b76ac 100644
--- a/engines/sherlock/resources.h
+++ b/engines/sherlock/resources.h
@@ -173,6 +173,10 @@ struct ImageFrame {
 	Common::Point _offset;
 	byte _rleMarker;
 	Graphics::Surface _frame;
+
+	int sDrawXSize(int scaleVal) const;
+
+	int sDrawYSize(int scaleVal) const;
 };
 
 class ImageFile : public Common::Array<ImageFrame> {
diff --git a/engines/sherlock/scene.h b/engines/sherlock/scene.h
index b5e27ff..624e4d3 100644
--- a/engines/sherlock/scene.h
+++ b/engines/sherlock/scene.h
@@ -273,11 +273,6 @@ public:
 	int toggleObject(const Common::String &name);
 
 	/**
-	 * Draw all objects and characters.
-	 */
-	virtual void doBgAnim() = 0;
-
-	/**
 	 * Attempts to find a background shape within the passed bounds. If found,
 	 * it will return the shape number, or -1 on failure.
 	 */
@@ -300,12 +295,6 @@ public:
 	int closestZone(const Common::Point &pt);
 
 	/**
-	 * Update the screen back buffer with all of the scene objects which need
-	 * to be drawn
-	 */
-	void updateBackground();
-
-	/**
 	 * Synchronize the data for a savegame
 	 */
 	void synchronize(Common::Serializer &s);
@@ -316,6 +305,17 @@ public:
 	 *		the scene number being entered
 	 */
 	void setNPCPath(int npc);
+public:
+	/**
+	 * Draw all objects and characters.
+	 */
+	virtual void doBgAnim() = 0;
+
+	/**
+	 * Update the screen back buffer with all of the scene objects which need
+	 * to be drawn
+	 */
+	virtual void updateBackground();
 };
 
 } // End of namespace Sherlock
diff --git a/engines/sherlock/screen.cpp b/engines/sherlock/screen.cpp
index 350341f..e826a10 100644
--- a/engines/sherlock/screen.cpp
+++ b/engines/sherlock/screen.cpp
@@ -253,24 +253,26 @@ void Screen::slamRect(const Common::Rect &r) {
 	}
 }
 
-void Screen::flushImage(ImageFrame *frame, const Common::Point &pt,
-		int16 *xp, int16 *yp, int16 *width, int16 *height) {
+void Screen::flushImage(ImageFrame *frame, const Common::Point &pt, int16 *xp, int16 *yp, 
+		int16 *width, int16 *height) {
 	Common::Point imgPos = pt + frame->_offset;
 	Common::Rect newBounds(imgPos.x, imgPos.y, imgPos.x + frame->_frame.w, imgPos.y + frame->_frame.h);
 	Common::Rect oldBounds(*xp, *yp, *xp + *width, *yp + *height);
 
-	// See if the areas of the old and new overlap, and if so combine the areas
-	if (newBounds.intersects(oldBounds)) {
-		Common::Rect mergedBounds = newBounds;
-		mergedBounds.extend(oldBounds);
-		mergedBounds.right += 1;
-		mergedBounds.bottom += 1;
+	if (!_flushScreen) {
+		// See if the areas of the old and new overlap, and if so combine the areas
+		if (newBounds.intersects(oldBounds)) {
+			Common::Rect mergedBounds = newBounds;
+			mergedBounds.extend(oldBounds);
+			mergedBounds.right += 1;
+			mergedBounds.bottom += 1;
 
-		slamRect(mergedBounds);
-	} else {
-		// The two areas are independent, so copy them both
-		slamRect(newBounds);
-		slamRect(oldBounds);
+			slamRect(mergedBounds);
+		} else {
+			// The two areas are independent, so copy them both
+			slamRect(newBounds);
+			slamRect(oldBounds);
+		}
 	}
 
 	*xp = newBounds.left;
@@ -279,6 +281,11 @@ void Screen::flushImage(ImageFrame *frame, const Common::Point &pt,
 	*height = newBounds.height();
 }
 
+void Screen::flushScaleImage(ImageFrame *frame, const Common::Point &pt, int16 *xp, int16 *yp,
+		int16 *width, int16 *height, int scaleVal) {
+	error("TODO");
+}
+
 void Screen::print(const Common::Point &pt, byte color, const char *formatStr, ...) {
 	// Create the string to display
 	va_list args;
diff --git a/engines/sherlock/screen.h b/engines/sherlock/screen.h
index ae368cf..949f9de 100644
--- a/engines/sherlock/screen.h
+++ b/engines/sherlock/screen.h
@@ -184,6 +184,9 @@ public:
 	void flushImage(ImageFrame *frame, const Common::Point &pt,
 		int16 *xp, int16 *yp, int16 *width, int16 *height);
 
+	void flushScaleImage(ImageFrame *frame, const Common::Point &pt,
+		int16 *xp, int16 *yp, int16 *width, int16 *height, int scaleVal);
+
 	/**
 	 * Returns the width of a string in pixels
 	 */
diff --git a/engines/sherlock/surface.cpp b/engines/sherlock/surface.cpp
index 80495a3..6cf479c 100644
--- a/engines/sherlock/surface.cpp
+++ b/engines/sherlock/surface.cpp
@@ -186,4 +186,10 @@ void Surface::setPixels(byte *pixels, int width, int height) {
 	_surface.setPixels(pixels);
 }
 
+void Surface::maskArea(const ImageFrame &src, const Common::Point &pt, int scrollX) {
+	// TODO
+	error("TODO: maskArea");
+}
+
+
 } // End of namespace Sherlock
diff --git a/engines/sherlock/surface.h b/engines/sherlock/surface.h
index ccabf02..663f87f 100644
--- a/engines/sherlock/surface.h
+++ b/engines/sherlock/surface.h
@@ -126,6 +126,8 @@ public:
 	 */
 	void fillRect(const Common::Rect &r, byte color);
 
+	void maskArea(const ImageFrame &src, const Common::Point &pt, int scrollX);
+
 	/**
 	 * Clear the screen
 	 */
diff --git a/engines/sherlock/tattoo/tattoo_scene.cpp b/engines/sherlock/tattoo/tattoo_scene.cpp
index f03e791..1effd60 100644
--- a/engines/sherlock/tattoo/tattoo_scene.cpp
+++ b/engines/sherlock/tattoo/tattoo_scene.cpp
@@ -222,6 +222,114 @@ void TattooScene::doBgAnim() {
 	doBgAnimEraseBackground();
 }
 
+void TattooScene::updateBackground() {
+	People &people = *_vm->_people;
+	Screen &screen = *_vm->_screen;
+
+	Scene::updateBackground();
+
+	if (_mask != nullptr) {
+		switch (_currentScene) {
+		case 7:
+			screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x - SHERLOCK_SCREEN_WIDTH, 110), screen._currentScroll);
+			screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x, 110), screen._currentScroll);
+			screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x + SHERLOCK_SCREEN_WIDTH, 110), screen._currentScroll);
+			break;
+
+		case 8:
+			screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x - SHERLOCK_SCREEN_WIDTH, 180), screen._currentScroll);
+			screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x, 180), screen._currentScroll);
+			screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x + SHERLOCK_SCREEN_WIDTH, 180), screen._currentScroll);
+			if (!_vm->readFlags(880))
+				screen._backBuffer1.maskArea((*_mask1)[0], Common::Point(940, 300), screen._currentScroll);
+			break;
+
+		case 18:
+			screen._backBuffer1.maskArea((*_mask)[0], Common::Point(0, 203), screen._currentScroll);
+			if (!_vm->readFlags(189))
+				screen._backBuffer1.maskArea((*_mask1)[0], Common::Point(124, 239), screen._currentScroll);
+			break;
+
+		case 53:
+			screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x, 110), screen._currentScroll);
+			break;
+
+		case 68:
+			screen._backBuffer1.maskArea((*_mask)[0], Common::Point(0, 203), screen._currentScroll);
+			screen._backBuffer1.maskArea((*_mask1)[0], Common::Point(124, 239), screen._currentScroll);
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	screen._flushScreen = true;
+
+	for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
+		Person &p = people[idx];
+
+		if (p._type != INVALID) {
+			if (_goToScene == -1 || _cAnim.size() == 0) {
+				if (p._type == REMOVE) {
+					screen.slamArea(p._oldPosition.x, p._oldPosition.y, p._oldSize.x, p._oldSize.y);
+					p._type = INVALID;
+				} else {
+					if (p._tempScaleVal == 256) {
+						screen.flushImage(p._imageFrame, Common::Point(p._tempX, p._position.y / FIXED_INT_MULTIPLIER
+							- p._imageFrame->_width), &p._oldPosition.x, &p._oldPosition.y, &p._oldSize.x, &p._oldSize.y);
+					}  else {
+						int ts = p._imageFrame->sDrawYSize(p._tempScaleVal);
+						int ty = p._position.y / FIXED_INT_MULTIPLIER - ts;
+						screen.flushScaleImage(p._imageFrame, Common::Point(p._tempX, ty),
+							&p._oldPosition.x, &p._oldPosition.y, &p._oldSize.x, &p._oldSize.y, p._tempScaleVal);
+					}
+				}
+			}
+		}
+	}
+
+	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+		Object &obj = _bgShapes[idx];
+
+		if (obj._type == ACTIVE_BG_SHAPE || obj._type == REMOVE) {
+			if (_goToScene == -1) {
+				if (obj._scaleVal == 256)
+					screen.flushImage(obj._imageFrame, obj._position, &obj._oldPosition.x, &obj._oldPosition.y,
+						&obj._oldSize.x, &obj._oldSize.y);
+				else
+					screen.flushScaleImage(obj._imageFrame, obj._position, &obj._oldPosition.x, &obj._oldPosition.y,
+						&obj._oldSize.x, &obj._oldSize.y, obj._scaleVal);
+
+				if (obj._type == REMOVE)
+					obj._type = INVALID;
+			}
+		}
+	}
+
+	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+		Object &obj = _bgShapes[idx];
+
+		if (_goToScene == -1) {
+			if (obj._type == NO_SHAPE && (obj._flags & 1) == 0) {
+				screen.slamRect(obj.getNoShapeBounds());
+				screen.slamRect(obj.getOldBounds());
+			} else if (obj._type == HIDE_SHAPE) {
+				if (obj._scaleVal == 256)
+					screen.flushImage(obj._imageFrame, obj._position, &obj._oldPosition.x, &obj._oldPosition.y,
+						&obj._oldSize.x, &obj._oldSize.y);
+				else
+					screen.flushScaleImage(obj._imageFrame, obj._position, &obj._oldPosition.x, &obj._oldPosition.y,
+						&obj._oldSize.x, &obj._oldSize.y, obj._scaleVal);
+				obj._type = HIDDEN;
+			}
+		}
+	}
+
+	screen._flushScreen = false;
+}
+
+
 } // End of namespace Tattoo
 
 } // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/tattoo_scene.h b/engines/sherlock/tattoo/tattoo_scene.h
index 34e87f4..5e26eaa 100644
--- a/engines/sherlock/tattoo/tattoo_scene.h
+++ b/engines/sherlock/tattoo/tattoo_scene.h
@@ -56,6 +56,13 @@ public:
 	 * Draw all objects and characters.
 	 */
 	virtual void doBgAnim();
+
+	/**
+	 * Update the screen back buffer with all of the scene objects which need
+	 * to be drawn
+	 */
+	virtual void updateBackground();
+
 };
 
 } // End of namespace Tattoo


Commit: 074669ad45bcb1eec4901f644e00ca8f1169706a
    https://github.com/scummvm/scummvm/commit/074669ad45bcb1eec4901f644e00ca8f1169706a
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-28T21:47:52-04:00

Commit Message:
SHERLOCK: Implemented flushScaleImage and scale calculations

Changed paths:
    engines/sherlock/resources.cpp
    engines/sherlock/resources.h
    engines/sherlock/screen.cpp
    engines/sherlock/screen.h



diff --git a/engines/sherlock/resources.cpp b/engines/sherlock/resources.cpp
index 961286f..f1c705b 100644
--- a/engines/sherlock/resources.cpp
+++ b/engines/sherlock/resources.cpp
@@ -469,11 +469,31 @@ void ImageFile::decompressFrame(ImageFrame &frame, const byte *src) {
 /*----------------------------------------------------------------*/
 
 int ImageFrame::sDrawXSize(int scaleVal) const {
-	error("TODO: sDrawXSize");
+	int width = _width;
+	int scale = scaleVal == 0 ? 1 : scaleVal;
+
+	if (scaleVal >= 256)
+		--width;
+
+	int result = width * 256 / scale;
+	if (scaleVal >= 256)
+		++result;
+
+	return result;
 }
 
 int ImageFrame::sDrawYSize(int scaleVal) const {
-	error("TODO: sDrawYSize");
+	int height = _height;
+	int scale = scaleVal == 0 ? 1 : scaleVal;
+
+	if (scaleVal >= 256)
+		--height;
+
+	int result = height * 256 / scale;
+	if (scaleVal >= 256)
+		++result;
+
+	return result;
 }
 
 } // End of namespace Sherlock
diff --git a/engines/sherlock/resources.h b/engines/sherlock/resources.h
index c5b76ac..5c071e3 100644
--- a/engines/sherlock/resources.h
+++ b/engines/sherlock/resources.h
@@ -174,8 +174,14 @@ struct ImageFrame {
 	byte _rleMarker;
 	Graphics::Surface _frame;
 
+	/**
+	 * Return the frame width adjusted by a specified scale amount
+	 */
 	int sDrawXSize(int scaleVal) const;
 
+	/**
+	 * Return the frame height adjusted by a specified scale amount
+	 */
 	int sDrawYSize(int scaleVal) const;
 };
 
diff --git a/engines/sherlock/screen.cpp b/engines/sherlock/screen.cpp
index e826a10..a3af555 100644
--- a/engines/sherlock/screen.cpp
+++ b/engines/sherlock/screen.cpp
@@ -283,7 +283,31 @@ void Screen::flushImage(ImageFrame *frame, const Common::Point &pt, int16 *xp, i
 
 void Screen::flushScaleImage(ImageFrame *frame, const Common::Point &pt, int16 *xp, int16 *yp,
 		int16 *width, int16 *height, int scaleVal) {
-	error("TODO");
+	Common::Point imgPos = pt + frame->_offset;
+	Common::Rect newBounds(imgPos.x, imgPos.y, imgPos.x + frame->sDrawXSize(scaleVal), 
+		imgPos.y + frame->sDrawYSize(scaleVal));
+	Common::Rect oldBounds(*xp, *yp, *xp + *width, *yp + *height);
+
+	if (!_flushScreen) {
+		// See if the areas of the old and new overlap, and if so combine the areas
+		if (newBounds.intersects(oldBounds)) {
+			Common::Rect mergedBounds = newBounds;
+			mergedBounds.extend(oldBounds);
+			mergedBounds.right += 1;
+			mergedBounds.bottom += 1;
+
+			slamRect(mergedBounds);
+		} else {
+			// The two areas are independent, so copy them both
+			slamRect(newBounds);
+			slamRect(oldBounds);
+		}
+	}
+
+	*xp = newBounds.left;
+	*yp = newBounds.top;
+	*width = newBounds.width();
+	*height = newBounds.height();
 }
 
 void Screen::print(const Common::Point &pt, byte color, const char *formatStr, ...) {
diff --git a/engines/sherlock/screen.h b/engines/sherlock/screen.h
index 949f9de..8fda9cb 100644
--- a/engines/sherlock/screen.h
+++ b/engines/sherlock/screen.h
@@ -181,11 +181,15 @@ public:
 	 * Copy an image from the back buffer to the screen, taking care of both the
 	 * new area covered by the shape as well as the old area, which must be restored
 	 */
-	void flushImage(ImageFrame *frame, const Common::Point &pt,
-		int16 *xp, int16 *yp, int16 *width, int16 *height);
+	void flushImage(ImageFrame *frame, const Common::Point &pt, int16 *xp, int16 *yp, 
+		int16 *width, int16 *height);
 
-	void flushScaleImage(ImageFrame *frame, const Common::Point &pt,
-		int16 *xp, int16 *yp, int16 *width, int16 *height, int scaleVal);
+	/**
+	 * Similar to flushImage, this method takes in an extra parameter for the scale proporation,
+	 * which affects the calculated bounds accordingly
+	 */
+	void flushScaleImage(ImageFrame *frame, const Common::Point &pt, int16 *xp, int16 *yp, 
+		int16 *width, int16 *height, int scaleVal);
 
 	/**
 	 * Returns the width of a string in pixels


Commit: c9bfc5c4814c26b0a6a1e2cdd22e3e1ce114eddd
    https://github.com/scummvm/scummvm/commit/c9bfc5c4814c26b0a6a1e2cdd22e3e1ce114eddd
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-29T22:56:34-04:00

Commit Message:
SHERLOCK: More RT doBgAnim code, interface draw

Changed paths:
    engines/sherlock/objects.cpp
    engines/sherlock/objects.h
    engines/sherlock/scene.h
    engines/sherlock/surface.cpp
    engines/sherlock/tattoo/tattoo.cpp
    engines/sherlock/tattoo/tattoo.h
    engines/sherlock/tattoo/tattoo_scene.cpp
    engines/sherlock/tattoo/tattoo_scene.h
    engines/sherlock/tattoo/tattoo_user_interface.cpp
    engines/sherlock/tattoo/tattoo_user_interface.h



diff --git a/engines/sherlock/objects.cpp b/engines/sherlock/objects.cpp
index 3e8838c..8818f80 100644
--- a/engines/sherlock/objects.cpp
+++ b/engines/sherlock/objects.cpp
@@ -1151,6 +1151,10 @@ CAnimStream::CAnimStream() {
 	_zPlacement = 0;
 }
 
+void CAnimStream::getNextFrame() {
+	// TODO
+}
+
 /*----------------------------------------------------------------*/
 
 SceneImage::SceneImage() {
diff --git a/engines/sherlock/objects.h b/engines/sherlock/objects.h
index ec5c2e7..d671066 100644
--- a/engines/sherlock/objects.h
+++ b/engines/sherlock/objects.h
@@ -429,6 +429,8 @@ struct CAnimStream {
 	int _zPlacement;				// Used by doBgAnim for determining Z order
 
 	CAnimStream();
+
+	void getNextFrame();
 };
 
 struct SceneImage {
diff --git a/engines/sherlock/scene.h b/engines/sherlock/scene.h
index 624e4d3..37a1b32 100644
--- a/engines/sherlock/scene.h
+++ b/engines/sherlock/scene.h
@@ -183,11 +183,6 @@ private:
 	 * will remain the same on future visits to the scene
 	 */
 	void saveSceneStatus();
-
-	/**
-	 * Draw all the shapes, people and NPCs in the correct order
-	 */
-	void drawAllShapes();
 protected:
 	SherlockEngine *_vm;
 
@@ -198,6 +193,11 @@ protected:
 	 */
 	virtual void checkBgShapes();
 
+	/**
+	 * Draw all the shapes, people and NPCs in the correct order
+	 */
+	void drawAllShapes();
+
 	Scene(SherlockEngine *vm);
 public:
 	int _currentScene;
diff --git a/engines/sherlock/surface.cpp b/engines/sherlock/surface.cpp
index 6cf479c..5a9e59e 100644
--- a/engines/sherlock/surface.cpp
+++ b/engines/sherlock/surface.cpp
@@ -96,6 +96,12 @@ void Surface::transBlitFrom(const ImageFrame &src, const Common::Point &pt,
 	transBlitFrom(src._frame, pt + src._offset, flipped, overrideColor);
 }
 
+void Surface::transBlitFrom(const Surface &src, const Common::Point &pt,
+		bool flipped, int overrideColor) {
+	const Graphics::Surface &s = src._surface;
+	transBlitFrom(s, pt, flipped, overrideColor);
+}
+
 void Surface::transBlitFrom(const Graphics::Surface &src, const Common::Point &pt,
 		bool flipped, int overrideColor) {
 	Common::Rect drawRect(0, 0, src.w, src.h);
diff --git a/engines/sherlock/tattoo/tattoo.cpp b/engines/sherlock/tattoo/tattoo.cpp
index 6d90416..368b24b 100644
--- a/engines/sherlock/tattoo/tattoo.cpp
+++ b/engines/sherlock/tattoo/tattoo.cpp
@@ -68,6 +68,10 @@ void TattooEngine::loadInitialPalette() {
 	delete stream;
 }
 
+void TattooEngine::drawCredits() {
+	// TODO
+}
+
 void TattooEngine::eraseCredits() {
 	// TODO
 }
diff --git a/engines/sherlock/tattoo/tattoo.h b/engines/sherlock/tattoo/tattoo.h
index b6a8510..bb6310d 100644
--- a/engines/sherlock/tattoo/tattoo.h
+++ b/engines/sherlock/tattoo/tattoo.h
@@ -54,6 +54,11 @@ public:
 	virtual ~TattooEngine() {}
 
 	/**
+	 * Draw credits on the screen
+	 */
+	void drawCredits();
+
+	/**
 	 * Erase any area of the screen covered by credits
 	 */
 	void eraseCredits();
diff --git a/engines/sherlock/tattoo/tattoo_scene.cpp b/engines/sherlock/tattoo/tattoo_scene.cpp
index 1effd60..dd96f33 100644
--- a/engines/sherlock/tattoo/tattoo_scene.cpp
+++ b/engines/sherlock/tattoo/tattoo_scene.cpp
@@ -196,6 +196,8 @@ void TattooScene::doBgAnimEraseBackground() {
 }
 
 void TattooScene::doBgAnim() {
+	TattooUserInterface &ui = *((TattooUserInterface *)_vm->_ui);
+
 	doBgAnimCheckCursor();
 
 //	Events &events = *_vm->_events;
@@ -208,7 +210,7 @@ void TattooScene::doBgAnim() {
 	talk._talkToAbort = false;
 
 	// Check the characters and sprites for updates
-	for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
+	for (uint idx = 0; idx < MAX_CHARACTERS; ++idx) {
 		if (people[idx]._type == CHARACTER)
 			people[idx].checkSprite();
 	}
@@ -220,8 +222,73 @@ void TattooScene::doBgAnim() {
 
 	// Erase any affected background areas
 	doBgAnimEraseBackground();
+
+	doBgAnimUpdateBgObjectsAndAnim();
+
+	ui.drawInterface();
+}
+
+void TattooScene::doBgAnimUpdateBgObjectsAndAnim() {
+	TattooEngine &vm = *((TattooEngine *)_vm);
+	People &people = *_vm->_people;
+	Screen &screen = *_vm->_screen;
+
+	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
+		Object &obj = _bgShapes[idx];
+		if (obj._type == ACTIVE_BG_SHAPE || obj._type == NO_SHAPE)
+			obj.adjustObject();
+	}
+
+	for (uint idx = 0; idx < MAX_CHARACTERS; ++idx) {
+		if (people[idx]._type == CHARACTER)
+			people[idx].adjustSprite();
+	}
+
+	if (_activeCAnim._images != nullptr != _activeCAnim._zPlacement != REMOVE) {
+		_activeCAnim.getNextFrame();
+	}
+
+	// Flag the bg shapes which need to be redrawn
+	checkBgShapes();
+	drawAllShapes();
+
+
+	if (_mask != nullptr) {
+		switch (_currentScene) {
+		case 7:
+			screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x - SHERLOCK_SCREEN_WIDTH, 110), screen._currentScroll);
+			screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x, 110), screen._currentScroll);
+			screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x + SHERLOCK_SCREEN_WIDTH, 110), screen._currentScroll);
+			break;
+
+		case 8:
+			screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x - SHERLOCK_SCREEN_WIDTH, 180), screen._currentScroll);
+			screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x, 180), screen._currentScroll);
+			screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x + SHERLOCK_SCREEN_WIDTH, 180), screen._currentScroll);
+			if (!_vm->readFlags(880))
+				screen._backBuffer1.maskArea((*_mask1)[0], Common::Point(940, 300), screen._currentScroll);
+			break;
+
+		case 18:
+			screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x, 203), screen._currentScroll);
+			if (!_vm->readFlags(189))
+				screen._backBuffer1.maskArea((*_mask1)[0], Common::Point(124 + _maskOffset.x, 239), screen._currentScroll);
+			break;
+
+		case 53:
+			screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x, 110), screen._currentScroll);
+			screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x - SHERLOCK_SCREEN_WIDTH, 110), screen._currentScroll);
+			break;
+
+		case 68:
+			screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x, 203), screen._currentScroll);
+			screen._backBuffer1.maskArea((*_mask1)[0], Common::Point(124 + _maskOffset.x, 239), screen._currentScroll);
+			break;
+		}
+	}
 }
 
+
 void TattooScene::updateBackground() {
 	People &people = *_vm->_people;
 	Screen &screen = *_vm->_screen;
diff --git a/engines/sherlock/tattoo/tattoo_scene.h b/engines/sherlock/tattoo/tattoo_scene.h
index 5e26eaa..de28306 100644
--- a/engines/sherlock/tattoo/tattoo_scene.h
+++ b/engines/sherlock/tattoo/tattoo_scene.h
@@ -39,6 +39,11 @@ private:
 	void doBgAnimCheckCursor();
 
 	void doBgAnimEraseBackground();
+
+	/**
+	 * Update the background objects and canimations as part of doBgAnim
+	 */
+	void doBgAnimUpdateBgObjectsAndAnim();
 protected:
 	/**
 	 * Checks all the background shapes. If a background shape is animating,
diff --git a/engines/sherlock/tattoo/tattoo_user_interface.cpp b/engines/sherlock/tattoo/tattoo_user_interface.cpp
index 98ec34d..e763228 100644
--- a/engines/sherlock/tattoo/tattoo_user_interface.cpp
+++ b/engines/sherlock/tattoo/tattoo_user_interface.cpp
@@ -22,7 +22,7 @@
 
 #include "sherlock/tattoo/tattoo_user_interface.h"
 #include "sherlock/tattoo/tattoo_scene.h"
-#include "sherlock/sherlock.h"
+#include "sherlock/tattoo/tattoo.h"
 
 namespace Sherlock {
 
@@ -31,6 +31,8 @@ namespace Tattoo {
 TattooUserInterface::TattooUserInterface(SherlockEngine *vm): UserInterface(vm) {
 	_menuBuffer = nullptr;
 	_invMenuBuffer = nullptr;
+	_tagBuffer = nullptr;
+	_invGraphic = nullptr;
 }
 
 void TattooUserInterface::handleInput() {
@@ -38,6 +40,44 @@ void TattooUserInterface::handleInput() {
 	_vm->_events->pollEventsAndWait();
 }
 
+void TattooUserInterface::drawInterface(int bufferNum) {
+	Screen &screen = *_vm->_screen;
+	TattooEngine &vm = *((TattooEngine *)_vm);
+	
+	if (_invMenuBuffer != nullptr) {
+		Common::Rect r = _invMenuBounds;
+		r.grow(-3);
+		r.translate(-screen._currentScroll, 0);
+		_grayAreas.clear();
+		_grayAreas.push_back(r);
+
+		drawGrayAreas();
+		screen._backBuffer1.transBlitFrom(*_invMenuBuffer, Common::Point(_invMenuBounds.left, _invMenuBounds.top));
+	}
+
+	if (_menuBuffer != nullptr) {
+		Common::Rect r = _menuBounds;
+		r.grow(-3);
+		r.translate(-screen._currentScroll, 0);
+		_grayAreas.clear();
+		_grayAreas.push_back(r);
+
+		drawGrayAreas();
+		screen._backBuffer1.transBlitFrom(*_menuBuffer, Common::Point(_invMenuBounds.left, _invMenuBounds.top));
+	}
+
+	// See if we need to draw a Text Tag floating with the cursor
+	if (_tagBuffer != nullptr)
+		screen._backBuffer1.transBlitFrom(*_tagBuffer, Common::Point(_tagBounds.left, _tagBounds.top));
+
+	// See if we need to draw an Inventory Item Graphic floating with the cursor
+	if (_invGraphic != nullptr)
+		screen._backBuffer1.transBlitFrom(*_invGraphic, Common::Point(_invGraphicBounds.left, _invGraphicBounds.top));
+
+	if (vm._creditsActive)
+		vm.drawCredits();
+}
+
 void TattooUserInterface::doBgAnimRestoreUI() {
 	TattooScene &scene = *((TattooScene *)_vm->_scene);
 	Screen &screen = *_vm->_screen;
@@ -101,6 +141,10 @@ void TattooUserInterface::doScroll() {
 		_invMenuBounds.translate(screen._currentScroll - oldScroll, 0);
 }
 
+void TattooUserInterface::drawGrayAreas() {
+	// TODO
+}
+
 } // End of namespace Tattoo
 
 } // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/tattoo_user_interface.h b/engines/sherlock/tattoo/tattoo_user_interface.h
index c7a4c4c..2125f1b 100644
--- a/engines/sherlock/tattoo/tattoo_user_interface.h
+++ b/engines/sherlock/tattoo/tattoo_user_interface.h
@@ -36,10 +36,20 @@ private:
 	Common::Rect _oldMenuBounds;
 	Common::Rect _invMenuBounds;
 	Common::Rect _oldInvMenuBounds;
+	Common::Rect _tagBounds;
 	Common::Rect _oldTagBounds;
+	Common::Rect _invGraphicBounds;
 	Common::Rect _oldInvGraphicBounds;
 	Surface *_menuBuffer;
 	Surface *_invMenuBuffer;
+	Surface *_tagBuffer;
+	Surface *_invGraphic;
+	Common::Array<Common::Rect> _grayAreas;
+private:
+	/**
+	 * Draws designated areas of the screen that are meant to be grayed out using grayscale colors
+	 */
+	void drawGrayAreas();
 public:
 	TattooUserInterface(SherlockEngine *vm);
 
@@ -59,6 +69,11 @@ public:
 	 * Main input handler for the user interface
 	 */
 	virtual void handleInput();
+
+	/**
+	 * Draw the user interface onto the screen's back buffers
+	 */	
+	virtual void drawInterface(int bufferNum = 3);
 };
 
 } // End of namespace Tattoo


Commit: fc6320c256616559a4c4433db1a5df23a8a667fd
    https://github.com/scummvm/scummvm/commit/fc6320c256616559a4c4433db1a5df23a8a667fd
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-30T10:46:19-04:00

Commit Message:
Merge branch 'sherlock2'

Changed paths:
  A engines/sherlock/decompress.cpp
  A engines/sherlock/scalpel/scalpel_scene.cpp
  A engines/sherlock/scalpel/scalpel_scene.h
  A engines/sherlock/scalpel/scalpel_user_interface.cpp
  A engines/sherlock/scalpel/scalpel_user_interface.h
  A engines/sherlock/scalpel/settings.cpp
  A engines/sherlock/scalpel/settings.h
  A engines/sherlock/tattoo/tattoo_scene.cpp
  A engines/sherlock/tattoo/tattoo_scene.h
  A engines/sherlock/tattoo/tattoo_user_interface.cpp
  A engines/sherlock/tattoo/tattoo_user_interface.h
  R engines/sherlock/settings.cpp
  R engines/sherlock/settings.h
    engines/sherlock/events.cpp
    engines/sherlock/events.h
    engines/sherlock/inventory.cpp
    engines/sherlock/journal.cpp
    engines/sherlock/map.cpp
    engines/sherlock/map.h
    engines/sherlock/module.mk
    engines/sherlock/music.cpp
    engines/sherlock/music.h
    engines/sherlock/objects.cpp
    engines/sherlock/objects.h
    engines/sherlock/people.cpp
    engines/sherlock/people.h
    engines/sherlock/resources.cpp
    engines/sherlock/resources.h
    engines/sherlock/scalpel/scalpel.cpp
    engines/sherlock/scene.cpp
    engines/sherlock/scene.h
    engines/sherlock/screen.cpp
    engines/sherlock/screen.h
    engines/sherlock/sherlock.cpp
    engines/sherlock/sherlock.h
    engines/sherlock/sound.cpp
    engines/sherlock/sound.h
    engines/sherlock/surface.cpp
    engines/sherlock/surface.h
    engines/sherlock/talk.cpp
    engines/sherlock/talk.h
    engines/sherlock/tattoo/tattoo.cpp
    engines/sherlock/tattoo/tattoo.h
    engines/sherlock/user_interface.cpp
    engines/sherlock/user_interface.h



diff --cc engines/sherlock/module.mk
index d8c1d78,cee48ae..9ebe416
--- a/engines/sherlock/module.mk
+++ b/engines/sherlock/module.mk
@@@ -3,8 -3,12 +3,13 @@@ MODULE := engines/sherloc
  MODULE_OBJS = \
  	scalpel/darts.o \
  	scalpel/scalpel.o \
 +	scalpel/drivers/adlib.o \
+ 	scalpel/scalpel_scene.o \
+ 	scalpel/scalpel_user_interface.o \
+ 	scalpel/settings.o \
  	tattoo/tattoo.o \
+ 	tattoo/tattoo_scene.o \
+ 	tattoo/tattoo_user_interface.o \
  	animation.o \
  	debugger.o \
  	detection.o \
diff --cc engines/sherlock/music.cpp
index ed047f6,0000000..3e31bcc
mode 100644,000000..100644
--- a/engines/sherlock/music.cpp
+++ b/engines/sherlock/music.cpp
@@@ -1,358 -1,0 +1,363 @@@
 +/* 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 "common/config-manager.h"
 +#include "sherlock/sherlock.h"
 +#include "sherlock/music.h"
 +#include "sherlock/scalpel/drivers/mididriver.h"
 +
 +namespace Sherlock {
 +
 +#define NUM_SONGS 45
 +
 +#define USE_SCI_MIDI_PLAYER 1
 +
 +/* This tells which song to play in each room, 0 = no song played */
 +static const char ROOM_SONG[62] = {
 +	 0, 20, 43,  6, 11,  2,  8, 15,  6, 28,
 +	 6, 38,  7, 32, 16,  5,  8, 41,  9, 22,
 +	10, 23,  4, 39, 19, 24, 13, 27,  0, 30,
 +	 3, 21, 26, 25, 16, 29,  1,  1, 18, 12,
 +	 1, 17, 17, 31, 17, 34, 36,  7, 20, 20,
 +	33,  8, 44, 40, 42, 35,  0,  0,  0, 12,
 +	12
 +};
 +
 +static const char *const SONG_NAMES[NUM_SONGS] = {
 +	"SINGERF",  "CHEMIST",  "TOBAC",   "EQUEST",  "MORTUARY", "DOCKS",    "LSTUDY",
 +	"LORD",     "BOY",      "PERFUM1", "BAKER1",  "BAKER2",   "OPERA1",   "HOLMES",
 +	"FFLAT",    "OP1FLAT",  "ZOO",     "SROOM",   "FLOWERS",  "YARD",     "TAXID",
 +	"PUB1",     "VICTIM",   "RUGBY",   "DORM",    "SHERMAN",  "LAWYER",   "THEATRE",
 +	"DETECT",   "OPERA4",   "POOL",    "SOOTH",   "ANNA1",    "ANNA2",    "PROLOG3",
 +	"PAWNSHOP", "MUSICBOX", "MOZART1", "ROBHUNT", "PANCRAS1", "PANCRAS2", "LORDKILL",
 +	"BLACKWEL", "RESCUE",   "MAP"
 +};
 +
 +MidiParser_SH::MidiParser_SH() {
 +	_ppqn = 1;
 +	setTempo(16667);
 +	_data = nullptr;
 +	_beats = 0;
 +	_lastEvent = 0;
 +	_trackEnd = nullptr;
 +}
 +
 +void MidiParser_SH::parseNextEvent(EventInfo &info) {
 +//	warning("parseNextEvent");
 +
 +	// An attempt to remap MT32 instruments to GMIDI. Only partially successful, it still
 +	// does not sound even close to the real MT32. Oddly enough, on the actual hardware MT32
 +	// and SB sound very differently.
 +	static const byte mt32Map[128] = {
 +		0,     1,   0,   2,   4,   4,   5,   3, /* 0-7 */
 +		16,   17,  18,  16,  16,  19,  20,  21, /* 8-15 */
 +		6,     6,   6,   7,   7,   7,   8, 112, /* 16-23 */
 +		62,   62,  63,  63 , 38,  38,  39,  39, /* 24-31 */
 +		88,   95,  52,  98,  97,  99,  14,  54, /* 32-39 */
 +		102,  96,  53, 102,  81, 100,  14,  80, /* 40-47 */
 +		48,   48,  49,  45,  41,  40,  42,  42, /* 48-55 */
 +		43,   46,  45,  24,  25,  28,  27, 104, /* 56-63 */
 +		32,   32,  34,  33,  36,  37,  35,  35, /* 64-71 */
 +		79,   73,  72,  72,  74,  75,  64,  65, /* 72-79 */
 +		66,   67,  71,  71,  68,  69,  70,  22, /* 80-87 */
 +		56,   59,  57,  57,  60,  60,  58,  61, /* 88-95 */
 +		61,   11,  11,  98,  14,   9,  14,  13, /* 96-103 */
 +		12,  107, 107,  77,  78,  78,  76,  76, /* 104-111 */
 +		47,  117, 127, 118, 118, 116, 115, 119, /* 112-119 */
 +		115, 112,  55, 124, 123,   0,  14, 117  /* 120-127 */
 +	};
 +
 +
 +	info.start = _position._playPos;
 +	info.delta = 0;
 +
 +	info.event = *_position._playPos++;
 +	//warning("Event %x", info.event);
 +	_position._runningStatus = info.event;
 +
 +	switch (info.command()) {
 +	case 0xC: { // program change
 +		int idx = *_position._playPos++;
 +		info.basic.param1 = idx & 0x7f;
 +		// don't do this here, it breaks adlib
 +		//info.basic.param1 = mt32Map[idx & 0x7f]; // remap MT32 to GM
 +		info.basic.param2 = 0;
 +		}
 +		break;
 +	case 0xD:
 +		info.basic.param1 = *_position._playPos++;
 +		info.basic.param2 = 0;
 +		break;
 +
 +	case 0xB:
 +		info.basic.param1 = *_position._playPos++;
 +		info.basic.param2 = *_position._playPos++;
 +		info.length = 0;
 +		break;
 +
 +	case 0x8:
 +	case 0x9:
 +	case 0xA:
 +	case 0xE:
 +		info.basic.param1 = *(_position._playPos++);
 +		info.basic.param2 = *(_position._playPos++);
 +		if (info.command() == 0x9 && info.basic.param2 == 0) {
 +			// NoteOn with param2==0 is a NoteOff
 +			info.event = info.channel() | 0x80;
 +		}
 +		info.length = 0;
 +		break;
 +	case 0xF:
 +		if (info.event == 0xFF) {
 +			byte type = *(_position._playPos++);
 +			switch(type) {
 +			case 0x2F:
 +				// End of Track
 +				allNotesOff();
 +				stopPlaying();
 +				unloadMusic();
 +				return;
 +			case 0x51:
 +				warning("TODO: 0xFF / 0x51");
 +				return;
 +			default:
 +				warning("TODO: 0xFF / %x Unknown", type);
 +				break;
 +			}
 +		} else if (info.event == 0xFC) {
 +			allNotesOff();
 +			stopPlaying();
 +			unloadMusic();
 +			return;
 +		} else {
 +			warning("TODO: %x / Unknown", info.event);
 +			break;
 +		}
 +		break;
 +	default:
 +		warning("MidiParser_SH::parseNextEvent: Unsupported event code %x", info.event);
 +		break;
 +	}// switch (info.command())
 +
 +	info.delta = *(_position._playPos++);
 +}
 +
 +bool MidiParser_SH::loadMusic(byte *data, uint32 size) {
 +	warning("loadMusic");
 +	unloadMusic();
 +
 +	byte  *headerPtr  = data;
 +	byte  *pos        = data;
 +	uint16 headerSize = READ_LE_UINT16(headerPtr);
 +	assert(headerSize == 0x7F);
 +
 +	// Skip over header
 +	pos += headerSize;
 +
 +	_lastEvent = 0;
 +	_trackEnd = data + size;
 +
 +	_numTracks = 1;
 +	_tracks[0] = pos;
 +	
 +	_ppqn = 1;
 +	setTempo(16667);
 +	setTrack(0);
 +
 +	return true;
 +}
 +
 +/*----------------------------------------------------------------*/
 +
 +Music::Music(SherlockEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {
 +	if (_vm->_interactiveFl)
 +		_vm->_res->addToCache("MUSIC.LIB");
 +
 +	MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
 +
 +	_musicType = MidiDriver::getMusicType(dev);
 +
 +#if USE_SCI_MIDI_PLAYER
 +	_pMidiDrv = NULL;
 +#endif
 +	_driver = NULL;
 +
 +	switch (_musicType) {
 +	case MT_ADLIB:
 +#if USE_SCI_MIDI_PLAYER
 +		_pMidiDrv = MidiPlayer_AdLib_create();
 +#else
 +		_driver = MidiDriver_AdLib_create();
 +#endif
 +		break;
 +	default:
 +		_driver = MidiDriver::createMidi(dev);
 +		break;
 +	}
 +#if USE_SCI_MIDI_PLAYER
 +	if (_pMidiDrv) {
 +		assert(_pMidiDrv);
 +		int ret = _pMidiDrv->open();
 +		if (ret == 0) {
 +			_pMidiDrv->setTimerCallback(&_midiParser, &_midiParser.timerCallback);
 +		}
 +		_midiParser.setMidiDriver(_pMidiDrv);
 +		_midiParser.setTimerRate(_pMidiDrv->getBaseTempo());
 +	}
 +#endif
 +
 +	if (_driver) {
 +		assert(_driver);
 +
 +		int ret = _driver->open();
 +		if (ret == 0) {
 +			_driver->sendGMReset();
 +			_driver->setTimerCallback(&_midiParser, &_midiParser.timerCallback);
 +		}
 +		_midiParser.setMidiDriver(_driver);
 +		_midiParser.setTimerRate(_driver->getBaseTempo());
 +	}
 +
 +	_musicPlaying = false;
 +	_musicOn = true;
 +}
 +
 +bool Music::loadSong(int songNumber) {
 +	warning("loadSong");
 +
 +	if(songNumber == 100)
 +		songNumber = 55;
 +	else if(songNumber == 70)
 +		songNumber = 54;
 +
 +	if((songNumber > 60) || (songNumber < 1))
 +		return false;
 +
 +	songNumber = ROOM_SONG[songNumber];
 +
 +	if(songNumber == 0)
 +		songNumber = 12;
 +
 +	if((songNumber > NUM_SONGS) || (songNumber < 1))
 +		return false;
 +
 +	Common::String songName = Common::String(SONG_NAMES[songNumber - 1]) + ".MUS";
 +
 +	freeSong();  // free any song that is currently loaded
 +	
 +	if (!playMusic(songName))
 +		return false;
 +
 +	stopMusic();
 +	startSong();
 +	return true;
 +}
 +
++bool Music::loadSong(const Common::String &songName) {
++	warning("TODO: Music::loadSong");
++	return false;
++}
++
 +void Music::syncMusicSettings() {
 +	_musicOn = !ConfMan.getBool("mute") && !ConfMan.getBool("music_mute");
 +}
 +
 +bool Music::playMusic(const Common::String &name) {
 +	if (!_musicOn)
 +		return false;
 +
 +	warning("Sound::playMusic %s", name.c_str());
 +	Common::SeekableReadStream *stream = _vm->_res->load(name, "MUSIC.LIB");
 +
 +	byte *data = new byte[stream->size()];
 +	int32 dataSize = stream->size();
 +	assert(data);
 +
 +	stream->read(data, dataSize);
 +
 +	// for dumping the music tracks
 +#if 0
 +	Common::DumpFile outFile;
 +	outFile.open(name + ".RAW");
 +	outFile.write(data, stream->size());
 +	outFile.flush();
 +	outFile.close();
 +#endif
 +
 +	if (dataSize < 14) {
 +		warning("not enough data in music file");
 +		return false;
 +	}
 +
 +	byte *dataPos = data;
 +	if (memcmp("            ", dataPos, 12)) {
 +		warning("Expected header not found in music file");
 +		return false;
 +	}
 +	dataPos += 12;
 +	dataSize -= 12;
 +
 +	uint16 headerSize = READ_LE_UINT16(dataPos);
 +	if (headerSize != 0x7F) {
 +		warning("music header is not as expected");
 +		return false;
 +	}
 +
 +	if (_musicType == MT_ADLIB) {
 +		if (_driver)
 +			MidiDriver_AdLib_newMusicData(_driver, dataPos, dataSize);
 +#if USE_SCI_MIDI_PLAYER
 +		if (_pMidiDrv)
 +			MidiPlayer_AdLib_newMusicData(_pMidiDrv, dataPos, dataSize);
 +#endif
 +	}
 +
 +	_midiParser.loadMusic(dataPos, dataSize);
 +	return true;
 +}
 +
 +void Music::stopMusic() {
 +	// TODO
 +	warning("TODO: Sound::stopMusic");
 +
 +	_musicPlaying = false;
 +}
 +
 +void Music::startSong() {
 +	if (!_musicOn)
 +		return;
 +
 +	// TODO
 +	warning("TODO: Sound::startSong");
 +	_musicPlaying = true;
 +}
 +
 +void Music::freeSong() {
 +	// TODO
 +	warning("TODO: Sound::freeSong");
 +}
 +
 +void Music::waitTimerRoland(uint time) {
 +	// TODO
 +	warning("TODO: Sound::waitTimerRoland");
 +}} // End of namespace Sherlock
 +
diff --cc engines/sherlock/music.h
index a195b26,0000000..c371060
mode 100644,000000..100644
--- a/engines/sherlock/music.h
+++ b/engines/sherlock/music.h
@@@ -1,102 -1,0 +1,107 @@@
 +/* 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 SHERLOCK_MUSIC_H
 +#define SHERLOCK_MUSIC_H
 +
 +#include "audio/midiplayer.h"
 +#include "audio/midiparser.h"
 +//#include "audio/mididrv.h"
 +#include "sherlock/scalpel/drivers/mididriver.h"
 +
 +namespace Sherlock {
 +
 +class SherlockEngine;
 +
 +class MidiParser_SH : public MidiParser {
 +protected:
 +	virtual void parseNextEvent(EventInfo &info);
 +
 +	uint8 _beats;
 +	uint8 _lastEvent;
 +	byte *_data;
 +	byte *_trackEnd;
 +public:
 +	MidiParser_SH();
 +	virtual bool loadMusic(byte *data, uint32 size);
 +};
 +
 +class Music {
 +private:
 +	SherlockEngine *_vm;
 +	Audio::Mixer *_mixer;
 +	MidiParser_SH _midiParser;
 +	MidiPlayer *_pMidiDrv;
 +	MidiDriver *_driver;
 +
 +public:
 +	bool _musicPlaying;
 +	bool _musicOn;
 +
 +private:
 +	MusicType _musicType;
 +
 +public:
 +	Music(SherlockEngine *vm, Audio::Mixer *mixer);
 +
 +	/**
 +	 * Saves sound-related settings
 +	 */
 +	void syncMusicSettings();
 +
 +	/**
 +	 * Load a specified song
 +	 */
 +	bool loadSong(int songNumber);
 +
 +	/**
++	 * Load a specified song
++	 */
++	bool loadSong(const Common::String &songName);
++
++	/**
 +	 * Start playing a song
 +	 */
 +	void startSong();
 +	
 +	/**
 +	 * Free any currently loaded song
 +	 */
 +	void freeSong();
 +	
 +	/**
 +	 * Play the specified music resource
 +	 */
 +	bool playMusic(const Common::String &name);
 +
 +	/**
 +	 * Stop playing the music
 +	 */
 +	void stopMusic();
 +	
 +	void waitTimerRoland(uint time);
 +};
 +
 +} // End of namespace Sherlock
 +
 +#endif
 +
diff --cc engines/sherlock/scalpel/scalpel.cpp
index bee44bf,6b72188..304445d
--- a/engines/sherlock/scalpel/scalpel.cpp
+++ b/engines/sherlock/scalpel/scalpel.cpp
@@@ -22,8 -22,8 +22,9 @@@
  
  #include "sherlock/scalpel/scalpel.h"
  #include "sherlock/sherlock.h"
 +#include "sherlock/music.h"
  #include "sherlock/animation.h"
+ #include "engines/util.h"
  
  namespace Sherlock {
  
diff --cc engines/sherlock/scalpel/settings.cpp
index 0000000,4459786..aa8033d
mode 000000,100644..100644
--- a/engines/sherlock/scalpel/settings.cpp
+++ b/engines/sherlock/scalpel/settings.cpp
@@@ -1,0 -1,341 +1,341 @@@
+ /* 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 "sherlock/sherlock.h"
+ #include "sherlock/scalpel/settings.h"
+ #include "sherlock/scalpel/scalpel_user_interface.h"
+ 
+ namespace Sherlock {
+ 
+ namespace Scalpel {
+ 
+ static const int SETUP_POINTS[12][4]  = {
+ 	{ 4, 154, 101, 53 },		// Exit
+ 	{ 4, 165, 101, 53 },		// Music Toggle
+ 	{ 219, 165, 316, 268 },		// Voice Toggle
+ 	{ 103, 165, 217, 160 },		// Sound Effects Toggle
+ 	{ 219, 154, 316, 268 },		// Help Button Left/Right
+ 	{ 103, 154, 217, 160 },		// New Font Style
+ 	{ 4, 187, 101, 53 },		// Joystick Toggle
+ 	{ 103, 187, 217, 160 },		// Calibrate Joystick
+ 	{ 219, 176, 316, 268 },		// Fade Style
+ 	{ 103, 176, 217, 160 },		// Window Open Style
+ 	{ 4, 176, 101, 53 }, 		// Portraits Toggle
+ 	{ 219, 187, 316, 268 }		// _key Pad Accel. Toggle
+ };
+ 
+ static const char *const SETUP_STRS0[2] = { "off", "on" };
+ static const char *const SETUP_STRS1[2] = { "Directly", "by Pixel" };
+ static const char *const SETUP_STRS2[2] = { "Left", "Right" };
+ static const char *const SETUP_STRS3[2] = { "Appear", "Slide" };
+ static const char *const SETUP_STRS5[2] = { "Left", "Right" };
+ static const char *const SETUP_NAMES[12] = {
+ 	"Exit", "M", "V", "S", "B", "New Font Style", "J", "Calibrate Joystick", "F", "W", "P", "K"
+ };
+ 
+ /*----------------------------------------------------------------*/
+ 
+ void Settings::drawInteface(bool flag) {
+ 	People &people = *_vm->_people;
+ 	Screen &screen = *_vm->_screen;
+ 	Sound &sound = *_vm->_sound;
++	Music &music = *_vm->_music;
+ 	UserInterface &ui = *_vm->_ui;
+ 	Common::String tempStr;
+ 
+ 	if (!flag) {
+ 		screen._backBuffer1.fillRect(Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH, CONTROLS_Y1 + 1), BORDER_COLOR);
+ 		screen._backBuffer1.fillRect(Common::Rect(0, CONTROLS_Y1 + 1, 2, SHERLOCK_SCREEN_HEIGHT), BORDER_COLOR);
+ 		screen._backBuffer1.fillRect(Common::Rect(SHERLOCK_SCREEN_WIDTH - 2, CONTROLS_Y1 + 1, SHERLOCK_SCREEN_WIDTH,
+ 			SHERLOCK_SCREEN_HEIGHT), BORDER_COLOR);
+ 		screen._backBuffer1.hLine(0, SHERLOCK_SCREEN_HEIGHT - 1, SHERLOCK_SCREEN_WIDTH - 1, BORDER_COLOR);
+ 		screen._backBuffer1.fillRect(Common::Rect(2, CONTROLS_Y1 + 1, SHERLOCK_SCREEN_WIDTH - 2,
+ 			SHERLOCK_SCREEN_HEIGHT - 2), INV_BACKGROUND);
+ 	}
+ 
+ 	screen.makeButton(Common::Rect(SETUP_POINTS[0][0], SETUP_POINTS[0][1], SETUP_POINTS[0][2], SETUP_POINTS[0][1] + 10),
+ 		SETUP_POINTS[0][3] - screen.stringWidth("Exit") / 2, "Exit");
+ 
 -	tempStr = Common::String::format("Music %s", SETUP_STRS0[sound._music]);
++	tempStr = Common::String::format("Music %s", SETUP_STRS0[music._musicOn]);
+ 	screen.makeButton(Common::Rect(SETUP_POINTS[1][0], SETUP_POINTS[1][1], SETUP_POINTS[1][2], SETUP_POINTS[1][1] + 10),
+ 		SETUP_POINTS[1][3] - screen.stringWidth(tempStr) / 2, tempStr);
+ 
+ 	tempStr = Common::String::format("Voices %s", SETUP_STRS0[sound._voices]);
+ 	screen.makeButton(Common::Rect(SETUP_POINTS[2][0], SETUP_POINTS[2][1], SETUP_POINTS[2][2], SETUP_POINTS[2][1] + 10),
+ 		SETUP_POINTS[2][3] - screen.stringWidth(tempStr) / 2, tempStr);
+ 
+ 	tempStr = Common::String::format("Sound Effects %s", SETUP_STRS0[sound._digitized]);
+ 	screen.makeButton(Common::Rect(SETUP_POINTS[3][0], SETUP_POINTS[3][1], SETUP_POINTS[3][2], SETUP_POINTS[3][1] + 10),
+ 		SETUP_POINTS[3][3] - screen.stringWidth(tempStr) / 2, tempStr);
+ 
+ 	tempStr = Common::String::format("Auto Help %s", SETUP_STRS5[ui._helpStyle]);
+ 	screen.makeButton(Common::Rect(SETUP_POINTS[4][0], SETUP_POINTS[4][1], SETUP_POINTS[4][2], SETUP_POINTS[4][1] + 10),
+ 		SETUP_POINTS[4][3] - screen.stringWidth(tempStr) / 2, tempStr);
+ 	screen.makeButton(Common::Rect(SETUP_POINTS[5][0], SETUP_POINTS[5][1], SETUP_POINTS[5][2], SETUP_POINTS[5][1] + 10),
+ 		SETUP_POINTS[5][3] - screen.stringWidth("New Font Style") / 2, "New Font Style");
+ 
+ 	// WORKAROUND: We don't support the joystick in ScummVM, so draw the next two buttons as disabled
+ 	tempStr = "Joystick Off";
+ 	screen.makeButton(Common::Rect(SETUP_POINTS[6][0], SETUP_POINTS[6][1], SETUP_POINTS[6][2], SETUP_POINTS[6][1] + 10),
+ 		SETUP_POINTS[6][3] - screen.stringWidth(tempStr) / 2, tempStr);
+ 	screen.buttonPrint(Common::Point(SETUP_POINTS[6][3], SETUP_POINTS[6][1]), COMMAND_NULL, false, tempStr);
+ 
+ 	tempStr = "Calibrate Joystick";
+ 	screen.makeButton(Common::Rect(SETUP_POINTS[7][0], SETUP_POINTS[7][1], SETUP_POINTS[7][2], SETUP_POINTS[7][1] + 10),
+ 		SETUP_POINTS[7][3] - screen.stringWidth(tempStr) / 2, tempStr);
+ 	screen.buttonPrint(Common::Point(SETUP_POINTS[7][3], SETUP_POINTS[7][1]), COMMAND_NULL, false, tempStr);
+ 
+ 	tempStr = Common::String::format("Fade %s", screen._fadeStyle ? "by Pixel" : "Directly");
+ 	screen.makeButton(Common::Rect(SETUP_POINTS[8][0], SETUP_POINTS[8][1], SETUP_POINTS[8][2], SETUP_POINTS[8][1] + 10),
+ 		SETUP_POINTS[8][3] - screen.stringWidth(tempStr) / 2, tempStr);
+ 
+ 	tempStr = Common::String::format("Windows %s", ui._slideWindows ? "Slide" : "Appear");
+ 	screen.makeButton(Common::Rect(SETUP_POINTS[9][0], SETUP_POINTS[9][1], SETUP_POINTS[9][2], SETUP_POINTS[9][1] + 10),
+ 		SETUP_POINTS[9][3] - screen.stringWidth(tempStr) / 2, tempStr);
+ 
+ 	tempStr = Common::String::format("Portraits %s", SETUP_STRS0[people._portraitsOn]);
+ 	screen.makeButton(Common::Rect(SETUP_POINTS[10][0], SETUP_POINTS[10][1], SETUP_POINTS[10][2], SETUP_POINTS[10][1] + 10),
+ 		SETUP_POINTS[10][3] - screen.stringWidth(tempStr) / 2, tempStr);
+ 
+ 	tempStr = "Key Pad Slow";
+ 	screen.makeButton(Common::Rect(SETUP_POINTS[11][0], SETUP_POINTS[11][1], SETUP_POINTS[11][2], SETUP_POINTS[11][1] + 10),
+ 		SETUP_POINTS[11][3] - screen.stringWidth(tempStr) / 2, tempStr);
+ 	screen.buttonPrint(Common::Point(SETUP_POINTS[11][3], SETUP_POINTS[11][1]), COMMAND_NULL, false, tempStr);
+ 
+ 	// Show the window immediately, or slide it on-screen
+ 	if (!flag) {
+ 		if (!ui._slideWindows) {
+ 			screen.slamRect(Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
+ 		} else {
+ 			ui.summonWindow(true, CONTROLS_Y1);
+ 		}
+ 
+ 		ui._windowOpen = true;
+ 	} else {
+ 		screen.slamRect(Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
+ 	}
+ }
+ 
+ int Settings::drawButtons(const Common::Point &pt, int _key) {
+ 	Events &events = *_vm->_events;
+ 	People &people = *_vm->_people;
+ 	Screen &screen = *_vm->_screen;
++	Music &music = *_vm->_music;
+ 	Sound &sound = *_vm->_sound;
+ 	UserInterface &ui = *_vm->_ui;
+ 	int found = -1;
+ 	byte color;
+ 	Common::String tempStr;
+ 
+ 	for (int idx = 0; idx < 12; ++idx) {
+ 		if ((pt.x > SETUP_POINTS[idx][0] && pt.x < SETUP_POINTS[idx][2] && pt.y > SETUP_POINTS[idx][1]
+ 				&& pt.y < (SETUP_POINTS[idx][1] + 10) && (events._pressed || events._released))
+ 				|| (_key == SETUP_NAMES[idx][0])) {
+ 			found = idx;
+ 			color = COMMAND_HIGHLIGHTED;
+ 		} else {
+ 			color = COMMAND_FOREGROUND;
+ 		}
+ 
+ 		// Print the button text
+ 		switch (idx) {
+ 		case 1:
 -			tempStr = Common::String::format("Music %s", SETUP_STRS0[sound._music]);
++			tempStr = Common::String::format("Music %s", SETUP_STRS0[music._musicOn]);
+ 			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, tempStr);
+ 			break;
+ 		case 2:
+ 			tempStr = Common::String::format("Voices %s", SETUP_STRS0[sound._voices]);
+ 			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, tempStr);
+ 			break;
+ 		case 3:
+ 			tempStr = Common::String::format("Sound Effects %s", SETUP_STRS0[sound._digitized]);
+ 			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, tempStr);
+ 			break;
+ 		case 4:
+ 			tempStr = Common::String::format("Auto Help %s", SETUP_STRS2[ui._helpStyle]);
+ 			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, tempStr);
+ 			break;
+ 		case 6:
+ 			tempStr = "Joystick Off";
+ 			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), COMMAND_NULL, true, tempStr);
+ 			break;
+ 		case 7:
+ 			tempStr = "Calibrate Joystick";
+ 			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), COMMAND_NULL, true, tempStr);
+ 			break;
+ 		case 8:
+ 			tempStr = Common::String::format("Fade %s", SETUP_STRS1[screen._fadeStyle]);
+ 			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, tempStr);
+ 			break;
+ 		case 9:
+ 			tempStr = Common::String::format("Windows %s", SETUP_STRS3[ui._slideWindows]);
+ 			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, tempStr);
+ 			break;
+ 		case 10:
+ 			tempStr = Common::String::format("Portraits %s", SETUP_STRS0[people._portraitsOn]);
+ 			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, tempStr);
+ 			break;
+ 		case 11:
+ 			tempStr = "Key Pad Slow";
+ 			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), COMMAND_NULL, true, tempStr);
+ 			break;
+ 		default:
+ 			screen.buttonPrint(Common::Point(SETUP_POINTS[idx][3], SETUP_POINTS[idx][1]), color, true, SETUP_NAMES[idx]);
+ 			break;
+ 		}
+ 	}
+ 
+ 	return found;
+ }
+ 
+ void Settings::show(SherlockEngine *vm) {
+ 	Events &events = *vm->_events;
+ 	People &people = *vm->_people;
+ 	Scene &scene = *vm->_scene;
+ 	Screen &screen = *vm->_screen;
+ 	Sound &sound = *vm->_sound;
++	Music &music = *vm->_music;
+ 	Talk &talk = *vm->_talk;
+ 	ScalpelUserInterface &ui = *(ScalpelUserInterface *)vm->_ui;
+ 	bool updateConfig = false;
+ 
+ 	assert(vm->getGameID() == GType_SerratedScalpel);
+ 	Settings settings(vm);
+ 	settings.drawInteface(false);
+ 
+ 	do {
+ 		if (ui._menuCounter)
+ 			ui.whileMenuCounter();
+ 
+ 		int found = -1;
+ 		ui._key = -1;
+ 
+ 		scene.doBgAnim();
+ 		if (talk._talkToAbort)
+ 			return;
+ 
+ 		events.setButtonState();
+ 		Common::Point pt = events.mousePos();
+ 
+ 		if (events._pressed || events._released || events.kbHit()) {
+ 			ui.clearInfo();
+ 			ui._key = -1;
+ 
+ 			if (events.kbHit()) {
+ 				Common::KeyState keyState = events.getKey();
+ 				ui._key = toupper(keyState.keycode);
+ 
+ 				if (ui._key == Common::KEYCODE_RETURN || ui._key == Common::KEYCODE_SPACE) {
+ 					events._pressed = false;
+ 					events._oldButtons = 0;
+ 					ui._keyPress = '\0';
+ 					events._released = true;
+ 				}
+ 			}
+ 
+ 			// Handle highlighting button under mouse
+ 			found = settings.drawButtons(pt, ui._key);
+ 		}
+ 
+ 		if ((found == 0 && events._released) || (ui._key == 'E' || ui._key == Common::KEYCODE_ESCAPE))
+ 			// Exit
+ 			break;
+ 
+ 		if ((found == 1 && events._released) || ui._key == 'M') {
+ 			// Toggle music
 -			if (sound._music) {
 -				sound.stopSound();
 -				sound._music = false;
 -			}
 -			else {
 -				sound._music = true;
 -				sound.startSong();
 -			}
++			music._musicOn = !music._musicOn;
++			if (!music._musicOn)
++				music.stopMusic();
++			else
++				music.startSong();
+ 
+ 			updateConfig = true;
+ 			settings.drawInteface(true);
+ 		}
+ 
+ 		if ((found == 2 && events._released) || ui._key == 'V') {
+ 			sound._voices = !sound._voices;
+ 			updateConfig = true;
+ 			settings.drawInteface(true);
+ 		}
+ 
+ 		if ((found == 3 && events._released) || ui._key == 'S') {
+ 			// Toggle sound effects
+ 			sound._digitized = !sound._digitized;
+ 			updateConfig = true;
+ 			settings.drawInteface(true);
+ 		}
+ 
+ 		if ((found == 4 && events._released) || ui._key == 'A') {
+ 			// Help button style
+ 			ui._helpStyle = !ui._helpStyle;
+ 			updateConfig = true;
+ 			settings.drawInteface(true);
+ 		}
+ 
+ 		if ((found == 5 && events._released) || ui._key == 'N') {
+ 			// New font style
+ 			int fontNum = screen.fontNumber() + 1;
+ 			if (fontNum == 3)
+ 				fontNum = 0;
+ 
+ 			screen.setFont(fontNum);
+ 			updateConfig = true;
+ 			settings.drawInteface(true);
+ 		}
+ 
+ 		if ((found == 8 && events._released) || ui._key == 'F') {
+ 			// Toggle fade style
+ 			screen._fadeStyle = !screen._fadeStyle;
+ 			updateConfig = true;
+ 			settings.drawInteface(true);
+ 		}
+ 
+ 		if ((found == 9 && events._released) || ui._key == 'W') {
+ 			// Window style
+ 			ui._slideWindows = !ui._slideWindows;
+ 			updateConfig = true;
+ 			settings.drawInteface(true);
+ 		}
+ 
+ 		if ((found == 10 && events._released) || ui._key == 'P') {
+ 			// Toggle portraits being shown
+ 			people._portraitsOn = !people._portraitsOn;
+ 			updateConfig = true;
+ 			settings.drawInteface(true);
+ 		}
+ 	} while (!vm->shouldQuit());
+ 
+ 	ui.banishWindow();
+ 
+ 	if (updateConfig)
+ 		vm->saveConfig();
+ 
+ 	ui._keyPress = '\0';
+ 	ui._keyboardInput = false;
+ 	ui._windowBounds.top = CONTROLS_Y1;
+ 	ui._key = -1;
+ }
+ 
+ } // End of namespace Scalpel
+ 
+ } // End of namespace Sherlock
diff --cc engines/sherlock/scene.cpp
index 781e596,0f0187e..76fb7ae
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@@ -193,7 -254,8 +254,9 @@@ void Scene::freeScene() 
  bool Scene::loadScene(const Common::String &filename) {
  	Events &events = *_vm->_events;
  	Map &map = *_vm->_map;
++	Music &music = *_vm->_music;
  	People &people = *_vm->_people;
+ 	Resources &res = *_vm->_res;
  	SaveManager &saves = *_vm->_saves;
  	Screen &screen = *_vm->_screen;
  	Sound &sound = *_vm->_sound;
@@@ -213,8 -275,38 +276,38 @@@
  	_cAnim.clear();
  	_sequenceBuffer.clear();
  
+ 	// Check if it's a scene we need to keep trakc track of how many times we've visited
+ 	for (int idx = (int)_sceneTripCounters.size() - 1; idx >= 0; --idx) {
+ 		if (_sceneTripCounters[idx]._sceneNumber == _currentScene) {
+ 			if (--_sceneTripCounters[idx]._numTimes == 0) {
+ 				_vm->setFlags(_sceneTripCounters[idx]._flag);
+ 				_sceneTripCounters.remove_at(idx);
+ 			}
+ 		}
+ 	}
+ 
+ 	if (IS_ROSE_TATTOO) {
+ 		// Set the NPC paths for the scene
+ 		setNPCPath(0);
+ 
+ 		// Handle loading music for the scene
+ 		if (sound._midiDrvLoaded) {
+ 			if (talk._scriptMoreFlag != 1 && talk._scriptMoreFlag != 3)
+ 				sound._nextSongName = Common::String::format("res%02d", _currentScene);
+ 
+ 			// If it's a new song, then start it up
+ 			if (sound._currentSongName.compareToIgnoreCase(sound._nextSongName)) {
 -				if (sound.loadSong(sound._nextSongName)) {
++				if (music.loadSong(sound._nextSongName)) {
+ 					sound.setMIDIVolume(sound._musicVolume);
 -					if (sound._musicOn)
 -						sound.startSong();
++					if (music._musicOn)
++						music.startSong();
+ 				}
+ 			}
+ 		}
+ 	}
+ 
  	//
- 	// Load background shapes from <filename>.rrm
+ 	// Load the room resource file for the scene
  	//
  
  	Common::String rrmFile = filename + ".rrm";
@@@ -447,8 -608,10 +609,8 @@@
  	checkInventory();
  
  	// Handle starting any music for the scene
- 	if (music._musicOn && music.loadSong(_currentScene))
 -	if (IS_SERRATED_SCALPEL && sound._musicOn && sound.loadSong(_currentScene)) {
 -		if (sound._music)
 -			sound.startSong();
 -	}
++	if (IS_SERRATED_SCALPEL && music._musicOn && music.loadSong(_currentScene))
 +		music.startSong();
  
  	// Load walking images if not already loaded
  	people.loadWalk();
diff --cc engines/sherlock/sound.cpp
index a923cf9,279dd44..e7f4fe8
--- a/engines/sherlock/sound.cpp
+++ b/engines/sherlock/sound.cpp
@@@ -57,11 -58,14 +57,14 @@@ Sound::Sound(SherlockEngine *vm, Audio:
  	_soundPlaying = false;
  	_soundIsOn = &_soundPlaying;
  	_curPriority = 0;
 +	_digiBuf = nullptr;
+ 	_midiDrvLoaded = false;
+ 	_musicVolume = 0;
  
  	_soundOn = true;
 -	_musicOn = true;
  	_speechOn = true;
  
+ 	_vm->_res->addToCache("MUSIC.LIB");
  	if (!_vm->_interactiveFl)
  		_vm->_res->addToCache("TITLE.SND");
  	else {
diff --cc engines/sherlock/sound.h
index 2351beb,06450ff..e1c0777
--- a/engines/sherlock/sound.h
+++ b/engines/sherlock/sound.h
@@@ -89,8 -94,36 +92,9 @@@ public
  	 */
  	void stopSound();
  
 -	/**
 -	 * Load a specified song
 -	 */
 -	bool loadSong(int songNumber);
 -	bool loadSong(const Common::String &name);
 -
 -	/**
 -	 * Start playing a song
 -	 */
 -	void startSong();
 -	
 -	/**
 -	 * Free any currently loaded song
 -	 */
 -	void freeSong();
 -	
 -	/**
 -	 * Play the specified music resource
 -	 */
 -	void playMusic(const Common::String &name);
 -
 -	/**
 -	 * Stop playing the music
 -	 */
 -	void stopMusic();
 -	
  	void stopSndFuncPtr(int v1, int v2);
 -	void waitTimerRoland(uint time);
  	void freeDigiSound();
+ 	void setMIDIVolume(int volume);
  };
  
  } // End of namespace Sherlock


Commit: d53ed7408da6af2ac55672a38ddbea6278677957
    https://github.com/scummvm/scummvm/commit/d53ed7408da6af2ac55672a38ddbea6278677957
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2015-05-30T10:47:47-04:00

Commit Message:
Merge branch 'master' of https://github.com/scummvm/scummvm

Changed paths:
    engines/sherlock/scalpel/drivers/adlib.cpp









More information about the Scummvm-git-logs mailing list