Index: scumm/actor.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/actor.cpp,v
retrieving revision 1.389
diff -u -r1.389 actor.cpp
--- scumm/actor.cpp	31 Oct 2005 19:48:48 -0000	1.389
+++ scumm/actor.cpp	2 Nov 2005 12:01:04 -0000
@@ -1360,10 +1360,13 @@
 	}
 	_charsetBufPos = 0;
 	_talkDelay = 0;
-	_haveMsg = 0xFF;
+	_haveMsg = 1;
 	if (_version == 7)
 		VAR(VAR_HAVE_MSG) = 0xFF;
+	_haveActorSpeechMsg = true;
 	CHARSET_1();
+	if (_version == 8)
+		VAR(VAR_HAVE_MSG) = (_string[0].no_talk_anim) ? 2 : 1;
 }
 #endif
 
@@ -1428,6 +1431,7 @@
 	VAR(VAR_HAVE_MSG) = 0xFF;
 	if (VAR_CHARCOUNT != 0xFF)
 		VAR(VAR_CHARCOUNT) = 0;
+	_haveActorSpeechMsg = true;
 	CHARSET_1();
 }
 
@@ -1474,7 +1478,13 @@
 	if (_version == 8)
 		VAR(VAR_HAVE_MSG) = 0;
 	_keepText = false;
-	_charset->restoreCharsetBg();
+	if (_version >= 7) {
+#ifndef DISABLE_SCUMM_7_8
+		((ScummEngine_v7 *)this)->clearSubtitleQueue();
+#endif
+	} else {
+		_charset->restoreCharsetBg();
+	}
 }
 
 void Actor::setActorCostume(int c) {
Index: scumm/intern.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/intern.h,v
retrieving revision 2.538
diff -u -r2.538 intern.h
--- scumm/intern.h	27 Oct 2005 06:51:41 -0000	2.538
+++ scumm/intern.h	2 Nov 2005 12:01:05 -0000
@@ -1003,6 +1003,8 @@
 
 	int findObject(int x, int y, int num, int *args);
 	int getSoundResourceSize(int id);
+	
+	virtual bool handleNextCharsetCode(Actor *a, int *c);
 
 	/* HE version 72 script opcodes */
 	void o72_pushDWord();
@@ -1338,6 +1340,21 @@
 	int _languageIndexSize;
 	char _lastStringTag[12+1];
 
+	struct SubtitleText {
+		byte text[256];
+		byte charset;
+		byte color;
+		int16 xpos, ypos;
+		bool actorSpeechMsg;
+	};
+
+	int _subtitleQueuePos;
+	SubtitleText _subtitleQueue[20];
+
+	void processSubtitleQueue();
+	void addSubtitleToQueue(const byte *text, const Common::Point &pos, byte color, byte charset);
+	void clearSubtitleQueue();	
+
 protected:
 	virtual void setupScummVars();
 	virtual void initScummVars();
Index: scumm/saveload.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/saveload.cpp,v
retrieving revision 1.253
diff -u -r1.253 saveload.cpp
--- scumm/saveload.cpp	1 Nov 2005 02:43:54 -0000	1.253
+++ scumm/saveload.cpp	2 Nov 2005 12:01:08 -0000
@@ -730,6 +730,7 @@
 		MKLINE(ScummEngine, _charsetBufPos, sleInt16, VER(10)),
 
 		MKLINE(ScummEngine, _haveMsg, sleByte, VER(8)),
+		MKLINE(ScummEngine, _haveActorSpeechMsg, sleByte, VER(61)),
 		MKLINE(ScummEngine, _useTalkAnims, sleByte, VER(8)),
 
 		MKLINE(ScummEngine, _talkDelay, sleInt16, VER(8)),
@@ -952,6 +953,13 @@
 		_system->warpMouse(_mouse.x, _mouse.y);
 	}
 
+	// Before V61, we reused the _haveMsg flag to handle "alternative" speech sound
+	// files (see charset code 10). Behave like the original, rather.
+	if (s->isLoading() && s->getVersion() < VER(61)) {
+		_haveActorSpeechMsg = (_haveMsg != 0xFE);
+		_haveMsg = 0xFF;
+	}
+
 	//
 	// Save/load actors
 	//
