From d0e487da8abc97b910bb08e68668a8675d8135e1 Mon Sep 17 00:00:00 2001 From: Sam Date: Sat, 27 Nov 2021 23:32:24 -0500 Subject: [PATCH] Ability sets now start with non-empty defaults. --- common/src/comp/ability.rs | 115 +++++++++++------------ common/src/event.rs | 6 ++ common/systems/src/controller.rs | 22 ++--- server/src/events/entity_manipulation.rs | 24 +++++ server/src/events/mod.rs | 14 ++- voxygen/src/hud/diary.rs | 6 +- voxygen/src/hud/hotbar.rs | 11 ++- voxygen/src/hud/skillbar.rs | 6 +- voxygen/src/hud/slots.rs | 4 +- 9 files changed, 125 insertions(+), 83 deletions(-) diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index 46cf0ce717..90b4669314 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -74,41 +74,57 @@ impl ActiveAbilities { slot: usize, auxiliary_key: AuxiliaryKey, new_ability: AuxiliaryAbility, + inventory: Option<&Inventory>, + skill_set: Option<&SkillSet>, ) { let auxiliary_set = self .auxiliary_sets .entry(auxiliary_key) - .or_insert([AuxiliaryAbility::Empty; 5]); + .or_insert(Self::default_ability_set(inventory, skill_set)); if let Some(ability) = auxiliary_set.get_mut(slot) { *ability = new_ability; } } - pub fn get_ability(&self, input: AbilityInput, inventory: Option<&Inventory>) -> Ability { + pub fn auxiliary_set( + &self, + inv: Option<&Inventory>, + skill_set: Option<&SkillSet>, + ) -> [AuxiliaryAbility; MAX_ABILITIES] { + let tool_kind = |slot| { + inv.and_then(|inv| inv.equipped(slot)) + .and_then(|item| match item.kind() { + ItemKind::Tool(tool) => Some(tool.kind), + _ => None, + }) + }; + + let aux_key = ( + tool_kind(EquipSlot::ActiveMainhand), + tool_kind(EquipSlot::ActiveOffhand), + ); + + self.auxiliary_sets + .get(&aux_key) + .copied() + .unwrap_or_else(|| Self::default_ability_set(inv, skill_set)) + } + + pub fn get_ability( + &self, + input: AbilityInput, + inventory: Option<&Inventory>, + skill_set: Option<&SkillSet>, + ) -> Ability { match input { AbilityInput::Primary => self.primary.into(), AbilityInput::Secondary => self.secondary.into(), AbilityInput::Movement => self.movement.into(), - AbilityInput::Auxiliary(index) => inventory - .and_then(|inv| { - let tool_kind = |slot| { - inv.equipped(slot).and_then(|item| match item.kind() { - ItemKind::Tool(tool) => Some(tool.kind), - _ => None, - }) - }; - - let aux_key = ( - tool_kind(EquipSlot::ActiveMainhand), - tool_kind(EquipSlot::ActiveOffhand), - ); - - self.auxiliary_sets - .get(&aux_key) - .and_then(|entry| entry.get(index)) - .copied() - .map(|a| a.into()) - }) + AbilityInput::Auxiliary(index) => self + .auxiliary_set(inventory, skill_set) + .get(index) + .copied() + .map(|a| a.into()) .unwrap_or(Ability::Empty), } } @@ -123,7 +139,7 @@ impl ActiveAbilities { body: Option<&Body>, // bool is from_offhand ) -> Option<(CharacterAbility, bool)> { - let ability = self.get_ability(input, inv); + let ability = self.get_ability(input, inv, Some(skill_set)); let ability_set = |equip_slot| { inv.and_then(|inv| inv.equipped(equip_slot)) @@ -193,44 +209,27 @@ impl ActiveAbilities { }) } - pub fn iter_aux_abilities<'a>( - &'a self, - inventory: Option<&'a Inventory>, - ) -> impl Iterator + 'a { - inventory - .and_then(|inv| { - let tool_kind = |slot| { - inv.equipped(slot).and_then(|item| match item.kind() { - ItemKind::Tool(tool) => Some(tool.kind), - _ => None, - }) - }; + pub fn default_ability_set<'a>( + inv: Option<&'a Inventory>, + skill_set: Option<&'a SkillSet>, + ) -> [AuxiliaryAbility; MAX_ABILITIES] { + let mut iter = Self::iter_unlocked_abilities(inv, skill_set, EquipSlot::ActiveMainhand) + .map(AuxiliaryAbility::MainWeapon) + .chain( + Self::iter_unlocked_abilities(inv, skill_set, EquipSlot::ActiveOffhand) + .map(AuxiliaryAbility::OffWeapon), + ); - let aux_key = ( - tool_kind(EquipSlot::ActiveMainhand), - tool_kind(EquipSlot::ActiveOffhand), - ); + let mut array = [AuxiliaryAbility::Empty; MAX_ABILITIES]; - self.auxiliary_sets.get(&aux_key) - }) - .into_iter() - .flatten() + for ability in array.iter_mut() { + if let Some(available_ability) = iter.next() { + *ability = available_ability; + } + } + + array } - - // TODO: Maybe keep this for autopopulating a new combination of weapons? - // pub fn auto_update(&mut self, inv: Option<&Inventory>, skill_set: - // Option<&SkillSet>) { let main_abilities = - // Self::iter_unlocked_abilities(inv, skill_set, EquipSlot::ActiveMainhand) - // .map(AuxiliaryAbility::MainWeapon); - // let off_abilities = Self::iter_unlocked_abilities(inv, skill_set, - // EquipSlot::ActiveOffhand) .map(AuxiliaryAbility::OffWeapon); - - // (0..MAX_ABILITIES) - // .zip(main_abilities.chain(off_abilities)) - // .for_each(|(i, ability)| { - // self.change_ability(i, ability); - // }) - // } } pub enum AbilityInput { diff --git a/common/src/event.rs b/common/src/event.rs index a712721cee..f5dd7d6e4e 100644 --- a/common/src/event.rs +++ b/common/src/event.rs @@ -204,6 +204,12 @@ pub enum ServerEvent { EntityAttackedHook { entity: EcsEntity, }, + ChangeAbility { + entity: EcsEntity, + slot: usize, + auxiliary_key: comp::ability::AuxiliaryKey, + new_ability: comp::ability::AuxiliaryAbility, + }, } pub struct EventBus { diff --git a/common/systems/src/controller.rs b/common/systems/src/controller.rs index 87a9acbc88..baefa30fd9 100644 --- a/common/systems/src/controller.rs +++ b/common/systems/src/controller.rs @@ -1,7 +1,7 @@ use common::{ comp::{ agent::{Sound, SoundKind}, - ActiveAbilities, Body, BuffChange, ControlEvent, Controller, Pos, + Body, BuffChange, ControlEvent, Controller, Pos, }, event::{EventBus, ServerEvent}, uid::UidAllocator, @@ -27,20 +27,13 @@ pub struct ReadData<'a> { pub struct Sys; impl<'a> System<'a> for Sys { - type SystemData = ( - ReadData<'a>, - WriteStorage<'a, Controller>, - WriteStorage<'a, ActiveAbilities>, - ); + type SystemData = (ReadData<'a>, WriteStorage<'a, Controller>); const NAME: &'static str = "controller"; const ORIGIN: Origin = Origin::Common; const PHASE: Phase = Phase::Create; - fn run( - _job: &mut Job, - (read_data, mut controllers, mut active_abilities): Self::SystemData, - ) { + fn run(_job: &mut Job, (read_data, mut controllers): Self::SystemData) { let mut server_emitter = read_data.server_bus.emitter(); for (entity, controller) in (&read_data.entities, &mut controllers).join() { @@ -115,9 +108,12 @@ impl<'a> System<'a> for Sys { auxiliary_key, new_ability, } => { - if let Some(mut active_abilities) = active_abilities.get_mut(entity) { - active_abilities.change_ability(slot, auxiliary_key, new_ability); - } + server_emitter.emit(ServerEvent::ChangeAbility { + entity, + slot, + auxiliary_key, + new_ability, + }); }, } } diff --git a/server/src/events/entity_manipulation.rs b/server/src/events/entity_manipulation.rs index 2123983133..40ba9eebba 100644 --- a/server/src/events/entity_manipulation.rs +++ b/server/src/events/entity_manipulation.rs @@ -1,6 +1,7 @@ use crate::{ client::Client, comp::{ + ability, agent::{Agent, AgentEvent, Sound, SoundKind}, skillset::SkillGroupKind, BuffKind, BuffSource, PhysicsState, @@ -1260,3 +1261,26 @@ pub fn handle_entity_attacked_hook(server: &Server, entity: EcsEntity) { buff_change: buff::BuffChange::RemoveByKind(buff::BuffKind::Saturation), }); } + +pub fn handle_change_ability( + server: &Server, + entity: EcsEntity, + slot: usize, + auxiliary_key: ability::AuxiliaryKey, + new_ability: ability::AuxiliaryAbility, +) { + let ecs = &server.state.ecs(); + let inventories = ecs.read_storage::(); + let skill_sets = ecs.read_storage::(); + + if let Some(mut active_abilities) = ecs.write_storage::().get_mut(entity) + { + active_abilities.change_ability( + slot, + auxiliary_key, + new_ability, + inventories.get(entity), + skill_sets.get(entity), + ); + } +} diff --git a/server/src/events/mod.rs b/server/src/events/mod.rs index 4fee80df93..9ab4bf23bd 100644 --- a/server/src/events/mod.rs +++ b/server/src/events/mod.rs @@ -6,10 +6,10 @@ use entity_creation::{ handle_initialize_character, handle_loaded_character_data, handle_shockwave, handle_shoot, }; use entity_manipulation::{ - handle_aura, handle_bonk, handle_buff, handle_combo_change, handle_delete, handle_destroy, - handle_energy_change, handle_entity_attacked_hook, handle_explosion, handle_health_change, - handle_knockback, handle_land_on_ground, handle_parry, handle_poise, handle_respawn, - handle_teleport_to, + handle_aura, handle_bonk, handle_buff, handle_change_ability, handle_combo_change, + handle_delete, handle_destroy, handle_energy_change, handle_entity_attacked_hook, + handle_explosion, handle_health_change, handle_knockback, handle_land_on_ground, handle_parry, + handle_poise, handle_respawn, handle_teleport_to, }; use group_manip::handle_group; use information::handle_site_info; @@ -233,6 +233,12 @@ impl Server { ServerEvent::EntityAttackedHook { entity } => { handle_entity_attacked_hook(self, entity) }, + ServerEvent::ChangeAbility { + entity, + slot, + auxiliary_key, + new_ability, + } => handle_change_ability(self, entity, slot, auxiliary_key, new_ability), } } diff --git a/voxygen/src/hud/diary.rs b/voxygen/src/hud/diary.rs index 997e14ef0e..1181d1f7f0 100644 --- a/voxygen/src/hud/diary.rs +++ b/voxygen/src/hud/diary.rs @@ -780,7 +780,11 @@ impl<'a> Widget for Diary<'a> { for i in 0..MAX_ABILITIES { let ability_id = self .active_abilities - .get_ability(AbilityInput::Auxiliary(i), Some(self.inventory)) + .get_ability( + AbilityInput::Auxiliary(i), + Some(self.inventory), + Some(self.skill_set), + ) .ability_id(Some(self.inventory)); let image_size = 50.0; diff --git a/voxygen/src/hud/hotbar.rs b/voxygen/src/hud/hotbar.rs index d95239293a..f0a94ace5c 100644 --- a/voxygen/src/hud/hotbar.rs +++ b/voxygen/src/hud/hotbar.rs @@ -1,5 +1,5 @@ use crate::hud::item_imgs::ItemKey; -use common::comp::inventory::item::Item; +use common::comp::{self, inventory::item::Item}; use serde::{Deserialize, Serialize}; #[derive(Clone, Copy, Debug, PartialEq)] @@ -70,7 +70,14 @@ impl State { { use common::comp::ability::AuxiliaryAbility; for ((i, ability), hotbar_slot) in active_abilities - .iter_aux_abilities(client.inventories().get(client.entity())) + .auxiliary_set( + client.inventories().get(client.entity()), + client + .state() + .read_storage::() + .get(client.entity()), + ) + .iter() .enumerate() .zip(self.slots.iter_mut()) { diff --git a/voxygen/src/hud/skillbar.rs b/voxygen/src/hud/skillbar.rs index 8f0c1098dc..e4f5248f65 100644 --- a/voxygen/src/hud/skillbar.rs +++ b/voxygen/src/hud/skillbar.rs @@ -601,14 +601,14 @@ impl<'a> Skillbar<'a> { // Helper let tooltip_text = |slot| { - let (hotbar, inventory, _, _, active_abilities, _) = content_source; + let (hotbar, inventory, _, skill_set, active_abilities, _) = content_source; hotbar.get(slot).and_then(|content| match content { hotbar::SlotContents::Inventory(i, _) => inventory .get_by_hash(i) .map(|item| (item.name(), item.description())), hotbar::SlotContents::Ability(i) => active_abilities - .iter_aux_abilities(Some(inventory)) - .nth(i) + .auxiliary_set(Some(inventory), Some(skill_set)) + .get(i) .and_then(|a| Ability::from(*a).ability_id(Some(inventory))) .map(util::ability_description), }) diff --git a/voxygen/src/hud/slots.rs b/voxygen/src/hud/slots.rs index de192d225f..877e1a87d5 100644 --- a/voxygen/src/hud/slots.rs +++ b/voxygen/src/hud/slots.rs @@ -141,8 +141,8 @@ impl<'a> SlotKey, HotbarImageSource<'a>> for HotbarSlot { }, hotbar::SlotContents::Ability(i) => { let ability_id = active_abilities - .iter_aux_abilities(Some(inventory)) - .nth(i) + .auxiliary_set(Some(inventory), Some(skillset)) + .get(i) .and_then(|a| Ability::from(*a).ability_id(Some(inventory))); ability_id