diff options
-rw-r--r-- | engines/drascula/graphics.cpp | 102 |
1 files changed, 66 insertions, 36 deletions
diff --git a/engines/drascula/graphics.cpp b/engines/drascula/graphics.cpp index 5e37d2c3b0..4ed949cc99 100644 --- a/engines/drascula/graphics.cpp +++ b/engines/drascula/graphics.cpp @@ -319,31 +319,42 @@ int DrasculaEngine::print_abc_opc(const char *said, int screenY, int game) { } bool DrasculaEngine::textFitsCentered(char *text, int x) { - int half_len = strlen(text) * CHAR_WIDTH / 2; - // Clip center between 60 and 255 - x = CLIP<int>(x, 60, 259); - // We want a text centered on x thats fits on screen - // CHAR_WIDTH is even so x - length / 2 + length is always equal to x + length / 2 - return (x - half_len >= 2 && x + half_len <= 317); + int halfLen = (strlen(text) / 2) * CHAR_WIDTH; + + // See comment in centerText() + if (x > 160) + x = 315 - x; + return (halfLen <= x); } void DrasculaEngine::centerText(const char *message, int textX, int textY) { char msg[200]; - char messageLine[200]; - char tmpMessageLine[200]; - *messageLine = 0; - *tmpMessageLine = 0; - char *curWord; - int curLine = 0; - int x = 0; - // original starts printing 4 lines above textY - int y = CLIP<int>(textY - (4 * CHAR_HEIGHT), 0, 320); - Common::strlcpy(msg, message, 200); + + // We make sure to have a width of at least 120 pixels by clipping the center. + // In theory since the screen width is 320 I would expect something like this: + // x = CLIP<int>(x, 60, 260); + // return (x - halfLen >= 0 && x + halfLen <= 319); + + // The engines does things differently though. It tries to clips text at 315 instead of 319. + // And instead of testing the upper bound if x is greater than 160 it takes the complement to 315 + // and test only the lower bounds. However since 160 is not the middle of 315, we end up having + // text that can go beyond 315 (up to 320) if x is in [159, 160]. + // Also note that if the numbers of characters is odd, there is one more character to the right + // than to the left as it computes the half length with an integer division by two BEFORE multiplying + // by CHAR_WIDTH. Thus in theory we may end up with one character out of the screen! + // Be faithfull to the original and do the same though. + + textX = CLIP<int>(textX, 60, 255); // If the message fits on screen as-is, just print it here if (textFitsCentered(msg, textX)) { - x = CLIP<int>(textX, 60, 259) - strlen(msg) * CHAR_WIDTH / 2; + int x = textX - (strlen(msg) / 2) * CHAR_WIDTH - 1; + // The original starts to draw (nbLines + 2) lines above textY, except if there is a single line + // in which case it starts drawing at (nbLines + 3) above textY. + // Also clip to the screen height although the original does not do it. + int y = textY - 4 * CHAR_HEIGHT; + y = CLIP<int>(y, 0, 200 - CHAR_HEIGHT); print_abc(msg, x, y); return; } @@ -354,42 +365,61 @@ void DrasculaEngine::centerText(const char *message, int textX, int textY) { // with the German translation. if (!strchr(msg, ' ')) { int len = strlen(msg); - x = CLIP<int>(textX - len * CHAR_WIDTH / 2, 2, 317 - len * CHAR_WIDTH); + int x = CLIP<int>(textX - (len / 2) * CHAR_WIDTH - 1, 0, 319 - len * CHAR_WIDTH); + int y = textY - 4 * CHAR_HEIGHT; + y = CLIP<int>(y, 0, 200 - CHAR_HEIGHT); print_abc(msg, x, y); return; } // Message doesn't fit on screen, split it - + char messageLines[15][41]; // screenWidth/charWidth = 320/8 = 40. Thus lines can have up to 41 characters with the null terminator (despite the original allocating only 40 characters here). + int curLine = 0; + char messageCurLine[50]; + char tmpMessageCurLine[50]; + *messageCurLine = 0; + *tmpMessageCurLine = 0; // Get a word from the message - curWord = strtok(msg, " "); + char* curWord = strtok(msg, " "); while (curWord != NULL) { // Check if the word and the current line fit on screen - if (tmpMessageLine[0] != '\0') - Common::strlcat(tmpMessageLine, " ", 200); - Common::strlcat(tmpMessageLine, curWord, 200); - if (textFitsCentered(tmpMessageLine, textX)) { + if (tmpMessageCurLine[0] != '\0') + Common::strlcat(tmpMessageCurLine, " ", 50); + Common::strlcat(tmpMessageCurLine, curWord, 50); + if (textFitsCentered(tmpMessageCurLine, textX)) { // Line fits, so add the word to the current message line - strcpy(messageLine, tmpMessageLine); + strcpy(messageCurLine, tmpMessageCurLine); } else { - // Line doesn't fit, so show the current line on screen and - // create a new one - // If it goes off screen, print_abc will adjust it - x = CLIP<int>(textX, 60, 259) - strlen(messageLine) * CHAR_WIDTH / 2; - print_abc(messageLine, x, y + curLine * (CHAR_HEIGHT + 2)); - Common::strlcpy(messageLine, curWord, 200); - Common::strlcpy(tmpMessageLine, curWord, 200); - curLine++; + // Line does't fit. Store the current line and start a new line. + Common::strlcpy(messageLines[curLine++], messageCurLine, 41); + Common::strlcpy(messageCurLine, curWord, 50); + Common::strlcpy(tmpMessageCurLine, curWord, 50); } // Get next word curWord = strtok(NULL, " "); - if (curWord == NULL) { - x = CLIP<int>(textX, 60, 259) - strlen(messageLine) * CHAR_WIDTH / 2; - print_abc(messageLine, x, y + curLine * (CHAR_HEIGHT + 2)); + // The original has an interesting bug that if we split the text on several lines + // a space is added at the end (which impacts the alignment, and may even cause the line + // to become too long). + Common::strlcat(messageCurLine, " ", 50); + if (!textFitsCentered(messageCurLine, textX)) { + messageCurLine[strlen(messageCurLine) - 1] = '\0'; + Common::strlcpy(messageLines[curLine++], messageCurLine, 41); + strcpy(messageLines[curLine++], " "); + } else + Common::strlcpy(messageLines[curLine++], messageCurLine, 41); } } + + // The original starts to draw (nbLines + 2) lines above textY. + // Also clip to the screen height although the original does not do it. + int y = textY - (curLine + 2) * CHAR_HEIGHT; + y = CLIP<int>(y, 0, 200 - curLine * (CHAR_HEIGHT + 2) + 2); + for (int line = 0 ; line < curLine ; ++line, y += CHAR_HEIGHT + 2) { + int textHalfLen = (strlen(messageLines[line]) / 2) * CHAR_WIDTH; + print_abc(messageLines[line], textX - textHalfLen - 1, y); + } } void DrasculaEngine::screenSaver() { |