Index: scumm/intern.h
===================================================================
--- scumm/intern.h	(revision 26513)
+++ scumm/intern.h	(working copy)
@@ -972,6 +972,7 @@
 	virtual const char *getOpcodeDesc(byte i);
 
 	virtual void printString(int m, const byte *msg);
+	virtual void CHARSET_1();
 
 	virtual void scummLoop_handleSaveLoad();
 
Index: scumm/actor.cpp
===================================================================
--- scumm/actor.cpp	(revision 26513)
+++ scumm/actor.cpp	(working copy)
@@ -1850,6 +1850,7 @@
 #ifndef DISABLE_SCUMM_7_8
 void ScummEngine_v7::actorTalk(const byte *msg) {
 	Actor *a;
+	bool stringWrap;
 
 	convertMessageToString(msg, _charsetBuffer, sizeof(_charsetBuffer));
 
@@ -1882,9 +1883,15 @@
 	if (_game.version == 7)
 		VAR(VAR_HAVE_MSG) = 0xFF;
 	_haveActorSpeechMsg = true;
+	if (_game.version == 8) {
+		stringWrap = _string[0].wrapping;
+		_string[0].wrapping = true;
+	}
 	CHARSET_1();
-	if (_game.version == 8)
+	if (_game.version == 8) {
 		VAR(VAR_HAVE_MSG) = (_string[0].no_talk_anim) ? 2 : 1;
+		_string[0].wrapping = stringWrap;
+	}
 }
 #endif
 
Index: scumm/charset.h
===================================================================
--- scumm/charset.h	(revision 26513)
+++ scumm/charset.h	(working copy)
@@ -73,6 +73,7 @@
 	virtual void drawChar(int chr, const Graphics::Surface &s, int x, int y) {}
 
 	int getStringWidth(int a, const byte *str);
+	int getStringHeight(const byte *text);
 	void addLinebreaks(int a, byte *str, int pos, int maxwidth);
 	void translateColor();
 
Index: scumm/string.cpp
===================================================================
--- scumm/string.cpp	(revision 26513)
+++ scumm/string.cpp	(working copy)
@@ -437,7 +437,7 @@
 	if (getTalkingActor() != 0xFF)
 		a = derefActorSafe(getTalkingActor(), "CHARSET_1");
 
