Skip to content

Commit 9c59955

Browse files
committed
Overhaul the text buffer
1 parent c4aabdc commit 9c59955

File tree

3 files changed

+104
-134
lines changed

3 files changed

+104
-134
lines changed

src/game/boe.main.cpp

-4
Original file line numberDiff line numberDiff line change
@@ -1336,10 +1336,6 @@ int last_window_x = 0;
13361336
int last_window_y = 0;
13371337

13381338
void handle_one_event(const sf::Event& event, cFramerateLimiter& fps_limiter) {
1339-
1340-
// What does this do and should it be here?
1341-
through_sending();
1342-
13431339
// What does this do and should it be here?
13441340
clear_sound_memory();
13451341

src/game/boe.text.cpp

+104-128
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,14 @@ const int LINES_IN_ITEM_WIN = 8;
3131
#include <boost/lexical_cast.hpp>
3232

3333
typedef struct {
34-
char line[50];
35-
} buf_line;
34+
std::string message;
35+
int line_count;
36+
int duplicate_count;
37+
bool duplicate_overflow;
38+
} buf_msg;
39+
40+
buf_msg text_buffer[TEXT_BUF_LEN];
3641

37-
buf_line text_buffer[TEXT_BUF_LEN];
3842
short buf_pointer = 30;
3943

4044
rectangle status_panel_clip_rect = {11, 299, 175, 495},item_panel_clip_rect = {11,297,175,463};
@@ -59,7 +63,7 @@ extern location store_anim_ul;
5963
extern tessel_ref_t bg[];
6064
extern short dest_personalities[40];
6165
extern location source_locs[6];
62-
extern location dest_locs[40] ;
66+
extern location dest_locs[40];
6367
extern location center;
6468

