OpenTTD Source: src/strings.cpp Source File

OpenTTD Source 15.0-RC2

strings.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
10#include "stdafx.h"
11#include "currency.h"
12#include "station_base.h"
13#include "town.h"
14#include "waypoint_base.h"
15#include "depot_base.h"
16#include "industry.h"
17#include "newgrf_text.h"
18#include "fileio_func.h"
19#include "signs_base.h"
20#include "error.h"
21#include "error_func.h"
22#include "strings_func.h"
23#include "rev.h"
24#include "core/endian_func.hpp"
25#include "timer/timer_game_calendar.h"
26#include "vehicle_base.h"
27#include "engine_base.h"
28#include "language.h"
29#include "townname_func.h"
30#include "string_func.h"
31#include "company_base.h"
32#include "smallmap_gui.h"
33#include "window_func.h"
34#include "debug.h"
35#include "game/game_text.hpp"
36#include "network/network_content_gui.h"
37#include "newgrf_engine.h"
38#include "core/backup_type.hpp"
39#include "gfx_layout.h"
40#include "core/utf8.hpp"
41#include "core/string_consumer.hpp"
42#include <stack>
43
44#include "table/strings.h"
45#include "table/control_codes.h"
46#include "3rdparty/fmt/std.h"
47
48#include "strings_internal.h"
49
50#include "safeguards.h"
51
52std::string _config_language_file;
53 LanguageList _languages;
54 const LanguageMetadata *_current_language = nullptr;
55
56 TextDirection _current_text_dir;
57
58#ifdef WITH_ICU_I18N
59std::unique_ptr<icu::Collator> _current_collator;
60#endif /* WITH_ICU_I18N */
61
68 const StringParameter &StringParameters::GetNextParameterReference()
69{
70 assert(this->next_type == 0 || (SCC_CONTROL_START <= this->next_type && this->next_type <= SCC_CONTROL_END));
71 if (this->offset >= this->parameters.size()) {
72 throw std::out_of_range("Trying to read invalid string parameter");
73 }
74
75 auto &param = this->parameters[this->offset++];
76 if (param.type != 0 && param.type != this->next_type) {
77 this->next_type = 0;
78 throw std::out_of_range("Trying to read string parameter with wrong type");
79 }
80 param.type = this->next_type;
81 this->next_type = 0;
82 return param;
83}
84
90 EncodedString GetEncodedString(StringID str)
91{
92 return GetEncodedStringWithArgs(str, {});
93}
94
102 EncodedString GetEncodedStringWithArgs(StringID str, std::span<const StringParameter> params)
103{
104 std::string result;
105 StringBuilder builder(result);
106 builder.PutUtf8(SCC_ENCODED_INTERNAL);
107 builder.PutIntegerBase(str, 16);
108
109 struct visitor {
110 StringBuilder &builder;
111
112 void operator()(const std::monostate &) {}
113
114 void operator()(const uint64_t &arg)
115 {
116 this->builder.PutUtf8(SCC_ENCODED_NUMERIC);
117 this->builder.PutIntegerBase(arg, 16);
118 }
119
120 void operator()(const std::string &value)
121 {
122#ifdef WITH_ASSERT
123 /* Don't allow an encoded string to contain another encoded string. */
124 {
125 auto [len, c] = DecodeUtf8(value);
126 assert(len == 0 || (c != SCC_ENCODED && c != SCC_ENCODED_INTERNAL && c != SCC_RECORD_SEPARATOR));
127 }
128#endif /* WITH_ASSERT */
129 this->builder.PutUtf8(SCC_ENCODED_STRING);
130 this->builder += value;
131 }
132 };
133
134 visitor v{builder};
135 for (const auto &param : params) {
136 builder.PutUtf8(SCC_RECORD_SEPARATOR);
137 std::visit(v, param.data);
138 }
139
140 return EncodedString{std::move(result)};
141}
142
150 EncodedString EncodedString::ReplaceParam(size_t param, StringParameter &&data) const
151{
152 if (this->empty()) return {};
153
154 std::vector<StringParameter> params;
155 StringConsumer consumer(this->string);
156
157 if (!consumer.ReadUtf8If(SCC_ENCODED_INTERNAL)) return {};
158
159 StringID str;
160 if (auto r = consumer.TryReadIntegerBase<uint32_t>(16); r.has_value()) {
161 str = *r;
162 } else {
163 return {};
164 }
165 if (consumer.AnyBytesLeft() && !consumer.ReadUtf8If(SCC_RECORD_SEPARATOR)) return {};
166
167 while (consumer.AnyBytesLeft()) {
168 StringConsumer record(consumer.ReadUntilUtf8(SCC_RECORD_SEPARATOR, StringConsumer::SKIP_ONE_SEPARATOR));
169
170 if (!record.AnyBytesLeft()) {
171 /* This is an empty parameter. */
172 params.emplace_back(std::monostate{});
173 continue;
174 }
175
176 /* Get the parameter type. */
177 char32_t parameter_type = record.ReadUtf8();
178 switch (parameter_type) {
179 case SCC_ENCODED_NUMERIC: {
180 uint64_t value = record.ReadIntegerBase<uint64_t>(16);
181 assert(!record.AnyBytesLeft());
182 params.emplace_back(value);
183 break;
184 }
185
186 case SCC_ENCODED_STRING: {
187 params.emplace_back(record.Read(StringConsumer::npos));
188 break;
189 }
190
191 default:
192 /* Unknown parameter, make it blank. */
193 params.emplace_back(std::monostate{});
194 break;
195 }
196 }
197
198 if (param >= std::size(params)) return {};
199 params[param] = data;
200 return GetEncodedStringWithArgs(str, params);
201}
202
207std::string EncodedString::GetDecodedString() const
208{
209 return GetString(STR_JUST_RAW_STRING, this->string);
210}
211
218uint64_t GetParamMaxDigits(uint count, FontSize size)
219{
220 auto [front, next] = GetBroadestDigit(size);
221 uint64_t val = count > 1 ? front : next;
222 for (; count > 1; count--) {
223 val = 10 * val + next;
224 }
225 return val;
226}
227
236uint64_t GetParamMaxValue(uint64_t max_value, uint min_count, FontSize size)
237{
238 uint num_digits = 1;
239 while (max_value >= 10) {
240 num_digits++;
241 max_value /= 10;
242 }
243 return GetParamMaxDigits(std::max(min_count, num_digits), size);
244}
245
246static void StationGetSpecialString(StringBuilder &builder, StationFacilities x);
247static bool GetSpecialNameString(StringBuilder &builder, StringID string, StringParameters &args);
248
249static void FormatString(StringBuilder &builder, std::string_view str, StringParameters &args, uint case_index = 0, bool game_script = false, bool dry_run = false);
250
261 static void FormatString(StringBuilder &builder, std::string_view str, std::span<StringParameter> params, uint case_index = 0, bool game_script = false, bool dry_run = false)
262{
263 StringParameters tmp_params{params};
264 FormatString(builder, str, tmp_params, case_index, game_script, dry_run);
265}
266
267 struct LanguagePack : public LanguagePackHeader {
268 char data[]; // list of strings
269};
270
271 struct LanguagePackDeleter {
272 void operator()(LanguagePack *langpack)
273 {
274 /* LanguagePack is in fact reinterpreted char[], we need to reinterpret it back to free it properly. */
275 delete[] reinterpret_cast<char *>(langpack);
276 }
277};
278
279 struct LoadedLanguagePack {
280 std::unique_ptr<LanguagePack, LanguagePackDeleter> langpack;
281
282 std::vector<std::string_view> strings;
283
284 std::array<uint, TEXT_TAB_END> langtab_num;
285 std::array<uint, TEXT_TAB_END> langtab_start;
286
287 std::string list_separator;
288 std::string ellipsis;
289};
290
291static LoadedLanguagePack _langpack;
292
293 static bool _scan_for_gender_data = false;
294
299std::string_view GetListSeparator()
300{
301 return _langpack.list_separator;
302}
303
308std::string_view GetEllipsis()
309{
310 return _langpack.ellipsis;
311}
312
313std::string_view GetStringPtr(StringID string)
314{
315 switch (GetStringTab(string)) {
316 case TEXT_TAB_GAMESCRIPT_START: return GetGameStringPtr(GetStringIndex(string));
317 /* 0xD0xx and 0xD4xx IDs have been converted earlier. */
318 case TEXT_TAB_OLD_NEWGRF: NOT_REACHED();
319 case TEXT_TAB_NEWGRF_START: return GetGRFStringPtr(GetStringIndex(string));
320 default: {
321 const size_t offset = _langpack.langtab_start[GetStringTab(string)] + GetStringIndex(string).base();
322 if (offset < _langpack.strings.size()) return _langpack.strings[offset];
323 return "(undefined string)";
324 }
325 }
326}
327
336 void GetStringWithArgs(StringBuilder &builder, StringID string, StringParameters &args, uint case_index, bool game_script)
337{
338 if (string == 0) {
339 GetStringWithArgs(builder, STR_UNDEFINED, args);
340 return;
341 }
342
343 StringIndexInTab index = GetStringIndex(string);
344 StringTab tab = GetStringTab(string);
345
346 switch (tab) {
347 case TEXT_TAB_TOWN:
348 if (IsInsideMM(string, SPECSTR_TOWNNAME_START, SPECSTR_TOWNNAME_END) && !game_script) {
349 try {
350 GenerateTownNameString(builder, string - SPECSTR_TOWNNAME_START, args.GetNextParameter<uint32_t>());
351 } catch (const std::runtime_error &e) {
352 Debug(misc, 0, "GetStringWithArgs: {}", e.what());
353 builder += "(invalid string parameter)";
354 }
355 return;
356 }
357 break;
358
359 case TEXT_TAB_SPECIAL:
360 if (!game_script) {
361 try {
362 if (GetSpecialNameString(builder, string, args)) return;
363 } catch (const std::runtime_error &e) {
364 Debug(misc, 0, "GetStringWithArgs: {}", e.what());
365 builder += "(invalid string parameter)";
366 return;
367 }
368 }
369 break;
370
371 case TEXT_TAB_OLD_CUSTOM:
372 /* Old table for custom names. This is no longer used */
373 if (!game_script) {
374 FatalError("Incorrect conversion of custom name string.");
375 }
376 break;
377
378 case TEXT_TAB_GAMESCRIPT_START: {
379 FormatString(builder, GetGameStringPtr(index), args, case_index, true);
380 return;
381 }
382
383 case TEXT_TAB_OLD_NEWGRF:
384 NOT_REACHED();
385
386 case TEXT_TAB_NEWGRF_START: {
387 FormatString(builder, GetGRFStringPtr(index), args, case_index);
388 return;
389 }
390
391 default:
392 break;
393 }
394
395 if (index >= _langpack.langtab_num[tab]) {
396 if (game_script) {
397 return GetStringWithArgs(builder, STR_UNDEFINED, args);
398 }
399 FatalError("String 0x{:X} is invalid. You are probably using an old version of the .lng file.\n", string);
400 }
401
402 FormatString(builder, GetStringPtr(string), args, case_index);
403}
404
413 void GetStringWithArgs(StringBuilder &builder, StringID string, std::span<StringParameter> params, uint case_index, bool game_script)
414{
415 StringParameters tmp_params{params};
416 GetStringWithArgs(builder, string, tmp_params, case_index, game_script);
417}
418
424std::string GetString(StringID string)
425{
426 return GetStringWithArgs(string, {});
427}
428
434 void AppendStringInPlace(std::string &result, StringID string)
435{
436 StringBuilder builder(result);
437 GetStringWithArgs(builder, string, {});
438}
439
440void AppendStringWithArgsInPlace(std::string &result, StringID string, std::span<StringParameter> params)
441{
442 StringParameters tmp_params{params};
443 StringBuilder builder(result);
444 GetStringWithArgs(builder, string, tmp_params);
445}
446
453std::string GetStringWithArgs(StringID string, StringParameters &args)
454{
455 std::string result;
456 StringBuilder builder(result);
457 GetStringWithArgs(builder, string, args);
458 return result;
459}
460
461std::string GetStringWithArgs(StringID string, std::span<StringParameter> args)
462{
463 std::string result;
464 StringBuilder builder(result);
465 GetStringWithArgs(builder, string, args);
466 return result;
467}
468
469static std::string_view GetDecimalSeparator()
470{
471 std::string_view decimal_separator = _settings_game.locale.digit_decimal_separator;
472 if (decimal_separator.empty()) decimal_separator = _langpack.langpack->digit_decimal_separator;
473 return decimal_separator;
474}
475
482 static void FormatNumber(StringBuilder &builder, int64_t number, std::string_view separator)
483{
484 static const int max_digits = 20;
485 uint64_t divisor = 10000000000000000000ULL;
486 int thousands_offset = (max_digits - 1) % 3;
487
488 if (number < 0) {
489 builder.PutChar('-');
490 number = -number;
491 }
492
493 uint64_t num = number;
494 uint64_t tot = 0;
495 for (int i = 0; i < max_digits; i++) {
496 uint64_t quot = 0;
497 if (num >= divisor) {
498 quot = num / divisor;
499 num = num % divisor;
500 }
501 if ((tot |= quot) || i == max_digits - 1) {
502 builder.PutChar('0' + quot); // quot is a single digit
503 if ((i % 3) == thousands_offset && i < max_digits - 1) builder += separator;
504 }
505
506 divisor /= 10;
507 }
508}
509
510static void FormatCommaNumber(StringBuilder &builder, int64_t number)
511{
512 std::string_view separator = _settings_game.locale.digit_group_separator;
513 if (separator.empty()) separator = _langpack.langpack->digit_group_separator;
514 FormatNumber(builder, number, separator);
515}
516
517static void FormatNoCommaNumber(StringBuilder &builder, int64_t number)
518{
519 fmt::format_to(builder.back_inserter(), "{}", number);
520}
521
522static void FormatZerofillNumber(StringBuilder &builder, int64_t number, int count)
523{
524 fmt::format_to(builder.back_inserter(), "{:0{}d}", number, count);
525}
526
527static void FormatHexNumber(StringBuilder &builder, uint64_t number)
528{
529 fmt::format_to(builder.back_inserter(), "0x{:X}", number);
530}
531
537 static void FormatBytes(StringBuilder &builder, int64_t number)
538{
539 assert(number >= 0);
540
541 /* 1 2^10 2^20 2^30 2^40 2^50 2^60 */
542 static const std::string_view iec_prefixes[] = {"", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei"};
543 uint id = 1;
544 while (number >= 1024 * 1024) {
545 number /= 1024;
546 id++;
547 }
548
549 if (number < 1024) {
550 id = 0;
551 fmt::format_to(builder.back_inserter(), "{}", number);
552 } else if (number < 1024 * 10) {
553 fmt::format_to(builder.back_inserter(), "{}{}{:02}", number / 1024, GetDecimalSeparator(), (number % 1024) * 100 / 1024);
554 } else if (number < 1024 * 100) {
555 fmt::format_to(builder.back_inserter(), "{}{}{:01}", number / 1024, GetDecimalSeparator(), (number % 1024) * 10 / 1024);
556 } else {
557 assert(number < 1024 * 1024);
558 fmt::format_to(builder.back_inserter(), "{}", number / 1024);
559 }
560
561 assert(id < lengthof(iec_prefixes));
562 fmt::format_to(builder.back_inserter(), NBSP "{}B", iec_prefixes[id]);
563}
564
565static void FormatYmdString(StringBuilder &builder, TimerGameCalendar::Date date, uint case_index)
566{
567 TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(date);
568
569 auto tmp_params = MakeParameters(STR_DAY_NUMBER_1ST + ymd.day - 1, STR_MONTH_ABBREV_JAN + ymd.month, ymd.year);
570 FormatString(builder, GetStringPtr(STR_FORMAT_DATE_LONG), tmp_params, case_index);
571}
572
573static void FormatMonthAndYear(StringBuilder &builder, TimerGameCalendar::Date date, uint case_index)
574{
575 TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(date);
576
577 auto tmp_params = MakeParameters(STR_MONTH_JAN + ymd.month, ymd.year);
578 FormatString(builder, GetStringPtr(STR_FORMAT_DATE_SHORT), tmp_params, case_index);
579}
580
581static void FormatTinyOrISODate(StringBuilder &builder, TimerGameCalendar::Date date, StringID str)
582{
583 TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(date);
584
585 /* Day and month are zero-padded with ZEROFILL_NUM, hence the two 2s. */
586 auto tmp_params = MakeParameters(ymd.day, 2, ymd.month + 1, 2, ymd.year);
587 FormatString(builder, GetStringPtr(str), tmp_params);
588}
589
590static void FormatGenericCurrency(StringBuilder &builder, const CurrencySpec *spec, Money number, bool compact)
591{
592 /* We are going to make number absolute for printing, so
593 * keep this piece of data as we need it later on */
594 bool negative = number < 0;
595
596 number *= spec->rate;
597
598 /* convert from negative */
599 if (number < 0) {
600 builder.PutUtf8(SCC_PUSH_COLOUR);
601 builder.PutUtf8(SCC_RED);
602 builder.PutChar('-');
603 number = -number;
604 }
605
606 /* Add prefix part, following symbol_pos specification.
607 * Here, it can can be either 0 (prefix) or 2 (both prefix and suffix).
608 * The only remaining value is 1 (suffix), so everything that is not 1 */
609 if (spec->symbol_pos != 1) builder += spec->prefix;
610
611 StringID number_str = STR_NULL;
612
613 /* For huge numbers, compact the number. */
614 if (compact) {
615 /* Take care of the thousand rounding. Having 1 000 000 k
616 * and 1 000 M is inconsistent, so always use 1 000 M. */
617 if (number >= Money(1'000'000'000'000'000) - 500'000'000) {
618 number = (number + Money(500'000'000'000)) / Money(1'000'000'000'000);
619 number_str = STR_CURRENCY_SHORT_TERA;
620 } else if (number >= Money(1'000'000'000'000) - 500'000) {
621 number = (number + 500'000'000) / 1'000'000'000;
622 number_str = STR_CURRENCY_SHORT_GIGA;
623 } else if (number >= 1'000'000'000 - 500) {
624 number = (number + 500'000) / 1'000'000;
625 number_str = STR_CURRENCY_SHORT_MEGA;
626 } else if (number >= 1'000'000) {
627 number = (number + 500) / 1'000;
628 number_str = STR_CURRENCY_SHORT_KILO;
629 }
630 }
631
632 std::string_view separator = _settings_game.locale.digit_group_separator_currency;
633 if (separator.empty()) separator = GetCurrency().separator;
634 if (separator.empty()) separator = _langpack.langpack->digit_group_separator_currency;
635 FormatNumber(builder, number, separator);
636 if (number_str != STR_NULL) {
637 FormatString(builder, GetStringPtr(number_str), {});
638 }
639
640 /* Add suffix part, following symbol_pos specification.
641 * Here, it can can be either 1 (suffix) or 2 (both prefix and suffix).
642 * The only remaining value is 1 (prefix), so everything that is not 0 */
643 if (spec->symbol_pos != 0) builder += spec->suffix;
644
645 if (negative) {
646 builder.PutUtf8(SCC_POP_COLOUR);
647 }
648}
649
656 static int DeterminePluralForm(int64_t count, uint plural_form)
657{
658 /* The absolute value determines plurality */
659 uint64_t n = abs(count);
660
661 switch (plural_form) {
662 default:
663 NOT_REACHED();
664
665 /* Two forms: singular used for one only.
666 * Used in:
667 * Danish, Dutch, English, German, Norwegian, Swedish, Estonian, Finnish,
668 * Greek, Hebrew, Italian, Portuguese, Spanish, Esperanto */
669 case 0:
670 return n != 1 ? 1 : 0;
671
672 /* Only one form.
673 * Used in:
674 * Hungarian, Japanese, Turkish */
675 case 1:
676 return 0;
677
678 /* Two forms: singular used for 0 and 1.
679 * Used in:
680 * French, Brazilian Portuguese */
681 case 2:
682 return n > 1 ? 1 : 0;
683
684 /* Three forms: special cases for 0, and numbers ending in 1 except when ending in 11.
685 * Note: Cases are out of order for hysterical reasons. '0' is last.
686 * Used in:
687 * Latvian */
688 case 3:
689 return n % 10 == 1 && n % 100 != 11 ? 0 : n != 0 ? 1 : 2;
690
691 /* Five forms: special cases for 1, 2, 3 to 6, and 7 to 10.
692 * Used in:
693 * Gaelige (Irish) */
694 case 4:
695 return n == 1 ? 0 : n == 2 ? 1 : n < 7 ? 2 : n < 11 ? 3 : 4;
696
697 /* 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.
698 * Used in:
699 * Lithuanian */
700 case 5:
701 return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
702
703 /* 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.
704 * Used in:
705 * Croatian, Russian, Ukrainian */
706 case 6:
707 return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
708
709 /* Three forms: special cases for 1, and numbers ending in 2 to 4 except when ending in 12 to 14.
710 * Used in:
711 * Polish */
712 case 7:
713 return n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
714
715 /* Four forms: special cases for numbers ending in 01, 02, and 03 to 04.
716 * Used in:
717 * Slovenian */
718 case 8:
719 return n % 100 == 1 ? 0 : n % 100 == 2 ? 1 : n % 100 == 3 || n % 100 == 4 ? 2 : 3;
720
721 /* Two forms: singular used for numbers ending in 1 except when ending in 11.
722 * Used in:
723 * Icelandic */
724 case 9:
725 return n % 10 == 1 && n % 100 != 11 ? 0 : 1;
726
727 /* Three forms: special cases for 1, and 2 to 4
728 * Used in:
729 * Czech, Slovak */
730 case 10:
731 return n == 1 ? 0 : n >= 2 && n <= 4 ? 1 : 2;
732
733 /* Two forms: cases for numbers ending with a consonant, and with a vowel.
734 * Korean doesn't have the concept of plural, but depending on how a
735 * number is pronounced it needs another version of a particle.
736 * As such the plural system is misused to give this distinction.
737 */
738 case 11:
739 switch (n % 10) {
740 case 0: // yeong
741 case 1: // il
742 case 3: // sam
743 case 6: // yuk
744 case 7: // chil
745 case 8: // pal
746 return 0;
747
748 case 2: // i
749 case 4: // sa
750 case 5: // o
751 case 9: // gu
752 return 1;
753
754 default:
755 NOT_REACHED();
756 }
757
758 /* Four forms: special cases for 1, 0 and numbers ending in 02 to 10, and numbers ending in 11 to 19.
759 * Used in:
760 * Maltese */
761 case 12:
762 return (n == 1 ? 0 : n == 0 || (n % 100 > 1 && n % 100 < 11) ? 1 : (n % 100 > 10 && n % 100 < 20) ? 2 : 3);
763 /* Four forms: special cases for 1 and 11, 2 and 12, 3 .. 10 and 13 .. 19, other
764 * Used in:
765 * Scottish Gaelic */
766 case 13:
767 return ((n == 1 || n == 11) ? 0 : (n == 2 || n == 12) ? 1 : ((n > 2 && n < 11) || (n > 12 && n < 20)) ? 2 : 3);
768
769 /* Three forms: special cases for 1, 0 and numbers ending in 01 to 19.
770 * Used in:
771 * Romanian */
772 case 14:
773 return n == 1 ? 0 : (n == 0 || (n % 100 > 0 && n % 100 < 20)) ? 1 : 2;
774 }
775}
776
777static void SkipStringChoice(StringConsumer &consumer)
778{
779 uint n = consumer.ReadUint8();
780 uint len = 0;
781 for (uint i = 0; i != n; i++) {
782 len += consumer.ReadUint8();
783 }
784 consumer.Skip(len);
785}
786
787static void ParseStringChoice(StringConsumer &consumer, uint form, StringBuilder &builder)
788{
789 /* <NUM> {Length of each string} {each string} */
790 uint n = consumer.ReadUint8();
791 size_t form_pre = 0, form_len = 0, form_post = 0;
792 for (uint i = 0; i != n; i++) {
793 uint len = consumer.ReadUint8();
794 if (i < form) {
795 form_pre += len;
796 } else if (i > form) {
797 form_post += len;
798 } else {
799 form_len = len;
800 }
801 }
802
803 consumer.Skip(form_pre);
804 builder += consumer.Read(form_len);
805 consumer.Skip(form_post);
806}
807
809 struct UnitConversion {
810 double factor;
811
818 int64_t ToDisplay(int64_t input, bool round = true) const
819 {
820 return round
821 ? (int64_t)std::round(input * this->factor)
822 : (int64_t)(input * this->factor);
823 }
824
832 int64_t FromDisplay(int64_t input, bool round = true, int64_t divider = 1) const
833 {
834 return round
835 ? (int64_t)std::round(input / this->factor / divider)
836 : (int64_t)(input / this->factor / divider);
837 }
838};
839
841 struct Units {
842 UnitConversion c;
843 StringID s;
844 unsigned int decimal_places;
845};
846
848 struct UnitsLong {
849 UnitConversion c;
850 StringID s;
851 StringID l;
852 unsigned int decimal_places;
853};
854
856 static const Units _units_velocity_calendar[] = {
857 { { 1.0 }, STR_UNITS_VELOCITY_IMPERIAL, 0 },
858 { { 1.609344 }, STR_UNITS_VELOCITY_METRIC, 0 },
859 { { 0.44704 }, STR_UNITS_VELOCITY_SI, 0 },
860 { { 0.578125 }, STR_UNITS_VELOCITY_GAMEUNITS_DAY, 1 },
861 { { 0.868976 }, STR_UNITS_VELOCITY_KNOTS, 0 },
862};
863
865 static const Units _units_velocity_realtime[] = {
866 { { 1.0 }, STR_UNITS_VELOCITY_IMPERIAL, 0 },
867 { { 1.609344 }, STR_UNITS_VELOCITY_METRIC, 0 },
868 { { 0.44704 }, STR_UNITS_VELOCITY_SI, 0 },
869 { { 0.289352 }, STR_UNITS_VELOCITY_GAMEUNITS_SEC, 1 },
870 { { 0.868976 }, STR_UNITS_VELOCITY_KNOTS, 0 },
871};
872
874 static const Units _units_power[] = {
875 { { 1.0 }, STR_UNITS_POWER_IMPERIAL, 0 },
876 { { 1.01387 }, STR_UNITS_POWER_METRIC, 0 },
877 { { 0.745699 }, STR_UNITS_POWER_SI, 0 },
878};
879
881 static const Units _units_power_to_weight[] = {
882 { { 0.907185 }, STR_UNITS_POWER_IMPERIAL_TO_WEIGHT_IMPERIAL, 1 },
883 { { 1.0 }, STR_UNITS_POWER_IMPERIAL_TO_WEIGHT_METRIC, 1 },
884 { { 1.0 }, STR_UNITS_POWER_IMPERIAL_TO_WEIGHT_SI, 1 },
885 { { 0.919768 }, STR_UNITS_POWER_METRIC_TO_WEIGHT_IMPERIAL, 1 },
886 { { 1.01387 }, STR_UNITS_POWER_METRIC_TO_WEIGHT_METRIC, 1 },
887 { { 1.01387 }, STR_UNITS_POWER_METRIC_TO_WEIGHT_SI, 1 },
888 { { 0.676487 }, STR_UNITS_POWER_SI_TO_WEIGHT_IMPERIAL, 1 },
889 { { 0.745699 }, STR_UNITS_POWER_SI_TO_WEIGHT_METRIC, 1 },
890 { { 0.745699 }, STR_UNITS_POWER_SI_TO_WEIGHT_SI, 1 },
891};
892
894 static const UnitsLong _units_weight[] = {
895 { { 1.102311 }, STR_UNITS_WEIGHT_SHORT_IMPERIAL, STR_UNITS_WEIGHT_LONG_IMPERIAL, 0 },
896 { { 1.0 }, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC, 0 },
897 { { 1000.0 }, STR_UNITS_WEIGHT_SHORT_SI, STR_UNITS_WEIGHT_LONG_SI, 0 },
898};
899
901 static const UnitsLong _units_volume[] = {
902 { { 264.172 }, STR_UNITS_VOLUME_SHORT_IMPERIAL, STR_UNITS_VOLUME_LONG_IMPERIAL, 0 },
903 { { 1000.0 }, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC, 0 },
904 { { 1.0 }, STR_UNITS_VOLUME_SHORT_SI, STR_UNITS_VOLUME_LONG_SI, 0 },
905};
906
908 static const Units _units_force[] = {
909 { { 0.224809 }, STR_UNITS_FORCE_IMPERIAL, 0 },
910 { { 0.101972 }, STR_UNITS_FORCE_METRIC, 0 },
911 { { 0.001 }, STR_UNITS_FORCE_SI, 0 },
912};
913
915 static const Units _units_height[] = {
916 { { 3.0 }, STR_UNITS_HEIGHT_IMPERIAL, 0 }, // "Wrong" conversion factor for more nicer GUI values
917 { { 1.0 }, STR_UNITS_HEIGHT_METRIC, 0 },
918 { { 1.0 }, STR_UNITS_HEIGHT_SI, 0 },
919 { { .02 }, STR_UNITS_HEIGHT_GAMEUNITS,0 },
920};
921
923 static const Units _units_time_days_or_seconds[] = {
924 { { 1 }, STR_UNITS_DAYS, 0 },
925 { { 2 }, STR_UNITS_SECONDS, 0 },
926};
927
929 static const Units _units_time_months_or_minutes[] = {
930 { { 1 }, STR_UNITS_MONTHS, 0 },
931 { { 1 }, STR_UNITS_MINUTES, 0 },
932};
933
935 static const Units _units_time_years_or_periods[] = {
936 { { 1 }, STR_UNITS_YEARS, 0 },
937 { { 1 }, STR_UNITS_PERIODS, 0 },
938};
939
941 static const Units _units_time_years_or_minutes[] = {
942 { { 1 }, STR_UNITS_YEARS, 0 },
943 { { 12 }, STR_UNITS_MINUTES, 0 },
944};
945
951 static const Units GetVelocityUnits(VehicleType type)
952{
953 uint8_t setting = (type == VEH_SHIP || type == VEH_AIRCRAFT) ? _settings_game.locale.units_velocity_nautical : _settings_game.locale.units_velocity;
954
955 assert(setting < lengthof(_units_velocity_calendar));
956 assert(setting < lengthof(_units_velocity_realtime));
957
958 if (TimerGameEconomy::UsingWallclockUnits()) return _units_velocity_realtime[setting];
959
960 return _units_velocity_calendar[setting];
961}
962
968uint ConvertSpeedToDisplaySpeed(uint speed, VehicleType type)
969{
970 /* For historical reasons we don't want to mess with the
971 * conversion for speed. So, don't round it and keep the
972 * original conversion factors instead of the real ones. */
973 return GetVelocityUnits(type).c.ToDisplay(speed, false);
974}
975
981uint ConvertDisplaySpeedToSpeed(uint speed, VehicleType type)
982{
983 return GetVelocityUnits(type).c.FromDisplay(speed);
984}
985
991uint ConvertKmhishSpeedToDisplaySpeed(uint speed, VehicleType type)
992{
993 return GetVelocityUnits(type).c.ToDisplay(speed * 10, false) / 16;
994}
995
1001uint ConvertDisplaySpeedToKmhishSpeed(uint speed, VehicleType type)
1002{
1003 return GetVelocityUnits(type).c.FromDisplay(speed * 16, true, 10);
1004}
1005
1012 static void DecodeEncodedString(StringConsumer &consumer, bool game_script, StringBuilder &builder)
1013{
1014 std::vector<StringParameter> sub_args;
1015
1016 StringIndexInTab id(consumer.ReadIntegerBase<uint32_t>(16));
1017 if (consumer.AnyBytesLeft() && !consumer.PeekUtf8If(SCC_RECORD_SEPARATOR)) {
1018 consumer.SkipAll();
1019 builder += "(invalid SCC_ENCODED)";
1020 return;
1021 }
1022 if (game_script && id >= TAB_SIZE_GAMESCRIPT) {
1023 consumer.SkipAll();
1024 builder += "(invalid StringID)";
1025 return;
1026 }
1027
1028 while (consumer.AnyBytesLeft()) {
1029 consumer.SkipUtf8If(SCC_RECORD_SEPARATOR);
1030 StringConsumer record(consumer.ReadUntilUtf8(SCC_RECORD_SEPARATOR, StringConsumer::KEEP_SEPARATOR));
1031
1032 if (!record.AnyBytesLeft()) {
1033 /* This is an empty parameter. */
1034 sub_args.emplace_back(std::monostate{});
1035 continue;
1036 }
1037
1038 /* Get the parameter type. */
1039 char32_t parameter_type = record.ReadUtf8();
1040 switch (parameter_type) {
1041 case SCC_ENCODED: {
1042 uint64_t param = record.ReadIntegerBase<uint64_t>(16);
1043 if (param >= TAB_SIZE_GAMESCRIPT) {
1044 builder += "(invalid sub-StringID)";
1045 return;
1046 }
1047 assert(!record.AnyBytesLeft());
1048 param = MakeStringID(TEXT_TAB_GAMESCRIPT_START, StringIndexInTab(param));
1049 sub_args.emplace_back(param);
1050 break;
1051 }
1052
1053 case SCC_ENCODED_NUMERIC: {
1054 uint64_t param = record.ReadIntegerBase<uint64_t>(16);
1055 assert(!record.AnyBytesLeft());
1056 sub_args.emplace_back(param);
1057 break;
1058 }
1059
1060 case SCC_ENCODED_STRING: {
1061 sub_args.emplace_back(record.Read(StringConsumer::npos));
1062 break;
1063 }
1064
1065 default:
1066 /* Unknown parameter, make it blank. */
1067 sub_args.emplace_back(std::monostate{});
1068 break;
1069 }
1070 }
1071
1072 StringID stringid = game_script ? MakeStringID(TEXT_TAB_GAMESCRIPT_START, id) : StringID{id.base()};
1073 GetStringWithArgs(builder, stringid, sub_args, true);
1074}
1075
1083 static void FormatString(StringBuilder &builder, std::string_view str_arg, StringParameters &args, uint orig_case_index, bool game_script, bool dry_run)
1084{
1085 size_t orig_first_param_offset = args.GetOffset();
1086
1087 if (!dry_run) {
1088 /*
1089 * This function is normally called with `dry_run` false, then we call this function again
1090 * with `dry_run` being true. The dry run is required for the gender formatting. For the
1091 * gender determination we need to format a sub string to get the gender, but for that we
1092 * need to know as what string control code type the specific parameter is encoded. Since
1093 * gendered words can be before the "parameter" words, this needs to be determined before
1094 * the actual formatting.
1095 */
1096 std::string buffer;
1097 StringBuilder dry_run_builder(buffer);
1098 FormatString(dry_run_builder, str_arg, args, orig_case_index, game_script, true);
1099 /* We have to restore the original offset here to to read the correct values. */
1100 args.SetOffset(orig_first_param_offset);
1101 }
1102 uint next_substr_case_index = 0;
1103 struct StrStackItem {
1104 StringConsumer consumer;
1105 size_t first_param_offset;
1106 uint case_index;
1107
1108 StrStackItem(std::string_view view, size_t first_param_offset, uint case_index)
1109 : consumer(view), first_param_offset(first_param_offset), case_index(case_index)
1110 {}
1111 };
1112 std::stack<StrStackItem, std::vector<StrStackItem>> str_stack;
1113 str_stack.emplace(str_arg, orig_first_param_offset, orig_case_index);
1114
1115 for (;;) {
1116 try {
1117 while (!str_stack.empty() && !str_stack.top().consumer.AnyBytesLeft()) {
1118 str_stack.pop();
1119 }
1120 if (str_stack.empty()) break;
1121 StringConsumer &consumer = str_stack.top().consumer;
1122 const size_t ref_param_offset = str_stack.top().first_param_offset;
1123 const uint case_index = str_stack.top().case_index;
1124 char32_t b = consumer.ReadUtf8();
1125 assert(b != 0);
1126 if (b == 0) {
1127 /* A NUL character should never be encountered, but for non-debug builds handle it gracefully. */
1128 builder += "(unexpected NUL)";
1129 continue;
1130 }
1131
1132 if (SCC_NEWGRF_FIRST <= b && b <= SCC_NEWGRF_LAST) {
1133 /* We need to pass some stuff as it might be modified. */
1134 b = RemapNewGRFStringControlCode(b, consumer);
1135 if (b == 0) continue;
1136 }
1137
1138 if (b < SCC_CONTROL_START || b > SCC_CONTROL_END) {
1139 builder.PutUtf8(b);
1140 continue;
1141 }
1142
1143 args.SetTypeOfNextParameter(b);
1144 switch (b) {
1145 case SCC_ENCODED:
1146 case SCC_ENCODED_INTERNAL:
1147 DecodeEncodedString(consumer, b == SCC_ENCODED, builder);
1148 break;
1149
1150 case SCC_NEWGRF_STRINL: {
1151 StringID substr = consumer.ReadUtf8(STR_NULL);
1152 std::string_view ptr = GetStringPtr(substr);
1153 str_stack.emplace(ptr, args.GetOffset(), next_substr_case_index); // this may invalidate "consumer"
1154 next_substr_case_index = 0;
1155 break;
1156 }
1157
1158 case SCC_NEWGRF_PRINT_WORD_STRING_ID: {
1159 StringID substr = args.GetNextParameter<StringID>();
1160 std::string_view ptr = GetStringPtr(substr);
1161 str_stack.emplace(ptr, args.GetOffset(), next_substr_case_index); // this may invalidate "consumer"
1162 next_substr_case_index = 0;
1163 break;
1164 }
1165
1166 case SCC_GENDER_LIST: { // {G 0 Der Die Das}
1167 /* First read the meta data from the language file. */
1168 size_t offset = ref_param_offset + consumer.ReadUint8();
1169 uint8_t gender = 0;
1170 if (offset >= args.GetNumParameters()) {
1171 /* The offset may come from an external NewGRF, and be invalid. */
1172 builder += "(invalid GENDER parameter)";
1173 } else if (!dry_run && args.GetTypeAtOffset(offset) != 0) {
1174 /* Now we need to figure out what text to resolve, i.e.
1175 * what do we need to draw? So get the actual raw string
1176 * first using the control code to get said string. */
1177 std::string input;
1178 {
1179 StringBuilder tmp_builder(input);
1180 tmp_builder.PutUtf8(args.GetTypeAtOffset(offset));
1181 }
1182
1183 std::string buffer;
1184 {
1185 AutoRestoreBackup sgd_backup(_scan_for_gender_data, true);
1186 StringBuilder tmp_builder(buffer);
1187 StringParameters tmp_params = args.GetRemainingParameters(offset);
1188 FormatString(tmp_builder, input, tmp_params);
1189 }
1190
1191 /* The gender is stored at the start of the formatted string.
1192 * Does this string have a gender, if so, set it. */
1193 StringConsumer gender_consumer(buffer);
1194 if (gender_consumer.ReadUtf8If(SCC_GENDER_INDEX)) {
1195 gender = gender_consumer.ReadUint8();
1196 }
1197 }
1198 ParseStringChoice(consumer, gender, builder);
1199 break;
1200 }
1201
1202 /* This sets up the gender for the string.
1203 * We just ignore this one. It's used in {G 0 Der Die Das} to determine the case. */
1204 case SCC_GENDER_INDEX: { // {GENDER 0}
1205 uint8_t gender = consumer.ReadUint8();
1206 if (_scan_for_gender_data) {
1207 builder.PutUtf8(SCC_GENDER_INDEX);
1208 builder.PutUint8(gender);
1209 }
1210 break;
1211 }
1212
1213 case SCC_PLURAL_LIST: { // {P}
1214 uint8_t plural_form = consumer.ReadUint8(); // contains the plural form for this string
1215 size_t offset = ref_param_offset + consumer.ReadUint8();
1216 const uint64_t *v = nullptr;
1217 /* The offset may come from an external NewGRF, and be invalid. */
1218 if (offset < args.GetNumParameters()) {
1219 v = std::get_if<uint64_t>(&args.GetParam(offset)); // contains the number that determines plural
1220 }
1221 if (v != nullptr) {
1222 ParseStringChoice(consumer, DeterminePluralForm(static_cast<int64_t>(*v), plural_form), builder);
1223 } else {
1224 SkipStringChoice(consumer);
1225 builder += "(invalid PLURAL parameter)";
1226 }
1227 break;
1228 }
1229
1230 case SCC_ARG_INDEX: { // Move argument pointer
1231 args.SetOffset(ref_param_offset + consumer.ReadUint8());
1232 break;
1233 }
1234
1235 case SCC_SET_CASE: { // {SET_CASE}
1236 /* This is a pseudo command, it's outputted when someone does {STRING.ack}
1237 * The modifier is added to all subsequent GetStringWithArgs that accept the modifier. */
1238 next_substr_case_index = consumer.ReadUint8();
1239 break;
1240 }
1241
1242 case SCC_SWITCH_CASE: { // {Used to implement case switching}
1243 /* <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <LENDEFAULT> <STRINGDEFAULT>
1244 * Each LEN is printed using 2 bytes in little endian order. */
1245 uint num = consumer.ReadUint8();
1246 std::optional<std::string_view> found;
1247 for (; num > 0; --num) {
1248 uint8_t index = consumer.ReadUint8();
1249 uint16_t len = consumer.ReadUint16LE();
1250 auto case_str = consumer.Read(len);
1251 if (index == case_index) {
1252 /* Found the case */
1253 found = case_str;
1254 }
1255 }
1256 uint16_t default_len = consumer.ReadUint16LE();
1257 auto default_str = consumer.Read(default_len);
1258 if (!found.has_value()) found = default_str;
1259 str_stack.emplace(*found, ref_param_offset, case_index); // this may invalidate "consumer"
1260 break;
1261 }
1262
1263 case SCC_REVISION: // {REV}
1264 builder += _openttd_revision;
1265 break;
1266
1267 case SCC_RAW_STRING_POINTER: // {RAW_STRING}
1268 FormatString(builder, args.GetNextParameterString(), args);
1269 break;
1270
1271 case SCC_STRING: {// {STRING}
1272 StringID string_id = args.GetNextParameter<StringID>();
1273 if (game_script && GetStringTab(string_id) != TEXT_TAB_GAMESCRIPT_START) break;
1274 /* It's prohibited for the included string to consume any arguments. */
1275 StringParameters tmp_params(args, game_script ? args.GetDataLeft() : 0);
1276 GetStringWithArgs(builder, string_id, tmp_params, next_substr_case_index, game_script);
1277 next_substr_case_index = 0;
1278 break;
1279 }
1280
1281 case SCC_STRING1:
1282 case SCC_STRING2:
1283 case SCC_STRING3:
1284 case SCC_STRING4:
1285 case SCC_STRING5:
1286 case SCC_STRING6:
1287 case SCC_STRING7: { // {STRING1..7}
1288 /* Strings that consume arguments */
1289 StringID string_id = args.GetNextParameter<StringID>();
1290 if (game_script && GetStringTab(string_id) != TEXT_TAB_GAMESCRIPT_START) break;
1291 uint size = b - SCC_STRING1 + 1;
1292 if (size > args.GetDataLeft()) {
1293 builder += "(consumed too many parameters)";
1294 } else {
1295 StringParameters sub_args(args, game_script ? args.GetDataLeft() : size);
1296 GetStringWithArgs(builder, string_id, sub_args, next_substr_case_index, game_script);
1297 args.AdvanceOffset(size);
1298 }
1299 next_substr_case_index = 0;
1300 break;
1301 }
1302
1303 case SCC_COMMA: // {COMMA}
1304 FormatCommaNumber(builder, args.GetNextParameter<int64_t>());
1305 break;
1306
1307 case SCC_DECIMAL: { // {DECIMAL}
1308 int64_t number = args.GetNextParameter<int64_t>();
1309 int digits = args.GetNextParameter<int>();
1310 if (digits == 0) {
1311 FormatCommaNumber(builder, number);
1312 break;
1313 }
1314
1315 int64_t divisor = PowerOfTen(digits);
1316 int64_t fractional = number % divisor;
1317 number /= divisor;
1318 FormatCommaNumber(builder, number);
1319 fmt::format_to(builder.back_inserter(), "{}{:0{}d}", GetDecimalSeparator(), fractional, digits);
1320 break;
1321 }
1322
1323 case SCC_NUM: // {NUM}
1324 FormatNoCommaNumber(builder, args.GetNextParameter<int64_t>());
1325 break;
1326
1327 case SCC_ZEROFILL_NUM: { // {ZEROFILL_NUM}
1328 int64_t num = args.GetNextParameter<int64_t>();
1329 FormatZerofillNumber(builder, num, args.GetNextParameter<int>());
1330 break;
1331 }
1332
1333 case SCC_HEX: // {HEX}
1334 FormatHexNumber(builder, args.GetNextParameter<uint64_t>());
1335 break;
1336
1337 case SCC_BYTES: // {BYTES}
1338 FormatBytes(builder, args.GetNextParameter<int64_t>());
1339 break;
1340
1341 case SCC_CARGO_TINY: { // {CARGO_TINY}
1342 /* Tiny description of cargotypes. Layout:
1343 * param 1: cargo type
1344 * param 2: cargo count */
1345 CargoType cargo = args.GetNextParameter<CargoType>();
1346 int64_t amount = args.GetNextParameter<int64_t>();
1347
1348 if (cargo >= CargoSpec::GetArraySize()) {
1349 builder += "(invalid cargo type)";
1350 break;
1351 }
1352
1353 switch (CargoSpec::Get(cargo)->units_volume) {
1354 case STR_TONS:
1355 amount = _units_weight[_settings_game.locale.units_weight].c.ToDisplay(amount);
1356 break;
1357
1358 case STR_LITERS:
1359 amount = _units_volume[_settings_game.locale.units_volume].c.ToDisplay(amount);
1360 break;
1361
1362 default:
1363 break;
1364 }
1365
1366 FormatCommaNumber(builder, amount);
1367 break;
1368 }
1369
1370 case SCC_CARGO_SHORT: { // {CARGO_SHORT}
1371 /* Short description of cargotypes. Layout:
1372 * param 1: cargo type
1373 * param 2: cargo count */
1374 CargoType cargo = args.GetNextParameter<CargoType>();
1375 int64_t amount = args.GetNextParameter<int64_t>();
1376
1377 if (cargo >= CargoSpec::GetArraySize()) {
1378 builder += "(invalid cargo type)";
1379 break;
1380 }
1381
1382 StringID cargo_str = CargoSpec::Get(cargo)->units_volume;
1383 switch (cargo_str) {
1384 case STR_TONS: {
1385 assert(_settings_game.locale.units_weight < lengthof(_units_weight));
1386 const auto &x = _units_weight[_settings_game.locale.units_weight];
1387 auto tmp_params = MakeParameters(x.c.ToDisplay(amount), x.decimal_places);
1388 FormatString(builder, GetStringPtr(x.l), tmp_params);
1389 break;
1390 }
1391
1392 case STR_LITERS: {
1393 assert(_settings_game.locale.units_volume < lengthof(_units_volume));
1394 const auto &x = _units_volume[_settings_game.locale.units_volume];
1395 auto tmp_params = MakeParameters(x.c.ToDisplay(amount), x.decimal_places);
1396 FormatString(builder, GetStringPtr(x.l), tmp_params);
1397 break;
1398 }
1399
1400 default: {
1401 auto tmp_params = MakeParameters(amount);
1402 GetStringWithArgs(builder, cargo_str, tmp_params);
1403 break;
1404 }
1405 }
1406 break;
1407 }
1408
1409 case SCC_CARGO_LONG: { // {CARGO_LONG}
1410 /* First parameter is cargo type, second parameter is cargo count */
1411 CargoType cargo = args.GetNextParameter<CargoType>();
1412 int64_t amount = args.GetNextParameter<int64_t>();
1413 if (cargo < CargoSpec::GetArraySize()) {
1414 auto tmp_args = MakeParameters(amount);
1415 GetStringWithArgs(builder, CargoSpec::Get(cargo)->quantifier, tmp_args);
1416 } else if (!IsValidCargoType(cargo)) {
1417 GetStringWithArgs(builder, STR_QUANTITY_N_A, {});
1418 } else {
1419 builder += "(invalid cargo type)";
1420 }
1421 break;
1422 }
1423
1424 case SCC_CARGO_LIST: { // {CARGO_LIST}
1425 CargoTypes cmask = args.GetNextParameter<CargoTypes>();
1426 bool first = true;
1427
1428 std::string_view list_separator = GetListSeparator();
1429 for (const auto &cs : _sorted_cargo_specs) {
1430 if (!HasBit(cmask, cs->Index())) continue;
1431
1432 if (first) {
1433 first = false;
1434 } else {
1435 /* Add a comma if this is not the first item */
1436 builder += list_separator;
1437 }
1438
1439 GetStringWithArgs(builder, cs->name, args, next_substr_case_index, game_script);
1440 }
1441
1442 /* If first is still true then no cargo is accepted */
1443 if (first) GetStringWithArgs(builder, STR_JUST_NOTHING, args, next_substr_case_index, game_script);
1444
1445 next_substr_case_index = 0;
1446 break;
1447 }
1448
1449 case SCC_CURRENCY_SHORT: // {CURRENCY_SHORT}
1450 FormatGenericCurrency(builder, &GetCurrency(), args.GetNextParameter<int64_t>(), true);
1451 break;
1452
1453 case SCC_CURRENCY_LONG: // {CURRENCY_LONG}
1454 FormatGenericCurrency(builder, &GetCurrency(), args.GetNextParameter<int64_t>(), false);
1455 break;
1456
1457 case SCC_DATE_TINY: // {DATE_TINY}
1458 FormatTinyOrISODate(builder, args.GetNextParameter<TimerGameCalendar::Date>(), STR_FORMAT_DATE_TINY);
1459 break;
1460
1461 case SCC_DATE_SHORT: // {DATE_SHORT}
1462 FormatMonthAndYear(builder, args.GetNextParameter<TimerGameCalendar::Date>(), next_substr_case_index);
1463 next_substr_case_index = 0;
1464 break;
1465
1466 case SCC_DATE_LONG: // {DATE_LONG}
1467 FormatYmdString(builder, args.GetNextParameter<TimerGameCalendar::Date>(), next_substr_case_index);
1468 next_substr_case_index = 0;
1469 break;
1470
1471 case SCC_DATE_ISO: // {DATE_ISO}
1472 FormatTinyOrISODate(builder, args.GetNextParameter<TimerGameCalendar::Date>(), STR_FORMAT_DATE_ISO);
1473 break;
1474
1475 case SCC_FORCE: { // {FORCE}
1476 assert(_settings_game.locale.units_force < lengthof(_units_force));
1477 const auto &x = _units_force[_settings_game.locale.units_force];
1478 auto tmp_params = MakeParameters(x.c.ToDisplay(args.GetNextParameter<int64_t>()), x.decimal_places);
1479 FormatString(builder, GetStringPtr(x.s), tmp_params);
1480 break;
1481 }
1482
1483 case SCC_HEIGHT: { // {HEIGHT}
1484 assert(_settings_game.locale.units_height < lengthof(_units_height));
1485 const auto &x = _units_height[_settings_game.locale.units_height];
1486 auto tmp_params = MakeParameters(x.c.ToDisplay(args.GetNextParameter<int64_t>()), x.decimal_places);
1487 FormatString(builder, GetStringPtr(x.s), tmp_params);
1488 break;
1489 }
1490
1491 case SCC_POWER: { // {POWER}
1492 assert(_settings_game.locale.units_power < lengthof(_units_power));
1493 const auto &x = _units_power[_settings_game.locale.units_power];
1494 auto tmp_params = MakeParameters(x.c.ToDisplay(args.GetNextParameter<int64_t>()), x.decimal_places);
1495 FormatString(builder, GetStringPtr(x.s), tmp_params);
1496 break;
1497 }
1498
1499 case SCC_POWER_TO_WEIGHT: { // {POWER_TO_WEIGHT}
1500 auto setting = _settings_game.locale.units_power * 3u + _settings_game.locale.units_weight;
1501 assert(setting < lengthof(_units_power_to_weight));
1502 const auto &x = _units_power_to_weight[setting];
1503 auto tmp_params = MakeParameters(x.c.ToDisplay(args.GetNextParameter<int64_t>()), x.decimal_places);
1504 FormatString(builder, GetStringPtr(x.s), tmp_params);
1505 break;
1506 }
1507
1508 case SCC_VELOCITY: { // {VELOCITY}
1509 int64_t arg = args.GetNextParameter<int64_t>();
1510 /* Unpack vehicle type from packed argument to get desired units. */
1511 VehicleType vt = static_cast<VehicleType>(GB(arg, 56, 8));
1512 const auto &x = GetVelocityUnits(vt);
1513 auto tmp_params = MakeParameters(ConvertKmhishSpeedToDisplaySpeed(GB(arg, 0, 56), vt), x.decimal_places);
1514 FormatString(builder, GetStringPtr(x.s), tmp_params);
1515 break;
1516 }
1517
1518 case SCC_VOLUME_SHORT: { // {VOLUME_SHORT}
1519 assert(_settings_game.locale.units_volume < lengthof(_units_volume));
1520 const auto &x = _units_volume[_settings_game.locale.units_volume];
1521 auto tmp_params = MakeParameters(x.c.ToDisplay(args.GetNextParameter<int64_t>()), x.decimal_places);
1522 FormatString(builder, GetStringPtr(x.s), tmp_params);
1523 break;
1524 }
1525
1526 case SCC_VOLUME_LONG: { // {VOLUME_LONG}
1527 assert(_settings_game.locale.units_volume < lengthof(_units_volume));
1528 const auto &x = _units_volume[_settings_game.locale.units_volume];
1529 auto tmp_params = MakeParameters(x.c.ToDisplay(args.GetNextParameter<int64_t>()), x.decimal_places);
1530 FormatString(builder, GetStringPtr(x.l), tmp_params);
1531 break;
1532 }
1533
1534 case SCC_WEIGHT_SHORT: { // {WEIGHT_SHORT}
1535 assert(_settings_game.locale.units_weight < lengthof(_units_weight));
1536 const auto &x = _units_weight[_settings_game.locale.units_weight];
1537 auto tmp_params = MakeParameters(x.c.ToDisplay(args.GetNextParameter<int64_t>()), x.decimal_places);
1538 FormatString(builder, GetStringPtr(x.s), tmp_params);
1539 break;
1540 }
1541
1542 case SCC_WEIGHT_LONG: { // {WEIGHT_LONG}
1543 assert(_settings_game.locale.units_weight < lengthof(_units_weight));
1544 const auto &x = _units_weight[_settings_game.locale.units_weight];
1545 auto tmp_params = MakeParameters(x.c.ToDisplay(args.GetNextParameter<int64_t>()), x.decimal_places);
1546 FormatString(builder, GetStringPtr(x.l), tmp_params);
1547 break;
1548 }
1549
1550 case SCC_UNITS_DAYS_OR_SECONDS: { // {UNITS_DAYS_OR_SECONDS}
1551 uint8_t realtime = TimerGameEconomy::UsingWallclockUnits(_game_mode == GM_MENU);
1552 const auto &x = _units_time_days_or_seconds[realtime];
1553 auto tmp_params = MakeParameters(x.c.ToDisplay(args.GetNextParameter<int64_t>()), x.decimal_places);
1554 FormatString(builder, GetStringPtr(x.s), tmp_params);
1555 break;
1556 }
1557
1558 case SCC_UNITS_MONTHS_OR_MINUTES: { // {UNITS_MONTHS_OR_MINUTES}
1559 uint8_t realtime = TimerGameEconomy::UsingWallclockUnits(_game_mode == GM_MENU);
1560 const auto &x = _units_time_months_or_minutes[realtime];
1561 auto tmp_params = MakeParameters(x.c.ToDisplay(args.GetNextParameter<int64_t>()), x.decimal_places);
1562 FormatString(builder, GetStringPtr(x.s), tmp_params);
1563 break;
1564 }
1565
1566 case SCC_UNITS_YEARS_OR_PERIODS: { // {UNITS_YEARS_OR_PERIODS}
1567 uint8_t realtime = TimerGameEconomy::UsingWallclockUnits(_game_mode == GM_MENU);
1568 const auto &x = _units_time_years_or_periods[realtime];
1569 auto tmp_params = MakeParameters(x.c.ToDisplay(args.GetNextParameter<int64_t>()), x.decimal_places);
1570 FormatString(builder, GetStringPtr(x.s), tmp_params);
1571 break;
1572 }
1573
1574 case SCC_UNITS_YEARS_OR_MINUTES: { // {UNITS_YEARS_OR_MINUTES}
1575 uint8_t realtime = TimerGameEconomy::UsingWallclockUnits(_game_mode == GM_MENU);
1576 const auto &x = _units_time_years_or_minutes[realtime];
1577 auto tmp_params = MakeParameters(x.c.ToDisplay(args.GetNextParameter<int64_t>()), x.decimal_places);
1578 FormatString(builder, GetStringPtr(x.s), tmp_params);
1579 break;
1580 }
1581
1582 case SCC_COMPANY_NAME: { // {COMPANY}
1583 const Company *c = Company::GetIfValid(args.GetNextParameter<CompanyID>());
1584 if (c == nullptr) break;
1585
1586 if (!c->name.empty()) {
1587 auto tmp_params = MakeParameters(c->name);
1588 GetStringWithArgs(builder, STR_JUST_RAW_STRING, tmp_params);
1589 } else {
1590 auto tmp_params = MakeParameters(c->name_2);
1591 GetStringWithArgs(builder, c->name_1, tmp_params);
1592 }
1593 break;
1594 }
1595
1596 case SCC_COMPANY_NUM: { // {COMPANY_NUM}
1597 CompanyID company = args.GetNextParameter<CompanyID>();
1598
1599 /* Nothing is added for AI or inactive companies */
1600 if (Company::IsValidHumanID(company)) {
1601 auto tmp_params = MakeParameters(company + 1);
1602 GetStringWithArgs(builder, STR_FORMAT_COMPANY_NUM, tmp_params);
1603 }
1604 break;
1605 }
1606
1607 case SCC_DEPOT_NAME: { // {DEPOT}
1608 VehicleType vt = args.GetNextParameter<VehicleType>();
1609 if (vt == VEH_AIRCRAFT) {
1610 auto tmp_params = MakeParameters(args.GetNextParameter<StationID>());
1611 GetStringWithArgs(builder, STR_FORMAT_DEPOT_NAME_AIRCRAFT, tmp_params);
1612 break;
1613 }
1614
1615 const Depot *d = Depot::Get(args.GetNextParameter<DepotID>());
1616 if (!d->name.empty()) {
1617 auto tmp_params = MakeParameters(d->name);
1618 GetStringWithArgs(builder, STR_JUST_RAW_STRING, tmp_params);
1619 } else {
1620 auto tmp_params = MakeParameters(d->town->index, d->town_cn + 1);
1621 GetStringWithArgs(builder, STR_FORMAT_DEPOT_NAME_TRAIN + 2 * vt + (d->town_cn == 0 ? 0 : 1), tmp_params);
1622 }
1623 break;
1624 }
1625
1626 case SCC_ENGINE_NAME: { // {ENGINE}
1627 int64_t arg = args.GetNextParameter<int64_t>();
1628 const Engine *e = Engine::GetIfValid(static_cast<EngineID>(arg));
1629 if (e == nullptr) break;
1630
1631 if (!e->name.empty() && e->IsEnabled()) {
1632 auto tmp_params = MakeParameters(e->name);
1633 GetStringWithArgs(builder, STR_JUST_RAW_STRING, tmp_params);
1634 break;
1635 }
1636
1637 if (e->info.callback_mask.Test(VehicleCallbackMask::Name)) {
1638 std::array<int32_t, 16> regs100;
1639 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_NAME, static_cast<uint32_t>(arg >> 32), 0, e->index, nullptr, regs100);
1640 /* Not calling ErrorUnknownCallbackResult due to being inside string processing. */
1641 if (callback == 0x40F) {
1642 const GRFFile *grffile = e->GetGRF();
1643 assert(grffile != nullptr);
1644
1645 builder += GetGRFStringWithTextStack(grffile, static_cast<GRFStringID>(regs100[0]), std::span{regs100}.subspan(1));
1646 break;
1647 } else if (callback < 0x400) {
1648 const GRFFile *grffile = e->GetGRF();
1649 assert(grffile != nullptr);
1650
1651 builder += GetGRFStringWithTextStack(grffile, GRFSTR_MISC_GRF_TEXT + callback, regs100);
1652 break;
1653 }
1654 }
1655
1656 GetStringWithArgs(builder, e->info.string_id, {});
1657 break;
1658 }
1659
1660 case SCC_GROUP_NAME: { // {GROUP}
1661 const Group *g = Group::GetIfValid(args.GetNextParameter<GroupID>());
1662 if (g == nullptr) break;
1663
1664 if (!g->name.empty()) {
1665 auto tmp_params = MakeParameters(g->name);
1666 GetStringWithArgs(builder, STR_JUST_RAW_STRING, tmp_params);
1667 } else {
1668 auto tmp_params = MakeParameters(g->number);
1669 GetStringWithArgs(builder, STR_FORMAT_GROUP_NAME, tmp_params);
1670 }
1671 break;
1672 }
1673
1674 case SCC_INDUSTRY_NAME: { // {INDUSTRY}
1675 const Industry *i = Industry::GetIfValid(args.GetNextParameter<IndustryID>());
1676 if (i == nullptr) break;
1677
1678 static bool use_cache = true;
1679 if (_scan_for_gender_data) {
1680 /* Gender is defined by the industry type.
1681 * STR_FORMAT_INDUSTRY_NAME may have the town first, so it would result in the gender of the town name */
1682 FormatString(builder, GetStringPtr(GetIndustrySpec(i->type)->name), {}, next_substr_case_index);
1683 } else if (use_cache) { // Use cached version if first call
1684 AutoRestoreBackup cache_backup(use_cache, false);
1685 builder += i->GetCachedName();
1686 } else {
1687 /* First print the town name and the industry type name. */
1688 auto tmp_params = MakeParameters(i->town->index, GetIndustrySpec(i->type)->name);
1689 FormatString(builder, GetStringPtr(STR_FORMAT_INDUSTRY_NAME), tmp_params, next_substr_case_index);
1690 }
1691 next_substr_case_index = 0;
1692 break;
1693 }
1694
1695 case SCC_PRESIDENT_NAME: { // {PRESIDENT_NAME}
1696 const Company *c = Company::GetIfValid(args.GetNextParameter<CompanyID>());
1697 if (c == nullptr) break;
1698
1699 if (!c->president_name.empty()) {
1700 auto tmp_params = MakeParameters(c->president_name);
1701 GetStringWithArgs(builder, STR_JUST_RAW_STRING, tmp_params);
1702 } else {
1703 auto tmp_params = MakeParameters(c->president_name_2);
1704 GetStringWithArgs(builder, c->president_name_1, tmp_params);
1705 }
1706 break;
1707 }
1708
1709 case SCC_STATION_NAME: { // {STATION}
1710 StationID sid = args.GetNextParameter<StationID>();
1711 const Station *st = Station::GetIfValid(sid);
1712
1713 if (st == nullptr) {
1714 /* The station doesn't exist anymore. The only place where we might
1715 * be "drawing" an invalid station is in the case of cargo that is
1716 * in transit. */
1717 GetStringWithArgs(builder, STR_UNKNOWN_STATION, {});
1718 break;
1719 }
1720
1721 static bool use_cache = true;
1722 if (use_cache) { // Use cached version if first call
1723 AutoRestoreBackup cache_backup(use_cache, false);
1724 builder += st->GetCachedName();
1725 } else if (!st->name.empty()) {
1726 auto tmp_params = MakeParameters(st->name);
1727 GetStringWithArgs(builder, STR_JUST_RAW_STRING, tmp_params);
1728 } else {
1729 StringID string_id = st->string_id;
1730 if (st->indtype != IT_INVALID) {
1731 /* Special case where the industry provides the name for the station */
1732 const IndustrySpec *indsp = GetIndustrySpec(st->indtype);
1733
1734 /* Industry GRFs can change which might remove the station name and
1735 * thus cause very strange things. Here we check for that before we
1736 * actually set the station name. */
1737 if (indsp->station_name != STR_NULL && indsp->station_name != STR_UNDEFINED) {
1738 string_id = indsp->station_name;
1739 }
1740 }
1741
1742 auto tmp_params = MakeParameters(STR_TOWN_NAME, st->town->index, st->index);
1743 GetStringWithArgs(builder, string_id, tmp_params);
1744 }
1745 break;
1746 }
1747
1748 case SCC_TOWN_NAME: { // {TOWN}
1749 const Town *t = Town::GetIfValid(args.GetNextParameter<TownID>());
1750 if (t == nullptr) break;
1751
1752 static bool use_cache = true;
1753 if (use_cache) { // Use cached version if first call
1754 AutoRestoreBackup cache_backup(use_cache, false);
1755 builder += t->GetCachedName();
1756 } else if (!t->name.empty()) {
1757 auto tmp_params = MakeParameters(t->name);
1758 GetStringWithArgs(builder, STR_JUST_RAW_STRING, tmp_params);
1759 } else {
1760 GetTownName(builder, t);
1761 }
1762 break;
1763 }
1764
1765 case SCC_WAYPOINT_NAME: { // {WAYPOINT}
1766 Waypoint *wp = Waypoint::GetIfValid(args.GetNextParameter<StationID>());
1767 if (wp == nullptr) break;
1768
1769 if (!wp->name.empty()) {
1770 auto tmp_params = MakeParameters(wp->name);
1771 GetStringWithArgs(builder, STR_JUST_RAW_STRING, tmp_params);
1772 } else {
1773 auto tmp_params = MakeParameters(wp->town->index, wp->town_cn + 1);
1774 StringID string_id = ((wp->string_id == STR_SV_STNAME_BUOY) ? STR_FORMAT_BUOY_NAME : STR_FORMAT_WAYPOINT_NAME);
1775 if (wp->town_cn != 0) string_id++;
1776 GetStringWithArgs(builder, string_id, tmp_params);
1777 }
1778 break;
1779 }
1780
1781 case SCC_VEHICLE_NAME: { // {VEHICLE}
1782 const Vehicle *v = Vehicle::GetIfValid(args.GetNextParameter<VehicleID>());
1783 if (v == nullptr) break;
1784
1785 if (!v->name.empty()) {
1786 auto tmp_params = MakeParameters(v->name);
1787 GetStringWithArgs(builder, STR_JUST_RAW_STRING, tmp_params);
1788 } else if (v->group_id != DEFAULT_GROUP) {
1789 /* The vehicle has no name, but is member of a group, so print group name */
1790 auto tmp_params = MakeParameters(v->group_id, v->unitnumber);
1791 GetStringWithArgs(builder, STR_FORMAT_GROUP_VEHICLE_NAME, tmp_params);
1792 } else {
1793 auto tmp_params = MakeParameters(v->unitnumber);
1794
1795 StringID string_id;
1796 switch (v->type) {
1797 default: string_id = STR_INVALID_VEHICLE; break;
1798 case VEH_TRAIN: string_id = STR_SV_TRAIN_NAME; break;
1799 case VEH_ROAD: string_id = STR_SV_ROAD_VEHICLE_NAME; break;
1800 case VEH_SHIP: string_id = STR_SV_SHIP_NAME; break;
1801 case VEH_AIRCRAFT: string_id = STR_SV_AIRCRAFT_NAME; break;
1802 }
1803
1804 GetStringWithArgs(builder, string_id, tmp_params);
1805 }
1806 break;
1807 }
1808
1809 case SCC_SIGN_NAME: { // {SIGN}
1810 const Sign *si = Sign::GetIfValid(args.GetNextParameter<SignID>());
1811 if (si == nullptr) break;
1812
1813 if (!si->name.empty()) {
1814 auto tmp_params = MakeParameters(si->name);
1815 GetStringWithArgs(builder, STR_JUST_RAW_STRING, tmp_params);
1816 } else {
1817 GetStringWithArgs(builder, STR_DEFAULT_SIGN_NAME, {});
1818 }
1819 break;
1820 }
1821
1822 case SCC_STATION_FEATURES: { // {STATIONFEATURES}
1823 StationGetSpecialString(builder, args.GetNextParameter<StationFacilities>());
1824 break;
1825 }
1826
1827 case SCC_COLOUR: { // {COLOUR}
1828 StringControlCode scc = (StringControlCode)(SCC_BLUE + args.GetNextParameter<Colours>());
1829 if (IsInsideMM(scc, SCC_BLUE, SCC_COLOUR)) builder.PutUtf8(scc);
1830 break;
1831 }
1832
1833 default:
1834 builder.PutUtf8(b);
1835 break;
1836 }
1837 } catch (std::out_of_range &e) {
1838 Debug(misc, 0, "FormatString: {}", e.what());
1839 builder += "(invalid parameter)";
1840 }
1841 }
1842}
1843
1844
1845static void StationGetSpecialString(StringBuilder &builder, StationFacilities x)
1846{
1847 if (x.Test(StationFacility::Train)) builder.PutUtf8(SCC_TRAIN);
1848 if (x.Test(StationFacility::TruckStop)) builder.PutUtf8(SCC_LORRY);
1849 if (x.Test(StationFacility::BusStop)) builder.PutUtf8(SCC_BUS);
1850 if (x.Test(StationFacility::Dock)) builder.PutUtf8(SCC_SHIP);
1851 if (x.Test(StationFacility::Airport)) builder.PutUtf8(SCC_PLANE);
1852}
1853
1854static const std::string_view _silly_company_names[] = {
1855 "Bloggs Brothers",
1856 "Tiny Transport Ltd.",
1857 "Express Travel",
1858 "Comfy-Coach & Co.",
1859 "Crush & Bump Ltd.",
1860 "Broken & Late Ltd.",
1861 "Sam Speedy & Son",
1862 "Supersonic Travel",
1863 "Mike's Motors",
1864 "Lightning International",
1865 "Pannik & Loozit Ltd.",
1866 "Inter-City Transport",
1867 "Getout & Pushit Ltd."
1868};
1869
1870static const std::string_view _surname_list[] = {
1871 "Adams",
1872 "Allan",
1873 "Baker",
1874 "Bigwig",
1875 "Black",
1876 "Bloggs",
1877 "Brown",
1878 "Campbell",
1879 "Gordon",
1880 "Hamilton",
1881 "Hawthorn",
1882 "Higgins",
1883 "Green",
1884 "Gribble",
1885 "Jones",
1886 "McAlpine",
1887 "MacDonald",
1888 "McIntosh",
1889 "Muir",
1890 "Murphy",
1891 "Nelson",
1892 "O'Donnell",
1893 "Parker",
1894 "Phillips",
1895 "Pilkington",
1896 "Quigley",
1897 "Sharkey",
1898 "Thomson",
1899 "Watkins"
1900};
1901
1902static const std::string_view _silly_surname_list[] = {
1903 "Grumpy",
1904 "Dozy",
1905 "Speedy",
1906 "Nosey",
1907 "Dribble",
1908 "Mushroom",
1909 "Cabbage",
1910 "Sniffle",
1911 "Fishy",
1912 "Swindle",
1913 "Sneaky",
1914 "Nutkins"
1915};
1916
1917static const char _initial_name_letters[] = {
1918 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
1919 'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'W',
1920};
1921
1922static std::span<const std::string_view> GetSurnameOptions()
1923{
1924 if (_settings_game.game_creation.landscape == LandscapeType::Toyland) return _silly_surname_list;
1925 return _surname_list;
1926}
1927
1933 static std::string_view GetSurname(uint32_t seed)
1934{
1935 auto surname_options = GetSurnameOptions();
1936 return surname_options[surname_options.size() * GB(seed, 16, 8) >> 8];
1937}
1938
1939static void GenAndCoName(StringBuilder &builder, uint32_t seed)
1940{
1941 builder += GetSurname(seed);
1942 builder += " & Co.";
1943}
1944
1945static void GenPresidentName(StringBuilder &builder, uint32_t seed)
1946{
1947 builder.PutChar(_initial_name_letters[std::size(_initial_name_letters) * GB(seed, 0, 8) >> 8]);
1948 builder += ". ";
1949
1950 /* The second initial is optional. */
1951 size_t index = (std::size(_initial_name_letters) + 35) * GB(seed, 8, 8) >> 8;
1952 if (index < std::size(_initial_name_letters)) {
1953 builder.PutChar(_initial_name_letters[index]);
1954 builder += ". ";
1955 }
1956
1957 builder += GetSurname(seed);
1958}
1959
1960static bool GetSpecialNameString(StringBuilder &builder, StringID string, StringParameters &args)
1961{
1962 switch (string) {
1963 case SPECSTR_SILLY_NAME: // Not used in new companies, but retained for old-loader savegames
1964 builder += _silly_company_names[std::min<size_t>(args.GetNextParameter<uint16_t>(), std::size(_silly_company_names) - 1)];
1965 return true;
1966
1967 case SPECSTR_ANDCO_NAME: // used for Foobar & Co company names
1968 GenAndCoName(builder, args.GetNextParameter<uint32_t>());
1969 return true;
1970
1971 case SPECSTR_PRESIDENT_NAME: // President name
1972 GenPresidentName(builder, args.GetNextParameter<uint32_t>());
1973 return true;
1974 }
1975
1976 /* TownName Transport company names, with the appropriate town name. */
1977 if (IsInsideMM(string, SPECSTR_COMPANY_NAME_START, SPECSTR_COMPANY_NAME_END)) {
1978 GenerateTownNameString(builder, string - SPECSTR_COMPANY_NAME_START, args.GetNextParameter<uint32_t>());
1979 builder += " Transport";
1980 return true;
1981 }
1982
1983 return false;
1984}
1985
1990 bool LanguagePackHeader::IsValid() const
1991{
1992 return this->ident == TO_LE32(LanguagePackHeader::IDENT) &&
1993 this->version == TO_LE32(LANGUAGE_PACK_VERSION) &&
1994 this->plural_form < LANGUAGE_MAX_PLURAL &&
1995 this->text_dir <= 1 &&
1996 this->newgrflangid < MAX_LANG &&
1997 this->num_genders < MAX_NUM_GENDERS &&
1998 this->num_cases < MAX_NUM_CASES &&
1999 StrValid(this->name) &&
2000 StrValid(this->own_name) &&
2001 StrValid(this->isocode) &&
2002 StrValid(this->digit_group_separator) &&
2003 StrValid(this->digit_group_separator_currency) &&
2004 StrValid(this->digit_decimal_separator);
2005}
2006
2010 bool LanguagePackHeader::IsReasonablyFinished() const
2011{
2012 /* "Less than 25% missing" is "sufficiently finished". */
2013 return 4 * this->missing < LANGUAGE_TOTAL_STRINGS;
2014}
2015
2021 bool ReadLanguagePack(const LanguageMetadata *lang)
2022{
2023 /* Current language pack */
2024 size_t total_len = 0;
2025 std::unique_ptr<LanguagePack, LanguagePackDeleter> lang_pack(reinterpret_cast<LanguagePack *>(ReadFileToMem(FS2OTTD(lang->file.native()), total_len, 1U << 20).release()));
2026 if (!lang_pack) return false;
2027
2028 /* End of read data (+ terminating zero added in ReadFileToMem()) */
2029 const char *end = (char *)lang_pack.get() + total_len + 1;
2030
2031 /* We need at least one byte of lang_pack->data */
2032 if (end <= lang_pack->data || !lang_pack->IsValid()) {
2033 return false;
2034 }
2035
2036 std::array<uint, TEXT_TAB_END> tab_start, tab_num;
2037
2038 uint count = 0;
2039 for (uint i = 0; i < TEXT_TAB_END; i++) {
2040 uint16_t num = FROM_LE16(lang_pack->offsets[i]);
2041 if (num > TAB_SIZE) return false;
2042
2043 tab_start[i] = count;
2044 tab_num[i] = num;
2045 count += num;
2046 }
2047
2048 /* Allocate offsets */
2049 std::vector<std::string_view> strings;
2050
2051 /* Fill offsets */
2052 char *s = lang_pack->data;
2053 for (uint i = 0; i < count; i++) {
2054 size_t len = static_cast<uint8_t>(*s++);
2055 if (s + len >= end) return false;
2056
2057 if (len >= 0xC0) {
2058 len = ((len & 0x3F) << 8) + static_cast<uint8_t>(*s++);
2059 if (s + len >= end) return false;
2060 }
2061 strings.emplace_back(s, len);
2062 s += len;
2063 }
2064 assert(strings.size() == count);
2065
2066 _langpack.langpack = std::move(lang_pack);
2067 _langpack.strings = std::move(strings);
2068 _langpack.langtab_num = tab_num;
2069 _langpack.langtab_start = tab_start;
2070
2071 _current_language = lang;
2072 _current_text_dir = (TextDirection)_current_language->text_dir;
2073 _config_language_file = FS2OTTD(_current_language->file.filename().native());
2074 SetCurrentGrfLangID(_current_language->newgrflangid);
2075 _langpack.list_separator = GetString(STR_LIST_SEPARATOR);
2076 _langpack.ellipsis = GetString(STR_TRUNCATION_ELLIPSIS);
2077
2078#ifdef _WIN32
2079 extern void Win32SetCurrentLocaleName(std::string iso_code);
2080 Win32SetCurrentLocaleName(_current_language->isocode);
2081#endif
2082
2083#ifdef WITH_COCOA
2084 extern void MacOSSetCurrentLocaleName(std::string_view iso_code);
2085 MacOSSetCurrentLocaleName(_current_language->isocode);
2086#endif
2087
2088#ifdef WITH_ICU_I18N
2089 /* Create a collator instance for our current locale. */
2090 UErrorCode status = U_ZERO_ERROR;
2091 _current_collator.reset(icu::Collator::createInstance(icu::Locale(_current_language->isocode), status));
2092 /* Sort number substrings by their numerical value. */
2093 if (_current_collator) _current_collator->setAttribute(UCOL_NUMERIC_COLLATION, UCOL_ON, status);
2094 /* Avoid using the collator if it is not correctly set. */
2095 if (U_FAILURE(status)) {
2096 _current_collator.reset();
2097 }
2098#endif /* WITH_ICU_I18N */
2099
2100 Layouter::Initialize();
2101
2102 /* Some lists need to be sorted again after a language change. */
2103 ReconsiderGameScriptLanguage();
2104 InitializeSortedCargoSpecs();
2105 SortIndustryTypes();
2106 BuildIndustriesLegend();
2107 BuildContentTypeStringList();
2108 InvalidateWindowClassesData(WC_BUILD_VEHICLE); // Build vehicle window.
2109 InvalidateWindowClassesData(WC_TRAINS_LIST); // Train group window.
2110 InvalidateWindowClassesData(WC_ROADVEH_LIST); // Road vehicle group window.
2111 InvalidateWindowClassesData(WC_SHIPS_LIST); // Ship group window.
2112 InvalidateWindowClassesData(WC_AIRCRAFT_LIST); // Aircraft group window.
2113 InvalidateWindowClassesData(WC_INDUSTRY_DIRECTORY); // Industry directory window.
2114 InvalidateWindowClassesData(WC_STATION_LIST); // Station list window.
2115
2116 return true;
2117}
2118
2119/* Win32 implementation in win32.cpp.
2120 * OS X implementation in os/macosx/macos.mm. */
2121#if !(defined(_WIN32) || defined(__APPLE__))
2130std::optional<std::string> GetCurrentLocale(const char *param)
2131{
2132 auto env = GetEnv("LANGUAGE");
2133 if (env.has_value()) return std::string{*env};
2134
2135 env = GetEnv("LC_ALL");
2136 if (env.has_value()) return std::string{*env};
2137
2138 if (param != nullptr) {
2139 env = GetEnv(param);
2140 if (env.has_value()) return std::string{*env};
2141 }
2142
2143 env = GetEnv("LANG");
2144 if (env.has_value()) return std::string{*env};
2145
2146 return std::nullopt;
2147}
2148#else
2149std::optional<std::string> GetCurrentLocale(const char *param);
2150#endif /* !(defined(_WIN32) || defined(__APPLE__)) */
2151
2157 const LanguageMetadata *GetLanguage(uint8_t newgrflangid)
2158{
2159 for (const LanguageMetadata &lang : _languages) {
2160 if (newgrflangid == lang.newgrflangid) return &lang;
2161 }
2162
2163 return nullptr;
2164}
2165
2172 static bool GetLanguageFileHeader(const std::string &file, LanguagePackHeader *hdr)
2173{
2174 auto f = FileHandle::Open(file, "rb");
2175 if (!f.has_value()) return false;
2176
2177 size_t read = fread(hdr, sizeof(*hdr), 1, *f);
2178
2179 bool ret = read == 1 && hdr->IsValid();
2180
2181 /* Convert endianness for the windows language ID */
2182 if (ret) {
2183 hdr->missing = FROM_LE16(hdr->missing);
2184 hdr->winlangid = FROM_LE16(hdr->winlangid);
2185 }
2186 return ret;
2187}
2188
2193 static void FillLanguageList(const std::string &path)
2194{
2195 std::error_code error_code;
2196 for (const auto &dir_entry : std::filesystem::directory_iterator(OTTD2FS(path), error_code)) {
2197 if (!dir_entry.is_regular_file()) continue;
2198 if (dir_entry.path().extension() != ".lng") continue;
2199
2200 LanguageMetadata lmd;
2201 lmd.file = dir_entry.path();
2202
2203 /* Check whether the file is of the correct version */
2204 std::string file = FS2OTTD(lmd.file.native());
2205 if (!GetLanguageFileHeader(file, &lmd)) {
2206 Debug(misc, 3, "{} is not a valid language file", file);
2207 } else if (GetLanguage(lmd.newgrflangid) != nullptr) {
2208 Debug(misc, 3, "{}'s language ID is already known", file);
2209 } else {
2210 _languages.push_back(std::move(lmd));
2211 }
2212 }
2213 if (error_code) {
2214 Debug(misc, 9, "Unable to open directory {}: {}", path, error_code.message());
2215 }
2216}
2217
2222 void InitializeLanguagePacks()
2223{
2224 for (Searchpath sp : _valid_searchpaths) {
2225 FillLanguageList(FioGetDirectory(sp, LANG_DIR));
2226 }
2227 if (_languages.empty()) UserError("No available language packs (invalid versions?)");
2228
2229 /* Acquire the locale of the current system */
2230 auto str_lang = GetCurrentLocale("LC_MESSAGES");
2231 std::string_view lang = str_lang.has_value() ? std::string_view{*str_lang} : "en_GB";
2232
2233 const LanguageMetadata *chosen_language = nullptr;
2234 const LanguageMetadata *language_fallback = nullptr;
2235 const LanguageMetadata *en_GB_fallback = _languages.data();
2236
2237 /* Find a proper language. */
2238 for (const LanguageMetadata &lng : _languages) {
2239 /* We are trying to find a default language. The priority is by
2240 * configuration file, local environment and last, if nothing found,
2241 * English. */
2242 if (_config_language_file == FS2OTTD(lng.file.filename().native())) {
2243 chosen_language = &lng;
2244 break;
2245 }
2246
2247 std::string_view iso_code = lng.isocode;
2248 if (iso_code == "en_GB") en_GB_fallback = &lng;
2249
2250 /* Only auto-pick finished translations */
2251 if (!lng.IsReasonablyFinished()) continue;
2252
2253 if (iso_code.starts_with(lang.substr(0, 5))) chosen_language = &lng;
2254 if (iso_code.starts_with(lang.substr(0, 2))) language_fallback = &lng;
2255 }
2256
2257 /* We haven't found the language in the config nor the one in the locale.
2258 * Now we set it to one of the fallback languages */
2259 if (chosen_language == nullptr) {
2260 chosen_language = (language_fallback != nullptr) ? language_fallback : en_GB_fallback;
2261 }
2262
2263 if (!ReadLanguagePack(chosen_language)) UserError("Can't read language pack '{}'", FS2OTTD(chosen_language->file.native()));
2264}
2265
2270std::string_view GetCurrentLanguageIsoCode()
2271{
2272 return _langpack.langpack->isocode;
2273}
2274
2279 bool MissingGlyphSearcher::FindMissingGlyphs()
2280{
2281 FontCache::LoadFontCaches(this->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
2282
2283 this->Reset();
2284 for (auto text = this->NextString(); text.has_value(); text = this->NextString()) {
2285 FontSize size = this->DefaultSize();
2286 FontCache *fc = FontCache::Get(size);
2287 for (char32_t c : Utf8View(*text)) {
2288 if (c >= SCC_FIRST_FONT && c <= SCC_LAST_FONT) {
2289 size = (FontSize)(c - SCC_FIRST_FONT);
2290 fc = FontCache::Get(size);
2291 } else if (!IsInsideMM(c, SCC_SPRITE_START, SCC_SPRITE_END) && IsPrintable(c) && !IsTextDirectionChar(c) && fc->MapCharToGlyph(c, false) == 0) {
2292 /* The character is printable, but not in the normal font. This is the case we were testing for. */
2293 Debug(fontcache, 0, "Font is missing glyphs to display char 0x{:X} in {} font size", static_cast<uint32_t>(c), FontSizeToName(size));
2294 return true;
2295 }
2296 }
2297 }
2298 return false;
2299}
2300
2302 class LanguagePackGlyphSearcher : public MissingGlyphSearcher {
2303 uint i;
2304 uint j;
2305
2306 void Reset() override
2307 {
2308 this->i = 0;
2309 this->j = 0;
2310 }
2311
2312 FontSize DefaultSize() override
2313 {
2314 return FS_NORMAL;
2315 }
2316
2317 std::optional<std::string_view> NextString() override
2318 {
2319 if (this->i >= TEXT_TAB_END) return std::nullopt;
2320
2321 std::string_view ret = _langpack.strings[_langpack.langtab_start[this->i] + this->j];
2322
2323 this->j++;
2324 while (this->i < TEXT_TAB_END && this->j >= _langpack.langtab_num[this->i]) {
2325 this->i++;
2326 this->j = 0;
2327 }
2328
2329 return ret;
2330 }
2331
2332 bool Monospace() override
2333 {
2334 return false;
2335 }
2336
2337 void SetFontNames([[maybe_unused]] FontCacheSettings *settings, [[maybe_unused]] std::string_view font_name, [[maybe_unused]] const void *os_data) override
2338 {
2339#if defined(WITH_FREETYPE) || defined(_WIN32) || defined(WITH_COCOA)
2340 settings->small.font = font_name;
2341 settings->medium.font = font_name;
2342 settings->large.font = font_name;
2343
2344 settings->small.os_handle = os_data;
2345 settings->medium.os_handle = os_data;
2346 settings->large.os_handle = os_data;
2347#endif
2348 }
2349};
2350
2363 void CheckForMissingGlyphs(MissingGlyphSearcher *searcher)
2364{
2365 static LanguagePackGlyphSearcher pack_searcher;
2366 if (searcher == nullptr) searcher = &pack_searcher;
2367 bool bad_font = searcher->FindMissingGlyphs();
2368#if defined(WITH_FREETYPE) || defined(_WIN32) || defined(WITH_COCOA)
2369 if (bad_font) {
2370 /* We found an unprintable character... lets try whether we can find
2371 * a fallback font that can print the characters in the current language. */
2372 bool any_font_configured = !_fcsettings.medium.font.empty();
2373 FontCacheSettings backup = _fcsettings;
2374
2375 _fcsettings.mono.os_handle = nullptr;
2376 _fcsettings.medium.os_handle = nullptr;
2377
2378 bad_font = !FontProviderManager::FindFallbackFont(&_fcsettings, _langpack.langpack->isocode, searcher);
2379
2380 _fcsettings = std::move(backup);
2381
2382 if (!bad_font && any_font_configured) {
2383 /* If the user configured a bad font, and we found a better one,
2384 * show that we loaded the better font instead of the configured one.
2385 */
2386 std::string err_str;
2387 StringBuilder builder(err_str);
2388 builder.PutUtf8(SCC_YELLOW);
2389 builder.Put("The current font is missing some of the characters used in the texts for this language. Using system fallback font instead.");
2390 ShowErrorMessage(GetEncodedString(STR_JUST_RAW_STRING, std::move(err_str)), {}, WL_WARNING);
2391 }
2392
2393 if (bad_font) {
2394 /* Our fallback font does miss characters too, so keep the
2395 * user chosen font as that is more likely to be any good than
2396 * the wild guess we made */
2397 FontCache::LoadFontCaches(searcher->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
2398 }
2399 }
2400#endif
2401
2402 if (bad_font) {
2403 /* All attempts have failed. Display an error. As we do not want the string to be translated by
2404 * the translators, we 'force' it into the binary and 'load' it via a BindCString. To do this
2405 * properly we have to set the colour of the string, otherwise we end up with a lot of artifacts.
2406 */
2407 std::string err_str;
2408 StringBuilder builder(err_str);
2409 builder.PutUtf8(SCC_YELLOW);
2410 builder.Put("The current font is missing some of the characters used in the texts for this language. Go to Help & Manuals > Fonts, or read the file docs/fonts.md in your OpenTTD directory, to see how to solve this.");
2411 ShowErrorMessage(GetEncodedString(STR_JUST_RAW_STRING, std::move(err_str)), {}, WL_WARNING);
2412
2413 /* Reset the font width */
2414 LoadStringWidthTable(searcher->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
2415 return;
2416 }
2417
2418 /* Update the font with cache */
2419 LoadStringWidthTable(searcher->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
2420
2421#if !(defined(WITH_ICU_I18N) && defined(WITH_HARFBUZZ)) && !defined(WITH_UNISCRIBE) && !defined(WITH_COCOA)
2422 /*
2423 * For right-to-left languages we need the ICU library. If
2424 * we do not have support for that library we warn the user
2425 * about it with a message. As we do not want the string to
2426 * be translated by the translators, we 'force' it into the
2427 * binary and 'load' it via a BindCString. To do this
2428 * properly we have to set the colour of the string,
2429 * otherwise we end up with a lot of artifacts.
2430 */
2431 if (_current_text_dir != TD_LTR) {
2432 std::string err_str;
2433 StringBuilder builder(err_str);
2434 builder.PutUtf8(SCC_YELLOW);
2435 builder.Put("This version of OpenTTD does not support right-to-left languages. Recompile with ICU + Harfbuzz enabled.");
2436 ShowErrorMessage(GetEncodedString(STR_JUST_RAW_STRING, std::move(err_str)), {}, WL_ERROR);
2437 }
2438#endif /* !(WITH_ICU_I18N && WITH_HARFBUZZ) && !WITH_UNISCRIBE && !WITH_COCOA */
2439}
backup_type.hpp
Class for backupping variables and making sure they are restored later.
GB
static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
Definition bitmath_func.hpp:32
HasBit
constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
Definition bitmath_func.hpp:103
CargoType
uint8_t CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:21
IsValidCargoType
bool IsValidCargoType(CargoType cargo)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:104
_sorted_cargo_specs
std::vector< const CargoSpec * > _sorted_cargo_specs
Cargo specifications sorted alphabetically by name.
Definition cargotype.cpp:190
InitializeSortedCargoSpecs
void InitializeSortedCargoSpecs()
Initialize the list of sorted cargo specifications.
Definition cargotype.cpp:223
BaseStringBuilder::PutUtf8
void PutUtf8(char32_t c)
Append UTF.8 char.
Definition string_builder.cpp:113
BaseStringBuilder::Put
void Put(std::string_view str)
Append string.
Definition string_builder.hpp:34
BaseStringBuilder::PutIntegerBase
void PutIntegerBase(T value, int base)
Append integer 'value' in given number 'base'.
Definition string_builder.hpp:52
BaseStringBuilder::PutChar
void PutChar(char c)
Append 8-bit char.
Definition string_builder.cpp:105
BaseStringBuilder::PutUint8
void PutUint8(uint8_t value)
Append binary uint8.
Definition string_builder.cpp:18
EncodedString
Container for an encoded string, created by GetEncodedString.
Definition strings_type.h:98
EncodedString::GetEncodedStringWithArgs
friend EncodedString GetEncodedStringWithArgs(StringID str, std::span< const StringParameter > params)
Encode a string with its parameters into an encoded string.
Definition strings.cpp:102
EncodedString::GetDecodedString
std::string GetDecodedString() const
Decode the encoded string.
Definition strings.cpp:207
EncodedString::ReplaceParam
EncodedString ReplaceParam(size_t param, StringParameter &&value) const
Replace a parameter of this EncodedString.
Definition strings.cpp:150
Engine
Definition engine_base.h:38
EnumBitSet< StationFacility, uint8_t >
FileHandle::Open
static std::optional< FileHandle > Open(const std::string &filename, std::string_view mode)
Open an RAII file handle if possible.
Definition fileio.cpp:1171
FontCache
Font cache for basic fonts.
Definition fontcache.h:22
FontCache::MapCharToGlyph
virtual GlyphID MapCharToGlyph(char32_t key, bool fallback=true)=0
Map a character into a glyph.
FontCache::LoadFontCaches
static void LoadFontCaches(FontSizes fontsizes)
(Re)initialize the font cache related things, i.e.
Definition fontcache.cpp:237
FontCache::Get
static FontCache * Get(FontSize fs)
Get the font cache of a given font size.
Definition fontcache.h:130
FontProviderManager::FindFallbackFont
static bool FindFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback)
We would like to have a fallback font as the current one doesn't contain all characters we need.
Definition fontcache.cpp:55
LanguagePackGlyphSearcher
Helper for searching through the language pack.
Definition strings.cpp:2302
LanguagePackGlyphSearcher::Monospace
bool Monospace() override
Whether to search for a monospace font or not.
Definition strings.cpp:2332
LanguagePackGlyphSearcher::SetFontNames
void SetFontNames(FontCacheSettings *settings, std::string_view font_name, const void *os_data) override
Set the right font names.
Definition strings.cpp:2337
LanguagePackGlyphSearcher::j
uint j
Iterator for the secondary language tables.
Definition strings.cpp:2304
LanguagePackGlyphSearcher::NextString
std::optional< std::string_view > NextString() override
Get the next string to search through.
Definition strings.cpp:2317
LanguagePackGlyphSearcher::DefaultSize
FontSize DefaultSize() override
Get the default (font) size of the string.
Definition strings.cpp:2312
LanguagePackGlyphSearcher::i
uint i
Iterator for the primary language tables.
Definition strings.cpp:2303
LanguagePackGlyphSearcher::Reset
void Reset() override
Reset the search, i.e.
Definition strings.cpp:2306
Layouter::Initialize
static void Initialize()
Perform initialization of layout engine.
Definition gfx_layout.cpp:356
MissingGlyphSearcher
A searcher for missing glyphs.
Definition strings_func.h:156
MissingGlyphSearcher::Reset
virtual void Reset()=0
Reset the search, i.e.
MissingGlyphSearcher::DefaultSize
virtual FontSize DefaultSize()=0
Get the default (font) size of the string.
MissingGlyphSearcher::FindMissingGlyphs
bool FindMissingGlyphs()
Check whether there are glyphs missing in the current language.
Definition strings.cpp:2279
MissingGlyphSearcher::Monospace
virtual bool Monospace()=0
Whether to search for a monospace font or not.
MissingGlyphSearcher::NextString
virtual std::optional< std::string_view > NextString()=0
Get the next string to search through.
OverflowSafeInt< int64_t >
StringBuilder
Compose data into a growing std::string.
Definition string_builder.hpp:65
StringBuilder::back_inserter
back_insert_iterator back_inserter()
Create a back-insert-iterator.
Definition string_builder.hpp:106
StringConsumer
Parse data from a string / buffer.
Definition string_consumer.hpp:27
StringConsumer::TryReadIntegerBase
std::optional< T > TryReadIntegerBase(int base, bool clamp=false)
Try to read and parse an integer in number 'base', and then advance the reader.
Definition string_consumer.hpp:874
StringConsumer::PeekUtf8If
bool PeekUtf8If(char32_t c) const
Check whether the next UTF-8 char matches 'c'.
Definition string_consumer.hpp:493
StringConsumer::ReadUtf8
char32_t ReadUtf8(char32_t def='?')
Read UTF-8 character, and advance reader.
Definition string_consumer.hpp:425
StringConsumer::SKIP_ONE_SEPARATOR
@ SKIP_ONE_SEPARATOR
Read and discard one separator, do not include it in the result.
Definition string_consumer.hpp:696
StringConsumer::KEEP_SEPARATOR
@ KEEP_SEPARATOR
Keep the separator in the data as next value to be read.
Definition string_consumer.hpp:695
StringConsumer::AnyBytesLeft
bool AnyBytesLeft() const noexcept
Check whether any bytes left to read.
Definition string_consumer.hpp:70
StringConsumer::ReadUint8
uint8_t ReadUint8(uint8_t def=0)
Read binary uint8, and advance reader.
Definition string_consumer.hpp:122
StringConsumer::ReadUint16LE
uint16_t ReadUint16LE(uint16_t def=0)
Read binary uint16 using little endian, and advance reader.
Definition string_consumer.hpp:188
StringConsumer::SkipAll
void SkipAll()
Discard all remaining data.
Definition string_consumer.hpp:101
StringConsumer::ReadIntegerBase
T ReadIntegerBase(int base, T def=0, bool clamp=false)
Read and parse an integer in number 'base', and advance the reader.
Definition string_consumer.hpp:891
StringConsumer::Read
std::string_view Read(size_type len)
Read the next 'len' bytes, and advance reader.
Definition string_consumer.hpp:530
StringConsumer::ReadUtf8If
bool ReadUtf8If(char32_t c)
Check whether the next UTF-8 char matches 'c', and skip it.
Definition string_consumer.hpp:501
StringConsumer::npos
static constexpr size_type npos
Special value for "end of data".
Definition string_consumer.hpp:34
StringConsumer::Skip
void Skip(size_type len)
Discard some bytes.
Definition string_consumer.cpp:97
StringConsumer::SkipUtf8If
void SkipUtf8If(char32_t c)
If the next data matches the UTF-8 char 'c', then skip it.
Definition string_consumer.hpp:511
StringConsumer::ReadUntilUtf8
std::string_view ReadUntilUtf8(char32_t c, SeparatorUsage sep)
Read data until the first occurrence of UTF-8 char 'c', and advance reader.
Definition string_consumer.cpp:162
StringParameters
Definition strings_internal.h:18
StringParameters::SetOffset
void SetOffset(size_t offset)
Set the offset within the string from where to return the next result of GetInt64 or GetInt32.
Definition strings_internal.h:54
StringParameters::GetNextParameterString
std::string_view GetNextParameterString()
Get the next string parameter from our parameters.
Definition strings_internal.h:115
StringParameters::GetRemainingParameters
StringParameters GetRemainingParameters()
Get a new instance of StringParameters that is a "range" into the remaining existing parameters.
Definition strings_internal.h:135
StringParameters::parameters
std::span< StringParameter > parameters
Array with the actual parameters.
Definition strings_internal.h:21
StringParameters::GetNextParameterReference
const StringParameter & GetNextParameterReference()
Get the next parameter from our parameters.
Definition strings.cpp:68
StringParameters::AdvanceOffset
void AdvanceOffset(size_t advance)
Advance the offset within the string from where to return the next result of GetInt64 or GetInt32.
Definition strings_internal.h:72
StringParameters::GetNextParameter
uint64_t GetNextParameter()
Get the next parameter from our parameters.
Definition strings_internal.h:84
StringParameters::offset
size_t offset
Current offset in the parameters span.
Definition strings_internal.h:23
StringParameters::next_type
char32_t next_type
The type of the next data that is retrieved.
Definition strings_internal.h:24
StringParameters::GetOffset
size_t GetOffset()
Get the current offset, so it can be backed up for certain processing steps, or be used to offset the...
Definition strings_internal.h:47
StringParameters::GetNumParameters
size_t GetNumParameters() const
Return the number of parameters.
Definition strings_internal.h:159
StringParameters::GetDataLeft
size_t GetDataLeft() const
Return the amount of elements which can still be read.
Definition strings_internal.h:153
StringParameters::GetTypeAtOffset
char32_t GetTypeAtOffset(size_t offset) const
Get the type of a specific element.
Definition strings_internal.h:165
TimerGameCalendar::ConvertDateToYMD
static YearMonthDay ConvertDateToYMD(Date date)
Converts a Date to a Year, Month & Day.
Definition timer_game_calendar.cpp:42
TimerGameEconomy::UsingWallclockUnits
static bool UsingWallclockUnits(bool newgame=false)
Check if we are using wallclock units.
Definition timer_game_economy.cpp:98
Utf8View
Constant span of UTF-8 encoded data.
Definition utf8.hpp:30
company_base.h
Definition of stuff that is very close to a company, like the company struct itself.
control_codes.h
Control codes that are embedded in the translation strings.
StringControlCode
StringControlCode
List of string control codes used for string formatting, displaying, and by strgen to generate the la...
Definition control_codes.h:17
SCC_ENCODED
@ SCC_ENCODED
Encoded string marker and sub-string parameter.
Definition control_codes.h:27
SCC_ENCODED_NUMERIC
@ SCC_ENCODED_NUMERIC
Encoded numeric parameter.
Definition control_codes.h:29
SCC_ENCODED_STRING
@ SCC_ENCODED_STRING
Encoded string parameter.
Definition control_codes.h:30
SCC_NEWGRF_STRINL
@ SCC_NEWGRF_STRINL
Inline another string at the current position, StringID is encoded in the string.
Definition control_codes.h:168
SCC_NEWGRF_FIRST
@ SCC_NEWGRF_FIRST
The next variables are part of a NewGRF subsystem for creating text strings.
Definition control_codes.h:135
SCC_NEWGRF_PRINT_WORD_STRING_ID
@ SCC_NEWGRF_PRINT_WORD_STRING_ID
81: Read 2 bytes from the stack as String ID
Definition control_codes.h:141
SCC_ENCODED_INTERNAL
@ SCC_ENCODED_INTERNAL
Encoded text from OpenTTD.
Definition control_codes.h:28
DecodeUtf8
std::pair< size_t, char32_t > DecodeUtf8(std::string_view buf)
Decode a character from UTF-8.
Definition utf8.cpp:48
currency.h
Functions to handle different currencies.
GetCurrency
const CurrencySpec & GetCurrency()
Get the currently selected currency.
Definition currency.h:119
debug.h
Functions related to debugging.
Debug
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Definition debug.h:37
depot_base.h
Base for all depots (except hangars)
endian_func.hpp
Function to handling different endian machines.
engine_base.h
Base class for engines.
error.h
Functions related to errors.
WL_WARNING
@ WL_WARNING
Other information.
Definition error.h:25
WL_ERROR
@ WL_ERROR
Errors (eg. saving/loading failed)
Definition error.h:26
ShowErrorMessage
void ShowErrorMessage(EncodedString &&summary_msg, int x, int y, CommandCost &cc)
Display an error message in a window.
Definition error_gui.cpp:290
error_func.h
Error reporting related functions.
ReadFileToMem
std::unique_ptr< char[]> ReadFileToMem(const std::string &filename, size_t &lenp, size_t maxsize)
Load a file into memory.
Definition fileio.cpp:1026
fileio_func.h
Functions for Standard In/Out file operations.
Searchpath
Searchpath
Types of searchpaths OpenTTD might use.
Definition fileio_type.h:113
LANG_DIR
@ LANG_DIR
Subdirectory for all translation files.
Definition fileio_type.h:98
settings
fluid_settings_t * settings
FluidSynth settings handle.
Definition fluidsynth.cpp:25
ReconsiderGameScriptLanguage
void ReconsiderGameScriptLanguage()
Reconsider the game script language, so we use the right one.
Definition game_text.cpp:381
GetGameStringPtr
std::string_view GetGameStringPtr(StringIndexInTab id)
Get the string pointer of a particular game string.
Definition game_text.cpp:315
game_text.hpp
Base functions regarding game texts.
GetBroadestDigit
std::pair< uint8_t, uint8_t > GetBroadestDigit(FontSize size)
Determine the broadest digits for guessing the maximum width of a n-digit number.
Definition gfx.cpp:1299
LoadStringWidthTable
void LoadStringWidthTable(FontSizes fontsizes)
Initialize _stringwidth_table cache for the specified font sizes.
Definition gfx.cpp:1253
gfx_layout.h
Functions related to laying out the texts.
FontSize
FontSize
Available font sizes.
Definition gfx_type.h:248
FS_MONO
@ FS_MONO
Index of the monospaced font in the font tables.
Definition gfx_type.h:252
FS_NORMAL
@ FS_NORMAL
Index of the normal font in the font tables.
Definition gfx_type.h:249
FONTSIZES_REQUIRED
constexpr FontSizes FONTSIZES_REQUIRED
Mask of font sizes required to be present.
Definition gfx_type.h:264
DEFAULT_GROUP
static constexpr GroupID DEFAULT_GROUP
Ungrouped vehicles are in this group.
Definition group_type.h:18
industry.h
Base of all industries.
GetIndustrySpec
const IndustrySpec * GetIndustrySpec(IndustryType thistype)
Accessor for array _industry_specs.
Definition industry_cmd.cpp:126
SortIndustryTypes
void SortIndustryTypes()
Initialize the list of sorted industry types.
Definition industry_gui.cpp:249
language.h
Information about languages and their files.
MAX_NUM_GENDERS
static const uint8_t MAX_NUM_GENDERS
Maximum number of supported genders.
Definition language.h:20
LanguageList
std::vector< LanguageMetadata > LanguageList
Type for the list of language meta data.
Definition language.h:94
MAX_NUM_CASES
static const uint8_t MAX_NUM_CASES
Maximum number of supported cases.
Definition language.h:21
IsInsideMM
constexpr bool IsInsideMM(const size_t x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
Definition math_func.hpp:267
abs
constexpr T abs(const T a)
Returns the absolute value of (scalar) variable.
Definition math_func.hpp:23
PowerOfTen
constexpr uint64_t PowerOfTen(int power)
Computes ten to the given power.
Definition math_func.hpp:348
BuildContentTypeStringList
void BuildContentTypeStringList()
Build array of all strings corresponding to the content types.
Definition network_content_gui.cpp:1020
network_content_gui.h
User interface for downloading files.
VehicleCallbackMask::Name
@ Name
Engine name.
CBID_VEHICLE_NAME
@ CBID_VEHICLE_NAME
Called to determine the engine name to show.
Definition newgrf_callbacks.h:286
GetVehicleCallback
uint16_t GetVehicleCallback(CallbackID callback, uint32_t param1, uint32_t param2, EngineID engine, const Vehicle *v, std::span< int32_t > regs100)
Evaluate a newgrf callback for vehicles.
Definition newgrf_engine.cpp:1198
newgrf_engine.h
Functions for NewGRF engines.
GetGRFStringPtr
std::string_view GetGRFStringPtr(StringIndexInTab stringid)
Get a C-string from a stringid set by a newgrf.
Definition newgrf_text.cpp:632
GetGRFStringWithTextStack
std::string GetGRFStringWithTextStack(const struct GRFFile *grffile, GRFStringID grfstringid, std::span< const int32_t > textstack)
Format a GRF string using the text ref stack for parameters.
Definition newgrf_text.cpp:999
SetCurrentGrfLangID
void SetCurrentGrfLangID(uint8_t language_id)
Equivalence Setter function between game and newgrf langID.
Definition newgrf_text.cpp:652
RemapNewGRFStringControlCode
char32_t RemapNewGRFStringControlCode(char32_t scc, StringConsumer &consumer)
Emit OpenTTD's internal string code for the different NewGRF string codes.
Definition newgrf_text.cpp:878
newgrf_text.h
Header of Action 04 "universal holder" structure and functions.
GRFSTR_MISC_GRF_TEXT
static constexpr GRFStringID GRFSTR_MISC_GRF_TEXT
Miscellaneous GRF text range.
Definition newgrf_text_type.h:18
rev.h
declaration of OTTD revision dependent variables
safeguards.h
A number of safeguards to prevent using unsafe methods.
_settings_game
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:61
signs_base.h
Base class for signs.
BuildIndustriesLegend
void BuildIndustriesLegend()
Fills an array for the industries legends.
Definition smallmap_gui.cpp:189
smallmap_gui.h
Smallmap GUI functions.
station_base.h
Base classes/functions for stations.
StationFacility::Dock
@ Dock
Station with a dock.
StationFacility::TruckStop
@ TruckStop
Station with truck stops.
StationFacility::Train
@ Train
Station with train station.
StationFacility::Airport
@ Airport
Station with an airport.
StationFacility::BusStop
@ BusStop
Station with bus stops.
stdafx.h
Definition of base types and functions in a cross-platform compatible way.
lengthof
#define lengthof(array)
Return the length of an fixed size array.
Definition stdafx.h:271
GetEnv
std::optional< std::string_view > GetEnv(const char *variable)
Get the environment variable using std::getenv and when it is an empty string (or nullptr),...
Definition string.cpp:854
StrValid
bool StrValid(std::span< const char > str)
Checks whether the given string is valid, i.e.
Definition string.cpp:205
string_consumer.hpp
Parse strings.
string_func.h
Functions related to low-level strings.
IsTextDirectionChar
bool IsTextDirectionChar(char32_t c)
Is the given character a text direction character.
Definition string_func.h:111
MacOSSetCurrentLocaleName
void MacOSSetCurrentLocaleName(std::string_view iso_code)
Store current language locale as a CoreFoundation locale.
Definition string_osx.cpp:316
NBSP
#define NBSP
A non-breaking space.
Definition string_type.h:16
GetParamMaxValue
uint64_t GetParamMaxValue(uint64_t max_value, uint min_count, FontSize size)
Get some number that is suitable for string size computations.
Definition strings.cpp:236
_languages
LanguageList _languages
The actual list of language meta data.
Definition strings.cpp:53
FormatNumber
static void FormatNumber(StringBuilder &builder, int64_t number, std::string_view separator)
Format a number into a string.
Definition strings.cpp:482
GetEncodedStringWithArgs
EncodedString GetEncodedStringWithArgs(StringID str, std::span< const StringParameter > params)
Encode a string with its parameters into an encoded string.
Definition strings.cpp:102
GetStringWithArgs
void GetStringWithArgs(StringBuilder &builder, StringID string, StringParameters &args, uint case_index, bool game_script)
Get a parsed string with most special stringcodes replaced by the string parameters.
Definition strings.cpp:336
GetCurrentLocale
std::optional< std::string > GetCurrentLocale(const char *param)
Determine the current charset based on the environment First check some default values,...
Definition strings.cpp:2130
GetListSeparator
std::string_view GetListSeparator()
Get the list separator string for the current language.
Definition strings.cpp:299
_units_height
static const Units _units_height[]
Unit conversions for height.
Definition strings.cpp:915
_current_language
const LanguageMetadata * _current_language
The currently loaded language.
Definition strings.cpp:54
FormatBytes
static void FormatBytes(StringBuilder &builder, int64_t number)
Format a given number as a number of bytes with the SI prefix.
Definition strings.cpp:537
AppendStringInPlace
void AppendStringInPlace(std::string &result, StringID string)
Resolve the given StringID and append in place into an existing std::string with formatting but no pa...
Definition strings.cpp:434
ConvertSpeedToDisplaySpeed
uint ConvertSpeedToDisplaySpeed(uint speed, VehicleType type)
Convert the given (internal) speed to the display speed.
Definition strings.cpp:968
_config_language_file
std::string _config_language_file
The file (name) stored in the configuration.
Definition strings.cpp:52
GetVelocityUnits
static const Units GetVelocityUnits(VehicleType type)
Get the correct velocity units depending on the vehicle type and whether we're using real-time units.
Definition strings.cpp:951
DeterminePluralForm
static int DeterminePluralForm(int64_t count, uint plural_form)
Determine the "plural" index given a plural form and a number.
Definition strings.cpp:656
GetEncodedString
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp:90
ConvertDisplaySpeedToKmhishSpeed
uint ConvertDisplaySpeedToKmhishSpeed(uint speed, VehicleType type)
Convert the given display speed to the km/h-ish speed.
Definition strings.cpp:1001
_units_power
static const Units _units_power[]
Unit conversions for power.
Definition strings.cpp:874
GetSurname
static std::string_view GetSurname(uint32_t seed)
Get the surname of the president with the given seed.
Definition strings.cpp:1933
CheckForMissingGlyphs
void CheckForMissingGlyphs(MissingGlyphSearcher *searcher)
Check whether the currently loaded language pack uses characters that the currently loaded font does ...
Definition strings.cpp:2363
GetString
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:424
GetCurrentLanguageIsoCode
std::string_view GetCurrentLanguageIsoCode()
Get the ISO language code of the currently loaded language.
Definition strings.cpp:2270
_scan_for_gender_data
static bool _scan_for_gender_data
Are we scanning for the gender of the current string? (instead of formatting it)
Definition strings.cpp:293
_units_volume
static const UnitsLong _units_volume[]
Unit conversions for volume.
Definition strings.cpp:901
DecodeEncodedString
static void DecodeEncodedString(StringConsumer &consumer, bool game_script, StringBuilder &builder)
Decodes an encoded string during FormatString.
Definition strings.cpp:1012
_units_weight
static const UnitsLong _units_weight[]
Unit conversions for weight.
Definition strings.cpp:894
_units_velocity_calendar
static const Units _units_velocity_calendar[]
Unit conversions for velocity.
Definition strings.cpp:856
_current_collator
std::unique_ptr< icu::Collator > _current_collator
Collator for the language currently in use.
Definition strings.cpp:59
FillLanguageList
static void FillLanguageList(const std::string &path)
Search for the languages in the given directory and add them to the _languages list.
Definition strings.cpp:2193
ConvertKmhishSpeedToDisplaySpeed
uint ConvertKmhishSpeedToDisplaySpeed(uint speed, VehicleType type)
Convert the given km/h-ish speed to the display speed.
Definition strings.cpp:991
_units_force
static const Units _units_force[]
Unit conversions for force.
Definition strings.cpp:908
InitializeLanguagePacks
void InitializeLanguagePacks()
Make a list of the available language packs.
Definition strings.cpp:2222
GetLanguage
const LanguageMetadata * GetLanguage(uint8_t newgrflangid)
Get the language with the given NewGRF language ID.
Definition strings.cpp:2157
_units_time_days_or_seconds
static const Units _units_time_days_or_seconds[]
Unit conversions for time in calendar days or wallclock seconds.
Definition strings.cpp:923
ConvertDisplaySpeedToSpeed
uint ConvertDisplaySpeedToSpeed(uint speed, VehicleType type)
Convert the given display speed to the (internal) speed.
Definition strings.cpp:981
_current_text_dir
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition strings.cpp:56
_units_velocity_realtime
static const Units _units_velocity_realtime[]
Unit conversions for velocity.
Definition strings.cpp:865
ReadLanguagePack
bool ReadLanguagePack(const LanguageMetadata *lang)
Read a particular language.
Definition strings.cpp:2021
GetLanguageFileHeader
static bool GetLanguageFileHeader(const std::string &file, LanguagePackHeader *hdr)
Reads the language file header and checks compatibility.
Definition strings.cpp:2172
_units_time_months_or_minutes
static const Units _units_time_months_or_minutes[]
Unit conversions for time in calendar months or wallclock minutes.
Definition strings.cpp:929
FormatString
static void FormatString(StringBuilder &builder, std::string_view str, StringParameters &args, 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:1083
_units_time_years_or_minutes
static const Units _units_time_years_or_minutes[]
Unit conversions for time in calendar years or wallclock minutes.
Definition strings.cpp:941
_units_power_to_weight
static const Units _units_power_to_weight[]
Unit conversions for power to weight.
Definition strings.cpp:881
GetParamMaxDigits
uint64_t GetParamMaxDigits(uint count, FontSize size)
Get some number that is suitable for string size computations.
Definition strings.cpp:218
GetEllipsis
std::string_view GetEllipsis()
Get the ellipsis string for the current language.
Definition strings.cpp:308
_units_time_years_or_periods
static const Units _units_time_years_or_periods[]
Unit conversions for time in calendar years or economic periods.
Definition strings.cpp:935
strings_func.h
Functions related to OTTD's strings.
GetStringTab
StringTab GetStringTab(StringID str)
Extract the StringTab from a StringID.
Definition strings_func.h:22
MakeParameters
auto MakeParameters(Args &&... args)
Helper to create the StringParameters with its own buffer with the given parameter values.
Definition strings_func.h:107
MakeStringID
StringID MakeStringID(StringTab tab, StringIndexInTab index)
Create a StringID.
Definition strings_func.h:46
GetStringIndex
StringIndexInTab GetStringIndex(StringID str)
Extract the StringIndex from a StringID.
Definition strings_func.h:35
strings_internal.h
Types and functions related to the internal workings of formatting OpenTTD's strings.
GenerateTownNameString
void GenerateTownNameString(StringBuilder &builder, size_t lang, uint32_t seed)
Generates town name from given seed.
Definition townname.cpp:991
StringID
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Definition strings_type.h:19
StringIndexInTab
StrongType::Typedef< uint32_t, struct StringIndexInTabTag, StrongType::Compare, StrongType::Integer > StringIndexInTab
The index/offset of a string within a StringTab.
Definition strings_type.h:47
SPECSTR_COMPANY_NAME_START
static constexpr StringID SPECSTR_COMPANY_NAME_START
Special strings for company names on the form "TownName transport".
Definition strings_type.h:68
SPECSTR_SILLY_NAME
static constexpr StringID SPECSTR_SILLY_NAME
Special string for silly company names.
Definition strings_type.h:71
TAB_SIZE_GAMESCRIPT
static const uint TAB_SIZE_GAMESCRIPT
Number of strings for GameScripts.
Definition strings_type.h:55
MAX_LANG
static const uint MAX_LANG
Maximum number of languages supported by the game, and the NewGRF specs.
Definition strings_type.h:22
SPECSTR_ANDCO_NAME
static constexpr StringID SPECSTR_ANDCO_NAME
Special string for Surname & Co company names.
Definition strings_type.h:72
SPECSTR_PRESIDENT_NAME
static constexpr StringID SPECSTR_PRESIDENT_NAME
Special string for the president's name.
Definition strings_type.h:73
SPECSTR_TOWNNAME_START
static constexpr StringID SPECSTR_TOWNNAME_START
Special strings for town names.
Definition strings_type.h:64
TAB_SIZE
static const uint TAB_SIZE
Number of strings per StringTab.
Definition strings_type.h:52
StringTab
StringTab
StringTabs to group StringIDs.
Definition strings_type.h:31
TEXT_TAB_NEWGRF_START
@ TEXT_TAB_NEWGRF_START
Start of NewGRF supplied strings.
Definition strings_type.h:43
TEXT_TAB_GAMESCRIPT_START
@ TEXT_TAB_GAMESCRIPT_START
Start of GameScript supplied strings.
Definition strings_type.h:42
TEXT_TAB_END
@ TEXT_TAB_END
End of language files.
Definition strings_type.h:41
TextDirection
TextDirection
Directions a text can go to.
Definition strings_type.h:25
TD_LTR
@ TD_LTR
Text is written left-to-right by default.
Definition strings_type.h:26
AutoRestoreBackup
Class to backup a specific variable and restore it upon destruction of this object to prevent stack v...
Definition backup_type.hpp:150
BaseConsist::name
std::string name
Name of vehicle.
Definition base_consist.h:34
BaseStation::string_id
StringID string_id
Default name (town area) of station.
Definition base_station_base.h:64
BaseStation::town
Town * town
The town this station is associated with.
Definition base_station_base.h:67
BaseStation::name
std::string name
Custom name.
Definition base_station_base.h:63
BaseVehicle::type
VehicleType type
Type of vehicle.
Definition vehicle_type.h:51
CargoSpec::units_volume
StringID units_volume
Name of a single unit of cargo of this type.
Definition cargotype.h:93
CargoSpec::Get
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo type.
Definition cargotype.h:137
CargoSpec::GetArraySize
static size_t GetArraySize()
Total number of cargospecs, both valid and invalid.
Definition cargotype.h:127
CompanyProperties::president_name
std::string president_name
Name of the president if the user changed it.
Definition company_base.h:78
CompanyProperties::name_2
uint32_t name_2
Parameter of name_1.
Definition company_base.h:72
CompanyProperties::president_name_2
uint32_t president_name_2
Parameter of president_name_1.
Definition company_base.h:77
CompanyProperties::name_1
StringID name_1
Name of the company if the user did not change it.
Definition company_base.h:73
CompanyProperties::president_name_1
StringID president_name_1
Name of the president if the user did not change it.
Definition company_base.h:76
CompanyProperties::name
std::string name
Name of the company if the user changed it.
Definition company_base.h:74
Company
Definition company_base.h:127
Company::IsValidHumanID
static bool IsValidHumanID(auto index)
Is this company a valid company, not controlled by a NoAI program?
Definition company_base.h:165
CurrencySpec
Specification of a currency.
Definition currency.h:77
CurrencySpec::separator
std::string separator
The thousands separator for this currency.
Definition currency.h:79
CurrencySpec::prefix
std::string prefix
Prefix to apply when formatting money in this currency.
Definition currency.h:81
CurrencySpec::suffix
std::string suffix
Suffix to apply when formatting money in this currency.
Definition currency.h:82
CurrencySpec::rate
uint16_t rate
The conversion rate compared to the base currency.
Definition currency.h:78
CurrencySpec::symbol_pos
uint8_t symbol_pos
The currency symbol is represented by two possible values, prefix and suffix Usage of one or the othe...
Definition currency.h:93
Depot
Definition depot_base.h:20
Depot::town_cn
uint16_t town_cn
The N-1th depot for this town (consecutive number)
Definition depot_base.h:22
FontCacheSettings
Settings for the four different fonts.
Definition fontcache.h:180
FontCacheSettings::mono
FontCacheSubSetting mono
The mono space font used for license/readme viewers.
Definition fontcache.h:184
FontCacheSettings::medium
FontCacheSubSetting medium
The normal font size.
Definition fontcache.h:182
FontCacheSubSetting::font
std::string font
The name of the font, or path to the font.
Definition fontcache.h:173
FontCacheSubSetting::os_handle
const void * os_handle
Optional native OS font info. Only valid during font search.
Definition fontcache.h:176
GRFFile
Dynamic data of a loaded NewGRF.
Definition newgrf.h:114
GameCreationSettings::landscape
LandscapeType landscape
the landscape we're currently in
Definition settings_type.h:395
GameSettings::locale
LocaleSettings locale
settings related to used currency/unit system in the current game
Definition settings_type.h:645
GameSettings::game_creation
GameCreationSettings game_creation
settings used during the creation of a game (map)
Definition settings_type.h:634
Group
Group data.
Definition group.h:73
Group::name
std::string name
Group Name.
Definition group.h:74
Group::number
uint16_t number
Per-company group number.
Definition group.h:86
IndustrySpec
Defines the data structure for constructing industry.
Definition industrytype.h:103
IndustrySpec::name
StringID name
Displayed name of the industry.
Definition industrytype.h:123
IndustrySpec::station_name
StringID station_name
Default name for nearby station.
Definition industrytype.h:128
Industry
Defines the internal data of a functional industry.
Definition industry.h:62
Industry::type
IndustryType type
type of industry.
Definition industry.h:115
Industry::town
Town * town
Nearest town.
Definition industry.h:107
LanguageMetadata
Make sure the size is right.
Definition language.h:89
LanguageMetadata::file
std::filesystem::path file
Name of the file we read this data from.
Definition language.h:90
LanguagePackDeleter
Definition strings.cpp:271
LanguagePackHeader
Header of a language file.
Definition language.h:24
LanguagePackHeader::plural_form
uint8_t plural_form
plural form index
Definition language.h:41
LanguagePackHeader::IsValid
bool IsValid() const
Check whether the header is a valid header for OpenTTD.
Definition strings.cpp:1990
LanguagePackHeader::IsReasonablyFinished
bool IsReasonablyFinished() const
Check whether a translation is sufficiently finished to offer it to the public.
Definition strings.cpp:2010
LanguagePackHeader::version
uint32_t version
32-bits of auto generated version info which is basically a hash of strings.h
Definition language.h:28
LanguagePackHeader::isocode
char isocode[16]
the ISO code for the language (not country code)
Definition language.h:31
LanguagePackHeader::own_name
char own_name[32]
the localized name of this language
Definition language.h:30
LanguagePackHeader::name
char name[32]
the international name of this language
Definition language.h:29
LanguagePackHeader::winlangid
uint16_t winlangid
Windows language ID: Windows cannot and will not convert isocodes to something it can use to determin...
Definition language.h:51
LanguagePackHeader::num_genders
uint8_t num_genders
the number of genders of this language
Definition language.h:53
LanguagePackHeader::missing
uint16_t missing
number of missing strings.
Definition language.h:40
LanguagePackHeader::digit_group_separator
char digit_group_separator[8]
Thousand separator used for anything not currencies.
Definition language.h:35
LanguagePackHeader::newgrflangid
uint8_t newgrflangid
newgrf language id
Definition language.h:52
LanguagePackHeader::text_dir
uint8_t text_dir
default direction of the text
Definition language.h:42
LanguagePackHeader::num_cases
uint8_t num_cases
the number of cases of this language
Definition language.h:54
LanguagePackHeader::ident
uint32_t ident
32-bits identifier
Definition language.h:27
LanguagePackHeader::digit_decimal_separator
char digit_decimal_separator[8]
Decimal separator.
Definition language.h:39
LanguagePackHeader::digit_group_separator_currency
char digit_group_separator_currency[8]
Thousand separator used for currencies.
Definition language.h:37
LanguagePackHeader::IDENT
static const uint32_t IDENT
Identifier for OpenTTD language files, big endian for "LANG".
Definition language.h:25
LanguagePack
Definition strings.cpp:267
LoadedLanguagePack
Definition strings.cpp:279
LoadedLanguagePack::list_separator
std::string list_separator
Current list separator string.
Definition strings.cpp:287
LoadedLanguagePack::ellipsis
std::string ellipsis
Current ellipsis string.
Definition strings.cpp:288
LoadedLanguagePack::langtab_num
std::array< uint, TEXT_TAB_END > langtab_num
Offset into langpack offs.
Definition strings.cpp:284
LoadedLanguagePack::langtab_start
std::array< uint, TEXT_TAB_END > langtab_start
Offset into langpack offs.
Definition strings.cpp:285
LocaleSettings::units_velocity_nautical
uint8_t units_velocity_nautical
unit system for velocity of ships and aircraft
Definition settings_type.h:297
LocaleSettings::units_velocity
uint8_t units_velocity
unit system for velocity of trains and road vehicles
Definition settings_type.h:296
LocaleSettings::digit_decimal_separator
std::string digit_decimal_separator
decimal separator
Definition settings_type.h:305
LocaleSettings::digit_group_separator_currency
std::string digit_group_separator_currency
thousand separator for currencies
Definition settings_type.h:304
LocaleSettings::units_power
uint8_t units_power
unit system for power
Definition settings_type.h:298
LocaleSettings::units_height
uint8_t units_height
unit system for height
Definition settings_type.h:302
LocaleSettings::units_force
uint8_t units_force
unit system for force
Definition settings_type.h:301
LocaleSettings::units_volume
uint8_t units_volume
unit system for volume
Definition settings_type.h:300
LocaleSettings::units_weight
uint8_t units_weight
unit system for weight
Definition settings_type.h:299
LocaleSettings::digit_group_separator
std::string digit_group_separator
thousand separator for non-currencies
Definition settings_type.h:303
PoolID< uint8_t, struct CompanyIDTag, 0xF, 0xFF >
Pool::PoolItem<&_depot_pool >::Get
static Titem * Get(auto index)
Returns Titem with given index.
Definition pool_type.hpp:387
Pool::PoolItem::index
Tindex index
Index of this pool item.
Definition pool_type.hpp:286
Pool::PoolItem<&_company_pool >::GetIfValid
static Titem * GetIfValid(auto index)
Returns Titem with given index.
Definition pool_type.hpp:398
Sign
Definition signs_base.h:21
SpecializedStation< Station, false >::GetIfValid
static Station * GetIfValid(auto index)
Returns station if the index is a valid index for this station type.
Definition base_station_base.h:257
Station
Station data structure.
Definition station_base.h:500
StringParameter
The data required to format and validate a single parameter of a string.
Definition strings_type.h:78
StrongType::Typedef
Templated helper to make a type-safe 'typedef' representing a single POD value.
Definition strong_typedef_type.hpp:130
Town
Town data structure.
Definition town.h:63
Town::name
std::string name
Custom town name. If empty, the town was not renamed and uses the generated name.
Definition town.h:72
UnitConversion
Helper for unit conversion.
Definition strings.cpp:809
UnitConversion::factor
double factor
Amount to multiply or divide upon conversion.
Definition strings.cpp:810
UnitConversion::ToDisplay
int64_t ToDisplay(int64_t input, bool round=true) const
Convert value from OpenTTD's internal unit into the displayed value.
Definition strings.cpp:818
UnitConversion::FromDisplay
int64_t FromDisplay(int64_t input, bool round=true, int64_t divider=1) const
Convert the displayed value back into a value of OpenTTD's internal unit.
Definition strings.cpp:832
UnitsLong
Information about a specific unit system with a long variant.
Definition strings.cpp:848
UnitsLong::s
StringID s
String for the short variant of the unit.
Definition strings.cpp:850
UnitsLong::l
StringID l
String for the long variant of the unit.
Definition strings.cpp:851
UnitsLong::decimal_places
unsigned int decimal_places
Number of decimal places embedded in the value. For example, 1 if the value is in tenths,...
Definition strings.cpp:852
UnitsLong::c
UnitConversion c
Conversion.
Definition strings.cpp:849
Units
Information about a specific unit system.
Definition strings.cpp:841
Units::s
StringID s
String for the unit.
Definition strings.cpp:843
Units::decimal_places
unsigned int decimal_places
Number of decimal places embedded in the value. For example, 1 if the value is in tenths,...
Definition strings.cpp:844
Units::c
UnitConversion c
Conversion.
Definition strings.cpp:842
Vehicle
Vehicle data structure.
Definition vehicle_base.h:205
Vehicle::group_id
GroupID group_id
Index of group Pool array.
Definition vehicle_base.h:321
Vehicle::unitnumber
UnitID unitnumber
unit number, for display purposes only
Definition vehicle_base.h:281
Waypoint
Representation of a waypoint.
Definition waypoint_base.h:23
Waypoint::town_cn
uint16_t town_cn
The N-1th waypoint for this town (consecutive number)
Definition waypoint_base.h:24
timer_game_calendar.h
Definition of the game-calendar-timer.
town.h
Base of the town class.
townname_func.h
Town name generator stuff.
utf8.hpp
Handling of UTF-8 encoded data.
vehicle_base.h
Base class for all vehicles.
VehicleType
VehicleType
Available vehicle types.
Definition vehicle_type.h:22
VEH_ROAD
@ VEH_ROAD
Road vehicle type.
Definition vehicle_type.h:26
VEH_AIRCRAFT
@ VEH_AIRCRAFT
Aircraft vehicle type.
Definition vehicle_type.h:28
VEH_SHIP
@ VEH_SHIP
Ship vehicle type.
Definition vehicle_type.h:27
VEH_TRAIN
@ VEH_TRAIN
Train vehicle type.
Definition vehicle_type.h:25
waypoint_base.h
Base of waypoints.
OTTD2FS
std::wstring OTTD2FS(std::string_view name)
Convert from OpenTTD's encoding to a wide string.
Definition win32.cpp:357
FS2OTTD
std::string FS2OTTD(std::wstring_view name)
Convert to OpenTTD's encoding from a wide string.
Definition win32.cpp:340
InvalidateWindowClassesData
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:3311
window_func.h
Window functions not directly related to making/drawing windows.
WC_STATION_LIST
@ WC_STATION_LIST
Station list; Window numbers:
Definition window_type.h:307
WC_ROADVEH_LIST
@ WC_ROADVEH_LIST
Road vehicle list; Window numbers:
Definition window_type.h:319
WC_INDUSTRY_DIRECTORY
@ WC_INDUSTRY_DIRECTORY
Industry directory; Window numbers:
Definition window_type.h:271
WC_SHIPS_LIST
@ WC_SHIPS_LIST
Ships list; Window numbers:
Definition window_type.h:325
WC_TRAINS_LIST
@ WC_TRAINS_LIST
Trains list; Window numbers:
Definition window_type.h:313
WC_BUILD_VEHICLE
@ WC_BUILD_VEHICLE
Build vehicle; Window numbers:
Definition window_type.h:394
WC_AIRCRAFT_LIST
@ WC_AIRCRAFT_LIST
Aircraft list; Window numbers:
Definition window_type.h:331