@@ -444,13 +444,13 @@ char *TranslateTTDPatchCodes(uint32 grfi
case 0x80: d += Utf8Encode(d, SCC_NEWGRF_PRINT_DWORD + c - 0x7B); break;
case 0x81: {
if (str[0] == '\0' || str[1] == '\0') goto string_end;
StringID string;
string = ((uint8)*str++);
string |= ((uint8)*str++) << 8;
d += Utf8Encode(d, SCC_STRING_ID);
d += Utf8Encode(d, SCC_NEWGRF_STRINL);
d += Utf8Encode(d, MapGRFStringID(grfid, string));
break;
}
case 0x82:
case 0x83:
case 0x84: d += Utf8Encode(d, SCC_NEWGRF_PRINT_DATE + c - 0x82); break;
@@ -1056,13 +1056,13 @@ uint RemapNewGRFStringControlCode(uint s
case SCC_NEWGRF_PRINT_DWORD_CURRENCY:
case SCC_NEWGRF_PRINT_QWORD_CURRENCY:
return SCC_CURRENCY;
case SCC_NEWGRF_PRINT_STRING_ID:
return SCC_STRING1;
return SCC_NEWGRF_PRINT_STRING_ID;
case SCC_NEWGRF_PRINT_DATE:
return SCC_DATE_LONG;
case SCC_NEWGRF_PRINT_MONTH_YEAR:
return SCC_DATE_TINY;
@@ -34,12 +34,13 @@
#include "townname_func.h"
#include "string_func.h"
#include "company_base.h"
#include "smallmap_gui.h"
#include "window_func.h"
#include "debug.h"
#include <stack>
#include "table/strings.h"
#include "table/control_codes.h"
char _config_language_file[MAX_PATH]; ///< The file (name) stored in the configuration.
LanguageList _languages; ///< The actual list of language meta data.
@@ -118,12 +119,14 @@ static inline int64 *GetArgvPtr(int64 **
const char *GetStringPtr(StringID string)
{
switch (GB(string, 11, 5)) {
/* GetGRFStringPtr doesn't handle 0xD4xx ids, we need to convert those to 0xD0xx. */
case 26: return GetStringPtr(GetGRFStringID(0, 0xD000 + GB(string, 0, 10)));
case 28: return GetGRFStringPtr(GB(string, 0, 11));
case 29: return GetGRFStringPtr(GB(string, 0, 11) + 0x0800);
case 30: return GetGRFStringPtr(GB(string, 0, 11) + 0x1000);
default: return _langpack_offs[_langtab_start[string >> 11] + (string & 0x7FF)];
@@ -619,44 +622,65 @@ uint ConvertDisplaySpeedToSpeed(uint spe
* @param argve Pointer to just past the end of the argv array.
* @param casei
* @param last Pointer to just past the end of the buff array.
* @param argt Pointer to an array with the string codes used to parse the argv array.
* @param dry_run True when the argt array is not yet initialized.
*/
static char *FormatString(char *buff, const char *str, int64 *argv, const int64 *argve, uint casei, const char *last, WChar *argt, bool dry_run)
static char *FormatString(char *buff, const char *str_arg, int64 *argv, const int64 *argve, uint casei, const char *last, WChar *argt, bool dry_run)
/* When there is no array with types there is no need to do a dry run. */
if (argt == NULL) dry_run = true;
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, argve, casei, last, argt, true);
FormatString(buff, str_arg, argv, argve, casei, last, argt, true);
RestoreTextRefStackBackup(backup);
} else if (!dry_run) {
WChar b;
int64 *argv_orig = argv;
WChar *argt_orig = argt;
uint modifier = 0;
char *buf_start = buff;
std::stack<const char *> str_stack;
str_stack.push(str_arg);
while ((b = Utf8Consume(&str)) != '\0') {
while (true) {
while (!str_stack.empty() && (b = Utf8Consume(&str_stack.top())) == '\0') {
str_stack.pop();
if (str_stack.empty()) break;
const char *&str = str_stack.top();
if (SCC_NEWGRF_FIRST <= b && b <= SCC_NEWGRF_LAST) {
/* We need to pass some stuff as it might be modified; oh boy. */
//todo: should argve be passed here too?
b = RemapNewGRFStringControlCode(b, buf_start, &buff, &str, argv);
if (b == 0) continue;
switch (b) {
case SCC_NEWGRF_STRINL: {
StringID substr = Utf8Consume(&str);
str_stack.push(GetStringPtr(substr));
case SCC_NEWGRF_PRINT_STRING_ID: {
StringID substr = GetInt32(&argv, argve, &argt, SCC_NEWGRF_PRINT_STRING_ID);
case SCC_SETX: // {SETX}
if (buff + Utf8CharLen(SCC_SETX) + 1 < last) {
buff += Utf8Encode(buff, SCC_SETX);
*buff++ = *str++;
@@ -131,12 +131,14 @@ enum StringControlCode {
SCC_NEWGRF_PUSH_WORD, ///< Pushes 2 bytes onto the stack
SCC_NEWGRF_UNPRINT, ///< "Unprints" the given number of bytes from the string
SCC_NEWGRF_DISCARD_WORD, ///< Discard the next two bytes
SCC_NEWGRF_ROTATE_TOP_4_WORDS, ///< Rotate the top 4 words of the stack (W4 W1 W2 W3)
SCC_NEWGRF_LAST = SCC_NEWGRF_ROTATE_TOP_4_WORDS,
SCC_NEWGRF_STRINL, ///< Inline another string at the current position, StringID is encoded in the string
/* Special printable symbols.
* These are mapped to the original glyphs */
SCC_LESSTHAN = SCC_SPRITE_START + 0x3C,
SCC_GREATERTHAN = SCC_SPRITE_START + 0x3E,
SCC_UPARROW = SCC_SPRITE_START + 0xA0,
SCC_DOWNARROW = SCC_SPRITE_START + 0xAA,
Status change: