1
0
Fork 0

Codechange: Use EncodedString for error messages. (#13569)

pull/13574/head
Peter Nelson 2025-02-16 10:04:32 +00:00 committed by GitHub
parent 43c7865ca2
commit 2d7d085e8e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
55 changed files with 426 additions and 390 deletions

View File

@ -281,7 +281,7 @@ struct AIConfigWindow : public Window {
case WID_AIC_CONTENT_DOWNLOAD:
if (!_network_available) {
ShowErrorMessage(STR_NETWORK_ERROR_NOTAVAILABLE, INVALID_STRING_ID, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_NETWORK_ERROR_NOTAVAILABLE), {}, WL_ERROR);
} else {
ShowNetworkContentListWindow(nullptr, CONTENT_TYPE_AI);
}

View File

@ -71,7 +71,7 @@ void AIInstance::Died()
const AIInfo *info = AIConfig::GetConfig(_current_company)->GetInfo();
if (info != nullptr) {
ShowErrorMessage(STR_ERROR_AI_PLEASE_REPORT_CRASH, INVALID_STRING_ID, WL_WARNING);
ShowErrorMessage(GetEncodedString(STR_ERROR_AI_PLEASE_REPORT_CRASH), {}, WL_WARNING);
if (!info->GetURL().empty()) {
ScriptLog::Info("Please report the error to the following URL:");

View File

@ -437,6 +437,7 @@ void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transpo
if (!bl.empty()) {
new BuildBridgeWindow(_build_bridge_desc, start, end, transport_type, road_rail_type, std::move(bl));
} else {
ShowErrorMessage(STR_ERROR_CAN_T_BUILD_BRIDGE_HERE, errmsg, WL_INFO, TileX(end) * TILE_SIZE, TileY(end) * TILE_SIZE);
ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_BUILD_BRIDGE_HERE), GetEncodedString(errmsg),
WL_INFO, TileX(end) * TILE_SIZE, TileY(end) * TILE_SIZE);
}
}

View File

@ -151,7 +151,7 @@ static int32_t ClickChangeMaxHlCheat(int32_t new_value, int32_t)
* If yes, disallow the change. */
for (const auto t : Map::Iterate()) {
if ((int32_t)TileHeight(t) > new_value) {
ShowErrorMessage(STR_CONFIG_SETTING_TOO_HIGH_MOUNTAIN, INVALID_STRING_ID, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_CONFIG_SETTING_TOO_HIGH_MOUNTAIN), {}, WL_ERROR);
/* Return old, unchanged value */
return _settings_game.construction.map_height_limit;
}

View File

@ -218,7 +218,8 @@ std::tuple<bool, bool, bool> CommandHelperBase::InternalPostBefore(Commands cmd,
bool only_sending = _networking && !network_command;
if (_pause_mode.Any() && !IsCommandAllowedWhilePaused(cmd) && !estimate_only) {
ShowErrorMessage(err_message, STR_ERROR_NOT_ALLOWED_WHILE_PAUSED, WL_INFO, TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE);
ShowErrorMessage(GetEncodedString(err_message), GetEncodedString(STR_ERROR_NOT_ALLOWED_WHILE_PAUSED),
WL_INFO, TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE);
return { true, estimate_only, only_sending };
} else {
return { false, estimate_only, only_sending };
@ -242,7 +243,7 @@ void CommandHelperBase::InternalPostResult(const CommandCost &res, TileIndex til
if (res.Failed()) {
/* Only show the error when it's for us. */
if (estimate_only || (IsLocalCompany() && err_message != 0 && my_cmd)) {
ShowErrorMessage(err_message, x, y, res);
ShowErrorMessage(GetEncodedString(err_message), x, y, res);
}
} else if (estimate_only) {
ShowEstimatedCostOrIncome(res.GetCost(), x, y);
@ -371,8 +372,7 @@ CommandCost CommandHelperBase::InternalExecuteProcessResult(Commands cmd, Comman
/* It could happen we removed rail, thus gained money, and deleted something else.
* So make sure the signal buffer is empty even in this case */
UpdateSignalsInBuffer();
SetDParam(0, extra_cash);
return CommandCost(STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY);
return CommandCostWithParam(STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY, extra_cash);
}
/* update last build coordinate of company. */
@ -412,7 +412,9 @@ void CommandCost::AddCost(const CommandCost &ret)
* There is only one static instance of the array, just like there is only one
* instance of normal DParams.
*/
uint32_t CommandCost::textref_stack[16];
/* static */ uint32_t CommandCost::textref_stack[16];
/* static */ EncodedString CommandCost::encoded_message;
/**
* Activate usage of the NewGRF #TextRefStack for the error message.
@ -430,3 +432,18 @@ void CommandCost::UseTextRefStack(const GRFFile *grffile, uint num_registers)
textref_stack[i] = _temp_store.GetValue(0x100 + i);
}
}
/**
* Return an error status, with string and parameter.
* @param str StringID of error.
* @param value Single parameter for error.
* @returns CommandCost representing the error.
*/
CommandCost CommandCostWithParam(StringID str, uint64_t value)
{
CommandCost error = CommandCost(str);
if (IsLocalCompany()) {
error.SetEncodedMessage(GetEncodedString(str, value));
}
return error;
}

View File

@ -10,6 +10,7 @@
#ifndef COMMAND_TYPE_H
#define COMMAND_TYPE_H
#include "company_type.h"
#include "economy_type.h"
#include "strings_type.h"
#include "tile_type.h"
@ -25,12 +26,15 @@ class CommandCost {
StringID message; ///< Warning message for when success is unset
ExpensesType expense_type; ///< the type of expence as shown on the finances view
bool success; ///< Whether the command went fine up to this moment
Owner owner = INVALID_COMPANY; ///< Originator owner of error.
const GRFFile *textref_stack_grffile = nullptr; ///< NewGRF providing the #TextRefStack content.
uint textref_stack_size = 0; ///< Number of uint32_t values to put on the #TextRefStack for the error message.
StringID extra_message = INVALID_STRING_ID; ///< Additional warning message for when success is unset
static uint32_t textref_stack[16];
static EncodedString encoded_message; ///< Encoded error message, used if the error message includes parameters.
public:
/**
* Creates a command cost return with no cost and no error
@ -55,6 +59,42 @@ public:
*/
CommandCost(ExpensesType ex_t, const Money &cst) : cost(cst), message(INVALID_STRING_ID), expense_type(ex_t), success(true) {}
/**
* Set the 'owner' (the originator) of this error message. This is used to show a company owner's face if you
* attempt an action on something owned by other company.
*/
inline void SetErrorOwner(Owner owner)
{
this->owner = owner;
}
/**
* Set the encoded message string. If set, this is used by the error message window instead of the error StringID,
* to allow more information to be displayed to the local player.
* @note Do not set an encoded message if the error is not for the local player, as it will never be seen.
* @param message EncodedString message to set.
*/
static void SetEncodedMessage(EncodedString &&message)
{
CommandCost::encoded_message = std::move(message);
}
/**
* Get the last encoded error message.
* @returns Reference to the encoded message.
*/
static EncodedString &GetEncodedMessage()
{
return CommandCost::encoded_message;
}
/**
* Get the originator owner for this error.
*/
inline CompanyID GetErrorOwner() const
{
return this->owner;
}
/**
* Adds the given cost to the cost of the command.
@ -98,12 +138,12 @@ public:
* Makes this #CommandCost behave like an error command.
* @param message The error message.
*/
void MakeError(StringID message, StringID extra_message = INVALID_STRING_ID)
void MakeError(StringID message)
{
assert(message != INVALID_STRING_ID);
this->success = false;
this->message = message;
this->extra_message = extra_message;
this->extra_message = INVALID_STRING_ID;
}
void UseTextRefStack(const GRFFile *grffile, uint num_registers);
@ -174,6 +214,8 @@ public:
}
};
CommandCost CommandCostWithParam(StringID str, uint64_t value);
/**
* List of commands.
*

View File

@ -245,8 +245,10 @@ bool CheckCompanyHasMoney(CommandCost &cost)
const Company *c = Company::GetIfValid(_current_company);
if (c != nullptr && cost.GetCost() > c->money) {
SetDParam(0, cost.GetCost());
cost.MakeError(STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY);
if (IsLocalCompany()) {
cost.SetEncodedMessage(GetEncodedString(STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY, cost.GetCost()));
}
return false;
}
return true;
@ -331,26 +333,20 @@ void UpdateLandscapingLimits()
* @param tile optional tile to get the right town.
* @pre if tile == 0, then owner can't be OWNER_TOWN.
*/
void SetDParamsForOwnedBy(Owner owner, TileIndex tile)
std::array<StringParameter, 2> GetParamsForOwnedBy(Owner owner, TileIndex tile)
{
SetDParam(OWNED_BY_OWNER_IN_PARAMETERS_OFFSET, owner);
if (owner != OWNER_TOWN) {
if (!Company::IsValidID(owner)) {
SetDParam(0, STR_COMPANY_SOMEONE);
} else {
SetDParam(0, STR_COMPANY_NAME);
SetDParam(1, owner);
}
} else {
if (owner == OWNER_TOWN) {
assert(tile != 0);
const Town *t = ClosestTownFromTile(tile, UINT_MAX);
SetDParam(0, STR_TOWN_NAME);
SetDParam(1, t->index);
return {STR_TOWN_NAME, t->index};
}
}
if (!Company::IsValidID(owner)) {
return {STR_COMPANY_SOMEONE, std::monostate{}};
}
return {STR_COMPANY_NAME, owner};
}
/**
* Check whether the current owner owns something.
@ -367,8 +363,13 @@ CommandCost CheckOwnership(Owner owner, TileIndex tile)
if (owner == _current_company) return CommandCost();
SetDParamsForOwnedBy(owner, tile);
return CommandCost(STR_ERROR_OWNED_BY);
CommandCost error{STR_ERROR_OWNED_BY};
if (IsLocalCompany()) {
auto params = GetParamsForOwnedBy(owner, tile);
error.SetEncodedMessage(GetEncodedStringWithArgs(STR_ERROR_OWNED_BY, params));
error.SetErrorOwner(owner);
}
return error;
}
/**
@ -380,15 +381,7 @@ CommandCost CheckOwnership(Owner owner, TileIndex tile)
*/
CommandCost CheckTileOwnership(TileIndex tile)
{
Owner owner = GetTileOwner(tile);
assert(owner < OWNER_END);
if (owner == _current_company) return CommandCost();
/* no need to get the name of the owner unless we're the local company (saves some time) */
if (IsLocalCompany()) SetDParamsForOwnedBy(owner, tile);
return CommandCost(STR_ERROR_OWNED_BY);
return CheckOwnership(GetTileOwner(tile), tile);
}
/**

View File

@ -17,8 +17,7 @@
bool CheckTakeoverVehicleLimit(CompanyID cbig, CompanyID small);
void ChangeOwnershipOfCompanyItems(Owner old_owner, Owner new_owner);
static const int OWNED_BY_OWNER_IN_PARAMETERS_OFFSET = 2; ///< The index in the parameters for the owner information.
void SetDParamsForOwnedBy(Owner owner, TileIndex tile);
std::array<StringParameter, 2> GetParamsForOwnedBy(Owner owner, TileIndex tile);
void SetLocalCompany(CompanyID new_company);
void ShowBuyCompanyDialog(CompanyID company, bool hostile_takeover);
void CompanyAdminUpdate(const Company *company);

View File

@ -1624,7 +1624,7 @@ public:
case WID_SCMF_LOAD:
this->face = _company_manager_face;
ScaleAllCompanyManagerFaceBits(this->face);
ShowErrorMessage(STR_FACE_LOAD_DONE, INVALID_STRING_ID, WL_INFO);
ShowErrorMessage(GetEncodedString(STR_FACE_LOAD_DONE), {}, WL_INFO);
this->UpdateData();
this->SetDirty();
break;
@ -1637,7 +1637,7 @@ public:
/* Save button */
case WID_SCMF_SAVE:
_company_manager_face = this->face;
ShowErrorMessage(STR_FACE_SAVE_DONE, INVALID_STRING_ID, WL_INFO);
ShowErrorMessage(GetEncodedString(STR_FACE_SAVE_DONE), {}, WL_INFO);
break;
/* Toggle gender (male/female) button */
@ -1714,11 +1714,11 @@ public:
if (!str->empty()) {
this->face = std::strtoul(str->c_str(), nullptr, 10);
ScaleAllCompanyManagerFaceBits(this->face);
ShowErrorMessage(STR_FACE_FACECODE_SET, INVALID_STRING_ID, WL_INFO);
ShowErrorMessage(GetEncodedString(STR_FACE_FACECODE_SET), {}, WL_INFO);
this->UpdateData();
this->SetDirty();
} else {
ShowErrorMessage(STR_FACE_FACECODE_ERR, INVALID_STRING_ID, WL_INFO);
ShowErrorMessage(GetEncodedString(STR_FACE_FACECODE_ERR), {}, WL_INFO);
}
}
};
@ -2635,8 +2635,7 @@ struct BuyCompanyWindow : Window {
{
switch (widget) {
case WID_BC_CAPTION:
SetDParam(0, STR_COMPANY_NAME);
SetDParam(1, Company::Get(this->window_number)->index);
SetDParam(0, Company::Get(this->window_number)->index);
break;
}
}

View File

@ -944,10 +944,12 @@ struct DepotWindow : Window {
})) {
OnVehicleSelect(*begin);
} else {
ShowErrorMessage(STR_ERROR_CAN_T_BUY_TRAIN + (*begin)->type, STR_ERROR_CAN_T_COPY_ORDER_VEHICLE_LIST, WL_INFO);
ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_BUY_TRAIN + (*begin)->type),
GetEncodedString(STR_ERROR_CAN_T_COPY_ORDER_VEHICLE_LIST), WL_INFO);
}
} else {
ShowErrorMessage(STR_ERROR_CAN_T_BUY_TRAIN + (*begin)->type, STR_ERROR_CAN_T_CLONE_VEHICLE_LIST, WL_INFO);
ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_BUY_TRAIN + (*begin)->type),
GetEncodedString(STR_ERROR_CAN_T_CLONE_VEHICLE_LIST), WL_INFO);
}
} else {
/* If CTRL is pressed: If all the vehicles in this list share orders, then copy orders */
@ -959,10 +961,12 @@ struct DepotWindow : Window {
})) {
OnVehicleSelect(*begin);
} else {
ShowErrorMessage(STR_ERROR_CAN_T_BUY_TRAIN + (*begin)->type, STR_ERROR_CAN_T_SHARE_ORDER_VEHICLE_LIST, WL_INFO);
ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_BUY_TRAIN + (*begin)->type),
GetEncodedString(STR_ERROR_CAN_T_SHARE_ORDER_VEHICLE_LIST), WL_INFO);
}
} else {
ShowErrorMessage(STR_ERROR_CAN_T_BUY_TRAIN + (*begin)->type, STR_ERROR_CAN_T_CLONE_VEHICLE_LIST, WL_INFO);
ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_BUY_TRAIN + (*begin)->type),
GetEncodedString(STR_ERROR_CAN_T_CLONE_VEHICLE_LIST), WL_INFO);
}
}

