overlord_event_system/async_handler/
abilities.rs1use crate::{
2 TICKER_UNIT_DURATION_MS, async_handler::handler::OverlordAsyncEventHandler,
3 entities::make_active_abilities_from_equipped, event::OverlordEvent,
4 game_config_helpers::GameConfigLookup, state::OverlordState,
5};
6
7use essences::{
8 abilities::{Ability, AbilityId, AbilitySlotId, ActiveAbility, EquippedAbilities},
9 effect::EffectId,
10 entity::{ActionWithDeadline, EntityAction, EntityId},
11};
12use event_system::system::EventHandleResult;
13
14impl OverlordAsyncEventHandler {
15 pub fn handle_equip_ability(
16 &self,
17 slot_id: u64,
18 ability_id: AbilityId,
19 current_tick: u64,
20 mut state: OverlordState,
21 ) -> EventHandleResult<OverlordEvent, OverlordState> {
22 let game_config = self.game_config.get();
23
24 if let Some((slot_id, _)) = state
25 .character_state
26 .equipped_abilities
27 .slotted
28 .iter()
29 .find(|(_, a)| a.template_id == ability_id)
30 {
31 tracing::error!(
32 "Ability_id = {ability_id} is already equipped in another slot in state: slot_id={slot_id}"
33 );
34 return EventHandleResult::fail(state);
35 }
36
37 let Some(ability) = state
38 .character_state
39 .all_abilities
40 .iter()
41 .find(|ab| ab.template_id == ability_id)
42 .cloned()
43 else {
44 tracing::error!("No ability with id = {} state exists", ability_id);
45 return EventHandleResult::fail(state);
46 };
47
48 let Some(ability_template) = game_config.ability_template(ability_id) else {
49 tracing::error!("No template found for ability_id = {}", ability_id);
50 return EventHandleResult::fail(state);
51 };
52
53 if !ability_template.fight_ui_visibility.is_player_equippable() {
54 tracing::error!("Trying to equip not visible ability {}", ability_id);
55 return EventHandleResult::fail(state);
56 }
57
58 let Some(ability_slots) = game_config
59 .ability_slots_for_chapter_level(state.character_state.character.current_chapter_level)
60 else {
61 tracing::error!(
62 "No ability slots for current_chapter_level = {}",
63 state.character_state.character.current_chapter_level
64 );
65 return EventHandleResult::fail(state);
66 };
67
68 if slot_id >= ability_slots {
69 tracing::error!(
70 "Slot_id is too high = {}, current max slots = {}",
71 slot_id,
72 ability_slots,
73 );
74 return EventHandleResult::fail(state);
75 }
76
77 self.set_ability_in_slot(&mut state, &ability, slot_id as usize, current_tick);
78
79 EventHandleResult::ok(state)
80 }
81
82 pub fn handle_unequip_ability(
83 &self,
84 slot_id: AbilitySlotId,
85 mut state: OverlordState,
86 ) -> EventHandleResult<OverlordEvent, OverlordState> {
87 if let Some(player) = state.get_active_fight_player_mut()
88 && let Some(pos) = player
89 .abilities
90 .iter()
91 .position(|a| a.slot_id == Some(slot_id))
92 {
93 let active_ability = player.abilities.swap_remove(pos);
94
95 player
96 .actions_queue
97 .remove_start_cast_ability_action(active_ability.ability.template_id);
98 }
99
100 state
101 .character_state
102 .equipped_abilities
103 .slotted
104 .remove(&slot_id);
105
106 EventHandleResult::ok(state)
107 }
108
109 fn set_ability_in_slot(
110 &self,
111 state: &mut OverlordState,
112 ability: &Ability,
113 slot_id: AbilitySlotId,
114 current_tick: u64,
115 ) {
116 let game_config = self.game_config.get();
117 let cooldown = game_config
118 .ability_template(ability.template_id)
119 .map(|t| t.cooldown)
120 .unwrap_or(0);
121
122 if let Some(player) = state.get_active_fight_player_mut() {
123 if let Some(pos) = player
124 .abilities
125 .iter()
126 .position(|a| a.slot_id == Some(slot_id))
127 {
128 let active_ability = player.abilities.swap_remove(pos);
129
130 player
131 .actions_queue
132 .remove_start_cast_ability_action(active_ability.ability.template_id);
133 }
134
135 player
136 .abilities
137 .push(self.make_active_ability(ability, Some(slot_id)));
138
139 player.actions_queue.push(&ActionWithDeadline {
140 action: self.make_start_cast_ability_action(player.id, ability.template_id),
141 deadline_tick: current_tick + cooldown,
142 });
143 }
144
145 state
146 .character_state
147 .equipped_abilities
148 .slotted
149 .insert(slot_id, ability.clone());
150 }
151
152 pub fn handle_equip_abilities(
153 &self,
154 equipped_abilities: EquippedAbilities,
155 current_tick: u64,
156 mut state: OverlordState,
157 ) -> EventHandleResult<OverlordEvent, OverlordState> {
158 let game_config = self.game_config.get();
159
160 if let Some(player) = state.get_active_fight_player_mut() {
161 for ability in &player.abilities {
162 player
163 .actions_queue
164 .remove_start_cast_ability_action(ability.ability.template_id);
165 }
166
167 player.abilities =
168 make_active_abilities_from_equipped(&equipped_abilities, &game_config, true);
169
170 for ability in &player.abilities {
171 let cooldown = game_config
172 .ability_template(ability.ability.template_id)
173 .map(|t| t.cooldown)
174 .unwrap_or(0);
175 player.actions_queue.push(&ActionWithDeadline {
176 action: self
177 .make_start_cast_ability_action(player.id, ability.ability.template_id),
178 deadline_tick: current_tick + cooldown,
179 });
180 }
181 }
182
183 state.character_state.equipped_abilities = equipped_abilities;
184
185 EventHandleResult::ok(state)
186 }
187
188 pub fn make_cast_effect_action(
189 &self,
190 entity_id: EntityId,
191 effect_id: EffectId,
192 ) -> EntityAction {
193 EntityAction::CastEffect {
194 entity_id,
195 effect_id,
196 }
197 }
198
199 pub fn make_start_cast_ability_action(
200 &self,
201 by_entity_id: EntityId,
202 ability_id: AbilityId,
203 ) -> EntityAction {
204 EntityAction::StartCastAbility {
205 ability_id,
206 by_entity_id,
207 pet_id: None,
208 }
209 }
210
211 fn make_active_ability(
212 &self,
213 ability: &Ability,
214 slot_id: Option<AbilitySlotId>,
215 ) -> ActiveAbility {
216 let game_config = self.game_config.get();
217 let cooldown = game_config
218 .ability_template(ability.template_id)
219 .map(|t| t.cooldown)
220 .unwrap_or(0);
221
222 ActiveAbility {
223 ability: ability.clone(),
224 deadline: Some(
225 ::time::utc_now()
226 + chrono::TimeDelta::milliseconds(
227 (cooldown as u128 * TICKER_UNIT_DURATION_MS) as i64,
228 ),
229 ),
230 slot_id,
231 }
232 }
233}