summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/newgrf_text.cpp35
-rw-r--r--src/newgrf_text.h3
-rw-r--r--src/strings.cpp15
3 files changed, 51 insertions, 2 deletions
diff --git a/src/newgrf_text.cpp b/src/newgrf_text.cpp
index a1b07ad3b..ff77c441c 100644
--- a/src/newgrf_text.cpp
+++ b/src/newgrf_text.cpp
@@ -863,6 +863,13 @@ struct TextRefStack {
TextRefStack() : used(false) {}
+ TextRefStack(const TextRefStack &stack) :
+ position(stack.position),
+ used(stack.used)
+ {
+ memcpy(this->stack, stack.stack, sizeof(this->stack));
+ }
+
uint8 PopUnsignedByte() { assert(this->position < lengthof(this->stack)); return this->stack[this->position++]; }
int8 PopSignedByte() { return (int8)this->PopUnsignedByte(); }
@@ -920,6 +927,34 @@ static TextRefStack _newgrf_error_textrefstack;
static TextRefStack *_newgrf_textrefstack = &_newgrf_normal_textrefstack;
/**
+ * Check whether the NewGRF text stack is in use.
+ * @return True iff the NewGRF text stack is used.
+ */
+bool UsingNewGRFTextStack()
+{
+ return _newgrf_textrefstack->used;
+}
+
+/**
+ * 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;
+}
+
+/**
* Prepare the TTDP compatible string code parsing
* @param numEntries number of entries to copy from the registers
*/
diff --git a/src/newgrf_text.h b/src/newgrf_text.h
index a4c5f6123..ac0c79130 100644
--- a/src/newgrf_text.h
+++ b/src/newgrf_text.h
@@ -39,6 +39,9 @@ void StopTextRefStackUsage();
void SwitchToNormalRefStack();
void SwitchToErrorRefStack();
void RewindTextRefStack();
+bool UsingNewGRFTextStack();
+struct TextRefStack *CreateTextRefStackBackup();
+void RestoreTextRefStackBackup(struct TextRefStack *backup);
uint RemapNewGRFStringControlCode(uint scc, char *buf_start, char **buff, const char **str, int64 *argv);
StringID TTDPStringIDToOTTDStringIDMapping(StringID string);
diff --git a/src/strings.cpp b/src/strings.cpp
index f6c62a947..f3db95fb1 100644
--- a/src/strings.cpp
+++ b/src/strings.cpp
@@ -56,7 +56,7 @@ static char *StationGetSpecialString(char *buff, int x, const char *last);
static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last);
static char *GetSpecialNameString(char *buff, int ind, int64 *argv, const char *last);
-static char *FormatString(char *buff, const char *str, int64 *argv, uint casei, const char *last);
+static char *FormatString(char *buff, const char *str, int64 *argv, uint casei, const char *last, bool dry_run = false);
struct LanguagePack : public LanguagePackHeader {
char data[]; // list of strings
@@ -583,8 +583,19 @@ uint ConvertDisplaySpeedToSpeed(uint speed)
return ((speed << units[_settings_game.locale.units].s_s) + units[_settings_game.locale.units].s_m / 2) / units[_settings_game.locale.units].s_m;
}
-static char *FormatString(char *buff, const char *str, int64 *argv, uint casei, const char *last)
+static char *FormatString(char *buff, const char *str, int64 *argv, uint casei, const char *last, bool dry_run)
{
+ if (UsingNewGRFTextStack() && !dry_run) {
+ /* 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(buff, str, argv, casei, last, true);
+ RestoreTextRefStackBackup(backup);
+ }
WChar b;
int64 *argv_orig = argv;
uint modifier = 0;