1use std::sync::LazyLock;
7
8use crate::block::BV;
9use crate::context::ScopeContext;
10use crate::everything::Everything;
11use crate::game::Game;
12use crate::helpers::TigerHashMap;
13#[cfg(feature = "hoi4")]
14use crate::hoi4::tables::on_action::on_action_scopecontext_hoi4;
15#[cfg(feature = "ck3")]
16use crate::item::Item;
17use crate::parse::pdxfile::parse_pdx_internal;
18use crate::scopes::Scopes;
19use crate::token::Token;
20
21#[derive(Debug, Clone)]
22struct OnActionScopeContext {
23 root: Scopes,
24 names: Vec<(String, Scopes)>,
25 lists: Vec<(String, Scopes)>,
26}
27
28static ON_ACTION_SCOPES_MAP: LazyLock<TigerHashMap<String, OnActionScopeContext>> =
29 LazyLock::new(|| {
30 build_on_action_hashmap(match Game::game() {
31 #[cfg(feature = "ck3")]
32 Game::Ck3 => crate::ck3::tables::on_action::ON_ACTION_SCOPES,
33 #[cfg(feature = "vic3")]
34 Game::Vic3 => crate::vic3::tables::on_action::ON_ACTION_SCOPES,
35 #[cfg(feature = "imperator")]
36 Game::Imperator => crate::imperator::tables::on_action::ON_ACTION_SCOPES,
37 #[cfg(feature = "eu5")]
38 Game::Eu5 => crate::eu5::tables::on_action::ON_ACTION_SCOPES,
39 #[cfg(feature = "hoi4")]
40 Game::Hoi4 => crate::hoi4::tables::on_action::ON_ACTION_SCOPES,
41 })
42 });
43
44#[allow(unused_variables)] pub fn on_action_scopecontext(key: &Token, data: &Everything) -> Option<ScopeContext> {
46 if let Some(oa_sc) = ON_ACTION_SCOPES_MAP.get(key.as_str()) {
47 let mut sc = ScopeContext::new(oa_sc.root, key);
48 for (name, s) in &oa_sc.names {
49 sc.define_name(name, *s, key);
50 }
51 for (list, s) in &oa_sc.lists {
52 sc.define_list(list, *s, key);
53 }
54 return Some(sc);
55 }
56
57 #[cfg(feature = "ck3")]
58 if Game::is_ck3() {
59 if let Some(relation) = key.as_str().strip_suffix("_quarterly_pulse") {
60 if data.item_exists(Item::Relation, relation) {
61 let mut sc = ScopeContext::new(Scopes::Character, key);
62 sc.define_name("quarter", Scopes::Value, key); return Some(sc);
64 }
65 } else {
66 for pfx in &["on_set_relation_", "on_remove_relation_", "on_death_relation_"] {
67 if let Some(relation) = key.as_str().strip_prefix(pfx) {
68 if data.item_exists(Item::Relation, relation) {
69 let mut sc = ScopeContext::new(Scopes::Character, key);
70 sc.define_name("target", Scopes::Character, key); return Some(sc);
72 }
73 }
74 }
75 }
76 }
77
78 #[cfg(feature = "hoi4")]
79 if Game::is_hoi4() {
80 if let Some(sc) = on_action_scopecontext_hoi4(key, data) {
81 return Some(sc);
82 }
83 }
84 None
85}
86
87fn build_on_action_hashmap(
88 description: &'static str,
89) -> TigerHashMap<String, OnActionScopeContext> {
90 let mut hash: TigerHashMap<String, OnActionScopeContext> = TigerHashMap::default();
91
92 let mut block = parse_pdx_internal(description, "on action builtin scopes");
93 for item in block.drain() {
94 let field = item.get_field().expect("internal error");
95 match field.bv() {
96 BV::Value(token) => {
97 let value = hash.get(token.as_str()).expect("internal error");
99 hash.insert(field.key().to_string(), value.clone());
100 }
101 BV::Block(block) => {
102 let root = block.get_field_value("root").expect("internal error");
103 let root = Scopes::from_snake_case_multi(root.as_str()).expect("internal error");
104 let mut value = OnActionScopeContext { root, names: Vec::new(), lists: Vec::new() };
105 for (key, token) in block.iter_assignments() {
106 if key.is("root") {
107 continue;
108 }
109 let s = Scopes::from_snake_case_multi(token.as_str()).expect("internal error");
110 value.names.push((key.to_string(), s));
111 }
112 for (key, block) in block.iter_definitions() {
113 if key.is("list") {
114 for (key, token) in block.iter_assignments() {
115 let s = Scopes::from_snake_case_multi(token.as_str())
116 .expect("internal error");
117 value.lists.push((key.to_string(), s));
118 }
119 }
120 }
121 hash.insert(field.key().to_string(), value);
122 }
123 }
124 }
125
126 hash
127}