tiger_lib/data/
customloca.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
use crate::block::Block;
use crate::context::ScopeContext;
use crate::data::localization::Language;
use crate::db::{Db, DbKind};
use crate::effect::validate_effect;
use crate::everything::Everything;
use crate::game::GameFlags;
use crate::item::{Item, ItemLoader};
use crate::report::{warn, ErrorKey};
use crate::scopes::Scopes;
use crate::token::Token;
use crate::tooltipped::Tooltipped;
use crate::trigger::validate_trigger;
use crate::validate::validate_modifiers_with_base;
use crate::validator::Validator;

#[derive(Clone, Debug)]
pub struct CustomLocalization {}

inventory::submit! {
    ItemLoader::Normal(GameFlags::all(), Item::CustomLocalization, CustomLocalization::add)
}

impl CustomLocalization {
    pub fn add(db: &mut Db, key: Token, block: Block) {
        db.add(Item::CustomLocalization, key, block, Box::new(Self {}));
    }
}

impl DbKind for CustomLocalization {
    fn validate(&self, key: &Token, block: &Block, data: &Everything) {
        let mut vd = Validator::new(block, data);

        let mut sc;
        if let Some(token) = vd.field_value("type") {
            if token.is("all") {
                sc = ScopeContext::new(Scopes::all(), token);
            } else if let Some(scopes) = Scopes::from_snake_case(token.as_str()) {
                sc = ScopeContext::new(scopes, token);
            } else {
                warn(ErrorKey::Scopes).msg("unknown scope type").loc(token).push();
                sc = ScopeContext::new(Scopes::all(), token);
            }
        } else {
            sc = ScopeContext::new(Scopes::all(), key);
        }
        // TODO: Scopes depend on the scopes available in the loca where Custom or Custom2 is called.
        sc.set_strict_scopes(false);
        vd.field_bool("log_loc_errors");
        vd.field_bool("random_valid");

        if block.has_key("parent") {
            vd.field_item("parent", Item::CustomLocalization);
            vd.req_field("suffix");
            vd.field_value("suffix");
            // Actual loca existence is checked in validate_custom_call
            return;
        }
        vd.req_field("type");

        vd.multi_field_validated_block("text", |block, data| {
            let mut vd = Validator::new(block, data);
            vd.field_validated_block("setup_scope", |block, data| {
                validate_effect(block, data, &mut sc, Tooltipped::No);
            });
            vd.field_validated_block("trigger", |block, data| {
                validate_trigger(block, data, &mut sc, Tooltipped::No);
            });
            vd.field_validated_block_sc("weight_multiplier", &mut sc, validate_modifiers_with_base);

            vd.req_field("localization_key");
            // Actual loca existence is checked in validate_custom_call
            vd.field_value("localization_key");
            vd.field_bool("fallback");
        });
    }
}

impl CustomLocalization {
    #[allow(clippy::too_many_arguments)] // nothing can be cut here
    pub fn validate_custom_call(
        key: &Token,
        block: &Block,
        data: &Everything,
        caller: &Token,
        scopes: Scopes,
        lang: Option<Language>,
        suffix_str: &str,
        suffix_token: Option<&Token>,
    ) {
        if let Some(token) = block.get_field_value("type") {
            if let Some(this_scopes) = Scopes::from_snake_case(token.as_str()) {
                if !scopes.contains(this_scopes) {
                    let msg = format!(
                        "custom localization {key} is for {this_scopes} but context is {scopes}"
                    );
                    warn(ErrorKey::Scopes).msg(msg).loc(caller).push();
                }
            }
        }

        if let Some(parent) = block.get_field_value("parent") {
            if let Some(suffix) = block.get_field_value("suffix") {
                if let Some((key, block)) =
                    data.get_key_block(Item::CustomLocalization, parent.as_str())
                {
                    let suffix_str = format!("{suffix_str}{suffix}");
                    let suffix_token =
                        if suffix_token.is_some() { suffix_token } else { Some(suffix) };
                    Self::validate_custom_call(
                        key,
                        block,
                        data,
                        caller,
                        scopes,
                        lang,
                        &suffix_str,
                        suffix_token,
                    );
                }
            }
        } else {
            for block in block.get_field_blocks("text") {
                if let Some(key) = block.get_field_value("localization_key") {
                    if let Some(token) = suffix_token {
                        let loca = format!("{key}{suffix_str}");
                        data.localization.verify_exists_implied_lang(&loca, token, lang);
                    } else {
                        data.localization.verify_exists_lang(key, lang);
                    }
                }
            }
        }
    }
}