View File

@ -13,6 +13,7 @@
#include "error_func.h"
#include "sound/sound_driver.hpp"
#include "music/music_driver.hpp"
#include "strings_func.h"
#include "video/video_driver.hpp"
#include "string_func.h"
#include "table/strings.h"
@ -128,8 +129,8 @@ bool DriverFactoryBase::SelectDriverImpl(const std::string &name, Driver::Type t
Debug(driver, 1, "Probing {} driver '{}' skipped due to earlier crash", GetDriverTypeName(type), d->name);
_video_hw_accel = false;
ErrorMessageData msg(STR_VIDEO_DRIVER_ERROR, STR_VIDEO_DRIVER_ERROR_HARDWARE_ACCELERATION_CRASH, true);
ScheduleErrorMessage(msg);
ErrorMessageData msg(GetEncodedString(STR_VIDEO_DRIVER_ERROR), GetEncodedString(STR_VIDEO_DRIVER_ERROR_HARDWARE_ACCELERATION_CRASH), true);
ScheduleErrorMessage(std::move(msg));
continue;
}
@ -154,8 +155,8 @@ bool DriverFactoryBase::SelectDriverImpl(const std::string &name, Driver::Type t
if (type == Driver::DT_VIDEO && _video_hw_accel && d->UsesHardwareAcceleration()) {
_video_hw_accel = false;
ErrorMessageData msg(STR_VIDEO_DRIVER_ERROR, STR_VIDEO_DRIVER_ERROR_NO_HARDWARE_ACCELERATION, true);
ScheduleErrorMessage(msg);
ErrorMessageData msg(GetEncodedString(STR_VIDEO_DRIVER_ERROR), GetEncodedString(STR_VIDEO_DRIVER_ERROR_NO_HARDWARE_ACCELERATION), true);
ScheduleErrorMessage(std::move(msg));
}
}
}

View File

@ -1336,9 +1336,10 @@ void CheckEngines()
}
if (min_date < INT32_MAX) {
SetDParam(0, min_date);
ShowErrorMessage(STR_ERROR_NO_VEHICLES_AVAILABLE_YET, STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION, WL_WARNING);
ShowErrorMessage(GetEncodedString(STR_ERROR_NO_VEHICLES_AVAILABLE_YET),
GetEncodedString(STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION, min_date), WL_WARNING);
} else {
ShowErrorMessage(STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL, STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION, WL_WARNING);
ShowErrorMessage(GetEncodedString(STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL),
GetEncodedString(STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION), WL_WARNING);
}
}

View File

