tiger_lib/vic3/data/
ai_strategies.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::report::{ErrorKey, warn};
8use crate::scopes::Scopes;
9use crate::script_value::validate_script_value;
10use crate::token::Token;
11use crate::tooltipped::Tooltipped;
12use crate::validator::Validator;
13use crate::vic3::tables::misc::TREATY_ARTICLE_CATEGORIES;
14
15#[derive(Clone, Debug)]
16pub struct AiStrategy {}
17
18inventory::submit! {
19    ItemLoader::Normal(GameFlags::Vic3, Item::AiStrategy, AiStrategy::add)
20}
21
22impl AiStrategy {
23    pub fn add(db: &mut Db, key: Token, block: Block) {
24        db.add(Item::AiStrategy, key, block, Box::new(Self {}));
25    }
26}
27
28impl DbKind for AiStrategy {
29    fn validate(&self, key: &Token, block: &Block, data: &Everything) {
30        fn sc_builder_support(key: &Token) -> ScopeContext {
31            let mut sc = ScopeContext::new(Scopes::Country, key);
32            sc.define_name("country", Scopes::Country, key);
33            sc.define_name("enemy_country", Scopes::Country, key);
34            sc.define_name("diplomatic_play_type", Scopes::DiplomaticPlayType, key);
35            sc.define_name("is_initiator", Scopes::Bool, key);
36            sc
37        }
38
39        fn sc_builder_plays(key: &Token) -> ScopeContext {
40            let mut sc = ScopeContext::new(Scopes::Country, key);
41            sc.define_name("diplomatic_play", Scopes::DiplomaticPlay, key);
42            sc
43        }
44
45        fn sc_builder_conscripts(key: &Token) -> ScopeContext {
46            let mut sc = ScopeContext::new(Scopes::Country, key);
47            sc.define_name("military_formation", Scopes::MilitaryFormation, key);
48            sc
49        }
50
51        let mut vd = Validator::new(block, data);
52
53        if !key.is("ai_strategy_default") {
54            data.verify_exists(Item::Localization, key);
55            let loca = format!("{key}_desc");
56            data.verify_exists_implied(Item::Localization, &loca, key);
57        }
58
59        vd.field_choice("type", &["administrative", "diplomatic", "political"]);
60
61        vd.field_item("icon", Item::File);
62
63        // TODO verify scope type
64        vd.field_trigger_rooted("will_form_power_bloc", Tooltipped::No, Scopes::Country);
65
66        vd.field_item("desired_tax_level", Item::Level);
67        vd.field_item("max_tax_level", Item::Level);
68        vd.field_item("min_tax_level", Item::Level);
69
70        // TODO verify scope type
71        vd.field_script_value_rooted("undesirable_infamy_level", Scopes::Country);
72        // TODO verify scope type
73        vd.field_script_value_rooted("unacceptable_infamy_level", Scopes::Country);
74        // TODO verify scope type
75        vd.field_script_value_rooted("ideological_opinion_effect_mult", Scopes::Country);
76        // TODO verify scope type
77        vd.field_script_value_rooted("revolution_aversion", Scopes::Country);
78        // TODO verify scope type
79        vd.field_script_value_builder("min_law_chance_to_pass", |key| {
80            let mut sc = ScopeContext::new(Scopes::Country, key);
81            sc.define_name("law", Scopes::Law, key);
82            sc
83        });
84        vd.field_script_value_builder("negotiation_chance", |key| {
85            let mut sc = ScopeContext::new(Scopes::Country, key);
86            sc.define_name("law", Scopes::Law, key);
87            sc.define_name("interest_group", Scopes::InterestGroup, key);
88            sc.define_name("amenability", Scopes::Value, key);
89            sc.define_name("advance_chance", Scopes::Value, key);
90            sc.define_name("stall_chance", Scopes::Value, key);
91            sc
92        });
93        // TODO verify scope type
94        vd.field_script_value_rooted("max_progressiveness", Scopes::Country);
95        // TODO verify scope type
96        vd.field_script_value_rooted("max_regressiveness", Scopes::Country);
97
98        // TODO verify scopes
99        vd.field_script_value_builder("diplomatic_play_support", sc_builder_support);
100        vd.field_script_value_no_breakdown_builder("diplomatic_play_neutrality", sc_builder_plays);
101        vd.field_script_value_no_breakdown_builder("diplomatic_play_boldness", sc_builder_plays);
102        vd.field_validated_key("wargoal_maneuvers_fraction", |key, bv, data| {
103            let mut sc = ScopeContext::new(Scopes::Country, key);
104            sc.define_name("enemy_country", Scopes::Country, key);
105            validate_script_value(bv, data, &mut sc);
106        });
107        vd.field_script_value_rooted("change_law_chance", Scopes::Country);
108
109        vd.field_list_items("pro_interest_groups", Item::InterestGroup);
110        vd.field_list_items("anti_interest_groups", Item::InterestGroup);
111        vd.field_list_items("pro_movements", Item::PoliticalMovement);
112        vd.field_list_items("anti_movements", Item::PoliticalMovement);
113        vd.field_validated_key_block("institution_scores", validate_institution_scores);
114
115        vd.field_validated_key("obligation_value", |key, bv, data| {
116            let mut sc = ScopeContext::new(Scopes::Country, key);
117            sc.define_name("target_country", Scopes::Country, key);
118            validate_script_value(bv, data, &mut sc);
119        });
120        vd.field_script_value_no_breakdown_builder("interest_group_government_weight", |key| {
121            let mut sc = ScopeContext::new(Scopes::Country, key);
122            sc.define_name("interest_group", Scopes::InterestGroup, key);
123            sc
124        });
125        vd.field_validated_key("state_value", |key, bv, data| {
126            let mut sc = ScopeContext::new(Scopes::Country, key);
127            sc.define_name("target_state", Scopes::State, key);
128            sc.define_name("target_country", Scopes::Country, key);
129            validate_script_value(bv, data, &mut sc);
130        });
131        vd.field_validated_key("treaty_port_value", |key, bv, data| {
132            let mut sc = ScopeContext::new(Scopes::Country, key);
133            sc.define_name("target_state", Scopes::State, key);
134            sc.define_name("target_country", Scopes::Country, key);
135            validate_script_value(bv, data, &mut sc);
136        });
137        vd.field_validated_key("subject_value", |key, bv, data| {
138            let mut sc = ScopeContext::new(Scopes::Country, key);
139            sc.define_name("target_country", Scopes::Country, key);
140            validate_script_value(bv, data, &mut sc);
141        });
142        vd.field_validated_key("become_subject_value", |key, bv, data| {
143            let mut sc = ScopeContext::new(Scopes::Country, key);
144            sc.define_name("overlord", Scopes::Country, key);
145            validate_script_value(bv, data, &mut sc);
146        });
147        vd.field_validated_key("recklessness", |key, bv, data| {
148            let mut sc = ScopeContext::new(Scopes::Country, key);
149            sc.define_name("target_country", Scopes::Country, key);
150            validate_script_value(bv, data, &mut sc);
151        });
152        vd.field_validated_key("aggression", |key, bv, data| {
153            let mut sc = ScopeContext::new(Scopes::Country, key);
154            sc.define_name("target_country", Scopes::Country, key);
155            validate_script_value(bv, data, &mut sc);
156        });
157        vd.field_script_value_rooted("wanted_construction_output", Scopes::Country);
158        vd.replaced_field("wanted_construction_sector_levels", "wanted_construction_output");
159        vd.field_script_value_rooted("wanted_army_size", Scopes::Country);
160        vd.field_script_value_rooted("wanted_navy_size", Scopes::Country);
161
162        vd.field_validated_key_block(
163            "combat_unit_group_weights",
164            validate_combat_unit_group_weights,
165        );
166
167        vd.field_script_value_no_breakdown_builder(
168            "conscript_battalion_ratio",
169            sc_builder_conscripts,
170        );
171
172        vd.field_script_value_no_breakdown_rooted("nationalization_desire", Scopes::Country);
173
174        vd.field_validated_key_block("building_group_weights", validate_building_group_weights);
175
176        vd.field_validated_key_block("subsidies", validate_subsidies);
177        vd.field_validated_key_block("war_subsidies", validate_subsidies);
178        vd.field_validated_key_block("goods_stances", validate_goods_stances);
179
180        vd.field_script_value_rooted("colonial_interest_ratio", Scopes::Country);
181        vd.field_validated_block("liberate_country_scores", validate_liberate_country_scores);
182        vd.field_validated_key_block("strategic_region_scores", validate_strategic_region_scores);
183        vd.field_validated_key_block("secret_goal_scores", validate_secret_goal_scores);
184        vd.field_validated_key_block("secret_goal_weights", validate_secret_goal_weights);
185        vd.field_validated_key_block("treaty_category_scores", validate_treaty_category_scores);
186        vd.field_validated_key_block("wargoal_scores", validate_wargoal_scores);
187        vd.field_validated_key_block("wargoal_weights", validate_wargoal_weights);
188
189        vd.field_trigger_rooted("possible", Tooltipped::No, Scopes::Country); // TODO scope type
190        vd.field_script_value_rooted("weight", Scopes::Country);
191
192        vd.field_script_value_rooted("economic_vs_government_spending_balance", Scopes::Country);
193    }
194}
195
196fn validate_institution_scores(key: &Token, block: &Block, data: &Everything) {
197    let mut vd = Validator::new(block, data);
198    let mut sc = ScopeContext::new(Scopes::Country, key); // TODO verify scope type
199    vd.unknown_fields(|key, bv| {
200        data.verify_exists(Item::Institution, key);
201        validate_script_value(bv, data, &mut sc);
202    });
203}
204
205fn validate_combat_unit_group_weights(_key: &Token, block: &Block, data: &Everything) {
206    let mut vd = Validator::new(block, data);
207    vd.unknown_fields(|key, bv| {
208        data.verify_exists(Item::CombatUnitGroup, key);
209        let mut sc = ScopeContext::new(Scopes::Country, key);
210        sc.define_name("military_formation", Scopes::MilitaryFormation, key);
211        validate_script_value(bv, data, &mut sc);
212    });
213}
214
215fn validate_building_group_weights(_key: &Token, block: &Block, data: &Everything) {
216    let mut vd = Validator::new(block, data);
217    vd.unknown_value_fields(|key, token| {
218        data.verify_exists(Item::BuildingGroup, key);
219        token.expect_number();
220    });
221}
222
223// TODO what other options?
224const SUBSIDIES_TYPES: &[&str] = &["should_have", "wants_to_have", "must_have", "nice_to_have"];
225fn validate_subsidies(_key: &Token, block: &Block, data: &Everything) {
226    let mut vd = Validator::new(block, data);
227    vd.unknown_value_fields(|key, token| {
228        data.verify_exists(Item::BuildingType, key);
229        if !SUBSIDIES_TYPES.contains(&token.as_str()) {
230            warn(ErrorKey::Validation).weak().msg("unknown subsidy type").loc(token).push();
231        }
232    });
233}
234
235fn validate_goods_stances(key: &Token, block: &Block, data: &Everything) {
236    let mut vd = Validator::new(block, data);
237    let mut sc = ScopeContext::new(Scopes::Country, key);
238    vd.unknown_block_fields(|key, block| {
239        data.verify_exists(Item::Goods, key);
240        let mut vd = Validator::new(block, data);
241        vd.req_field("stance");
242        vd.field_choice("stance", &["wants_high_supply", "wants_export", "does_not_want"]);
243        vd.field_trigger("trigger", Tooltipped::No, &mut sc);
244    });
245}
246
247fn validate_strategic_region_scores(key: &Token, block: &Block, data: &Everything) {
248    let mut vd = Validator::new(block, data);
249    let mut sc = ScopeContext::new(Scopes::Country, key);
250    vd.unknown_fields(|key, bv| {
251        data.verify_exists(Item::StrategicRegion, key);
252        validate_script_value(bv, data, &mut sc);
253    });
254}
255
256fn validate_secret_goal_scores(key: &Token, block: &Block, data: &Everything) {
257    let mut vd = Validator::new(block, data);
258    let mut sc = ScopeContext::new(Scopes::Country, key);
259    sc.define_name("target_country", Scopes::Country, key);
260    vd.unknown_block_fields(|key, block| {
261        data.verify_exists(Item::SecretGoal, key);
262        let mut vd = Validator::new(block, data);
263        vd.field_trigger("trigger", Tooltipped::No, &mut sc);
264        vd.field_script_value_no_breakdown("score", &mut sc);
265    });
266}
267
268fn validate_secret_goal_weights(_key: &Token, block: &Block, data: &Everything) {
269    let mut vd = Validator::new(block, data);
270    vd.unknown_value_fields(|key, token| {
271        data.verify_exists(Item::SecretGoal, key);
272        token.expect_number();
273    });
274}
275
276fn validate_treaty_category_scores(_key: &Token, block: &Block, data: &Everything) {
277    let mut vd = Validator::new(block, data);
278    for category in TREATY_ARTICLE_CATEGORIES {
279        vd.field_script_value_rooted(category, Scopes::Country);
280    }
281    vd.field_script_value_rooted("none", Scopes::Country);
282}
283
284fn validate_wargoal_scores(key: &Token, block: &Block, data: &Everything) {
285    let mut vd = Validator::new(block, data);
286    let mut sc = ScopeContext::new(Scopes::Country, key);
287    sc.define_name("target_country", Scopes::Country, key);
288    sc.define_name("target_state", Scopes::State, key); // might not be set
289    vd.unknown_fields(|key, bv| {
290        data.verify_exists(Item::WarGoalType, key);
291        validate_script_value(bv, data, &mut sc);
292    });
293}
294
295fn validate_wargoal_weights(_key: &Token, block: &Block, data: &Everything) {
296    let mut vd = Validator::new(block, data);
297    vd.unknown_value_fields(|key, token| {
298        data.verify_exists(Item::WarGoalType, key);
299        token.expect_number();
300    });
301}
302
303fn validate_liberate_country_scores(block: &Block, data: &Everything) {
304    let mut vd = Validator::new(block, data);
305    vd.unknown_fields(|key, bv| {
306        data.verify_exists(Item::Country, key);
307        let mut sc = ScopeContext::new(Scopes::Country, key);
308        sc.define_name("target_country", Scopes::Country, key);
309        validate_script_value(bv, data, &mut sc);
310    });
311}