tiger_lib/ck3/data/
confederations.rs

1use crate::block::Block;
2use crate::ck3::modif::ModifKinds;
3use crate::context::ScopeContext;
4use crate::db::{Db, DbKind};
5use crate::everything::Everything;
6use crate::game::GameFlags;
7use crate::item::{Item, ItemLoader};
8use crate::modif::validate_modifs;
9use crate::scopes::Scopes;
10use crate::token::Token;
11use crate::tooltipped::Tooltipped;
12use crate::validator::{Validator, ValueValidator};
13
14#[derive(Clone, Debug)]
15pub struct ConfederationType {}
16
17inventory::submit! {
18    ItemLoader::Normal(GameFlags::Ck3, Item::ConfederationType, ConfederationType::add)
19}
20
21impl ConfederationType {
22    pub fn add(db: &mut Db, key: Token, block: Block) {
23        db.add(Item::ConfederationType, key, block, Box::new(Self {}));
24    }
25}
26
27impl DbKind for ConfederationType {
28    fn add_subitems(&self, _key: &Token, block: &Block, db: &mut Db) {
29        for block in block.get_field_blocks("cohesion_level") {
30            if let Some(block) = block.get_field_block("parameters") {
31                for (key, _) in block.iter_assignments() {
32                    db.add_flag(Item::CohesionLevelParameter, key.clone());
33                }
34            }
35        }
36    }
37
38    fn validate(&self, key: &Token, block: &Block, data: &Everything) {
39        let loca = format!("confederation_type_{key}_name");
40        data.verify_exists_implied(Item::Localization, &loca, key);
41
42        let mut vd = Validator::new(block, data);
43        vd.field_bool("house_based_confederation");
44        let house_based = block.get_field_bool("house_based_confederation").unwrap_or(false);
45
46        vd.field_script_value_builder("cohesion_base_change_monthly", |key| {
47            let mut sc = ScopeContext::new(Scopes::Confederation, key);
48            // TODO: figure out scope type
49            sc.define_name("bloc", Scopes::all(), key);
50            sc
51        });
52        vd.field_script_value_builder("cohesion_base_change_per_house_monthly", |key| {
53            let mut sc = ScopeContext::new(Scopes::Confederation, key);
54            sc.define_name("house", Scopes::DynastyHouse, key);
55            sc
56        });
57        vd.field_script_value_builder("cohesion_contribution", |key| {
58            let mut sc = ScopeContext::new(Scopes::Confederation, key);
59            sc.define_name("base_value", Scopes::Value, key);
60            sc.define_name("house", Scopes::DynastyHouse, key);
61            sc.define_name("house_relation", Scopes::HouseRelation, key);
62            sc.define_name("other_house", Scopes::DynastyHouse, key);
63            sc.define_name("num_relations", Scopes::Value, key);
64            sc
65        });
66
67        vd.field_script_value_rooted("cohesion_soft_cap", Scopes::Confederation);
68
69        let mut levels = 0;
70        vd.multi_field_validated_block("cohesion_level", |block, data| {
71            levels += 1;
72            let mut vd = Validator::new(block, data);
73            vd.field_numeric("cohesion_threshold");
74            vd.field_validated_block("parameters", |block, data| {
75                let mut vd = Validator::new(block, data);
76                vd.unknown_value_fields(|param, value| {
77                    let loca = format!("{key}_level_parameter_{param}");
78                    data.verify_exists_implied(Item::Localization, &loca, param);
79                    let mut vvd = ValueValidator::new(value, data);
80                    vvd.bool();
81                });
82            });
83            validate_confederation_modifiers(&mut vd, house_based);
84        });
85
86        if levels > 0 {
87            for lvl in 0..=levels {
88                let loca = format!("{key}_level_{lvl:02}");
89                data.verify_exists_implied(Item::Localization, &loca, key);
90            }
91        }
92
93        vd.field_trigger_rooted("is_valid_confederation", Tooltipped::No, Scopes::Confederation);
94        vd.field_effect_rooted("on_confederation_destroyed", Tooltipped::No, Scopes::Confederation);
95
96        validate_confederation_modifiers(&mut vd, house_based);
97
98        let sc_member_builder = |key: &Token| {
99            let mut sc = ScopeContext::new(Scopes::Confederation, key);
100            sc.define_name("character", Scopes::Character, key);
101            if house_based {
102                sc.define_name("house", Scopes::DynastyHouse, key);
103            }
104            sc
105        };
106        vd.field_trigger_builder("is_valid_member_character", Tooltipped::No, sc_member_builder);
107        vd.field_effect_builder("on_member_character_joined", Tooltipped::No, sc_member_builder);
108        vd.field_effect_builder("on_member_character_left", Tooltipped::No, sc_member_builder);
109
110        let sc_house_builder = |key: &Token| {
111            let mut sc = ScopeContext::new(Scopes::Confederation, key);
112            sc.define_name("house", Scopes::DynastyHouse, key);
113            sc
114        };
115        vd.field_trigger_builder("is_valid_member_house", Tooltipped::No, sc_house_builder);
116        vd.field_effect_builder("on_member_house_joined", Tooltipped::No, sc_house_builder);
117        vd.field_effect_builder("on_member_house_left", Tooltipped::No, sc_house_builder);
118    }
119}
120
121fn validate_confederation_modifiers(vd: &mut Validator, house_based: bool) {
122    for field in &[
123        "leading_house_head",
124        "leading_house_member",
125        "aligned_house_head",
126        "aligned_house_member",
127        "divergent_house_head",
128        "divergent_house_member",
129        "any_member_house_head",
130        "any_member_house_member",
131    ] {
132        if house_based {
133            vd.field_validated_block(field, |block, data| {
134                let vd = Validator::new(block, data);
135                validate_modifs(block, data, ModifKinds::Character, vd);
136            });
137        } else {
138            vd.ban_field(field, || "house based confederations");
139        }
140    }
141}