Skip to main content

tiger_lib/vic3/data/
journalentries.rs

1use crate::block::Block;
2use crate::context::ScopeContext;
3use crate::data::on_actions::validate_on_action;
4use crate::db::{Db, DbKind};
5use crate::desc::validate_desc;
6use crate::everything::Everything;
7use crate::game::GameFlags;
8use crate::item::{Item, ItemLoader};
9use crate::report::{ErrorKey, err};
10use crate::scopes::Scopes;
11use crate::token::Token;
12use crate::tooltipped::Tooltipped;
13use crate::validator::Validator;
14
15#[derive(Clone, Debug)]
16pub struct JournalEntry {}
17
18inventory::submit! {
19    ItemLoader::Normal(GameFlags::Vic3, Item::JournalEntry, JournalEntry::add)
20}
21
22impl JournalEntry {
23    pub fn add(db: &mut Db, key: Token, block: Block) {
24        db.add(Item::JournalEntry, key, block, Box::new(Self {}));
25    }
26}
27
28impl DbKind for JournalEntry {
29    fn validate(&self, key: &Token, block: &Block, data: &Everything) {
30        let mut vd = Validator::new(block, data);
31
32        data.verify_exists(Item::Localization, key);
33        let loca = format!("{key}_reason");
34        data.verify_exists_implied(Item::Localization, &loca, key);
35        // TODO: make this depend on whether the journalentry uses the "goal" mechanic
36        let loca = format!("{key}_goal");
37        data.mark_used(Item::Localization, &loca);
38
39        let sc_context = if let Some(group) = block.get_field_value("group") {
40            if data.item_has_property(Item::JournalEntryGroup, group.as_str(), "none_context") {
41                Scopes::None
42            } else {
43                Scopes::Country
44            }
45        } else {
46            Scopes::Country
47        };
48        let mut sc = ScopeContext::new(sc_context, key);
49        sc.define_name("journal_entry", Scopes::JournalEntry, key);
50        sc.define_name("target", Scopes::all(), key);
51
52        let mut country_sc = ScopeContext::new(Scopes::Country, key);
53        country_sc.define_name("journal_entry", Scopes::JournalEntry, key);
54        country_sc.define_name("target", Scopes::all(), key);
55
56        vd.field_item("group", Item::JournalEntryGroup);
57
58        vd.field_item("icon", Item::File);
59
60        vd.field_trigger("is_shown_when_inactive", Tooltipped::No, &mut sc);
61        vd.field_trigger("should_be_involved", Tooltipped::No, &mut country_sc);
62        vd.field_trigger("should_show_when_not_involved", Tooltipped::No, &mut country_sc);
63
64        vd.multi_field_item("scripted_button", Item::ScriptedButton);
65
66        vd.field_trigger("possible", Tooltipped::Yes, &mut sc);
67        vd.field_effect("immediate", Tooltipped::No, &mut sc);
68        vd.field_effect("immediate_all_involved", Tooltipped::No, &mut country_sc);
69        vd.field_trigger("complete", Tooltipped::Yes, &mut sc);
70        vd.field_effect("on_complete", Tooltipped::Yes, &mut sc);
71        vd.field_effect("on_complete_all_involved", Tooltipped::No, &mut country_sc);
72        vd.field_trigger("fail", Tooltipped::Yes, &mut sc);
73        vd.field_effect("on_fail", Tooltipped::Yes, &mut sc);
74        vd.field_effect("on_fail_all_involved", Tooltipped::No, &mut country_sc);
75        vd.field_trigger("invalid", Tooltipped::No, &mut sc);
76        vd.field_effect("on_invalid", Tooltipped::Yes, &mut sc);
77        vd.field_effect("on_invalid_all_involved", Tooltipped::No, &mut country_sc);
78        vd.field_effect("on_become_involved_after_activation", Tooltipped::No, &mut country_sc);
79        vd.field_effect("on_no_longer_involved", Tooltipped::No, &mut country_sc);
80
81        vd.field_validated_block("widget", |block, data| {
82            let mut vd = Validator::new(block, data);
83            vd.field_item("gui", Item::File);
84            vd.field_value("name");
85            vd.field_value("container");
86        });
87
88        if !vd.field_validated_sc("status_desc", &mut sc, validate_desc) {
89            data.mark_used(Item::Localization, &format!("{key}_status"));
90        }
91
92        vd.multi_field_validated_sc("event_outcome_activated_desc", &mut sc, validate_desc);
93        vd.multi_field_validated_block_sc(
94            "event_outcome_activated_effect_desc",
95            &mut sc,
96            validate_effect_desc,
97        );
98        vd.multi_field_validated_sc("event_outcome_invalidated_desc", &mut sc, validate_desc);
99        vd.multi_field_validated_block_sc(
100            "event_outcome_invalidated_effect_desc",
101            &mut sc,
102            validate_effect_desc,
103        );
104        vd.multi_field_validated_sc("event_outcome_completed_desc", &mut sc, validate_desc);
105        vd.multi_field_validated_block_sc(
106            "event_outcome_completed_effect_desc",
107            &mut sc,
108            validate_effect_desc,
109        );
110        vd.multi_field_validated_sc("event_outcome_failed_desc", &mut sc, validate_desc);
111        vd.multi_field_validated_block_sc(
112            "event_outcome_failed_effect_desc",
113            &mut sc,
114            validate_effect_desc,
115        );
116        vd.multi_field_validated_sc("event_outcome_timeout_desc", &mut sc, validate_desc);
117        vd.multi_field_validated_block_sc(
118            "event_outcome_timeout_effect_desc",
119            &mut sc,
120            validate_effect_desc,
121        );
122        vd.field_localization("custom_completion_header", &mut sc);
123        vd.field_localization("custom_failure_header", &mut sc);
124        vd.field_localization("custom_on_completion_header", &mut sc);
125        vd.field_localization("custom_on_failure_header", &mut sc);
126
127        vd.field_script_value("timeout", &mut sc);
128        if let Some(token) = block.get_field_value("timeout")
129            && token.is("0")
130        {
131            let msg = "as of 1.9.5, a timeout of 0 will close the journal entry immediately";
132            err(ErrorKey::Logic).msg(msg).loc(token).push();
133        }
134        vd.field_effect("on_timeout", Tooltipped::Yes, &mut sc);
135        vd.field_effect("on_timeout_all_involved", Tooltipped::No, &mut country_sc);
136
137        vd.field_list_items("modifiers_while_active", Item::Modifier);
138
139        for field in &["on_weekly_pulse", "on_monthly_pulse", "on_yearly_pulse"] {
140            vd.multi_field_validated_block_sc(field, &mut sc, validate_on_action);
141        }
142
143        vd.field_script_value("current_value", &mut sc);
144        vd.field_script_value("goal_add_value", &mut sc);
145        vd.field_script_value("weight", &mut sc);
146
147        vd.field_bool("transferable");
148        vd.field_bool("can_revolution_inherit");
149
150        vd.field_trigger("is_progressing", Tooltipped::No, &mut sc);
151        vd.field_bool("progressbar");
152        vd.multi_field_item("scripted_progress_bar", Item::ScriptedProgressBar);
153
154        vd.field_bool("can_deactivate");
155
156        if block.field_value_is("progressbar", "yes") {
157            if !vd.field_validated_sc("progress_desc", &mut sc, validate_desc) {
158                data.mark_used(Item::Localization, &format!("{key}_progress"));
159            }
160        } else {
161            vd.ban_field("progress_desc", || "progressbar = yes");
162        }
163
164        vd.field_item("how_tutorial", Item::TutorialLesson);
165        vd.field_item("why_tutorial", Item::TutorialLesson);
166
167        vd.field_bool("should_be_pinned_by_default");
168        vd.field_bool("should_be_pinned_by_default_uninvolved_or_context");
169
170        // undocumented
171
172        vd.field_integer("active_update_frequency");
173        vd.field_bool("should_update_on_player_command");
174        vd.field_bool("display_progressbar_as_months");
175        vd.field_trigger("is_shown_in_lobby", Tooltipped::No, &mut sc);
176    }
177}
178
179#[derive(Clone, Debug)]
180pub struct JournalEntryGroup {}
181
182inventory::submit! {
183    ItemLoader::Normal(GameFlags::Vic3, Item::JournalEntryGroup, JournalEntryGroup::add)
184}
185
186impl JournalEntryGroup {
187    pub fn add(db: &mut Db, key: Token, block: Block) {
188        db.add(Item::JournalEntryGroup, key, block, Box::new(Self {}));
189    }
190}
191
192impl DbKind for JournalEntryGroup {
193    fn validate(&self, key: &Token, block: &Block, data: &Everything) {
194        data.verify_exists(Item::Localization, key);
195
196        let mut vd = Validator::new(block, data);
197        vd.field_choice("context", &["none", "country"]);
198    }
199
200    fn has_property(
201        &self,
202        _key: &Token,
203        block: &Block,
204        property: &str,
205        _data: &Everything,
206    ) -> bool {
207        if property == "none_context" {
208            return block.get_field_value("context").is_some_and(|v| v.is("none"));
209        }
210        false
211    }
212}
213
214fn validate_effect_desc(block: &Block, data: &Everything, sc: &mut ScopeContext) {
215    let mut vd = Validator::new(block, data);
216
217    vd.field_localization("header", sc);
218    vd.field_effect("effect", Tooltipped::Yes, sc);
219}