diff --git a/src/company_cmd.cpp b/src/company_cmd.cpp index 1c79c4b8a5..3c5e5f5c75 100644 --- a/src/company_cmd.cpp +++ b/src/company_cmd.cpp @@ -376,7 +376,7 @@ set_name:; MarkWholeScreenDirty(); if (c->is_ai) { - CompanyNewsInformation *cni = MallocT(1); + CompanyNewsInformation *cni = new CompanyNewsInformation(); cni->FillData(c); SetDParam(0, STR_NEWS_COMPANY_LAUNCH_TITLE); SetDParam(1, STR_NEWS_COMPANY_LAUNCH_DESCRIPTION); @@ -888,7 +888,7 @@ CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 /* Delete any open window of the company */ CloseCompanyWindows(c->index); - CompanyNewsInformation *cni = MallocT(1); + CompanyNewsInformation *cni = new CompanyNewsInformation(); cni->FillData(c); /* Show the bankrupt news */ diff --git a/src/economy.cpp b/src/economy.cpp index 7f14bed8ad..cb45d55b75 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -580,7 +580,7 @@ static void CompanyCheckBankrupt(Company *c) /* Warn about bankruptcy after 3 months */ case 4: { - CompanyNewsInformation *cni = MallocT(1); + CompanyNewsInformation *cni = new CompanyNewsInformation(); cni->FillData(c); SetDParam(0, STR_NEWS_COMPANY_IN_TROUBLE_TITLE); SetDParam(1, STR_NEWS_COMPANY_IN_TROUBLE_DESCRIPTION); @@ -1975,7 +1975,7 @@ static void DoAcquireCompany(Company *c) { CompanyID ci = c->index; - CompanyNewsInformation *cni = MallocT(1); + CompanyNewsInformation *cni = new CompanyNewsInformation(); cni->FillData(c, Company::Get(_current_company)); SetDParam(0, STR_NEWS_COMPANY_MERGER_TITLE); diff --git a/src/news_func.h b/src/news_func.h index 2131c8a749..3f21f3dca1 100644 --- a/src/news_func.h +++ b/src/news_func.h @@ -15,7 +15,7 @@ #include "station_type.h" #include "industry_type.h" -void AddNewsItem(StringID string, NewsType type, NewsFlag flags, NewsReferenceType reftype1 = NR_NONE, uint32 ref1 = UINT32_MAX, NewsReferenceType reftype2 = NR_NONE, uint32 ref2 = UINT32_MAX, void *free_data = nullptr); +void AddNewsItem(StringID string, NewsType type, NewsFlag flags, NewsReferenceType reftype1 = NR_NONE, uint32 ref1 = UINT32_MAX, NewsReferenceType reftype2 = NR_NONE, uint32 ref2 = UINT32_MAX, const NewsAllocatedData *data = nullptr); static inline void AddCompanyNewsItem(StringID string, CompanyNewsInformation *cni) { @@ -42,9 +42,9 @@ static inline void AddVehicleAdviceNewsItem(StringID string, VehicleID vehicle) AddNewsItem(string, NT_ADVICE, NF_INCOLOUR | NF_SMALL | NF_VEHICLE_PARAM0, NR_VEHICLE, vehicle); } -static inline void AddTileNewsItem(StringID string, NewsType type, TileIndex tile, void *free_data = nullptr, StationID station = INVALID_STATION) +static inline void AddTileNewsItem(StringID string, NewsType type, TileIndex tile, const NewsAllocatedData *data = nullptr, StationID station = INVALID_STATION) { - AddNewsItem(string, type, NF_NO_TRANSPARENT | NF_SHADE | NF_THIN, NR_TILE, tile, station == INVALID_STATION ? NR_NONE : NR_STATION, station, free_data); + AddNewsItem(string, type, NF_NO_TRANSPARENT | NF_SHADE | NF_THIN, NR_TILE, tile, station == INVALID_STATION ? NR_NONE : NR_STATION, station, data); } static inline void AddIndustryNewsItem(StringID string, NewsType type, IndustryID industry) diff --git a/src/news_gui.cpp b/src/news_gui.cpp index 5c72f87410..fb03207150 100644 --- a/src/news_gui.cpp +++ b/src/news_gui.cpp @@ -355,7 +355,7 @@ struct NewsWindow : Window { break; case WID_N_MGR_NAME: - SetDParamStr(0, static_cast(this->ni->free_data)->president_name); + SetDParamStr(0, static_cast(this->ni->data)->president_name); str = STR_JUST_RAW_STRING; break; @@ -433,13 +433,13 @@ struct NewsWindow : Window { break; case WID_N_MGR_FACE: { - const CompanyNewsInformation *cni = (const CompanyNewsInformation*)this->ni->free_data; + const CompanyNewsInformation *cni = static_cast(this->ni->data); DrawCompanyManagerFace(cni->face, cni->colour, r.left, r.top); GfxFillRect(r.left, r.top, r.right, r.bottom, PALETTE_NEWSPAPER, FILLRECT_RECOLOUR); break; } case WID_N_MGR_NAME: { - const CompanyNewsInformation *cni = (const CompanyNewsInformation*)this->ni->free_data; + const CompanyNewsInformation *cni = static_cast(this->ni->data); SetDParamStr(0, cni->president_name); DrawStringMultiLine(r.left, r.right, r.top, r.bottom, STR_JUST_RAW_STRING, TC_FROMSTRING, SA_CENTER); break; @@ -783,7 +783,7 @@ static void DeleteNewsItem(NewsItem *ni) * * @see NewsSubtype */ -void AddNewsItem(StringID string, NewsType type, NewsFlag flags, NewsReferenceType reftype1, uint32 ref1, NewsReferenceType reftype2, uint32 ref2, void *free_data) +void AddNewsItem(StringID string, NewsType type, NewsFlag flags, NewsReferenceType reftype1, uint32 ref1, NewsReferenceType reftype2, uint32 ref2, const NewsAllocatedData *data) { if (_game_mode == GM_MENU) return; @@ -801,7 +801,7 @@ void AddNewsItem(StringID string, NewsType type, NewsFlag flags, NewsReferenceTy ni->reftype2 = reftype2; ni->ref1 = ref1; ni->ref2 = ref2; - ni->free_data = free_data; + ni->data = data; ni->date = _date; CopyOutDParam(ni->params, 0, lengthof(ni->params)); @@ -882,8 +882,8 @@ CommandCost CmdCustomNewsItem(TileIndex tile, DoCommandFlag flags, uint32 p1, ui if (company != INVALID_OWNER && company != _local_company) return CommandCost(); if (flags & DC_EXEC) { - char *news = stredup(text.c_str()); - SetDParamStr(0, news); + NewsStringData *news = new NewsStringData(text); + SetDParamStr(0, news->string); AddNewsItem(STR_NEWS_CUSTOM_ITEM, type, NF_NORMAL, reftype1, p2, NR_NONE, UINT32_MAX, news); } diff --git a/src/news_type.h b/src/news_type.h index 1929804e4b..bed8f16e7c 100644 --- a/src/news_type.h +++ b/src/news_type.h @@ -115,6 +115,12 @@ struct NewsTypeData { NewsDisplay GetDisplay() const; }; +/** Container for any custom data that must be deleted after the news item has reached end-of-life. */ +struct NewsAllocatedData { + virtual ~NewsAllocatedData() {} +}; + + /** Information about a single item of news. */ struct NewsItem { NewsItem *prev; ///< Previous news item @@ -129,23 +135,29 @@ struct NewsItem { uint32 ref1; ///< Reference 1 to some object: Used for a possible viewport, scrolling after clicking on the news, and for deleting the news when the object is deleted. uint32 ref2; ///< Reference 2 to some object: Used for scrolling after clicking on the news, and for deleting the news when the object is deleted. - void *free_data; ///< Data to be freed when the news item has reached its end. + const NewsAllocatedData *data; ///< Custom data for the news item that have to be deallocated (deleted) when the news item has reached its end. ~NewsItem() { - free(this->free_data); + delete this->data; } uint64 params[10]; ///< Parameters for string resolving. }; +/** Container for a single string to be passed as NewsAllocatedData. */ +struct NewsStringData : NewsAllocatedData { + std::string string; ///< The string to retain. + NewsStringData(const std::string &str) : string(str) {} +}; + /** * Data that needs to be stored for company news messages. * The problem with company news messages are the custom name * of the companies and the fact that the company data is reset, * resulting in wrong names and such. */ -struct CompanyNewsInformation { +struct CompanyNewsInformation : NewsAllocatedData { char company_name[64]; ///< The name of the company char president_name[64]; ///< The name of the president char other_company_name[64]; ///< The name of the company taking over this one diff --git a/src/subsidy.cpp b/src/subsidy.cpp index 8800da1bd0..28cb0d3ccb 100644 --- a/src/subsidy.cpp +++ b/src/subsidy.cpp @@ -43,22 +43,19 @@ void Subsidy::AwardTo(CompanyID company) this->awarded = company; this->remaining = _settings_game.difficulty.subsidy_duration * MONTHS_IN_YEAR; - char company_name[MAX_LENGTH_COMPANY_NAME_CHARS * MAX_CHAR_LENGTH]; SetDParam(0, company); - GetString(company_name, STR_COMPANY_NAME, lastof(company_name)); - - char *cn = stredup(company_name); + NewsStringData *company_name = new NewsStringData(GetString(STR_COMPANY_NAME)); /* Add a news item */ std::pair reftype = SetupSubsidyDecodeParam(this, SubsidyDecodeParamType::NewsAwarded); InjectDParam(1); - SetDParamStr(0, cn); + SetDParamStr(0, company_name->string); AddNewsItem( STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF + _settings_game.difficulty.subsidy_multiplier, NT_SUBSIDIES, NF_NORMAL, reftype.first, this->src, reftype.second, this->dst, - cn + company_name ); AI::BroadcastNewEvent(new ScriptEventSubsidyAwarded(this->index)); Game::NewEvent(new ScriptEventSubsidyAwarded(this->index)); diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index d397825afc..b21d0ab714 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -2020,15 +2020,13 @@ CommandCost CmdFoundTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 SetDParam(0, t->index); AddTileNewsItem(STR_NEWS_NEW_TOWN_UNSPONSORED, NT_INDUSTRY_OPEN, tile); } else { - char company_name[MAX_LENGTH_COMPANY_NAME_CHARS * MAX_CHAR_LENGTH]; SetDParam(0, _current_company); - GetString(company_name, STR_COMPANY_NAME, lastof(company_name)); + NewsStringData *company_name = new NewsStringData(GetString(STR_COMPANY_NAME)); - char *cn = stredup(company_name); - SetDParamStr(0, cn); + SetDParamStr(0, company_name->string); SetDParam(1, t->index); - AddTileNewsItem(STR_NEWS_NEW_TOWN, NT_INDUSTRY_OPEN, tile, cn); + AddTileNewsItem(STR_NEWS_NEW_TOWN, NT_INDUSTRY_OPEN, tile, company_name); } AI::BroadcastNewEvent(new ScriptEventTownFounded(t->index)); Game::NewEvent(new ScriptEventTownFounded(t->index)); @@ -3090,15 +3088,13 @@ static CommandCost TownActionRoadRebuild(Town *t, DoCommandFlag flags) if (flags & DC_EXEC) { t->road_build_months = 6; - char company_name[MAX_LENGTH_COMPANY_NAME_CHARS * MAX_CHAR_LENGTH]; SetDParam(0, _current_company); - GetString(company_name, STR_COMPANY_NAME, lastof(company_name)); + NewsStringData *company_name = new NewsStringData(GetString(STR_COMPANY_NAME)); - char *cn = stredup(company_name); SetDParam(0, t->index); - SetDParamStr(1, cn); + SetDParamStr(1, company_name->string); - AddNewsItem(STR_NEWS_ROAD_REBUILDING, NT_GENERAL, NF_NORMAL, NR_TOWN, t->index, NR_NONE, UINT32_MAX, cn); + AddNewsItem(STR_NEWS_ROAD_REBUILDING, NT_GENERAL, NF_NORMAL, NR_TOWN, t->index, NR_NONE, UINT32_MAX, company_name); AI::BroadcastNewEvent(new ScriptEventRoadReconstruction((ScriptCompany::CompanyID)(Owner)_current_company, t->index)); Game::NewEvent(new ScriptEventRoadReconstruction((ScriptCompany::CompanyID)(Owner)_current_company, t->index)); } @@ -3235,7 +3231,7 @@ static CommandCost TownActionBuyRights(Town *t, DoCommandFlag flags) SetWindowClassesDirty(WC_STATION_VIEW); /* Spawn news message */ - CompanyNewsInformation *cni = MallocT(1); + CompanyNewsInformation *cni = new CompanyNewsInformation(); cni->FillData(Company::Get(_current_company)); SetDParam(0, STR_NEWS_EXCLUSIVE_RIGHTS_TITLE); SetDParam(1, STR_NEWS_EXCLUSIVE_RIGHTS_DESCRIPTION);