diff --git a/desktop_version/src/Game.cpp b/desktop_version/src/Game.cpp index c31576a3..5a326745 100644 --- a/desktop_version/src/Game.cpp +++ b/desktop_version/src/Game.cpp @@ -695,16 +695,21 @@ void Game::levelcomplete_textbox(void) graphics.addline(" "); graphics.addline(""); graphics.addline(""); + graphics.textboxoriginalcontextauto(); graphics.textboxprintflags(PR_FONT_8X8); graphics.textboxcenterx(); graphics.setimage(TEXTIMAGE_LEVELCOMPLETE); graphics.setlinegap(0); + graphics.textboxapplyposition(); } -void Game::crewmate_textbox(const int color) +static void compute_crewmate_textbox(textboxclass* THIS) { + THIS->lines.clear(); + THIS->addline(""); + const int extra_cjk_height = (font::height(PR_FONT_INTERFACE) * 4) - 32; - graphics.createtextboxflipme("", -1, 64 + 8 + 16 - extra_cjk_height/2, TEXT_COLOUR("gray")); + THIS->yp = 64 + 8 + 16 - extra_cjk_height/2; /* This is a special case for wrapping, we MUST have two lines. * So just make sure it can't fit in one line. */ @@ -717,23 +722,36 @@ void Game::crewmate_textbox(const int color) size_t pos_n = wrapped.find('\n', startline); size_t pos_p = wrapped.find('|', startline); newline = SDL_min(pos_n, pos_p); - graphics.addline(wrapped.substr(startline, newline-startline)); + THIS->addline(wrapped.substr(startline, newline-startline)); startline = newline+1; } while (newline != std::string::npos); - graphics.addline(""); - graphics.textboxprintflags(PR_FONT_INTERFACE); - graphics.textboxcentertext(); + THIS->addline(""); + THIS->centertext(); float spaces_per_8 = font::len(PR_FONT_INTERFACE, " ")/8.0f; - graphics.textboxpad(SDL_ceilf(5/spaces_per_8), SDL_ceilf(2/spaces_per_8)); - graphics.textboxcenterx(); - graphics.addsprite(14, 12 + extra_cjk_height/2, 0, color); - graphics.setlinegap(0); + THIS->pad(SDL_ceilf(5/spaces_per_8), SDL_ceilf(2/spaces_per_8)); + if (!THIS->sprites.empty()) + { + THIS->sprites[0].y = 12 + extra_cjk_height/2; + } } -void Game::remaining_textbox(void) +void Game::crewmate_textbox(const int color) { - const int remaining = 6 - crewrescued(); + const int extra_cjk_height = (font::height(PR_FONT_INTERFACE) * 4) - 32; + graphics.createtextboxflipme("", -1, 64 + 8 + 16, TEXT_COLOUR("gray")); + graphics.textboxprintflags(PR_FONT_INTERFACE); + graphics.textboxcenterx(); + graphics.addsprite(14, 12 + extra_cjk_height/2, 0, color); + graphics.textboxtranslate(TEXTTRANSLATE_FUNCTION, compute_crewmate_textbox); + graphics.setlinegap(0); + graphics.textboxapplyposition(); +} + +static void compute_remaining_textbox(textboxclass* THIS) +{ + extern Game game; + const int remaining = 6 - game.crewrescued(); char buffer[SCREEN_WIDTH_CHARS + 1]; if (remaining > 0) { @@ -744,16 +762,29 @@ void Game::remaining_textbox(void) SDL_strlcpy(buffer, loc::gettext("All Crew Members Rescued!"), sizeof(buffer)); } + THIS->lines.clear(); + THIS->lines.push_back(buffer); + // In CJK, the "You have rescued" box becomes so big we should lower this one a bit... const int cjk_lowering = font::height(PR_FONT_INTERFACE) - 8; - graphics.createtextboxflipme(buffer, -1, 128 + 16 + cjk_lowering, TEXT_COLOUR("gray")); - graphics.textboxprintflags(PR_FONT_INTERFACE); - graphics.textboxpad(2, 2); - graphics.textboxcenterx(); + THIS->yp = 128 + 16 + cjk_lowering; + THIS->pad(2, 2); + } -void Game::actionprompt_textbox(void) +void Game::remaining_textbox(void) { + graphics.createtextboxflipme("", -1, 128 + 16, TEXT_COLOUR("gray")); + graphics.textboxprintflags(PR_FONT_INTERFACE); + graphics.textboxcenterx(); + graphics.textboxtranslate(TEXTTRANSLATE_FUNCTION, compute_remaining_textbox); + graphics.textboxapplyposition(); +} + +static void compute_actionprompt_textbox(textboxclass* THIS) +{ + THIS->lines.clear(); + char buffer[SCREEN_WIDTH_CHARS + 1]; vformat_buf( buffer, sizeof(buffer), @@ -761,10 +792,18 @@ void Game::actionprompt_textbox(void) "button:but", vformat_button(ActionSet_InGame, Action_InGame_ACTION) ); - graphics.createtextboxflipme(buffer, -1, 196, TEXT_COLOUR("cyan")); + + THIS->lines.push_back(buffer); + THIS->pad(1, 1); +} + +void Game::actionprompt_textbox(void) +{ + graphics.createtextboxflipme("", -1, 196, TEXT_COLOUR("cyan")); graphics.textboxprintflags(PR_FONT_INTERFACE); - graphics.textboxpad(1, 1); graphics.textboxcenterx(); + graphics.textboxtranslate(TEXTTRANSLATE_FUNCTION, compute_actionprompt_textbox); + graphics.textboxapplyposition(); } void Game::savetele_textbox(void) @@ -2896,10 +2935,12 @@ void Game::updatestate(void) graphics.addline(" "); graphics.addline(""); graphics.addline(""); + graphics.textboxoriginalcontextauto(); graphics.textboxprintflags(PR_FONT_8X8); graphics.textboxcenterx(); graphics.setimage(TEXTIMAGE_GAMECOMPLETE); graphics.setlinegap(0); + graphics.textboxapplyposition(); break; case 3502: { diff --git a/desktop_version/src/Graphics.cpp b/desktop_version/src/Graphics.cpp index 8fb4fa02..033c7401 100644 --- a/desktop_version/src/Graphics.cpp +++ b/desktop_version/src/Graphics.cpp @@ -1495,6 +1495,17 @@ void Graphics::setlarge(bool large) textboxes[m].large = large; } +void Graphics::textboxapplyposition(void) +{ + if (!INBOUNDS_VEC(m, textboxes)) + { + vlog_error("textboxapplyposition() out-of-bounds!"); + return; + } + + textboxes[m].applyposition(); +} + void Graphics::textboxadjust(void) { if (!INBOUNDS_VEC(m, textboxes)) @@ -3272,7 +3283,8 @@ void Graphics::textboxpad(size_t left_pad, size_t right_pad) return; } - textboxes[m].pad(left_pad, right_pad); + textboxes[m].spacing.pad_left = left_pad; + textboxes[m].spacing.pad_right = right_pad; } void Graphics::textboxpadtowidth(size_t new_w) @@ -3283,7 +3295,7 @@ void Graphics::textboxpadtowidth(size_t new_w) return; } - textboxes[m].padtowidth(new_w); + textboxes[m].spacing.padtowidth = new_w; } void Graphics::textboxcentertext(void) @@ -3294,7 +3306,7 @@ void Graphics::textboxcentertext(void) return; } - textboxes[m].centertext(); + textboxes[m].spacing.centertext = true; } void Graphics::textboxprintflags(const uint32_t flags) @@ -3342,6 +3354,25 @@ void Graphics::textboxoriginalcontext(const TextboxOriginalContext* original_con textboxes[m].original = *original_context; } +void Graphics::textboxoriginalcontextauto(void) +{ + if (!INBOUNDS_VEC(m, textboxes)) + { + vlog_error("textboxoriginalcontextauto() out-of-bounds!"); + return; + } + + TextboxOriginalContext context = TextboxOriginalContext(); + context.text_case = 1; + context.lines = textboxes[m].lines; + if (script.running) + { + context.script_name = script.scriptname; + } + + textboxes[m].original = context; +} + void Graphics::textboxcase(char text_case) { if (!INBOUNDS_VEC(m, textboxes)) @@ -3353,7 +3384,7 @@ void Graphics::textboxcase(char text_case) textboxes[m].original.text_case = text_case; } -void Graphics::textboxtranslate(void) +void Graphics::textboxtranslate(const TextboxTranslate translate, const TextboxFunction function) { if (!INBOUNDS_VEC(m, textboxes)) { @@ -3361,7 +3392,15 @@ void Graphics::textboxtranslate(void) return; } - textboxes[m].translate(); + if (translate == TEXTTRANSLATE_FUNCTION && function == NULL) + { + SDL_assert(0 && "function is NULL!"); + return; + } + + textboxes[m].translate = translate; + textboxes[m].function = function; + textboxes[m].updatetext(); } void Graphics::textboxcommsrelay(void) diff --git a/desktop_version/src/Graphics.h b/desktop_version/src/Graphics.h index 3fca3944..4916f15a 100644 --- a/desktop_version/src/Graphics.h +++ b/desktop_version/src/Graphics.h @@ -117,13 +117,16 @@ public: void textboxcrewmateposition(const TextboxCrewmatePosition* crewmate_position); void textboxoriginalcontext(const TextboxOriginalContext* original_context); + void textboxoriginalcontextauto(void); void textboxcase(char text_case); - void textboxtranslate(void); + void textboxtranslate(TextboxTranslate translate, TextboxFunction function); void textboxcommsrelay(void); + void textboxapplyposition(void); + void textboxadjust(void); void addline(const std::string& t); diff --git a/desktop_version/src/Input.cpp b/desktop_version/src/Input.cpp index 8ecf1e4a..725c2dc7 100644 --- a/desktop_version/src/Input.cpp +++ b/desktop_version/src/Input.cpp @@ -1134,8 +1134,8 @@ static void menuactionpress(void) /* Retranslate and reposition all text boxes. */ for (size_t i = 0; i < graphics.textboxes.size(); i++) { - graphics.textboxes[i].translate(); - graphics.textboxes[i].adjust(); // FIXME: not all textboxes obey the 10-pixel inner border! + graphics.textboxes[i].updatetext(); + graphics.textboxes[i].applyposition(); } } diff --git a/desktop_version/src/Script.cpp b/desktop_version/src/Script.cpp index 1128a244..a49a4906 100644 --- a/desktop_version/src/Script.cpp +++ b/desktop_version/src/Script.cpp @@ -764,7 +764,7 @@ void scriptclass::run(void) } graphics.textboxprintflags(flags); } - graphics.textboxtranslate(); + graphics.textboxtranslate(TEXTTRANSLATE_CUTSCENE, NULL); graphics.textboxadjust(); if (words[0] == "speak_active") diff --git a/desktop_version/src/Textbox.cpp b/desktop_version/src/Textbox.cpp index c329dbe2..f6ad2884 100644 --- a/desktop_version/src/Textbox.cpp +++ b/desktop_version/src/Textbox.cpp @@ -32,6 +32,8 @@ textboxclass::textboxclass(int gap) should_centery = false; print_flags = PR_FONT_LEVEL; + translate = TEXTTRANSLATE_NONE; + function = NULL; fill_buttons = false; sprites.clear(); @@ -41,6 +43,7 @@ textboxclass::textboxclass(int gap) crewmate_position = TextboxCrewmatePosition(); original = TextboxOriginalContext(); original.text_case = 1; + spacing = TextboxSpacing(); } void textboxclass::addsprite(int x, int y, int tile, int col) @@ -71,7 +74,7 @@ void textboxclass::centery(void) resize(); } -void textboxclass::adjust(void) +void textboxclass::applyposition(void) { resize(); repositionfromcrewmate(); @@ -83,6 +86,12 @@ void textboxclass::adjust(void) { centery(); } +} + +void textboxclass::adjust(void) +{ + resize(); + applyposition(); if (xp < 10) xp = 10; if (yp < 10) yp = 10; if (xp + w > 310) xp = 310 - w; @@ -246,16 +255,59 @@ void textboxclass::centertext(void) padtowidth(w-16); } -void textboxclass::translate(void) +void textboxclass::copyoriginaltext(void) +{ + // Copy the original back, but keep the limit of lines in mind + lines.clear(); + for (size_t i = 0; i < original.lines.size(); i++) + { + addline(original.lines[i]); + } +} + +void textboxclass::applyoriginalspacing(void) +{ + if (spacing.centertext) + { + centertext(); + } + if (spacing.pad_left > 0 || spacing.pad_right > 0) + { + pad(spacing.pad_left, spacing.pad_right); + } + if (spacing.padtowidth > 0) + { + padtowidth(spacing.padtowidth); + } +} + +void textboxclass::updatetext(void) +{ + switch (translate) + { + case TEXTTRANSLATE_NONE: + copyoriginaltext(); + applyoriginalspacing(); + break; + case TEXTTRANSLATE_CUTSCENE: + translatecutscene(); + break; + case TEXTTRANSLATE_FUNCTION: + if (function == NULL) + { + SDL_assert(0 && "function is NULL!"); + break; + } + function(this); + } +} + +void textboxclass::translatecutscene(void) { if (!loc::is_cutscene_translated(original.script_name)) { - // Copy the original back, but keep the limit of lines in mind - lines.clear(); - for (size_t i = 0; i < original.lines.size(); i++) - { - addline(original.lines[i]); - } + copyoriginaltext(); + applyoriginalspacing(); return; } @@ -274,6 +326,8 @@ void textboxclass::translate(void) const loc::TextboxFormat* format = loc::gettext_cutscene(original.script_name, eng, original.text_case); if (format == NULL || format->text == NULL || format->text[0] == '\0') { + copyoriginaltext(); + applyoriginalspacing(); return; } diff --git a/desktop_version/src/Textbox.h b/desktop_version/src/Textbox.h index 45d76860..b5c46cd7 100644 --- a/desktop_version/src/Textbox.h +++ b/desktop_version/src/Textbox.h @@ -24,6 +24,15 @@ struct TextboxOriginalContext char text_case; }; +/* Similar to, but NOT the same as a loc::TextboxFormat. */ +struct TextboxSpacing +{ + bool centertext; + unsigned char pad_left; + unsigned char pad_right; + unsigned short padtowidth; +}; + struct TextboxSprite { int x; @@ -39,6 +48,16 @@ enum TextboxImage TEXTIMAGE_GAMECOMPLETE }; +enum TextboxTranslate +{ + TEXTTRANSLATE_NONE, + TEXTTRANSLATE_CUTSCENE, + TEXTTRANSLATE_FUNCTION +}; + +class textboxclass; +typedef void (*TextboxFunction)(textboxclass* THIS); + class textboxclass { public: @@ -52,6 +71,8 @@ public: void centery(void); + void applyposition(void); + void adjust(void); void initcol(int rr, int gg, int bb); @@ -74,7 +95,13 @@ public: void centertext(void); - void translate(void); + void copyoriginaltext(void); + + void applyoriginalspacing(void); + + void updatetext(void); + + void translatecutscene(void); public: //Fundamentals std::vector lines; @@ -98,6 +125,7 @@ public: bool should_centery; uint32_t print_flags; + TextboxTranslate translate; bool fill_buttons; std::vector sprites; @@ -105,6 +133,8 @@ public: TextboxCrewmatePosition crewmate_position; TextboxOriginalContext original; + TextboxSpacing spacing; + TextboxFunction function; }; #endif /* TEXTBOX_H */