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/>.
8 /** @file townname.cpp %Town name generators. */
11 #include "string_func.h"
12 #include "townname_type.h"
14 #include "strings_func.h"
15 #include "core/random_func.hpp"
17 #include "gfx_layout.h"
18 #include "strings_internal.h"
20 #include "table/townname.h"
22 #include "safeguards.h"
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
33 if (t
->townnamegrfid
!= 0 && GetGRFTownName(t
->townnamegrfid
) == nullptr) {
34 /* Fallback to english original */
36 this->type
= SPECSTR_TOWNNAME_ENGLISH
;
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
);
56 GRFTownNameGenerate(builder
, par
->grfid
, par
->type
, townnameparts
);
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
)
68 StringBuilder
builder(result
);
69 GetTownName(builder
, par
, townnameparts
);
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
);
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
);
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
);
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;
120 if (name
== t
->name
) return false;
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
149 for (int i
= 1000; i
!= 0; i
--) {
150 uint32_t r
= randomizer
.Next();
151 if (!VerifyTownName(r
, &par
, town_names
)) continue;
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
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
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).
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
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
)];
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
)];
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
];
327 i
= SeedChance(4, 6, seed
);
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
)];
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 "
339 builder
+= _name_austrian_a4
[SeedChance( 7, std::size(_name_austrian_a4
), seed
)];
342 i
= SeedChance(1, 6, seed
);
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
];
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
];
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
)];
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
)];
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
)];
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
) {
504 builder
+= "l\u00e4";
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
)];
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
),
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
)];
542 if (i
< std::size(_name_polish_2_m
) + std::size(_name_polish_2_o
)) {
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
)];
556 if (i
< std::size(_name_polish_2_f
) + std::size(_name_polish_2_m
) + std::size(_name_polish_2_o
)) {
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
)];
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
)];
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
)];
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;
604 /* IDs of the respective parts */
605 int prefix
= 0, ending
= 0, suffix
= 0;
609 /* The select criteria. */
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
),
620 if (stem
< std::size(_name_czech_subst_full
)) {
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
;
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
;
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;
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 */
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) {
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. */
699 /* Now finally construct the name */
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
) {
712 builder
[endpos
- 2] = 'u';
714 builder
+= _name_czech_patmod
[gender
][pattern
];
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])) {
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;
747 builder
+= _name_czech_subst_ending
[ending
].name
;
749 builder
+= _name_czech_subst_full
[stem
].name
;
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
)];
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
)];
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
);
870 builder
+= _name_turkish_prefix
[SeedModChance( 2, std::size(_name_turkish_prefix
), seed
)];
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
)];
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
)];
887 builder
+= _name_turkish_real
[SeedModChance( 4, std::size(_name_turkish_real
), seed
)];
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
)];
905 static const char * const mascul_femin_italian
[] = {
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
];
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
)];
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
986 MakeEnglishAdditionalTownName
, // replaces first 4 characters of name
991 MakeFinnishTownName
, // _name_finnish_1
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
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
);