diff --git a/src/goal.cpp b/src/goal.cpp index 3e1f565cfd..2b200683ef 100644 --- a/src/goal.cpp +++ b/src/goal.cpp @@ -75,7 +75,7 @@ INSTANTIATE_POOL_METHODS(Goal) * @param text Text of the goal. * @return the cost of this operation or an error */ -std::tuple CmdCreateGoal(DoCommandFlags flags, CompanyID company, GoalType type, GoalTypeID dest, const std::string &text) +std::tuple CmdCreateGoal(DoCommandFlags flags, CompanyID company, GoalType type, GoalTypeID dest, const EncodedString &text) { if (!Goal::CanAllocateItem()) return { CMD_ERROR, GoalID::Invalid() }; @@ -157,7 +157,7 @@ CommandCost CmdSetGoalDestination(DoCommandFlags flags, GoalID goal, GoalType ty * @param text Text of the goal. * @return the cost of this operation or an error */ -CommandCost CmdSetGoalText(DoCommandFlags flags, GoalID goal, const std::string &text) +CommandCost CmdSetGoalText(DoCommandFlags flags, GoalID goal, const EncodedString &text) { if (_current_company != OWNER_DEITY) return CMD_ERROR; if (!Goal::IsValidID(goal)) return CMD_ERROR; @@ -184,7 +184,7 @@ CommandCost CmdSetGoalText(DoCommandFlags flags, GoalID goal, const std::string * @param text Progress text of the goal. * @return the cost of this operation or an error */ -CommandCost CmdSetGoalProgress(DoCommandFlags flags, GoalID goal, const std::string &text) +CommandCost CmdSetGoalProgress(DoCommandFlags flags, GoalID goal, const EncodedString &text) { if (_current_company != OWNER_DEITY) return CMD_ERROR; if (!Goal::IsValidID(goal)) return CMD_ERROR; @@ -240,7 +240,7 @@ CommandCost CmdSetGoalCompleted(DoCommandFlags flags, GoalID goal, bool complete * @param text Text of the question. * @return the cost of this operation or an error */ -CommandCost CmdGoalQuestion(DoCommandFlags flags, uint16_t uniqueid, uint32_t target, bool is_client, uint32_t button_mask, GoalQuestionType type, const std::string &text) +CommandCost CmdGoalQuestion(DoCommandFlags flags, uint16_t uniqueid, uint32_t target, bool is_client, uint32_t button_mask, GoalQuestionType type, const EncodedString &text) { static_assert(sizeof(uint32_t) >= sizeof(CompanyID)); CompanyID company = (CompanyID)target; diff --git a/src/goal_base.h b/src/goal_base.h index af15e86fee..40b0fe44dc 100644 --- a/src/goal_base.h +++ b/src/goal_base.h @@ -13,6 +13,7 @@ #include "company_type.h" #include "goal_type.h" #include "core/pool_type.hpp" +#include "strings_type.h" using GoalPool = Pool; extern GoalPool _goal_pool; @@ -22,15 +23,15 @@ struct Goal : GoalPool::PoolItem<&_goal_pool> { CompanyID company = CompanyID::Invalid(); ///< Goal is for a specific company; CompanyID::Invalid() if it is global GoalType type = GT_NONE; ///< Type of the goal GoalTypeID dst = 0; ///< Index of type - std::string text{}; ///< Text of the goal. - std::string progress{}; ///< Progress text of the goal. + EncodedString text{}; ///< Text of the goal. + EncodedString progress{}; ///< Progress text of the goal. bool completed = false; ///< Is the goal completed or not? /** * We need an (empty) constructor so struct isn't zeroed (as C++ standard states) */ Goal() { } - Goal(GoalType type, GoalTypeID dst, CompanyID company, const std::string &text) : company(company), type(type), dst(dst), text(text) {} + Goal(GoalType type, GoalTypeID dst, CompanyID company, const EncodedString &text) : company(company), type(type), dst(dst), text(text) {} /** * (Empty) destructor has to be defined else operator delete might be called with nullptr parameter diff --git a/src/goal_cmd.h b/src/goal_cmd.h index 41b61c80d5..4cb017ede9 100644 --- a/src/goal_cmd.h +++ b/src/goal_cmd.h @@ -13,13 +13,13 @@ #include "command_type.h" #include "goal_type.h" -std::tuple CmdCreateGoal(DoCommandFlags flags, CompanyID company, GoalType type, GoalTypeID dest, const std::string &text); +std::tuple CmdCreateGoal(DoCommandFlags flags, CompanyID company, GoalType type, GoalTypeID dest, const EncodedString &text); CommandCost CmdRemoveGoal(DoCommandFlags flags, GoalID goal); CommandCost CmdSetGoalDestination(DoCommandFlags flags, GoalID goal, GoalType type, GoalTypeID dest); -CommandCost CmdSetGoalText(DoCommandFlags flags, GoalID goal, const std::string &text); -CommandCost CmdSetGoalProgress(DoCommandFlags flags, GoalID goal, const std::string &text); +CommandCost CmdSetGoalText(DoCommandFlags flags, GoalID goal, const EncodedString &text); +CommandCost CmdSetGoalProgress(DoCommandFlags flags, GoalID goal, const EncodedString &text); CommandCost CmdSetGoalCompleted(DoCommandFlags flags, GoalID goal, bool completed); -CommandCost CmdGoalQuestion(DoCommandFlags flags, uint16_t uniqueid, uint32_t target, bool is_client, uint32_t button_mask, GoalQuestionType type, const std::string &text); +CommandCost CmdGoalQuestion(DoCommandFlags flags, uint16_t uniqueid, uint32_t target, bool is_client, uint32_t button_mask, GoalQuestionType type, const EncodedString &text); CommandCost CmdGoalQuestionAnswer(DoCommandFlags flags, uint16_t uniqueid, uint8_t button); DEF_CMD_TRAIT(CMD_CREATE_GOAL, CmdCreateGoal, CommandFlags({CommandFlag::Deity, CommandFlag::StrCtrl}), CMDT_OTHER_MANAGEMENT) diff --git a/src/goal_gui.cpp b/src/goal_gui.cpp index cbde78c16c..cccb600371 100644 --- a/src/goal_gui.cpp +++ b/src/goal_gui.cpp @@ -204,14 +204,14 @@ struct GoalListWindow : public Window { case GC_GOAL: { /* Display the goal. */ uint width_reduction = progress_col_width > 0 ? progress_col_width + WidgetDimensions::scaled.framerect.Horizontal() : 0; - DrawString(r.Indent(width_reduction, !rtl), GetString(STR_GOALS_TEXT, s->text)); + DrawString(r.Indent(width_reduction, !rtl), GetString(STR_GOALS_TEXT, s->text.GetDecodedString())); break; } case GC_PROGRESS: if (!s->progress.empty()) { StringID str = s->completed ? STR_GOALS_PROGRESS_COMPLETE : STR_GOALS_PROGRESS; - DrawString(r.WithWidth(progress_col_width, !rtl), GetString(str, s->progress), TC_FROMSTRING, SA_RIGHT | SA_FORCE); + DrawString(r.WithWidth(progress_col_width, !rtl), GetString(str, s->progress.GetDecodedString()), TC_FROMSTRING, SA_RIGHT | SA_FORCE); } break; } @@ -240,7 +240,7 @@ struct GoalListWindow : public Window { for (const Goal *s : Goal::Iterate()) { if (!s->progress.empty()) { StringID str = s->completed ? STR_GOALS_PROGRESS_COMPLETE : STR_GOALS_PROGRESS; - uint str_width = GetStringBoundingBox(GetString(str, s->progress)).width; + uint str_width = GetStringBoundingBox(GetString(str, s->progress.GetDecodedString())).width; if (str_width > max_width) max_width = str_width; } } @@ -317,12 +317,12 @@ void ShowGoalsList(CompanyID company) /** Ask a question about a goal. */ struct GoalQuestionWindow : public Window { - std::string question{}; ///< Question to ask (private copy). + EncodedString question{}; ///< Question to ask (private copy). int buttons = 0; ///< Number of valid buttons in #button. std::array button{}; ///< Buttons to display. TextColour colour{}; ///< Colour of the question text. - GoalQuestionWindow(WindowDesc &desc, WindowNumber window_number, TextColour colour, uint32_t button_mask, const std::string &question) : Window(desc), colour(colour) + GoalQuestionWindow(WindowDesc &desc, WindowNumber window_number, TextColour colour, uint32_t button_mask, const EncodedString &question) : Window(desc), colour(colour) { this->question = question; @@ -387,14 +387,14 @@ struct GoalQuestionWindow : public Window { { if (widget != WID_GQ_QUESTION) return; - size.height = GetStringHeight(GetString(STR_JUST_RAW_STRING, this->question), size.width); + size.height = GetStringHeight(this->question.GetDecodedString(), size.width); } void DrawWidget(const Rect &r, WidgetID widget) const override { if (widget != WID_GQ_QUESTION) return; - DrawStringMultiLine(r, GetString(STR_JUST_RAW_STRING, this->question), this->colour, SA_TOP | SA_HOR_CENTER); + DrawStringMultiLine(r, this->question.GetDecodedString(), this->colour, SA_TOP | SA_HOR_CENTER); } }; @@ -472,7 +472,7 @@ static WindowDesc _goal_question_list_desc[] = { * @param button_mask Buttons to display. * @param question Question to ask. */ -void ShowGoalQuestion(uint16_t id, uint8_t type, uint32_t button_mask, const std::string &question) +void ShowGoalQuestion(uint16_t id, uint8_t type, uint32_t button_mask, const EncodedString &question) { assert(type < GQT_END); new GoalQuestionWindow(_goal_question_list_desc[type], id, type == 3 ? TC_WHITE : TC_BLACK, button_mask, question); diff --git a/src/gui.h b/src/gui.h index ed8a7d3e98..60c5c394e9 100644 --- a/src/gui.h +++ b/src/gui.h @@ -10,6 +10,7 @@ #ifndef GUI_H #define GUI_H +#include "strings_type.h" #include "vehicle_type.h" #include "economy_type.h" #include "tile_type.h" @@ -62,7 +63,7 @@ void ShowSubsidiesList(); /* goal_gui.cpp */ void ShowGoalsList(CompanyID company); -void ShowGoalQuestion(uint16_t id, uint8_t type, uint32_t button_mask, const std::string &question); +void ShowGoalQuestion(uint16_t id, uint8_t type, uint32_t button_mask, const EncodedString &question); /* story_gui.cpp */ void ShowStoryBook(CompanyID company, StoryPageID page_id = StoryPageID::Invalid(), bool centered = false); diff --git a/src/industry.h b/src/industry.h index 7b96c45251..b8e99436d9 100644 --- a/src/industry.h +++ b/src/industry.h @@ -113,7 +113,7 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> { uint8_t selected_layout = 0; ///< Which tile layout was used when creating the industry Owner exclusive_supplier = INVALID_OWNER; ///< Which company has exclusive rights to deliver cargo (INVALID_OWNER = anyone) Owner exclusive_consumer = INVALID_OWNER; ///< Which company has exclusive rights to take cargo (INVALID_OWNER = anyone) - std::string text{}; ///< General text with additional information. + EncodedString text{}; ///< General text with additional information. uint16_t random = 0; ///< Random value used for randomisation of all kinds of things diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp index 28804931d8..3e1a569d36 100644 --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -2161,7 +2161,7 @@ CommandCost CmdIndustrySetFlags(DoCommandFlags flags, IndustryID ind_id, Industr * @param custom_news Custom news message text. * @return Empty cost or an error. */ -CommandCost CmdIndustrySetProduction(DoCommandFlags flags, IndustryID ind_id, uint8_t prod_level, bool show_news, const std::string &custom_news) +CommandCost CmdIndustrySetProduction(DoCommandFlags flags, IndustryID ind_id, uint8_t prod_level, bool show_news, const EncodedString &custom_news) { if (_current_company != OWNER_DEITY) return CMD_ERROR; if (prod_level < PRODLEVEL_MINIMUM || prod_level > PRODLEVEL_MAXIMUM) return CMD_ERROR; @@ -2195,12 +2195,13 @@ CommandCost CmdIndustrySetProduction(DoCommandFlags flags, IndustryID ind_id, ui /* Set parameters of news string */ EncodedString headline; if (str == STR_NEWS_CUSTOM_ITEM) { - headline = GetEncodedString(str, custom_news); + headline = GetEncodedString(str, custom_news.GetDecodedString()); } else if (str > STR_LAST_STRINGID) { headline = GetEncodedString(str, STR_TOWN_NAME, ind->town->index, GetIndustrySpec(ind->type)->name); } else { headline = GetEncodedString(str, ind->index); } + AddIndustryNewsItem(std::move(headline), nt, ind->index); } } @@ -2246,7 +2247,7 @@ CommandCost CmdIndustrySetExclusivity(DoCommandFlags flags, IndustryID ind_id, O * @param text - Additional industry text. * @return Empty cost or an error. */ -CommandCost CmdIndustrySetText(DoCommandFlags flags, IndustryID ind_id, const std::string &text) +CommandCost CmdIndustrySetText(DoCommandFlags flags, IndustryID ind_id, const EncodedString &text) { if (_current_company != OWNER_DEITY) return CMD_ERROR; diff --git a/src/industry_cmd.h b/src/industry_cmd.h index 37dc494e9e..e848260181 100644 --- a/src/industry_cmd.h +++ b/src/industry_cmd.h @@ -18,8 +18,8 @@ CommandCost CmdBuildIndustry(DoCommandFlags flags, TileIndex tile, IndustryType it, uint32_t first_layout, bool fund, uint32_t seed); CommandCost CmdIndustrySetFlags(DoCommandFlags flags, IndustryID ind_id, IndustryControlFlags ctlflags); CommandCost CmdIndustrySetExclusivity(DoCommandFlags flags, IndustryID ind_id, Owner company_id, bool consumer); -CommandCost CmdIndustrySetText(DoCommandFlags flags, IndustryID ind_id, const std::string &text); -CommandCost CmdIndustrySetProduction(DoCommandFlags flags, IndustryID ind_id, uint8_t prod_level, bool show_news, const std::string &text); +CommandCost CmdIndustrySetText(DoCommandFlags flags, IndustryID ind_id, const EncodedString &text); +CommandCost CmdIndustrySetProduction(DoCommandFlags flags, IndustryID ind_id, uint8_t prod_level, bool show_news, const EncodedString &text); DEF_CMD_TRAIT(CMD_BUILD_INDUSTRY, CmdBuildIndustry, CommandFlag::Deity, CMDT_LANDSCAPE_CONSTRUCTION) DEF_CMD_TRAIT(CMD_INDUSTRY_SET_FLAGS, CmdIndustrySetFlags, CommandFlag::Deity, CMDT_OTHER_MANAGEMENT) diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index 0ca025f0ea..3f5d00a999 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -990,7 +990,7 @@ public: if (!i->text.empty()) { ir.top += WidgetDimensions::scaled.vsep_wide; - ir.top = DrawStringMultiLine(ir, GetString(STR_JUST_RAW_STRING, i->text), TC_BLACK); + ir.top = DrawStringMultiLine(ir, i->text.GetDecodedString(), TC_BLACK); } /* Return required bottom position, the last pixel row plus some padding. */ diff --git a/src/league_base.h b/src/league_base.h index 6d448ff507..61ef32a83c 100644 --- a/src/league_base.h +++ b/src/league_base.h @@ -14,6 +14,7 @@ #include "goal_type.h" #include "league_type.h" #include "core/pool_type.hpp" +#include "strings_type.h" bool IsValidLink(Link link); @@ -32,15 +33,15 @@ struct LeagueTableElement : LeagueTableElementPool::PoolItem<&_league_table_elem LeagueTableID table = LeagueTableID::Invalid(); ///< Id of the table which this element belongs to int64_t rating = 0; ///< Value that determines ordering of elements in the table (higher=better) CompanyID company = CompanyID::Invalid(); ///< Company Id to show the color blob for or CompanyID::Invalid() - std::string text{}; ///< Text of the element - std::string score{}; ///< String representation of the score associated with the element + EncodedString text{}; ///< Text of the element + EncodedString score{}; ///< String representation of the score associated with the element Link link{}; ///< What opens when element is clicked /** * We need an (empty) constructor so struct isn't zeroed (as C++ standard states) */ LeagueTableElement() { } - LeagueTableElement(LeagueTableID table, int64_t rating, CompanyID company, const std::string &text, const std::string &score, const Link &link) : + LeagueTableElement(LeagueTableID table, int64_t rating, CompanyID company, const EncodedString &text, const EncodedString &score, const Link &link) : table(table), rating(rating), company(company), text(text), score(score), link(link) {} /** @@ -52,15 +53,15 @@ struct LeagueTableElement : LeagueTableElementPool::PoolItem<&_league_table_elem /** Struct about custom league tables */ struct LeagueTable : LeagueTablePool::PoolItem<&_league_table_pool> { - std::string title{}; ///< Title of the table - std::string header{}; ///< Text to show above the table - std::string footer{}; ///< Text to show below the table + EncodedString title{}; ///< Title of the table + EncodedString header{}; ///< Text to show above the table + EncodedString footer{}; ///< Text to show below the table /** * We need an (empty) constructor so struct isn't zeroed (as C++ standard states) */ LeagueTable() { } - LeagueTable(const std::string &title, const std::string &header, const std::string &footer) : title(title), header(header), footer(footer) { } + LeagueTable(const EncodedString &title, const EncodedString &header, const EncodedString &footer) : title(title), header(header), footer(footer) { } /** * (Empty) destructor has to be defined else operator delete might be called with nullptr parameter diff --git a/src/league_cmd.cpp b/src/league_cmd.cpp index 876a6d1a97..4fbfc0918d 100644 --- a/src/league_cmd.cpp +++ b/src/league_cmd.cpp @@ -53,7 +53,7 @@ bool IsValidLink(Link link) * @param footer Text to show below the table * @return the cost of this operation or an error */ -std::tuple CmdCreateLeagueTable(DoCommandFlags flags, const std::string &title, const std::string &header, const std::string &footer) +std::tuple CmdCreateLeagueTable(DoCommandFlags flags, const EncodedString &title, const EncodedString &header, const EncodedString &footer) { if (_current_company != OWNER_DEITY) return { CMD_ERROR, LeagueTableID::Invalid() }; if (!LeagueTable::CanAllocateItem()) return { CMD_ERROR, LeagueTableID::Invalid() }; @@ -80,7 +80,7 @@ std::tuple CmdCreateLeagueTable(DoCommandFlags flags * @param link_target Id of the referenced object * @return the cost of this operation or an error */ -std::tuple CmdCreateLeagueTableElement(DoCommandFlags flags, LeagueTableID table, int64_t rating, CompanyID company, const std::string &text, const std::string &score, LinkType link_type, LinkTargetID link_target) +std::tuple CmdCreateLeagueTableElement(DoCommandFlags flags, LeagueTableID table, int64_t rating, CompanyID company, const EncodedString &text, const EncodedString &score, LinkType link_type, LinkTargetID link_target) { if (_current_company != OWNER_DEITY) return { CMD_ERROR, LeagueTableElementID::Invalid() }; if (!LeagueTableElement::CanAllocateItem()) return { CMD_ERROR, LeagueTableElementID::Invalid() }; @@ -106,7 +106,7 @@ std::tuple CmdCreateLeagueTableElement(DoComm * @param link_target Id of the referenced object * @return the cost of this operation or an error */ -CommandCost CmdUpdateLeagueTableElementData(DoCommandFlags flags, LeagueTableElementID element, CompanyID company, const std::string &text, LinkType link_type, LinkTargetID link_target) +CommandCost CmdUpdateLeagueTableElementData(DoCommandFlags flags, LeagueTableElementID element, CompanyID company, const EncodedString &text, LinkType link_type, LinkTargetID link_target) { if (_current_company != OWNER_DEITY) return CMD_ERROR; auto lte = LeagueTableElement::GetIfValid(element); @@ -132,7 +132,7 @@ CommandCost CmdUpdateLeagueTableElementData(DoCommandFlags flags, LeagueTableEle * @param score String representation of the score associated with the element * @return the cost of this operation or an error */ -CommandCost CmdUpdateLeagueTableElementScore(DoCommandFlags flags, LeagueTableElementID element, int64_t rating, const std::string &score) +CommandCost CmdUpdateLeagueTableElementScore(DoCommandFlags flags, LeagueTableElementID element, int64_t rating, const EncodedString &score) { if (_current_company != OWNER_DEITY) return CMD_ERROR; auto lte = LeagueTableElement::GetIfValid(element); diff --git a/src/league_cmd.h b/src/league_cmd.h index 600aafc3c8..89a58915a4 100644 --- a/src/league_cmd.h +++ b/src/league_cmd.h @@ -14,10 +14,10 @@ #include "command_type.h" #include "company_type.h" -std::tuple CmdCreateLeagueTable(DoCommandFlags flags, const std::string &title, const std::string &header, const std::string &footer); -std::tuple CmdCreateLeagueTableElement(DoCommandFlags flags, LeagueTableID table, int64_t rating, CompanyID company, const std::string &text, const std::string &score, LinkType link_type, LinkTargetID link_target); -CommandCost CmdUpdateLeagueTableElementData(DoCommandFlags flags, LeagueTableElementID element, CompanyID company, const std::string &text, LinkType link_type, LinkTargetID link_target); -CommandCost CmdUpdateLeagueTableElementScore(DoCommandFlags flags, LeagueTableElementID element, int64_t rating, const std::string &score); +std::tuple CmdCreateLeagueTable(DoCommandFlags flags, const EncodedString &title, const EncodedString &header, const EncodedString &footer); +std::tuple CmdCreateLeagueTableElement(DoCommandFlags flags, LeagueTableID table, int64_t rating, CompanyID company, const EncodedString &text, const EncodedString &score, LinkType link_type, LinkTargetID link_target); +CommandCost CmdUpdateLeagueTableElementData(DoCommandFlags flags, LeagueTableElementID element, CompanyID company, const EncodedString &text, LinkType link_type, LinkTargetID link_target); +CommandCost CmdUpdateLeagueTableElementScore(DoCommandFlags flags, LeagueTableElementID element, int64_t rating, const EncodedString &score); CommandCost CmdRemoveLeagueTableElement(DoCommandFlags flags, LeagueTableElementID element); DEF_CMD_TRAIT(CMD_CREATE_LEAGUE_TABLE, CmdCreateLeagueTable, CommandFlags({CommandFlag::Deity, CommandFlag::StrCtrl}), CMDT_OTHER_MANAGEMENT) diff --git a/src/league_gui.cpp b/src/league_gui.cpp index 43333f727e..f1c697c709 100644 --- a/src/league_gui.cpp +++ b/src/league_gui.cpp @@ -257,7 +257,7 @@ private: uint header_height = 0; ///< Height of the table header int line_height = 0; ///< Height of the text lines Dimension icon_size{}; ///< Dimension of the company icon. - std::string title{}; + EncodedString title{}; /** * Rebuild the company league list @@ -265,7 +265,7 @@ private: void BuildTable() { this->rows.clear(); - this->title = std::string{}; + this->title = {}; const LeagueTable *lt = LeagueTable::GetIfValid(this->table); if (lt == nullptr) return; @@ -300,8 +300,7 @@ public: { if (widget != WID_SLT_CAPTION) return this->Window::GetWidgetString(widget, stringid); - /* Encoded string from game script needs to be formatted. */ - return GetString(STR_JUST_RAW_STRING, this->title); + return this->title.GetDecodedString(); } void OnPaint() override @@ -319,7 +318,7 @@ public: Rect ir = r.Shrink(WidgetDimensions::scaled.framerect); if (!lt->header.empty()) { - ir.top = DrawStringMultiLine(ir, GetString(STR_JUST_RAW_STRING, lt->header), TC_BLACK) + WidgetDimensions::scaled.vsep_wide; + ir.top = DrawStringMultiLine(ir, lt->header.GetDecodedString(), TC_BLACK) + WidgetDimensions::scaled.vsep_wide; } int icon_y_offset = (this->line_height - this->icon_size.height) / 2; @@ -336,14 +335,14 @@ public: for (const auto &[rank, lte] : this->rows) { DrawString(rank_rect.left, rank_rect.right, ir.top + text_y_offset, GetString(STR_COMPANY_LEAGUE_COMPANY_RANK, rank + 1)); if (this->icon_size.width > 0 && lte->company != CompanyID::Invalid()) DrawCompanyIcon(lte->company, icon_rect.left, ir.top + icon_y_offset); - DrawString(text_rect.left, text_rect.right, ir.top + text_y_offset, GetString(STR_JUST_RAW_STRING, lte->text), TC_BLACK); - DrawString(score_rect.left, score_rect.right, ir.top + text_y_offset, GetString(STR_JUST_RAW_STRING, lte->score), TC_BLACK, SA_RIGHT); + DrawString(text_rect.left, text_rect.right, ir.top + text_y_offset, lte->text.GetDecodedString(), TC_BLACK); + DrawString(score_rect.left, score_rect.right, ir.top + text_y_offset, lte->score.GetDecodedString(), TC_BLACK, SA_RIGHT); ir.top += this->line_height; } if (!lt->footer.empty()) { ir.top += WidgetDimensions::scaled.vsep_wide; - ir.top = DrawStringMultiLine(ir, GetString(STR_JUST_RAW_STRING, lt->footer), TC_BLACK); + ir.top = DrawStringMultiLine(ir, lt->footer.GetDecodedString(), TC_BLACK); } } @@ -362,8 +361,8 @@ public: bool show_icon_column = false; for (const auto &[rank, lte] : this->rows) { this->rank_width = std::max(this->rank_width, GetStringBoundingBox(GetString(STR_COMPANY_LEAGUE_COMPANY_RANK, rank + 1)).width); - this->text_width = std::max(this->text_width, GetStringBoundingBox(GetString(STR_JUST_RAW_STRING, lte->text)).width); - this->score_width = std::max(this->score_width, GetStringBoundingBox(GetString(STR_JUST_RAW_STRING, lte->score)).width); + this->text_width = std::max(this->text_width, GetStringBoundingBox(lte->text.GetDecodedString()).width); + this->score_width = std::max(this->score_width, GetStringBoundingBox(lte->score.GetDecodedString()).width); if (lte->company != CompanyID::Invalid()) show_icon_column = true; } @@ -381,14 +380,14 @@ public: this->text_width = size.width - non_text_width; if (!lt->header.empty()) { - this->header_height = GetStringHeight(GetString(STR_JUST_RAW_STRING, lt->header), size.width - WidgetDimensions::scaled.framerect.Horizontal()) + WidgetDimensions::scaled.vsep_wide; + this->header_height = GetStringHeight(lt->header.GetDecodedString(), size.width - WidgetDimensions::scaled.framerect.Horizontal()) + WidgetDimensions::scaled.vsep_wide; size.height += header_height; } else { this->header_height = 0; } if (!lt->footer.empty()) { - size.height += GetStringHeight(GetString(STR_JUST_RAW_STRING, lt->footer), size.width - WidgetDimensions::scaled.framerect.Horizontal()) + WidgetDimensions::scaled.vsep_wide; + size.height += GetStringHeight(lt->footer.GetDecodedString(), size.width - WidgetDimensions::scaled.framerect.Horizontal()) + WidgetDimensions::scaled.vsep_wide; } } diff --git a/src/misc/endian_buffer.hpp b/src/misc/endian_buffer.hpp index e3c561d5e6..d72cfca8af 100644 --- a/src/misc/endian_buffer.hpp +++ b/src/misc/endian_buffer.hpp @@ -12,6 +12,7 @@ #include #include "../core/bitmath_func.hpp" +#include "../strings_type.h" /** * Endian-aware buffer adapter that always writes values in little endian order. @@ -29,6 +30,7 @@ public: EndianBufferWriter(typename Titer::container_type &container) : buffer(std::back_inserter(container)) {} EndianBufferWriter &operator <<(const std::string &data) { return *this << std::string_view{ data }; } + EndianBufferWriter &operator <<(const EncodedString &data) { return *this << data.string; } EndianBufferWriter &operator <<(const char *data) { return *this << std::string_view{ data }; } EndianBufferWriter &operator <<(std::string_view data) { this->Write(data); return *this; } EndianBufferWriter &operator <<(bool data) { return *this << static_cast(data ? 1 : 0); } @@ -153,6 +155,7 @@ public: void rewind() { this->read_pos = 0; } EndianBufferReader &operator >>(std::string &data) { data = this->ReadStr(); return *this; } + EndianBufferReader &operator >>(EncodedString &data) { data = EncodedString{this->ReadStr()}; return *this; } EndianBufferReader &operator >>(bool &data) { data = this->Read() != 0; return *this; } template diff --git a/src/news_cmd.h b/src/news_cmd.h index 2653c3660a..df9523c253 100644 --- a/src/news_cmd.h +++ b/src/news_cmd.h @@ -14,7 +14,7 @@ #include "company_type.h" #include "news_func.h" -CommandCost CmdCustomNewsItem(DoCommandFlags flags, NewsType type, CompanyID company, NewsReference reference, const std::string &text); +CommandCost CmdCustomNewsItem(DoCommandFlags flags, NewsType type, CompanyID company, NewsReference reference, const EncodedString &text); DEF_CMD_TRAIT(CMD_CUSTOM_NEWS_ITEM, CmdCustomNewsItem, CommandFlags({CommandFlag::StrCtrl, CommandFlag::Deity}), CMDT_OTHER_MANAGEMENT) diff --git a/src/news_gui.cpp b/src/news_gui.cpp index f588d196ca..0356acbe61 100644 --- a/src/news_gui.cpp +++ b/src/news_gui.cpp @@ -934,7 +934,7 @@ uint32_t SerialiseNewsReference(const NewsReference &reference) * @param text The text of the news message. * @return the cost of this operation or an error */ -CommandCost CmdCustomNewsItem(DoCommandFlags flags, NewsType type, CompanyID company, NewsReference reference, const std::string &text) +CommandCost CmdCustomNewsItem(DoCommandFlags flags, NewsType type, CompanyID company, NewsReference reference, const EncodedString &text) { if (_current_company != OWNER_DEITY) return CMD_ERROR; @@ -957,7 +957,7 @@ CommandCost CmdCustomNewsItem(DoCommandFlags flags, NewsType type, CompanyID com if (company != INVALID_OWNER && company != _local_company) return CommandCost(); if (flags.Test(DoCommandFlag::Execute)) { - AddNewsItem(GetEncodedString(STR_NEWS_CUSTOM_ITEM, text), type, NewsStyle::Normal, {}, reference, {}); + AddNewsItem(GetEncodedString(STR_NEWS_CUSTOM_ITEM, text.GetDecodedString()), type, NewsStyle::Normal, {}, reference, {}); } return CommandCost(); diff --git a/src/script/api/script_goal.cpp b/src/script/api/script_goal.cpp index b36ad62272..1f4e7cf1e8 100644 --- a/src/script/api/script_goal.cpp +++ b/src/script/api/script_goal.cpp @@ -47,7 +47,7 @@ EnforceDeityMode(GOAL_INVALID); EnforcePrecondition(GOAL_INVALID, goal != nullptr); - std::string text = goal->GetEncodedText(); + EncodedString text = goal->GetEncodedText(); EnforcePreconditionEncodedText(GOAL_INVALID, text); EnforcePrecondition(GOAL_INVALID, company == ScriptCompany::COMPANY_INVALID || ScriptCompany::ResolveCompanyID(company) != ScriptCompany::COMPANY_INVALID); EnforcePrecondition(GOAL_INVALID, IsValidGoalDestination(company, type, destination)); @@ -83,7 +83,7 @@ EnforcePrecondition(false, IsValidGoal(goal_id)); EnforceDeityMode(false); EnforcePrecondition(false, goal != nullptr); - std::string text = goal->GetEncodedText(); + EncodedString text = goal->GetEncodedText(); EnforcePreconditionEncodedText(false, text); return ScriptObject::Command::Do(goal_id, text); @@ -96,7 +96,7 @@ EnforcePrecondition(false, IsValidGoal(goal_id)); EnforceDeityMode(false); - return ScriptObject::Command::Do(goal_id, progress != nullptr ? progress->GetEncodedText() : std::string{}); + return ScriptObject::Command::Do(goal_id, progress != nullptr ? progress->GetEncodedText() : EncodedString{}); } /* static */ bool ScriptGoal::SetCompleted(GoalID goal_id, bool completed) @@ -122,7 +122,7 @@ EnforceDeityMode(false); EnforcePrecondition(false, question != nullptr); - std::string text = question->GetEncodedText(); + EncodedString text = question->GetEncodedText(); EnforcePreconditionEncodedText(false, text); uint min_buttons = (type == QT_QUESTION ? 1 : 0); EnforcePrecondition(false, CountBits(buttons) >= min_buttons && CountBits(buttons) <= 3); diff --git a/src/script/api/script_industry.cpp b/src/script/api/script_industry.cpp index 19387503a4..74945bceba 100644 --- a/src/script/api/script_industry.cpp +++ b/src/script/api/script_industry.cpp @@ -62,7 +62,7 @@ EnforceDeityMode(false); EnforcePrecondition(false, IsValidIndustry(industry_id)); - return ScriptObject::Command::Do(industry_id, text != nullptr ? text->GetEncodedText() : std::string{}); + return ScriptObject::Command::Do(industry_id, text != nullptr ? text->GetEncodedText() : EncodedString{}); } /* static */ ScriptIndustry::CargoAcceptState ScriptIndustry::IsCargoAccepted(IndustryID industry_id, CargoType cargo_type) @@ -310,5 +310,5 @@ EnforcePrecondition(false, IsValidIndustry(industry_id)); EnforcePrecondition(false, prod_level >= PRODLEVEL_MINIMUM && prod_level <= PRODLEVEL_MAXIMUM); - return ScriptObject::Command::Do(industry_id, prod_level, show_news, custom_news != nullptr ? custom_news->GetEncodedText() : std::string{}); + return ScriptObject::Command::Do(industry_id, prod_level, show_news, custom_news != nullptr ? custom_news->GetEncodedText() : EncodedString{}); } diff --git a/src/script/api/script_league.cpp b/src/script/api/script_league.cpp index 90a04dabbc..33d74e45e8 100644 --- a/src/script/api/script_league.cpp +++ b/src/script/api/script_league.cpp @@ -32,11 +32,11 @@ EnforceDeityMode(LEAGUE_TABLE_INVALID); EnforcePrecondition(LEAGUE_TABLE_INVALID, title != nullptr); - std::string encoded_title = title->GetEncodedText(); + EncodedString encoded_title = title->GetEncodedText(); EnforcePreconditionEncodedText(LEAGUE_TABLE_INVALID, encoded_title); - std::string encoded_header = (header != nullptr ? header->GetEncodedText() : std::string{}); - std::string encoded_footer = (footer != nullptr ? footer->GetEncodedText() : std::string{}); + EncodedString encoded_header = (header != nullptr ? header->GetEncodedText() : EncodedString{}); + EncodedString encoded_footer = (footer != nullptr ? footer->GetEncodedText() : EncodedString{}); if (!ScriptObject::Command::Do(&ScriptInstance::DoCommandReturnLeagueTableID, encoded_title, encoded_header, encoded_footer)) return LEAGUE_TABLE_INVALID; @@ -62,11 +62,11 @@ ::CompanyID c = ScriptCompany::FromScriptCompanyID(company); EnforcePrecondition(LEAGUE_TABLE_ELEMENT_INVALID, text != nullptr); - std::string encoded_text = text->GetEncodedText(); + EncodedString encoded_text = text->GetEncodedText(); EnforcePreconditionEncodedText(LEAGUE_TABLE_ELEMENT_INVALID, encoded_text); EnforcePrecondition(LEAGUE_TABLE_ELEMENT_INVALID, score != nullptr); - std::string encoded_score = score->GetEncodedText(); + EncodedString encoded_score = score->GetEncodedText(); EnforcePreconditionEncodedText(LEAGUE_TABLE_ELEMENT_INVALID, encoded_score); EnforcePrecondition(LEAGUE_TABLE_ELEMENT_INVALID, IsValidLink(Link((::LinkType)link_type, link_target))); @@ -88,7 +88,7 @@ ::CompanyID c = ScriptCompany::FromScriptCompanyID(company); EnforcePrecondition(false, text != nullptr); - std::string encoded_text = text->GetEncodedText(); + EncodedString encoded_text = text->GetEncodedText(); EnforcePreconditionEncodedText(false, encoded_text); EnforcePrecondition(false, IsValidLink(Link((::LinkType)link_type, link_target))); @@ -104,7 +104,7 @@ EnforcePrecondition(false, IsValidLeagueTableElement(element)); EnforcePrecondition(false, score != nullptr); - std::string encoded_score = score->GetEncodedText(); + EncodedString encoded_score = score->GetEncodedText(); EnforcePreconditionEncodedText(false, encoded_score); return ScriptObject::Command::Do(element, rating, encoded_score); diff --git a/src/script/api/script_news.cpp b/src/script/api/script_news.cpp index 1a76ec7799..ae4daa9f01 100644 --- a/src/script/api/script_news.cpp +++ b/src/script/api/script_news.cpp @@ -38,7 +38,7 @@ static NewsReference CreateReference(ScriptNews::NewsReferenceType ref_type, SQI EnforceDeityMode(false); EnforcePrecondition(false, text != nullptr); - std::string encoded = text->GetEncodedText(); + EncodedString encoded = text->GetEncodedText(); EnforcePreconditionEncodedText(false, encoded); EnforcePrecondition(false, type == NT_ECONOMY || type == NT_SUBSIDIES || type == NT_GENERAL); EnforcePrecondition(false, company == ScriptCompany::COMPANY_INVALID || ScriptCompany::ResolveCompanyID(company) != ScriptCompany::COMPANY_INVALID); diff --git a/src/script/api/script_story_page.cpp b/src/script/api/script_story_page.cpp index 2977e4f1d5..3a5fb911a5 100644 --- a/src/script/api/script_story_page.cpp +++ b/src/script/api/script_story_page.cpp @@ -53,7 +53,7 @@ static inline bool StoryPageElementTypeRequiresText(StoryPageElementType type) ::CompanyID c = ScriptCompany::FromScriptCompanyID(company); if (!ScriptObject::Command::Do(&ScriptInstance::DoCommandReturnStoryPageID, - c, title != nullptr ? title->GetEncodedText() : std::string{})) return STORY_PAGE_INVALID; + c, title != nullptr ? title->GetEncodedText() : EncodedString{})) return STORY_PAGE_INVALID; /* In case of test-mode, we return StoryPageID 0 */ return StoryPageID::Begin(); @@ -68,7 +68,7 @@ static inline bool StoryPageElementTypeRequiresText(StoryPageElementType type) EnforceDeityMode(STORY_PAGE_ELEMENT_INVALID); EnforcePrecondition(STORY_PAGE_ELEMENT_INVALID, IsValidStoryPage(story_page_id)); EnforcePrecondition(STORY_PAGE_ELEMENT_INVALID, IsValidStoryPageElementType(type)); - std::string encoded_text; + EncodedString encoded_text; if (StoryPageElementTypeRequiresText(btype)) { EnforcePrecondition(STORY_PAGE_ELEMENT_INVALID, text != nullptr); encoded_text = text->GetEncodedText(); @@ -117,7 +117,7 @@ static inline bool StoryPageElementTypeRequiresText(StoryPageElementType type) const StoryPage *p = StoryPage::Get(pe->page); ::StoryPageElementType type = pe->type; - std::string encoded_text; + EncodedString encoded_text; if (StoryPageElementTypeRequiresText(type)) { EnforcePrecondition(false, text != nullptr); encoded_text = text->GetEncodedText(); @@ -169,7 +169,7 @@ static inline bool StoryPageElementTypeRequiresText(StoryPageElementType type) EnforcePrecondition(false, IsValidStoryPage(story_page_id)); EnforceDeityMode(false); - return ScriptObject::Command::Do(story_page_id, title != nullptr ? title->GetEncodedText() : std::string{}); + return ScriptObject::Command::Do(story_page_id, title != nullptr ? title->GetEncodedText() : EncodedString{}); } /* static */ ScriptCompany::CompanyID ScriptStoryPage::GetCompany(StoryPageID story_page_id) diff --git a/src/script/api/script_text.cpp b/src/script/api/script_text.cpp index 3faa424d31..9fea597317 100644 --- a/src/script/api/script_text.cpp +++ b/src/script/api/script_text.cpp @@ -153,7 +153,7 @@ SQInteger ScriptText::_set(HSQUIRRELVM vm) return this->_SetParam(k, vm); } -std::string ScriptText::GetEncodedText() +EncodedString ScriptText::GetEncodedText() { ScriptTextList seen_texts; ParamList params; @@ -163,7 +163,7 @@ std::string ScriptText::GetEncodedText() this->_FillParamList(params, seen_texts); this->_GetEncodedText(output, param_count, params, true); if (param_count > SCRIPT_TEXT_MAX_PARAMETERS) throw Script_FatalError(fmt::format("{}: Too many parameters", GetGameStringName(this->string))); - return result; + return ::EncodedString{std::move(result)}; } void ScriptText::_FillParamList(ParamList ¶ms, ScriptTextList &seen_texts) @@ -298,5 +298,5 @@ void ScriptText::_GetEncodedText(std::back_insert_iterator &output, const std::string Text::GetDecodedText() { - return ::GetString(STR_JUST_RAW_STRING, this->GetEncodedText()); + return this->GetEncodedText().GetDecodedString(); } diff --git a/src/script/api/script_text.hpp b/src/script/api/script_text.hpp index 6447e6cc76..0d82082faf 100644 --- a/src/script/api/script_text.hpp +++ b/src/script/api/script_text.hpp @@ -11,6 +11,7 @@ #define SCRIPT_TEXT_HPP #include "script_object.hpp" +#include "../../strings_func.h" #include @@ -25,7 +26,7 @@ public: * @return A string. * @api -all */ - virtual std::string GetEncodedText() = 0; + virtual EncodedString GetEncodedText() = 0; /** * Convert a #ScriptText into a decoded normal string. @@ -43,7 +44,7 @@ class RawText : public Text { public: RawText(const std::string &text) : text(text) {} - std::string GetEncodedText() override { return this->text; } + EncodedString GetEncodedText() override { return ::GetEncodedString(STR_JUST_RAW_STRING, this->text); } private: const std::string text; }; @@ -124,7 +125,7 @@ public: /** * @api -all */ - std::string GetEncodedText() override; + EncodedString GetEncodedText() override; private: using ScriptTextRef = ScriptObjectRef; diff --git a/src/script/api/script_town.cpp b/src/script/api/script_town.cpp index 6316297920..bf456dddb2 100644 --- a/src/script/api/script_town.cpp +++ b/src/script/api/script_town.cpp @@ -61,7 +61,7 @@ EnforceDeityMode(false); EnforcePrecondition(false, IsValidTown(town_id)); - return ScriptObject::Command::Do(town_id, text != nullptr ? text->GetEncodedText() : std::string{}); + return ScriptObject::Command::Do(town_id, text != nullptr ? text->GetEncodedText() : EncodedString{}); } /* static */ SQInteger ScriptTown::GetPopulation(TownID town_id) diff --git a/src/story.cpp b/src/story.cpp index d8c46267b3..89a2474811 100644 --- a/src/story.cpp +++ b/src/story.cpp @@ -56,7 +56,7 @@ StoryPage::~StoryPage() * @param text The text parameter of the DoCommand proc * @return true, if and only if the given parameters are valid for the given page element type and page id. */ -static bool VerifyElementContentParameters(StoryPageID page_id, StoryPageElementType type, TileIndex tile, uint32_t reference, const std::string &text) +static bool VerifyElementContentParameters(StoryPageID page_id, StoryPageElementType type, TileIndex tile, uint32_t reference, const EncodedString &text) { StoryPageButtonData button_data{ reference }; @@ -103,7 +103,7 @@ static bool VerifyElementContentParameters(StoryPageID page_id, StoryPageElement * @param reference The reference parameter of the DoCommand proc (p2) * @param text The text parameter of the DoCommand proc */ -static void UpdateElement(StoryPageElement &pe, TileIndex tile, uint32_t reference, const std::string &text) +static void UpdateElement(StoryPageElement &pe, TileIndex tile, uint32_t reference, const EncodedString &text) { switch (pe.type) { case SPET_TEXT: @@ -215,7 +215,7 @@ bool StoryPageButtonData::ValidateVehicleType() const * @param text Title of the story page. Null is allowed in which case a generic page title is provided by OpenTTD. * @return the cost of this operation or an error */ -std::tuple CmdCreateStoryPage(DoCommandFlags flags, CompanyID company, const std::string &text) +std::tuple CmdCreateStoryPage(DoCommandFlags flags, CompanyID company, const EncodedString &text) { if (!StoryPage::CanAllocateItem()) return { CMD_ERROR, StoryPageID::Invalid() }; @@ -250,7 +250,7 @@ std::tuple CmdCreateStoryPage(DoCommandFlags flags, Co * @param text Text content in case it is a text or location page element * @return the cost of this operation or an error */ -std::tuple CmdCreateStoryPageElement(DoCommandFlags flags, TileIndex tile, StoryPageID page_id, StoryPageElementType type, uint32_t reference, const std::string &text) +std::tuple CmdCreateStoryPageElement(DoCommandFlags flags, TileIndex tile, StoryPageID page_id, StoryPageElementType type, uint32_t reference, const EncodedString &text) { if (!StoryPageElement::CanAllocateItem()) return { CMD_ERROR, StoryPageElementID::Invalid() }; @@ -293,7 +293,7 @@ std::tuple CmdCreateStoryPageElement(DoCommandF * @param text Text content in case it is a text or location page element * @return the cost of this operation or an error */ -CommandCost CmdUpdateStoryPageElement(DoCommandFlags flags, TileIndex tile, StoryPageElementID page_element_id, uint32_t reference, const std::string &text) +CommandCost CmdUpdateStoryPageElement(DoCommandFlags flags, TileIndex tile, StoryPageElementID page_element_id, uint32_t reference, const EncodedString &text) { if (_current_company != OWNER_DEITY) return CMD_ERROR; if (!StoryPageElement::IsValidID(page_element_id)) return CMD_ERROR; @@ -319,7 +319,7 @@ CommandCost CmdUpdateStoryPageElement(DoCommandFlags flags, TileIndex tile, Stor * @param text title text of the story page. * @return the cost of this operation or an error */ -CommandCost CmdSetStoryPageTitle(DoCommandFlags flags, StoryPageID page_id, const std::string &text) +CommandCost CmdSetStoryPageTitle(DoCommandFlags flags, StoryPageID page_id, const EncodedString &text) { if (_current_company != OWNER_DEITY) return CMD_ERROR; if (!StoryPage::IsValidID(page_id)) return CMD_ERROR; diff --git a/src/story_base.h b/src/story_base.h index fe3fa94c9b..f856895a57 100644 --- a/src/story_base.h +++ b/src/story_base.h @@ -12,6 +12,7 @@ #include "company_type.h" #include "story_type.h" +#include "strings_type.h" #include "timer/timer_game_calendar.h" #include "gfx_type.h" #include "vehicle_type.h" @@ -147,7 +148,7 @@ struct StoryPageElement : StoryPageElementPool::PoolItem<&_story_page_element_po StoryPageElementType type; ///< Type of page element uint32_t referenced_id; ///< Id of referenced object (location, goal etc.) - std::string text; ///< Static content text of page element + EncodedString text; ///< Static content text of page element /** * We need an (empty) constructor so struct isn't zeroed (as C++ standard states) @@ -168,13 +169,13 @@ struct StoryPage : StoryPagePool::PoolItem<&_story_page_pool> { TimerGameCalendar::Date date{}; ///< Date when the page was created. CompanyID company = CompanyID::Invalid(); ///< StoryPage is for a specific company; CompanyID::Invalid() if it is global - std::string title; ///< Title of story page + EncodedString title; ///< Title of story page /** * We need an (empty) constructor so struct isn't zeroed (as C++ standard states) */ StoryPage() { } - StoryPage(uint32_t sort_value, TimerGameCalendar::Date date, CompanyID company, const std::string &title) : + StoryPage(uint32_t sort_value, TimerGameCalendar::Date date, CompanyID company, const EncodedString &title) : sort_value(sort_value), date(date), company(company), title(title) {} ~StoryPage(); diff --git a/src/story_cmd.h b/src/story_cmd.h index 4f652385a3..08075db057 100644 --- a/src/story_cmd.h +++ b/src/story_cmd.h @@ -15,10 +15,10 @@ #include "story_type.h" #include "vehicle_type.h" -std::tuple CmdCreateStoryPage(DoCommandFlags flags, CompanyID company, const std::string &text); -std::tuple CmdCreateStoryPageElement(DoCommandFlags flags, TileIndex tile, StoryPageID page_id, StoryPageElementType type, uint32_t reference, const std::string &text); -CommandCost CmdUpdateStoryPageElement(DoCommandFlags flags, TileIndex tile, StoryPageElementID page_element_id, uint32_t reference, const std::string &text); -CommandCost CmdSetStoryPageTitle(DoCommandFlags flags, StoryPageID page_id, const std::string &text); +std::tuple CmdCreateStoryPage(DoCommandFlags flags, CompanyID company, const EncodedString &text); +std::tuple CmdCreateStoryPageElement(DoCommandFlags flags, TileIndex tile, StoryPageID page_id, StoryPageElementType type, uint32_t reference, const EncodedString &text); +CommandCost CmdUpdateStoryPageElement(DoCommandFlags flags, TileIndex tile, StoryPageElementID page_element_id, uint32_t reference, const EncodedString &text); +CommandCost CmdSetStoryPageTitle(DoCommandFlags flags, StoryPageID page_id, const EncodedString &text); CommandCost CmdSetStoryPageDate(DoCommandFlags flags, StoryPageID page_id, TimerGameCalendar::Date date); CommandCost CmdShowStoryPage(DoCommandFlags flags, StoryPageID page_id); CommandCost CmdRemoveStoryPage(DoCommandFlags flags, StoryPageID page_id); diff --git a/src/story_gui.cpp b/src/story_gui.cpp index 1880f49730..c74e840185 100644 --- a/src/story_gui.cpp +++ b/src/story_gui.cpp @@ -250,7 +250,7 @@ protected: for (const StoryPage *p : this->story_pages) { bool current_page = p->index == this->selected_page_id; if (!p->title.empty()) { - list.push_back(MakeDropDownListStringItem(GetString(STR_JUST_RAW_STRING, p->title), p->index.base(), current_page)); + list.push_back(MakeDropDownListStringItem(p->title.GetDecodedString(), p->index.base(), current_page)); } else { /* No custom title => use a generic page title with page number. */ list.push_back(MakeDropDownListStringItem(GetString(STR_STORY_BOOK_GENERIC_PAGE_ITEM, page_num), p->index.base(), current_page)); @@ -284,7 +284,7 @@ protected: /* Title lines */ height += GetCharacterHeight(FS_NORMAL); // Date always use exactly one line. - height += GetStringHeight(GetString(STR_STORY_BOOK_TITLE, !page->title.empty() ? page->title : this->selected_generic_title), max_width); + height += GetStringHeight(GetString(STR_STORY_BOOK_TITLE, !page->title.empty() ? page->title.GetDecodedString() : this->selected_generic_title), max_width); return height; } @@ -320,7 +320,7 @@ protected: { switch (pe.type) { case SPET_TEXT: - return GetStringHeight(GetString(STR_JUST_RAW_STRING, pe.text), max_width); + return GetStringHeight(pe.text.GetDecodedString(), max_width); case SPET_GOAL: case SPET_LOCATION: { @@ -331,7 +331,7 @@ protected: case SPET_BUTTON_PUSH: case SPET_BUTTON_TILE: case SPET_BUTTON_VEHICLE: { - Dimension dim = GetStringBoundingBox(pe.text, FS_NORMAL); + Dimension dim = GetStringBoundingBox(pe.text.GetDecodedString(), FS_NORMAL); return dim.height + WidgetDimensions::scaled.framerect.Vertical() + WidgetDimensions::scaled.frametext.Vertical(); } @@ -374,7 +374,7 @@ protected: case SPET_BUTTON_PUSH: case SPET_BUTTON_TILE: case SPET_BUTTON_VEHICLE: { - Dimension dim = GetStringBoundingBox(pe.text, FS_NORMAL); + Dimension dim = GetStringBoundingBox(pe.text.GetDecodedString(), FS_NORMAL); return dim.width + WidgetDimensions::scaled.framerect.Vertical() + WidgetDimensions::scaled.frametext.Vertical(); } @@ -642,8 +642,7 @@ public: switch (widget) { case WID_SB_SEL_PAGE: { const StoryPage *page = this->GetSelPage(); - /* Encoded string from game script needs to be formatted. */ - return GetString(STR_JUST_RAW_STRING, page != nullptr && !page->title.empty() ? page->title : this->selected_generic_title); + return page != nullptr && !page->title.empty() ? page->title.GetDecodedString() : this->selected_generic_title; } case WID_SB_CAPTION: @@ -701,7 +700,7 @@ public: /* Title */ y_offset = DrawStringMultiLine(0, fr.right, y_offset, fr.bottom, - GetString(STR_STORY_BOOK_TITLE, !page->title.empty() ? page->title : this->selected_generic_title), TC_BLACK, SA_TOP | SA_HOR_CENTER); + GetString(STR_STORY_BOOK_TITLE, !page->title.empty() ? page->title.GetDecodedString() : this->selected_generic_title), TC_BLACK, SA_TOP | SA_HOR_CENTER); /* Page elements */ this->EnsureStoryPageElementLayout(); @@ -714,19 +713,19 @@ public: switch (ce.pe->type) { case SPET_TEXT: y_offset = DrawStringMultiLine(ce.bounds.left, ce.bounds.right, ce.bounds.top - scrollpos, ce.bounds.bottom - scrollpos, - GetString(STR_JUST_RAW_STRING, ce.pe->text), TC_BLACK, SA_TOP | SA_LEFT); + ce.pe->text.GetDecodedString(), TC_BLACK, SA_TOP | SA_LEFT); break; case SPET_GOAL: { Goal *g = Goal::Get((GoalID) ce.pe->referenced_id); DrawActionElement(y_offset, ce.bounds.right - ce.bounds.left, line_height, GetPageElementSprite(*ce.pe), - g == nullptr ? GetString(STR_STORY_BOOK_INVALID_GOAL_REF) : GetString(STR_JUST_RAW_STRING, g->text)); + g == nullptr ? GetString(STR_STORY_BOOK_INVALID_GOAL_REF) : g->text.GetDecodedString()); break; } case SPET_LOCATION: DrawActionElement(y_offset, ce.bounds.right - ce.bounds.left, line_height, GetPageElementSprite(*ce.pe), - GetString(STR_JUST_RAW_STRING, ce.pe->text)); + ce.pe->text.GetDecodedString()); break; case SPET_BUTTON_PUSH: @@ -739,7 +738,7 @@ public: DrawFrameRect(ce.bounds.left, ce.bounds.top - scrollpos, ce.bounds.right, ce.bounds.bottom - scrollpos - 1, bgcolour, frame); DrawString(ce.bounds.left + WidgetDimensions::scaled.bevel.left, ce.bounds.right - WidgetDimensions::scaled.bevel.right, ce.bounds.top + tmargin - scrollpos, - GetString(STR_JUST_RAW_STRING, ce.pe->text), TC_WHITE, SA_CENTER); + ce.pe->text.GetDecodedString(), TC_WHITE, SA_CENTER); break; } @@ -762,7 +761,7 @@ public: /* Get max title width. */ for (size_t i = 0; i < this->story_pages.size(); i++) { const StoryPage *s = this->story_pages[i]; - Dimension title_d = GetStringBoundingBox(GetString(STR_JUST_RAW_STRING, s->title.empty() ? this->selected_generic_title : s->title)); + Dimension title_d = GetStringBoundingBox(s->title.empty() ? this->selected_generic_title : s->title.GetDecodedString()); if (title_d.width > d.width) { d.width = title_d.width; diff --git a/src/strings_type.h b/src/strings_type.h index 8078d65dd5..f6d15f00eb 100644 --- a/src/strings_type.h +++ b/src/strings_type.h @@ -114,6 +114,11 @@ private: explicit EncodedString(std::string &&string) : string(std::move(string)) {} friend EncodedString GetEncodedStringWithArgs(StringID str, std::span params); + + template + friend class EndianBufferWriter; + friend class EndianBufferReader; + friend class ScriptText; }; #endif /* STRINGS_TYPE_H */ diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 091bc929be..56462d8ff9 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -658,7 +658,7 @@ static void AddDropDownLeagueTableOptions(DropDownList &list) { if (LeagueTable::GetNumItems() > 0) { for (LeagueTable *lt : LeagueTable::Iterate()) { - list.push_back(MakeDropDownListStringItem(GetString(STR_JUST_RAW_STRING, lt->title), lt->index.base())); + list.push_back(MakeDropDownListStringItem(lt->title.GetDecodedString(), lt->index.base())); } } else { list.push_back(MakeDropDownListStringItem(STR_GRAPH_MENU_COMPANY_LEAGUE_TABLE, LTMN_PERFORMANCE_LEAGUE)); diff --git a/src/town.h b/src/town.h index 6dc104f241..517c6b1b24 100644 --- a/src/town.h +++ b/src/town.h @@ -78,7 +78,7 @@ struct Town : TownPool::PoolItem<&_town_pool> { std::array, NUM_TAE> received{}; ///< Cargo statistics about received cargotypes. std::array goal{}; ///< Amount of cargo required for the town to grow. - std::string text{}; ///< General text with additional information. + EncodedString text{}; ///< General text with additional information. inline uint8_t GetPercentTransported(CargoType cargo_type) const { diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index bb10dd8811..078d2750e3 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -3115,7 +3115,7 @@ CommandCost CmdTownCargoGoal(DoCommandFlags flags, TownID town_id, TownAcceptanc * @param text The new text (empty to remove the text). * @return Empty cost or an error. */ -CommandCost CmdTownSetText(DoCommandFlags flags, TownID town_id, const std::string &text) +CommandCost CmdTownSetText(DoCommandFlags flags, TownID town_id, const EncodedString &text) { if (_current_company != OWNER_DEITY) return CMD_ERROR; Town *t = Town::GetIfValid(town_id); diff --git a/src/town_cmd.h b/src/town_cmd.h index c23eb6c91a..79151162dc 100644 --- a/src/town_cmd.h +++ b/src/town_cmd.h @@ -24,7 +24,7 @@ CommandCost CmdDoTownAction(DoCommandFlags flags, TownID town_id, TownAction act CommandCost CmdTownGrowthRate(DoCommandFlags flags, TownID town_id, uint16_t growth_rate); CommandCost CmdTownRating(DoCommandFlags flags, TownID town_id, CompanyID company_id, int16_t rating); CommandCost CmdTownCargoGoal(DoCommandFlags flags, TownID town_id, TownAcceptanceEffect tae, uint32_t goal); -CommandCost CmdTownSetText(DoCommandFlags flags, TownID town_id, const std::string &text); +CommandCost CmdTownSetText(DoCommandFlags flags, TownID town_id, const EncodedString &text); CommandCost CmdExpandTown(DoCommandFlags flags, TownID town_id, uint32_t grow_amount); CommandCost CmdDeleteTown(DoCommandFlags flags, TownID town_id); CommandCost CmdPlaceHouse(DoCommandFlags flags, TileIndex tile, HouseID house, bool house_protected); diff --git a/src/town_gui.cpp b/src/town_gui.cpp index fd1cacd7cf..58d9019121 100644 --- a/src/town_gui.cpp +++ b/src/town_gui.cpp @@ -482,7 +482,7 @@ public: } if (!this->town->text.empty()) { - tr.top = DrawStringMultiLine(tr, GetString(STR_JUST_RAW_STRING, this->town->text), TC_BLACK); + tr.top = DrawStringMultiLine(tr, this->town->text.GetDecodedString(), TC_BLACK); } } @@ -554,7 +554,7 @@ public: if (_settings_game.economy.station_noise_level) aimed_height += GetCharacterHeight(FS_NORMAL); if (!this->town->text.empty()) { - aimed_height += GetStringHeight(GetString(STR_JUST_RAW_STRING, this->town->text), width - WidgetDimensions::scaled.framerect.Horizontal()); + aimed_height += GetStringHeight(this->town->text.GetDecodedString(), width - WidgetDimensions::scaled.framerect.Horizontal()); } return aimed_height;