tiger_lib/ck3/data/
event_themes.rs

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    /// Themes are unusual in that they are validated through the events that use them.
43    /// This means that unused themes are not validated, which is ok.
44    /// The purpose is to allow the triggers to be validated in the context of the scope
45    /// of the event that uses them.
46    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        // Check if the passed-in scope type has already been validated for
56        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    /// Like `EventTheme`, `EventBackground` are validated through the events (and themes) that use them.
102    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    /// Like `EventTheme`, `EventTransition` are validated through the events (and themes) that use them.
159    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}