Fix: server menu tooltip shouldn't show language info (#12955)
[openttd-github.git] / src / townname.cpp
blob1a1e16b4c02804d7640107731abdf704e84d778c
1 /*
2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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/>.
6 */
8 /** @file townname.cpp %Town name generators. */
10 #include "stdafx.h"
11 #include "string_func.h"
12 #include "townname_type.h"
13 #include "town.h"
14 #include "strings_func.h"
15 #include "core/random_func.hpp"
16 #include "genworld.h"
17 #include "gfx_layout.h"
18 #include "strings_internal.h"
20 #include "table/townname.h"
22 #include "safeguards.h"
25 /**
26 * Initializes this struct from town data
27 * @param t town for which we will be printing name later
29 TownNameParams::TownNameParams(const Town *t) :
30 grfid(t->townnamegrfid), // by default, use supplied data
31 type(t->townnametype)
33 if (t->townnamegrfid != 0 && GetGRFTownName(t->townnamegrfid) == nullptr) {
34 /* Fallback to english original */
35 this->grfid = 0;
36 this->type = SPECSTR_TOWNNAME_ENGLISH;
37 return;
42 /**
43 * Fills builder with specified town name.
44 * @param builder The string builder.
45 * @param par Town name parameters.
46 * @param townnameparts 'Encoded' town name.
48 static void GetTownName(StringBuilder &builder, const TownNameParams *par, uint32_t townnameparts)
50 if (par->grfid == 0) {
51 auto tmp_params = MakeParameters(townnameparts);
52 GetStringWithArgs(builder, par->type, tmp_params);
53 return;
56 GRFTownNameGenerate(builder, par->grfid, par->type, townnameparts);
59 /**
60 * Get the town name for the given parameters and parts.
61 * @param par Town name parameters.
62 * @param townnameparts 'Encoded' town name.
63 * @return The town name.
65 std::string GetTownName(const TownNameParams *par, uint32_t townnameparts)
67 std::string result;
68 StringBuilder builder(result);
69 GetTownName(builder, par, townnameparts);
70 return result;
73 /**
74 * Fills builder with town's name.
75 * @param builder String builder.
76 * @param t The town to get the name from.
78 void GetTownName(StringBuilder &builder, const Town *t)
80 TownNameParams par(t);
81 GetTownName(builder, &par, t->townnameparts);
84 /**
85 * Get the name of the given town.
86 * @param t The town to get the name for.
87 * @return The town name.
89 std::string GetTownName(const Town *t)
91 TownNameParams par(t);
92 return GetTownName(&par, t->townnameparts);
96 /**
97 * Verifies the town name is valid and unique.
98 * @param r random bits
99 * @param par town name parameters
100 * @param town_names if a name is generated, check its uniqueness with the set
101 * @return true iff name is valid and unique
103 bool VerifyTownName(uint32_t r, const TownNameParams *par, TownNames *town_names)
105 std::string name = GetTownName(par, r);
107 /* Check size and width */
108 if (Utf8StringLength(name) >= MAX_LENGTH_TOWN_NAME_CHARS) return false;
110 if (town_names != nullptr) {
111 if (town_names->find(name) != town_names->end()) return false;
112 town_names->insert(name);
113 } else {
114 for (const Town *t : Town::Iterate()) {
115 /* We can't just compare the numbers since
116 * several numbers may map to a single name. */
117 if (t->name.empty()) {
118 if (name == GetTownName(t)) return false;
119 } else {
120 if (name == t->name) return false;
125 return true;
130 * Generates valid town name.
131 * @param randomizer the source of random data for generating the name
132 * @param townnameparts if a name is generated, it's stored there
133 * @param town_names if a name is generated, check its uniqueness with the set
134 * @return true iff a name was generated
136 bool GenerateTownName(Randomizer &randomizer, uint32_t *townnameparts, TownNames *town_names)
138 TownNameParams par(_settings_game.game_creation.town_name);
140 /* This function is called very often without entering the gameloop
141 * in between. So reset layout cache to prevent it from growing too big. */
142 Layouter::ReduceLineCache();
144 /* Do not set i too low, since when we run out of names, we loop
145 * for #tries only one time anyway - then we stop generating more
146 * towns. Do not set it too high either, since looping through all
147 * the other towns may take considerable amount of time (10000 is
148 * too much). */
149 for (int i = 1000; i != 0; i--) {
150 uint32_t r = randomizer.Next();
151 if (!VerifyTownName(r, &par, town_names)) continue;
153 *townnameparts = r;
154 return true;
157 return false;
163 * Generates a number from given seed.
164 * @param shift_by number of bits seed is shifted to the right
165 * @param max generated number is in interval 0...max-1
166 * @param seed seed
167 * @return seed transformed to a number from given range
169 static inline uint32_t SeedChance(uint8_t shift_by, size_t max, uint32_t seed)
171 return (GB(seed, shift_by, 16) * ClampTo<uint16_t>(max)) >> 16;
176 * Generates a number from given seed. Uses different algorithm than SeedChance().
177 * @param shift_by number of bits seed is shifted to the right
178 * @param max generated number is in interval 0...max-1
179 * @param seed seed
180 * @return seed transformed to a number from given range
182 static inline uint32_t SeedModChance(uint8_t shift_by, size_t max, uint32_t seed)
184 /* This actually gives *MUCH* more even distribution of the values
185 * than SeedChance(), which is absolutely horrible in that. If
186 * you do not believe me, try with i.e. the Czech town names,
187 * compare the words (nicely visible on prefixes) generated by
188 * SeedChance() and SeedModChance(). Do not get discouraged by the
189 * never-use-modulo myths, which hold true only for the linear
190 * congruential generators (and Random() isn't such a generator).
191 * --pasky
192 * TODO: Perhaps we should use it for all the name generators? --pasky */
193 return (seed >> shift_by) % max;
198 * Generates a number from given seed.
199 * @param shift_by number of bits seed is shifted to the right
200 * @param max generated number is in interval -bias...max-1
201 * @param seed seed
202 * @param bias minimum value that can be returned
203 * @return seed transformed to a number from given range
205 static inline int32_t SeedChanceBias(uint8_t shift_by, size_t max, uint32_t seed, int bias)
207 return SeedChance(shift_by, max + bias, seed) - bias;
212 * Replaces a string beginning in 'org' with 'rep'.
213 * @param org string to replace, has to be 4 characters long
214 * @param rep string to be replaced with, has to be 4 characters long
215 * @param builder string builder of the town name
216 * @param start the start index within the builder for the town name
218 static void ReplaceWords(const char *org, const char *rep, StringBuilder &builder, size_t start)
220 assert(strlen(org) == 4 && strlen(rep) == 4 && builder.CurrentIndex() - start >= 4);
221 if (strncmp(&builder[start], org, 4) == 0) memcpy(&builder[start], rep, 4); // Safe as the string in buf is always more than 4 characters long.
226 * Replaces english curses and ugly letter combinations by nicer ones.
227 * @param builder The builder with the town name
228 * @param start The start index into the builder for the first town name
229 * @param original English (Original) generator was used
231 static void ReplaceEnglishWords(StringBuilder &builder, size_t start, bool original)
233 ReplaceWords("Cunt", "East", builder, start);
234 ReplaceWords("Slag", "Pits", builder, start);
235 ReplaceWords("Slut", "Edin", builder, start);
236 if (!original) ReplaceWords("Fart", "Boot", builder, start); // never happens with 'English (Original)'
237 ReplaceWords("Drar", "Quar", builder, start);
238 ReplaceWords("Dreh", "Bash", builder, start);
239 ReplaceWords("Frar", "Shor", builder, start);
240 ReplaceWords("Grar", "Aber", builder, start);
241 ReplaceWords("Brar", "Over", builder, start);
242 ReplaceWords("Wrar", original ? "Inve" : "Stan", builder, start);
246 * Generates English (Original) town name from given seed.
247 * @param builder string builder
248 * @param seed town name seed
250 static void MakeEnglishOriginalTownName(StringBuilder &builder, uint32_t seed)
252 size_t start = builder.CurrentIndex();
254 /* optional first segment */
255 int i = SeedChanceBias(0, std::size(_name_original_english_1), seed, 50);
256 if (i >= 0) builder += _name_original_english_1[i];
258 /* mandatory middle segments */
259 builder += _name_original_english_2[SeedChance(4, std::size(_name_original_english_2), seed)];
260 builder += _name_original_english_3[SeedChance(7, std::size(_name_original_english_3), seed)];
261 builder += _name_original_english_4[SeedChance(10, std::size(_name_original_english_4), seed)];
262 builder += _name_original_english_5[SeedChance(13, std::size(_name_original_english_5), seed)];
264 /* optional last segment */
265 i = SeedChanceBias(15, std::size(_name_original_english_6), seed, 60);
266 if (i >= 0) builder += _name_original_english_6[i];
268 /* Ce, Ci => Ke, Ki */
269 if (builder[start] == 'C' && (builder[start + 1] == 'e' || builder[start + 1] == 'i')) {
270 builder[start] = 'K';
273 assert(builder.CurrentIndex() - start >= 4);
274 ReplaceEnglishWords(builder, start, true);
279 * Generates English (Additional) town name from given seed.
280 * @param builder string builder
281 * @param seed town name seed
283 static void MakeEnglishAdditionalTownName(StringBuilder &builder, uint32_t seed)
285 size_t start = builder.CurrentIndex();
287 /* optional first segment */
288 int i = SeedChanceBias(0, std::size(_name_additional_english_prefix), seed, 50);
289 if (i >= 0) builder += _name_additional_english_prefix[i];
291 if (SeedChance(3, 20, seed) >= 14) {
292 builder += _name_additional_english_1a[SeedChance(6, std::size(_name_additional_english_1a), seed)];
293 } else {
294 builder += _name_additional_english_1b1[SeedChance(6, std::size(_name_additional_english_1b1), seed)];
295 builder += _name_additional_english_1b2[SeedChance(9, std::size(_name_additional_english_1b2), seed)];
296 if (SeedChance(11, 20, seed) >= 4) {
297 builder += _name_additional_english_1b3a[SeedChance(12, std::size(_name_additional_english_1b3a), seed)];
298 } else {
299 builder += _name_additional_english_1b3b[SeedChance(12, std::size(_name_additional_english_1b3b), seed)];
303 builder += _name_additional_english_2[SeedChance(14, std::size(_name_additional_english_2), seed)];
305 /* optional last segment */
306 i = SeedChanceBias(15, std::size(_name_additional_english_3), seed, 60);
307 if (i >= 0) builder += _name_additional_english_3[i];
309 assert(builder.CurrentIndex() - start >= 4);
310 ReplaceEnglishWords(builder, start, false);
315 * Generates Austrian town name from given seed.
316 * @param builder string builder
317 * @param seed town name seed
319 static void MakeAustrianTownName(StringBuilder &builder, uint32_t seed)
321 /* Bad, Maria, Gross, ... */
322 int i = SeedChanceBias(0, std::size(_name_austrian_a1), seed, 15);
323 if (i >= 0) builder += _name_austrian_a1[i];
325 int j = 0;
327 i = SeedChance(4, 6, seed);
328 if (i >= 4) {
329 /* Kaisers-kirchen */
330 builder += _name_austrian_a2[SeedChance( 7, std::size(_name_austrian_a2), seed)];
331 builder += _name_austrian_a3[SeedChance(13, std::size(_name_austrian_a3), seed)];
332 } else if (i >= 2) {
333 /* St. Johann */
334 builder += _name_austrian_a5[SeedChance( 7, std::size(_name_austrian_a5), seed)];
335 builder += _name_austrian_a6[SeedChance( 9, std::size(_name_austrian_a6), seed)];
336 j = 1; // More likely to have a " an der " or " am "
337 } else {
338 /* Zell */
339 builder += _name_austrian_a4[SeedChance( 7, std::size(_name_austrian_a4), seed)];
342 i = SeedChance(1, 6, seed);
343 if (i >= 4 - j) {
344 /* an der Donau (rivers) */
345 builder += _name_austrian_f1[SeedChance(4, std::size(_name_austrian_f1), seed)];
346 builder += _name_austrian_f2[SeedChance(5, std::size(_name_austrian_f2), seed)];
347 } else if (i >= 2 - j) {
348 /* am Dachstein (mountains) */
349 builder += _name_austrian_b1[SeedChance(4, std::size(_name_austrian_b1), seed)];
350 builder += _name_austrian_b2[SeedChance(5, std::size(_name_austrian_b2), seed)];
356 * Generates German town name from given seed.
357 * @param builder string builder
358 * @param seed town name seed
360 static void MakeGermanTownName(StringBuilder &builder, uint32_t seed)
362 uint seed_derivative = SeedChance(7, 28, seed);
364 /* optional prefix */
365 if (seed_derivative == 12 || seed_derivative == 19) {
366 uint i = SeedChance(2, std::size(_name_german_pre), seed);
367 builder += _name_german_pre[i];
370 /* mandatory middle segments including option of hardcoded name */
371 uint i = SeedChance(3, std::size(_name_german_real) + std::size(_name_german_1), seed);
372 if (i < std::size(_name_german_real)) {
373 builder += _name_german_real[i];
374 } else {
375 builder += _name_german_1[i - std::size(_name_german_real)];
377 i = SeedChance(5, std::size(_name_german_2), seed);
378 builder += _name_german_2[i];
381 /* optional suffix */
382 if (seed_derivative == 24) {
383 i = SeedChance(9, std::size(_name_german_4_an_der) + std::size(_name_german_4_am), seed);
384 if (i < std::size(_name_german_4_an_der)) {
385 builder += _name_german_3_an_der[0];
386 builder += _name_german_4_an_der[i];
387 } else {
388 builder += _name_german_3_am[0];
389 builder += _name_german_4_am[i - std::size(_name_german_4_an_der)];
396 * Generates Latin-American town name from given seed.
397 * @param builder string builder
398 * @param seed town name seed
400 static void MakeSpanishTownName(StringBuilder &builder, uint32_t seed)
402 builder += _name_spanish_real[SeedChance(0, std::size(_name_spanish_real), seed)];
407 * Generates French town name from given seed.
408 * @param builder string builder
409 * @param seed town name seed
411 static void MakeFrenchTownName(StringBuilder &builder, uint32_t seed)
413 builder += _name_french_real[SeedChance(0, std::size(_name_french_real), seed)];
418 * Generates Silly town name from given seed.
419 * @param builder string builder
420 * @param seed town name seed
422 static void MakeSillyTownName(StringBuilder &builder, uint32_t seed)
424 builder += _name_silly_1[SeedChance( 0, std::size(_name_silly_1), seed)];
425 builder += _name_silly_2[SeedChance(16, std::size(_name_silly_2), seed)];
430 * Generates Swedish town name from given seed.
431 * @param builder string builder
432 * @param seed town name seed
434 static void MakeSwedishTownName(StringBuilder &builder, uint32_t seed)
436 /* optional first segment */
437 int i = SeedChanceBias(0, std::size(_name_swedish_1), seed, 50);
438 if (i >= 0) builder += _name_swedish_1[i];
440 /* mandatory middle segments including option of hardcoded name */
441 if (SeedChance(4, 5, seed) >= 3) {
442 builder += _name_swedish_2[SeedChance( 7, std::size(_name_swedish_2), seed)];
443 } else {
444 builder += _name_swedish_2a[SeedChance( 7, std::size(_name_swedish_2a), seed)];
445 builder += _name_swedish_2b[SeedChance(10, std::size(_name_swedish_2b), seed)];
446 builder += _name_swedish_2c[SeedChance(13, std::size(_name_swedish_2c), seed)];
449 builder += _name_swedish_3[SeedChance(16, std::size(_name_swedish_3), seed)];
454 * Generates Dutch town name from given seed.
455 * @param builder string builder
456 * @param seed town name seed
458 static void MakeDutchTownName(StringBuilder &builder, uint32_t seed)
460 /* optional first segment */
461 int i = SeedChanceBias(0, std::size(_name_dutch_1), seed, 50);
462 if (i >= 0) builder += _name_dutch_1[i];
464 /* mandatory middle segments including option of hardcoded name */
465 if (SeedChance(6, 9, seed) > 4) {
466 builder += _name_dutch_2[SeedChance( 9, std::size(_name_dutch_2), seed)];
467 } else {
468 builder += _name_dutch_3[SeedChance( 9, std::size(_name_dutch_3), seed)];
469 builder += _name_dutch_4[SeedChance(12, std::size(_name_dutch_4), seed)];
472 builder += _name_dutch_5[SeedChance(15, std::size(_name_dutch_5), seed)];
477 * Generates Finnish town name from given seed.
478 * @param builder string builder
479 * @param seed town name seed
481 static void MakeFinnishTownName(StringBuilder &builder, uint32_t seed)
483 size_t start = builder.CurrentIndex();
485 /* Select randomly if town name should consists of one or two parts. */
486 if (SeedChance(0, 15, seed) >= 10) {
487 builder += _name_finnish_real[SeedChance(2, std::size(_name_finnish_real), seed)];
488 return;
491 if (SeedChance(0, 15, seed) >= 5) {
492 /* A two-part name by combining one of _name_finnish_1 + "la"/"lä"
493 * The reason for not having the contents of _name_finnish_{1,2} in the same table is
494 * that the ones in _name_finnish_2 are not good for this purpose. */
495 uint sel = SeedChance( 0, std::size(_name_finnish_1), seed);
496 builder += _name_finnish_1[sel];
497 size_t last = builder.CurrentIndex() - 1;
498 if (builder[last] == 'i') builder[last] = 'e';
500 std::string_view view(&builder[start], builder.CurrentIndex() - start);
501 if (view.find_first_of("aouAOU") != std::string_view::npos) {
502 builder += "la";
503 } else {
504 builder += "l\u00e4";
506 return;
509 /* A two-part name by combining one of _name_finnish_{1,2} + _name_finnish_3.
510 * Why aren't _name_finnish_{1,2} just one table? See above. */
511 uint sel = SeedChance(2, std::size(_name_finnish_1) + std::size(_name_finnish_2), seed);
512 if (sel >= std::size(_name_finnish_1)) {
513 builder += _name_finnish_2[sel - std::size(_name_finnish_1)];
514 } else {
515 builder += _name_finnish_1[sel];
518 builder += _name_finnish_3[SeedChance(10, std::size(_name_finnish_3), seed)];
523 * Generates Polish town name from given seed.
524 * @param builder string builder
525 * @param seed town name seed
527 static void MakePolishTownName(StringBuilder &builder, uint32_t seed)
529 /* optional first segment */
530 uint i = SeedChance(0,
531 std::size(_name_polish_2_o) + std::size(_name_polish_2_m) +
532 std::size(_name_polish_2_f) + std::size(_name_polish_2_n),
533 seed);
534 uint j = SeedChance(2, 20, seed);
537 if (i < std::size(_name_polish_2_o)) {
538 builder += _name_polish_2_o[SeedChance(3, std::size(_name_polish_2_o), seed)];
539 return;
542 if (i < std::size(_name_polish_2_m) + std::size(_name_polish_2_o)) {
543 if (j < 4) {
544 builder += _name_polish_1_m[SeedChance(5, std::size(_name_polish_1_m), seed)];
547 builder += _name_polish_2_m[SeedChance(7, std::size(_name_polish_2_m), seed)];
549 if (j >= 4 && j < 16) {
550 builder += _name_polish_3_m[SeedChance(10, std::size(_name_polish_3_m), seed)];
553 return;
556 if (i < std::size(_name_polish_2_f) + std::size(_name_polish_2_m) + std::size(_name_polish_2_o)) {
557 if (j < 4) {
558 builder += _name_polish_1_f[SeedChance(5, std::size(_name_polish_1_f), seed)];
561 builder += _name_polish_2_f[SeedChance(7, std::size(_name_polish_2_f), seed)];
563 if (j >= 4 && j < 16) {
564 builder += _name_polish_3_f[SeedChance(10, std::size(_name_polish_3_f), seed)];
567 return;
570 if (j < 4) {
571 builder += _name_polish_1_n[SeedChance(5, std::size(_name_polish_1_n), seed)];
574 builder += _name_polish_2_n[SeedChance(7, std::size(_name_polish_2_n), seed)];
576 if (j >= 4 && j < 16) {
577 builder += _name_polish_3_n[SeedChance(10, std::size(_name_polish_3_n), seed)];
580 return;
585 * Generates Czech town name from given seed.
586 * @param builder string builder
587 * @param seed town name seed
589 static void MakeCzechTownName(StringBuilder &builder, uint32_t seed)
591 /* 1:3 chance to use a real name. */
592 if (SeedModChance(0, 4, seed) == 0) {
593 builder += _name_czech_real[SeedModChance(4, std::size(_name_czech_real), seed)];
594 return;
597 /* Probability of prefixes/suffixes
598 * 0..11 prefix, 12..13 prefix+suffix, 14..17 suffix, 18..31 nothing */
599 int prob_tails = SeedModChance(2, 32, seed);
600 bool do_prefix = prob_tails < 12;
601 bool do_suffix = prob_tails > 11 && prob_tails < 17;
602 bool dynamic_subst;
604 /* IDs of the respective parts */
605 int prefix = 0, ending = 0, suffix = 0;
606 size_t postfix = 0;
607 size_t stem;
609 /* The select criteria. */
610 CzechGender gender;
611 CzechChoose choose;
612 CzechAllow allow;
614 if (do_prefix) prefix = SeedModChance(5, std::size(_name_czech_adj) * 12, seed) / 12;
615 if (do_suffix) suffix = SeedModChance(7, std::size(_name_czech_suffix), seed);
616 /* 3:1 chance 3:1 to use dynamic substantive */
617 stem = SeedModChance(9,
618 std::size(_name_czech_subst_full) + 3 * std::size(_name_czech_subst_stem),
619 seed);
620 if (stem < std::size(_name_czech_subst_full)) {
621 /* That was easy! */
622 dynamic_subst = false;
623 gender = _name_czech_subst_full[stem].gender;
624 choose = _name_czech_subst_full[stem].choose;
625 allow = _name_czech_subst_full[stem].allow;
626 } else {
627 uint map[std::size(_name_czech_subst_ending)];
628 int ending_start = -1, ending_stop = -1;
630 /* Load the substantive */
631 dynamic_subst = true;
632 stem -= std::size(_name_czech_subst_full);
633 stem %= std::size(_name_czech_subst_stem);
634 gender = _name_czech_subst_stem[stem].gender;
635 choose = _name_czech_subst_stem[stem].choose;
636 allow = _name_czech_subst_stem[stem].allow;
638 /* Load the postfix (1:1 chance that a postfix will be inserted) */
639 postfix = SeedModChance(14, std::size(_name_czech_subst_postfix) * 2, seed);
641 if (choose & CZC_POSTFIX) {
642 /* Always get a real postfix. */
643 postfix %= std::size(_name_czech_subst_postfix);
645 if (choose & CZC_NOPOSTFIX) {
646 /* Always drop a postfix. */
647 postfix += std::size(_name_czech_subst_postfix);
649 if (postfix < std::size(_name_czech_subst_postfix)) {
650 choose |= CZC_POSTFIX;
651 } else {
652 choose |= CZC_NOPOSTFIX;
655 /* Localize the array segment containing a good gender */
656 for (ending = 0; ending < (int)std::size(_name_czech_subst_ending); ending++) {
657 const CzechNameSubst *e = &_name_czech_subst_ending[ending];
659 if (gender == CZG_FREE ||
660 (gender == CZG_NFREE && e->gender != CZG_SNEUT && e->gender != CZG_PNEUT) ||
661 gender == e->gender) {
662 if (ending_start < 0) {
663 ending_start = ending;
665 } else if (ending_start >= 0) {
666 ending_stop = ending - 1;
667 break;
670 if (ending_stop < 0) {
671 /* Whoa. All the endings matched. */
672 ending_stop = ending - 1;
675 /* Make a sequential map of the items with good mask */
676 size_t i = 0;
677 for (ending = ending_start; ending <= ending_stop; ending++) {
678 const CzechNameSubst *e = &_name_czech_subst_ending[ending];
680 if ((e->choose & choose) == choose && (e->allow & allow) != 0) {
681 map[i++] = ending;
684 assert(i > 0);
686 /* Load the ending */
687 ending = map[SeedModChance(16, (int)i, seed)];
688 /* Override possible CZG_*FREE; this must be a real gender,
689 * otherwise we get overflow when modifying the adjectivum. */
690 gender = _name_czech_subst_ending[ending].gender;
691 assert(gender != CZG_FREE && gender != CZG_NFREE);
694 if (do_prefix && (_name_czech_adj[prefix].choose & choose) != choose) {
695 /* Throw away non-matching prefix. */
696 do_prefix = false;
699 /* Now finally construct the name */
700 if (do_prefix) {
701 CzechPattern pattern = _name_czech_adj[prefix].pattern;
703 builder += _name_czech_adj[prefix].name;
705 size_t endpos = builder.CurrentIndex() - 1;
706 /* Find the first character in a UTF-8 sequence */
707 while (GB(builder[endpos], 6, 2) == 2) endpos--;
708 builder.RemoveElementsFromBack(builder.CurrentIndex() - endpos);
710 if (gender == CZG_SMASC && pattern == CZP_PRIVL) {
711 /* -ovX -> -uv */
712 builder[endpos - 2] = 'u';
713 } else {
714 builder += _name_czech_patmod[gender][pattern];
717 builder += ' ';
720 if (dynamic_subst) {
721 builder += _name_czech_subst_stem[stem].name;
722 if (postfix < std::size(_name_czech_subst_postfix)) {
723 const char *poststr = _name_czech_subst_postfix[postfix];
724 const char *endstr = _name_czech_subst_ending[ending].name;
726 size_t postlen = strlen(poststr);
727 size_t endlen = strlen(endstr);
728 assert(postlen > 0 && endlen > 0);
730 /* Kill the "avava" and "Jananna"-like cases */
731 if (postlen < 2 || postlen > endlen ||
732 ((poststr[1] != 'v' || poststr[1] != endstr[1]) &&
733 poststr[2] != endstr[1])) {
734 builder += poststr;
736 /* k-i -> c-i, h-i -> z-i */
737 if (endstr[0] == 'i') {
738 size_t last = builder.CurrentIndex() - 1;
739 switch (builder[last]) {
740 case 'k': builder[last] = 'c'; break;
741 case 'h': builder[last] = 'z'; break;
742 default: break;
747 builder += _name_czech_subst_ending[ending].name;
748 } else {
749 builder += _name_czech_subst_full[stem].name;
752 if (do_suffix) {
753 builder += " ";
754 builder += _name_czech_suffix[suffix];
760 * Generates Romanian town name from given seed.
761 * @param builder string builder
762 * @param seed town name seed
764 static void MakeRomanianTownName(StringBuilder &builder, uint32_t seed)
766 builder += _name_romanian_real[SeedChance(0, std::size(_name_romanian_real), seed)];
771 * Generates Slovak town name from given seed.
772 * @param builder string builder
773 * @param seed town name seed
775 static void MakeSlovakTownName(StringBuilder &builder, uint32_t seed)
777 builder += _name_slovak_real[SeedChance(0, std::size(_name_slovak_real), seed)];
782 * Generates Norwegian town name from given seed.
783 * @param builder string builder
784 * @param seed town name seed
786 static void MakeNorwegianTownName(StringBuilder &builder, uint32_t seed)
788 /* Use first 4 bit from seed to decide whether or not this town should
789 * have a real name 3/16 chance. Bit 0-3 */
790 if (SeedChance(0, 15, seed) < 3) {
791 /* Use 7bit for the realname table index. Bit 4-10 */
792 builder += _name_norwegian_real[SeedChance(4, std::size(_name_norwegian_real), seed)];
793 return;
796 /* Use 7bit for the first fake part. Bit 4-10 */
797 builder += _name_norwegian_1[SeedChance(4, std::size(_name_norwegian_1), seed)];
798 /* Use 7bit for the last fake part. Bit 11-17 */
799 builder += _name_norwegian_2[SeedChance(11, std::size(_name_norwegian_2), seed)];
804 * Generates Hungarian town name from given seed.
805 * @param builder string builder
806 * @param seed town name seed
808 static void MakeHungarianTownName(StringBuilder &builder, uint32_t seed)
810 if (SeedChance(12, 15, seed) < 3) {
811 builder += _name_hungarian_real[SeedChance(0, std::size(_name_hungarian_real), seed)];
812 return;
815 /* optional first segment */
816 uint i = SeedChance(3, std::size(_name_hungarian_1) * 3, seed);
817 if (i < std::size(_name_hungarian_1)) builder += _name_hungarian_1[i];
819 /* mandatory middle segments */
820 builder += _name_hungarian_2[SeedChance(3, std::size(_name_hungarian_2), seed)];
821 builder += _name_hungarian_3[SeedChance(6, std::size(_name_hungarian_3), seed)];
823 /* optional last segment */
824 i = SeedChance(10, std::size(_name_hungarian_4) * 3, seed);
825 if (i < std::size(_name_hungarian_4)) {
826 builder += _name_hungarian_4[i];
832 * Generates Swiss town name from given seed.
833 * @param builder string builder
834 * @param seed town name seed
836 static void MakeSwissTownName(StringBuilder &builder, uint32_t seed)
838 builder += _name_swiss_real[SeedChance(0, std::size(_name_swiss_real), seed)];
843 * Generates Danish town name from given seed.
844 * @param builder string builder
845 * @param seed town name seed
847 static void MakeDanishTownName(StringBuilder &builder, uint32_t seed)
849 /* optional first segment */
850 int i = SeedChanceBias(0, std::size(_name_danish_1), seed, 50);
851 if (i >= 0) builder += _name_danish_1[i];
853 /* middle segments removed as this algorithm seems to create much more realistic names */
854 builder += _name_danish_2[SeedChance( 7, std::size(_name_danish_2), seed)];
855 builder += _name_danish_3[SeedChance(16, std::size(_name_danish_3), seed)];
860 * Generates Turkish town name from given seed.
861 * @param builder string builder
862 * @param seed town name seed
864 static void MakeTurkishTownName(StringBuilder &builder, uint32_t seed)
866 uint i = SeedModChance(0, 5, seed);
868 switch (i) {
869 case 0:
870 builder += _name_turkish_prefix[SeedModChance( 2, std::size(_name_turkish_prefix), seed)];
872 /* middle segment */
873 builder += _name_turkish_middle[SeedModChance( 4, std::size(_name_turkish_middle), seed)];
875 /* optional suffix */
876 if (SeedModChance(0, 7, seed) == 0) {
877 builder += _name_turkish_suffix[SeedModChance( 10, std::size(_name_turkish_suffix), seed)];
879 break;
881 case 1: case 2:
882 builder += _name_turkish_prefix[SeedModChance( 2, std::size(_name_turkish_prefix), seed)];
883 builder += _name_turkish_suffix[SeedModChance( 4, std::size(_name_turkish_suffix), seed)];
884 break;
886 default:
887 builder += _name_turkish_real[SeedModChance( 4, std::size(_name_turkish_real), seed)];
888 break;
894 * Generates Italian town name from given seed.
895 * @param builder string builder
896 * @param seed town name seed
898 static void MakeItalianTownName(StringBuilder &builder, uint32_t seed)
900 if (SeedModChance(0, 6, seed) == 0) { // real city names
901 builder += _name_italian_real[SeedModChance(4, std::size(_name_italian_real), seed)];
902 return;
905 static const char * const mascul_femin_italian[] = {
906 "o",
907 "a",
910 if (SeedModChance(0, 8, seed) == 0) { // prefix
911 builder += _name_italian_pref[SeedModChance(11, std::size(_name_italian_pref), seed)];
914 uint i = SeedChance(0, 2, seed);
915 if (i == 0) { // masculine form
916 builder += _name_italian_1m[SeedModChance(4, std::size(_name_italian_1m), seed)];
917 } else { // feminine form
918 builder += _name_italian_1f[SeedModChance(4, std::size(_name_italian_1f), seed)];
921 if (SeedModChance(3, 3, seed) == 0) {
922 builder += _name_italian_2[SeedModChance(11, std::size(_name_italian_2), seed)];
923 builder += mascul_femin_italian[i];
924 } else {
925 builder += _name_italian_2i[SeedModChance(16, std::size(_name_italian_2i), seed)];
928 if (SeedModChance(15, 4, seed) == 0) {
929 if (SeedModChance(5, 2, seed) == 0) { // generic suffix
930 builder += _name_italian_3[SeedModChance(4, std::size(_name_italian_3), seed)];
931 } else { // river name suffix
932 builder += _name_italian_river1[SeedModChance(4, std::size(_name_italian_river1), seed)];
933 builder += _name_italian_river2[SeedModChance(16, std::size(_name_italian_river2), seed)];
940 * Generates Catalan town name from given seed.
941 * @param builder string builder
942 * @param seed town name seed
944 static void MakeCatalanTownName(StringBuilder &builder, uint32_t seed)
946 if (SeedModChance(0, 3, seed) == 0) { // real city names
947 builder += _name_catalan_real[SeedModChance(4, std::size(_name_catalan_real), seed)];
948 return;
951 if (SeedModChance(0, 2, seed) == 0) { // prefix
952 builder += _name_catalan_pref[SeedModChance(11, std::size(_name_catalan_pref), seed)];
955 uint i = SeedChance(0, 2, seed);
956 if (i == 0) { // masculine form
957 builder += _name_catalan_1m[SeedModChance(4, std::size(_name_catalan_1m), seed)];
958 builder += _name_catalan_2m[SeedModChance(11, std::size(_name_catalan_2m), seed)];
959 } else { // feminine form
960 builder += _name_catalan_1f[SeedModChance(4, std::size(_name_catalan_1f), seed)];
961 builder += _name_catalan_2f[SeedModChance(11, std::size(_name_catalan_2f), seed)];
964 if (SeedModChance(15, 5, seed) == 0) {
965 if (SeedModChance(5, 2, seed) == 0) { // generic suffix
966 builder += _name_catalan_3[SeedModChance(4, std::size(_name_catalan_3), seed)];
967 } else { // river name suffix
968 builder += _name_catalan_river1[SeedModChance(4, std::size(_name_catalan_river1), seed)];
975 * Type for all town name generator functions.
976 * @param builder The builder to write the name to.
977 * @param seed The seed of the town name.
979 typedef void TownNameGenerator(StringBuilder &builder, uint32_t seed);
981 /** Town name generators */
982 static TownNameGenerator *_town_name_generators[] = {
983 MakeEnglishOriginalTownName, // replaces first 4 characters of name
984 MakeFrenchTownName,
985 MakeGermanTownName,
986 MakeEnglishAdditionalTownName, // replaces first 4 characters of name
987 MakeSpanishTownName,
988 MakeSillyTownName,
989 MakeSwedishTownName,
990 MakeDutchTownName,
991 MakeFinnishTownName, // _name_finnish_1
992 MakePolishTownName,
993 MakeSlovakTownName,
994 MakeNorwegianTownName,
995 MakeHungarianTownName,
996 MakeAustrianTownName,
997 MakeRomanianTownName,
998 MakeCzechTownName, // _name_czech_adj + _name_czech_patmod + 1 + _name_czech_subst_stem + _name_czech_subst_postfix
999 MakeSwissTownName,
1000 MakeDanishTownName,
1001 MakeTurkishTownName,
1002 MakeItalianTownName,
1003 MakeCatalanTownName,
1008 * Generates town name from given seed.
1009 * @param builder string builder to write to
1010 * @param lang town name language
1011 * @param seed generation seed
1013 void GenerateTownNameString(StringBuilder &builder, size_t lang, uint32_t seed)
1015 assert(lang < std::size(_town_name_generators));
1016 return _town_name_generators[lang](builder, seed);