From 642fa67da9c271244de373431166f23449ec8543 Mon Sep 17 00:00:00 2001 From: Gregory Montoir Date: Sun, 15 Apr 2007 20:36:44 +0000 Subject: Added code for decodeParseString.SO_PRINT_WRAP and rewrote the CHARSET_1 function in order to match the original V8 interpreter. This should fix bugs #1036707 and #1662610 (subtitles word wrapping issues). svn-id: r26516 --- engines/scumm/actor.cpp | 9 ++- engines/scumm/charset.cpp | 38 +++++++++++ engines/scumm/charset.h | 1 + engines/scumm/intern.h | 1 + engines/scumm/saveload.cpp | 2 + engines/scumm/saveload.h | 2 +- engines/scumm/script_v8.cpp | 5 +- engines/scumm/scumm.h | 3 +- engines/scumm/string.cpp | 163 +++++++++++++++++++++++++++++++++++++++++++- 9 files changed, 216 insertions(+), 8 deletions(-) (limited to 'engines') diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp index af5726a273..f104f7bb8b 100644 --- a/engines/scumm/actor.cpp +++ b/engines/scumm/actor.cpp @@ -1850,6 +1850,7 @@ void ScummEngine::resetV1ActorTalkColor() { #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 @@ void ScummEngine_v7::actorTalk(const byte *msg) { 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 diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp index 654a7fd6c3..92642faaa5 100644 --- a/engines/scumm/charset.cpp +++ b/engines/scumm/charset.cpp @@ -348,6 +348,44 @@ int CharsetRenderer::getStringWidth(int arg, const byte *text) { 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; diff --git a/engines/scumm/charset.h b/engines/scumm/charset.h index 5039d31573..476b57b86e 100644 --- a/engines/scumm/charset.h +++ b/engines/scumm/charset.h @@ -73,6 +73,7 @@ public: 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(); diff --git a/engines/scumm/intern.h b/engines/scumm/intern.h index 796867a116..3d3a07a2ed 100644 --- a/engines/scumm/intern.h +++ b/engines/scumm/intern.h @@ -972,6 +972,7 @@ protected: virtual const char *getOpcodeDesc(byte i); virtual void printString(int m, const byte *msg); + virtual void CHARSET_1(); virtual void scummLoop_handleSaveLoad(); diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp index 7df428529a..6d8798a1e7 100644 --- a/engines/scumm/saveload.cpp +++ b/engines/scumm/saveload.cpp @@ -834,6 +834,8 @@ void ScummEngine::saveOrLoad(Serializer *s) { 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() }; diff --git a/engines/scumm/saveload.h b/engines/scumm/saveload.h index e98704bc2b..dbbf9a8a09 100644 --- a/engines/scumm/saveload.h +++ b/engines/scumm/saveload.h @@ -47,7 +47,7 @@ namespace Scumm { * 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 diff --git a/engines/scumm/script_v8.cpp b/engines/scumm/script_v8.cpp index 17b494250e..011c41856a 100644 --- a/engines/scumm/script_v8.cpp +++ b/engines/scumm/script_v8.cpp @@ -488,7 +488,7 @@ void ScummEngine_v8::decodeParseString(int m, int n) { _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 @@ void ScummEngine_v8::decodeParseString(int m, int n) { _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); diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h index 90cb14de1f..76b36fe935 100644 --- a/engines/scumm/scumm.h +++ b/engines/scumm/scumm.h @@ -243,6 +243,7 @@ struct StringSlot { bool center; bool overhead; bool no_talk_anim; + bool wrapping; }; struct StringTab : StringSlot { @@ -1169,7 +1170,7 @@ protected: 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); diff --git a/engines/scumm/string.cpp b/engines/scumm/string.cpp index 432cd7f1c9..90f227d0b3 100644 --- a/engines/scumm/string.cpp +++ b/engines/scumm/string.cpp @@ -437,7 +437,7 @@ void ScummEngine::CHARSET_1() { 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 @@ void ScummEngine::CHARSET_1() { 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 @@ void ScummEngine::CHARSET_1() { #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; -- cgit v1.2.3