Add: CommandCost supports an optional second error string
This commit is contained in:
		@@ -442,7 +442,7 @@ static CommandCost ReplaceFreeUnit(Vehicle **single_unit, DoCommandFlag flags, b
 | 
			
		||||
	Train *old_v = Train::From(*single_unit);
 | 
			
		||||
	assert(!old_v->IsArticulatedPart() && !old_v->IsRearDualheaded());
 | 
			
		||||
 | 
			
		||||
	CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES, 0);
 | 
			
		||||
	CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES, (Money)0);
 | 
			
		||||
 | 
			
		||||
	/* Build and refit replacement vehicle */
 | 
			
		||||
	Vehicle *new_v = nullptr;
 | 
			
		||||
@@ -494,7 +494,7 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon
 | 
			
		||||
	Vehicle *old_head = *chain;
 | 
			
		||||
	assert(old_head->IsPrimaryVehicle());
 | 
			
		||||
 | 
			
		||||
	CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES, 0);
 | 
			
		||||
	CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES, (Money)0);
 | 
			
		||||
 | 
			
		||||
	if (old_head->type == VEH_TRAIN) {
 | 
			
		||||
		/* Store the length of the old vehicle chain, rounded up to whole tiles */
 | 
			
		||||
@@ -753,7 +753,7 @@ CommandCost CmdAutoreplaceVehicle(DoCommandFlag flags, VehicleID veh_id)
 | 
			
		||||
		w = (!free_wagon && w->type == VEH_TRAIN ? Train::From(w)->GetNextUnit() : nullptr);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES, 0);
 | 
			
		||||
	CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES, (Money)0);
 | 
			
		||||
	bool nothing_to_do = true;
 | 
			
		||||
 | 
			
		||||
	if (any_replacements) {
 | 
			
		||||
 
 | 
			
		||||
@@ -259,7 +259,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, res.GetErrorMessage(), WL_INFO, x, y, res.GetTextRefStackGRF(), res.GetTextRefStackSize(), res.GetTextRefStack());
 | 
			
		||||
			ShowErrorMessage(err_message, x, y, res);
 | 
			
		||||
		}
 | 
			
		||||
	} else if (estimate_only) {
 | 
			
		||||
		ShowEstimatedCostOrIncome(res.GetCost(), x, y);
 | 
			
		||||
 
 | 
			
		||||
@@ -22,12 +22,13 @@ struct GRFFile;
 | 
			
		||||
 * a possible error message/state together.
 | 
			
		||||
 */
 | 
			
		||||
class CommandCost {
 | 
			
		||||
	ExpensesType expense_type; ///< the type of expence as shown on the finances view
 | 
			
		||||
	Money cost;       ///< The cost of this action
 | 
			
		||||
	StringID message; ///< Warning message for when success is unset
 | 
			
		||||
	bool success;     ///< Whether the command went fine up to this moment
 | 
			
		||||
	const GRFFile *textref_stack_grffile; ///< NewGRF providing the #TextRefStack content.
 | 
			
		||||
	uint textref_stack_size;   ///< Number of uint32 values to put on the #TextRefStack for the error message.
 | 
			
		||||
	ExpensesType expense_type;                  ///< the type of expence as shown on the finances view
 | 
			
		||||
	Money cost;                                 ///< The cost of this action
 | 
			
		||||
	StringID message;                           ///< Warning message for when success is unset
 | 
			
		||||
	bool success;                               ///< Whether the command went fine up to this moment
 | 
			
		||||
	const GRFFile *textref_stack_grffile;       ///< NewGRF providing the #TextRefStack content.
 | 
			
		||||
	uint textref_stack_size;                    ///< Number of uint32 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 textref_stack[16];
 | 
			
		||||
 | 
			
		||||
@@ -38,9 +39,9 @@ public:
 | 
			
		||||
	CommandCost() : expense_type(INVALID_EXPENSES), cost(0), message(INVALID_STRING_ID), success(true), textref_stack_grffile(nullptr), textref_stack_size(0) {}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Creates a command return value the is failed with the given message
 | 
			
		||||
	 * Creates a command return value with one, or optionally two, error message strings.
 | 
			
		||||
	 */
 | 
			
		||||
	explicit CommandCost(StringID msg) : expense_type(INVALID_EXPENSES), cost(0), message(msg), success(false), textref_stack_grffile(nullptr), textref_stack_size(0) {}
 | 
			
		||||
	explicit CommandCost(StringID msg, StringID extra_msg = INVALID_STRING_ID) : expense_type(INVALID_EXPENSES), cost(0), message(msg), success(false), textref_stack_grffile(nullptr), textref_stack_size(0), extra_message(extra_msg) {}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Creates a command cost with given expense type and start cost of 0
 | 
			
		||||
@@ -98,11 +99,12 @@ public:
 | 
			
		||||
	 * Makes this #CommandCost behave like an error command.
 | 
			
		||||
	 * @param message The error message.
 | 
			
		||||
	 */
 | 
			
		||||
	void MakeError(StringID message)
 | 
			
		||||
	void MakeError(StringID message, StringID extra_message = INVALID_STRING_ID)
 | 
			
		||||
	{
 | 
			
		||||
		assert(message != INVALID_STRING_ID);
 | 
			
		||||
		this->success = false;
 | 
			
		||||
		this->message = message;
 | 
			
		||||
		this->extra_message = extra_message;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void UseTextRefStack(const GRFFile *grffile, uint num_registers);
 | 
			
		||||
@@ -144,6 +146,16 @@ public:
 | 
			
		||||
		return this->message;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Returns the extra error message of a command
 | 
			
		||||
	 * @return the extra error message, if succeeded #INVALID_STRING_ID
 | 
			
		||||
	 */
 | 
			
		||||
	StringID GetExtraErrorMessage() const
 | 
			
		||||
	{
 | 
			
		||||
		if (this->success) return INVALID_STRING_ID;
 | 
			
		||||
		return this->extra_message;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Did this command succeed?
 | 
			
		||||
	 * @return true if and only if it succeeded
 | 
			
		||||
 
 | 
			
		||||
@@ -13,6 +13,7 @@
 | 
			
		||||
#include <list>
 | 
			
		||||
#include "strings_type.h"
 | 
			
		||||
#include "company_type.h"
 | 
			
		||||
#include "command_type.h"
 | 
			
		||||
#include "core/geometry_type.hpp"
 | 
			
		||||
#include "guitimer_func.h"
 | 
			
		||||
 | 
			
		||||
@@ -37,13 +38,14 @@ protected:
 | 
			
		||||
	uint32 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.
 | 
			
		||||
	Point position;                 ///< Position of the error message window.
 | 
			
		||||
	CompanyID face;                 ///< Company belonging to the face being shown. #INVALID_COMPANY if no face present.
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	ErrorMessageData(const ErrorMessageData &data);
 | 
			
		||||
	~ErrorMessageData();
 | 
			
		||||
	ErrorMessageData(StringID summary_msg, StringID detailed_msg, uint duration = 0, int x = 0, int y = 0, const GRFFile *textref_stack_grffile = nullptr, uint textref_stack_size = 0, const uint32 *textref_stack = nullptr);
 | 
			
		||||
	ErrorMessageData(StringID summary_msg, StringID detailed_msg, uint duration = 0, int x = 0, int y = 0, const GRFFile *textref_stack_grffile = nullptr, uint textref_stack_size = 0, const uint32 *textref_stack = nullptr, StringID extra_msg = INVALID_STRING_ID);
 | 
			
		||||
 | 
			
		||||
	/* Remove the copy assignment, as the default implementation will not do the right thing. */
 | 
			
		||||
	ErrorMessageData &operator=(ErrorMessageData &rhs) = delete;
 | 
			
		||||
@@ -64,7 +66,8 @@ typedef std::list<ErrorMessageData> ErrorList;
 | 
			
		||||
void ScheduleErrorMessage(ErrorList &datas);
 | 
			
		||||
void ScheduleErrorMessage(const ErrorMessageData &data);
 | 
			
		||||
 | 
			
		||||
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 *textref_stack = nullptr);
 | 
			
		||||
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 *textref_stack = nullptr, StringID extra_msg = INVALID_STRING_ID);
 | 
			
		||||
bool HideActiveErrorMessage();
 | 
			
		||||
 | 
			
		||||
void ClearErrorMessages();
 | 
			
		||||
 
 | 
			
		||||
@@ -72,7 +72,7 @@ static WindowDesc _errmsg_face_desc(
 | 
			
		||||
 */
 | 
			
		||||
ErrorMessageData::ErrorMessageData(const ErrorMessageData &data) :
 | 
			
		||||
	display_timer(data.display_timer), textref_stack_grffile(data.textref_stack_grffile), textref_stack_size(data.textref_stack_size),
 | 
			
		||||
	summary_msg(data.summary_msg), detailed_msg(data.detailed_msg), position(data.position), face(data.face)
 | 
			
		||||
	summary_msg(data.summary_msg), detailed_msg(data.detailed_msg), extra_msg(data.extra_msg), position(data.position), face(data.face)
 | 
			
		||||
{
 | 
			
		||||
	memcpy(this->textref_stack, data.textref_stack, sizeof(this->textref_stack));
 | 
			
		||||
	memcpy(this->decode_params, data.decode_params, sizeof(this->decode_params));
 | 
			
		||||
@@ -101,12 +101,14 @@ ErrorMessageData::~ErrorMessageData()
 | 
			
		||||
 * @param textref_stack_grffile NewGRF that provides the #TextRefStack for the error message.
 | 
			
		||||
 * @param textref_stack_size Number of uint32 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.
 | 
			
		||||
 */
 | 
			
		||||
ErrorMessageData::ErrorMessageData(StringID summary_msg, StringID detailed_msg, uint duration, int x, int y, const GRFFile *textref_stack_grffile, uint textref_stack_size, const uint32 *textref_stack) :
 | 
			
		||||
ErrorMessageData::ErrorMessageData(StringID summary_msg, StringID detailed_msg, uint duration, int x, int y, const GRFFile *textref_stack_grffile, uint textref_stack_size, const uint32 *textref_stack, StringID extra_msg) :
 | 
			
		||||
	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)
 | 
			
		||||
{
 | 
			
		||||
	this->position.x = x;
 | 
			
		||||
@@ -184,6 +186,7 @@ struct ErrmsgWindow : public Window, ErrorMessageData {
 | 
			
		||||
private:
 | 
			
		||||
	uint height_summary;            ///< Height of the #summary_msg string in pixels in the #WID_EM_MESSAGE widget.
 | 
			
		||||
	uint height_detailed;           ///< Height of the #detailed_msg string in pixels in the #WID_EM_MESSAGE widget.
 | 
			
		||||
	uint height_extra;              ///< Height of the #extra_msg string in pixels in the #WID_EM_MESSAGE widget.
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	ErrmsgWindow(const ErrorMessageData &data) : Window(data.HasFace() ? &_errmsg_face_desc : &_errmsg_desc), ErrorMessageData(data)
 | 
			
		||||
@@ -200,11 +203,13 @@ public:
 | 
			
		||||
 | 
			
		||||
				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);
 | 
			
		||||
 | 
			
		||||
				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;
 | 
			
		||||
 | 
			
		||||
				size->height = std::max(size->height, panel_height);
 | 
			
		||||
				break;
 | 
			
		||||
@@ -280,13 +285,24 @@ public:
 | 
			
		||||
 | 
			
		||||
				if (this->detailed_msg == INVALID_STRING_ID) {
 | 
			
		||||
					DrawStringMultiLine(r, this->summary_msg, TC_FROMSTRING, SA_CENTER);
 | 
			
		||||
				} else {
 | 
			
		||||
				} else if (this->extra_msg == INVALID_STRING_ID) {
 | 
			
		||||
					/* 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);
 | 
			
		||||
				} 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;
 | 
			
		||||
 | 
			
		||||
					/* Note: NewGRF supplied error message often do not start with a colour code, so default to white. */
 | 
			
		||||
					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);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (this->textref_stack_size > 0) StopTextRefStackUsage();
 | 
			
		||||
@@ -361,6 +377,19 @@ void UnshowCriticalError()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Display an error message in a window.
 | 
			
		||||
 * Note: CommandCost errors are always severity level WL_INFO.
 | 
			
		||||
 * @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.
 | 
			
		||||
 */
 | 
			
		||||
void ShowErrorMessage(StringID summary_msg, int x, int y, CommandCost cc)
 | 
			
		||||
{
 | 
			
		||||
	ShowErrorMessage(summary_msg, cc.GetErrorMessage(), WL_INFO, x, y, cc.GetTextRefStackGRF(), cc.GetTextRefStackSize(), cc.GetTextRefStack(), cc.GetExtraErrorMessage());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Display an error message in a window.
 | 
			
		||||
 * @param summary_msg  General error message showed in first line. Must be valid.
 | 
			
		||||
@@ -371,8 +400,9 @@ void UnshowCriticalError()
 | 
			
		||||
 * @param textref_stack_grffile NewGRF providing the #TextRefStack for the error message.
 | 
			
		||||
 * @param textref_stack_size Number of uint32 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.
 | 
			
		||||
 */
 | 
			
		||||
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 *textref_stack)
 | 
			
		||||
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 *textref_stack, StringID extra_msg)
 | 
			
		||||
{
 | 
			
		||||
	assert(textref_stack_size == 0 || (textref_stack_grffile != nullptr && textref_stack != nullptr));
 | 
			
		||||
	if (summary_msg == STR_NULL) summary_msg = STR_EMPTY;
 | 
			
		||||
@@ -388,6 +418,10 @@ void ShowErrorMessage(StringID summary_msg, StringID detailed_msg, WarningLevel
 | 
			
		||||
			b += seprintf(b, lastof(buf), " ");
 | 
			
		||||
			GetString(b, detailed_msg, lastof(buf));
 | 
			
		||||
		}
 | 
			
		||||
		if (extra_msg != INVALID_STRING_ID) {
 | 
			
		||||
			b += seprintf(b, lastof(buf), " ");
 | 
			
		||||
			GetString(b, extra_msg, lastof(buf));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (textref_stack_size > 0) StopTextRefStackUsage();
 | 
			
		||||
 | 
			
		||||
@@ -399,7 +433,7 @@ void ShowErrorMessage(StringID summary_msg, StringID detailed_msg, WarningLevel
 | 
			
		||||
	if (_game_mode == GM_BOOTSTRAP) return;
 | 
			
		||||
	if (_settings_client.gui.errmsg_duration == 0 && !no_timeout) return;
 | 
			
		||||
 | 
			
		||||
	ErrorMessageData data(summary_msg, detailed_msg, no_timeout ? 0 : _settings_client.gui.errmsg_duration, x, y, textref_stack_grffile, textref_stack_size, textref_stack);
 | 
			
		||||
	ErrorMessageData data(summary_msg, detailed_msg, no_timeout ? 0 : _settings_client.gui.errmsg_duration, x, y, textref_stack_grffile, textref_stack_size, textref_stack, extra_msg);
 | 
			
		||||
	data.CopyOutDParams();
 | 
			
		||||
 | 
			
		||||
	ErrmsgWindow *w = (ErrmsgWindow*)FindWindowById(WC_ERRMSG, 0);
 | 
			
		||||
 
 | 
			
		||||
@@ -222,6 +222,6 @@ CommandCost CmdChangeBankBalance(DoCommandFlag flags, TileIndex tile, Money delt
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* This command doesn't cost anything for deity. */
 | 
			
		||||
	CommandCost zero_cost(expenses_type, 0);
 | 
			
		||||
	CommandCost zero_cost(expenses_type, (Money)0);
 | 
			
		||||
	return zero_cost;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user