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 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}