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::validator::{Validator, ValueValidator};
12use crate::vic3::modif::ModifKinds;
13
14#[derive(Clone, Debug)]
15pub struct DiplomaticAction {}
16
17inventory::submit! {
18 ItemLoader::Normal(GameFlags::Vic3, Item::DiplomaticAction, DiplomaticAction::add)
19}
20
21impl DiplomaticAction {
22 pub fn add(db: &mut Db, key: Token, block: Block) {
23 db.add(Item::DiplomaticAction, key, block, Box::new(Self {}));
24 }
25}
26
27impl DbKind for DiplomaticAction {
28 fn validate(&self, key: &Token, block: &Block, data: &Everything) {
29 let mut vd = Validator::new(block, data);
30 let mut sc = ScopeContext::new(Scopes::Country, key);
31 sc.define_name("target_country", Scopes::Country, key);
32 sc.define_name("actor", Scopes::Country, key);
34
35 data.verify_exists(Item::Localization, key);
36 let loca = format!("{key}_desc");
37 data.verify_exists_implied(Item::Localization, &loca, key);
38
39 if block.get_field_bool("requires_approval").unwrap_or(true) {
40 let loca = format!("{key}_action_name");
41 data.verify_exists_implied(Item::Localization, &loca, key);
42 if block.get_field_bool("show_in_lens").unwrap_or(true) {
45 let loca = format!("{key}_proposal_accepted_name");
46 data.verify_exists_implied(Item::Localization, &loca, key);
47 let loca = format!("{key}_proposal_accepted_desc");
48 data.verify_exists_implied(Item::Localization, &loca, key);
49 let loca = format!("{key}_proposal_declined_name");
50 data.verify_exists_implied(Item::Localization, &loca, key);
51 let loca = format!("{key}_proposal_declined_desc");
52 data.verify_exists_implied(Item::Localization, &loca, key);
53 let loca = format!("{key}_proposal_notification_name");
54 data.verify_exists_implied(Item::Localization, &loca, key);
55 let loca = format!("{key}_proposal_notification_desc");
56 data.verify_exists_implied(Item::Localization, &loca, key);
57 let loca = format!("{key}_proposal_third_party_accepted_name");
58 data.verify_exists_implied(Item::Localization, &loca, key);
59 let loca = format!("{key}_proposal_third_party_accepted_desc");
60 data.verify_exists_implied(Item::Localization, &loca, key);
61 let loca = format!("{key}_proposal_third_party_declined_name");
62 data.verify_exists_implied(Item::Localization, &loca, key);
63 let loca = format!("{key}_proposal_third_party_declined_desc");
64 data.verify_exists_implied(Item::Localization, &loca, key);
65 }
66 } else {
67 let loca = format!("{key}_action_notification_name");
68 data.verify_exists_implied(Item::Localization, &loca, key);
69 let loca = format!("{key}_action_notification_desc");
70 data.verify_exists_implied(Item::Localization, &loca, key);
71 if block.get_field_bool("should_notify_third_parties").unwrap_or(false) {
72 let loca = format!("{key}_action_notification_third_party_name");
73 data.verify_exists_implied(Item::Localization, &loca, key);
74 let loca = format!("{key}_action_notification_third_party_desc");
75 data.verify_exists_implied(Item::Localization, &loca, key);
76 }
77 }
78 if block.has_key("pact") {
79 let loca = format!("{key}_pact_desc");
80 data.verify_exists_implied(Item::Localization, &loca, key);
81 let loca = format!("{key}_action_propose_name");
82 data.verify_exists_implied(Item::Localization, &loca, key);
83 let loca = format!("{key}_action_break_name");
84 data.verify_exists_implied(Item::Localization, &loca, key);
85 let loca = format!("{key}_action_notification_break_name");
86 data.verify_exists_implied(Item::Localization, &loca, key);
87 let loca = format!("{key}_action_notification_break_desc");
88 data.verify_exists_implied(Item::Localization, &loca, key);
89 if block.get_field_bool("should_notify_third_parties").unwrap_or(false) {
90 let loca = format!("{key}_action_notification_third_party_break_name");
91 data.verify_exists_implied(Item::Localization, &loca, key);
92 let loca = format!("{key}_action_notification_third_party_break_desc");
93 data.verify_exists_implied(Item::Localization, &loca, key);
94 }
95 }
96
97 vd.field_validated_list("groups", |token, data| {
98 let mut vd = ValueValidator::new(token, data);
99 vd.choice(&[
100 "general",
101 "subject",
102 "overlord",
103 "power_bloc",
104 "power_bloc_leader",
105 "power_bloc_member",
106 ]);
107 });
108
109 vd.field_bool("requires_approval");
110 vd.field_bool("uses_random_approval");
111 vd.field_bool("show_confirmation_box");
112 vd.field_bool("is_hostile");
113 vd.field_bool("should_notify_third_parties"); vd.field_bool("show_effect_in_tooltip"); vd.field_bool("violates_sovereignty"); vd.field_bool("can_use_obligations"); vd.field_bool("can_select"); vd.field_bool("can_select_to_break"); vd.field_bool("show_in_lens"); vd.field_choice(
122 "state_selection",
123 &[
124 "first_required",
125 "first_optional",
126 "second_required",
127 "second_optional",
128 "both_required",
129 "both_optional",
130 "any_required",
131 ],
132 );
133 for field in &["first_state_list", "second_state_list"] {
134 vd.field_choice(
135 field,
136 &[
137 "first_country",
138 "second_country",
139 "all",
140 "first_country_and_subjects",
141 "second_country_and_subjects",
142 ],
143 );
144 }
145
146 vd.multi_field_list_items("unlocking_technologies", Item::Technology); vd.field_trigger("selectable", Tooltipped::No, &mut sc);
149 vd.field_trigger("potential", Tooltipped::No, &mut sc);
150 vd.field_trigger("possible", Tooltipped::Yes, &mut sc);
151 for field in &["first_state_trigger", "second_state_trigger"] {
152 vd.field_trigger_builder(field, Tooltipped::Yes, |key| {
153 let mut sc = ScopeContext::new(Scopes::State, key);
154 sc.define_name("country", Scopes::Country, key);
155 sc.define_name("target_country", Scopes::Country, key);
156 sc
157 });
158 }
159 vd.field_effect("accept_effect", Tooltipped::Yes, &mut sc);
160 vd.field_effect("decline_effect", Tooltipped::Yes, &mut sc);
161 vd.advice_field("effect", "the docs say effect but the field is called accept_effect");
162 vd.field_validated_block_sc("pact", &mut sc, validate_pact);
163 vd.field_validated_block_sc("ai", &mut sc, validate_ai);
164
165 vd.field_item("reverse_pact", Item::DiplomaticAction); vd.field_item("transfer_pact", Item::DiplomaticAction); vd.field_item("confirmation_sound", Item::Sound);
169 vd.field_item("request_sound", Item::Sound);
170 vd.field_item("hostile_sound", Item::Sound);
171 vd.field_item("benign_sound", Item::Sound);
172
173 vd.field_item("texture", Item::File);
176 }
177}
178
179fn validate_pact(block: &Block, data: &Everything, sc: &mut ScopeContext) {
180 let mut vd = Validator::new(block, data);
181
182 vd.field_numeric("cost");
183 vd.field_bool("counts_for_tech_spread");
184 vd.field_bool("show_in_outliner"); vd.field_bool("can_be_used_in_sway_offers"); vd.field_integer("sway_maneuvers_cost"); vd.field_bool("infamy_affects_maintenance"); vd.field_bool("has_junior_participant"); vd.field_bool("is_two_sided_pact"); vd.field_bool("is_alliance"); vd.field_bool("is_defensive_pact"); vd.field_bool("is_rivalry"); vd.field_bool("is_embargo"); vd.field_bool("is_trade_agreement"); vd.field_bool("is_customs_union"); vd.field_bool("is_humiliation"); vd.field_bool("is_colonization_rights"); vd.field_bool("is_hostile"); vd.field_bool("is_guarantee_independence"); vd.field_bool("exempt_from_service"); vd.field_bool("is_foreign_investment_rights"); vd.field_bool("junior_support_only_against_overlord"); vd.field_item("subject_type", Item::SubjectType); vd.field_choice("maintenance_paid_by", &["first_country", "second_country"]); vd.advice_field("recipient_pays_maintenance", "removed in 1.9.3");
208
209 vd.replaced_field(
210 "recipient_gets_income_transfer",
211 "renamed to second_country_gets_income_transfer",
212 );
213 vd.field_bool("second_country_gets_income_transfer");
214 vd.replaced_field(
215 "income_transfer_based_on_recipient",
216 "renamed to income_transfer_based_on_second_country",
217 );
218 vd.field_bool("income_transfer_based_on_second_country");
219 vd.field_validated_block("income_transfer_to_pops", |block, data| {
220 let mut vd = Validator::new(block, data);
221 vd.replaced_field("allow_discriminated", "allow_non_fully_accepted");
222 vd.field_bool("allow_non_fully_accepted");
223 for field in &["upper_strata_pops", "middle_strata_pops", "lower_strata_pops"] {
224 vd.field_script_value(field, sc);
225 }
226 });
227 vd.field_numeric("income_transfer"); vd.field_numeric("max_paying_country_income_to_transfer");
229
230 vd.field_numeric("relations_progress_per_day"); vd.field_numeric("relations_improvement_max"); vd.field_numeric("relations_improvement_min"); vd.field_integer("forced_duration");
235 vd.field_integer("max_target_involvement");
236 vd.field_choice(
237 "target_involvement_applies_to",
238 &["source_country", "target_country", "mutual"],
239 );
240
241 vd.field_item("propose_string", Item::Localization);
242 vd.field_item("break_string", Item::Localization);
243 vd.field_item("ask_to_end_string", Item::Localization);
244
245 vd.field_bool("military_access");
246 vd.field_bool("actor_requires_approval_to_break");
247 vd.field_bool("target_requires_approval_to_break");
248 vd.field_bool("is_breaking_hostile");
249 vd.field_bool("is_target_breaking_hostile");
250
251 vd.replaced_field(
252 "is_about_to_auto_break",
253 "show_about_to_break_warning in requirement_to_maintain",
254 );
255 vd.replaced_field("should_auto_break", "trigger in requirement_to_maintain");
256 vd.replaced_field("should_invalidate", "trigger in requirement_to_maintain");
257 vd.field_trigger("actor_can_break", Tooltipped::No, sc);
258 vd.field_trigger("target_can_break", Tooltipped::No, sc);
259 vd.multi_field_validated_block("requirement_to_maintain", |block, data| {
260 let mut vd = Validator::new(block, data);
261 vd.field_trigger("trigger", Tooltipped::No, sc);
262 vd.field_trigger("show_about_to_break_warning", Tooltipped::No, sc);
263 });
264
265 vd.replaced_field("break_effect", "manual_break_effect and auto_break_effect");
266 for field in &[
267 "daily_effect",
268 "weekly_effect",
269 "monthly_effect",
270 "manual_break_effect",
271 "auto_break_effect",
272 ] {
273 vd.field_effect(field, Tooltipped::No, sc);
274 }
275
276 vd.field_validated_block("subject_relation", |block, data| {
277 let mut vd = Validator::new(block, data);
278 vd.field_bool("annex_on_country_formation");
279 });
280
281 vd.multi_field_item("auto_support_type", Item::DiplomaticPlay);
282
283 for field in &["first_modifier", "second_modifier"] {
286 vd.field_validated_block(field, |block, data| {
287 let vd = Validator::new(block, data);
288 validate_modifs(block, data, ModifKinds::Country, vd);
289 });
290 }
291
292 for field in &[
295 "first_foreign_pro_country_lobby_member_modifier",
296 "first_foreign_anti_country_lobby_member_modifier",
297 "second_foreign_pro_country_lobby_member_modifier",
298 "second_foreign_anti_country_lobby_member_modifier",
299 ] {
300 vd.field_validated_block(field, |block, data| {
301 let vd = Validator::new(block, data);
302 validate_modifs(block, data, ModifKinds::InterestGroup, vd);
303 });
304 }
305
306 vd.field_choice("market_owner", &["first_country", "second_country"]);
307}
308
309fn validate_ai(block: &Block, data: &Everything, sc: &mut ScopeContext) {
310 let mut vd = Validator::new(block, data);
311
312 vd.field_script_value_rooted("evaluation_chance", Scopes::Country);
313
314 vd.field_trigger_rooted("will_select_as_first_state", Tooltipped::No, Scopes::State);
315 vd.field_trigger_rooted("will_select_as_second_state", Tooltipped::No, Scopes::State);
316
317 vd.field_bool("check_acceptance_for_will_break");
318 vd.field_bool("check_acceptance_for_will_propose");
319
320 vd.field_numeric_range("max_influence_spending_fraction", 0.0..=1.0);
321
322 for field in &[
323 "will_propose_with_states",
324 "will_propose",
325 "will_break",
326 "will_propose_even_if_not_accepted",
327 ] {
328 vd.field_trigger(field, Tooltipped::No, sc);
329 }
330
331 for field in &[
332 "accept_score",
333 "accept_break_score",
334 "propose_score",
335 "propose_break_score",
336 "use_obligation_chance",
337 "owe_obligation_chance",
338 "junior_accept_score",
339 ] {
340 vd.field_script_value(field, sc);
341 }
342 vd.advice_field("use_favor_chance", "this field is called use_obligation_chance");
343 vd.advice_field("owe_favor_chance", "this field is called owe_obligation_chance");
344}