Skip to main content

tiger_lib/ck3/data/
stories.rs

1use crate::block::{BV, Block};
2use crate::context::ScopeContext;
3use crate::db::{Db, DbKind};
4use crate::everything::Everything;
5use crate::game::GameFlags;
6use crate::item::{Item, ItemLoader};
7use crate::scopes::Scopes;
8use crate::token::Token;
9use crate::tooltipped::Tooltipped;
10use crate::validator::Validator;
11
12#[derive(Clone, Debug)]
13pub struct Story {}
14
15inventory::submit! {
16    ItemLoader::Normal(GameFlags::Ck3, Item::Story, Story::add)
17}
18
19impl Story {
20    pub fn add(db: &mut Db, key: Token, block: Block) {
21        db.add(Item::Story, key, block, Box::new(Self {}));
22    }
23}
24
25impl DbKind for Story {
26    fn validate(&self, _key: &Token, block: &Block, data: &Everything) {
27        let mut vd = Validator::new(block, data);
28
29        let sc_builder = |key: &Token| {
30            let mut sc = ScopeContext::new(Scopes::StoryCycle, key);
31            sc.define_name("story", Scopes::StoryCycle, key);
32            sc
33        };
34
35        vd.field_effect_builder("on_setup", Tooltipped::No, sc_builder);
36        vd.field_effect_builder("on_end", Tooltipped::No, sc_builder);
37        vd.field_effect_builder("on_owner_death", Tooltipped::No, sc_builder);
38
39        vd.field_bool("visible");
40        // TODO: if visible and no icon, look for icon in STORY_CYCLE_TYPE_ICON_PATH define
41        vd.multi_field_validated_block("icon", |block, data| {
42            let mut vd = Validator::new(block, data);
43            vd.field_trigger_builder("trigger", Tooltipped::No, sc_builder);
44            vd.field_item("reference", Item::File);
45        });
46
47        // TODO: if visible and no background, look for STORY_CYCLE_TYPE_FALLBACK_BACKGROUND define
48        vd.multi_field_validated_block("background", |block, data| {
49            let mut vd = Validator::new(block, data);
50            vd.field_trigger_builder("trigger", Tooltipped::No, sc_builder);
51            vd.field_item("reference", Item::File);
52        });
53
54        vd.field_validated_block("visualization", |block, data| {
55            let mut vd = Validator::new(block, data);
56            for field in
57                &["character", "character_list", "title", "title_list", "artifact", "artifact_list"]
58            {
59                vd.multi_field_validated_block(field, |block, data| {
60                    let mut vd = Validator::new(block, data);
61                    // TODO: register these variable types?
62                    vd.field_value("variable_name");
63                    vd.field_item("label", Item::Localization);
64                });
65            }
66            // TODO: "has STORY as an available scope"
67            vd.field_item("custom_string_key", Item::Localization);
68            for field in &["basic_counter", "tug_of_war_counter"] {
69                vd.multi_field_validated_block(field, |block, data| {
70                    let mut vd = Validator::new(block, data);
71                    // TODO: register these variable types?
72                    vd.field_value("variable_name");
73                    vd.field_numeric("min");
74                    vd.field_numeric("max");
75                    vd.field_item("label", Item::Localization);
76                    vd.field_item("tooltip", Item::Localization);
77                    vd.field_item("min_label", Item::Localization);
78                    vd.field_item("max_label", Item::Localization);
79                });
80            }
81            vd.field_list_items("decisions", Item::Decision);
82            vd.field_list_items("modifiers", Item::Modifier);
83            vd.field_list_items("traits", Item::Trait);
84        });
85
86        vd.multi_field_validated_key_block("effect_group", |key, block, data| {
87            let mut sc = ScopeContext::new(Scopes::StoryCycle, key);
88            sc.define_name("story", Scopes::StoryCycle, key);
89            let mut vd = Validator::new(block, data);
90
91            // TODO: handle case of multiple of these fields being specified
92            for field in &["days", "weeks", "months", "years"] {
93                vd.field_validated(field, |bv, data| match bv {
94                    BV::Value(token) => {
95                        token.expect_integer();
96                    }
97                    BV::Block(block) => {
98                        let mut vd = Validator::new(block, data);
99                        vd.req_tokens_integers_exactly(2);
100                    }
101                });
102            }
103            vd.field_numeric_range("chance", 0.0..=100.0);
104
105            vd.field_trigger("trigger", Tooltipped::No, &mut sc);
106
107            validate_complex_effect(&mut vd, &mut sc);
108        });
109    }
110}
111
112fn validate_complex_effect(vd: &mut Validator, sc: &mut ScopeContext) {
113    vd.multi_field_validated_block("first_valid", |block, data| {
114        let mut vd = Validator::new(block, data);
115        validate_complex_effect(&mut vd, sc);
116    });
117    vd.multi_field_validated_block("random_valid", |block, data| {
118        let mut vd = Validator::new(block, data);
119        validate_complex_effect(&mut vd, sc);
120    });
121    vd.multi_field_validated_block("triggered_effect", |block, data| {
122        let mut vd = Validator::new(block, data);
123        vd.field_trigger("trigger", Tooltipped::No, sc);
124        vd.field_effect("effect", Tooltipped::No, sc);
125    });
126    vd.field_effect("fallback", Tooltipped::No, sc);
127}