[Scummvm-git-logs] scummvm master -> ee644ec01b292c3308085170021f04f6f6917bc9

csnover csnover at users.noreply.github.com
Fri Mar 31 03:59:26 CEST 2017


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

Summary:
477e31cea6 SCI32: Ignore invalid audio map entries in GK2
0be9ace649 SCI: Fix incorrect read of LB2/MG256 audio sizes
d0e9724ae1 SCI32: Support reading sound effects from normal resource bundles
65fe7bcfd8 SCI: Print more detailed information on audio header size mismatch
766d46153a SCI32: Implement known-used portions of kPlayDuck
3b34f17fb3 SCI32: Add kWebConnect and kWinExec
f4d3664d3f SCI: Replace magic numbers in reg_t handling with symbols
ceacf7df12 SCI: Handle >64KiB offsets in parse_reg_t
4c942758c0 SCI32: Use built-in system font as default font for GfxText32
0826501ef6 SCI32: Fix audio, wave, VMD, Duck, CLUT, TGA, ZZZ, Etc patches
77a4074106 SCI: Protect and clarify the purpose of Resource _header data
9a637ec324 SCI32: Skip bad map 405 on CD 1 of PQ:SWAT
bd7a62e996 SCI: Fix typo in comment
fa9523933f SCI32: Fix broken sliders in Shivers settings
6b0cd955fa SCI32: Fix crash when using brightness slider in Shivers
e74adcec52 SCI: Whitespace alignment
4d062fc7a0 SCI32: Do not default to General MIDI for SCI2.1 games
dd23085845 SCI: Give kernel calls a valid stack pointer
3de6f290e7 SCI: Change default master MIDI volume to 15
739047f887 SCI32: Always reinit GfxText32 statics on game startup
159438848b SCI32: Add workaround for uninitialised read in GK1
5e81db8fd0 SCI32: Add workaround for uninitialised read in Torin
2d0c1c8ab5 SCI: Ensure object name reg_ts are valid before dereferencing them
4284488244 SCI32: Improve bounds checking in SciString trim
5723f2f5fe SCI32: Hack around MIDI parser causing stuck harp animation in KQ7
a1153661c4 SCI: Stop getCurrentCallOrigin from mutating stack frames
3678390f3e SCI: Add clarifying comment to op_rest
ee644ec01b SCI32: Check for game aborts in all kList iteration methods


Commit: 477e31cea69f2ac4f2cf80549d6a773319868a61
    https://github.com/scummvm/scummvm/commit/477e31cea69f2ac4f2cf80549d6a773319868a61
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-03-30T19:46:27-05:00

Commit Message:
SCI32: Ignore invalid audio map entries in GK2

The invalid entries, which are on CD 6, appear to correspond to
audio that's on CD 4 (though not with the correct offset for CD
4's RESOURCE.AUD).

Skipping the invalid map entries on CD 6 should cause these audio
files to be loaded from the CD 4 audio bundle if they are
requested during chapter six since ScummVM combines resources from
all CDs and matches on their IDs.

Changed paths:
    engines/sci/resource.h
    engines/sci/resource_audio.cpp


diff --git a/engines/sci/resource.h b/engines/sci/resource.h
index a9a7a86..3e7a7a5 100644
--- a/engines/sci/resource.h
+++ b/engines/sci/resource.h
@@ -185,7 +185,7 @@ public:
 	}
 
 	// Convert from a resource ID to a base36 patch name
-	Common::String toPatchNameBase36() {
+	Common::String toPatchNameBase36() const {
 		Common::String output;
 
 		output += (getType() == kResourceTypeAudio36) ? '@' : '#'; // Identifier
diff --git a/engines/sci/resource_audio.cpp b/engines/sci/resource_audio.cpp
index 7423890..c70a2a2 100644
--- a/engines/sci/resource_audio.cpp
+++ b/engines/sci/resource_audio.cpp
@@ -430,8 +430,20 @@ int ResourceManager::readAudioMapSCI11(IntMapResourceSource *map) {
 				}
 			}
 
+			const ResourceId id = ResourceId(kResourceTypeAudio36, map->_mapNumber, n & 0xffffff3f);
+
+			// At least version 1.00 of GK2 has multiple invalid audio36 map
+			// entries on CD 6
+			if (g_sci->getGameId() == GID_GK2 &&
+				map->_volumeNumber == 6 &&
+				offset + syncSize >= srcSize) {
+
+				debugC(kDebugLevelResMan, "Invalid offset %u for %s in map %d for disc %d", offset + syncSize, id.toPatchNameBase36().c_str(), map->_mapNumber, map->_volumeNumber);
+				continue;
+			}
+
 			assert(offset + syncSize < srcSize);
-			addResource(ResourceId(kResourceTypeAudio36, map->_mapNumber, n & 0xffffff3f), src, offset + syncSize);
+			addResource(id, src, offset + syncSize);
 		}
 	}
 


Commit: 0be9ace649a5f7cc70ec247a4997a4ed705a5720
    https://github.com/scummvm/scummvm/commit/0be9ace649a5f7cc70ec247a4997a4ed705a5720
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-03-30T19:46:27-05:00

Commit Message:
SCI: Fix incorrect read of LB2/MG256 audio sizes

This happened to work previously because the size was not checked
for validity, and because the audio player calculates its own size
so this value was never actually used.

Changed paths:
    engines/sci/resource_audio.cpp