@@ -1190,8 +1198,25 @@
 void ScummEngine_v7::saveOrLoad(Serializer *s) {
 	ScummEngine::saveOrLoad(s);
 
-	assert(_imuseDigital);
+	const SaveLoadEntry subtitleQueueEntries[] = {
+		MKARRAY(SubtitleText, text[0], sleByte, 256, VER(61)),
+		MKLINE(SubtitleText, charset, sleByte, VER(61)),
+		MKLINE(SubtitleText, color, sleByte, VER(61)),
+		MKLINE(SubtitleText, xpos, sleInt16, VER(61)),
+		MKLINE(SubtitleText, ypos, sleInt16, VER(61)),
+		MKLINE(SubtitleText, actorSpeechMsg, sleByte, VER(61)),
+		MKEND()
+	};
+
+	const SaveLoadEntry V7Entries[] = {
+		MKLINE(ScummEngine_v7, _subtitleQueuePos, sleInt32, VER(61)),
+		MKEND()
+	};
+
 	_imuseDigital->saveOrLoad(s);
+
+	s->saveLoadArrayOf(_subtitleQueue, ARRAYSIZE(_subtitleQueue), sizeof(_subtitleQueue[0]), subtitleQueueEntries);
+	s->saveLoadEntries(this, V7Entries);
 }
 #endif
 
Index: scumm/saveload.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/saveload.h,v
retrieving revision 1.71
diff -u -r1.71 saveload.h
--- scumm/saveload.h	1 Nov 2005 02:43:54 -0000	1.71
+++ scumm/saveload.h	2 Nov 2005 12:01:08 -0000
@@ -45,7 +45,7 @@
  * only saves/loads those which are valid for the version of the savegame
  * which is being loaded/saved currently.
  */