@ -31,31 +31,24 @@ enum WarningLevel : uint8_t {
class ErrorMessageData {
protected:
bool is_critical; ///< Whether the error message is critical.
std::vector<StringParameterData> params; ///< Backup of parameters of the message strings.
const GRFFile *textref_stack_grffile; ///< NewGRF that filled the #TextRefStack for the error message.
uint textref_stack_size; ///< Number of uint32_t values to put on the #TextRefStack for the error message.
uint32_t textref_stack[16]; ///< Values to put on the #TextRefStack for the error message.
StringID summary_msg; ///< General error message showed in first line. Must be valid.
StringID detailed_msg; ///< Detailed error message showed in second line. Can be #INVALID_STRING_ID.
StringID extra_msg; ///< Extra error message shown in third line. Can be #INVALID_STRING_ID.
EncodedString summary_msg; ///< General error message showed in first line. Must be valid.
EncodedString detailed_msg; ///< Detailed error message showed in second line. Can be #INVALID_STRING_ID.
EncodedString extra_msg; ///< Extra error message shown in third line. Can be #INVALID_STRING_ID.
Point position; ///< Position of the error message window.
CompanyID face; ///< Company belonging to the face being shown. #INVALID_COMPANY if no face present.
CompanyID company; ///< Company belonging to the face being shown. #INVALID_COMPANY if no face present.
public:
ErrorMessageData(const ErrorMessageData &data);
ErrorMessageData(StringID summary_msg, StringID detailed_msg, bool is_critical = false, int x = 0, int y = 0, const GRFFile *textref_stack_grffile = nullptr, uint textref_stack_size = 0, const uint32_t *textref_stack = nullptr, StringID extra_msg = INVALID_STRING_ID);
ErrorMessageData(EncodedString &&summary_msg, EncodedString &&detailed_msg, bool is_critical = false, int x = 0, int y = 0, const GRFFile *textref_stack_grffile = nullptr, uint textref_stack_size = 0, const uint32_t *textref_stack = nullptr, EncodedString &&extra_msg = {}, CompanyID company = INVALID_COMPANY);
/* Remove the copy assignment, as the default implementation will not do the right thing. */
ErrorMessageData &operator=(ErrorMessageData &rhs) = delete;
/** Check whether error window shall display a company manager face */
bool HasFace() const { return face != INVALID_COMPANY; }
void SetDParam(uint n, uint64_t v);
void SetDParamStr(uint n, const char *str);
void SetDParamStr(uint n, const std::string &str);
void CopyOutDParams();
bool HasFace() const { return company != INVALID_COMPANY; }
};
/** Define a queue with errors. */
@ -64,8 +57,8 @@ typedef std::list<ErrorMessageData> ErrorList;
void ScheduleErrorMessage(ErrorList &datas);
void ScheduleErrorMessage(const ErrorMessageData &data);
void ShowErrorMessage(StringID summary_msg, int x, int y, CommandCost cc);
void ShowErrorMessage(StringID summary_msg, StringID detailed_msg, WarningLevel wl, int x = 0, int y = 0, const GRFFile *textref_stack_grffile = nullptr, uint textref_stack_size = 0, const uint32_t *textref_stack = nullptr, StringID extra_msg = INVALID_STRING_ID);
void ShowErrorMessage(EncodedString &&summary_msg, int x, int y, const CommandCost &cc);
void ShowErrorMessage(EncodedString &&summary_msg, EncodedString &&detailed_msg, WarningLevel wl, int x = 0, int y = 0, const GRFFile *textref_stack_grffile = nullptr, uint textref_stack_size = 0, const uint32_t *textref_stack = nullptr, EncodedString &&extra_msg = {}, CompanyID company = INVALID_COMPANY);
bool HideActiveErrorMessage();
void ClearErrorMessages();

View File

@ -75,8 +75,8 @@ static WindowDesc _errmsg_face_desc(
* @param data The data to copy.
*/
ErrorMessageData::ErrorMessageData(const ErrorMessageData &data) :
is_critical(data.is_critical), params(data.params), textref_stack_grffile(data.textref_stack_grffile), textref_stack_size(data.textref_stack_size),
summary_msg(data.summary_msg), detailed_msg(data.detailed_msg), extra_msg(data.extra_msg), position(data.position), face(data.face)
is_critical(data.is_critical), textref_stack_grffile(data.textref_stack_grffile), textref_stack_size(data.textref_stack_size),
summary_msg(data.summary_msg), detailed_msg(data.detailed_msg), extra_msg(data.extra_msg), position(data.position), company(data.company)
{
memcpy(this->textref_stack, data.textref_stack, sizeof(this->textref_stack));
}
@ -84,80 +84,30 @@ ErrorMessageData::ErrorMessageData(const ErrorMessageData &data) :
/**
* Display an error message in a window.
* @param summary_msg General error message showed in first line. Must be valid.
* @param detailed_msg Detailed error message showed in second line. Can be INVALID_STRING_ID.
* @param detailed_msg Detailed error message showed in second line. Can be empty.
* @param is_critical Whether the error is critical. Critical messages never go away on their own.
* @param x World X position (TileVirtX) of the error location. Set both x and y to 0 to just center the message when there is no related error tile.
* @param y World Y position (TileVirtY) of the error location. Set both x and y to 0 to just center the message when there is no related error tile.
* @param textref_stack_grffile NewGRF that provides the #TextRefStack for the error message.
* @param textref_stack_size Number of uint32_t values to put on the #TextRefStack for the error message; 0 if the #TextRefStack shall not be used.
* @param textref_stack Values to put on the #TextRefStack.
* @param extra_msg Extra error message showed in third line. Can be INVALID_STRING_ID.
* @param extra_msg Extra error message showed in third line. Can be empty.
*/
ErrorMessageData::ErrorMessageData(StringID summary_msg, StringID detailed_msg, bool is_critical, int x, int y, const GRFFile *textref_stack_grffile, uint textref_stack_size, const uint32_t *textref_stack, StringID extra_msg) :
ErrorMessageData::ErrorMessageData(EncodedString &&summary_msg, EncodedString &&detailed_msg, bool is_critical, int x, int y, const GRFFile *textref_stack_grffile, uint textref_stack_size, const uint32_t *textref_stack, EncodedString &&extra_msg, CompanyID company) :
is_critical(is_critical),
textref_stack_grffile(textref_stack_grffile),
textref_stack_size(textref_stack_size),
summary_msg(summary_msg),
detailed_msg(detailed_msg),
extra_msg(extra_msg),
face(INVALID_COMPANY)
summary_msg(std::move(summary_msg)),
detailed_msg(std::move(detailed_msg)),
extra_msg(std::move(extra_msg)),
company(company)
{
this->position.x = x;
this->position.y = y;
if (textref_stack_size > 0) MemCpyT(this->textref_stack, textref_stack, textref_stack_size);
assert(summary_msg != INVALID_STRING_ID);
}
/**
* Copy error parameters from current DParams.
*/
void ErrorMessageData::CopyOutDParams()
{
if (this->detailed_msg == STR_ERROR_OWNED_BY) {
/* The parameters are set by SetDParamsForOwnedBy. */
CompanyID company = (CompanyID)GetDParam(OWNED_BY_OWNER_IN_PARAMETERS_OFFSET);
if (company < MAX_COMPANIES) face = company;
}
/* Get parameters using type information */
if (this->textref_stack_size > 0) StartTextRefStackUsage(this->textref_stack_grffile, this->textref_stack_size, this->textref_stack);
CopyOutDParam(this->params, 20);
if (this->textref_stack_size > 0) StopTextRefStackUsage();
}
/**
* Set a error string parameter.
* @param n Parameter index
* @param v Parameter value
*/
void ErrorMessageData::SetDParam(uint n, uint64_t v)
{
if (n >= this->params.size()) this->params.resize(n + 1);
this->params[n] = v;
}
/**
* Set a rawstring parameter.
* @param n Parameter index
* @param str Raw string
*/
void ErrorMessageData::SetDParamStr(uint n, const char *str)
{
if (n >= this->params.size()) this->params.resize(n + 1);
this->params[n] = str;
}
/**
* Set a rawstring parameter.
* @param n Parameter index
* @param str Raw string
*/
void ErrorMessageData::SetDParamStr(uint n, const std::string &str)
{
if (n >= this->params.size()) this->params.resize(n + 1);
this->params[n] = str;
assert(!this->summary_msg.empty());
}
/** The actual queue with errors. */
@ -193,18 +143,17 @@ public:
{
switch (widget) {
case WID_EM_MESSAGE: {
CopyInDParam(this->params);
if (this->textref_stack_size > 0) StartTextRefStackUsage(this->textref_stack_grffile, this->textref_stack_size, this->textref_stack);
this->height_summary = GetStringHeight(this->summary_msg, size.width);
this->height_detailed = (this->detailed_msg == INVALID_STRING_ID) ? 0 : GetStringHeight(this->detailed_msg, size.width);
this->height_extra = (this->extra_msg == INVALID_STRING_ID) ? 0 : GetStringHeight(this->extra_msg, size.width);
this->height_summary = GetStringHeight(this->summary_msg.GetDecodedString(), size.width);
this->height_detailed = (this->detailed_msg.empty()) ? 0 : GetStringHeight(this->detailed_msg.GetDecodedString(), size.width);
this->height_extra = (this->extra_msg.empty()) ? 0 : GetStringHeight(this->extra_msg.GetDecodedString(), size.width);
if (this->textref_stack_size > 0) StopTextRefStackUsage();
uint panel_height = this->height_summary;
if (this->detailed_msg != INVALID_STRING_ID) panel_height += this->height_detailed + WidgetDimensions::scaled.vsep_wide;
if (this->extra_msg != INVALID_STRING_ID) panel_height += this->height_extra + WidgetDimensions::scaled.vsep_wide;
if (!this->detailed_msg.empty()) panel_height += this->height_detailed + WidgetDimensions::scaled.vsep_wide;
if (!this->extra_msg.empty()) panel_height += this->height_extra + WidgetDimensions::scaled.vsep_wide;
size.height = std::max(size.height, panel_height);
break;
@ -248,36 +197,35 @@ public:
void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
{
/* If company gets shut down, while displaying an error about it, remove the error message. */
if (this->face != INVALID_COMPANY && !Company::IsValidID(this->face)) this->Close();
if (this->company != INVALID_COMPANY && !Company::IsValidID(this->company)) this->Close();
}
void SetStringParameters(WidgetID widget) const override
{
if (widget == WID_EM_CAPTION) CopyInDParam(this->params);
if (widget == WID_EM_CAPTION && this->company != INVALID_COMPANY) SetDParam(0, this->company);
}
void DrawWidget(const Rect &r, WidgetID widget) const override
{
switch (widget) {
case WID_EM_FACE: {
const Company *c = Company::Get(this->face);
const Company *c = Company::Get(this->company);
DrawCompanyManagerFace(c->face, c->colour, r);
break;
}
case WID_EM_MESSAGE:
CopyInDParam(this->params);
if (this->textref_stack_size > 0) StartTextRefStackUsage(this->textref_stack_grffile, this->textref_stack_size, this->textref_stack);
if (this->detailed_msg == INVALID_STRING_ID) {
DrawStringMultiLine(r, this->summary_msg, TC_FROMSTRING, SA_CENTER);
} else if (this->extra_msg == INVALID_STRING_ID) {
if (this->detailed_msg.empty()) {
DrawStringMultiLine(r, this->summary_msg.GetDecodedString(), TC_FROMSTRING, SA_CENTER);
} else if (this->extra_msg.empty()) {
/* Extra space when message is shorter than company face window */
int extra = (r.Height() - this->height_summary - this->height_detailed - WidgetDimensions::scaled.vsep_wide) / 2;
/* Note: NewGRF supplied error message often do not start with a colour code, so default to white. */
DrawStringMultiLine(r.WithHeight(this->height_summary + extra, false), this->summary_msg, TC_WHITE, SA_CENTER);
DrawStringMultiLine(r.WithHeight(this->height_detailed + extra, true), this->detailed_msg, TC_WHITE, SA_CENTER);
DrawStringMultiLine(r.WithHeight(this->height_summary + extra, false), this->summary_msg.GetDecodedString(), TC_WHITE, SA_CENTER);
DrawStringMultiLine(r.WithHeight(this->height_detailed + extra, true), this->detailed_msg.GetDecodedString(), TC_WHITE, SA_CENTER);
} else {
/* Extra space when message is shorter than company face window */
int extra = (r.Height() - this->height_summary - this->height_detailed - this->height_extra - (WidgetDimensions::scaled.vsep_wide * 2)) / 3;
@ -286,9 +234,9 @@ public:
Rect top_section = r.WithHeight(this->height_summary + extra, false);
Rect bottom_section = r.WithHeight(this->height_extra + extra, true);
Rect middle_section = { top_section.left, top_section.bottom, top_section.right, bottom_section.top };
DrawStringMultiLine(top_section, this->summary_msg, TC_WHITE, SA_CENTER);
DrawStringMultiLine(middle_section, this->detailed_msg, TC_WHITE, SA_CENTER);
DrawStringMultiLine(bottom_section, this->extra_msg, TC_WHITE, SA_CENTER);
DrawStringMultiLine(top_section, this->summary_msg.GetDecodedString(), TC_WHITE, SA_CENTER);
DrawStringMultiLine(middle_section, this->detailed_msg.GetDecodedString(), TC_WHITE, SA_CENTER);
DrawStringMultiLine(bottom_section, this->extra_msg.GetDecodedString(), TC_WHITE, SA_CENTER);
}
if (this->textref_stack_size > 0) StopTextRefStackUsage();
@ -362,43 +310,47 @@ void UnshowCriticalError()
* @param summary_msg General error message showed in first line. Must be valid.
* @param x World X position (TileVirtX) of the error location. Set both x and y to 0 to just center the message when there is no related error tile.
* @param y World Y position (TileVirtY) of the error location. Set both x and y to 0 to just center the message when there is no related error tile.
* @param cc CommandCost containing the optional detailed and extra error messages shown in the second and third lines (can be INVALID_STRING_ID) and TextRefStack info.
* @param cc CommandCost containing the optional detailed and extra error messages shown in the second and third lines (can be empty) and TextRefStack info.
*/
void ShowErrorMessage(StringID summary_msg, int x, int y, CommandCost cc)
void ShowErrorMessage(EncodedString &&summary_msg, int x, int y, const CommandCost &cc)
{
ShowErrorMessage(summary_msg, cc.GetErrorMessage(), WL_INFO, x, y, cc.GetTextRefStackGRF(), cc.GetTextRefStackSize(), cc.GetTextRefStack(), cc.GetExtraErrorMessage());
EncodedString error = std::move(cc.GetEncodedMessage());
if (error.empty()) error = GetEncodedStringIfValid(cc.GetErrorMessage());
ShowErrorMessage(std::move(summary_msg), std::move(error), WL_INFO, x, y,
cc.GetTextRefStackGRF(), cc.GetTextRefStackSize(), cc.GetTextRefStack(),
GetEncodedStringIfValid(cc.GetExtraErrorMessage()), cc.GetErrorOwner());
}
/**
* Display an error message in a window.
* @param summary_msg General error message showed in first line. Must be valid.
* @param detailed_msg Detailed error message showed in second line. Can be INVALID_STRING_ID.
* @param detailed_msg Detailed error message showed in second line. Can be empty.
* @param wl Message severity.
* @param x World X position (TileVirtX) of the error location. Set both x and y to 0 to just center the message when there is no related error tile.
* @param y World Y position (TileVirtY) of the error location. Set both x and y to 0 to just center the message when there is no related error tile.
* @param textref_stack_grffile NewGRF providing the #TextRefStack for the error message.
* @param textref_stack_size Number of uint32_t values to put on the #TextRefStack for the error message; 0 if the #TextRefStack shall not be used.
* @param textref_stack Values to put on the #TextRefStack.
* @param extra_msg Extra error message shown in third line. Can be INVALID_STRING_ID.
* @param extra_msg Extra error message shown in third line. Can be empty.
*/
void ShowErrorMessage(StringID summary_msg, StringID detailed_msg, WarningLevel wl, int x, int y, const GRFFile *textref_stack_grffile, uint textref_stack_size, const uint32_t *textref_stack, StringID extra_msg)
void ShowErrorMessage(EncodedString &&summary_msg, EncodedString &&detailed_msg, WarningLevel wl, int x, int y, const GRFFile *textref_stack_grffile, uint textref_stack_size, const uint32_t *textref_stack, EncodedString &&extra_msg, CompanyID company)
{
assert(textref_stack_size == 0 || (textref_stack_grffile != nullptr && textref_stack != nullptr));
if (summary_msg == STR_NULL) summary_msg = STR_EMPTY;
if (wl != WL_INFO) {
/* Print message to console */
if (textref_stack_size > 0) StartTextRefStackUsage(textref_stack_grffile, textref_stack_size, textref_stack);
std::string message = GetString(summary_msg);
if (detailed_msg != INVALID_STRING_ID) {
std::string message = summary_msg.GetDecodedString();
if (!detailed_msg.empty()) {
message += " ";
AppendStringInPlace(message, detailed_msg);
message += detailed_msg.GetDecodedString();
}
if (extra_msg != INVALID_STRING_ID) {
if (!extra_msg.empty()) {
message += " ";
AppendStringInPlace(message, extra_msg);
message += extra_msg.GetDecodedString();
}
if (textref_stack_size > 0) StopTextRefStackUsage();
@ -411,8 +363,7 @@ void ShowErrorMessage(StringID summary_msg, StringID detailed_msg, WarningLevel
if (_game_mode == GM_BOOTSTRAP) return;
if (_settings_client.gui.errmsg_duration == 0 && !is_critical) return;
ErrorMessageData data(summary_msg, detailed_msg, is_critical, x, y, textref_stack_grffile, textref_stack_size, textref_stack, extra_msg);
data.CopyOutDParams();
ErrorMessageData data(std::move(summary_msg), std::move(detailed_msg), is_critical, x, y, textref_stack_grffile, textref_stack_size, textref_stack, std::move(extra_msg), company);
ErrmsgWindow *w = dynamic_cast<ErrmsgWindow *>(FindWindowById(WC_ERRMSG, 0));
if (w != nullptr) {

View File

@ -703,7 +703,7 @@ public:
case WID_SL_MISSING_NEWGRFS:
if (!_network_available) {
ShowErrorMessage(STR_NETWORK_ERROR_NOTAVAILABLE, INVALID_STRING_ID, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_NETWORK_ERROR_NOTAVAILABLE), {}, WL_ERROR);
} else if (_load_check_data.HasNewGrfs()) {
ShowMissingContentWindow(_load_check_data.grfconfig);
}
@ -758,7 +758,7 @@ public:
case WID_SL_CONTENT_DOWNLOAD:
if (!_network_available) {
ShowErrorMessage(STR_NETWORK_ERROR_NOTAVAILABLE, INVALID_STRING_ID, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_NETWORK_ERROR_NOTAVAILABLE), {}, WL_ERROR);
} else {
assert(this->fop == SLO_LOAD);
switch (this->abstract_filetype) {
@ -815,7 +815,7 @@ public:
if (this->IsWidgetLowered(WID_SL_DELETE_SELECTION)) { // Delete button clicked
if (!FiosDelete(this->filename_editbox.text.GetText())) {
ShowErrorMessage(STR_ERROR_UNABLE_TO_DELETE_FILE, INVALID_STRING_ID, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_ERROR_UNABLE_TO_DELETE_FILE), {}, WL_ERROR);
} else {
this->InvalidateData(SLIWD_RESCAN_FILES);
/* Reset file name to current date on successful delete */

View File

@ -265,7 +265,7 @@ struct GSConfigWindow : public Window {
case WID_GSC_CONTENT_DOWNLOAD:
if (!_network_available) {
ShowErrorMessage(STR_NETWORK_ERROR_NOTAVAILABLE, INVALID_STRING_ID, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_NETWORK_ERROR_NOTAVAILABLE), {}, WL_ERROR);
} else {
ShowNetworkContentListWindow(nullptr, CONTENT_TYPE_GAME);
}

View File

@ -74,7 +74,7 @@ void GameInstance::Died()
const GameInfo *info = Game::GetInfo();
if (info != nullptr) {
ShowErrorMessage(STR_ERROR_AI_PLEASE_REPORT_CRASH, INVALID_STRING_ID, WL_WARNING);
ShowErrorMessage(GetEncodedString(STR_ERROR_AI_PLEASE_REPORT_CRASH), {}, WL_WARNING);
if (!info->GetURL().empty()) {
ScriptLog::Info("Please report the error to the following URL:");

View File

@ -390,7 +390,8 @@ void LoadTownData()
auto f = FioFOpenFile(_file_to_saveload.name, "rb", HEIGHTMAP_DIR, &filesize);
if (!f.has_value()) {
ShowErrorMessage(STR_TOWN_DATA_ERROR_LOAD_FAILED, STR_TOWN_DATA_ERROR_JSON_FORMATTED_INCORRECTLY, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_TOWN_DATA_ERROR_LOAD_FAILED),
GetEncodedString(STR_TOWN_DATA_ERROR_JSON_FORMATTED_INCORRECTLY), WL_ERROR);
return;
}
@ -398,7 +399,8 @@ void LoadTownData()
size_t len = fread(text.data(), filesize, 1, *f);
f.reset();
if (len != 1) {
ShowErrorMessage(STR_TOWN_DATA_ERROR_LOAD_FAILED, STR_TOWN_DATA_ERROR_JSON_FORMATTED_INCORRECTLY, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_TOWN_DATA_ERROR_LOAD_FAILED),
GetEncodedString(STR_TOWN_DATA_ERROR_JSON_FORMATTED_INCORRECTLY), WL_ERROR);
return;
}
@ -407,13 +409,13 @@ void LoadTownData()
try {
town_data = nlohmann::json::parse(text);
} catch (nlohmann::json::exception &) {
ShowErrorMessage(STR_TOWN_DATA_ERROR_LOAD_FAILED, STR_TOWN_DATA_ERROR_JSON_FORMATTED_INCORRECTLY, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_TOWN_DATA_ERROR_LOAD_FAILED), GetEncodedString(STR_TOWN_DATA_ERROR_JSON_FORMATTED_INCORRECTLY), WL_ERROR);
return;
}
/* Check for JSON formatting errors with the array of towns. */
if (!town_data.is_array()) {
ShowErrorMessage(STR_TOWN_DATA_ERROR_LOAD_FAILED, STR_TOWN_DATA_ERROR_JSON_FORMATTED_INCORRECTLY, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_TOWN_DATA_ERROR_LOAD_FAILED), GetEncodedString(STR_TOWN_DATA_ERROR_JSON_FORMATTED_INCORRECTLY), WL_ERROR);
return;
}
@ -426,14 +428,14 @@ void LoadTownData()
/* Ensure JSON is formatted properly. */
if (!feature.is_object()) {
ShowErrorMessage(STR_TOWN_DATA_ERROR_LOAD_FAILED, STR_TOWN_DATA_ERROR_JSON_FORMATTED_INCORRECTLY, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_TOWN_DATA_ERROR_LOAD_FAILED), GetEncodedString(STR_TOWN_DATA_ERROR_JSON_FORMATTED_INCORRECTLY), WL_ERROR);
return;
}
/* Check to ensure all fields exist and are of the correct type.
* If the town name is formatted wrong, all we can do is give a general warning. */
if (!feature.contains("name") || !feature.at("name").is_string()) {
ShowErrorMessage(STR_TOWN_DATA_ERROR_LOAD_FAILED, STR_TOWN_DATA_ERROR_JSON_FORMATTED_INCORRECTLY, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_TOWN_DATA_ERROR_LOAD_FAILED), GetEncodedString(STR_TOWN_DATA_ERROR_JSON_FORMATTED_INCORRECTLY), WL_ERROR);
return;
}
@ -443,8 +445,8 @@ void LoadTownData()
!feature.contains("x") || !feature.at("x").is_number() ||
!feature.contains("y") || !feature.at("y").is_number()) {
feature.at("name").get_to(town.name);
SetDParamStr(0, town.name);
ShowErrorMessage(STR_TOWN_DATA_ERROR_LOAD_FAILED, STR_TOWN_DATA_ERROR_TOWN_FORMATTED_INCORRECTLY, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_TOWN_DATA_ERROR_LOAD_FAILED),
GetEncodedString(STR_TOWN_DATA_ERROR_TOWN_FORMATTED_INCORRECTLY, town.name), WL_ERROR);
return;
}
@ -459,8 +461,8 @@ void LoadTownData()
/* Check for improper coordinates and warn the player. */
if (town.x_proportion <= 0.0f || town.y_proportion <= 0.0f || town.x_proportion >= 1.0f || town.y_proportion >= 1.0f) {
SetDParamStr(0, town.name);
ShowErrorMessage(STR_TOWN_DATA_ERROR_LOAD_FAILED, STR_TOWN_DATA_ERROR_BAD_COORDINATE, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_TOWN_DATA_ERROR_LOAD_FAILED),
GetEncodedString(STR_TOWN_DATA_ERROR_BAD_COORDINATE, town.name), WL_ERROR);
return;
}
@ -496,8 +498,7 @@ void LoadTownData()
/* If we couldn't found a town (or multiple), display a message to the player with the number of failed towns. */
if (failed_towns > 0) {
SetDParam(0, failed_towns);
ShowErrorMessage(STR_TOWN_DATA_ERROR_FAILED_TO_FOUND_TOWN, INVALID_STRING_ID, WL_WARNING);
ShowErrorMessage(GetEncodedString(STR_TOWN_DATA_ERROR_FAILED_TO_FOUND_TOWN, failed_towns), {}, WL_WARNING);
}
/* Now that we've created the towns, let's grow them to their target populations. */

View File

@ -10,6 +10,7 @@
#include "stdafx.h"
#include "heightmap.h"
#include "clear_map.h"
#include "strings_func.h"
#include "void_map.h"
#include "error.h"
#include "saveload/saveload.h"
@ -141,19 +142,19 @@ static bool ReadHeightmapPNG(const char *filename, uint *x, uint *y, std::vector
auto fp = FioFOpenFile(filename, "rb", HEIGHTMAP_DIR);
if (!fp.has_value()) {
ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_FILE_NOT_FOUND, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_ERROR_PNGMAP), GetEncodedString(STR_ERROR_PNGMAP_FILE_NOT_FOUND), WL_ERROR);
return false;
}
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (png_ptr == nullptr) {
ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_MISC, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_ERROR_PNGMAP), GetEncodedString(STR_ERROR_PNGMAP_MISC), WL_ERROR);
return false;
}
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == nullptr || setjmp(png_jmpbuf(png_ptr))) {
ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_MISC, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_ERROR_PNGMAP), GetEncodedString(STR_ERROR_PNGMAP_MISC), WL_ERROR);
png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
return false;
}
@ -168,7 +169,7 @@ static bool ReadHeightmapPNG(const char *filename, uint *x, uint *y, std::vector
/* Maps of wrong colour-depth are not used.
* (this should have been taken care of by stripping alpha and 16-bit samples on load) */
if ((png_get_channels(png_ptr, info_ptr) != 1) && (png_get_channels(png_ptr, info_ptr) != 3) && (png_get_bit_depth(png_ptr, info_ptr) != 8)) {
ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_IMAGE_TYPE, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_ERROR_PNGMAP), GetEncodedString(STR_ERROR_PNGMAP_IMAGE_TYPE), WL_ERROR);
png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
return false;
}
@ -177,7 +178,7 @@ static bool ReadHeightmapPNG(const char *filename, uint *x, uint *y, std::vector
uint height = png_get_image_height(png_ptr, info_ptr);
if (!IsValidHeightmapDimension(width, height)) {
ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_HEIGHTMAP_TOO_LARGE, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_ERROR_PNGMAP), GetEncodedString(STR_ERROR_HEIGHTMAP_TOO_LARGE), WL_ERROR);
png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
return false;
}
@ -259,7 +260,7 @@ static bool ReadHeightmapBMP(const char *filename, uint *x, uint *y, std::vector
{
auto f = FioFOpenFile(filename, "rb", HEIGHTMAP_DIR);
if (!f.has_value()) {
ShowErrorMessage(STR_ERROR_BMPMAP, STR_ERROR_PNGMAP_FILE_NOT_FOUND, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_ERROR_BMPMAP), GetEncodedString(STR_ERROR_PNGMAP_FILE_NOT_FOUND), WL_ERROR);
return false;
}
@ -268,18 +269,18 @@ static bool ReadHeightmapBMP(const char *filename, uint *x, uint *y, std::vector
BmpData data{};
if (!BmpReadHeader(file, info, data)) {
ShowErrorMessage(STR_ERROR_BMPMAP, STR_ERROR_BMPMAP_IMAGE_TYPE, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_ERROR_BMPMAP), GetEncodedString(STR_ERROR_BMPMAP_IMAGE_TYPE), WL_ERROR);
return false;
}
if (!IsValidHeightmapDimension(info.width, info.height)) {
ShowErrorMessage(STR_ERROR_BMPMAP, STR_ERROR_HEIGHTMAP_TOO_LARGE, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_ERROR_BMPMAP), GetEncodedString(STR_ERROR_HEIGHTMAP_TOO_LARGE), WL_ERROR);
return false;
}
if (map != nullptr) {
if (!BmpReadBitmap(file, info, data)) {
ShowErrorMessage(STR_ERROR_BMPMAP, STR_ERROR_BMPMAP_IMAGE_TYPE, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_ERROR_BMPMAP), GetEncodedString(STR_ERROR_BMPMAP_IMAGE_TYPE), WL_ERROR);
return false;
}

