forked from CleverRaven/Cataclysm-DDA
-
Notifications
You must be signed in to change notification settings - Fork 0
/
name.cpp
166 lines (148 loc) · 4.92 KB
/
name.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#include "name.h"
#include <cstddef>
#include <functional>
#include <map>
#include <string>
#include <utility>
#include <vector>
#include "cata_utility.h"
#include "enum_traits.h"
#include "json.h"
#include "rng.h"
#include "string_formatter.h"
#include "translations.h"
namespace Name
{
names_map &get_names()
{
static names_map names;
return names;
}
static const std::map< std::string, nameFlags > usage_flags = {
{ "given", nameFlags::IsGivenName },
{ "family", nameFlags::IsFamilyName },
{ "universal", nameFlags::IsGivenName | nameFlags::IsFamilyName },
{ "nick", nameFlags::IsNickName },
{ "backer", nameFlags::IsFullName },
{ "city", nameFlags::IsTownName },
{ "world", nameFlags::IsWorldName }
};
static const std::map< std::string, nameFlags > gender_flags {
{ "male", nameFlags::IsMaleName },
{ "female", nameFlags::IsFemaleName },
{ "unisex", nameFlags::IsUnisexName }
};
static nameFlags usage_flag( const std::string &usage )
{
const auto it = usage_flags.find( usage );
if( it != usage_flags.end() ) {
return it->second;
}
return static_cast< nameFlags >( 0 );
}
static nameFlags gender_flag( const std::string &gender )
{
const auto it = gender_flags.find( gender );
if( it != gender_flags.end() ) {
return it->second;
}
return static_cast< nameFlags >( 0 );
}
// The loaded name is one of usage with optional gender.
// The combinations used in names files are as follows.
//
// Backer | (Female|Male|Unisex)
// Given | (Female|Male) // unisex names are duplicated in each group
// Family | Unisex
// Nick
// City
// World
static void load( JsonIn &jsin )
{
jsin.start_array();
while( !jsin.end_array() ) {
JsonObject jo = jsin.get_object();
// get flags of name.
const nameFlags type =
usage_flag( jo.get_string( "usage" ) )
| gender_flag( jo.get_string( "gender", "" ) );
// find group type and add name(s) to group
if( jo.has_array( "name" ) ) {
for( const std::string n : jo.get_array( "name" ) ) {
get_names()[type].push_back( n );
}
} else {
get_names()[type].push_back( jo.get_string( "name" ) );
}
}
}
void load_from_file( const std::string &filename )
{
read_from_file_json( filename, load );
}
// get name groups for which searchFlag is a subset.
//
// i.e. if searchFlag is [ Male|Family ]
// it will match any group with those two flags set, such as [ Unisex|Family ]
using names_vec = std::vector < decltype( get_names().cbegin() ) >;
static names_vec get_matching_groups( nameFlags searchFlags )
{
names_vec matching_groups;
for( auto it = get_names().cbegin(), end = get_names().cend(); it != end; ++it ) {
const nameFlags type = it->first;
if( ( searchFlags & type ) == searchFlags ) {
matching_groups.push_back( it );
}
}
return matching_groups;
}
// Get a random name with the specified flag
std::string get( nameFlags searchFlags )
{
auto matching_groups = get_matching_groups( searchFlags );
if( !matching_groups.empty() ) {
// get number of choices
size_t nChoices = 0;
for( const auto &i : matching_groups ) {
const auto &group = i->second;
nChoices += group.size();
}
// make random selection and return result.
size_t choice = rng( 0, nChoices - 1 );
for( const auto &i : matching_groups ) {
const auto &group = i->second;
if( choice < group.size() ) {
return group[choice];
}
choice -= group.size();
}
}
// BUG, no matching name found.
return std::string( _( "Tom" ) );
}
std::string generate( bool is_male )
{
const nameFlags baseSearchFlags = is_male ? nameFlags::IsMaleName : nameFlags::IsFemaleName;
//One in twenty chance to pull from the backer list, otherwise generate a name from the parts list
if( one_in( 20 ) ) {
return get( baseSearchFlags | nameFlags::IsFullName );
} else {
//~ Used for constructing full name: %1$s is `given name`, %2$s is `family name`
translation full_name_format = to_translation( "Full Name", "%1$s %2$s" );
// Chance to add a nickname to full name
if( one_in( 10 ) ) {
//~ Used for constructing full name with nickname: %1$s is `given name`, %2$s is `family name`, %3$s is `nickname`
full_name_format = to_translation( "Full Name", "%1$s '%3$s' %2$s" );
}
return string_format( full_name_format,
get( baseSearchFlags | nameFlags::IsGivenName ).c_str(),
get( baseSearchFlags | nameFlags::IsFamilyName ).c_str(),
get( nameFlags::IsNickName ).c_str()
);
}
}
void clear()
{
get_names().clear();
}
} // namespace Name