mirror of https://github.com/OpenTTD/OpenTTD
Codechange: Use EncodedStrings for News messages. (#13654)
parent
0afae7c546
commit
6e10584b91
|
@ -1335,18 +1335,17 @@ static void CrashAirplane(Aircraft *v)
|
|||
CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
|
||||
|
||||
uint victims = v->Crash();
|
||||
SetDParam(0, victims);
|
||||
|
||||
v->cargo.Truncate();
|
||||
v->Next()->cargo.Truncate();
|
||||
const Station *st = GetTargetAirportIfValid(v);
|
||||
StringID newsitem;
|
||||
TileIndex vt = TileVirtXY(v->x_pos, v->y_pos);
|
||||
|
||||
EncodedString headline;
|
||||
if (st == nullptr) {
|
||||
newsitem = STR_NEWS_PLANE_CRASH_OUT_OF_FUEL;
|
||||
headline = GetEncodedString(STR_NEWS_PLANE_CRASH_OUT_OF_FUEL, victims);
|
||||
} else {
|
||||
SetDParam(1, st->index);
|
||||
newsitem = STR_NEWS_AIRCRAFT_CRASH;
|
||||
headline = GetEncodedString(STR_NEWS_AIRCRAFT_CRASH, victims, st->index);
|
||||
}
|
||||
|
||||
AI::NewEvent(v->owner, new ScriptEventVehicleCrashed(v->index, vt, st == nullptr ? ScriptEventVehicleCrashed::CRASH_AIRCRAFT_NO_AIRPORT : ScriptEventVehicleCrashed::CRASH_PLANE_LANDING, victims));
|
||||
|
@ -1357,7 +1356,7 @@ static void CrashAirplane(Aircraft *v)
|
|||
newstype = NewsType::AccidentOther;
|
||||
}
|
||||
|
||||
AddTileNewsItem(newsitem, newstype, vt, st != nullptr ? st->index : StationID::Invalid());
|
||||
AddTileNewsItem(std::move(headline), newstype, vt, st != nullptr ? st->index : StationID::Invalid());
|
||||
|
||||
ModifyStationRatingAround(vt, v->owner, -160, 30);
|
||||
if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_12_EXPLOSION, v);
|
||||
|
@ -1408,10 +1407,9 @@ static void AircraftEntersTerminal(Aircraft *v)
|
|||
/* Check if station was ever visited before */
|
||||
if (!(st->had_vehicle_of_type & HVOT_AIRCRAFT)) {
|
||||
st->had_vehicle_of_type |= HVOT_AIRCRAFT;
|
||||
SetDParam(0, st->index);
|
||||
/* show newsitem of celebrating citizens */
|
||||
AddVehicleNewsItem(
|
||||
STR_NEWS_FIRST_AIRCRAFT_ARRIVAL,
|
||||
GetEncodedString(STR_NEWS_FIRST_AIRCRAFT_ARRIVAL, st->index),
|
||||
(v->owner == _local_company) ? NewsType::ArrivalCompany : NewsType::ArrivalOther,
|
||||
v->index,
|
||||
st->index
|
||||
|
@ -2063,8 +2061,7 @@ static void AircraftHandleDestTooFar(Aircraft *v, bool too_far)
|
|||
AI::NewEvent(v->owner, new ScriptEventAircraftDestTooFar(v->index));
|
||||
if (v->owner == _local_company) {
|
||||
/* Post a news message. */
|
||||
SetDParam(0, v->index);
|
||||
AddVehicleAdviceNewsItem(AdviceType::AircraftDestinationTooFar, STR_NEWS_AIRCRAFT_DEST_TOO_FAR, v->index);
|
||||
AddVehicleAdviceNewsItem(AdviceType::AircraftDestinationTooFar, GetEncodedString(STR_NEWS_AIRCRAFT_DEST_TOO_FAR, v->index), v->index);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
|
|
@ -335,20 +335,24 @@ static CommandCost BuildReplacementVehicle(Vehicle *old_veh, Vehicle **new_vehic
|
|||
if (!IsLocalCompany() || !flags.Test(DoCommandFlag::Execute)) return CommandCost();
|
||||
|
||||
VehicleID old_veh_id = (old_veh->type == VEH_TRAIN) ? Train::From(old_veh)->First()->index : old_veh->index;
|
||||
SetDParam(0, old_veh_id);
|
||||
EncodedString headline;
|
||||
|
||||
int order_id = GetIncompatibleRefitOrderIdForAutoreplace(old_veh, e);
|
||||
if (order_id != -1) {
|
||||
/* Orders contained a refit order that is incompatible with the new vehicle. */
|
||||
SetDParam(1, STR_ERROR_AUTOREPLACE_INCOMPATIBLE_REFIT);
|
||||
SetDParam(2, order_id + 1); // 1-based indexing for display
|
||||
headline = GetEncodedString(STR_NEWS_VEHICLE_AUTORENEW_FAILED,
|
||||
old_veh_id,
|
||||
STR_ERROR_AUTOREPLACE_INCOMPATIBLE_REFIT,
|
||||
order_id + 1); // 1-based indexing for display
|
||||
} else {
|
||||
/* Current cargo is incompatible with the new vehicle. */
|
||||
SetDParam(1, STR_ERROR_AUTOREPLACE_INCOMPATIBLE_CARGO);
|
||||
SetDParam(2, CargoSpec::Get(old_veh->cargo_type)->name);
|
||||
headline = GetEncodedString(STR_NEWS_VEHICLE_AUTORENEW_FAILED,
|
||||
old_veh_id,
|
||||
STR_ERROR_AUTOREPLACE_INCOMPATIBLE_CARGO,
|
||||
CargoSpec::Get(old_veh->cargo_type)->name);
|
||||
}
|
||||
|
||||
AddVehicleAdviceNewsItem(AdviceType::AutorenewFailed, STR_NEWS_VEHICLE_AUTORENEW_FAILED, old_veh_id);
|
||||
AddVehicleAdviceNewsItem(AdviceType::AutorenewFailed, std::move(headline), old_veh_id);
|
||||
return CommandCost();
|
||||
}
|
||||
|
||||
|
|
|
@ -419,12 +419,10 @@ set_name:;
|
|||
Game::NewEvent(new ScriptEventCompanyRenamed(c->index, name));
|
||||
|
||||
if (c->is_ai) {
|
||||
auto cni = std::make_unique<CompanyNewsInformation>(c);
|
||||
SetDParam(0, STR_NEWS_COMPANY_LAUNCH_TITLE);
|
||||
SetDParam(1, STR_NEWS_COMPANY_LAUNCH_DESCRIPTION);
|
||||
SetDParamStr(2, cni->company_name);
|
||||
SetDParam(3, t->index);
|
||||
AddNewsItem(STR_MESSAGE_NEWS_FORMAT, NewsType::CompanyInfo, NewsStyle::Company, {}, c->last_build_coordinate, {}, std::move(cni));
|
||||
auto cni = std::make_unique<CompanyNewsInformation>(STR_NEWS_COMPANY_LAUNCH_TITLE, c);
|
||||
EncodedString headline = GetEncodedString(STR_NEWS_COMPANY_LAUNCH_DESCRIPTION, cni->company_name, t->index);
|
||||
AddNewsItem(std::move(headline),
|
||||
NewsType::CompanyInfo, NewsStyle::Company, {}, c->last_build_coordinate, {}, std::move(cni));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -806,7 +804,7 @@ static IntervalTimer<TimerGameEconomy> _economy_companies_yearly({TimerGameEcono
|
|||
* @param c the current company.
|
||||
* @param other the other company (use \c nullptr if not relevant).
|
||||
*/
|
||||
CompanyNewsInformation::CompanyNewsInformation(const Company *c, const Company *other)
|
||||
CompanyNewsInformation::CompanyNewsInformation(StringID title, const Company *c, const Company *other)
|
||||
{
|
||||
this->company_name = GetString(STR_COMPANY_NAME, c->index);
|
||||
|
||||
|
@ -817,6 +815,7 @@ CompanyNewsInformation::CompanyNewsInformation(const Company *c, const Company *
|
|||
|
||||
this->president_name = GetString(STR_PRESIDENT_NAME_MANAGER, c->index);
|
||||
|
||||
this->title = title;
|
||||
this->colour = c->colour;
|
||||
this->face = c->face;
|
||||
|
||||
|
@ -934,13 +933,10 @@ CommandCost CmdCompanyCtrl(DoCommandFlags flags, CompanyCtrlAction cca, CompanyI
|
|||
|
||||
if (!flags.Test(DoCommandFlag::Execute)) return CommandCost();
|
||||
|
||||
auto cni = std::make_unique<CompanyNewsInformation>(c);
|
||||
|
||||
/* Show the bankrupt news */
|
||||
SetDParam(0, STR_NEWS_COMPANY_BANKRUPT_TITLE);
|
||||
SetDParam(1, STR_NEWS_COMPANY_BANKRUPT_DESCRIPTION);
|
||||
SetDParamStr(2, cni->company_name);
|
||||
AddCompanyNewsItem(STR_MESSAGE_NEWS_FORMAT, std::move(cni));
|
||||
auto cni = std::make_unique<CompanyNewsInformation>(STR_NEWS_COMPANY_BANKRUPT_TITLE, c);
|
||||
EncodedString headline = GetEncodedString(STR_NEWS_COMPANY_BANKRUPT_DESCRIPTION, cni->company_name);
|
||||
AddCompanyNewsItem(std::move(headline), std::move(cni));
|
||||
|
||||
/* Remove the company */
|
||||
ChangeOwnershipOfCompanyItems(c->index, INVALID_OWNER);
|
||||
|
|
|
@ -59,8 +59,8 @@ static void SurveyRecentNews(nlohmann::json &json)
|
|||
int i = 0;
|
||||
for (const auto &news : GetNews()) {
|
||||
TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(news.date);
|
||||
json.push_back(fmt::format("({}-{:02}-{:02}) StringID: {}, Type: {}, Ref1: {}, {}, Ref2: {}, {}",
|
||||
ymd.year, ymd.month + 1, ymd.day, news.string_id, news.type,
|
||||
json.push_back(fmt::format("({}-{:02}-{:02}) String: {}, Type: {}, Ref1: {}, {}, Ref2: {}, {}",
|
||||
ymd.year, ymd.month + 1, ymd.day, news.GetStatusText(), news.type,
|
||||
news.ref1.index(), SerialiseNewsReference(news.ref1),
|
||||
news.ref2.index(), SerialiseNewsReference(news.ref2)));
|
||||
if (++i > 32) break;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "news_func.h"
|
||||
#include "settings_type.h"
|
||||
#include "string_type.h"
|
||||
#include "strings_func.h"
|
||||
#include "timer/timer.h"
|
||||
#include "timer/timer_game_calendar.h"
|
||||
|
||||
|
@ -148,7 +149,7 @@ static IntervalTimer<TimerGameCalendar> _check_switch_to_euro({TimerGameCalendar
|
|||
_currency_specs[_settings_game.locale.currency].to_euro != CF_ISEURO &&
|
||||
TimerGameCalendar::year >= _currency_specs[_settings_game.locale.currency].to_euro) {
|
||||
_settings_game.locale.currency = 2; // this is the index of euro above.
|
||||
AddNewsItem(STR_NEWS_EURO_INTRODUCTION, NewsType::Economy, NewsStyle::Normal, {});
|
||||
AddNewsItem(GetEncodedString(STR_NEWS_EURO_INTRODUCTION), NewsType::Economy, NewsStyle::Normal, {});
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -245,8 +245,7 @@ static bool DisasterTick_Zeppeliner(DisasterVehicle *v)
|
|||
v->state = 1;
|
||||
v->age = CalendarTime::MIN_DATE;
|
||||
|
||||
SetDParam(0, GetStationIndex(v->tile));
|
||||
AddTileNewsItem(STR_NEWS_DISASTER_ZEPPELIN, NewsType::Accident, v->tile);
|
||||
AddTileNewsItem(GetEncodedString(STR_NEWS_DISASTER_ZEPPELIN, GetStationIndex(v->tile)), NewsType::Accident, v->tile);
|
||||
AI::NewEvent(GetTileOwner(v->tile), new ScriptEventDisasterZeppelinerCrashed(GetStationIndex(v->tile)));
|
||||
}
|
||||
}
|
||||
|
@ -387,7 +386,7 @@ static bool DisasterTick_Ufo(DisasterVehicle *v)
|
|||
uint victims = u->Crash();
|
||||
u->disaster_vehicle = VehicleID::Invalid();
|
||||
|
||||
AddTileNewsItem(STR_NEWS_DISASTER_SMALL_UFO, NewsType::Accident, u->tile);
|
||||
AddTileNewsItem(GetEncodedString(STR_NEWS_DISASTER_SMALL_UFO), NewsType::Accident, u->tile);
|
||||
|
||||
AI::NewEvent(u->owner, new ScriptEventVehicleCrashed(u->index, u->tile, ScriptEventVehicleCrashed::CRASH_RV_UFO, victims));
|
||||
Game::NewEvent(new ScriptEventVehicleCrashed(u->index, u->tile, ScriptEventVehicleCrashed::CRASH_RV_UFO, victims));
|
||||
|
@ -465,8 +464,7 @@ static bool DisasterTick_Aircraft(DisasterVehicle *v, uint16_t image_override, b
|
|||
Industry *i = Industry::Get(v->dest_tile.base()); // Industry destructor calls ReleaseDisastersTargetingIndustry, so this is valid
|
||||
DestructIndustry(i);
|
||||
|
||||
SetDParam(0, i->town->index);
|
||||
AddIndustryNewsItem(news_message, NewsType::Accident, i->index);
|
||||
AddIndustryNewsItem(GetEncodedString(news_message, i->town->index), NewsType::Accident, i->index);
|
||||
if (_settings_client.sound.disaster) SndPlayTileFx(SND_12_EXPLOSION, i->location.tile);
|
||||
}
|
||||
} else if (v->state == 0) {
|
||||
|
@ -561,8 +559,7 @@ static bool DisasterTick_Big_Ufo(DisasterVehicle *v)
|
|||
}
|
||||
|
||||
Town *t = ClosestTownFromTile(v->dest_tile, UINT_MAX);
|
||||
SetDParam(0, t->index);
|
||||
AddTileNewsItem(STR_NEWS_DISASTER_BIG_UFO, NewsType::Accident, v->tile);
|
||||
AddTileNewsItem(GetEncodedString(STR_NEWS_DISASTER_BIG_UFO, t->index), NewsType::Accident, v->tile);
|
||||
|
||||
if (!Vehicle::CanAllocateItem(2)) {
|
||||
delete v;
|
||||
|
@ -887,8 +884,7 @@ static void Disaster_CoalMine_Init()
|
|||
for (m = 0; m < 15; m++) {
|
||||
for (const Industry *i : Industry::Iterate()) {
|
||||
if (GetIndustrySpec(i->type)->behaviour.Test(IndustryBehaviour::CanSubsidence) && --index < 0) {
|
||||
SetDParam(0, i->town->index);
|
||||
AddTileNewsItem(STR_NEWS_DISASTER_COAL_MINE_SUBSIDENCE, NewsType::Accident, i->location.tile + TileDiffXY(1, 1)); // keep the news, even when the mine closes
|
||||
AddTileNewsItem(GetEncodedString(STR_NEWS_DISASTER_COAL_MINE_SUBSIDENCE, i->town->index), NewsType::Accident, i->location.tile + TileDiffXY(1, 1)); // keep the news, even when the mine closes
|
||||
|
||||
{
|
||||
TileIndex tile = i->location.tile;
|
||||
|
|
|
@ -582,11 +582,9 @@ static void CompanyCheckBankrupt(Company *c)
|
|||
|
||||
/* Warn about bankruptcy after 3 months */
|
||||
case 4: {
|
||||
auto cni = std::make_unique<CompanyNewsInformation>(c);
|
||||
SetDParam(0, STR_NEWS_COMPANY_IN_TROUBLE_TITLE);
|
||||
SetDParam(1, STR_NEWS_COMPANY_IN_TROUBLE_DESCRIPTION);
|
||||
SetDParamStr(2, cni->company_name);
|
||||
AddCompanyNewsItem(STR_MESSAGE_NEWS_FORMAT, std::move(cni));
|
||||
auto cni = std::make_unique<CompanyNewsInformation>(STR_NEWS_COMPANY_IN_TROUBLE_TITLE, c);
|
||||
EncodedString headline = GetEncodedString(STR_NEWS_COMPANY_IN_TROUBLE_DESCRIPTION, cni->company_name);
|
||||
AddCompanyNewsItem(std::move(headline), std::move(cni));
|
||||
AI::BroadcastNewEvent(new ScriptEventCompanyInTrouble(c->index));
|
||||
Game::NewEvent(new ScriptEventCompanyInTrouble(c->index));
|
||||
break;
|
||||
|
@ -861,10 +859,10 @@ static void HandleEconomyFluctuations()
|
|||
|
||||
if (_economy.fluct == 0) {
|
||||
_economy.fluct = -(int)GB(Random(), 0, 2);
|
||||
AddNewsItem(STR_NEWS_BEGIN_OF_RECESSION, NewsType::Economy, NewsStyle::Normal, {});
|
||||
AddNewsItem(GetEncodedString(STR_NEWS_BEGIN_OF_RECESSION), NewsType::Economy, NewsStyle::Normal, {});
|
||||
} else if (_economy.fluct == -12) {
|
||||
_economy.fluct = GB(Random(), 0, 8) + 312;
|
||||
AddNewsItem(STR_NEWS_END_OF_RECESSION, NewsType::Economy, NewsStyle::Normal, {});
|
||||
AddNewsItem(GetEncodedString(STR_NEWS_END_OF_RECESSION), NewsType::Economy, NewsStyle::Normal, {});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1995,14 +1993,11 @@ static void DoAcquireCompany(Company *c, bool hostile_takeover)
|
|||
{
|
||||
CompanyID ci = c->index;
|
||||
|
||||
auto cni = std::make_unique<CompanyNewsInformation>(c, Company::Get(_current_company));
|
||||
|
||||
SetDParam(0, STR_NEWS_COMPANY_MERGER_TITLE);
|
||||
SetDParam(1, hostile_takeover ? STR_NEWS_MERGER_TAKEOVER_TITLE : STR_NEWS_COMPANY_MERGER_DESCRIPTION);
|
||||
SetDParamStr(2, cni->company_name);
|
||||
SetDParamStr(3, cni->other_company_name);
|
||||
SetDParam(4, c->bankrupt_value);
|
||||
AddCompanyNewsItem(STR_MESSAGE_NEWS_FORMAT, std::move(cni));
|
||||
auto cni = std::make_unique<CompanyNewsInformation>(STR_NEWS_COMPANY_MERGER_TITLE, c, Company::Get(_current_company));
|
||||
EncodedString headline = hostile_takeover
|
||||
? GetEncodedString(STR_NEWS_MERGER_TAKEOVER_TITLE, cni->company_name, cni->other_company_name)
|
||||
: GetEncodedString(STR_NEWS_COMPANY_MERGER_DESCRIPTION, cni->company_name, cni->other_company_name, c->bankrupt_value);
|
||||
AddCompanyNewsItem(std::move(headline), std::move(cni));
|
||||
AI::BroadcastNewEvent(new ScriptEventCompanyMerger(ci, _current_company));
|
||||
Game::NewEvent(new ScriptEventCompanyMerger(ci, _current_company));
|
||||
|
||||
|
|
|
@ -1129,9 +1129,10 @@ static void NewVehicleAvailable(Engine *e)
|
|||
|
||||
/* Only provide the "New Vehicle available" news paper entry, if engine can be built. */
|
||||
if (!IsVehicleTypeDisabled(e->type, false) && !e->info.extra_flags.Test(ExtraEngineFlag::NoNews)) {
|
||||
SetDParam(0, GetEngineCategoryName(index));
|
||||
SetDParam(1, PackEngineNameDParam(index, EngineNameContext::PreviewNews));
|
||||
AddNewsItem(STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE, NewsType::NewVehicles, NewsStyle::Vehicle, {}, index);
|
||||
AddNewsItem(GetEncodedString(STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE,
|
||||
GetEngineCategoryName(index),
|
||||
PackEngineNameDParam(index, EngineNameContext::PreviewNews)),
|
||||
NewsType::NewVehicles, NewsStyle::Vehicle, {}, index);
|
||||
}
|
||||
|
||||
/* Update the toolbar. */
|
||||
|
|
|
@ -1719,14 +1719,13 @@ static CommandCost CheckIfFarEnoughFromConflictingIndustry(TileIndex tile, Indus
|
|||
static void AdvertiseIndustryOpening(const Industry *ind)
|
||||
{
|
||||
const IndustrySpec *ind_spc = GetIndustrySpec(ind->type);
|
||||
SetDParam(0, ind_spc->name);
|
||||
EncodedString headline;
|
||||
if (ind_spc->new_industry_text > STR_LAST_STRINGID) {
|
||||
SetDParam(1, STR_TOWN_NAME);
|
||||
SetDParam(2, ind->town->index);
|
||||
headline = GetEncodedString(ind_spc->new_industry_text, ind_spc->name, STR_TOWN_NAME, ind->town->index);
|
||||
} else {
|
||||
SetDParam(1, ind->town->index);
|
||||
headline = GetEncodedString(ind_spc->new_industry_text, ind_spc->name, ind->town->index);
|
||||
}
|
||||
AddIndustryNewsItem(ind_spc->new_industry_text, NewsType::IndustryOpen, ind->index);
|
||||
AddIndustryNewsItem(std::move(headline), NewsType::IndustryOpen, ind->index);
|
||||
AI::BroadcastNewEvent(new ScriptEventIndustryOpen(ind->index));
|
||||
Game::NewEvent(new ScriptEventIndustryOpen(ind->index));
|
||||
}
|
||||
|
@ -2194,16 +2193,15 @@ CommandCost CmdIndustrySetProduction(DoCommandFlags flags, IndustryID ind_id, ui
|
|||
}
|
||||
|
||||
/* Set parameters of news string */
|
||||
EncodedString headline;
|
||||
if (str == STR_NEWS_CUSTOM_ITEM) {
|
||||
SetDParamStr(0, custom_news);
|
||||
headline = GetEncodedString(str, custom_news);
|
||||
} else if (str > STR_LAST_STRINGID) {
|
||||
SetDParam(0, STR_TOWN_NAME);
|
||||
SetDParam(1, ind->town->index);
|
||||
SetDParam(2, GetIndustrySpec(ind->type)->name);
|
||||
headline = GetEncodedString(str, STR_TOWN_NAME, ind->town->index, GetIndustrySpec(ind->type)->name);
|
||||
} else {
|
||||
SetDParam(0, ind->index);
|
||||
headline = GetEncodedString(str, ind->index);
|
||||
}
|
||||
AddIndustryNewsItem(str, nt, ind->index);
|
||||
AddIndustryNewsItem(std::move(headline), nt, ind->index);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2778,11 +2776,10 @@ static void ReportNewsProductionChangeIndustry(Industry *ind, CargoType type, in
|
|||
case 2: nt = NewsType::IndustryCompany; break;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
SetDParam(2, abs(percent));
|
||||
SetDParam(0, CargoSpec::Get(type)->name);
|
||||
SetDParam(1, ind->index);
|
||||
AddIndustryNewsItem(
|
||||
percent >= 0 ? STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_SMOOTH : STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_SMOOTH,
|
||||
GetEncodedString(percent >= 0 ? STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_SMOOTH : STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_SMOOTH,
|
||||
CargoSpec::Get(type)->name, ind->index, abs(percent)
|
||||
),
|
||||
nt,
|
||||
ind->index
|
||||
);
|
||||
|
@ -2985,22 +2982,19 @@ static void ChangeIndustryProduction(Industry *i, bool monthly)
|
|||
}
|
||||
}
|
||||
/* Set parameters of news string */
|
||||
EncodedString headline;
|
||||
if (str > STR_LAST_STRINGID) {
|
||||
SetDParam(0, STR_TOWN_NAME);
|
||||
SetDParam(1, i->town->index);
|
||||
SetDParam(2, indspec->name);
|
||||
headline = GetEncodedString(str, STR_TOWN_NAME, i->town->index, indspec->name);
|
||||
} else if (closeit) {
|
||||
SetDParam(0, STR_FORMAT_INDUSTRY_NAME);
|
||||
SetDParam(1, i->town->index);
|
||||
SetDParam(2, indspec->name);
|
||||
headline = GetEncodedString(str, STR_FORMAT_INDUSTRY_NAME, i->town->index, indspec->name);
|
||||
} else {
|
||||
SetDParam(0, i->index);
|
||||
headline = GetEncodedString(str, i->index);
|
||||
}
|
||||
/* and report the news to the user */
|
||||
if (closeit) {
|
||||
AddTileNewsItem(str, nt, i->location.tile + TileDiffXY(1, 1));
|
||||
AddTileNewsItem(std::move(headline), nt, i->location.tile + TileDiffXY(1, 1));
|
||||
} else {
|
||||
AddIndustryNewsItem(str, nt, i->index);
|
||||
AddIndustryNewsItem(std::move(headline), nt, i->index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -838,7 +838,7 @@ STR_STATUSBAR_INFINITE_MONEY :{WHITE}(infinit
|
|||
# News message history
|
||||
STR_MESSAGE_HISTORY :{WHITE}Message History
|
||||
STR_MESSAGE_HISTORY_TOOLTIP :{BLACK}A list of the recent news messages
|
||||
STR_MESSAGE_NEWS_FORMAT :{STRING} - {STRING5}
|
||||
STR_MESSAGE_NEWS_FORMAT :{STRING} - {RAW_STRING}
|
||||
|
||||
STR_NEWS_MESSAGE_CAPTION :{WHITE}Message
|
||||
STR_NEWS_CUSTOM_ITEM :{BIG_FONT}{BLACK}{RAW_STRING}
|
||||
|
@ -934,14 +934,14 @@ STR_NEWS_SHOW_VEHICLE_GROUP_TOOLTIP :{BLACK}Open the
|
|||
STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO_LIST :{WHITE}{STATION} no longer accepts: {CARGO_LIST}
|
||||
STR_NEWS_STATION_NOW_ACCEPTS_CARGO_LIST :{WHITE}{STATION} now accepts: {CARGO_LIST}
|
||||
|
||||
STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED :{BIG_FONT}{BLACK}Offer of subsidy expired:{}{}{STRING} from {STRING2} to {STRING2} will now not attract a subsidy
|
||||
STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE :{BIG_FONT}{BLACK}Subsidy withdrawn:{}{}{STRING} service from {STRING2} to {STRING2} is no longer subsidised
|
||||
STR_NEWS_SERVICE_SUBSIDY_OFFERED :{BIG_FONT}{BLACK}Service subsidy offered:{}{}First {STRING} from {STRING2} to {STRING2} will attract a {UNITS_YEARS_OR_MINUTES} subsidy from the local authority!
|
||||
STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED :{BIG_FONT}{BLACK}Offer of subsidy expired:{}{}{STRING} from {STRING1} to {STRING1} will now not attract a subsidy
|
||||
STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE :{BIG_FONT}{BLACK}Subsidy withdrawn:{}{}{STRING} service from {STRING1} to {STRING1} is no longer subsidised
|
||||
STR_NEWS_SERVICE_SUBSIDY_OFFERED :{BIG_FONT}{BLACK}Service subsidy offered:{}{}First {STRING} from {STRING1} to {STRING1} will attract a {UNITS_YEARS_OR_MINUTES} subsidy from the local authority!
|
||||
###length 4
|
||||
STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF :{BIG_FONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} from {STRING2} to {STRING2} will pay 50% extra for the next {UNITS_YEARS_OR_MINUTES}!
|
||||
STR_NEWS_SERVICE_SUBSIDY_AWARDED_DOUBLE :{BIG_FONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} from {STRING2} to {STRING2} will pay double rates for the next {UNITS_YEARS_OR_MINUTES}!
|
||||
STR_NEWS_SERVICE_SUBSIDY_AWARDED_TRIPLE :{BIG_FONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} from {STRING2} to {STRING2} will pay triple rates for the next {UNITS_YEARS_OR_MINUTES}!
|
||||
STR_NEWS_SERVICE_SUBSIDY_AWARDED_QUADRUPLE :{BIG_FONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} from {STRING2} to {STRING2} will pay quadruple rates for the next {UNITS_YEARS_OR_MINUTES}!
|
||||
STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF :{BIG_FONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} from {STRING1} to {STRING1} will pay 50% extra for the next {UNITS_YEARS_OR_MINUTES}!
|
||||
STR_NEWS_SERVICE_SUBSIDY_AWARDED_DOUBLE :{BIG_FONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} from {STRING1} to {STRING1} will pay double rates for the next {UNITS_YEARS_OR_MINUTES}!
|
||||
STR_NEWS_SERVICE_SUBSIDY_AWARDED_TRIPLE :{BIG_FONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} from {STRING1} to {STRING1} will pay triple rates for the next {UNITS_YEARS_OR_MINUTES}!
|
||||
STR_NEWS_SERVICE_SUBSIDY_AWARDED_QUADRUPLE :{BIG_FONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} from {STRING1} to {STRING1} will pay quadruple rates for the next {UNITS_YEARS_OR_MINUTES}!
|
||||
|
||||
STR_NEWS_ROAD_REBUILDING_MONTHS :{BIG_FONT}{BLACK}Traffic chaos in {TOWN}!{}{}Road rebuilding programme funded by {RAW_STRING} brings 6 months of misery to motorists!
|
||||
STR_NEWS_ROAD_REBUILDING_MINUTES :{BIG_FONT}{BLACK}Traffic chaos in {TOWN}!{}{}Road rebuilding programme funded by {RAW_STRING} brings 6 minutes of misery to motorists!
|
||||
|
@ -3784,10 +3784,10 @@ STR_GOAL_QUESTION_BUTTON_CLOSE :Close
|
|||
# Subsidies window
|
||||
STR_SUBSIDIES_CAPTION :{WHITE}Subsidies
|
||||
STR_SUBSIDIES_OFFERED_TITLE :{BLACK}Subsidies on offer for services taking:
|
||||
STR_SUBSIDIES_OFFERED_FROM_TO :{ORANGE}{STRING} from {STRING2} to {STRING2}{YELLOW} ({STRING1})
|
||||
STR_SUBSIDIES_OFFERED_FROM_TO :{ORANGE}{STRING} from {STRING1} to {STRING1}{YELLOW} ({STRING1})
|
||||
STR_SUBSIDIES_NONE :{ORANGE}- None -
|
||||
STR_SUBSIDIES_SUBSIDISED_TITLE :{BLACK}Services already subsidised:
|
||||
STR_SUBSIDIES_SUBSIDISED_FROM_TO :{ORANGE}{STRING} from {STRING2} to {STRING2}{YELLOW} ({COMPANY}{YELLOW}, {STRING1})
|
||||
STR_SUBSIDIES_SUBSIDISED_FROM_TO :{ORANGE}{STRING} from {STRING1} to {STRING1}{YELLOW} ({COMPANY}{YELLOW}, {STRING1})
|
||||
STR_SUBSIDIES_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Click on service to centre main view on industry/town. Ctrl+Click to open a new viewport on industry/town location
|
||||
STR_SUBSIDIES_OFFERED_EXPIRY_DATE :by {DATE_SHORT}
|
||||
STR_SUBSIDIES_OFFERED_EXPIRY_TIME :within {UNITS_MONTHS_OR_MINUTES}
|
||||
|
|
|
@ -15,11 +15,11 @@
|
|||
#include "station_type.h"
|
||||
#include "industry_type.h"
|
||||
|
||||
void AddNewsItem(StringID string, NewsType type, NewsStyle style, NewsFlags flags, NewsReference ref1 = {}, NewsReference ref2 = {}, std::unique_ptr<NewsAllocatedData> &&data = nullptr, AdviceType advice_type = AdviceType::Invalid);
|
||||
void AddNewsItem(EncodedString &&headline, NewsType type, NewsStyle style, NewsFlags flags, NewsReference ref1 = {}, NewsReference ref2 = {}, std::unique_ptr<NewsAllocatedData> &&data = nullptr, AdviceType advice_type = AdviceType::Invalid);
|
||||
|
||||
inline void AddCompanyNewsItem(StringID string, std::unique_ptr<CompanyNewsInformation> cni)
|
||||
inline void AddCompanyNewsItem(EncodedString &&headline, std::unique_ptr<CompanyNewsInformation> cni)
|
||||
{
|
||||
AddNewsItem(string, NewsType::CompanyInfo, NewsStyle::Company, {}, {}, {}, std::move(cni));
|
||||
AddNewsItem(std::move(headline), NewsType::CompanyInfo, NewsStyle::Company, {}, {}, {}, std::move(cni));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -27,9 +27,9 @@ inline void AddCompanyNewsItem(StringID string, std::unique_ptr<CompanyNewsInfor
|
|||
*
|
||||
* @warning The DParams may not reference the vehicle due to autoreplace stuff. See AddVehicleAdviceNewsItem for how that can be done.
|
||||
*/
|
||||
inline void AddVehicleNewsItem(StringID string, NewsType type, VehicleID vehicle, StationID station = StationID::Invalid())
|
||||
inline void AddVehicleNewsItem(EncodedString &&headline, NewsType type, VehicleID vehicle, StationID station = StationID::Invalid())
|
||||
{
|
||||
AddNewsItem(string, type, NewsStyle::Thin, {NewsFlag::NoTransparency, NewsFlag::Shaded}, vehicle, station == StationID::Invalid() ? NewsReference{} : station);
|
||||
AddNewsItem(std::move(headline), type, NewsStyle::Thin, {NewsFlag::NoTransparency, NewsFlag::Shaded}, vehicle, station == StationID::Invalid() ? NewsReference{} : station);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -37,19 +37,19 @@ inline void AddVehicleNewsItem(StringID string, NewsType type, VehicleID vehicle
|
|||
*
|
||||
* @warning DParam 0 must reference the vehicle!
|
||||
*/
|
||||
inline void AddVehicleAdviceNewsItem(AdviceType advice_type, StringID string, VehicleID vehicle)
|
||||
inline void AddVehicleAdviceNewsItem(AdviceType advice_type, EncodedString &&headline, VehicleID vehicle)
|
||||
{
|
||||
AddNewsItem(string, NewsType::Advice, NewsStyle::Small, {NewsFlag::InColour, NewsFlag::VehicleParam0}, vehicle, {}, nullptr, advice_type);
|
||||
AddNewsItem(std::move(headline), NewsType::Advice, NewsStyle::Small, {NewsFlag::InColour, NewsFlag::VehicleParam0}, vehicle, {}, nullptr, advice_type);
|
||||
}
|
||||
|
||||
inline void AddTileNewsItem(StringID string, NewsType type, TileIndex tile, StationID station = StationID::Invalid())
|
||||
inline void AddTileNewsItem(EncodedString &&headline, NewsType type, TileIndex tile, StationID station = StationID::Invalid())
|
||||
{
|
||||
AddNewsItem(string, type, NewsStyle::Thin, {NewsFlag::NoTransparency, NewsFlag::Shaded}, tile, station == StationID::Invalid() ? NewsReference{} : station);
|
||||
AddNewsItem(std::move(headline), type, NewsStyle::Thin, {NewsFlag::NoTransparency, NewsFlag::Shaded}, tile, station == StationID::Invalid() ? NewsReference{} : station);
|
||||
}
|
||||
|
||||
inline void AddIndustryNewsItem(StringID string, NewsType type, IndustryID industry)
|
||||
inline void AddIndustryNewsItem(EncodedString &&headline, NewsType type, IndustryID industry)
|
||||
{
|
||||
AddNewsItem(string, type, NewsStyle::Thin, {NewsFlag::NoTransparency, NewsFlag::Shaded}, industry, {});
|
||||
AddNewsItem(std::move(headline), type, NewsStyle::Thin, {NewsFlag::NoTransparency, NewsFlag::Shaded}, industry, {});
|
||||
}
|
||||
|
||||
void NewsLoop();
|
||||
|
|
|
@ -365,9 +365,6 @@ struct NewsWindow : Window {
|
|||
|
||||
this->CreateNestedTree();
|
||||
|
||||
/* For company news with a face we have a separate headline in param[0] */
|
||||
if (&desc == &_company_news_desc) this->GetWidget<NWidgetCore>(WID_N_TITLE)->SetString(static_cast<StringID>(std::get<uint64_t>(this->ni->params[0])));
|
||||
|
||||
NWidgetCore *nwid = this->GetWidget<NWidgetCore>(WID_N_SHOW_GROUP);
|
||||
if (std::holds_alternative<VehicleID>(ni->ref1) && nwid != nullptr) {
|
||||
const Vehicle *v = Vehicle::Get(std::get<VehicleID>(ni->ref1));
|
||||
|
@ -446,12 +443,8 @@ struct NewsWindow : Window {
|
|||
break;
|
||||
|
||||
case WID_N_MESSAGE:
|
||||
CopyInDParam(this->ni->params);
|
||||
str = GetString(this->ni->string_id);
|
||||
break;
|
||||
|
||||
case WID_N_COMPANY_MSG:
|
||||
str = GetString(this->GetCompanyMessageString());
|
||||
str = this->ni->headline.GetDecodedString();
|
||||
break;
|
||||
|
||||
case WID_N_VEH_NAME:
|
||||
|
@ -499,7 +492,12 @@ struct NewsWindow : Window {
|
|||
|
||||
void SetStringParameters(WidgetID widget) const override
|
||||
{
|
||||
if (widget == WID_N_DATE) SetDParam(0, this->ni->date);
|
||||
if (widget == WID_N_DATE) {
|
||||
SetDParam(0, this->ni->date);
|
||||
} else if (widget == WID_N_TITLE) {
|
||||
const CompanyNewsInformation *cni = static_cast<const CompanyNewsInformation*>(this->ni->data.get());
|
||||
SetDParam(0, cni->title);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawWidget(const Rect &r, WidgetID widget) const override
|
||||
|
@ -514,8 +512,8 @@ struct NewsWindow : Window {
|
|||
break;
|
||||
|
||||
case WID_N_MESSAGE:
|
||||
CopyInDParam(this->ni->params);
|
||||
DrawStringMultiLine(r.left, r.right, r.top, r.bottom, this->ni->string_id, TC_FROMSTRING, SA_CENTER);
|
||||
case WID_N_COMPANY_MSG:
|
||||
DrawStringMultiLine(r.left, r.right, r.top, r.bottom, this->ni->headline.GetDecodedString(), TC_FROMSTRING, SA_CENTER);
|
||||
break;
|
||||
|
||||
case WID_N_MGR_FACE: {
|
||||
|
@ -530,9 +528,6 @@ struct NewsWindow : Window {
|
|||
DrawStringMultiLine(r.left, r.right, r.top, r.bottom, STR_JUST_RAW_STRING, TC_FROMSTRING, SA_CENTER);
|
||||
break;
|
||||
}
|
||||
case WID_N_COMPANY_MSG:
|
||||
DrawStringMultiLine(r.left, r.right, r.top, r.bottom, this->GetCompanyMessageString(), TC_FROMSTRING, SA_CENTER);
|
||||
break;
|
||||
|
||||
case WID_N_VEH_BKGND:
|
||||
GfxFillRect(r.left, r.top, r.right, r.bottom, PC_GREY);
|
||||
|
@ -671,13 +666,6 @@ private:
|
|||
AddDirtyBlock(this->left, mintop, this->left + this->width, maxtop + this->height);
|
||||
}
|
||||
|
||||
StringID GetCompanyMessageString() const
|
||||
{
|
||||
/* Company news with a face have a separate headline, so the normal message is shifted by two params */
|
||||
CopyInDParam(std::span(this->ni->params.data() + 2, this->ni->params.size() - 2));
|
||||
return std::get<uint64_t>(this->ni->params[1]);
|
||||
}
|
||||
|
||||
StringID GetNewVehicleMessageString(WidgetID widget) const
|
||||
{
|
||||
assert(std::holds_alternative<EngineID>(ni->ref1));
|
||||
|
@ -875,12 +863,22 @@ static std::list<NewsItem>::iterator DeleteNewsItem(std::list<NewsItem>::iterato
|
|||
*
|
||||
* @see NewsSubtype
|
||||
*/
|
||||
NewsItem::NewsItem(StringID string_id, NewsType type, NewsStyle style, NewsFlags flags, NewsReference ref1, NewsReference ref2, std::unique_ptr<NewsAllocatedData> &&data, AdviceType advice_type) :
|
||||
string_id(string_id), date(TimerGameCalendar::date), economy_date(TimerGameEconomy::date), type(type), advice_type(advice_type), style(style), flags(flags), ref1(ref1), ref2(ref2), data(std::move(data))
|
||||
NewsItem::NewsItem(EncodedString &&headline, NewsType type, NewsStyle style, NewsFlags flags, NewsReference ref1, NewsReference ref2, std::unique_ptr<NewsAllocatedData> &&data, AdviceType advice_type) :
|
||||
headline(std::move(headline)), date(TimerGameCalendar::date), economy_date(TimerGameEconomy::date), type(type), advice_type(advice_type), style(style), flags(flags), ref1(ref1), ref2(ref2), data(std::move(data))
|
||||
{
|
||||
/* show this news message in colour? */
|
||||
if (TimerGameCalendar::year >= _settings_client.gui.coloured_news_year) this->flags.Set(NewsFlag::InColour);
|
||||
CopyOutDParam(this->params, 10);
|
||||
}
|
||||
|
||||
std::string NewsItem::GetStatusText() const
|
||||
{
|
||||
if (this->data != nullptr) {
|
||||
/* CompanyNewsInformation is the only type of additional data used. */
|
||||
const CompanyNewsInformation &cni = *static_cast<const CompanyNewsInformation*>(this->data.get());
|
||||
return GetString(STR_MESSAGE_NEWS_FORMAT, cni.title, this->headline.GetDecodedString());
|
||||
}
|
||||
|
||||
return this->headline.GetDecodedString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -895,12 +893,12 @@ NewsItem::NewsItem(StringID string_id, NewsType type, NewsStyle style, NewsFlags
|
|||
*
|
||||
* @see NewsSubtype
|
||||
*/
|
||||
void AddNewsItem(StringID string, NewsType type, NewsStyle style, NewsFlags flags, NewsReference ref1, NewsReference ref2, std::unique_ptr<NewsAllocatedData> &&data, AdviceType advice_type)
|
||||
void AddNewsItem(EncodedString &&headline, NewsType type, NewsStyle style, NewsFlags flags, NewsReference ref1, NewsReference ref2, std::unique_ptr<NewsAllocatedData> &&data, AdviceType advice_type)
|
||||
{
|
||||
if (_game_mode == GM_MENU) return;
|
||||
|
||||
/* Create new news item node */
|
||||
_news.emplace_front(string, type, style, flags, ref1, ref2, std::move(data), advice_type);
|
||||
_news.emplace_front(std::move(headline), type, style, flags, ref1, ref2, std::move(data), advice_type);
|
||||
|
||||
/* Keep the number of stored news items to a manageable number */
|
||||
if (std::size(_news) > MAX_NEWS_AMOUNT) {
|
||||
|
@ -963,8 +961,7 @@ CommandCost CmdCustomNewsItem(DoCommandFlags flags, NewsType type, CompanyID com
|
|||
if (company != INVALID_OWNER && company != _local_company) return CommandCost();
|
||||
|
||||
if (flags.Test(DoCommandFlag::Execute)) {
|
||||
SetDParamStr(0, text);
|
||||
AddNewsItem(STR_NEWS_CUSTOM_ITEM, type, NewsStyle::Normal, {}, reference, {});
|
||||
AddNewsItem(GetEncodedString(STR_NEWS_CUSTOM_ITEM, text), type, NewsStyle::Normal, {}, reference, {});
|
||||
}
|
||||
|
||||
return CommandCost();
|
||||
|
@ -1084,7 +1081,7 @@ void ChangeVehicleNews(VehicleID from_index, VehicleID to_index)
|
|||
for (auto &ni : _news) {
|
||||
ChangeObject(ni.ref1, from_index, to_index);
|
||||
ChangeObject(ni.ref2, from_index, to_index);
|
||||
if (ni.flags.Test(NewsFlag::VehicleParam0) && std::get<uint64_t>(ni.params[0]) == from_index) ni.params[0] = to_index.base();
|
||||
if (ni.flags.Test(NewsFlag::VehicleParam0) && IsReferenceObject(ni.ref1, to_index)) ni.headline = ni.headline.ReplaceParam(0, to_index.base());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1186,10 +1183,8 @@ void ShowLastNewsMessage()
|
|||
*/
|
||||
static void DrawNewsString(uint left, uint right, int y, TextColour colour, const NewsItem *ni)
|
||||
{
|
||||
CopyInDParam(ni->params);
|
||||
|
||||
/* Get the string, replaces newlines with spaces and remove control codes from the string. */
|
||||
std::string message = StrMakeValid(GetString(ni->string_id), SVS_REPLACE_TAB_CR_NL_WITH_SPACE);
|
||||
std::string message = StrMakeValid(ni->GetStatusText(), SVS_REPLACE_TAB_CR_NL_WITH_SPACE);
|
||||
|
||||
/* Truncate and show string; postfixed by '...' if necessary */
|
||||
DrawString(left, right, y, message, colour);
|
||||
|
|
|
@ -134,7 +134,7 @@ struct NewsAllocatedData {
|
|||
|
||||
/** Information about a single item of news. */
|
||||
struct NewsItem {
|
||||
StringID string_id; ///< Message text
|
||||
EncodedString headline; ///< Headline of news.
|
||||
TimerGameCalendar::Date date; ///< Calendar date to show for the news
|
||||
TimerGameEconomy::Date economy_date; ///< Economy date of the news item, never shown but used to calculate age
|
||||
NewsType type; ///< Type of the news
|
||||
|
@ -147,9 +147,9 @@ struct NewsItem {
|
|||
|
||||
std::unique_ptr<NewsAllocatedData> data; ///< Custom data for the news item that will be deallocated (deleted) when the news item has reached its end.
|
||||
|
||||
std::vector<StringParameterData> params; ///< Parameters for string resolving.
|
||||
NewsItem(EncodedString &&headline, NewsType type, NewsStyle style, NewsFlags flags, NewsReference ref1, NewsReference ref2, std::unique_ptr<NewsAllocatedData> &&data, AdviceType advice_type);
|
||||
|
||||
NewsItem(StringID string_id, NewsType type, NewsStyle style, NewsFlags flags, NewsReference ref1, NewsReference ref2, std::unique_ptr<NewsAllocatedData> &&data, AdviceType advice_type);
|
||||
std::string GetStatusText() const;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -163,10 +163,11 @@ struct CompanyNewsInformation : NewsAllocatedData {
|
|||
std::string president_name; ///< The name of the president
|
||||
std::string other_company_name; ///< The name of the company taking over this one
|
||||
|
||||
StringID title;
|
||||
uint32_t face; ///< The face of the president
|
||||
Colours colour; ///< The colour related to the company
|
||||
|
||||
CompanyNewsInformation(const struct Company *c, const struct Company *other = nullptr);
|
||||
CompanyNewsInformation(StringID title, const struct Company *c, const struct Company *other = nullptr);
|
||||
};
|
||||
|
||||
using NewsContainer = std::list<NewsItem>; ///< Container type for storing news items.
|
||||
|
|
|
@ -1756,8 +1756,7 @@ void CheckOrders(const Vehicle *v)
|
|||
/* We don't have a problem */
|
||||
if (message == INVALID_STRING_ID) return;
|
||||
|
||||
SetDParam(0, v->index);
|
||||
AddVehicleAdviceNewsItem(AdviceType::Order, message, v->index);
|
||||
AddVehicleAdviceNewsItem(AdviceType::Order, GetEncodedString(message, v->index), v->index);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -548,15 +548,12 @@ static void RoadVehCrash(RoadVehicle *v)
|
|||
AI::NewEvent(v->owner, new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_RV_LEVEL_CROSSING, victims));
|
||||
Game::NewEvent(new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_RV_LEVEL_CROSSING, victims));
|
||||
|
||||
SetDParam(0, victims);
|
||||
StringID newsitem = (victims == 1) ? STR_NEWS_ROAD_VEHICLE_CRASH_DRIVER : STR_NEWS_ROAD_VEHICLE_CRASH;
|
||||
NewsType newstype = NewsType::Accident;
|
||||
EncodedString headline = (victims == 1)
|
||||
? GetEncodedString(STR_NEWS_ROAD_VEHICLE_CRASH_DRIVER)
|
||||
: GetEncodedString(STR_NEWS_ROAD_VEHICLE_CRASH, victims);
|
||||
NewsType newstype = v->owner == _local_company ? NewsType::Accident : NewsType::AccidentOther;
|
||||
|
||||
if (v->owner != _local_company) {
|
||||
newstype = NewsType::AccidentOther;
|
||||
}
|
||||
|
||||
AddTileNewsItem(newsitem, newstype, v->tile);
|
||||
AddTileNewsItem(std::move(headline), newstype, v->tile);
|
||||
|
||||
ModifyStationRatingAround(v->tile, v->owner, -160, 22);
|
||||
if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_12_EXPLOSION, v);
|
||||
|
@ -689,9 +686,8 @@ static void RoadVehArrivesAt(const RoadVehicle *v, Station *st)
|
|||
/* Check if station was ever visited before */
|
||||
if (!(st->had_vehicle_of_type & HVOT_BUS)) {
|
||||
st->had_vehicle_of_type |= HVOT_BUS;
|
||||
SetDParam(0, st->index);
|
||||
AddVehicleNewsItem(
|
||||
RoadTypeIsRoad(v->roadtype) ? STR_NEWS_FIRST_BUS_ARRIVAL : STR_NEWS_FIRST_PASSENGER_TRAM_ARRIVAL,
|
||||
GetEncodedString(RoadTypeIsRoad(v->roadtype) ? STR_NEWS_FIRST_BUS_ARRIVAL : STR_NEWS_FIRST_PASSENGER_TRAM_ARRIVAL, st->index),
|
||||
(v->owner == _local_company) ? NewsType::ArrivalCompany : NewsType::ArrivalOther,
|
||||
v->index,
|
||||
st->index
|
||||
|
@ -703,9 +699,8 @@ static void RoadVehArrivesAt(const RoadVehicle *v, Station *st)
|
|||
/* Check if station was ever visited before */
|
||||
if (!(st->had_vehicle_of_type & HVOT_TRUCK)) {
|
||||
st->had_vehicle_of_type |= HVOT_TRUCK;
|
||||
SetDParam(0, st->index);
|
||||
AddVehicleNewsItem(
|
||||
RoadTypeIsRoad(v->roadtype) ? STR_NEWS_FIRST_TRUCK_ARRIVAL : STR_NEWS_FIRST_CARGO_TRAM_ARRIVAL,
|
||||
GetEncodedString(RoadTypeIsRoad(v->roadtype) ? STR_NEWS_FIRST_TRUCK_ARRIVAL : STR_NEWS_FIRST_CARGO_TRAM_ARRIVAL, st->index),
|
||||
(v->owner == _local_company) ? NewsType::ArrivalCompany : NewsType::ArrivalOther,
|
||||
v->index,
|
||||
st->index
|
||||
|
|
|
@ -471,9 +471,8 @@ static void ShipArrivesAt(const Vehicle *v, Station *st)
|
|||
if (!(st->had_vehicle_of_type & HVOT_SHIP)) {
|
||||
st->had_vehicle_of_type |= HVOT_SHIP;
|
||||
|
||||
SetDParam(0, st->index);
|
||||
AddVehicleNewsItem(
|
||||
STR_NEWS_FIRST_SHIP_ARRIVAL,
|
||||
GetEncodedString(STR_NEWS_FIRST_SHIP_ARRIVAL, st->index),
|
||||
(v->owner == _local_company) ? NewsType::ArrivalCompany : NewsType::ArrivalOther,
|
||||
v->index,
|
||||
st->index
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
#include "company_type.h"
|
||||
#include "industry_type.h"
|
||||
#include "news_type.h"
|
||||
#include "strings_type.h"
|
||||
#include "town_type.h"
|
||||
|
||||
/** Types of cargo source and destination */
|
||||
|
@ -48,6 +50,9 @@ public:
|
|||
|
||||
constexpr bool IsValid() const noexcept { return this->id != Source::Invalid; }
|
||||
auto operator<=>(const Source &source) const = default;
|
||||
|
||||
NewsReference GetNewsReference() const;
|
||||
StringID GetFormat() const;
|
||||
};
|
||||
|
||||
#endif /* SOURCE_TYPE_H */
|
||||
|
|
|
@ -529,10 +529,8 @@ CargoTypes GetEmptyMask(const Station *st)
|
|||
*/
|
||||
static void ShowRejectOrAcceptNews(const Station *st, CargoTypes cargoes, bool reject)
|
||||
{
|
||||
SetDParam(0, st->index);
|
||||
SetDParam(1, cargoes);
|
||||
StringID msg = reject ? STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO_LIST : STR_NEWS_STATION_NOW_ACCEPTS_CARGO_LIST;
|
||||
AddNewsItem(msg, NewsType::Acceptance, NewsStyle::Small, NewsFlag::InColour, st->index);
|
||||
AddNewsItem(GetEncodedString(msg, st->index, cargoes), NewsType::Acceptance, NewsStyle::Small, NewsFlag::InColour, st->index);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -38,10 +38,8 @@
|
|||
|
||||
static bool DrawScrollingStatusText(const NewsItem *ni, int scroll_pos, int left, int right, int top, int bottom)
|
||||
{
|
||||
CopyInDParam(ni->params);
|
||||
|
||||
/* Replace newlines and the likes with spaces. */
|
||||
std::string message = StrMakeValid(GetString(ni->string_id), SVS_REPLACE_TAB_CR_NL_WITH_SPACE);
|
||||
std::string message = StrMakeValid(ni->GetStatusText(), SVS_REPLACE_TAB_CR_NL_WITH_SPACE);
|
||||
|
||||
DrawPixelInfo tmp_dpi;
|
||||
if (!FillDrawPixelInfo(&tmp_dpi, left, top, right - left, bottom)) return true;
|
||||
|
@ -145,7 +143,7 @@ struct StatusBarWindow : Window {
|
|||
} else if (_pause_mode.Any()) {
|
||||
StringID msg = _pause_mode.Test(PauseMode::LinkGraph) ? STR_STATUSBAR_PAUSED_LINK_GRAPH : STR_STATUSBAR_PAUSED;
|
||||
DrawString(tr, msg, TC_FROMSTRING, SA_HOR_CENTER);
|
||||
} else if (this->ticker_scroll < TICKER_STOP && GetStatusbarNews() != nullptr && GetStatusbarNews()->string_id != 0) {
|
||||
} else if (this->ticker_scroll < TICKER_STOP && GetStatusbarNews() != nullptr && !GetStatusbarNews()->headline.empty()) {
|
||||
/* Draw the scrolling news text */
|
||||
if (!DrawScrollingStatusText(GetStatusbarNews(), ScaleGUITrad(this->ticker_scroll), tr.left, tr.right, tr.top, tr.bottom)) {
|
||||
InvalidateWindowData(WC_STATUS_BAR, 0, SBI_NEWS_DELETED);
|
||||
|
|
|
@ -146,6 +146,75 @@ EncodedString GetEncodedStringWithArgs(StringID str, std::span<const StringParam
|
|||
return EncodedString{std::move(result)};
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace a parameter of this EncodedString.
|
||||
* @note If the string cannot be decoded for some reason, an empty EncodedString will be returned instead.
|
||||
* @param param Index of parameter to replace.
|
||||
* @param data New data for parameter.
|
||||
* @returns a new EncodedString with the parameter replaced.
|
||||
*/
|
||||
EncodedString EncodedString::ReplaceParam(size_t param, StringParameter &&data) const
|
||||
{
|
||||
if (this->empty()) return {};
|
||||
|
||||
std::vector<StringParameter> params;
|
||||
|
||||
/* We need char * for std::from_chars. Iterate the underlying data, as string's own iterators may interfere. */
|
||||
const char *p = this->string.data();
|
||||
const char *e = this->string.data() + this->string.length();
|
||||
|
||||
char32_t c = Utf8Consume(p);
|
||||
if (c != SCC_ENCODED_INTERNAL) return {};
|
||||
|
||||
StringID str;
|
||||
auto result = std::from_chars(p, e, str, 16);
|
||||
if (result.ec != std::errc()) return {};
|
||||
if (result.ptr != e && *result.ptr != SCC_RECORD_SEPARATOR) return {};
|
||||
p = result.ptr;
|
||||
|
||||
while (p != e) {
|
||||
auto s = ++p;
|
||||
|
||||
/* Find end of the parameter. */
|
||||
for (; p != e && *p != SCC_RECORD_SEPARATOR; ++p) {}
|
||||
|
||||
if (s == p) {
|
||||
/* This is an empty parameter. */
|
||||
params.emplace_back(std::monostate{});
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Get the parameter type. */
|
||||
char32_t parameter_type;
|
||||
size_t len = Utf8Decode(¶meter_type, s);
|
||||
s += len;
|
||||
|
||||
switch (parameter_type) {
|
||||
case SCC_ENCODED_NUMERIC: {
|
||||
uint64_t value;
|
||||
result = std::from_chars(s, p, value, 16);
|
||||
if (result.ec != std::errc() || result.ptr != p) return {};
|
||||
params.emplace_back(value);
|
||||
break;
|
||||
}
|
||||
|
||||
case SCC_ENCODED_STRING: {
|
||||
params.emplace_back(std::string(s, p));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
/* Unknown parameter, make it blank. */
|
||||
params.emplace_back(std::monostate{});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (param >= std::size(params)) return {};
|
||||
params[param] = data;
|
||||
return GetEncodedStringWithArgs(str, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the encoded string.
|
||||
* @returns Decoded raw string.
|
||||
|
|
|
@ -102,6 +102,7 @@ public:
|
|||
auto operator<=>(const EncodedString &) const = default;
|
||||
|
||||
std::string GetDecodedString() const;
|
||||
EncodedString ReplaceParam(size_t param, StringParameter &&value) const;
|
||||
|
||||
inline void clear() { this->string.clear(); }
|
||||
inline bool empty() const { return this->string.empty(); }
|
||||
|
|
102
src/subsidy.cpp
102
src/subsidy.cpp
|
@ -36,6 +36,32 @@
|
|||
SubsidyPool _subsidy_pool("Subsidy"); ///< Pool for the subsidies.
|
||||
INSTANTIATE_POOL_METHODS(Subsidy)
|
||||
|
||||
/**
|
||||
* Get the NewsReference for a subsidy Source.
|
||||
* @returns NewsReference.
|
||||
*/
|
||||
NewsReference Source::GetNewsReference() const
|
||||
{
|
||||
switch (this->type) {
|
||||
case SourceType::Industry: return static_cast<IndustryID>(this->id);
|
||||
case SourceType::Town: return static_cast<TownID>(this->id);
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the format string for a subsidy Source.
|
||||
* @returns The format string.
|
||||
*/
|
||||
StringID Source::GetFormat() const
|
||||
{
|
||||
switch (this->type) {
|
||||
case SourceType::Industry: return STR_INDUSTRY_NAME;
|
||||
case SourceType::Town: return STR_TOWN_NAME;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks subsidy as awarded, creates news and AI event
|
||||
* @param company awarded company
|
||||
|
@ -50,70 +76,15 @@ void Subsidy::AwardTo(CompanyID company)
|
|||
std::string company_name = GetString(STR_COMPANY_NAME, company);
|
||||
|
||||
/* Add a news item */
|
||||
std::pair<NewsReference, NewsReference> references = SetupSubsidyDecodeParam(this, SubsidyDecodeParamType::NewsAwarded, 1);
|
||||
|
||||
SetDParamStr(0, company_name);
|
||||
AddNewsItem(
|
||||
STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF + _settings_game.difficulty.subsidy_multiplier,
|
||||
NewsType::Subsidies, NewsStyle::Normal, {},
|
||||
references.first, references.second
|
||||
);
|
||||
const CargoSpec *cs = CargoSpec::Get(this->cargo_type);
|
||||
EncodedString headline = GetEncodedString(STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF + _settings_game.difficulty.subsidy_multiplier, std::move(company_name), cs->name, this->src.GetFormat(), this->src.id, this->dst.GetFormat(), this->dst.id, _settings_game.difficulty.subsidy_duration);
|
||||
AddNewsItem(std::move(headline), NewsType::Subsidies, NewsStyle::Normal, {}, this->src.GetNewsReference(), this->dst.GetNewsReference());
|
||||
AI::BroadcastNewEvent(new ScriptEventSubsidyAwarded(this->index));
|
||||
Game::NewEvent(new ScriptEventSubsidyAwarded(this->index));
|
||||
|
||||
InvalidateWindowData(WC_SUBSIDIES_LIST, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the string parameters for printing the subsidy at the screen, and compute the news reference for the subsidy.
|
||||
* @param s %Subsidy being printed.
|
||||
* @param mode Type of subsidy news message to decide on parameter format.
|
||||
* @param parameter_offset The location/index in the String DParams to start decoding the subsidy's parameters. Defaults to 0.
|
||||
* @return Reference of the subsidy in the news system.
|
||||
*/
|
||||
std::pair<NewsReference, NewsReference> SetupSubsidyDecodeParam(const Subsidy *s, SubsidyDecodeParamType mode, uint parameter_offset)
|
||||
{
|
||||
NewsReference reference1{};
|
||||
NewsReference reference2{};
|
||||
|
||||
/* Always use the plural form of the cargo name - trying to decide between plural or singular causes issues for translations */
|
||||
const CargoSpec *cs = CargoSpec::Get(s->cargo_type);
|
||||
SetDParam(parameter_offset, cs->name);
|
||||
|
||||
switch (s->src.type) {
|
||||
case SourceType::Industry:
|
||||
reference1 = static_cast<IndustryID>(s->src.id);
|
||||
SetDParam(parameter_offset + 1, STR_INDUSTRY_NAME);
|
||||
break;
|
||||
case SourceType::Town:
|
||||
reference1 = static_cast<TownID>(s->src.id);
|
||||
SetDParam(parameter_offset + 1, STR_TOWN_NAME);
|
||||
break;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
SetDParam(parameter_offset + 2, s->src.id);
|
||||
|
||||
switch (s->dst.type) {
|
||||
case SourceType::Industry:
|
||||
reference2 = static_cast<IndustryID>(s->dst.id);
|
||||
SetDParam(parameter_offset + 4, STR_INDUSTRY_NAME);
|
||||
break;
|
||||
case SourceType::Town:
|
||||
reference2 = static_cast<TownID>(s->dst.id);
|
||||
SetDParam(parameter_offset + 4, STR_TOWN_NAME);
|
||||
break;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
SetDParam(parameter_offset + 5, s->dst.id);
|
||||
|
||||
/* If the subsidy is being offered or awarded, the news item mentions the subsidy duration. */
|
||||
if (mode == SubsidyDecodeParamType::NewsOffered || mode == SubsidyDecodeParamType::NewsAwarded) {
|
||||
SetDParam(parameter_offset + 7, _settings_game.difficulty.subsidy_duration);
|
||||
}
|
||||
|
||||
return {reference1, reference2};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a flag indicating that given town/industry is part of subsidised route.
|
||||
* @param source actual source
|
||||
|
@ -203,8 +174,9 @@ void CreateSubsidy(CargoType cargo_type, Source src, Source dst)
|
|||
{
|
||||
Subsidy *s = new Subsidy(cargo_type, src, dst, SUBSIDY_OFFER_MONTHS);
|
||||
|
||||
std::pair<NewsReference, NewsReference> references = SetupSubsidyDecodeParam(s, SubsidyDecodeParamType::NewsOffered);
|
||||
AddNewsItem(STR_NEWS_SERVICE_SUBSIDY_OFFERED, NewsType::Subsidies, NewsStyle::Normal, {}, references.first, references.second);
|
||||
const CargoSpec *cs = CargoSpec::Get(s->cargo_type);
|
||||
EncodedString headline = GetEncodedString(STR_NEWS_SERVICE_SUBSIDY_OFFERED, cs->name, s->src.GetFormat(), s->src.id, s->dst.GetFormat(), s->dst.id, _settings_game.difficulty.subsidy_duration);
|
||||
AddNewsItem(std::move(headline), NewsType::Subsidies, NewsStyle::Normal, {}, s->src.GetNewsReference(), s->dst.GetNewsReference());
|
||||
SetPartOfSubsidyFlag(s->src, POS_SRC);
|
||||
SetPartOfSubsidyFlag(s->dst, POS_DST);
|
||||
AI::BroadcastNewEvent(new ScriptEventSubsidyOffer(s->index));
|
||||
|
@ -457,14 +429,16 @@ static IntervalTimer<TimerGameEconomy> _economy_subsidies_monthly({TimerGameEcon
|
|||
for (Subsidy *s : Subsidy::Iterate()) {
|
||||
if (--s->remaining == 0) {
|
||||
if (!s->IsAwarded()) {
|
||||
std::pair<NewsReference, NewsReference> references = SetupSubsidyDecodeParam(s, SubsidyDecodeParamType::NewsWithdrawn);
|
||||
AddNewsItem(STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED, NewsType::Subsidies, NewsStyle::Normal, {}, references.first, references.second);
|
||||
const CargoSpec *cs = CargoSpec::Get(s->cargo_type);
|
||||
EncodedString headline = GetEncodedString(STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED, cs->name, s->src.GetFormat(), s->src.id, s->dst.GetFormat(), s->dst.id);
|
||||
AddNewsItem(std::move(headline), NewsType::Subsidies, NewsStyle::Normal, {}, s->src.GetNewsReference(), s->dst.GetNewsReference());
|
||||
AI::BroadcastNewEvent(new ScriptEventSubsidyOfferExpired(s->index));
|
||||
Game::NewEvent(new ScriptEventSubsidyOfferExpired(s->index));
|
||||
} else {
|
||||
if (s->awarded == _local_company) {
|
||||
std::pair<NewsReference, NewsReference> references = SetupSubsidyDecodeParam(s, SubsidyDecodeParamType::NewsWithdrawn);
|
||||
AddNewsItem(STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE, NewsType::Subsidies, NewsStyle::Normal, {}, references.first, references.second);
|
||||
const CargoSpec *cs = CargoSpec::Get(s->cargo_type);
|
||||
EncodedString headline = GetEncodedString(STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE, cs->name, s->src.GetFormat(), s->src.id, s->dst.GetFormat(), s->dst.id);
|
||||
AddNewsItem(std::move(headline), NewsType::Subsidies, NewsStyle::Normal, {}, s->src.GetNewsReference(), s->dst.GetNewsReference());
|
||||
}
|
||||
AI::BroadcastNewEvent(new ScriptEventSubsidyExpired(s->index));
|
||||
Game::NewEvent(new ScriptEventSubsidyExpired(s->index));
|
||||
|
|
|
@ -58,12 +58,4 @@ static const uint SUBSIDY_MAX_PCT_TRANSPORTED = 42; ///< Subsidy will be creat
|
|||
static const uint SUBSIDY_MAX_DISTANCE = 70; ///< Max. length of subsidised route (DistanceManhattan)
|
||||
static const uint SUBSIDY_TOWN_CARGO_RADIUS = 6; ///< Extent of a tile area around town center when scanning for town cargo acceptance and production (6 ~= min catchmement + min station / 2)
|
||||
|
||||
/** Types of subsidy news messages, which determine how the date is printed and whether to use singular or plural cargo names */
|
||||
enum class SubsidyDecodeParamType : uint8_t {
|
||||
NewsOffered = 0, ///< News item for an offered subsidy
|
||||
NewsAwarded = 1, ///< News item for an awarded subsidy
|
||||
NewsWithdrawn = 2, ///< News item for a subsidy offer withdrawn, or expired subsidy
|
||||
Gui = 3, ///< Subsidies listed in the Subsidy GUI
|
||||
};
|
||||
|
||||
#endif /* SUBSIDY_BASE_H */
|
||||
|
|
|
@ -10,14 +10,10 @@
|
|||
#ifndef SUBSIDY_FUNC_H
|
||||
#define SUBSIDY_FUNC_H
|
||||
|
||||
#include "core/geometry_type.hpp"
|
||||
#include "station_type.h"
|
||||
#include "company_type.h"
|
||||
#include "cargo_type.h"
|
||||
#include "news_type.h"
|
||||
#include "subsidy_base.h"
|
||||
|
||||
std::pair<NewsReference, NewsReference> SetupSubsidyDecodeParam(const struct Subsidy *s, SubsidyDecodeParamType mode, uint parameter_offset = 0);
|
||||
void DeleteSubsidyWith(Source src);
|
||||
bool CheckSubsidised(CargoType cargo_type, CompanyID company, Source src, const Station *st);
|
||||
void RebuildSubsidisedSourceAndDestinationCache();
|
||||
|
|
|
@ -174,18 +174,24 @@ struct SubsidyListWindow : Window {
|
|||
if (!s->IsAwarded()) {
|
||||
if (IsInsideMM(pos, 0, cap)) {
|
||||
/* Displays the two offered towns */
|
||||
SetupSubsidyDecodeParam(s, SubsidyDecodeParamType::Gui);
|
||||
const CargoSpec *cs = CargoSpec::Get(s->cargo_type);
|
||||
std::string text;
|
||||
|
||||
/* If using wallclock units, show minutes remaining. Otherwise show the date when the subsidy ends. */
|
||||
if (TimerGameEconomy::UsingWallclockUnits()) {
|
||||
SetDParam(7, STR_SUBSIDIES_OFFERED_EXPIRY_TIME);
|
||||
SetDParam(8, s->remaining + 1); // We get the rest of the current economy month for free, since the expiration is checked on each new month.
|
||||
text = GetString(STR_SUBSIDIES_OFFERED_FROM_TO,
|
||||
cs->name, s->src.GetFormat(), s->src.id, s->dst.GetFormat(), s->dst.id,
|
||||
STR_SUBSIDIES_OFFERED_EXPIRY_TIME,
|
||||
s->remaining + 1); // We get the rest of the current economy month for free, since the expiration is checked on each new month.
|
||||
} else {
|
||||
SetDParam(7, STR_SUBSIDIES_OFFERED_EXPIRY_DATE);
|
||||
SetDParam(8, TimerGameEconomy::date - ymd.day + s->remaining * 32);
|
||||
text = GetString(STR_SUBSIDIES_OFFERED_FROM_TO,
|
||||
cs->name, s->src.GetFormat(), s->src.id, s->dst.GetFormat(), s->dst.id,
|
||||
STR_SUBSIDIES_OFFERED_EXPIRY_DATE,
|
||||
TimerGameEconomy::date.base() - ymd.day + s->remaining * 32);
|
||||
}
|
||||
|
||||
DrawCargoIcon(tr, pos * GetCharacterHeight(FS_NORMAL), s->cargo_type);
|
||||
DrawString(sr.left, sr.right, sr.top + pos * GetCharacterHeight(FS_NORMAL), STR_SUBSIDIES_OFFERED_FROM_TO);
|
||||
DrawString(sr.left, sr.right, sr.top + pos * GetCharacterHeight(FS_NORMAL), text);
|
||||
}
|
||||
pos++;
|
||||
num++;
|
||||
|
@ -206,21 +212,27 @@ struct SubsidyListWindow : Window {
|
|||
for (const Subsidy *s : Subsidy::Iterate()) {
|
||||
if (s->IsAwarded()) {
|
||||
if (IsInsideMM(pos, 0, cap)) {
|
||||
SetupSubsidyDecodeParam(s, SubsidyDecodeParamType::Gui);
|
||||
SetDParam(7, s->awarded);
|
||||
const CargoSpec *cs = CargoSpec::Get(s->cargo_type);
|
||||
std::string text;
|
||||
|
||||
/* If using wallclock units, show minutes remaining. Otherwise show the date when the subsidy ends. */
|
||||
if (TimerGameEconomy::UsingWallclockUnits()) {
|
||||
SetDParam(8, STR_SUBSIDIES_SUBSIDISED_EXPIRY_TIME);
|
||||
SetDParam(9, s->remaining);
|
||||
}
|
||||
else {
|
||||
SetDParam(8, STR_SUBSIDIES_SUBSIDISED_EXPIRY_DATE);
|
||||
SetDParam(9, TimerGameEconomy::date - ymd.day + s->remaining * 32);
|
||||
text = GetString(STR_SUBSIDIES_SUBSIDISED_FROM_TO,
|
||||
cs->name, s->src.GetFormat(), s->src.id, s->dst.GetFormat(), s->dst.id,
|
||||
GetString(STR_COMPANY_NAME, s->awarded),
|
||||
STR_SUBSIDIES_SUBSIDISED_EXPIRY_TIME,
|
||||
s->remaining + 1); // We get the rest of the current economy month for free, since the expiration is checked on each new month.
|
||||
} else {
|
||||
text = GetString(STR_SUBSIDIES_SUBSIDISED_FROM_TO,
|
||||
cs->name, s->src.GetFormat(), s->src.id, s->dst.GetFormat(), s->dst.id,
|
||||
GetString(STR_COMPANY_NAME, s->awarded),
|
||||
STR_SUBSIDIES_SUBSIDISED_EXPIRY_DATE,
|
||||
TimerGameEconomy::date.base() - ymd.day + s->remaining * 32);
|
||||
}
|
||||
|
||||
/* Displays the two connected stations */
|
||||
DrawCargoIcon(tr, pos * GetCharacterHeight(FS_NORMAL), s->cargo_type);
|
||||
DrawString(sr.left, sr.right, sr.top + pos * GetCharacterHeight(FS_NORMAL), STR_SUBSIDIES_SUBSIDISED_FROM_TO);
|
||||
DrawString(sr.left, sr.right, sr.top + pos * GetCharacterHeight(FS_NORMAL), text);
|
||||
}
|
||||
pos++;
|
||||
num++;
|
||||
|
|
|
@ -12,8 +12,11 @@
|
|||
#include "../3rdparty/catch2/catch.hpp"
|
||||
|
||||
#include "../string_func.h"
|
||||
#include "../strings_func.h"
|
||||
#include "../table/control_codes.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
|
||||
/**** String compare/equals *****/
|
||||
|
||||
TEST_CASE("StrCompareIgnoreCase - std::string")
|
||||
|
@ -473,3 +476,15 @@ TEST_CASE("FixSCCEncoded")
|
|||
/* Test conversion with one sub-string and two string parameters. */
|
||||
CHECK(FixSCCEncodedWrapper("\uE000777:\uE0008888:\"Foo\":\"BarBaz\"", false) == Compose(SCC_ENCODED, "777", SCC_RECORD_SEPARATOR, SCC_ENCODED, "8888", SCC_RECORD_SEPARATOR, SCC_ENCODED_STRING, "Foo", SCC_RECORD_SEPARATOR, SCC_ENCODED_STRING, "BarBaz"));
|
||||
}
|
||||
|
||||
TEST_CASE("EncodedString::ReplaceParam")
|
||||
{
|
||||
/* Test that two encoded strings with different parameters are not the same. */
|
||||
EncodedString string1 = GetEncodedString(STR_NULL, "Foo", 10, "Bar");
|
||||
EncodedString string2 = GetEncodedString(STR_NULL, "Foo", 15, "Bar");
|
||||
CHECK(string1 != string2);
|
||||
|
||||
/* Test that replacing parameter results in the same string. */
|
||||
EncodedString string3 = string1.ReplaceParam(1, 15);
|
||||
CHECK(string2 == string3);
|
||||
}
|
||||
|
|
|
@ -2232,15 +2232,10 @@ std::tuple<CommandCost, Money, TownID> CmdFoundTown(DoCommandFlags flags, TileIn
|
|||
assert(!random_location);
|
||||
|
||||
if (_current_company == OWNER_DEITY) {
|
||||
SetDParam(0, t->index);
|
||||
AddTileNewsItem(STR_NEWS_NEW_TOWN_UNSPONSORED, NewsType::IndustryOpen, tile);
|
||||
AddTileNewsItem(GetEncodedString(STR_NEWS_NEW_TOWN_UNSPONSORED, t->index), NewsType::IndustryOpen, tile);
|
||||
} else {
|
||||
std::string company_name = GetString(STR_COMPANY_NAME, _current_company);
|
||||
|
||||
SetDParamStr(0, company_name);
|
||||
SetDParam(1, t->index);
|
||||
|
||||
AddTileNewsItem(STR_NEWS_NEW_TOWN, NewsType::IndustryOpen, tile);
|
||||
AddTileNewsItem(GetEncodedString(STR_NEWS_NEW_TOWN, company_name, t->index), NewsType::IndustryOpen, tile);
|
||||
}
|
||||
AI::BroadcastNewEvent(new ScriptEventTownFounded(t->index));
|
||||
Game::NewEvent(new ScriptEventTownFounded(t->index));
|
||||
|
@ -3411,11 +3406,8 @@ static CommandCost TownActionRoadRebuild(Town *t, DoCommandFlags flags)
|
|||
|
||||
std::string company_name = GetString(STR_COMPANY_NAME, _current_company);
|
||||
|
||||
SetDParam(0, t->index);
|
||||
SetDParamStr(1, company_name);
|
||||
|
||||
AddNewsItem(
|
||||
TimerGameEconomy::UsingWallclockUnits() ? STR_NEWS_ROAD_REBUILDING_MINUTES : STR_NEWS_ROAD_REBUILDING_MONTHS,
|
||||
GetEncodedString(TimerGameEconomy::UsingWallclockUnits() ? STR_NEWS_ROAD_REBUILDING_MINUTES : STR_NEWS_ROAD_REBUILDING_MONTHS, t->index, company_name),
|
||||
NewsType::General, NewsStyle::Normal, {}, t->index);
|
||||
AI::BroadcastNewEvent(new ScriptEventRoadReconstruction(_current_company, t->index));
|
||||
Game::NewEvent(new ScriptEventRoadReconstruction(_current_company, t->index));
|
||||
|
@ -3566,12 +3558,10 @@ static CommandCost TownActionBuyRights(Town *t, DoCommandFlags flags)
|
|||
SetWindowClassesDirty(WC_STATION_VIEW);
|
||||
|
||||
/* Spawn news message */
|
||||
auto cni = std::make_unique<CompanyNewsInformation>(Company::Get(_current_company));
|
||||
SetDParam(0, STR_NEWS_EXCLUSIVE_RIGHTS_TITLE);
|
||||
SetDParam(1, TimerGameEconomy::UsingWallclockUnits() ? STR_NEWS_EXCLUSIVE_RIGHTS_DESCRIPTION_MINUTES : STR_NEWS_EXCLUSIVE_RIGHTS_DESCRIPTION_MONTHS);
|
||||
SetDParam(2, t->index);
|
||||
SetDParamStr(3, cni->company_name);
|
||||
AddNewsItem(STR_MESSAGE_NEWS_FORMAT, NewsType::General, NewsStyle::Company, {}, t->index, {}, std::move(cni));
|
||||
auto cni = std::make_unique<CompanyNewsInformation>(STR_NEWS_EXCLUSIVE_RIGHTS_TITLE, Company::Get(_current_company));
|
||||
EncodedString message = GetEncodedString(TimerGameEconomy::UsingWallclockUnits() ? STR_NEWS_EXCLUSIVE_RIGHTS_DESCRIPTION_MINUTES : STR_NEWS_EXCLUSIVE_RIGHTS_DESCRIPTION_MONTHS, t->index, cni->company_name);
|
||||
AddNewsItem(std::move(message),
|
||||
NewsType::General, NewsStyle::Company, {}, t->index, {}, std::move(cni));
|
||||
AI::BroadcastNewEvent(new ScriptEventExclusiveTransportRights(_current_company, t->index));
|
||||
Game::NewEvent(new ScriptEventExclusiveTransportRights(_current_company, t->index));
|
||||
}
|
||||
|
|
|
@ -3006,9 +3006,8 @@ static void TrainEnterStation(Train *v, StationID station)
|
|||
Station *st = Station::Get(station);
|
||||
if (!(st->had_vehicle_of_type & HVOT_TRAIN)) {
|
||||
st->had_vehicle_of_type |= HVOT_TRAIN;
|
||||
SetDParam(0, st->index);
|
||||
AddVehicleNewsItem(
|
||||
STR_NEWS_FIRST_TRAIN_ARRIVAL,
|
||||
GetEncodedString(STR_NEWS_FIRST_TRAIN_ARRIVAL, st->index),
|
||||
v->owner == _local_company ? NewsType::ArrivalCompany : NewsType::ArrivalOther,
|
||||
v->index,
|
||||
st->index
|
||||
|
@ -3243,8 +3242,7 @@ static bool CheckTrainCollision(Train *v)
|
|||
/* any dead -> no crash */
|
||||
if (tcc.num == 0) return false;
|
||||
|
||||
SetDParam(0, tcc.num);
|
||||
AddTileNewsItem(STR_NEWS_TRAIN_CRASH, NewsType::Accident, v->tile);
|
||||
AddTileNewsItem(GetEncodedString(STR_NEWS_TRAIN_CRASH, tcc.num), NewsType::Accident, v->tile);
|
||||
|
||||
ModifyStationRatingAround(v->tile, v->owner, -160, 30);
|
||||
if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_13_TRAIN_COLLISION, v);
|
||||
|
@ -4006,8 +4004,7 @@ static bool TrainLocoHandler(Train *v, bool mode)
|
|||
if (HasBit(v->flags, VRF_TRAIN_STUCK) && v->wait_counter > 2 * _settings_game.pf.wait_for_pbs_path * Ticks::DAY_TICKS) {
|
||||
/* Show message to player. */
|
||||
if (_settings_client.gui.lost_vehicle_warn && v->owner == _local_company) {
|
||||
SetDParam(0, v->index);
|
||||
AddVehicleAdviceNewsItem(AdviceType::TrainStuck, STR_NEWS_TRAIN_IS_STUCK, v->index);
|
||||
AddVehicleAdviceNewsItem(AdviceType::TrainStuck, GetEncodedString(STR_NEWS_TRAIN_IS_STUCK, v->index), v->index);
|
||||
}
|
||||
v->wait_counter = 0;
|
||||
}
|
||||
|
|
|
@ -814,8 +814,7 @@ void Vehicle::HandlePathfindingResult(bool path_found)
|
|||
/* Notify user about the event. */
|
||||
AI::NewEvent(this->owner, new ScriptEventVehicleLost(this->index));
|
||||
if (_settings_client.gui.lost_vehicle_warn && this->owner == _local_company) {
|
||||
SetDParam(0, this->index);
|
||||
AddVehicleAdviceNewsItem(AdviceType::VehicleLost, STR_NEWS_VEHICLE_IS_LOST, this->index);
|
||||
AddVehicleAdviceNewsItem(AdviceType::VehicleLost, GetEncodedString(STR_NEWS_VEHICLE_IS_LOST, this->index), this->index);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1106,9 +1105,7 @@ void CallVehicleTicks()
|
|||
message = STR_NEWS_VEHICLE_AUTORENEW_FAILED;
|
||||
}
|
||||
|
||||
SetDParam(0, v->index);
|
||||
SetDParam(1, error_message);
|
||||
AddVehicleAdviceNewsItem(AdviceType::AutorenewFailed, message, v->index);
|
||||
AddVehicleAdviceNewsItem(AdviceType::AutorenewFailed, GetEncodedString(message, v->index, error_message), v->index);
|
||||
}
|
||||
|
||||
cur_company.Restore();
|
||||
|
@ -1474,8 +1471,7 @@ void AgeVehicle(Vehicle *v)
|
|||
return;
|
||||
}
|
||||
|
||||
SetDParam(0, v->index);
|
||||
AddVehicleAdviceNewsItem(AdviceType::VehicleOld, str, v->index);
|
||||
AddVehicleAdviceNewsItem(AdviceType::VehicleOld, GetEncodedString(str, v->index), v->index);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1630,8 +1626,7 @@ void VehicleEnterDepot(Vehicle *v)
|
|||
_vehicles_to_autoreplace[v->index] = false;
|
||||
if (v->owner == _local_company) {
|
||||
/* Notify the user that we stopped the vehicle */
|
||||
SetDParam(0, v->index);
|
||||
AddVehicleAdviceNewsItem(AdviceType::RefitFailed, STR_NEWS_ORDER_REFIT_FAILED, v->index);
|
||||
AddVehicleAdviceNewsItem(AdviceType::RefitFailed, GetEncodedString(STR_NEWS_ORDER_REFIT_FAILED, v->index), v->index);
|
||||
}
|
||||
} else if (cost.GetCost() != 0) {
|
||||
v->profit_this_year -= cost.GetCost() << 8;
|
||||
|
@ -1660,8 +1655,7 @@ void VehicleEnterDepot(Vehicle *v)
|
|||
|
||||
/* Announce that the vehicle is waiting to players and AIs. */
|
||||
if (v->owner == _local_company) {
|
||||
SetDParam(0, v->index);
|
||||
AddVehicleAdviceNewsItem(AdviceType::VehicleWaiting, STR_NEWS_TRAIN_IS_WAITING + v->type, v->index);
|
||||
AddVehicleAdviceNewsItem(AdviceType::VehicleWaiting, GetEncodedString(STR_NEWS_TRAIN_IS_WAITING + v->type, v->index), v->index);
|
||||
}
|
||||
AI::NewEvent(v->owner, new ScriptEventVehicleWaitingInDepot(v->index));
|
||||
}
|
||||
|
@ -3022,10 +3016,8 @@ static IntervalTimer<TimerGameEconomy> _economy_vehicles_yearly({TimerGameEconom
|
|||
Money profit = v->GetDisplayProfitThisYear();
|
||||
if (v->economy_age >= VEHICLE_PROFIT_MIN_AGE && profit < 0) {
|
||||
if (_settings_client.gui.vehicle_income_warn && v->owner == _local_company) {
|
||||
SetDParam(0, v->index);
|
||||
SetDParam(1, profit);
|
||||
AddVehicleAdviceNewsItem(AdviceType::VehicleUnprofitable,
|
||||
TimerGameEconomy::UsingWallclockUnits() ? STR_NEWS_VEHICLE_UNPROFITABLE_PERIOD : STR_NEWS_VEHICLE_UNPROFITABLE_YEAR,
|
||||
GetEncodedString(TimerGameEconomy::UsingWallclockUnits() ? STR_NEWS_VEHICLE_UNPROFITABLE_PERIOD : STR_NEWS_VEHICLE_UNPROFITABLE_YEAR, v->index, profit),
|
||||
v->index);
|
||||
}
|
||||
AI::NewEvent(v->owner, new ScriptEventVehicleUnprofitable(v->index));
|
||||
|
|
|
@ -1007,8 +1007,7 @@ static void FloodVehicle(Vehicle *v)
|
|||
|
||||
AI::NewEvent(v->owner, new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_FLOODED, victims));
|
||||
Game::NewEvent(new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_FLOODED, victims));
|
||||
SetDParam(0, victims);
|
||||
AddTileNewsItem(STR_NEWS_DISASTER_FLOOD_VEHICLE, NewsType::Accident, v->tile);
|
||||
AddTileNewsItem(GetEncodedString(STR_NEWS_DISASTER_FLOOD_VEHICLE, victims), NewsType::Accident, v->tile);
|
||||
CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
|
||||
if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_12_EXPLOSION, v);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue