4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
10 /** @file townname.cpp %Town name generators. */
13 #include "string_func.h"
14 #include "townname_type.h"
16 #include "strings_func.h"
17 #include "core/random_func.hpp"
20 #include "table/townname.h"
24 * Initializes this struct from town data
25 * @param t town for which we will be printing name later
27 TownNameParams::TownNameParams(const Town
*t
) :
28 grfid(t
->townnamegrfid
), // by default, use supplied data
31 if (t
->townnamegrfid
!= 0 && GetGRFTownName(t
->townnamegrfid
) == NULL
) {
32 /* Fallback to english original */
34 this->type
= SPECSTR_TOWNNAME_ENGLISH
;
41 * Fills buffer with specified town name
42 * @param buff buffer start
43 * @param par town name parameters
44 * @param townnameparts 'encoded' town name
45 * @param last end of buffer
46 * @return pointer to terminating '\0'
48 char *GetTownName(char *buff
, const TownNameParams
*par
, uint32 townnameparts
, const char *last
)
50 if (par
->grfid
== 0) {
51 int64 args_array
[1] = { townnameparts
};
52 StringParameters
tmp_params(args_array
);
53 return GetStringWithArgs(buff
, par
->type
, &tmp_params
, last
);
56 return GRFTownNameGenerate(buff
, par
->grfid
, par
->type
, townnameparts
, last
);
61 * Fills buffer with town's name
62 * @param buff buffer start
63 * @param t we want to get name of this town
64 * @param last end of buffer
65 * @return pointer to terminating '\0'
67 char *GetTownName(char *buff
, const Town
*t
, const char *last
)
69 TownNameParams
par(t
);
70 return GetTownName(buff
, &par
, t
->townnameparts
, last
);
75 * Verifies the town name is valid and unique.
76 * @param r random bits
77 * @param par town name parameters
78 * @return true iff name is valid and unique
80 bool VerifyTownName(uint32 r
, const TownNameParams
*par
)
82 /* reserve space for extra unicode character and terminating '\0' */
83 char buf1
[(MAX_LENGTH_TOWN_NAME_CHARS
+ 1) * MAX_CHAR_LENGTH
];
84 char buf2
[(MAX_LENGTH_TOWN_NAME_CHARS
+ 1) * MAX_CHAR_LENGTH
];
86 GetTownName(buf1
, par
, r
, lastof(buf1
));
88 /* Check size and width */
89 if (Utf8StringLength(buf1
) >= MAX_LENGTH_TOWN_NAME_CHARS
) return false;
93 /* We can't just compare the numbers since
94 * several numbers may map to a single name. */
95 const char *buf
= t
->name
;
97 GetTownName(buf2
, t
, lastof(buf2
));
100 if (strcmp(buf1
, buf
) == 0) return false;
108 * Generates valid town name.
109 * @param townnameparts if a name is generated, it's stored there
110 * @return true iff a name was generated
112 bool GenerateTownName(uint32
*townnameparts
)
114 /* Do not set too low tries, since when we run out of names, we loop
115 * for #tries only one time anyway - then we stop generating more
116 * towns. Do not show it too high neither, since looping through all
117 * the other towns may take considerable amount of time (10000 is
119 TownNameParams
par(_settings_game
.game_creation
.town_name
);
121 for (int i
= 1000; i
!= 0; i
--) {
122 uint32 r
= _generating_world
? Random() : InteractiveRandom();
123 if (!VerifyTownName(r
, &par
)) continue;
135 * Generates a number from given seed.
136 * @param shift_by number of bits seed is shifted to the right
137 * @param max generated number is in interval 0...max-1
139 * @return seed transformed to a number from given range
141 static inline uint32
SeedChance(byte shift_by
, int max
, uint32 seed
)
143 return (GB(seed
, shift_by
, 16) * max
) >> 16;
148 * Generates a number from given seed. Uses different algorithm than SeedChance().
149 * @param shift_by number of bits seed is shifted to the right
150 * @param max generated number is in interval 0...max-1
152 * @return seed transformed to a number from given range
154 static inline uint32
SeedModChance(byte shift_by
, int max
, uint32 seed
)
156 /* This actually gives *MUCH* more even distribution of the values
157 * than SeedChance(), which is absolutely horrible in that. If
158 * you do not believe me, try with i.e. the Czech town names,
159 * compare the words (nicely visible on prefixes) generated by
160 * SeedChance() and SeedModChance(). Do not get discouraged by the
161 * never-use-modulo myths, which hold true only for the linear
162 * congruential generators (and Random() isn't such a generator).
164 * TODO: Perhaps we should use it for all the name generators? --pasky */
165 return (seed
>> shift_by
) % max
;
170 * Generates a number from given seed.
171 * @param shift_by number of bits seed is shifted to the right
172 * @param max generated number is in interval -bias...max-1
174 * @param bias minimum value that can be returned
175 * @return seed transformed to a number from given range
177 static inline int32
SeedChanceBias(byte shift_by
, int max
, uint32 seed
, int bias
)
179 return SeedChance(shift_by
, max
+ bias
, seed
) - bias
;
184 * Replaces a string beginning in 'org' with 'rep'.
185 * @param org string to replace, has to be 4 characters long
186 * @param rep string to be replaced with, has to be 4 characters long
187 * @param buf buffer with string
189 static void ReplaceWords(const char *org
, const char *rep
, char *buf
)
191 if (strncmp(buf
, org
, 4) == 0) strncpy(buf
, rep
, 4); // Safe as the string in buf is always more than 4 characters long.
196 * Replaces english curses and ugly letter combinations by nicer ones.
197 * @param buf buffer with town name
198 * @param original English (Original) generator was used
200 static void ReplaceEnglishWords(char *buf
, bool original
)
202 ReplaceWords("Cunt", "East", buf
);
203 ReplaceWords("Slag", "Pits", buf
);
204 ReplaceWords("Slut", "Edin", buf
);
205 if (!original
) ReplaceWords("Fart", "Boot", buf
); // never happens with 'English (Original)'
206 ReplaceWords("Drar", "Quar", buf
);
207 ReplaceWords("Dreh", "Bash", buf
);
208 ReplaceWords("Frar", "Shor", buf
);
209 ReplaceWords("Grar", "Aber", buf
);
210 ReplaceWords("Brar", "Over", buf
);
211 ReplaceWords("Wrar", original
? "Inve" : "Stan", buf
);
215 * Generates English (Original) town name from given seed.
216 * @param buf output buffer
217 * @param seed town name seed
218 * @param last end of buffer
220 static char *MakeEnglishOriginalTownName(char *buf
, const char *last
, uint32 seed
)
224 /* optional first segment */
225 int i
= SeedChanceBias(0, lengthof(_name_original_english_1
), seed
, 50);
226 if (i
>= 0) buf
= strecpy(buf
, _name_original_english_1
[i
], last
);
228 /* mandatory middle segments */
229 buf
= strecpy(buf
, _name_original_english_2
[SeedChance(4, lengthof(_name_original_english_2
), seed
)], last
);
230 buf
= strecpy(buf
, _name_original_english_3
[SeedChance(7, lengthof(_name_original_english_3
), seed
)], last
);
231 buf
= strecpy(buf
, _name_original_english_4
[SeedChance(10, lengthof(_name_original_english_4
), seed
)], last
);
232 buf
= strecpy(buf
, _name_original_english_5
[SeedChance(13, lengthof(_name_original_english_5
), seed
)], last
);
234 /* optional last segment */
235 i
= SeedChanceBias(15, lengthof(_name_original_english_6
), seed
, 60);
236 if (i
>= 0) buf
= strecpy(buf
, _name_original_english_6
[i
], last
);
238 /* Ce, Ci => Ke, Ki */
239 if (orig
[0] == 'C' && (orig
[1] == 'e' || orig
[1] == 'i')) {
243 assert(buf
- orig
>= 4);
244 ReplaceEnglishWords(orig
, true);
251 * Generates English (Additional) town name from given seed.
252 * @param buf output buffer
253 * @param seed town name seed
254 * @param last end of buffer
256 static char *MakeEnglishAdditionalTownName(char *buf
, const char *last
, uint32 seed
)
260 /* optional first segment */
261 int i
= SeedChanceBias(0, lengthof(_name_additional_english_prefix
), seed
, 50);
262 if (i
>= 0) buf
= strecpy(buf
, _name_additional_english_prefix
[i
], last
);
264 if (SeedChance(3, 20, seed
) >= 14) {
265 buf
= strecpy(buf
, _name_additional_english_1a
[SeedChance(6, lengthof(_name_additional_english_1a
), seed
)], last
);
267 buf
= strecpy(buf
, _name_additional_english_1b1
[SeedChance(6, lengthof(_name_additional_english_1b1
), seed
)], last
);
268 buf
= strecpy(buf
, _name_additional_english_1b2
[SeedChance(9, lengthof(_name_additional_english_1b2
), seed
)], last
);
269 if (SeedChance(11, 20, seed
) >= 4) {
270 buf
= strecpy(buf
, _name_additional_english_1b3a
[SeedChance(12, lengthof(_name_additional_english_1b3a
), seed
)], last
);
272 buf
= strecpy(buf
, _name_additional_english_1b3b
[SeedChance(12, lengthof(_name_additional_english_1b3b
), seed
)], last
);
276 buf
= strecpy(buf
, _name_additional_english_2
[SeedChance(14, lengthof(_name_additional_english_2
), seed
)], last
);
278 /* optional last segment */
279 i
= SeedChanceBias(15, lengthof(_name_additional_english_3
), seed
, 60);
280 if (i
>= 0) buf
= strecpy(buf
, _name_additional_english_3
[i
], last
);
282 assert(buf
- orig
>= 4);
283 ReplaceEnglishWords(orig
, false);
290 * Generates Austrian town name from given seed.
291 * @param buf output buffer
292 * @param seed town name seed
293 * @param last end of buffer
295 static char *MakeAustrianTownName(char *buf
, const char *last
, uint32 seed
)
297 /* Bad, Maria, Gross, ... */
298 int i
= SeedChanceBias(0, lengthof(_name_austrian_a1
), seed
, 15);
299 if (i
>= 0) buf
= strecpy(buf
, _name_austrian_a1
[i
], last
);
303 i
= SeedChance(4, 6, seed
);
305 /* Kaisers-kirchen */
306 buf
= strecpy(buf
, _name_austrian_a2
[SeedChance( 7, lengthof(_name_austrian_a2
), seed
)], last
);
307 buf
= strecpy(buf
, _name_austrian_a3
[SeedChance(13, lengthof(_name_austrian_a3
), seed
)], last
);
310 buf
= strecpy(buf
, _name_austrian_a5
[SeedChance( 7, lengthof(_name_austrian_a5
), seed
)], last
);
311 buf
= strecpy(buf
, _name_austrian_a6
[SeedChance( 9, lengthof(_name_austrian_a6
), seed
)], last
);
312 j
= 1; // More likely to have a " an der " or " am "
315 buf
= strecpy(buf
, _name_austrian_a4
[SeedChance( 7, lengthof(_name_austrian_a4
), seed
)], last
);
318 i
= SeedChance(1, 6, seed
);
320 /* an der Donau (rivers) */
321 buf
= strecpy(buf
, _name_austrian_f1
[SeedChance(4, lengthof(_name_austrian_f1
), seed
)], last
);
322 buf
= strecpy(buf
, _name_austrian_f2
[SeedChance(5, lengthof(_name_austrian_f2
), seed
)], last
);
323 } else if (i
>= 2 - j
) {
324 /* am Dachstein (mountains) */
325 buf
= strecpy(buf
, _name_austrian_b1
[SeedChance(4, lengthof(_name_austrian_b1
), seed
)], last
);
326 buf
= strecpy(buf
, _name_austrian_b2
[SeedChance(5, lengthof(_name_austrian_b2
), seed
)], last
);
334 * Generates German town name from given seed.
335 * @param buf output buffer
336 * @param seed town name seed
337 * @param last end of buffer
339 static char *MakeGermanTownName(char *buf
, const char *last
, uint32 seed
)
341 uint seed_derivative
= SeedChance(7, 28, seed
);
343 /* optional prefix */
344 if (seed_derivative
== 12 || seed_derivative
== 19) {
345 uint i
= SeedChance(2, lengthof(_name_german_pre
), seed
);
346 buf
= strecpy(buf
, _name_german_pre
[i
], last
);
349 /* mandatory middle segments including option of hardcoded name */
350 uint i
= SeedChance(3, lengthof(_name_german_real
) + lengthof(_name_german_1
), seed
);
351 if (i
< lengthof(_name_german_real
)) {
352 buf
= strecpy(buf
, _name_german_real
[i
], last
);
354 buf
= strecpy(buf
, _name_german_1
[i
- lengthof(_name_german_real
)], last
);
356 i
= SeedChance(5, lengthof(_name_german_2
), seed
);
357 buf
= strecpy(buf
, _name_german_2
[i
], last
);
360 /* optional suffix */
361 if (seed_derivative
== 24) {
362 i
= SeedChance(9, lengthof(_name_german_4_an_der
) + lengthof(_name_german_4_am
), seed
);
363 if (i
< lengthof(_name_german_4_an_der
)) {
364 buf
= strecpy(buf
, _name_german_3_an_der
[0], last
);
365 buf
= strecpy(buf
, _name_german_4_an_der
[i
], last
);
367 buf
= strecpy(buf
, _name_german_3_am
[0], last
);
368 buf
= strecpy(buf
, _name_german_4_am
[i
- lengthof(_name_german_4_an_der
)], last
);
377 * Generates Latin-American town name from given seed.
378 * @param buf output buffer
379 * @param seed town name seed
380 * @param last end of buffer
382 static char *MakeSpanishTownName(char *buf
, const char *last
, uint32 seed
)
384 return strecpy(buf
, _name_spanish_real
[SeedChance(0, lengthof(_name_spanish_real
), seed
)], last
);
389 * Generates French town name from given seed.
390 * @param buf output buffer
391 * @param seed town name seed
392 * @param last end of buffer
394 static char *MakeFrenchTownName(char *buf
, const char *last
, uint32 seed
)
396 return strecpy(buf
, _name_french_real
[SeedChance(0, lengthof(_name_french_real
), seed
)], last
);
401 * Generates Silly town name from given seed.
402 * @param buf output buffer
403 * @param seed town name seed
404 * @param last end of buffer
406 static char *MakeSillyTownName(char *buf
, const char *last
, uint32 seed
)
408 buf
= strecpy(buf
, _name_silly_1
[SeedChance( 0, lengthof(_name_silly_1
), seed
)], last
);
409 buf
= strecpy(buf
, _name_silly_2
[SeedChance(16, lengthof(_name_silly_2
), seed
)], last
);
416 * Generates Swedish town name from given seed.
417 * @param buf output buffer
418 * @param seed town name seed
419 * @param last end of buffer
421 static char *MakeSwedishTownName(char *buf
, const char *last
, uint32 seed
)
423 /* optional first segment */
424 int i
= SeedChanceBias(0, lengthof(_name_swedish_1
), seed
, 50);
425 if (i
>= 0) buf
= strecpy(buf
, _name_swedish_1
[i
], last
);
427 /* mandatory middle segments including option of hardcoded name */
428 if (SeedChance(4, 5, seed
) >= 3) {
429 buf
= strecpy(buf
, _name_swedish_2
[SeedChance( 7, lengthof(_name_swedish_2
), seed
)], last
);
431 buf
= strecpy(buf
, _name_swedish_2a
[SeedChance( 7, lengthof(_name_swedish_2a
), seed
)], last
);
432 buf
= strecpy(buf
, _name_swedish_2b
[SeedChance(10, lengthof(_name_swedish_2b
), seed
)], last
);
433 buf
= strecpy(buf
, _name_swedish_2c
[SeedChance(13, lengthof(_name_swedish_2c
), seed
)], last
);
436 buf
= strecpy(buf
, _name_swedish_3
[SeedChance(16, lengthof(_name_swedish_3
), seed
)], last
);
443 * Generates Dutch town name from given seed.
444 * @param buf output buffer
445 * @param seed town name seed
446 * @param last end of buffer
448 static char *MakeDutchTownName(char *buf
, const char *last
, uint32 seed
)
450 /* optional first segment */
451 int i
= SeedChanceBias(0, lengthof(_name_dutch_1
), seed
, 50);
452 if (i
>= 0) buf
= strecpy(buf
, _name_dutch_1
[i
], last
);
454 /* mandatory middle segments including option of hardcoded name */
455 if (SeedChance(6, 9, seed
) > 4) {
456 buf
= strecpy(buf
, _name_dutch_2
[SeedChance( 9, lengthof(_name_dutch_2
), seed
)], last
);
458 buf
= strecpy(buf
, _name_dutch_3
[SeedChance( 9, lengthof(_name_dutch_3
), seed
)], last
);
459 buf
= strecpy(buf
, _name_dutch_4
[SeedChance(12, lengthof(_name_dutch_4
), seed
)], last
);
462 buf
= strecpy(buf
, _name_dutch_5
[SeedChance(15, lengthof(_name_dutch_5
), seed
)], last
);
469 * Generates Finnish town name from given seed.
470 * @param buf output buffer
471 * @param seed town name seed
472 * @param last end of buffer
474 static char *MakeFinnishTownName(char *buf
, const char *last
, uint32 seed
)
478 /* Select randomly if town name should consists of one or two parts. */
479 if (SeedChance(0, 15, seed
) >= 10) {
480 return strecpy(buf
, _name_finnish_real
[SeedChance(2, lengthof(_name_finnish_real
), seed
)], last
);
483 if (SeedChance(0, 15, seed
) >= 5) {
484 /* A two-part name by combining one of _name_finnish_1 + "la"/"lä"
485 * The reason for not having the contents of _name_finnish_{1,2} in the same table is
486 * that the ones in _name_finnish_2 are not good for this purpose. */
487 uint sel
= SeedChance( 0, lengthof(_name_finnish_1
), seed
);
488 buf
= strecpy(buf
, _name_finnish_1
[sel
], last
);
491 if (*end
== 'i') *end
= 'e';
492 if (strstr(orig
, "a") != NULL
|| strstr(orig
, "o") != NULL
|| strstr(orig
, "u") != NULL
||
493 strstr(orig
, "A") != NULL
|| strstr(orig
, "O") != NULL
|| strstr(orig
, "U") != NULL
) {
494 buf
= strecpy(buf
, "la", last
);
496 buf
= strecpy(buf
, "l\xC3\xA4", last
);
501 /* A two-part name by combining one of _name_finnish_{1,2} + _name_finnish_3.
502 * Why aren't _name_finnish_{1,2} just one table? See above. */
503 uint sel
= SeedChance(2, lengthof(_name_finnish_1
) + lengthof(_name_finnish_2
), seed
);
504 if (sel
>= lengthof(_name_finnish_1
)) {
505 buf
= strecpy(buf
, _name_finnish_2
[sel
- lengthof(_name_finnish_1
)], last
);
507 buf
= strecpy(buf
, _name_finnish_1
[sel
], last
);
510 buf
= strecpy(buf
, _name_finnish_3
[SeedChance(10, lengthof(_name_finnish_3
), seed
)], last
);
517 * Generates Polish town name from given seed.
518 * @param buf output buffer
519 * @param seed town name seed
520 * @param last end of buffer
522 static char *MakePolishTownName(char *buf
, const char *last
, uint32 seed
)
524 /* optional first segment */
525 uint i
= SeedChance(0,
526 lengthof(_name_polish_2_o
) + lengthof(_name_polish_2_m
) +
527 lengthof(_name_polish_2_f
) + lengthof(_name_polish_2_n
),
529 uint j
= SeedChance(2, 20, seed
);
532 if (i
< lengthof(_name_polish_2_o
)) {
533 return strecpy(buf
, _name_polish_2_o
[SeedChance(3, lengthof(_name_polish_2_o
), seed
)], last
);
536 if (i
< lengthof(_name_polish_2_m
) + lengthof(_name_polish_2_o
)) {
538 buf
= strecpy(buf
, _name_polish_1_m
[SeedChance(5, lengthof(_name_polish_1_m
), seed
)], last
);
541 buf
= strecpy(buf
, _name_polish_2_m
[SeedChance(7, lengthof(_name_polish_2_m
), seed
)], last
);
543 if (j
>= 4 && j
< 16) {
544 buf
= strecpy(buf
, _name_polish_3_m
[SeedChance(10, lengthof(_name_polish_3_m
), seed
)], last
);
550 if (i
< lengthof(_name_polish_2_f
) + lengthof(_name_polish_2_m
) + lengthof(_name_polish_2_o
)) {
552 buf
= strecpy(buf
, _name_polish_1_f
[SeedChance(5, lengthof(_name_polish_1_f
), seed
)], last
);
555 buf
= strecpy(buf
, _name_polish_2_f
[SeedChance(7, lengthof(_name_polish_2_f
), seed
)], last
);
557 if (j
>= 4 && j
< 16) {
558 buf
= strecpy(buf
, _name_polish_3_f
[SeedChance(10, lengthof(_name_polish_3_f
), seed
)], last
);
565 buf
= strecpy(buf
, _name_polish_1_n
[SeedChance(5, lengthof(_name_polish_1_n
), seed
)], last
);
568 buf
= strecpy(buf
, _name_polish_2_n
[SeedChance(7, lengthof(_name_polish_2_n
), seed
)], last
);
570 if (j
>= 4 && j
< 16) {
571 buf
= strecpy(buf
, _name_polish_3_n
[SeedChance(10, lengthof(_name_polish_3_n
), seed
)], last
);
579 * Generates Czech town name from given seed.
580 * @param buf output buffer
581 * @param seed town name seed
582 * @param last end of buffer
584 static char *MakeCzechTownName(char *buf
, const char *last
, uint32 seed
)
586 /* 1:3 chance to use a real name. */
587 if (SeedModChance(0, 4, seed
) == 0) {
588 return strecpy(buf
, _name_czech_real
[SeedModChance(4, lengthof(_name_czech_real
), seed
)], last
);
591 const char *orig
= buf
;
593 /* Probability of prefixes/suffixes
594 * 0..11 prefix, 12..13 prefix+suffix, 14..17 suffix, 18..31 nothing */
595 int prob_tails
= SeedModChance(2, 32, seed
);
596 bool do_prefix
= prob_tails
< 12;
597 bool do_suffix
= prob_tails
> 11 && prob_tails
< 17;
600 /* IDs of the respective parts */
601 int prefix
= 0, ending
= 0, suffix
= 0;
605 /* The select criteria. */
610 if (do_prefix
) prefix
= SeedModChance(5, lengthof(_name_czech_adj
) * 12, seed
) / 12;
611 if (do_suffix
) suffix
= SeedModChance(7, lengthof(_name_czech_suffix
), seed
);
612 /* 3:1 chance 3:1 to use dynamic substantive */
613 stem
= SeedModChance(9,
614 lengthof(_name_czech_subst_full
) + 3 * lengthof(_name_czech_subst_stem
),
616 if (stem
< lengthof(_name_czech_subst_full
)) {
618 dynamic_subst
= false;
619 gender
= _name_czech_subst_full
[stem
].gender
;
620 choose
= _name_czech_subst_full
[stem
].choose
;
621 allow
= _name_czech_subst_full
[stem
].allow
;
623 unsigned int map
[lengthof(_name_czech_subst_ending
)];
624 int ending_start
= -1, ending_stop
= -1;
626 /* Load the substantive */
627 dynamic_subst
= true;
628 stem
-= lengthof(_name_czech_subst_full
);
629 stem
%= lengthof(_name_czech_subst_stem
);
630 gender
= _name_czech_subst_stem
[stem
].gender
;
631 choose
= _name_czech_subst_stem
[stem
].choose
;
632 allow
= _name_czech_subst_stem
[stem
].allow
;
634 /* Load the postfix (1:1 chance that a postfix will be inserted) */
635 postfix
= SeedModChance(14, lengthof(_name_czech_subst_postfix
) * 2, seed
);
637 if (choose
& CZC_POSTFIX
) {
638 /* Always get a real postfix. */
639 postfix
%= lengthof(_name_czech_subst_postfix
);
641 if (choose
& CZC_NOPOSTFIX
) {
642 /* Always drop a postfix. */
643 postfix
+= lengthof(_name_czech_subst_postfix
);
645 if (postfix
< lengthof(_name_czech_subst_postfix
)) {
646 choose
|= CZC_POSTFIX
;
648 choose
|= CZC_NOPOSTFIX
;
651 /* Localize the array segment containing a good gender */
652 for (ending
= 0; ending
< (int)lengthof(_name_czech_subst_ending
); ending
++) {
653 const CzechNameSubst
*e
= &_name_czech_subst_ending
[ending
];
655 if (gender
== CZG_FREE
||
656 (gender
== CZG_NFREE
&& e
->gender
!= CZG_SNEUT
&& e
->gender
!= CZG_PNEUT
) ||
657 gender
== e
->gender
) {
658 if (ending_start
< 0) {
659 ending_start
= ending
;
661 } else if (ending_start
>= 0) {
662 ending_stop
= ending
- 1;
666 if (ending_stop
< 0) {
667 /* Whoa. All the endings matched. */
668 ending_stop
= ending
- 1;
671 /* Make a sequential map of the items with good mask */
673 for (ending
= ending_start
; ending
<= ending_stop
; ending
++) {
674 const CzechNameSubst
*e
= &_name_czech_subst_ending
[ending
];
676 if ((e
->choose
& choose
) == choose
&& (e
->allow
& allow
) != 0) {
682 /* Load the ending */
683 ending
= map
[SeedModChance(16, (int)i
, seed
)];
684 /* Override possible CZG_*FREE; this must be a real gender,
685 * otherwise we get overflow when modifying the adjectivum. */
686 gender
= _name_czech_subst_ending
[ending
].gender
;
687 assert(gender
!= CZG_FREE
&& gender
!= CZG_NFREE
);
690 if (do_prefix
&& (_name_czech_adj
[prefix
].choose
& choose
) != choose
) {
691 /* Throw away non-matching prefix. */
695 /* Now finally construct the name */
697 CzechPattern pattern
= _name_czech_adj
[prefix
].pattern
;
699 buf
= strecpy(buf
, _name_czech_adj
[prefix
].name
, last
);
701 char *endpos
= buf
- 1;
702 /* Find the first character in a UTF-8 sequence */
703 while (GB(*endpos
, 6, 2) == 2) endpos
--;
705 if (gender
== CZG_SMASC
&& pattern
== CZP_PRIVL
) {
706 assert(endpos
>= orig
+ 2);
709 assert(*(endpos
- 1) == 'v');
712 assert(endpos
>= orig
);
713 endpos
= strecpy(endpos
, _name_czech_patmod
[gender
][pattern
], last
);
716 buf
= strecpy(endpos
, " ", last
);
720 buf
= strecpy(buf
, _name_czech_subst_stem
[stem
].name
, last
);
721 if (postfix
< lengthof(_name_czech_subst_postfix
)) {
722 const char *poststr
= _name_czech_subst_postfix
[postfix
];
723 const char *endstr
= _name_czech_subst_ending
[ending
].name
;
725 size_t postlen
= strlen(poststr
);
726 size_t endlen
= strlen(endstr
);
727 assert(postlen
> 0 && endlen
> 0);
729 /* Kill the "avava" and "Jananna"-like cases */
730 if (postlen
< 2 || postlen
> endlen
||
731 ((poststr
[1] != 'v' || poststr
[1] != endstr
[1]) &&
732 poststr
[2] != endstr
[1])) {
733 buf
= strecpy(buf
, poststr
, last
);
735 /* k-i -> c-i, h-i -> z-i */
736 if (endstr
[0] == 'i') {
737 switch (*(buf
- 1)) {
738 case 'k': *(buf
- 1) = 'c'; break;
739 case 'h': *(buf
- 1) = 'z'; break;
745 buf
= strecpy(buf
, _name_czech_subst_ending
[ending
].name
, last
);
747 buf
= strecpy(buf
, _name_czech_subst_full
[stem
].name
, last
);
751 buf
= strecpy(buf
, " ", last
);
752 buf
= strecpy(buf
, _name_czech_suffix
[suffix
], last
);
760 * Generates Romanian town name from given seed.
761 * @param buf output buffer
762 * @param seed town name seed
763 * @param last end of buffer
765 static char *MakeRomanianTownName(char *buf
, const char *last
, uint32 seed
)
767 return strecpy(buf
, _name_romanian_real
[SeedChance(0, lengthof(_name_romanian_real
), seed
)], last
);
772 * Generates Slovak town name from given seed.
773 * @param buf output buffer
774 * @param seed town name seed
775 * @param last end of buffer
777 static char *MakeSlovakTownName(char *buf
, const char *last
, uint32 seed
)
779 return strecpy(buf
, _name_slovak_real
[SeedChance(0, lengthof(_name_slovak_real
), seed
)], last
);
784 * Generates Norwegian town name from given seed.
785 * @param buf output buffer
786 * @param seed town name seed
787 * @param last end of buffer
789 static char *MakeNorwegianTownName(char *buf
, const char *last
, uint32 seed
)
791 /* Use first 4 bit from seed to decide whether or not this town should
792 * have a real name 3/16 chance. Bit 0-3 */
793 if (SeedChance(0, 15, seed
) < 3) {
794 /* Use 7bit for the realname table index. Bit 4-10 */
795 return strecpy(buf
, _name_norwegian_real
[SeedChance(4, lengthof(_name_norwegian_real
), seed
)], last
);
798 /* Use 7bit for the first fake part. Bit 4-10 */
799 buf
= strecpy(buf
, _name_norwegian_1
[SeedChance(4, lengthof(_name_norwegian_1
), seed
)], last
);
800 /* Use 7bit for the last fake part. Bit 11-17 */
801 buf
= strecpy(buf
, _name_norwegian_2
[SeedChance(11, lengthof(_name_norwegian_2
), seed
)], last
);
808 * Generates Hungarian town name from given seed.
809 * @param buf output buffer
810 * @param seed town name seed
811 * @param last end of buffer
813 static char *MakeHungarianTownName(char *buf
, const char *last
, uint32 seed
)
815 if (SeedChance(12, 15, seed
) < 3) {
816 return strecpy(buf
, _name_hungarian_real
[SeedChance(0, lengthof(_name_hungarian_real
), seed
)], last
);
819 /* optional first segment */
820 uint i
= SeedChance(3, lengthof(_name_hungarian_1
) * 3, seed
);
821 if (i
< lengthof(_name_hungarian_1
)) buf
= strecpy(buf
, _name_hungarian_1
[i
], last
);
823 /* mandatory middle segments */
824 buf
= strecpy(buf
, _name_hungarian_2
[SeedChance(3, lengthof(_name_hungarian_2
), seed
)], last
);
825 buf
= strecpy(buf
, _name_hungarian_3
[SeedChance(6, lengthof(_name_hungarian_3
), seed
)], last
);
827 /* optional last segment */
828 i
= SeedChance(10, lengthof(_name_hungarian_4
) * 3, seed
);
829 if (i
< lengthof(_name_hungarian_4
)) {
830 buf
= strecpy(buf
, _name_hungarian_4
[i
], last
);
838 * Generates Swiss town name from given seed.
839 * @param buf output buffer
840 * @param seed town name seed
841 * @param last end of buffer
843 static char *MakeSwissTownName(char *buf
, const char *last
, uint32 seed
)
845 return strecpy(buf
, _name_swiss_real
[SeedChance(0, lengthof(_name_swiss_real
), seed
)], last
);
850 * Generates Danish town name from given seed.
851 * @param buf output buffer
852 * @param seed town name seed
853 * @param last end of buffer
855 static char *MakeDanishTownName(char *buf
, const char *last
, uint32 seed
)
857 /* optional first segment */
858 int i
= SeedChanceBias(0, lengthof(_name_danish_1
), seed
, 50);
859 if (i
>= 0) buf
= strecpy(buf
, _name_danish_1
[i
], last
);
861 /* middle segments removed as this algorithm seems to create much more realistic names */
862 buf
= strecpy(buf
, _name_danish_2
[SeedChance( 7, lengthof(_name_danish_2
), seed
)], last
);
863 buf
= strecpy(buf
, _name_danish_3
[SeedChance(16, lengthof(_name_danish_3
), seed
)], last
);
870 * Generates Turkish town name from given seed.
871 * @param buf output buffer
872 * @param seed town name seed
873 * @param last end of buffer
875 static char *MakeTurkishTownName(char *buf
, const char *last
, uint32 seed
)
877 uint i
= SeedModChance(0, 5, seed
);
881 buf
= strecpy(buf
, _name_turkish_prefix
[SeedModChance( 2, lengthof(_name_turkish_prefix
), seed
)], last
);
884 buf
= strecpy(buf
, _name_turkish_middle
[SeedModChance( 4, lengthof(_name_turkish_middle
), seed
)], last
);
886 /* optional suffix */
887 if (SeedModChance(0, 7, seed
) == 0) {
888 buf
= strecpy(buf
, _name_turkish_suffix
[SeedModChance( 10, lengthof(_name_turkish_suffix
), seed
)], last
);
893 buf
= strecpy(buf
, _name_turkish_prefix
[SeedModChance( 2, lengthof(_name_turkish_prefix
), seed
)], last
);
894 buf
= strecpy(buf
, _name_turkish_suffix
[SeedModChance( 4, lengthof(_name_turkish_suffix
), seed
)], last
);
898 buf
= strecpy(buf
, _name_turkish_real
[SeedModChance( 4, lengthof(_name_turkish_real
), seed
)], last
);
907 * Generates Italian town name from given seed.
908 * @param buf output buffer
909 * @param seed town name seed
910 * @param last end of buffer
912 static char *MakeItalianTownName(char *buf
, const char *last
, uint32 seed
)
914 if (SeedModChance(0, 6, seed
) == 0) { // real city names
915 return strecpy(buf
, _name_italian_real
[SeedModChance(4, lengthof(_name_italian_real
), seed
)], last
);
918 static const char * const mascul_femin_italian
[] = {
923 if (SeedModChance(0, 8, seed
) == 0) { // prefix
924 buf
= strecpy(buf
, _name_italian_pref
[SeedModChance(11, lengthof(_name_italian_pref
), seed
)], last
);
927 uint i
= SeedChance(0, 2, seed
);
928 if (i
== 0) { // masculine form
929 buf
= strecpy(buf
, _name_italian_1m
[SeedModChance(4, lengthof(_name_italian_1m
), seed
)], last
);
930 } else { // feminine form
931 buf
= strecpy(buf
, _name_italian_1f
[SeedModChance(4, lengthof(_name_italian_1f
), seed
)], last
);
934 if (SeedModChance(3, 3, seed
) == 0) {
935 buf
= strecpy(buf
, _name_italian_2
[SeedModChance(11, lengthof(_name_italian_2
), seed
)], last
);
936 buf
= strecpy(buf
, mascul_femin_italian
[i
], last
);
938 buf
= strecpy(buf
, _name_italian_2i
[SeedModChance(16, lengthof(_name_italian_2i
), seed
)], last
);
941 if (SeedModChance(15, 4, seed
) == 0) {
942 if (SeedModChance(5, 2, seed
) == 0) { // generic suffix
943 buf
= strecpy(buf
, _name_italian_3
[SeedModChance(4, lengthof(_name_italian_3
), seed
)], last
);
944 } else { // river name suffix
945 buf
= strecpy(buf
, _name_italian_river1
[SeedModChance(4, lengthof(_name_italian_river1
), seed
)], last
);
946 buf
= strecpy(buf
, _name_italian_river2
[SeedModChance(16, lengthof(_name_italian_river2
), seed
)], last
);
955 * Generates Catalan town name from given seed.
956 * @param buf output buffer
957 * @param seed town name seed
958 * @param last end of buffer
960 static char *MakeCatalanTownName(char *buf
, const char *last
, uint32 seed
)
962 if (SeedModChance(0, 3, seed
) == 0) { // real city names
963 return strecpy(buf
, _name_catalan_real
[SeedModChance(4, lengthof(_name_catalan_real
), seed
)], last
);
966 if (SeedModChance(0, 2, seed
) == 0) { // prefix
967 buf
= strecpy(buf
, _name_catalan_pref
[SeedModChance(11, lengthof(_name_catalan_pref
), seed
)], last
);
970 uint i
= SeedChance(0, 2, seed
);
971 if (i
== 0) { // masculine form
972 buf
= strecpy(buf
, _name_catalan_1m
[SeedModChance(4, lengthof(_name_catalan_1m
), seed
)], last
);
973 buf
= strecpy(buf
, _name_catalan_2m
[SeedModChance(11, lengthof(_name_catalan_2m
), seed
)], last
);
974 } else { // feminine form
975 buf
= strecpy(buf
, _name_catalan_1f
[SeedModChance(4, lengthof(_name_catalan_1f
), seed
)], last
);
976 buf
= strecpy(buf
, _name_catalan_2f
[SeedModChance(11, lengthof(_name_catalan_2f
), seed
)], last
);
979 if (SeedModChance(15, 5, seed
) == 0) {
980 if (SeedModChance(5, 2, seed
) == 0) { // generic suffix
981 buf
= strecpy(buf
, _name_catalan_3
[SeedModChance(4, lengthof(_name_catalan_3
), seed
)], last
);
982 } else { // river name suffix
983 buf
= strecpy(buf
, _name_catalan_river1
[SeedModChance(4, lengthof(_name_catalan_river1
), seed
)], last
);
992 * Type for all town name generator functions.
993 * @param buf The buffer to write the name to.
994 * @param last The last element of the buffer.
995 * @param seed The seed of the town name.
996 * @return The end of the filled buffer.
998 typedef char *TownNameGenerator(char *buf
, const char *last
, uint32 seed
);
1000 /** Contains pointer to generator and minimum buffer size (not incl. terminating '\0') */
1001 struct TownNameGeneratorParams
{
1002 byte min
; ///< minimum number of characters that need to be printed for generator to work correctly
1003 TownNameGenerator
*proc
; ///< generator itself
1006 /** Town name generators */
1007 static const TownNameGeneratorParams _town_name_generators
[] = {
1008 { 4, MakeEnglishOriginalTownName
}, // replaces first 4 characters of name
1009 { 0, MakeFrenchTownName
},
1010 { 0, MakeGermanTownName
},
1011 { 4, MakeEnglishAdditionalTownName
}, // replaces first 4 characters of name
1012 { 0, MakeSpanishTownName
},
1013 { 0, MakeSillyTownName
},
1014 { 0, MakeSwedishTownName
},
1015 { 0, MakeDutchTownName
},
1016 { 8, MakeFinnishTownName
}, // _name_finnish_1
1017 { 0, MakePolishTownName
},
1018 { 0, MakeSlovakTownName
},
1019 { 0, MakeNorwegianTownName
},
1020 { 0, MakeHungarianTownName
},
1021 { 0, MakeAustrianTownName
},
1022 { 0, MakeRomanianTownName
},
1023 { 28, MakeCzechTownName
}, // _name_czech_adj + _name_czech_patmod + 1 + _name_czech_subst_stem + _name_czech_subst_postfix
1024 { 0, MakeSwissTownName
},
1025 { 0, MakeDanishTownName
},
1026 { 0, MakeTurkishTownName
},
1027 { 0, MakeItalianTownName
},
1028 { 0, MakeCatalanTownName
},
1033 * Generates town name from given seed. a language.
1034 * @param buf output buffer
1035 * @param last end of buffer
1036 * @param lang town name language
1037 * @param seed generation seed
1038 * @return last character ('/0')
1040 char *GenerateTownNameString(char *buf
, const char *last
, size_t lang
, uint32 seed
)
1042 assert(lang
< lengthof(_town_name_generators
));
1044 /* Some generators need at least 9 bytes in buffer. English generators need 5 for
1045 * string replacing, others use constructions like strlen(buf)-3 and so on.
1046 * Finnish generator needs to fit all strings from _name_finnish_1.
1047 * Czech generator needs to fit almost whole town name...
1048 * These would break. Using another temporary buffer results in ~40% slower code,
1049 * so use it only when really needed. */
1050 const TownNameGeneratorParams
*par
= &_town_name_generators
[lang
];
1051 if (last
>= buf
+ par
->min
) return par
->proc(buf
, last
, seed
);
1053 char *buffer
= AllocaM(char, par
->min
+ 1);
1054 par
->proc(buffer
, buffer
+ par
->min
, seed
);
1056 return strecpy(buf
, buffer
, last
);