diff --git a/gumps/Book_gump.cc b/gumps/Book_gump.cc
index 3e7da65bb..1433fdaa9 100644
--- a/gumps/Book_gump.cc
+++ b/gumps/Book_gump.cc
@@ -1,5 +1,5 @@
/*
-Copyright (C) 2000-2022 The Exult Team
+Copyright (C) 2000-2025 The Exult Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@@ -40,7 +40,7 @@ void Book_gump::paint() {
// Paint the gump itself.
paint_shape(x, y);
// Paint left page.
- curend = paint_page(TileRect(36, 10, 122, 130), curtop);
+ curend = paint_page(TileRect(35, 8, 125, 130), curtop);
// Paint right page.
- curend = paint_page(TileRect(174, 10, 122, 130), curend);
+ curend = paint_page(TileRect(173, 8, 125, 130), curend);
}
diff --git a/gumps/Scroll_gump.cc b/gumps/Scroll_gump.cc
index 533f4f49b..9d57b2302 100644
--- a/gumps/Scroll_gump.cc
+++ b/gumps/Scroll_gump.cc
@@ -1,5 +1,5 @@
/*
-Copyright (C) 2000-2022 The Exult Team
+Copyright (C) 2000-2025 The Exult Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@@ -39,5 +39,5 @@ Scroll_gump::Scroll_gump(int fnt, int gump)
void Scroll_gump::paint() {
// Paint the gump itself.
paint_shape(x, y);
- curend = paint_page(TileRect(52, 30, 142, 118), curtop);
+ curend = paint_page(TileRect(51, 31, 142, 118), curtop);
}
diff --git a/gumps/Text_gump.cc b/gumps/Text_gump.cc
index 5feb93b07..5594115fc 100644
--- a/gumps/Text_gump.cc
+++ b/gumps/Text_gump.cc
@@ -1,5 +1,5 @@
/*
-Copyright (C) 2000-2022 The Exult Team
+Copyright (C) 2000-2025 The Exult Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@@ -21,10 +21,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#endif
#include "Text_gump.h"
-
+#include "game.h"
#include "gamewin.h"
#include <cstring>
+#include <string>
using std::strchr;
@@ -33,21 +34,23 @@ using std::strchr;
*/
void Text_gump::add_text(const char* str) {
- const int slen = strlen(str); // Length of new text.
- // Allocate new space.
- char* newtext = new char[textlen + (textlen != 0) + slen + 1];
- if (textlen) { // Copy over old.
- strcpy(newtext, text);
- // Add new line if not starting a new page and if first char of new
- // string is not a new line
+ std::string newtext;
+ if (textlen) {
+ newtext = text;
if (newtext[textlen - 1] != '*') {
- newtext[textlen++] = '~';
+ // Scrolls in SI break page with embedded 0x00
+ if (GAME_SI && get_shapenum() == game->get_shape("gumps/scroll")) {
+ newtext += "*";
+ } else {
+ newtext += "~";
+ }
}
}
- strcpy(newtext + textlen, str); // Append new.
+ newtext += str;
delete[] text;
- text = newtext;
- textlen += slen;
+ text = new char[newtext.length() + 1];
+ strcpy(text, newtext.c_str());
+ textlen = newtext.length();
}
/*
@@ -56,50 +59,172 @@ void Text_gump::add_text(const char* str) {
* Output: Index past end of displayed page.
*/
-int Text_gump::paint_page(
- const TileRect& box, // Display box rel. to gump.
- int start // Starting offset into text.
-) {
- const int vlead = 1; // Extra inter-line spacing.
+int Text_gump::paint_page(const TileRect& box, int start) {
int ypos = 0;
+ const int vlead = 1;
const int textheight = sman->get_text_height(font) + vlead;
char* str = text + start;
- while (*str && *str != '*' && ypos + textheight <= box.h) {
- if (*str == '~') { // Empty paragraph?
- ypos += textheight;
- str++;
- continue;
+ curend = start; // Initialize curend to the starting position
+
+ char* lineBreak = nullptr;
+ char* pageBreakStar = nullptr;
+ char* extraBreak = nullptr;
+ char* epage = nullptr; // page break marker
+ char* eol = nullptr; // end-of-line marker
+
+ while (*str && ypos + textheight <= box.h) {
+ lineBreak = strchr(str, '~');
+ pageBreakStar = strchr(str, '*');
+
+ if (GAME_BG && get_shapenum() == game->get_shape("gumps/scroll")) {
+ extraBreak = strstr(str, " ~~");
+ if (extraBreak) {
+ // If " ~~" is preceded by "~~", ignore it.
+ if (extraBreak - text >= 2 && *(extraBreak - 2) == '~'
+ && *(extraBreak - 1) == '~') {
+ extraBreak = nullptr;
+ }
+ }
}
- // Look for page break.
- char* epage = strchr(str, '*');
- // Look for line break.
- char* eol = strchr(str, '~');
- if (epage && (!eol || eol > epage)) {
- eol = epage;
+
+ // if extraBreak is found and it occurs at the same position
+ // as the first tilde, use it as page break.
+ if (extraBreak && lineBreak && extraBreak + 1 == lineBreak) {
+ epage = extraBreak;
+ eol = extraBreak;
+ } else if (pageBreakStar && (!lineBreak || pageBreakStar < lineBreak)) {
+ epage = pageBreakStar;
+ eol = pageBreakStar;
+ } else {
+ eol = lineBreak;
+ epage = nullptr; // no page break marker
}
- if (!eol) { // No end found?
+
+ if (!eol) {
+ // No marker found: paint until the end of text.
eol = text + textlen;
}
- const char eolchr = *eol; // Save char. at EOL.
- *eol = 0;
- const int endoff = sman->paint_text_box(
- font, str, x + box.x, y + box.y + ypos, box.w, box.h - ypos,
- vlead);
- *eol = eolchr; // Restore char.
- if (endoff > 0) { // All painted?
- // Value returned is height.
- str = eol + (eolchr == '~');
+
+ // Temporarily null-terminate at eol for painting.
+ const char eolchr = *eol;
+ *eol = '\0';
+
+ int endoff = sman->paint_text_box(
+ font, str, x + box.x, y + box.y + ypos, box.w, box.h - ypos,
+ vlead);
+ // Restore the character at eol.
+ *eol = eolchr;
+
+ if (endoff > 0) {
+ // Check for a page‑break marker
+ if (epage && get_shapenum() == game->get_shape("gumps/scroll")) {
+ if (GAME_SI && start == 0 && ypos <= 5 * textheight) {
+ // ignore page breaks on the first 5 lines of a scroll
+ str = pageBreakStar + 1;
+ curend = str - text;
+ ypos += endoff;
+ continue;
+ }
+ // Calculate vertical space remaining after the current
+ // block has been painted.
+ int remaining = box.h - (ypos + endoff);
+
+ // Require room for at least two extra full line.
+ if (remaining >= 2 * textheight) {
+ // Reserve two extra line for spacing; the rest is
+ // available for the next text chunk.
+ int available = remaining - (2 * textheight);
+ if (available < 0) {
+ available = 0;
+ }
+
+ // Use existing markers to find earliest upcoming marker
+ const char* earliest
+ = text + textlen; // default: measure to
+ // end-of-text
+
+ // Use same check for both page break markers
+ const char* nextBreak = nullptr;
+ if ((pageBreakStar > eol + (epage == extraBreak ? 3 : 1)
+ && pageBreakStar < earliest)
+ || (extraBreak > eol + (epage == extraBreak ? 3 : 1)
+ && extraBreak < earliest)) {
+ earliest = (pageBreakStar && pageBreakStar < earliest)
+ ? pageBreakStar
+ : extraBreak;
+ }
+
+ // Temporarily replace the character at 'earliest' with
+ // '\0' to isolate the next chunk.
+ char saved = *earliest;
+
+ // PEEK MEASUREMENT:
+ // To avoid drawing on top of already painted text, we
+ // use an off-screen y coordinate (e.g. -1000).
+ int peekHeight = sman->paint_text_box(
+ font, eol + (epage == extraBreak ? 3 : 1),
+ x + box.x,
+ -1000, // off-screen y coordinate for
+ // measurement only
+ box.w, available, vlead);
+ // Restore the character we replaced.
+ *((char*)earliest) = saved;
+
+ if (peekHeight > 0
+ && peekHeight
+ <= available
+ + 5) // Add 5 pixels tolerance
+ {
+ // The entire upcoming text fits in the available
+ // space. Consume most of the extraBreak/pageBreakStar
+ // marker and add an extra line spacing.
+ eol += (epage == extraBreak ? 2 : 1);
+ ypos += endoff; // update vertical offset
+ str = eol; // continue painting after the marker
+ curend = str - text; // Update curend
+ continue; // next iteration: the peeked block
+ // will be painted on this page only
+ } else {
+ // The upcoming block does not fully fit;
+ // consume the marker and break so that it will be
+ // painted on the next page.
+ eol += (epage == extraBreak ? 3 : 1);
+ str = eol;
+ curend = str - text; // Update curend
+ break;
+ }
+ }
+ } else if (eolchr == '~' || (lineBreak && lineBreak == eol)) {
+ // Normal handling for a tilde line break.
+ eol++;
+ }
+
+ // After handling markers (or if none applied), update the text
+ // pointer and vertical offset.
ypos += endoff;
- } else { // Out of room.
+ str = eol;
+ curend = str - text; // Update curend
+
+ // Skip any leading space at the beginning of a new line.
+ if (*str == ' ') {
+ str++;
+ }
+ } else {
+ // Out of room or partial paint -> back up
str += -endoff;
+ curend = str - text; // Update curend
break;
}
}
- if (*str == '*') { // Saw end of page?
- str++;
+
+ // After the loop, check for markers at current position
+ if (pageBreakStar && pageBreakStar == str) {
+ str++; // skip "*"
}
- gwin->set_painted(); // Force blit.
- return str - text; // Return offset past end.
+
+ curend = str - text; // Update curend one last time after the loop
+ gwin->set_painted();
+ return str - text;
}
/*
@@ -113,6 +238,12 @@ int Text_gump::show_next_page() {
return 0; // That's all, folks.
}
curtop = curend; // Start next page or pair of pages.
- paint(); // Paint. This updates curend.
+
+ // Skip any leading tildes at the beginning of the new page.
+ while (curtop < textlen && text[curtop] == '~') {
+ curtop++;
+ }
+
+ paint(); // Paint. This updates curend.
return 1;
}
Comments
0 B
|👍
/👎
0 B
|👍
/👎