View File

@ -505,8 +505,11 @@ static CommandCost ClearTile_Industry(TileIndex tile, DoCommandFlags flags)
(_current_company == OWNER_WATER &&
(indspec->behaviour.Test(IndustryBehaviour::BuiltOnWater) ||
HasBit(GetIndustryTileSpec(GetIndustryGfx(tile))->slopes_refused, 5)))) {
SetDParam(1, indspec->name);
return CommandCost(flags.Test(DoCommandFlag::Auto) ? STR_ERROR_GENERIC_OBJECT_IN_THE_WAY : INVALID_STRING_ID);
if (flags.Test(DoCommandFlag::Auto)) {
return CommandCostWithParam(STR_ERROR_GENERIC_OBJECT_IN_THE_WAY, indspec->name);
}
return CommandCost(INVALID_STRING_ID);
}
if (flags.Test(DoCommandFlag::Execute)) {
@ -2103,9 +2106,9 @@ CommandCost CmdBuildIndustry(DoCommandFlags flags, TileIndex tile, IndustryType
}
if (ret.Failed() && IsLocalCompany()) {
if (prospect_success) {
ShowErrorMessage(STR_ERROR_CAN_T_PROSPECT_INDUSTRY, STR_ERROR_NO_SUITABLE_PLACES_FOR_PROSPECTING, WL_INFO);
ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_PROSPECT_INDUSTRY), GetEncodedString(STR_ERROR_NO_SUITABLE_PLACES_FOR_PROSPECTING), WL_INFO);
} else {
ShowErrorMessage(STR_ERROR_CAN_T_PROSPECT_INDUSTRY, STR_ERROR_PROSPECTING_WAS_UNLUCKY, WL_INFO);
ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_PROSPECT_INDUSTRY), GetEncodedString(STR_ERROR_PROSPECTING_WAS_UNLUCKY), WL_INFO);
}
}
}
@ -3095,8 +3098,8 @@ void CheckIndustries()
if (chance == 0 || !force_at_least_one) continue; // Types that are not available can be skipped.
const IndustrySpec *is = GetIndustrySpec(it);
SetDParam(0, is->name);
ShowErrorMessage(STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES, STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION, WL_WARNING);
ShowErrorMessage(GetEncodedString(STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES, is->name),
GetEncodedString(STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION), WL_WARNING);
count++;
if (count >= 3) break; // Don't swamp the user with errors.

View File

@ -259,8 +259,8 @@ void CcBuildIndustry(Commands, const CommandCost &result, TileIndex tile, Indust
if (indtype < NUM_INDUSTRYTYPES) {
const IndustrySpec *indsp = GetIndustrySpec(indtype);
if (indsp->enabled) {
SetDParam(0, indsp->name);
ShowErrorMessage(STR_ERROR_CAN_T_BUILD_HERE, result.GetErrorMessage(), WL_INFO, TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE);
ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_BUILD_HERE, indsp->name),
GetEncodedString(result.GetErrorMessage()), WL_INFO, TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE);
}
}
}
@ -605,7 +605,7 @@ public:
if (!confirmed) return;
if (Town::GetNumItems() == 0) {
ShowErrorMessage(STR_ERROR_CAN_T_GENERATE_INDUSTRIES, STR_ERROR_MUST_FOUND_TOWN_FIRST, WL_INFO);
ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_GENERATE_INDUSTRIES), GetEncodedString(STR_ERROR_MUST_FOUND_TOWN_FIRST), WL_INFO);
} else {
Backup<bool> old_generating_world(_generating_world, true);
BasePersistentStorageArray::SwitchMode(PSM_ENTER_GAMELOOP);
@ -712,8 +712,8 @@ public:
if (_game_mode == GM_EDITOR) {
/* Show error if no town exists at all */
if (Town::GetNumItems() == 0) {
SetDParam(0, indsp->name);
ShowErrorMessage(STR_ERROR_CAN_T_BUILD_HERE, STR_ERROR_MUST_FOUND_TOWN_FIRST, WL_INFO, pt.x, pt.y);
ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_BUILD_HERE, indsp->name),
GetEncodedString(STR_ERROR_MUST_FOUND_TOWN_FIRST), WL_INFO, pt.x, pt.y);
return;
}

View File

@ -345,7 +345,7 @@ struct SelectGameWindow : public Window {
case WID_SGI_PLAY_NETWORK:
if (!_network_available) {
ShowErrorMessage(STR_NETWORK_ERROR_NOTAVAILABLE, INVALID_STRING_ID, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_NETWORK_ERROR_NOTAVAILABLE), {}, WL_ERROR);
} else {
ShowNetworkGameWindow();
}
@ -363,7 +363,7 @@ struct SelectGameWindow : public Window {
case WID_SGI_GRF_SETTINGS: ShowNewGRFSettings(true, true, false, _grfconfig_newgame); break;
case WID_SGI_CONTENT_DOWNLOAD:
if (!_network_available) {
ShowErrorMessage(STR_NETWORK_ERROR_NOTAVAILABLE, INVALID_STRING_ID, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_NETWORK_ERROR_NOTAVAILABLE), {}, WL_ERROR);
} else {
ShowNetworkContentListWindow();
}

View File

@ -4999,7 +4999,7 @@ STR_ERROR_SCREENSHOT_FAILED :{WHITE}Screensh
# Error message titles
STR_ERROR_MESSAGE_CAPTION :{YELLOW}Message
STR_ERROR_MESSAGE_CAPTION_OTHER_COMPANY :{YELLOW}Message from {STRING1}
STR_ERROR_MESSAGE_CAPTION_OTHER_COMPANY :{YELLOW}Message from {COMPANY}
# Generic construction errors
STR_ERROR_OFF_EDGE_OF_MAP :{WHITE}Off edge of map
@ -5018,7 +5018,7 @@ STR_ERROR_TERRAFORM_LIMIT_REACHED :{WHITE}... land
STR_ERROR_CLEARING_LIMIT_REACHED :{WHITE}... tile clearing limit reached
STR_ERROR_TREE_PLANT_LIMIT_REACHED :{WHITE}... tree planting limit reached
STR_ERROR_NAME_MUST_BE_UNIQUE :{WHITE}Name must be unique
STR_ERROR_GENERIC_OBJECT_IN_THE_WAY :{WHITE}{1:STRING} in the way
STR_ERROR_GENERIC_OBJECT_IN_THE_WAY :{WHITE}{STRING} in the way
STR_ERROR_NOT_ALLOWED_WHILE_PAUSED :{WHITE}Not allowed while paused
# Local authority errors

View File

