# namegen.cpp

Go to the documentation of this file.

    00001 /* $Id: namegen.cpp 15765 2009-03-18 19:50:34Z rubidium $ */
    00002
    00005 #include "stdafx.h"
    00006 #include "namegen_func.h"
    00007 #include "string_func.h"
    00008
    00009 #include "table/namegen.h"
    00010
    00011 static inline uint32 SeedChance(int shift_by, int max, uint32 seed)
    00012 {
    00013   return (GB(seed, shift_by, 16) * max) >> 16;
    00014 }
    00015
    00016 static inline uint32 SeedModChance(int shift_by, int max, uint32 seed)
    00017 {
    00018   /* This actually gives *MUCH* more even distribution of the values
    00019    * than SeedChance(), which is absolutely horrible in that. If
    00020    * you do not believe me, try with i.e. the Czech town names,
    00021    * compare the words (nicely visible on prefixes) generated by
    00022    * SeedChance() and SeedModChance(). Do not get dicouraged by the
    00023    * never-use-modulo myths, which hold true only for the linear
    00024    * congruential generators (and Random() isn't such a generator).
    00025    * --pasky
    00026    * TODO: Perhaps we should use it for all the name generators? --pasky */
    00027   return (seed >> shift_by) % max;
    00028 }
    00029
    00030 static inline int32 SeedChanceBias(int shift_by, int max, uint32 seed, int bias)
    00031 {
    00032   return SeedChance(shift_by, max + bias, seed) - bias;
    00033 }
    00034
    00035 static void ReplaceWords(const char *org, const char *rep, char *buf)
    00036 {
    00037   if (strncmp(buf, org, 4) == 0) strncpy(buf, rep, 4); // Safe as the string in buf is always more than 4 characters long.
    00038 }
    00039
    00040 static byte MakeEnglishOriginalTownName(char *buf, uint32 seed, const char *last)
    00041 {
    00042   int i;
    00043
    00044   /* null terminates the string for strcat */
    00045   strecpy(buf, "", last);
    00046
    00047   /* optional first segment */
    00048   i = SeedChanceBias(0, lengthof(_name_original_english_1), seed, 50);
    00049   if (i >= 0)
    00050     strecat(buf, _name_original_english_1[i], last);
    00051
    00052   /* mandatory middle segments */
    00053   strecat(buf, _name_original_english_2[SeedChance(4,  lengthof(_name_original_english_2), seed)], last);
    00054   strecat(buf, _name_original_english_3[SeedChance(7,  lengthof(_name_original_english_3), seed)], last);
    00055   strecat(buf, _name_original_english_4[SeedChance(10, lengthof(_name_original_english_4), seed)], last);
    00056   strecat(buf, _name_original_english_5[SeedChance(13, lengthof(_name_original_english_5), seed)], last);
    00057
    00058   /* optional last segment */
    00059   i = SeedChanceBias(15, lengthof(_name_original_english_6), seed, 60);
    00060   if (i >= 0)
    00061     strecat(buf, _name_original_english_6[i], last);
    00062
    00063   if (buf[0] == 'C' && (buf[1] == 'e' || buf[1] == 'i'))
    00064     buf[0] = 'K';
    00065
    00066   ReplaceWords("Cunt", "East", buf);
    00067   ReplaceWords("Slag", "Pits", buf);
    00068   ReplaceWords("Slut", "Edin", buf);
    00069   //ReplaceWords("Fart", "Boot", buf);
    00070   ReplaceWords("Drar", "Quar", buf);
    00071   ReplaceWords("Dreh", "Bash", buf);
    00072   ReplaceWords("Frar", "Shor", buf);
    00073   ReplaceWords("Grar", "Aber", buf);
    00074   ReplaceWords("Brar", "Over", buf);
    00075   ReplaceWords("Wrar", "Inve", buf);
    00076
    00077   return 0;
    00078 }
    00079
    00080
    00081 static byte MakeEnglishAdditionalTownName(char *buf, uint32 seed, const char *last)
    00082 {
    00083   int i;
    00084
    00085   /* null terminates the string for strcat */
    00086   strecpy(buf, "", last);
    00087
    00088   /* optional first segment */
    00089   i = SeedChanceBias(0, lengthof(_name_additional_english_prefix), seed, 50);
    00090   if (i >= 0)
    00091     strecat(buf, _name_additional_english_prefix[i], last);
    00092
    00093   if (SeedChance(3, 20, seed) >= 14) {
    00094     strecat(buf, _name_additional_english_1a[SeedChance(6, lengthof(_name_additional_english_1a), seed)], last);
    00095   } else {
    00096     strecat(buf, _name_additional_english_1b1[SeedChance(6, lengthof(_name_additional_english_1b1), seed)], last);
    00097     strecat(buf, _name_additional_english_1b2[SeedChance(9, lengthof(_name_additional_english_1b2), seed)], last);
    00098     if (SeedChance(11, 20, seed) >= 4) {
    00099       strecat(buf, _name_additional_english_1b3a[SeedChance(12, lengthof(_name_additional_english_1b3a), seed)], last);
    00100     } else {
    00101       strecat(buf, _name_additional_english_1b3b[SeedChance(12, lengthof(_name_additional_english_1b3b), seed)], last);
    00102     }
    00103   }
    00104
    00105   strecat(buf, _name_additional_english_2[SeedChance(14, lengthof(_name_additional_english_2), seed)], last);
    00106
    00107   /* optional last segment */
    00108   i = SeedChanceBias(15, lengthof(_name_additional_english_3), seed, 60);
    00109   if (i >= 0)
    00110     strecat(buf, _name_additional_english_3[i], last);
    00111
    00112   ReplaceWords("Cunt", "East", buf);
    00113   ReplaceWords("Slag", "Pits", buf);
    00114   ReplaceWords("Slut", "Edin", buf);
    00115   ReplaceWords("Fart", "Boot", buf);
    00116   ReplaceWords("Drar", "Quar", buf);
    00117   ReplaceWords("Dreh", "Bash", buf);
    00118   ReplaceWords("Frar", "Shor", buf);
    00119   ReplaceWords("Grar", "Aber", buf);
    00120   ReplaceWords("Brar", "Over", buf);
    00121   ReplaceWords("Wrar", "Stan", buf);
    00122
    00123   return 0;
    00124 }
    00125
    00126 static byte MakeAustrianTownName(char *buf, uint32 seed, const char *last)
    00127 {
    00128   int i, j = 0;
    00129   strecpy(buf, "", last);
    00130
    00131   /* Bad, Maria, Gross, ... */
    00132   i = SeedChanceBias(0, lengthof(_name_austrian_a1), seed, 15);
    00133   if (i >= 0) strecat(buf, _name_austrian_a1[i], last);
    00134
    00135   i = SeedChance(4, 6, seed);
    00136   if (i >= 4) {
    00137     /* Kaisers-kirchen */
    00138     strecat(buf, _name_austrian_a2[SeedChance( 7, lengthof(_name_austrian_a2), seed)], last);
    00139     strecat(buf, _name_austrian_a3[SeedChance(13, lengthof(_name_austrian_a3), seed)], last);
    00140   } else if (i >= 2) {
    00141     /* St. Johann */
    00142     strecat(buf, _name_austrian_a5[SeedChance( 7, lengthof(_name_austrian_a5), seed)], last);
    00143     strecat(buf, _name_austrian_a6[SeedChance( 9, lengthof(_name_austrian_a6), seed)], last);
    00144     j = 1; // More likely to have a " an der " or " am "
    00145   } else {
    00146     /* Zell */
    00147     strecat(buf, _name_austrian_a4[SeedChance( 7, lengthof(_name_austrian_a4), seed)], last);
    00148   }
    00149
    00150   i = SeedChance(1, 6, seed);
    00151   if (i >= 4 - j) {
    00152     /* an der Donau (rivers) */
    00153     strecat(buf, _name_austrian_f1[SeedChance(4, lengthof(_name_austrian_f1), seed)], last);
    00154     strecat(buf, _name_austrian_f2[SeedChance(5, lengthof(_name_austrian_f2), seed)], last);
    00155   } else if (i >= 2 - j) {
    00156     /* am Dachstein (mountains) */
    00157     strecat(buf, _name_austrian_b1[SeedChance(4, lengthof(_name_austrian_b1), seed)], last);
    00158     strecat(buf, _name_austrian_b2[SeedChance(5, lengthof(_name_austrian_b2), seed)], last);
    00159   }
    00160
    00161   return 0;
    00162 }
    00163
    00164 static byte MakeGermanTownName(char *buf, uint32 seed, const char *last)
    00165 {
    00166   uint i;
    00167   uint seed_derivative;
    00168
    00169   /* null terminates the string for strcat */
    00170   strecpy(buf, "", last);
    00171
    00172   seed_derivative = SeedChance(7, 28, seed);
    00173
    00174   /* optional prefix */
    00175   if (seed_derivative == 12 || seed_derivative == 19) {
    00176     i = SeedChance(2, lengthof(_name_german_pre), seed);
    00177     strecat(buf, _name_german_pre[i], last);
    00178   }
    00179
    00180   /* mandatory middle segments including option of hardcoded name */
    00181   i = SeedChance(3, lengthof(_name_german_real) + lengthof(_name_german_1), seed);
    00182   if (i < lengthof(_name_german_real)) {
    00183     strecat(buf, _name_german_real[i], last);
    00184   } else {
    00185     strecat(buf, _name_german_1[i - lengthof(_name_german_real)], last);
    00186
    00187     i = SeedChance(5, lengthof(_name_german_2), seed);
    00188     strecat(buf, _name_german_2[i], last);
    00189   }
    00190
    00191   /* optional suffix */
    00192   if (seed_derivative == 24) {
    00193     i = SeedChance(9,
    00194       lengthof(_name_german_4_an_der) + lengthof(_name_german_4_am), seed);
    00195     if (i < lengthof(_name_german_4_an_der)) {
    00196       strecat(buf, _name_german_3_an_der[0], last);
    00197       strecat(buf, _name_german_4_an_der[i], last);
    00198     } else {
    00199       strecat(buf, _name_german_3_am[0], last);
    00200       strecat(buf, _name_german_4_am[i - lengthof(_name_german_4_an_der)], last);
    00201     }
    00202   }
    00203   return 0;
    00204 }
    00205
    00206 static byte MakeSpanishTownName(char *buf, uint32 seed, const char *last)
    00207 {
    00208   strecpy(buf, _name_spanish_real[SeedChance(0, lengthof(_name_spanish_real), seed)], last);
    00209   return 0;
    00210 }
    00211
    00212 static byte MakeFrenchTownName(char *buf, uint32 seed, const char *last)
    00213 {
    00214   strecpy(buf, _name_french_real[SeedChance(0, lengthof(_name_french_real), seed)], last);
    00215   return 0;
    00216 }
    00217
    00218 static byte MakeSillyTownName(char *buf, uint32 seed, const char *last)
    00219 {
    00220   strecpy(buf, _name_silly_1[SeedChance( 0, lengthof(_name_silly_1), seed)], last);
    00221   strecat(buf, _name_silly_2[SeedChance(16, lengthof(_name_silly_2), seed)], last);
    00222   return 0;
    00223 }
    00224
    00225 static byte MakeSwedishTownName(char *buf, uint32 seed, const char *last)
    00226 {
    00227   int i;
    00228
    00229   /* null terminates the string for strcat */
    00230   strecpy(buf, "", last);
    00231
    00232   /* optional first segment */
    00233   i = SeedChanceBias(0, lengthof(_name_swedish_1), seed, 50);
    00234   if (i >= 0)
    00235     strecat(buf, _name_swedish_1[i], last);
    00236
    00237   /* mandatory middle segments including option of hardcoded name */
    00238   if (SeedChance(4, 5, seed) >= 3) {
    00239     strecat(buf, _name_swedish_2[SeedChance( 7, lengthof(_name_swedish_2), seed)], last);
    00240   } else {
    00241     strecat(buf, _name_swedish_2a[SeedChance( 7, lengthof(_name_swedish_2a), seed)], last);
    00242     strecat(buf, _name_swedish_2b[SeedChance(10, lengthof(_name_swedish_2b), seed)], last);
    00243     strecat(buf, _name_swedish_2c[SeedChance(13, lengthof(_name_swedish_2c), seed)], last);
    00244   }
    00245
    00246   strecat(buf, _name_swedish_3[SeedChance(16, lengthof(_name_swedish_3), seed)], last);
    00247
    00248   return 0;
    00249 }
    00250
    00251 static byte MakeDutchTownName(char *buf, uint32 seed, const char *last)
    00252 {
    00253   int i;
    00254
    00255   /* null terminates the string for strcat */
    00256   strecpy(buf, "", last);
    00257
    00258   /* optional first segment */
    00259   i = SeedChanceBias(0, lengthof(_name_dutch_1), seed, 50);
    00260   if (i >= 0)
    00261     strecat(buf, _name_dutch_1[i], last);
    00262
    00263   /* mandatory middle segments including option of hardcoded name */
    00264   if (SeedChance(6, 9, seed) > 4) {
    00265     strecat(buf, _name_dutch_2[SeedChance( 9, lengthof(_name_dutch_2), seed)], last);
    00266   } else {
    00267     strecat(buf, _name_dutch_3[SeedChance( 9, lengthof(_name_dutch_3), seed)], last);
    00268     strecat(buf, _name_dutch_4[SeedChance(12, lengthof(_name_dutch_4), seed)], last);
    00269   }
    00270   strecat(buf, _name_dutch_5[SeedChance(15, lengthof(_name_dutch_5), seed)], last);
    00271
    00272   return 0;
    00273 }
    00274
    00275 static byte MakeFinnishTownName(char *buf, uint32 seed, const char *last)
    00276 {
    00277   /* null terminates the string for strcat */
    00278   strecpy(buf, "", last);
    00279
    00280   /* Select randomly if town name should consists of one or two parts. */
    00281   if (SeedChance(0, 15, seed) >= 10) {
    00282     strecat(buf, _name_finnish_real[SeedChance(2, lengthof(_name_finnish_real), seed)], last);
    00283   } else if (SeedChance(0, 15, seed) >= 5) {
    00284     /* A two-part name by combining one of _name_finnish_1 + "la"/"lä"
    00285      * The reason for not having the contents of _name_finnish_{1,2} in the same table is
    00286      * that the ones in _name_finnish_2 are not good for this purpose. */
    00287     uint sel = SeedChance( 0, lengthof(_name_finnish_1), seed);
    00288     char *end;
    00289     strecat(buf, _name_finnish_1[sel], last);
    00290     end = &buf[strlen(buf)-1];
    00291     if (*end == 'i')
    00292       *end = 'e';
    00293     if (strstr(buf, "a") || strstr(buf, "o") || strstr(buf, "u") ||
    00294       strstr(buf, "A") || strstr(buf, "O") || strstr(buf, "U"))
    00295     {
    00296       strecat(buf, "la", last);
    00297     } else {
    00298       strecat(buf, "l\xC3\xA4", last);
    00299     }
    00300   } else {
    00301     /* A two-part name by combining one of _name_finnish_{1,2} + _name_finnish_3.
    00302      * Why aren't _name_finnish_{1,2} just one table? See above. */
    00303     uint sel = SeedChance(2,
    00304       lengthof(_name_finnish_1) + lengthof(_name_finnish_2), seed);
    00305     if (sel >= lengthof(_name_finnish_1)) {
    00306       strecat(buf, _name_finnish_2[sel - lengthof(_name_finnish_1)], last);
    00307     } else {
    00308       strecat(buf, _name_finnish_1[sel], last);
    00309     }
    00310     strecat(buf, _name_finnish_3[SeedChance(10, lengthof(_name_finnish_3), seed)], last);
    00311   }
    00312
    00313   return 0;
    00314 }
    00315
    00316 static byte MakePolishTownName(char *buf, uint32 seed, const char *last)
    00317 {
    00318   uint i;
    00319   uint j;
    00320
    00321   /* null terminates the string for strcat */
    00322   strecpy(buf, "", last);
    00323
    00324   /* optional first segment */
    00325   i = SeedChance(0,
    00326     lengthof(_name_polish_2_o) + lengthof(_name_polish_2_m) +
    00327     lengthof(_name_polish_2_f) + lengthof(_name_polish_2_n),
    00328     seed);
    00329   j = SeedChance(2, 20, seed);
    00330
    00331
    00332   if (i < lengthof(_name_polish_2_o)) {
    00333     strecat(buf, _name_polish_2_o[SeedChance(3, lengthof(_name_polish_2_o), seed)], last);
    00334   } else if (i < lengthof(_name_polish_2_m) + lengthof(_name_polish_2_o)) {
    00335     if (j < 4)
    00336       strecat(buf, _name_polish_1_m[SeedChance(5, lengthof(_name_polish_1_m), seed)], last);
    00337
    00338     strecat(buf, _name_polish_2_m[SeedChance(7, lengthof(_name_polish_2_m), seed)], last);
    00339
    00340     if (j >= 4 && j < 16)
    00341       strecat(buf, _name_polish_3_m[SeedChance(10, lengthof(_name_polish_3_m), seed)], last);
    00342   } else if (i < lengthof(_name_polish_2_f) + lengthof(_name_polish_2_m) + lengthof(_name_polish_2_o)) {
    00343     if (j < 4)
    00344       strecat(buf, _name_polish_1_f[SeedChance(5, lengthof(_name_polish_1_f), seed)], last);
    00345
    00346     strecat(buf, _name_polish_2_f[SeedChance(7, lengthof(_name_polish_2_f), seed)], last);
    00347
    00348     if (j >= 4 && j < 16)
    00349       strecat(buf, _name_polish_3_f[SeedChance(10, lengthof(_name_polish_3_f), seed)], last);
    00350   } else {
    00351     if (j < 4)
    00352       strecat(buf, _name_polish_1_n[SeedChance(5, lengthof(_name_polish_1_n), seed)], last);
    00353
    00354     strecat(buf, _name_polish_2_n[SeedChance(7, lengthof(_name_polish_2_n), seed)], last);
    00355
    00356     if (j >= 4 && j < 16)
    00357       strecat(buf, _name_polish_3_n[SeedChance(10, lengthof(_name_polish_3_n), seed)], last);
    00358   }
    00359   return 0;
    00360 }
    00361
    00362 static byte MakeCzechTownName(char *buf, uint32 seed, const char *last)
    00363 {
    00364   /* Probability of prefixes/suffixes
    00365    * 0..11 prefix, 12..13 prefix+suffix, 14..17 suffix, 18..31 nothing */
    00366   int prob_tails;
    00367   bool do_prefix, do_suffix, dynamic_subst;
    00368   /* IDs of the respective parts */
    00369   int prefix = 0, ending = 0, suffix = 0;
    00370   uint postfix = 0;
    00371   uint stem;
    00372   /* The select criteria. */
    00373   CzechGender gender;
    00374   CzechChoose choose;
    00375   CzechAllow allow;
    00376
    00377   /* 1:3 chance to use a real name. */
    00378   if (SeedModChance(0, 4, seed) == 0) {
    00379     strecpy(buf, _name_czech_real[SeedModChance(4, lengthof(_name_czech_real), seed)], last);
    00380     return 0;
    00381   }
    00382
    00383   /* NUL terminates the string for strcat() */
    00384   strecpy(buf, "", last);
    00385
    00386   prob_tails = SeedModChance(2, 32, seed);
    00387   do_prefix = prob_tails < 12;
    00388   do_suffix = prob_tails > 11 && prob_tails < 17;
    00389
    00390   if (do_prefix) prefix = SeedModChance(5, lengthof(_name_czech_adj) * 12, seed) / 12;
    00391   if (do_suffix) suffix = SeedModChance(7, lengthof(_name_czech_suffix), seed);
    00392   /* 3:1 chance 3:1 to use dynamic substantive */
    00393   stem = SeedModChance(9,
    00394     lengthof(_name_czech_subst_full) + 3 * lengthof(_name_czech_subst_stem),
    00395     seed);
    00396   if (stem < lengthof(_name_czech_subst_full)) {
    00397     /* That was easy! */
    00398     dynamic_subst = false;
    00399     gender = _name_czech_subst_full[stem].gender;
    00400     choose = _name_czech_subst_full[stem].choose;
    00401     allow = _name_czech_subst_full[stem].allow;
    00402   } else {
    00403     unsigned int map[lengthof(_name_czech_subst_ending)];
    00404     int ending_start = -1, ending_stop = -1;
    00405     int i;
    00406
    00407     /* Load the substantive */
    00408     dynamic_subst = true;
    00409     stem -= lengthof(_name_czech_subst_full);
    00410     stem %= lengthof(_name_czech_subst_stem);
    00411     gender = _name_czech_subst_stem[stem].gender;
    00412     choose = _name_czech_subst_stem[stem].choose;
    00413     allow = _name_czech_subst_stem[stem].allow;
    00414
    00415     /* Load the postfix (1:1 chance that a postfix will be inserted) */
    00416     postfix = SeedModChance(14, lengthof(_name_czech_subst_postfix) * 2, seed);
    00417
    00418     if (choose & CZC_POSTFIX) {
    00419       /* Always get a real postfix. */
    00420       postfix %= lengthof(_name_czech_subst_postfix);
    00421     }
    00422     if (choose & CZC_NOPOSTFIX) {
    00423       /* Always drop a postfix. */
    00424       postfix += lengthof(_name_czech_subst_postfix);
    00425     }
    00426     if (postfix < lengthof(_name_czech_subst_postfix)) {
    00427       choose |= CZC_POSTFIX;
    00428     } else {
    00429       choose |= CZC_NOPOSTFIX;
    00430     }
    00431
    00432     /* Localize the array segment containing a good gender */
    00433     for (ending = 0; ending < (int) lengthof(_name_czech_subst_ending); ending++) {
    00434       const CzechNameSubst *e = &_name_czech_subst_ending[ending];
    00435
    00436       if (gender == CZG_FREE ||
    00437           (gender == CZG_NFREE && e->gender != CZG_SNEUT && e->gender != CZG_PNEUT) ||
    00438           gender == e->gender) {
    00439         if (ending_start < 0)
    00440           ending_start = ending;
    00441
    00442       } else if (ending_start >= 0) {
    00443         ending_stop = ending - 1;
    00444         break;
    00445       }
    00446     }
    00447     if (ending_stop < 0) {
    00448       /* Whoa. All the endings matched. */
    00449       ending_stop = ending - 1;
    00450     }
    00451
    00452     /* Make a sequential map of the items with good mask */
    00453     i = 0;
    00454     for (ending = ending_start; ending <= ending_stop; ending++) {
    00455       const CzechNameSubst *e = &_name_czech_subst_ending[ending];
    00456
    00457       if ((e->choose & choose) == choose && (e->allow & allow) != 0)
    00458         map[i++] = ending;
    00459     }
    00460     assert(i > 0);
    00461
    00462     /* Load the ending */
    00463     ending = map[SeedModChance(16, i, seed)];
    00464     /* Override possible CZG_*FREE; this must be a real gender,
    00465      * otherwise we get overflow when modifying the adjectivum. */
    00466     gender = _name_czech_subst_ending[ending].gender;
    00467     assert(gender != CZG_FREE && gender != CZG_NFREE);
    00468   }
    00469
    00470   if (do_prefix && (_name_czech_adj[prefix].choose & choose) != choose) {
    00471     /* Throw away non-matching prefix. */
    00472     do_prefix = false;
    00473   }
    00474
    00475   /* Now finally construct the name */
    00476
    00477   if (do_prefix) {
    00478     CzechPattern pattern = _name_czech_adj[prefix].pattern;
    00479     size_t endpos;
    00480
    00481     strecat(buf, _name_czech_adj[prefix].name, last);
    00482     endpos = strlen(buf) - 1;
    00483     /* Find the first character in a UTF-8 sequence */
    00484     while (GB(buf[endpos], 6, 2) == 2) endpos--;
    00485     if (gender == CZG_SMASC && pattern == CZP_PRIVL) {
    00486       /* -ovX -> -uv */
    00487       buf[endpos - 2] = 'u';
    00488       assert(buf[endpos - 1] == 'v');
    00489       buf[endpos] = '\0';
    00490     } else {
    00491       strecpy(buf + endpos, _name_czech_patmod[gender][pattern], last);
    00492     }
    00493
    00494     strecat(buf, " ", last);
    00495   }
    00496
    00497   if (dynamic_subst) {
    00498     strecat(buf, _name_czech_subst_stem[stem].name, last);
    00499     if (postfix < lengthof(_name_czech_subst_postfix)) {
    00500       const char *poststr = _name_czech_subst_postfix[postfix];
    00501       const char *endstr = _name_czech_subst_ending[ending].name;
    00502       size_t postlen, endlen;
    00503
    00504       postlen = strlen(poststr);
    00505       endlen = strlen(endstr);
    00506       assert(postlen > 0 && endlen > 0);
    00507
    00508       /* Kill the "avava" and "Jananna"-like cases */
    00509       if (postlen < 2 || postlen > endlen || (
    00510             (poststr[1] != 'v' || poststr[1] != endstr[1]) &&
    00511             poststr[2] != endstr[1])
    00512           ) {
    00513         size_t buflen;
    00514         strecat(buf, poststr, last);
    00515         buflen = strlen(buf);
    00516
    00517         /* k-i -> c-i, h-i -> z-i */
    00518         if (endstr[0] == 'i') {
    00519           switch (buf[buflen - 1]) {
    00520             case 'k': buf[buflen - 1] = 'c'; break;
    00521             case 'h': buf[buflen - 1] = 'z'; break;
    00522             default: break;
    00523           }
    00524         }
    00525       }
    00526     }
    00527     strecat(buf, _name_czech_subst_ending[ending].name, last);
    00528   } else {
    00529     strecat(buf, _name_czech_subst_full[stem].name, last);
    00530   }
    00531
    00532   if (do_suffix) {
    00533     strecat(buf, " ", last);
    00534     strecat(buf, _name_czech_suffix[suffix], last);
    00535   }
    00536
    00537   return 0;
    00538 }
    00539
    00540 static byte MakeRomanianTownName(char *buf, uint32 seed, const char *last)
    00541 {
    00542   strecpy(buf, _name_romanian_real[SeedChance(0, lengthof(_name_romanian_real), seed)], last);
    00543   return 0;
    00544 }
    00545
    00546 static byte MakeSlovakTownName(char *buf, uint32 seed, const char *last)
    00547 {
    00548   strecpy(buf, _name_slovak_real[SeedChance(0, lengthof(_name_slovak_real), seed)], last);
    00549   return 0;
    00550 }
    00551
    00552 static byte MakeNorwegianTownName(char *buf, uint32 seed, const char *last)
    00553 {
    00554   strecpy(buf, "", last);
    00555
    00556   /* Use first 4 bit from seed to decide whether or not this town should
    00557    * have a real name 3/16 chance.  Bit 0-3 */
    00558   if (SeedChance(0, 15, seed) < 3) {
    00559     /* Use 7bit for the realname table index.  Bit 4-10 */
    00560     strecat(buf, _name_norwegian_real[SeedChance(4, lengthof(_name_norwegian_real), seed)], last);
    00561   } else {
    00562     /* Use 7bit for the first fake part.  Bit 4-10 */
    00563     strecat(buf, _name_norwegian_1[SeedChance(4, lengthof(_name_norwegian_1), seed)], last);
    00564     /* Use 7bit for the last fake part.  Bit 11-17 */
    00565     strecat(buf, _name_norwegian_2[SeedChance(11, lengthof(_name_norwegian_2), seed)], last);
    00566   }
    00567
    00568   return 0;
    00569 }
    00570
    00571 static byte MakeHungarianTownName(char *buf, uint32 seed, const char *last)
    00572 {
    00573   uint i;
    00574
    00575   /* null terminates the string for strcat */
    00576   strecpy(buf, "", last);
    00577
    00578   if (SeedChance(12, 15, seed) < 3) {
    00579     strecat(buf, _name_hungarian_real[SeedChance(0, lengthof(_name_hungarian_real), seed)], last);
    00580   } else {
    00581     /* optional first segment */
    00582     i = SeedChance(3, lengthof(_name_hungarian_1) * 3, seed);
    00583     if (i < lengthof(_name_hungarian_1))
    00584       strecat(buf, _name_hungarian_1[i], last);
    00585
    00586     /* mandatory middle segments */
    00587     strecat(buf, _name_hungarian_2[SeedChance(3, lengthof(_name_hungarian_2), seed)], last);
    00588     strecat(buf, _name_hungarian_3[SeedChance(6, lengthof(_name_hungarian_3), seed)], last);
    00589
    00590     /* optional last segment */
    00591     i = SeedChance(10, lengthof(_name_hungarian_4) * 3, seed);
    00592     if (i < lengthof(_name_hungarian_4)) {
    00593       strecat(buf, _name_hungarian_4[i], last);
    00594     }
    00595   }
    00596
    00597   return 0;
    00598 }
    00599
    00600 static byte MakeSwissTownName(char *buf, uint32 seed, const char *last)
    00601 {
    00602   strecpy(buf, _name_swiss_real[SeedChance(0, lengthof(_name_swiss_real), seed)], last);
    00603   return 0;
    00604 }
    00605
    00606 static byte MakeDanishTownName(char *buf, uint32 seed, const char *last)
    00607 {
    00608   int i;
    00609
    00610   /* null terminates the string for strcat */
    00611   strecpy(buf, "", last);
    00612
    00613   /* optional first segment */
    00614   i = SeedChanceBias(0, lengthof(_name_danish_1), seed, 50);
    00615   if (i >= 0)
    00616     strecat(buf, _name_danish_1[i], last);
    00617
    00618   /* middle segments removed as this algorithm seems to create much more realistic names */
    00619   strecat(buf, _name_danish_2[SeedChance( 7, lengthof(_name_danish_2), seed)], last);
    00620   strecat(buf, _name_danish_3[SeedChance(16, lengthof(_name_danish_3), seed)], last);
    00621
    00622   return 0;
    00623 }
    00624
    00625 static byte MakeTurkishTownName(char *buf, uint32 seed, const char *last)
    00626 {
    00627   uint i;
    00628
    00629   /* null terminates the string for strcat */
    00630   strecpy(buf, "", last);
    00631
    00632   if ((i = SeedModChance(0, 5, seed)) == 0) {
    00633     strecat(buf, _name_turkish_prefix[SeedModChance( 2, lengthof(_name_turkish_prefix), seed)], last);
    00634
    00635     /* middle segment */
    00636     strecat(buf, _name_turkish_middle[SeedModChance( 4, lengthof(_name_turkish_middle), seed)], last);
    00637
    00638     /* optional suffix */
    00639     if (SeedModChance(0, 7, seed) == 0) {
    00640       strecat(buf, _name_turkish_suffix[SeedModChance( 10, lengthof(_name_turkish_suffix), seed)], last);
    00641     }
    00642   } else {
    00643     if (i == 1 || i == 2) {
    00644       strecat(buf, _name_turkish_prefix[SeedModChance( 2, lengthof(_name_turkish_prefix), seed)], last);
    00645       strecat(buf, _name_turkish_suffix[SeedModChance( 4, lengthof(_name_turkish_suffix), seed)], last);
    00646     } else {
    00647       strecat(buf, _name_turkish_real[SeedModChance( 4, lengthof(_name_turkish_real), seed)], last);
    00648     }
    00649   }
    00650   return 0;
    00651 }
    00652
    00653 static const char *mascul_femin_italian[] = {
    00654   "o",
    00655   "a",
    00656 };
    00657
    00658 static byte MakeItalianTownName(char *buf, uint32 seed, const char *last)
    00659 {
    00660   strecpy(buf, "", last);
    00661
    00662   if (SeedModChance(0, 6, seed) == 0) { // real city names
    00663     strecat(buf, _name_italian_real[SeedModChance(4, lengthof(_name_italian_real), seed)], last);
    00664   } else {
    00665     uint i;
    00666
    00667     if (SeedModChance(0, 8, seed) == 0) { // prefix
    00668       strecat(buf, _name_italian_pref[SeedModChance(11, lengthof(_name_italian_pref), seed)], last);
    00669     }
    00670
    00671     i = SeedChance(0, 2, seed);
    00672     if (i == 0) { // masculine form
    00673       strecat(buf, _name_italian_1m[SeedModChance(4, lengthof(_name_italian_1m), seed)], last);
    00674     } else { // feminine form
    00675       strecat(buf, _name_italian_1f[SeedModChance(4, lengthof(_name_italian_1f), seed)], last);
    00676     }
    00677
    00678     if (SeedModChance(3, 3, seed) == 0) {
    00679       strecat(buf, _name_italian_2[SeedModChance(11, lengthof(_name_italian_2), seed)], last);
    00680       strecat(buf, mascul_femin_italian[i], last);
    00681     } else {
    00682       strecat(buf, _name_italian_2i[SeedModChance(16, lengthof(_name_italian_2i), seed)], last);
    00683     }
    00684
    00685     if (SeedModChance(15, 4, seed) == 0) {
    00686       if (SeedModChance(5, 2, seed) == 0) { // generic suffix
    00687         strecat(buf, _name_italian_3[SeedModChance(4, lengthof(_name_italian_3), seed)], last);
    00688       } else { // river name suffix
    00689         strecat(buf, _name_italian_river1[SeedModChance(4, lengthof(_name_italian_river1), seed)], last);
    00690         strecat(buf, _name_italian_river2[SeedModChance(16, lengthof(_name_italian_river2), seed)], last);
    00691       }
    00692     }
    00693   }
    00694
    00695   return 0;
    00696 }
    00697
    00698 static byte MakeCatalanTownName(char *buf, uint32 seed, const char *last)
    00699 {
    00700   strecpy(buf, "", last);
    00701
    00702   if (SeedModChance(0, 3, seed) == 0) { // real city names
    00703     strecat(buf, _name_catalan_real[SeedModChance(4, lengthof(_name_catalan_real), seed)], last);
    00704   } else {
    00705     uint i;
    00706
    00707     if (SeedModChance(0, 2, seed) == 0) { // prefix
    00708       strecat(buf, _name_catalan_pref[SeedModChance(11, lengthof(_name_catalan_pref), seed)], last);
    00709     }
    00710
    00711     i = SeedChance(0, 2, seed);
    00712     if (i == 0) { // masculine form
    00713       strecat(buf, _name_catalan_1m[SeedModChance(4, lengthof(_name_catalan_1m), seed)], last);
    00714       strecat(buf, _name_catalan_2m[SeedModChance(11, lengthof(_name_catalan_2m), seed)], last);
    00715     } else { // feminine form
    00716       strecat(buf, _name_catalan_1f[SeedModChance(4, lengthof(_name_catalan_1f), seed)], last);
    00717       strecat(buf, _name_catalan_2f[SeedModChance(11, lengthof(_name_catalan_2f), seed)], last);
    00718     }
    00719
    00720
    00721     if (SeedModChance(15, 5, seed) == 0) {
    00722       if (SeedModChance(5, 2, seed) == 0) { // generic suffix
    00723         strecat(buf, _name_catalan_3[SeedModChance(4, lengthof(_name_catalan_3), seed)], last);
    00724       } else { // river name suffix
    00725         strecat(buf, _name_catalan_river1[SeedModChance(4, lengthof(_name_catalan_river1), seed)], last);
    00726       }
    00727     }
    00728   }
    00729
    00730   return 0;
    00731 }
    00732
    00733
    00734
    00735 TownNameGenerator * const _town_name_generators[] =
    00736 {
    00737   MakeEnglishOriginalTownName,
    00738   MakeFrenchTownName,
    00739   MakeGermanTownName,
    00740   MakeEnglishAdditionalTownName,
    00741   MakeSpanishTownName,
    00742   MakeSillyTownName,
    00743   MakeSwedishTownName,
    00744   MakeDutchTownName,
    00745   MakeFinnishTownName,
    00746   MakePolishTownName,
    00747   MakeSlovakTownName,
    00748   MakeNorwegianTownName,
    00749   MakeHungarianTownName,
    00750   MakeAustrianTownName,
    00751   MakeRomanianTownName,
    00752   MakeCzechTownName,
    00753   MakeSwissTownName,
    00754   MakeDanishTownName,
    00755   MakeTurkishTownName,
    00756   MakeItalianTownName,
    00757   MakeCatalanTownName,
    00758 };