tiger_lib/vic3/data/
countries.rs

1use crate::block::Block;
2use crate::context::ScopeContext;
3use crate::db::{Db, DbKind};
4use crate::everything::Everything;
5use crate::game::GameFlags;
6use crate::item::{Item, ItemLoader};
7use crate::modif::validate_modifs;
8use crate::scopes::Scopes;
9use crate::token::Token;
10use crate::tooltipped::Tooltipped;
11use crate::validate::validate_possibly_named_color;
12use crate::validator::Validator;
13use crate::vic3::modif::ModifKinds;
14use crate::vic3::tables::modifs::maybe_warn_modifiable_capitalization;
15
16#[derive(Clone, Debug)]
17pub struct Country {}
18
19inventory::submit! {
20    ItemLoader::Normal(GameFlags::Vic3, Item::Country, Country::add)
21}
22
23impl Country {
24    pub fn add(db: &mut Db, key: Token, block: Block) {
25        db.add(Item::Country, key, block, Box::new(Self {}));
26    }
27}
28
29impl DbKind for Country {
30    fn validate(&self, key: &Token, block: &Block, data: &Everything) {
31        let mut vd = Validator::new(block, data);
32
33        data.verify_exists(Item::Localization, key);
34        let loca = format!("{key}_ADJ");
35        data.verify_exists_implied(Item::Localization, &loca, key);
36
37        vd.field_validated("color", validate_possibly_named_color);
38        vd.field_item("country_type", Item::CountryType);
39        vd.field_item("tier", Item::CountryTier);
40        vd.field_item("social_hierarchy", Item::SocialHierarchy);
41        vd.field_list_items("cultures", Item::Culture);
42        vd.field_item("religion", Item::Religion);
43        vd.field_item("capital", Item::StateRegion);
44        vd.field_bool("is_named_from_capital");
45        vd.field_bool("dynamic_country_definition");
46
47        vd.field_validated("primary_unit_color", validate_possibly_named_color);
48        vd.field_validated("secondary_unit_color", validate_possibly_named_color);
49        vd.field_validated("tertiary_unit_color", validate_possibly_named_color);
50
51        // TODO: what is the scope type here?
52        vd.field_trigger_rooted(
53            "valid_as_home_country_for_separatists",
54            Tooltipped::No,
55            Scopes::None,
56        );
57    }
58}
59
60#[derive(Clone, Debug)]
61pub struct CountryType {}
62
63inventory::submit! {
64    ItemLoader::Normal(GameFlags::Vic3, Item::CountryType, CountryType::add)
65}
66
67impl CountryType {
68    pub fn add(db: &mut Db, key: Token, block: Block) {
69        db.add(Item::CountryType, key, block, Box::new(Self {}));
70    }
71}
72
73impl DbKind for CountryType {
74    fn validate(&self, _key: &Token, block: &Block, data: &Everything) {
75        let mut vd = Validator::new(block, data);
76
77        vd.field_bool("is_colonizable");
78        vd.field_bool("is_unrecognized");
79        vd.field_bool("uses_prestige");
80        vd.field_bool("has_events");
81        vd.field_bool("has_military");
82        vd.field_bool("has_economy");
83        vd.field_bool("has_politics");
84        vd.field_bool("can_research");
85
86        vd.req_field("default_rank");
87        vd.field_item("default_rank", Item::CountryRank);
88        vd.field_item("default_subject_type", Item::SubjectType);
89    }
90}
91
92#[derive(Clone, Debug)]
93pub struct CountryRank {}
94
95inventory::submit! {
96    ItemLoader::Normal(GameFlags::Vic3, Item::CountryRank, CountryRank::add)
97}
98
99impl CountryRank {
100    pub fn add(db: &mut Db, key: Token, block: Block) {
101        db.add(Item::CountryRank, key, block, Box::new(Self {}));
102    }
103}
104
105impl DbKind for CountryRank {
106    fn validate(&self, key: &Token, block: &Block, data: &Everything) {
107        let mut vd = Validator::new(block, data);
108
109        maybe_warn_modifiable_capitalization(key);
110
111        data.verify_exists(Item::Localization, key);
112        let loca = format!("{key}_desc");
113        data.verify_exists_implied(Item::Localization, &loca, key);
114
115        vd.field_integer("rank_value");
116        vd.field_integer("icon_index");
117        vd.field_bool("enforce_subject_rank_check");
118        vd.field_numeric("diplo_pact_cost");
119        vd.field_numeric("treaty_article_cost");
120        vd.field_numeric("prestige_average_threshold");
121        vd.field_numeric("prestige_relative_threshold");
122        vd.field_numeric("infamy_aggressor_scaling");
123        vd.field_numeric("infamy_target_scaling");
124
125        vd.field_list_items("valid_country_types", Item::CountryType);
126
127        vd.field_validated_block("modifier", |block, data| {
128            let vd = Validator::new(block, data);
129            validate_modifs(block, data, ModifKinds::Country, vd);
130        });
131    }
132}
133
134#[derive(Clone, Debug)]
135pub struct CountryFormation {}
136
137inventory::submit! {
138    ItemLoader::Normal(GameFlags::Vic3, Item::CountryFormation, CountryFormation::add)
139}
140
141impl CountryFormation {
142    pub fn add(db: &mut Db, key: Token, block: Block) {
143        db.add(Item::CountryFormation, key, block, Box::new(Self {}));
144    }
145}
146
147impl DbKind for CountryFormation {
148    fn validate(&self, key: &Token, block: &Block, data: &Everything) {
149        let mut vd = Validator::new(block, data);
150        vd.set_case_sensitive(false);
151
152        data.verify_exists(Item::Country, key);
153        vd.field_item("geographic_region", Item::GeographicRegion);
154        vd.field_bool("is_major_formation");
155
156        vd.field_bool("use_culture_states");
157        vd.field_numeric("required_states_fraction");
158        vd.field_list_items("states", Item::StateRegion);
159
160        if block.field_value_is("is_major_formation", "yes") {
161            vd.field_item("unification_play", Item::DiplomaticPlay);
162            vd.field_item("leadership_play", Item::DiplomaticPlay);
163        } else {
164            vd.ban_field("unification_play", || "major formations");
165            vd.ban_field("leadership_play", || "major formations");
166        }
167
168        vd.field_trigger_rooted("ai_will_do", Tooltipped::No, Scopes::Country);
169        vd.field_trigger_rooted("possible", Tooltipped::Yes, Scopes::Country);
170
171        // undocumented
172
173        vd.field_integer("max_num_formation_candidates");
174        vd.field_trigger_rooted("can_be_formation_candidate", Tooltipped::No, Scopes::Country);
175        vd.field_trigger_rooted("can_be_unification_target", Tooltipped::Yes, Scopes::Country);
176        vd.field_trigger_rooted("potential", Tooltipped::No, Scopes::Country);
177    }
178}
179
180#[derive(Clone, Debug)]
181pub struct CountryCreation {}
182
183inventory::submit! {
184    ItemLoader::Normal(GameFlags::Vic3, Item::CountryCreation, CountryCreation::add)
185}
186
187impl CountryCreation {
188    pub fn add(db: &mut Db, key: Token, block: Block) {
189        db.add(Item::CountryCreation, key, block, Box::new(Self {}));
190    }
191}
192
193impl DbKind for CountryCreation {
194    fn validate(&self, key: &Token, block: &Block, data: &Everything) {
195        let mut vd = Validator::new(block, data);
196        vd.set_case_sensitive(false);
197        let mut sc = ScopeContext::new(Scopes::Country, key);
198
199        data.verify_exists(Item::Country, key);
200
201        // TODO: verify if `use_culture_states = yes` together with a `states` list is an error
202
203        vd.field_bool("use_culture_states");
204        vd.field_integer("required_num_states");
205        vd.field_list_items("states", Item::StateRegion);
206        vd.field_list_items("provinces", Item::Province);
207
208        vd.field_trigger("possible", Tooltipped::Yes, &mut sc);
209        vd.field_trigger("ai_will_do", Tooltipped::No, &mut sc);
210    }
211}