@ -41,8 +41,7 @@ CommandCost CmdIncreaseLoan(DoCommandFlags flags, LoanCommand cmd, Money amount)
Company *c = Company::Get(_current_company);
Money max_loan = c->GetMaxLoan();
if (c->current_loan >= max_loan) {
SetDParam(0, max_loan);
return CommandCost(STR_ERROR_MAXIMUM_PERMITTED_LOAN);
return CommandCostWithParam(STR_ERROR_MAXIMUM_PERMITTED_LOAN, max_loan);
}
Money loan;
@ -106,8 +105,7 @@ CommandCost CmdDecreaseLoan(DoCommandFlags flags, LoanCommand cmd, Money amount)
}
if (GetAvailableMoneyForCommand() < loan) {
SetDParam(0, loan);
return CommandCost(STR_ERROR_CURRENCY_REQUIRED);
return CommandCostWithParam(STR_ERROR_CURRENCY_REQUIRED, loan);
}
if (flags.Test(DoCommandFlag::Execute)) {

View File

@ -185,9 +185,12 @@ public:
for (uint i = 0; i < 4; i++) {
if (td.owner_type[i] == STR_NULL) continue;
SetDParam(0, STR_LAND_AREA_INFORMATION_OWNER_N_A);
if (td.owner[i] != OWNER_NONE && td.owner[i] != OWNER_WATER) SetDParamsForOwnedBy(td.owner[i], tile);
this->landinfo_data.push_back(GetString(td.owner_type[i]));
if (td.owner[i] != OWNER_NONE && td.owner[i] != OWNER_WATER) {
this->landinfo_data.push_back(GetString(td.owner_type[i], STR_LAND_AREA_INFORMATION_OWNER_N_A));
} else {
auto params = GetParamsForOwnedBy(td.owner[i], tile);
this->landinfo_data.push_back(GetStringWithArgs(td.owner_type[i], params));
}
}
/* Cost to clear/revenue when cleared */
@ -522,8 +525,7 @@ void ShowEstimatedCostOrIncome(Money cost, int x, int y)
cost = -cost;
msg = STR_MESSAGE_ESTIMATED_INCOME;
}
SetDParam(0, cost);
ShowErrorMessage(msg, INVALID_STRING_ID, WL_INFO, x, y);
ShowErrorMessage(GetEncodedString(msg, cost), {}, WL_INFO, x, y);
}
/**

View File

@ -15,6 +15,7 @@
#include "../network_internal.h"
#include "../../debug.h"
#include "../../error.h"
#include "../../strings_func.h"
#include "table/strings.h"
@ -43,7 +44,7 @@ NetworkRecvStatus NetworkGameSocketHandler::CloseConnection(bool)
ClientNetworkEmergencySave();
_switch_mode = SM_MENU;
_networking = false;
ShowErrorMessage(STR_NETWORK_ERROR_LOSTCONNECTION, INVALID_STRING_ID, WL_CRITICAL);
ShowErrorMessage(GetEncodedString(STR_NETWORK_ERROR_LOSTCONNECTION), {}, WL_CRITICAL);
return this->CloseConnection(NETWORK_RECV_STATUS_CLIENT_QUIT);
}

View File

@ -302,7 +302,7 @@ uint NetworkCalculateLag(const NetworkClientSocket *cs)
void ShowNetworkError(StringID error_string)
{
_switch_mode = SM_MENU;
ShowErrorMessage(error_string, INVALID_STRING_ID, WL_CRITICAL);
ShowErrorMessage(GetEncodedString(error_string), {}, WL_CRITICAL);
}
/**
@ -862,7 +862,7 @@ bool NetworkValidateServerName(std::string &server_name)
StrTrimInPlace(server_name);
if (!server_name.empty()) return true;
ShowErrorMessage(STR_NETWORK_ERROR_BAD_SERVER_NAME, INVALID_STRING_ID, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_NETWORK_ERROR_BAD_SERVER_NAME), {}, WL_ERROR);
return false;
}

View File

@ -508,7 +508,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_FULL(Packet &)
Debug(net, 9, "Client::Receive_SERVER_FULL()");
/* We try to join a server which is full */
ShowErrorMessage(STR_NETWORK_ERROR_SERVER_FULL, INVALID_STRING_ID, WL_CRITICAL);
ShowErrorMessage(GetEncodedString(STR_NETWORK_ERROR_SERVER_FULL), {}, WL_CRITICAL);
return NETWORK_RECV_STATUS_SERVER_FULL;
}
@ -518,7 +518,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_BANNED(Packet &
Debug(net, 9, "Client::Receive_SERVER_BANNED()");
/* We try to join a server where we are banned */
ShowErrorMessage(STR_NETWORK_ERROR_SERVER_BANNED, INVALID_STRING_ID, WL_CRITICAL);
ShowErrorMessage(GetEncodedString(STR_NETWORK_ERROR_SERVER_BANNED), {}, WL_CRITICAL);
return NETWORK_RECV_STATUS_SERVER_BANNED;
}
@ -624,10 +624,11 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR(Packet &p
if (error < (ptrdiff_t)lengthof(network_error_strings)) err = network_error_strings[error];
/* In case of kicking a client, we assume there is a kick message in the packet if we can read one byte */
if (error == NETWORK_ERROR_KICKED && p.CanReadFromPacket(1)) {
SetDParamStr(0, p.Recv_string(NETWORK_CHAT_LENGTH));
ShowErrorMessage(err, STR_NETWORK_ERROR_KICK_MESSAGE, WL_CRITICAL);
ShowErrorMessage(GetEncodedString(err),
GetEncodedString(STR_NETWORK_ERROR_KICK_MESSAGE, p.Recv_string(NETWORK_CHAT_LENGTH)),
WL_CRITICAL);
} else {
ShowErrorMessage(err, INVALID_STRING_ID, WL_CRITICAL);
ShowErrorMessage(GetEncodedString(err), {}, WL_CRITICAL);
}
/* Perform an emergency save if we had already entered the game */
@ -665,7 +666,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CHECK_NEWGRFS(P
}
/* NewGRF mismatch, bail out */
ShowErrorMessage(STR_NETWORK_ERROR_NEWGRF_MISMATCH, INVALID_STRING_ID, WL_CRITICAL);
ShowErrorMessage(GetEncodedString(STR_NETWORK_ERROR_NEWGRF_MISMATCH), {}, WL_CRITICAL);
return ret;
}
@ -831,7 +832,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet
this->last_packet = std::chrono::steady_clock::now();
if (!load_success) {
ShowErrorMessage(STR_NETWORK_ERROR_SAVEGAMEERROR, INVALID_STRING_ID, WL_CRITICAL);
ShowErrorMessage(GetEncodedString(STR_NETWORK_ERROR_SAVEGAMEERROR), {}, WL_CRITICAL);
return NETWORK_RECV_STATUS_SAVEGAME;
}
/* If the savegame has successfully loaded, ALL windows have been removed,
@ -1074,7 +1075,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_SHUTDOWN(Packet
/* Only when we're trying to join we really
* care about the server shutting down. */
if (this->status >= STATUS_JOIN) {
ShowErrorMessage(STR_NETWORK_MESSAGE_SERVER_SHUTDOWN, INVALID_STRING_ID, WL_CRITICAL);
ShowErrorMessage(GetEncodedString(STR_NETWORK_MESSAGE_SERVER_SHUTDOWN), {}, WL_CRITICAL);
}
if (this->status == STATUS_ACTIVE) ClientNetworkEmergencySave();
@ -1093,7 +1094,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEWGAME(Packet
* Client ID modulo 16 + 1 (value 0 means no reconnect).
* This way reconnects should be spread out a bit. */
_network_reconnect = _network_own_client_id % 16 + 1;
ShowErrorMessage(STR_NETWORK_MESSAGE_SERVER_REBOOT, INVALID_STRING_ID, WL_CRITICAL);
ShowErrorMessage(GetEncodedString(STR_NETWORK_MESSAGE_SERVER_REBOOT), {}, WL_CRITICAL);
}
if (this->status == STATUS_ACTIVE) ClientNetworkEmergencySave();
@ -1185,8 +1186,10 @@ void ClientNetworkGameSocketHandler::CheckConnection()
if (std::chrono::duration_cast<std::chrono::seconds>(last_lag) == std::chrono::duration_cast<std::chrono::seconds>(lag)) return;
last_lag = lag;
SetDParam(0, std::chrono::duration_cast<std::chrono::seconds>(lag).count());
ShowErrorMessage(STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION, STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION, WL_INFO);
ShowErrorMessage(
GetEncodedString(STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION),
GetEncodedString(STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION, std::chrono::duration_cast<std::chrono::seconds>(lag).count()),
WL_INFO);
}
@ -1276,7 +1279,7 @@ bool NetworkValidateClientName(std::string &client_name)
StrTrimInPlace(client_name);
if (NetworkIsValidClientName(client_name)) return true;
ShowErrorMessage(STR_NETWORK_ERROR_BAD_PLAYER_NAME, INVALID_STRING_ID, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_NETWORK_ERROR_BAD_PLAYER_NAME), {}, WL_ERROR);
return false;
}

View File

@ -16,6 +16,7 @@
#include "../fileio_func.h"
#include "../base_media_base.h"
#include "../settings_type.h"
#include "../strings_func.h"
#include "network_content.h"
#include "table/strings.h"
@ -496,7 +497,10 @@ bool ClientNetworkContentSocketHandler::Receive_SERVER_CONTENT(Packet &p)
size_t toRead = p.RemainingBytesToTransfer();
if (toRead != 0 && static_cast<size_t>(p.TransferOut(TransferOutFWrite, std::ref(this->curFile))) != toRead) {
CloseWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD);
ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD, STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE, WL_ERROR);
ShowErrorMessage(
GetEncodedString(STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD),
GetEncodedString(STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE),
WL_ERROR);
this->CloseConnection();
this->curFile.reset();
@ -529,7 +533,10 @@ bool ClientNetworkContentSocketHandler::BeforeDownload()
if (filename.empty() || !(this->curFile = FileHandle::Open(filename, "wb")).has_value()) {
/* Unless that fails of course... */
CloseWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD);
ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD, STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE, WL_ERROR);
ShowErrorMessage(
GetEncodedString(STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD),
GetEncodedString(STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE),
WL_ERROR);
return false;
}
}
@ -568,7 +575,7 @@ void ClientNetworkContentSocketHandler::AfterDownload()
this->OnDownloadComplete(this->curInfo->id);
} else {
ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_EXTRACT, INVALID_STRING_ID, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_CONTENT_ERROR_COULD_NOT_EXTRACT), {}, WL_ERROR);
}
}

View File

@ -957,7 +957,7 @@ public:
void OnConnect(bool success) override
{
if (!success) {
ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_CONNECT, INVALID_STRING_ID, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_CONTENT_ERROR_COULD_NOT_CONNECT), {}, WL_ERROR);
this->Close();
return;
}
@ -1150,7 +1150,10 @@ void ShowNetworkContentListWindow(ContentVector *cv, ContentType type1, ContentT
CloseWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_CONTENT_LIST);
new NetworkContentListWindow(_network_content_list_desc, cv != nullptr, types);
#else
ShowErrorMessage(STR_CONTENT_NO_ZLIB, STR_CONTENT_NO_ZLIB_SUB, WL_ERROR);
ShowErrorMessage(
GetEncodedString(STR_CONTENT_NO_ZLIB),
GetEncodedString(STR_CONTENT_NO_ZLIB_SUB),
WL_ERROR);
/* Connection failed... clean up the mess */
if (cv != nullptr) {
for (ContentInfo *ci : *cv) delete ci;

View File

@ -135,7 +135,7 @@ bool ClientNetworkCoordinatorSocketHandler::Receive_GC_ERROR(Packet &p)
return false;
case NETWORK_COORDINATOR_ERROR_REGISTRATION_FAILED:
ShowErrorMessage(STR_NETWORK_ERROR_COORDINATOR_REGISTRATION_FAILED, INVALID_STRING_ID, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_NETWORK_ERROR_COORDINATOR_REGISTRATION_FAILED), {}, WL_ERROR);
/* To prevent that we constantly try to reconnect, switch to local game. */
_settings_client.network.server_game_type = SERVER_GAME_TYPE_LOCAL;
@ -159,7 +159,7 @@ bool ClientNetworkCoordinatorSocketHandler::Receive_GC_ERROR(Packet &p)
}
case NETWORK_COORDINATOR_ERROR_REUSE_OF_INVITE_CODE:
ShowErrorMessage(STR_NETWORK_ERROR_COORDINATOR_REUSE_OF_INVITE_CODE, INVALID_STRING_ID, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_NETWORK_ERROR_COORDINATOR_REUSE_OF_INVITE_CODE), {}, WL_ERROR);
/* To prevent that we constantly battle for the same invite-code, switch to local game. */
_settings_client.network.server_game_type = SERVER_GAME_TYPE_LOCAL;
@ -184,7 +184,10 @@ bool ClientNetworkCoordinatorSocketHandler::Receive_GC_REGISTER_ACK(Packet &p)
_network_server_connection_type = (ConnectionType)p.Recv_uint8();
if (_network_server_connection_type == CONNECTION_TYPE_ISOLATED) {
ShowErrorMessage(STR_NETWORK_ERROR_COORDINATOR_ISOLATED, STR_NETWORK_ERROR_COORDINATOR_ISOLATED_DETAIL, WL_ERROR);
ShowErrorMessage(
GetEncodedString(STR_NETWORK_ERROR_COORDINATOR_ISOLATED),
GetEncodedString(STR_NETWORK_ERROR_COORDINATOR_ISOLATED_DETAIL),
WL_ERROR);
}
/* Users can change the invite code in the settings, but this has no effect

View File

@ -16,6 +16,7 @@
#include "house.h"
#include "industrytype.h"
#include "newgrf_config.h"
#include "company_func.h"
#include "clear_map.h"
#include "station_map.h"
#include "tree_map.h"
@ -489,8 +490,13 @@ CommandCost GetErrorMessageFromLocationCallbackResult(uint16_t cb_res, const GRF
}
}
/* If this error isn't for the local player then it won't be seen, so don't bother encoding anything. */
if (!IsLocalCompany()) return res;
/* Copy some parameters from the registers to the error message text ref. stack */
std::array<StringParameter, 20> params{};
res.UseTextRefStack(grffile, 4);
res.SetEncodedMessage(GetEncodedStringWithArgs(res.GetErrorMessage(), params));
return res;
}
@ -508,10 +514,9 @@ void ErrorUnknownCallbackResult(uint32_t grfid, uint16_t cbid, uint16_t cb_res)
if (grfconfig->grf_bugs.Test(GRFBug::UnknownCbResult)) {
grfconfig->grf_bugs.Set(GRFBug::UnknownCbResult);
SetDParamStr(0, grfconfig->GetName());
SetDParam(1, cbid);
SetDParam(2, cb_res);
ShowErrorMessage(STR_NEWGRF_BUGGY, STR_NEWGRF_BUGGY_UNKNOWN_CALLBACK_RESULT, WL_CRITICAL);
ShowErrorMessage(GetEncodedString(STR_NEWGRF_BUGGY, grfconfig->GetName()),
GetEncodedString(STR_NEWGRF_BUGGY_UNKNOWN_CALLBACK_RESULT, std::monostate{}, cbid, cb_res),
WL_CRITICAL);
}
/* debug output */

View File

