overlord_event_system/
bundles.rs

1use configs::game_config::GameConfig;
2use essences::{
3    bundles::{BundleAbility, BundleElement, BundleRawStep, BundleStepType},
4    character_state::CharacterState,
5    currency::from_es_currencies,
6    items::Item,
7};
8
9use event_system::script::runner::ScriptRandom;
10
11use crate::{
12    ScriptRunner, cases::try_finalize_item, event::OverlordEvent,
13    gacha::item_case::generate_item_from_template, game_config_helpers::GameConfigLookup,
14    state::OverlordState,
15};
16use rand::SeedableRng;
17
18pub fn bundle_raw_step_to_element(
19    raw_item: &BundleRawStep,
20    character_state: &CharacterState,
21    script_runner: &ScriptRunner<OverlordEvent, OverlordState>,
22    game_config: &GameConfig,
23) -> BundleElement {
24    match raw_item.item_type {
25        BundleStepType::Currency => process_currency(raw_item, character_state, script_runner),
26        BundleStepType::Ability => {
27            process_ability(raw_item, character_state, script_runner, game_config)
28        }
29        BundleStepType::Item => process_item(raw_item, character_state, script_runner, game_config),
30    }
31}
32
33pub fn bundle_raw_afk_step_to_element(
34    raw_item: &BundleRawStep,
35    character_state: &CharacterState,
36    now: chrono::DateTime<chrono::Utc>,
37    script_runner: &ScriptRunner<OverlordEvent, OverlordState>,
38    game_config: &GameConfig,
39) -> BundleElement {
40    match raw_item.item_type {
41        BundleStepType::Currency => {
42            process_afk_currency(raw_item, character_state, now, script_runner)
43        }
44        BundleStepType::Ability => {
45            process_afk_ability(raw_item, character_state, now, script_runner, game_config)
46        }
47        BundleStepType::Item => {
48            process_afk_item(raw_item, character_state, now, script_runner, game_config)
49        }
50    }
51}
52
53fn process_currency(
54    raw_item: &BundleRawStep,
55    character_state: &CharacterState,
56    script_runner: &ScriptRunner<OverlordEvent, OverlordState>,
57) -> BundleElement {
58    let currency_unit = from_es_currencies(&script_runner.run_currencies_calculate(
59        |mut scope| {
60            scope.set_const("CharacterState", character_state.clone());
61            scope
62        },
63        &raw_item.script,
64    ));
65
66    BundleElement::Currencies(currency_unit)
67}
68
69fn process_afk_currency(
70    raw_item: &BundleRawStep,
71    character_state: &CharacterState,
72    now: chrono::DateTime<chrono::Utc>,
73    script_runner: &ScriptRunner<OverlordEvent, OverlordState>,
74) -> BundleElement {
75    let currency_unit = from_es_currencies(&script_runner.run_currencies_calculate(
76        |mut scope| {
77            scope.set_const("CharacterState", character_state.clone());
78            scope.set_const(
79                "LastClaimAt",
80                character_state
81                    .character
82                    .last_afk_reward_claimed_at
83                    .timestamp()
84                    .max(0) as u64,
85            );
86            scope.set_const("Now", now.timestamp().max(0) as u64);
87            scope.set_const(
88                "Random",
89                ScriptRandom::new(rand::rngs::StdRng::seed_from_u64(
90                    character_state.character.afk_reward_seed,
91                )),
92            );
93            scope
94        },
95        &raw_item.script,
96    ));
97
98    BundleElement::Currencies(currency_unit)
99}
100
101fn process_ability(
102    raw_item: &BundleRawStep,
103    character_state: &CharacterState,
104    script_runner: &ScriptRunner<OverlordEvent, OverlordState>,
105    game_config: &GameConfig,
106) -> BundleElement {
107    let ability_shards = script_runner.run_ability_shards_calculate(
108        |mut scope| {
109            scope.set_const("CharacterState", character_state.clone());
110            scope
111        },
112        &raw_item.script,
113    );
114
115    let abilities = ability_shards
116        .iter()
117        .filter_map(|ability_shard| {
118            let Some(template) = game_config
119                .ability_template(ability_shard.ability_id)
120                .cloned()
121            else {
122                tracing::error!(
123                    "Failed to get ability with ability_id={}",
124                    ability_shard.ability_id
125                );
126                return None;
127            };
128
129            Some(BundleAbility {
130                template,
131                shards_amount: ability_shard.shards_amount,
132            })
133        })
134        .collect();
135
136    BundleElement::Abilities(abilities)
137}
138
139fn process_afk_ability(
140    raw_item: &BundleRawStep,
141    character_state: &CharacterState,
142    now: chrono::DateTime<chrono::Utc>,
143    script_runner: &ScriptRunner<OverlordEvent, OverlordState>,
144    game_config: &GameConfig,
145) -> BundleElement {
146    let ability_shards = script_runner.run_ability_shards_calculate(
147        |mut scope| {
148            scope.set_const("CharacterState", character_state.clone());
149            scope.set_const(
150                "LastClaimAt",
151                character_state
152                    .character
153                    .last_afk_reward_claimed_at
154                    .timestamp()
155                    .max(0) as u64,
156            );
157            scope.set_const("Now", now.timestamp().max(0) as u64);
158            scope.set_const(
159                "Random",
160                ScriptRandom::new(rand::rngs::StdRng::seed_from_u64(
161                    character_state.character.afk_reward_seed,
162                )),
163            );
164            scope
165        },
166        &raw_item.script,
167    );
168
169    let abilities = ability_shards
170        .iter()
171        .filter_map(|ability_shard| {
172            let Some(template) = game_config
173                .ability_template(ability_shard.ability_id)
174                .cloned()
175            else {
176                tracing::error!(
177                    "Failed to get ability with ability_id={}",
178                    ability_shard.ability_id
179                );
180                return None;
181            };
182
183            Some(BundleAbility {
184                template,
185                shards_amount: ability_shard.shards_amount,
186            })
187        })
188        .collect();
189
190    BundleElement::Abilities(abilities)
191}
192
193fn process_item(
194    raw_item: &BundleRawStep,
195    character_state: &CharacterState,
196    script_runner: &ScriptRunner<OverlordEvent, OverlordState>,
197    game_config: &GameConfig,
198) -> BundleElement {
199    let item_ids = script_runner.run_item_ids_script(
200        |mut scope| {
201            scope.set_const("CharacterState", character_state.clone());
202            scope
203        },
204        &raw_item.script,
205    );
206
207    let items: Vec<Item> = item_ids
208        .iter()
209        .filter_map(|&item_id| {
210            let Some(template) = game_config.item_template(item_id) else {
211                tracing::error!("Failed to get item template with item_id={}", item_id);
212                return None;
213            };
214
215            let Some(rarity) = game_config.item_rarity(template.rarity_id).cloned() else {
216                tracing::error!("Failed to get item rarity with id={}", template.rarity_id);
217                return None;
218            };
219
220            Some(generate_item_from_template(
221                template,
222                rarity,
223                character_state.character.character_level,
224                game_config,
225                &mut rand::rngs::StdRng::from_os_rng(),
226            ))
227        })
228        .collect();
229
230    let finalized_items = items
231        .into_iter()
232        .filter_map(
233            |mut item| match try_finalize_item(&mut item, game_config, script_runner) {
234                Ok(()) => Some(item),
235                Err(e) => {
236                    tracing::error!("Failed to finalize item: {}", e);
237                    None
238                }
239            },
240        )
241        .collect();
242
243    BundleElement::Items(finalized_items)
244}
245
246fn process_afk_item(
247    raw_item: &BundleRawStep,
248    character_state: &CharacterState,
249    now: chrono::DateTime<chrono::Utc>,
250    script_runner: &ScriptRunner<OverlordEvent, OverlordState>,
251    game_config: &GameConfig,
252) -> BundleElement {
253    let item_ids = script_runner.run_item_ids_script(
254        |mut scope| {
255            scope.set_const("CharacterState", character_state.clone());
256            scope.set_const(
257                "LastClaimAt",
258                character_state
259                    .character
260                    .last_afk_reward_claimed_at
261                    .timestamp()
262                    .max(0) as u64,
263            );
264            scope.set_const("Now", now.timestamp().max(0) as u64);
265            scope.set_const(
266                "Random",
267                ScriptRandom::new(rand::rngs::StdRng::seed_from_u64(
268                    character_state.character.afk_reward_seed,
269                )),
270            );
271            scope
272        },
273        &raw_item.script,
274    );
275
276    let items: Vec<Item> = item_ids
277        .iter()
278        .filter_map(|&item_id| {
279            let Some(template) = game_config.item_template(item_id) else {
280                tracing::error!("Failed to get item template with item_id={}", item_id);
281                return None;
282            };
283
284            let Some(rarity) = game_config.item_rarity(template.rarity_id).cloned() else {
285                tracing::error!("Failed to get item rarity with id={}", template.rarity_id);
286                return None;
287            };
288
289            Some(generate_item_from_template(
290                template,
291                rarity,
292                character_state.character.character_level,
293                game_config,
294                &mut rand::rngs::StdRng::seed_from_u64(character_state.character.afk_reward_seed),
295            ))
296        })
297        .collect();
298
299    let finalized_items = items
300        .into_iter()
301        .filter_map(
302            |mut item| match try_finalize_item(&mut item, game_config, script_runner) {
303                Ok(()) => Some(item),
304                Err(e) => {
305                    tracing::error!("Failed to finalize item: {}", e);
306                    None
307                }
308            },
309        )
310        .collect();
311
312    BundleElement::Items(finalized_items)
313}