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 && let Some(n) = block.get_field_integer("num_options")
74 {
75 data.localization.verify_key_has_options(key.as_str(), key, n, "OPTION_");
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 && count != n
86 {
87 let msg = format!("expected {n} `option` blocks, found {count}");
88 err(ErrorKey::Validation).msg(msg).loc(block).push();
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 && let Some(vec) = block.get_field_list("accolade_parameters")
121 {
122 for token in vec {
123 db.add_flag(Item::AccoladeParameter, token);
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("portrait_pose", Item::PortraitAnimation);
139
140 vd.field_item("adjective", Item::Localization);
141 vd.field_item("noun", Item::Localization);
142 vd.field_trigger("squire_perfect_fit", Tooltipped::No, &mut sc);
143 vd.field_trigger("squire_acceptable_fit", Tooltipped::No, &mut sc);
144 vd.field_list("accolade_categories");
145
146 vd.advice_field("potential", "removed in 1.19");
147
148 sc.define_name("owner", Scopes::Character, key);
149 vd.field_script_value("weight", &mut sc);
150
151 vd.field_validated_block("ranks", |block, data| {
152 let mut vd = Validator::new(block, data);
153 for (_, block) in vd.integer_blocks() {
154 let mut vd = Validator::new(block, data);
155 vd.field_validated_block("liege_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_modifier", |block, data| {
160 let vd = Validator::new(block, data);
161 validate_modifs(block, data, ModifKinds::Character, vd);
162 });
163 vd.field_validated_block("knight_army_modifier", |block, data| {
164 let vd = Validator::new(block, data);
165 validate_modifs(block, data, ModifKinds::Character, vd);
166 });
167 vd.field_list_items("men_at_arms", Item::MenAtArms);
168 vd.field_validated_block("terrain_bonus", |block, data| {
169 let mut vd = Validator::new(block, data);
170 vd.unknown_block_fields(|key, block| {
171 data.verify_exists(Item::MenAtArms, key);
172 validate_terrain_bonus(block, data);
173 });
174 });
175 vd.field_validated_block("holding_bonus", |block, data| {
176 let mut vd = Validator::new(block, data);
177 vd.unknown_block_fields(|key, block| {
178 data.verify_exists(Item::MenAtArms, key);
179 validate_holding_bonus(block, data);
180 });
181 });
182 vd.field_validated_block("winter_bonus", |block, data| {
183 let mut vd = Validator::new(block, data);
184 vd.unknown_block_fields(|key, block| {
185 data.verify_exists(Item::MenAtArms, key);
186 validate_winter_bonus(block, data);
187 });
188 });
189 vd.field_list_items("accolade_parameters", Item::Localization);
190 }
191 });
192
193 vd.field_item("icon", Item::File);
196 }
197}