overlord_event_system/logic/
auto_chest.rs

1use crate::{
2    event::OverlordEvent, game_config_helpers::GameConfigLookup, logic::handler::OverlordLogic,
3    state::OverlordState,
4};
5
6use essences::autochest::{AutoChestFilter, AutoChestFilterId};
7use event_system::{event::EventPluginized, system::EventHandleResult};
8
9impl OverlordLogic {
10    pub fn handle_enable_auto_chest(
11        &self,
12        mut state: OverlordState,
13    ) -> EventHandleResult<OverlordEvent, OverlordState> {
14        let game_config = self.game_config.get();
15
16        // Gate auto-chest on character LEVEL (not just chapter): a player must
17        // manually open chests to reach the level threshold before auto-open
18        // unlocks — rewards hands-on early play (playtester request).
19        let level_gate = game_config
20            .gatings
21            .autochest
22            .autochest_button_unlock_character_level;
23        if state.character_state.character.character_level < level_gate {
24            tracing::warn!(
25                "EnableAutoChest rejected: character_level {} < gate {}",
26                state.character_state.character.character_level,
27                level_gate
28            );
29            return EventHandleResult::fail(state);
30        }
31
32        let events = if !state.character_state.character.auto_chest_enabled {
33            state.character_state.character.auto_chest_enabled = true;
34
35            vec![EventPluginized::delayed(
36                OverlordEvent::AutoChestOpenItemCase {
37                    batch_size: state.auto_chest.batch_size,
38                },
39                game_config.game_settings.auto_chest_pause_duration_ticks,
40            )]
41        } else {
42            vec![]
43        };
44
45        EventHandleResult::ok_events(state, events)
46    }
47
48    pub fn handle_disable_auto_chest(
49        &self,
50        mut state: OverlordState,
51    ) -> EventHandleResult<OverlordEvent, OverlordState> {
52        state.character_state.character.auto_chest_enabled = false;
53
54        EventHandleResult::ok(state)
55    }
56
57    pub fn handle_enable_auto_chest_filter(
58        &self,
59        filter_id: AutoChestFilterId,
60        mut state: OverlordState,
61    ) -> EventHandleResult<OverlordEvent, OverlordState> {
62        let Some(filter) = state.auto_chest.filters.iter().find(|f| f.id == filter_id) else {
63            tracing::error!(
64                "Tried enabling auto_chest filter with id = {}, but didnt find it in state",
65                filter_id
66            );
67            return EventHandleResult::fail(state);
68        };
69
70        state.character_state.character.last_filter_used_id = Some(filter.id);
71
72        state.auto_chest.active_filter = Some(filter.clone());
73
74        EventHandleResult::ok(state)
75    }
76
77    pub fn handle_disable_auto_chest_filter(
78        &self,
79        mut state: OverlordState,
80    ) -> EventHandleResult<OverlordEvent, OverlordState> {
81        state.auto_chest.active_filter = None;
82
83        EventHandleResult::ok(state)
84    }
85
86    pub fn handle_enable_auto_chest_power_compare(
87        &self,
88        mut state: OverlordState,
89    ) -> EventHandleResult<OverlordEvent, OverlordState> {
90        state.auto_chest.power_compare_enabled = true;
91
92        EventHandleResult::ok(state)
93    }
94
95    pub fn handle_disable_auto_chest_power_compare(
96        &self,
97        mut state: OverlordState,
98    ) -> EventHandleResult<OverlordEvent, OverlordState> {
99        state.auto_chest.power_compare_enabled = false;
100
101        EventHandleResult::ok(state)
102    }
103
104    pub fn handle_update_auto_chest_batch_size(
105        &self,
106        batch_size: i64,
107        mut state: OverlordState,
108    ) -> EventHandleResult<OverlordEvent, OverlordState> {
109        let game_config = self.game_config.get();
110        let Some(item_case_settings) = game_config
111            .item_case_settings_by_level(state.character_state.character.item_case_level)
112        else {
113            tracing::error!(
114                "No item case settings for level = {}",
115                state.character_state.character.item_case_level
116            );
117            return EventHandleResult::fail(state);
118        };
119
120        if batch_size > item_case_settings.auto_chest_settings.max_batch_size {
121            tracing::error!(
122                "Batch size = {}, is bigger than max = {}",
123                batch_size,
124                item_case_settings.auto_chest_settings.max_batch_size,
125            );
126            return EventHandleResult::fail(state);
127        }
128        state.auto_chest.batch_size = batch_size;
129
130        EventHandleResult::ok(state)
131    }
132
133    pub fn handle_new_auto_chest_filter(
134        &self,
135        filter: AutoChestFilter,
136        mut state: OverlordState,
137    ) -> EventHandleResult<OverlordEvent, OverlordState> {
138        let game_config = self.game_config.get();
139
140        if state.auto_chest.filters.iter().any(|f| f.id == filter.id) {
141            tracing::error!(
142                "Auto_chest filter with id = {}, already in state",
143                filter.id
144            );
145            return EventHandleResult::fail(state);
146        }
147
148        if let Err(e) = filter.validate(
149            state.character_state.character.current_chapter_level,
150            state.character_state.character.character_level,
151            &game_config.attributes,
152            &game_config.gatings.autochest,
153        ) {
154            tracing::error!("Filter {:?},\n Didn't pass validation: {:?}", filter, e);
155            return EventHandleResult::fail(state);
156        }
157
158        state.auto_chest.filters.push(filter);
159
160        EventHandleResult::ok(state)
161    }
162
163    pub fn handle_update_auto_chest_filter(
164        &self,
165        updated_filter: AutoChestFilter,
166        mut state: OverlordState,
167    ) -> EventHandleResult<OverlordEvent, OverlordState> {
168        let game_config = self.game_config.get();
169
170        let Some(old_filter) = state
171            .auto_chest
172            .filters
173            .iter_mut()
174            .find(|f| f.id == updated_filter.id)
175        else {
176            tracing::error!(
177                "Tried updating auto_chest filter with id = {}, but didn't find it in state",
178                updated_filter.id
179            );
180            return EventHandleResult::fail(state);
181        };
182
183        if let Err(e) = updated_filter.validate(
184            state.character_state.character.current_chapter_level,
185            state.character_state.character.character_level,
186            &game_config.attributes,
187            &game_config.gatings.autochest,
188        ) {
189            tracing::error!(
190                "Filter {:?}, didn't pass validation = {:?}",
191                updated_filter,
192                e
193            );
194            return EventHandleResult::fail(state);
195        }
196
197        *old_filter = updated_filter.clone();
198
199        EventHandleResult::ok(state)
200    }
201
202    pub fn handle_remove_auto_chest_filter(
203        &self,
204        filter_id: AutoChestFilterId,
205        mut state: OverlordState,
206    ) -> EventHandleResult<OverlordEvent, OverlordState> {
207        let Some(filter_position) = state
208            .auto_chest
209            .filters
210            .iter()
211            .position(|filter| filter.id == filter_id)
212        else {
213            tracing::error!(
214                "Tried removing filter with id = {}, but didn't find it in state",
215                filter_id
216            );
217            return EventHandleResult::fail(state);
218        };
219
220        if state.character_state.character.last_filter_used_id == Some(filter_id) {
221            state.character_state.character.last_filter_used_id = None;
222        }
223
224        state.auto_chest.filters.remove(filter_position);
225
226        EventHandleResult::ok(state)
227    }
228}