changeset 16702:9ef2e68ef3c6 draft

(svn r21435) -Fix: NewGRF strings that referenced a value that was set by a string command later in the string failed
author yexo <yexo@openttd.org>
date Wed, 08 Dec 2010 13:44:01 +0000 (2010-12-08)
parents 90ef25d1d9e6
children f0f404702f1c
files src/newgrf_text.cpp src/newgrf_text.h src/strings.cpp
diffstat 3 files changed, 51 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/src/newgrf_text.cpp
+++ b/src/newgrf_text.cpp
@@ -863,6 +863,13 @@
 
 	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_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
  */
--- a/src/newgrf_text.h
+++ b/src/newgrf_text.h
@@ -39,6 +39,9 @@
 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);
--- a/src/strings.cpp
+++ b/src/strings.cpp
@@ -56,7 +56,7 @@
 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 @@
 	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;