(svn r22629) -Fix [FS#4599]: Remove all usages of the ErrorRefStack. It was continuously overwritten by e.g. industry prospection without closing the old error window; also StopTextRefStackUsage() was not called for errors returned by commands (which caused FS#4599). Now return in the CommandCost result whether the textref stack needs to be used, and store a copy of the stack values in the error window just like for the normal string parameters.

pull/155/head
frosch 13 years ago
parent 600c6c0f2e
commit ef5b18ab3b

@ -530,7 +530,7 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallbac
/* Only show the error when it's for us. */ /* Only show the error when it's for us. */
StringID error_part1 = GB(cmd, 16, 16); StringID error_part1 = GB(cmd, 16, 16);
if (estimate_only || (IsLocalCompany() && error_part1 != 0 && my_cmd)) { if (estimate_only || (IsLocalCompany() && error_part1 != 0 && my_cmd)) {
ShowErrorMessage(error_part1, res.GetErrorMessage(), WL_INFO, x, y); ShowErrorMessage(error_part1, res.GetErrorMessage(), WL_INFO, x, y, res.GetTextRefStackSize(), res.GetTextRefStack());
} }
} else if (estimate_only) { } else if (estimate_only) {
ShowEstimatedCostOrIncome(res.GetCost(), x, y); ShowEstimatedCostOrIncome(res.GetCost(), x, y);
@ -735,3 +735,25 @@ void CommandCost::AddCost(const CommandCost &ret)
this->success = false; this->success = false;
} }
} }
/**
* Values to put on the #TextRefStack for the error message.
* There is only one static instance of the array, just like there is only one
* instance of normal DParams.
*/
uint32 CommandCost::textref_stack[16];
/**
* Activate usage of the NewGRF #TextRefStack for the error message.
* @param number of entries to copy from the temporary NewGRF registers
*/
void CommandCost::UseTextRefStack(uint num_registers)
{
extern TemporaryStorageArray<int32, 0x110> _temp_store;
assert(num_registers < lengthof(textref_stack));
this->textref_stack_size = num_registers;
for (uint i = 0; i < num_registers; i++) {
textref_stack[i] = _temp_store.GetValue(0x100 + i);
}
}

