1use crate::block::Block;
2use crate::ck3::data::maa::{
3 validate_holding_bonus, validate_terrain_bonus, validate_winter_bonus,
4};
5use crate::ck3::modif::ModifKinds;
6use crate::context::ScopeContext;
7use crate::db::{Db, DbKind};
8use crate::desc::validate_desc;
9use crate::everything::Everything;
10use crate::game::GameFlags;
11use crate::item::{Item, ItemLoader};
12use crate::modif::validate_modifs;
13use crate::report::{ErrorKey, err};
14use crate::scopes::Scopes;
15use crate::token::Token;
16use crate::tooltipped::Tooltipped;
17use crate::validator::Validator;
18
19#[derive(Clone, Debug)]
20pub struct AccoladeIcon {}
21
22inventory::submit! {
23 ItemLoader::Normal(GameFlags::Ck3, Item::AccoladeIcon, AccoladeIcon::add)
24}
25
26impl AccoladeIcon {
27 pub fn add(db: &mut Db, key: Token, block: Block) {
28 db.add(Item::AccoladeIcon, key, block, Box::new(Self {}));
29 }
30}
31
32impl DbKind for AccoladeIcon {
33 fn validate(&self, key: &Token, block: &Block, data: &Everything) {
34 let mut vd = Validator::new(block, data);
35 let mut sc = ScopeContext::new(Scopes::AccoladeType, key);
36 sc.define_name("accolade", Scopes::Accolade, key);
37
38 if let Some(token) = vd.field_value("texture") {
39 let pathname = format!("gfx/interface/icons/knight_badge/icons/{token}");
40 data.verify_exists_implied(Item::File, &pathname, token);
41 }
42
43 vd.field_trigger("potential", Tooltipped::No, &mut sc);
44 }
45}
46
47#[derive(Clone, Debug)]
48pub struct AccoladeName {}
49
50inventory::submit! {
51 ItemLoader::Normal(GameFlags::Ck3, Item::AccoladeName, AccoladeName::add)
52}
53
54impl AccoladeName {
55 pub fn add(db: &mut Db, key: Token, block: Block) {
56 db.add(Item::AccoladeName, key, block, Box::new(Self {}));
57 }
58}
59
60impl DbKind for AccoladeName {
61 fn validate(&self, key: &Token, block: &Block, data: &Everything) {
62 let mut vd = Validator::new(block, data);
63 let mut sc = ScopeContext::new(Scopes::Character, key);
64 sc.define_name("owner", Scopes::Character, key);
65 sc.define_name("accolade_type", Scopes::AccoladeType, key);
66
67 vd.req_field("key");
68 vd.req_field("num_options");
69
70 vd.field_item("key", Item::Localization);
71 vd.field_integer("num_options");
72 if let Some(key) = block.get_field_value("key") {
73 if let Some(n) = block.get_field_integer("num_options") {
74 data.localization.verify_key_has_options(key.as_str(), key, n, "OPTION_");
75 }
76 }
77
78 let mut count = 0;
79 vd.multi_field_validated("option", |bv, data| {
80 count += 1;
81 validate_desc(bv, data, &mut sc);
82 });
83
84 if let Some(n) = block.get_field_integer("num_options") {
85 if count != n {
86 let msg = format!("expected {n} `option` blocks, found {count}");
87 err(ErrorKey::Validation).msg(msg).loc(block).push();
88 }
89 }
90
91 vd.field_trigger("potential", Tooltipped::No, &mut sc);
92
93 vd.field_script_value("weight", &mut sc);
94 }
95}
96
97#[derive(Clone, Debug)]
98pub struct AccoladeType {}
99
100inventory::submit! {
101 ItemLoader::Normal(GameFlags::Ck3, Item::AccoladeType, AccoladeType::add)
102}
103
104impl AccoladeType {
105 pub fn add(db: &mut Db, key: Token, block: Block) {
106 db.add(Item::AccoladeType, key, block, Box::new(Self {}));
107 }
108}
109
110impl DbKind for AccoladeType {
111 fn add_subitems(&self, _key: &Token, block: &Block, db: &mut Db) {
112 if let Some(vec) = block.get_field_list("accolade_categories") {
113 for token in vec {
114 db.add_flag(Item::AccoladeCategory, token);
115 }
116 }
117 if let Some(block) = block.get_field_block("ranks") {
118 for (key, block) in block.iter_definitions() {
119 if key.is_integer() {
120 if let Some(vec) = block.get_field_list("accolade_parameters") {
121 for token in vec {
122 db.add_flag(Item::AccoladeParameter, token);
123 }
124 }
125 }
126 }
127 }
128 }
129
130 fn validate(&self, key: &Token, block: &Block, data: &Everything) {
131 let mut vd = Validator::new(block, data);
132 let mut sc = ScopeContext::new(Scopes::Character, key);
133
134 data.verify_exists(Item::Localization, key);
135 let loca = format!("{key}_modifier");
136 data.verify_exists_implied(Item::Localization, &loca, key);
137
138 vd.field_item("adjective", Item::Localization);
139 vd.field_item("noun", Item::Localization);
140 vd.field_list("accolade_categories");
141
142 vd.field_trigger("potential", Tooltipped::Yes, &mut sc);
143
144 sc.define_name("owner", Scopes::Character, key);
145 vd.field_script_value("weight", &mut sc);
146
147 vd.field_validated_block("ranks", |block, data| {
148 let mut vd = Validator::new(block, data);
149 for (_, block) in vd.integer_blocks() {
150 let mut vd = Validator::new(block, data);
151 vd.field_validated_block("liege_modifier", |block, data| {
152 let vd = Validator::new(block, data);
153 validate_modifs(block, data, ModifKinds::Character, vd);
154 });
155 vd.field_validated_block("knight_modifier", |block, data| {
156 let vd = Validator::new(block, data);
157 validate_modifs(block, data, ModifKinds::Character, vd);
158 });
159 vd.field_validated_block("knight_army_modifier", |block, data| {
160 let vd = Validator::new(block, data);
161 validate_modifs(block, data, ModifKinds::Character, vd);
162 });
163 vd.field_list_items("men_at_arms", Item::MenAtArms);
164 vd.field_validated_block("terrain_bonus", |block, data| {
165 let mut vd = Validator::new(block, data);
166 vd.unknown_block_fields(|key, block| {
167 data.verify_exists(Item::MenAtArms, key);
168 validate_terrain_bonus(block, data);
169 });
170 });
171 vd.field_validated_block("holding_bonus", |block, data| {
172 let mut vd = Validator::new(block, data);
173 vd.unknown_block_fields(|key, block| {
174 data.verify_exists(Item::MenAtArms, key);
175 validate_holding_bonus(block, data);
176 });
177 });
178 vd.field_validated_block("winter_bonus", |block, data| {
179 let mut vd = Validator::new(block, data);
180 vd.unknown_block_fields(|key, block| {
181 data.verify_exists(Item::MenAtArms, key);
182 validate_winter_bonus(block, data);
183 });
184 });
185 vd.field_list_items("accolade_parameters", Item::Localization);
186 }
187 });
188 }
189}