@ -51,18 +51,18 @@ void ShowNewGRFError()
/* Only show Fatal and Error level messages */
if (!c->error.has_value() || (c->error->severity != STR_NEWGRF_ERROR_MSG_FATAL && c->error->severity != STR_NEWGRF_ERROR_MSG_ERROR)) continue;
SetDParamStr(0, c->GetName());
SetDParam (1, c->error->message != STR_NULL ? c->error->message : STR_JUST_RAW_STRING);
SetDParamStr(2, c->error->custom_message);
SetDParamStr(3, c->filename);
SetDParamStr(4, c->error->data);
for (uint i = 0; i < c->error->param_value.size(); i++) {
SetDParam(5 + i, c->error->param_value[i]);
}
std::vector<StringParameter> params;
params.emplace_back(c->GetName());
params.emplace_back(c->error->message != STR_NULL ? c->error->message : STR_JUST_RAW_STRING);
params.emplace_back(c->error->custom_message);
params.emplace_back(c->filename);
params.emplace_back(c->error->data);
for (const uint32_t &value : c->error->param_value) params.emplace_back(value);
if (c->error->severity == STR_NEWGRF_ERROR_MSG_FATAL) {
ShowErrorMessage(STR_NEWGRF_ERROR_FATAL_POPUP, INVALID_STRING_ID, WL_CRITICAL);
ShowErrorMessage(GetEncodedStringWithArgs(STR_NEWGRF_ERROR_FATAL_POPUP, params), {}, WL_CRITICAL);
} else {
ShowErrorMessage(STR_NEWGRF_ERROR_POPUP, INVALID_STRING_ID, WL_ERROR);
ShowErrorMessage(GetEncodedStringWithArgs(STR_NEWGRF_ERROR_POPUP, params), {}, WL_ERROR);
}
break;
}
@ -1131,7 +1131,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
case WID_NS_CONTENT_DOWNLOAD:
case WID_NS_CONTENT_DOWNLOAD2:
if (!_network_available) {
ShowErrorMessage(STR_NETWORK_ERROR_NOTAVAILABLE, INVALID_STRING_ID, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_NETWORK_ERROR_NOTAVAILABLE), {}, WL_ERROR);
} else {
this->CloseChildWindows(WC_QUERY_STRING); // Remove the parameter query window
@ -1487,13 +1487,13 @@ private:
/* Get number of non-static NewGRFs. */
size_t count = std::ranges::count_if(this->actives, [](const auto &gc) { return !gc->flags.Test(GRFConfigFlag::Static); });
if (count >= NETWORK_MAX_GRF_COUNT) {
ShowErrorMessage(STR_NEWGRF_TOO_MANY_NEWGRFS, INVALID_STRING_ID, WL_INFO);
ShowErrorMessage(GetEncodedString(STR_NEWGRF_TOO_MANY_NEWGRFS), {}, WL_INFO);
return false;
}
/* Check for duplicate GRF ID. */
if (std::ranges::any_of(this->actives, [&grfid = this->avail_sel->ident.grfid](const auto &gc) { return gc->ident.grfid == grfid; })) {
ShowErrorMessage(STR_NEWGRF_DUPLICATE_GRFID, INVALID_STRING_ID, WL_INFO);
ShowErrorMessage(GetEncodedString(STR_NEWGRF_DUPLICATE_GRFID), {}, WL_INFO);
return false;
}

View File

@ -615,9 +615,9 @@ void IndustryProductionCallback(Industry *ind, int reason)
* 'loop' is provided as 16 bits to the newgrf, so abort when those are exceeded. */
if (loop >= 0x10000) {
/* display error message */
SetDParamStr(0, spec->grf_prop.grffile->filename);
SetDParam(1, spec->name);
ShowErrorMessage(STR_NEWGRF_BUGGY, STR_NEWGRF_BUGGY_ENDLESS_PRODUCTION_CALLBACK, WL_WARNING);
ShowErrorMessage(GetEncodedString(STR_NEWGRF_BUGGY, spec->grf_prop.grffile->filename),
GetEncodedString(STR_NEWGRF_BUGGY_ENDLESS_PRODUCTION_CALLBACK, std::monostate{}, spec->name),
WL_WARNING);
/* abort the function early, this error isn't critical and will allow the game to continue to run */
break;
@ -630,10 +630,9 @@ void IndustryProductionCallback(Industry *ind, int reason)
if (group->version == 0xFF) {
/* Result was marked invalid on load, display error message */
SetDParamStr(0, spec->grf_prop.grffile->filename);
SetDParam(1, spec->name);
SetDParam(2, ind->location.tile);
ShowErrorMessage(STR_NEWGRF_BUGGY, STR_NEWGRF_BUGGY_INVALID_CARGO_PRODUCTION_CALLBACK, WL_WARNING);
ShowErrorMessage(GetEncodedString(STR_NEWGRF_BUGGY, spec->grf_prop.grffile->filename),
GetEncodedString(STR_NEWGRF_BUGGY_INVALID_CARGO_PRODUCTION_CALLBACK, std::monostate{}, spec->name, ind->location.tile),
WL_WARNING);
/* abort the function early, this error isn't critical and will allow the game to continue to run */
break;

View File

@ -721,8 +721,7 @@ int openttd_main(std::span<char * const> arguments)
if (!valid_graphics_set) {
BaseGraphics::SetSet(nullptr);
ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_BASE_GRAPHICS_NOT_FOUND);
msg.SetDParamStr(0, graphics_set);
ErrorMessageData msg(GetEncodedString(STR_CONFIG_ERROR), GetEncodedString(STR_CONFIG_ERROR_INVALID_BASE_GRAPHICS_NOT_FOUND, graphics_set));
ScheduleErrorMessage(msg);
}
@ -775,8 +774,7 @@ int openttd_main(std::span<char * const> arguments)
if (sounds_set.empty() || !BaseSounds::SetSet({})) {
UserError("Failed to find a sounds set. Please acquire a sounds set for OpenTTD. See section 1.4 of README.md.");
} else {
ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_BASE_SOUNDS_NOT_FOUND);
msg.SetDParamStr(0, sounds_set);
ErrorMessageData msg(GetEncodedString(STR_CONFIG_ERROR), GetEncodedString(STR_CONFIG_ERROR_INVALID_BASE_SOUNDS_NOT_FOUND, sounds_set));
ScheduleErrorMessage(msg);
}
}
@ -787,8 +785,7 @@ int openttd_main(std::span<char * const> arguments)
if (music_set.empty() || !BaseMusic::SetSet({})) {
UserError("Failed to find a music set. Please acquire a music set for OpenTTD. See section 1.4 of README.md.");
} else {
ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_BASE_MUSIC_NOT_FOUND);
msg.SetDParamStr(0, music_set);
ErrorMessageData msg(GetEncodedString(STR_CONFIG_ERROR), GetEncodedString(STR_CONFIG_ERROR_INVALID_BASE_MUSIC_NOT_FOUND, music_set));
ScheduleErrorMessage(msg);
}
}
@ -1159,7 +1156,7 @@ void SwitchToMode(SwitchMode new_mode)
case SM_MENU: // Switch to game intro menu
LoadIntroGame();
if (BaseSounds::ini_set.empty() && BaseSounds::GetUsedSet()->fallback && SoundDriver::GetInstance()->HasOutput()) {
ShowErrorMessage(STR_WARNING_FALLBACK_SOUNDSET, INVALID_STRING_ID, WL_CRITICAL);
ShowErrorMessage(GetEncodedString(STR_WARNING_FALLBACK_SOUNDSET), {}, WL_CRITICAL);
BaseSounds::ini_set = BaseSounds::GetUsedSet()->name;
}
if (_settings_client.network.participate_survey == PS_ASK) {

View File

@ -393,15 +393,15 @@ static Order GetOrderCmdFromTile(const Vehicle *v, TileIndex tile)
bool failed = false;
if (v->HasFullLoadOrder()) {
/* We don't allow unbunching if the vehicle has a full load order. */
ShowErrorMessage(STR_ERROR_CAN_T_INSERT_NEW_ORDER, STR_ERROR_UNBUNCHING_NO_UNBUNCHING_FULL_LOAD, WL_INFO);
ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_INSERT_NEW_ORDER), GetEncodedString(STR_ERROR_UNBUNCHING_NO_UNBUNCHING_FULL_LOAD), WL_INFO);
failed = true;
} else if (v->HasUnbunchingOrder()) {
/* Don't allow a new unbunching order if we already have one. */
ShowErrorMessage(STR_ERROR_CAN_T_INSERT_NEW_ORDER, STR_ERROR_UNBUNCHING_ONLY_ONE_ALLOWED, WL_INFO);
ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_INSERT_NEW_ORDER), GetEncodedString(STR_ERROR_UNBUNCHING_ONLY_ONE_ALLOWED), WL_INFO);
failed = true;
} else if (v->HasConditionalOrder()) {
/* We don't allow unbunching if the vehicle has a conditional order. */
ShowErrorMessage(STR_ERROR_CAN_T_INSERT_NEW_ORDER, STR_ERROR_UNBUNCHING_NO_UNBUNCHING_CONDITIONAL, WL_INFO);
ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_INSERT_NEW_ORDER), GetEncodedString(STR_ERROR_UNBUNCHING_NO_UNBUNCHING_CONDITIONAL), WL_INFO);
failed = true;
}
@ -1543,7 +1543,7 @@ public:
})) {
OnVehicleSelect(*begin);
} else {
ShowErrorMessage(STR_ERROR_CAN_T_COPY_ORDER_LIST, STR_ERROR_CAN_T_COPY_ORDER_VEHICLE_LIST, WL_INFO);
ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_COPY_ORDER_LIST), GetEncodedString(STR_ERROR_CAN_T_COPY_ORDER_VEHICLE_LIST), WL_INFO);
}
} else {
/* If CTRL is pressed: If all the vehicles in this list share orders, then copy orders */
@ -1552,7 +1552,7 @@ public:
})) {
OnVehicleSelect(*begin);
} else {
ShowErrorMessage(STR_ERROR_CAN_T_SHARE_ORDER_LIST, STR_ERROR_CAN_T_SHARE_ORDER_VEHICLE_LIST, WL_INFO);
ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_SHARE_ORDER_LIST), GetEncodedString(STR_ERROR_CAN_T_SHARE_ORDER_VEHICLE_LIST), WL_INFO);
}
}

View File

@ -303,8 +303,7 @@ CommandCost CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, R
if (KillFirstBit(n) != ROAD_NONE && (n & remove) != ROAD_NONE) {
/* you can remove all kind of roads with extra dynamite */
if (!_settings_game.construction.extra_dynamite) {
SetDParam(0, t->index);
return CommandCost(STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS);
return CommandCostWithParam(STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS, t->index);
}
rating_decrease = RATING_ROAD_DOWN_STEP_INNER;
}
@ -2515,8 +2514,12 @@ CommandCost CmdConvertRoad(DoCommandFlags flags, TileIndex tile, TileIndex area_
}
if (rtt == RTT_ROAD && owner == OWNER_TOWN) {
SetDParamsForOwnedBy(OWNER_TOWN, tile);
error.MakeError(STR_ERROR_OWNED_BY);
if (IsLocalCompany()) {
auto params = GetParamsForOwnedBy(OWNER_TOWN, tile);
error.SetEncodedMessage(GetEncodedStringWithArgs(STR_ERROR_OWNED_BY, params));
error.SetErrorOwner(owner);
}
continue;
}
}
@ -2568,8 +2571,12 @@ CommandCost CmdConvertRoad(DoCommandFlags flags, TileIndex tile, TileIndex area_
}
if (rtt == RTT_ROAD && owner == OWNER_TOWN) {
SetDParamsForOwnedBy(OWNER_TOWN, tile);
error.MakeError(STR_ERROR_OWNED_BY);
if (IsLocalCompany()) {
auto params = GetParamsForOwnedBy(OWNER_TOWN, tile);
error.SetEncodedMessage(GetEncodedStringWithArgs(STR_ERROR_OWNED_BY, params));
error.SetErrorOwner(owner);
}
continue;
}
}

View File

@ -22,6 +22,8 @@
#include "../clear_map.h"
#include "../vehicle_func.h"
#include "../string_func.h"
#include "../strings_func.h"
#include "../window_func.h"
#include "../roadveh.h"
#include "../roadveh_cmd.h"
#include "../train.h"
@ -70,7 +72,6 @@
#include <signal.h>
#include "../safeguards.h"
#include "../window_func.h"
extern Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMPANY);
@ -722,8 +723,8 @@ bool AfterLoadGame()
}
switch (gcf_res) {
case GLC_COMPATIBLE: ShowErrorMessage(STR_NEWGRF_COMPATIBLE_LOAD_WARNING, INVALID_STRING_ID, WL_CRITICAL); break;
case GLC_NOT_FOUND: ShowErrorMessage(STR_NEWGRF_DISABLED_WARNING, INVALID_STRING_ID, WL_CRITICAL); _pause_mode = PauseMode::Error; break;
case GLC_COMPATIBLE: ShowErrorMessage(GetEncodedString(STR_NEWGRF_COMPATIBLE_LOAD_WARNING), {}, WL_CRITICAL); break;
case GLC_NOT_FOUND: ShowErrorMessage(GetEncodedString(STR_NEWGRF_DISABLED_WARNING), {}, WL_CRITICAL); _pause_mode = PauseMode::Error; break;
default: break;
}
@ -1952,7 +1953,7 @@ bool AfterLoadGame()
* There would be trams without tram track under causing crashes sooner or later. */
for (RoadVehicle *v : RoadVehicle::Iterate()) {
if (v->First() == v && EngInfo(v->engine_type)->misc_flags.Test(EngineMiscFlag::RoadIsTram)) {
ShowErrorMessage(STR_WARNING_LOADGAME_REMOVED_TRAMS, INVALID_STRING_ID, WL_CRITICAL);
ShowErrorMessage(GetEncodedString(STR_WARNING_LOADGAME_REMOVED_TRAMS), {}, WL_CRITICAL);
delete v;
}
}

View File

@ -42,6 +42,7 @@
#include "../string_func.h"
#include "../fios.h"
#include "../error.h"
#include "../strings_type.h"
#include "../newgrf_railtype.h"
#include "../newgrf_roadtype.h"
@ -2827,8 +2828,10 @@ static std::pair<const SaveLoadFormat &, uint8_t> GetSavegameFormat(const std::s
size_t processed;
long level = std::stol(complevel, &processed, 10);
if (processed == 0 || level != Clamp(level, slf.min_compression, slf.max_compression)) {
SetDParamStr(0, complevel);
ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL, WL_CRITICAL);
ShowErrorMessage(
GetEncodedString(STR_CONFIG_ERROR),
GetEncodedString(STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL, complevel),
WL_CRITICAL);
} else {
return {slf, ClampTo<uint8_t>(level)};
}
@ -2837,9 +2840,10 @@ static std::pair<const SaveLoadFormat &, uint8_t> GetSavegameFormat(const std::s
}
}
SetDParamStr(0, name);
SetDParamStr(1, def.name);
ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM, WL_CRITICAL);
ShowErrorMessage(
GetEncodedString(STR_CONFIG_ERROR),
GetEncodedString(STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM, name, def.name),
WL_CRITICAL);
}
return {def, def.default_compression};
}
@ -2900,16 +2904,15 @@ void SetSaveLoadError(StringID str)
}
/** Return the appropriate initial string for an error depending on whether we are saving or loading. */
StringID GetSaveLoadErrorType()
EncodedString GetSaveLoadErrorType()
{
return _sl.action == SLA_SAVE ? STR_ERROR_GAME_SAVE_FAILED : STR_ERROR_GAME_LOAD_FAILED;
return GetEncodedString(_sl.action == SLA_SAVE ? STR_ERROR_GAME_SAVE_FAILED : STR_ERROR_GAME_LOAD_FAILED);
}
/** Return the description of the error. **/
StringID GetSaveLoadErrorMessage()
EncodedString GetSaveLoadErrorMessage()
{
SetDParamStr(0, _sl.extra_msg);
return _sl.error_str;
return GetEncodedString(_sl.error_str, _sl.extra_msg);
}
/** Show a gui message when saving has failed */
@ -2949,7 +2952,7 @@ static SaveOrLoadResult SaveFileToDisk(bool threaded)
* cancelled due to a client disconnecting. */
if (_sl.error_str != STR_NETWORK_ERROR_LOSTCONNECTION) {
/* Skip the "colour" character */
Debug(sl, 0, "{}", GetString(GetSaveLoadErrorType()).substr(3) + GetString(GetSaveLoadErrorMessage()));
Debug(sl, 0, "{}", GetSaveLoadErrorType().GetDecodedString().substr(3) + GetSaveLoadErrorMessage().GetDecodedString());
asfp = SaveFileError;
}
@ -3197,7 +3200,7 @@ SaveOrLoadResult SaveOrLoad(const std::string &filename, SaveLoadOperation fop,
/* An instance of saving is already active, so don't go saving again */
if (_sl.saveinprogress && fop == SLO_SAVE && dft == DFT_GAME_FILE && threaded) {
/* if not an autosave, but a user action, show error message */
if (!_do_autosave) ShowErrorMessage(STR_ERROR_SAVE_STILL_IN_PROGRESS, INVALID_STRING_ID, WL_ERROR);
if (!_do_autosave) ShowErrorMessage(GetEncodedString(STR_ERROR_SAVE_STILL_IN_PROGRESS), {}, WL_ERROR);
return SL_OK;
}
WaitTillSaved();
@ -3271,7 +3274,7 @@ SaveOrLoadResult SaveOrLoad(const std::string &filename, SaveLoadOperation fop,
ClearSaveLoadState();
/* Skip the "colour" character */
if (fop != SLO_CHECK) Debug(sl, 0, "{}", GetString(GetSaveLoadErrorType()).substr(3) + GetString(GetSaveLoadErrorMessage()));
if (fop != SLO_CHECK) Debug(sl, 0, "{}", GetSaveLoadErrorType().GetDecodedString().substr(3) + GetSaveLoadErrorMessage().GetDecodedString());
/* A saver/loader exception!! reinitialize all variables to prevent crash! */
return (fop == SLO_LOAD) ? SL_REINIT : SL_ERROR;
@ -3295,7 +3298,7 @@ void DoAutoOrNetsave(FiosNumberedSaveName &counter)
Debug(sl, 2, "Autosaving to '{}'", filename);
if (SaveOrLoad(filename, SLO_SAVE, DFT_GAME_FILE, AUTOSAVE_DIR) != SL_OK) {
ShowErrorMessage(STR_ERROR_AUTOSAVE_FAILED, INVALID_STRING_ID, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_ERROR_AUTOSAVE_FAILED), {}, WL_ERROR);
}
}