@ -25,30 +25,33 @@ class CommandCost {
Money cost; ///< The cost of this action Money cost; ///< The cost of this action
StringID message; ///< Warning message for when success is unset StringID message; ///< Warning message for when success is unset
bool success; ///< Whether the comment went fine up to this moment bool success; ///< Whether the comment went fine up to this moment
uint textref_stack_size; ///< Number of uint32 values to put on the #TextRefStack for the error message.
static uint32 textref_stack[16];
public: public:
/** /**
* Creates a command cost return with no cost and no error * Creates a command cost return with no cost and no error
*/ */
CommandCost() : expense_type(INVALID_EXPENSES), cost(0), message(INVALID_STRING_ID), success(true) {} CommandCost() : expense_type(INVALID_EXPENSES), cost(0), message(INVALID_STRING_ID), success(true), textref_stack_size(0) {}
/** /**
* Creates a command return value the is failed with the given message * Creates a command return value the is failed with the given message
*/ */
explicit CommandCost(StringID msg) : expense_type(INVALID_EXPENSES), cost(0), message(msg), success(false) {} explicit CommandCost(StringID msg) : expense_type(INVALID_EXPENSES), cost(0), message(msg), success(false), textref_stack_size(0) {}
/** /**
* Creates a command cost with given expense type and start cost of 0 * Creates a command cost with given expense type and start cost of 0
* @param ex_t the expense type * @param ex_t the expense type
*/ */
explicit CommandCost(ExpensesType ex_t) : expense_type(ex_t), cost(0), message(INVALID_STRING_ID), success(true) {} explicit CommandCost(ExpensesType ex_t) : expense_type(ex_t), cost(0), message(INVALID_STRING_ID), success(true), textref_stack_size(0) {}
/** /**
* Creates a command return value with the given start cost and expense type * Creates a command return value with the given start cost and expense type
* @param ex_t the expense type * @param ex_t the expense type
* @param cst the initial cost of this command * @param cst the initial cost of this command
*/ */
CommandCost(ExpensesType ex_t, const Money &cst) : expense_type(ex_t), cost(cst), message(INVALID_STRING_ID), success(true) {} CommandCost(ExpensesType ex_t, const Money &cst) : expense_type(ex_t), cost(cst), message(INVALID_STRING_ID), success(true), textref_stack_size(0) {}
/** /**
@ -100,6 +103,26 @@ public:
this->message = message; this->message = message;
} }
void UseTextRefStack(uint num_registers);
/**
* Returns the number of uint32 values for the #TextRefStack of the error message.
* @return number of uint32 values.
*/
uint GetTextRefStackSize() const
{
return this->textref_stack_size;
}
/**
* Returns a pointer to the values for the #TextRefStack of the error message.
* @return uint32 values for the #TextRefStack
*/
const uint32 *GetTextRefStack() const
{
return textref_stack;
}
/** /**
* Returns the error message of a command * Returns the error message of a command
* @return the error message, if succeeded #INVALID_STRING_ID * @return the error message, if succeeded #INVALID_STRING_ID

@ -63,7 +63,7 @@ enum WarningLevel {
WL_CRITICAL, ///< Critical errors, the MessageBox is shown in all cases WL_CRITICAL, ///< Critical errors, the MessageBox is shown in all cases
}; };
void ShowErrorMessage(StringID summary_msg, StringID detailed_msg, WarningLevel wl, int x = 0, int y = 0); void ShowErrorMessage(StringID summary_msg, StringID detailed_msg, WarningLevel wl, int x = 0, int y = 0, uint textref_stack_size = 0, const uint32 *textref_stack = NULL);
void ShowExtraViewPortWindow(TileIndex tile = INVALID_TILE); void ShowExtraViewPortWindow(TileIndex tile = INVALID_TILE);
void ShowExtraViewPortWindowForTileUnderCursor(); void ShowExtraViewPortWindowForTileUnderCursor();

@ -566,6 +566,8 @@ struct ErrmsgWindow : public Window {
private: private:
uint duration; ///< Length of display of the message. 0 means forever, uint duration; ///< Length of display of the message. 0 means forever,
uint64 decode_params[20]; ///< Parameters of the message strings. uint64 decode_params[20]; ///< Parameters of the message strings.
uint textref_stack_size; ///< Number of uint32 values to put on the #TextRefStack for the error message.
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 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 detailed_msg; ///< Detailed error message showed in second line. Can be #INVALID_STRING_ID.
uint height_summary; ///< Height of the #summary_msg string in pixels in the #EMW_MESSAGE widget. uint height_summary; ///< Height of the #summary_msg string in pixels in the #EMW_MESSAGE widget.
@ -574,13 +576,17 @@ private:
CompanyID face; ///< Company belonging to the face being shown. #INVALID_COMPANY if no face present. CompanyID face; ///< Company belonging to the face being shown. #INVALID_COMPANY if no face present.
public: public:
ErrmsgWindow(Point pt, StringID summary_msg, StringID detailed_msg, bool no_timeout) : Window() ErrmsgWindow(Point pt, StringID summary_msg, StringID detailed_msg, bool no_timeout, uint textref_stack_size, const uint32 *textref_stack) : Window()
{ {
this->position = pt; this->position = pt;
this->duration = no_timeout ? 0 : _settings_client.gui.errmsg_duration; this->duration = no_timeout ? 0 : _settings_client.gui.errmsg_duration;
CopyOutDParam(this->decode_params, 0, lengthof(this->decode_params)); CopyOutDParam(this->decode_params, 0, lengthof(this->decode_params));
this->summary_msg = summary_msg; this->summary_msg = summary_msg;
this->detailed_msg = detailed_msg; this->detailed_msg = detailed_msg;
this->textref_stack_size = textref_stack_size;
if (textref_stack_size > 0) {
MemCpyT(this->textref_stack, textref_stack, textref_stack_size);
}
CompanyID company = (CompanyID)GetDParamX(this->decode_params, 2); CompanyID company = (CompanyID)GetDParamX(this->decode_params, 2);
this->face = (this->detailed_msg == STR_ERROR_OWNED_BY && company < MAX_COMPANIES) ? company : INVALID_COMPANY; this->face = (this->detailed_msg == STR_ERROR_OWNED_BY && company < MAX_COMPANIES) ? company : INVALID_COMPANY;
@ -596,17 +602,13 @@ public:
if (widget != EMW_MESSAGE) return; if (widget != EMW_MESSAGE) return;
CopyInDParam(0, this->decode_params, lengthof(this->decode_params)); CopyInDParam(0, this->decode_params, lengthof(this->decode_params));
/* If the error message comes from a NewGRF, we must use the text ref. stack reserved for error messages. if (this->textref_stack_size > 0) StartTextRefStackUsage(this->textref_stack_size, this->textref_stack);
* If the message doesn't come from a NewGRF, it won't use the TTDP-style text ref. stack, so we won't hurt anything
*/
SwitchToErrorRefStack();
RewindTextRefStack();
int text_width = max(0, (int)size->width - WD_FRAMETEXT_LEFT - WD_FRAMETEXT_RIGHT); int text_width = max(0, (int)size->width - WD_FRAMETEXT_LEFT - WD_FRAMETEXT_RIGHT);
this->height_summary = GetStringHeight(this->summary_msg, text_width); this->height_summary = GetStringHeight(this->summary_msg, text_width);
this->height_detailed = (this->detailed_msg == INVALID_STRING_ID) ? 0 : GetStringHeight(this->detailed_msg, text_width); this->height_detailed = (this->detailed_msg == INVALID_STRING_ID) ? 0 : GetStringHeight(this->detailed_msg, text_width);
SwitchToNormalRefStack(); // Switch back to the normal text ref. stack for NewGRF texts. if (this->textref_stack_size > 0) StopTextRefStackUsage();
uint panel_height = WD_FRAMERECT_TOP + this->height_summary + WD_FRAMERECT_BOTTOM; uint panel_height = WD_FRAMERECT_TOP + this->height_summary + WD_FRAMERECT_BOTTOM;
if (this->detailed_msg != INVALID_STRING_ID) panel_height += this->height_detailed + WD_PAR_VSEP_WIDE; if (this->detailed_msg != INVALID_STRING_ID) panel_height += this->height_detailed + WD_PAR_VSEP_WIDE;
@ -672,8 +674,7 @@ public:
case EMW_MESSAGE: case EMW_MESSAGE:
CopyInDParam(0, this->decode_params, lengthof(this->decode_params)); CopyInDParam(0, this->decode_params, lengthof(this->decode_params));
SwitchToErrorRefStack(); if (this->textref_stack_size > 0) StartTextRefStackUsage(this->textref_stack_size, this->textref_stack);
RewindTextRefStack();
if (this->detailed_msg == INVALID_STRING_ID) { if (this->detailed_msg == INVALID_STRING_ID) {
DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, r.top + WD_FRAMERECT_TOP, r.bottom - WD_FRAMERECT_BOTTOM, DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, r.top + WD_FRAMERECT_TOP, r.bottom - WD_FRAMERECT_BOTTOM,
@ -691,7 +692,7 @@ public:
DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, top, bottom, this->detailed_msg, TC_WHITE, SA_CENTER); DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, top, bottom, this->detailed_msg, TC_WHITE, SA_CENTER);
} }
SwitchToNormalRefStack(); // Switch back to the normal text ref. stack for NewGRF texts. if (this->textref_stack_size > 0) StopTextRefStackUsage();
break; break;
default: default:
@ -734,19 +735,28 @@ public:
* @param wl Message severity. * @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 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 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_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.
*/ */
void ShowErrorMessage(StringID summary_msg, StringID detailed_msg, WarningLevel wl, int x, int y) void ShowErrorMessage(StringID summary_msg, StringID detailed_msg, WarningLevel wl, int x, int y, uint textref_stack_size, const uint32 *textref_stack)
{ {
assert(textref_stack_size == 0 || textref_stack != NULL);
if (summary_msg == STR_NULL) summary_msg = STR_EMPTY; if (summary_msg == STR_NULL) summary_msg = STR_EMPTY;
if (wl != WL_INFO) { if (wl != WL_INFO) {
/* Print message to console */ /* Print message to console */
char buf[DRAW_STRING_BUFFER]; char buf[DRAW_STRING_BUFFER];
if (textref_stack_size > 0) StartTextRefStackUsage(textref_stack_size, textref_stack);
char *b = GetString(buf, summary_msg, lastof(buf)); char *b = GetString(buf, summary_msg, lastof(buf));
if (detailed_msg != INVALID_STRING_ID) { if (detailed_msg != INVALID_STRING_ID) {
b += seprintf(b, lastof(buf), " "); b += seprintf(b, lastof(buf), " ");
GetString(b, detailed_msg, lastof(buf)); GetString(b, detailed_msg, lastof(buf));
} }
if (textref_stack_size > 0) StopTextRefStackUsage();
switch (wl) { switch (wl) {
case WL_WARNING: IConsolePrint(CC_WARNING, buf); break; case WL_WARNING: IConsolePrint(CC_WARNING, buf); break;
default: IConsoleError(buf); break; default: IConsoleError(buf); break;
@ -760,7 +770,7 @@ void ShowErrorMessage(StringID summary_msg, StringID detailed_msg, WarningLevel
DeleteWindowById(WC_ERRMSG, 0); DeleteWindowById(WC_ERRMSG, 0);
Point pt = {x, y}; Point pt = {x, y};
new ErrmsgWindow(pt, summary_msg, detailed_msg, no_timeout); new ErrmsgWindow(pt, summary_msg, detailed_msg, no_timeout, textref_stack_size, textref_stack);
} }
/** /**

@ -549,18 +549,18 @@ CommandCost CheckIfCallBackAllowsCreation(TileIndex tile, IndustryType type, uin
uint16 result = group->GetCallbackResult(); uint16 result = group->GetCallbackResult();
if (result == 0x400 || result == CALLBACK_FAILED) return CommandCost(); if (result == 0x400 || result == CALLBACK_FAILED) return CommandCost();
/* Copy some parameters from the registers to the error message text ref. stack */ CommandCost res;
SwitchToErrorRefStack();
StartTextRefStackUsage(4);
SwitchToNormalRefStack();
switch (result) { switch (result) {
case 0x401: return_cmd_error(STR_ERROR_SITE_UNSUITABLE); case 0x401: res = CommandCost(STR_ERROR_SITE_UNSUITABLE);
case 0x402: return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST); case 0x402: res = CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST);
case 0x403: return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT); case 0x403: res = CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT);
default: return_cmd_error(GetGRFStringID(indspec->grf_prop.grffile->grfid, 0xD000 + result)); default: res = CommandCost(GetGRFStringID(indspec->grf_prop.grffile->grfid, 0xD000 + result));
} }
NOT_REACHED();
/* Copy some parameters from the registers to the error message text ref. stack */
res.UseTextRefStack(4);
return res;
} }
/** /**

@ -308,17 +308,18 @@ CommandCost PerformIndustryTileSlopeCheck(TileIndex ind_base_tile, TileIndex ind
} }
if (callback_res == 0x400) return CommandCost(); if (callback_res == 0x400) return CommandCost();
/* Copy some parameters from the registers to the error message text ref. stack */ CommandCost res;
SwitchToErrorRefStack();
StartTextRefStackUsage(4);
SwitchToNormalRefStack();
switch (callback_res) { switch (callback_res) {
case 0x401: return_cmd_error(STR_ERROR_SITE_UNSUITABLE); case 0x401: res = CommandCost(STR_ERROR_SITE_UNSUITABLE);
case 0x402: return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST); case 0x402: res = CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST);
case 0x403: return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT); case 0x403: res = CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT);
default: return_cmd_error(GetGRFStringID(its->grf_prop.grffile->grfid, 0xD000 + callback_res)); default: res = CommandCost(GetGRFStringID(its->grf_prop.grffile->grfid, 0xD000 + callback_res));
} }
/* Copy some parameters from the registers to the error message text ref. stack */
res.UseTextRefStack(4);
return res;
} }
/* Simple wrapper for GetHouseCallback to keep the animation unified. */ /* Simple wrapper for GetHouseCallback to keep the animation unified. */

Loading…
Cancel
Save