-	if (a && _string[0].overhead != 0) {
+	if (a && _string[0].overhead) {
 		int s;
 
 		_string[0].xpos = a->getPos().x - virtscr[0].xstart;
@@ -490,8 +490,7 @@
 		return;
 
 	if ((_game.version <= 6 && _haveMsg == 1) ||
-	    (_game.version == 7 && _haveMsg != 1) ||
-	    (_game.version == 8 && VAR(VAR_HAVE_MSG))) {
+	    (_game.version == 7 && _haveMsg != 1)) {
 
 		if (_game.heversion >= 60) {
 			if (_sound->isSoundRunning(1) == 0)
@@ -644,6 +643,164 @@
 #endif
 }
 
+#ifndef DISABLE_SCUMM_7_8
+void ScummEngine_v8::CHARSET_1() {
+	byte subtitleBuffer[2048];
+	byte *subtitleLine = subtitleBuffer;
+	Common::Point subtitlePos;
+
+	processSubtitleQueue();
+
+	if (!_haveMsg)
+		return;
+
+	Actor *a = NULL;
+	if (getTalkingActor() != 0xFF)
+		a = derefActorSafe(getTalkingActor(), "CHARSET_1");
+
+	StringTab saveStr = _string[0];
+	if (a && _string[0].overhead) {
+		int s;
+
+		_string[0].xpos = a->getPos().x - virtscr[0].xstart;
+		s = a->_scalex * a->_talkPosX / 255;
+		_string[0].xpos += (a->_talkPosX - s) / 2 + s;
+
+		_string[0].ypos = a->getPos().y - a->getElevation() - _screenTop;
+		s = a->_scaley * a->_talkPosY / 255;
+		_string[0].ypos += (a->_talkPosY - s) / 2 + s;
+	}
+
+	_charset->setColor(_charsetColor);
+
+	if (a && a->_charset)
+		_charset->setCurID(a->_charset);
+	else
+		_charset->setCurID(_string[0].charset);
+
+	if (_talkDelay)
+		return;
+
+	if (VAR(VAR_HAVE_MSG)) {
+		if ((_sound->_sfxMode & 2) == 0) {
+			stopTalk();
+		}
+		return;
+	}
+
+	if (a && !_string[0].no_talk_anim) {
+		a->runActorTalkScript(a->_talkStartFrame);
+	}
+
+	if (!_keepText) {
+		clearSubtitleQueue();
+		_nextLeft = _string[0].xpos;
+		_nextTop = _string[0].ypos + _screenTop;
+	}
+
+	_charset->_disableOffsX = _charset->_firstChar = !_keepText;
+
+	_talkDelay = VAR(VAR_DEFAULT_TALK_DELAY);
+	for (int i = _charsetBufPos; _charsetBuffer[i]; ++i) {
+		_talkDelay += VAR(VAR_CHARINC);
+	}
+
+	if (_string[0].wrapping) {
+		_charset->addLinebreaks(0, _charsetBuffer, _charsetBufPos, _screenWidth - 20);
+
+		struct { int pos, w; } substring[10];
+		int count = 0;
+		int maxLineWidth = 0;
+		int lastPos = 0;
+		int code = 0;
+		while (handleNextCharsetCode(a, &code)) {
+			if (code == 13 || code == 0) {
+				*subtitleLine++ = '\0';
+				assert(count < 10);
+				substring[count].w = _charset->getStringWidth(0, subtitleBuffer + lastPos);
+				if (maxLineWidth < substring[count].w) {
+					maxLineWidth = substring[count].w;
+				}
+				substring[count].pos = lastPos;
+				++count;
+				lastPos = subtitleLine - subtitleBuffer;
+			} else {
+				*subtitleLine++ = code;
+				*subtitleLine = '\0';
+			}
+			if (code == 0) {
+				break;
+			}
+		}
+
+		int h = count * _charset->getFontHeight();
+		h += _charset->getFontHeight() / 2;
+		subtitlePos.y = _string[0].ypos;
+		if (subtitlePos.y + h > _screenHeight - 10) {
+			subtitlePos.y = _screenHeight - 10 - h;
+		}
+		if (subtitlePos.y < 10) {
+			subtitlePos.y = 10;
+		}
+
+		for (int i = 0; i < count; ++i) {
+			subtitlePos.x = _string[0].xpos;
+			if (_string[0].center) {
+				if (subtitlePos.x + maxLineWidth / 2 > _screenWidth - 10) {
+					subtitlePos.x = _screenWidth - 10 - maxLineWidth / 2;
+				}
+				if (subtitlePos.x - maxLineWidth / 2 < 10) {
+					subtitlePos.x = 10 + maxLineWidth / 2;
+				}
+				subtitlePos.x -= substring[i].w / 2;
+			} else {
+				if (subtitlePos.x + maxLineWidth > _screenWidth - 10) {
+					subtitlePos.x = _screenWidth - 10 - maxLineWidth;
+				}
+				if (subtitlePos.x - maxLineWidth < 10) {
+					subtitlePos.x = 10;
+				}
+			}
+			if (subtitlePos.y < _screenHeight - 10) {
+				((ScummEngine_v7 *)this)->addSubtitleToQueue(subtitleBuffer + substring[i].pos, subtitlePos, _charsetColor, _charset->getCurID());
+			}
+			subtitlePos.y += _charset->getFontHeight();
+		}
+	} else {
+		int code = 0;
+		subtitlePos.y = _string[0].ypos;
+		if (subtitlePos.y < 10) {
+			subtitlePos.y = 10;
+		}
+		while (handleNextCharsetCode(a, &code)) {
+			if (code == 13 || code == 0) {
+				subtitlePos.x = _string[0].xpos;
+				if (_string[0].center) {
+					subtitlePos.x -= _charset->getStringWidth(0, subtitleBuffer) / 2;
+				}
+				if (subtitlePos.x < 10) {
+					subtitlePos.x = 10;
+				}
+				if (subtitlePos.y < _screenHeight - 10) {
+					((ScummEngine_v7 *)this)->addSubtitleToQueue(subtitleBuffer, subtitlePos, _charsetColor, _charset->getCurID());
+					subtitlePos.y += _charset->getFontHeight();
+				}
+				subtitleLine = subtitleBuffer;
+			} else {
+				*subtitleLine++ = code;
+			}
+			*subtitleLine = '\0';
+			if (code == 0) {
+				break;
+			}
+		}
+	}
+	_haveMsg = 2;
+	_keepText = false;
+	_string[0] = saveStr;
+}
+#endif
+
 void ScummEngine::drawString(int a, const byte *msg) {
 	byte buf[270];
 	byte *space;
Index: scumm/scumm.h
===================================================================
--- scumm/scumm.h	(revision 26513)
+++ scumm/scumm.h	(working copy)
@@ -243,6 +243,7 @@
 	bool center;
 	bool overhead;
 	bool no_talk_anim;
+	bool wrapping;
 };
 
 struct StringTab : StringSlot {
@@ -1169,7 +1170,7 @@
 	virtual void printString(int m, const byte *msg);
 
 	virtual bool handleNextCharsetCode(Actor *a, int *c);
-	void CHARSET_1();
+	virtual void CHARSET_1();
 	void drawString(int a, const byte *msg);
 	void debugMessage(const byte *msg);
 	void showMessageDialog(const byte *msg);
Index: scumm/charset.cpp
===================================================================
--- scumm/charset.cpp	(revision 26513)
+++ scumm/charset.cpp	(working copy)
@@ -348,6 +348,44 @@
 	return width;
 }
 
+int CharsetRenderer::getStringHeight(const byte *text) {
+	int pos = 0;
+	int height = 0;
+	byte chr;
+	int oldID = getCurID();
+
+	while ((chr = text[pos++]) != 0) {
+		if (chr == '\n' || chr == '\r')
+			break;
+		if (chr == '@')
+			continue;
+		if (chr == 255 || (_vm->_game.version <= 6 && chr == 254)) {
+			chr = text[pos++];
+			if (chr == 3) { // 'WAIT'
+				height += getFontHeight();
+				break;
+			}
+			if (chr == 10 || chr == 21 || chr == 12 || chr == 13) {
+				pos += 2;
+				continue;
+			}
+			if (chr == 9 || chr == 1 || chr == 2) { // 'Newline'
+				height += getFontHeight();
+				continue;
+			}
+			if (chr == 14) {
+				int set = text[pos] | (text[pos + 1] << 8);
+				pos += 2;
+				setCurID(set);
+				continue;
+			}
+		}
+	}
+
+	setCurID(oldID);
+	return height + getFontHeight();
+}
+
 void CharsetRenderer::addLinebreaks(int a, byte *str, int pos, int maxwidth) {
 	int lastspace = -1;
 	int curw = 1;
Index: scumm/saveload.cpp
===================================================================
--- scumm/saveload.cpp	(revision 26513)
+++ scumm/saveload.cpp	(working copy)
@@ -834,6 +834,8 @@
 		MKLINE(StringTab, _default.overhead, sleByte, VER(8)),
 		MKLINE(StringTab, no_talk_anim, sleByte, VER(8)),
 		MKLINE(StringTab, _default.no_talk_anim, sleByte, VER(8)),
+		MKLINE(StringTab, wrapping, sleByte, VER(71)),
+		MKLINE(StringTab, _default.wrapping, sleByte, VER(71)),
 		MKEND()
 	};
 
Index: scumm/script_v8.cpp
===================================================================
--- scumm/script_v8.cpp	(revision 26513)
+++ scumm/script_v8.cpp	(working copy)
@@ -488,7 +488,7 @@
 		_string[m].charset = pop();
 		break;
 	case 0xCE:		// SO_PRINT_LEFT
-		_string[m].center = false;
+		_string[m].wrapping = false;
 		_string[m].overhead = false;
 		break;
 	case 0xCF:		// SO_PRINT_OVERHEAD
@@ -503,7 +503,8 @@
 		_scriptPointer += resStrLen(_scriptPointer) + 1;
 		break;
 	case 0xD2:		// SO_PRINT_WRAP Set print wordwrap
-		//debug(0, "decodeParseString: SO_PRINT_WRAP");
+		_string[m].wrapping = true;
+		_string[m].overhead = false;
 		break;
 	default:
 		error("decodeParseString: default case 0x%x", b);
Index: scumm/saveload.h
===================================================================
--- scumm/saveload.h	(revision 26513)
+++ scumm/saveload.h	(working copy)
@@ -47,7 +47,7 @@
  * only saves/loads those which are valid for the version of the savegame
  * which is being loaded/saved currently.
  */
-#define CURRENT_VER 70
+#define CURRENT_VER 71
 
 /**
  * An auxillary macro, used to specify savegame versions. We use this instead
