From d86692c4fe79e7066e86697abe4a8a40caceb4e9 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 25 Nov 2021 23:30:28 -0500 Subject: [PATCH] Added in-memory persistence of ability sets per weapon kind pair. --- .../common/abilities/ability_set_manifest.ron | 12 +--- client/src/lib.rs | 20 +++++- common/src/comp/ability.rs | 72 ++++++++++++++++--- common/src/comp/controller.rs | 1 + common/systems/src/controller.rs | 8 ++- voxygen/src/hud/diary.rs | 2 +- voxygen/src/hud/hotbar.rs | 3 +- voxygen/src/hud/skillbar.rs | 4 +- voxygen/src/hud/slots.rs | 4 +- 9 files changed, 96 insertions(+), 30 deletions(-) diff --git a/assets/common/abilities/ability_set_manifest.ron b/assets/common/abilities/ability_set_manifest.ron index e1815533ec..580338644f 100644 --- a/assets/common/abilities/ability_set_manifest.ron +++ b/assets/common/abilities/ability_set_manifest.ron @@ -9,15 +9,6 @@ // TODO: Remove these (Some(Axe(UnlockLeap)), "common.abilities.axe.leap"), (Some(Hammer(UnlockLeap)), "common.abilities.hammer.leap"), - (Some(Bow(UnlockShotgun)), "common.abilities.bow.shotgun"), - (Some(Staff(UnlockShockwave)), "common.abilities.staff.fireshockwave"), - (Some(Sceptre(UnlockAura)), "common.abilities.sceptre.wardingaura"), - (Some(Sword(UnlockSpin)), "common.abilities.sword.spin"), - (Some(Axe(UnlockLeap)), "common.abilities.axe.leap"), - (Some(Hammer(UnlockLeap)), "common.abilities.hammer.leap"), - (Some(Bow(UnlockShotgun)), "common.abilities.bow.shotgun"), - (Some(Staff(UnlockShockwave)), "common.abilities.staff.fireshockwave"), - (Some(Sceptre(UnlockAura)), "common.abilities.sceptre.wardingaura"), ], ), Tool(Axe): ( @@ -39,6 +30,9 @@ secondary: "common.abilities.bow.repeater", abilities: [ (Some(Bow(UnlockShotgun)), "common.abilities.bow.shotgun"), + // TODO: Remove these + (Some(Staff(UnlockShockwave)), "common.abilities.staff.fireshockwave"), + (Some(Sceptre(UnlockAura)), "common.abilities.sceptre.wardingaura"), ], ), Tool(Staff): ( diff --git a/client/src/lib.rs b/client/src/lib.rs index 41f364b938..e6b6181f8f 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -27,7 +27,7 @@ use common::{ group, invite::{InviteKind, InviteResponse}, skills::Skill, - slot::{InvSlotId, Slot}, + slot::{EquipSlot, InvSlotId, Slot}, CharacterState, ChatMode, ControlAction, ControlEvent, Controller, ControllerInputs, GroupManip, InputKind, InventoryAction, InventoryEvent, InventoryUpdateEvent, UtteranceKind, @@ -1404,8 +1404,26 @@ impl Client { } pub fn change_ability(&mut self, slot: usize, new_ability: comp::ability::AuxiliaryAbility) { + let auxiliary_key = self + .inventories() + .get(self.entity()) + .map_or((None, None), |inv| { + let tool_kind = |slot| { + inv.equipped(slot).and_then(|item| match item.kind() { + comp::item::ItemKind::Tool(tool) => Some(tool.kind), + _ => None, + }) + }; + + ( + tool_kind(EquipSlot::ActiveMainhand), + tool_kind(EquipSlot::ActiveOffhand), + ) + }); + self.send_msg(ClientGeneral::ControlEvent(ControlEvent::ChangeAbility { slot, + auxiliary_key, new_ability, })) } diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index ad56259565..6f1a020ae6 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -25,12 +25,14 @@ use crate::{ }, terrain::SpriteKind, }; +use hashbrown::HashMap; use serde::{Deserialize, Serialize}; use specs::{Component, DerefFlaggedStorage}; use specs_idvs::IdvStorage; use std::{convert::TryFrom, time::Duration}; pub const MAX_ABILITIES: usize = 5; +pub type AuxiliaryKey = (Option, Option); // TODO: Potentially look into storing previous ability sets for weapon // combinations and automatically reverting back to them on switching to that @@ -41,7 +43,7 @@ pub struct ActiveAbilities { pub primary: PrimaryAbility, pub secondary: SecondaryAbility, pub movement: MovementAbility, - pub abilities: [AuxiliaryAbility; MAX_ABILITIES], + pub auxiliary_sets: HashMap, } impl Component for ActiveAbilities { @@ -54,7 +56,7 @@ impl Default for ActiveAbilities { primary: PrimaryAbility::Tool, secondary: SecondaryAbility::Tool, movement: MovementAbility::Species, - abilities: [AuxiliaryAbility::Empty; MAX_ABILITIES], + auxiliary_sets: HashMap::new(), } } } @@ -68,22 +70,46 @@ impl ActiveAbilities { Self::default() } - pub fn change_ability(&mut self, slot: usize, new_ability: AuxiliaryAbility) { - if let Some(ability) = self.abilities.get_mut(slot) { + pub fn change_ability( + &mut self, + slot: usize, + auxiliary_key: AuxiliaryKey, + new_ability: AuxiliaryAbility, + ) { + let auxiliary_set = self + .auxiliary_sets + .entry(auxiliary_key) + .or_insert([AuxiliaryAbility::Empty; 5]); + if let Some(ability) = auxiliary_set.get_mut(slot) { *ability = new_ability; } } - pub fn get_ability(&self, input: AbilityInput) -> Ability { + pub fn get_ability(&self, input: AbilityInput, inventory: Option<&Inventory>) -> Ability { match input { AbilityInput::Primary => self.primary.into(), AbilityInput::Secondary => self.secondary.into(), AbilityInput::Movement => self.movement.into(), - AbilityInput::Auxiliary(index) => self - .abilities - .get(index) - .copied() - .map(|a| a.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()) + }) .unwrap_or(Ability::Empty), } } @@ -98,7 +124,7 @@ impl ActiveAbilities { body: Option<&Body>, // bool is from_offhand ) -> Option<(CharacterAbility, bool)> { - let ability = self.get_ability(input); + let ability = self.get_ability(input, inv); let ability_set = |equip_slot| { inv.and_then(|inv| inv.equipped(equip_slot)) @@ -168,6 +194,30 @@ 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, + }) + }; + + let aux_key = ( + tool_kind(EquipSlot::ActiveMainhand), + tool_kind(EquipSlot::ActiveOffhand), + ); + + self.auxiliary_sets.get(&aux_key) + }) + .into_iter() + .flatten() + } + // 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 = diff --git a/common/src/comp/controller.rs b/common/src/comp/controller.rs index 7c06b42e1c..fe803208ea 100644 --- a/common/src/comp/controller.rs +++ b/common/src/comp/controller.rs @@ -138,6 +138,7 @@ pub enum ControlEvent { Utterance(UtteranceKind), ChangeAbility { slot: usize, + auxiliary_key: ability::AuxiliaryKey, new_ability: ability::AuxiliaryAbility, }, } diff --git a/common/systems/src/controller.rs b/common/systems/src/controller.rs index dcc403e15f..87a9acbc88 100644 --- a/common/systems/src/controller.rs +++ b/common/systems/src/controller.rs @@ -110,9 +110,13 @@ impl<'a> System<'a> for Sys { server_emitter.emit(ServerEvent::Sound { sound }); } }, - ControlEvent::ChangeAbility { slot, new_ability } => { + ControlEvent::ChangeAbility { + slot, + auxiliary_key, + new_ability, + } => { if let Some(mut active_abilities) = active_abilities.get_mut(entity) { - active_abilities.change_ability(slot, new_ability); + active_abilities.change_ability(slot, auxiliary_key, new_ability); } }, } diff --git a/voxygen/src/hud/diary.rs b/voxygen/src/hud/diary.rs index 767bfd91da..997e14ef0e 100644 --- a/voxygen/src/hud/diary.rs +++ b/voxygen/src/hud/diary.rs @@ -780,7 +780,7 @@ impl<'a> Widget for Diary<'a> { for i in 0..MAX_ABILITIES { let ability_id = self .active_abilities - .get_ability(AbilityInput::Auxiliary(i)) + .get_ability(AbilityInput::Auxiliary(i), Some(self.inventory)) .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 6007aa812a..d95239293a 100644 --- a/voxygen/src/hud/hotbar.rs +++ b/voxygen/src/hud/hotbar.rs @@ -70,8 +70,7 @@ impl State { { use common::comp::ability::AuxiliaryAbility; for ((i, ability), hotbar_slot) in active_abilities - .abilities - .iter() + .iter_aux_abilities(client.inventories().get(client.entity())) .enumerate() .zip(self.slots.iter_mut()) { diff --git a/voxygen/src/hud/skillbar.rs b/voxygen/src/hud/skillbar.rs index 76e4510799..8f0c1098dc 100644 --- a/voxygen/src/hud/skillbar.rs +++ b/voxygen/src/hud/skillbar.rs @@ -607,8 +607,8 @@ impl<'a> Skillbar<'a> { .get_by_hash(i) .map(|item| (item.name(), item.description())), hotbar::SlotContents::Ability(i) => active_abilities - .abilities - .get(i) + .iter_aux_abilities(Some(inventory)) + .nth(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 7256c698a7..de192d225f 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 - .abilities - .get(i) + .iter_aux_abilities(Some(inventory)) + .nth(i) .and_then(|a| Ability::from(*a).ability_id(Some(inventory))); ability_id