tiger_lib/ck3/data/
casusbelli.rs

1use crate::block::Block;
2use crate::ck3::validate::validate_cost;
3use crate::context::ScopeContext;
4use crate::db::{Db, DbKind};
5use crate::desc::validate_desc;
6use crate::everything::Everything;
7use crate::game::GameFlags;
8use crate::item::{Item, ItemLoader};
9use crate::scopes::Scopes;
10use crate::token::Token;
11use crate::tooltipped::Tooltipped;
12use crate::validate::validate_duration;
13use crate::validator::Validator;
14
15#[derive(Clone, Debug)]
16pub struct CasusBelli {}
17
18inventory::submit! {
19    ItemLoader::Normal(GameFlags::Ck3, Item::CasusBelli, CasusBelli::add)
20}
21
22impl CasusBelli {
23    pub fn add(db: &mut Db, key: Token, block: Block) {
24        db.add(Item::CasusBelli, key, block, Box::new(Self {}));
25    }
26}
27
28impl DbKind for CasusBelli {
29    fn validate(&self, key: &Token, block: &Block, data: &Everything) {
30        data.verify_exists(Item::Localization, key);
31
32        let mut vd = Validator::new(block, data);
33        let has_claimant = block.has_key("is_allowed_claim_title");
34
35        let sc_builder = |key: &Token| {
36            let mut sc = ScopeContext::new(Scopes::CasusBelli, key);
37            sc.define_name("attacker", Scopes::Character, key);
38            sc.define_name("defender", Scopes::Character, key);
39            // TODO: figure out when claimant is defined
40            sc.define_name("claimant", Scopes::Character, key);
41            // TODO: be more specific about when this list is defined
42            sc.define_list("target_titles", Scopes::LandedTitle, key);
43            if has_claimant {
44                sc.define_name("claimant", Scopes::Character, key);
45            }
46            sc
47        };
48
49        let mut sc = sc_builder(key);
50
51        vd.field_item("group", Item::CasusBelliGroup);
52        let icon = vd.field_value("icon").unwrap_or(key);
53        data.verify_icon("NGameIcons|CASUS_BELLI_TYPE_ICON_PATH", icon, ".dds");
54
55        vd.field_validated_block_rooted(
56            "attacker_ticking_warscore_delay",
57            Scopes::Character,
58            validate_duration,
59        );
60        vd.field_validated_block_rooted(
61            "defender_ticking_warscore_delay",
62            Scopes::Character,
63            validate_duration,
64        );
65        vd.field_numeric("attacker_ticking_warscore");
66        vd.field_numeric("defender_ticking_warscore");
67        vd.field_numeric_range("attacker_wargoal_percentage", 0.0..=1.0);
68        vd.field_numeric_range("defender_wargoal_percentage", 0.0..=1.0);
69        vd.field_numeric("attacker_score_from_occupation_scale");
70        vd.field_numeric("defender_score_from_occupation_scale");
71        vd.field_numeric("attacker_score_from_battles_scale");
72        vd.field_numeric("defender_score_from_battles_scale");
73        vd.field_numeric("max_attacker_score_from_battles");
74        vd.field_numeric("max_defender_score_from_battles");
75        vd.field_numeric("max_attacker_score_from_occupation");
76        vd.field_numeric("max_defender_score_from_occupation");
77        vd.field_bool("full_occupation_by_defender_gives_victory");
78        vd.field_bool("full_occupation_by_attacker_gives_victory");
79        vd.field_bool("landless_attacker_needs_armies");
80        vd.field_bool("allow_hostages");
81
82        vd.field_numeric("occupation_participation_mult");
83        vd.field_numeric("siege_participation_mult");
84        vd.field_numeric("battle_participation_mult");
85
86        vd.field_validated_block_sc("cost", &mut sc, validate_cost);
87
88        vd.field_bool("attacker_capital_gives_war_score");
89        vd.field_bool("defender_capital_gives_war_score");
90        vd.field_bool("imprisonment_by_attacker_give_war_score");
91        vd.field_bool("imprisonment_by_defender_give_war_score");
92
93        let sc_effect_builder = |key: &Token| {
94            let mut sc = sc_builder(key);
95            sc.define_name("war", Scopes::War, key);
96            sc.define_list("attackers", Scopes::LandedTitle, key);
97            sc.define_list("defenders", Scopes::LandedTitle, key);
98            sc
99        };
100
101        // TODO: check which are tooltipped
102        for field in
103            &["on_declaration", "on_victory", "on_white_peace", "on_defeat", "on_invalidated"]
104        {
105            vd.field_effect_builder(field, Tooltipped::No, sc_effect_builder);
106        }
107
108        for field in
109            &["on_victory_desc", "on_defeat_desc", "on_white_peace_desc", "on_invalidated_desc"]
110        {
111            vd.field_validated_sc(field, &mut sc, validate_desc);
112        }
113
114        vd.field_trigger("should_invalidate", Tooltipped::No, &mut sc);
115        vd.field_trigger("mutually_exclusive_titles", Tooltipped::No, &mut sc);
116        vd.field_bool("combine_into_one");
117
118        for (tooltipped, field) in &[
119            (Tooltipped::No, "allowed_for_character"),
120            (Tooltipped::Yes, "allowed_for_character_display_regardless"),
121            (Tooltipped::No, "allowed_against_character"),
122            (Tooltipped::Yes, "allowed_against_character_display_regardless"),
123        ] {
124            vd.field_trigger_builder(field, *tooltipped, |key| {
125                let mut sc = ScopeContext::new(Scopes::Character, key);
126                sc.define_name("attacker", Scopes::Character, key);
127                sc.define_name("defender", Scopes::Character, key);
128                sc.define_list("target_titles", Scopes::LandedTitle, key);
129                sc
130            });
131        }
132
133        for (tooltipped, field) in &[
134            (Tooltipped::No, "valid_to_start"),
135            (Tooltipped::Yes, "valid_to_start_display_regardless"),
136        ] {
137            vd.field_trigger_builder(field, *tooltipped, |key| {
138                let mut sc = ScopeContext::new(Scopes::Character, key);
139                sc.define_name("attacker", Scopes::Character, key);
140                sc.define_name("defender", Scopes::Character, key);
141                sc.define_name("target", Scopes::LandedTitle, key);
142                sc.define_list("target_titles", Scopes::LandedTitle, key);
143                sc
144            });
145        }
146
147        vd.field_trigger_builder("is_allowed_claim_title", Tooltipped::Yes, |key| {
148            let mut sc = ScopeContext::new(Scopes::LandedTitle, key);
149            sc.define_name("attacker", Scopes::Character, key);
150            sc.define_name("defender", Scopes::Character, key);
151            sc.define_name("claimant", Scopes::Character, key);
152            sc.define_list("target_titles", Scopes::LandedTitle, key);
153            sc
154        });
155
156        let choices = &[
157            "none",
158            "neighbor_land",
159            "neighbor_land_or_water",
160            "neighbor_land_tributary",
161            "neighbor_land_or_water_tributary",
162            "de_jure_claim",
163            "title_claim",
164            "all",
165            // undocumented after here
166            "claim",
167            "de_jure",
168            "independence_domain",
169        ];
170        vd.field_choice("target_titles", choices);
171        let choices = &["all", "barony", "county", "duchy", "kingdom", "empire", "hegemony"];
172        vd.field_choice("target_title_tier", choices);
173        vd.field_bool("target_de_jure_regions_above");
174        vd.field_bool("use_de_jure_wargoal_only");
175
176        // undocumented
177        vd.field_item("cb_name", Item::Localization);
178        vd.field_item("cb_name_no_target", Item::Localization);
179
180        vd.field_item("war_name", Item::Localization);
181        vd.field_item("my_war_name", Item::Localization);
182        vd.field_item("war_name_base", Item::Localization);
183        vd.field_item("my_war_name_base", Item::Localization);
184
185        vd.field_integer("truce_days"); // not used in vanilla
186
187        vd.multi_field_value("ignore_effect"); // TODO
188
189        let choices = &["invalidate", "inherit", "inherit_faction"];
190        vd.field_choice("on_primary_attacker_death", choices);
191        vd.field_choice("on_primary_defender_death", choices);
192        vd.field_choice("transfer_behavior", &["invalidate", "transfer"]);
193        vd.field_bool("check_attacker_inheritance_validity");
194        vd.field_bool("check_defender_inheritance_validity");
195        vd.field_bool("attacker_allies_inherit");
196        vd.field_bool("defender_allies_inherit");
197
198        vd.field_integer("interface_priority");
199        vd.field_integer("max_ai_diplo_distance_to_title");
200        vd.field_bool("ai_only_against_liege");
201        vd.field_bool("ai_only_against_neighbors");
202        vd.field_trigger_rooted("ai_can_target_all_titles", Tooltipped::No, Scopes::Character);
203        vd.field_bool("ai");
204
205        vd.field_script_value_no_breakdown_builder("ai_overlord_defensive_power_impact", |key| {
206            let mut sc = ScopeContext::new(Scopes::Character, key);
207            sc.define_name("attacker", Scopes::Character, key);
208            sc.define_name("defender", Scopes::Character, key);
209            sc.define_name("overlord", Scopes::Character, key);
210            sc
211        });
212        vd.field_bool("white_peace_possible");
213        vd.field_bool("check_all_defenders_for_ticking_war_score");
214        vd.field_bool("ticking_war_score_targets_entire_realm");
215
216        vd.field_bool("gui_attacker_faith_might_join");
217        vd.field_bool("gui_defender_faith_might_join");
218        vd.field_bool("defender_faith_can_join");
219        vd.field_bool("is_great_holy_war");
220        vd.field_bool("is_holy_war"); // undocumented
221        vd.field_bool("target_top_liege_if_outside_realm");
222        vd.field_bool("should_check_for_interface_availability");
223
224        vd.field_script_value("ai_score", &mut sc);
225        vd.field_script_value("ai_score_mult", &mut sc);
226
227        // undocumented
228        vd.field_bool("should_show_war_goal_subview");
229    }
230}
231
232#[derive(Clone, Debug)]
233pub struct CasusBelliGroup {}
234
235inventory::submit! {
236    ItemLoader::Normal(GameFlags::Ck3, Item::CasusBelliGroup, CasusBelliGroup::add)
237}
238
239impl CasusBelliGroup {
240    pub fn add(db: &mut Db, key: Token, block: Block) {
241        db.add(Item::CasusBelliGroup, key, block, Box::new(Self {}));
242    }
243}
244
245impl DbKind for CasusBelliGroup {
246    fn validate(&self, _key: &Token, block: &Block, data: &Everything) {
247        let mut vd = Validator::new(block, data);
248        vd.field_trigger_rooted("allowed_for_character", Tooltipped::No, Scopes::Character);
249        vd.field_bool("should_check_for_interface_availability");
250        vd.field_bool("can_only_start_via_script");
251
252        // undocumented
253
254        vd.field_bool("debug");
255    }
256}