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