aboutsummaryrefslogtreecommitdiff
path: root/engines/agi/text.cpp
diff options
context:
space:
mode:
authorEugene Sandulenko2009-01-02 01:34:53 +0000
committerEugene Sandulenko2009-01-02 01:34:53 +0000
commit8dfa9a70f26f508779d674520673718ae1b6e995 (patch)
treeb1f270329f74be49206131a9d161c62477a3d718 /engines/agi/text.cpp
parent903f52cff878bf4584bdcfd5ceb1b6885504196a (diff)
downloadscummvm-rg350-8dfa9a70f26f508779d674520673718ae1b6e995.tar.gz
scummvm-rg350-8dfa9a70f26f508779d674520673718ae1b6e995.tar.bz2
scummvm-rg350-8dfa9a70f26f508779d674520673718ae1b6e995.zip
Fix bugs #1940871: "AGI: Fan(Beyond Titanic 2) - Lockup" and #1874918:
"AGI GR: Text wrapping broken on long strings in the mines" by replacing our text wrap routine with one based on GBAGI. Also made debug messages more clear. svn-id: r35664
Diffstat (limited to 'engines/agi/text.cpp')
-rw-r--r--engines/agi/text.cpp145
1 files changed, 78 insertions, 67 deletions
diff --git a/engines/agi/text.cpp b/engines/agi/text.cpp
index 99031612f0..7e8d569fea 100644
--- a/engines/agi/text.cpp
+++ b/engines/agi/text.cpp
@@ -128,7 +128,7 @@ void AgiEngine::blitTextbox(const char *p, int y, int x, int len) {
int xoff, yoff, lin, h, w;
char *msg, *m;
- debugC(3, kDebugLevelText, "x=%d, y=%d, len=%d", x, y, len);
+ debugC(3, kDebugLevelText, "blitTextbox(): x=%d, y=%d, len=%d", x, y, len);
if (_game.window.active)
closeWindow();
@@ -140,7 +140,6 @@ void AgiEngine::blitTextbox(const char *p, int y, int x, int len) {
xoff = x * CHAR_COLS;
yoff = y * CHAR_LINES;
- len--;
m = msg = wordWrapString(agiSprintf(p), &len);
@@ -176,11 +175,11 @@ void AgiEngine::blitTextbox(const char *p, int y, int x, int len) {
void AgiEngine::eraseTextbox() {
if (!_game.window.active) {
- debugC(3, kDebugLevelText, "no window active");
+ debugC(3, kDebugLevelText, "eraseTextbox(): no window active");
return;
}
- debugC(4, kDebugLevelText, "x1=%d, y1=%d, x2=%d, y2=%d", _game.window.x1,
+ debugC(4, kDebugLevelText, "eraseTextbox(): x1=%d, y1=%d, x2=%d, y2=%d", _game.window.x1,
_game.window.y1, _game.window.x2, _game.window.y2);
_gfx->restoreBlock(_game.window.x1, _game.window.y1,
@@ -204,7 +203,7 @@ void AgiEngine::printText(const char *msg, int f, int x, int y, int len, int fg,
x *= CHAR_COLS;
y *= CHAR_LINES;
- debugC(4, kDebugLevelText, "%s, %d, %d, %d, %d, %d, %d", msg, f, x, y, len, fg, bg);
+ debugC(4, kDebugLevelText, "printText(): %s, %d, %d, %d, %d, %d, %d", msg, f, x, y, len, fg, bg);
printText2(0, agiSprintf(msg), f, x, y, len, fg, bg, checkerboard);
}
@@ -222,71 +221,83 @@ void AgiEngine::printTextConsole(const char *msg, int x, int y, int len, int fg,
* Wrap text line to the specified width.
* @param str String to wrap.
* @param len Length of line.
+ *
+ * Based on GBAGI implementaiton with permission from the author
*/
-char *AgiEngine::wordWrapString(char *str, int *len) {
- /* If the message has a long word (longer than 31 character) then
- * loop in line 239 (for (; *v != ' '; v--, c--);) can wrap
- * around 0 and write large number in c. This causes returned
- * length to be negative (!) and eventually crashes in calling
- * code. The fix is simple -- remove unsigned in maxc, c, l
- * declaration. --Vasyl
- */
- char *msg, *v, *e;
- int maxc, c, l = *len;
-
- v = msg = strdup(str);
- e = msg + strlen(msg);
- maxc = 0;
-
- for (;;) {
- debugC(3, kDebugLevelText, "[%s], %d", msg, maxc);
- if (strchr(v, ' ') == NULL && (int)strlen(v) > l) {
- debugC(1, kDebugLevelText | kDebugLevelMain, "Word too long in message");
- l = strlen(v);
+char *AgiEngine::wordWrapString(char *s, int *len) {
+ char *pWord, *outStr, *msgBuf, maxWidth = *len;
+ int lnLen, wLen;
+
+ msgBuf = outStr = strdup(s);
+
+ int msgWidth = 0;
+
+ lnLen = 0;
+
+ while (*s) {
+ pWord = s;
+ wLen = 0;
+
+ while (*s != '\0' && *s != ' ' && *s != '\n' && *s != '\r')
+ s++;
+
+ wLen = (int)(s - pWord);
+
+ if (wLen && *s == '\n' && s[-1] == ' ')
+ wLen--;
+
+ if (wLen + lnLen >= maxWidth) {
+ if (outStr != msgBuf) {
+ if (outStr[-1] == ' ')
+ outStr[-1] = '\n';
+ else
+ *outStr++ = '\n';
+ }
+
+ lnLen = 0;
+
+ while (wLen >= maxWidth) {
+ msgWidth = maxWidth;
+
+ memcpy(outStr, pWord, maxWidth);
+
+ wLen -= maxWidth;
+ outStr += maxWidth;
+ pWord += maxWidth;
+ *outStr++ = '\n';
+ }
}
- /* Must include \r for MacOS 8 */
- while ((c = strcspn(v, "\n\r")) <= l) {
- debugC(3, kDebugLevelText, "c = %d, maxc = %d", c, maxc);
- if (c > maxc)
- maxc = c;
- if ((v += c + 1) >= e)
- goto end;
+
+ if (wLen) {
+ memcpy(outStr, pWord, wLen);
+ outStr += wLen;
+ }
+ lnLen += wLen+1;
+
+ if (lnLen > msgWidth) {
+ msgWidth = lnLen;
+
+ if (*s == '\0' || *s == ' ' || *s == '\n' || *s == '\r')
+ msgWidth--;
}
- c = l;
- if ((v += l) >= e)
- break;
- /* The same line that caused that bug I mentioned
- * should also do another check:
- * for (; *v != ' ' && *v != '\n'; v--, c--);
- * While this does not matter in most cases, in the case of
- * long words it caused extra \n inserted in the line
- * preceding long word. This one is definitely non-critical;
- * one might argue that the function is not supposed to deal
- * with long words. BTW, that condition at the beginning of
- * the while loop that checks word length does not make much
- * sense -- it verifies the length of the first word but for
- * the rest it does something odd. Overall, even with these
- * changes the function is still not completely robust.
- * --Vasyl
- */
- if (*v != ' ')
- for (; *v != ' ' && *v != '\n' && *v != '\r';
- v--, c--);
- if (c > maxc)
- maxc = c;
- *v++ = '\n';
+ if (*s == '\n')
+ lnLen = 0;
+
+ if (*s)
+ *outStr++ = *s++;
}
- end:
- *len = maxc;
- return msg;
+ *outStr = '\0';
+ *len = msgWidth;
+
+ return msgBuf;
}
/**
* Remove existing window, if any.
*/
void AgiEngine::closeWindow() {
- debugC(4, kDebugLevelText, "close window");
+ debugC(4, kDebugLevelText, "closeWindow()");
_sprites->eraseBoth();
eraseTextbox(); /* remove window, if any */
_sprites->blitBoth();
@@ -307,7 +318,7 @@ int AgiEngine::messageBox(const char *s) {
blitTextbox(s, -1, -1, -1);
_sprites->blitBoth();
k = waitKey();
- debugC(4, kDebugLevelText, "wait_key returned %02x", k);
+ debugC(4, kDebugLevelText, "messageBox(): wait_key returned %02x", k);
closeWindow();
return k;
@@ -333,7 +344,7 @@ int AgiEngine::selectionBox(const char *m, const char **b) {
x = _game.window.x1 + 5 * CHAR_COLS / 2;
y = _game.window.y2 - 5 * CHAR_LINES / 2;
s = _game.window.x2 - _game.window.x1 + 1 - 5 * CHAR_COLS;
- debugC(3, kDebugLevelText, "s = %d", s);
+ debugC(3, kDebugLevelText, "selectionBox(): s = %d", s);
/* Automatically position buttons */
for (i = 0; b[i]; i++) {
@@ -342,7 +353,7 @@ int AgiEngine::selectionBox(const char *m, const char **b) {
}
if (i > 1) {
- debugC(3, kDebugLevelText, "s / %d = %d", i - 1, s / (i - 1));
+ debugC(3, kDebugLevelText, "selectionBox(): s / %d = %d", i - 1, s / (i - 1));
s /= (i - 1);
} else {
x += s / 2;
@@ -363,7 +374,7 @@ int AgiEngine::selectionBox(const char *m, const char **b) {
AllowSyntheticEvents on(this);
- debugC(4, kDebugLevelText, "waiting...");
+ debugC(4, kDebugLevelText, "selectionBox(): waiting...");
while (!shouldQuit()) {
for (i = 0; b[i]; i++)
_gfx->drawCurrentStyleButton(bx[i], by[i], b[i], i == active, false, i == 0);
@@ -396,7 +407,7 @@ int AgiEngine::selectionBox(const char *m, const char **b) {
}
break;
case 0x09: /* Tab */
- debugC(3, kDebugLevelText, "Focus change");
+ debugC(3, kDebugLevelText, "selectionBox(): Focus change");
active++;
active %= i;
break;
@@ -405,11 +416,11 @@ int AgiEngine::selectionBox(const char *m, const char **b) {
}
press:
- debugC(4, kDebugLevelText, "Button pressed: %d", rc);
+ debugC(4, kDebugLevelText, "selectionBox(): Button pressed: %d", rc);
getout:
closeWindow();
- debugC(2, kDebugLevelText, "Result = %d", rc);
+ debugC(2, kDebugLevelText, "selectionBox(): Result = %d", rc);
return rc;
}
@@ -421,7 +432,7 @@ int AgiEngine::print(const char *p, int lin, int col, int len) {
if (p == NULL)
return 0;
- debugC(4, kDebugLevelText, "lin = %d, col = %d, len = %d", lin, col, len);
+ debugC(4, kDebugLevelText, "print(): lin = %d, col = %d, len = %d", lin, col, len);
if (col == 0 && lin == 0 && len == 0)
lin = col = -1;