-#define CURRENT_VER 60
+#define CURRENT_VER 61
 
 /**
  * An auxillary macro, used to specify savegame versions. We use this instead
Index: scumm/scumm.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/scumm.cpp,v
retrieving revision 1.622
diff -u -r1.622 scumm.cpp
--- scumm/scumm.cpp	1 Nov 2005 13:55:53 -0000	1.622
+++ scumm/scumm.cpp	2 Nov 2005 12:01:10 -0000
@@ -1125,6 +1125,7 @@
 	_palDirtyMin = 0;
 	_palDirtyMax = 0;
 	_haveMsg = 0;
+	_haveActorSpeechMsg = false;
 	_useTalkAnims = false;
 	_defaultTalkDelay = 0;
 	_midiDriver = MD_NULL;
@@ -1582,6 +1583,7 @@
 	_existLanguageFile = false;
 	_languageBuffer = NULL;
 	_languageIndex = NULL;
+	clearSubtitleQueue();
 }
 
 ScummEngine_v7::~ScummEngine_v7() {
@@ -1936,6 +1938,7 @@
 
 	_charsetBufPos = 0;
 	_haveMsg = 0;
+	_haveActorSpeechMsg = false;
 
 	_varwatch = -1;
 	_screenStartStrip = 0;
@@ -2293,7 +2296,7 @@
 		VAR(VAR_CAMERA_POS_X) = camera._cur.x;
 	}
 	if (_version <= 7)
-		VAR(VAR_HAVE_MSG) = (_haveMsg == 0xFE) ? 0xFF : _haveMsg;
+		VAR(VAR_HAVE_MSG) = _haveMsg;
 
 	if (_platform == Common::kPlatformC64 && _gameId == GID_MANIAC) {
 		// TODO
Index: scumm/scumm.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/scumm.h,v
retrieving revision 1.654
diff -u -r1.654 scumm.h
--- scumm/scumm.h	1 Nov 2005 02:43:54 -0000	1.654
+++ scumm/scumm.h	2 Nov 2005 12:01:11 -0000
@@ -1093,6 +1093,7 @@
 	byte *_palManipIntermediatePal;
 
 	byte _haveMsg;
+	bool _haveActorSpeechMsg;
 	bool _useTalkAnims;
 	uint16 _defaultTalkDelay;
 	int _tempMusic;
@@ -1161,7 +1162,9 @@
 
 	void printString(int m, const byte *msg);
 
+	virtual bool handleNextCharsetCode(Actor *a, int *c);
 	void CHARSET_1();
+
 	void drawString(int a, const byte *msg);
 	void debugMessage(const byte *msg);
 	void showMessageDialog(const byte *msg);
Index: scumm/string.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/string.cpp,v
retrieving revision 1.306
diff -u -r1.306 string.cpp
--- scumm/string.cpp	18 Oct 2005 01:30:21 -0000	1.306
+++ scumm/string.cpp	2 Nov 2005 12:01:11 -0000
@@ -95,17 +95,212 @@
 	VAR(VAR_KEYPRESS) = runDialog(dialog);
 }
 
-void ScummEngine::CHARSET_1() {
+#ifndef DISABLE_SCUMM_7_8
+void ScummEngine_v7::processSubtitleQueue() {
+	for (int i = 0; i < _subtitleQueuePos; ++i) {
+		SubtitleText *st = &_subtitleQueue[i];
+		if (!ConfMan.getBool("subtitles") || VAR(VAR_VOICE_MODE) == 0)
+			// subtitles are disabled, don't display the text
+			continue;
+		if (!ConfMan.getBool("subtitles") && (!st->actorSpeechMsg || _mixer->isSoundHandleActive(_sound->_talkChannelHandle)))
+			// no subtitles and there's a speech variant of the message, don't display the text
+			continue;
+		enqueueText(st->text, st->xpos, st->ypos, st->color, st->charset, false);
+	}
+}
+
+void ScummEngine_v7::addSubtitleToQueue(const byte *text, const Common::Point &pos, byte color, byte charset) {
+	if (text[0] && strcmp((const char *)text, " ") != 0) {
+		assert(_subtitleQueuePos < ARRAYSIZE(_subtitleQueue));
+		SubtitleText *st = &_subtitleQueue[_subtitleQueuePos];
+		int i = 0;
+		while (1) {
+			st->text[i] = text[i];
+			if (!text[i])
+				break;
+			++i;
+		}
+		st->xpos = pos.x;
+		st->ypos = pos.y;
+		st->color = color;
+		st->charset = charset;
+		st->actorSpeechMsg = _haveActorSpeechMsg;
+		++_subtitleQueuePos;
+	}
+}
+
+void ScummEngine_v7::clearSubtitleQueue() {
+	memset(_subtitleQueue, 0, sizeof(_subtitleQueue));
+	_subtitleQueuePos = 0;
+}
+#endif
+
+bool ScummEngine::handleNextCharsetCode(Actor *a, int *code) {
 	uint32 talk_sound_a = 0;
 	uint32 talk_sound_b = 0;
-	int i, t, c;
-	int frme;
-	Actor *a;
-	byte *buffer;
-	int code = (_heversion >= 80) ? 127 : 64;
+	int i, color, frme, c, oldy;
+	bool endLoop = false;
+	byte *buffer = _charsetBuffer + _charsetBufPos;
+	while (!endLoop) {
+		c = *buffer++;
+		if (!(c == 0xFF || (_version <= 6 && c == 0xFE))) {
+			break;
+		}
+		c = *buffer++;
+		switch (c) {
+		case 1:
+			endLoop = true;
+			c = 13; // new line
+			break;
+		case 2:
+			_haveMsg = 0;
+			_keepText = true;
+			endLoop = true;
+			break;
+		case 3:
+			_haveMsg = (_version >= 7) ? 1 : 0xFF;
+			_keepText = false;
+			endLoop = true;
+			break;
+		case 8:
+			// Ignore this code here. Occurs e.g. in MI2 when you
+			// talk to the carpenter on scabb island. It works like
+			// code 1 (=newline) in verb texts, but is ignored in
+			// spoken text (i.e. here). Used for very long verb
+			// sentences.
+			break;
+		case 9:
+			frme = buffer[0] | (buffer[1] << 8);
+			buffer += 2;
+			if (a)
+				a->startAnimActor(frme);
+			break;
+		case 10:
+			// Note the similarity to the code in debugMessage()
+			talk_sound_a = buffer[0] | (buffer[1] << 8) | (buffer[4] << 16) | (buffer[5] << 24);
+			talk_sound_b = buffer[8] | (buffer[9] << 8) | (buffer[12] << 16) | (buffer[13] << 24);
+			buffer += 14;
+			if (_heversion >= 60) {
+				_sound->startHETalkSound(talk_sound_a);
+			} else {
+				_sound->talkSound(talk_sound_a, talk_sound_b, 2);
+			}
+			_haveActorSpeechMsg = false;
+			break;
+		case 12:
+			color = buffer[0] | (buffer[1] << 8);
+			buffer += 2;
+			if (color == 0xFF)
+				_charset->setColor(_charsetColor);
+			else
+				_charset->setColor(color);
+			break;
+		case 13:
+			debug(0, "handleNextCharsetCode: Unknown opcode 13 %d", READ_LE_UINT16(buffer));
+			buffer += 2;
+			break;
+		case 14:
+			oldy = _charset->getFontHeight();
+			_charset->setCurID(*buffer++);
+			buffer += 2;
+			for (i = 0; i < 4; i++)
+				_charsetColorMap[i] = _charsetData[_charset->getCurID()][i];
+			_charset->_nextTop -= _charset->getFontHeight() - oldy;
+			break;
+		default:
+			error("handleNextCharsetCode: invalid code %d", c);
+		}
+	}
+	_charsetBufPos = buffer - _charsetBuffer;
+	*code = c;
+	return (c != 2 && c != 3);
+}
+
+#ifndef DISABLE_HE
+bool ScummEngine_v72he::handleNextCharsetCode(Actor *a, int *code) {
+	const int charsetCode = (_heversion >= 80) ? 127 : 64;
+	uint32 talk_sound_a = 0;
+	uint32 talk_sound_b = 0;
+	int i, c;
 	char value[32];
+	byte *buffer = _charsetBuffer + _charsetBufPos;
+	do {
+		c = *buffer++;
+		if (c != charsetCode) {
+			break;
+		}
+		c = *buffer++;
+		switch (c) {
+		case 84:
+			i = 0;
+			memset(value, 0, 32);
+			c = *buffer++;
+			while (c != 44) {
+				value[i] = c;
+				c = *buffer++;
+				i++;
+			}
+			value[i] = 0;
+			talk_sound_a = atoi(value);
+			i = 0;
+			memset(value, 0, 32);
+			c = *buffer++;
+			while (c != charsetCode) {
+				value[i] = c;
+				c = *buffer++;
+				i++;
+			}
+			value[i] = 0;
+			talk_sound_b = atoi(value);
+			_sound->startHETalkSound(talk_sound_a);
+			break;
+		case 104:
+			_haveMsg = 0;
+			_keepText = true;
+			break;
+		case 110:
+			c = 13; // new line
+			break;
+		case 116:
+			i = 0;
+			memset(value, 0, 32);
+			c = *buffer++;
+			while (c != charsetCode) {
+				value[i] = c;
+				c = *buffer++;
+				i++;
+			}
+			value[i] = 0;
+			talk_sound_a = atoi(value);
+			talk_sound_b = 0;
+			_sound->startHETalkSound(talk_sound_a);
+			break;
+		case 119:
+			_haveMsg = 0xFF;
+			_keepText = false;
+			break;
+		default:
+			error("handleNextCharsetCode: invalid code %d", c);
+		}
+	} while (c != 13);
+	_charsetBufPos = buffer - _charsetBuffer;
+	*code = c;
+	return true;
+}
+#endif
 
-	bool cmi_pos_hack = false;
+void ScummEngine::CHARSET_1() {
+	Actor *a;
+	int t, c = 0;
+#ifndef DISABLE_SCUMM_7_8
+	byte subtitleBuffer[200];
+	byte *subtitleLine = subtitleBuffer;
+	Common::Point subtitlePos;
+
+	if (_version >= 7) {
+		((ScummEngine_v7 *)this)->processSubtitleQueue();
+	}
+#endif
 
 	if (!_haveMsg)
 		return;
@@ -166,13 +361,12 @@
 		_charset->setCurID(_string[0].charset);
 
 	if (_version >= 5)
-		for (i = 0; i < 4; i++)
-			_charsetColorMap[i] = _charsetData[_charset->getCurID()][i];
+		memcpy(_charsetColorMap, _charsetData[_charset->getCurID()], 4);
 
 	if (_talkDelay)
 		return;
 
-	if ((_version <= 7 && _haveMsg == 1) || (_version == 8 && VAR(VAR_HAVE_MSG))) {
+	if ((_version <= 6 && _haveMsg == 1) || (_version == 7 && _haveMsg != 1) || (_version == 8 && VAR(VAR_HAVE_MSG))) {
 		if ((_sound->_sfxMode & 2) == 0)
 			stopTalk();
 		return;
@@ -183,14 +377,18 @@
 		_useTalkAnims = true;
 	}
 
-	// Always set to 60
-	if (_version <= 6)
-		_talkDelay = 60;
-	else
-		_talkDelay = VAR(VAR_DEFAULT_TALK_DELAY);
+	_talkDelay = (VAR_DEFAULT_TALK_DELAY != 0xFF) ? VAR(VAR_DEFAULT_TALK_DELAY) : 60;
 
 	if (!_keepText) {
-		_charset->restoreCharsetBg();
+		if (_version >= 7) {
+#ifndef DISABLE_SCUMM_7_8
+			((ScummEngine_v7 *)this)->clearSubtitleQueue();
+			_charset->_nextLeft = _string[0].xpos;
+			_charset->_nextTop = _string[0].ypos;
+#endif
+		} else {
+			_charset->restoreCharsetBg();
+		}
 	}
 
 	t = _charset->_right - _string[0].xpos - 1;
@@ -200,25 +398,21 @@
 		t *= 2;
 	}
 
-	buffer = _charsetBuffer + _charsetBufPos;
-
 	if (_version > 3)
-		_charset->addLinebreaks(0, buffer, 0, t);
+		_charset->addLinebreaks(0, _charsetBuffer + _charsetBufPos, 0, t);
 
 	if (_charset->_center) {
-		_charset->_nextLeft -= _charset->getStringWidth(0, buffer) / 2;
+		_charset->_nextLeft -= _charset->getStringWidth(0, _charsetBuffer + _charsetBufPos) / 2;
 		if (_charset->_nextLeft < 0)
 			_charset->_nextLeft = 0;
 	}
 
 	_charset->_disableOffsX = _charset->_firstChar = !_keepText;
 
-	do {
-		c = *buffer++;
+	while (handleNextCharsetCode(a, &c)) {
 		if (c == 0) {
-			// End of text reached, set _haveMsg to 1 so that the text will be
-			// removed next time CHARSET_1 is called.
-			_haveMsg = 1;
+			// End of text reached, set _haveMsg accordingly
+			_haveMsg = (_version >= 7) ? 2 : 1;
 			_keepText = false;
 			break;
 		}
@@ -233,9 +427,16 @@
 		if (c == 13) {
 		newLine:;
 			_charset->_nextLeft = _string[0].xpos;
+#ifndef DISABLE_SCUMM_7_8			
+			if (_version >= 7 && subtitleLine != subtitleBuffer) {
+				((ScummEngine_v7 *)this)->addSubtitleToQueue(subtitleBuffer, subtitlePos, _charsetColor, _charset->getCurID());
+				subtitleLine = subtitleBuffer;
+			}
+#endif
 			if (_charset->_center) {
-				_charset->_nextLeft -= _charset->getStringWidth(0, buffer) / 2;
+				_charset->_nextLeft -= _charset->getStringWidth(0, _charsetBuffer + _charsetBufPos) / 2;
 			}
+
 			if (_platform == Common::kPlatformC64 && _gameId == GID_MANIAC) {
 				break;
 			} else if (!(_platform == Common::kPlatformFMTowns) && _string[0].height) {
@@ -250,204 +451,59 @@
 			continue;
 		}
 
-		if (_heversion >= 72 && c == code) {
-			c = *buffer++;
-			switch (c) {
-			case 84:
-				i = 0;
-				memset(value, 0, 32);
-				c = *buffer++;
-				while (c != 44) {
-					value[i] = c;
-					c = *buffer++;
-					i++;
-				}
-				value[i] = 0;
-				talk_sound_a = atoi(value);
-
-				i = 0;
-				memset(value, 0, 32);
-				c = *buffer++;
-				while (c != code) {
-					value[i] = c;
-					c = *buffer++;
-					i++;
-				}
-				value[i] = 0;
-				talk_sound_b = atoi(value);
-
-				_sound->startHETalkSound(talk_sound_a);
-				break;
-			case 104:
-				_haveMsg = 0;
-				_keepText = true;
-				break;
-			case 110:
-				goto newLine;
-			case 116:
-				i = 0;
-				memset(value, 0, 32);
-				c = *buffer++;
-				while (c != code) {
-					value[i] = c;
-					c = *buffer++;
-					i++;
-				}
-				value[i] = 0;
-				talk_sound_a = atoi(value);
-				talk_sound_b = 0;
-
-				_sound->startHETalkSound(talk_sound_a);
-				break;
-			case 119:
-				if (_haveMsg != 0xFE)
-					_haveMsg = 0xFF;
-				_keepText = false;
-				break;
-			default:
-				error("CHARSET_1: invalid code %d", c);
-			}
-		} else if (c == 0xFE || c == 0xFF) {
-			// WORKAROUND to avoid korean code 0xfe treated as charset message code.
-			if (c == 0xFE && checkKSCode(*(buffer + 1), c) && _useCJKMode) {
-				goto loc_avoid_ks_fe;
-			}
-			c = *buffer++;
-			switch (c) {
-			case 1:
-				goto newLine;
-			case 2:
-				_haveMsg = 0;
-				_keepText = true;
-				break;
-			case 3:
-				if (_haveMsg != 0xFE)
-					_haveMsg = 0xFF;
-				_keepText = false;
-				break;
-			case 8:
-				// Ignore this code here. Occurs e.g. in MI2 when you
-				// talk to the carpenter on scabb island. It works like
-				// code 1 (=newline) in verb texts, but is ignored in
-				// spoken text (i.e. here). Used for very long verb
-				// sentences.
-				break;
-			case 9:
-				frme = *buffer++;
-				frme |= *buffer++ << 8;
-				if (a)
-					a->startAnimActor(frme);
-				break;
-			case 10:
-				// Note the similarity to the code in debugMessage()
-				talk_sound_a = buffer[0] | (buffer[1] << 8) | (buffer[4] << 16) | (buffer[5] << 24);
-				talk_sound_b = buffer[8] | (buffer[9] << 8) | (buffer[12] << 16) | (buffer[13] << 24);
-				buffer += 14;
-
-				if (_heversion >= 60) {
-					_sound->startHETalkSound(talk_sound_a);
-				} else {
-					_sound->talkSound(talk_sound_a, talk_sound_b, 2);
-				}
-
-				// Set flag that speech variant exist of this msg.
-				// This is actually a hack added by ScummVM; the original did
-				// subtitle hiding in some other way. I am not sure exactly
-				// how, though.
-				// FIXME: This is actually a rather ugly hack, and we should consider
-				// replacing it with something better; problem is that _haveMsg is saved,
-				// so we need to cope with old save games if we ever change this.
-				// And BTW Fingolfin was responsible for this silly bad hack. Stupid me! :-).
-				if (_haveMsg == 0xFF)
-					_haveMsg = 0xFE;
-				break;
-			case 12:
-				int color;
-				color = *buffer++;
-				color |= *buffer++ << 8;
-				if (color == 0xFF)
-					_charset->setColor(_charsetColor);
-				else
-					_charset->setColor(color);
-				break;
-			case 13:
-				debug(0, "CHARSET_1: Unknown opcode 13 %d", READ_LE_UINT16(buffer));
-				buffer += 2;
-				break;
-			case 14: {
-				int oldy = _charset->getFontHeight();
-
-				_charset->setCurID(*buffer++);
-				buffer += 2;
-				for (i = 0; i < 4; i++)
-					_charsetColorMap[i] = _charsetData[_charset->getCurID()][i];
-				_charset->_nextTop -= _charset->getFontHeight() - oldy;
-				break;
-				}
-			default:
-				error("CHARSET_1: invalid code %d", c);
+		_charset->_left = _charset->_nextLeft;
+		_charset->_top = _charset->_nextTop;
+		if (_version >= 7) {
+#ifndef DISABLE_SCUMM_7_8
+			if (subtitleLine == subtitleBuffer) {
+				subtitlePos.x = _charset->_left;
+				subtitlePos.y = _charset->_top;
 			}
-		} else {
-loc_avoid_ks_fe:
-			_charset->_left = _charset->_nextLeft;
-			_charset->_top = _charset->_nextTop;
-			if (c & 0x80 && _useCJKMode)
-				if (_language == Common::JA_JPN && !checkSJISCode(c)) {
-					c = 0x20; //not in S-JIS
-				} else {
-					c += *buffer++ * 256; //LE
-					if (_gameId == GID_CMI) { //HACK: This fixes korean text position in COMI (off by 6 pixel)
-						cmi_pos_hack = true;
-						_charset->_top += 6;
-					}
-				}
+			*subtitleLine++ = c;
+			*subtitleLine = '\0';
+#endif
+	} else {
 			if (_version <= 3) {
 				_charset->printChar(c);
 			} else {
 				if (_features & GF_HE_NOSUBTITLES) {
 					// HE games which use sprites for subtitles
-				} else if ((_imuseDigital && _sound->isSoundRunning(kTalkSoundID)) && (!ConfMan.getBool("subtitles") || VAR(VAR_VOICE_MODE) == 0)) {
-					// Special case for games using imuse digital.for sound
 				} else if (_heversion >= 60 && !ConfMan.getBool("subtitles") && _sound->isSoundRunning(1)) {
 					// Special case for HE games
 				} else if ((_gameId == GID_LOOM256) && !ConfMan.getBool("subtitles") && (_sound->pollCD())) {
 					// Special case for loomcd, since it only uses CD audio.for sound
-				} else if (!ConfMan.getBool("subtitles") && (_haveMsg == 0xFE || _mixer->isSoundHandleActive(_sound->_talkChannelHandle))) {
+				} else if (!ConfMan.getBool("subtitles") && (!_haveActorSpeechMsg || _mixer->isSoundHandleActive(_sound->_talkChannelHandle))) {
 					// Subtitles are turned off, and there is a voice version
 					// of this message -> don't print it.
 				} else {
 					_charset->printChar(c);
 				}
 			}
-			if (cmi_pos_hack) {
-				cmi_pos_hack = false;
-				_charset->_top -= 6;
-			}
-
 			_charset->_nextLeft = _charset->_left;
 			_charset->_nextTop = _charset->_top;
-			if (_version <= 2) {
-				_talkDelay += _defaultTalkDelay;
-				VAR(VAR_CHARCOUNT)++;
-			} else
-				_talkDelay += (int)VAR(VAR_CHARINC);
-
-			// Handle line overflow for V3
-			if (_version == 3 && _charset->_nextLeft > _screenWidth) {
-				_charset->_nextLeft = _screenWidth;
-			}
-			// Handle line breaks for V1-V2
-			if (_version <= 2 && _charset->_nextLeft > _screenWidth) {
-				goto newLine;
-			}
 		}
-	} while (c != 2 && c != 3);
 
-	_charsetBufPos = buffer - _charsetBuffer;
+		if (_version <= 2) {
+			_talkDelay += _defaultTalkDelay;
+			VAR(VAR_CHARCOUNT)++;
+		} else {
+			_talkDelay += (int)VAR(VAR_CHARINC);
+		}
+		// Handle line overflow for V3
+		if (_version == 3 && _charset->_nextLeft > _screenWidth) {
+			_charset->_nextLeft = _screenWidth;
+		}
+		// Handle line breaks for V1-V2
+		if (_version <= 2 && _charset->_nextLeft > _screenWidth) {
+			goto newLine;
+		}
+	}
 
-	// TODO Verify this is correct spot
-	if (_version == 8)
-		VAR(VAR_HAVE_MSG) = (_string[0].no_talk_anim) ? 2 : 1;
+#ifndef DISABLE_SCUMM_7_8
+	if (_version >= 7 && subtitleLine != subtitleBuffer) {
+		((ScummEngine_v7 *)this)->addSubtitleToQueue(subtitleBuffer, subtitlePos, _charsetColor, _charset->getCurID());
+	}
+#endif
 }
 
 void ScummEngine::drawString(int a, const byte *msg) {
@@ -859,7 +915,7 @@
 }
 
 #ifndef DISABLE_SCUMM_7_8
-int indexCompare(const void *p1, const void *p2) {
+static int indexCompare(const void *p1, const void *p2) {
 	const ScummEngine_v7::LangIndexNode *i1 = (const ScummEngine_v7::LangIndexNode *) p1;
 	const ScummEngine_v7::LangIndexNode *i2 = (const ScummEngine_v7::LangIndexNode *) p2;
 