View File

@ -437,8 +437,8 @@ extern FileToSaveLoad _file_to_saveload;
std::string GenerateDefaultSaveName();
void SetSaveLoadError(StringID str);
StringID GetSaveLoadErrorType();
StringID GetSaveLoadErrorMessage();
EncodedString GetSaveLoadErrorType();
EncodedString GetSaveLoadErrorMessage();
SaveOrLoadResult SaveOrLoad(const std::string &filename, SaveLoadOperation fop, DetailedFileType dft, Subdirectory sb, bool threaded = true);
void WaitTillSaved();
void ProcessAsyncSaveFinish();

View File

@ -433,15 +433,12 @@ static bool RealMakeScreenshot(ScreenshotType t, std::string name, uint32_t widt
if (ret) {
if (t == SC_HEIGHTMAP) {
SetDParamStr(0, _screenshot_name);
SetDParam(1, _heightmap_highest_peak);
ShowErrorMessage(STR_MESSAGE_HEIGHTMAP_SUCCESSFULLY, INVALID_STRING_ID, WL_WARNING);
ShowErrorMessage(GetEncodedString(STR_MESSAGE_HEIGHTMAP_SUCCESSFULLY, _screenshot_name, _heightmap_highest_peak), {}, WL_WARNING);
} else {
SetDParamStr(0, _screenshot_name);
ShowErrorMessage(STR_MESSAGE_SCREENSHOT_SUCCESSFULLY, INVALID_STRING_ID, WL_WARNING);
ShowErrorMessage(GetEncodedString(STR_MESSAGE_SCREENSHOT_SUCCESSFULLY, _screenshot_name), {}, WL_WARNING);
}
} else {
ShowErrorMessage(STR_ERROR_SCREENSHOT_FAILED, INVALID_STRING_ID, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_ERROR_SCREENSHOT_FAILED), {}, WL_ERROR);
}
return ret;

View File

@ -1324,7 +1324,7 @@ Window *ShowScriptDebugWindow(CompanyID show_company, bool new_window)
}
return new ScriptDebugWindow(_script_debug_desc, i, show_company);
} else {
ShowErrorMessage(STR_ERROR_AI_DEBUG_SERVER_ONLY, INVALID_STRING_ID, WL_INFO);
ShowErrorMessage(GetEncodedString(STR_ERROR_AI_DEBUG_SERVER_ONLY), {}, WL_INFO);
}
return nullptr;

View File

@ -33,6 +33,7 @@
#include "console_func.h"
#include "genworld.h"
#include "string_func.h"
#include "strings_func.h"
#include "window_func.h"
#include "company_func.h"
#include "rev.h"
@ -381,16 +382,15 @@ size_t IntSettingDesc::ParseValue(const char *str) const
char *end;
size_t val = std::strtoul(str, &end, 0);
if (end == str) {
ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE);
msg.SetDParamStr(0, str);
msg.SetDParamStr(1, this->GetName());
_settings_error_list.push_back(msg);
_settings_error_list.emplace_back(
GetEncodedString(STR_CONFIG_ERROR),
GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
return this->GetDefaultValue();
}
if (*end != '\0') {
ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_TRAILING_CHARACTERS);
msg.SetDParamStr(0, this->GetName());
_settings_error_list.push_back(msg);
_settings_error_list.emplace_back(
GetEncodedString(STR_CONFIG_ERROR),
GetEncodedString(STR_CONFIG_ERROR_TRAILING_CHARACTERS, this->GetName()));
}
return val;
}
@ -403,10 +403,9 @@ size_t OneOfManySettingDesc::ParseValue(const char *str) const
if (r == SIZE_MAX && this->many_cnvt != nullptr) r = this->many_cnvt(str);
if (r != SIZE_MAX) return r; // and here goes converted value
ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE);
msg.SetDParamStr(0, str);
msg.SetDParamStr(1, this->GetName());
_settings_error_list.push_back(msg);
_settings_error_list.emplace_back(
GetEncodedString(STR_CONFIG_ERROR),
GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
return this->GetDefaultValue();
}
@ -414,10 +413,10 @@ size_t ManyOfManySettingDesc::ParseValue(const char *str) const
{
size_t r = LookupManyOfMany(this->many, str);
if (r != SIZE_MAX) return r;
ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE);
msg.SetDParamStr(0, str);
msg.SetDParamStr(1, this->GetName());
_settings_error_list.push_back(msg);
_settings_error_list.emplace_back(
GetEncodedString(STR_CONFIG_ERROR),
GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
return this->GetDefaultValue();
}
@ -426,10 +425,9 @@ size_t BoolSettingDesc::ParseValue(const char *str) const
auto r = BoolSettingDesc::ParseSingleValue(str);
if (r.has_value()) return *r;
ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE);
msg.SetDParamStr(0, str);
msg.SetDParamStr(1, this->GetName());
_settings_error_list.push_back(msg);
_settings_error_list.emplace_back(
GetEncodedString(STR_CONFIG_ERROR),
GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
return this->GetDefaultValue();
}
@ -690,9 +688,9 @@ void ListSettingDesc::ParseValue(const IniItem *item, void *object) const
const char *str = (item == nullptr) ? this->def : item->value.has_value() ? item->value->c_str() : nullptr;
void *ptr = GetVariableAddress(object, this->save);
if (!LoadIntList(str, ptr, this->save.length, GetVarMemType(this->save.conv))) {
ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY);
msg.SetDParamStr(0, this->GetName());
_settings_error_list.push_back(msg);
_settings_error_list.emplace_back(
GetEncodedString(STR_CONFIG_ERROR),
GetEncodedString(STR_CONFIG_ERROR_ARRAY, this->GetName()));
/* Use default */
LoadIntList(this->def, ptr, this->save.length, GetVarMemType(this->save.conv));
@ -1035,8 +1033,9 @@ static void GraphicsSetLoadConfig(IniFile &ini)
if (params.has_value()) {
BaseGraphics::ini_data.extra_params = params.value();
} else {
SetDParamStr(0, BaseGraphics::ini_data.name);
ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY, WL_CRITICAL);
ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
GetEncodedString(STR_CONFIG_ERROR_ARRAY, BaseGraphics::ini_data.name),
WL_CRITICAL);
}
}
}
@ -1101,36 +1100,39 @@ static GRFConfigList GRFLoadConfig(const IniFile &ini, const char *grpname, bool
if (params.has_value()) {
c->SetParams(params.value());
} else {
SetDParamStr(0, filename);
ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY, WL_CRITICAL);
ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
GetEncodedString(STR_CONFIG_ERROR_ARRAY, filename),
WL_CRITICAL);
}
}
/* Check if item is valid */
if (!FillGRFDetails(*c, is_static) || c->flags.Test(GRFConfigFlag::Invalid)) {
StringID reason;
if (c->status == GCS_NOT_FOUND) {
SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_NOT_FOUND);
reason = STR_CONFIG_ERROR_INVALID_GRF_NOT_FOUND;
} else if (c->flags.Test(GRFConfigFlag::Unsafe)) {
SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_UNSAFE);
reason = STR_CONFIG_ERROR_INVALID_GRF_UNSAFE;
} else if (c->flags.Test(GRFConfigFlag::System)) {
SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_SYSTEM);
reason = STR_CONFIG_ERROR_INVALID_GRF_SYSTEM;
} else if (c->flags.Test(GRFConfigFlag::Invalid)) {
SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_INCOMPATIBLE);
reason = STR_CONFIG_ERROR_INVALID_GRF_INCOMPATIBLE;
} else {
SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN);
reason = STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN;
}
SetDParamStr(0, filename.empty() ? item.name.c_str() : filename);
ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_GRF, WL_CRITICAL);
ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
GetEncodedString(STR_CONFIG_ERROR_INVALID_GRF, filename.empty() ? item.name.c_str() : filename, reason),
WL_CRITICAL);
continue;
}
/* Check for duplicate GRFID (will also check for duplicate filenames) */
auto found = std::ranges::find_if(list, [&c](const auto &gc) { return gc->ident.grfid == c->ident.grfid; });
if (found != std::end(list)) {
SetDParamStr(0, c->filename);
SetDParamStr(1, (*found)->filename);
ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_DUPLICATE_GRFID, WL_CRITICAL);
ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
GetEncodedString(STR_CONFIG_ERROR_DUPLICATE_GRFID, c->filename, (*found)->filename),
WL_CRITICAL);
continue;
}
@ -1139,7 +1141,8 @@ static GRFConfigList GRFLoadConfig(const IniFile &ini, const char *grpname, bool
c->flags.Set(GRFConfigFlag::Static);
} else if (++num_grfs > NETWORK_MAX_GRF_COUNT) {
/* Check we will not load more non-static NewGRFs than allowed. This could trigger issues for game servers. */
ShowErrorMessage(STR_CONFIG_ERROR, STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED, WL_CRITICAL);
ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
GetEncodedString(STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED), WL_CRITICAL);
break;
}

View File

@ -717,7 +717,7 @@ struct GameOptionsWindow : Window {
case WID_GO_FULLSCREEN_BUTTON: // Click fullscreen on/off
/* try to toggle full-screen on/off */
if (!ToggleFullScreen(!_fullscreen)) {
ShowErrorMessage(STR_ERROR_FULLSCREEN_FAILED, INVALID_STRING_ID, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_ERROR_FULLSCREEN_FAILED), {}, WL_ERROR);
}
this->SetWidgetLoweredState(WID_GO_FULLSCREEN_BUTTON, _fullscreen);
this->SetWidgetDirty(WID_GO_FULLSCREEN_BUTTON);
@ -725,7 +725,7 @@ struct GameOptionsWindow : Window {
case WID_GO_VIDEO_ACCEL_BUTTON:
_video_hw_accel = !_video_hw_accel;
ShowErrorMessage(STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART, INVALID_STRING_ID, WL_INFO);
ShowErrorMessage(GetEncodedString(STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART), {}, WL_INFO);
this->SetWidgetLoweredState(WID_GO_VIDEO_ACCEL_BUTTON, _video_hw_accel);
this->SetWidgetDirty(WID_GO_VIDEO_ACCEL_BUTTON);
#ifndef __APPLE__
@ -880,7 +880,7 @@ struct GameOptionsWindow : Window {
if (!list.empty()) {
ShowDropDownList(this, std::move(list), selected, widget);
} else {
if (widget == WID_GO_RESOLUTION_DROPDOWN) ShowErrorMessage(STR_ERROR_RESOLUTION_LIST_FAILED, INVALID_STRING_ID, WL_ERROR);
if (widget == WID_GO_RESOLUTION_DROPDOWN) ShowErrorMessage(GetEncodedString(STR_ERROR_RESOLUTION_LIST_FAILED), {}, WL_ERROR);
}
break;
}
@ -936,7 +936,7 @@ struct GameOptionsWindow : Window {
if (_settings_client.gui.refresh_rate > 60) {
/* Show warning to the user that this refresh rate might not be suitable on
* larger maps with many NewGRFs and vehicles. */
ShowErrorMessage(STR_GAME_OPTIONS_REFRESH_RATE_WARNING, INVALID_STRING_ID, WL_INFO);
ShowErrorMessage(GetEncodedString(STR_GAME_OPTIONS_REFRESH_RATE_WARNING), {}, WL_INFO);
}
break;
}

View File

@ -421,7 +421,7 @@ static void MaxNoAIsChange(int32_t)
if (GetGameSettings().difficulty.max_no_competitors != 0 &&
AI::GetInfoList()->empty() &&
(!_networking || _network_server)) {
ShowErrorMessage(STR_WARNING_NO_SUITABLE_AI, INVALID_STRING_ID, WL_CRITICAL);
ShowErrorMessage(GetEncodedString(STR_WARNING_NO_SUITABLE_AI), {}, WL_CRITICAL);
}
InvalidateWindowClassesData(WC_GAME_OPTIONS, 0);
@ -457,39 +457,39 @@ static bool CheckFreeformEdges(int32_t &new_value)
for (Ship *s : Ship::Iterate()) {
/* Check if there is a ship on the northern border. */
if (TileX(s->tile) == 0 || TileY(s->tile) == 0) {
ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_EMPTY, INVALID_STRING_ID, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_CONFIG_SETTING_EDGES_NOT_EMPTY), {}, WL_ERROR);
return false;
}
}
for (const BaseStation *st : BaseStation::Iterate()) {
/* Check if there is a non-deleted buoy on the northern border. */
if (st->IsInUse() && (TileX(st->xy) == 0 || TileY(st->xy) == 0)) {
ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_EMPTY, INVALID_STRING_ID, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_CONFIG_SETTING_EDGES_NOT_EMPTY), {}, WL_ERROR);
return false;
}
}
} else {
for (uint i = 0; i < Map::MaxX(); i++) {
if (TileHeight(TileXY(i, 1)) != 0) {
ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_WATER, INVALID_STRING_ID, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_CONFIG_SETTING_EDGES_NOT_WATER), {}, WL_ERROR);
return false;
}
}
for (uint i = 1; i < Map::MaxX(); i++) {
if (!IsTileType(TileXY(i, Map::MaxY() - 1), MP_WATER) || TileHeight(TileXY(1, Map::MaxY())) != 0) {
ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_WATER, INVALID_STRING_ID, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_CONFIG_SETTING_EDGES_NOT_WATER), {}, WL_ERROR);
return false;
}
}
for (uint i = 0; i < Map::MaxY(); i++) {
if (TileHeight(TileXY(1, i)) != 0) {
ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_WATER, INVALID_STRING_ID, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_CONFIG_SETTING_EDGES_NOT_WATER), {}, WL_ERROR);
return false;
}
}
for (uint i = 1; i < Map::MaxY(); i++) {
if (!IsTileType(TileXY(Map::MaxX() - 1, i), MP_WATER) || TileHeight(TileXY(Map::MaxX(), i)) != 0) {
ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_WATER, INVALID_STRING_ID, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_CONFIG_SETTING_EDGES_NOT_WATER), {}, WL_ERROR);
return false;
}
}
@ -527,7 +527,7 @@ static bool CheckDynamicEngines(int32_t &)
if (_game_mode == GM_MENU) return true;
if (!EngineOverrideManager::ResetToCurrentNewGRFConfig()) {
ShowErrorMessage(STR_CONFIG_SETTING_DYNAMIC_ENGINES_EXISTING_VEHICLES, INVALID_STRING_ID, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_CONFIG_SETTING_DYNAMIC_ENGINES_EXISTING_VEHICLES), {}, WL_ERROR);
return false;
}
@ -543,7 +543,7 @@ static bool CheckMaxHeightLevel(int32_t &new_value)
* If yes, disallow the change. */
for (const auto t : Map::Iterate()) {
if ((int32_t)TileHeight(t) > new_value) {
ShowErrorMessage(STR_CONFIG_SETTING_TOO_HIGH_MOUNTAIN, INVALID_STRING_ID, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_CONFIG_SETTING_TOO_HIGH_MOUNTAIN), {}, WL_ERROR);
/* Return old, unchanged value */
return false;
}

