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 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 vd.field_script_value_rooted("undesirable_infamy_level", Scopes::Country);
72 vd.field_script_value_rooted("unacceptable_infamy_level", Scopes::Country);
74 vd.field_script_value_rooted("ideological_opinion_effect_mult", Scopes::Country);
76 vd.field_script_value_rooted("revolution_aversion", Scopes::Country);
78 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 vd.field_script_value_rooted("max_progressiveness", Scopes::Country);
95 vd.field_script_value_rooted("max_regressiveness", Scopes::Country);
97
98 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); 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); 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
223const 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); 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}