6569
extern cCustomGraphics spec_scen_g;
@@ -963,10 +967,20 @@ short print_terrain(location space) {
963967
void add_string_to_buf(std::string str) {
964968
// This is a separate overload instead of using a defaulted parameter so that
965969
// it can be passed as an argument to various other functions
966-
add_string_to_buf(str, 0);
970+
size_t starting_indent = str.find_first_not_of(' ');
971+
if(starting_indent != std::string::npos)
972+
add_string_to_buf(str, starting_indent + 2);
967973
}
968974

969975
void add_string_to_buf(std::string str, unsigned short indent) {
976+
if(overall_mode == MODE_STARTUP)
977+
return;
978+
if(str == "") return;
979+
if(str.find_last_not_of(' ') == std::string::npos)
980+
return;
981+
982+
if(indent > 20) indent = 20;
983+
970984
static bool inited;
971985
static size_t width;
972986
static TextStyle buf_style;
@@ -976,100 +990,46 @@ void add_string_to_buf(std::string str, unsigned short indent) {
976990
buf_style.pointSize = 12;
977991
width = text_area_gworld().getSize().x - 5;
978992
}
979-
if(overall_mode == MODE_STARTUP)
980-
return;
981-
982-
if(str == "") return;
983-
if(str.find_last_not_of(' ') == std::string::npos)
984-
return;
985-
986-
if(indent && string_length(str.substr(0,str.find_last_not_of(' ')), buf_style) >= width) {
987-
if(indent > 20) indent = 20;
988-
size_t split = str.find_last_of(' ', 49);
989-
while(string_length(str.substr(0,split), buf_style) >= width)
990-
split = str.find_last_of(' ', split - 1);
991-
add_string_to_buf(str.substr(0,split));
992-
str = str.substr(split);
993-
std::string space(indent, ' ');
994-
size_t wrap_w = width - string_length(space, buf_style);
995-
while(string_length(str.substr(0,str.find_last_not_of(' ')), buf_style) > wrap_w) {
996-
std::string wrap = space;
997-
split = str.find_last_of(' ', 49 - indent);
998-
while(string_length(str.substr(0,split), buf_style) >= wrap_w)
999-
split = str.find_last_of(' ', split - 1);
1000-
wrap += str.substr(0,split);
1001-
str = str.substr(split);
1002-
add_string_to_buf(wrap);
1003-
}
1004-
add_string_to_buf(space + str);
1005-
return;
993+
994+
std::string wrapped_str = str;
995+
int line_count = 1;
996+
int wrapped_idx = 0;
997+
std::string space(indent, ' ');
998+
while(string_length(wrapped_str.substr(wrapped_idx, wrapped_str.find_last_not_of(' ')), buf_style) >= width) {
999+
size_t split = wrapped_str.find_last_of(' ');
1000+
while(string_length(wrapped_str.substr(wrapped_idx, split), buf_style) >= width)
1001+
split = wrapped_str.find_last_of(' ', split - 1);
1002+
1003+
wrapped_str[split] = '\n';
1004+
wrapped_str.insert(split + 1, space);
1005+
1006+
wrapped_idx = split + 1 + indent;
1007+
line_count += 1;
10061008
}
10071009

1008-
// Now check if this is a duplicate message
1010+
// Check if this is a duplicate message
10091011
int prev_pointer = buf_pointer - 1;
10101012
if(prev_pointer < 0) prev_pointer = TEXT_BUF_LEN - 1;
1011-
size_t last = 0, new_last = str.find_last_not_of(' ');
1012-
// Find the last non-space character that matches
1013-
while(last < str.length() && str[last] == text_buffer[prev_pointer].line[last])
1014-
last++;
1015-
while(last > 0 && text_buffer[prev_pointer].line[--last] == ' ');
1016-
bool is_dup = false;
1017-
if(last == new_last) {
1018-
size_t num_pos = 0;
1019-
enum {begin, f_space, f_lparen, f_x, f_num, f_rparen, err} state = begin;
1020-
for(short i = last; i < 50 && text_buffer[prev_pointer].line[i]; i++) {
1021-
if(state == f_x) num_pos = i;
1022-
if(isdigit(text_buffer[prev_pointer].line[i]) && (state == f_x || state == f_num))
1023-
state = f_num;
1024-
else switch(text_buffer[prev_pointer].line[i]) {
1025-
case ' ':
1026-
if(state == begin || state == f_space)
1027-
state = f_space;
1028-
break;
1029-
case '(':
1030-
if(state == begin || state == f_space)
1031-
state = f_lparen;
1032-
break;
1033-
case 'x':
1034-
if(state == f_lparen)
1035-
state = f_x;
1036-
break;
1037-
case ')':
1038-
if(state == f_num)
1039-
state = f_rparen;
1040-
break;
1041-
default:
1042-
if(i > last)
1043-
state = err;
1044-
break;
1045-
}
1046-
if(state == f_rparen) break;
1047-
}
1048-
if(state == begin || state == f_space || state == f_rparen) {
1049-
is_dup = true;
1050-
last++;
1051-
}
1052-
if(is_dup) {
1053-
int lastCount = 1;
1054-
if(num_pos > 0)
1055-
sscanf(text_buffer[prev_pointer].line + num_pos, "%d", &lastCount);
1056-
1057-
sprintf(text_buffer[prev_pointer].line + last, " (x%d)", lastCount + 1);
1058-
return;
1013+
1014+
if(wrapped_str == text_buffer[prev_pointer].message){
1015+
text_buffer[prev_pointer].duplicate_count++;
1016+
std::string test_fit = wrapped_str + " (x" + std::to_string(text_buffer[prev_pointer].duplicate_count) + ")";
1017+
if(string_length(test_fit, buf_style) >= width){
1018+
text_buffer[prev_pointer].line_count = line_count + 1;
1019+
// The duplicate count in parenthesis is on its own line
1020+
text_buffer[prev_pointer].duplicate_overflow = true;
10591021
}
1022+
}else{
1023+
text_buffer[buf_pointer].message = wrapped_str;
1024+
text_buffer[buf_pointer].line_count = line_count;
1025+
text_buffer[buf_pointer].duplicate_count = 1;
1026+
text_buffer[buf_pointer].duplicate_overflow = false;
1027+
if(buf_pointer == (TEXT_BUF_LEN - 1))
1028+
buf_pointer = 0;
1029+
else buf_pointer++;
10601030
}
10611031

10621032
text_sbar->setPosition(58); // TODO: This seems oddly specific
1063-
if(buf_pointer == mark_where_printing_long) {
1064-
printing_long = true;
1065-
print_buf();
1066-
through_sending();
1067-
}
1068-
sprintf((char *)text_buffer[buf_pointer].line, "%-49.49s", str.c_str());
1069-
if(buf_pointer == (TEXT_BUF_LEN - 1))
1070-
buf_pointer = 0;
1071-
else buf_pointer++;
1072-
10731033
}
10741034

10751035
void add_caster_needs_to_buf(std::string needs_what, unsigned short pre_indent, unsigned short indent) {
@@ -1083,68 +1043,84 @@ void add_caster_needs_to_buf(std::string needs_what, unsigned short pre_indent,
10831043
}
10841044

10851045
void init_buf() {
1086-
for(short i = 0; i < TEXT_BUF_LEN; i++)
1087-
sprintf((char *) text_buffer[buf_pointer].line, " ");
1046+
for(short i = 0; i < TEXT_BUF_LEN; i++){
1047+
// Buffer messages are no longer forced down to 50 chars each. In an effort to keep memory usage predictable,
1048+
// I've set an expected capacity of 100 per message.
1049+
text_buffer[i].message.reserve(100);
1050+
text_buffer[i].line_count = 1;
1051+
text_buffer[i].duplicate_count = 1;
1052+
text_buffer[i].duplicate_overflow = false;
1053+
}
10881054
}
10891055

10901056
void print_buf () {
1091-
short num_lines_printed = 0;
1092-
long ctrl_val;
1093-
short line_to_print;
1094-
long start_print_point;
10951057
rectangle store_text_rect,dest_rect,erase_rect = {2,2,136,255};
10961058

10971059
text_area_gworld().setActive(false);
10981060
clear_scale_aware_text(text_area_gworld());
10991061

11001062
// First clean up gworld with pretty patterns
11011063
tileImage(text_area_gworld(), erase_rect,bg[6]);
1064+
1065+
// Don't draw wrapped scale-aware text outside of the viewport
1066+
clip_rect(text_area_gworld(), erase_rect);
1067+
1068+
// Handling scrolling is a lot more confusing now.
1069+
// Think of line 0 as the LAST line of the most recently printed message. We count up from that accounting for
1070+
// multiple lines being stored in each message, to find the BOTTOM-MOST message to print first.
1071+
long lines_clipped_below = 58 - text_sbar->getPosition();
1072+
int message_idx = buf_pointer - 1;
1073+
if(message_idx < 0)
1074+
message_idx = TEXT_BUF_LEN + message_idx;
1075+
int line = 0;
1076+
while(line + text_buffer[message_idx].line_count <= lines_clipped_below){
1077+
line += text_buffer[message_idx].line_count;
1078+
message_idx--;
1079+
if(message_idx < 0)
1080+
message_idx = TEXT_BUF_LEN + message_idx;
1081+
}
11021082

1103-
ctrl_val = 58 - text_sbar->getPosition();
1104-
start_print_point = buf_pointer - LINES_IN_TEXT_WIN - ctrl_val;
1105-
if(start_print_point< 0)
1106-
start_print_point= TEXT_BUF_LEN + start_print_point;
1107-
line_to_print= start_print_point;
1083+
// Shift the text down this many lines, counting on clip_rect to hide the overflow:
1084+
int line_offset = lines_clipped_below - line;
1085+
int num_lines_total = 0;
1086+
int num_lines_visible = -line_offset;
11081087

11091088
location moveTo;
1110-
while((line_to_print!= buf_pointer) && (num_lines_printed < LINES_IN_TEXT_WIN)) {
1111-
moveTo = location(4, 1 + 12 * num_lines_printed);
1112-
sf::Text text(text_buffer[line_to_print].line, *ResMgr::fonts.get("plain"), 12 * get_ui_scale());
1113-
text.setColor(Colours::BLACK);
1114-
text.setPosition(moveTo);
1115-
draw_scale_aware_text(text_area_gworld(), text);
1116-
num_lines_printed++;
1117-
line_to_print++;
1118-
if(line_to_print== TEXT_BUF_LEN) {
1119-
line_to_print= 0;
1120-
}
1121-
1122-
if((num_lines_printed == LINES_IN_TEXT_WIN - 1) && (printing_long)) {
1123-
line_to_print= buf_pointer;
1089+
while(num_lines_visible < LINES_IN_TEXT_WIN){
1090+
std::string message = text_buffer[message_idx].message;
1091+
int indent = message.find_first_not_of(' ');
1092+
if(indent != std::string::npos){
1093+
if(text_buffer[message_idx].duplicate_count > 1){
1094+
if(text_buffer[message_idx].duplicate_overflow){
1095+
message += "\n" + std::string(indent, ' ');
1096+
}else{
1097+
message += " ";
1098+
}
1099+
message += "(x" + std::to_string(text_buffer[message_idx].duplicate_count) + ")";
1100+
}
1101+
1102+
moveTo = location(4, 1 + 12 * (LINES_IN_TEXT_WIN + line_offset - num_lines_total - text_buffer[message_idx].line_count));
1103+
sf::Text text(message, *ResMgr::fonts.get("plain"), 12 * get_ui_scale());
1104+
text.setColor(Colours::BLACK);
1105+
text.setPosition(moveTo);
1106+
draw_scale_aware_text(text_area_gworld(), text);
11241107
}
11251108

1109+
num_lines_visible += text_buffer[message_idx].line_count;
1110+
num_lines_total += text_buffer[message_idx].line_count;
1111+
message_idx--;
1112+
if(message_idx < 0)
1113+
message_idx = TEXT_BUF_LEN + message_idx;
11261114
}
11271115

11281116
text_area_gworld().setActive();
11291117
text_area_gworld().display();
11301118
}
11311119

1132-
void restart_printing() {
1133-
lines_to_print = 0;
1134-
//clear_text_panel();
1135-
}
1136-
11371120
void restore_mode() {
11381121
overall_mode = store_mode;
11391122
}
11401123

1141-
void through_sending() {
1142-
mark_where_printing_long = buf_pointer + LINES_IN_TEXT_WIN - 1;
1143-
if(mark_where_printing_long > TEXT_BUF_LEN - 1)
1144-
mark_where_printing_long -= TEXT_BUF_LEN;
1145-
printing_long = false;
1146-
}
1147-
11481124
/* Draw a bitmap in the world window. hor in 0 .. 8, vert in 0 .. 8,
11491125
object is ptr. to bitmap to be drawn, and masking is for Copybits. */
11501126
void Draw_Some_Item(const sf::Texture& src_gworld, rectangle src_rect, sf::RenderTarget& targ_gworld,location target, char masked, short main_win) {

src/game/boe.text.hpp

-2
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,7 @@ void add_string_to_buf(std::string str);
3434
void add_caster_needs_to_buf(std::string needs_what, unsigned short pre_indent = 2, unsigned short indent = 4);
3535
void init_buf();
3636
void print_buf () ;
37-
void restart_printing();
3837
void restore_mode();
39-
void through_sending();
4038
rectangle coord_to_rect(short i,short j);
4139
bool day_reached(unsigned short which_day, unsigned short which_event);
4240
void Draw_Some_Item(const sf::Texture& src_gworld, rectangle src_rect, sf::RenderTarget& targ_gworld, location target, char masked, short main_win);

0 commit comments

Comments
 (0)