src/strings.cpp
branchgamebalance
changeset 9908 0fa543611bbe
parent 9906 6f41b8713b65
child 9910 0b2aebc8283e
equal deleted inserted replaced
9907:3b068c3a1c74 9908:0fa543611bbe
     1 /* $Id$ */
     1 /* $Id$ */
       
     2 
       
     3 /** @file strings.cpp */
     2 
     4 
     3 #include "stdafx.h"
     5 #include "stdafx.h"
     4 #include "openttd.h"
     6 #include "openttd.h"
     5 #include "currency.h"
     7 #include "currency.h"
     6 #include "functions.h"
     8 #include "functions.h"
    35 static char *GetSpecialPlayerNameString(char *buff, int ind, const int32 *argv, const char* last);
    37 static char *GetSpecialPlayerNameString(char *buff, int ind, const int32 *argv, const char* last);
    36 
    38 
    37 static char *FormatString(char *buff, const char *str, const int32 *argv, uint casei, const char* last);
    39 static char *FormatString(char *buff, const char *str, const int32 *argv, uint casei, const char* last);
    38 
    40 
    39 struct LanguagePack {
    41 struct LanguagePack {
    40 	uint32 ident;
    42 	uint32 ident;       // 32-bits identifier
    41 	uint32 version;     // 32-bits of auto generated version info which is basically a hash of strings.h
    43 	uint32 version;     // 32-bits of auto generated version info which is basically a hash of strings.h
    42 	char name[32];      // the international name of this language
    44 	char name[32];      // the international name of this language
    43 	char own_name[32];  // the localized name of this language
    45 	char own_name[32];  // the localized name of this language
    44 	char isocode[16];   // the ISO code for the language (not country code)
    46 	char isocode[16];   // the ISO code for the language (not country code)
    45 	uint16 offsets[32]; // the offsets
    47 	uint16 offsets[32]; // the offsets
    46 	byte plural_form;   // how to compute plural forms
    48 	byte plural_form;   // how to compute plural forms
    47 	byte pad[3];        // pad header to be a multiple of 4
    49 	byte pad[3];        // pad header to be a multiple of 4
    48 	char data[VARARRAY_SIZE];
    50 	char data[VARARRAY_SIZE]; // list of strings
    49 };
    51 };
    50 
    52 
    51 static char **_langpack_offs;
    53 static char **_langpack_offs;
    52 static LanguagePack *_langpack;
    54 static LanguagePack *_langpack;
    53 static uint _langtab_num[32]; // Offset into langpack offs
    55 static uint _langtab_num[32];   // Offset into langpack offs
    54 static uint _langtab_start[32]; // Offset into langpack offs
    56 static uint _langtab_start[32]; // Offset into langpack offs
    55 
    57 
    56 
    58 
    57 // Read an int64 from the argv array.
    59 /** Read an int64 from the argv array. */
    58 static inline int64 GetInt64(const int32 **argv)
    60 static inline int64 GetInt64(const int32 **argv)
    59 {
    61 {
    60 	int64 result;
    62 	int64 result;
    61 
    63 
    62 	assert(argv);
    64 	assert(argv);
    63 	result = (uint32)(*argv)[0] + ((uint64)(uint32)(*argv)[1] << 32);
    65 	result = (uint32)(*argv)[0] + ((uint64)(uint32)(*argv)[1] << 32);
    64 	(*argv)+=2;
    66 	(*argv)+=2;
    65 	return result;
    67 	return result;
    66 }
    68 }
    67 
    69 
    68 // Read an int32 from the argv array.
    70 /** Read an int32 from the argv array. */
    69 static inline int32 GetInt32(const int32 **argv)
    71 static inline int32 GetInt32(const int32 **argv)
    70 {
    72 {
    71 	assert(argv);
    73 	assert(argv);
    72 	return *(*argv)++;
    74 	return *(*argv)++;
    73 }
    75 }
    74 
    76 
    75 // Read an array from the argv array.
    77 /** Read an array from the argv array. */
    76 static inline const int32 *GetArgvPtr(const int32 **argv, int n)
    78 static inline const int32 *GetArgvPtr(const int32 **argv, int n)
    77 {
    79 {
    78 	const int32 *result;
    80 	const int32 *result;
    79 	assert(*argv);
    81 	assert(*argv);
    80 	result = *argv;
    82 	result = *argv;
    83 }
    85 }
    84 
    86 
    85 
    87 
    86 #define NUM_BOUND_STRINGS 8
    88 #define NUM_BOUND_STRINGS 8
    87 
    89 
    88 // Array to hold the bound strings.
    90 /* Array to hold the bound strings. */
    89 static const char *_bound_strings[NUM_BOUND_STRINGS];
    91 static const char *_bound_strings[NUM_BOUND_STRINGS];
    90 
    92 
    91 // This index is used to implement a "round-robin" allocating of
    93 /* This index is used to implement a "round-robin" allocating of
    92 // slots for BindCString. NUM_BOUND_STRINGS slots are reserved.
    94  * slots for BindCString. NUM_BOUND_STRINGS slots are reserved.
    93 // Which means that after NUM_BOUND_STRINGS calls to BindCString,
    95  * Which means that after NUM_BOUND_STRINGS calls to BindCString,
    94 // the indices will be reused.
    96  * the indices will be reused. */
    95 static int _bind_index;
    97 static int _bind_index;
    96 
    98 
    97 static const char *GetStringPtr(StringID string)
    99 static const char *GetStringPtr(StringID string)
    98 {
   100 {
    99 	return _langpack_offs[_langtab_start[string >> 11] + (string & 0x7FF)];
   101 	return _langpack_offs[_langtab_start[string >> 11] + (string & 0x7FF)];
   100 }
   102 }
   101 
   103 
   102 // The highest 8 bits of string contain the "case index".
   104 /** The highest 8 bits of string contain the "case index".
   103 // These 8 bits will only be set when FormatString wants to print
   105  * These 8 bits will only be set when FormatString wants to print
   104 // the string in a different case. No one else except FormatString
   106  * the string in a different case. No one else except FormatString
   105 // should set those bits, therefore string CANNOT be StringID, but uint32.
   107  * should set those bits, therefore string CANNOT be StringID, but uint32.
       
   108  * @param buffr
       
   109  * @param string
       
   110  * @param argv
       
   111  * @param last
       
   112  * @return a formatted string of char
       
   113  */
   106 static char *GetStringWithArgs(char *buffr, uint string, const int32 *argv, const char* last)
   114 static char *GetStringWithArgs(char *buffr, uint string, const int32 *argv, const char* last)
   107 {
   115 {
   108 	uint index = GB(string,  0, 11);
   116 	uint index = GB(string,  0, 11);
   109 	uint tab   = GB(string, 11,  5);
   117 	uint tab   = GB(string, 11,  5);
   110 	char buff[512];
   118 	char buff[512];
   120 		case 14:
   128 		case 14:
   121 			if (index >= 0xE4)
   129 			if (index >= 0xE4)
   122 				return GetSpecialPlayerNameString(buffr, index - 0xE4, argv, last);
   130 				return GetSpecialPlayerNameString(buffr, index - 0xE4, argv, last);
   123 			break;
   131 			break;
   124 
   132 
   125 		// User defined name
       
   126 		case 15:
   133 		case 15:
       
   134 			/* User defined name */
   127 			return GetName(buffr, index, last);
   135 			return GetName(buffr, index, last);
   128 
   136 
   129 		case 26:
   137 		case 26:
   130 			/* Include string within newgrf text (format code 81) */
   138 			/* Include string within newgrf text (format code 81) */
   131 			if (HASBIT(index, 10)) {
   139 			if (HASBIT(index, 10)) {
   145 		case 30:
   153 		case 30:
   146 			GetGRFString(buff, index + 0x1000, lastof(buff));
   154 			GetGRFString(buff, index + 0x1000, lastof(buff));
   147 			return FormatString(buffr, buff, argv, 0, last);
   155 			return FormatString(buffr, buff, argv, 0, last);
   148 
   156 
   149 		case 31:
   157 		case 31:
   150 			// dynamic strings. These are NOT to be passed through the formatter,
   158 			/* dynamic strings. These are NOT to be passed through the formatter,
   151 			// but passed through verbatim.
   159 			 * but passed through verbatim. */
   152 			if (index < (STR_SPEC_USERSTRING & 0x7FF)) {
   160 			if (index < (STR_SPEC_USERSTRING & 0x7FF)) {
   153 				return strecpy(buffr, _bound_strings[index], last);
   161 				return strecpy(buffr, _bound_strings[index], last);
   154 			}
   162 			}
   155 
   163 
   156 			return FormatString(buffr, _userstring, NULL, 0, last);
   164 			return FormatString(buffr, _userstring, NULL, 0, last);
   182 
   190 
   183 /**
   191 /**
   184  * This function takes a C-string and allocates a temporary string ID.
   192  * This function takes a C-string and allocates a temporary string ID.
   185  * The StringID of the bound string is valid until BindCString is called
   193  * The StringID of the bound string is valid until BindCString is called
   186  * another NUM_BOUND_STRINGS times. So be careful when using it.
   194  * another NUM_BOUND_STRINGS times. So be careful when using it.
   187  *
   195  * @param str temp string to add
       
   196  * @return the id of that temp string
   188  * @note formatting a DATE_TINY calls BindCString twice, thus reduces the
   197  * @note formatting a DATE_TINY calls BindCString twice, thus reduces the
   189  *       amount of 'user' bound strings by 2.
   198  *       amount of 'user' bound strings by 2.
   190  * @todo rewrite the BindCString system to make the limit flexible and
   199  * @todo rewrite the BindCString system to make the limit flexible and
   191  *       non-round-robin. For example by using smart pointers that free
   200  *       non-round-robin. For example by using smart pointers that free
   192  *       the allocated StringID when they go out-of-scope/are freed.
   201  *       the allocated StringID when they go out-of-scope/are freed.
   196 	int idx = (++_bind_index) & (NUM_BOUND_STRINGS - 1);
   205 	int idx = (++_bind_index) & (NUM_BOUND_STRINGS - 1);
   197 	_bound_strings[idx] = str;
   206 	_bound_strings[idx] = str;
   198 	return idx + STR_SPEC_DYNSTRING;
   207 	return idx + STR_SPEC_DYNSTRING;
   199 }
   208 }
   200 
   209 
   201 // This function is used to "bind" a C string to a OpenTTD dparam slot.
   210 /** This function is used to "bind" a C string to a OpenTTD dparam slot.
       
   211  * @param n slot of the string
       
   212  * @param str string to bind
       
   213  */
   202 void SetDParamStr(uint n, const char *str)
   214 void SetDParamStr(uint n, const char *str)
   203 {
   215 {
   204 	SetDParam(n, BindCString(str));
   216 	SetDParam(n, BindCString(str));
   205 }
   217 }
   206 
   218 
   329 	const char* multiplier = "";
   341 	const char* multiplier = "";
   330 	char buf[40];
   342 	char buf[40];
   331 	char* p;
   343 	char* p;
   332 	int j;
   344 	int j;
   333 
   345 
   334 	// multiply by exchange rate
   346 	/* multiply by exchange rate */
   335 	number *= spec->rate;
   347 	number *= spec->rate;
   336 
   348 
   337 	// convert from negative
   349 	/* convert from negative */
   338 	if (number < 0) {
   350 	if (number < 0) {
   339 		buff = strecpy(buff, "-", last);
   351 		buff = strecpy(buff, "-", last);
   340 		number = -number;
   352 		number = -number;
   341 	}
   353 	}
   342 
   354 
   343 	/* Add prefix part, folowing symbol_pos specification.
   355 	/* Add prefix part, folowing symbol_pos specification.
   344 	 * Here, it can can be either 0 (prefix) or 2 (both prefix anf suffix).
   356 	 * Here, it can can be either 0 (prefix) or 2 (both prefix anf suffix).
   345 	 * The only remaining value is 1 (suffix), so everything that is not 1 */
   357 	 * The only remaining value is 1 (suffix), so everything that is not 1 */
   346 	if (spec->symbol_pos != 1) buff = strecpy(buff, spec->prefix, last);
   358 	if (spec->symbol_pos != 1) buff = strecpy(buff, spec->prefix, last);
   347 
   359 
   348 	// for huge numbers, compact the number into k or M
   360 	/* for huge numbers, compact the number into k or M */
   349 	if (compact) {
   361 	if (compact) {
   350 		if (number >= 1000000000) {
   362 		if (number >= 1000000000) {
   351 			number = (number + 500000) / 1000000;
   363 			number = (number + 500000) / 1000000;
   352 			multiplier = "M";
   364 			multiplier = "M";
   353 		} else if (number >= 1000000) {
   365 		} else if (number >= 1000000) {
   354 			number = (number + 500) / 1000;
   366 			number = (number + 500) / 1000;
   355 			multiplier = "k";
   367 			multiplier = "k";
   356 		}
   368 		}
   357 	}
   369 	}
   358 
   370 
   359 	// convert to ascii number and add commas
   371 	/* convert to ascii number and add commas */
   360 	p = endof(buf);
   372 	p = endof(buf);
   361 	*--p = '\0';
   373 	*--p = '\0';
   362 	j = 4;
   374 	j = 4;
   363 	do {
   375 	do {
   364 		if (--j == 0) {
   376 		if (--j == 0) {
   379 	return buff;
   391 	return buff;
   380 }
   392 }
   381 
   393 
   382 static int DeterminePluralForm(int32 n)
   394 static int DeterminePluralForm(int32 n)
   383 {
   395 {
   384 	// The absolute value determines plurality
   396 	/* The absolute value determines plurality */
   385 	if (n < 0) n = -n;
   397 	if (n < 0) n = -n;
   386 
   398 
   387 	switch (_langpack->plural_form) {
   399 	switch (_langpack->plural_form) {
   388 	// Two forms, singular used for one only
   400 	/* Two forms, singular used for one only
   389 	// Used in:
   401 	 * Used in:
   390 	//   Danish, Dutch, English, German, Norwegian, Swedish, Estonian, Finnish,
   402 	 *   Danish, Dutch, English, German, Norwegian, Swedish, Estonian, Finnish,
   391 	//   Greek, Hebrew, Italian, Portuguese, Spanish, Esperanto
   403 	 *   Greek, Hebrew, Italian, Portuguese, Spanish, Esperanto */
   392 	case 0:
   404 	case 0:
   393 	default:
   405 	default:
   394 		return n != 1;
   406 		return n != 1;
   395 
   407 
   396 	// Only one form
   408 	/* Only one form
   397 	// Used in:
   409 	 * Used in:
   398 	//   Hungarian, Japanese, Korean, Turkish
   410 	 *   Hungarian, Japanese, Korean, Turkish */
   399 	case 1:
   411 	case 1:
   400 		return 0;
   412 		return 0;
   401 
   413 
   402 	// Two forms, singular used for zero and one
   414 	/* Two forms, singular used for zero and one
   403 	// Used in:
   415 	 * Used in:
   404 	//   French, Brazilian Portuguese
   416 	 *   French, Brazilian Portuguese */
   405 	case 2:
   417 	case 2:
   406 		return n > 1;
   418 		return n > 1;
   407 
   419 
   408 	// Three forms, special case for zero
   420 	/* Three forms, special case for zero
   409 	// Used in:
   421 	 * Used in:
   410 	//   Latvian
   422 	 *   Latvian */
   411 	case 3:
   423 	case 3:
   412 		return n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2;
   424 		return n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2;
   413 
   425 
   414 	// Three forms, special case for one and two
   426 	/* Three forms, special case for one and two
   415 	// Used in:
   427 	 * Used in:
   416 	//   Gaelige (Irish)
   428 	 *   Gaelige (Irish) */
   417 	case 4:
   429 	case 4:
   418 		return n==1 ? 0 : n==2 ? 1 : 2;
   430 		return n==1 ? 0 : n==2 ? 1 : 2;
   419 
   431 
   420 	// Three forms, special case for numbers ending in 1[2-9]
   432 	/* Three forms, special case for numbers ending in 1[2-9]
   421 	// Used in:
   433 	 * Used in:
   422 	//   Lithuanian
   434 	 *   Lithuanian */
   423 	case 5:
   435 	case 5:
   424 		return n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2;
   436 		return n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2;
   425 
   437 
   426 	// Three forms, special cases for numbers ending in 1 and 2, 3, 4, except those ending in 1[1-4]
   438 	/* Three forms, special cases for numbers ending in 1 and 2, 3, 4, except those ending in 1[1-4]
   427 	// Used in:
   439 	 * Used in:
   428 	//   Croatian, Czech, Russian, Slovak, Ukrainian
   440 	 *   Croatian, Czech, Russian, Slovak, Ukrainian */
   429 	case 6:
   441 	case 6:
   430 		return n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;
   442 		return n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;
   431 
   443 
   432 	// Three forms, special case for one and some numbers ending in 2, 3, or 4
   444 	/* Three forms, special case for one and some numbers ending in 2, 3, or 4
   433 	// Used in:
   445 	 * Used in:
   434 	//   Polish
   446 	 *   Polish */
   435 	case 7:
   447 	case 7:
   436 		return n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;
   448 		return n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;
   437 
   449 
   438 	// Four forms, special case for one and all numbers ending in 02, 03, or 04
   450 	/* Four forms, special case for one and all numbers ending in 02, 03, or 04
   439 	// Used in:
   451 	 * Used in:
   440 	//   Slovenian
   452 	 *   Slovenian */
   441 	case 8:
   453 	case 8:
   442 		return n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3;
   454 		return n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3;
   443 	}
   455 	}
   444 }
   456 }
   445 
   457 
   559 			case SCC_REVISION: /* {REV} */
   571 			case SCC_REVISION: /* {REV} */
   560 				buff = strecpy(buff, _openttd_revision, last);
   572 				buff = strecpy(buff, _openttd_revision, last);
   561 				break;
   573 				break;
   562 
   574 
   563 			case SCC_CARGO_SHORT: { /* {SHORTCARGO} */
   575 			case SCC_CARGO_SHORT: { /* {SHORTCARGO} */
   564 				// Short description of cargotypes. Layout:
   576 				/* Short description of cargotypes. Layout:
   565 				// 8-bit = cargo type
   577 				 * 8-bit = cargo type
   566 				// 16-bit = cargo count
   578 				 * 16-bit = cargo count */
   567 				StringID cargo_str = GetCargo(GetInt32(&argv))->units_volume;
   579 				StringID cargo_str = GetCargo(GetInt32(&argv))->units_volume;
   568 				switch (cargo_str) {
   580 				switch (cargo_str) {
   569 					case STR_TONS: {
   581 					case STR_TONS: {
   570 						int32 args[1];
   582 						int32 args[1];
   571 						assert(_opt_ptr->units < lengthof(units));
   583 						assert(_opt_ptr->units < lengthof(units));
   597 						break;
   609 						break;
   598 				}
   610 				}
   599 			} break;
   611 			} break;
   600 
   612 
   601 			case SCC_CURRENCY_COMPACT_64: { /* {CURRCOMPACT64} */
   613 			case SCC_CURRENCY_COMPACT_64: { /* {CURRCOMPACT64} */
   602 				// 64 bit compact currency-unit
   614 				/* 64 bit compact currency-unit */
   603 				buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), true, last);
   615 				buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), true, last);
   604 				break;
   616 				break;
   605 			}
   617 			}
   606 
   618 
   607 			case SCC_STRING1: { /* {STRING1} */
   619 			case SCC_STRING1: { /* {STRING1} */
   608 				// String that consumes ONE argument
   620 				/* String that consumes ONE argument */
   609 				uint str = modifier + GetInt32(&argv);
   621 				uint str = modifier + GetInt32(&argv);
   610 				buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 1), last);
   622 				buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 1), last);
   611 				modifier = 0;
   623 				modifier = 0;
   612 				break;
   624 				break;
   613 			}
   625 			}
   614 
   626 
   615 			case SCC_STRING2: { /* {STRING2} */
   627 			case SCC_STRING2: { /* {STRING2} */
   616 				// String that consumes TWO arguments
   628 				/* String that consumes TWO arguments */
   617 				uint str = modifier + GetInt32(&argv);
   629 				uint str = modifier + GetInt32(&argv);
   618 				buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 2), last);
   630 				buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 2), last);
   619 				modifier = 0;
   631 				modifier = 0;
   620 				break;
   632 				break;
   621 			}
   633 			}
   622 
   634 
   623 			case SCC_STRING3: { /* {STRING3} */
   635 			case SCC_STRING3: { /* {STRING3} */
   624 				// String that consumes THREE arguments
   636 				/* String that consumes THREE arguments */
   625 				uint str = modifier + GetInt32(&argv);
   637 				uint str = modifier + GetInt32(&argv);
   626 				buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 3), last);
   638 				buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 3), last);
   627 				modifier = 0;
   639 				modifier = 0;
   628 				break;
   640 				break;
   629 			}
   641 			}
   630 
   642 
   631 			case SCC_STRING4: { /* {STRING4} */
   643 			case SCC_STRING4: { /* {STRING4} */
   632 				// String that consumes FOUR arguments
   644 				/* String that consumes FOUR arguments */
   633 				uint str = modifier + GetInt32(&argv);
   645 				uint str = modifier + GetInt32(&argv);
   634 				buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 4), last);
   646 				buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 4), last);
   635 				modifier = 0;
   647 				modifier = 0;
   636 				break;
   648 				break;
   637 			}
   649 			}
   638 
   650 
   639 			case SCC_STRING5: { /* {STRING5} */
   651 			case SCC_STRING5: { /* {STRING5} */
   640 				// String that consumes FIVE arguments
   652 				/* String that consumes FIVE arguments */
   641 				uint str = modifier + GetInt32(&argv);
   653 				uint str = modifier + GetInt32(&argv);
   642 				buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 5), last);
   654 				buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 5), last);
   643 				modifier = 0;
   655 				modifier = 0;
   644 				break;
   656 				break;
   645 			}
   657 			}
   651 
   663 
   652 			case SCC_INDUSTRY_NAME: { /* {INDUSTRY} */
   664 			case SCC_INDUSTRY_NAME: { /* {INDUSTRY} */
   653 				const Industry* i = GetIndustry(GetInt32(&argv));
   665 				const Industry* i = GetIndustry(GetInt32(&argv));
   654 				int32 args[2];
   666 				int32 args[2];
   655 
   667 
   656 				// industry not valid anymore?
   668 				/* industry not valid anymore? */
   657 				if (!IsValidIndustry(i)) break;
   669 				if (!IsValidIndustry(i)) break;
   658 
   670 
   659 				// First print the town name and the industry type name
   671 				/* First print the town name and the industry type name
   660 				// The string STR_INDUSTRY_PATTERN controls the formatting
   672 				 * The string STR_INDUSTRY_PATTERN controls the formatting */
   661 				args[0] = i->town->index;
   673 				args[0] = i->town->index;
   662 				args[1] = GetIndustrySpec(i->type)->name;
   674 				args[1] = GetIndustrySpec(i->type)->name;
   663 				buff = FormatString(buff, GetStringPtr(STR_INDUSTRY_FORMAT), args, modifier >> 24, last);
   675 				buff = FormatString(buff, GetStringPtr(STR_INDUSTRY_FORMAT), args, modifier >> 24, last);
   664 				modifier = 0;
   676 				modifier = 0;
   665 				break;
   677 				break;
   688 				buff = FormatTinyDate(buff, GetInt32(&argv), last);
   700 				buff = FormatTinyDate(buff, GetInt32(&argv), last);
   689 				break;
   701 				break;
   690 			}
   702 			}
   691 
   703 
   692 			case SCC_CARGO: { // {CARGO}
   704 			case SCC_CARGO: { // {CARGO}
   693 				// Layout now is:
   705 				/* Layout now is:
   694 				//   8bit   - cargo type
   706 				 *   8bit   - cargo type
   695 				//   16-bit - cargo count
   707 				 *   16-bit - cargo count */
   696 				CargoID cargo = GetInt32(&argv);
   708 				CargoID cargo = GetInt32(&argv);
   697 				StringID cargo_str = (cargo == CT_INVALID) ? (StringID)STR_8838_N_A : GetCargo(cargo)->quantifier;
   709 				StringID cargo_str = (cargo == CT_INVALID) ? (StringID)STR_8838_N_A : GetCargo(cargo)->quantifier;
   698 				buff = GetStringWithArgs(buff, cargo_str, argv++, last);
   710 				buff = GetStringWithArgs(buff, cargo_str, argv++, last);
   699 				break;
   711 				break;
   700 			}
   712 			}
   746 
   758 
   747 			case SCC_SKIP: // {SKIP}
   759 			case SCC_SKIP: // {SKIP}
   748 				argv++;
   760 				argv++;
   749 				break;
   761 				break;
   750 
   762 
   751 			// This sets up the gender for the string.
   763 			/* This sets up the gender for the string.
   752 			// We just ignore this one. It's used in {G 0 Der Die Das} to determine the case.
   764 			 * We just ignore this one. It's used in {G 0 Der Die Das} to determine the case. */
   753 			case SCC_GENDER_INDEX: // {GENDER 0}
   765 			case SCC_GENDER_INDEX: // {GENDER 0}
   754 				str++;
   766 				str++;
   755 				break;
   767 				break;
   756 
   768 
   757 			case SCC_STRING: {// {STRING}
   769 			case SCC_STRING: {// {STRING}
   758 				uint str = modifier + GetInt32(&argv);
   770 				uint str = modifier + GetInt32(&argv);
   759 				// WARNING. It's prohibited for the included string to consume any arguments.
   771 				/* WARNING. It's prohibited for the included string to consume any arguments.
   760 				// For included strings that consume argument, you should use STRING1, STRING2 etc.
   772 				 * For included strings that consume argument, you should use STRING1, STRING2 etc.
   761 				// To debug stuff you can set argv to NULL and it will tell you
   773 				 * To debug stuff you can set argv to NULL and it will tell you */
   762 				buff = GetStringWithArgs(buff, str, argv, last);
   774 				buff = GetStringWithArgs(buff, str, argv, last);
   763 				modifier = 0;
   775 				modifier = 0;
   764 				break;
   776 				break;
   765 			}
   777 			}
   766 
   778 
   832 				buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), false, last);
   844 				buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), false, last);
   833 				break;
   845 				break;
   834 			}
   846 			}
   835 
   847 
   836 			case SCC_SETCASE: { // {SETCASE}
   848 			case SCC_SETCASE: { // {SETCASE}
   837 				// This is a pseudo command, it's outputted when someone does {STRING.ack}
   849 				/* This is a pseudo command, it's outputted when someone does {STRING.ack}
   838 				// The modifier is added to all subsequent GetStringWithArgs that accept the modifier.
   850 				 * The modifier is added to all subsequent GetStringWithArgs that accept the modifier. */
   839 				modifier = (byte)*str++ << 24;
   851 				modifier = (byte)*str++ << 24;
   840 				break;
   852 				break;
   841 			}
   853 			}
   842 
   854 
   843 			case SCC_SWITCH_CASE: { // {Used to implement case switching}
   855 			case SCC_SWITCH_CASE: { // {Used to implement case switching}
   844 				// <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT>
   856 				/* <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT>
   845 				// Each LEN is printed using 2 bytes in big endian order.
   857 				 * Each LEN is printed using 2 bytes in big endian order. */
   846 				uint num = (byte)*str++;
   858 				uint num = (byte)*str++;
   847 				while (num) {
   859 				while (num) {
   848 					if ((byte)str[0] == casei) {
   860 					if ((byte)str[0] == casei) {
   849 						// Found the case, adjust str pointer and continue
   861 						/* Found the case, adjust str pointer and continue */
   850 						str += 3;
   862 						str += 3;
   851 						break;
   863 						break;
   852 					}
   864 					}
   853 					// Otherwise skip to the next case
   865 					/* Otherwise skip to the next case */
   854 					str += 3 + (str[1] << 8) + str[2];
   866 					str += 3 + (str[1] << 8) + str[2];
   855 					num--;
   867 					num--;
   856 				}
   868 				}
   857 				break;
   869 				break;
   858 			}
   870 			}
  1016 
  1028 
  1017 		case 4: // song names
  1029 		case 4: // song names
  1018 			return strecpy(buff, origin_songs_specs[GetInt32(&argv) - 1].song_name, last);
  1030 			return strecpy(buff, origin_songs_specs[GetInt32(&argv) - 1].song_name, last);
  1019 	}
  1031 	}
  1020 
  1032 
  1021 	// town name?
  1033 	/* town name? */
  1022 	if (IS_INT_INSIDE(ind - 6, 0, SPECSTR_TOWNNAME_LAST-SPECSTR_TOWNNAME_START + 1)) {
  1034 	if (IS_INT_INSIDE(ind - 6, 0, SPECSTR_TOWNNAME_LAST-SPECSTR_TOWNNAME_START + 1)) {
  1023 		buff = GetSpecialTownNameString(buff, ind - 6, GetInt32(&argv), last);
  1035 		buff = GetSpecialTownNameString(buff, ind - 6, GetInt32(&argv), last);
  1024 		return strecpy(buff, " Transport", last);
  1036 		return strecpy(buff, " Transport", last);
  1025 	}
  1037 	}
  1026 
  1038 
  1027 	// language name?
  1039 	/* language name? */
  1028 	if (IS_INT_INSIDE(ind, (SPECSTR_LANGUAGE_START - 0x70E4), (SPECSTR_LANGUAGE_END - 0x70E4) + 1)) {
  1040 	if (IS_INT_INSIDE(ind, (SPECSTR_LANGUAGE_START - 0x70E4), (SPECSTR_LANGUAGE_END - 0x70E4) + 1)) {
  1029 		int i = ind - (SPECSTR_LANGUAGE_START - 0x70E4);
  1041 		int i = ind - (SPECSTR_LANGUAGE_START - 0x70E4);
  1030 		return strecpy(buff,
  1042 		return strecpy(buff,
  1031 			i == _dynlang.curr ? _langpack->own_name : _dynlang.ent[i].name, last);
  1043 			i == _dynlang.curr ? _langpack->own_name : _dynlang.ent[i].name, last);
  1032 	}
  1044 	}
  1033 
  1045 
  1034 	// resolution size?
  1046 	/* resolution size? */
  1035 	if (IS_INT_INSIDE(ind, (SPECSTR_RESOLUTION_START - 0x70E4), (SPECSTR_RESOLUTION_END - 0x70E4) + 1)) {
  1047 	if (IS_INT_INSIDE(ind, (SPECSTR_RESOLUTION_START - 0x70E4), (SPECSTR_RESOLUTION_END - 0x70E4) + 1)) {
  1036 		int i = ind - (SPECSTR_RESOLUTION_START - 0x70E4);
  1048 		int i = ind - (SPECSTR_RESOLUTION_START - 0x70E4);
  1037 		buff += snprintf(
  1049 		buff += snprintf(
  1038 			buff, last - buff + 1, "%dx%d", _resolutions[i][0], _resolutions[i][1]
  1050 			buff, last - buff + 1, "%dx%d", _resolutions[i][0], _resolutions[i][1]
  1039 		);
  1051 		);
  1040 		return buff;
  1052 		return buff;
  1041 	}
  1053 	}
  1042 
  1054 
  1043 	// screenshot format name?
  1055 	/* screenshot format name? */
  1044 	if (IS_INT_INSIDE(ind, (SPECSTR_SCREENSHOT_START - 0x70E4), (SPECSTR_SCREENSHOT_END - 0x70E4) + 1)) {
  1056 	if (IS_INT_INSIDE(ind, (SPECSTR_SCREENSHOT_START - 0x70E4), (SPECSTR_SCREENSHOT_END - 0x70E4) + 1)) {
  1045 		int i = ind - (SPECSTR_SCREENSHOT_START - 0x70E4);
  1057 		int i = ind - (SPECSTR_SCREENSHOT_START - 0x70E4);
  1046 		return strecpy(buff, GetScreenshotFormatDesc(i), last);
  1058 		return strecpy(buff, GetScreenshotFormatDesc(i), last);
  1047 	}
  1059 	}
  1048 
  1060 
  1049 	assert(0);
  1061 	assert(0);
  1050 	return NULL;
  1062 	return NULL;
  1051 }
  1063 }
  1052 
  1064 
  1053 // remap a string ID from the old format to the new format
  1065 /**
       
  1066  * remap a string ID from the old format to the new format
       
  1067  * @param s StringID that requires remapping
       
  1068  * @return translated ID*/
  1054 StringID RemapOldStringID(StringID s)
  1069 StringID RemapOldStringID(StringID s)
  1055 {
  1070 {
  1056 	switch (s) {
  1071 	switch (s) {
  1057 		case 0x0006: return STR_SV_EMPTY;
  1072 		case 0x0006: return STR_SV_EMPTY;
  1058 		case 0x7000: return STR_SV_UNNAMED;
  1073 		case 0x7000: return STR_SV_UNNAMED;
  1101 		_langtab_start[i] = tot_count;
  1116 		_langtab_start[i] = tot_count;
  1102 		_langtab_num[i] = num;
  1117 		_langtab_num[i] = num;
  1103 		tot_count += num;
  1118 		tot_count += num;
  1104 	}
  1119 	}
  1105 
  1120 
  1106 	// Allocate offsets
  1121 	/* Allocate offsets */
  1107 	langpack_offs = MallocT<char*>(tot_count);
  1122 	langpack_offs = MallocT<char*>(tot_count);
  1108 
  1123 
  1109 	// Fill offsets
  1124 	/* Fill offsets */
  1110 	s = lang_pack->data;
  1125 	s = lang_pack->data;
  1111 	for (i = 0; i != tot_count; i++) {
  1126 	for (i = 0; i != tot_count; i++) {
  1112 		len = (byte)*s;
  1127 		len = (byte)*s;
  1113 		*s++ = '\0'; // zero terminate the string before.
  1128 		*s++ = '\0'; // zero terminate the string before.
  1114 		if (len >= 0xC0) len = ((len & 0x3F) << 8) + (byte)*s++;
  1129 		if (len >= 0xC0) len = ((len & 0x3F) << 8) + (byte)*s++;
  1131 }
  1146 }
  1132 
  1147 
  1133 /** Determine the current charset based on the environment
  1148 /** Determine the current charset based on the environment
  1134  * First check some default values, after this one we passed ourselves
  1149  * First check some default values, after this one we passed ourselves
  1135  * and if none exist return the value for $LANG
  1150  * and if none exist return the value for $LANG
  1136  * @param environment variable to check conditionally if default ones are not
  1151  * @param param environment variable to check conditionally if default ones are not
  1137  *        set. Pass NULL if you don't want additional checks.
  1152  *        set. Pass NULL if you don't want additional checks.
  1138  * @return return string containing current charset, or NULL if not-determinable */
  1153  * @return return string containing current charset, or NULL if not-determinable */
  1139 const char *GetCurrentLocale(const char *param)
  1154 const char *GetCurrentLocale(const char *param)
  1140 {
  1155 {
  1141 	const char *env;
  1156 	const char *env;