strings.cpp

Go to the documentation of this file.
00001 /* $Id: strings.cpp 14840 2009-01-04 21:02:59Z glx $ */
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]; // list of strings
00057 };
00058 
00059 static char **_langpack_offs;
00060 static LanguagePack *_langpack;
00061 static uint _langtab_num[32];   // Offset into langpack offs
00062 static uint _langtab_start[32]; // Offset into langpack offs
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       /* Old table for custom names. This is no longer used */
00129       error("Incorrect conversion of custom name string.");
00130 
00131     case 26:
00132       /* Include string within newgrf text (format code 81) */
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 // TODO
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 // TODO
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   /* We want to zero-pad the days and months */
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   /* We are going to make number absolute for printing, so
00303    * keep this piece of data as we need it later on */
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   /* convert from negative */
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   /* Add prefix part, folowing symbol_pos specification.
00321    * Here, it can can be either 0 (prefix) or 2 (both prefix anf suffix).
00322    * The only remaining value is 1 (suffix), so everything that is not 1 */
00323   if (spec->symbol_pos != 1) buff = strecpy(buff, spec->prefix, last);
00324 
00325   /* for huge numbers, compact the number into k or M */
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   /* convert to ascii number and add commas */
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   /* Add suffix part, folowing symbol_pos specification.
00352    * Here, it can can be either 1 (suffix) or 2 (both prefix anf suffix).
00353    * The only remaining value is 1 (prefix), so everything that is not 0 */
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   /* The absolute value determines plurality */
00368   uint64 n = abs(count);
00369 
00370   switch (_langpack->plural_form) {
00371     default:
00372       NOT_REACHED();
00373 
00374     /* Two forms, singular used for one only
00375      * Used in:
00376      *   Danish, Dutch, English, German, Norwegian, Swedish, Estonian, Finnish,
00377      *   Greek, Hebrew, Italian, Portuguese, Spanish, Esperanto */
00378     case 0:
00379       return n != 1;
00380 
00381     /* Only one form
00382      * Used in:
00383      *   Hungarian, Japanese, Korean, Turkish */
00384     case 1:
00385       return 0;
00386 
00387     /* Two forms, singular used for zero and one
00388      * Used in:
00389      *   French, Brazilian Portuguese */
00390     case 2:
00391       return n > 1;
00392 
00393     /* Three forms, special case for zero
00394      * Used in:
00395      *   Latvian */
00396     case 3:
00397       return n % 10 == 1 && n % 100 != 11 ? 0 : n != 0 ? 1 : 2;
00398 
00399     /* Three forms, special case for one and two
00400      * Used in:
00401      *   Gaelige (Irish) */
00402     case 4:
00403       return n == 1 ? 0 : n == 2 ? 1 : 2;
00404 
00405     /* Three forms, special case for numbers ending in 1[2-9]
00406      * Used in:
00407      *   Lithuanian */
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     /* Three forms, special cases for numbers ending in 1 and 2, 3, 4, except those ending in 1[1-4]
00412      * Used in:
00413      *   Croatian, Czech, Russian, Slovak, Ukrainian */
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     /* Three forms, special case for one and some numbers ending in 2, 3, or 4
00418      * Used in:
00419      *   Polish */
00420     case 7:
00421       return n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
00422 
00423     /* Four forms, special case for one and all numbers ending in 02, 03, or 04
00424      * Used in:
00425      *   Slovenian */
00426     case 8:
00427       return n % 100 == 1 ? 0 : n % 100 == 2 ? 1 : n % 100 == 3 || n % 100 == 4 ? 2 : 3;
00428 
00429     /* Two forms; singular used for everything ending in 1 but not in 11.
00430      * Used in:
00431      *   Icelandic */
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   //<NUM> {Length of each string} {each string}
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 /* Unit conversions */
00477 static const Units units[] = {
00478   { // Imperial (Original, mph, hp, metric ton, litre, kN)
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   { // Metric (km/h, hp, metric ton, litre, kN)
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   { // SI (m/s, kilowatt, kilogram, cubic metres, kilonewton)
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       /* We need to pass some stuff as it might be modified; oh boy. */
00530       b = RemapNewGRFStringControlCode(b, &buff, &str, (int64*)argv);
00531       if (b == 0) continue;
00532     }
00533 
00534     switch (b) {
00535       case SCC_SETX: // {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: // {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: // {STRINL}
00551         buff = GetStringWithArgs(buff, Utf8Consume(&str), argv, last);
00552         break;
00553 
00554       case SCC_RAW_STRING_POINTER: { // {RAW_STRING}
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: // {DATE_LONG}
00561         buff = FormatYmdString(buff, GetInt32(&argv), last);
00562         break;
00563 
00564       case SCC_DATE_SHORT: // {DATE_SHORT}
00565         buff = FormatMonthAndYear(buff, GetInt32(&argv), last);
00566         break;
00567 
00568       case SCC_VELOCITY: {// {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: // {CURRCOMPACT}
00578         buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), true, last);
00579         break;
00580 
00581       case SCC_REVISION: // {REV}
00582         buff = strecpy(buff, _openttd_revision, last);
00583         break;
00584 
00585       case SCC_CARGO_SHORT: { // {SHORTCARGO}
00586         /* Short description of cargotypes. Layout:
00587          * 8-bit = cargo type
00588          * 16-bit = cargo count */
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               /* NewGRF strings from Action 4 use a different format here,
00612                * of e.g. "x tonnes of coal", so process accordingly. */
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: { // {STRING1}
00624         /* String that consumes ONE argument */
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: { // {STRING2}
00632         /* String that consumes TWO arguments */
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: { // {STRING3}
00640         /* String that consumes THREE arguments */
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: { // {STRING4}
00648         /* String that consumes FOUR arguments */
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: { // {STRING5}
00656         /* String that consumes FIVE arguments */
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: { // {STATIONFEATURES}
00664         buff = StationGetSpecialString(buff, GetInt32(&argv), last);
00665         break;
00666       }
00667 
00668       case SCC_INDUSTRY_NAME: { // {INDUSTRY}
00669         const Industry *i = GetIndustry(GetInt32(&argv));
00670         int64 args[2];
00671 
00672         /* industry not valid anymore? */
00673         if (!i->IsValid()) break;
00674 
00675         /* First print the town name and the industry type name
00676          * The string STR_INDUSTRY_PATTERN controls the formatting */
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: { // {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: { // {G 0 Der Die Das}
00694         const char *s = GetStringPtr(argv_orig[(byte)*str++]); // contains the string that determines gender.
00695         int len;
00696         int gender = 0;
00697         if (s != NULL) {
00698           wchar_t c = Utf8Consume(&s);
00699           /* Switch case is always put before genders, so remove those bits */
00700           if (c == SCC_SWITCH_CASE) {
00701             /* Skip to the last (i.e. default) case */
00702             for (uint num = (byte)*s++; num != 0; num--) s += 3 + (s[1] << 8) + s[2];
00703 
00704             c = Utf8Consume(&s);
00705           }
00706           /* Does this string have a gender, if so, set it */
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: { // {DATE_TINY}
00715         buff = FormatTinyOrISODate(buff, GetInt32(&argv), STR_DATE_TINY, last);
00716         break;
00717       }
00718 
00719       case SCC_DATE_ISO: { // {DATE_ISO}
00720         buff = FormatTinyOrISODate(buff, GetInt32(&argv), STR_DATE_ISO, last);
00721         break;
00722       }
00723 
00724       case SCC_CARGO: { // {CARGO}
00725         /* Layout now is:
00726          *   8bit   - cargo type
00727          *   16-bit - cargo count */
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: { // {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: { // {VOLUME_S}
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: { // {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: { // {WEIGHT_S}
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: { // {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: // {SKIP}
00780         argv++;
00781         break;
00782 
00783       /* This sets up the gender for the string.
00784        * We just ignore this one. It's used in {G 0 Der Die Das} to determine the case. */
00785       case SCC_GENDER_INDEX: // {GENDER 0}
00786         str++;
00787         break;
00788 
00789       case SCC_STRING: {// {STRING}
00790         uint str = modifier + GetInt32(&argv);
00791         /* WARNING. It's prohibited for the included string to consume any arguments.
00792          * For included strings that consume argument, you should use STRING1, STRING2 etc.
00793          * To debug stuff you can set argv to NULL and it will tell you */
00794         buff = GetStringWithArgs(buff, str, argv, last);
00795         modifier = 0;
00796         break;
00797       }
00798 
00799       case SCC_COMMA: // {COMMA}
00800         buff = FormatCommaNumber(buff, GetInt64(&argv), last);
00801         break;
00802 
00803       case SCC_ARG_INDEX: // Move argument pointer
00804         argv = argv_orig + (byte)*str++;
00805         break;
00806 
00807       case SCC_PLURAL_LIST: { // {P}
00808         int64 v = argv_orig[(byte)*str++]; // contains the number that determines plural
00809         int len;
00810         str = ParseStringChoice(str, DeterminePluralForm(v), buff, &len);
00811         buff += len;
00812         break;
00813       }
00814 
00815       case SCC_NUM: // {NUM}
00816         buff = FormatNoCommaNumber(buff, GetInt64(&argv), last);
00817         break;
00818 
00819       case SCC_HEX: // {HEX}
00820         buff = FormatHexNumber(buff, GetInt64(&argv), last);
00821         break;
00822 
00823       case SCC_CURRENCY: // {CURRENCY}
00824         buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), false, last);
00825         break;
00826 
00827       case SCC_WAYPOINT_NAME: { // {WAYPOINT}
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: { // {STATION}
00846         StationID sid = GetInt32(&argv);
00847 
00848         if (!IsValidStationID(sid)) {
00849           /* The station doesn't exist anymore. The only place where we might
00850            * be "drawing" an invalid station is in the case of cargo that is
00851            * in transit. */
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             /* Special case where the industry provides the name for the station */
00863             const IndustrySpec *indsp = GetIndustrySpec(st->indtype);
00864 
00865             /* Industry GRFs can change which might remove the station name and
00866              * thus cause very strange things. Here we check for that before we
00867              * actually set the station name. */
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: { // {TOWN}
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           /* Original town name */
00895           buff = GetStringWithArgs(buff, t->townnametype, temp, last);
00896         } else {
00897           /* Newgrf town name */
00898           if (GetGRFTownName(grfid) != NULL) {
00899             /* The grf is loaded */
00900             buff = GRFTownNameGenerate(buff, t->townnamegrfid, t->townnametype, t->townnameparts, last);
00901           } else {
00902             /* Fallback to english original */
00903             buff = GetStringWithArgs(buff, SPECSTR_TOWNNAME_ENGLISH, temp, last);
00904           }
00905         }
00906         break;
00907       }
00908 
00909       case SCC_GROUP_NAME: { // {GROUP}
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: { // {ENGINE}
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: { // {VEHICLE}
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: { // {SIGN}
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: { // {COMPANY}
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: { // {COMPANYNUM}
00984         CompanyID company = (CompanyID)GetInt32(&argv);
00985 
00986         /* Nothing is added for AI or inactive companies */
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: { // {PRESIDENTNAME}
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: { // {SETCASE}
01009         /* This is a pseudo command, it's outputted when someone does {STRING.ack}
01010          * The modifier is added to all subsequent GetStringWithArgs that accept the modifier. */
01011         modifier = (byte)*str++ << 24;
01012         break;
01013       }
01014 
01015       case SCC_SWITCH_CASE: { // {Used to implement case switching}
01016         /* <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT>
01017          * Each LEN is printed using 2 bytes in big endian order. */
01018         uint num = (byte)*str++;
01019         while (num) {
01020           if ((byte)str[0] == casei) {
01021             /* Found the case, adjust str pointer and continue */
01022             str += 3;
01023             break;
01024           }
01025           /* Otherwise skip to the next case */
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."