OpenTTD
strings.cpp
Go to the documentation of this file.
1 /* $Id$ */
2 
3 /*
4  * This file is part of OpenTTD.
5  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
8  */
9 
12 #include "stdafx.h"
13 #include "currency.h"
14 #include "station_base.h"
15 #include "town.h"
16 #include "waypoint_base.h"
17 #include "depot_base.h"
18 #include "industry.h"
19 #include "newgrf_text.h"
20 #include "fileio_func.h"
21 #include "signs_base.h"
22 #include "fontdetection.h"
23 #include "error.h"
24 #include "strings_func.h"
25 #include "rev.h"
26 #include "core/endian_func.hpp"
27 #include "date_func.h"
28 #include "vehicle_base.h"
29 #include "engine_base.h"
30 #include "language.h"
31 #include "townname_func.h"
32 #include "string_func.h"
33 #include "company_base.h"
34 #include "smallmap_gui.h"
35 #include "window_func.h"
36 #include "debug.h"
37 #include "game/game_text.hpp"
38 #ifdef ENABLE_NETWORK
40 #endif /* ENABLE_NETWORK */
41 #include <stack>
42 
43 #include "table/strings.h"
44 #include "table/control_codes.h"
45 
46 #include "safeguards.h"
47 
48 char _config_language_file[MAX_PATH];
51 
53 
54 #ifdef WITH_ICU_SORT
55 icu::Collator *_current_collator = NULL;
56 #endif /* WITH_ICU_SORT */
57 
58 static uint64 _global_string_params_data[20];
61 
64 {
65  assert(this->type != NULL);
66  MemSetT(this->type, 0, this->num_param);
67 }
68 
69 
75 {
76  if (this->offset >= this->num_param) {
77  DEBUG(misc, 0, "Trying to read invalid string parameter");
78  return 0;
79  }
80  if (this->type != NULL) {
81  if (this->type[this->offset] != 0 && this->type[this->offset] != type) {
82  DEBUG(misc, 0, "Trying to read string parameter with wrong type");
83  return 0;
84  }
85  this->type[this->offset] = type;
86  }
87  return this->data[this->offset++];
88 }
89 
95 {
96  assert(amount <= this->num_param);
97  MemMoveT(this->data + amount, this->data, this->num_param - amount);
98 }
99 
108 void SetDParamMaxValue(uint n, uint64 max_value, uint min_count, FontSize size)
109 {
110  uint num_digits = 1;
111  while (max_value >= 10) {
112  num_digits++;
113  max_value /= 10;
114  }
115  SetDParamMaxDigits(n, max(min_count, num_digits), size);
116 }
117 
124 void SetDParamMaxDigits(uint n, uint count, FontSize size)
125 {
126  uint front, next;
127  GetBroadestDigit(&front, &next, size);
128  uint64 val = count > 1 ? front : next;
129  for (; count > 1; count--) {
130  val = 10 * val + next;
131  }
132  SetDParam(n, val);
133 }
134 
141 void CopyInDParam(int offs, const uint64 *src, int num)
142 {
143  MemCpyT(_global_string_params.GetPointerToOffset(offs), src, num);
144 }
145 
152 void CopyOutDParam(uint64 *dst, int offs, int num)
153 {
154  MemCpyT(dst, _global_string_params.GetPointerToOffset(offs), num);
155 }
156 
165 void CopyOutDParam(uint64 *dst, const char **strings, StringID string, int num)
166 {
167  char buf[DRAW_STRING_BUFFER];
168  GetString(buf, string, lastof(buf));
169 
170  MemCpyT(dst, _global_string_params.GetPointerToOffset(0), num);
171  for (int i = 0; i < num; i++) {
172  if (_global_string_params.HasTypeInformation() && _global_string_params.GetTypeAtOffset(i) == SCC_RAW_STRING_POINTER) {
173  strings[i] = stredup((const char *)(size_t)_global_string_params.GetParam(i));
174  dst[i] = (size_t)strings[i];
175  } else {
176  strings[i] = NULL;
177  }
178  }
179 }
180 
181 static char *StationGetSpecialString(char *buff, int x, const char *last);
182 static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last);
183 static char *GetSpecialNameString(char *buff, int ind, StringParameters *args, const char *last);
184 
185 static char *FormatString(char *buff, const char *str, StringParameters *args, const char *last, uint case_index = 0, bool game_script = false, bool dry_run = false);
186 
188  char data[]; // list of strings
189 };
190 
191 static char **_langpack_offs;
192 static LanguagePack *_langpack;
195 static bool _scan_for_gender_data = false;
196 
197 
198 const char *GetStringPtr(StringID string)
199 {
200  switch (GetStringTab(string)) {
202  /* 0xD0xx and 0xD4xx IDs have been converted earlier. */
203  case TEXT_TAB_OLD_NEWGRF: NOT_REACHED();
205  default: return _langpack_offs[_langtab_start[GetStringTab(string)] + GetStringIndex(string)];
206  }
207 }
208 
219 char *GetStringWithArgs(char *buffr, StringID string, StringParameters *args, const char *last, uint case_index, bool game_script)
220 {
221  if (string == 0) return GetStringWithArgs(buffr, STR_UNDEFINED, args, last);
222 
223  uint index = GetStringIndex(string);
224  StringTab tab = GetStringTab(string);
225 
226  switch (tab) {
227  case TEXT_TAB_TOWN:
228  if (index >= 0xC0 && !game_script) {
229  return GetSpecialTownNameString(buffr, index - 0xC0, args->GetInt32(), last);
230  }
231  break;
232 
233  case TEXT_TAB_SPECIAL:
234  if (index >= 0xE4 && !game_script) {
235  return GetSpecialNameString(buffr, index - 0xE4, args, last);
236  }
237  break;
238 
239  case TEXT_TAB_OLD_CUSTOM:
240  /* Old table for custom names. This is no longer used */
241  if (!game_script) {
242  error("Incorrect conversion of custom name string.");
243  }
244  break;
245 
247  return FormatString(buffr, GetGameStringPtr(index), args, last, case_index, true);
248 
249  case TEXT_TAB_OLD_NEWGRF:
250  NOT_REACHED();
251 
253  return FormatString(buffr, GetGRFStringPtr(index), args, last, case_index);
254 
255  default:
256  break;
257  }
258 
259  if (index >= _langtab_num[tab]) {
260  if (game_script) {
261  return GetStringWithArgs(buffr, STR_UNDEFINED, args, last);
262  }
263  error("String 0x%X is invalid. You are probably using an old version of the .lng file.\n", string);
264  }
265 
266  return FormatString(buffr, GetStringPtr(string), args, last, case_index);
267 }
268 
269 char *GetString(char *buffr, StringID string, const char *last)
270 {
271  _global_string_params.ClearTypeInformation();
272  _global_string_params.offset = 0;
273  return GetStringWithArgs(buffr, string, &_global_string_params, last);
274 }
275 
276 
282 void SetDParamStr(uint n, const char *str)
283 {
284  SetDParam(n, (uint64)(size_t)str);
285 }
286 
291 void InjectDParam(uint amount)
292 {
293  _global_string_params.ShiftParameters(amount);
294 }
295 
307 static char *FormatNumber(char *buff, int64 number, const char *last, const char *separator, int zerofill = 1, int fractional_digits = 0)
308 {
309  static const int max_digits = 20;
310  uint64 divisor = 10000000000000000000ULL;
311  zerofill += fractional_digits;
312  int thousands_offset = (max_digits - fractional_digits - 1) % 3;
313 
314  if (number < 0) {
315  buff += seprintf(buff, last, "-");
316  number = -number;
317  }
318 
319  uint64 num = number;
320  uint64 tot = 0;
321  for (int i = 0; i < max_digits; i++) {
322  if (i == max_digits - fractional_digits) {
323  const char *decimal_separator = _settings_game.locale.digit_decimal_separator;
324  if (decimal_separator == NULL) decimal_separator = _langpack->digit_decimal_separator;
325  buff += seprintf(buff, last, "%s", decimal_separator);
326  }
327 
328  uint64 quot = 0;
329  if (num >= divisor) {
330  quot = num / divisor;
331  num = num % divisor;
332  }
333  if ((tot |= quot) || i >= max_digits - zerofill) {
334  buff += seprintf(buff, last, "%i", (int)quot);
335  if ((i % 3) == thousands_offset && i < max_digits - 1 - fractional_digits) buff = strecpy(buff, separator, last);
336  }
337 
338  divisor /= 10;
339  }
340 
341  *buff = '\0';
342 
343  return buff;
344 }
345 
346 static char *FormatCommaNumber(char *buff, int64 number, const char *last, int fractional_digits = 0)
347 {
348  const char *separator = _settings_game.locale.digit_group_separator;
349  if (separator == NULL) separator = _langpack->digit_group_separator;
350  return FormatNumber(buff, number, last, separator, 1, fractional_digits);
351 }
352 
353 static char *FormatNoCommaNumber(char *buff, int64 number, const char *last)
354 {
355  return FormatNumber(buff, number, last, "");
356 }
357 
358 static char *FormatZerofillNumber(char *buff, int64 number, int64 count, const char *last)
359 {
360  return FormatNumber(buff, number, last, "", count);
361 }
362 
363 static char *FormatHexNumber(char *buff, uint64 number, const char *last)
364 {
365  return buff + seprintf(buff, last, "0x" OTTD_PRINTFHEX64, number);
366 }
367 
375 static char *FormatBytes(char *buff, int64 number, const char *last)
376 {
377  assert(number >= 0);
378 
379  /* 1 2^10 2^20 2^30 2^40 2^50 2^60 */
380  const char * const iec_prefixes[] = {"", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei"};
381  uint id = 1;
382  while (number >= 1024 * 1024) {
383  number /= 1024;
384  id++;
385  }
386 
387  const char *decimal_separator = _settings_game.locale.digit_decimal_separator;
388  if (decimal_separator == NULL) decimal_separator = _langpack->digit_decimal_separator;
389 
390  if (number < 1024) {
391  id = 0;
392  buff += seprintf(buff, last, "%i", (int)number);
393  } else if (number < 1024 * 10) {
394  buff += seprintf(buff, last, "%i%s%02i", (int)number / 1024, decimal_separator, (int)(number % 1024) * 100 / 1024);
395  } else if (number < 1024 * 100) {
396  buff += seprintf(buff, last, "%i%s%01i", (int)number / 1024, decimal_separator, (int)(number % 1024) * 10 / 1024);
397  } else {
398  assert(number < 1024 * 1024);
399  buff += seprintf(buff, last, "%i", (int)number / 1024);
400  }
401 
402  assert(id < lengthof(iec_prefixes));
403  buff += seprintf(buff, last, NBSP "%sB", iec_prefixes[id]);
404 
405  return buff;
406 }
407 
408 static char *FormatYmdString(char *buff, Date date, const char *last, uint case_index)
409 {
410  YearMonthDay ymd;
411  ConvertDateToYMD(date, &ymd);
412 
413  int64 args[] = {ymd.day + STR_DAY_NUMBER_1ST - 1, STR_MONTH_ABBREV_JAN + ymd.month, ymd.year};
414  StringParameters tmp_params(args);
415  return FormatString(buff, GetStringPtr(STR_FORMAT_DATE_LONG), &tmp_params, last, case_index);
416 }
417 
418 static char *FormatMonthAndYear(char *buff, Date date, const char *last, uint case_index)
419 {
420  YearMonthDay ymd;
421  ConvertDateToYMD(date, &ymd);
422 
423  int64 args[] = {STR_MONTH_JAN + ymd.month, ymd.year};
424  StringParameters tmp_params(args);
425  return FormatString(buff, GetStringPtr(STR_FORMAT_DATE_SHORT), &tmp_params, last, case_index);
426 }
427 
428 static char *FormatTinyOrISODate(char *buff, Date date, StringID str, const char *last)
429 {
430  YearMonthDay ymd;
431  ConvertDateToYMD(date, &ymd);
432 
433  char day[3];
434  char month[3];
435  /* We want to zero-pad the days and months */
436  seprintf(day, lastof(day), "%02i", ymd.day);
437  seprintf(month, lastof(month), "%02i", ymd.month + 1);
438 
439  int64 args[] = {(int64)(size_t)day, (int64)(size_t)month, ymd.year};
440  StringParameters tmp_params(args);
441  return FormatString(buff, GetStringPtr(str), &tmp_params, last);
442 }
443 
444 static char *FormatGenericCurrency(char *buff, const CurrencySpec *spec, Money number, bool compact, const char *last)
445 {
446  /* We are going to make number absolute for printing, so
447  * keep this piece of data as we need it later on */
448  bool negative = number < 0;
449  const char *multiplier = "";
450 
451  number *= spec->rate;
452 
453  /* convert from negative */
454  if (number < 0) {
455  if (buff + Utf8CharLen(SCC_PUSH_COLOUR) > last) return buff;
456  buff += Utf8Encode(buff, SCC_PUSH_COLOUR);
457  if (buff + Utf8CharLen(SCC_RED) > last) return buff;
458  buff += Utf8Encode(buff, SCC_RED);
459  buff = strecpy(buff, "-", last);
460  number = -number;
461  }
462 
463  /* Add prefix part, following symbol_pos specification.
464  * Here, it can can be either 0 (prefix) or 2 (both prefix and suffix).
465  * The only remaining value is 1 (suffix), so everything that is not 1 */
466  if (spec->symbol_pos != 1) buff = strecpy(buff, spec->prefix, last);
467 
468  /* for huge numbers, compact the number into k or M */
469  if (compact) {
470  /* Take care of the 'k' rounding. Having 1 000 000 k
471  * and 1 000 M is inconsistent, so always use 1 000 M. */
472  if (number >= 1000000000 - 500) {
473  number = (number + 500000) / 1000000;
474  multiplier = NBSP "M";
475  } else if (number >= 1000000) {
476  number = (number + 500) / 1000;
477  multiplier = NBSP "k";
478  }
479  }
480 
481  const char *separator = _settings_game.locale.digit_group_separator_currency;
482  if (separator == NULL && !StrEmpty(_currency->separator)) separator = _currency->separator;
483  if (separator == NULL) separator = _langpack->digit_group_separator_currency;
484  buff = FormatNumber(buff, number, last, separator);
485  buff = strecpy(buff, multiplier, last);
486 
487  /* Add suffix part, following symbol_pos specification.
488  * Here, it can can be either 1 (suffix) or 2 (both prefix and suffix).
489  * The only remaining value is 1 (prefix), so everything that is not 0 */
490  if (spec->symbol_pos != 0) buff = strecpy(buff, spec->suffix, last);
491 
492  if (negative) {
493  if (buff + Utf8CharLen(SCC_POP_COLOUR) > last) return buff;
494  buff += Utf8Encode(buff, SCC_POP_COLOUR);
495  *buff = '\0';
496  }
497 
498  return buff;
499 }
500 
507 static int DeterminePluralForm(int64 count, int plural_form)
508 {
509  /* The absolute value determines plurality */
510  uint64 n = abs(count);
511 
512  switch (plural_form) {
513  default:
514  NOT_REACHED();
515 
516  /* Two forms: singular used for one only.
517  * Used in:
518  * Danish, Dutch, English, German, Norwegian, Swedish, Estonian, Finnish,
519  * Greek, Hebrew, Italian, Portuguese, Spanish, Esperanto */
520  case 0:
521  return n != 1 ? 1 : 0;
522 
523  /* Only one form.
524  * Used in:
525  * Hungarian, Japanese, Korean, Turkish */
526  case 1:
527  return 0;
528 
529  /* Two forms: singular used for 0 and 1.
530  * Used in:
531  * French, Brazilian Portuguese */
532  case 2:
533  return n > 1 ? 1 : 0;
534 
535  /* Three forms: special cases for 0, and numbers ending in 1 except when ending in 11.
536  * Note: Cases are out of order for hysterical reasons. '0' is last.
537  * Used in:
538  * Latvian */
539  case 3:
540  return n % 10 == 1 && n % 100 != 11 ? 0 : n != 0 ? 1 : 2;
541 
542  /* Five forms: special cases for 1, 2, 3 to 6, and 7 to 10.
543  * Used in:
544  * Gaelige (Irish) */
545  case 4:
546  return n == 1 ? 0 : n == 2 ? 1 : n < 7 ? 2 : n < 11 ? 3 : 4;
547 
548  /* Three forms: special cases for numbers ending in 1 except when ending in 11, and 2 to 9 except when ending in 12 to 19.
549  * Used in:
550  * Lithuanian */
551  case 5:
552  return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
553 
554  /* Three forms: special cases for numbers ending in 1 except when ending in 11, and 2 to 4 except when ending in 12 to 14.
555  * Used in:
556  * Croatian, Russian, Ukrainian */
557  case 6:
558  return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
559 
560  /* Three forms: special cases for 1, and numbers ending in 2 to 4 except when ending in 12 to 14.
561  * Used in:
562  * Polish */
563  case 7:
564  return n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
565 
566  /* Four forms: special cases for numbers ending in 01, 02, and 03 to 04.
567  * Used in:
568  * Slovenian */
569  case 8:
570  return n % 100 == 1 ? 0 : n % 100 == 2 ? 1 : n % 100 == 3 || n % 100 == 4 ? 2 : 3;
571 
572  /* Two forms: singular used for numbers ending in 1 except when ending in 11.
573  * Used in:
574  * Icelandic */
575  case 9:
576  return n % 10 == 1 && n % 100 != 11 ? 0 : 1;
577 
578  /* Three forms: special cases for 1, and 2 to 4
579  * Used in:
580  * Czech, Slovak */
581  case 10:
582  return n == 1 ? 0 : n >= 2 && n <= 4 ? 1 : 2;
583 
584  /* Two forms: cases for numbers ending with a consonant, and with a vowel.
585  * Korean doesn't have the concept of plural, but depending on how a
586  * number is pronounced it needs another version of a particle.
587  * As such the plural system is misused to give this distinction.
588  */
589  case 11:
590  switch (n % 10) {
591  case 0: // yeong
592  case 1: // il
593  case 3: // sam
594  case 6: // yuk
595  case 7: // chil
596  case 8: // pal
597  return 0;
598 
599  case 2: // i
600  case 4: // sa
601  case 5: // o
602  case 9: // gu
603  return 1;
604 
605  default:
606  NOT_REACHED();
607  }
608 
609  /* Four forms: special cases for 1, 0 and numbers ending in 02 to 10, and numbers ending in 11 to 19.
610  * Used in:
611  * Maltese */
612  case 12:
613  return (n == 1 ? 0 : n == 0 || (n % 100 > 1 && n % 100 < 11) ? 1 : (n % 100 > 10 && n % 100 < 20) ? 2 : 3);
614  /* Four forms: special cases for 1 and 11, 2 and 12, 3 .. 10 and 13 .. 19, other
615  * Used in:
616  * Scottish Gaelic */
617  case 13:
618  return ((n == 1 || n == 11) ? 0 : (n == 2 || n == 12) ? 1 : ((n > 2 && n < 11) || (n > 12 && n < 20)) ? 2 : 3);
619  }
620 }
621 
622 static const char *ParseStringChoice(const char *b, uint form, char **dst, const char *last)
623 {
624  /* <NUM> {Length of each string} {each string} */
625  uint n = (byte)*b++;
626  uint pos, i, mypos = 0;
627 
628  for (i = pos = 0; i != n; i++) {
629  uint len = (byte)*b++;
630  if (i == form) mypos = pos;
631  pos += len;
632  }
633 
634  *dst += seprintf(*dst, last, "%s", b + mypos);
635  return b + pos;
636 }
637 
641  int shift;
642 
649  int64 ToDisplay(int64 input, bool round = true) const
650  {
651  return ((input * this->multiplier) + (round && this->shift != 0 ? 1 << (this->shift - 1) : 0)) >> this->shift;
652  }
653 
661  int64 FromDisplay(int64 input, bool round = true, int64 divider = 1) const
662  {
663  return ((input << this->shift) + (round ? (this->multiplier * divider) - 1 : 0)) / (this->multiplier * divider);
664  }
665 };
666 
668 struct Units {
671 };
672 
674 struct UnitsLong {
678 };
679 
681 static const Units _units_velocity[] = {
682  { { 1, 0}, STR_UNITS_VELOCITY_IMPERIAL },
683  { { 103, 6}, STR_UNITS_VELOCITY_METRIC },
684  { {1831, 12}, STR_UNITS_VELOCITY_SI },
685 };
686 
688 static const Units _units_power[] = {
689  { { 1, 0}, STR_UNITS_POWER_IMPERIAL },
690  { {4153, 12}, STR_UNITS_POWER_METRIC },
691  { {6109, 13}, STR_UNITS_POWER_SI },
692 };
693 
695 static const UnitsLong _units_weight[] = {
696  { {4515, 12}, STR_UNITS_WEIGHT_SHORT_IMPERIAL, STR_UNITS_WEIGHT_LONG_IMPERIAL },
697  { { 1, 0}, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC },
698  { {1000, 0}, STR_UNITS_WEIGHT_SHORT_SI, STR_UNITS_WEIGHT_LONG_SI },
699 };
700 
702 static const UnitsLong _units_volume[] = {
703  { {4227, 4}, STR_UNITS_VOLUME_SHORT_IMPERIAL, STR_UNITS_VOLUME_LONG_IMPERIAL },
704  { {1000, 0}, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC },
705  { { 1, 0}, STR_UNITS_VOLUME_SHORT_SI, STR_UNITS_VOLUME_LONG_SI },
706 };
707 
709 static const Units _units_force[] = {
710  { {3597, 4}, STR_UNITS_FORCE_IMPERIAL },
711  { {3263, 5}, STR_UNITS_FORCE_METRIC },
712  { { 1, 0}, STR_UNITS_FORCE_SI },
713 };
714 
716 static const Units _units_height[] = {
717  { { 3, 0}, STR_UNITS_HEIGHT_IMPERIAL }, // "Wrong" conversion factor for more nicer GUI values
718  { { 1, 0}, STR_UNITS_HEIGHT_METRIC },
719  { { 1, 0}, STR_UNITS_HEIGHT_SI },
720 };
721 
728 {
729  /* For historical reasons we don't want to mess with the
730  * conversion for speed. So, don't round it and keep the
731  * original conversion factors instead of the real ones. */
732  return _units_velocity[_settings_game.locale.units_velocity].c.ToDisplay(speed, false);
733 }
734 
741 {
742  return _units_velocity[_settings_game.locale.units_velocity].c.FromDisplay(speed);
743 }
744 
751 {
752  return _units_velocity[_settings_game.locale.units_velocity].c.ToDisplay(speed * 10, false) / 16;
753 }
754 
761 {
762  return _units_velocity[_settings_game.locale.units_velocity].c.FromDisplay(speed * 16, true, 10);
763 }
772 static char *FormatString(char *buff, const char *str_arg, StringParameters *args, const char *last, uint case_index, bool game_script, bool dry_run)
773 {
774  uint orig_offset = args->offset;
775 
776  /* When there is no array with types there is no need to do a dry run. */
777  if (args->HasTypeInformation() && !dry_run) {
778  if (UsingNewGRFTextStack()) {
779  /* Values from the NewGRF text stack are only copied to the normal
780  * argv array at the time they are encountered. That means that if
781  * another string command references a value later in the string it
782  * would fail. We solve that by running FormatString twice. The first
783  * pass makes sure the argv array is correctly filled and the second
784  * pass can reference later values without problems. */
785  struct TextRefStack *backup = CreateTextRefStackBackup();
786  FormatString(buff, str_arg, args, last, case_index, game_script, true);
788  } else {
789  FormatString(buff, str_arg, args, last, case_index, game_script, true);
790  }
791  /* We have to restore the original offset here to to read the correct values. */
792  args->offset = orig_offset;
793  }
794  WChar b = '\0';
795  uint next_substr_case_index = 0;
796  char *buf_start = buff;
797  std::stack<const char *, std::vector<const char *>> str_stack;
798  str_stack.push(str_arg);
799 
800  for (;;) {
801  while (!str_stack.empty() && (b = Utf8Consume(&str_stack.top())) == '\0') {
802  str_stack.pop();
803  }
804  if (str_stack.empty()) break;
805  const char *&str = str_stack.top();
806 
807  if (SCC_NEWGRF_FIRST <= b && b <= SCC_NEWGRF_LAST) {
808  /* We need to pass some stuff as it might be modified; oh boy. */
809  //todo: should argve be passed here too?
810  b = RemapNewGRFStringControlCode(b, buf_start, &buff, &str, (int64 *)args->GetDataPointer(), args->GetDataLeft(), dry_run);
811  if (b == 0) continue;
812  }
813 
814  switch (b) {
815  case SCC_ENCODED: {
816  uint64 sub_args_data[20];
817  WChar sub_args_type[20];
818  bool sub_args_need_free[20];
819  StringParameters sub_args(sub_args_data, 20, sub_args_type);
820 
821  sub_args.ClearTypeInformation();
822  memset(sub_args_need_free, 0, sizeof(sub_args_need_free));
823 
824  char *p;
825  uint32 stringid = strtoul(str, &p, 16);
826  if (*p != ':' && *p != '\0') {
827  while (*p != '\0') p++;
828  str = p;
829  buff = strecat(buff, "(invalid SCC_ENCODED)", last);
830  break;
831  }
832  if (stringid >= TAB_SIZE_GAMESCRIPT) {
833  while (*p != '\0') p++;
834  str = p;
835  buff = strecat(buff, "(invalid StringID)", last);
836  break;
837  }
838 
839  int i = 0;
840  while (*p != '\0' && i < 20) {
841  uint64 param;
842  const char *s = ++p;
843 
844  /* Find the next value */
845  bool instring = false;
846  bool escape = false;
847  for (;; p++) {
848  if (*p == '\\') {
849  escape = true;
850  continue;
851  }
852  if (*p == '"' && escape) {
853  escape = false;
854  continue;
855  }
856  escape = false;
857 
858  if (*p == '"') {
859  instring = !instring;
860  continue;
861  }
862  if (instring) {
863  continue;
864  }
865 
866  if (*p == ':') break;
867  if (*p == '\0') break;
868  }
869 
870  if (*s != '"') {
871  /* Check if we want to look up another string */
872  WChar l;
873  size_t len = Utf8Decode(&l, s);
874  bool lookup = (l == SCC_ENCODED);
875  if (lookup) s += len;
876 
877  param = strtoull(s, &p, 16);
878 
879  if (lookup) {
880  if (param >= TAB_SIZE_GAMESCRIPT) {
881  while (*p != '\0') p++;
882  str = p;
883  buff = strecat(buff, "(invalid sub-StringID)", last);
884  break;
885  }
886  param = MakeStringID(TEXT_TAB_GAMESCRIPT_START, param);
887  }
888 
889  sub_args.SetParam(i++, param);
890  } else {
891  char *g = stredup(s);
892  g[p - s] = '\0';
893 
894  sub_args_need_free[i] = true;
895  sub_args.SetParam(i++, (uint64)(size_t)g);
896  }
897  }
898  /* If we didn't error out, we can actually print the string. */
899  if (*str != '\0') {
900  str = p;
901  buff = GetStringWithArgs(buff, MakeStringID(TEXT_TAB_GAMESCRIPT_START, stringid), &sub_args, last, true);
902  }
903 
904  for (int i = 0; i < 20; i++) {
905  if (sub_args_need_free[i]) free((void *)sub_args.GetParam(i));
906  }
907  break;
908  }
909 
910  case SCC_NEWGRF_STRINL: {
911  StringID substr = Utf8Consume(&str);
912  str_stack.push(GetStringPtr(substr));
913  break;
914  }
915 
918  str_stack.push(GetStringPtr(substr));
919  case_index = next_substr_case_index;
920  next_substr_case_index = 0;
921  break;
922  }
923 
924 
925  case SCC_GENDER_LIST: { // {G 0 Der Die Das}
926  /* First read the meta data from the language file. */
927  uint offset = orig_offset + (byte)*str++;
928  int gender = 0;
929  if (!dry_run && args->GetTypeAtOffset(offset) != 0) {
930  /* Now we need to figure out what text to resolve, i.e.
931  * what do we need to draw? So get the actual raw string
932  * first using the control code to get said string. */
933  char input[4 + 1];
934  char *p = input + Utf8Encode(input, args->GetTypeAtOffset(offset));
935  *p = '\0';
936 
937  /* Now do the string formatting. */
938  char buf[256];
939  bool old_sgd = _scan_for_gender_data;
940  _scan_for_gender_data = true;
941  StringParameters tmp_params(args->GetPointerToOffset(offset), args->num_param - offset, NULL);
942  p = FormatString(buf, input, &tmp_params, lastof(buf));
943  _scan_for_gender_data = old_sgd;
944  *p = '\0';
945 
946  /* And determine the string. */
947  const char *s = buf;
948  WChar c = Utf8Consume(&s);
949  /* Does this string have a gender, if so, set it */
950  if (c == SCC_GENDER_INDEX) gender = (byte)s[0];
951  }
952  str = ParseStringChoice(str, gender, &buff, last);
953  break;
954  }
955 
956  /* This sets up the gender for the string.
957  * We just ignore this one. It's used in {G 0 Der Die Das} to determine the case. */
958  case SCC_GENDER_INDEX: // {GENDER 0}
959  if (_scan_for_gender_data) {
960  buff += Utf8Encode(buff, SCC_GENDER_INDEX);
961  *buff++ = *str++;
962  } else {
963  str++;
964  }
965  break;
966 
967  case SCC_PLURAL_LIST: { // {P}
968  int plural_form = *str++; // contains the plural form for this string
969  uint offset = orig_offset + (byte)*str++;
970  int64 v = *args->GetPointerToOffset(offset); // contains the number that determines plural
971  str = ParseStringChoice(str, DeterminePluralForm(v, plural_form), &buff, last);
972  break;
973  }
974 
975  case SCC_ARG_INDEX: { // Move argument pointer
976  args->offset = orig_offset + (byte)*str++;
977  break;
978  }
979 
980  case SCC_SET_CASE: { // {SET_CASE}
981  /* This is a pseudo command, it's outputted when someone does {STRING.ack}
982  * The modifier is added to all subsequent GetStringWithArgs that accept the modifier. */
983  next_substr_case_index = (byte)*str++;
984  break;
985  }
986 
987  case SCC_SWITCH_CASE: { // {Used to implement case switching}
988  /* <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT>
989  * Each LEN is printed using 2 bytes in big endian order. */
990  uint num = (byte)*str++;
991  while (num) {
992  if ((byte)str[0] == case_index) {
993  /* Found the case, adjust str pointer and continue */
994  str += 3;
995  break;
996  }
997  /* Otherwise skip to the next case */
998  str += 3 + (str[1] << 8) + str[2];
999  num--;
1000  }
1001  break;
1002  }
1003 
1004  case SCC_REVISION: // {REV}
1005  buff = strecpy(buff, _openttd_revision, last);
1006  break;
1007 
1008  case SCC_RAW_STRING_POINTER: { // {RAW_STRING}
1009  if (game_script) break;
1010  const char *str = (const char *)(size_t)args->GetInt64(SCC_RAW_STRING_POINTER);
1011  buff = FormatString(buff, str, args, last);
1012  break;
1013  }
1014 
1015  case SCC_STRING: {// {STRING}
1016  StringID str = args->GetInt32(SCC_STRING);
1017  if (game_script && GetStringTab(str) != TEXT_TAB_GAMESCRIPT_START) break;
1018  /* WARNING. It's prohibited for the included string to consume any arguments.
1019  * For included strings that consume argument, you should use STRING1, STRING2 etc.
1020  * To debug stuff you can set argv to NULL and it will tell you */
1021  StringParameters tmp_params(args->GetDataPointer(), args->GetDataLeft(), NULL);
1022  buff = GetStringWithArgs(buff, str, &tmp_params, last, next_substr_case_index, game_script);
1023  next_substr_case_index = 0;
1024  break;
1025  }
1026 
1027  case SCC_STRING1:
1028  case SCC_STRING2:
1029  case SCC_STRING3:
1030  case SCC_STRING4:
1031  case SCC_STRING5:
1032  case SCC_STRING6:
1033  case SCC_STRING7: { // {STRING1..7}
1034  /* Strings that consume arguments */
1035  StringID str = args->GetInt32(b);
1036  if (game_script && GetStringTab(str) != TEXT_TAB_GAMESCRIPT_START) break;
1037  uint size = b - SCC_STRING1 + 1;
1038  if (game_script && size > args->GetDataLeft()) {
1039  buff = strecat(buff, "(too many parameters)", last);
1040  } else {
1041  StringParameters sub_args(*args, size);
1042  buff = GetStringWithArgs(buff, str, &sub_args, last, next_substr_case_index, game_script);
1043  }
1044  next_substr_case_index = 0;
1045  break;
1046  }
1047 
1048  case SCC_COMMA: // {COMMA}
1049  buff = FormatCommaNumber(buff, args->GetInt64(SCC_COMMA), last);
1050  break;
1051 
1052  case SCC_DECIMAL: {// {DECIMAL}
1053  int64 number = args->GetInt64(SCC_DECIMAL);
1054  int digits = args->GetInt32(SCC_DECIMAL);
1055  buff = FormatCommaNumber(buff, number, last, digits);
1056  break;
1057  }
1058 
1059  case SCC_NUM: // {NUM}
1060  buff = FormatNoCommaNumber(buff, args->GetInt64(SCC_NUM), last);
1061  break;
1062 
1063  case SCC_ZEROFILL_NUM: { // {ZEROFILL_NUM}
1064  int64 num = args->GetInt64();
1065  buff = FormatZerofillNumber(buff, num, args->GetInt64(), last);
1066  break;
1067  }
1068 
1069  case SCC_HEX: // {HEX}
1070  buff = FormatHexNumber(buff, (uint64)args->GetInt64(SCC_HEX), last);
1071  break;
1072 
1073  case SCC_BYTES: // {BYTES}
1074  buff = FormatBytes(buff, args->GetInt64(), last);
1075  break;
1076 
1077  case SCC_CARGO_TINY: { // {CARGO_TINY}
1078  /* Tiny description of cargotypes. Layout:
1079  * param 1: cargo type
1080  * param 2: cargo count */
1081  CargoID cargo = args->GetInt32(SCC_CARGO_TINY);
1082  if (cargo >= CargoSpec::GetArraySize()) break;
1083 
1084  StringID cargo_str = CargoSpec::Get(cargo)->units_volume;
1085  int64 amount = 0;
1086  switch (cargo_str) {
1087  case STR_TONS:
1088  amount = _units_weight[_settings_game.locale.units_weight].c.ToDisplay(args->GetInt64());
1089  break;
1090 
1091  case STR_LITERS:
1092  amount = _units_volume[_settings_game.locale.units_volume].c.ToDisplay(args->GetInt64());
1093  break;
1094 
1095  default: {
1096  amount = args->GetInt64();
1097  break;
1098  }
1099  }
1100 
1101  buff = FormatCommaNumber(buff, amount, last);
1102  break;
1103  }
1104 
1105  case SCC_CARGO_SHORT: { // {CARGO_SHORT}
1106  /* Short description of cargotypes. Layout:
1107  * param 1: cargo type
1108  * param 2: cargo count */
1109  CargoID cargo = args->GetInt32(SCC_CARGO_SHORT);
1110  if (cargo >= CargoSpec::GetArraySize()) break;
1111 
1112  StringID cargo_str = CargoSpec::Get(cargo)->units_volume;
1113  switch (cargo_str) {
1114  case STR_TONS: {
1115  assert(_settings_game.locale.units_weight < lengthof(_units_weight));
1116  int64 args_array[] = {_units_weight[_settings_game.locale.units_weight].c.ToDisplay(args->GetInt64())};
1117  StringParameters tmp_params(args_array);
1118  buff = FormatString(buff, GetStringPtr(_units_weight[_settings_game.locale.units_weight].l), &tmp_params, last);
1119  break;
1120  }
1121 
1122  case STR_LITERS: {
1123  assert(_settings_game.locale.units_volume < lengthof(_units_volume));
1124  int64 args_array[] = {_units_volume[_settings_game.locale.units_volume].c.ToDisplay(args->GetInt64())};
1125  StringParameters tmp_params(args_array);
1126  buff = FormatString(buff, GetStringPtr(_units_volume[_settings_game.locale.units_volume].l), &tmp_params, last);
1127  break;
1128  }
1129 
1130  default: {
1131  StringParameters tmp_params(*args, 1);
1132  buff = GetStringWithArgs(buff, cargo_str, &tmp_params, last);
1133  break;
1134  }
1135  }
1136  break;
1137  }
1138 
1139  case SCC_CARGO_LONG: { // {CARGO_LONG}
1140  /* First parameter is cargo type, second parameter is cargo count */
1141  CargoID cargo = args->GetInt32(SCC_CARGO_LONG);
1142  if (cargo != CT_INVALID && cargo >= CargoSpec::GetArraySize()) break;
1143 
1144  StringID cargo_str = (cargo == CT_INVALID) ? STR_QUANTITY_N_A : CargoSpec::Get(cargo)->quantifier;
1145  StringParameters tmp_args(*args, 1);
1146  buff = GetStringWithArgs(buff, cargo_str, &tmp_args, last);
1147  break;
1148  }
1149 
1150  case SCC_CARGO_LIST: { // {CARGO_LIST}
1151  CargoTypes cmask = args->GetInt64(SCC_CARGO_LIST);
1152  bool first = true;
1153 
1154  const CargoSpec *cs;
1156  if (!HasBit(cmask, cs->Index())) continue;
1157 
1158  if (buff >= last - 2) break; // ',' and ' '
1159 
1160  if (first) {
1161  first = false;
1162  } else {
1163  /* Add a comma if this is not the first item */
1164  *buff++ = ',';
1165  *buff++ = ' ';
1166  }
1167 
1168  buff = GetStringWithArgs(buff, cs->name, args, last, next_substr_case_index, game_script);
1169  }
1170 
1171  /* If first is still true then no cargo is accepted */
1172  if (first) buff = GetStringWithArgs(buff, STR_JUST_NOTHING, args, last, next_substr_case_index, game_script);
1173 
1174  *buff = '\0';
1175  next_substr_case_index = 0;
1176 
1177  /* Make sure we detect any buffer overflow */
1178  assert(buff < last);
1179  break;
1180  }
1181 
1182  case SCC_CURRENCY_SHORT: // {CURRENCY_SHORT}
1183  buff = FormatGenericCurrency(buff, _currency, args->GetInt64(), true, last);
1184  break;
1185 
1186  case SCC_CURRENCY_LONG: // {CURRENCY_LONG}
1187  buff = FormatGenericCurrency(buff, _currency, args->GetInt64(SCC_CURRENCY_LONG), false, last);
1188  break;
1189 
1190  case SCC_DATE_TINY: // {DATE_TINY}
1191  buff = FormatTinyOrISODate(buff, args->GetInt32(SCC_DATE_TINY), STR_FORMAT_DATE_TINY, last);
1192  break;
1193 
1194  case SCC_DATE_SHORT: // {DATE_SHORT}
1195  buff = FormatMonthAndYear(buff, args->GetInt32(SCC_DATE_SHORT), last, next_substr_case_index);
1196  next_substr_case_index = 0;
1197  break;
1198 
1199  case SCC_DATE_LONG: // {DATE_LONG}
1200  buff = FormatYmdString(buff, args->GetInt32(SCC_DATE_LONG), last, next_substr_case_index);
1201  next_substr_case_index = 0;
1202  break;
1203 
1204  case SCC_DATE_ISO: // {DATE_ISO}
1205  buff = FormatTinyOrISODate(buff, args->GetInt32(), STR_FORMAT_DATE_ISO, last);
1206  break;
1207 
1208  case SCC_FORCE: { // {FORCE}
1209  assert(_settings_game.locale.units_force < lengthof(_units_force));
1210  int64 args_array[1] = {_units_force[_settings_game.locale.units_force].c.ToDisplay(args->GetInt64())};
1211  StringParameters tmp_params(args_array);
1212  buff = FormatString(buff, GetStringPtr(_units_force[_settings_game.locale.units_force].s), &tmp_params, last);
1213  break;
1214  }
1215 
1216  case SCC_HEIGHT: { // {HEIGHT}
1217  assert(_settings_game.locale.units_height < lengthof(_units_height));
1218  int64 args_array[] = {_units_height[_settings_game.locale.units_height].c.ToDisplay(args->GetInt64())};
1219  StringParameters tmp_params(args_array);
1220  buff = FormatString(buff, GetStringPtr(_units_height[_settings_game.locale.units_height].s), &tmp_params, last);
1221  break;
1222  }
1223 
1224  case SCC_POWER: { // {POWER}
1225  assert(_settings_game.locale.units_power < lengthof(_units_power));
1226  int64 args_array[1] = {_units_power[_settings_game.locale.units_power].c.ToDisplay(args->GetInt64())};
1227  StringParameters tmp_params(args_array);
1228  buff = FormatString(buff, GetStringPtr(_units_power[_settings_game.locale.units_power].s), &tmp_params, last);
1229  break;
1230  }
1231 
1232  case SCC_VELOCITY: { // {VELOCITY}
1233  assert(_settings_game.locale.units_velocity < lengthof(_units_velocity));
1234  int64 args_array[] = {ConvertKmhishSpeedToDisplaySpeed(args->GetInt64(SCC_VELOCITY))};
1235  StringParameters tmp_params(args_array);
1236  buff = FormatString(buff, GetStringPtr(_units_velocity[_settings_game.locale.units_velocity].s), &tmp_params, last);
1237  break;
1238  }
1239 
1240  case SCC_VOLUME_SHORT: { // {VOLUME_SHORT}
1241  assert(_settings_game.locale.units_volume < lengthof(_units_volume));
1242  int64 args_array[1] = {_units_volume[_settings_game.locale.units_volume].c.ToDisplay(args->GetInt64())};
1243  StringParameters tmp_params(args_array);
1244  buff = FormatString(buff, GetStringPtr(_units_volume[_settings_game.locale.units_volume].s), &tmp_params, last);
1245  break;
1246  }
1247 
1248  case SCC_VOLUME_LONG: { // {VOLUME_LONG}
1249  assert(_settings_game.locale.units_volume < lengthof(_units_volume));
1250  int64 args_array[1] = {_units_volume[_settings_game.locale.units_volume].c.ToDisplay(args->GetInt64(SCC_VOLUME_LONG))};
1251  StringParameters tmp_params(args_array);
1252  buff = FormatString(buff, GetStringPtr(_units_volume[_settings_game.locale.units_volume].l), &tmp_params, last);
1253  break;
1254  }
1255 
1256  case SCC_WEIGHT_SHORT: { // {WEIGHT_SHORT}
1257  assert(_settings_game.locale.units_weight < lengthof(_units_weight));
1258  int64 args_array[1] = {_units_weight[_settings_game.locale.units_weight].c.ToDisplay(args->GetInt64())};
1259  StringParameters tmp_params(args_array);
1260  buff = FormatString(buff, GetStringPtr(_units_weight[_settings_game.locale.units_weight].s), &tmp_params, last);
1261  break;
1262  }
1263 
1264  case SCC_WEIGHT_LONG: { // {WEIGHT_LONG}
1265  assert(_settings_game.locale.units_weight < lengthof(_units_weight));
1266  int64 args_array[1] = {_units_weight[_settings_game.locale.units_weight].c.ToDisplay(args->GetInt64(SCC_WEIGHT_LONG))};
1267  StringParameters tmp_params(args_array);
1268  buff = FormatString(buff, GetStringPtr(_units_weight[_settings_game.locale.units_weight].l), &tmp_params, last);
1269  break;
1270  }
1271 
1272  case SCC_COMPANY_NAME: { // {COMPANY}
1273  const Company *c = Company::GetIfValid(args->GetInt32());
1274  if (c == NULL) break;
1275 
1276  if (c->name != NULL) {
1277  int64 args_array[] = {(int64)(size_t)c->name};
1278  StringParameters tmp_params(args_array);
1279  buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
1280  } else {
1281  int64 args_array[] = {c->name_2};
1282  StringParameters tmp_params(args_array);
1283  buff = GetStringWithArgs(buff, c->name_1, &tmp_params, last);
1284  }
1285  break;
1286  }
1287 
1288  case SCC_COMPANY_NUM: { // {COMPANY_NUM}
1289  CompanyID company = (CompanyID)args->GetInt32();
1290 
1291  /* Nothing is added for AI or inactive companies */
1292  if (Company::IsValidHumanID(company)) {
1293  int64 args_array[] = {company + 1};
1294  StringParameters tmp_params(args_array);
1295  buff = GetStringWithArgs(buff, STR_FORMAT_COMPANY_NUM, &tmp_params, last);
1296  }
1297  break;
1298  }
1299 
1300  case SCC_DEPOT_NAME: { // {DEPOT}
1301  VehicleType vt = (VehicleType)args->GetInt32(SCC_DEPOT_NAME);
1302  if (vt == VEH_AIRCRAFT) {
1303  uint64 args_array[] = {(uint64)args->GetInt32()};
1304  WChar types_array[] = {SCC_STATION_NAME};
1305  StringParameters tmp_params(args_array, 1, types_array);
1306  buff = GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_AIRCRAFT, &tmp_params, last);
1307  break;
1308  }
1309 
1310  const Depot *d = Depot::Get(args->GetInt32());
1311  if (d->name != NULL) {
1312  int64 args_array[] = {(int64)(size_t)d->name};
1313  StringParameters tmp_params(args_array);
1314  buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
1315  } else {
1316  int64 args_array[] = {d->town->index, d->town_cn + 1};
1317  StringParameters tmp_params(args_array);
1318  buff = GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_TRAIN + 2 * vt + (d->town_cn == 0 ? 0 : 1), &tmp_params, last);
1319  }
1320  break;
1321  }
1322 
1323  case SCC_ENGINE_NAME: { // {ENGINE}
1324  const Engine *e = Engine::GetIfValid(args->GetInt32(SCC_ENGINE_NAME));
1325  if (e == NULL) break;
1326 
1327  if (e->name != NULL && e->IsEnabled()) {
1328  int64 args_array[] = {(int64)(size_t)e->name};
1329  StringParameters tmp_params(args_array);
1330  buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
1331  } else {
1332  StringParameters tmp_params(NULL, 0, NULL);
1333  buff = GetStringWithArgs(buff, e->info.string_id, &tmp_params, last);
1334  }
1335  break;
1336  }
1337 
1338  case SCC_GROUP_NAME: { // {GROUP}
1339  const Group *g = Group::GetIfValid(args->GetInt32());
1340  if (g == NULL) break;
1341 
1342  if (g->name != NULL) {
1343  int64 args_array[] = {(int64)(size_t)g->name};
1344  StringParameters tmp_params(args_array);
1345  buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
1346  } else {
1347  int64 args_array[] = {g->index};
1348  StringParameters tmp_params(args_array);
1349 
1350  buff = GetStringWithArgs(buff, STR_FORMAT_GROUP_NAME, &tmp_params, last);
1351  }
1352  break;
1353  }
1354 
1355  case SCC_INDUSTRY_NAME: { // {INDUSTRY}
1356  const Industry *i = Industry::GetIfValid(args->GetInt32(SCC_INDUSTRY_NAME));
1357  if (i == NULL) break;
1358 
1359  if (_scan_for_gender_data) {
1360  /* Gender is defined by the industry type.
1361  * STR_FORMAT_INDUSTRY_NAME may have the town first, so it would result in the gender of the town name */
1362  StringParameters tmp_params(NULL, 0, NULL);
1363  buff = FormatString(buff, GetStringPtr(GetIndustrySpec(i->type)->name), &tmp_params, last, next_substr_case_index);
1364  } else {
1365  /* First print the town name and the industry type name. */
1366  int64 args_array[2] = {i->town->index, GetIndustrySpec(i->type)->name};
1367  StringParameters tmp_params(args_array);
1368 
1369  buff = FormatString(buff, GetStringPtr(STR_FORMAT_INDUSTRY_NAME), &tmp_params, last, next_substr_case_index);
1370  }
1371  next_substr_case_index = 0;
1372  break;
1373  }
1374 
1375  case SCC_PRESIDENT_NAME: { // {PRESIDENT_NAME}
1376  const Company *c = Company::GetIfValid(args->GetInt32(SCC_PRESIDENT_NAME));
1377  if (c == NULL) break;
1378 
1379  if (c->president_name != NULL) {
1380  int64 args_array[] = {(int64)(size_t)c->president_name};
1381  StringParameters tmp_params(args_array);
1382  buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
1383  } else {
1384  int64 args_array[] = {c->president_name_2};
1385  StringParameters tmp_params(args_array);
1386  buff = GetStringWithArgs(buff, c->president_name_1, &tmp_params, last);
1387  }
1388  break;
1389  }
1390 
1391  case SCC_STATION_NAME: { // {STATION}
1392  StationID sid = args->GetInt32(SCC_STATION_NAME);
1393  const Station *st = Station::GetIfValid(sid);
1394 
1395  if (st == NULL) {
1396  /* The station doesn't exist anymore. The only place where we might
1397  * be "drawing" an invalid station is in the case of cargo that is
1398  * in transit. */
1399  StringParameters tmp_params(NULL, 0, NULL);
1400  buff = GetStringWithArgs(buff, STR_UNKNOWN_STATION, &tmp_params, last);
1401  break;
1402  }
1403 
1404  if (st->name != NULL) {
1405  int64 args_array[] = {(int64)(size_t)st->name};
1406  StringParameters tmp_params(args_array);
1407  buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
1408  } else {
1409  StringID str = st->string_id;
1410  if (st->indtype != IT_INVALID) {
1411  /* Special case where the industry provides the name for the station */
1412  const IndustrySpec *indsp = GetIndustrySpec(st->indtype);
1413 
1414  /* Industry GRFs can change which might remove the station name and
1415  * thus cause very strange things. Here we check for that before we
1416  * actually set the station name. */
1417  if (indsp->station_name != STR_NULL && indsp->station_name != STR_UNDEFINED) {
1418  str = indsp->station_name;
1419  }
1420  }
1421 
1422  uint64 args_array[] = {STR_TOWN_NAME, st->town->index, st->index};
1423  WChar types_array[] = {0, SCC_TOWN_NAME, SCC_NUM};
1424  StringParameters tmp_params(args_array, 3, types_array);
1425  buff = GetStringWithArgs(buff, str, &tmp_params, last);
1426  }
1427  break;
1428  }
1429 
1430  case SCC_TOWN_NAME: { // {TOWN}
1431  const Town *t = Town::GetIfValid(args->GetInt32(SCC_TOWN_NAME));
1432  if (t == NULL) break;
1433 
1434  if (t->name != NULL) {
1435  int64 args_array[] = {(int64)(size_t)t->name};
1436  StringParameters tmp_params(args_array);
1437  buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
1438  } else {
1439  buff = GetTownName(buff, t, last);
1440  }
1441  break;
1442  }
1443 
1444  case SCC_WAYPOINT_NAME: { // {WAYPOINT}
1445  Waypoint *wp = Waypoint::GetIfValid(args->GetInt32(SCC_WAYPOINT_NAME));
1446  if (wp == NULL) break;
1447 
1448  if (wp->name != NULL) {
1449  int64 args_array[] = {(int64)(size_t)wp->name};
1450  StringParameters tmp_params(args_array);
1451  buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
1452  } else {
1453  int64 args_array[] = {wp->town->index, wp->town_cn + 1};
1454  StringParameters tmp_params(args_array);
1455  StringID str = ((wp->string_id == STR_SV_STNAME_BUOY) ? STR_FORMAT_BUOY_NAME : STR_FORMAT_WAYPOINT_NAME);
1456  if (wp->town_cn != 0) str++;
1457  buff = GetStringWithArgs(buff, str, &tmp_params, last);
1458  }
1459  break;
1460  }
1461 
1462  case SCC_VEHICLE_NAME: { // {VEHICLE}
1463  const Vehicle *v = Vehicle::GetIfValid(args->GetInt32(SCC_VEHICLE_NAME));
1464  if (v == NULL) break;
1465 
1466  if (v->name != NULL) {
1467  int64 args_array[] = {(int64)(size_t)v->name};
1468  StringParameters tmp_params(args_array);
1469  buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
1470  } else {
1471  int64 args_array[] = {v->unitnumber};
1472  StringParameters tmp_params(args_array);
1473 
1474  StringID str;
1475  switch (v->type) {
1476  default: str = STR_INVALID_VEHICLE; break;
1477  case VEH_TRAIN: str = STR_SV_TRAIN_NAME; break;
1478  case VEH_ROAD: str = STR_SV_ROAD_VEHICLE_NAME; break;
1479  case VEH_SHIP: str = STR_SV_SHIP_NAME; break;
1480  case VEH_AIRCRAFT: str = STR_SV_AIRCRAFT_NAME; break;
1481  }
1482 
1483  buff = GetStringWithArgs(buff, str, &tmp_params, last);
1484  }
1485  break;
1486  }
1487 
1488  case SCC_SIGN_NAME: { // {SIGN}
1489  const Sign *si = Sign::GetIfValid(args->GetInt32());
1490  if (si == NULL) break;
1491 
1492  if (si->name != NULL) {
1493  int64 args_array[] = {(int64)(size_t)si->name};
1494  StringParameters tmp_params(args_array);
1495  buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last);
1496  } else {
1497  StringParameters tmp_params(NULL, 0, NULL);
1498  buff = GetStringWithArgs(buff, STR_DEFAULT_SIGN_NAME, &tmp_params, last);
1499  }
1500  break;
1501  }
1502 
1503  case SCC_STATION_FEATURES: { // {STATIONFEATURES}
1504  buff = StationGetSpecialString(buff, args->GetInt32(SCC_STATION_FEATURES), last);
1505  break;
1506  }
1507 
1508  default:
1509  if (buff + Utf8CharLen(b) < last) buff += Utf8Encode(buff, b);
1510  break;
1511  }
1512  }
1513  *buff = '\0';
1514  return buff;
1515 }
1516 
1517 
1518 static char *StationGetSpecialString(char *buff, int x, const char *last)
1519 {
1520  if ((x & FACIL_TRAIN) && (buff + Utf8CharLen(SCC_TRAIN) < last)) buff += Utf8Encode(buff, SCC_TRAIN);
1521  if ((x & FACIL_TRUCK_STOP) && (buff + Utf8CharLen(SCC_LORRY) < last)) buff += Utf8Encode(buff, SCC_LORRY);
1522  if ((x & FACIL_BUS_STOP) && (buff + Utf8CharLen(SCC_BUS) < last)) buff += Utf8Encode(buff, SCC_BUS);
1523  if ((x & FACIL_DOCK) && (buff + Utf8CharLen(SCC_SHIP) < last)) buff += Utf8Encode(buff, SCC_SHIP);
1524  if ((x & FACIL_AIRPORT) && (buff + Utf8CharLen(SCC_PLANE) < last)) buff += Utf8Encode(buff, SCC_PLANE);
1525  *buff = '\0';
1526  return buff;
1527 }
1528 
1529 static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last)
1530 {
1531  return GenerateTownNameString(buff, last, ind, seed);
1532 }
1533 
1534 static const char * const _silly_company_names[] = {
1535  "Bloggs Brothers",
1536  "Tiny Transport Ltd.",
1537  "Express Travel",
1538  "Comfy-Coach & Co.",
1539  "Crush & Bump Ltd.",
1540  "Broken & Late Ltd.",
1541  "Sam Speedy & Son",
1542  "Supersonic Travel",
1543  "Mike's Motors",
1544  "Lightning International",
1545  "Pannik & Loozit Ltd.",
1546  "Inter-City Transport",
1547  "Getout & Pushit Ltd."
1548 };
1549 
1550 static const char * const _surname_list[] = {
1551  "Adams",
1552  "Allan",
1553  "Baker",
1554  "Bigwig",
1555  "Black",
1556  "Bloggs",
1557  "Brown",
1558  "Campbell",
1559  "Gordon",
1560  "Hamilton",
1561  "Hawthorn",
1562  "Higgins",
1563  "Green",
1564  "Gribble",
1565  "Jones",
1566  "McAlpine",
1567  "MacDonald",
1568  "McIntosh",
1569  "Muir",
1570  "Murphy",
1571  "Nelson",
1572  "O'Donnell",
1573  "Parker",
1574  "Phillips",
1575  "Pilkington",
1576  "Quigley",
1577  "Sharkey",
1578  "Thomson",
1579  "Watkins"
1580 };
1581 
1582 static const char * const _silly_surname_list[] = {
1583  "Grumpy",
1584  "Dozy",
1585  "Speedy",
1586  "Nosey",
1587  "Dribble",
1588  "Mushroom",
1589  "Cabbage",
1590  "Sniffle",
1591  "Fishy",
1592  "Swindle",
1593  "Sneaky",
1594  "Nutkins"
1595 };
1596 
1597 static const char _initial_name_letters[] = {
1598  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
1599  'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'W',
1600 };
1601 
1602 static char *GenAndCoName(char *buff, uint32 arg, const char *last)
1603 {
1604  const char * const *base;
1605  uint num;
1606 
1607  if (_settings_game.game_creation.landscape == LT_TOYLAND) {
1608  base = _silly_surname_list;
1609  num = lengthof(_silly_surname_list);
1610  } else {
1611  base = _surname_list;
1612  num = lengthof(_surname_list);
1613  }
1614 
1615  buff = strecpy(buff, base[num * GB(arg, 16, 8) >> 8], last);
1616  buff = strecpy(buff, " & Co.", last);
1617 
1618  return buff;
1619 }
1620 
1621 static char *GenPresidentName(char *buff, uint32 x, const char *last)
1622 {
1623  char initial[] = "?. ";
1624  const char * const *base;
1625  uint num;
1626  uint i;
1627 
1628  initial[0] = _initial_name_letters[sizeof(_initial_name_letters) * GB(x, 0, 8) >> 8];
1629  buff = strecpy(buff, initial, last);
1630 
1631  i = (sizeof(_initial_name_letters) + 35) * GB(x, 8, 8) >> 8;
1632  if (i < sizeof(_initial_name_letters)) {
1633  initial[0] = _initial_name_letters[i];
1634  buff = strecpy(buff, initial, last);
1635  }
1636 
1637  if (_settings_game.game_creation.landscape == LT_TOYLAND) {
1638  base = _silly_surname_list;
1639  num = lengthof(_silly_surname_list);
1640  } else {
1641  base = _surname_list;
1642  num = lengthof(_surname_list);
1643  }
1644 
1645  buff = strecpy(buff, base[num * GB(x, 16, 8) >> 8], last);
1646 
1647  return buff;
1648 }
1649 
1650 static char *GetSpecialNameString(char *buff, int ind, StringParameters *args, const char *last)
1651 {
1652  switch (ind) {
1653  case 1: // not used
1654  return strecpy(buff, _silly_company_names[min(args->GetInt32() & 0xFFFF, lengthof(_silly_company_names) - 1)], last);
1655 
1656  case 2: // used for Foobar & Co company names
1657  return GenAndCoName(buff, args->GetInt32(), last);
1658 
1659  case 3: // President name
1660  return GenPresidentName(buff, args->GetInt32(), last);
1661  }
1662 
1663  /* town name? */
1664  if (IsInsideMM(ind - 6, 0, SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1)) {
1665  buff = GetSpecialTownNameString(buff, ind - 6, args->GetInt32(), last);
1666  return strecpy(buff, " Transport", last);
1667  }
1668 
1669  /* language name? */
1670  if (IsInsideMM(ind, (SPECSTR_LANGUAGE_START - 0x70E4), (SPECSTR_LANGUAGE_END - 0x70E4) + 1)) {
1671  int i = ind - (SPECSTR_LANGUAGE_START - 0x70E4);
1672  return strecpy(buff,
1673  &_languages[i] == _current_language ? _current_language->own_name : _languages[i].name, last);
1674  }
1675 
1676  /* resolution size? */
1677  if (IsInsideMM(ind, (SPECSTR_RESOLUTION_START - 0x70E4), (SPECSTR_RESOLUTION_END - 0x70E4) + 1)) {
1678  int i = ind - (SPECSTR_RESOLUTION_START - 0x70E4);
1679  buff += seprintf(
1680  buff, last, "%ux%u", _resolutions[i].width, _resolutions[i].height
1681  );
1682  return buff;
1683  }
1684 
1685  NOT_REACHED();
1686 }
1687 
1688 #ifdef ENABLE_NETWORK
1689 extern void SortNetworkLanguages();
1690 #else /* ENABLE_NETWORK */
1691 static inline void SortNetworkLanguages() {}
1692 #endif /* ENABLE_NETWORK */
1693 
1699 {
1700  return this->ident == TO_LE32(LanguagePackHeader::IDENT) &&
1701  this->version == TO_LE32(LANGUAGE_PACK_VERSION) &&
1702  this->plural_form < LANGUAGE_MAX_PLURAL &&
1703  this->text_dir <= 1 &&
1704  this->newgrflangid < MAX_LANG &&
1705  this->num_genders < MAX_NUM_GENDERS &&
1706  this->num_cases < MAX_NUM_CASES &&
1707  StrValid(this->name, lastof(this->name)) &&
1708  StrValid(this->own_name, lastof(this->own_name)) &&
1709  StrValid(this->isocode, lastof(this->isocode)) &&
1710  StrValid(this->digit_group_separator, lastof(this->digit_group_separator)) &&
1711  StrValid(this->digit_group_separator_currency, lastof(this->digit_group_separator_currency)) &&
1712  StrValid(this->digit_decimal_separator, lastof(this->digit_decimal_separator));
1713 }
1714 
1721 {
1722  /* Current language pack */
1723  size_t len;
1724  LanguagePack *lang_pack = (LanguagePack *)ReadFileToMem(lang->file, &len, 1U << 20);
1725  if (lang_pack == NULL) return false;
1726 
1727  /* End of read data (+ terminating zero added in ReadFileToMem()) */
1728  const char *end = (char *)lang_pack + len + 1;
1729 
1730  /* We need at least one byte of lang_pack->data */
1731  if (end <= lang_pack->data || !lang_pack->IsValid()) {
1732  free(lang_pack);
1733  return false;
1734  }
1735 
1736 #if TTD_ENDIAN == TTD_BIG_ENDIAN
1737  for (uint i = 0; i < TEXT_TAB_END; i++) {
1738  lang_pack->offsets[i] = ReadLE16Aligned(&lang_pack->offsets[i]);
1739  }
1740 #endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */
1741 
1742  uint count = 0;
1743  for (uint i = 0; i < TEXT_TAB_END; i++) {
1744  uint16 num = lang_pack->offsets[i];
1745  if (num > TAB_SIZE) {
1746  free(lang_pack);
1747  return false;
1748  }
1749 
1750  _langtab_start[i] = count;
1751  _langtab_num[i] = num;
1752  count += num;
1753  }
1754 
1755  /* Allocate offsets */
1756  char **langpack_offs = MallocT<char *>(count);
1757 
1758  /* Fill offsets */
1759  char *s = lang_pack->data;
1760  len = (byte)*s++;
1761  for (uint i = 0; i < count; i++) {
1762  if (s + len >= end) {
1763  free(lang_pack);
1764  free(langpack_offs);
1765  return false;
1766  }
1767  if (len >= 0xC0) {
1768  len = ((len & 0x3F) << 8) + (byte)*s++;
1769  if (s + len >= end) {
1770  free(lang_pack);
1771  free(langpack_offs);
1772  return false;
1773  }
1774  }
1775  langpack_offs[i] = s;
1776  s += len;
1777  len = (byte)*s;
1778  *s++ = '\0'; // zero terminate the string
1779  }
1780 
1781  free(_langpack);
1782  _langpack = lang_pack;
1783 
1784  free(_langpack_offs);
1785  _langpack_offs = langpack_offs;
1786 
1787  _current_language = lang;
1788  _current_text_dir = (TextDirection)_current_language->text_dir;
1789  const char *c_file = strrchr(_current_language->file, PATHSEPCHAR) + 1;
1791  SetCurrentGrfLangID(_current_language->newgrflangid);
1792 
1793 #ifdef _WIN32
1794  extern void Win32SetCurrentLocaleName(const char *iso_code);
1795  Win32SetCurrentLocaleName(_current_language->isocode);
1796 #endif
1797 
1798 #ifdef WITH_COCOA
1799  extern void MacOSSetCurrentLocaleName(const char *iso_code);
1800  MacOSSetCurrentLocaleName(_current_language->isocode);
1801 #endif
1802 
1803 #ifdef WITH_ICU_SORT
1804  /* Delete previous collator. */
1805  if (_current_collator != NULL) {
1806  delete _current_collator;
1807  _current_collator = NULL;
1808  }
1809 
1810  /* Create a collator instance for our current locale. */
1811  UErrorCode status = U_ZERO_ERROR;
1812  _current_collator = icu::Collator::createInstance(icu::Locale(_current_language->isocode), status);
1813  /* Sort number substrings by their numerical value. */
1814  if (_current_collator != NULL) _current_collator->setAttribute(UCOL_NUMERIC_COLLATION, UCOL_ON, status);
1815  /* Avoid using the collator if it is not correctly set. */
1816  if (U_FAILURE(status)) {
1817  delete _current_collator;
1818  _current_collator = NULL;
1819  }
1820 #endif /* WITH_ICU_SORT */
1821 
1822  /* Some lists need to be sorted again after a language change. */
1827  SortNetworkLanguages();
1828 #ifdef ENABLE_NETWORK
1830 #endif /* ENABLE_NETWORK */
1831  InvalidateWindowClassesData(WC_BUILD_VEHICLE); // Build vehicle window.
1832  InvalidateWindowClassesData(WC_TRAINS_LIST); // Train group window.
1833  InvalidateWindowClassesData(WC_ROADVEH_LIST); // Road vehicle group window.
1834  InvalidateWindowClassesData(WC_SHIPS_LIST); // Ship group window.
1835  InvalidateWindowClassesData(WC_AIRCRAFT_LIST); // Aircraft group window.
1836  InvalidateWindowClassesData(WC_INDUSTRY_DIRECTORY); // Industry directory window.
1837  InvalidateWindowClassesData(WC_STATION_LIST); // Station list window.
1838 
1839  return true;
1840 }
1841 
1842 /* Win32 implementation in win32.cpp.
1843  * OS X implementation in os/macosx/macos.mm. */
1844 #if !(defined(_WIN32) || defined(__APPLE__))
1845 
1853 const char *GetCurrentLocale(const char *param)
1854 {
1855  const char *env;
1856 
1857  env = getenv("LANGUAGE");
1858  if (env != NULL) return env;
1859 
1860  env = getenv("LC_ALL");
1861  if (env != NULL) return env;
1862 
1863  if (param != NULL) {
1864  env = getenv(param);
1865  if (env != NULL) return env;
1866  }
1867 
1868  return getenv("LANG");
1869 }
1870 #else
1871 const char *GetCurrentLocale(const char *param);
1872 #endif /* !(defined(_WIN32) || defined(__APPLE__)) */
1873 
1874 int CDECL StringIDSorter(const StringID *a, const StringID *b)
1875 {
1876  char stra[512];
1877  char strb[512];
1878  GetString(stra, *a, lastof(stra));
1879  GetString(strb, *b, lastof(strb));
1880 
1881  return strnatcmp(stra, strb);
1882 }
1883 
1889 const LanguageMetadata *GetLanguage(byte newgrflangid)
1890 {
1891  for (const LanguageMetadata *lang = _languages.Begin(); lang != _languages.End(); lang++) {
1892  if (newgrflangid == lang->newgrflangid) return lang;
1893  }
1894 
1895  return NULL;
1896 }
1897 
1904 static bool GetLanguageFileHeader(const char *file, LanguagePackHeader *hdr)
1905 {
1906  FILE *f = fopen(file, "rb");
1907  if (f == NULL) return false;
1908 
1909  size_t read = fread(hdr, sizeof(*hdr), 1, f);
1910  fclose(f);
1911 
1912  bool ret = read == 1 && hdr->IsValid();
1913 
1914  /* Convert endianness for the windows language ID */
1915  if (ret) {
1916  hdr->missing = FROM_LE16(hdr->missing);
1917  hdr->winlangid = FROM_LE16(hdr->winlangid);
1918  }
1919  return ret;
1920 }
1921 
1926 static void GetLanguageList(const char *path)
1927 {
1928  DIR *dir = ttd_opendir(path);
1929  if (dir != NULL) {
1930  struct dirent *dirent;
1931  while ((dirent = readdir(dir)) != NULL) {
1932  const char *d_name = FS2OTTD(dirent->d_name);
1933  const char *extension = strrchr(d_name, '.');
1934 
1935  /* Not a language file */
1936  if (extension == NULL || strcmp(extension, ".lng") != 0) continue;
1937 
1938  LanguageMetadata lmd;
1939  seprintf(lmd.file, lastof(lmd.file), "%s%s", path, d_name);
1940 
1941  /* Check whether the file is of the correct version */
1942  if (!GetLanguageFileHeader(lmd.file, &lmd)) {
1943  DEBUG(misc, 3, "%s is not a valid language file", lmd.file);
1944  } else if (GetLanguage(lmd.newgrflangid) != NULL) {
1945  DEBUG(misc, 3, "%s's language ID is already known", lmd.file);
1946  } else {
1947  *_languages.Append() = lmd;
1948  }
1949  }
1950  closedir(dir);
1951  }
1952 }
1953 
1959 {
1960  Searchpath sp;
1961 
1962  FOR_ALL_SEARCHPATHS(sp) {
1963  char path[MAX_PATH];
1964  FioAppendDirectory(path, lastof(path), sp, LANG_DIR);
1965  GetLanguageList(path);
1966  }
1967  if (_languages.Length() == 0) usererror("No available language packs (invalid versions?)");
1968 
1969  /* Acquire the locale of the current system */
1970  const char *lang = GetCurrentLocale("LC_MESSAGES");
1971  if (lang == NULL) lang = "en_GB";
1972 
1973  const LanguageMetadata *chosen_language = NULL;
1974  const LanguageMetadata *language_fallback = NULL;
1975  const LanguageMetadata *en_GB_fallback = _languages.Begin();
1976 
1977  /* Find a proper language. */
1978  for (const LanguageMetadata *lng = _languages.Begin(); lng != _languages.End(); lng++) {
1979  /* We are trying to find a default language. The priority is by
1980  * configuration file, local environment and last, if nothing found,
1981  * English. */
1982  const char *lang_file = strrchr(lng->file, PATHSEPCHAR) + 1;
1983  if (strcmp(lang_file, _config_language_file) == 0) {
1984  chosen_language = lng;
1985  break;
1986  }
1987 
1988  if (strcmp (lng->isocode, "en_GB") == 0) en_GB_fallback = lng;
1989  if (strncmp(lng->isocode, lang, 5) == 0) chosen_language = lng;
1990  if (strncmp(lng->isocode, lang, 2) == 0) language_fallback = lng;
1991  }
1992 
1993  /* We haven't found the language in the config nor the one in the locale.
1994  * Now we set it to one of the fallback languages */
1995  if (chosen_language == NULL) {
1996  chosen_language = (language_fallback != NULL) ? language_fallback : en_GB_fallback;
1997  }
1998 
1999  if (!ReadLanguagePack(chosen_language)) usererror("Can't read language pack '%s'", chosen_language->file);
2000 }
2001 
2007 {
2008  return _langpack->isocode;
2009 }
2010 
2018 {
2019  InitFreeType(this->Monospace());
2020  const Sprite *question_mark[FS_END];
2021 
2022  for (FontSize size = this->Monospace() ? FS_MONO : FS_BEGIN; size < (this->Monospace() ? FS_END : FS_MONO); size++) {
2023  question_mark[size] = GetGlyph(size, '?');
2024  }
2025 
2026  this->Reset();
2027  for (const char *text = this->NextString(); text != NULL; text = this->NextString()) {
2028  FontSize size = this->DefaultSize();
2029  if (str != NULL) *str = text;
2030  for (WChar c = Utf8Consume(&text); c != '\0'; c = Utf8Consume(&text)) {
2031  if (c >= SCC_FIRST_FONT && c <= SCC_LAST_FONT) {
2032  size = (FontSize)(c - SCC_FIRST_FONT);
2033  } else if (!IsInsideMM(c, SCC_SPRITE_START, SCC_SPRITE_END) && IsPrintable(c) && !IsTextDirectionChar(c) && c != '?' && GetGlyph(size, c) == question_mark[size]) {
2034  /* The character is printable, but not in the normal font. This is the case we were testing for. */
2035  return true;
2036  }
2037  }
2038  }
2039  return false;
2040 }
2041 
2044  uint i;
2045  uint j;
2046 
2047  /* virtual */ void Reset()
2048  {
2049  this->i = 0;
2050  this->j = 0;
2051  }
2052 
2053  /* virtual */ FontSize DefaultSize()
2054  {
2055  return FS_NORMAL;
2056  }
2057 
2058  /* virtual */ const char *NextString()
2059  {
2060  if (this->i >= TEXT_TAB_END) return NULL;
2061 
2062  const char *ret = _langpack_offs[_langtab_start[this->i] + this->j];
2063 
2064  this->j++;
2065  while (this->i < TEXT_TAB_END && this->j >= _langtab_num[this->i]) {
2066  this->i++;
2067  this->j = 0;
2068  }
2069 
2070  return ret;
2071  }
2072 
2073  /* virtual */ bool Monospace()
2074  {
2075  return false;
2076  }
2077 
2078  /* virtual */ void SetFontNames(FreeTypeSettings *settings, const char *font_name)
2079  {
2080 #ifdef WITH_FREETYPE
2081  strecpy(settings->small.font, font_name, lastof(settings->small.font));
2082  strecpy(settings->medium.font, font_name, lastof(settings->medium.font));
2083  strecpy(settings->large.font, font_name, lastof(settings->large.font));
2084 #endif /* WITH_FREETYPE */
2085  }
2086 };
2087 
2101 void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher)
2102 {
2103  static LanguagePackGlyphSearcher pack_searcher;
2104  if (searcher == NULL) searcher = &pack_searcher;
2105  bool bad_font = !base_font || searcher->FindMissingGlyphs(NULL);
2106 #ifdef WITH_FREETYPE
2107  if (bad_font) {
2108  /* We found an unprintable character... lets try whether we can find
2109  * a fallback font that can print the characters in the current language. */
2110  FreeTypeSettings backup;
2111  memcpy(&backup, &_freetype, sizeof(backup));
2112 
2113  bad_font = !SetFallbackFont(&_freetype, _langpack->isocode, _langpack->winlangid, searcher);
2114 
2115  memcpy(&_freetype, &backup, sizeof(backup));
2116 
2117  if (bad_font && base_font) {
2118  /* Our fallback font does miss characters too, so keep the
2119  * user chosen font as that is more likely to be any good than
2120  * the wild guess we made */
2121  InitFreeType(searcher->Monospace());
2122  }
2123  }
2124 #endif
2125 
2126  if (bad_font) {
2127  /* All attempts have failed. Display an error. As we do not want the string to be translated by
2128  * the translators, we 'force' it into the binary and 'load' it via a BindCString. To do this
2129  * properly we have to set the colour of the string, otherwise we end up with a lot of artifacts.
2130  * The colour 'character' might change in the future, so for safety we just Utf8 Encode it into
2131  * the string, which takes exactly three characters, so it replaces the "XXX" with the colour marker. */
2132  static char *err_str = stredup("XXXThe current font is missing some of the characters used in the texts for this language. Read the readme to see how to solve this.");
2133  Utf8Encode(err_str, SCC_YELLOW);
2134  SetDParamStr(0, err_str);
2135  ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_WARNING);
2136 
2137  /* Reset the font width */
2138  LoadStringWidthTable(searcher->Monospace());
2139  return;
2140  }
2141 
2142  /* Update the font with cache */
2143  LoadStringWidthTable(searcher->Monospace());
2144 
2145 #if !defined(WITH_ICU_LAYOUT) && !defined(WITH_UNISCRIBE) && !defined(WITH_COCOA)
2146  /*
2147  * For right-to-left languages we need the ICU library. If
2148  * we do not have support for that library we warn the user
2149  * about it with a message. As we do not want the string to
2150  * be translated by the translators, we 'force' it into the
2151  * binary and 'load' it via a BindCString. To do this
2152  * properly we have to set the colour of the string,
2153  * otherwise we end up with a lot of artifacts. The colour
2154  * 'character' might change in the future, so for safety
2155  * we just Utf8 Encode it into the string, which takes
2156  * exactly three characters, so it replaces the "XXX" with
2157  * the colour marker.
2158  */
2159  if (_current_text_dir != TD_LTR) {
2160  static char *err_str = stredup("XXXThis version of OpenTTD does not support right-to-left languages. Recompile with icu enabled.");
2161  Utf8Encode(err_str, SCC_YELLOW);
2162  SetDParamStr(0, err_str);
2163  ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR);
2164  }
2165 #endif /* !WITH_ICU_LAYOUT */
2166 }
Helper for unit conversion.
Definition: strings.cpp:639
Functions related to OTTD&#39;s strings.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition: settings.cpp:77
Definition of stuff that is very close to a company, like the company struct itself.
void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher)
Check whether the currently loaded language pack uses characters that the currently loaded font does ...
Definition: strings.cpp:2101
static Titem * GetIfValid(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:257
int64 FromDisplay(int64 input, bool round=true, int64 divider=1) const
Convert the displayed value back into a value of OpenTTD&#39;s internal unit.
Definition: strings.cpp:661
static char * FormatBytes(char *buff, int64 number, const char *last)
Format a given number as a number of bytes with the SI prefix.
Definition: strings.cpp:375
static char * FormatString(char *buff, const char *str, StringParameters *args, const char *last, uint case_index=0, bool game_script=false, bool dry_run=false)
Parse most format codes within a string and write the result to a buffer.
Definition: strings.cpp:772
Inline another string at the current position, StringID is encoded in the string. ...
void SortIndustryTypes()
Initialize the list of sorted industry types.
uint16 town_cn
The N-1th waypoint for this town (consecutive number)
Definition: waypoint_base.h:19
static uint GetStringIndex(StringID str)
Extract the StringIndex from a StringID.
Definition: strings_func.h:38
char * name
Name of the company if the user changed it.
Definition: company_base.h:56
WChar * type
Array with type information about the data. Can be NULL when no type information is needed...
Definition: strings_func.h:65
Control codes that are embedded in the translation strings.
byte landscape
the landscape we&#39;re currently in
static char * strecat(char *dst, const char *src, const char *last)
Appends characters from one string to another.
Definition: depend.cpp:99
const char * FS2OTTD(const TCHAR *name)
Convert to OpenTTD&#39;s encoding from that of the local environment.
Definition: win32.cpp:565
bool UsingNewGRFTextStack()
Check whether the NewGRF text stack is in use.
static const Units _units_height[]
Unit conversions for height.
Definition: strings.cpp:716
bool IsEnabled() const
Checks whether the engine is a valid (non-articulated part of an) engine.
Definition: engine.cpp:152
static Titem * Get(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:246
void ClearTypeInformation()
Reset the type array.
Definition: strings.cpp:63
Functions related to dates.
static bool IsInsideMM(const T x, const uint min, const uint max)
Checks if a value is in an interval.
Definition: math_func.hpp:266
Day day
Day (1..31)
Definition: date_type.h:106
icu::Collator * _current_collator
Collator for the language currently in use.
Definition: strings.cpp:55
byte units_weight
unit system for weight
Functions to handle different currencies.
int CDECL seprintf(char *str, const char *last, const char *format,...)
Safer implementation of snprintf; same as snprintf except:
Definition: string.cpp:409
Town * town
Nearest town.
Definition: industry.h:43
Functions related to debugging.
uint num_param
Length of the data array.
Definition: strings_func.h:69
static uint64 _global_string_params_data[20]
Global array of string parameters. To access, use SetDParam.
Definition: strings.cpp:58
static int DeterminePluralForm(int64 count, int plural_form)
Determine the "plural" index given a plural form and a number.
Definition: strings.cpp:507
void SetCurrentGrfLangID(byte language_id)
Equivalence Setter function between game and newgrf langID.
Index of the monospaced font in the font tables.
Definition: gfx_type.h:207
Data structure describing a sprite.
Definition: spritecache.h:18
#define FOR_ALL_SEARCHPATHS(sp)
Iterator for all the search paths.
Definition: fileio_func.h:49
fluid_settings_t * settings
FluidSynth settings handle.
Definition: fluidsynth.cpp:22
#define FOR_ALL_SORTED_CARGOSPECS(var)
Loop header for iterating over cargoes, sorted by name.
Definition: cargotype.h:166
Specification of a cargo type.
Definition: cargotype.h:56
static uint _langtab_num[TEXT_TAB_END]
Offset into langpack offs.
Definition: strings.cpp:193
void ShiftParameters(uint amount)
Shift all data in the data array by the given amount to make room for some extra parameters.
Definition: strings.cpp:94
Build vehicle; Window numbers:
Definition: window_type.h:378
Vehicle data structure.
Definition: vehicle_base.h:212
void CopyInDParam(int offs, const uint64 *src, int num)
Copy num string parameters from array src into the global string parameter array. ...
Definition: strings.cpp:141
Base for all depots (except hangars)
Functions related to detecting/finding the right font.
uint offset
Current offset in the data/type arrays.
Definition: strings_func.h:68
byte units_velocity
unit system for velocity
Defines the internal data of a functional industry.
Definition: industry.h:41
const T * Begin() const
Get the pointer to the first item (const)
Base functions regarding game texts.
Tindex index
Index of this pool item.
Definition: pool_type.hpp:147
static bool IsTextDirectionChar(WChar c)
Is the given character a text direction character.
Definition: string_func.h:210
char * president_name
Name of the president if the user changed it.
Definition: company_base.h:60
static StringID MakeStringID(StringTab tab, uint index)
Create a StringID.
Definition: strings_func.h:49
static const uint32 IDENT
Identifier for OpenTTD language files, big endian for "LANG".
Definition: language.h:27
static const int DRAW_STRING_BUFFER
Size of the buffer used for drawing strings.
Definition: gfx_func.h:87
bool HasTypeInformation() const
Does this instance store information about the type of the parameters.
Definition: strings_func.h:149
virtual bool Monospace()=0
Whether to search for a monospace font or not.
Functions for Standard In/Out file operations.
size_t Utf8Decode(WChar *c, const char *s)
Decode and consume the next UTF-8 encoded character.
Definition: string.cpp:448
FreeTypeSubSetting large
The largest font; mostly used for newspapers.
Definition: fontcache.h:218
Representation of a waypoint.
Definition: waypoint_base.h:18
#define lastof(x)
Get the last element of an fixed size array.
Definition: depend.cpp:50
Simple vector template class.
Function to handling different endian machines.
StringTab
StringTabs to group StringIDs.
Definition: strings_type.h:30
static StringTab GetStringTab(StringID str)
Extract the StringTab from a StringID.
Definition: strings_func.h:25
Searchpath
Types of searchpaths OpenTTD might use.
Definition: fileio_type.h:133
uint16 offsets[TEXT_TAB_END]
the offsets
Definition: language.h:34
uint32 name_2
Parameter of name_1.
Definition: company_base.h:54
StringID quantifier
Text for multiple units of cargo of this type.
Definition: cargotype.h:74
static T max(const T a, const T b)
Returns the maximum of two values.
Definition: math_func.hpp:26
Information about a specific unit system with a long variant.
Definition: strings.cpp:674
byte units_force
unit system for force
Town * town
The town this station is associated with.
byte units_height
unit system for height
The next variables are part of a NewGRF subsystem for creating text strings.
const T * End() const
Get the pointer behind the last valid item (const)
uint16 winlangid
Windows language ID: Windows cannot and will not convert isocodes to something it can use to determin...
Definition: language.h:53
StringID name
Name of this type of cargo.
Definition: cargotype.h:71
Industry directory; Window numbers:
Definition: window_type.h:261
static void GetLanguageList(const char *path)
Gets a list of languages from the given directory.
Definition: strings.cpp:1926
Metadata about a single language.
Definition: language.h:94
StringID name
Displayed name of the industry.
Definition: industrytype.h:124
char isocode[16]
the ISO code for the language (not country code)
Definition: language.h:33
char * GetStringWithArgs(char *buffr, StringID string, StringParameters *args, const char *last, uint case_index, bool game_script)
Get a parsed string with most special stringcodes replaced by the string parameters.
Definition: strings.cpp:219
Settings for the freetype fonts.
Definition: fontcache.h:215
static const Units _units_force[]
Unit conversions for force.
Definition: strings.cpp:709
static bool IsValidHumanID(size_t index)
Is this company a valid company, not controlled by a NoAI program?
Definition: company_base.h:149
T * Append(uint to_add=1)
Append an item and return it.
void InitFreeType(bool monospace)
(Re)initialize the freetype related things, i.e.
Definition: fontcache.cpp:662
static void MemMoveT(T *destination, const T *source, size_t num=1)
Type-safe version of memmove().
Definition: mem_func.hpp:38
Invalid cargo type.
Definition: cargo_type.h:70
const char * NextString()
Get the next string to search through.
Definition: strings.cpp:2058
Helper for searching through the language pack.
Definition: strings.cpp:2043
void BuildContentTypeStringList()
Build array of all strings corresponding to the content types.
uint ConvertDisplaySpeedToSpeed(uint speed)
Convert the given display speed to the (internal) speed.
Definition: strings.cpp:740
void InvalidateWindowClassesData(WindowClass cls, int data, bool gui_scope)
Mark window data of all windows of a given class as invalid (in need of re-computing) Note that by de...
Definition: window.cpp:3319
uint RemapNewGRFStringControlCode(uint scc, char *buf_start, char **buff, const char **str, int64 *argv, uint argv_size, bool modify_argv)
FormatString for NewGRF specific "magic" string control codes.
byte symbol_pos
The currency symbol is represented by two possible values, prefix and suffix Usage of one or the othe...
Definition: currency.h:82
void ShowErrorMessage(StringID summary_msg, StringID detailed_msg, WarningLevel wl, int x=0, int y=0, const GRFFile *textref_stack_grffile=NULL, uint textref_stack_size=0, const uint32 *textref_stack=NULL)
Display an error message in a window.
Definition: error_gui.cpp:378
static WChar _global_string_params_type[20]
Type of parameters stored in #_global_string_params.
Definition: strings.cpp:59
Header of Action 04 "universal holder" structure and functions.
void SetDParamStr(uint n, const char *str)
This function is used to "bind" a C string to a OpenTTD dparam slot.
Definition: strings.cpp:282
Aircraft vehicle type.
Definition: vehicle_type.h:29
Functions related to low-level strings.
Other information.
Definition: error.h:24
void Reset()
Reset the search, i.e.
Definition: strings.cpp:2047
uint ConvertDisplaySpeedToKmhishSpeed(uint speed)
Convert the given display speed to the km/h-ish speed.
Definition: strings.cpp:760
uint64 * data
Array with the actual data.
Definition: strings_func.h:64
Functions related to errors.
UnitID unitnumber
unit number, for display purposes only
Definition: vehicle_base.h:291
uint Length() const
Get the number of items in the list.
Definition: win32.cpp:93
UnitConversion c
Conversion.
Definition: strings.cpp:675
Header of a language file.
Definition: language.h:26
First font.
Definition: gfx_type.h:210
VehicleType
Available vehicle types.
Definition: vehicle_type.h:23
81: Read 2 bytes from the stack as String ID
char * name
Group Name.
Definition: group.h:68
byte units_volume
unit system for volume
void ReconsiderGameScriptLanguage()
Reconsider the game script language, so we use the right one.
Definition: game_text.cpp:377
A searcher for missing glyphs.
Definition: strings_func.h:246
char * GetTownName(char *buff, const TownNameParams *par, uint32 townnameparts, const char *last)
Fills buffer with specified town name.
Definition: townname.cpp:51
Station with truck stops.
Definition: station_type.h:55
Subdirectory for all translation files.
Definition: fileio_type.h:120
const IndustrySpec * GetIndustrySpec(IndustryType thistype)
Accessor for array _industry_specs.
UnitConversion c
Conversion.
Definition: strings.cpp:669
Definition of base types and functions in a cross-platform compatible way.
void LoadStringWidthTable(bool monospace)
Initialize _stringwidth_table cache.
Definition: gfx.cpp:1132
static const uint TAB_SIZE
Number of strings per StringTab.
Definition: strings_type.h:48
Data structure to convert between Date and triplet (year, month, and day).
Definition: date_type.h:103
void CDECL usererror(const char *s,...)
Error handling for fatal user errors.
Definition: openttd.cpp:92
A number of safeguards to prevent using unsafe methods.
int64 ToDisplay(int64 input, bool round=true) const
Convert value from OpenTTD&#39;s internal unit into the displayed value.
Definition: strings.cpp:649
IndustryType type
type of industry.
Definition: industry.h:57
Base of waypoints.
void CopyOutDParam(uint64 *dst, int offs, int num)
Copy num string parameters from the global string parameter array to the dst array.
Definition: strings.cpp:152
void SetFontNames(FreeTypeSettings *settings, const char *font_name)
Set the right font names.
Definition: strings.cpp:2078
int64 GetInt64(WChar type=0)
Read an int64 from the argument array.
Definition: strings.cpp:74
const LanguageMetadata * GetLanguage(byte newgrflangid)
Get the language with the given NewGRF language ID.
Definition: strings.cpp:1889
static const uint TAB_SIZE_GAMESCRIPT
Number of strings for GameScripts.
Definition: strings_type.h:51
Information about languages and their files.
static const UnitsLong _units_weight[]
Unit conversions for weight.
Definition: strings.cpp:695
char * stredup(const char *s, const char *last)
Create a duplicate of the given string.
Definition: string.cpp:138
static int8 Utf8CharLen(WChar c)
Return the length of a UTF-8 encoded character.
Definition: string_func.h:99
void SetDParamMaxDigits(uint n, uint count, FontSize size)
Set DParam n to some number that is suitable for string size computations.
Definition: strings.cpp:124
LanguageList _languages
The actual list of language meta data.
Definition: strings.cpp:49
Road vehicle list; Window numbers:
Definition: window_type.h:309
Defines the data structure for constructing industry.
Definition: industrytype.h:103
bool FindMissingGlyphs(const char **str)
Check whether there are glyphs missing in the current language.
Definition: strings.cpp:2017
Year year
Year (0...)
Definition: date_type.h:104
static const uint8 MAX_NUM_GENDERS
Maximum number of supported genders.
Definition: language.h:22
char * digit_group_separator_currency
thousand separator for currencies
FreeTypeSubSetting medium
The normal font size.
Definition: fontcache.h:217
static bool GetLanguageFileHeader(const char *file, LanguagePackHeader *hdr)
Reads the language file header and checks compatibility.
Definition: strings.cpp:1904
uint GetDataLeft() const
Return the amount of elements which can still be read.
Definition: strings_func.h:136
char * digit_decimal_separator
decimal separator
#define lengthof(x)
Return the length of an fixed size array.
Definition: depend.cpp:42
Road vehicle type.
Definition: vehicle_type.h:27
static const uint8 MAX_NUM_CASES
Maximum number of supported cases.
Definition: language.h:23
static T min(const T a, const T b)
Returns the minimum of two values.
Definition: math_func.hpp:42
void InitializeLanguagePacks()
Make a list of the available language packs.
Definition: strings.cpp:1958
char * name
Custom name of engine.
Definition: engine_base.h:24
Station with a dock.
Definition: station_type.h:58
static const Sprite * GetGlyph(FontSize size, WChar key)
Get the Sprite for a glyph.
Definition: fontcache.h:187
StringID s
String for the short variant of the unit.
Definition: strings.cpp:676
uint32 StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:18
Text is written left-to-right by default.
Definition: strings_type.h:25
Month month
Month (0..11)
Definition: date_type.h:105
uint i
Iterator for the primary language tables.
Definition: strings.cpp:2044
FontSize DefaultSize()
Get the default (font) size of the string.
Definition: strings.cpp:2053
Start of GameScript supplied strings.
Definition: strings_type.h:41
Information about a specific unit system.
Definition: strings.cpp:668
char file[MAX_PATH]
Name of the file we read this data from.
Definition: language.h:95
Station list; Window numbers:
Definition: window_type.h:297
Ship vehicle type.
Definition: vehicle_type.h:28
static void MemCpyT(T *destination, const T *source, size_t num=1)
Type-safe version of memcpy().
Definition: mem_func.hpp:25
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback)
We would like to have a fallback font as the current one doesn&#39;t contain all characters we need...
#define DEBUG(name, level,...)
Output a line of debugging information.
Definition: debug.h:36
static const uint MAX_LANG
Maximum number of languages supported by the game, and the NewGRF specs.
Definition: strings_type.h:21
Dimension _resolutions[32]
List of resolutions.
Definition: driver.cpp:23
uint32 president_name_2
Parameter of president_name_1.
Definition: company_base.h:59
byte units_power
unit system for power
const LanguageMetadata * _current_language
The currently loaded language.
Definition: strings.cpp:50
char * name
Name of vehicle.
Definition: base_consist.h:20
uint16 missing
number of missing strings.
Definition: language.h:42
char font[MAX_PATH]
The name of the font, or path to the font.
Definition: fontcache.h:209
static const Units _units_power[]
Unit conversions for velocity.
Definition: strings.cpp:688
Smallmap GUI functions.
char _config_language_file[MAX_PATH]
The file (name) stored in the configuration.
Definition: strings.cpp:48
static const UnitsLong _units_volume[]
Unit conversions for volume.
Definition: strings.cpp:702
User interface for downloading files.
const char * GetCurrentLanguageIsoCode()
Get the ISO language code of the currently loaded language.
Definition: strings.cpp:2006
Base class for engines.
uint ConvertKmhishSpeedToDisplaySpeed(uint speed)
Convert the given km/h-ish speed to the display speed.
Definition: strings.cpp:750
End of language files.
Definition: strings_type.h:40
int shift
Amount to shift upon conversion.
Definition: strings.cpp:641
char digit_decimal_separator[8]
Decimal separator.
Definition: language.h:41
void InjectDParam(uint amount)
Shift the string parameters in the global string parameter array by amount positions, making room at the beginning.
Definition: strings.cpp:291
TextDirection
Directions a text can go to.
Definition: strings_type.h:24
int strnatcmp(const char *s1, const char *s2, bool ignore_garbage_at_front)
Compares two strings using case insensitive natural sort.
Definition: string.cpp:580
char digit_group_separator[8]
Thousand separator used for anything not currencies.
Definition: language.h:37
Base class for all vehicles.
static bool StrEmpty(const char *s)
Check if a string buffer is empty.
Definition: string_func.h:59
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo ID.
Definition: cargotype.h:118
Ships list; Window numbers:
Definition: window_type.h:315
StringID s
String for the unit.
Definition: strings.cpp:670
StringID name_1
Name of the company if the user did not change it.
Definition: company_base.h:55
WChar GetTypeAtOffset(uint offset) const
Get the type of a specific element.
Definition: strings_func.h:155
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition: strings.cpp:52
void SetDParamMaxValue(uint n, uint64 max_value, uint min_count, FontSize size)
Set DParam n to some number that is suitable for string size computations.
Definition: strings.cpp:108
bool IsValid() const
Check whether the header is a valid header for OpenTTD.
Definition: strings.cpp:1698
StringID president_name_1
Name of the president if the user did not change it.
Definition: company_base.h:58
void GetBroadestDigit(uint *front, uint *next, FontSize size)
Determine the broadest digits for guessing the maximum width of a n-digit number. ...
Definition: gfx.cpp:1179
void CDECL error(const char *s,...)
Error handling for fatal non-user errors.
Definition: openttd.cpp:112
char own_name[32]
the localized name of this language
Definition: language.h:32
static T abs(const T a)
Returns the absolute value of (scalar) variable.
Definition: math_func.hpp:83
void InitializeSortedCargoSpecs()
Initialize the list of sorted cargo specifications.
Definition: cargotype.cpp:173
static uint GB(const T x, const uint8 s, const uint8 n)
Fetch n bits from x, started at bit s.
StringID string_id
Default name of engine.
Definition: engine_type.h:145
Trains list; Window numbers:
Definition: window_type.h:303
FreeTypeSubSetting small
The smallest font; mostly used for zoomed out view.
Definition: fontcache.h:216
FontSize
Available font sizes.
Definition: gfx_type.h:203
void RestoreTextRefStackBackup(struct TextRefStack *backup)
Restore a copy of the text stack to the used stack.
char * strecpy(char *dst, const char *src, const char *last)
Copies characters from one buffer to another.
Definition: depend.cpp:68
static DIR * ttd_opendir(const char *path)
A wrapper around opendir() which will convert the string from OPENTTD encoding to that of the filesys...
Definition: fileio_func.h:148
const char * GetGRFStringPtr(uint16 stringid)
Get a C-string from a stringid set by a newgrf.
int multiplier
Amount to multiply upon conversion.
Definition: strings.cpp:640
Town data structure.
Definition: town.h:55
static bool _scan_for_gender_data
Are we scanning for the gender of the current string? (instead of formatting it)
Definition: strings.cpp:195
Index of the normal font in the font tables.
Definition: gfx_type.h:204
Group data.
Definition: group.h:67
char * digit_group_separator
thousand separator for non-currencies
Start of NewGRF supplied strings.
Definition: strings_type.h:42
Station with train station.
Definition: station_type.h:54
LocaleSettings locale
settings related to used currency/unit system in the current game
Aircraft list; Window numbers:
Definition: window_type.h:321
Specification of a currency.
Definition: currency.h:67
static const Units _units_velocity[]
Unit conversions for velocity.
Definition: strings.cpp:681
char * name
Custom town name. If NULL, the town was not renamed and uses the generated name.
Definition: town.h:64
uint ConvertSpeedToDisplaySpeed(uint speed)
Convert the given (internal) speed to the display speed.
Definition: strings.cpp:727
CargoID Index() const
Determines index of this cargospec.
Definition: cargotype.h:89
static size_t GetArraySize()
Total number of cargospecs, both valid and invalid.
Definition: cargotype.h:108
struct TextRefStack * CreateTextRefStackBackup()
Create a backup of the current NewGRF text stack.
char * GenerateTownNameString(char *buf, const char *last, size_t lang, uint32 seed)
Generates town name from given seed.
Definition: townname.cpp:1055
static uint _langtab_start[TEXT_TAB_END]
Offset into langpack offs.
Definition: strings.cpp:194
Station with bus stops.
Definition: station_type.h:56
static char * FormatNumber(char *buff, int64 number, const char *last, const char *separator, int zerofill=1, int fractional_digits=0)
Format a number into a string.
Definition: strings.cpp:307
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
Definition: strings_type.h:19
size_t Utf8Encode(char *buf, WChar c)
Encode a unicode character and place it in the buffer.
Definition: string.cpp:488
Base of all industries.
int32 Date
The type to store our dates in.
Definition: date_type.h:16
static void free(const void *ptr)
Version of the standard free that accepts const pointers.
Definition: depend.cpp:114
declaration of OTTD revision dependent variables
char digit_group_separator_currency[8]
Thousand separator used for currencies.
Definition: language.h:39
StringID station_name
Default name for nearby station.
Definition: industrytype.h:129
static bool HasBit(const T x, const uint8 y)
Checks if a bit in a value is set.
Town name generator stuff.
StringID units_volume
Name of a single unit of cargo of this type.
Definition: cargotype.h:73
Base of the town class.
bool ReadLanguagePack(const LanguageMetadata *lang)
Read a particular language.
Definition: strings.cpp:1720
void * ReadFileToMem(const char *filename, size_t *lenp, size_t maxsize)
Load a file into memory.
Definition: fileio.cpp:1310
uint64 * GetPointerToOffset(uint offset) const
Get a pointer to a specific element in the data array.
Definition: strings_func.h:142
GameCreationSettings game_creation
settings used during the creation of a game (map)
const char * GetCurrentLocale(const char *param)
Determine the current charset based on the environment First check some default values, after this one we passed ourselves and if none exist return the value for $LANG.
Definition: strings.cpp:1853
uint8 newgrflangid
newgrf language id
Definition: language.h:54
const char * GetGameStringPtr(uint id)
Get the string pointer of a particular game string.
Definition: game_text.cpp:341
byte CargoID
Cargo slots to indicate a cargo type within a game.
Definition: cargo_type.h:22
IndustryType indtype
Industry type to get the name from.
Definition: station_base.h:463
Owner
Enum for all companies/owners.
Definition: company_type.h:20
Window functions not directly related to making/drawing windows.
int32 GetInt32(WChar type=0)
Read an int32 from the argument array.
Definition: strings_func.h:122
Base classes/functions for stations.
Errors (eg. saving/loading failed)
Definition: error.h:25
byte text_dir
default direction of the text
Definition: language.h:44
#define NBSP
A non-breaking space.
Definition: string_type.h:18
char * name
Custom name.
uint32 WChar
Type for wide characters, i.e.
Definition: string_type.h:35
void ConvertDateToYMD(Date date, YearMonthDay *ymd)
Converts a Date to a Year, Month & Day.
Definition: date.cpp:94
uint j
Iterator for the secondary language tables.
Definition: strings.cpp:2045
StringID string_id
Default name (town area) of station.
VehicleTypeByte type
Type of vehicle.
Definition: vehicle_type.h:56
StringID l
String for the long variant of the unit.
Definition: strings.cpp:677
void MacOSSetCurrentLocaleName(const char *iso_code)
Store current language locale as a CoreFounation locale.
Definition: string_osx.cpp:280
Station data structure.
Definition: station_base.h:446
Station with an airport.
Definition: station_type.h:57
bool StrValid(const char *str, const char *last)
Checks whether the given string is valid, i.e.
Definition: string.cpp:259
uint16 town_cn
The N-1th depot for this town (consecutive number)
Definition: depot_base.h:26
bool Monospace()
Whether to search for a monospace font or not.
Definition: strings.cpp:2073
static void MemSetT(T *ptr, byte value, size_t num=1)
Type-safe version of memset().
Definition: mem_func.hpp:51
Base class for signs.
Train vehicle type.
Definition: vehicle_type.h:26
static void SetDParam(uint n, uint64 v)
Set a string parameter v at index n in the global string parameter array.
Definition: strings_func.h:201
uint64 * GetDataPointer() const
Get a pointer to the current element in the data array.
Definition: strings_func.h:130
static Station * GetIfValid(size_t index)
Returns station if the index is a valid index for this station type.
void BuildIndustriesLegend()
Fills an array for the industries legends.