src/strings.c
branchcustombridgeheads
changeset 5649 55c8267c933f
parent 5648 1608018c5ff2
child 5650 aefc131bf5ce
equal deleted inserted replaced
5648:1608018c5ff2 5649:55c8267c933f
     1 /* $Id$ */
       
     2 
       
     3 #include "stdafx.h"
       
     4 #include "openttd.h"
       
     5 #include "currency.h"
       
     6 #include "functions.h"
       
     7 #include "string.h"
       
     8 #include "strings.h"
       
     9 #include "table/strings.h"
       
    10 #include "namegen.h"
       
    11 #include "station.h"
       
    12 #include "town.h"
       
    13 #include "vehicle.h"
       
    14 #include "news.h"
       
    15 #include "screenshot.h"
       
    16 #include "waypoint.h"
       
    17 #include "industry.h"
       
    18 #include "variables.h"
       
    19 #include "newgrf_text.h"
       
    20 #include "table/landscape_const.h"
       
    21 #include "table/control_codes.h"
       
    22 #include "music.h"
       
    23 #include "date.h"
       
    24 #include "industry.h"
       
    25 
       
    26 #ifdef WIN32
       
    27 /* for opendir/readdir/closedir */
       
    28 # include "fios.h"
       
    29 #else
       
    30 # include <sys/types.h>
       
    31 # include <dirent.h>
       
    32 #endif /* WIN32 */
       
    33 
       
    34 char _userstring[128];
       
    35 
       
    36 static char *StationGetSpecialString(char *buff, int x, const char* last);
       
    37 static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char* last);
       
    38 static char *GetSpecialPlayerNameString(char *buff, int ind, const int32 *argv, const char* last);
       
    39 
       
    40 static char *FormatString(char *buff, const char *str, const int32 *argv, uint casei, const char* last);
       
    41 
       
    42 typedef struct LanguagePack {
       
    43 	uint32 ident;
       
    44 	uint32 version;     // 32-bits of auto generated version info which is basically a hash of strings.h
       
    45 	char name[32];      // the international name of this language
       
    46 	char own_name[32];  // the localized name of this language
       
    47 	char isocode[16];   // the ISO code for the language (not country code)
       
    48 	uint16 offsets[32]; // the offsets
       
    49 	byte plural_form;   // how to compute plural forms
       
    50 	byte pad[3];        // pad header to be a multiple of 4
       
    51 	char data[VARARRAY_SIZE];
       
    52 } LanguagePack;
       
    53 
       
    54 static char **_langpack_offs;
       
    55 static LanguagePack *_langpack;
       
    56 static uint _langtab_num[32]; // Offset into langpack offs
       
    57 static uint _langtab_start[32]; // Offset into langpack offs
       
    58 
       
    59 static const StringID _cargo_string_list[NUM_LANDSCAPE][NUM_CARGO] = {
       
    60 	{ /* LT_NORMAL */
       
    61 		STR_PASSENGERS,
       
    62 		STR_TONS,
       
    63 		STR_BAGS,
       
    64 		STR_LITERS,
       
    65 		STR_ITEMS,
       
    66 		STR_CRATES,
       
    67 		STR_TONS,
       
    68 		STR_TONS,
       
    69 		STR_TONS,
       
    70 		STR_TONS,
       
    71 		STR_BAGS,
       
    72 		STR_RES_OTHER
       
    73 	},
       
    74 
       
    75 	{ /* LT_HILLY */
       
    76 		STR_PASSENGERS,
       
    77 		STR_TONS,
       
    78 		STR_BAGS,
       
    79 		STR_LITERS,
       
    80 		STR_ITEMS,
       
    81 		STR_CRATES,
       
    82 		STR_TONS,
       
    83 		STR_TONS,
       
    84 		STR_RES_OTHER,
       
    85 		STR_TONS,
       
    86 		STR_BAGS,
       
    87 		STR_TONS
       
    88 	},
       
    89 
       
    90 	{ /* LT_DESERT */
       
    91 		STR_PASSENGERS,
       
    92 		STR_LITERS,
       
    93 		STR_BAGS,
       
    94 		STR_LITERS,
       
    95 		STR_TONS,
       
    96 		STR_CRATES,
       
    97 		STR_TONS,
       
    98 		STR_TONS,
       
    99 		STR_TONS,
       
   100 		STR_LITERS,
       
   101 		STR_BAGS,
       
   102 		STR_TONS
       
   103 	},
       
   104 
       
   105 	{ /* LT_CANDY */
       
   106 		STR_PASSENGERS,
       
   107 		STR_TONS,
       
   108 		STR_BAGS,
       
   109 		STR_NOTHING,
       
   110 		STR_NOTHING,
       
   111 		STR_TONS,
       
   112 		STR_TONS,
       
   113 		STR_LITERS,
       
   114 		STR_TONS,
       
   115 		STR_NOTHING,
       
   116 		STR_LITERS,
       
   117 		STR_NOTHING
       
   118 	}
       
   119 };
       
   120 
       
   121 
       
   122 // Read an int64 from the argv array.
       
   123 static inline int64 GetInt64(const int32 **argv)
       
   124 {
       
   125 	int64 result;
       
   126 
       
   127 	assert(argv);
       
   128 	result = (uint32)(*argv)[0] + ((uint64)(uint32)(*argv)[1] << 32);
       
   129 	(*argv)+=2;
       
   130 	return result;
       
   131 }
       
   132 
       
   133 // Read an int32 from the argv array.
       
   134 static inline int32 GetInt32(const int32 **argv)
       
   135 {
       
   136 	assert(argv);
       
   137 	return *(*argv)++;
       
   138 }
       
   139 
       
   140 // Read an array from the argv array.
       
   141 static inline const int32 *GetArgvPtr(const int32 **argv, int n)
       
   142 {
       
   143 	const int32 *result;
       
   144 	assert(*argv);
       
   145 	result = *argv;
       
   146 	(*argv) += n;
       
   147 	return result;
       
   148 }
       
   149 
       
   150 
       
   151 #define NUM_BOUND_STRINGS 8
       
   152 
       
   153 // Array to hold the bound strings.
       
   154 static const char *_bound_strings[NUM_BOUND_STRINGS];
       
   155 
       
   156 // This index is used to implement a "round-robin" allocating of
       
   157 // slots for BindCString. NUM_BOUND_STRINGS slots are reserved.
       
   158 // Which means that after NUM_BOUND_STRINGS calls to BindCString,
       
   159 // the indices will be reused.
       
   160 static int _bind_index;
       
   161 
       
   162 static const char *GetStringPtr(StringID string)
       
   163 {
       
   164 	return _langpack_offs[_langtab_start[string >> 11] + (string & 0x7FF)];
       
   165 }
       
   166 
       
   167 // The highest 8 bits of string contain the "case index".
       
   168 // These 8 bits will only be set when FormatString wants to print
       
   169 // the string in a different case. No one else except FormatString
       
   170 // should set those bits, therefore string CANNOT be StringID, but uint32.
       
   171 static char *GetStringWithArgs(char *buffr, uint string, const int32 *argv, const char* last)
       
   172 {
       
   173 	uint index = GB(string,  0, 11);
       
   174 	uint tab   = GB(string, 11,  5);
       
   175 	char buff[512];
       
   176 
       
   177 	if (GB(string, 0, 16) == 0) error("!invalid string id 0 in GetString");
       
   178 
       
   179 	switch (tab) {
       
   180 		case 4:
       
   181 			if (index >= 0xC0)
       
   182 				return GetSpecialTownNameString(buffr, index - 0xC0, GetInt32(&argv), last);
       
   183 			break;
       
   184 
       
   185 		case 14:
       
   186 			if (index >= 0xE4)
       
   187 				return GetSpecialPlayerNameString(buffr, index - 0xE4, argv, last);
       
   188 			break;
       
   189 
       
   190 		// User defined name
       
   191 		case 15:
       
   192 			return GetName(buffr, index, last);
       
   193 
       
   194 		case 26:
       
   195 			/* Include string within newgrf text (format code 81) */
       
   196 			if (HASBIT(index, 10)) {
       
   197 				StringID string = GetGRFStringID(0, 0xD000 + GB(index, 0, 10));
       
   198 				return GetStringWithArgs(buffr, string, argv, last);
       
   199 			}
       
   200 			break;
       
   201 
       
   202 		case 28:
       
   203 			GetGRFString(buff, index, lastof(buff));
       
   204 			return FormatString(buffr, buff, argv, 0, last);
       
   205 
       
   206 		case 29:
       
   207 			GetGRFString(buff, index + 0x800, lastof(buff));
       
   208 			return FormatString(buffr, buff, argv, 0, last);
       
   209 
       
   210 		case 30:
       
   211 			GetGRFString(buff, index + 0x1000, lastof(buff));
       
   212 			return FormatString(buffr, buff, argv, 0, last);
       
   213 
       
   214 		case 31:
       
   215 			// dynamic strings. These are NOT to be passed through the formatter,
       
   216 			// but passed through verbatim.
       
   217 			if (index < (STR_SPEC_USERSTRING & 0x7FF)) {
       
   218 				return strecpy(buffr, _bound_strings[index], last);
       
   219 			}
       
   220 
       
   221 			return FormatString(buffr, _userstring, NULL, 0, last);
       
   222 	}
       
   223 
       
   224 	if (index >= _langtab_num[tab]) {
       
   225 		error(
       
   226 			"!String 0x%X is invalid. "
       
   227 			"Probably because an old version of the .lng file.\n", string
       
   228 		);
       
   229 	}
       
   230 
       
   231 	return FormatString(buffr, GetStringPtr(GB(string, 0, 16)), argv, GB(string, 24, 8), last);
       
   232 }
       
   233 
       
   234 char *GetString(char *buffr, StringID string, const char* last)
       
   235 {
       
   236 	return GetStringWithArgs(buffr, string, (int32*)_decode_parameters, last);
       
   237 }
       
   238 
       
   239 
       
   240 char *InlineString(char *buf, StringID string)
       
   241 {
       
   242 	buf += Utf8Encode(buf, SCC_STRING_ID);
       
   243 	buf += Utf8Encode(buf, string);
       
   244 	return buf;
       
   245 }
       
   246 
       
   247 
       
   248 // This function takes a C-string and allocates a temporary string ID.
       
   249 // The duration of the bound string is valid only until the next GetString,
       
   250 // so be careful.
       
   251 StringID BindCString(const char *str)
       
   252 {
       
   253 	int idx = (++_bind_index) & (NUM_BOUND_STRINGS - 1);
       
   254 	_bound_strings[idx] = str;
       
   255 	return idx + STR_SPEC_DYNSTRING;
       
   256 }
       
   257 
       
   258 // This function is used to "bind" a C string to a OpenTTD dparam slot.
       
   259 void SetDParamStr(uint n, const char *str)
       
   260 {
       
   261 	SetDParam(n, BindCString(str));
       
   262 }
       
   263 
       
   264 void InjectDParam(int amount)
       
   265 {
       
   266 	memmove(_decode_parameters + amount, _decode_parameters, sizeof(_decode_parameters) - amount * sizeof(uint32));
       
   267 }
       
   268 
       
   269 static const uint32 _divisor_table[] = {
       
   270 	1000000000,
       
   271 	100000000,
       
   272 	10000000,
       
   273 	1000000,
       
   274 
       
   275 	100000,
       
   276 	10000,
       
   277 	1000,
       
   278 	100,
       
   279 	10,
       
   280 	1
       
   281 };
       
   282 
       
   283 // TODO
       
   284 static char *FormatCommaNumber(char *buff, int32 number, const char* last)
       
   285 {
       
   286 	uint32 quot,divisor;
       
   287 	int i;
       
   288 	uint32 tot;
       
   289 	uint32 num;
       
   290 
       
   291 	if (number < 0) {
       
   292 		*buff++ = '-';
       
   293 		number = -number;
       
   294 	}
       
   295 
       
   296 	num = number;
       
   297 
       
   298 	tot = 0;
       
   299 	for (i = 0; i != 10; i++) {
       
   300 		divisor = _divisor_table[i];
       
   301 		quot = 0;
       
   302 		if (num >= divisor) {
       
   303 			quot = num / _divisor_table[i];
       
   304 			num = num % _divisor_table[i];
       
   305 		}
       
   306 		if (tot |= quot || i == 9) {
       
   307 			*buff++ = '0' + quot;
       
   308 			if (i == 0 || i == 3 || i == 6) *buff++ = ',';
       
   309 		}
       
   310 	}
       
   311 
       
   312 	*buff = '\0';
       
   313 
       
   314 	return buff;
       
   315 }
       
   316 
       
   317 // TODO
       
   318 static char *FormatNoCommaNumber(char *buff, int32 number, const char* last)
       
   319 {
       
   320 	uint32 quot,divisor;
       
   321 	int i;
       
   322 	uint32 tot;
       
   323 	uint32 num;
       
   324 
       
   325 	if (number < 0) {
       
   326 		buff = strecpy(buff, "-", last);
       
   327 		number = -number;
       
   328 	}
       
   329 
       
   330 	num = number;
       
   331 
       
   332 	tot = 0;
       
   333 	for (i = 0; i != 10; i++) {
       
   334 		divisor = _divisor_table[i];
       
   335 		quot = 0;
       
   336 		if (num >= divisor) {
       
   337 			quot = num / _divisor_table[i];
       
   338 			num = num % _divisor_table[i];
       
   339 		}
       
   340 		if (tot |= quot || i == 9) {
       
   341 			*buff++ = '0' + quot;
       
   342 		}
       
   343 	}
       
   344 
       
   345 	*buff = '\0';
       
   346 
       
   347 	return buff;
       
   348 }
       
   349 
       
   350 
       
   351 static char *FormatYmdString(char *buff, Date date, const char* last)
       
   352 {
       
   353 	YearMonthDay ymd;
       
   354 
       
   355 	ConvertDateToYMD(date, &ymd);
       
   356 
       
   357 	buff = strecpy(buff, GetStringPtr(ymd.day + STR_01AC_1ST - 1), last);
       
   358 	buff = strecpy(buff, " ", last);
       
   359 	buff = strecpy(buff, GetStringPtr(STR_0162_JAN + ymd.month), last);
       
   360 	buff = strecpy(buff, " ", last);
       
   361 
       
   362 	return FormatNoCommaNumber(buff, ymd.year, last);
       
   363 }
       
   364 
       
   365 static char *FormatMonthAndYear(char *buff, Date date, const char* last)
       
   366 {
       
   367 	YearMonthDay ymd;
       
   368 
       
   369 	ConvertDateToYMD(date, &ymd);
       
   370 
       
   371 	buff = strecpy(buff, GetStringPtr(STR_MONTH_JAN + ymd.month), last);
       
   372 	buff = strecpy(buff, " ", last);
       
   373 
       
   374 	return FormatNoCommaNumber(buff, ymd.year, last);
       
   375 }
       
   376 
       
   377 static char *FormatTinyDate(char *buff, Date date, const char* last)
       
   378 {
       
   379 	YearMonthDay ymd;
       
   380 
       
   381 	ConvertDateToYMD(date, &ymd);
       
   382 	buff += snprintf(
       
   383 		buff, last - buff + 1,
       
   384 		" %02i-%02i-%04i", ymd.day, ymd.month + 1, ymd.year
       
   385 	);
       
   386 
       
   387 	return buff;
       
   388 }
       
   389 
       
   390 static char *FormatGenericCurrency(char *buff, const CurrencySpec *spec, int64 number, bool compact, const char* last)
       
   391 {
       
   392 	const char* multiplier = "";
       
   393 	char buf[40];
       
   394 	char* p;
       
   395 	int j;
       
   396 
       
   397 	// multiply by exchange rate
       
   398 	number *= spec->rate;
       
   399 
       
   400 	// convert from negative
       
   401 	if (number < 0) {
       
   402 		buff = strecpy(buff, "-", last);
       
   403 		number = -number;
       
   404 	}
       
   405 
       
   406 	/* Add prefix part, folowing symbol_pos specification.
       
   407 	 * Here, it can can be either 0 (prefix) or 2 (both prefix anf suffix).
       
   408 	 * The only remaining value is 1 (suffix), so everything that is not 1 */
       
   409 	if (spec->symbol_pos != 1) buff = strecpy(buff, spec->prefix, last);
       
   410 
       
   411 	// for huge numbers, compact the number into k or M
       
   412 	if (compact) {
       
   413 		if (number >= 1000000000) {
       
   414 			number = (number + 500000) / 1000000;
       
   415 			multiplier = "M";
       
   416 		} else if (number >= 1000000) {
       
   417 			number = (number + 500) / 1000;
       
   418 			multiplier = "k";
       
   419 		}
       
   420 	}
       
   421 
       
   422 	// convert to ascii number and add commas
       
   423 	p = endof(buf);
       
   424 	*--p = '\0';
       
   425 	j = 4;
       
   426 	do {
       
   427 		if (--j == 0) {
       
   428 			*--p = spec->separator;
       
   429 			j = 3;
       
   430 		}
       
   431 		*--p = '0' + number % 10;
       
   432 	} while ((number /= 10) != 0);
       
   433 	buff = strecpy(buff, p, last);
       
   434 
       
   435 	buff = strecpy(buff, multiplier, last);
       
   436 
       
   437 	/* Add suffix part, folowing symbol_pos specification.
       
   438 	 * Here, it can can be either 1 (suffix) or 2 (both prefix anf suffix).
       
   439 	 * The only remaining value is 1 (prefix), so everything that is not 0 */
       
   440 	if (spec->symbol_pos != 0) buff = strecpy(buff, spec->suffix, last);
       
   441 
       
   442 	return buff;
       
   443 }
       
   444 
       
   445 static int DeterminePluralForm(int32 n)
       
   446 {
       
   447 	// The absolute value determines plurality
       
   448 	if (n < 0) n = -n;
       
   449 
       
   450 	switch (_langpack->plural_form) {
       
   451 	// Two forms, singular used for one only
       
   452 	// Used in:
       
   453 	//   Danish, Dutch, English, German, Norwegian, Swedish, Estonian, Finnish,
       
   454 	//   Greek, Hebrew, Italian, Portuguese, Spanish, Esperanto
       
   455 	case 0:
       
   456 	default:
       
   457 		return n != 1;
       
   458 
       
   459 	// Only one form
       
   460 	// Used in:
       
   461 	//   Hungarian, Japanese, Korean, Turkish
       
   462 	case 1:
       
   463 		return 0;
       
   464 
       
   465 	// Two forms, singular used for zero and one
       
   466 	// Used in:
       
   467 	//   French, Brazilian Portuguese
       
   468 	case 2:
       
   469 		return n > 1;
       
   470 
       
   471 	// Three forms, special case for zero
       
   472 	// Used in:
       
   473 	//   Latvian
       
   474 	case 3:
       
   475 		return n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2;
       
   476 
       
   477 	// Three forms, special case for one and two
       
   478 	// Used in:
       
   479 	//   Gaelige (Irish)
       
   480 	case 4:
       
   481 		return n==1 ? 0 : n==2 ? 1 : 2;
       
   482 
       
   483 	// Three forms, special case for numbers ending in 1[2-9]
       
   484 	// Used in:
       
   485 	//   Lithuanian
       
   486 	case 5:
       
   487 		return n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2;
       
   488 
       
   489 	// Three forms, special cases for numbers ending in 1 and 2, 3, 4, except those ending in 1[1-4]
       
   490 	// Used in:
       
   491 	//   Croatian, Czech, Russian, Slovak, Ukrainian
       
   492 	case 6:
       
   493 		return n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;
       
   494 
       
   495 	// Three forms, special case for one and some numbers ending in 2, 3, or 4
       
   496 	// Used in:
       
   497 	//   Polish
       
   498 	case 7:
       
   499 		return n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;
       
   500 
       
   501 	// Four forms, special case for one and all numbers ending in 02, 03, or 04
       
   502 	// Used in:
       
   503 	//   Slovenian
       
   504 	case 8:
       
   505 		return n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3;
       
   506 	}
       
   507 }
       
   508 
       
   509 static const char *ParseStringChoice(const char *b, uint form, char *dst, int *dstlen)
       
   510 {
       
   511 	//<NUM> {Length of each string} {each string}
       
   512 	uint n = (byte)*b++;
       
   513 	uint pos,i, mylen=0,mypos=0;
       
   514 
       
   515 	for (i = pos = 0; i != n; i++) {
       
   516 		uint len = (byte)*b++;
       
   517 		if (i == form) {
       
   518 			mypos = pos;
       
   519 			mylen = len;
       
   520 		}
       
   521 		pos += len;
       
   522 	}
       
   523 	*dstlen = mylen;
       
   524 	memcpy(dst, b + mypos, mylen);
       
   525 	return b + pos;
       
   526 }
       
   527 
       
   528 typedef struct Units {
       
   529 	int s_m;           ///< Multiplier for velocity
       
   530 	int s_s;           ///< Shift for velocity
       
   531 	StringID velocity; ///< String for velocity
       
   532 	int p_m;           ///< Multiplier for power
       
   533 	int p_s;           ///< Shift for power
       
   534 	StringID power;    ///< String for velocity
       
   535 	int w_m;           ///< Multiplier for weight
       
   536 	int w_s;           ///< Shift for weight
       
   537 	StringID s_weight; ///< Short string for weight
       
   538 	StringID l_weight; ///< Long string for weight
       
   539 	int v_m;           ///< Multiplier for volume
       
   540 	int v_s;           ///< Shift for volume
       
   541 	StringID s_volume; ///< Short string for volume
       
   542 	StringID l_volume; ///< Long string for volume
       
   543 	int f_m;           ///< Multiplier for force
       
   544 	int f_s;           ///< Shift for force
       
   545 	StringID force;    ///< String for force
       
   546 } Units;
       
   547 
       
   548 /* Unit conversions */
       
   549 static const Units units[] = {
       
   550 	{ // Imperial (Original, mph, hp, metric ton, litre, kN)
       
   551 		  10,  4, STR_UNITS_VELOCITY_IMPERIAL,
       
   552 		   1,  0, STR_UNITS_POWER_IMPERIAL,
       
   553 		   1,  0, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC,
       
   554 		1000,  0, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC,
       
   555 		   1,  0, STR_UNITS_FORCE_SI,
       
   556 	},
       
   557 	{ // Metric (km/h, hp, metric ton, litre, kN)
       
   558 		   1,  0, STR_UNITS_VELOCITY_METRIC,
       
   559 		   1,  0, STR_UNITS_POWER_METRIC,
       
   560 		   1,  0, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC,
       
   561 		1000,  0, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC,
       
   562 		   1,  0, STR_UNITS_FORCE_SI,
       
   563 	},
       
   564 	{ // SI (m/s, kilowatt, kilogram, cubic metres, kilonewton)
       
   565 		 284, 10, STR_UNITS_VELOCITY_SI,
       
   566 		 764, 10, STR_UNITS_POWER_SI,
       
   567 		1000,  0, STR_UNITS_WEIGHT_SHORT_SI, STR_UNITS_WEIGHT_LONG_SI,
       
   568 		   1,  0, STR_UNITS_VOLUME_SHORT_SI, STR_UNITS_VOLUME_LONG_SI,
       
   569 		   1,  0, STR_UNITS_FORCE_SI,
       
   570 	},
       
   571 };
       
   572 
       
   573 static char* FormatString(char* buff, const char* str, const int32* argv, uint casei, const char* last)
       
   574 {
       
   575 	extern const char _openttd_revision[];
       
   576 	WChar b;
       
   577 	const int32 *argv_orig = argv;
       
   578 	uint modifier = 0;
       
   579 
       
   580 	while ((b = Utf8Consume(&str)) != '\0') {
       
   581 		switch (b) {
       
   582 			case SCC_SETX: // {SETX}
       
   583 				if (buff + Utf8CharLen(SCC_SETX) + 1 < last) {
       
   584 					buff += Utf8Encode(buff, SCC_SETX);
       
   585 					*buff++ = *str++;
       
   586 				}
       
   587 				break;
       
   588 
       
   589 			case SCC_SETXY: // {SETXY}
       
   590 				if (buff + Utf8CharLen(SCC_SETXY) + 2 < last) {
       
   591 					buff += Utf8Encode(buff, SCC_SETXY);
       
   592 					*buff++ = *str++;
       
   593 					*buff++ = *str++;
       
   594 				}
       
   595 				break;
       
   596 
       
   597 			case SCC_STRING_ID: // {STRINL}
       
   598 				buff = GetStringWithArgs(buff, Utf8Consume(&str), argv, last);
       
   599 				break;
       
   600 
       
   601 			case SCC_DATE_LONG: // {DATE_LONG}
       
   602 				buff = FormatYmdString(buff, GetInt32(&argv), last);
       
   603 				break;
       
   604 
       
   605 			case SCC_DATE_SHORT: // {DATE_SHORT}
       
   606 				buff = FormatMonthAndYear(buff, GetInt32(&argv), last);
       
   607 				break;
       
   608 
       
   609 			case SCC_VELOCITY: {// {VELOCITY}
       
   610 				int32 args[1];
       
   611 				assert(_opt_ptr->units < lengthof(units));
       
   612 				args[0] = GetInt32(&argv) * units[_opt_ptr->units].s_m >> units[_opt_ptr->units].s_s;
       
   613 				buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].velocity), args, modifier >> 24, last);
       
   614 				modifier = 0;
       
   615 				break;
       
   616 			}
       
   617 
       
   618 			case SCC_CURRENCY_COMPACT: /* {CURRCOMPACT} */
       
   619 				buff = FormatGenericCurrency(buff, _currency, GetInt32(&argv), true, last);
       
   620 				break;
       
   621 
       
   622 			case SCC_REVISION: /* {REV} */
       
   623 				buff = strecpy(buff, _openttd_revision, last);
       
   624 				break;
       
   625 
       
   626 			case SCC_CARGO_SHORT: { /* {SHORTCARGO} */
       
   627 				// Short description of cargotypes. Layout:
       
   628 				// 8-bit = cargo type
       
   629 				// 16-bit = cargo count
       
   630 				StringID cargo_str = _cargo_types_base_values[_opt_ptr->landscape].units_volume[GetInt32(&argv)];
       
   631 				switch (cargo_str) {
       
   632 					case STR_TONS: {
       
   633 						int32 args[1];
       
   634 						assert(_opt_ptr->units < lengthof(units));
       
   635 						args[0] = GetInt32(&argv) * units[_opt_ptr->units].w_m >> units[_opt_ptr->units].w_s;
       
   636 						buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].l_weight), args, modifier >> 24, last);
       
   637 						modifier = 0;
       
   638 						break;
       
   639 					}
       
   640 
       
   641 					case STR_LITERS: {
       
   642 						int32 args[1];
       
   643 						assert(_opt_ptr->units < lengthof(units));
       
   644 						args[0] = GetInt32(&argv) * units[_opt_ptr->units].v_m >> units[_opt_ptr->units].v_s;
       
   645 						buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].l_volume), args, modifier >> 24, last);
       
   646 						modifier = 0;
       
   647 						break;
       
   648 					}
       
   649 
       
   650 					default:
       
   651 						buff = FormatCommaNumber(buff, GetInt32(&argv), last);
       
   652 						buff = strecpy(buff, " ", last);
       
   653 						buff = strecpy(buff, GetStringPtr(cargo_str), last);
       
   654 						break;
       
   655 				}
       
   656 			} break;
       
   657 
       
   658 			case SCC_CURRENCY_COMPACT_64: { /* {CURRCOMPACT64} */
       
   659 				// 64 bit compact currency-unit
       
   660 				buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), true, last);
       
   661 				break;
       
   662 			}
       
   663 
       
   664 			case SCC_STRING1: { /* {STRING1} */
       
   665 				// String that consumes ONE argument
       
   666 				uint str = modifier + GetInt32(&argv);
       
   667 				buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 1), last);
       
   668 				modifier = 0;
       
   669 				break;
       
   670 			}
       
   671 
       
   672 			case SCC_STRING2: { /* {STRING2} */
       
   673 				// String that consumes TWO arguments
       
   674 				uint str = modifier + GetInt32(&argv);
       
   675 				buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 2), last);
       
   676 				modifier = 0;
       
   677 				break;
       
   678 			}
       
   679 
       
   680 			case SCC_STRING3: { /* {STRING3} */
       
   681 				// String that consumes THREE arguments
       
   682 				uint str = modifier + GetInt32(&argv);
       
   683 				buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 3), last);
       
   684 				modifier = 0;
       
   685 				break;
       
   686 			}
       
   687 
       
   688 			case SCC_STRING4: { /* {STRING4} */
       
   689 				// String that consumes FOUR arguments
       
   690 				uint str = modifier + GetInt32(&argv);
       
   691 				buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 4), last);
       
   692 				modifier = 0;
       
   693 				break;
       
   694 			}
       
   695 
       
   696 			case SCC_STRING5: { /* {STRING5} */
       
   697 				// String that consumes FIVE arguments
       
   698 				uint str = modifier + GetInt32(&argv);
       
   699 				buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 5), last);
       
   700 				modifier = 0;
       
   701 				break;
       
   702 			}
       
   703 
       
   704 			case SCC_STATION_FEATURES: { /* {STATIONFEATURES} */
       
   705 				buff = StationGetSpecialString(buff, GetInt32(&argv), last);
       
   706 				break;
       
   707 			}
       
   708 
       
   709 			case SCC_INDUSTRY_NAME: { /* {INDUSTRY} */
       
   710 				const Industry* i = GetIndustry(GetInt32(&argv));
       
   711 				int32 args[2];
       
   712 
       
   713 				// industry not valid anymore?
       
   714 				if (!IsValidIndustry(i)) break;
       
   715 
       
   716 				// First print the town name and the industry type name
       
   717 				// The string STR_INDUSTRY_PATTERN controls the formatting
       
   718 				args[0] = i->town->index;
       
   719 				args[1] = GetIndustrySpec(i->type)->name;
       
   720 				buff = FormatString(buff, GetStringPtr(STR_INDUSTRY_FORMAT), args, modifier >> 24, last);
       
   721 				modifier = 0;
       
   722 				break;
       
   723 			}
       
   724 
       
   725 			case SCC_VOLUME: { // {VOLUME}
       
   726 				int32 args[1];
       
   727 				assert(_opt_ptr->units < lengthof(units));
       
   728 				args[0] = GetInt32(&argv) * units[_opt_ptr->units].v_m >> units[_opt_ptr->units].v_s;
       
   729 				buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].l_volume), args, modifier >> 24, last);
       
   730 				modifier = 0;
       
   731 				break;
       
   732 			}
       
   733 
       
   734 			case SCC_GENDER_LIST: { // {G 0 Der Die Das}
       
   735 				const char* s = GetStringPtr(argv_orig[(byte)*str++]); // contains the string that determines gender.
       
   736 				int len;
       
   737 				int gender = 0;
       
   738 				if (s != NULL && Utf8Consume(&s) == SCC_GENDER_INDEX) gender = (byte)s[0];
       
   739 				str = ParseStringChoice(str, gender, buff, &len);
       
   740 				buff += len;
       
   741 				break;
       
   742 			}
       
   743 
       
   744 			case SCC_DATE_TINY: { // {DATE_TINY}
       
   745 				buff = FormatTinyDate(buff, GetInt32(&argv), last);
       
   746 				break;
       
   747 			}
       
   748 
       
   749 			case SCC_CARGO: { // {CARGO}
       
   750 				// Layout now is:
       
   751 				//   8bit   - cargo type
       
   752 				//   16-bit - cargo count
       
   753 				CargoID cargo = GetInt32(&argv);
       
   754 				StringID cargo_str = (cargo == CT_INVALID) ? STR_8838_N_A : _cargoc.names_long[cargo];
       
   755 				buff = GetStringWithArgs(buff, cargo_str, argv++, last);
       
   756 				break;
       
   757 			}
       
   758 
       
   759 			case SCC_POWER: { // {POWER}
       
   760 				int32 args[1];
       
   761 				assert(_opt_ptr->units < lengthof(units));
       
   762 				args[0] = GetInt32(&argv) * units[_opt_ptr->units].p_m >> units[_opt_ptr->units].p_s;
       
   763 				buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].power), args, modifier >> 24, last);
       
   764 				modifier = 0;
       
   765 				break;
       
   766 			}
       
   767 
       
   768 			case SCC_VOLUME_SHORT: { // {VOLUME_S}
       
   769 				int32 args[1];
       
   770 				assert(_opt_ptr->units < lengthof(units));
       
   771 				args[0] = GetInt32(&argv) * units[_opt_ptr->units].v_m >> units[_opt_ptr->units].v_s;
       
   772 				buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].s_volume), args, modifier >> 24, last);
       
   773 				modifier = 0;
       
   774 				break;
       
   775 			}
       
   776 
       
   777 			case SCC_WEIGHT: { // {WEIGHT}
       
   778 				int32 args[1];
       
   779 				assert(_opt_ptr->units < lengthof(units));
       
   780 				args[0] = GetInt32(&argv) * units[_opt_ptr->units].w_m >> units[_opt_ptr->units].w_s;
       
   781 				buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].l_weight), args, modifier >> 24, last);
       
   782 				modifier = 0;
       
   783 				break;
       
   784 			}
       
   785 
       
   786 			case SCC_WEIGHT_SHORT: { // {WEIGHT_S}
       
   787 				int32 args[1];
       
   788 				assert(_opt_ptr->units < lengthof(units));
       
   789 				args[0] = GetInt32(&argv) * units[_opt_ptr->units].w_m >> units[_opt_ptr->units].w_s;
       
   790 				buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].s_weight), args, modifier >> 24, last);
       
   791 				modifier = 0;
       
   792 				break;
       
   793 			}
       
   794 
       
   795 			case SCC_FORCE: { // {FORCE}
       
   796 				int32 args[1];
       
   797 				assert(_opt_ptr->units < lengthof(units));
       
   798 				args[0] = GetInt32(&argv) * units[_opt_ptr->units].f_m >> units[_opt_ptr->units].f_s;
       
   799 				buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].force), args, modifier >> 24, last);
       
   800 				modifier = 0;
       
   801 				break;
       
   802 			}
       
   803 
       
   804 			case SCC_SKIP: // {SKIP}
       
   805 				argv++;
       
   806 				break;
       
   807 
       
   808 			// This sets up the gender for the string.
       
   809 			// We just ignore this one. It's used in {G 0 Der Die Das} to determine the case.
       
   810 			case SCC_GENDER_INDEX: // {GENDER 0}
       
   811 				str++;
       
   812 				break;
       
   813 
       
   814 			case SCC_STRING: {// {STRING}
       
   815 				uint str = modifier + GetInt32(&argv);
       
   816 				// WARNING. It's prohibited for the included string to consume any arguments.
       
   817 				// For included strings that consume argument, you should use STRING1, STRING2 etc.
       
   818 				// To debug stuff you can set argv to NULL and it will tell you
       
   819 				buff = GetStringWithArgs(buff, str, argv, last);
       
   820 				modifier = 0;
       
   821 				break;
       
   822 			}
       
   823 
       
   824 			case SCC_COMMA: // {COMMA}
       
   825 				buff = FormatCommaNumber(buff, GetInt32(&argv), last);
       
   826 				break;
       
   827 
       
   828 			case SCC_ARG_INDEX: // Move argument pointer
       
   829 				argv = argv_orig + (byte)*str++;
       
   830 				break;
       
   831 
       
   832 			case SCC_PLURAL_LIST: { // {P}
       
   833 				int32 v = argv_orig[(byte)*str++]; // contains the number that determines plural
       
   834 				int len;
       
   835 				str = ParseStringChoice(str, DeterminePluralForm(v), buff, &len);
       
   836 				buff += len;
       
   837 				break;
       
   838 			}
       
   839 
       
   840 			case SCC_NUM: // {NUM}
       
   841 				buff = FormatNoCommaNumber(buff, GetInt32(&argv), last);
       
   842 				break;
       
   843 
       
   844 			case SCC_CURRENCY: // {CURRENCY}
       
   845 				buff = FormatGenericCurrency(buff, _currency, GetInt32(&argv), false, last);
       
   846 				break;
       
   847 
       
   848 			case SCC_WAYPOINT_NAME: { // {WAYPOINT}
       
   849 				int32 temp[2];
       
   850 				Waypoint *wp = GetWaypoint(GetInt32(&argv));
       
   851 				StringID str;
       
   852 				if (wp->string != STR_NULL) {
       
   853 					str = wp->string;
       
   854 				} else {
       
   855 					temp[0] = wp->town_index;
       
   856 					temp[1] = wp->town_cn + 1;
       
   857 					str = wp->town_cn == 0 ? STR_WAYPOINTNAME_CITY : STR_WAYPOINTNAME_CITY_SERIAL;
       
   858 				}
       
   859 				buff = GetStringWithArgs(buff, str, temp, last);
       
   860 				break;
       
   861 			}
       
   862 
       
   863 			case SCC_STATION_NAME: { // {STATION}
       
   864 				const Station* st = GetStation(GetInt32(&argv));
       
   865 
       
   866 				if (!IsValidStation(st)) { // station doesn't exist anymore
       
   867 					buff = GetStringWithArgs(buff, STR_UNKNOWN_DESTINATION, NULL, last);
       
   868 				} else {
       
   869 					int32 temp[2];
       
   870 					temp[0] = st->town->townnametype;
       
   871 					temp[1] = st->town->townnameparts;
       
   872 					buff = GetStringWithArgs(buff, st->string_id, temp, last);
       
   873 				}
       
   874 				break;
       
   875 			}
       
   876 
       
   877 			case SCC_TOWN_NAME: { // {TOWN}
       
   878 				const Town* t = GetTown(GetInt32(&argv));
       
   879 				int32 temp[1];
       
   880 
       
   881 				assert(IsValidTown(t));
       
   882 
       
   883 				temp[0] = t->townnameparts;
       
   884 				buff = GetStringWithArgs(buff, t->townnametype, temp, last);
       
   885 				break;
       
   886 			}
       
   887 
       
   888 			case SCC_CURRENCY_64: { // {CURRENCY64}
       
   889 				buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), false, last);
       
   890 				break;
       
   891 			}
       
   892 
       
   893 			case SCC_SETCASE: { // {SETCASE}
       
   894 				// This is a pseudo command, it's outputted when someone does {STRING.ack}
       
   895 				// The modifier is added to all subsequent GetStringWithArgs that accept the modifier.
       
   896 				modifier = (byte)*str++ << 24;
       
   897 				break;
       
   898 			}
       
   899 
       
   900 			case SCC_SWITCH_CASE: { // {Used to implement case switching}
       
   901 				// <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT>
       
   902 				// Each LEN is printed using 2 bytes in big endian order.
       
   903 				uint num = (byte)*str++;
       
   904 				while (num) {
       
   905 					if ((byte)str[0] == casei) {
       
   906 						// Found the case, adjust str pointer and continue
       
   907 						str += 3;
       
   908 						break;
       
   909 					}
       
   910 					// Otherwise skip to the next case
       
   911 					str += 3 + (str[1] << 8) + str[2];
       
   912 					num--;
       
   913 				}
       
   914 				break;
       
   915 			}
       
   916 
       
   917 			default:
       
   918 				if (buff + Utf8CharLen(b) < last) buff += Utf8Encode(buff, b);
       
   919 				break;
       
   920 		}
       
   921 	}
       
   922 	*buff = '\0';
       
   923 	return buff;
       
   924 }
       
   925 
       
   926 
       
   927 static char *StationGetSpecialString(char *buff, int x, const char* last)
       
   928 {
       
   929 	if ((x & 0x01) && (buff + Utf8CharLen(SCC_TRAIN) < last)) buff += Utf8Encode(buff, SCC_TRAIN);
       
   930 	if ((x & 0x02) && (buff + Utf8CharLen(SCC_LORRY) < last)) buff += Utf8Encode(buff, SCC_LORRY);
       
   931 	if ((x & 0x04) && (buff + Utf8CharLen(SCC_BUS)   < last)) buff += Utf8Encode(buff, SCC_BUS);
       
   932 	if ((x & 0x08) && (buff + Utf8CharLen(SCC_PLANE) < last)) buff += Utf8Encode(buff, SCC_PLANE);
       
   933 	if ((x & 0x10) && (buff + Utf8CharLen(SCC_SHIP)  < last)) buff += Utf8Encode(buff, SCC_SHIP);
       
   934 	*buff = '\0';
       
   935 	return buff;
       
   936 }
       
   937 
       
   938 static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char* last)
       
   939 {
       
   940 	char name[512];
       
   941 
       
   942 	_town_name_generators[ind](name, seed, lastof(name));
       
   943 	return strecpy(buff, name, last);
       
   944 }
       
   945 
       
   946 static const char* const _silly_company_names[] = {
       
   947 	"Bloggs Brothers",
       
   948 	"Tiny Transport Ltd.",
       
   949 	"Express Travel",
       
   950 	"Comfy-Coach & Co.",
       
   951 	"Crush & Bump Ltd.",
       
   952 	"Broken & Late Ltd.",
       
   953 	"Sam Speedy & Son",
       
   954 	"Supersonic Travel",
       
   955 	"Mike's Motors",
       
   956 	"Lightning International",
       
   957 	"Pannik & Loozit Ltd.",
       
   958 	"Inter-City Transport",
       
   959 	"Getout & Pushit Ltd."
       
   960 };
       
   961 
       
   962 static const char* const _surname_list[] = {
       
   963 	"Adams",
       
   964 	"Allan",
       
   965 	"Baker",
       
   966 	"Bigwig",
       
   967 	"Black",
       
   968 	"Bloggs",
       
   969 	"Brown",
       
   970 	"Campbell",
       
   971 	"Gordon",
       
   972 	"Hamilton",
       
   973 	"Hawthorn",
       
   974 	"Higgins",
       
   975 	"Green",
       
   976 	"Gribble",
       
   977 	"Jones",
       
   978 	"McAlpine",
       
   979 	"MacDonald",
       
   980 	"McIntosh",
       
   981 	"Muir",
       
   982 	"Murphy",
       
   983 	"Nelson",
       
   984 	"O'Donnell",
       
   985 	"Parker",
       
   986 	"Phillips",
       
   987 	"Pilkington",
       
   988 	"Quigley",
       
   989 	"Sharkey",
       
   990 	"Thomson",
       
   991 	"Watkins"
       
   992 };
       
   993 
       
   994 static const char* const _silly_surname_list[] = {
       
   995 	"Grumpy",
       
   996 	"Dozy",
       
   997 	"Speedy",
       
   998 	"Nosey",
       
   999 	"Dribble",
       
  1000 	"Mushroom",
       
  1001 	"Cabbage",
       
  1002 	"Sniffle",
       
  1003 	"Fishy",
       
  1004 	"Swindle",
       
  1005 	"Sneaky",
       
  1006 	"Nutkins"
       
  1007 };
       
  1008 
       
  1009 static const char _initial_name_letters[] = {
       
  1010 	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
       
  1011 	'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'W',
       
  1012 };
       
  1013 
       
  1014 static char *GenAndCoName(char *buff, uint32 arg, const char* last)
       
  1015 {
       
  1016 	const char* const* base;
       
  1017 	uint num;
       
  1018 
       
  1019 	if (_opt_ptr->landscape == LT_CANDY) {
       
  1020 		base = _silly_surname_list;
       
  1021 		num  = lengthof(_silly_surname_list);
       
  1022 	} else {
       
  1023 		base = _surname_list;
       
  1024 		num  = lengthof(_surname_list);
       
  1025 	}
       
  1026 
       
  1027 	buff = strecpy(buff, base[num * GB(arg, 16, 8) >> 8], last);
       
  1028 	buff = strecpy(buff, " & Co.", last);
       
  1029 
       
  1030 	return buff;
       
  1031 }
       
  1032 
       
  1033 static char *GenPresidentName(char *buff, uint32 x, const char* last)
       
  1034 {
       
  1035 	char initial[] = "?. ";
       
  1036 	const char* const* base;
       
  1037 	uint num;
       
  1038 	uint i;
       
  1039 
       
  1040 	initial[0] = _initial_name_letters[sizeof(_initial_name_letters) * GB(x, 0, 8) >> 8];
       
  1041 	buff = strecpy(buff, initial, last);
       
  1042 
       
  1043 	i = (sizeof(_initial_name_letters) + 35) * GB(x, 8, 8) >> 8;
       
  1044 	if (i < sizeof(_initial_name_letters)) {
       
  1045 		initial[0] = _initial_name_letters[i];
       
  1046 		buff = strecpy(buff, initial, last);
       
  1047 	}
       
  1048 
       
  1049 	if (_opt_ptr->landscape == LT_CANDY) {
       
  1050 		base = _silly_surname_list;
       
  1051 		num  = lengthof(_silly_surname_list);
       
  1052 	} else {
       
  1053 		base = _surname_list;
       
  1054 		num  = lengthof(_surname_list);
       
  1055 	}
       
  1056 
       
  1057 	buff = strecpy(buff, base[num * GB(x, 16, 8) >> 8], last);
       
  1058 
       
  1059 	return buff;
       
  1060 }
       
  1061 
       
  1062 static char *GetSpecialPlayerNameString(char *buff, int ind, const int32 *argv, const char* last)
       
  1063 {
       
  1064 	switch (ind) {
       
  1065 		case 1: // not used
       
  1066 			return strecpy(buff, _silly_company_names[GetInt32(&argv) & 0xFFFF], last);
       
  1067 
       
  1068 		case 2: // used for Foobar & Co company names
       
  1069 			return GenAndCoName(buff, GetInt32(&argv), last);
       
  1070 
       
  1071 		case 3: // President name
       
  1072 			return GenPresidentName(buff, GetInt32(&argv), last);
       
  1073 
       
  1074 		case 4: // song names
       
  1075 			return strecpy(buff, origin_songs_specs[GetInt32(&argv) - 1].song_name, last);
       
  1076 	}
       
  1077 
       
  1078 	// town name?
       
  1079 	if (IS_INT_INSIDE(ind - 6, 0, SPECSTR_TOWNNAME_LAST-SPECSTR_TOWNNAME_START + 1)) {
       
  1080 		buff = GetSpecialTownNameString(buff, ind - 6, GetInt32(&argv), last);
       
  1081 		return strecpy(buff, " Transport", last);
       
  1082 	}
       
  1083 
       
  1084 	// language name?
       
  1085 	if (IS_INT_INSIDE(ind, (SPECSTR_LANGUAGE_START - 0x70E4), (SPECSTR_LANGUAGE_END - 0x70E4) + 1)) {
       
  1086 		int i = ind - (SPECSTR_LANGUAGE_START - 0x70E4);
       
  1087 		return strecpy(buff,
       
  1088 			i == _dynlang.curr ? _langpack->own_name : _dynlang.ent[i].name, last);
       
  1089 	}
       
  1090 
       
  1091 	// resolution size?
       
  1092 	if (IS_INT_INSIDE(ind, (SPECSTR_RESOLUTION_START - 0x70E4), (SPECSTR_RESOLUTION_END - 0x70E4) + 1)) {
       
  1093 		int i = ind - (SPECSTR_RESOLUTION_START - 0x70E4);
       
  1094 		buff += snprintf(
       
  1095 			buff, last - buff + 1, "%dx%d", _resolutions[i][0], _resolutions[i][1]
       
  1096 		);
       
  1097 		return buff;
       
  1098 	}
       
  1099 
       
  1100 	// screenshot format name?
       
  1101 	if (IS_INT_INSIDE(ind, (SPECSTR_SCREENSHOT_START - 0x70E4), (SPECSTR_SCREENSHOT_END - 0x70E4) + 1)) {
       
  1102 		int i = ind - (SPECSTR_SCREENSHOT_START - 0x70E4);
       
  1103 		return strecpy(buff, GetScreenshotFormatDesc(i), last);
       
  1104 	}
       
  1105 
       
  1106 	assert(0);
       
  1107 	return NULL;
       
  1108 }
       
  1109 
       
  1110 // remap a string ID from the old format to the new format
       
  1111 StringID RemapOldStringID(StringID s)
       
  1112 {
       
  1113 	switch (s) {
       
  1114 		case 0x0006: return STR_SV_EMPTY;
       
  1115 		case 0x7000: return STR_SV_UNNAMED;
       
  1116 		case 0x70E4: return SPECSTR_PLAYERNAME_ENGLISH;
       
  1117 		case 0x70E9: return SPECSTR_PLAYERNAME_ENGLISH;
       
  1118 		case 0x8864: return STR_SV_TRAIN_NAME;
       
  1119 		case 0x902B: return STR_SV_ROADVEH_NAME;
       
  1120 		case 0x9830: return STR_SV_SHIP_NAME;
       
  1121 		case 0xA02F: return STR_SV_AIRCRAFT_NAME;
       
  1122 
       
  1123 		default:
       
  1124 			if (IS_INT_INSIDE(s, 0x300F, 0x3030)) {
       
  1125 				return s - 0x300F + STR_SV_STNAME;
       
  1126 			} else {
       
  1127 				return s;
       
  1128 			}
       
  1129 	}
       
  1130 }
       
  1131 
       
  1132 bool ReadLanguagePack(int lang_index)
       
  1133 {
       
  1134 	int tot_count, i;
       
  1135 	LanguagePack *lang_pack;
       
  1136 	size_t len;
       
  1137 	char **langpack_offs;
       
  1138 	char *s;
       
  1139 
       
  1140 	{
       
  1141 		char *lang = str_fmt("%s%s", _paths.lang_dir, _dynlang.ent[lang_index].file);
       
  1142 		lang_pack = ReadFileToMem(lang, &len, 200000);
       
  1143 		free(lang);
       
  1144 	}
       
  1145 	if (lang_pack == NULL) return false;
       
  1146 	if (len < sizeof(LanguagePack) ||
       
  1147 			lang_pack->ident != TO_LE32(LANGUAGE_PACK_IDENT) ||
       
  1148 			lang_pack->version != TO_LE32(LANGUAGE_PACK_VERSION)) {
       
  1149 		free(lang_pack);
       
  1150 		return false;
       
  1151 	}
       
  1152 
       
  1153 #if defined(TTD_BIG_ENDIAN)
       
  1154 	for (i = 0; i != 32; i++) {
       
  1155 		lang_pack->offsets[i] = ReadLE16Aligned(&lang_pack->offsets[i]);
       
  1156 	}
       
  1157 #endif
       
  1158 
       
  1159 	tot_count = 0;
       
  1160 	for (i = 0; i != 32; i++) {
       
  1161 		uint num = lang_pack->offsets[i];
       
  1162 		_langtab_start[i] = tot_count;
       
  1163 		_langtab_num[i] = num;
       
  1164 		tot_count += num;
       
  1165 	}
       
  1166 
       
  1167 	// Allocate offsets
       
  1168 	langpack_offs = malloc(tot_count * sizeof(*langpack_offs));
       
  1169 
       
  1170 	// Fill offsets
       
  1171 	s = lang_pack->data;
       
  1172 	for (i = 0; i != tot_count; i++) {
       
  1173 		len = (byte)*s;
       
  1174 		*s++ = '\0'; // zero terminate the string before.
       
  1175 		if (len >= 0xC0) len = ((len & 0x3F) << 8) + (byte)*s++;
       
  1176 		langpack_offs[i] = s;
       
  1177 		s += len;
       
  1178 	}
       
  1179 
       
  1180 	free(_langpack);
       
  1181 	_langpack = lang_pack;
       
  1182 
       
  1183 	free(_langpack_offs);
       
  1184 	_langpack_offs = langpack_offs;
       
  1185 
       
  1186 	ttd_strlcpy(_dynlang.curr_file, _dynlang.ent[lang_index].file, sizeof(_dynlang.curr_file));
       
  1187 
       
  1188 	_dynlang.curr = lang_index;
       
  1189 	SetCurrentGrfLangID(_langpack->isocode);
       
  1190 	return true;
       
  1191 }
       
  1192 
       
  1193 /** Determine the current charset based on the environment
       
  1194  * First check some default values, after this one we passed ourselves
       
  1195  * and if none exist return the value for $LANG
       
  1196  * @param environment variable to check conditionally if default ones are not
       
  1197  *        set. Pass NULL if you don't want additional checks.
       
  1198  * @return return string containing current charset, or NULL if not-determinable */
       
  1199 const char *GetCurrentLocale(const char *param)
       
  1200 {
       
  1201 	const char *env;
       
  1202 
       
  1203 	env = getenv("LANGUAGE");
       
  1204 	if (env != NULL) return env;
       
  1205 
       
  1206 	env = getenv("LC_ALL");
       
  1207 	if (env != NULL) return env;
       
  1208 
       
  1209 	if (param != NULL) {
       
  1210 		env = getenv(param);
       
  1211 		if (env != NULL) return env;
       
  1212 	}
       
  1213 
       
  1214 	return getenv("LANG");
       
  1215 }
       
  1216 
       
  1217 static int CDECL LanguageCompareFunc(const void *a, const void *b)
       
  1218 {
       
  1219 	return strcmp(*(const char* const *)a, *(const char* const *)b);
       
  1220 }
       
  1221 
       
  1222 static int GetLanguageList(char **languages, int max)
       
  1223 {
       
  1224 	DIR *dir;
       
  1225 	struct dirent *dirent;
       
  1226 	int num = 0;
       
  1227 
       
  1228 	dir = opendir(_paths.lang_dir);
       
  1229 	if (dir != NULL) {
       
  1230 		while ((dirent = readdir(dir)) != NULL) {
       
  1231 			const char *d_name = FS2OTTD(dirent->d_name);
       
  1232 			char *t = strrchr(d_name, '.');
       
  1233 
       
  1234 			if (t != NULL && strcmp(t, ".lng") == 0) {
       
  1235 				languages[num++] = strdup(d_name);
       
  1236 				if (num == max) break;
       
  1237 			}
       
  1238 		}
       
  1239 		closedir(dir);
       
  1240 	}
       
  1241 
       
  1242 	qsort(languages, num, sizeof(char*), LanguageCompareFunc);
       
  1243 	return num;
       
  1244 }
       
  1245 
       
  1246 // make a list of the available language packs. put the data in _dynlang struct.
       
  1247 void InitializeLanguagePacks(void)
       
  1248 {
       
  1249 	DynamicLanguages *dl = &_dynlang;
       
  1250 	int i;
       
  1251 	int n;
       
  1252 	int m;
       
  1253 	int def;
       
  1254 	int def2;
       
  1255 	int fallback;
       
  1256 	LanguagePack hdr;
       
  1257 	FILE *in;
       
  1258 	char *files[MAX_LANG];
       
  1259 	const char* lang;
       
  1260 
       
  1261 	lang = GetCurrentLocale("LC_MESSAGES");
       
  1262 	if (lang == NULL) lang = "en_GB";
       
  1263 
       
  1264 	n = GetLanguageList(files, lengthof(files));
       
  1265 
       
  1266 	def = -1;
       
  1267 	def2 = -1;
       
  1268 	fallback = 0;
       
  1269 
       
  1270 	// go through the language files and make sure that they are valid.
       
  1271 	for (i = m = 0; i != n; i++) {
       
  1272 		size_t j;
       
  1273 
       
  1274 		char *s = str_fmt("%s%s", _paths.lang_dir, files[i]);
       
  1275 		in = fopen(s, "rb");
       
  1276 		free(s);
       
  1277 		if (in == NULL ||
       
  1278 				(j = fread(&hdr, sizeof(hdr), 1, in), fclose(in), j) != 1 ||
       
  1279 				hdr.ident != TO_LE32(LANGUAGE_PACK_IDENT) ||
       
  1280 				hdr.version != TO_LE32(LANGUAGE_PACK_VERSION)) {
       
  1281 			free(files[i]);
       
  1282 			continue;
       
  1283 		}
       
  1284 
       
  1285 		dl->ent[m].file = files[i];
       
  1286 		dl->ent[m].name = strdup(hdr.name);
       
  1287 
       
  1288 		if (strcmp(hdr.isocode, "en_GB")  == 0) fallback = m;
       
  1289 		if (strncmp(hdr.isocode, lang, 2) == 0) def2 = m;
       
  1290 		if (strncmp(hdr.isocode, lang, 5) == 0) def = m;
       
  1291 
       
  1292 		m++;
       
  1293 	}
       
  1294 	if (def == -1) def = (def2 != -1 ? def2 : fallback);
       
  1295 
       
  1296 	if (m == 0)
       
  1297 		error(n == 0 ? "No available language packs" : "Invalid version of language packs");
       
  1298 
       
  1299 	dl->num = m;
       
  1300 	for (i = 0; i != dl->num; i++) dl->dropdown[i] = SPECSTR_LANGUAGE_START + i;
       
  1301 	dl->dropdown[i] = INVALID_STRING_ID;
       
  1302 
       
  1303 	for (i = 0; i != dl->num; i++)
       
  1304 		if (strcmp(dl->ent[i].file, dl->curr_file) == 0) {
       
  1305 			def = i;
       
  1306 			break;
       
  1307 		}
       
  1308 
       
  1309 	if (!ReadLanguagePack(def))
       
  1310 		error("can't read language pack '%s'", dl->ent[def].file);
       
  1311 }