View File

@ -14,6 +14,7 @@
#include "gfx_func.h"
#include "error.h"
#include "error_func.h"
#include "strings_func.h"
#include "zoom_func.h"
#include "settings_type.h"
#include "blitter/factory.hpp"
@ -1028,9 +1029,7 @@ static void GfxInitSpriteCache()
if (_allocated_sprite_cache_size != target_size) {
Debug(misc, 0, "Not enough memory to allocate {} MiB of spritecache. Spritecache was reduced to {} MiB.", target_size / 1024 / 1024, _allocated_sprite_cache_size / 1024 / 1024);
ErrorMessageData msg(STR_CONFIG_ERROR_OUT_OF_MEMORY, STR_CONFIG_ERROR_SPRITECACHE_TOO_BIG);
msg.SetDParam(0, target_size);
msg.SetDParam(1, _allocated_sprite_cache_size);
ErrorMessageData msg(GetEncodedString(STR_CONFIG_ERROR_OUT_OF_MEMORY), GetEncodedString(STR_CONFIG_ERROR_SPRITECACHE_TOO_BIG, target_size, _allocated_sprite_cache_size));
ScheduleErrorMessage(msg);
}
}

View File

@ -36,8 +36,7 @@ static bool WarnCorruptSprite(const SpriteFile &file, size_t file_pos, int line)
{
static uint8_t warning_level = 0;
if (warning_level == 0) {
SetDParamStr(0, file.GetSimplifiedFilename());
ShowErrorMessage(STR_NEWGRF_ERROR_CORRUPT_SPRITE, INVALID_STRING_ID, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_NEWGRF_ERROR_CORRUPT_SPRITE, file.GetSimplifiedFilename()), {}, WL_ERROR);
}
Debug(sprite, warning_level, "[{}] Loading corrupted sprite from {} at position {}", line, file.GetSimplifiedFilename(), file_pos);
warning_level = 6;

View File

@ -2580,8 +2580,7 @@ CommandCost CmdBuildAirport(DoCommandFlags flags, TileIndex tile, uint8_t airpor
}
if (authority_refuse_message != STR_NULL) {
SetDParam(0, authority_refuse_town->index);
return CommandCost(authority_refuse_message);
return CommandCostWithParam(authority_refuse_message, authority_refuse_town->index);
}
Station *st = nullptr;
@ -4709,8 +4708,7 @@ CommandCost ClearTile_Station(TileIndex tile, DoCommandFlags flags)
case StationType::Buoy: return CommandCost(STR_ERROR_BUOY_IN_THE_WAY);
case StationType::Dock: return CommandCost(STR_ERROR_MUST_DEMOLISH_DOCK_FIRST);
case StationType::Oilrig:
SetDParam(1, STR_INDUSTRY_NAME_OIL_RIG);
return CommandCost(STR_ERROR_GENERIC_OBJECT_IN_THE_WAY);
return CommandCostWithParam(STR_ERROR_GENERIC_OBJECT_IN_THE_WAY, STR_INDUSTRY_NAME_OIL_RIG);
}
}

View File

@ -2404,8 +2404,7 @@ void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher)
* with the colour marker. */
static std::string err_str("XXXThe current font is missing some of the characters used in the texts for this language. Using system fallback font instead.");
Utf8Encode(err_str.data(), SCC_YELLOW);
SetDParamStr(0, err_str);
ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_WARNING);
ShowErrorMessage(GetEncodedString(STR_JUST_RAW_STRING, err_str), {}, WL_WARNING);
}
if (bad_font && base_font) {
@ -2425,8 +2424,7 @@ void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher)
* the string, which takes exactly three characters, so it replaces the "XXX" with the colour marker. */
static std::string err_str("XXXThe current font is missing some of the characters used in the texts for this language. Go to Help & Manuals > Fonts, or read the file docs/fonts.md in your OpenTTD directory, to see how to solve this.");
Utf8Encode(err_str.data(), SCC_YELLOW);
SetDParamStr(0, err_str);
ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_WARNING);
ShowErrorMessage(GetEncodedString(STR_JUST_RAW_STRING, err_str), {}, WL_WARNING);
/* Reset the font width */
LoadStringWidthTable(searcher->Monospace());
@ -2453,8 +2451,7 @@ void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher)
if (_current_text_dir != TD_LTR) {
static std::string err_str("XXXThis version of OpenTTD does not support right-to-left languages. Recompile with ICU + Harfbuzz enabled.");
Utf8Encode(err_str.data(), SCC_YELLOW);
SetDParamStr(0, err_str);
ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
ShowErrorMessage(GetEncodedString(STR_JUST_RAW_STRING, err_str), {}, WL_ERROR);
}
#endif /* !(WITH_ICU_I18N && WITH_HARFBUZZ) && !WITH_UNISCRIBE && !WITH_COCOA */
}

View File

@ -138,6 +138,18 @@ std::string GetString(StringID string, Args &&... args)
EncodedString GetEncodedString(StringID str);
EncodedString GetEncodedStringWithArgs(StringID str, std::span<const StringParameter> params);
/**
* Encode a string with no parameters into an encoded string, if the string id is valid.
* @note the return encoded string will be empty if the string id is not valid.
* @param str String to encode.
* @returns an EncodedString.
*/
static inline EncodedString GetEncodedStringIfValid(StringID str)
{
if (str == INVALID_STRING_ID) return {};
return GetEncodedString(str);
}
/**
* Get an encoded string with parameters.
* @param string String ID to encode.

View File

@ -731,13 +731,11 @@ static CommandCost ClearTile_Town(TileIndex tile, DoCommandFlags flags)
if (!_cheats.magic_bulldozer.value && !flags.Test(DoCommandFlag::NoTestTownRating)) {
/* NewGRFs can add indestructible houses. */
if (rating > RATING_MAXIMUM) {
SetDParam(0, t->index);
return CommandCost(CMD_ERROR);
}
/* If town authority controls removal, check the company's rating. */
if (rating > t->ratings[_current_company] && _settings_game.difficulty.town_council_tolerance != TOWN_COUNCIL_PERMISSIVE) {
SetDParam(0, t->index);
return CommandCost(STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS);
return CommandCostWithParam(STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS, t->index);
}
}
}
@ -1020,10 +1018,14 @@ bool CheckTownRoadTypes()
if (min_date <= TimerGameCalendar::date) return true;
if (min_date < INT32_MAX) {
SetDParam(0, min_date);
ShowErrorMessage(STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_YET, STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_YET_EXPLANATION, WL_CRITICAL);
ShowErrorMessage(
GetEncodedString(STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_YET),
GetEncodedString(STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_YET_EXPLANATION, min_date),
WL_CRITICAL);
} else {
ShowErrorMessage(STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_AT_ALL, STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_AT_ALL_EXPLANATION, WL_CRITICAL);
ShowErrorMessage(
GetEncodedString(STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_AT_ALL),
GetEncodedString(STR_ERROR_NO_TOWN_ROADTYPES_AVAILABLE_AT_ALL_EXPLANATION), WL_CRITICAL);
}
return false;
}
@ -2468,7 +2470,7 @@ bool GenerateTowns(TownLayout layout)
/* If there are no towns at all and we are generating new game, bail out */
if (Town::GetNumItems() == 0 && _game_mode != GM_EDITOR) {
ShowErrorMessage(STR_ERROR_COULD_NOT_CREATE_TOWN, INVALID_STRING_ID, WL_CRITICAL);
ShowErrorMessage(GetEncodedString(STR_ERROR_COULD_NOT_CREATE_TOWN), {}, WL_CRITICAL);
}
return false; // we are still without a town? we failed, simply
@ -3598,7 +3600,7 @@ static CommandCost TownActionBribe(Town *t, DoCommandFlags flags)
/* only show error message to the executing player. All errors are handled command.c
* but this is special, because it can only 'fail' on a DoCommandFlag::Execute */
if (IsLocalCompany()) ShowErrorMessage(STR_ERROR_BRIBE_FAILED, INVALID_STRING_ID, WL_INFO);
if (IsLocalCompany()) ShowErrorMessage(GetEncodedString(STR_ERROR_BRIBE_FAILED), {}, WL_INFO);
/* decrease by a lot!
* ChangeTownRating is only for stuff in demolishing. Bribe failure should
@ -3898,8 +3900,7 @@ CommandCost CheckIfAuthorityAllowsNewStation(TileIndex tile, DoCommandFlags flag
if (t->ratings[_current_company] > RATING_VERYPOOR) return CommandCost();
SetDParam(0, t->index);
return CommandCost(STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS);
return CommandCostWithParam(STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS, t->index);
}
/**
@ -4068,8 +4069,7 @@ CommandCost CheckforTownRating(DoCommandFlags flags, Town *t, TownRatingCheckTyp
int needed = needed_rating[_settings_game.difficulty.town_council_tolerance][type];
if (GetRating(t) < needed) {
SetDParam(0, t->index);
return CommandCost(STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS);
return CommandCostWithParam(STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS, t->index);
}
return CommandCost();

View File

@ -1274,7 +1274,7 @@ public:
Backup<bool> old_generating_world(_generating_world, true);
UpdateNearestTownForRoadTiles(true);
if (!GenerateTowns(this->town_layout)) {
ShowErrorMessage(STR_ERROR_CAN_T_GENERATE_TOWN, STR_ERROR_NO_SPACE_FOR_TOWN, WL_INFO);
ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_GENERATE_TOWN), GetEncodedString(STR_ERROR_NO_SPACE_FOR_TOWN), WL_INFO);
}
UpdateNearestTownForRoadTiles(false);
old_generating_world.Restore();

View File

@ -84,9 +84,7 @@ void CheckTrainsLengths()
if ((w->track != TRACK_BIT_DEPOT &&
std::max(abs(u->x_pos - w->x_pos), abs(u->y_pos - w->y_pos)) != u->CalcNextVehicleOffset()) ||
(w->track == TRACK_BIT_DEPOT && TicksToLeaveDepot(u) <= 0)) {
SetDParam(0, v->index);
SetDParam(1, v->owner);
ShowErrorMessage(STR_BROKEN_VEHICLE_LENGTH, INVALID_STRING_ID, WL_CRITICAL);
ShowErrorMessage(GetEncodedString(STR_BROKEN_VEHICLE_LENGTH, v->index, v->owner), {}, WL_CRITICAL);
if (!_networking && first) {
first = false;

View File

@ -385,8 +385,7 @@ CommandCost CmdBuildBridge(DoCommandFlags flags, TileIndex tile_end, TileIndex t
if (t == nullptr) return CMD_ERROR;
if (GetBridgeSpec(bridge_type)->speed < GetBridgeSpec(GetBridgeType(tile_start))->speed) {
SetDParam(0, t->index);
return CommandCost(STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS);
return CommandCostWithParam(STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS, t->index);
} else {
ChangeTownRating(t, RATING_TUNNEL_BRIDGE_UP_STEP, RATING_MAXIMUM, flags);
}

View File

@ -324,9 +324,8 @@ void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRF
if (!grfconfig->grf_bugs.Test(bug_type)) {
grfconfig->grf_bugs.Set(bug_type);
SetDParamStr(0, grfconfig->GetName());
SetDParam(1, engine);
ShowErrorMessage(part1, part2, WL_CRITICAL);
ShowErrorMessage(GetEncodedString(part1, grfconfig->GetName()),
GetEncodedString(part2, std::monostate{}, engine), WL_CRITICAL);
if (!_networking) Command<CMD_PAUSE>::Do(DoCommandFlag::Execute, critical ? PauseMode::Error : PauseMode::Normal, true);
}