41 #include "table/strings.h" 63 assert(this->
type !=
nullptr);
75 DEBUG(misc, 0,
"Trying to read invalid string parameter");
78 if (this->type !=
nullptr) {
79 if (this->type[this->
offset] != 0 && this->type[this->
offset] != type) {
80 DEBUG(misc, 0,
"Trying to read string parameter with wrong type");
109 while (max_value >= 10) {
127 uint64 val = count > 1 ? front : next;
128 for (; count > 1; count--) {
129 val = 10 * val + next;
167 GetString(buf,
string,
lastof(buf));
170 for (
int i = 0; i < num; i++) {
172 strings[i] =
stredup((
const char *)(
size_t)_global_string_params.GetParam(i));
173 dst[i] = (size_t)strings[i];
175 strings[i] =
nullptr;
180 static char *StationGetSpecialString(
char *buff,
int x,
const char *last);
181 static char *GetSpecialTownNameString(
char *buff,
int ind, uint32 seed,
const char *last);
182 static char *GetSpecialNameString(
char *buff,
int ind,
StringParameters *args,
const char *last);
184 static char *
FormatString(
char *buff,
const char *str,
StringParameters *args,
const char *last, uint case_index = 0,
bool game_script =
false,
bool dry_run =
false);
190 static char **_langpack_offs;
197 const char *GetStringPtr(
StringID string)
202 case TEXT_TAB_OLD_NEWGRF: NOT_REACHED();
227 if (index >= 0xC0 && !game_script) {
228 return GetSpecialTownNameString(buffr, index - 0xC0, args->
GetInt32(), last);
232 case TEXT_TAB_SPECIAL:
233 if (index >= 0xE4 && !game_script) {
234 return GetSpecialNameString(buffr, index - 0xE4, args, last);
238 case TEXT_TAB_OLD_CUSTOM:
241 error(
"Incorrect conversion of custom name string.");
248 case TEXT_TAB_OLD_NEWGRF:
262 error(
"String 0x%X is invalid. You are probably using an old version of the .lng file.\n",
string);
265 return FormatString(buffr, GetStringPtr(
string), args, last, case_index);
268 char *GetString(
char *buffr,
StringID string,
const char *last)
271 _global_string_params.
offset = 0;
306 static char *
FormatNumber(
char *buff, int64 number,
const char *last,
const char *separator,
int zerofill = 1,
int fractional_digits = 0)
308 static const int max_digits = 20;
309 uint64 divisor = 10000000000000000000ULL;
310 zerofill += fractional_digits;
311 int thousands_offset = (max_digits - fractional_digits - 1) % 3;
320 for (
int i = 0; i < max_digits; i++) {
321 if (i == max_digits - fractional_digits) {
324 buff +=
seprintf(buff, last,
"%s", decimal_separator);
328 if (num >= divisor) {
329 quot = num / divisor;
332 if ((tot |= quot) || i >= max_digits - zerofill) {
333 buff +=
seprintf(buff, last,
"%i", (
int)quot);
334 if ((i % 3) == thousands_offset && i < max_digits - 1 - fractional_digits) buff =
strecpy(buff, separator, last);
345 static char *FormatCommaNumber(
char *buff, int64 number,
const char *last,
int fractional_digits = 0)
349 return FormatNumber(buff, number, last, separator, 1, fractional_digits);
352 static char *FormatNoCommaNumber(
char *buff, int64 number,
const char *last)
357 static char *FormatZerofillNumber(
char *buff, int64 number, int64 count,
const char *last)
362 static char *FormatHexNumber(
char *buff, uint64 number,
const char *last)
364 return buff +
seprintf(buff, last,
"0x" OTTD_PRINTFHEX64, number);
374 static char *
FormatBytes(
char *buff, int64 number,
const char *last)
379 const char *
const iec_prefixes[] = {
"",
"Ki",
"Mi",
"Gi",
"Ti",
"Pi",
"Ei"};
381 while (number >= 1024 * 1024) {
391 buff +=
seprintf(buff, last,
"%i", (
int)number);
392 }
else if (number < 1024 * 10) {
393 buff +=
seprintf(buff, last,
"%i%s%02i", (
int)number / 1024, decimal_separator, (
int)(number % 1024) * 100 / 1024);
394 }
else if (number < 1024 * 100) {
395 buff +=
seprintf(buff, last,
"%i%s%01i", (
int)number / 1024, decimal_separator, (
int)(number % 1024) * 10 / 1024);
397 assert(number < 1024 * 1024);
398 buff +=
seprintf(buff, last,
"%i", (
int)number / 1024);
401 assert(
id <
lengthof(iec_prefixes));
402 buff +=
seprintf(buff, last,
NBSP "%sB", iec_prefixes[
id]);
407 static char *FormatYmdString(
char *buff,
Date date,
const char *last, uint case_index)
412 int64 args[] = {ymd.
day + STR_DAY_NUMBER_1ST - 1, STR_MONTH_ABBREV_JAN + ymd.
month, ymd.
year};
414 return FormatString(buff, GetStringPtr(STR_FORMAT_DATE_LONG), &tmp_params, last, case_index);
417 static char *FormatMonthAndYear(
char *buff,
Date date,
const char *last, uint case_index)
422 int64 args[] = {STR_MONTH_JAN + ymd.
month, ymd.
year};
424 return FormatString(buff, GetStringPtr(STR_FORMAT_DATE_SHORT), &tmp_params, last, case_index);
427 static char *FormatTinyOrISODate(
char *buff,
Date date,
StringID str,
const char *last)
438 int64 args[] = {(int64)(
size_t)day, (int64)(
size_t)month, ymd.
year};
440 return FormatString(buff, GetStringPtr(str), &tmp_params, last);
443 static char *FormatGenericCurrency(
char *buff,
const CurrencySpec *spec,
Money number,
bool compact,
const char *last)
447 bool negative = number < 0;
448 const char *multiplier =
"";
450 number *= spec->rate;
454 if (buff +
Utf8CharLen(SCC_PUSH_COLOUR) > last)
return buff;
456 if (buff +
Utf8CharLen(SCC_RED) > last)
return buff;
458 buff =
strecpy(buff,
"-", last);
471 if (number >= 1000000000 - 500) {
472 number = (number + 500000) / 1000000;
473 multiplier =
NBSP "M";
474 }
else if (number >= 1000000) {
475 number = (number + 500) / 1000;
476 multiplier =
NBSP "k";
481 if (separator ==
nullptr && !
StrEmpty(_currency->separator)) separator = _currency->separator;
484 buff =
strecpy(buff, multiplier, last);
492 if (buff +
Utf8CharLen(SCC_POP_COLOUR) > last)
return buff;
509 uint64 n =
abs(count);
511 switch (plural_form) {
520 return n != 1 ? 1 : 0;
532 return n > 1 ? 1 : 0;
539 return n % 10 == 1 && n % 100 != 11 ? 0 : n != 0 ? 1 : 2;
545 return n == 1 ? 0 : n == 2 ? 1 : n < 7 ? 2 : n < 11 ? 3 : 4;
551 return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
557 return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
563 return n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
569 return n % 100 == 1 ? 0 : n % 100 == 2 ? 1 : n % 100 == 3 || n % 100 == 4 ? 2 : 3;
575 return n % 10 == 1 && n % 100 != 11 ? 0 : 1;
581 return n == 1 ? 0 : n >= 2 && n <= 4 ? 1 : 2;
612 return (n == 1 ? 0 : n == 0 || (n % 100 > 1 && n % 100 < 11) ? 1 : (n % 100 > 10 && n % 100 < 20) ? 2 : 3);
617 return ((n == 1 || n == 11) ? 0 : (n == 2 || n == 12) ? 1 : ((n > 2 && n < 11) || (n > 12 && n < 20)) ? 2 : 3);
621 static const char *ParseStringChoice(
const char *b, uint form,
char **dst,
const char *last)
625 uint pos, i, mypos = 0;
627 for (i = pos = 0; i != n; i++) {
628 uint len = (byte)*b++;
629 if (i == form) mypos = pos;
633 *dst +=
seprintf(*dst, last,
"%s", b + mypos);
650 return ((input * this->multiplier) + (round && this->shift != 0 ? 1 << (this->shift - 1) : 0)) >> this->shift;
660 int64
FromDisplay(int64 input,
bool round =
true, int64 divider = 1)
const 662 return ((input << this->shift) + (round ? (this->multiplier * divider) - 1 : 0)) / (this->multiplier * divider);
681 { { 1, 0}, STR_UNITS_VELOCITY_IMPERIAL },
682 { { 103, 6}, STR_UNITS_VELOCITY_METRIC },
683 { {1831, 12}, STR_UNITS_VELOCITY_SI },
688 { { 1, 0}, STR_UNITS_POWER_IMPERIAL },
689 { {4153, 12}, STR_UNITS_POWER_METRIC },
690 { {6109, 13}, STR_UNITS_POWER_SI },
695 { {4515, 12}, STR_UNITS_WEIGHT_SHORT_IMPERIAL, STR_UNITS_WEIGHT_LONG_IMPERIAL },
696 { { 1, 0}, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC },
697 { {1000, 0}, STR_UNITS_WEIGHT_SHORT_SI, STR_UNITS_WEIGHT_LONG_SI },
702 { {4227, 4}, STR_UNITS_VOLUME_SHORT_IMPERIAL, STR_UNITS_VOLUME_LONG_IMPERIAL },
703 { {1000, 0}, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC },
704 { { 1, 0}, STR_UNITS_VOLUME_SHORT_SI, STR_UNITS_VOLUME_LONG_SI },
709 { {3597, 4}, STR_UNITS_FORCE_IMPERIAL },
710 { {3263, 5}, STR_UNITS_FORCE_METRIC },
711 { { 1, 0}, STR_UNITS_FORCE_SI },
716 { { 3, 0}, STR_UNITS_HEIGHT_IMPERIAL },
717 { { 1, 0}, STR_UNITS_HEIGHT_METRIC },
718 { { 1, 0}, STR_UNITS_HEIGHT_SI },
773 uint orig_offset = args->
offset;
785 FormatString(buff, str_arg, args, last, case_index, game_script,
true);
788 FormatString(buff, str_arg, args, last, case_index, game_script,
true);
791 args->
offset = orig_offset;
794 uint next_substr_case_index = 0;
795 char *buf_start = buff;
796 std::stack<const char *, std::vector<const char *>> str_stack;
797 str_stack.push(str_arg);
800 while (!str_stack.empty() && (b = Utf8Consume(&str_stack.top())) ==
'\0') {
803 if (str_stack.empty())
break;
804 const char *&str = str_stack.top();
810 if (b == 0)
continue;
815 uint64 sub_args_data[20];
816 WChar sub_args_type[20];
817 bool sub_args_need_free[20];
821 memset(sub_args_need_free, 0,
sizeof(sub_args_need_free));
824 uint32 stringid = strtoul(str, &p, 16);
825 if (*p !=
':' && *p !=
'\0') {
826 while (*p !=
'\0') p++;
828 buff =
strecat(buff,
"(invalid SCC_ENCODED)", last);
832 while (*p !=
'\0') p++;
834 buff =
strecat(buff,
"(invalid StringID)", last);
839 while (*p !=
'\0' && i < 20) {
844 bool instring =
false;
851 if (*p ==
'"' && escape) {
858 instring = !instring;
865 if (*p ==
':')
break;
866 if (*p ==
'\0')
break;
873 bool lookup = (l == SCC_ENCODED);
874 if (lookup) s += len;
876 param = strtoull(s, &p, 16);
880 while (*p !=
'\0') p++;
882 buff =
strecat(buff,
"(invalid sub-StringID)", last);
888 sub_args.SetParam(i++, param);
893 sub_args_need_free[i] =
true;
894 sub_args.SetParam(i++, (uint64)(
size_t)g);
903 for (
int i = 0; i < 20; i++) {
904 if (sub_args_need_free[i])
free((
void *)sub_args.GetParam(i));
910 StringID substr = Utf8Consume(&str);
911 str_stack.push(GetStringPtr(substr));
917 str_stack.push(GetStringPtr(substr));
918 case_index = next_substr_case_index;
919 next_substr_case_index = 0;
924 case SCC_GENDER_LIST: {
926 uint
offset = orig_offset + (byte)*str++;
947 WChar c = Utf8Consume(&s);
949 if (c == SCC_GENDER_INDEX) gender = (byte)s[0];
951 str = ParseStringChoice(str, gender, &buff, last);
957 case SCC_GENDER_INDEX:
966 case SCC_PLURAL_LIST: {
967 int plural_form = *str++;
968 uint
offset = orig_offset + (byte)*str++;
974 case SCC_ARG_INDEX: {
975 args->
offset = orig_offset + (byte)*str++;
982 next_substr_case_index = (byte)*str++;
986 case SCC_SWITCH_CASE: {
989 uint num = (byte)*str++;
991 if ((byte)str[0] == case_index) {
997 str += 3 + (str[1] << 8) + str[2];
1004 buff =
strecpy(buff, _openttd_revision, last);
1007 case SCC_RAW_STRING_POINTER: {
1008 if (game_script)
break;
1009 const char *str = (
const char *)(
size_t)args->
GetInt64(SCC_RAW_STRING_POINTER);
1021 buff =
GetStringWithArgs(buff, str, &tmp_params, last, next_substr_case_index, game_script);
1022 next_substr_case_index = 0;
1036 uint size = b - SCC_STRING1 + 1;
1038 buff =
strecat(buff,
"(too many parameters)", last);
1041 buff =
GetStringWithArgs(buff, str, &sub_args, last, next_substr_case_index, game_script);
1043 next_substr_case_index = 0;
1048 buff = FormatCommaNumber(buff, args->
GetInt64(SCC_COMMA), last);
1052 int64 number = args->
GetInt64(SCC_DECIMAL);
1053 int digits = args->
GetInt32(SCC_DECIMAL);
1054 buff = FormatCommaNumber(buff, number, last, digits);
1059 buff = FormatNoCommaNumber(buff, args->
GetInt64(SCC_NUM), last);
1062 case SCC_ZEROFILL_NUM: {
1064 buff = FormatZerofillNumber(buff, num, args->
GetInt64(), last);
1069 buff = FormatHexNumber(buff, (uint64)args->
GetInt64(SCC_HEX), last);
1076 case SCC_CARGO_TINY: {
1085 switch (cargo_str) {
1100 buff = FormatCommaNumber(buff, amount, last);
1104 case SCC_CARGO_SHORT: {
1112 switch (cargo_str) {
1138 case SCC_CARGO_LONG: {
1149 case SCC_CARGO_LIST: {
1150 CargoTypes cmask = args->
GetInt64(SCC_CARGO_LIST);
1157 if (buff >= last - 2)
break;
1171 if (first) buff =
GetStringWithArgs(buff, STR_JUST_NOTHING, args, last, next_substr_case_index, game_script);
1174 next_substr_case_index = 0;
1177 assert(buff < last);
1181 case SCC_CURRENCY_SHORT:
1182 buff = FormatGenericCurrency(buff, _currency, args->
GetInt64(),
true, last);
1185 case SCC_CURRENCY_LONG:
1186 buff = FormatGenericCurrency(buff, _currency, args->
GetInt64(SCC_CURRENCY_LONG),
false, last);
1190 buff = FormatTinyOrISODate(buff, args->
GetInt32(SCC_DATE_TINY), STR_FORMAT_DATE_TINY, last);
1193 case SCC_DATE_SHORT:
1194 buff = FormatMonthAndYear(buff, args->
GetInt32(SCC_DATE_SHORT), last, next_substr_case_index);
1195 next_substr_case_index = 0;
1199 buff = FormatYmdString(buff, args->
GetInt32(SCC_DATE_LONG), last, next_substr_case_index);
1200 next_substr_case_index = 0;
1204 buff = FormatTinyOrISODate(buff, args->
GetInt32(), STR_FORMAT_DATE_ISO, last);
1231 case SCC_VELOCITY: {
1239 case SCC_VOLUME_SHORT: {
1247 case SCC_VOLUME_LONG: {
1255 case SCC_WEIGHT_SHORT: {
1263 case SCC_WEIGHT_LONG: {
1271 case SCC_COMPANY_NAME: {
1273 if (c ==
nullptr)
break;
1275 if (c->
name !=
nullptr) {
1276 int64 args_array[] = {(int64)(
size_t)c->
name};
1280 int64 args_array[] = {c->
name_2};
1287 case SCC_COMPANY_NUM: {
1292 int64 args_array[] = {company + 1};
1299 case SCC_DEPOT_NAME: {
1302 uint64 args_array[] = {(uint64)args->
GetInt32()};
1303 WChar types_array[] = {SCC_STATION_NAME};
1305 buff =
GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_AIRCRAFT, &tmp_params, last);
1310 if (d->name !=
nullptr) {
1311 int64 args_array[] = {(int64)(
size_t)d->name};
1317 buff =
GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_TRAIN + 2 * vt + (d->
town_cn == 0 ? 0 : 1), &tmp_params, last);
1322 case SCC_ENGINE_NAME: {
1324 if (e ==
nullptr)
break;
1327 int64 args_array[] = {(int64)(
size_t)e->
name};
1337 case SCC_GROUP_NAME: {
1339 if (g ==
nullptr)
break;
1341 if (g->
name !=
nullptr) {
1342 int64 args_array[] = {(int64)(
size_t)g->
name};
1346 int64 args_array[] = {g->
index};
1354 case SCC_INDUSTRY_NAME: {
1356 if (i ==
nullptr)
break;
1368 buff =
FormatString(buff, GetStringPtr(STR_FORMAT_INDUSTRY_NAME), &tmp_params, last, next_substr_case_index);
1370 next_substr_case_index = 0;
1374 case SCC_PRESIDENT_NAME: {
1376 if (c ==
nullptr)
break;
1390 case SCC_STATION_NAME: {
1391 StationID sid = args->
GetInt32(SCC_STATION_NAME);
1394 if (st ==
nullptr) {
1403 if (st->
name !=
nullptr) {
1404 int64 args_array[] = {(int64)(
size_t)st->
name};
1409 if (st->
indtype != IT_INVALID) {
1421 uint64 args_array[] = {STR_TOWN_NAME, st->
town->
index, st->
index};
1422 WChar types_array[] = {0, SCC_TOWN_NAME, SCC_NUM};
1429 case SCC_TOWN_NAME: {
1431 if (t ==
nullptr)
break;
1433 if (t->
name !=
nullptr) {
1434 int64 args_array[] = {(int64)(
size_t)t->
name};
1443 case SCC_WAYPOINT_NAME: {
1445 if (wp ==
nullptr)
break;
1447 if (wp->
name !=
nullptr) {
1448 int64 args_array[] = {(int64)(
size_t)wp->
name};
1454 StringID str = ((wp->
string_id == STR_SV_STNAME_BUOY) ? STR_FORMAT_BUOY_NAME : STR_FORMAT_WAYPOINT_NAME);
1461 case SCC_VEHICLE_NAME: {
1463 if (v ==
nullptr)
break;
1465 if (v->
name !=
nullptr) {
1466 int64 args_array[] = {(int64)(
size_t)v->
name};
1475 default: str = STR_INVALID_VEHICLE;
break;
1476 case VEH_TRAIN: str = STR_SV_TRAIN_NAME;
break;
1477 case VEH_ROAD: str = STR_SV_ROAD_VEHICLE_NAME;
break;
1478 case VEH_SHIP: str = STR_SV_SHIP_NAME;
break;
1487 case SCC_SIGN_NAME: {
1489 if (si ==
nullptr)
break;
1491 if (si->name !=
nullptr) {
1492 int64 args_array[] = {(int64)(
size_t)si->name};
1502 case SCC_STATION_FEATURES: {
1503 buff = StationGetSpecialString(buff, args->
GetInt32(SCC_STATION_FEATURES), last);
1517 static char *StationGetSpecialString(
char *buff,
int x,
const char *last)
1528 static char *GetSpecialTownNameString(
char *buff,
int ind, uint32 seed,
const char *last)
1533 static const char *
const _silly_company_names[] = {
1535 "Tiny Transport Ltd.",
1537 "Comfy-Coach & Co.",
1538 "Crush & Bump Ltd.",
1539 "Broken & Late Ltd.",
1541 "Supersonic Travel",
1543 "Lightning International",
1544 "Pannik & Loozit Ltd.",
1545 "Inter-City Transport",
1546 "Getout & Pushit Ltd." 1549 static const char *
const _surname_list[] = {
1581 static const char *
const _silly_surname_list[] = {
1596 static const char _initial_name_letters[] = {
1597 'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
1598 'K',
'L',
'M',
'N',
'P',
'R',
'S',
'T',
'W',
1601 static char *GenAndCoName(
char *buff, uint32 arg,
const char *last)
1603 const char *
const *base;
1607 base = _silly_surname_list;
1608 num =
lengthof(_silly_surname_list);
1610 base = _surname_list;
1614 buff =
strecpy(buff, base[num *
GB(arg, 16, 8) >> 8], last);
1615 buff =
strecpy(buff,
" & Co.", last);
1620 static char *GenPresidentName(
char *buff, uint32 x,
const char *last)
1622 char initial[] =
"?. ";
1623 const char *
const *base;
1627 initial[0] = _initial_name_letters[
sizeof(_initial_name_letters) *
GB(x, 0, 8) >> 8];
1628 buff =
strecpy(buff, initial, last);
1630 i = (
sizeof(_initial_name_letters) + 35) *
GB(x, 8, 8) >> 8;
1631 if (i <
sizeof(_initial_name_letters)) {
1632 initial[0] = _initial_name_letters[i];
1633 buff =
strecpy(buff, initial, last);
1637 base = _silly_surname_list;
1638 num =
lengthof(_silly_surname_list);
1640 base = _surname_list;
1644 buff =
strecpy(buff, base[num *
GB(x, 16, 8) >> 8], last);
1649 static char *GetSpecialNameString(
char *buff,
int ind,
StringParameters *args,
const char *last)
1656 return GenAndCoName(buff, args->
GetInt32(), last);
1659 return GenPresidentName(buff, args->
GetInt32(), last);
1663 if (
IsInsideMM(ind - 6, 0, SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1)) {
1664 buff = GetSpecialTownNameString(buff, ind - 6, args->
GetInt32(), last);
1665 return strecpy(buff,
" Transport", last);
1669 if (
IsInsideMM(ind, (SPECSTR_LANGUAGE_START - 0x70E4), (SPECSTR_LANGUAGE_END - 0x70E4) + 1)) {
1670 int i = ind - (SPECSTR_LANGUAGE_START - 0x70E4);
1677 int i = ind - (SPECSTR_RESOLUTION_START - 0x70E4);
1687 extern void SortNetworkLanguages();
1696 this->version == TO_LE32(LANGUAGE_PACK_VERSION) &&
1697 this->plural_form < LANGUAGE_MAX_PLURAL &&
1698 this->text_dir <= 1 &&
1705 StrValid(this->digit_group_separator,
lastof(this->digit_group_separator)) &&
1706 StrValid(this->digit_group_separator_currency,
lastof(this->digit_group_separator_currency)) &&
1707 StrValid(this->digit_decimal_separator,
lastof(this->digit_decimal_separator));
1720 if (lang_pack ==
nullptr)
return false;
1723 const char *end = (
char *)lang_pack + len + 1;
1726 if (end <= lang_pack->
data || !lang_pack->
IsValid()) {
1731 #if TTD_ENDIAN == TTD_BIG_ENDIAN 1739 uint16 num = lang_pack->
offsets[i];
1751 char **langpack_offs = MallocT<char *>(count);
1754 char *s = lang_pack->data;
1756 for (uint i = 0; i < count; i++) {
1757 if (s + len >= end) {
1759 free(langpack_offs);
1763 len = ((len & 0x3F) << 8) + (byte)*s++;
1764 if (s + len >= end) {
1766 free(langpack_offs);
1770 langpack_offs[i] = s;
1777 _langpack = lang_pack;
1779 free(_langpack_offs);
1780 _langpack_offs = langpack_offs;
1782 _current_language = lang;
1784 const char *c_file = strrchr(_current_language->
file, PATHSEPCHAR) + 1;
1789 extern void Win32SetCurrentLocaleName(
const char *iso_code);
1790 Win32SetCurrentLocaleName(_current_language->
isocode);
1798 #ifdef WITH_ICU_I18N 1806 UErrorCode status = U_ZERO_ERROR;
1811 if (U_FAILURE(status)) {
1822 SortNetworkLanguages();
1837 #if !(defined(_WIN32) || defined(__APPLE__)) 1850 env = getenv(
"LANGUAGE");
1851 if (env !=
nullptr)
return env;
1853 env = getenv(
"LC_ALL");
1854 if (env !=
nullptr)
return env;
1856 if (param !=
nullptr) {
1857 env = getenv(param);
1858 if (env !=
nullptr)
return env;
1861 return getenv(
"LANG");
1871 GetString(stra, a,
lastof(stra));
1872 GetString(strb, b,
lastof(strb));
1885 if (newgrflangid == lang.newgrflangid)
return ⟨
1899 FILE *f = fopen(file,
"rb");
1900 if (f ==
nullptr)
return false;
1902 size_t read = fread(hdr,
sizeof(*hdr), 1, f);
1905 bool ret = read == 1 && hdr->
IsValid();
1922 if (dir !=
nullptr) {
1923 struct dirent *dirent;
1924 while ((dirent = readdir(dir)) !=
nullptr) {
1925 const char *d_name =
FS2OTTD(dirent->d_name);
1926 const char *extension = strrchr(d_name,
'.');
1929 if (extension ==
nullptr || strcmp(extension,
".lng") != 0)
continue;
1936 DEBUG(misc, 3,
"%s is not a valid language file", lmd.
file);
1938 DEBUG(misc, 3,
"%s's language ID is already known", lmd.
file);
1956 char path[MAX_PATH];
1964 if (lang ==
nullptr) lang =
"en_GB";
1975 const char *lang_file = strrchr(lng.file, PATHSEPCHAR) + 1;
1977 chosen_language = &lng;
1981 if (strcmp (lng.isocode,
"en_GB") == 0) en_GB_fallback = &lng;
1982 if (strncmp(lng.isocode, lang, 5) == 0) chosen_language = &lng;
1983 if (strncmp(lng.isocode, lang, 2) == 0) language_fallback = &lng;
1988 if (chosen_language ==
nullptr) {
1989 chosen_language = (language_fallback !=
nullptr) ? language_fallback : en_GB_fallback;
2013 const Sprite *question_mark[FS_END];
2016 question_mark[size] =
GetGlyph(size,
'?');
2020 for (
const char *text = this->NextString(); text !=
nullptr; text = this->NextString()) {
2021 FontSize size = this->DefaultSize();
2022 if (str !=
nullptr) *str = text;
2023 for (
WChar c = Utf8Consume(&text); c !=
'\0'; c = Utf8Consume(&text)) {
2024 if (c >= SCC_FIRST_FONT && c <= SCC_LAST_FONT) {
2025 size = (
FontSize)(c - SCC_FIRST_FONT);
2055 const char *ret = _langpack_offs[
_langtab_start[this->i] + this->j];
2058 while (this->i < TEXT_TAB_END && this->j >=
_langtab_num[this->i]) {
2073 #if defined(WITH_FREETYPE) || defined(_WIN32) 2102 if (searcher ==
nullptr) searcher = &pack_searcher;
2104 #if defined(WITH_FREETYPE) || defined(_WIN32) 2109 memcpy(&backup, &_freetype,
sizeof(backup));
2119 memcpy(&_freetype, &backup,
sizeof(backup));
2121 if (bad_font && base_font) {
2136 static char *err_str =
stredup(
"XXXThe current font is missing some of the characters used in the texts for this language. Read the readme to see how to solve this.");
2149 #if !defined(WITH_ICU_LX) && !defined(WITH_UNISCRIBE) && !defined(WITH_COCOA) 2164 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.