# townname.cpp

Go to the documentation of this file.

    00001 /* $Id$ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
    00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
    00008  */
    00009
    00012 #include "stdafx.h"
    00013 #include "string_func.h"
    00014 #include "townname_type.h"
    00015 #include "town.h"
    00016 #include "core/alloc_func.hpp"
    00017 #include "strings_func.h"
    00018
    00019 #include "table/townname.h"
    00020
    00021
    00026 TownNameParams::TownNameParams(const Town *t) :
    00027     grfid(t->townnamegrfid), // by default, use supplied data
    00028     type(t->townnametype)
    00029 {
    00030   if (t->townnamegrfid != 0 && GetGRFTownName(t->townnamegrfid) == NULL) {
    00031     /* Fallback to english original */
    00032     this->grfid = 0;
    00033     this->type = SPECSTR_TOWNNAME_ENGLISH;
    00034     return;
    00035   }
    00036 }
    00037
    00038
    00047 char *GetTownName(char *buff, const TownNameParams *par, uint32 townnameparts, const char *last)
    00048 {
    00049   if (par->grfid == 0) {
    00050     int64 temp[1] = { townnameparts };
    00051     return GetStringWithArgs(buff, par->type, temp, last);
    00052   }
    00053
    00054   return GRFTownNameGenerate(buff, par->grfid, par->type, townnameparts, last);
    00055 }
    00056
    00057
    00065 char *GetTownName(char *buff, const Town *t, const char *last)
    00066 {
    00067   TownNameParams par(t);
    00068   return GetTownName(buff, &par, t->townnameparts, last);
    00069 }
    00070
    00071
    00078 bool VerifyTownName(uint32 r, const TownNameParams *par)
    00079 {
    00080   /* reserve space for extra unicode character and terminating '\0' */
    00081   char buf1[MAX_LENGTH_TOWN_NAME_BYTES + MAX_CHAR_LENGTH];
    00082   char buf2[MAX_LENGTH_TOWN_NAME_BYTES + MAX_CHAR_LENGTH];
    00083
    00084   GetTownName(buf1, par, r, lastof(buf1));
    00085
    00086   /* Check size and width */
    00087   if (strlen(buf1) >= MAX_LENGTH_TOWN_NAME_BYTES) return false;
    00088
    00089   const Town *t;
    00090   FOR_ALL_TOWNS(t) {
    00091     /* We can't just compare the numbers since
    00092      * several numbers may map to a single name. */
    00093     const char *buf = t->name;
    00094     if (buf == NULL) {
    00095       GetTownName(buf2, t, lastof(buf2));
    00096       buf = buf2;
    00097     }
    00098     if (strcmp(buf1, buf2) == 0) return false;
    00099   }
    00100
    00101   return true;
    00102 }
    00103
    00104
    00110 bool GenerateTownName(uint32 *townnameparts)
    00111 {
    00112   /* Do not set too low tries, since when we run out of names, we loop
    00113    * for #tries only one time anyway - then we stop generating more
    00114    * towns. Do not show it too high neither, since looping through all
    00115    * the other towns may take considerable amount of time (10000 is
    00116    * too much). */
    00117   TownNameParams par(_settings_game.game_creation.town_name);
    00118
    00119   for (int i = 1000; i != 0; i--) {
    00120     uint32 r = InteractiveRandom();
    00121     if (!VerifyTownName(r, &par)) continue;
    00122
    00123     *townnameparts = r;
    00124     return true;
    00125   }
    00126
    00127   return false;
    00128 }
    00129
    00130
    00131
    00139 static inline uint32 SeedChance(byte shift_by, int max, uint32 seed)
    00140 {
    00141   return (GB(seed, shift_by, 16) * max) >> 16;
    00142 }
    00143
    00144
    00152 static inline uint32 SeedModChance(byte shift_by, int max, uint32 seed)
    00153 {
    00154   /* This actually gives *MUCH* more even distribution of the values
    00155    * than SeedChance(), which is absolutely horrible in that. If
    00156    * you do not believe me, try with i.e. the Czech town names,
    00157    * compare the words (nicely visible on prefixes) generated by
    00158    * SeedChance() and SeedModChance(). Do not get dicouraged by the
    00159    * never-use-modulo myths, which hold true only for the linear
    00160    * congruential generators (and Random() isn't such a generator).
    00161    * --pasky
    00162    * TODO: Perhaps we should use it for all the name generators? --pasky */
    00163   return (seed >> shift_by) % max;
    00164 }
    00165
    00166
    00175 static inline int32 SeedChanceBias(byte shift_by, int max, uint32 seed, int bias)
    00176 {
    00177   return SeedChance(shift_by, max + bias, seed) - bias;
    00178 }
    00179
    00180
    00187 static void ReplaceWords(const char *org, const char *rep, char *buf)
    00188 {
    00189   if (strncmp(buf, org, 4) == 0) strncpy(buf, rep, 4); // Safe as the string in buf is always more than 4 characters long.
    00190 }
    00191
    00192
    00198 static void ReplaceEnglishWords(char *buf, bool original)
    00199 {
    00200   ReplaceWords("Cunt", "East", buf);
    00201   ReplaceWords("Slag", "Pits", buf);
    00202   ReplaceWords("Slut", "Edin", buf);
    00203   if (!original) ReplaceWords("Fart", "Boot", buf); // never happens with 'English (Original)'
    00204   ReplaceWords("Drar", "Quar", buf);
    00205   ReplaceWords("Dreh", "Bash", buf);
    00206   ReplaceWords("Frar", "Shor", buf);
    00207   ReplaceWords("Grar", "Aber", buf);
    00208   ReplaceWords("Brar", "Over", buf);
    00209   ReplaceWords("Wrar", original ? "Inve" : "Stan", buf);
    00210 }
    00211
    00218 static char *MakeEnglishOriginalTownName(char *buf, const char *last, uint32 seed)
    00219 {
    00220   char *orig = buf;
    00221
    00222   /* optional first segment */
    00223   int i = SeedChanceBias(0, lengthof(_name_original_english_1), seed, 50);
    00224   if (i >= 0) buf = strecpy(buf, _name_original_english_1[i], last);
    00225
    00226   /* mandatory middle segments */
    00227   buf = strecpy(buf, _name_original_english_2[SeedChance(4,  lengthof(_name_original_english_2), seed)], last);
    00228   buf = strecpy(buf, _name_original_english_3[SeedChance(7,  lengthof(_name_original_english_3), seed)], last);
    00229   buf = strecpy(buf, _name_original_english_4[SeedChance(10, lengthof(_name_original_english_4), seed)], last);
    00230   buf = strecpy(buf, _name_original_english_5[SeedChance(13, lengthof(_name_original_english_5), seed)], last);
    00231
    00232   /* optional last segment */
    00233   i = SeedChanceBias(15, lengthof(_name_original_english_6), seed, 60);
    00234   if (i >= 0) buf = strecpy(buf, _name_original_english_6[i], last);
    00235
    00236   /* Ce, Ci => Ke, Ki */
    00237   if (orig[0] == 'C' && (orig[1] == 'e' || orig[1] == 'i')) {
    00238     orig[0] = 'K';
    00239   }
    00240
    00241   assert(buf - orig >= 4);
    00242   ReplaceEnglishWords(orig, true);
    00243
    00244   return buf;
    00245 }
    00246
    00247
    00254 static char *MakeEnglishAdditionalTownName(char *buf, const char *last, uint32 seed)
    00255 {
    00256   char *orig = buf;
    00257
    00258   /* optional first segment */
    00259   int i = SeedChanceBias(0, lengthof(_name_additional_english_prefix), seed, 50);
    00260   if (i >= 0) buf = strecpy(buf, _name_additional_english_prefix[i], last);
    00261
    00262   if (SeedChance(3, 20, seed) >= 14) {
    00263     buf = strecpy(buf, _name_additional_english_1a[SeedChance(6, lengthof(_name_additional_english_1a), seed)], last);
    00264   } else {
    00265     buf = strecpy(buf, _name_additional_english_1b1[SeedChance(6, lengthof(_name_additional_english_1b1), seed)], last);
    00266     buf = strecpy(buf, _name_additional_english_1b2[SeedChance(9, lengthof(_name_additional_english_1b2), seed)], last);
    00267     if (SeedChance(11, 20, seed) >= 4) {
    00268       buf = strecpy(buf, _name_additional_english_1b3a[SeedChance(12, lengthof(_name_additional_english_1b3a), seed)], last);
    00269     } else {
    00270       buf = strecpy(buf, _name_additional_english_1b3b[SeedChance(12, lengthof(_name_additional_english_1b3b), seed)], last);
    00271     }
    00272   }
    00273
    00274   buf = strecpy(buf, _name_additional_english_2[SeedChance(14, lengthof(_name_additional_english_2), seed)], last);
    00275
    00276   /* optional last segment */
    00277   i = SeedChanceBias(15, lengthof(_name_additional_english_3), seed, 60);
    00278   if (i >= 0) buf = strecpy(buf, _name_additional_english_3[i], last);
    00279
    00280   assert(buf - orig >= 4);
    00281   ReplaceEnglishWords(orig, false);
    00282
    00283   return buf;
    00284 }
    00285
    00286
    00293 static char *MakeAustrianTownName(char *buf, const char *last, uint32 seed)
    00294 {
    00295   /* Bad, Maria, Gross, ... */
    00296   int i = SeedChanceBias(0, lengthof(_name_austrian_a1), seed, 15);
    00297   if (i >= 0) buf = strecpy(buf, _name_austrian_a1[i], last);
    00298
    00299   int j = 0;
    00300
    00301   i = SeedChance(4, 6, seed);
    00302   if (i >= 4) {
    00303     /* Kaisers-kirchen */
    00304     buf = strecpy(buf, _name_austrian_a2[SeedChance( 7, lengthof(_name_austrian_a2), seed)], last);
    00305     buf = strecpy(buf, _name_austrian_a3[SeedChance(13, lengthof(_name_austrian_a3), seed)], last);
    00306   } else if (i >= 2) {
    00307     /* St. Johann */
    00308     buf = strecpy(buf, _name_austrian_a5[SeedChance( 7, lengthof(_name_austrian_a5), seed)], last);
    00309     buf = strecpy(buf, _name_austrian_a6[SeedChance( 9, lengthof(_name_austrian_a6), seed)], last);
    00310     j = 1; // More likely to have a " an der " or " am "
    00311   } else {
    00312     /* Zell */
    00313     buf = strecpy(buf, _name_austrian_a4[SeedChance( 7, lengthof(_name_austrian_a4), seed)], last);
    00314   }
    00315
    00316   i = SeedChance(1, 6, seed);
    00317   if (i >= 4 - j) {
    00318     /* an der Donau (rivers) */
    00319     buf = strecpy(buf, _name_austrian_f1[SeedChance(4, lengthof(_name_austrian_f1), seed)], last);
    00320     buf = strecpy(buf, _name_austrian_f2[SeedChance(5, lengthof(_name_austrian_f2), seed)], last);
    00321   } else if (i >= 2 - j) {
    00322     /* am Dachstein (mountains) */
    00323     buf = strecpy(buf, _name_austrian_b1[SeedChance(4, lengthof(_name_austrian_b1), seed)], last);
    00324     buf = strecpy(buf, _name_austrian_b2[SeedChance(5, lengthof(_name_austrian_b2), seed)], last);
    00325   }
    00326
    00327   return buf;
    00328 }
    00329
    00330
    00337 static char *MakeGermanTownName(char *buf, const char *last, uint32 seed)
    00338 {
    00339   uint seed_derivative = SeedChance(7, 28, seed);
    00340
    00341   /* optional prefix */
    00342   if (seed_derivative == 12 || seed_derivative == 19) {
    00343     uint i = SeedChance(2, lengthof(_name_german_pre), seed);
    00344     buf = strecpy(buf, _name_german_pre[i], last);
    00345   }
    00346
    00347   /* mandatory middle segments including option of hardcoded name */
    00348   uint i = SeedChance(3, lengthof(_name_german_real) + lengthof(_name_german_1), seed);
    00349   if (i < lengthof(_name_german_real)) {
    00350     buf = strecpy(buf, _name_german_real[i], last);
    00351   } else {
    00352     buf = strecpy(buf, _name_german_1[i - lengthof(_name_german_real)], last);
    00353
    00354     i = SeedChance(5, lengthof(_name_german_2), seed);
    00355     buf = strecpy(buf, _name_german_2[i], last);
    00356   }
    00357
    00358   /* optional suffix */
    00359   if (seed_derivative == 24) {
    00360     i = SeedChance(9, lengthof(_name_german_4_an_der) + lengthof(_name_german_4_am), seed);
    00361     if (i < lengthof(_name_german_4_an_der)) {
    00362       buf = strecpy(buf, _name_german_3_an_der[0], last);
    00363       buf = strecpy(buf, _name_german_4_an_der[i], last);
    00364     } else {
    00365       buf = strecpy(buf, _name_german_3_am[0], last);
    00366       buf = strecpy(buf, _name_german_4_am[i - lengthof(_name_german_4_an_der)], last);
    00367     }
    00368   }
    00369
    00370   return buf;
    00371 }
    00372
    00373
    00380 static char *MakeSpanishTownName(char *buf, const char *last, uint32 seed)
    00381 {
    00382   return strecpy(buf, _name_spanish_real[SeedChance(0, lengthof(_name_spanish_real), seed)], last);
    00383 }
    00384
    00385
    00392 static char *MakeFrenchTownName(char *buf, const char *last, uint32 seed)
    00393 {
    00394   return strecpy(buf, _name_french_real[SeedChance(0, lengthof(_name_french_real), seed)], last);
    00395 }
    00396
    00397
    00404 static char *MakeSillyTownName(char *buf, const char *last, uint32 seed)
    00405 {
    00406   buf = strecpy(buf, _name_silly_1[SeedChance( 0, lengthof(_name_silly_1), seed)], last);
    00407   buf = strecpy(buf, _name_silly_2[SeedChance(16, lengthof(_name_silly_2), seed)], last);
    00408
    00409   return buf;
    00410 }
    00411
    00412
    00419 static char *MakeSwedishTownName(char *buf, const char *last, uint32 seed)
    00420 {
    00421   /* optional first segment */
    00422   int i = SeedChanceBias(0, lengthof(_name_swedish_1), seed, 50);
    00423   if (i >= 0) buf = strecpy(buf, _name_swedish_1[i], last);
    00424
    00425   /* mandatory middle segments including option of hardcoded name */
    00426   if (SeedChance(4, 5, seed) >= 3) {
    00427     buf = strecpy(buf, _name_swedish_2[SeedChance( 7, lengthof(_name_swedish_2), seed)], last);
    00428   } else {
    00429     buf = strecpy(buf, _name_swedish_2a[SeedChance( 7, lengthof(_name_swedish_2a), seed)], last);
    00430     buf = strecpy(buf, _name_swedish_2b[SeedChance(10, lengthof(_name_swedish_2b), seed)], last);
    00431     buf = strecpy(buf, _name_swedish_2c[SeedChance(13, lengthof(_name_swedish_2c), seed)], last);
    00432   }
    00433
    00434   buf = strecpy(buf, _name_swedish_3[SeedChance(16, lengthof(_name_swedish_3), seed)], last);
    00435
    00436   return buf;
    00437 }
    00438
    00439
    00446 static char *MakeDutchTownName(char *buf, const char *last, uint32 seed)
    00447 {
    00448   /* optional first segment */
    00449   int i = SeedChanceBias(0, lengthof(_name_dutch_1), seed, 50);
    00450   if (i >= 0) buf = strecpy(buf, _name_dutch_1[i], last);
    00451
    00452   /* mandatory middle segments including option of hardcoded name */
    00453   if (SeedChance(6, 9, seed) > 4) {
    00454     buf = strecpy(buf, _name_dutch_2[SeedChance( 9, lengthof(_name_dutch_2), seed)], last);
    00455   } else {
    00456     buf = strecpy(buf, _name_dutch_3[SeedChance( 9, lengthof(_name_dutch_3), seed)], last);
    00457     buf = strecpy(buf, _name_dutch_4[SeedChance(12, lengthof(_name_dutch_4), seed)], last);
    00458   }
    00459
    00460   buf = strecpy(buf, _name_dutch_5[SeedChance(15, lengthof(_name_dutch_5), seed)], last);
    00461
    00462   return buf;
    00463 }
    00464
    00465
    00472 static char *MakeFinnishTownName(char *buf, const char *last, uint32 seed)
    00473 {
    00474   char *orig = buf;
    00475
    00476   /* Select randomly if town name should consists of one or two parts. */
    00477   if (SeedChance(0, 15, seed) >= 10) {
    00478     return strecpy(buf, _name_finnish_real[SeedChance(2, lengthof(_name_finnish_real), seed)], last);
    00479   }
    00480
    00481   if (SeedChance(0, 15, seed) >= 5) {
    00482     /* A two-part name by combining one of _name_finnish_1 + "la"/"lä"
    00483      * The reason for not having the contents of _name_finnish_{1,2} in the same table is
    00484      * that the ones in _name_finnish_2 are not good for this purpose. */
    00485     uint sel = SeedChance( 0, lengthof(_name_finnish_1), seed);
    00486     buf = strecpy(buf, _name_finnish_1[sel], last);
    00487     char *end = buf - 1;
    00488     assert(end >= orig);
    00489     if (*end == 'i') *end = 'e';
    00490     if (strstr(orig, "a") != NULL || strstr(orig, "o") != NULL || strstr(orig, "u") != NULL ||
    00491         strstr(orig, "A") != NULL || strstr(orig, "O") != NULL || strstr(orig, "U")  != NULL) {
    00492       buf = strecpy(buf, "la", last);
    00493     } else {
    00494       buf = strecpy(buf, "l\xC3\xA4", last);
    00495     }
    00496     return buf;
    00497   }
    00498
    00499   /* A two-part name by combining one of _name_finnish_{1,2} + _name_finnish_3.
    00500    * Why aren't _name_finnish_{1,2} just one table? See above. */
    00501   uint sel = SeedChance(2, lengthof(_name_finnish_1) + lengthof(_name_finnish_2), seed);
    00502   if (sel >= lengthof(_name_finnish_1)) {
    00503     buf = strecpy(buf, _name_finnish_2[sel - lengthof(_name_finnish_1)], last);
    00504   } else {
    00505     buf = strecpy(buf, _name_finnish_1[sel], last);
    00506   }
    00507
    00508   buf = strecpy(buf, _name_finnish_3[SeedChance(10, lengthof(_name_finnish_3), seed)], last);
    00509
    00510   return buf;
    00511 }
    00512
    00513
    00520 static char *MakePolishTownName(char *buf, const char *last, uint32 seed)
    00521 {
    00522   /* optional first segment */
    00523   uint i = SeedChance(0,
    00524       lengthof(_name_polish_2_o) + lengthof(_name_polish_2_m) +
    00525       lengthof(_name_polish_2_f) + lengthof(_name_polish_2_n),
    00526       seed);
    00527   uint j = SeedChance(2, 20, seed);
    00528
    00529
    00530   if (i < lengthof(_name_polish_2_o)) {
    00531     return strecpy(buf, _name_polish_2_o[SeedChance(3, lengthof(_name_polish_2_o), seed)], last);
    00532   }
    00533
    00534   if (i < lengthof(_name_polish_2_m) + lengthof(_name_polish_2_o)) {
    00535     if (j < 4) {
    00536       buf = strecpy(buf, _name_polish_1_m[SeedChance(5, lengthof(_name_polish_1_m), seed)], last);
    00537     }
    00538
    00539     buf = strecpy(buf, _name_polish_2_m[SeedChance(7, lengthof(_name_polish_2_m), seed)], last);
    00540
    00541     if (j >= 4 && j < 16) {
    00542       buf = strecpy(buf, _name_polish_3_m[SeedChance(10, lengthof(_name_polish_3_m), seed)], last);
    00543     }
    00544
    00545     return buf;
    00546   }
    00547
    00548   if (i < lengthof(_name_polish_2_f) + lengthof(_name_polish_2_m) + lengthof(_name_polish_2_o)) {
    00549     if (j < 4) {
    00550       buf = strecpy(buf, _name_polish_1_f[SeedChance(5, lengthof(_name_polish_1_f), seed)], last);
    00551     }
    00552
    00553     buf = strecpy(buf, _name_polish_2_f[SeedChance(7, lengthof(_name_polish_2_f), seed)], last);
    00554
    00555     if (j >= 4 && j < 16) {
    00556       buf = strecpy(buf, _name_polish_3_f[SeedChance(10, lengthof(_name_polish_3_f), seed)], last);
    00557     }
    00558
    00559     return buf;
    00560   }
    00561
    00562   if (j < 4) {
    00563     buf = strecpy(buf, _name_polish_1_n[SeedChance(5, lengthof(_name_polish_1_n), seed)], last);
    00564   }
    00565
    00566   buf = strecpy(buf, _name_polish_2_n[SeedChance(7, lengthof(_name_polish_2_n), seed)], last);
    00567
    00568   if (j >= 4 && j < 16) {
    00569     buf = strecpy(buf, _name_polish_3_n[SeedChance(10, lengthof(_name_polish_3_n), seed)], last);
    00570   }
    00571
    00572   return buf;
    00573 }
    00574
    00575
    00582 static char *MakeCzechTownName(char *buf, const char *last, uint32 seed)
    00583 {
    00584   /* 1:3 chance to use a real name. */
    00585   if (SeedModChance(0, 4, seed) == 0) {
    00586     return strecpy(buf, _name_czech_real[SeedModChance(4, lengthof(_name_czech_real), seed)], last);
    00587   }
    00588
    00589   const char *orig = buf;
    00590
    00591   /* Probability of prefixes/suffixes
    00592    * 0..11 prefix, 12..13 prefix+suffix, 14..17 suffix, 18..31 nothing */
    00593   int prob_tails = SeedModChance(2, 32, seed);
    00594   bool do_prefix = prob_tails < 12;
    00595   bool do_suffix = prob_tails > 11 && prob_tails < 17;
    00596   bool dynamic_subst;
    00597
    00598   /* IDs of the respective parts */
    00599   int prefix = 0, ending = 0, suffix = 0;
    00600   uint postfix = 0;
    00601   uint stem;
    00602
    00603   /* The select criteria. */
    00604   CzechGender gender;
    00605   CzechChoose choose;
    00606   CzechAllow allow;
    00607
    00608   if (do_prefix) prefix = SeedModChance(5, lengthof(_name_czech_adj) * 12, seed) / 12;
    00609   if (do_suffix) suffix = SeedModChance(7, lengthof(_name_czech_suffix), seed);
    00610   /* 3:1 chance 3:1 to use dynamic substantive */
    00611   stem = SeedModChance(9,
    00612       lengthof(_name_czech_subst_full) + 3 * lengthof(_name_czech_subst_stem),
    00613       seed);
    00614   if (stem < lengthof(_name_czech_subst_full)) {
    00615     /* That was easy! */
    00616     dynamic_subst = false;
    00617     gender = _name_czech_subst_full[stem].gender;
    00618     choose = _name_czech_subst_full[stem].choose;
    00619     allow = _name_czech_subst_full[stem].allow;
    00620   } else {
    00621     unsigned int map[lengthof(_name_czech_subst_ending)];
    00622     int ending_start = -1, ending_stop = -1;
    00623
    00624     /* Load the substantive */
    00625     dynamic_subst = true;
    00626     stem -= lengthof(_name_czech_subst_full);
    00627     stem %= lengthof(_name_czech_subst_stem);
    00628     gender = _name_czech_subst_stem[stem].gender;
    00629     choose = _name_czech_subst_stem[stem].choose;
    00630     allow = _name_czech_subst_stem[stem].allow;
    00631
    00632     /* Load the postfix (1:1 chance that a postfix will be inserted) */
    00633     postfix = SeedModChance(14, lengthof(_name_czech_subst_postfix) * 2, seed);
    00634
    00635     if (choose & CZC_POSTFIX) {
    00636       /* Always get a real postfix. */
    00637       postfix %= lengthof(_name_czech_subst_postfix);
    00638     }
    00639     if (choose & CZC_NOPOSTFIX) {
    00640       /* Always drop a postfix. */
    00641       postfix += lengthof(_name_czech_subst_postfix);
    00642     }
    00643     if (postfix < lengthof(_name_czech_subst_postfix)) {
    00644       choose |= CZC_POSTFIX;
    00645     } else {
    00646       choose |= CZC_NOPOSTFIX;
    00647     }
    00648
    00649     /* Localize the array segment containing a good gender */
    00650     for (ending = 0; ending < (int)lengthof(_name_czech_subst_ending); ending++) {
    00651       const CzechNameSubst *e = &_name_czech_subst_ending[ending];
    00652
    00653       if (gender == CZG_FREE ||
    00654           (gender == CZG_NFREE && e->gender != CZG_SNEUT && e->gender != CZG_PNEUT) ||
    00655            gender == e->gender) {
    00656         if (ending_start < 0) {
    00657           ending_start = ending;
    00658         }
    00659       } else if (ending_start >= 0) {
    00660         ending_stop = ending - 1;
    00661         break;
    00662       }
    00663     }
    00664     if (ending_stop < 0) {
    00665       /* Whoa. All the endings matched. */
    00666       ending_stop = ending - 1;
    00667     }
    00668
    00669     /* Make a sequential map of the items with good mask */
    00670     size_t i = 0;
    00671     for (ending = ending_start; ending <= ending_stop; ending++) {
    00672       const CzechNameSubst *e = &_name_czech_subst_ending[ending];
    00673
    00674       if ((e->choose & choose) == choose && (e->allow & allow) != 0) {
    00675         map[i++] = ending;
    00676       }
    00677     }
    00678     assert(i > 0);
    00679
    00680     /* Load the ending */
    00681     ending = map[SeedModChance(16, (int)i, seed)];
    00682     /* Override possible CZG_*FREE; this must be a real gender,
    00683      * otherwise we get overflow when modifying the adjectivum. */
    00684     gender = _name_czech_subst_ending[ending].gender;
    00685     assert(gender != CZG_FREE && gender != CZG_NFREE);
    00686   }
    00687
    00688   if (do_prefix && (_name_czech_adj[prefix].choose & choose) != choose) {
    00689     /* Throw away non-matching prefix. */
    00690     do_prefix = false;
    00691   }
    00692
    00693   /* Now finally construct the name */
    00694   if (do_prefix) {
    00695     CzechPattern pattern = _name_czech_adj[prefix].pattern;
    00696
    00697     buf = strecpy(buf, _name_czech_adj[prefix].name, last);
    00698
    00699     char *endpos = buf - 1;
    00700     /* Find the first character in a UTF-8 sequence */
    00701     while (GB(*endpos, 6, 2) == 2) endpos--;
    00702
    00703     if (gender == CZG_SMASC && pattern == CZP_PRIVL) {
    00704       assert(endpos >= orig + 2);
    00705       /* -ovX -> -uv */
    00706       *(endpos - 2) = 'u';
    00707       assert(*(endpos - 1) == 'v');
    00708       *endpos = '\0';
    00709     } else {
    00710       assert(endpos >= orig);
    00711       endpos = strecpy(endpos, _name_czech_patmod[gender][pattern], last);
    00712     }
    00713
    00714     buf = strecpy(endpos, " ", last);
    00715   }
    00716
    00717   if (dynamic_subst) {
    00718     buf = strecpy(buf, _name_czech_subst_stem[stem].name, last);
    00719     if (postfix < lengthof(_name_czech_subst_postfix)) {
    00720       const char *poststr = _name_czech_subst_postfix[postfix];
    00721       const char *endstr = _name_czech_subst_ending[ending].name;
    00722
    00723       size_t postlen = strlen(poststr);
    00724       size_t endlen = strlen(endstr);
    00725       assert(postlen > 0 && endlen > 0);
    00726
    00727       /* Kill the "avava" and "Jananna"-like cases */
    00728       if (postlen < 2 || postlen > endlen ||
    00729           ((poststr[1] != 'v' || poststr[1] != endstr[1]) &&
    00730           poststr[2] != endstr[1])) {
    00731         buf = strecpy(buf, poststr, last);
    00732
    00733         /* k-i -> c-i, h-i -> z-i */
    00734         if (endstr[0] == 'i') {
    00735           switch (*(buf - 1)) {
    00736             case 'k': *(buf - 1) = 'c'; break;
    00737             case 'h': *(buf - 1) = 'z'; break;
    00738             default: break;
    00739           }
    00740         }
    00741       }
    00742     }
    00743     buf = strecpy(buf, _name_czech_subst_ending[ending].name, last);
    00744   } else {
    00745     buf = strecpy(buf, _name_czech_subst_full[stem].name, last);
    00746   }
    00747
    00748   if (do_suffix) {
    00749     buf = strecpy(buf, " ", last);
    00750     buf = strecpy(buf, _name_czech_suffix[suffix], last);
    00751   }
    00752
    00753   return buf;
    00754 }
    00755
    00756
    00763 static char *MakeRomanianTownName(char *buf, const char *last, uint32 seed)
    00764 {
    00765   return strecpy(buf, _name_romanian_real[SeedChance(0, lengthof(_name_romanian_real), seed)], last);
    00766 }
    00767
    00768
    00775 static char *MakeSlovakTownName(char *buf, const char *last, uint32 seed)
    00776 {
    00777   return strecpy(buf, _name_slovak_real[SeedChance(0, lengthof(_name_slovak_real), seed)], last);
    00778 }
    00779
    00780
    00787 static char *MakeNorwegianTownName(char *buf, const char *last, uint32 seed)
    00788 {
    00789   /* Use first 4 bit from seed to decide whether or not this town should
    00790    * have a real name 3/16 chance.  Bit 0-3 */
    00791   if (SeedChance(0, 15, seed) < 3) {
    00792     /* Use 7bit for the realname table index.  Bit 4-10 */
    00793     return strecpy(buf, _name_norwegian_real[SeedChance(4, lengthof(_name_norwegian_real), seed)], last);
    00794   }
    00795
    00796   /* Use 7bit for the first fake part.  Bit 4-10 */
    00797   buf = strecpy(buf, _name_norwegian_1[SeedChance(4, lengthof(_name_norwegian_1), seed)], last);
    00798   /* Use 7bit for the last fake part.  Bit 11-17 */
    00799   buf = strecpy(buf, _name_norwegian_2[SeedChance(11, lengthof(_name_norwegian_2), seed)], last);
    00800
    00801   return buf;
    00802 }
    00803
    00804
    00811 static char *MakeHungarianTownName(char *buf, const char *last, uint32 seed)
    00812 {
    00813   if (SeedChance(12, 15, seed) < 3) {
    00814     return strecpy(buf, _name_hungarian_real[SeedChance(0, lengthof(_name_hungarian_real), seed)], last);
    00815   }
    00816
    00817   /* optional first segment */
    00818   uint i = SeedChance(3, lengthof(_name_hungarian_1) * 3, seed);
    00819   if (i < lengthof(_name_hungarian_1)) buf = strecpy(buf, _name_hungarian_1[i], last);
    00820
    00821   /* mandatory middle segments */
    00822   buf = strecpy(buf, _name_hungarian_2[SeedChance(3, lengthof(_name_hungarian_2), seed)], last);
    00823   buf = strecpy(buf, _name_hungarian_3[SeedChance(6, lengthof(_name_hungarian_3), seed)], last);
    00824
    00825   /* optional last segment */
    00826   i = SeedChance(10, lengthof(_name_hungarian_4) * 3, seed);
    00827   if (i < lengthof(_name_hungarian_4)) {
    00828     buf = strecpy(buf, _name_hungarian_4[i], last);
    00829   }
    00830
    00831   return buf;
    00832 }
    00833
    00834
    00841 static char *MakeSwissTownName(char *buf, const char *last, uint32 seed)
    00842 {
    00843   return strecpy(buf, _name_swiss_real[SeedChance(0, lengthof(_name_swiss_real), seed)], last);
    00844 }
    00845
    00846
    00853 static char *MakeDanishTownName(char *buf, const char *last, uint32 seed)
    00854 {
    00855   /* optional first segment */
    00856   int i = SeedChanceBias(0, lengthof(_name_danish_1), seed, 50);
    00857   if (i >= 0) buf = strecpy(buf, _name_danish_1[i], last);
    00858
    00859   /* middle segments removed as this algorithm seems to create much more realistic names */
    00860   buf = strecpy(buf, _name_danish_2[SeedChance( 7, lengthof(_name_danish_2), seed)], last);
    00861   buf = strecpy(buf, _name_danish_3[SeedChance(16, lengthof(_name_danish_3), seed)], last);
    00862
    00863   return buf;
    00864 }
    00865
    00866
    00873 static char *MakeTurkishTownName(char *buf, const char *last, uint32 seed)
    00874 {
    00875   uint i = SeedModChance(0, 5, seed);
    00876
    00877   switch (i) {
    00878     case 0:
    00879       buf = strecpy(buf, _name_turkish_prefix[SeedModChance( 2, lengthof(_name_turkish_prefix), seed)], last);
    00880
    00881       /* middle segment */
    00882       buf = strecpy(buf, _name_turkish_middle[SeedModChance( 4, lengthof(_name_turkish_middle), seed)], last);
    00883
    00884       /* optional suffix */
    00885       if (SeedModChance(0, 7, seed) == 0) {
    00886         buf = strecpy(buf, _name_turkish_suffix[SeedModChance( 10, lengthof(_name_turkish_suffix), seed)], last);
    00887       }
    00888       break;
    00889
    00890     case 1: case 2:
    00891       buf = strecpy(buf, _name_turkish_prefix[SeedModChance( 2, lengthof(_name_turkish_prefix), seed)], last);
    00892       buf = strecpy(buf, _name_turkish_suffix[SeedModChance( 4, lengthof(_name_turkish_suffix), seed)], last);
    00893       break;
    00894
    00895     default:
    00896       buf = strecpy(buf, _name_turkish_real[SeedModChance( 4, lengthof(_name_turkish_real), seed)], last);
    00897       break;
    00898   }
    00899
    00900   return buf;
    00901 }
    00902
    00903
    00910 static char *MakeItalianTownName(char *buf, const char *last, uint32 seed)
    00911 {
    00912   if (SeedModChance(0, 6, seed) == 0) { // real city names
    00913     return strecpy(buf, _name_italian_real[SeedModChance(4, lengthof(_name_italian_real), seed)], last);
    00914   }
    00915
    00916   static const char * const mascul_femin_italian[] = {
    00917     "o",
    00918     "a",
    00919   };
    00920
    00921   if (SeedModChance(0, 8, seed) == 0) { // prefix
    00922     buf = strecpy(buf, _name_italian_pref[SeedModChance(11, lengthof(_name_italian_pref), seed)], last);
    00923   }
    00924
    00925   uint i = SeedChance(0, 2, seed);
    00926   if (i == 0) { // masculine form
    00927     buf = strecpy(buf, _name_italian_1m[SeedModChance(4, lengthof(_name_italian_1m), seed)], last);
    00928   } else { // feminine form
    00929     buf = strecpy(buf, _name_italian_1f[SeedModChance(4, lengthof(_name_italian_1f), seed)], last);
    00930   }
    00931
    00932   if (SeedModChance(3, 3, seed) == 0) {
    00933     buf = strecpy(buf, _name_italian_2[SeedModChance(11, lengthof(_name_italian_2), seed)], last);
    00934     buf = strecpy(buf, mascul_femin_italian[i], last);
    00935   } else {
    00936     buf = strecpy(buf, _name_italian_2i[SeedModChance(16, lengthof(_name_italian_2i), seed)], last);
    00937   }
    00938
    00939   if (SeedModChance(15, 4, seed) == 0) {
    00940     if (SeedModChance(5, 2, seed) == 0) { // generic suffix
    00941       buf = strecpy(buf, _name_italian_3[SeedModChance(4, lengthof(_name_italian_3), seed)], last);
    00942     } else { // river name suffix
    00943       buf = strecpy(buf, _name_italian_river1[SeedModChance(4, lengthof(_name_italian_river1), seed)], last);
    00944       buf = strecpy(buf, _name_italian_river2[SeedModChance(16, lengthof(_name_italian_river2), seed)], last);
    00945     }
    00946   }
    00947
    00948   return buf;
    00949 }
    00950
    00951
    00958 static char *MakeCatalanTownName(char *buf, const char *last, uint32 seed)
    00959 {
    00960   if (SeedModChance(0, 3, seed) == 0) { // real city names
    00961     return strecpy(buf, _name_catalan_real[SeedModChance(4, lengthof(_name_catalan_real), seed)], last);
    00962   }
    00963
    00964   if (SeedModChance(0, 2, seed) == 0) { // prefix
    00965     buf = strecpy(buf, _name_catalan_pref[SeedModChance(11, lengthof(_name_catalan_pref), seed)], last);
    00966   }
    00967
    00968   uint i = SeedChance(0, 2, seed);
    00969   if (i == 0) { // masculine form
    00970     buf = strecpy(buf, _name_catalan_1m[SeedModChance(4, lengthof(_name_catalan_1m), seed)], last);
    00971     buf = strecpy(buf, _name_catalan_2m[SeedModChance(11, lengthof(_name_catalan_2m), seed)], last);
    00972   } else { // feminine form
    00973     buf = strecpy(buf, _name_catalan_1f[SeedModChance(4, lengthof(_name_catalan_1f), seed)], last);
    00974     buf = strecpy(buf, _name_catalan_2f[SeedModChance(11, lengthof(_name_catalan_2f), seed)], last);
    00975   }
    00976
    00977   if (SeedModChance(15, 5, seed) == 0) {
    00978     if (SeedModChance(5, 2, seed) == 0) { // generic suffix
    00979       buf = strecpy(buf, _name_catalan_3[SeedModChance(4, lengthof(_name_catalan_3), seed)], last);
    00980     } else { // river name suffix
    00981       buf = strecpy(buf, _name_catalan_river1[SeedModChance(4, lengthof(_name_catalan_river1), seed)], last);
    00982     }
    00983   }
    00984
    00985   return buf;
    00986 }
    00987
    00988
    00989 typedef char *TownNameGenerator(char *buf, const char *last, uint32 seed);
    00990
    00992 struct TownNameGeneratorParams {
    00993   byte min;
    00994   TownNameGenerator *proc;
    00995 };
    00996
    00998 static const TownNameGeneratorParams _town_name_generators[] = {
    00999   {  4, MakeEnglishOriginalTownName},  // replaces first 4 characters of name
    01000   {  0, MakeFrenchTownName},
    01001   {  0, MakeGermanTownName},
    01002   {  4, MakeEnglishAdditionalTownName}, // replaces first 4 characters of name
    01003   {  0, MakeSpanishTownName},
    01004   {  0, MakeSillyTownName},
    01005   {  0, MakeSwedishTownName},
    01006   {  0, MakeDutchTownName},
    01007   {  8, MakeFinnishTownName}, // _name_finnish_1
    01008   {  0, MakePolishTownName},
    01009   {  0, MakeSlovakTownName},
    01010   {  0, MakeNorwegianTownName},
    01011   {  0, MakeHungarianTownName},
    01012   {  0, MakeAustrianTownName},
    01013   {  0, MakeRomanianTownName},
    01014   { 28, MakeCzechTownName}, // _name_czech_adj + _name_czech_patmod + 1 + _name_czech_subst_stem + _name_czech_subst_postfix
    01015   {  0, MakeSwissTownName},
    01016   {  0, MakeDanishTownName},
    01017   {  0, MakeTurkishTownName},
    01018   {  0, MakeItalianTownName},
    01019   {  0, MakeCatalanTownName},
    01020 };
    01021
    01022
    01031 char *GenerateTownNameString(char *buf, const char *last, size_t lang, uint32 seed)
    01032 {
    01033   assert(lang < lengthof(_town_name_generators));
    01034
    01035   /* Some generators need at least 9 bytes in buffer.  English generators need 5 for
    01036    * string replacing, others use constructions like strlen(buf)-3 and so on.
    01037    * Finnish generator needs to fit all strings from _name_finnish_1.
    01038    * Czech generator needs to fit almost whole town name...
    01039    * These would break. Using another temporary buffer results in ~40% slower code,
    01040    * so use it only when really needed. */
    01041   const TownNameGeneratorParams *par = &_town_name_generators[lang];
    01042   if (last >= buf + par->min) return par->proc(buf, last, seed);
    01043
    01044   char *buffer = AllocaM(char, par->min + 1);
    01045   par->proc(buffer, buffer + par->min, seed);
    01046
    01047   return strecpy(buf, buffer, last);
    01048 }