mirror of https://github.com/OpenTTD/OpenTTD
Codechange: Preprocess text ref stack parameters. (#13642)
NewGRF text ref stack is now processed in advance, creating parameters as necessary, and then encoding this into an EncodedString.pull/13625/head
parent
4ac81656ee
commit
b28dca2222
|
@ -804,10 +804,7 @@ static std::optional<std::string> GetNewGRFAdditionalText(EngineID engine)
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
StartTextRefStackUsage(grffile, 6);
|
||||
std::string result = GetString(GetGRFStringID(grffile->grfid, GRFSTR_MISC_GRF_TEXT + callback));
|
||||
StopTextRefStackUsage();
|
||||
return result;
|
||||
return GetGRFStringWithTextStack(grffile, GRFSTR_MISC_GRF_TEXT + callback, 6);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -407,32 +407,8 @@ void CommandCost::AddCost(const CommandCost &ret)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
/* static */ uint32_t CommandCost::textref_stack[16];
|
||||
|
||||
/* static */ EncodedString CommandCost::encoded_message;
|
||||
|
||||
/**
|
||||
* Activate usage of the NewGRF #TextRefStack for the error message.
|
||||
* @param grffile NewGRF that provides the #TextRefStack
|
||||
* @param num_registers number of entries to copy from the temporary NewGRF registers
|
||||
*/
|
||||
void CommandCost::UseTextRefStack(const GRFFile *grffile, uint num_registers)
|
||||
{
|
||||
extern TemporaryStorageArray<int32_t, 0x110> _temp_store;
|
||||
|
||||
assert(num_registers < lengthof(textref_stack));
|
||||
this->textref_stack_grffile = grffile;
|
||||
this->textref_stack_size = num_registers;
|
||||
for (uint i = 0; i < num_registers; i++) {
|
||||
textref_stack[i] = _temp_store.GetValue(0x100 + i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an error status, with string and parameter.
|
||||
* @param str StringID of error.
|
||||
|
|
|
@ -27,12 +27,8 @@ class CommandCost {
|
|||
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 = CompanyID::Invalid(); ///< 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:
|
||||
|
@ -146,35 +142,6 @@ public:
|
|||
this->extra_message = INVALID_STRING_ID;
|
||||
}
|
||||
|
||||
void UseTextRefStack(const GRFFile *grffile, uint num_registers);
|
||||
|
||||
/**
|
||||
* Returns the NewGRF providing the #TextRefStack of the error message.
|
||||
* @return the NewGRF.
|
||||
*/
|
||||
const GRFFile *GetTextRefStackGRF() const
|
||||
{
|
||||
return this->textref_stack_grffile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of uint32_t values for the #TextRefStack of the error message.
|
||||
* @return number of uint32_t values.
|
||||
*/
|
||||
uint GetTextRefStackSize() const
|
||||
{
|
||||
return this->textref_stack_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pointer to the values for the #TextRefStack of the error message.
|
||||
* @return uint32_t values for the #TextRefStack
|
||||
*/
|
||||
const uint32_t *GetTextRefStack() const
|
||||
{
|
||||
return textref_stack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the error message of a command
|
||||
* @return the error message, if succeeded #INVALID_STRING_ID
|
||||
|
|
11
src/error.h
11
src/error.h
|
@ -31,9 +31,6 @@ enum WarningLevel : uint8_t {
|
|||
class ErrorMessageData {
|
||||
protected:
|
||||
bool is_critical; ///< Whether the error message is critical.
|
||||
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.
|
||||
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.
|
||||
|
@ -41,11 +38,7 @@ protected:
|
|||
CompanyID company; ///< Company belonging to the face being shown. #CompanyID::Invalid() if no face present.
|
||||
|
||||
public:
|
||||
ErrorMessageData(const ErrorMessageData &data);
|
||||
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 = CompanyID::Invalid());
|
||||
|
||||
/* Remove the copy assignment, as the default implementation will not do the right thing. */
|
||||
ErrorMessageData &operator=(ErrorMessageData &rhs) = delete;
|
||||
ErrorMessageData(EncodedString &&summary_msg, EncodedString &&detailed_msg, bool is_critical = false, int x = 0, int y = 0, EncodedString &&extra_msg = {}, CompanyID company = CompanyID::Invalid());
|
||||
|
||||
/** Check whether error window shall display a company manager face */
|
||||
bool HasFace() const { return company != CompanyID::Invalid(); }
|
||||
|
@ -58,7 +51,7 @@ void ScheduleErrorMessage(ErrorList &datas);
|
|||
void ScheduleErrorMessage(const ErrorMessageData &data);
|
||||
|
||||
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 = CompanyID::Invalid());
|
||||
void ShowErrorMessage(EncodedString &&summary_msg, EncodedString &&detailed_msg, WarningLevel wl, int x = 0, int y = 0, EncodedString &&extra_msg = {}, CompanyID company = CompanyID::Invalid());
|
||||
bool HideActiveErrorMessage();
|
||||
|
||||
void ClearErrorMessages();
|
||||
|
|
|
@ -70,17 +70,6 @@ static WindowDesc _errmsg_face_desc(
|
|||
_nested_errmsg_face_widgets
|
||||
);
|
||||
|
||||
/**
|
||||
* Copy the given data into our instance.
|
||||
* @param data The data to copy.
|
||||
*/
|
||||
ErrorMessageData::ErrorMessageData(const ErrorMessageData &data) :
|
||||
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));
|
||||
}
|
||||
|
||||
/**
|
||||
* Display an error message in a window.
|
||||
* @param summary_msg General error message showed in first line. Must be valid.
|
||||
|
@ -88,25 +77,16 @@ ErrorMessageData::ErrorMessageData(const ErrorMessageData &data) :
|
|||
* @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 empty.
|
||||
*/
|
||||
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) :
|
||||
ErrorMessageData::ErrorMessageData(EncodedString &&summary_msg, EncodedString &&detailed_msg, bool is_critical, int x, int y, EncodedString &&extra_msg, CompanyID company) :
|
||||
is_critical(is_critical),
|
||||
textref_stack_grffile(textref_stack_grffile),
|
||||
textref_stack_size(textref_stack_size),
|
||||
summary_msg(std::move(summary_msg)),
|
||||
detailed_msg(std::move(detailed_msg)),
|
||||
extra_msg(std::move(extra_msg)),
|
||||
position(x, y),
|
||||
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(!this->summary_msg.empty());
|
||||
}
|
||||
|
||||
|
@ -143,14 +123,10 @@ public:
|
|||
{
|
||||
switch (widget) {
|
||||
case WID_EM_MESSAGE: {
|
||||
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.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.empty()) panel_height += this->height_detailed + WidgetDimensions::scaled.vsep_wide;
|
||||
if (!this->extra_msg.empty()) panel_height += this->height_extra + WidgetDimensions::scaled.vsep_wide;
|
||||
|
@ -215,8 +191,6 @@ public:
|
|||
}
|
||||
|
||||
case WID_EM_MESSAGE:
|
||||
if (this->textref_stack_size > 0) StartTextRefStackUsage(this->textref_stack_grffile, this->textref_stack_size, this->textref_stack);
|
||||
|
||||
if (this->detailed_msg.empty()) {
|
||||
DrawStringMultiLine(r, this->summary_msg.GetDecodedString(), TC_FROMSTRING, SA_CENTER);
|
||||
} else if (this->extra_msg.empty()) {
|
||||
|
@ -239,7 +213,6 @@ public:
|
|||
DrawStringMultiLine(bottom_section, this->extra_msg.GetDecodedString(), TC_WHITE, SA_CENTER);
|
||||
}
|
||||
|
||||
if (this->textref_stack_size > 0) StopTextRefStackUsage();
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -310,7 +283,7 @@ 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 empty) and TextRefStack info.
|
||||
* @param cc CommandCost containing the optional detailed and extra error messages shown in the second and third lines (can be empty).
|
||||
*/
|
||||
void ShowErrorMessage(EncodedString &&summary_msg, int x, int y, const CommandCost &cc)
|
||||
{
|
||||
|
@ -318,7 +291,6 @@ void ShowErrorMessage(EncodedString &&summary_msg, int x, int y, const CommandCo
|
|||
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());
|
||||
}
|
||||
|
||||
|
@ -329,20 +301,13 @@ void ShowErrorMessage(EncodedString &&summary_msg, int x, int y, const CommandCo
|
|||
* @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 empty.
|
||||
*/
|
||||
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)
|
||||
void ShowErrorMessage(EncodedString &&summary_msg, EncodedString &&detailed_msg, WarningLevel wl, int x, int y, EncodedString &&extra_msg, CompanyID company)
|
||||
{
|
||||
assert(textref_stack_size == 0 || (textref_stack_grffile != nullptr && textref_stack != nullptr));
|
||||
|
||||
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 = summary_msg.GetDecodedString();
|
||||
if (!detailed_msg.empty()) {
|
||||
message += " ";
|
||||
|
@ -353,8 +318,6 @@ void ShowErrorMessage(EncodedString &&summary_msg, EncodedString &&detailed_msg,
|
|||
message += extra_msg.GetDecodedString();
|
||||
}
|
||||
|
||||
if (textref_stack_size > 0) StopTextRefStackUsage();
|
||||
|
||||
IConsolePrint(wl == WL_WARNING ? CC_WARNING : CC_ERROR, message);
|
||||
}
|
||||
|
||||
|
@ -363,7 +326,7 @@ void ShowErrorMessage(EncodedString &&summary_msg, EncodedString &&detailed_msg,
|
|||
if (_game_mode == GM_BOOTSTRAP) return;
|
||||
if (_settings_client.gui.errmsg_duration == 0 && !is_critical) return;
|
||||
|
||||
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);
|
||||
ErrorMessageData data(std::move(summary_msg), std::move(detailed_msg), is_critical, x, y, std::move(extra_msg), company);
|
||||
|
||||
ErrmsgWindow *w = dynamic_cast<ErrmsgWindow *>(FindWindowById(WC_ERRMSG, 0));
|
||||
if (w != nullptr) {
|
||||
|
|
|
@ -104,9 +104,7 @@ static void GetCargoSuffix(uint cargo, CargoSuffixType cst, const Industry *ind,
|
|||
if (indspec->grf_prop.grffile->grf_version < 8) {
|
||||
if (GB(callback, 0, 8) == 0xFF) return;
|
||||
if (callback < 0x400) {
|
||||
StartTextRefStackUsage(indspec->grf_prop.grffile, 6);
|
||||
suffix.text = GetString(GetGRFStringID(indspec->grf_prop.grfid, GRFSTR_MISC_GRF_TEXT + callback));
|
||||
StopTextRefStackUsage();
|
||||
suffix.text = GetGRFStringWithTextStack(indspec->grf_prop.grffile, GRFSTR_MISC_GRF_TEXT + callback, 6);
|
||||
suffix.display = CSD_CARGO_AMOUNT_TEXT;
|
||||
return;
|
||||
}
|
||||
|
@ -120,16 +118,12 @@ static void GetCargoSuffix(uint cargo, CargoSuffixType cst, const Industry *ind,
|
|||
return;
|
||||
}
|
||||
if (callback < 0x400) {
|
||||
StartTextRefStackUsage(indspec->grf_prop.grffile, 6);
|
||||
suffix.text = GetString(GetGRFStringID(indspec->grf_prop.grfid, GRFSTR_MISC_GRF_TEXT + callback));
|
||||
StopTextRefStackUsage();
|
||||
suffix.text = GetGRFStringWithTextStack(indspec->grf_prop.grffile, GRFSTR_MISC_GRF_TEXT + callback, 6);
|
||||
suffix.display = CSD_CARGO_AMOUNT_TEXT;
|
||||
return;
|
||||
}
|
||||
if (callback >= 0x800 && callback < 0xC00) {
|
||||
StartTextRefStackUsage(indspec->grf_prop.grffile, 6);
|
||||
suffix.text = GetString(GetGRFStringID(indspec->grf_prop.grfid, GRFSTR_MISC_GRF_TEXT + callback - 0x800));
|
||||
StopTextRefStackUsage();
|
||||
suffix.text = GetGRFStringWithTextStack(indspec->grf_prop.grffile, GRFSTR_MISC_GRF_TEXT + callback - 0x800, 6);
|
||||
suffix.display = CSD_CARGO_TEXT;
|
||||
return;
|
||||
}
|
||||
|
@ -604,11 +598,9 @@ public:
|
|||
if (callback_res > 0x400) {
|
||||
ErrorUnknownCallbackResult(indsp->grf_prop.grfid, CBID_INDUSTRY_FUND_MORE_TEXT, callback_res);
|
||||
} else {
|
||||
StringID str = GetGRFStringID(indsp->grf_prop.grfid, GRFSTR_MISC_GRF_TEXT + callback_res); // No. here's the new string
|
||||
if (str != STR_UNDEFINED) {
|
||||
StartTextRefStackUsage(indsp->grf_prop.grffile, 6);
|
||||
std::string str = GetGRFStringWithTextStack(indsp->grf_prop.grffile, GRFSTR_MISC_GRF_TEXT + callback_res, 6);
|
||||
if (!str.empty()) {
|
||||
DrawStringMultiLine(ir, str, TC_YELLOW);
|
||||
StopTextRefStackUsage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1006,13 +998,10 @@ public:
|
|||
if (callback_res > 0x400) {
|
||||
ErrorUnknownCallbackResult(ind->grf_prop.grfid, CBID_INDUSTRY_WINDOW_MORE_TEXT, callback_res);
|
||||
} else {
|
||||
StringID message = GetGRFStringID(ind->grf_prop.grfid, GRFSTR_MISC_GRF_TEXT + callback_res);
|
||||
if (message != STR_NULL && message != STR_UNDEFINED) {
|
||||
std::string str = GetGRFStringWithTextStack(ind->grf_prop.grffile, GRFSTR_MISC_GRF_TEXT + callback_res, 6);
|
||||
if (!str.empty()) {
|
||||
ir.top += WidgetDimensions::scaled.vsep_wide;
|
||||
|
||||
StartTextRefStackUsage(ind->grf_prop.grffile, 6);
|
||||
ir.top = DrawStringMultiLine(ir, message, TC_BLACK);
|
||||
StopTextRefStackUsage();
|
||||
ir.top = DrawStringMultiLine(ir, str, TC_YELLOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -473,6 +473,13 @@ CommandCost GetErrorMessageFromLocationCallbackResult(uint16_t cb_res, const GRF
|
|||
|
||||
if (cb_res < 0x400) {
|
||||
res = CommandCost(GetGRFStringID(grffile->grfid, GRFSTR_MISC_GRF_TEXT + cb_res));
|
||||
|
||||
/* 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;
|
||||
|
||||
StringID stringid = GetGRFStringID(grffile->grfid, GRFSTR_MISC_GRF_TEXT + cb_res);
|
||||
auto params = GetGRFSringTextStackParameters(grffile, stringid, 4);
|
||||
res.SetEncodedMessage(GetEncodedStringWithArgs(stringid, params));
|
||||
} else {
|
||||
switch (cb_res) {
|
||||
case 0x400: return res; // No error.
|
||||
|
@ -490,14 +497,6 @@ 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include "newgrf.h"
|
||||
#include "strings_internal.h"
|
||||
#include "newgrf_storage.h"
|
||||
|
@ -685,12 +686,24 @@ void CleanUpStrings()
|
|||
}
|
||||
|
||||
struct TextRefStack {
|
||||
std::array<uint8_t, 0x30> stack;
|
||||
uint8_t position;
|
||||
const GRFFile *grffile;
|
||||
bool used;
|
||||
std::array<uint8_t, 0x30> stack{};
|
||||
uint8_t position = 0;
|
||||
const GRFFile *grffile = nullptr;
|
||||
|
||||
TextRefStack() : position(0), grffile(nullptr), used(false) {}
|
||||
TextRefStack(const GRFFile *grffile, uint8_t num_entries) : grffile(grffile)
|
||||
{
|
||||
extern TemporaryStorageArray<int32_t, 0x110> _temp_store;
|
||||
|
||||
assert(num_entries < sizeof(uint32_t) * std::size(stack));
|
||||
|
||||
auto stack_it = this->stack.begin();
|
||||
for (uint i = 0; i < num_entries; i++) {
|
||||
uint32_t value = _temp_store.GetValue(0x100 + i);
|
||||
for (uint j = 0; j < 32; j += 8) {
|
||||
*stack_it++ = GB(value, j, 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t PopUnsignedByte() { assert(this->position < this->stack.size()); return this->stack[this->position++]; }
|
||||
int8_t PopSignedByte() { return (int8_t)this->PopUnsignedByte(); }
|
||||
|
@ -736,213 +749,95 @@ struct TextRefStack {
|
|||
this->stack[this->position] = GB(word, 0, 8);
|
||||
this->stack[this->position + 1] = GB(word, 8, 8);
|
||||
}
|
||||
|
||||
void ResetStack(const GRFFile *grffile)
|
||||
{
|
||||
assert(grffile != nullptr);
|
||||
this->position = 0;
|
||||
this->grffile = grffile;
|
||||
this->used = true;
|
||||
}
|
||||
};
|
||||
|
||||
/** The stack that is used for TTDP compatible string code parsing */
|
||||
static TextRefStack _newgrf_textrefstack;
|
||||
static void HandleNewGRFStringControlCodes(const char *str, TextRefStack &stack, std::vector<StringParameter> ¶ms);
|
||||
|
||||
/**
|
||||
* Check whether the NewGRF text stack is in use.
|
||||
* @return True iff the NewGRF text stack is used.
|
||||
* Process NewGRF string control code instructions.
|
||||
* @param scc The string control code that has been read.
|
||||
* @param str The string that we are reading from.
|
||||
* @param stack The TextRefStack.
|
||||
* @param[out] params Output parameters
|
||||
*/
|
||||
bool UsingNewGRFTextStack()
|
||||
static void RemapNewGRFStringControlCode(char32_t scc, const char **str, TextRefStack &stack, std::vector<StringParameter> ¶ms)
|
||||
{
|
||||
return _newgrf_textrefstack.used;
|
||||
}
|
||||
auto it = std::back_inserter(params);
|
||||
|
||||
/**
|
||||
* Create a backup of the current NewGRF text stack.
|
||||
* @return A copy of the current text stack.
|
||||
*/
|
||||
struct TextRefStack *CreateTextRefStackBackup()
|
||||
{
|
||||
return new TextRefStack(_newgrf_textrefstack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore a copy of the text stack to the used stack.
|
||||
* @param backup The copy to restore.
|
||||
*/
|
||||
void RestoreTextRefStackBackup(struct TextRefStack *backup)
|
||||
{
|
||||
_newgrf_textrefstack = *backup;
|
||||
delete backup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start using the TTDP compatible string code parsing.
|
||||
*
|
||||
* On start a number of values is copied on the #TextRefStack.
|
||||
* You can then use #GetString() and the normal string drawing functions,
|
||||
* and they will use the #TextRefStack for NewGRF string codes.
|
||||
*
|
||||
* However, when you want to draw a string multiple times using the same stack,
|
||||
* you have to call #RewindTextRefStack() between draws.
|
||||
*
|
||||
* After you are done with drawing, you must disable usage of the #TextRefStack
|
||||
* by calling #StopTextRefStackUsage(), so NewGRF string codes operate on the
|
||||
* normal string parameters again.
|
||||
*
|
||||
* @param grffile the NewGRF providing the stack data
|
||||
* @param numEntries number of entries to copy from the registers
|
||||
* @param values values to copy onto the stack; if nullptr the temporary NewGRF registers will be used instead
|
||||
*/
|
||||
void StartTextRefStackUsage(const GRFFile *grffile, uint8_t numEntries, const uint32_t *values)
|
||||
{
|
||||
extern TemporaryStorageArray<int32_t, 0x110> _temp_store;
|
||||
|
||||
_newgrf_textrefstack.ResetStack(grffile);
|
||||
|
||||
auto stack_it = _newgrf_textrefstack.stack.begin();
|
||||
for (uint i = 0; i < numEntries; i++) {
|
||||
uint32_t value = values != nullptr ? values[i] : _temp_store.GetValue(0x100 + i);
|
||||
for (uint j = 0; j < 32; j += 8) {
|
||||
*stack_it = GB(value, j, 8);
|
||||
stack_it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Stop using the TTDP compatible string code parsing */
|
||||
void StopTextRefStackUsage()
|
||||
{
|
||||
_newgrf_textrefstack.used = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* FormatString for NewGRF specific "magic" string control codes
|
||||
* @param scc the string control code that has been read
|
||||
* @param str the string that we need to write
|
||||
* @param parameters the OpenTTD string formatting parameters
|
||||
* @param modify_parameters When true, modify the OpenTTD string formatting parameters.
|
||||
* @return the string control code to "execute" now
|
||||
*/
|
||||
char32_t RemapNewGRFStringControlCode(char32_t scc, const char **str, StringParameters ¶meters, bool modify_parameters)
|
||||
{
|
||||
/* There is data on the NewGRF text stack, and we want to move them to OpenTTD's string stack.
|
||||
* After this call, a new call is made with `modify_parameters` set to false when the string is finally formatted. */
|
||||
switch (scc) {
|
||||
default: break;
|
||||
default: return;
|
||||
case SCC_NEWGRF_PRINT_BYTE_SIGNED: *it = stack.PopSignedByte(); break;
|
||||
case SCC_NEWGRF_PRINT_QWORD_CURRENCY: *it = stack.PopSignedQWord(); break;
|
||||
|
||||
/* These control codes take one string parameter, check there are at least that many available. */
|
||||
case SCC_NEWGRF_PRINT_DWORD_SIGNED:
|
||||
case SCC_NEWGRF_PRINT_WORD_SIGNED:
|
||||
case SCC_NEWGRF_PRINT_BYTE_SIGNED:
|
||||
case SCC_NEWGRF_PRINT_WORD_UNSIGNED:
|
||||
case SCC_NEWGRF_PRINT_BYTE_HEX:
|
||||
case SCC_NEWGRF_PRINT_WORD_HEX:
|
||||
case SCC_NEWGRF_PRINT_DWORD_HEX:
|
||||
case SCC_NEWGRF_PRINT_QWORD_HEX:
|
||||
case SCC_NEWGRF_PRINT_DWORD_CURRENCY:
|
||||
case SCC_NEWGRF_PRINT_QWORD_CURRENCY:
|
||||
case SCC_NEWGRF_PRINT_WORD_STRING_ID:
|
||||
case SCC_NEWGRF_PRINT_WORD_DATE_LONG:
|
||||
case SCC_NEWGRF_PRINT_DWORD_DATE_LONG:
|
||||
case SCC_NEWGRF_PRINT_WORD_DATE_SHORT:
|
||||
case SCC_NEWGRF_PRINT_DWORD_DATE_SHORT:
|
||||
case SCC_NEWGRF_PRINT_DWORD_SIGNED: *it = stack.PopSignedDWord(); break;
|
||||
|
||||
case SCC_NEWGRF_PRINT_BYTE_HEX: *it = stack.PopUnsignedByte(); break;
|
||||
case SCC_NEWGRF_PRINT_QWORD_HEX: *it = stack.PopUnsignedQWord(); break;
|
||||
|
||||
case SCC_NEWGRF_PRINT_WORD_SPEED:
|
||||
case SCC_NEWGRF_PRINT_WORD_VOLUME_LONG:
|
||||
case SCC_NEWGRF_PRINT_WORD_VOLUME_SHORT:
|
||||
case SCC_NEWGRF_PRINT_WORD_SIGNED: *it = stack.PopSignedWord(); break;
|
||||
|
||||
case SCC_NEWGRF_PRINT_WORD_HEX:
|
||||
case SCC_NEWGRF_PRINT_WORD_WEIGHT_LONG:
|
||||
case SCC_NEWGRF_PRINT_WORD_WEIGHT_SHORT:
|
||||
case SCC_NEWGRF_PRINT_WORD_POWER:
|
||||
case SCC_NEWGRF_PRINT_DWORD_FORCE:
|
||||
case SCC_NEWGRF_PRINT_WORD_STATION_NAME:
|
||||
case SCC_NEWGRF_PRINT_WORD_CARGO_NAME:
|
||||
if (parameters.GetDataLeft() < 1) {
|
||||
Debug(misc, 0, "Too many NewGRF string parameters.");
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case SCC_NEWGRF_PRINT_WORD_UNSIGNED: *it = stack.PopUnsignedWord(); break;
|
||||
|
||||
case SCC_NEWGRF_PRINT_DWORD_FORCE:
|
||||
case SCC_NEWGRF_PRINT_DWORD_DATE_LONG:
|
||||
case SCC_NEWGRF_PRINT_DWORD_DATE_SHORT:
|
||||
case SCC_NEWGRF_PRINT_DWORD_HEX: *it = stack.PopUnsignedDWord(); break;
|
||||
|
||||
/* Dates from NewGRFs have 1920-01-01 as their zero point, convert it to OpenTTD's epoch. */
|
||||
case SCC_NEWGRF_PRINT_WORD_DATE_LONG:
|
||||
case SCC_NEWGRF_PRINT_WORD_DATE_SHORT: *it = CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR + stack.PopUnsignedWord(); break;
|
||||
|
||||
case SCC_NEWGRF_DISCARD_WORD: stack.PopUnsignedWord(); break;
|
||||
|
||||
case SCC_NEWGRF_ROTATE_TOP_4_WORDS: stack.RotateTop4Words(); break;
|
||||
case SCC_NEWGRF_PUSH_WORD: stack.PushWord(Utf8Consume(str)); break;
|
||||
|
||||
/* These string code take two string parameters, check there are at least that many available. */
|
||||
case SCC_NEWGRF_PRINT_WORD_CARGO_LONG:
|
||||
case SCC_NEWGRF_PRINT_WORD_CARGO_SHORT:
|
||||
case SCC_NEWGRF_PRINT_WORD_CARGO_TINY:
|
||||
if (parameters.GetDataLeft() < 2) {
|
||||
Debug(misc, 0, "Too many NewGRF string parameters.");
|
||||
return 0;
|
||||
}
|
||||
*it = GetCargoTranslation(stack.PopUnsignedWord(), stack.grffile);
|
||||
*it = stack.PopUnsignedWord();
|
||||
break;
|
||||
}
|
||||
|
||||
if (_newgrf_textrefstack.used && modify_parameters) {
|
||||
/* There is data on the NewGRF text stack, and we want to move them to OpenTTD's string stack.
|
||||
* After this call, a new call is made with `modify_parameters` set to false when the string is finally formatted. */
|
||||
switch (scc) {
|
||||
default: NOT_REACHED();
|
||||
case SCC_NEWGRF_PRINT_BYTE_SIGNED: parameters.SetParam(0, _newgrf_textrefstack.PopSignedByte()); break;
|
||||
case SCC_NEWGRF_PRINT_QWORD_CURRENCY: parameters.SetParam(0, _newgrf_textrefstack.PopSignedQWord()); break;
|
||||
|
||||
case SCC_NEWGRF_PRINT_DWORD_CURRENCY:
|
||||
case SCC_NEWGRF_PRINT_DWORD_SIGNED: parameters.SetParam(0, _newgrf_textrefstack.PopSignedDWord()); break;
|
||||
|
||||
case SCC_NEWGRF_PRINT_BYTE_HEX: parameters.SetParam(0, _newgrf_textrefstack.PopUnsignedByte()); break;
|
||||
case SCC_NEWGRF_PRINT_QWORD_HEX: parameters.SetParam(0, _newgrf_textrefstack.PopUnsignedQWord()); break;
|
||||
|
||||
case SCC_NEWGRF_PRINT_WORD_SPEED:
|
||||
case SCC_NEWGRF_PRINT_WORD_VOLUME_LONG:
|
||||
case SCC_NEWGRF_PRINT_WORD_VOLUME_SHORT:
|
||||
case SCC_NEWGRF_PRINT_WORD_SIGNED: parameters.SetParam(0, _newgrf_textrefstack.PopSignedWord()); break;
|
||||
|
||||
case SCC_NEWGRF_PRINT_WORD_HEX:
|
||||
case SCC_NEWGRF_PRINT_WORD_WEIGHT_LONG:
|
||||
case SCC_NEWGRF_PRINT_WORD_WEIGHT_SHORT:
|
||||
case SCC_NEWGRF_PRINT_WORD_POWER:
|
||||
case SCC_NEWGRF_PRINT_WORD_STATION_NAME:
|
||||
case SCC_NEWGRF_PRINT_WORD_UNSIGNED: parameters.SetParam(0, _newgrf_textrefstack.PopUnsignedWord()); break;
|
||||
|
||||
case SCC_NEWGRF_PRINT_DWORD_FORCE:
|
||||
case SCC_NEWGRF_PRINT_DWORD_DATE_LONG:
|
||||
case SCC_NEWGRF_PRINT_DWORD_DATE_SHORT:
|
||||
case SCC_NEWGRF_PRINT_DWORD_HEX: parameters.SetParam(0, _newgrf_textrefstack.PopUnsignedDWord()); break;
|
||||
|
||||
/* Dates from NewGRFs have 1920-01-01 as their zero point, convert it to OpenTTD's epoch. */
|
||||
case SCC_NEWGRF_PRINT_WORD_DATE_LONG:
|
||||
case SCC_NEWGRF_PRINT_WORD_DATE_SHORT: parameters.SetParam(0, CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR + _newgrf_textrefstack.PopUnsignedWord()); break;
|
||||
|
||||
case SCC_NEWGRF_DISCARD_WORD: _newgrf_textrefstack.PopUnsignedWord(); break;
|
||||
|
||||
case SCC_NEWGRF_ROTATE_TOP_4_WORDS: _newgrf_textrefstack.RotateTop4Words(); break;
|
||||
case SCC_NEWGRF_PUSH_WORD: _newgrf_textrefstack.PushWord(Utf8Consume(str)); break;
|
||||
|
||||
case SCC_NEWGRF_PRINT_WORD_CARGO_LONG:
|
||||
case SCC_NEWGRF_PRINT_WORD_CARGO_SHORT:
|
||||
case SCC_NEWGRF_PRINT_WORD_CARGO_TINY:
|
||||
parameters.SetParam(0, GetCargoTranslation(_newgrf_textrefstack.PopUnsignedWord(), _newgrf_textrefstack.grffile));
|
||||
parameters.SetParam(1, _newgrf_textrefstack.PopUnsignedWord());
|
||||
break;
|
||||
|
||||
case SCC_NEWGRF_PRINT_WORD_STRING_ID:
|
||||
parameters.SetParam(0, MapGRFStringID(_newgrf_textrefstack.grffile->grfid, GRFStringID{_newgrf_textrefstack.PopUnsignedWord()}));
|
||||
break;
|
||||
|
||||
case SCC_NEWGRF_PRINT_WORD_CARGO_NAME: {
|
||||
CargoType cargo = GetCargoTranslation(_newgrf_textrefstack.PopUnsignedWord(), _newgrf_textrefstack.grffile);
|
||||
parameters.SetParam(0, cargo < NUM_CARGO ? 1ULL << cargo : 0);
|
||||
break;
|
||||
}
|
||||
case SCC_NEWGRF_PRINT_WORD_STRING_ID: {
|
||||
StringID stringid = MapGRFStringID(stack.grffile->grfid, GRFStringID{stack.PopUnsignedWord()});
|
||||
*it = stringid;
|
||||
/* We also need to handle the substring's stack usage. */
|
||||
HandleNewGRFStringControlCodes(GetStringPtr(stringid), stack, params);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Consume additional parameter characters that follow the NewGRF string code. */
|
||||
switch (scc) {
|
||||
default: break;
|
||||
|
||||
case SCC_NEWGRF_PUSH_WORD:
|
||||
Utf8Consume(str);
|
||||
break;
|
||||
case SCC_NEWGRF_PRINT_WORD_CARGO_NAME: {
|
||||
CargoType cargo = GetCargoTranslation(stack.PopUnsignedWord(), stack.grffile);
|
||||
*it = cargo < NUM_CARGO ? 1ULL << cargo : 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Emit OpenTTD's internal string code for the different NewGRF variants. */
|
||||
/**
|
||||
* Emit OpenTTD's internal string code for the different NewGRF string codes.
|
||||
* @param scc NewGRF string code.
|
||||
* @param[in,out] str String iterator, moved forward if SCC_NEWGRF_PUSH_WORD is found.
|
||||
* @returns String code to use.
|
||||
*/
|
||||
char32_t RemapNewGRFStringControlCode(char32_t scc, const char **str)
|
||||
{
|
||||
switch (scc) {
|
||||
default: NOT_REACHED();
|
||||
default:
|
||||
return scc;
|
||||
|
||||
case SCC_NEWGRF_PRINT_DWORD_SIGNED:
|
||||
case SCC_NEWGRF_PRINT_WORD_SIGNED:
|
||||
case SCC_NEWGRF_PRINT_BYTE_SIGNED:
|
||||
|
@ -1007,9 +902,66 @@ char32_t RemapNewGRFStringControlCode(char32_t scc, const char **str, StringPara
|
|||
return SCC_STATION_NAME;
|
||||
|
||||
/* These NewGRF string codes modify the NewGRF stack or otherwise do not map to OpenTTD string codes. */
|
||||
case SCC_NEWGRF_PUSH_WORD:
|
||||
Utf8Consume(str);
|
||||
return 0;
|
||||
|
||||
case SCC_NEWGRF_DISCARD_WORD:
|
||||
case SCC_NEWGRF_ROTATE_TOP_4_WORDS:
|
||||
case SCC_NEWGRF_PUSH_WORD:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle control codes in a NewGRF string, processing the stack and filling parameters.
|
||||
* @param str String to process.
|
||||
* @param[in,out] stack Stack to use.
|
||||
* @param[out] params Parameters to fill.
|
||||
*/
|
||||
static void HandleNewGRFStringControlCodes(const char *str, TextRefStack &stack, std::vector<StringParameter> ¶ms)
|
||||
{
|
||||
if (str == nullptr) return;
|
||||
|
||||
for (const char *p = str; *p != '\0'; /* nothing */) {
|
||||
char32_t scc;
|
||||
p += Utf8Decode(&scc, p);
|
||||
RemapNewGRFStringControlCode(scc, &p, stack, params);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the text ref stack for a GRF String and return its parameters.
|
||||
* @param grffile GRFFile of string.
|
||||
* @param stringid StringID of string.
|
||||
* @param num_entries Number of temporary storage registers to import.
|
||||
* @returns Parameters for GRF string.
|
||||
*/
|
||||
std::vector<StringParameter> GetGRFSringTextStackParameters(const GRFFile *grffile, StringID stringid, uint8_t num_entries)
|
||||
{
|
||||
if (stringid == INVALID_STRING_ID) return {};
|
||||
|
||||
const char *str = GetStringPtr(stringid);
|
||||
if (str == nullptr) return {};
|
||||
|
||||
std::vector<StringParameter> params;
|
||||
params.reserve(20);
|
||||
|
||||
TextRefStack stack{grffile, num_entries};
|
||||
HandleNewGRFStringControlCodes(str, stack, params);
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a GRF string using the text ref stack for parameters.
|
||||
* @param grffile GRFFile of string.
|
||||
* @param grfstringid GRFStringID of string.
|
||||
* @param num_entries Number of temporary storage registers to import.
|
||||
* @returns Formatted string.
|
||||
*/
|
||||
std::string GetGRFStringWithTextStack(const struct GRFFile *grffile, GRFStringID grfstringid, uint8_t num_entries)
|
||||
{
|
||||
StringID stringid = GetGRFStringID(grffile->grfid, grfstringid);
|
||||
auto params = GetGRFSringTextStackParameters(grffile, stringid, num_entries);
|
||||
return GetStringWithArgs(stringid, params);
|
||||
}
|
||||
|
|
|
@ -28,10 +28,7 @@ void AddGRFTextToList(GRFTextWrapper &list, std::string_view text_to_add);
|
|||
|
||||
bool CheckGrfLangID(uint8_t lang_id, uint8_t grf_version);
|
||||
|
||||
void StartTextRefStackUsage(const struct GRFFile *grffile, uint8_t numEntries, const uint32_t *values = nullptr);
|
||||
void StopTextRefStackUsage();
|
||||
bool UsingNewGRFTextStack();
|
||||
struct TextRefStack *CreateTextRefStackBackup();
|
||||
void RestoreTextRefStackBackup(struct TextRefStack *backup);
|
||||
std::vector<StringParameter> GetGRFSringTextStackParameters(const struct GRFFile *grffile, StringID stringid, uint8_t num_entries);
|
||||
std::string GetGRFStringWithTextStack(const struct GRFFile *grffile, GRFStringID grfstringid, uint8_t num_entries);
|
||||
|
||||
#endif /* NEWGRF_TEXT_H */
|
||||
|
|
|
@ -245,11 +245,9 @@ public:
|
|||
if (callback_res > 0x400) {
|
||||
ErrorUnknownCallbackResult(spec->grf_prop.grfid, CBID_OBJECT_FUND_MORE_TEXT, callback_res);
|
||||
} else {
|
||||
StringID message = GetGRFStringID(spec->grf_prop.grfid, GRFSTR_MISC_GRF_TEXT + callback_res);
|
||||
if (message != STR_NULL && message != STR_UNDEFINED) {
|
||||
StartTextRefStackUsage(spec->grf_prop.grffile, 6);
|
||||
tr.top = DrawStringMultiLine(tr, message, TC_ORANGE);
|
||||
StopTextRefStackUsage();
|
||||
std::string str = GetGRFStringWithTextStack(spec->grf_prop.grffile, GRFSTR_MISC_GRF_TEXT + callback_res, 6);
|
||||
if (!str.empty()) {
|
||||
tr.top = DrawStringMultiLine(tr, str, TC_ORANGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1143,19 +1143,7 @@ static void FormatString(StringBuilder &builder, const char *str_arg, StringPara
|
|||
*/
|
||||
std::string buffer;
|
||||
StringBuilder dry_run_builder(buffer);
|
||||
if (UsingNewGRFTextStack()) {
|
||||
/* Values from the NewGRF text stack are only copied to the normal
|
||||
* argv array at the time they are encountered. That means that if
|
||||
* another string command references a value later in the string it
|
||||
* would fail. We solve that by running FormatString twice. The first
|
||||
* pass makes sure the argv array is correctly filled and the second
|
||||
* pass can reference later values without problems. */
|
||||
struct TextRefStack *backup = CreateTextRefStackBackup();
|
||||
FormatString(dry_run_builder, str_arg, args, case_index, game_script, true);
|
||||
RestoreTextRefStackBackup(backup);
|
||||
} else {
|
||||
FormatString(dry_run_builder, str_arg, args, case_index, game_script, true);
|
||||
}
|
||||
FormatString(dry_run_builder, str_arg, args, case_index, game_script, true);
|
||||
/* We have to restore the original offset here to to read the correct values. */
|
||||
args.SetOffset(orig_offset);
|
||||
}
|
||||
|
@ -1174,8 +1162,7 @@ static void FormatString(StringBuilder &builder, const char *str_arg, StringPara
|
|||
|
||||
if (SCC_NEWGRF_FIRST <= b && b <= SCC_NEWGRF_LAST) {
|
||||
/* We need to pass some stuff as it might be modified. */
|
||||
StringParameters remaining = args.GetRemainingParameters();
|
||||
b = RemapNewGRFStringControlCode(b, &str, remaining, dry_run);
|
||||
b = RemapNewGRFStringControlCode(b, &str);
|
||||
if (b == 0) continue;
|
||||
}
|
||||
|
||||
|
@ -1677,11 +1664,7 @@ static void FormatString(StringBuilder &builder, const char *str_arg, StringPara
|
|||
const GRFFile *grffile = e->GetGRF();
|
||||
assert(grffile != nullptr);
|
||||
|
||||
StartTextRefStackUsage(grffile, 6);
|
||||
ArrayStringParameters<6> tmp_params;
|
||||
GetStringWithArgs(builder, GetGRFStringID(grffile->grfid, GRFSTR_MISC_GRF_TEXT + callback), tmp_params);
|
||||
StopTextRefStackUsage();
|
||||
|
||||
builder += GetGRFStringWithTextStack(grffile, GRFSTR_MISC_GRF_TEXT + callback, 6);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -338,6 +338,6 @@ void GenerateTownNameString(StringBuilder &builder, size_t lang, uint32_t seed);
|
|||
void GetTownName(StringBuilder &builder, const struct Town *t);
|
||||
void GRFTownNameGenerate(StringBuilder &builder, uint32_t grfid, uint16_t gen, uint32_t seed);
|
||||
|
||||
char32_t RemapNewGRFStringControlCode(char32_t scc, const char **str, StringParameters ¶meters, bool modify_parameters);
|
||||
char32_t RemapNewGRFStringControlCode(char32_t scc, const char **str);
|
||||
|
||||
#endif /* STRINGS_INTERNAL_H */
|
||||
|
|
Loading…
Reference in New Issue