1use std::sync::RwLock;
2
3use crate::block::Block;
4use crate::ck3::validate::{
5 validate_theme_background, validate_theme_effect_2d, validate_theme_header_background,
6 validate_theme_icon, validate_theme_sound, validate_theme_transition,
7};
8use crate::context::ScopeContext;
9use crate::db::{Db, DbKind};
10use crate::everything::Everything;
11use crate::game::GameFlags;
12use crate::item::{Item, ItemLoader};
13use crate::report::Severity;
14use crate::scopes::Scopes;
15use crate::token::Token;
16use crate::tooltipped::Tooltipped;
17use crate::validator::Validator;
18
19#[derive(Debug)]
20pub struct EventTheme {
21 validated_scopes: RwLock<Scopes>,
22}
23
24inventory::submit! {
25 ItemLoader::Normal(GameFlags::Ck3, Item::EventTheme, EventTheme::add)
26}
27
28impl EventTheme {
29 pub fn new() -> Self {
30 let validated_scopes = RwLock::new(Scopes::empty());
31 Self { validated_scopes }
32 }
33
34 pub fn add(db: &mut Db, key: Token, block: Block) {
35 db.add(Item::EventTheme, key, block, Box::new(Self::new()));
36 }
37}
38
39impl DbKind for EventTheme {
40 fn validate(&self, _key: &Token, _block: &Block, _data: &Everything) {}
41
42 fn validate_call(
47 &self,
48 _key: &Token,
49 block: &Block,
50 _caller: &Token,
51 _caller_block: &Block,
52 data: &Everything,
53 sc: &mut ScopeContext,
54 ) {
55 let scopes = sc.scopes(data);
57 if self.validated_scopes.read().unwrap().contains(scopes) {
58 return;
59 }
60 *self.validated_scopes.write().unwrap() |= scopes;
61
62 let mut vd = Validator::new(block, data);
63 vd.set_max_severity(Severity::Warning);
64
65 vd.req_field("background");
66 vd.req_field("icon");
67 vd.req_field("sound");
68
69 vd.multi_field_validated_sc("background", sc, validate_theme_background);
70 vd.multi_field_validated_sc("header_background", sc, validate_theme_header_background);
71 vd.multi_field_validated_sc("icon", sc, validate_theme_icon);
72 vd.multi_field_validated_block_sc("sound", sc, validate_theme_sound);
73 vd.multi_field_validated_block_sc("transition", sc, validate_theme_transition);
74 vd.multi_field_validated_sc("effect_2d", sc, validate_theme_effect_2d);
75 }
76}
77
78#[derive(Debug)]
79pub struct EventBackground {
80 validated_scopes: RwLock<Scopes>,
81}
82
83inventory::submit! {
84 ItemLoader::Normal(GameFlags::Ck3, Item::EventBackground, EventBackground::add)
85}
86
87impl EventBackground {
88 pub fn new() -> Self {
89 let validated_scopes = RwLock::new(Scopes::empty());
90 Self { validated_scopes }
91 }
92
93 pub fn add(db: &mut Db, key: Token, block: Block) {
94 db.add(Item::EventBackground, key, block, Box::new(Self::new()));
95 }
96}
97
98impl DbKind for EventBackground {
99 fn validate(&self, _key: &Token, _block: &Block, _data: &Everything) {}
100
101 fn validate_call(
103 &self,
104 key: &Token,
105 block: &Block,
106 _caller: &Token,
107 _caller_block: &Block,
108 data: &Everything,
109 sc: &mut ScopeContext,
110 ) {
111 let scopes = sc.scopes(data);
112 if self.validated_scopes.read().unwrap().contains(scopes) {
113 return;
114 }
115 *self.validated_scopes.write().unwrap() |= scopes;
116
117 data.mark_used(Item::Localization, key.as_str());
118
119 let mut vd = Validator::new(block, data);
120 vd.set_max_severity(Severity::Warning);
121 vd.req_field("background");
122 vd.multi_field_validated_block("background", |block, data| {
123 let mut vd = Validator::new(block, data);
124 vd.set_max_severity(Severity::Warning);
125 vd.field_trigger("trigger", Tooltipped::No, sc);
126 vd.field_item("reference", Item::File);
127 vd.field_bool("video");
128 vd.field_item("environment", Item::PortraitEnvironment);
129 vd.field_value("ambience");
130 vd.field_item("video_mask", Item::File);
131 });
132 }
133}
134
135#[derive(Debug)]
136pub struct EventTransition {
137 validated_scopes: RwLock<Scopes>,
138}
139
140inventory::submit! {
141 ItemLoader::Normal(GameFlags::Ck3, Item::EventTransition, EventTransition::add)
142}
143
144impl EventTransition {
145 pub fn new() -> Self {
146 let validated_scopes = RwLock::new(Scopes::empty());
147 Self { validated_scopes }
148 }
149
150 pub fn add(db: &mut Db, key: Token, block: Block) {
151 db.add(Item::EventTransition, key, block, Box::new(Self::new()));
152 }
153}
154
155impl DbKind for EventTransition {
156 fn validate(&self, _key: &Token, _block: &Block, _data: &Everything) {}
157
158 fn validate_call(
160 &self,
161 _key: &Token,
162 block: &Block,
163 _caller: &Token,
164 _caller_block: &Block,
165 data: &Everything,
166 sc: &mut ScopeContext,
167 ) {
168 let scopes = sc.scopes(data);
169 if self.validated_scopes.read().unwrap().contains(scopes) {
170 return;
171 }
172 *self.validated_scopes.write().unwrap() |= scopes;
173
174 let mut vd = Validator::new(block, data);
175 vd.set_max_severity(Severity::Warning);
176 vd.req_field("transition");
177 vd.multi_field_validated_block("transition", |block, data| {
178 let mut vd = Validator::new(block, data);
179 vd.set_max_severity(Severity::Warning);
180 vd.field_trigger("trigger", Tooltipped::No, sc);
181 vd.field_item("reference", Item::File);
182 vd.field_bool("video");
183 vd.field_value("ambience");
184 vd.field_item("video_mask", Item::File);
185 vd.field_numeric("duration");
186 });
187 }
188}