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