39 #include "table/strings.h" 61 assert(this->
type !=
nullptr);
73 DEBUG(misc, 0,
"Trying to read invalid string parameter");
76 if (this->type !=
nullptr) {
77 if (this->type[this->
offset] != 0 && this->type[this->
offset] != type) {
78 DEBUG(misc, 0,
"Trying to read string parameter with wrong type");
107 while (max_value >= 10) {
125 uint64 val = count > 1 ? front : next;
126 for (; count > 1; count--) {
127 val = 10 * val + next;
165 GetString(buf,
string,
lastof(buf));
168 for (
int i = 0; i < num; i++) {
170 strings[i] =
stredup((
const char *)(
size_t)_global_string_params.GetParam(i));
171 dst[i] = (size_t)strings[i];
173 strings[i] =
nullptr;
178 static char *StationGetSpecialString(
char *buff,
int x,
const char *last);
179 static char *GetSpecialTownNameString(
char *buff,
int ind, uint32 seed,
const char *last);
180 static char *GetSpecialNameString(
char *buff,
int ind,
StringParameters *args,
const char *last);
182 static char *
FormatString(
char *buff,
const char *str,
StringParameters *args,
const char *last, uint case_index = 0,
bool game_script =
false,
bool dry_run =
false);
188 static char **_langpack_offs;
195 const char *GetStringPtr(
StringID string)
200 case TEXT_TAB_OLD_NEWGRF: NOT_REACHED();
225 if (index >= 0xC0 && !game_script) {
226 return GetSpecialTownNameString(buffr, index - 0xC0, args->
GetInt32(), last);
230 case TEXT_TAB_SPECIAL:
231 if (index >= 0xE4 && !game_script) {
232 return GetSpecialNameString(buffr, index - 0xE4, args, last);
236 case TEXT_TAB_OLD_CUSTOM:
239 error(
"Incorrect conversion of custom name string.");
246 case TEXT_TAB_OLD_NEWGRF:
260 error(
"String 0x%X is invalid. You are probably using an old version of the .lng file.\n",
string);
263 return FormatString(buffr, GetStringPtr(
string), args, last, case_index);
266 char *GetString(
char *buffr,
StringID string,
const char *last)
269 _global_string_params.
offset = 0;
304 static char *
FormatNumber(
char *buff, int64 number,
const char *last,
const char *separator,
int zerofill = 1,
int fractional_digits = 0)
306 static const int max_digits = 20;
307 uint64 divisor = 10000000000000000000ULL;
308 zerofill += fractional_digits;
309 int thousands_offset = (max_digits - fractional_digits - 1) % 3;
318 for (
int i = 0; i < max_digits; i++) {
319 if (i == max_digits - fractional_digits) {
322 buff +=
seprintf(buff, last,
"%s", decimal_separator);
326 if (num >= divisor) {
327 quot = num / divisor;
330 if ((tot |= quot) || i >= max_digits - zerofill) {
331 buff +=
seprintf(buff, last,
"%i", (
int)quot);
332 if ((i % 3) == thousands_offset && i < max_digits - 1 - fractional_digits) buff =
strecpy(buff, separator, last);
343 static char *FormatCommaNumber(
char *buff, int64 number,
const char *last,
int fractional_digits = 0)
347 return FormatNumber(buff, number, last, separator, 1, fractional_digits);
350 static char *FormatNoCommaNumber(
char *buff, int64 number,
const char *last)
355 static char *FormatZerofillNumber(
char *buff, int64 number, int64 count,
const char *last)
360 static char *FormatHexNumber(
char *buff, uint64 number,
const char *last)
362 return buff +
seprintf(buff, last,
"0x" OTTD_PRINTFHEX64, number);
372 static char *
FormatBytes(
char *buff, int64 number,
const char *last)
377 const char *
const iec_prefixes[] = {
"",
"Ki",
"Mi",
"Gi",
"Ti",
"Pi",
"Ei"};
379 while (number >= 1024 * 1024) {
389 buff +=
seprintf(buff, last,
"%i", (
int)number);
390 }
else if (number < 1024 * 10) {
391 buff +=
seprintf(buff, last,
"%i%s%02i", (
int)number / 1024, decimal_separator, (
int)(number % 1024) * 100 / 1024);
392 }
else if (number < 1024 * 100) {
393 buff +=
seprintf(buff, last,
"%i%s%01i", (
int)number / 1024, decimal_separator, (
int)(number % 1024) * 10 / 1024);
395 assert(number < 1024 * 1024);
396 buff +=
seprintf(buff, last,
"%i", (
int)number / 1024);
399 assert(
id <
lengthof(iec_prefixes));
400 buff +=
seprintf(buff, last,
NBSP "%sB", iec_prefixes[
id]);
405 static char *FormatYmdString(
char *buff,
Date date,
const char *last, uint case_index)
410 int64 args[] = {ymd.
day + STR_DAY_NUMBER_1ST - 1, STR_MONTH_ABBREV_JAN + ymd.
month, ymd.
year};
412 return FormatString(buff, GetStringPtr(STR_FORMAT_DATE_LONG), &tmp_params, last, case_index);
415 static char *FormatMonthAndYear(
char *buff,
Date date,
const char *last, uint case_index)
420 int64 args[] = {STR_MONTH_JAN + ymd.
month, ymd.
year};
422 return FormatString(buff, GetStringPtr(STR_FORMAT_DATE_SHORT), &tmp_params, last, case_index);
425 static char *FormatTinyOrISODate(
char *buff,
Date date,
StringID str,
const char *last)
436 int64 args[] = {(int64)(
size_t)day, (int64)(
size_t)month, ymd.
year};
438 return FormatString(buff, GetStringPtr(str), &tmp_params, last);
441 static char *FormatGenericCurrency(
char *buff,
const CurrencySpec *spec,
Money number,
bool compact,
const char *last)
445 bool negative = number < 0;
446 const char *multiplier =
"";
448 number *= spec->rate;
452 if (buff +
Utf8CharLen(SCC_PUSH_COLOUR) > last)
return buff;
454 if (buff +
Utf8CharLen(SCC_RED) > last)
return buff;
456 buff =
strecpy(buff,
"-", last);
469 if (number >= 1000000000 - 500) {
470 number = (number + 500000) / 1000000;
471 multiplier =
NBSP "M";
472 }
else if (number >= 1000000) {
473 number = (number + 500) / 1000;
474 multiplier =
NBSP "k";
479 if (separator ==
nullptr && !
StrEmpty(_currency->separator)) separator = _currency->separator;
482 buff =
strecpy(buff, multiplier, last);
490 if (buff +
Utf8CharLen(SCC_POP_COLOUR) > last)
return buff;
507 uint64 n =
abs(count);
509 switch (plural_form) {
518 return n != 1 ? 1 : 0;
530 return n > 1 ? 1 : 0;
537 return n % 10 == 1 && n % 100 != 11 ? 0 : n != 0 ? 1 : 2;
543 return n == 1 ? 0 : n == 2 ? 1 : n < 7 ? 2 : n < 11 ? 3 : 4;
549 return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
555 return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
561 return n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
567 return n % 100 == 1 ? 0 : n % 100 == 2 ? 1 : n % 100 == 3 || n % 100 == 4 ? 2 : 3;
573 return n % 10 == 1 && n % 100 != 11 ? 0 : 1;
579 return n == 1 ? 0 : n >= 2 && n <= 4 ? 1 : 2;
610 return (n == 1 ? 0 : n == 0 || (n % 100 > 1 && n % 100 < 11) ? 1 : (n % 100 > 10 && n % 100 < 20) ? 2 : 3);
615 return ((n == 1 || n == 11) ? 0 : (n == 2 || n == 12) ? 1 : ((n > 2 && n < 11) || (n > 12 && n < 20)) ? 2 : 3);
619 static const char *ParseStringChoice(
const char *b, uint form,
char **dst,
const char *last)
623 uint pos, i, mypos = 0;
625 for (i = pos = 0; i != n; i++) {
626 uint len = (byte)*b++;
627 if (i == form) mypos = pos;
631 *dst +=
seprintf(*dst, last,
"%s", b + mypos);
648 return ((input * this->multiplier) + (round && this->shift != 0 ? 1 << (this->shift - 1) : 0)) >> this->shift;
658 int64
FromDisplay(int64 input,
bool round =
true, int64 divider = 1)
const 660 return ((input << this->shift) + (round ? (this->multiplier * divider) - 1 : 0)) / (this->multiplier * divider);
679 { { 1, 0}, STR_UNITS_VELOCITY_IMPERIAL },
680 { { 103, 6}, STR_UNITS_VELOCITY_METRIC },
681 { {1831, 12}, STR_UNITS_VELOCITY_SI },
686 { { 1, 0}, STR_UNITS_POWER_IMPERIAL },
687 { {4153, 12}, STR_UNITS_POWER_METRIC },
688 { {6109, 13}, STR_UNITS_POWER_SI },
693 { {4515, 12}, STR_UNITS_WEIGHT_SHORT_IMPERIAL, STR_UNITS_WEIGHT_LONG_IMPERIAL },
694 { { 1, 0}, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC },
695 { {1000, 0}, STR_UNITS_WEIGHT_SHORT_SI, STR_UNITS_WEIGHT_LONG_SI },
700 { {4227, 4}, STR_UNITS_VOLUME_SHORT_IMPERIAL, STR_UNITS_VOLUME_LONG_IMPERIAL },
701 { {1000, 0}, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC },
702 { { 1, 0}, STR_UNITS_VOLUME_SHORT_SI, STR_UNITS_VOLUME_LONG_SI },
707 { {3597, 4}, STR_UNITS_FORCE_IMPERIAL },
708 { {3263, 5}, STR_UNITS_FORCE_METRIC },
709 { { 1, 0}, STR_UNITS_FORCE_SI },
714 { { 3, 0}, STR_UNITS_HEIGHT_IMPERIAL },
715 { { 1, 0}, STR_UNITS_HEIGHT_METRIC },
716 { { 1, 0}, STR_UNITS_HEIGHT_SI },
771 uint orig_offset = args->
offset;
783 FormatString(buff, str_arg, args, last, case_index, game_script,
true);
786 FormatString(buff, str_arg, args, last, case_index, game_script,
true);
789 args->
offset = orig_offset;
792 uint next_substr_case_index = 0;
793 char *buf_start = buff;
794 std::stack<const char *, std::vector<const char *>> str_stack;
795 str_stack.push(str_arg);
798 while (!str_stack.empty() && (b = Utf8Consume(&str_stack.top())) ==
'\0') {
801 if (str_stack.empty())
break;
802 const char *&str = str_stack.top();
808 if (b == 0)
continue;
813 uint64 sub_args_data[20];
814 WChar sub_args_type[20];
815 bool sub_args_need_free[20];
819 memset(sub_args_need_free, 0,
sizeof(sub_args_need_free));
822 uint32 stringid = strtoul(str, &p, 16);
823 if (*p !=
':' && *p !=
'\0') {
824 while (*p !=
'\0') p++;
826 buff =
strecat(buff,
"(invalid SCC_ENCODED)", last);
830 while (*p !=
'\0') p++;
832 buff =
strecat(buff,
"(invalid StringID)", last);
837 while (*p !=
'\0' && i < 20) {
842 bool instring =
false;
849 if (*p ==
'"' && escape) {
856 instring = !instring;
863 if (*p ==
':')
break;
864 if (*p ==
'\0')
break;
871 bool lookup = (l == SCC_ENCODED);
872 if (lookup) s += len;
874 param = strtoull(s, &p, 16);
878 while (*p !=
'\0') p++;
880 buff =
strecat(buff,
"(invalid sub-StringID)", last);
886 sub_args.SetParam(i++, param);
891 sub_args_need_free[i] =
true;
892 sub_args.SetParam(i++, (uint64)(
size_t)g);
901 for (
int i = 0; i < 20; i++) {
902 if (sub_args_need_free[i])
free((
void *)sub_args.GetParam(i));
908 StringID substr = Utf8Consume(&str);
909 str_stack.push(GetStringPtr(substr));
915 str_stack.push(GetStringPtr(substr));
916 case_index = next_substr_case_index;
917 next_substr_case_index = 0;
922 case SCC_GENDER_LIST: {
924 uint
offset = orig_offset + (byte)*str++;
945 WChar c = Utf8Consume(&s);
947 if (c == SCC_GENDER_INDEX) gender = (byte)s[0];
949 str = ParseStringChoice(str, gender, &buff, last);
955 case SCC_GENDER_INDEX:
964 case SCC_PLURAL_LIST: {
965 int plural_form = *str++;
966 uint
offset = orig_offset + (byte)*str++;
972 case SCC_ARG_INDEX: {
973 args->
offset = orig_offset + (byte)*str++;
980 next_substr_case_index = (byte)*str++;
984 case SCC_SWITCH_CASE: {
987 uint num = (byte)*str++;
989 if ((byte)str[0] == case_index) {
995 str += 3 + (str[1] << 8) + str[2];
1002 buff =
strecpy(buff, _openttd_revision, last);
1005 case SCC_RAW_STRING_POINTER: {
1006 if (game_script)
break;
1007 const char *str = (
const char *)(
size_t)args->
GetInt64(SCC_RAW_STRING_POINTER);
1019 buff =
GetStringWithArgs(buff, str, &tmp_params, last, next_substr_case_index, game_script);
1020 next_substr_case_index = 0;
1034 uint size = b - SCC_STRING1 + 1;
1036 buff =
strecat(buff,
"(too many parameters)", last);
1039 buff =
GetStringWithArgs(buff, str, &sub_args, last, next_substr_case_index, game_script);
1041 next_substr_case_index = 0;
1046 buff = FormatCommaNumber(buff, args->
GetInt64(SCC_COMMA), last);
1050 int64 number = args->
GetInt64(SCC_DECIMAL);
1051 int digits = args->
GetInt32(SCC_DECIMAL);
1052 buff = FormatCommaNumber(buff, number, last, digits);
1057 buff = FormatNoCommaNumber(buff, args->
GetInt64(SCC_NUM), last);
1060 case SCC_ZEROFILL_NUM: {
1062 buff = FormatZerofillNumber(buff, num, args->
GetInt64(), last);
1067 buff = FormatHexNumber(buff, (uint64)args->
GetInt64(SCC_HEX), last);
1074 case SCC_CARGO_TINY: {
1083 switch (cargo_str) {
1098 buff = FormatCommaNumber(buff, amount, last);
1102 case SCC_CARGO_SHORT: {
1110 switch (cargo_str) {
1136 case SCC_CARGO_LONG: {
1147 case SCC_CARGO_LIST: {
1148 CargoTypes cmask = args->
GetInt64(SCC_CARGO_LIST);
1155 if (buff >= last - 2)
break;
1169 if (first) buff =
GetStringWithArgs(buff, STR_JUST_NOTHING, args, last, next_substr_case_index, game_script);
1172 next_substr_case_index = 0;
1175 assert(buff < last);
1179 case SCC_CURRENCY_SHORT:
1180 buff = FormatGenericCurrency(buff, _currency, args->
GetInt64(),
true, last);
1183 case SCC_CURRENCY_LONG:
1184 buff = FormatGenericCurrency(buff, _currency, args->
GetInt64(SCC_CURRENCY_LONG),
false, last);
1188 buff = FormatTinyOrISODate(buff, args->
GetInt32(SCC_DATE_TINY), STR_FORMAT_DATE_TINY, last);
1191 case SCC_DATE_SHORT:
1192 buff = FormatMonthAndYear(buff, args->
GetInt32(SCC_DATE_SHORT), last, next_substr_case_index);
1193 next_substr_case_index = 0;
1197 buff = FormatYmdString(buff, args->
GetInt32(SCC_DATE_LONG), last, next_substr_case_index);
1198 next_substr_case_index = 0;
1202 buff = FormatTinyOrISODate(buff, args->
GetInt32(), STR_FORMAT_DATE_ISO, last);
1229 case SCC_VELOCITY: {
1237 case SCC_VOLUME_SHORT: {
1245 case SCC_VOLUME_LONG: {
1253 case SCC_WEIGHT_SHORT: {
1261 case SCC_WEIGHT_LONG: {
1269 case SCC_COMPANY_NAME: {
1271 if (c ==
nullptr)
break;
1273 if (c->
name !=
nullptr) {
1274 int64 args_array[] = {(int64)(
size_t)c->
name};
1278 int64 args_array[] = {c->
name_2};
1285 case SCC_COMPANY_NUM: {
1290 int64 args_array[] = {company + 1};
1297 case SCC_DEPOT_NAME: {
1300 uint64 args_array[] = {(uint64)args->
GetInt32()};
1301 WChar types_array[] = {SCC_STATION_NAME};
1303 buff =
GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_AIRCRAFT, &tmp_params, last);
1308 if (d->name !=
nullptr) {
1309 int64 args_array[] = {(int64)(
size_t)d->name};
1315 buff =
GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_TRAIN + 2 * vt + (d->
town_cn == 0 ? 0 : 1), &tmp_params, last);
1320 case SCC_ENGINE_NAME: {
1322 if (e ==
nullptr)
break;
1325 int64 args_array[] = {(int64)(
size_t)e->
name};
1335 case SCC_GROUP_NAME: {
1337 if (g ==
nullptr)
break;
1339 if (g->
name !=
nullptr) {
1340 int64 args_array[] = {(int64)(
size_t)g->
name};
1344 int64 args_array[] = {g->
index};
1352 case SCC_INDUSTRY_NAME: {
1354 if (i ==
nullptr)
break;
1366 buff =
FormatString(buff, GetStringPtr(STR_FORMAT_INDUSTRY_NAME), &tmp_params, last, next_substr_case_index);
1368 next_substr_case_index = 0;
1372 case SCC_PRESIDENT_NAME: {
1374 if (c ==
nullptr)
break;
1388 case SCC_STATION_NAME: {
1389 StationID sid = args->
GetInt32(SCC_STATION_NAME);
1392 if (st ==
nullptr) {
1401 if (st->
name !=
nullptr) {
1402 int64 args_array[] = {(int64)(
size_t)st->
name};
1407 if (st->
indtype != IT_INVALID) {
1419 uint64 args_array[] = {STR_TOWN_NAME, st->
town->
index, st->
index};
1420 WChar types_array[] = {0, SCC_TOWN_NAME, SCC_NUM};
1427 case SCC_TOWN_NAME: {
1429 if (t ==
nullptr)
break;
1431 if (t->
name !=
nullptr) {
1432 int64 args_array[] = {(int64)(
size_t)t->
name};
1441 case SCC_WAYPOINT_NAME: {
1443 if (wp ==
nullptr)
break;
1445 if (wp->
name !=
nullptr) {
1446 int64 args_array[] = {(int64)(
size_t)wp->
name};
1452 StringID str = ((wp->
string_id == STR_SV_STNAME_BUOY) ? STR_FORMAT_BUOY_NAME : STR_FORMAT_WAYPOINT_NAME);
1459 case SCC_VEHICLE_NAME: {
1461 if (v ==
nullptr)
break;
1463 if (v->
name !=
nullptr) {
1464 int64 args_array[] = {(int64)(
size_t)v->
name};
1473 default: str = STR_INVALID_VEHICLE;
break;
1474 case VEH_TRAIN: str = STR_SV_TRAIN_NAME;
break;
1475 case VEH_ROAD: str = STR_SV_ROAD_VEHICLE_NAME;
break;
1476 case VEH_SHIP: str = STR_SV_SHIP_NAME;
break;
1485 case SCC_SIGN_NAME: {
1487 if (si ==
nullptr)
break;
1489 if (si->name !=
nullptr) {
1490 int64 args_array[] = {(int64)(
size_t)si->name};
1500 case SCC_STATION_FEATURES: {
1501 buff = StationGetSpecialString(buff, args->
GetInt32(SCC_STATION_FEATURES), last);
1515 static char *StationGetSpecialString(
char *buff,
int x,
const char *last)
1526 static char *GetSpecialTownNameString(
char *buff,
int ind, uint32 seed,
const char *last)
1531 static const char *
const _silly_company_names[] = {
1533 "Tiny Transport Ltd.",
1535 "Comfy-Coach & Co.",
1536 "Crush & Bump Ltd.",
1537 "Broken & Late Ltd.",
1539 "Supersonic Travel",
1541 "Lightning International",
1542 "Pannik & Loozit Ltd.",
1543 "Inter-City Transport",
1544 "Getout & Pushit Ltd." 1547 static const char *
const _surname_list[] = {
1579 static const char *
const _silly_surname_list[] = {
1594 static const char _initial_name_letters[] = {
1595 'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
1596 'K',
'L',
'M',
'N',
'P',
'R',
'S',
'T',
'W',
1599 static char *GenAndCoName(
char *buff, uint32 arg,
const char *last)
1601 const char *
const *base;
1605 base = _silly_surname_list;
1606 num =
lengthof(_silly_surname_list);
1608 base = _surname_list;
1612 buff =
strecpy(buff, base[num *
GB(arg, 16, 8) >> 8], last);
1613 buff =
strecpy(buff,
" & Co.", last);
1618 static char *GenPresidentName(
char *buff, uint32 x,
const char *last)
1620 char initial[] =
"?. ";
1621 const char *
const *base;
1625 initial[0] = _initial_name_letters[
sizeof(_initial_name_letters) *
GB(x, 0, 8) >> 8];
1626 buff =
strecpy(buff, initial, last);
1628 i = (
sizeof(_initial_name_letters) + 35) *
GB(x, 8, 8) >> 8;
1629 if (i <
sizeof(_initial_name_letters)) {
1630 initial[0] = _initial_name_letters[i];
1631 buff =
strecpy(buff, initial, last);
1635 base = _silly_surname_list;
1636 num =
lengthof(_silly_surname_list);
1638 base = _surname_list;
1642 buff =
strecpy(buff, base[num *
GB(x, 16, 8) >> 8], last);
1647 static char *GetSpecialNameString(
char *buff,
int ind,
StringParameters *args,
const char *last)
1654 return GenAndCoName(buff, args->
GetInt32(), last);
1657 return GenPresidentName(buff, args->
GetInt32(), last);
1661 if (
IsInsideMM(ind - 6, 0, SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1)) {
1662 buff = GetSpecialTownNameString(buff, ind - 6, args->
GetInt32(), last);
1663 return strecpy(buff,
" Transport", last);
1667 if (
IsInsideMM(ind, (SPECSTR_LANGUAGE_START - 0x70E4), (SPECSTR_LANGUAGE_END - 0x70E4) + 1)) {
1668 int i = ind - (SPECSTR_LANGUAGE_START - 0x70E4);
1675 int i = ind - (SPECSTR_RESOLUTION_START - 0x70E4);
1685 extern void SortNetworkLanguages();
1694 this->version == TO_LE32(LANGUAGE_PACK_VERSION) &&
1695 this->plural_form < LANGUAGE_MAX_PLURAL &&
1696 this->text_dir <= 1 &&
1703 StrValid(this->digit_group_separator,
lastof(this->digit_group_separator)) &&
1704 StrValid(this->digit_group_separator_currency,
lastof(this->digit_group_separator_currency)) &&
1705 StrValid(this->digit_decimal_separator,
lastof(this->digit_decimal_separator));
1718 if (lang_pack ==
nullptr)
return false;
1721 const char *end = (
char *)lang_pack + len + 1;
1724 if (end <= lang_pack->
data || !lang_pack->
IsValid()) {
1729 #if TTD_ENDIAN == TTD_BIG_ENDIAN 1737 uint16 num = lang_pack->
offsets[i];
1749 char **langpack_offs = MallocT<char *>(count);
1752 char *s = lang_pack->data;
1754 for (uint i = 0; i < count; i++) {
1755 if (s + len >= end) {
1757 free(langpack_offs);
1761 len = ((len & 0x3F) << 8) + (byte)*s++;
1762 if (s + len >= end) {
1764 free(langpack_offs);
1768 langpack_offs[i] = s;
1775 _langpack = lang_pack;
1777 free(_langpack_offs);
1778 _langpack_offs = langpack_offs;
1780 _current_language = lang;
1782 const char *c_file = strrchr(_current_language->
file, PATHSEPCHAR) + 1;
1787 extern void Win32SetCurrentLocaleName(
const char *iso_code);
1788 Win32SetCurrentLocaleName(_current_language->
isocode);
1796 #ifdef WITH_ICU_I18N 1804 UErrorCode status = U_ZERO_ERROR;
1809 if (U_FAILURE(status)) {
1820 SortNetworkLanguages();
1835 #if !(defined(_WIN32) || defined(__APPLE__)) 1848 env = getenv(
"LANGUAGE");
1849 if (env !=
nullptr)
return env;
1851 env = getenv(
"LC_ALL");
1852 if (env !=
nullptr)
return env;
1854 if (param !=
nullptr) {
1855 env = getenv(param);
1856 if (env !=
nullptr)
return env;
1859 return getenv(
"LANG");
1869 GetString(stra, a,
lastof(stra));
1870 GetString(strb, b,
lastof(strb));
1883 if (newgrflangid == lang.newgrflangid)
return ⟨
1897 FILE *f = fopen(file,
"rb");
1898 if (f ==
nullptr)
return false;
1900 size_t read = fread(hdr,
sizeof(*hdr), 1, f);
1903 bool ret = read == 1 && hdr->
IsValid();
1920 if (dir !=
nullptr) {
1921 struct dirent *dirent;
1922 while ((dirent = readdir(dir)) !=
nullptr) {
1923 const char *d_name =
FS2OTTD(dirent->d_name);
1924 const char *extension = strrchr(d_name,
'.');
1927 if (extension ==
nullptr || strcmp(extension,
".lng") != 0)
continue;
1934 DEBUG(misc, 3,
"%s is not a valid language file", lmd.
file);
1936 DEBUG(misc, 3,
"%s's language ID is already known", lmd.
file);
1954 char path[MAX_PATH];
1962 if (lang ==
nullptr) lang =
"en_GB";
1973 const char *lang_file = strrchr(lng.file, PATHSEPCHAR) + 1;
1975 chosen_language = &lng;
1979 if (strcmp (lng.isocode,
"en_GB") == 0) en_GB_fallback = &lng;
1980 if (strncmp(lng.isocode, lang, 5) == 0) chosen_language = &lng;
1981 if (strncmp(lng.isocode, lang, 2) == 0) language_fallback = &lng;
1986 if (chosen_language ==
nullptr) {
1987 chosen_language = (language_fallback !=
nullptr) ? language_fallback : en_GB_fallback;
2011 const Sprite *question_mark[FS_END];
2014 question_mark[size] =
GetGlyph(size,
'?');
2018 for (
const char *text = this->NextString(); text !=
nullptr; text = this->NextString()) {
2019 FontSize size = this->DefaultSize();
2020 if (str !=
nullptr) *str = text;
2021 for (
WChar c = Utf8Consume(&text); c !=
'\0'; c = Utf8Consume(&text)) {
2022 if (c >= SCC_FIRST_FONT && c <= SCC_LAST_FONT) {
2023 size = (
FontSize)(c - SCC_FIRST_FONT);
2053 const char *ret = _langpack_offs[
_langtab_start[this->i] + this->j];
2056 while (this->i < TEXT_TAB_END && this->j >=
_langtab_num[this->i]) {
2071 #if defined(WITH_FREETYPE) || defined(_WIN32) 2100 if (searcher ==
nullptr) searcher = &pack_searcher;
2102 #if defined(WITH_FREETYPE) || defined(_WIN32) 2107 memcpy(&backup, &_freetype,
sizeof(backup));
2117 memcpy(&_freetype, &backup,
sizeof(backup));
2119 if (bad_font && base_font) {
2134 static char *err_str =
stredup(
"XXXThe current font is missing some of the characters used in the texts for this language. Read the readme to see how to solve this.");
2147 #if !defined(WITH_ICU_LX) && !defined(WITH_UNISCRIBE) && !defined(WITH_COCOA) 2162 static char *err_str =
stredup(
"XXXThis version of OpenTTD does not support right-to-left languages. Recompile with icu enabled.");
Helper for unit conversion.
Functions related to OTTD's strings.
Owner
Enum for all companies/owners.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition of stuff that is very close to a company, like the company struct itself.
void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher)
Check whether the currently loaded language pack uses characters that the currently loaded font does ...
static Titem * GetIfValid(size_t index)
Returns Titem with given index.
int64 FromDisplay(int64 input, bool round=true, int64 divider=1) const
Convert the displayed value back into a value of OpenTTD's internal unit.
static char * FormatBytes(char *buff, int64 number, const char *last)
Format a given number as a number of bytes with the SI prefix.
static char * FormatString(char *buff, const char *str, StringParameters *args, const char *last, uint case_index=0, bool game_script=false, bool dry_run=false)
Parse most format codes within a string and write the result to a buffer.
Inline another string at the current position, StringID is encoded in the string. ...
void SortIndustryTypes()
Initialize the list of sorted industry types.
uint16 town_cn
The N-1th waypoint for this town (consecutive number)
static uint GetStringIndex(StringID str)
Extract the StringIndex from a StringID.
char * name
Name of the company if the user changed it.
WChar * type
Array with type information about the data. Can be nullptr when no type information is needed...
Control codes that are embedded in the translation strings.
byte landscape
the landscape we're currently in
static char * strecat(char *dst, const char *src, const char *last)
Appends characters from one string to another.
const char * FS2OTTD(const TCHAR *name)
Convert to OpenTTD's encoding from that of the local environment.
bool UsingNewGRFTextStack()
Check whether the NewGRF text stack is in use.
static const Units _units_height[]
Unit conversions for height.
bool IsEnabled() const
Checks whether the engine is a valid (non-articulated part of an) engine.
static Titem * Get(size_t index)
Returns Titem with given index.
void ClearTypeInformation()
Reset the type array.
Functions related to dates.
icu::Collator * _current_collator
Collator for the language currently in use.
byte units_weight
unit system for weight
Functions to handle different currencies.
int CDECL seprintf(char *str, const char *last, const char *format,...)
Safer implementation of snprintf; same as snprintf except:
Functions related to debugging.
uint num_param
Length of the data array.
static uint64 _global_string_params_data[20]
Global array of string parameters. To access, use SetDParam.
static int DeterminePluralForm(int64 count, int plural_form)
Determine the "plural" index given a plural form and a number.
void SetCurrentGrfLangID(byte language_id)
Equivalence Setter function between game and newgrf langID.
Index of the monospaced font in the font tables.
Data structure describing a sprite.
#define FOR_ALL_SEARCHPATHS(sp)
Iterator for all the search paths.
fluid_settings_t * settings
FluidSynth settings handle.
#define FOR_ALL_SORTED_CARGOSPECS(var)
Loop header for iterating over cargoes, sorted by name.
Specification of a cargo type.
VehicleType
Available vehicle types.
static uint _langtab_num[TEXT_TAB_END]
Offset into langpack offs.
void ShiftParameters(uint amount)
Shift all data in the data array by the given amount to make room for some extra parameters.
Build vehicle; Window numbers:
void CopyInDParam(int offs, const uint64 *src, int num)
Copy num string parameters from array src into the global string parameter array. ...
Base for all depots (except hangars)
Functions related to detecting/finding the right font.
uint offset
Current offset in the data/type arrays.
byte units_velocity
unit system for velocity
Defines the internal data of a functional industry.
Base functions regarding game texts.
Tindex index
Index of this pool item.
static bool IsTextDirectionChar(WChar c)
Is the given character a text direction character.
void ShowErrorMessage(StringID summary_msg, StringID detailed_msg, WarningLevel wl, int x=0, int y=0, const GRFFile *textref_stack_grffile=nullptr, uint textref_stack_size=0, const uint32 *textref_stack=nullptr)
Display an error message in a window.
char * president_name
Name of the president if the user changed it.
static StringID MakeStringID(StringTab tab, uint index)
Create a StringID.
static const int DRAW_STRING_BUFFER
Size of the buffer used for drawing strings.
bool HasTypeInformation() const
Does this instance store information about the type of the parameters.
virtual bool Monospace()=0
Whether to search for a monospace font or not.
Functions for Standard In/Out file operations.
size_t Utf8Decode(WChar *c, const char *s)
Decode and consume the next UTF-8 encoded character.
FreeTypeSubSetting large
The largest font; mostly used for newspapers.
Representation of a waypoint.
#define lastof(x)
Get the last element of an fixed size array.
Function to handling different endian machines.
StringTab
StringTabs to group StringIDs.
static StringTab GetStringTab(StringID str)
Extract the StringTab from a StringID.
Searchpath
Types of searchpaths OpenTTD might use.
uint32 name_2
Parameter of name_1.
StringID quantifier
Text for multiple units of cargo of this type.
static T max(const T a, const T b)
Returns the maximum of two values.
Information about a specific unit system with a long variant.
byte units_force
unit system for force
Town * town
The town this station is associated with.
byte units_height
unit system for height
The next variables are part of a NewGRF subsystem for creating text strings.
StringID name
Name of this type of cargo.
Industry directory; Window numbers:
static void GetLanguageList(const char *path)
Gets a list of languages from the given directory.
StringID name
Displayed name of the industry.
bool Monospace() override
Whether to search for a monospace font or not.
char * GetStringWithArgs(char *buffr, StringID string, StringParameters *args, const char *last, uint case_index, bool game_script)
Get a parsed string with most special stringcodes replaced by the string parameters.
Settings for the freetype fonts.
static bool IsInsideBS(const T x, const size_t base, const size_t size)
Checks if a value is between a window started at some base point.
static const Units _units_force[]
Unit conversions for force.
static bool IsValidHumanID(size_t index)
Is this company a valid company, not controlled by a NoAI program?
std::vector< Dimension > _resolutions
List of resolutions.
void InitFreeType(bool monospace)
(Re)initialize the freetype related things, i.e.
static void MemMoveT(T *destination, const T *source, size_t num=1)
Type-safe version of memmove().
Helper for searching through the language pack.
void BuildContentTypeStringList()
Build array of all strings corresponding to the content types.
uint ConvertDisplaySpeedToSpeed(uint speed)
Convert the given display speed to the (internal) speed.
static bool IsInsideMM(const T x, const size_t min, const size_t max)
Checks if a value is in an interval.
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...
uint RemapNewGRFStringControlCode(uint scc, char *buf_start, char **buff, const char **str, int64 *argv, uint argv_size, bool modify_argv)
FormatString for NewGRF specific "magic" string control codes.
byte symbol_pos
The currency symbol is represented by two possible values, prefix and suffix Usage of one or the othe...
static WChar _global_string_params_type[20]
Type of parameters stored in #_global_string_params.
Header of Action 04 "universal holder" structure and functions.
void SetDParamStr(uint n, const char *str)
This function is used to "bind" a C string to a OpenTTD dparam slot.
const char * NextString() override
Get the next string to search through.
Functions related to low-level strings.
uint ConvertDisplaySpeedToKmhishSpeed(uint speed)
Convert the given display speed to the km/h-ish speed.
uint64 * data
Array with the actual data.
Functions related to errors.
UnitID unitnumber
unit number, for display purposes only
UnitConversion c
Conversion.
FreeTypeSubSetting mono
The mono space font used for license/readme viewers.
81: Read 2 bytes from the stack as String ID
byte units_volume
unit system for volume
void ReconsiderGameScriptLanguage()
Reconsider the game script language, so we use the right one.
A searcher for missing glyphs.
char * GetTownName(char *buff, const TownNameParams *par, uint32 townnameparts, const char *last)
Fills buffer with specified town name.
Subdirectory for all translation files.
const IndustrySpec * GetIndustrySpec(IndustryType thistype)
Accessor for array _industry_specs.
UnitConversion c
Conversion.
Definition of base types and functions in a cross-platform compatible way.
void LoadStringWidthTable(bool monospace)
Initialize _stringwidth_table cache.
static const uint TAB_SIZE
Number of strings per StringTab.
Data structure to convert between Date and triplet (year, month, and day).
void CDECL usererror(const char *s,...)
Error handling for fatal user errors.
A number of safeguards to prevent using unsafe methods.
int64 ToDisplay(int64 input, bool round=true) const
Convert value from OpenTTD's internal unit into the displayed value.
IndustryType type
type of industry.
void CopyOutDParam(uint64 *dst, int offs, int num)
Copy num string parameters from the global string parameter array to the dst array.
int64 GetInt64(WChar type=0)
Read an int64 from the argument array.
const LanguageMetadata * GetLanguage(byte newgrflangid)
Get the language with the given NewGRF language ID.
static const uint TAB_SIZE_GAMESCRIPT
Number of strings for GameScripts.
Information about languages and their files.
static const UnitsLong _units_weight[]
Unit conversions for weight.
char * stredup(const char *s, const char *last)
Create a duplicate of the given string.
static int8 Utf8CharLen(WChar c)
Return the length of a UTF-8 encoded character.
void SetDParamMaxDigits(uint n, uint count, FontSize size)
Set DParam n to some number that is suitable for string size computations.
LanguageList _languages
The actual list of language meta data.
Road vehicle list; Window numbers:
Defines the data structure for constructing industry.
bool FindMissingGlyphs(const char **str)
Check whether there are glyphs missing in the current language.
static const uint8 MAX_NUM_GENDERS
Maximum number of supported genders.
char * digit_group_separator_currency
thousand separator for currencies
FreeTypeSubSetting medium
The normal font size.
static bool GetLanguageFileHeader(const char *file, LanguagePackHeader *hdr)
Reads the language file header and checks compatibility.
uint GetDataLeft() const
Return the amount of elements which can still be read.
char * digit_decimal_separator
decimal separator
#define lengthof(x)
Return the length of an fixed size array.
static const uint8 MAX_NUM_CASES
Maximum number of supported cases.
static T min(const T a, const T b)
Returns the minimum of two values.
void InitializeLanguagePacks()
Make a list of the available language packs.
char * name
Custom name of engine.
static const Sprite * GetGlyph(FontSize size, WChar key)
Get the Sprite for a glyph.
StringID s
String for the short variant of the unit.
uint32 StringID
Numeric value that represents a string, independent of the selected language.
Text is written left-to-right by default.
uint i
Iterator for the primary language tables.
Start of GameScript supplied strings.
Information about a specific unit system.
Station list; Window numbers:
static void MemCpyT(T *destination, const T *source, size_t num=1)
Type-safe version of memcpy().
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback)
We would like to have a fallback font as the current one doesn't contain all characters we need...
#define DEBUG(name, level,...)
Output a line of debugging information.
static const uint MAX_LANG
Maximum number of languages supported by the game, and the NewGRF specs.
uint32 president_name_2
Parameter of president_name_1.
byte units_power
unit system for power
const LanguageMetadata * _current_language
The currently loaded language.
char * name
Name of vehicle.
char font[MAX_PATH]
The name of the font, or path to the font.
static const Units _units_power[]
Unit conversions for velocity.
char _config_language_file[MAX_PATH]
The file (name) stored in the configuration.
static const UnitsLong _units_volume[]
Unit conversions for volume.
User interface for downloading files.
const char * GetCurrentLanguageIsoCode()
Get the ISO language code of the currently loaded language.
uint ConvertKmhishSpeedToDisplaySpeed(uint speed)
Convert the given km/h-ish speed to the display speed.
int shift
Amount to shift upon conversion.
const void * os_handle
Optional native OS font info.
void InjectDParam(uint amount)
Shift the string parameters in the global string parameter array by amount positions, making room at the beginning.
TextDirection
Directions a text can go to.
int strnatcmp(const char *s1, const char *s2, bool ignore_garbage_at_front)
Compares two strings using case insensitive natural sort.
Base class for all vehicles.
void SetFontNames(FreeTypeSettings *settings, const char *font_name, const void *os_data) override
Set the right font names.
static bool StrEmpty(const char *s)
Check if a string buffer is empty.
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo ID.
Ships list; Window numbers:
StringID s
String for the unit.
StringID name_1
Name of the company if the user did not change it.
WChar GetTypeAtOffset(uint offset) const
Get the type of a specific element.
TextDirection _current_text_dir
Text direction of the currently selected language.
void SetDParamMaxValue(uint n, uint64 max_value, uint min_count, FontSize size)
Set DParam n to some number that is suitable for string size computations.
StringID president_name_1
Name of the president if the user did not change it.
std::vector< LanguageMetadata > LanguageList
Type for the list of language meta data.
void Reset() override
Reset the search, i.e.
void GetBroadestDigit(uint *front, uint *next, FontSize size)
Determine the broadest digits for guessing the maximum width of a n-digit number. ...
void CDECL error(const char *s,...)
Error handling for fatal non-user errors.
static T abs(const T a)
Returns the absolute value of (scalar) variable.
void InitializeSortedCargoSpecs()
Initialize the list of sorted cargo specifications.
static uint GB(const T x, const uint8 s, const uint8 n)
Fetch n bits from x, started at bit s.
StringID string_id
Default name of engine.
Trains list; Window numbers:
FreeTypeSubSetting small
The smallest font; mostly used for zoomed out view.
FontSize
Available font sizes.
void RestoreTextRefStackBackup(struct TextRefStack *backup)
Restore a copy of the text stack to the used stack.
char * strecpy(char *dst, const char *src, const char *last)
Copies characters from one buffer to another.
VehicleType type
Type of vehicle.
static DIR * ttd_opendir(const char *path)
A wrapper around opendir() which will convert the string from OPENTTD encoding to that of the filesys...
const char * GetGRFStringPtr(uint16 stringid)
Get a C-string from a stringid set by a newgrf.
int multiplier
Amount to multiply upon conversion.
static bool _scan_for_gender_data
Are we scanning for the gender of the current string? (instead of formatting it)
Index of the normal font in the font tables.
char * digit_group_separator
thousand separator for non-currencies
Start of NewGRF supplied strings.
LocaleSettings locale
settings related to used currency/unit system in the current game
Aircraft list; Window numbers:
FontSize DefaultSize() override
Get the default (font) size of the string.
Specification of a currency.
static const Units _units_velocity[]
Unit conversions for velocity.
char * name
Custom town name. If nullptr, the town was not renamed and uses the generated name.
uint ConvertSpeedToDisplaySpeed(uint speed)
Convert the given (internal) speed to the display speed.
CargoID Index() const
Determines index of this cargospec.
static size_t GetArraySize()
Total number of cargospecs, both valid and invalid.
struct TextRefStack * CreateTextRefStackBackup()
Create a backup of the current NewGRF text stack.
char * GenerateTownNameString(char *buf, const char *last, size_t lang, uint32 seed)
Generates town name from given seed.
static uint _langtab_start[TEXT_TAB_END]
Offset into langpack offs.
static char * FormatNumber(char *buff, int64 number, const char *last, const char *separator, int zerofill=1, int fractional_digits=0)
Format a number into a string.
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
size_t Utf8Encode(char *buf, WChar c)
Encode a unicode character and place it in the buffer.
int32 Date
The type to store our dates in.
static void free(const void *ptr)
Version of the standard free that accepts const pointers.
declaration of OTTD revision dependent variables
StringID station_name
Default name for nearby station.
static bool HasBit(const T x, const uint8 y)
Checks if a bit in a value is set.
Town name generator stuff.
StringID units_volume
Name of a single unit of cargo of this type.
Station with truck stops.
bool ReadLanguagePack(const LanguageMetadata *lang)
Read a particular language.
void * ReadFileToMem(const char *filename, size_t *lenp, size_t maxsize)
Load a file into memory.
uint64 * GetPointerToOffset(uint offset) const
Get a pointer to a specific element in the data array.
GameCreationSettings game_creation
settings used during the creation of a game (map)
const char * GetCurrentLocale(const char *param)
Determine the current charset based on the environment First check some default values, after this one we passed ourselves and if none exist return the value for $LANG.
const char * GetGameStringPtr(uint id)
Get the string pointer of a particular game string.
byte CargoID
Cargo slots to indicate a cargo type within a game.
IndustryType indtype
Industry type to get the name from.
Window functions not directly related to making/drawing windows.
Station with train station.
int32 GetInt32(WChar type=0)
Read an int32 from the argument array.
Base classes/functions for stations.
Errors (eg. saving/loading failed)
#define NBSP
A non-breaking space.
uint32 WChar
Type for wide characters, i.e.
void ConvertDateToYMD(Date date, YearMonthDay *ymd)
Converts a Date to a Year, Month & Day.
uint j
Iterator for the secondary language tables.
StringID string_id
Default name (town area) of station.
StringID l
String for the long variant of the unit.
void MacOSSetCurrentLocaleName(const char *iso_code)
Store current language locale as a CoreFounation locale.
bool StrValid(const char *str, const char *last)
Checks whether the given string is valid, i.e.
uint16 town_cn
The N-1th depot for this town (consecutive number)
static void MemSetT(T *ptr, byte value, size_t num=1)
Type-safe version of memset().
static void SetDParam(uint n, uint64 v)
Set a string parameter v at index n in the global string parameter array.
uint64 * GetDataPointer() const
Get a pointer to the current element in the data array.
static Station * GetIfValid(size_t index)
Returns station if the index is a valid index for this station type.
void BuildIndustriesLegend()
Fills an array for the industries legends.