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