diff --git a/engines/sci/resource_audio.cpp b/engines/sci/resource_audio.cpp
index c70a2a2..30d01b9 100644
--- a/engines/sci/resource_audio.cpp
+++ b/engines/sci/resource_audio.cpp
@@ -373,7 +373,7 @@ int ResourceManager::readAudioMapSCI11(IntMapResourceSource *map) {
 			byte headerSize = stream->readByte();
 			assert(headerSize == 11 || headerSize == 12);
 
-			stream->skip(5);
+			stream->skip(7);
 			uint32 size = stream->readUint32LE() + headerSize + 2;
 
 			assert(offset + size <= srcSize);


Commit: d0e9724ae18025d31a50842df5951ee56ba47c49
    https://github.com/scummvm/scummvm/commit/d0e9724ae18025d31a50842df5951ee56ba47c49
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-03-30T19:46:27-05:00

Commit Message:
SCI32: Support reading sound effects from normal resource bundles

Changed paths:
    engines/sci/resource.cpp


diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp
index 6aaf51b..921c8c9 100644
--- a/engines/sci/resource.cpp
+++ b/engines/sci/resource.cpp
@@ -2086,6 +2086,28 @@ int Resource::decompress(ResVersion volVersion, Common::SeekableReadStream *file
 	errorNum = ptr ? dec->unpack(file, ptr, szPacked, _size) : SCI_ERROR_RESOURCE_TOO_BIG;
 	if (errorNum)
 		unalloc();
+	else {
+		// At least Lighthouse puts sound effects in RESSCI.00n/RESSCI.PAT
+		// instead of using a RESOURCE.SFX
+		if (getType() == kResourceTypeAudio) {
+			_headerSize = ptr[1];
+			assert(_headerSize == 12);
+			uint32 audioSize = READ_LE_UINT32(ptr + 9);
+			assert(audioSize + _headerSize + 2 == _size);
+			_size = audioSize;
+
+			// TODO: This extra memory copying is necessary because
+			// AudioVolumeResourceSource splits the audio header from the rest
+			// of the data; fix AudioVolumeResourceSource to stop doing this and
+			// then this extra copying can be eliminated too
+			byte *dataPtr = new byte[_size];
+			_data = dataPtr;
+			_header = new byte[_headerSize];
+			memcpy(_header, ptr + 2, _headerSize);
+			memcpy(dataPtr, ptr + 2 + _headerSize, _size);
+			delete[] ptr;
+		}
+	}
 
 	delete dec;
 	return errorNum;


Commit: 65fe7bcfd8431888d9fdf345759bad1a78c455b7
    https://github.com/scummvm/scummvm/commit/65fe7bcfd8431888d9fdf345759bad1a78c455b7
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-03-30T19:46:27-05:00

Commit Message:
SCI: Print more detailed information on audio header size mismatch

Changed paths:
    engines/sci/resource_audio.cpp


diff --git a/engines/sci/resource_audio.cpp b/engines/sci/resource_audio.cpp
index 30d01b9..b9f24cf 100644
--- a/engines/sci/resource_audio.cpp
+++ b/engines/sci/resource_audio.cpp
@@ -116,7 +116,7 @@ bool Resource::loadFromAudioVolumeSCI11(Common::SeekableReadStream *file) {
 
 		if (type == kResourceTypeAudio) {
 			if (_headerSize != 7 && _headerSize != 11 && _headerSize != 12) {
-				warning("Unsupported audio header");
+				warning("Unsupported audio header size %d", _headerSize);
 				unalloc();
 				return false;
 			}


Commit: 766d46153a285794d573d84d237aac3821431a01
    https://github.com/scummvm/scummvm/commit/766d46153a285794d573d84d237aac3821431a01
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-03-30T19:46:27-05:00

Commit Message:
SCI32: Implement known-used portions of kPlayDuck

Changed paths:
    engines/sci/engine/kernel.h
    engines/sci/engine/kernel_tables.h
    engines/sci/engine/kscripts.cpp
    engines/sci/engine/kvideo.cpp
    engines/sci/graphics/video32.cpp
    engines/sci/graphics/video32.h
    engines/sci/sound/audio32.h


diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index 51f4b5d..ebd7d33 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -657,6 +657,11 @@ reg_t kDoSoundPhantasmagoriaMac(EngineState *s, int argc, reg_t *argv);
 
 // SCI3 Kernel functions
 reg_t kPlayDuck(EngineState *s, int argc, reg_t *argv);
+reg_t kPlayDuckPlay(EngineState *s, int argc, reg_t *argv);
+reg_t kPlayDuckSetFrameOut(EngineState *s, int argc, reg_t *argv);
+reg_t kPlayDuckOpen(EngineState *s, int argc, reg_t *argv);
+reg_t kPlayDuckClose(EngineState *s, int argc, reg_t *argv);
+reg_t kPlayDuckSetVolume(EngineState *s, int argc, reg_t *argv);
 #endif
 
 reg_t kDoSoundInit(EngineState *s, int argc, reg_t *argv);
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index 211d96b..95f3197 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -495,6 +495,15 @@ static const SciKernelMapSubEntry kRobot_subops[] = {
 };
 
 //    version,         subId, function-mapping,                    signature,              workarounds
+static const SciKernelMapSubEntry kPlayDuck_subops[] = {
+	{ SIG_SCI3,            1, MAP_CALL(PlayDuckPlay),              "iiiii",                NULL },
+	{ SIG_SCI3,            2, MAP_CALL(PlayDuckSetFrameOut),       "i",                    NULL },
+	{ SIG_SCI3,            5, MAP_CALL(PlayDuckClose),             "",                     NULL },
+	{ SIG_SCI3,            6, MAP_CALL(PlayDuckSetVolume),         "i",                    NULL },
+	SCI_SUBOPENTRY_TERMINATOR
+};
+
+//    version,         subId, function-mapping,                    signature,              workarounds
 static const SciKernelMapSubEntry kRemapColors_subops[] = {
 	{ SIG_SCI32,           0, MAP_CALL(RemapColorsOff),            "(i)",                  NULL },
 	{ SIG_SCI32,           1, MAP_CALL(RemapColorsByRange),        "iiii(i)",              NULL },
@@ -1008,7 +1017,7 @@ static SciKernelMapEntry s_kernelMap[] = {
 	{ MAP_CALL(MorphOn),            SIG_EVERYWHERE,           "",                     NULL,            NULL },
 
 	// SCI3 Kernel Functions
-	{ MAP_CALL(PlayDuck),           SIG_EVERYWHERE,           "(.*)",                 NULL,            NULL },
+	{ MAP_CALL(PlayDuck),           SIG_SCI3, SIGFOR_ALL,     "(.*)",                 kPlayDuck_subops,NULL },
 #endif
 
 	{ NULL, NULL,                   SIG_EVERYWHERE,           NULL,                   NULL,            NULL }
diff --git a/engines/sci/engine/kscripts.cpp b/engines/sci/engine/kscripts.cpp
index 77ef92b..7c4c955 100644
--- a/engines/sci/engine/kscripts.cpp
+++ b/engines/sci/engine/kscripts.cpp
@@ -119,11 +119,28 @@ reg_t kResCheck(EngineState *s, int argc, reg_t *argv) {
 	}
 
 #ifdef ENABLE_SCI32
-	// GK2 stores some VMDs inside of resource volumes, but usually they are
-	// streamed from the filesystem
-	if (res == nullptr && restype == kResourceTypeVMD) {
-		const Common::String fileName = Common::String::format("%u.vmd", argv[1].toUint16());
-		return make_reg(0, Common::File::exists(fileName));
+	// GK2 stores some VMDs inside of resource volumes, but usually videos are
+	// streamed from the filesystem.
+	if (res == nullptr) {
+		const char *format = nullptr;
+		switch (restype) {
+		case kResourceTypeRobot:
+			format = "%u.rbt";
+			break;
+		case kResourceTypeDuck:
+			format = "%u.duk";
+			break;
+		case kResourceTypeVMD:
+			format = "%u.vmd";
+			break;
+		default:
+			format = nullptr;
+		}
+
+		if (format) {
+			const Common::String fileName = Common::String::format(format, argv[1].toUint16());
+			return make_reg(0, Common::File::exists(fileName));
+		}
 	}
 #endif
 
diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp
index 3d689f2..e4f2ff7 100644
--- a/engines/sci/engine/kvideo.cpp
+++ b/engines/sci/engine/kvideo.cpp
@@ -472,52 +472,41 @@ reg_t kPlayVMDRestrictPalette(EngineState *s, int argc, reg_t *argv) {
 }
 
 reg_t kPlayDuck(EngineState *s, int argc, reg_t *argv) {
-	uint16 operation = argv[0].toUint16();
-	Video::VideoDecoder *videoDecoder = 0;
-	bool reshowCursor = g_sci->_gfxCursor->isVisible();
-
-	switch (operation) {
-	case 1:	// Play
-		// 6 params
-		s->_videoState.reset();
-		s->_videoState.fileName = Common::String::format("%d.duk", argv[1].toUint16());
-
-		videoDecoder = new Video::AVIDecoder();
-
-		if (!videoDecoder->loadFile(s->_videoState.fileName)) {
-			warning("Could not open Duck %s", s->_videoState.fileName.c_str());
-			break;
-		}
-
-		if (reshowCursor)
-			g_sci->_gfxCursor->kernelHide();
-
-		{
-		// Duck videos are 16bpp, so we need to change the active pixel format
-		int oldWidth = g_system->getWidth();
-		int oldHeight = g_system->getHeight();
-		Common::List<Graphics::PixelFormat> formats;
-		formats.push_back(videoDecoder->getPixelFormat());
-		initGraphics(640, 480, true, formats);
+	if (!s)
+		return make_reg(0, getSciVersion());
+	error("not supposed to call this");
+}
 
-		if (g_system->getScreenFormat().bytesPerPixel != videoDecoder->getPixelFormat().bytesPerPixel)
-			error("Could not switch screen format for the duck video");
+reg_t kPlayDuckPlay(EngineState *s, int argc, reg_t *argv) {
+	kPlayDuckOpen(s, argc, argv);
+	g_sci->_video32->getDuckPlayer().play(-1);
+	g_sci->_video32->getDuckPlayer().close();
+	return NULL_REG;
+}
 
-		playVideo(videoDecoder, s->_videoState);
+reg_t kPlayDuckSetFrameOut(EngineState *s, int argc, reg_t *argv) {
+	g_sci->_video32->getDuckPlayer().setDoFrameOut((bool)argv[0].toUint16());
+	return NULL_REG;
+}
 
-		// Switch back to 8bpp
-		initGraphics(oldWidth, oldHeight, oldWidth > 320);
-		}
+reg_t kPlayDuckOpen(EngineState *s, int argc, reg_t *argv) {
+	const GuiResourceId resourceId = argv[0].toUint16();
+	const int displayMode = argv[1].toSint16();
+	const int16 x = argv[2].toSint16();
+	const int16 y = argv[3].toSint16();
+	// argv[4] is a cache size argument that we do not use
+	g_sci->_video32->getDuckPlayer().open(resourceId, displayMode, x, y);
+	return NULL_REG;
+}
 
-		if (reshowCursor)
-			g_sci->_gfxCursor->kernelShow();
-		break;
-	default:
-		kStub(s, argc, argv);
-		break;
-	}
+reg_t kPlayDuckClose(EngineState *s, int argc, reg_t *argv) {
+	g_sci->_video32->getDuckPlayer().close();
+	return NULL_REG;
+}
 
-	return s->r_acc;
+reg_t kPlayDuckSetVolume(EngineState *s, int argc, reg_t *argv) {
+	g_sci->_video32->getDuckPlayer().setVolume(argv[0].toUint16());
+	return NULL_REG;
 }
 
 #endif
diff --git a/engines/sci/graphics/video32.cpp b/engines/sci/graphics/video32.cpp
index f4eb2c2..8cd6fc7 100644
--- a/engines/sci/graphics/video32.cpp
+++ b/engines/sci/graphics/video32.cpp
@@ -51,6 +51,25 @@ namespace Graphics { struct Surface; }
 
 namespace Sci {
 
+/**
+ * @returns true if the player should quit
+ */
+static bool flushEvents(EventManager *eventMan) {
+	// Flushing all the keyboard and mouse events out of the event manager
+	// keeps events queued from before the start of playback from accidentally
+	// activating a video stop flag
+	for (;;) {
+		const SciEvent event = eventMan->getSciEvent(SCI_EVENT_KEYBOARD | SCI_EVENT_MOUSE_PRESS | SCI_EVENT_MOUSE_RELEASE | SCI_EVENT_HOT_RECTANGLE | SCI_EVENT_QUIT);
+		if (event.type == SCI_EVENT_NONE) {
+			break;
+		} else if (event.type == SCI_EVENT_QUIT) {
+			return true;
+		}
+	}
+
+	return false;
+}
+
 #pragma mark SEQPlayer
 
 SEQPlayer::SEQPlayer(SegManager *segMan) :
@@ -672,16 +691,8 @@ VMDPlayer::EventFlags VMDPlayer::kernelPlayUntilEvent(const EventFlags flags, co
 }
 
 VMDPlayer::EventFlags VMDPlayer::playUntilEvent(const EventFlags flags) {
-	// Flushing all the keyboard and mouse events out of the event manager
-	// keeps events queued from before the start of playback from accidentally
-	// activating a video stop flag
-	for (;;) {
-		const SciEvent event = _eventMan->getSciEvent(SCI_EVENT_KEYBOARD | SCI_EVENT_MOUSE_PRESS | SCI_EVENT_MOUSE_RELEASE | SCI_EVENT_HOT_RECTANGLE | SCI_EVENT_QUIT);
-		if (event.type == SCI_EVENT_NONE) {
-			break;
-		} else if (event.type == SCI_EVENT_QUIT) {
-			return kEventFlagEnd;
-		}
+	if (flushEvents(_eventMan)) {
+		return kEventFlagEnd;
 	}
 
 	if (flags & kEventFlagReverse) {
@@ -914,4 +925,231 @@ void VMDPlayer::restrictPalette(const uint8 startColor, const int16 endColor) {
 	_endColor = MIN<int16>(255, endColor);
 }
 
+#pragma mark -
+#pragma mark DuckPlayer
+
+DuckPlayer::DuckPlayer(SegManager *segMan, EventManager *eventMan) :
+	_segMan(segMan),
+	_eventMan(eventMan),
+	_decoder(new Video::AVIDecoder(Audio::Mixer::kSFXSoundType)),
+	_plane(nullptr),
+	_status(kDuckClosed),
+	_drawRect(),
+	_volume(Audio::Mixer::kMaxChannelVolume),
+	_doFrameOut(false),
+	_pixelDouble(false),
+	_scaleBuffer(nullptr) {}
+
+DuckPlayer::~DuckPlayer() {
+	close();
+	delete _decoder;
+}
+
+void DuckPlayer::open(const GuiResourceId resourceId, const int displayMode, const int16 x, const int16 y) {
+	if (_status != kDuckClosed) {
+		error("Attempted to play %u.duk, but another video was loaded", resourceId);
+	}
+
+	const Common::String fileName = Common::String::format("%u.duk", resourceId);
+	if (!_decoder->loadFile(fileName)) {
+		error("Can't open %s", fileName.c_str());
+	}
+
+	_decoder->setVolume(_volume);
+	_pixelDouble = displayMode != 0;
+
+	const int16 scale = _pixelDouble ? 2 : 1;
+	_drawRect = Common::Rect(x, y,
+							 (x + _decoder->getWidth()) * scale,
+							 (y + _decoder->getHeight()) * scale);
+
+	g_sci->_gfxCursor32->hide();
+
+	if (_doFrameOut) {
+		_plane = new Plane(_drawRect, kPlanePicColored);
+		g_sci->_gfxFrameout->addPlane(*_plane);
+		g_sci->_gfxFrameout->frameOut(true);
+	}
+
+	const Buffer &currentBuffer = g_sci->_gfxFrameout->getCurrentBuffer();
+	const Graphics::PixelFormat format = _decoder->getPixelFormat();
+
+	if (_pixelDouble) {
+		assert(_scaleBuffer == nullptr);
+		_scaleBuffer = new byte[_drawRect.width() * _drawRect.height() * format.bytesPerPixel];
+	}
+
+	initGraphics(currentBuffer.screenWidth, currentBuffer.screenHeight, true, &format);
+
+	_status = kDuckOpen;
+}
+
+void DuckPlayer::play(const int lastFrameNo) {
+	flushEvents(_eventMan);
+
+	if (_status != kDuckPlaying) {
+		_status = kDuckPlaying;
+		_decoder->start();
+	}
+
+	while (!g_engine->shouldQuit()) {
+		if (_decoder->endOfVideo() || (lastFrameNo != -1 && _decoder->getCurFrame() >= lastFrameNo)) {
+			break;
+		}
+
+		g_sci->sleep(_decoder->getTimeToNextFrame());
+		while (_decoder->needsUpdate()) {
+			renderFrame();
+		}
+
+		SciEvent event = _eventMan->getSciEvent(SCI_EVENT_MOUSE_PRESS | SCI_EVENT_PEEK);
+		if (event.type == SCI_EVENT_MOUSE_PRESS) {
+			flushEvents(_eventMan);
+			break;
+		}
+
+		event = _eventMan->getSciEvent(SCI_EVENT_KEYBOARD | SCI_EVENT_PEEK);
+		if (event.type == SCI_EVENT_KEYBOARD) {
+			bool stop = false;
+			while ((event = _eventMan->getSciEvent(SCI_EVENT_KEYBOARD)),
+				   event.type != SCI_EVENT_NONE) {
+				if (event.character == SCI_KEY_ESC) {
+					stop = true;
+					break;
+				}
+			}
+
+			if (stop) {
+				flushEvents(_eventMan);
+				break;
+			}
+		}
+	}
+}
+
+void DuckPlayer::close() {
+	if (_status == kDuckClosed) {
+		return;
+	}
+
+	_decoder->close();
+
+	const Buffer &currentBuffer = g_sci->_gfxFrameout->getCurrentBuffer();
+	const Graphics::PixelFormat format = Graphics::PixelFormat::createFormatCLUT8();
+	initGraphics(currentBuffer.screenWidth, currentBuffer.screenHeight, true, &format);
+
+	g_sci->_gfxCursor32->unhide();
+
+	if (_doFrameOut) {
+		g_sci->_gfxFrameout->deletePlane(*_plane);
+		g_sci->_gfxFrameout->frameOut(true);
+		_plane = nullptr;
+	}
+
+	_pixelDouble = false;
+	delete[] _scaleBuffer;
+	_scaleBuffer = nullptr;
+
+	_status = kDuckClosed;
+}
+
+static inline uint16 interpolate(const Graphics::PixelFormat &format, const uint16 p1, const uint16 p2) {
+	uint8 r1, g1, b1, r2, g2, b2;
+	format.colorToRGB(p1, r1, g1, b1);
+	format.colorToRGB(p2, r2, g2, b2);
+	return format.RGBToColor((r1 + r2) >> 1, (g1 + g2) >> 1, (b1 + b2) >> 1);
+}
+
+void DuckPlayer::renderFrame() const {
+	const Graphics::Surface *surface = _decoder->decodeNextFrame();
+
+	// Audio-only or non-updated frame
+	if (surface == nullptr) {
+		return;
+	}
+
+	assert(surface->format.bytesPerPixel == 2);
+
+	if (_pixelDouble) {
+		const uint16 *source = (const uint16 *)surface->getPixels();
+		const Graphics::PixelFormat &format = surface->format;
+		uint16 *target = (uint16 *)_scaleBuffer;
+
+#ifndef SCI_DUCK_NO_INTERPOLATION
+		// divide by 2 gets pixel pitch instead of byte pitch for source
+		const uint16 sourcePitch = surface->pitch >> 1;
+#endif
+
+		const uint16 targetPitch = surface->pitch;
+		const bool blackLined = ConfMan.getBool("enable_black_lined_video");
+		for (int y = 0; y < surface->h - 1; ++y) {
+			for (int x = 0; x < surface->w - 1; ++x) {
+#ifndef SCI_DUCK_NO_INTERPOLATION
+				const uint16 a = source[0];
+				const uint16 b = source[1];
+				const uint16 c = source[sourcePitch];
+				const uint16 d = source[sourcePitch + 1];
+
+				target[0] = a;
+				target[1] = interpolate(format, a, b);
+#else
+				const uint16 value = *source;
+				target[0] = value;
+				target[1] = value;
+#endif
+				if (!blackLined) {
+#ifndef SCI_DUCK_NO_INTERPOLATION
+					target[targetPitch] = interpolate(format, a, c);
+					target[targetPitch + 1] = interpolate(format, target[1], interpolate(format, c, d));
+#else
+					target[targetPitch] = value;
+					target[targetPitch + 1] = value;
+#endif
+				}
+
+				target += 2;
+				++source;
+			}
+
+			const uint16 value = *source++;
+			target[0] = value;
+			target[1] = value;
+			if (!blackLined) {
+				target[targetPitch] = value;
+				target[targetPitch + 1] = value;
+			}
+			target += 2;
+
+			if (blackLined) {
+				memset(target, 0, targetPitch * format.bytesPerPixel);
+			}
+
+			target += targetPitch;
+		}
+
+		for (int x = 0; x < surface->w; ++x) {
+			const uint16 lastValue = *source++;
+			target[0] = lastValue;
+			target[1] = lastValue;
+
+			if (!blackLined) {
+				target[targetPitch] = lastValue;
+				target[targetPitch + 1] = lastValue;
+				target += 2;
+			}
+		}
+
+		if (blackLined) {
+			memset(target, 0, targetPitch);
+		}
+
+		g_system->copyRectToScreen(_scaleBuffer, surface->pitch * 2, _drawRect.left, _drawRect.top, _drawRect.width(), _drawRect.height());
+	} else {
+		g_system->copyRectToScreen(surface->getPixels(), surface->pitch, _drawRect.left, _drawRect.top, surface->w, surface->h);
+	}
+
+	g_system->updateScreen();
+	g_sci->getSciDebugger()->onFrame();
+}
+
 } // End of namespace Sci
diff --git a/engines/sci/graphics/video32.h b/engines/sci/graphics/video32.h
index 5ed8fd9..fae5caf 100644
--- a/engines/sci/graphics/video32.h
+++ b/engines/sci/graphics/video32.h
@@ -28,10 +28,11 @@
 #include "common/str.h"           // for String
 #include "sci/engine/vm_types.h"  // for reg_t
 #include "sci/video/robot_decoder.h" // for RobotDecoder
+#include "sci/sound/audio32.h"    // for Audio32::kMaxVolume
+#include "video/avi_decoder.h"    // for AVIDecoder::setVolume
 
 namespace Video {
 class AdvancedVMDDecoder;
-class AVIDecoder;
 }
 namespace Sci {
 class EventManager;
@@ -531,6 +532,103 @@ private:
 	bool _showCursor;
 };
 
+#pragma mark -
+#pragma mark DuckPlayer
+
+class DuckPlayer {
+public:
+	enum DuckStatus {
+		kDuckClosed  = 0,
+		kDuckOpen    = 1,
+		kDuckPlaying = 2,
+		kDuckPaused  = 3
+	};
+
+	DuckPlayer(SegManager *segMan, EventManager *eventMan);
+
+	~DuckPlayer();
+
+	/**
+	 * Opens a stream to a Duck resource.
+	 */
+	void open(const GuiResourceId resourceId, const int displayMode, const int16 x, const int16 y);
+
+	/**
+	 * Stops playback and closes the currently open Duck stream.
+	 */
+	void close();
+
+	/**
+	 * Begins playback of the current Duck video.
+	 */
+	void play(const int lastFrameNo);
+
+	/**
+	 * Sets a flag indicating that an opaque plane should be added
+	 * to the graphics manager underneath the video surface during
+	 * playback.
+	 */
+	void setDoFrameOut(const bool value) { _doFrameOut = value; }
+
+	/**
+	 * Sets the volume of the decoder.
+	 */
+	void setVolume(const uint8 value) {
+		_volume = (uint)value * Audio::Mixer::kMaxChannelVolume / Audio32::kMaxVolume;
+		_decoder->setVolume(_volume);
+	}
+
+private:
+	SegManager *_segMan;
+	EventManager *_eventMan;
+	Video::AVIDecoder *_decoder;
+
+	/**
+	 * An empty plane drawn behind the video when the doFrameOut
+	 * flag is true.
+	 */
+	Plane *_plane;
+
+	/**
+	 * The player status.
+	 */
+	DuckStatus _status;
+
+	/**
+	 * The screen rect where the video should be drawn.
+	 */
+	Common::Rect _drawRect;
+
+	/**
+	 * The playback volume for the player.
+	 */
+	uint8 _volume;
+
+	/**
+	 * If true, frameOut will be called during Duck video playback to update
+	 * other parts of the screen.
+	 */
+	bool _doFrameOut;
+
+	/**
+	 * If true, the video will be pixel doubled during playback.
+	 */
+	bool _pixelDouble;
+
+	/**
+	 * The buffer used to perform scaling of the video.
+	 */
+	byte *_scaleBuffer;
+
+	/**
+	 * Renders the current frame to the system video buffer.
+	 */
+	void renderFrame() const;
+};
+
+#pragma mark -
+#pragma mark Video32
+
 /**
  * Video32 provides facilities for playing back
  * video in SCI engine.
@@ -541,18 +639,21 @@ public:
 	_SEQPlayer(segMan),
 	_AVIPlayer(segMan, eventMan),
 	_VMDPlayer(segMan, eventMan),
-	_robotPlayer(segMan) {}
+	_robotPlayer(segMan),
+	_duckPlayer(segMan, eventMan) {}
 
 	SEQPlayer &getSEQPlayer() { return _SEQPlayer; }
 	AVIPlayer &getAVIPlayer() { return _AVIPlayer; }
 	VMDPlayer &getVMDPlayer() { return _VMDPlayer; }
 	RobotDecoder &getRobotPlayer() { return _robotPlayer; }
+	DuckPlayer &getDuckPlayer() { return _duckPlayer; }
 
 private:
 	SEQPlayer _SEQPlayer;
 	AVIPlayer _AVIPlayer;
 	VMDPlayer _VMDPlayer;
 	RobotDecoder _robotPlayer;
+	DuckPlayer _duckPlayer;
 };
 } // End of namespace Sci
 
diff --git a/engines/sci/sound/audio32.h b/engines/sci/sound/audio32.h
index a9905ab..9130cbe 100644
--- a/engines/sci/sound/audio32.h
+++ b/engines/sci/sound/audio32.h
@@ -160,12 +160,6 @@ public:
 	Audio32(ResourceManager *resMan);
 	~Audio32();
 
-private:
-	ResourceManager *_resMan;
-	Audio::Mixer *_mixer;
-	Audio::SoundHandle _handle;
-	Common::Mutex _mutex;
-
 	enum {
 		/**
 		 * The maximum channel volume.
@@ -173,6 +167,12 @@ private:
 		kMaxVolume = 127
 	};
 
+private:
+	ResourceManager *_resMan;
+	Audio::Mixer *_mixer;
+	Audio::SoundHandle _handle;
+	Common::Mutex _mutex;
+
 #pragma mark -
 #pragma mark AudioStream implementation
 public:


Commit: 3b34f17fb3f8d4f325fd8f7b10dc3a9325d72b29
    https://github.com/scummvm/scummvm/commit/3b34f17fb3f8d4f325fd8f7b10dc3a9325d72b29
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-03-30T19:46:27-05:00

Commit Message:
SCI32: Add kWebConnect and kWinExec

Used by Phant2.

Changed paths:
    engines/sci/engine/kernel.cpp
    engines/sci/engine/kernel.h
    engines/sci/engine/kernel_tables.h
    engines/sci/engine/kmisc.cpp


diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp
index d029923..60d4ccb 100644
--- a/engines/sci/engine/kernel.cpp
+++ b/engines/sci/engine/kernel.cpp
@@ -806,7 +806,7 @@ enum {
 	kKernelEntriesSci2 = 0x8b,
 	kKernelEntriesGk2Demo = 0xa0,
 	kKernelEntriesSci21 = 0x9d,
-	kKernelEntriesSci3 = 0xa1
+	kKernelEntriesSci3 = 0xa2
 };
 #endif
 
diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index ebd7d33..3d33701 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -662,6 +662,8 @@ reg_t kPlayDuckSetFrameOut(EngineState *s, int argc, reg_t *argv);
 reg_t kPlayDuckOpen(EngineState *s, int argc, reg_t *argv);
 reg_t kPlayDuckClose(EngineState *s, int argc, reg_t *argv);
 reg_t kPlayDuckSetVolume(EngineState *s, int argc, reg_t *argv);
+reg_t kWebConnect(EngineState *s, int argc, reg_t *argv);
+reg_t kWinExec(EngineState *s, int argc, reg_t *argv);
 #endif
 
 reg_t kDoSoundInit(EngineState *s, int argc, reg_t *argv);
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index 95f3197..46132d3 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -1018,6 +1018,8 @@ static SciKernelMapEntry s_kernelMap[] = {
 
 	// SCI3 Kernel Functions
 	{ MAP_CALL(PlayDuck),           SIG_SCI3, SIGFOR_ALL,     "(.*)",                 kPlayDuck_subops,NULL },
+	{ MAP_CALL(WebConnect),         SIG_SCI3, SIGFOR_ALL,     "(r)",                  NULL,            NULL },
+	{ MAP_CALL(WinExec),            SIG_SCI3, SIGFOR_ALL,     "r",                    NULL,            NULL },
 #endif
 
 	{ NULL, NULL,                   SIG_EVERYWHERE,           NULL,                   NULL,            NULL }
@@ -1499,7 +1501,8 @@ static const char *const sci21_default_knames[] = {
 	/*0x9d*/ "Dummy",
 	/*0x9e*/ "WebConnect",
 	/*0x9f*/ "Dummy",
-	/*0xa0*/ "PlayDuck"
+	/*0xa0*/ "PlayDuck",
+	/*0xa1*/ "WinExec"
 };
 
 #endif
diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp
index 9aa03a4..f0090cf 100644
--- a/engines/sci/engine/kmisc.cpp
+++ b/engines/sci/engine/kmisc.cpp
@@ -643,6 +643,16 @@ reg_t kPlatform32(EngineState *s, int argc, reg_t *argv) {
 		return make_reg(0, 0);
 	}
 }
+
+reg_t kWebConnect(EngineState *s, int argc, reg_t *argv) {
+	const Common::String baseUrl = "https://web.archive.org/web/1996/";
+	const Common::String gameUrl = argc > 0 ? s->_segMan->getString(argv[0]) : "http://www.sierra.com";
+	return make_reg(0, !g_system->openUrl(baseUrl + gameUrl));
+}
+
+reg_t kWinExec(EngineState *s, int argc, reg_t *argv) {
+	return NULL_REG;
+}
 #endif
 
 reg_t kEmpty(EngineState *s, int argc, reg_t *argv) {


Commit: f4d3664d3fb529a451ef57658b443fb1c878bdfa
    https://github.com/scummvm/scummvm/commit/f4d3664d3fb529a451ef57658b443fb1c878bdfa
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-03-30T19:46:27-05:00

Commit Message:
SCI: Replace magic numbers in reg_t handling with symbols

Changed paths:
    engines/sci/engine/kernel.cpp
    engines/sci/engine/scriptdebug.cpp
    engines/sci/engine/vm.cpp
    engines/sci/engine/vm.h
    engines/sci/engine/vm_types.h


diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp
index 60d4ccb..13a836a 100644
--- a/engines/sci/engine/kernel.cpp
+++ b/engines/sci/engine/kernel.cpp
@@ -380,7 +380,7 @@ uint16 Kernel::findRegType(reg_t reg) {
 	if (!reg.getSegment())
 		return SIG_TYPE_INTEGER | (reg.getOffset() ? 0 : SIG_TYPE_NULL);
 
-	if (reg.getSegment() == 0xFFFF)
+	if (reg.getSegment() == kUninitializedSegment)
 		return SIG_TYPE_UNINITIALIZED;
 
 	// Otherwise it's an object
diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp
index d15cf83..971c721 100644
--- a/engines/sci/engine/scriptdebug.cpp
+++ b/engines/sci/engine/scriptdebug.cpp
@@ -230,12 +230,12 @@ reg_t disassemble(EngineState *s, reg32_t pos, reg_t objAddr, bool printBWTag, b
 			if (opsize) {
 				int8 offset = (int8)scr[retval.getOffset()];
 				retval.incOffset(1);
-				debugN("\t%02x  [%04x]", 0xff & offset, 0xffff & (retval.getOffset() + offset));
+				debugN("\t%02x  [%04x]", 0xff & offset, kOffsetMask & (retval.getOffset() + offset));
 			}
 			else {
 				int16 offset = (int16)READ_SCI11ENDIAN_UINT16(&scr[retval.getOffset()]);
 				retval.incOffset(2);
-				debugN("\t%04x  [%04x]", 0xffff & offset, 0xffff & (retval.getOffset() + offset));
+				debugN("\t%04x  [%04x]", 0xffff & offset, kOffsetMask & (retval.getOffset() + offset));
 			}
 			break;
 
diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp
index 74a2841..a9d575b 100644
--- a/engines/sci/engine/vm.cpp
+++ b/engines/sci/engine/vm.cpp
@@ -120,7 +120,7 @@ extern const char *opcodeNames[]; // from scriptdebug.cpp
 
 static reg_t read_var(EngineState *s, int type, int index) {
 	if (validate_variable(s->variables[type], s->stack_base, type, s->variablesMax[type], index)) {
-		if (s->variables[type][index].getSegment() == 0xffff) {
+		if (s->variables[type][index].getSegment() == kUninitializedSegment) {
 			switch (type) {
 			case VAR_TEMP: {
 				// Uninitialized read on a temp
@@ -194,7 +194,7 @@ static void write_var(EngineState *s, int type, int index, reg_t value) {
 		//  this happens at least in sq1/room 44 (slot-machine), because a send is missing parameters, then
 		//  those parameters are taken from uninitialized stack and afterwards they are copied back into temps
 		//  if we don't remove the segment, we would get false-positive uninitialized reads later
-		if (type == VAR_TEMP && value.getSegment() == 0xffff)
+		if (type == VAR_TEMP && value.getSegment() == kUninitializedSegment)
 			value.setSegment(0);
 
 		s->variables[type][index] = value;
@@ -331,7 +331,7 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
 
 		assert(argp[0].toUint16() == argc); // The first argument is argc
 		ExecStack xstack(work_obj, send_obj, curSP, argc, argp,
-							0xFFFF, curFP, selector, -1, -1, -1, -1,
+							kUninitializedSegment, curFP, selector, -1, -1, -1, -1,
 							origin, stackType);
 
 		if (selectorType == kSelectorVariable)
@@ -360,7 +360,7 @@ static void addKernelCallToExecStack(EngineState *s, int kernelCallNr, int kerne
 	// Add stack frame to indicate we're executing a callk.
 	// This is useful in debugger backtraces if this
 	// kernel function calls a script itself.
-	ExecStack xstack(NULL_REG, NULL_REG, NULL, argc, argv - 1, 0xFFFF, make_reg32(0, 0),
+	ExecStack xstack(NULL_REG, NULL_REG, NULL, argc, argv - 1, kUninitializedSegment, make_reg32(0, 0),
 						-1, kernelCallNr, kernelSubCallNr, -1, -1, s->_executionStack.size() - 1, EXEC_STACK_TYPE_KERNEL);
 	s->_executionStack.push_back(xstack);
 }
@@ -884,7 +884,7 @@ void run_vm(EngineState *s) {
 			// We shouldn't initialize temp variables at all
 			//  We put special segment 0xFFFF in there, so that uninitialized reads can get detected
 			for (int i = 0; i < opparams[0]; i++)
-				s->xs->sp[i] = make_reg(0xffff, 0);
+				s->xs->sp[i] = make_reg(kUninitializedSegment, 0);
 
 			s->xs->sp += opparams[0];
 			break;
diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h
index 18549e3..dbd4ee1 100644
--- a/engines/sci/engine/vm.h
+++ b/engines/sci/engine/vm.h
@@ -116,7 +116,7 @@ struct ExecStack {
 		fp = sp = sp_;
 		argc = argc_;
 		variables_argp = argp_;
-		if (localsSegment_ != 0xFFFF)
+		if (localsSegment_ != kUninitializedSegment)
 			local_segment = localsSegment_;
 		else
 			local_segment = pc_.getSegment();
diff --git a/engines/sci/engine/vm_types.h b/engines/sci/engine/vm_types.h
index e60f52e..734f4d3 100644
--- a/engines/sci/engine/vm_types.h
+++ b/engines/sci/engine/vm_types.h
@@ -30,6 +30,12 @@ namespace Sci {
 // Segment ID type
 typedef uint16 SegmentId;
 
+enum {
+	kUninitializedSegment = 0x1FFF,
+	kSegmentMask = 0x1FFF,
+	kOffsetMask = 0x7FFFF
+};
+
 struct reg_t {
 	// Segment and offset. These should never be accessed directly
 	SegmentId _segment;
@@ -61,14 +67,14 @@ struct reg_t {
 	}
 
 	bool isPointer() const {
-		return getSegment() != 0 && getSegment() != 0xFFFF;
+		return getSegment() != 0 && getSegment() != kUninitializedSegment;
 	}
 
 	uint16 requireUint16() const;
 	int16 requireSint16() const;
 
 	inline bool isInitialized() const {
-		return getSegment() != 0xFFFF;
+		return getSegment() != kUninitializedSegment;
 	}
 
 	// Comparison operators
@@ -173,7 +179,7 @@ static inline reg_t make_reg(SegmentId segment, uint16 offset) {
 	return r;
 }
 
-#define PRINT_REG(r) (0xffff) & (unsigned) (r).getSegment(), (unsigned) (r).getOffset()
+#define PRINT_REG(r) (kSegmentMask) & (unsigned) (r).getSegment(), (unsigned) (r).getOffset()
 
 // A true 32-bit reg_t
 struct reg32_t {


Commit: ceacf7df12edbdce058f9124ea3639a490fd824b
    https://github.com/scummvm/scummvm/commit/ceacf7df12edbdce058f9124ea3639a490fd824b
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-03-30T19:46:27-05:00

Commit Message:
SCI: Handle >64KiB offsets in parse_reg_t

Changed paths:
    engines/sci/console.cpp


diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index 16f5952..5c7a9e6 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -4233,14 +4233,14 @@ static int parse_reg_t(EngineState *s, const char *str, reg_t *dest, bool mayBeV
 		relativeOffset = true;
 
 		if (!scumm_strnicmp(str + 1, "PC", 2)) {
-			// TODO: Handle 32-bit PC addresses
 			reg32_t pc = s->_executionStack.back().addr.pc;
-			*dest = make_reg(pc.getSegment(), (uint16)pc.getOffset());
+			dest->setSegment(pc.getSegment());
+			dest->setOffset(pc.getOffset());
 			offsetStr = str + 3;
 		} else if (!scumm_strnicmp(str + 1, "P", 1)) {
-			// TODO: Handle 32-bit PC addresses
 			reg32_t pc = s->_executionStack.back().addr.pc;
-			*dest = make_reg(pc.getSegment(), (uint16)pc.getOffset());
+			dest->setSegment(pc.getSegment());
+			dest->setOffset(pc.getOffset());
 			offsetStr = str + 2;
 		} else if (!scumm_strnicmp(str + 1, "PREV", 4)) {
 			*dest = s->r_prev;


Commit: 4c942758c073ac007f8eefc819bcf7e2ac58557c
    https://github.com/scummvm/scummvm/commit/4c942758c073ac007f8eefc819bcf7e2ac58557c
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-03-30T19:46:27-05:00

Commit Message:
SCI32: Use built-in system font as default font for GfxText32

Fixes the non-interactive Lighthouse demo.

Changed paths:
    engines/sci/graphics/font.cpp
    engines/sci/graphics/font.h
    engines/sci/graphics/text32.cpp
    engines/sci/graphics/text32.h


diff --git a/engines/sci/graphics/font.cpp b/engines/sci/graphics/font.cpp
index ff2f361..8dd6cbd 100644
--- a/engines/sci/graphics/font.cpp
+++ b/engines/sci/graphics/font.cpp
@@ -27,34 +27,206 @@
 
 namespace Sci {
 
-GfxFontFromResource::GfxFontFromResource(ResourceManager *resMan, GfxScreen *screen, GuiResourceId resourceId)
+#ifdef ENABLE_SCI32
+static const byte sci32SystemFont[] = {
+	0x00, 0x00, 0x80, 0x00, 0x08, 0x00, 0x06, 0x01,
+	0x09, 0x01, 0x0c, 0x01, 0x0f, 0x01, 0x12, 0x01,
+	0x15, 0x01, 0x18, 0x01, 0x1b, 0x01, 0x1e, 0x01,
+	0x21, 0x01, 0x26, 0x01, 0x29, 0x01, 0x2c, 0x01,
+	0x2f, 0x01, 0x32, 0x01, 0x35, 0x01, 0x38, 0x01,
+	0x3b, 0x01, 0x3e, 0x01, 0x41, 0x01, 0x44, 0x01,
+	0x47, 0x01, 0x4a, 0x01, 0x4d, 0x01, 0x50, 0x01,
+	0x53, 0x01, 0x56, 0x01, 0x59, 0x01, 0x5c, 0x01,
+	0x5f, 0x01, 0x62, 0x01, 0x65, 0x01, 0x68, 0x01,
+	0x71, 0x01, 0x7a, 0x01, 0x83, 0x01, 0x8c, 0x01,
+	0x95, 0x01, 0x9e, 0x01, 0xa7, 0x01, 0xb0, 0x01,
+	0xb9, 0x01, 0xc2, 0x01, 0xc9, 0x01, 0xd3, 0x01,
+	0xdc, 0x01, 0xe5, 0x01, 0xee, 0x01, 0xf7, 0x01,
+	0x00, 0x02, 0x09, 0x02, 0x12, 0x02, 0x1b, 0x02,
+	0x24, 0x02, 0x2d, 0x02, 0x36, 0x02, 0x3f, 0x02,
+	0x48, 0x02, 0x51, 0x02, 0x5a, 0x02, 0x63, 0x02,
+	0x6c, 0x02, 0x75, 0x02, 0x7e, 0x02, 0x87, 0x02,
+	0x90, 0x02, 0x99, 0x02, 0xa2, 0x02, 0xab, 0x02,
+	0xb4, 0x02, 0xbd, 0x02, 0xc6, 0x02, 0xcf, 0x02,
+	0xd8, 0x02, 0xe1, 0x02, 0xea, 0x02, 0xf3, 0x02,
+	0xfc, 0x02, 0x05, 0x03, 0x0e, 0x03, 0x17, 0x03,
+	0x20, 0x03, 0x29, 0x03, 0x32, 0x03, 0x3b, 0x03,
+	0x44, 0x03, 0x4d, 0x03, 0x56, 0x03, 0x5f, 0x03,
+	0x68, 0x03, 0x71, 0x03, 0x7a, 0x03, 0x83, 0x03,
+	0x8c, 0x03, 0x95, 0x03, 0x9e, 0x03, 0xa7, 0x03,
+	0xb0, 0x03, 0xb9, 0x03, 0xc2, 0x03, 0xcb, 0x03,
+	0xd4, 0x03, 0xdd, 0x03, 0xe6, 0x03, 0xef, 0x03,
+	0xf8, 0x03, 0x01, 0x04, 0x0a, 0x04, 0x13, 0x04,
+	0x1c, 0x04, 0x25, 0x04, 0x2e, 0x04, 0x37, 0x04,
+	0x40, 0x04, 0x49, 0x04, 0x52, 0x04, 0x5b, 0x04,
+	0x64, 0x04, 0x6d, 0x04, 0x76, 0x04, 0x7f, 0x04,
+	0x88, 0x04, 0x91, 0x04, 0x9b, 0x04, 0xa4, 0x04,
+	0xad, 0x04, 0xb6, 0x04, 0xbf, 0x04, 0x02, 0x01,
+	0x00, 0x02, 0x01, 0x00, 0x02, 0x01, 0x40, 0x02,
+	0x01, 0x40, 0x02, 0x01, 0x40, 0x02, 0x01, 0x40,
+	0x02, 0x01, 0x40, 0x02, 0x01, 0x40, 0x02, 0x01,
+	0x40, 0x13, 0x01, 0x00, 0x00, 0x00, 0x02, 0x01,
+	0x40, 0x02, 0x01, 0x40, 0x02, 0x01, 0x40, 0x02,
+	0x01, 0x40, 0x02, 0x01, 0x40, 0x02, 0x01, 0x40,
+	0x02, 0x01, 0x40, 0x02, 0x01, 0x40, 0x02, 0x01,
+	0x40, 0x02, 0x01, 0x40, 0x02, 0x01, 0x40, 0x02,
+	0x01, 0x40, 0x02, 0x01, 0x40, 0x02, 0x01, 0x40,
+	0x02, 0x01, 0x40, 0x02, 0x01, 0x40, 0x02, 0x01,
+	0x40, 0x02, 0x01, 0x40, 0x02, 0x01, 0x40, 0x02,
+	0x01, 0x40, 0x02, 0x01, 0x40, 0x02, 0x01, 0x40,
+	0x04, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x02, 0x07, 0x40, 0x40, 0x40, 0x40, 0x00,
+	0x40, 0x00, 0x05, 0x07, 0x50, 0x50, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x06, 0x07, 0x28, 0x7c, 0x28,
+	0x28, 0x7c, 0x28, 0x00, 0x04, 0x07, 0x20, 0x30,
+	0x40, 0x20, 0x10, 0x60, 0x20, 0x06, 0x07, 0x24,
+	0x58, 0x34, 0x28, 0x40, 0x00, 0x00, 0x04, 0x07,
+	0x20, 0x30, 0x40, 0x20, 0x40, 0x30, 0x20, 0x03,
+	0x07, 0x20, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00,
+	0x04, 0x07, 0x10, 0x20, 0x40, 0x40, 0x40, 0x20,
+	0x10, 0x04, 0x07, 0x40, 0x20, 0x10, 0x10, 0x10,
+	0x20, 0x40, 0x06, 0x05, 0x10, 0x54, 0x38, 0x54,
+	0x10, 0x04, 0x08, 0x00, 0x20, 0x20, 0x70, 0x20,
+	0x20, 0x00, 0x00, 0x03, 0x07, 0x00, 0x00, 0x00,
+	0x00, 0x20, 0x20, 0x40, 0x05, 0x07, 0x00, 0x00,
+	0x00, 0x70, 0x00, 0x00, 0x00, 0x04, 0x07, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x05, 0x07,
+	0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x00, 0x05,
+	0x07, 0x30, 0x48, 0x58, 0x68, 0x48, 0x30, 0x00,
+	0x05, 0x07, 0x20, 0x60, 0x20, 0x20, 0x20, 0x70,
+	0x00, 0x05, 0x07, 0x30, 0x48, 0x08, 0x30, 0x40,
+	0x78, 0x00, 0x05, 0x07, 0x70, 0x08, 0x30, 0x08,
+	0x08, 0x70, 0x00, 0x05, 0x07, 0x18, 0x28, 0x48,
+	0x78, 0x08, 0x08, 0x00, 0x05, 0x07, 0x78, 0x40,
+	0x70, 0x08, 0x08, 0x70, 0x00, 0x05, 0x07, 0x30,
+	0x40, 0x70, 0x48, 0x48, 0x30, 0x00, 0x05, 0x07,
+	0x78, 0x08, 0x10, 0x20, 0x20, 0x20, 0x00, 0x05,
+	0x07, 0x30, 0x48, 0x30, 0x48, 0x48, 0x30, 0x00,
+	0x05, 0x07, 0x30, 0x48, 0x48, 0x38, 0x08, 0x30,
+	0x00, 0x02, 0x07, 0x00, 0x40, 0x00, 0x00, 0x40,
+	0x00, 0x00, 0x03, 0x07, 0x00, 0x20, 0x00, 0x00,
+	0x20, 0x20, 0x40, 0x04, 0x07, 0x00, 0x10, 0x20,
+	0x40, 0x20, 0x10, 0x00, 0x04, 0x07, 0x00, 0x00,
+	0x70, 0x00, 0x70, 0x00, 0x00, 0x04, 0x07, 0x00,
+	0x40, 0x20, 0x10, 0x20, 0x40, 0x00, 0x04, 0x07,
+	0x20, 0x50, 0x10, 0x20, 0x20, 0x00, 0x20, 0x08,
+	0x07, 0x1c, 0x2a, 0x55, 0x55, 0x2e, 0x18, 0x00,
+	0x05, 0x07, 0x30, 0x48, 0x48, 0x78, 0x48, 0x48,
+	0x00, 0x05, 0x07, 0x70, 0x48, 0x70, 0x48, 0x48,
+	0x70, 0x00, 0x05, 0x07, 0x30, 0x48, 0x40, 0x40,
+	0x48, 0x30, 0x00, 0x05, 0x07, 0x70, 0x48, 0x48,
+	0x48, 0x48, 0x70, 0x00, 0x05, 0x07, 0x78, 0x40,
+	0x70, 0x40, 0x40, 0x78, 0x00, 0x05, 0x07, 0x78,
+	0x40, 0x70, 0x40, 0x40, 0x40, 0x00, 0x05, 0x07,
+	0x30, 0x48, 0x40, 0x58, 0x48, 0x30, 0x00, 0x05,
+	0x07, 0x48, 0x48, 0x78, 0x48, 0x48, 0x48, 0x00,
+	0x04, 0x07, 0x70, 0x20, 0x20, 0x20, 0x20, 0x70,
+	0x00, 0x05, 0x07, 0x08, 0x08, 0x08, 0x08, 0x48,
+	0x30, 0x00, 0x05, 0x07, 0x48, 0x50, 0x60, 0x50,
+	0x48, 0x48, 0x00, 0x05, 0x07, 0x40, 0x40, 0x40,
+	0x40, 0x40, 0x78, 0x00, 0x06, 0x07, 0x44, 0x6c,
+	0x54, 0x44, 0x44, 0x44, 0x00, 0x06, 0x07, 0x44,
+	0x64, 0x54, 0x4c, 0x44, 0x44, 0x00, 0x05, 0x07,
+	0x30, 0x48, 0x48, 0x48, 0x48, 0x30, 0x00, 0x05,
+	0x07, 0x70, 0x48, 0x48, 0x70, 0x40, 0x40, 0x00,
+	0x06, 0x07, 0x30, 0x48, 0x48, 0x48, 0x48, 0x38,
+	0x04, 0x05, 0x07, 0x70, 0x48, 0x48, 0x70, 0x48,
+	0x48, 0x00, 0x05, 0x07, 0x30, 0x48, 0x20, 0x10,
+	0x48, 0x30, 0x00, 0x06, 0x07, 0x7c, 0x10, 0x10,
+	0x10, 0x10, 0x10, 0x00, 0x05, 0x07, 0x48, 0x48,
+	0x48, 0x48, 0x48, 0x30, 0x00, 0x06, 0x07, 0x44,
+	0x44, 0x44, 0x44, 0x28, 0x10, 0x00, 0x06, 0x07,
+	0x44, 0x44, 0x44, 0x54, 0x54, 0x28, 0x00, 0x06,
+	0x07, 0x44, 0x28, 0x10, 0x10, 0x28, 0x44, 0x00,
+	0x06, 0x07, 0x44, 0x44, 0x28, 0x10, 0x10, 0x10,
+	0x00, 0x05, 0x07, 0x78, 0x08, 0x10, 0x20, 0x40,
+	0x78, 0x00, 0x03, 0x07, 0x60, 0x40, 0x40, 0x40,
+	0x40, 0x40, 0x60, 0x05, 0x07, 0x40, 0x20, 0x20,
+	0x10, 0x10, 0x08, 0x00, 0x03, 0x07, 0x60, 0x20,
+	0x20, 0x20, 0x20, 0x20, 0x60, 0x04, 0x07, 0x20,
+	0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x07,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x03,
+	0x07, 0x40, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x05, 0x07, 0x00, 0x30, 0x08, 0x38, 0x48, 0x38,
+	0x00, 0x05, 0x07, 0x40, 0x40, 0x70, 0x48, 0x48,
+	0x70, 0x00, 0x05, 0x07, 0x00, 0x30, 0x48, 0x40,
+	0x48, 0x30, 0x00, 0x05, 0x07, 0x08, 0x08, 0x38,
+	0x48, 0x48, 0x38, 0x00, 0x05, 0x07, 0x00, 0x30,
+	0x48, 0x78, 0x40, 0x38, 0x00, 0x05, 0x07, 0x18,
+	0x20, 0x70, 0x20, 0x20, 0x20, 0x00, 0x05, 0x07,
+	0x00, 0x30, 0x48, 0x48, 0x38, 0x48, 0x30, 0x05,
+	0x07, 0x40, 0x40, 0x50, 0x68, 0x48, 0x48, 0x00,
+	0x02, 0x07, 0x40, 0x00, 0x40, 0x40, 0x40, 0x40,
+	0x00, 0x04, 0x07, 0x10, 0x00, 0x10, 0x10, 0x10,
+	0x10, 0x60, 0x04, 0x07, 0x40, 0x50, 0x50, 0x60,
+	0x50, 0x50, 0x00, 0x02, 0x07, 0x40, 0x40, 0x40,
+	0x40, 0x40, 0x40, 0x00, 0x06, 0x07, 0x00, 0x68,
+	0x54, 0x54, 0x54, 0x54, 0x00, 0x05, 0x07, 0x00,
+	0x50, 0x68, 0x48, 0x48, 0x48, 0x00, 0x05, 0x07,
+	0x00, 0x30, 0x48, 0x48, 0x48, 0x30, 0x00, 0x05,
+	0x07, 0x00, 0x70, 0x48, 0x48, 0x70, 0x40, 0x40,
+	0x05, 0x07, 0x00, 0x30, 0x48, 0x48, 0x38, 0x08,
+	0x08, 0x05, 0x07, 0x00, 0x58, 0x60, 0x40, 0x40,
+	0x40, 0x00, 0x05, 0x07, 0x00, 0x38, 0x40, 0x30,
+	0x08, 0x70, 0x00, 0x04, 0x07, 0x20, 0x70, 0x20,
+	0x20, 0x20, 0x20, 0x00, 0x05, 0x07, 0x00, 0x48,
+	0x48, 0x48, 0x48, 0x38, 0x00, 0x06, 0x07, 0x00,
+	0x44, 0x44, 0x44, 0x28, 0x10, 0x00, 0x06, 0x07,
+	0x00, 0x54, 0x54, 0x54, 0x54, 0x28, 0x00, 0x05,
+	0x07, 0x00, 0x48, 0x48, 0x30, 0x48, 0x48, 0x00,
+	0x05, 0x07, 0x00, 0x48, 0x48, 0x48, 0x38, 0x08,
+	0x70, 0x05, 0x08, 0x00, 0x78, 0x08, 0x30, 0x40,
+	0x78, 0x00, 0x00, 0x04, 0x07, 0x10, 0x20, 0x20,
+	0x40, 0x20, 0x20, 0x10, 0x03, 0x07, 0x40, 0x40,
+	0x40, 0x00, 0x40, 0x40, 0x40, 0x04, 0x07, 0x40,
+	0x20, 0x20, 0x10, 0x20, 0x20, 0x40, 0x05, 0x07,
+	0x28, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+	0x01, 0x40
+};
+#endif
+
+	GfxFontFromResource::GfxFontFromResource(ResourceManager *resMan, GfxScreen *screen, GuiResourceId resourceId)
 	: _resourceId(resourceId), _screen(screen), _resMan(resMan) {
-	assert(resourceId != -1);
+	if (getSciVersion() < SCI_VERSION_2) {
+		assert(resourceId != -1);
+	}
 
-	// Workaround: lsl1sci mixes its own internal fonts with the global
-	// SCI ones, so we translate them here, by removing their extra bits
-	if (!resMan->testResource(ResourceId(kResourceTypeFont, resourceId)))
-		resourceId = resourceId & 0x7ff;
+#ifdef ENABLE_SCI32
+	if (getSciVersion() >= SCI_VERSION_2 && resourceId == kSci32SystemFont) {
+		_resource = nullptr;
+		_resourceData = SciSpan<const byte>(sci32SystemFont, sizeof(sci32SystemFont), "system font");
+	} else {
+#endif
+		// Workaround: lsl1sci mixes its own internal fonts with the global
+		// SCI ones, so we translate them here, by removing their extra bits
+		if (!resMan->testResource(ResourceId(kResourceTypeFont, resourceId)))
+			resourceId = resourceId & 0x7ff;
 
-	_resource = resMan->findResource(ResourceId(kResourceTypeFont, resourceId), true);
-	if (!_resource) {
-		error("font resource %d not found", resourceId);
+		_resource = resMan->findResource(ResourceId(kResourceTypeFont, resourceId), true);
+		if (!_resource) {
+			error("font resource %d not found", resourceId);
+		}
+		_resourceData = *_resource;
+#ifdef ENABLE_SCI32
 	}
+#endif
 
-	_numChars = _resource->getUint16SE32At(2);
-	_fontHeight = _resource->getUint16SE32At(4);
+	_numChars = _resourceData.getUint16SE32At(2);
+	_fontHeight = _resourceData.getUint16SE32At(4);
 	_chars = new Charinfo[_numChars];
 	// filling info for every char
 	for (int16 i = 0; i < _numChars; i++) {
-		_chars[i].offset = _resource->getUint16SE32At(6 + i * 2);
-		_chars[i].width = _resource->getUint8At(_chars[i].offset);
-		_chars[i].height = _resource->getUint8At(_chars[i].offset + 1);
+		_chars[i].offset = _resourceData.getUint16SE32At(6 + i * 2);
+		_chars[i].width = _resourceData.getUint8At(_chars[i].offset);
+		_chars[i].height = _resourceData.getUint8At(_chars[i].offset + 1);
 	}
 }
 
 GfxFontFromResource::~GfxFontFromResource() {
 	delete[] _chars;
-	_resMan->unlockResource(_resource);
+	if (_resource) {
+		_resMan->unlockResource(_resource);
+	}
 }
 
 GuiResourceId GfxFontFromResource::getResourceId() {
@@ -64,19 +236,22 @@ GuiResourceId GfxFontFromResource::getResourceId() {
 uint8 GfxFontFromResource::getHeight() {
 	return _fontHeight;
 }
+
 uint8 GfxFontFromResource::getCharWidth(uint16 chr) {
 	return chr < _numChars ? _chars[chr].width : 0;
 }
+
 uint8 GfxFontFromResource::getCharHeight(uint16 chr) {
 	return chr < _numChars ? _chars[chr].height : 0;
 }
+
 SciSpan<const byte> GfxFontFromResource::getCharData(uint16 chr) {
 	if (chr >= _numChars) {
 		return SciSpan<const byte>();
 	}
 
-	const uint32 size = (chr + 1 >= _numChars ? _resource->size() : _chars[chr + 1].offset) - _chars[chr].offset - 2;
-	return _resource->subspan(_chars[chr].offset + 2, size);
+	const uint32 size = (chr + 1 >= _numChars ? _resourceData.size() : _chars[chr + 1].offset) - _chars[chr].offset - 2;
+	return _resourceData.subspan(_chars[chr].offset + 2, size);
 }
 
 void GfxFontFromResource::draw(uint16 chr, int16 top, int16 left, byte color, bool greyedOutput) {
@@ -114,7 +289,6 @@ void GfxFontFromResource::draw(uint16 chr, int16 top, int16 left, byte color, bo
 }
 
 #ifdef ENABLE_SCI32
-
 void GfxFontFromResource::drawToBuffer(uint16 chr, int16 top, int16 left, byte color, bool greyedOutput, byte *buffer, int16 bufWidth, int16 bufHeight) {
 	if (chr >= _numChars) {
 		// SSCI silently ignores attempts to draw characters that do not exist
@@ -145,7 +319,6 @@ void GfxFontFromResource::drawToBuffer(uint16 chr, int16 top, int16 left, byte c
 		}
 	}
 }
-
 #endif
 
 } // End of namespace Sci
diff --git a/engines/sci/graphics/font.h b/engines/sci/graphics/font.h
index 4e26510..05008de 100644
--- a/engines/sci/graphics/font.h
+++ b/engines/sci/graphics/font.h
@@ -28,6 +28,12 @@
 
 namespace Sci {
 
+#ifdef ENABLE_SCI32
+enum {
+	kSci32SystemFont = -1
+};
+#endif
+
 class GfxFont {
 public:
 	GfxFont() {}
@@ -68,6 +74,7 @@ private:
 	GfxScreen *_screen;
 
 	Resource *_resource;
+	SciSpan<const byte> _resourceData;
 	GuiResourceId _resourceId;
 
 	struct Charinfo {
diff --git a/engines/sci/graphics/text32.cpp b/engines/sci/graphics/text32.cpp
index 181dabc..c636001 100644
--- a/engines/sci/graphics/text32.cpp
+++ b/engines/sci/graphics/text32.cpp
@@ -38,7 +38,6 @@
 
 namespace Sci {
 
-int16 GfxText32::_defaultFontId = 0;
 int16 GfxText32::_xResolution = 0;
 int16 GfxText32::_yResolution = 0;
 
@@ -49,8 +48,8 @@ GfxText32::GfxText32(SegManager *segMan, GfxCache *fonts) :
 	_width(0),
 	_text(""),
 	_bitmap(NULL_REG) {
-		_fontId = _defaultFontId;
-		_font = _cache->getFont(_defaultFontId);
+		_fontId = kSci32SystemFont;
+		_font = _cache->getFont(kSci32SystemFont);
 
 		if (_xResolution == 0) {
 			// initialize the statics
@@ -170,7 +169,7 @@ void GfxText32::setFont(const GuiResourceId fontId) {
 	// table is built on the FontMgr directly; instead, because we already have
 	// font resources, this code just grabs a font out of GfxCache.
 	if (fontId != _fontId) {
-		_fontId = fontId == -1 ? _defaultFontId : fontId;
+		_fontId = fontId;
 		_font = _cache->getFont(_fontId);
 	}
 }
diff --git a/engines/sci/graphics/text32.h b/engines/sci/graphics/text32.h
index c4521a4..722af34 100644
--- a/engines/sci/graphics/text32.h
+++ b/engines/sci/graphics/text32.h
@@ -57,14 +57,6 @@ private:
 	GfxCache *_cache;
 
 	/**
-	 * The resource ID of the default font used by the game.
-	 *
-	 * @todo Check all SCI32 games to learn what their
-	 * default font is.
-	 */
-	static int16 _defaultFontId;
-
-	/**
 	 * The width and height of the currently active text
 	 * bitmap, in text-system coordinates.
 	 *


Commit: 0826501ef63c5b8e6b40299d25142a3562c6fde9
    https://github.com/scummvm/scummvm/commit/0826501ef63c5b8e6b40299d25142a3562c6fde9
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-03-30T19:46:27-05:00

Commit Message:
SCI32: Fix audio, wave, VMD, Duck, CLUT, TGA, ZZZ, Etc patches

Specifically, audio patches are used in at least PQ:SWAT
(40103.AUD), Lighthouse (9103.AUD), and the GK2 demo (300.AUD).

Changed paths:
    engines/sci/resource.cpp
    engines/sci/resource.h
    engines/sci/resource_audio.cpp
    engines/sci/sound/audio.cpp
    engines/sci/sound/audio32.cpp
    engines/sci/sound/decoders/sol.cpp
    engines/sci/sound/decoders/sol.h


diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp
index 921c8c9..d71f435 100644
--- a/engines/sci/resource.cpp
+++ b/engines/sci/resource.cpp
@@ -335,8 +335,7 @@ bool Resource::loadFromPatchFile() {
 		unalloc();
 		return false;
 	}
-	// Skip resourceid and header size byte
-	file.seek(2, SEEK_SET);
+	file.seek(0, SEEK_SET);
 	return loadPatch(&file);
 }
 
@@ -1401,21 +1400,56 @@ void ResourceManager::processPatch(ResourceSource *source, ResourceType resource
 		return;
 	}
 
-	byte patchType = convertResType(fileStream->readByte());
-	int32 patchDataOffset;
-	if (_volVersion < kResVersionSci2) {
-		patchDataOffset = fileStream->readByte();
-	} else if (patchType == kResourceTypeView) {
-		fileStream->seek(3, SEEK_SET);
-		patchDataOffset = fileStream->readByte() + 22 + 2;
-	} else if (patchType == kResourceTypePic) {
-		patchDataOffset = 2;
-	} else if (patchType == kResourceTypePalette) {
-		fileStream->seek(3, SEEK_SET);
-		patchDataOffset = fileStream->readByte() + 2;
+	byte patchType;
+	if (fileStream->readUint32BE() == MKTAG('R','I','F','F')) {
+		fileStream->seek(-4, SEEK_CUR);
+		patchType = kResourceTypeAudio;
 	} else {
-		patchDataOffset = 0;
+		fileStream->seek(-4, SEEK_CUR);
+		patchType = convertResType(fileStream->readByte());
+	}
+
+	enum {
+		kExtraHeaderSize    = 2, ///< extra header used in gfx resources
+		kViewHeaderSize     = 22 ///< extra header used in view resources
+	};
+
+	int32 patchDataOffset = kResourceHeaderSize;
+	if (_volVersion < kResVersionSci2) {
+		patchDataOffset += fileStream->readByte();
+	}
+#ifdef ENABLE_SCI32
+	else {
+		switch (patchType) {
+		case kResourceTypeView:
+			fileStream->seek(3, SEEK_SET);
+			patchDataOffset += fileStream->readByte() + kViewHeaderSize + kExtraHeaderSize;
+			break;
+		case kResourceTypePic:
+			patchDataOffset += kExtraHeaderSize;
+			break;
+		case kResourceTypePalette:
+			fileStream->seek(3, SEEK_SET);
+			patchDataOffset += fileStream->readByte() + kExtraHeaderSize;
+			break;
+		case kResourceTypeWave:
+		case kResourceTypeAudio:
+		case kResourceTypeAudio36:
+		case kResourceTypeVMD:
+		case kResourceTypeDuck:
+		case kResourceTypeClut:
+		case kResourceTypeTGA:
+		case kResourceTypeZZZ:
+		case kResourceTypeEtc:
+			patchDataOffset = 0;
+			break;
+		default:
+			fileStream->seek(1, SEEK_SET);
+			patchDataOffset += fileStream->readByte();
+			break;
+		}
 	}
+#endif
 
 	delete fileStream;
 
@@ -1427,15 +1461,15 @@ void ResourceManager::processPatch(ResourceSource *source, ResourceType resource
 
 	// Fixes SQ5/German, patch file special case logic taken from SCI View disassembly
 	if (patchDataOffset & 0x80) {
-		switch (patchDataOffset & 0x7F) {
+		switch ((patchDataOffset - kResourceHeaderSize) & 0x7F) {
 			case 0:
-				patchDataOffset = 24;
+				patchDataOffset = kResourceHeaderSize + 24;
 				break;
 			case 1:
-				patchDataOffset = 2;
+				patchDataOffset = kResourceHeaderSize + 2;
 				break;
 			case 4:
-				patchDataOffset = 8;
+				patchDataOffset = kResourceHeaderSize + 8;
 				break;
 			default:
 				error("Resource patch unsupported special case %X", patchDataOffset & 0x7F);
@@ -1443,15 +1477,15 @@ void ResourceManager::processPatch(ResourceSource *source, ResourceType resource
 		}
 	}
 
-	if (patchDataOffset + 2 >= fsize) {
+	if (patchDataOffset >= fsize) {
 		debug("Patching %s failed - patch starting at offset %d can't be in file of size %d",
-		      source->getLocationName().c_str(), patchDataOffset + 2, fsize);
+		      source->getLocationName().c_str(), patchDataOffset, fsize);
 		delete source;
 		return;
 	}
 
 	// Overwrite everything, because we're patching
-	newrsc = updateResource(resId, source, fsize - patchDataOffset - 2);
+	newrsc = updateResource(resId, source, fsize - patchDataOffset);
 	newrsc->_headerSize = patchDataOffset;
 	newrsc->_fileOffset = 0;
 
@@ -2084,28 +2118,17 @@ int Resource::decompress(ResVersion volVersion, Common::SeekableReadStream *file
 	_data = ptr;
 	_status = kResStatusAllocated;
 	errorNum = ptr ? dec->unpack(file, ptr, szPacked, _size) : SCI_ERROR_RESOURCE_TOO_BIG;
-	if (errorNum)
+	if (errorNum) {
 		unalloc();
-	else {
+	} else {
 		// At least Lighthouse puts sound effects in RESSCI.00n/RESSCI.PAT
 		// instead of using a RESOURCE.SFX
 		if (getType() == kResourceTypeAudio) {
-			_headerSize = ptr[1];
-			assert(_headerSize == 12);
+			const uint8 headerSize = ptr[1];
+			assert(headerSize >= 11);
 			uint32 audioSize = READ_LE_UINT32(ptr + 9);
-			assert(audioSize + _headerSize + 2 == _size);
-			_size = audioSize;
-
-			// TODO: This extra memory copying is necessary because
-			// AudioVolumeResourceSource splits the audio header from the rest
-			// of the data; fix AudioVolumeResourceSource to stop doing this and
-			// then this extra copying can be eliminated too
-			byte *dataPtr = new byte[_size];
-			_data = dataPtr;
-			_header = new byte[_headerSize];
-			memcpy(_header, ptr + 2, _headerSize);
-			memcpy(dataPtr, ptr + 2 + _headerSize, _size);
-			delete[] ptr;
+			assert(audioSize + headerSize + kResourceHeaderSize == _size);
+			_size = headerSize + audioSize;
 		}
 	}
 
diff --git a/engines/sci/resource.h b/engines/sci/resource.h
index 3e7a7a5..65a26ba 100644
--- a/engines/sci/resource.h
+++ b/engines/sci/resource.h
@@ -43,6 +43,8 @@ class SeekableReadStream;
 namespace Sci {
 
 enum {
+	kResourceHeaderSize = 2, ///< patch type + header size
+
 	/** The maximum allowed size for a compressed or decompressed resource */
 	SCI_MAX_RESOURCE_SIZE = 0x0400000
 };
diff --git a/engines/sci/resource_audio.cpp b/engines/sci/resource_audio.cpp
index b9f24cf..7151c67 100644
--- a/engines/sci/resource_audio.cpp
+++ b/engines/sci/resource_audio.cpp
@@ -95,7 +95,6 @@ bool Resource::loadFromAudioVolumeSCI11(Common::SeekableReadStream *file) {
 	// Check for WAVE files here
 	uint32 riffTag = file->readUint32BE();
 	if (riffTag == MKTAG('R','I','F','F')) {
-		_headerSize = 0;
 		_size = file->readUint32LE() + 8;
 		file->seek(-8, SEEK_CUR);
 		return loadFromWaveFile(file);
@@ -105,6 +104,7 @@ bool Resource::loadFromAudioVolumeSCI11(Common::SeekableReadStream *file) {
 	// Rave-resources (King's Quest 6) don't have any header at all
 	if (getType() != kResourceTypeRave) {
 		ResourceType type = _resMan->convertResType(file->readByte());
+
 		if (((getType() == kResourceTypeAudio || getType() == kResourceTypeAudio36) && (type != kResourceTypeAudio))
 			|| ((getType() == kResourceTypeSync || getType() == kResourceTypeSync36) && (type != kResourceTypeSync))) {
 			warning("Resource type mismatch loading %s", _id.toString().c_str());
@@ -112,23 +112,27 @@ bool Resource::loadFromAudioVolumeSCI11(Common::SeekableReadStream *file) {
 			return false;
 		}
 
-		_headerSize = file->readByte();
+		const uint8 headerSize = file->readByte();
 
 		if (type == kResourceTypeAudio) {
-			if (_headerSize != 7 && _headerSize != 11 && _headerSize != 12) {
-				warning("Unsupported audio header size %d", _headerSize);
+			if (headerSize != 7 && headerSize != 11 && headerSize != 12) {
+				warning("Unsupported audio header size %d", headerSize);
 				unalloc();
 				return false;
 			}
 
-			if (_headerSize != 7) { // Size is defined already from the map
+			if (headerSize != 7) { // Size is defined already from the map
 				// Load sample size
 				file->seek(7, SEEK_CUR);
-				_size = file->readUint32LE();
+				_size = file->readUint32LE() + headerSize + kResourceHeaderSize;
 				assert(!file->err() && !file->eos());
-				// Adjust offset to point at the header data again
+				// Adjust offset to point at the beginning of the audio file
+				// again
 				file->seek(-11, SEEK_CUR);
 			}
+
+			// SOL audio files are designed to require the resource header
+			file->seek(-2, SEEK_CUR);
 		}
 	}
 	return loadPatch(file);
diff --git a/engines/sci/sound/audio.cpp b/engines/sci/sound/audio.cpp
index e470b31..273c4c1 100644
--- a/engines/sci/sound/audio.cpp
+++ b/engines/sci/sound/audio.cpp
@@ -397,12 +397,13 @@ Audio::RewindableAudioStream *AudioPlayer::getAudioStream(uint32 number, uint32
 #endif
 	} else {
 		// Original source file
-		if (audioRes->_headerSize > 0) {
+		if ((audioRes->getUint8At(0) & 0x7f) == kResourceTypeAudio && audioRes->getUint32BEAt(2) == MKTAG('S','O','L',0)) {
 			// SCI1.1
-			Common::MemoryReadStream headerStream(audioRes->_header, audioRes->_headerSize, DisposeAfterUse::NO);
+			const uint8 headerSize = audioRes->getUint8At(1);
+			Common::MemoryReadStream headerStream = audioRes->subspan(kResourceHeaderSize, headerSize).toStream();
 
-			if (readSOLHeader(&headerStream, audioRes->_headerSize, size, _audioRate, audioFlags, audioRes->size())) {
-				Common::MemoryReadStream dataStream(audioRes->toStream());
+			if (readSOLHeader(&headerStream, headerSize, size, _audioRate, audioFlags, audioRes->size())) {
+				Common::MemoryReadStream dataStream(audioRes->subspan(kResourceHeaderSize + headerSize).toStream());
 				data = readSOLAudio(&dataStream, size, audioFlags, flags);
 			}
 		} else if (audioRes->size() > 4 && audioRes->getUint32BEAt(0) == MKTAG('R','I','F','F')) {
diff --git a/engines/sci/sound/audio32.cpp b/engines/sci/sound/audio32.cpp
index ca2402c..69a83eb 100644
--- a/engines/sci/sound/audio32.cpp
+++ b/engines/sci/sound/audio32.cpp
@@ -46,10 +46,6 @@ namespace Sci {
 bool detectSolAudio(Common::SeekableReadStream &stream) {
 	const size_t initialPosition = stream.pos();
 
-// TODO: Resource manager for audio resources reads past the
-// header so even though this is the detection algorithm
-// in SSCI, ScummVM can't use it
-#if 0
 	byte header[6];
 	if (stream.read(header, sizeof(header)) != sizeof(header)) {
 		stream.seek(initialPosition);
@@ -58,26 +54,11 @@ bool detectSolAudio(Common::SeekableReadStream &stream) {
 
 	stream.seek(initialPosition);
 
-	if (header[0] != 0x8d || READ_BE_UINT32(header + 2) != MKTAG('S', 'O', 'L', 0)) {
+	if ((header[0] & 0x7f) != kResourceTypeAudio || READ_BE_UINT32(header + 2) != MKTAG('S', 'O', 'L', 0)) {
 		return false;
 	}
 
 	return true;
-#else
-	byte header[4];
-	if (stream.read(header, sizeof(header)) != sizeof(header)) {
-		stream.seek(initialPosition);
-		return false;
-	}
-
-	stream.seek(initialPosition);
-
-	if (READ_BE_UINT32(header) != MKTAG('S', 'O', 'L', 0)) {
-		return false;
-	}
-
-	return true;
-#endif
 }
 
 bool detectWaveAudio(Common::SeekableReadStream &stream) {
@@ -723,11 +704,10 @@ uint16 Audio32::play(int16 channelIndex, const ResourceId resourceId, const bool
 		_monitoredChannelIndex = channelIndex;
 	}
 
-	Common::MemoryReadStream headerStream(resource->_header, resource->_headerSize, DisposeAfterUse::NO);
 	Common::SeekableReadStream *dataStream = channel.resourceStream = resource->makeStream();
 
-	if (detectSolAudio(headerStream)) {
-		channel.stream = makeSOLStream(&headerStream, dataStream, DisposeAfterUse::NO);
+	if (detectSolAudio(*dataStream)) {
+		channel.stream = makeSOLStream(dataStream, DisposeAfterUse::NO);
 	} else if (detectWaveAudio(*dataStream)) {
 		channel.stream = Audio::makeWAVStream(dataStream, DisposeAfterUse::NO);
 	} else {
diff --git a/engines/sci/sound/decoders/sol.cpp b/engines/sci/sound/decoders/sol.cpp
index 2dbe98c..973ebf3 100644
--- a/engines/sci/sound/decoders/sol.cpp
+++ b/engines/sci/sound/decoders/sol.cpp
@@ -25,8 +25,9 @@
 #include "audio/decoders/raw.h"
 #include "common/substream.h"
 #include "common/util.h"
-#include "engines/sci/sci.h"
-#include "engines/sci/sound/decoders/sol.h"
+#include "sci/sci.h"
+#include "sci/sound/decoders/sol.h"
+#include "sci/resource.h"
 
 namespace Sci {
 
@@ -127,16 +128,11 @@ static void deDPCM8Stereo(int16 *out, Common::ReadStream &audioStream, uint32 nu
 # pragma mark -
 
 template<bool STEREO, bool S16BIT>
-SOLStream<STEREO, S16BIT>::SOLStream(Common::SeekableReadStream *stream, const DisposeAfterUse::Flag disposeAfterUse, const int32 dataOffset, const uint16 sampleRate, const int32 rawDataSize) :
+SOLStream<STEREO, S16BIT>::SOLStream(Common::SeekableReadStream *stream, const DisposeAfterUse::Flag disposeAfterUse, const uint16 sampleRate, const int32 rawDataSize) :
 	_stream(stream, disposeAfterUse),
-	_dataOffset(dataOffset),
 	_sampleRate(sampleRate),
 	// SSCI aligns the size of SOL data to 32 bits
 	_rawDataSize(rawDataSize & ~3) {
-		// TODO: This is not valid for stereo SOL files, which
-		// have interleaved L/R compression so need to store the
-		// carried values for each channel separately. See
-		// 60900.aud from Lighthouse for an example stereo file
 		if (S16BIT) {
 			_dpcmCarry16.l = _dpcmCarry16.r = 0;
 		} else {
@@ -166,7 +162,7 @@ bool SOLStream<STEREO, S16BIT>::seek(const Audio::Timestamp &where) {
 		_dpcmCarry8.l = _dpcmCarry8.r = 0x80;
 	}
 
-	return _stream->seek(_dataOffset, SEEK_SET);
+	return _stream->seek(0, SEEK_SET);
 }
 
 template <bool STEREO, bool S16BIT>
@@ -227,72 +223,35 @@ bool SOLStream<STEREO, S16BIT>::rewind() {
 }
 
 Audio::SeekableAudioStream *makeSOLStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse) {
-
-	// TODO: Might not be necessary? Makes seeking work, but
-	// not sure if audio is ever actually seeked in SSCI.
-	const int32 initialPosition = stream->pos();
+	int32 initialPosition = stream->pos();
 
 	byte header[6];
 	if (stream->read(header, sizeof(header)) != sizeof(header)) {
+		stream->seek(initialPosition, SEEK_SET);
 		return nullptr;
 	}
 
-	if (header[0] != 0x8d || READ_BE_UINT32(header + 2) != MKTAG('S', 'O', 'L', 0)) {
+	if ((header[0] & 0x7f) != kResourceTypeAudio || READ_BE_UINT32(header + 2) != MKTAG('S', 'O', 'L', 0)) {
+		stream->seek(initialPosition, SEEK_SET);
 		return nullptr;
 	}
 
-	const uint8 headerSize = header[1];
+	const uint8 headerSize = header[1] + /* resource header */ 2;
 	const uint16 sampleRate = stream->readUint16LE();
 	const byte flags = stream->readByte();
 	const uint32 dataSize = stream->readUint32LE();
 
-	if (flags & kCompressed) {
-		if (flags & kStereo && flags & k16Bit) {
-			return new SOLStream<true, true>(new Common::SeekableSubReadStream(stream, initialPosition, initialPosition + dataSize, disposeAfterUse), disposeAfterUse, headerSize, sampleRate, dataSize);
-		} else if (flags & kStereo) {
-			return new SOLStream<true, false>(new Common::SeekableSubReadStream(stream, initialPosition, initialPosition + dataSize, disposeAfterUse), disposeAfterUse, headerSize, sampleRate, dataSize);
-		} else if (flags & k16Bit) {
-			return new SOLStream<false, true>(new Common::SeekableSubReadStream(stream, initialPosition, initialPosition + dataSize, disposeAfterUse), disposeAfterUse, headerSize, sampleRate, dataSize);
-		} else {
-			return new SOLStream<false, false>(new Common::SeekableSubReadStream(stream, initialPosition, initialPosition + dataSize, disposeAfterUse), disposeAfterUse, headerSize, sampleRate, dataSize);
-		}
-	}
-
-	byte rawFlags = Audio::FLAG_LITTLE_ENDIAN;
-	if (flags & k16Bit) {
-		rawFlags |= Audio::FLAG_16BITS;
-	} else {
-		rawFlags |= Audio::FLAG_UNSIGNED;
-	}
-
-	if (flags & kStereo) {
-		rawFlags |= Audio::FLAG_STEREO;
-	}
-
-	return Audio::makeRawStream(new Common::SeekableSubReadStream(stream, initialPosition + headerSize, initialPosition + headerSize + dataSize, disposeAfterUse), sampleRate, rawFlags, disposeAfterUse);
-}
-
-// TODO: This needs to be removed when resource manager is fixed
-// to not split audio into two parts
-Audio::SeekableAudioStream *makeSOLStream(Common::SeekableReadStream *headerStream, Common::SeekableReadStream *dataStream, DisposeAfterUse::Flag disposeAfterUse) {
-
-	if (headerStream->readUint32BE() != MKTAG('S', 'O', 'L', 0)) {
-		return nullptr;
-	}
-
-	const uint16 sampleRate = headerStream->readUint16LE();
-	const byte flags = headerStream->readByte();
-	const int32 dataSize = headerStream->readSint32LE();
+	initialPosition += headerSize;
 
 	if (flags & kCompressed) {
 		if (flags & kStereo && flags & k16Bit) {
-			return new SOLStream<true, true>(dataStream, disposeAfterUse, 0, sampleRate, dataSize);
+			return new SOLStream<true, true>(new Common::SeekableSubReadStream(stream, initialPosition, initialPosition + dataSize, disposeAfterUse), disposeAfterUse, sampleRate, dataSize);
 		} else if (flags & kStereo) {
-			return new SOLStream<true, false>(dataStream, disposeAfterUse, 0, sampleRate, dataSize);
+			return new SOLStream<true, false>(new Common::SeekableSubReadStream(stream, initialPosition, initialPosition + dataSize, disposeAfterUse), disposeAfterUse, sampleRate, dataSize);
 		} else if (flags & k16Bit) {
-			return new SOLStream<false, true>(dataStream, disposeAfterUse, 0, sampleRate, dataSize);
+			return new SOLStream<false, true>(new Common::SeekableSubReadStream(stream, initialPosition, initialPosition + dataSize, disposeAfterUse), disposeAfterUse, sampleRate, dataSize);
 		} else {
-			return new SOLStream<false, false>(dataStream, disposeAfterUse, 0, sampleRate, dataSize);
+			return new SOLStream<false, false>(new Common::SeekableSubReadStream(stream, initialPosition, initialPosition + dataSize, disposeAfterUse), disposeAfterUse, sampleRate, dataSize);
 		}
 	}
 
@@ -307,6 +266,6 @@ Audio::SeekableAudioStream *makeSOLStream(Common::SeekableReadStream *headerStre
 		rawFlags |= Audio::FLAG_STEREO;
 	}
 
-	return Audio::makeRawStream(dataStream, sampleRate, rawFlags, disposeAfterUse);
+	return Audio::makeRawStream(new Common::SeekableSubReadStream(stream, initialPosition, initialPosition + dataSize, disposeAfterUse), sampleRate, rawFlags, disposeAfterUse);
 }
 }
diff --git a/engines/sci/sound/decoders/sol.h b/engines/sci/sound/decoders/sol.h
index 31914c0..80a2181 100644
--- a/engines/sci/sound/decoders/sol.h
+++ b/engines/sci/sound/decoders/sol.h
@@ -42,11 +42,6 @@ private:
 	Common::DisposablePtr<Common::SeekableReadStream> _stream;
 
 	/**
-	 * Start offset of the audio data in the read stream.
-	 */
-	int32 _dataOffset;
-
-	/**
 	 * Sample rate of audio data.
 	 */
 	uint16 _sampleRate;
@@ -79,11 +74,9 @@ private:
 	virtual bool rewind() override;
 
 public:
-	SOLStream(Common::SeekableReadStream *stream, const DisposeAfterUse::Flag disposeAfterUse, const int32 dataOffset, const uint16 sampleRate, const int32 rawDataSize);
+	SOLStream(Common::SeekableReadStream *stream, const DisposeAfterUse::Flag disposeAfterUse, const uint16 sampleRate, const int32 rawDataSize);
 };
 
 Audio::SeekableAudioStream *makeSOLStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse);
-
-Audio::SeekableAudioStream *makeSOLStream(Common::SeekableReadStream *headerStream, Common::SeekableReadStream *dataStream, DisposeAfterUse::Flag disposeAfterUse);
 }
 #endif


Commit: 77a40741060f75fe1ac46217d75e77c3b2738242
    https://github.com/scummvm/scummvm/commit/77a40741060f75fe1ac46217d75e77c3b2738242
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-03-30T19:46:27-05:00

Commit Message:
SCI: Protect and clarify the purpose of Resource _header data

Changed paths:
    engines/sci/resource.h


diff --git a/engines/sci/resource.h b/engines/sci/resource.h
index 65a26ba..c0c969a 100644
--- a/engines/sci/resource.h
+++ b/engines/sci/resource.h
@@ -243,9 +243,12 @@ class Resource : public SciSpan<const byte> {
 	friend class ChunkResourceSource;
 #endif
 
-// NOTE : Currently most member variables lack the underscore prefix and have
-// public visibility to let the rest of the engine compile without changes.
-public:
+protected:
+	/**
+	 * Holds the extra header data from view, pic, and palette patches so that
+	 * these patches can be rewritten to disk as valid patch files by the
+	 * `diskdump` debugger command.
+	 */
 	byte *_header;
 	uint32 _headerSize;
 


Commit: 9a637ec324e8c0c7ff8fab28bc8105e8609e18ba
    https://github.com/scummvm/scummvm/commit/9a637ec324e8c0c7ff8fab28bc8105e8609e18ba
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-03-30T19:46:27-05:00

Commit Message:
SCI32: Skip bad map 405 on CD 1 of PQ:SWAT

The resources on CD 1 are corrupt and point to invalid locations
in the CD 1 RESOURCE.AUD. This can be noticed during the briefing
on the Lucy Long callup, where descriptions of the map are missing
and eventually the game gets stuck waiting for missing audio to
finish playback.

Changed paths:
    engines/sci/resource_audio.cpp


diff --git a/engines/sci/resource_audio.cpp b/engines/sci/resource_audio.cpp
index 7151c67..3be7b10 100644
--- a/engines/sci/resource_audio.cpp
+++ b/engines/sci/resource_audio.cpp
@@ -436,6 +436,14 @@ int ResourceManager::readAudioMapSCI11(IntMapResourceSource *map) {
 
 			const ResourceId id = ResourceId(kResourceTypeAudio36, map->_mapNumber, n & 0xffffff3f);
 
+			// Map 405 on CD 1 of the US release of PQ:SWAT 1.000 is broken
+			// and points to garbage in the RESOURCE.AUD. The affected audio36
+			// assets seem to be able to load successfully from one of the later
+			// CDs, so just ignore the map on this disc
+			if (g_sci->getGameId() == GID_PQSWAT && map->_volumeNumber == 1 && map->_mapNumber == 405) {
+				continue;
+			}
+
 			// At least version 1.00 of GK2 has multiple invalid audio36 map
 			// entries on CD 6
 			if (g_sci->getGameId() == GID_GK2 &&


Commit: bd7a62e99693e6df5c39efe09a8d28c57bfa7cd1
    https://github.com/scummvm/scummvm/commit/bd7a62e99693e6df5c39efe09a8d28c57bfa7cd1
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-03-30T19:46:27-05:00

Commit Message:
SCI: Fix typo in comment

Changed paths:
    engines/sci/console.cpp


diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index 5c7a9e6..d0ac1ba 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -3657,7 +3657,7 @@ bool Console::cmdSend(int argc, const char **argv) {
 	// everything after the selector name is passed as an argument to the send
 	int send_argc = argc - 3;
 
-	// Create the data block for send_selecor() at the top of the stack:
+	// Create the data block for send_selector() at the top of the stack:
 	// [selector_number][argument_counter][arguments...]
 	StackPtr stackframe = _engine->_gamestate->_executionStack.back().sp;
 	stackframe[0] = make_reg(0, selectorId);


Commit: fa9523933f69497bae19510ff1c7f17e4cbe8024
    https://github.com/scummvm/scummvm/commit/fa9523933f69497bae19510ff1c7f17e4cbe8024
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-03-30T19:46:27-05:00

Commit Message:
SCI32: Fix broken sliders in Shivers settings

This problem is caused by the same invalid super call that broke
the CCTV joystick.

Changed paths:
    engines/sci/engine/script_patches.cpp


diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index d84d2ab..f5ec2d3 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -4871,7 +4871,9 @@ static const SciScriptPatcherEntry sq5Signatures[] = {
 // In SSCI, this happens to work because the uninitialized value on the stack
 // happens to be 1. Disabling the super call avoids the bad doVerb call without
 // any apparent ill effect.
-static const uint16 shiversSignatureJoystickFix[] = {
+// The same problem exists when trying to drag the volume & brightness sliders
+// in the main menu. These controls are also fixed by this patch.
+static const uint16 shiversSignatureSuperCall[] = {
 	SIG_MAGICDWORD,
 	0x38, SIG_UINT16(0xa5),    // pushi handleEvent
 	0x78,                      // push1
@@ -4881,14 +4883,15 @@ static const uint16 shiversSignatureJoystickFix[] = {
 	SIG_END
 };
 
-static const uint16 shiversPatchJoystickFix[] = {
+static const uint16 shiversPatchSuperCall[] = {
 	0x48,                      // ret
 	PATCH_END
 };
 
 //          script, description,                                      signature                        patch
 static const SciScriptPatcherEntry shiversSignatures[] = {
-	{  true, 35170, "fix CCTV joystick interaction",               1, shiversSignatureJoystickFix,     shiversPatchJoystickFix },
+	{  true, 35170, "fix CCTV joystick interaction",               1, shiversSignatureSuperCall,     shiversPatchSuperCall },
+	{  true,   990, "fix volume & brightness sliders",             2, shiversSignatureSuperCall,     shiversPatchSuperCall },
 	SCI_SIGNATUREENTRY_TERMINATOR
 };
 


Commit: 6b0cd955faf6df00a55664ef30cb8e6cf981bc6e
    https://github.com/scummvm/scummvm/commit/6b0cd955faf6df00a55664ef30cb8e6cf981bc6e
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-03-30T19:46:27-05:00

Commit Message:
SCI32: Fix crash when using brightness slider in Shivers

Changed paths:
    engines/sci/engine/kernel_tables.h
    engines/sci/engine/kgraphics32.cpp


diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index 46132d3..6f696c4 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -306,7 +306,7 @@ static const SciKernelMapSubEntry kPalette_subops[] = {
 	{ SIG_SCI32,          1, MAP_CALL(PaletteSetFromResource32),  "i(i)",                 NULL },
 	{ SIG_SCI32,          2, MAP_CALL(PaletteSetFade),            "iii",                  NULL },
 	{ SIG_SCI32,          3, MAP_CALL(PaletteFindColor32),        "iii",                  NULL },
-	{ SIG_SCI3,           4, MAP_CALL(PaletteSetGamma),           "i",                    NULL },
+	{ SIG_SCI32,          4, MAP_CALL(PaletteSetGamma),           "i",                    NULL },
 #endif
 	SCI_SUBOPENTRY_TERMINATOR
 };
diff --git a/engines/sci/engine/kgraphics32.cpp b/engines/sci/engine/kgraphics32.cpp
index f6aeeb7..07a63c7 100644
--- a/engines/sci/engine/kgraphics32.cpp
+++ b/engines/sci/engine/kgraphics32.cpp
@@ -935,8 +935,8 @@ reg_t kPaletteFindColor32(EngineState *s, int argc, reg_t *argv) {
 }
 
 /*
- * Used in SCI3. SCI3 contains 6 gamma look-up tables, with the first
- * table (gamma = 0) being the default one.
+ * Used starting in Shivers 1. SCI3 contains 6 gamma look-up tables, with the
+ * first table (gamma = 0) being the default one.
  */
 reg_t kPaletteSetGamma(EngineState *s, int argc, reg_t *argv) {
 	const uint8 gamma = argv[0].toUint16();


Commit: e74adcec5263027fd623967da091b971e85146c1
    https://github.com/scummvm/scummvm/commit/e74adcec5263027fd623967da091b971e85146c1
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-03-30T19:46:27-05:00

Commit Message:
SCI: Whitespace alignment

Changed paths:
    engines/sci/engine/vm.h


diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h
index dbd4ee1..0444cf5 100644
--- a/engines/sci/engine/vm.h
+++ b/engines/sci/engine/vm.h
@@ -132,9 +132,9 @@ struct ExecStack {
 
 enum {
 	VAR_GLOBAL = 0,
-	VAR_LOCAL = 1,
-	VAR_TEMP = 2,
-	VAR_PARAM = 3
+	VAR_LOCAL  = 1,
+	VAR_TEMP   = 2,
+	VAR_PARAM  = 3
 };
 
 enum GlobalVar {


Commit: 4d062fc7a0157f2044f3ab69c7487a841babadeb
    https://github.com/scummvm/scummvm/commit/4d062fc7a0157f2044f3ab69c7487a841babadeb
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-03-30T19:46:27-05:00

Commit Message:
SCI32: Do not default to General MIDI for SCI2.1 games

The only SCI32 game that uses MIDI and does not support AdLib is
MGDX, and it its MIDI playback is currently broken regardless of
the synth setting.

Changed paths:
    engines/sci/sound/music.cpp


diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp
index f78f146..1808cf3 100644
--- a/engines/sci/sound/music.cpp
+++ b/engines/sci/sound/music.cpp
@@ -70,10 +70,9 @@ void SciMusic::init() {
 	Common::Platform platform = g_sci->getPlatform();
 	uint32 deviceFlags = MDT_PCSPK | MDT_PCJR | MDT_ADLIB | MDT_MIDI;
 
-	// Default to MIDI in SCI2.1+ games, as many don't have AdLib support.
-	// Also, default to MIDI for Windows versions of SCI1.1 games, as their
+	// Default to MIDI for Windows versions of SCI1.1 games, as their
 	// soundtrack is written for GM.
-	if (getSciVersion() >= SCI_VERSION_2_1_EARLY || g_sci->_features->useAltWinGMSound())
+	if (g_sci->_features->useAltWinGMSound())
 		deviceFlags |= MDT_PREFER_GM;
 
 	// Currently our CMS implementation only supports SCI1(.1)


Commit: dd230858455171dbd618118e7516fccc11a97202
    https://github.com/scummvm/scummvm/commit/dd230858455171dbd618118e7516fccc11a97202
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-03-30T19:46:27-05:00

Commit Message:
SCI: Give kernel calls a valid stack pointer

Some kernel calls need to be able to call back into game script
code, which requires a valid stack pointer for use with
invokeSelector.

An example of this is the guest additions code that syncs audio
volumes from ScummVM: it needs to be able to call into the game
scripts responsible for managing the in-game audio volume UI.

Changed paths:
    engines/sci/engine/vm.cpp


diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp
index a9d575b..b2807e0 100644
--- a/engines/sci/engine/vm.cpp
+++ b/engines/sci/engine/vm.cpp
@@ -360,7 +360,7 @@ static void addKernelCallToExecStack(EngineState *s, int kernelCallNr, int kerne
 	// Add stack frame to indicate we're executing a callk.
 	// This is useful in debugger backtraces if this
 	// kernel function calls a script itself.
-	ExecStack xstack(NULL_REG, NULL_REG, NULL, argc, argv - 1, kUninitializedSegment, make_reg32(0, 0),
+	ExecStack xstack(NULL_REG, NULL_REG, argv + argc, argc, argv - 1, kUninitializedSegment, make_reg32(0, 0),
 						-1, kernelCallNr, kernelSubCallNr, -1, -1, s->_executionStack.size() - 1, EXEC_STACK_TYPE_KERNEL);
 	s->_executionStack.push_back(xstack);
 }


Commit: 3de6f290e7724369424ec33dd56b60fbc393460c
    https://github.com/scummvm/scummvm/commit/3de6f290e7724369424ec33dd56b60fbc393460c
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-03-30T19:46:27-05:00

Commit Message:
SCI: Change default master MIDI volume to 15

GK1 handles MIDI volume by changing the volumes of individual
sound objects, rather than by using the MIDI master volume. As a
result, the master volume needs to default to the maximum output
level in order for GK1 to play music at the correct volume.

This change does not affect earlier games, since SCI16 managed
MIDI volume via the master volume, and for these games the master
volume from ScummVM is synced at startup.

Changed paths:
    engines/sci/sound/music.cpp


diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp
index 1808cf3..dd9fbcb 100644
--- a/engines/sci/sound/music.cpp
+++ b/engines/sci/sound/music.cpp
@@ -38,7 +38,7 @@
 namespace Sci {
 
 SciMusic::SciMusic(SciVersion soundVersion, bool useDigitalSFX)
-	: _soundVersion(soundVersion), _soundOn(true), _masterVolume(0), _globalReverb(0), _useDigitalSFX(useDigitalSFX) {
+	: _soundVersion(soundVersion), _soundOn(true), _masterVolume(15), _globalReverb(0), _useDigitalSFX(useDigitalSFX) {
 
 	// Reserve some space in the playlist, to avoid expensive insertion
 	// operations


Commit: 739047f887e9fef53c89ecf76de8809e7ae6809f
    https://github.com/scummvm/scummvm/commit/739047f887e9fef53c89ecf76de8809e7ae6809f
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-03-30T19:46:27-05:00

Commit Message:
SCI32: Always reinit GfxText32 statics on game startup

Fixes bad scaling of text when switching between games with
different script resolutions.

Changed paths:
    engines/sci/graphics/frameout.cpp
    engines/sci/graphics/text32.cpp
    engines/sci/graphics/text32.h


diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index 464b28a..5f96a8e 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -117,6 +117,7 @@ void GfxFrameout::run() {
 	CelObj::init();
 	Plane::init();
 	ScreenItem::init();
+	GfxText32::init();
 
 	// NOTE: This happens in SCI::InitPlane in the actual engine,
 	// and is a background fill plane to ensure hidden planes
diff --git a/engines/sci/graphics/text32.cpp b/engines/sci/graphics/text32.cpp
index c636001..a017a2f 100644
--- a/engines/sci/graphics/text32.cpp
+++ b/engines/sci/graphics/text32.cpp
@@ -50,14 +50,13 @@ GfxText32::GfxText32(SegManager *segMan, GfxCache *fonts) :
 	_bitmap(NULL_REG) {
 		_fontId = kSci32SystemFont;
 		_font = _cache->getFont(kSci32SystemFont);
-
-		if (_xResolution == 0) {
-			// initialize the statics
-			_xResolution = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
-			_yResolution = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
-		}
 	}
 
+void GfxText32::init() {
+	_xResolution = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
+	_yResolution = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
+}
+
 reg_t GfxText32::createFontBitmap(int16 width, int16 height, const Common::Rect &rect, const Common::String &text, const uint8 foreColor, const uint8 backColor, const uint8 skipColor, const GuiResourceId fontId, const TextAlign alignment, const int16 borderColor, const bool dimmed, const bool doScaling, const bool gc) {
 
 	_borderColor = borderColor;
diff --git a/engines/sci/graphics/text32.h b/engines/sci/graphics/text32.h
index 722af34..bfd5ebc 100644
--- a/engines/sci/graphics/text32.h
+++ b/engines/sci/graphics/text32.h
@@ -153,6 +153,11 @@ public:
 	GfxText32(SegManager *segMan, GfxCache *fonts);
 
 	/**
+	 * Initialises static GfxText32 members.
+	 */
+	static void init();
+
+	/**
 	 * The memory handle of the currently active bitmap.
 	 */
 	reg_t _bitmap;


Commit: 159438848becb0fd51dc0763300e3ab6c0a9f331
    https://github.com/scummvm/scummvm/commit/159438848becb0fd51dc0763300e3ab6c0a9f331
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-03-30T19:46:27-05:00

Commit Message:
SCI32: Add workaround for uninitialised read in GK1

Changed paths:
    engines/sci/engine/workarounds.cpp


diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp
index 84211fd..1b9fe7b 100644
--- a/engines/sci/engine/workarounds.cpp
+++ b/engines/sci/engine/workarounds.cpp
@@ -270,6 +270,7 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = {
 	{ GID_FREDDYPHARKAS,  -1,    31,  0,            "quitWin", "open",                            NULL,     5, { WORKAROUND_FAKE, 0xf } }, // is used as priority for game menu
 	{ GID_FREDDYPHARKAS, 540,   540,  0,          "WaverCode", "init",                            NULL,    -1, { WORKAROUND_FAKE,   0 } }, // Gun pratice mini-game - bug #5232
 	{ GID_GK1,            -1, 64950, -1,            "Feature", "handleEvent",                     NULL,     0, { WORKAROUND_FAKE,   0 } }, // sometimes when walk-clicking
+	{ GID_GK1,            -1, 64937, -1,         "GKControls", "dispatchEvent",                   NULL,     6, { WORKAROUND_FAKE,   0 } }, // when using keyboard navigation (tab) in the game settings and hitting 'enter' when over a slider
 	{ GID_GK2,            -1,    11,  0,                   "", "export 10",                       NULL,     3, { WORKAROUND_FAKE,   0 } }, // called when the game starts
 	{ GID_GK2,            -1,    11,  0,                   "", "export 10",                       NULL,     4, { WORKAROUND_FAKE,   0 } }, // called during the game
 	{ GID_HOYLE1,          4,   104,  0,   "GinRummyCardList", "calcRuns",                        NULL,     4, { WORKAROUND_FAKE,   0 } }, // Gin Rummy / right when the game starts


Commit: 5e81db8fd09d1783bd9503ac875eb36d9d1b3b80
    https://github.com/scummvm/scummvm/commit/5e81db8fd09d1783bd9503ac875eb36d9d1b3b80
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-03-30T19:46:27-05:00

Commit Message:
SCI32: Add workaround for uninitialised read in Torin

Changed paths:
    engines/sci/engine/workarounds.cpp


diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp
index 1b9fe7b..148e9e7 100644
--- a/engines/sci/engine/workarounds.cpp
+++ b/engines/sci/engine/workarounds.cpp
@@ -412,6 +412,7 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = {
 	{ GID_TORIN,          -1, 64017,  0,             "oFlags", "clear",                           NULL,     0, { WORKAROUND_FAKE,   0 } }, // entering Torin's home in the French version
 	{ GID_TORIN,       10000, 64029,  0,          "oMessager", "nextMsg",                         NULL,     3, { WORKAROUND_FAKE,   0 } }, // start of chapter one
 	{ GID_TORIN,       20100, 64964,  0,              "DPath", "init",                            NULL,     1, { WORKAROUND_FAKE,   0 } }, // going down the cliff at the first screen of chapter 2 (washing area)
+	{ GID_TORIN,       61100, 64888,  0,              "Torin", "autorestore",                     NULL,    11, { WORKAROUND_FAKE,   0 } }, // after attempting to restore a save game saved with the wrong game version
 	SCI_WORKAROUNDENTRY_TERMINATOR
 };
 


Commit: 2d0c1c8ab50862136cf4c5c75e016a1def90c3e4
    https://github.com/scummvm/scummvm/commit/2d0c1c8ab50862136cf4c5c75e016a1def90c3e4
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-03-30T19:46:27-05:00

Commit Message:
SCI: Ensure object name reg_ts are valid before dereferencing them

Changed paths:
    engines/sci/engine/seg_manager.cpp


diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp
index 3157c84..1262569 100644
--- a/engines/sci/engine/seg_manager.cpp
+++ b/engines/sci/engine/seg_manager.cpp
@@ -272,9 +272,23 @@ const char *SegManager::getObjectName(reg_t pos) {
 	if (nameReg.isNull())
 		return "<no name>";
 
-	const char *name = 0;
-	if (nameReg.getSegment())
-		name  = derefString(nameReg);
+	const char *name = nullptr;
+
+	if (nameReg.getSegment()) {
+#ifdef ENABLE_SCI32
+		// At least Torin script 64000 creates objects with names that are
+		// pointed to dynamically generated strings which are freed before the
+		// objects themselves are freed. This causes a crash when using
+		// `findObjectByName`, since the name of the object is no longer valid
+		if (nameReg.getSegment() != _arraysSegId ||
+			_heap[_arraysSegId]->isValidOffset(nameReg.getOffset())) {
+#endif
+			name = derefString(nameReg);
+#ifdef ENABLE_SCI32
+		}
+#endif
+	}
+
 	if (!name) {
 		// Crazy Nick Laura Bow is missing some object names needed for the static
 		// selector vocabulary


Commit: 4284488244248e610cac5178fa27c6c1f51e6c58
    https://github.com/scummvm/scummvm/commit/4284488244248e610cac5178fa27c6c1f51e6c58
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-03-30T19:46:27-05:00

Commit Message:
SCI32: Improve bounds checking in SciString trim

Changed paths:
    engines/sci/engine/segment.h


diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h
index 281837d..f9d151c 100644
--- a/engines/sci/engine/segment.h
+++ b/engines/sci/engine/segment.h
@@ -795,13 +795,14 @@ public:
 		};
 
 		byte *data = (byte *)_data;
+		byte *end = data + _size;
 		byte *source;
 		byte *target;
 
 		if (flags & kArrayTrimLeft) {
 			target = data;
 			source = data;
-			while (*source != '\0' && *source != showChar && *source <= kWhitespaceBoundary) {
+			while (source < end && *source != '\0' && *source != showChar && *source <= kWhitespaceBoundary) {
 				++source;
 			}
 			memmove(target, source, Common::strnlen((char *)source, _size - 1) + 1);
@@ -817,29 +818,29 @@ public:
 
 		if (flags & kArrayTrimCenter) {
 			target = data;
-			while (*target && *target <= kWhitespaceBoundary && *target != showChar) {
+			while (target < end && *target != '\0' && *target <= kWhitespaceBoundary && *target != showChar) {
 				++target;
 			}
 
-			if (*target) {
-				while (*target && (*target > kWhitespaceBoundary || *target == showChar)) {
+			if (*target != '\0') {
+				while (target < end && *target != '\0' && (*target > kWhitespaceBoundary || *target == showChar)) {
 					++target;
 				}
 
-				if (*target) {
+				if (*target != '\0') {
 					source = target;
-					while (*source) {
-						while (*source && *source <= kWhitespaceBoundary && *source != showChar) {
+					while (*source != '\0') {
+						while (source < end && *source != '\0' && *source <= kWhitespaceBoundary && *source != showChar) {
 							++source;
 						}
 
-						while (*source && (*source > kWhitespaceBoundary || *source == showChar)) {
+						while (source < end && *source != '\0' && (*source > kWhitespaceBoundary || *source == showChar)) {
 							*target++ = *source++;
 						}
 					}
 
 					--source;
-					while (source > target && (*source <= kWhitespaceBoundary || *source >= kAsciiBoundary) && *source != showChar) {
+					while (source >= data && source > target && (*source <= kWhitespaceBoundary || *source >= kAsciiBoundary) && *source != showChar) {
 						--source;
 					}
 					++source;


Commit: 5723f2f5feb4dc0b51423e7d03c6fc05dc201c9e
    https://github.com/scummvm/scummvm/commit/5723f2f5feb4dc0b51423e7d03c6fc05dc201c9e
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-03-30T20:49:36-05:00

Commit Message:
SCI32: Hack around MIDI parser causing stuck harp animation in KQ7

The eventual proper fix for this is to change the current MIDI
parser to work the same as in SSCI, but for now this workaround
allows the game to continue.

Fixes Trac#9696.

Changed paths:
    engines/sci/sound/midiparser_sci.cpp


diff --git a/engines/sci/sound/midiparser_sci.cpp b/engines/sci/sound/midiparser_sci.cpp
index 20688ca..ea1ef74 100644
--- a/engines/sci/sound/midiparser_sci.cpp
+++ b/engines/sci/sound/midiparser_sci.cpp
@@ -653,6 +653,12 @@ bool MidiParser_SCI::processEvent(const EventInfo &info, bool fireEvents) {
 							if (g_sci->getEngineState()->currentRoomNumber() == 530)
 								skipSignal = false;
 							break;
+#ifdef ENABLE_SCI32
+						case GID_KQ7:
+							if (g_sci->getEngineState()->currentRoomNumber() == 6050) {
+								skipSignal = false;
+							}
+#endif
 						default:
 							break;
 						}


Commit: a1153661c4747711abc52a35a54bc04c8f56f0cf
    https://github.com/scummvm/scummvm/commit/a1153661c4747711abc52a35a54bc04c8f56f0cf
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-03-30T20:49:36-05:00

Commit Message:
SCI: Stop getCurrentCallOrigin from mutating stack frames

This fixes incorrect backtraces after a workaround failure or
other call to getCurrentCallOrigin when one or more stack frames
are calls to local procedures.

Changed paths:
    engines/sci/engine/state.cpp
    engines/sci/engine/workarounds.cpp


diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp
index c23add1..76df322 100644
--- a/engines/sci/engine/state.cpp
+++ b/engines/sci/engine/state.cpp
@@ -390,26 +390,29 @@ SciCallOrigin EngineState::getCurrentCallOrigin() const {
 	const Script *localScript = _segMan->getScriptIfLoaded(xs->local_segment);
 	int curScriptNr = localScript->getScriptNumber();
 
+	Selector debugSelector = xs->debugSelector;
+	int debugExportId = xs->debugExportId;
+
 	if (xs->debugLocalCallOffset != -1) {
 		// if lastcall was actually a local call search back for a real call
 		Common::List<ExecStack>::const_iterator callIterator = _executionStack.end();
 		while (callIterator != _executionStack.begin()) {
 			callIterator--;
 			const ExecStack &loopCall = *callIterator;
-			if ((loopCall.debugSelector != -1) || (loopCall.debugExportId != -1)) {
-				xs->debugSelector = loopCall.debugSelector;
-				xs->debugExportId = loopCall.debugExportId;
+			if (loopCall.debugSelector != -1 || loopCall.debugExportId != -1) {
+				debugSelector = loopCall.debugSelector;
+				debugExportId = loopCall.debugExportId;
 				break;
 			}
 		}
 	}
 
 	if (xs->type == EXEC_STACK_TYPE_CALL) {
-		if (xs->debugSelector != -1) {
-			curMethodName = g_sci->getKernel()->getSelectorName(xs->debugSelector);
-		} else if (xs->debugExportId != -1) {
+		if (debugSelector != -1) {
+			curMethodName = g_sci->getKernel()->getSelectorName(debugSelector);
+		} else if (debugExportId != -1) {
 			curObjectName = "";
-			curMethodName = Common::String::format("export %d", xs->debugExportId);
+			curMethodName = Common::String::format("export %d", debugExportId);
 		}
 	}
 
diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp
index 148e9e7..025e94a 100644
--- a/engines/sci/engine/workarounds.cpp
+++ b/engines/sci/engine/workarounds.cpp
@@ -876,7 +876,7 @@ const SciWorkaroundEntry kScrollWindowAdd_workarounds[] = {
 
 SciWorkaroundSolution trackOriginAndFindWorkaround(int index, const SciWorkaroundEntry *workaroundList, SciCallOrigin *trackOrigin) {
 	const EngineState *state = g_sci->getEngineState();
-	ExecStack *lastCall = state->xs;
+	const ExecStack *lastCall = state->xs;
 	const SciGameId gameId = g_sci->getGameId();
 
 	*trackOrigin = state->getCurrentCallOrigin();


Commit: 3678390f3eac8d8373840c91646076154f49aed1
    https://github.com/scummvm/scummvm/commit/3678390f3eac8d8373840c91646076154f49aed1
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-03-30T20:49:37-05:00

Commit Message:
SCI: Add clarifying comment to op_rest

Changed paths:
    engines/sci/engine/vm.cpp


diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp
index b2807e0..3535b27 100644
--- a/engines/sci/engine/vm.cpp
+++ b/engines/sci/engine/vm.cpp
@@ -1114,6 +1114,8 @@ void run_vm(EngineState *s) {
 
 		case op_rest: // 0x2c (44)
 			// Pushes all or part of the parameter variable list on the stack
+			// Index 0 is argc, so normally this will be called as &rest 1 to
+			// forward all the arguments.
 			temp = (uint16) opparams[0]; // First argument
 			s->r_rest = MAX<int16>(s->xs->argc - temp + 1, 0); // +1 because temp counts the paramcount while argc doesn't
 


Commit: ee644ec01b292c3308085170021f04f6f6917bc9
    https://github.com/scummvm/scummvm/commit/ee644ec01b292c3308085170021f04f6f6917bc9
Author: Colin Snover (github.com at zetafleet.com)
Date: 2017-03-30T20:49:37-05:00

Commit Message:
SCI32: Check for game aborts in all kList iteration methods

This fixes a use-after-free in GK2 when restoring a second save
game, when the List reg_t is still considered valid but the List
has moved due to a partial game restore.

Changed paths:
    engines/sci/engine/klists.cpp


diff --git a/engines/sci/engine/klists.cpp b/engines/sci/engine/klists.cpp
index 305d459..2f66e51 100644
--- a/engines/sci/engine/klists.cpp
+++ b/engines/sci/engine/klists.cpp
@@ -618,6 +618,7 @@ reg_t kListEachElementDo(EngineState *s, int argc, reg_t *argv) {
 			}
 		} else {
 			invokeSelector(s, curObject, slc, argc, argv, argc - 2, argv + 2);
+
 			// Check if the call above leads to a game restore, in which case
 			// the segment manager will be reset, and the original list will
 			// be invalidated
@@ -672,6 +673,12 @@ reg_t kListFirstTrue(EngineState *s, int argc, reg_t *argv) {
 		} else {
 			invokeSelector(s, curObject, slc, argc, argv, argc - 2, argv + 2);
 
+			// Check if the call above leads to a game restore, in which case
+			// the segment manager will be reset, and the original list will
+			// be invalidated
+			if (s->abortScriptProcessing == kAbortLoadGame)
+				return s->r_acc;
+
 			// Check if the result is true
 			if (!s->r_acc.isNull()) {
 				s->r_acc = curObject;
@@ -721,6 +728,12 @@ reg_t kListAllTrue(EngineState *s, int argc, reg_t *argv) {
 			s->r_acc = readSelector(s->_segMan, curObject, slc);
 		} else {
 			invokeSelector(s, curObject, slc, argc, argv, argc - 2, argv + 2);
+
+			// Check if the call above leads to a game restore, in which case
+			// the segment manager will be reset, and the original list will
+			// be invalidated
+			if (s->abortScriptProcessing == kAbortLoadGame)
+				return s->r_acc;
 		}
 
 		// Check if the result isn't true





More information about the Scummvm-git-logs mailing list