overlord_event_system/logic/
pets.rs1use crate::{
2 attributes::calculate_player_entity_stats_without_zeroes,
3 entities::{make_active_abilities_from_equipped, sort_active_abilities},
4 event::OverlordEvent,
5 game_config_helpers::GameConfigLookup,
6 logic::handler::OverlordLogic,
7 state::OverlordState,
8};
9
10use essences::entity::{ActionWithDeadline, EntityState};
11use essences::pets::{EquippedPets, PetId, PetSlotId};
12use event_system::system::EventHandleResult;
13
14impl OverlordLogic {
15 pub fn handle_equip_pet(
16 &self,
17 slot_id: u64,
18 pet_id: PetId,
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((existing_slot, _)) = state
26 .character_state
27 .equipped_pets
28 .slotted
29 .iter()
30 .find(|(_, p)| p.template_id == pet_id)
31 {
32 tracing::error!("Pet_id = {pet_id} is already equipped in slot_id={existing_slot}");
33 return EventHandleResult::fail(state);
34 }
35
36 let Some(pet) = state
38 .character_state
39 .all_pets
40 .iter()
41 .find(|p| p.template_id == pet_id)
42 .cloned()
43 else {
44 tracing::error!("No pet with id = {} in state", pet_id);
45 return EventHandleResult::fail(state);
46 };
47
48 let Some(pet_slots) = game_config
50 .pet_slots_for_chapter_level(state.character_state.character.current_chapter_level)
51 else {
52 tracing::error!(
53 "No pet slots for current_chapter_level = {}",
54 state.character_state.character.current_chapter_level
55 );
56 return EventHandleResult::fail(state);
57 };
58
59 if slot_id >= pet_slots {
60 tracing::error!(
61 "Slot_id is too high = {}, current max pet slots = {}",
62 slot_id,
63 pet_slots,
64 );
65 return EventHandleResult::fail(state);
66 }
67
68 state
69 .character_state
70 .equipped_pets
71 .slotted
72 .insert(slot_id as PetSlotId, pet);
73
74 self.refresh_player_entity_in_active_fight(&mut state, current_tick);
75
76 EventHandleResult::ok(state)
77 }
78
79 pub fn handle_unequip_pet(
80 &self,
81 slot_id: PetSlotId,
82 current_tick: u64,
83 mut state: OverlordState,
84 ) -> EventHandleResult<OverlordEvent, OverlordState> {
85 state.character_state.equipped_pets.slotted.remove(&slot_id);
86
87 self.refresh_player_entity_in_active_fight(&mut state, current_tick);
88
89 EventHandleResult::ok(state)
90 }
91
92 pub fn handle_equip_pets(
93 &self,
94 equipped_pets: EquippedPets,
95 current_tick: u64,
96 mut state: OverlordState,
97 ) -> EventHandleResult<OverlordEvent, OverlordState> {
98 state.character_state.equipped_pets = equipped_pets;
99
100 self.refresh_player_entity_in_active_fight(&mut state, current_tick);
101
102 EventHandleResult::ok(state)
103 }
104
105 fn refresh_player_entity_in_active_fight(&self, state: &mut OverlordState, current_tick: u64) {
108 if state.active_fight.is_none() {
109 return;
110 }
111
112 let game_config = self.game_config.get();
113
114 let entity_stats = match calculate_player_entity_stats_without_zeroes(
116 &EntityState::Character(&state.character_state),
117 &game_config,
118 ) {
119 Ok(stats) => stats,
120 Err(err) => {
121 tracing::error!("Failed to recalculate player stats after pet change: {err}");
122 return;
123 }
124 };
125
126 let mut new_abilities = make_active_abilities_from_equipped(
128 &state.character_state.equipped_abilities,
129 &game_config,
130 true,
131 );
132 sort_active_abilities(&mut new_abilities);
133
134 let active_fight = state.active_fight.as_mut().unwrap();
136 if let Some(player) = active_fight
137 .entities
138 .iter_mut()
139 .find(|e| e.id == active_fight.player_id)
140 {
141 let hp_delta = entity_stats.max_hp as i64 - player.max_hp as i64;
142 player.max_hp = entity_stats.max_hp;
143 player.hp = (player.hp as i64 + hp_delta).max(1) as u64;
144 player.attributes = entity_stats.attributes;
145
146 for ability in &player.abilities {
148 player
149 .actions_queue
150 .remove_start_cast_ability_action(ability.ability.template_id);
151 }
152
153 player.abilities = new_abilities;
154
155 for ability in &player.abilities {
157 let Some(ability_template) =
158 game_config.ability_template(ability.ability.template_id)
159 else {
160 tracing::error!(
161 "Couldn't find template for ability_id = {}",
162 ability.ability.template_id
163 );
164 continue;
165 };
166 player.actions_queue.push(&ActionWithDeadline::core(
167 self.make_start_cast_ability_action(player.id, ability.ability.template_id),
168 current_tick + ability_template.cooldown,
169 ));
170 }
171 }
172 }
173}