00001
00002
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "currency.h"
00008 #include "namegen_func.h"
00009 #include "station_base.h"
00010 #include "town.h"
00011 #include "screenshot.h"
00012 #include "waypoint.h"
00013 #include "industry.h"
00014 #include "variables.h"
00015 #include "newgrf_text.h"
00016 #include "music.h"
00017 #include "fileio_func.h"
00018 #include "cargotype.h"
00019 #include "group.h"
00020 #include "debug.h"
00021 #include "newgrf_townname.h"
00022 #include "signs_base.h"
00023 #include "newgrf_engine.h"
00024 #include "spritecache.h"
00025 #include "fontcache.h"
00026 #include "gui.h"
00027 #include "strings_func.h"
00028 #include "functions.h"
00029 #include "rev.h"
00030 #include "core/endian_func.hpp"
00031 #include "date_func.h"
00032 #include "vehicle_base.h"
00033 #include "string_func.h"
00034 #include "company_func.h"
00035 #include "company_base.h"
00036 #include "fios.h"
00037 #include "settings_type.h"
00038 #include "video/video_driver.hpp"
00039 #include "engine_func.h"
00040 #include "engine_base.h"
00041 #include "strgen/strgen.h"
00042
00043 #include "table/strings.h"
00044 #include "table/control_codes.h"
00045
00046 DynamicLanguages _dynlang;
00047 uint64 _decode_parameters[20];
00048
00049 static char *StationGetSpecialString(char *buff, int x, const char *last);
00050 static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last);
00051 static char *GetSpecialNameString(char *buff, int ind, const int64 *argv, const char *last);
00052
00053 static char *FormatString(char *buff, const char *str, const int64 *argv, uint casei, const char *last);
00054
00055 struct LanguagePack : public LanguagePackHeader {
00056 char data[VARARRAY_SIZE];
00057 };
00058
00059 static char **_langpack_offs;
00060 static LanguagePack *_langpack;
00061 static uint _langtab_num[32];
00062 static uint _langtab_start[32];
00063
00064
00066 static inline int64 GetInt64(const int64 **argv)
00067 {
00068 assert(argv);
00069 return *(*argv)++;
00070 }
00071
00073 static inline int32 GetInt32(const int64 **argv)
00074 {
00075 return (int32)GetInt64(argv);
00076 }
00077
00079 static inline const int64 *GetArgvPtr(const int64 **argv, int n)
00080 {
00081 const int64 *result;
00082 assert(*argv);
00083 result = *argv;
00084 (*argv) += n;
00085 return result;
00086 }
00087
00088
00089 const char *GetStringPtr(StringID string)
00090 {
00091 switch (GB(string, 11, 5)) {
00092 case 28: return GetGRFStringPtr(GB(string, 0, 11));
00093 case 29: return GetGRFStringPtr(GB(string, 0, 11) + 0x0800);
00094 case 30: return GetGRFStringPtr(GB(string, 0, 11) + 0x1000);
00095 default: return _langpack_offs[_langtab_start[string >> 11] + (string & 0x7FF)];
00096 }
00097 }
00098
00109 static char *GetStringWithArgs(char *buffr, uint string, const int64 *argv, const char *last)
00110 {
00111 if (GB(string, 0, 16) == 0) return GetStringWithArgs(buffr, STR_UNDEFINED, argv, last);
00112
00113 uint index = GB(string, 0, 11);
00114 uint tab = GB(string, 11, 5);
00115
00116 switch (tab) {
00117 case 4:
00118 if (index >= 0xC0)
00119 return GetSpecialTownNameString(buffr, index - 0xC0, GetInt32(&argv), last);
00120 break;
00121
00122 case 14:
00123 if (index >= 0xE4)
00124 return GetSpecialNameString(buffr, index - 0xE4, argv, last);
00125 break;
00126
00127 case 15:
00128
00129 error("Incorrect conversion of custom name string.");
00130
00131 case 26:
00132
00133 if (HasBit(index, 10)) {
00134 StringID string = GetGRFStringID(0, 0xD000 + GB(index, 0, 10));
00135 return GetStringWithArgs(buffr, string, argv, last);
00136 }
00137 break;
00138
00139 case 28:
00140 return FormatString(buffr, GetGRFStringPtr(index), argv, 0, last);
00141
00142 case 29:
00143 return FormatString(buffr, GetGRFStringPtr(index + 0x0800), argv, 0, last);
00144
00145 case 30:
00146 return FormatString(buffr, GetGRFStringPtr(index + 0x1000), argv, 0, last);
00147
00148 case 31:
00149 NOT_REACHED();
00150 }
00151
00152 if (index >= _langtab_num[tab]) {
00153 error(
00154 "String 0x%X is invalid. "
00155 "Probably because an old version of the .lng file.\n", string
00156 );
00157 }
00158
00159 return FormatString(buffr, GetStringPtr(GB(string, 0, 16)), argv, GB(string, 24, 8), last);
00160 }
00161
00162 char *GetString(char *buffr, StringID string, const char *last)
00163 {
00164 return GetStringWithArgs(buffr, string, (int64*)_decode_parameters, last);
00165 }
00166
00167
00168 char *InlineString(char *buf, StringID string)
00169 {
00170 buf += Utf8Encode(buf, SCC_STRING_ID);
00171 buf += Utf8Encode(buf, string);
00172 return buf;
00173 }
00174
00175
00180 void SetDParamStr(uint n, const char *str)
00181 {
00182 SetDParam(n, (uint64)(size_t)str);
00183 }
00184
00185 void InjectDParam(uint amount)
00186 {
00187 assert((uint)amount < lengthof(_decode_parameters));
00188 memmove(_decode_parameters + amount, _decode_parameters, sizeof(_decode_parameters) - amount * sizeof(uint64));
00189 }
00190
00191
00192 static char *FormatCommaNumber(char *buff, int64 number, const char *last)
00193 {
00194 uint64 divisor = 10000000000000000000ULL;
00195 uint64 quot;
00196 int i;
00197 uint64 tot;
00198 uint64 num;
00199
00200 if (number < 0) {
00201 *buff++ = '-';
00202 number = -number;
00203 }
00204
00205 num = number;
00206
00207 tot = 0;
00208 for (i = 0; i < 20; i++) {
00209 quot = 0;
00210 if (num >= divisor) {
00211 quot = num / divisor;
00212 num = num % divisor;
00213 }
00214 if (tot |= quot || i == 19) {
00215 *buff++ = '0' + quot;
00216 if ((i % 3) == 1 && i != 19) *buff++ = ',';
00217 }
00218
00219 divisor /= 10;
00220 }
00221
00222 *buff = '\0';
00223
00224 return buff;
00225 }
00226
00227
00228 static char *FormatNoCommaNumber(char *buff, int64 number, const char *last)
00229 {
00230 uint64 divisor = 10000000000000000000ULL;
00231 uint64 quot;
00232 int i;
00233 uint64 tot;
00234 uint64 num;
00235
00236 if (number < 0) {
00237 buff = strecpy(buff, "-", last);
00238 number = -number;
00239 }
00240
00241 num = number;
00242
00243 tot = 0;
00244 for (i = 0; i < 20; i++) {
00245 quot = 0;
00246 if (num >= divisor) {
00247 quot = num / divisor;
00248 num = num % divisor;
00249 }
00250 if (tot |= quot || i == 19) {
00251 *buff++ = '0' + quot;
00252 }
00253
00254 divisor /= 10;
00255 }
00256
00257 *buff = '\0';
00258
00259 return buff;
00260 }
00261
00262 static char *FormatHexNumber(char *buff, int64 number, const char *last)
00263 {
00264 return buff + seprintf(buff, last, "0x%x", (uint32)number);
00265 }
00266
00267 static char *FormatYmdString(char *buff, Date date, const char *last)
00268 {
00269 YearMonthDay ymd;
00270 ConvertDateToYMD(date, &ymd);
00271
00272 int64 args[3] = { ymd.day + STR_01AC_1ST - 1, STR_0162_JAN + ymd.month, ymd.year };
00273 return FormatString(buff, GetStringPtr(STR_DATE_LONG), args, 0, last);
00274 }
00275
00276 static char *FormatMonthAndYear(char *buff, Date date, const char *last)
00277 {
00278 YearMonthDay ymd;
00279 ConvertDateToYMD(date, &ymd);
00280
00281 int64 args[2] = { STR_MONTH_JAN + ymd.month, ymd.year };
00282 return FormatString(buff, GetStringPtr(STR_DATE_SHORT), args, 0, last);
00283 }
00284
00285 static char *FormatTinyOrISODate(char *buff, Date date, StringID str, const char *last)
00286 {
00287 YearMonthDay ymd;
00288 ConvertDateToYMD(date, &ymd);
00289
00290 char day[3];
00291 char month[3];
00292
00293 snprintf(day, lengthof(day), "%02i", ymd.day);
00294 snprintf(month, lengthof(month), "%02i", ymd.month + 1);
00295
00296 int64 args[3] = { (int64)(size_t)day, (int64)(size_t)month, ymd.year };
00297 return FormatString(buff, GetStringPtr(str), args, 0, last);
00298 }
00299
00300 static char *FormatGenericCurrency(char *buff, const CurrencySpec *spec, Money number, bool compact, const char *last)
00301 {
00302
00303
00304 bool negative = number < 0;
00305 const char *multiplier = "";
00306 char buf[40];
00307 char *p;
00308 int j;
00309
00310 number *= spec->rate;
00311
00312
00313 if (number < 0) {
00314 if (buff + Utf8CharLen(SCC_RED) > last) return buff;
00315 buff += Utf8Encode(buff, SCC_RED);
00316 buff = strecpy(buff, "-", last);
00317 number = -number;
00318 }
00319
00320
00321
00322
00323 if (spec->symbol_pos != 1) buff = strecpy(buff, spec->prefix, last);
00324
00325
00326 if (compact) {
00327 if (number >= 1000000000) {
00328 number = (number + 500000) / 1000000;
00329 multiplier = "M";
00330 } else if (number >= 1000000) {
00331 number = (number + 500) / 1000;
00332 multiplier = "k";
00333 }
00334 }
00335
00336
00337 p = endof(buf);
00338 *--p = '\0';
00339 j = 4;
00340 do {
00341 if (--j == 0) {
00342 *--p = spec->separator;
00343 j = 3;
00344 }
00345 *--p = '0' + (char)(number % 10);
00346 } while ((number /= 10) != 0);
00347 buff = strecpy(buff, p, last);
00348
00349 buff = strecpy(buff, multiplier, last);
00350
00351
00352
00353
00354 if (spec->symbol_pos != 0) buff = strecpy(buff, spec->suffix, last);
00355
00356 if (negative) {
00357 if (buff + Utf8CharLen(SCC_PREVIOUS_COLOUR) > last) return buff;
00358 buff += Utf8Encode(buff, SCC_PREVIOUS_COLOUR);
00359 *buff = '\0';
00360 }
00361
00362 return buff;
00363 }
00364
00365 static int DeterminePluralForm(int64 count)
00366 {
00367
00368 uint64 n = abs(count);
00369
00370 switch (_langpack->plural_form) {
00371 default:
00372 NOT_REACHED();
00373
00374
00375
00376
00377
00378 case 0:
00379 return n != 1;
00380
00381
00382
00383
00384 case 1:
00385 return 0;
00386
00387
00388
00389
00390 case 2:
00391 return n > 1;
00392
00393
00394
00395
00396 case 3:
00397 return n % 10 == 1 && n % 100 != 11 ? 0 : n != 0 ? 1 : 2;
00398
00399
00400
00401
00402 case 4:
00403 return n == 1 ? 0 : n == 2 ? 1 : 2;
00404
00405
00406
00407
00408 case 5:
00409 return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
00410
00411
00412
00413
00414 case 6:
00415 return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
00416
00417
00418
00419
00420 case 7:
00421 return n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
00422
00423
00424
00425
00426 case 8:
00427 return n % 100 == 1 ? 0 : n % 100 == 2 ? 1 : n % 100 == 3 || n % 100 == 4 ? 2 : 3;
00428
00429
00430
00431
00432 case 9:
00433 return n % 10 == 1 && n % 100 != 11 ? 0 : 1;
00434 }
00435 }
00436
00437 static const char *ParseStringChoice(const char *b, uint form, char *dst, int *dstlen)
00438 {
00439
00440 uint n = (byte)*b++;
00441 uint pos, i, mylen = 0, mypos = 0;
00442
00443 for (i = pos = 0; i != n; i++) {
00444 uint len = (byte)*b++;
00445 if (i == form) {
00446 mypos = pos;
00447 mylen = len;
00448 }
00449 pos += len;
00450 }
00451 *dstlen = mylen;
00452 memcpy(dst, b + mypos, mylen);
00453 return b + pos;
00454 }
00455
00456 struct Units {
00457 int s_m;
00458 int s_s;
00459 StringID velocity;
00460 int p_m;
00461 int p_s;
00462 StringID power;
00463 int w_m;
00464 int w_s;
00465 StringID s_weight;
00466 StringID l_weight;
00467 int v_m;
00468 int v_s;
00469 StringID s_volume;
00470 StringID l_volume;
00471 int f_m;
00472 int f_s;
00473 StringID force;
00474 };
00475
00476
00477 static const Units units[] = {
00478 {
00479 1, 0, STR_UNITS_VELOCITY_IMPERIAL,
00480 1, 0, STR_UNITS_POWER_IMPERIAL,
00481 1, 0, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC,
00482 1000, 0, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC,
00483 1, 0, STR_UNITS_FORCE_SI,
00484 },
00485 {
00486 103, 6, STR_UNITS_VELOCITY_METRIC,
00487 1, 0, STR_UNITS_POWER_METRIC,
00488 1, 0, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC,
00489 1000, 0, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC,
00490 1, 0, STR_UNITS_FORCE_SI,
00491 },
00492 {
00493 1831, 12, STR_UNITS_VELOCITY_SI,
00494 764, 10, STR_UNITS_POWER_SI,
00495 1000, 0, STR_UNITS_WEIGHT_SHORT_SI, STR_UNITS_WEIGHT_LONG_SI,
00496 1, 0, STR_UNITS_VOLUME_SHORT_SI, STR_UNITS_VOLUME_LONG_SI,
00497 1, 0, STR_UNITS_FORCE_SI,
00498 },
00499 };
00500
00506 uint ConvertSpeedToDisplaySpeed(uint speed)
00507 {
00508 return (speed * units[_settings_game.locale.units].s_m) >> units[_settings_game.locale.units].s_s;
00509 }
00510
00516 uint ConvertDisplaySpeedToSpeed(uint speed)
00517 {
00518 return ((speed << units[_settings_game.locale.units].s_s) + units[_settings_game.locale.units].s_m / 2) / units[_settings_game.locale.units].s_m;
00519 }
00520
00521 static char *FormatString(char *buff, const char *str, const int64 *argv, uint casei, const char *last)
00522 {
00523 WChar b;
00524 const int64 *argv_orig = argv;
00525 uint modifier = 0;
00526
00527 while ((b = Utf8Consume(&str)) != '\0') {
00528 if (SCC_NEWGRF_FIRST <= b && b <= SCC_NEWGRF_LAST) {
00529
00530 b = RemapNewGRFStringControlCode(b, &buff, &str, (int64*)argv);
00531 if (b == 0) continue;
00532 }
00533
00534 switch (b) {
00535 case SCC_SETX:
00536 if (buff + Utf8CharLen(SCC_SETX) + 1 < last) {
00537 buff += Utf8Encode(buff, SCC_SETX);
00538 *buff++ = *str++;
00539 }
00540 break;
00541
00542 case SCC_SETXY:
00543 if (buff + Utf8CharLen(SCC_SETXY) + 2 < last) {
00544 buff += Utf8Encode(buff, SCC_SETXY);
00545 *buff++ = *str++;
00546 *buff++ = *str++;
00547 }
00548 break;
00549
00550 case SCC_STRING_ID:
00551 buff = GetStringWithArgs(buff, Utf8Consume(&str), argv, last);
00552 break;
00553
00554 case SCC_RAW_STRING_POINTER: {
00555 const char *str = (const char*)(size_t)GetInt64(&argv);
00556 buff = FormatString(buff, str, argv, casei, last);
00557 break;
00558 }
00559
00560 case SCC_DATE_LONG:
00561 buff = FormatYmdString(buff, GetInt32(&argv), last);
00562 break;
00563
00564 case SCC_DATE_SHORT:
00565 buff = FormatMonthAndYear(buff, GetInt32(&argv), last);
00566 break;
00567
00568 case SCC_VELOCITY: {
00569 int64 args[1];
00570 assert(_settings_game.locale.units < lengthof(units));
00571 args[0] = ConvertSpeedToDisplaySpeed(GetInt32(&argv));
00572 buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].velocity), args, modifier >> 24, last);
00573 modifier = 0;
00574 break;
00575 }
00576
00577 case SCC_CURRENCY_COMPACT:
00578 buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), true, last);
00579 break;
00580
00581 case SCC_REVISION:
00582 buff = strecpy(buff, _openttd_revision, last);
00583 break;
00584
00585 case SCC_CARGO_SHORT: {
00586
00587
00588
00589 StringID cargo_str = GetCargo(GetInt32(&argv))->units_volume;
00590 switch (cargo_str) {
00591 case STR_TONS: {
00592 int64 args[1];
00593 assert(_settings_game.locale.units < lengthof(units));
00594 args[0] = GetInt32(&argv) * units[_settings_game.locale.units].w_m >> units[_settings_game.locale.units].w_s;
00595 buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].l_weight), args, modifier >> 24, last);
00596 modifier = 0;
00597 break;
00598 }
00599
00600 case STR_LITERS: {
00601 int64 args[1];
00602 assert(_settings_game.locale.units < lengthof(units));
00603 args[0] = GetInt32(&argv) * units[_settings_game.locale.units].v_m >> units[_settings_game.locale.units].v_s;
00604 buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].l_volume), args, modifier >> 24, last);
00605 modifier = 0;
00606 break;
00607 }
00608
00609 default:
00610 if (cargo_str >= 0xE000 && cargo_str < 0xF800) {
00611
00612
00613 buff = GetStringWithArgs(buff, cargo_str, argv++, last);
00614 } else {
00615 buff = FormatCommaNumber(buff, GetInt32(&argv), last);
00616 buff = strecpy(buff, " ", last);
00617 buff = strecpy(buff, GetStringPtr(cargo_str), last);
00618 }
00619 break;
00620 }
00621 } break;
00622
00623 case SCC_STRING1: {
00624
00625 uint str = modifier + GetInt32(&argv);
00626 buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 1), last);
00627 modifier = 0;
00628 break;
00629 }
00630
00631 case SCC_STRING2: {
00632
00633 uint str = modifier + GetInt32(&argv);
00634 buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 2), last);
00635 modifier = 0;
00636 break;
00637 }
00638
00639 case SCC_STRING3: {
00640
00641 uint str = modifier + GetInt32(&argv);
00642 buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 3), last);
00643 modifier = 0;
00644 break;
00645 }
00646
00647 case SCC_STRING4: {
00648
00649 uint str = modifier + GetInt32(&argv);
00650 buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 4), last);
00651 modifier = 0;
00652 break;
00653 }
00654
00655 case SCC_STRING5: {
00656
00657 uint str = modifier + GetInt32(&argv);
00658 buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 5), last);
00659 modifier = 0;
00660 break;
00661 }
00662
00663 case SCC_STATION_FEATURES: {
00664 buff = StationGetSpecialString(buff, GetInt32(&argv), last);
00665 break;
00666 }
00667
00668 case SCC_INDUSTRY_NAME: {
00669 const Industry *i = GetIndustry(GetInt32(&argv));
00670 int64 args[2];
00671
00672
00673 if (!i->IsValid()) break;
00674
00675
00676
00677 args[0] = i->town->index;
00678 args[1] = GetIndustrySpec(i->type)->name;
00679 buff = FormatString(buff, GetStringPtr(STR_INDUSTRY_FORMAT), args, modifier >> 24, last);
00680 modifier = 0;
00681 break;
00682 }
00683
00684 case SCC_VOLUME: {
00685 int64 args[1];
00686 assert(_settings_game.locale.units < lengthof(units));
00687 args[0] = GetInt32(&argv) * units[_settings_game.locale.units].v_m >> units[_settings_game.locale.units].v_s;
00688 buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].l_volume), args, modifier >> 24, last);
00689 modifier = 0;
00690 break;
00691 }
00692
00693 case SCC_GENDER_LIST: {
00694 const char *s = GetStringPtr(argv_orig[(byte)*str++]);
00695 int len;
00696 int gender = 0;
00697 if (s != NULL) {
00698 wchar_t c = Utf8Consume(&s);
00699
00700 if (c == SCC_SWITCH_CASE) {
00701
00702 for (uint num = (byte)*s++; num != 0; num--) s += 3 + (s[1] << 8) + s[2];
00703
00704 c = Utf8Consume(&s);
00705 }
00706
00707 if (c == SCC_GENDER_INDEX) gender = (byte)s[0];
00708 }
00709 str = ParseStringChoice(str, gender, buff, &len);
00710 buff += len;
00711 break;
00712 }
00713
00714 case SCC_DATE_TINY: {
00715 buff = FormatTinyOrISODate(buff, GetInt32(&argv), STR_DATE_TINY, last);
00716 break;
00717 }
00718
00719 case SCC_DATE_ISO: {
00720 buff = FormatTinyOrISODate(buff, GetInt32(&argv), STR_DATE_ISO, last);
00721 break;
00722 }
00723
00724 case SCC_CARGO: {
00725
00726
00727
00728 CargoID cargo = GetInt32(&argv);
00729 StringID cargo_str = (cargo == CT_INVALID) ? STR_8838_N_A : GetCargo(cargo)->quantifier;
00730 buff = GetStringWithArgs(buff, cargo_str, argv++, last);
00731 break;
00732 }
00733
00734 case SCC_POWER: {
00735 int64 args[1];
00736 assert(_settings_game.locale.units < lengthof(units));
00737 args[0] = GetInt32(&argv) * units[_settings_game.locale.units].p_m >> units[_settings_game.locale.units].p_s;
00738 buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].power), args, modifier >> 24, last);
00739 modifier = 0;
00740 break;
00741 }
00742
00743 case SCC_VOLUME_SHORT: {
00744 int64 args[1];
00745 assert(_settings_game.locale.units < lengthof(units));
00746 args[0] = GetInt32(&argv) * units[_settings_game.locale.units].v_m >> units[_settings_game.locale.units].v_s;
00747 buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].s_volume), args, modifier >> 24, last);
00748 modifier = 0;
00749 break;
00750 }
00751
00752 case SCC_WEIGHT: {
00753 int64 args[1];
00754 assert(_settings_game.locale.units < lengthof(units));
00755 args[0] = GetInt32(&argv) * units[_settings_game.locale.units].w_m >> units[_settings_game.locale.units].w_s;
00756 buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].l_weight), args, modifier >> 24, last);
00757 modifier = 0;
00758 break;
00759 }
00760
00761 case SCC_WEIGHT_SHORT: {
00762 int64 args[1];
00763 assert(_settings_game.locale.units < lengthof(units));
00764 args[0] = GetInt32(&argv) * units[_settings_game.locale.units].w_m >> units[_settings_game.locale.units].w_s;
00765 buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].s_weight), args, modifier >> 24, last);
00766 modifier = 0;
00767 break;
00768 }
00769
00770 case SCC_FORCE: {
00771 int64 args[1];
00772 assert(_settings_game.locale.units < lengthof(units));
00773 args[0] = GetInt32(&argv) * units[_settings_game.locale.units].f_m >> units[_settings_game.locale.units].f_s;
00774 buff = FormatString(buff, GetStringPtr(units[_settings_game.locale.units].force), args, modifier >> 24, last);
00775 modifier = 0;
00776 break;
00777 }
00778
00779 case SCC_SKIP:
00780 argv++;
00781 break;
00782
00783
00784
00785 case SCC_GENDER_INDEX:
00786 str++;
00787 break;
00788
00789 case SCC_STRING: {
00790 uint str = modifier + GetInt32(&argv);
00791
00792
00793
00794 buff = GetStringWithArgs(buff, str, argv, last);
00795 modifier = 0;
00796 break;
00797 }
00798
00799 case SCC_COMMA:
00800 buff = FormatCommaNumber(buff, GetInt64(&argv), last);
00801 break;
00802
00803 case SCC_ARG_INDEX:
00804 argv = argv_orig + (byte)*str++;
00805 break;
00806
00807 case SCC_PLURAL_LIST: {
00808 int64 v = argv_orig[(byte)*str++];
00809 int len;
00810 str = ParseStringChoice(str, DeterminePluralForm(v), buff, &len);
00811 buff += len;
00812 break;
00813 }
00814
00815 case SCC_NUM:
00816 buff = FormatNoCommaNumber(buff, GetInt64(&argv), last);
00817 break;
00818
00819 case SCC_HEX:
00820 buff = FormatHexNumber(buff, GetInt64(&argv), last);
00821 break;
00822
00823 case SCC_CURRENCY:
00824 buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), false, last);
00825 break;
00826
00827 case SCC_WAYPOINT_NAME: {
00828 Waypoint *wp = GetWaypoint(GetInt32(&argv));
00829
00830 assert(wp->IsValid());
00831
00832 if (wp->name != NULL) {
00833 buff = strecpy(buff, wp->name, last);
00834 } else {
00835 int64 temp[2];
00836 temp[0] = wp->town_index;
00837 temp[1] = wp->town_cn + 1;
00838 StringID str = wp->town_cn == 0 ? STR_WAYPOINTNAME_CITY : STR_WAYPOINTNAME_CITY_SERIAL;
00839
00840 buff = GetStringWithArgs(buff, str, temp, last);
00841 }
00842 break;
00843 }
00844
00845 case SCC_STATION_NAME: {
00846 StationID sid = GetInt32(&argv);
00847
00848 if (!IsValidStationID(sid)) {
00849
00850
00851
00852 buff = GetStringWithArgs(buff, STR_UNKNOWN_STATION, NULL, last);
00853 break;
00854 }
00855
00856 const Station *st = GetStation(sid);
00857 if (st->name != NULL) {
00858 buff = strecpy(buff, st->name, last);
00859 } else {
00860 StringID str = st->string_id;
00861 if (st->indtype != IT_INVALID) {
00862
00863 const IndustrySpec *indsp = GetIndustrySpec(st->indtype);
00864
00865
00866
00867
00868 if (indsp->station_name != STR_NULL && indsp->station_name != STR_UNDEFINED) {
00869 str = indsp->station_name;
00870 }
00871 }
00872
00873 int64 temp[3];
00874 temp[0] = STR_TOWN;
00875 temp[1] = st->town->index;
00876 temp[2] = st->index;
00877 buff = GetStringWithArgs(buff, str, temp, last);
00878 }
00879 break;
00880 }
00881
00882 case SCC_TOWN_NAME: {
00883 const Town *t = GetTown(GetInt32(&argv));
00884 int64 temp[1];
00885
00886 assert(t->IsValid());
00887
00888 temp[0] = t->townnameparts;
00889 uint32 grfid = t->townnamegrfid;
00890
00891 if (t->name != NULL) {
00892 buff = strecpy(buff, t->name, last);
00893 } else if (grfid == 0) {
00894
00895 buff = GetStringWithArgs(buff, t->townnametype, temp, last);
00896 } else {
00897
00898 if (GetGRFTownName(grfid) != NULL) {
00899
00900 buff = GRFTownNameGenerate(buff, t->townnamegrfid, t->townnametype, t->townnameparts, last);
00901 } else {
00902
00903 buff = GetStringWithArgs(buff, SPECSTR_TOWNNAME_ENGLISH, temp, last);
00904 }
00905 }
00906 break;
00907 }
00908
00909 case SCC_GROUP_NAME: {
00910 const Group *g = GetGroup(GetInt32(&argv));
00911
00912 assert(g->IsValid());
00913
00914 if (g->name != NULL) {
00915 buff = strecpy(buff, g->name, last);
00916 } else {
00917 int64 args[1];
00918
00919 args[0] = g->index;
00920 buff = GetStringWithArgs(buff, STR_GROUP_NAME_FORMAT, args, last);
00921 }
00922 break;
00923 }
00924
00925 case SCC_ENGINE_NAME: {
00926 EngineID engine = (EngineID)GetInt32(&argv);
00927 const Engine *e = GetEngine(engine);
00928
00929 if (e->name != NULL) {
00930 buff = strecpy(buff, e->name, last);
00931 } else {
00932 buff = GetStringWithArgs(buff, e->info.string_id, NULL, last);
00933 }
00934 break;
00935 }
00936
00937 case SCC_VEHICLE_NAME: {
00938 const Vehicle *v = GetVehicle(GetInt32(&argv));
00939
00940 if (v->name != NULL) {
00941 buff = strecpy(buff, v->name, last);
00942 } else {
00943 int64 args[1];
00944 args[0] = v->unitnumber;
00945
00946 StringID str;
00947 switch (v->type) {
00948 default: NOT_REACHED();
00949 case VEH_TRAIN: str = STR_SV_TRAIN_NAME; break;
00950 case VEH_ROAD: str = STR_SV_ROADVEH_NAME; break;
00951 case VEH_SHIP: str = STR_SV_SHIP_NAME; break;
00952 case VEH_AIRCRAFT: str = STR_SV_AIRCRAFT_NAME; break;
00953 }
00954
00955 buff = GetStringWithArgs(buff, str, args, last);
00956 }
00957 break;
00958 }
00959
00960 case SCC_SIGN_NAME: {
00961 const Sign *si = GetSign(GetInt32(&argv));
00962 if (si->name != NULL) {
00963 buff = strecpy(buff, si->name, last);
00964 } else {
00965 buff = GetStringWithArgs(buff, STR_280A_SIGN, NULL, last);
00966 }
00967 break;
00968 }
00969
00970 case SCC_COMPANY_NAME: {
00971 const Company *c = GetCompany((CompanyID)GetInt32(&argv));
00972
00973 if (c->name != NULL) {
00974 buff = strecpy(buff, c->name, last);
00975 } else {
00976 int64 args[1];
00977 args[0] = c->name_2;
00978 buff = GetStringWithArgs(buff, c->name_1, args, last);
00979 }
00980 break;
00981 }
00982
00983 case SCC_COMPANY_NUM: {
00984 CompanyID company = (CompanyID)GetInt32(&argv);
00985
00986
00987 if (IsValidCompanyID(company) && IsHumanCompany(company)) {
00988 int64 args[1];
00989 args[0] = company + 1;
00990 buff = GetStringWithArgs(buff, STR_7002_COMPANY, args, last);
00991 }
00992 break;
00993 }
00994
00995 case SCC_PRESIDENT_NAME: {
00996 const Company *c = GetCompany((CompanyID)GetInt32(&argv));
00997
00998 if (c->president_name != NULL) {
00999 buff = strecpy(buff, c->president_name, last);
01000 } else {
01001 int64 args[1];
01002 args[0] = c->president_name_2;
01003 buff = GetStringWithArgs(buff, c->president_name_1, args, last);
01004 }
01005 break;
01006 }
01007
01008 case SCC_SETCASE: {
01009
01010
01011 modifier = (byte)*str++ << 24;
01012 break;
01013 }
01014
01015 case SCC_SWITCH_CASE: {
01016
01017
01018 uint num = (byte)*str++;
01019 while (num) {
01020 if ((byte)str[0] == casei) {
01021
01022 str += 3;
01023 break;
01024 }
01025
01026 str += 3 + (str[1] << 8) + str[2];
01027 num--;
01028 }
01029 break;
01030 }
01031
01032 default:
01033 if (buff + Utf8CharLen(b) < last) buff += Utf8Encode(buff, b);
01034 break;
01035 }
01036 }
01037 *buff = '\0';
01038 return buff;
01039 }
01040
01041
01042 static char *StationGetSpecialString(char *buff, int x, const char *last)
01043 {
01044 if ((x & FACIL_TRAIN) && (buff + Utf8CharLen(SCC_TRAIN) < last)) buff += Utf8Encode(buff, SCC_TRAIN);
01045 if ((x & FACIL_TRUCK_STOP) && (buff + Utf8CharLen(SCC_LORRY) < last)) buff += Utf8Encode(buff, SCC_LORRY);
01046 if ((x & FACIL_BUS_STOP) && (buff + Utf8CharLen(SCC_BUS) < last)) buff += Utf8Encode(buff, SCC_BUS);
01047 if ((x & FACIL_AIRPORT) && (buff + Utf8CharLen(SCC_PLANE) < last)) buff += Utf8Encode(buff, SCC_PLANE);
01048 if ((x & FACIL_DOCK) && (buff + Utf8CharLen(SCC_SHIP) < last)) buff += Utf8Encode(buff, SCC_SHIP);
01049 *buff = '\0';
01050 return buff;
01051 }
01052
01053 static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last)
01054 {
01055 char name[512];
01056
01057 _town_name_generators[ind](name, seed, lastof(name));
01058 return strecpy(buff, name, last);
01059 }
01060
01061 static const char * const _silly_company_names[] = {
01062 "Bloggs Brothers",
01063 "Tiny Transport Ltd.",
01064 "Express Travel",
01065 "Comfy-Coach & Co.",
01066 "Crush & Bump Ltd.",
01067 "Broken & Late Ltd.",
01068 "Sam Speedy & Son",
01069 "Supersonic Travel",
01070 "Mike's Motors",
01071 "Lightning International",
01072 "Pannik & Loozit Ltd.",
01073 "Inter-City Transport",
01074 "Getout & Pushit Ltd."