1use crate::block::Block;
2use crate::ck3::modif::ModifKinds;
3use crate::ck3::validate::validate_maa_stats;
4use crate::context::ScopeContext;
5use crate::db::{Db, DbKind};
6use crate::everything::Everything;
7use crate::game::GameFlags;
8use crate::item::{Item, ItemLoader};
9use crate::modif::validate_modifs;
10use crate::report::{ErrorKey, err, warn};
11use crate::scopes::Scopes;
12use crate::token::Token;
13use crate::tooltipped::Tooltipped;
14use crate::validator::{Validator, ValueValidator};
15
16#[derive(Clone, Debug)]
17pub struct Innovation {}
18
19inventory::submit! {
20 ItemLoader::Normal(GameFlags::Ck3, Item::Innovation, Innovation::add)
21}
22
23impl Innovation {
24 pub fn add(db: &mut Db, key: Token, block: Block) {
25 db.add(Item::Innovation, key, block, Box::new(Self {}));
26 }
27}
28
29impl DbKind for Innovation {
30 fn add_subitems(&self, _key: &Token, block: &Block, db: &mut Db) {
31 for token in block.get_field_values("flag") {
32 db.add_flag(Item::InnovationFlag, token.clone());
33 }
34 if let Some(block) = block.get_field_block("parameters") {
35 for (key, _) in block.iter_assignments() {
36 db.add_flag(Item::InnovationParameter, key.clone());
37 db.add_flag(Item::CultureParameter, key.clone());
38 }
39 }
40 }
41
42 fn validate(&self, key: &Token, block: &Block, data: &Everything) {
43 let mut vd = Validator::new(block, data);
44 let mut sc = ScopeContext::new(Scopes::Culture, key);
45
46 data.verify_exists(Item::Localization, key);
47 data.localization.suggest(&format!("{key}_desc"), key);
48
49 vd.field_item("culture_era", Item::CultureEra);
50 vd.field_choice(
51 "group",
52 &["culture_group_military", "culture_group_civic", "culture_group_regional"],
53 );
54 vd.field_item("icon", Item::File);
55 vd.field_item("skill", Item::Skill);
56
57 vd.field_script_value_no_breakdown_rooted("ai_weight_for_spread", Scopes::Character);
58 vd.field_script_value_no_breakdown_builder("ai_weight_for_fascination", |key| {
59 let mut sc = ScopeContext::new(Scopes::Culture, key);
60 sc.define_name("character", Scopes::Character, key);
61 sc
62 });
63
64 vd.multi_field_validated_key_block("asset", |key, block, data| {
65 let mut vd = Validator::new(block, data);
66 vd.field_trigger_rooted("trigger", Tooltipped::No, Scopes::Culture);
67 if !block.has_key("name") && !block.has_key("icon") {
68 let msg = "asset must have `name` or `icon";
69 warn(ErrorKey::FieldMissing).msg(msg).loc(key).push();
70 }
71 vd.field_item("name", Item::Localization);
72 vd.field_item("icon", Item::File);
73 });
74
75 vd.field_item("region", Item::Region);
76 vd.field_trigger("potential", Tooltipped::No, &mut sc);
77 vd.field_trigger("can_progress", Tooltipped::Yes, &mut sc);
78
79 vd.field_validated_block("character_modifier", |block, data| {
82 let vd = Validator::new(block, data);
83 validate_modifs(block, data, ModifKinds::Character, vd);
84 });
85 vd.field_validated_block("culture_modifier", |block, data| {
86 let vd = Validator::new(block, data);
87 validate_modifs(block, data, ModifKinds::Culture, vd);
88 });
89 vd.field_validated_block("county_modifier", |block, data| {
90 let vd = Validator::new(block, data);
91 validate_modifs(block, data, ModifKinds::County, vd);
92 });
93 vd.field_validated_block("province_modifier", |block, data| {
94 let vd = Validator::new(block, data);
95 validate_modifs(block, data, ModifKinds::Province, vd);
96 });
97
98 vd.field_validated_block("parameters", |block, data| {
99 let mut vd = Validator::new(block, data);
100 vd.unknown_value_fields(|key, value| {
101 ValueValidator::new(value, data).bool();
103 let loca = format!("culture_parameter_{}", key.as_str().to_ascii_lowercase());
105 data.verify_exists_implied(Item::Localization, &loca, key);
106 });
107 });
108 vd.multi_field_value("flag");
109
110 vd.multi_field_item("unlock_building", Item::Building);
111 vd.multi_field_item("unlock_decision", Item::Decision);
112 vd.multi_field_item("unlock_casus_belli", Item::CasusBelli);
113 vd.multi_field_item("unlock_maa", Item::MenAtArms);
114 vd.multi_field_item("unlock_law", Item::Law);
115
116 vd.multi_field_item("custom", Item::Localization);
117
118 vd.multi_field_validated_block("maa_upgrade", |block, data| {
119 let mut vd = Validator::new(block, data);
120 if let Some(token) = vd.field_value("type") {
121 if !data.item_exists(Item::MenAtArms, token.as_str())
122 && !data.item_exists(Item::MenAtArmsBase, token.as_str())
123 {
124 let msg = format!("{token} is not a men-at-arms type or base type");
125 err(ErrorKey::MissingItem).msg(msg).loc(token).push();
126 }
127 }
128 validate_maa_stats(&mut vd);
129 });
130 }
131}