diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index afbe22ad59..575dfe433e 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -144,7 +144,7 @@ impl ActiveAbilities { skill_set: &SkillSet, body: Option<&Body>, char_state: Option<&CharacterState>, - context: AbilityContext, + contexts: &[AbilityContext], // bool is from_offhand ) -> Option<(CharacterAbility, bool)> { let ability = self.get_ability(input, inv, Some(skill_set)); @@ -168,14 +168,14 @@ impl ActiveAbilities { Ability::ToolPrimary => ability_set(EquipSlot::ActiveMainhand) .and_then(|abilities| { abilities - .primary(Some(skill_set), context) + .primary(Some(skill_set), contexts) .map(|a| a.ability.clone()) }) .map(|ability| (scale_ability(ability, EquipSlot::ActiveMainhand), false)), Ability::ToolSecondary => ability_set(EquipSlot::ActiveOffhand) .and_then(|abilities| { abilities - .secondary(Some(skill_set), context) + .secondary(Some(skill_set), contexts) .map(|a| a.ability.clone()) }) .map(|ability| (scale_ability(ability, EquipSlot::ActiveOffhand), true)) @@ -183,7 +183,7 @@ impl ActiveAbilities { ability_set(EquipSlot::ActiveMainhand) .and_then(|abilities| { abilities - .secondary(Some(skill_set), context) + .secondary(Some(skill_set), contexts) .map(|a| a.ability.clone()) }) .map(|ability| (scale_ability(ability, EquipSlot::ActiveMainhand), false)) @@ -194,14 +194,14 @@ impl ActiveAbilities { Ability::MainWeaponAux(index) => ability_set(EquipSlot::ActiveMainhand) .and_then(|abilities| { abilities - .auxiliary(index, Some(skill_set), context) + .auxiliary(index, Some(skill_set), contexts) .map(|a| a.ability.clone()) }) .map(|ability| (scale_ability(ability, EquipSlot::ActiveMainhand), false)), Ability::OffWeaponAux(index) => ability_set(EquipSlot::ActiveOffhand) .and_then(|abilities| { abilities - .auxiliary(index, Some(skill_set), context) + .auxiliary(index, Some(skill_set), contexts) .map(|a| a.ability.clone()) }) .map(|ability| (scale_ability(ability, EquipSlot::ActiveOffhand), true)), @@ -226,8 +226,8 @@ impl ActiveAbilities { pseudo_id: _, abilities, } => abilities - .values() - .any(|(skill, _)| { + .iter() + .any(|(_contexts, (skill, _))| { skill.map_or(true, |s| skill_set.map_or(false, |ss| ss.has_skill(s))) }) .then_some(i), @@ -273,7 +273,7 @@ impl Ability { self, inv: Option<&'a Inventory>, skillset: Option<&'a SkillSet>, - context: AbilityContext, + contexts: &[AbilityContext], ) -> Option<&'a str> { let ability_set = |equip_slot| { inv.and_then(|inv| inv.equipped(equip_slot)) @@ -295,21 +295,21 @@ impl Ability { match self { Ability::ToolPrimary => ability_set(EquipSlot::ActiveMainhand).and_then(|abilities| { abilities - .primary(skillset, context) + .primary(skillset, contexts) .map(|a| a.id.as_str()) .or_else(|| contextual_id(Some(&abilities.primary))) }), Ability::ToolSecondary => ability_set(EquipSlot::ActiveOffhand) .and_then(|abilities| { abilities - .secondary(skillset, context) + .secondary(skillset, contexts) .map(|a| a.id.as_str()) .or_else(|| contextual_id(Some(&abilities.secondary))) }) .or_else(|| { ability_set(EquipSlot::ActiveMainhand).and_then(|abilities| { abilities - .secondary(skillset, context) + .secondary(skillset, contexts) .map(|a| a.id.as_str()) .or_else(|| contextual_id(Some(&abilities.secondary))) }) @@ -318,7 +318,7 @@ impl Ability { Ability::MainWeaponAux(index) => { ability_set(EquipSlot::ActiveMainhand).and_then(|abilities| { abilities - .auxiliary(index, skillset, context) + .auxiliary(index, skillset, contexts) .map(|a| a.id.as_str()) .or_else(|| contextual_id(abilities.abilities.get(index))) }) @@ -326,7 +326,7 @@ impl Ability { Ability::OffWeaponAux(index) => { ability_set(EquipSlot::ActiveOffhand).and_then(|abilities| { abilities - .auxiliary(index, skillset, context) + .auxiliary(index, skillset, contexts) .map(|a| a.id.as_str()) .or_else(|| contextual_id(abilities.abilities.get(index))) }) diff --git a/common/src/comp/inventory/item/tool.rs b/common/src/comp/inventory/item/tool.rs index 74ad86df93..5b934b1212 100644 --- a/common/src/comp/inventory/item/tool.rs +++ b/common/src/comp/inventory/item/tool.rs @@ -297,7 +297,7 @@ pub enum AbilityKind { Simple(Option, T), Contextualized { pseudo_id: String, - abilities: HashMap, T)>, + abilities: Vec<(Vec, (Option, T))>, }, } @@ -328,13 +328,13 @@ impl AbilityKind { pseudo_id: pseudo_id.clone(), abilities: abilities .into_iter() - .map(|(c, (s, x))| (*c, (*s, f(x)))) + .map(|(c, (s, x))| (c.clone(), (*s, f(x)))) .collect(), }, } } - pub fn ability(&self, skillset: Option<&SkillSet>, context: AbilityContext) -> Option<&T> { + pub fn ability(&self, skillset: Option<&SkillSet>, contexts: &[AbilityContext]) -> Option<&T> { let unlocked = |s: Option, a| { // If there is a skill requirement and the skillset does not contain the // required skill, return None @@ -352,13 +352,14 @@ impl AbilityKind { // the required skill, try falling back to the ability from this input that does // not require a context abilities - .get(&context) - .and_then(|(s, a)| unlocked(*s, a)) - .or_else(|| { - abilities - .get(&AbilityContext::None) - .and_then(|(s, a)| unlocked(*s, a)) + .iter() + .find_map(|(req_contexts, (s, a))| { + req_contexts + .iter() + .all(|req| contexts.contains(req)) + .then_some((s, a)) }) + .and_then(|(s, a)| unlocked(*s, a)) }, } } @@ -371,16 +372,17 @@ pub enum AbilityContext { /// `AbilityContext::Stance(Stance::None)` in the ability map config /// files(s). Stance(Stance), - None, } impl AbilityContext { - pub fn from(stance: Option<&Stance>) -> Self { + pub fn from(stance: Option<&Stance>) -> Vec { + let mut contexts = Vec::new(); match stance { - Some(Stance::None) => AbilityContext::None, - Some(stance) => AbilityContext::Stance(*stance), - None => AbilityContext::None, + Some(Stance::None) => {}, + Some(stance) => contexts.push(AbilityContext::Stance(*stance)), + None => {}, } + contexts } } @@ -417,23 +419,27 @@ impl AbilitySet { } } - pub fn primary(&self, skillset: Option<&SkillSet>, context: AbilityContext) -> Option<&T> { - self.primary.ability(skillset, context) + pub fn primary(&self, skillset: Option<&SkillSet>, contexts: &[AbilityContext]) -> Option<&T> { + self.primary.ability(skillset, contexts) } - pub fn secondary(&self, skillset: Option<&SkillSet>, context: AbilityContext) -> Option<&T> { - self.secondary.ability(skillset, context) + pub fn secondary( + &self, + skillset: Option<&SkillSet>, + contexts: &[AbilityContext], + ) -> Option<&T> { + self.secondary.ability(skillset, contexts) } pub fn auxiliary( &self, index: usize, skillset: Option<&SkillSet>, - context: AbilityContext, + contexts: &[AbilityContext], ) -> Option<&T> { self.abilities .get(index) - .and_then(|a| a.ability(skillset, context)) + .and_then(|a| a.ability(skillset, contexts)) } } diff --git a/common/src/states/utils.rs b/common/src/states/utils.rs index c001212a28..58a8bab895 100644 --- a/common/src/states/utils.rs +++ b/common/src/states/utils.rs @@ -1107,7 +1107,7 @@ fn handle_ability( output_events: &mut OutputEvents, input: InputKind, ) -> bool { - let context = AbilityContext::from(data.stance); + let contexts = AbilityContext::from(data.stance); if let Some(ability_input) = input.into() { if let Some((ability, from_offhand)) = data .active_abilities @@ -1118,7 +1118,7 @@ fn handle_ability( data.skill_set, Some(data.body), Some(data.character), - context, + &contexts, ) }) .filter(|(ability, _)| ability.requirements_paid(data, update)) diff --git a/server/agent/src/attack.rs b/server/agent/src/attack.rs index 07d94b07be..c6d6850c98 100644 --- a/server/agent/src/attack.rs +++ b/server/agent/src/attack.rs @@ -757,7 +757,7 @@ impl<'a> AgentData<'a> { ); let attack_failed = if attempt_attack { - let context = AbilityContext::from(self.stance); + let contexts = AbilityContext::from(self.stance); let extract_ability = |input: AbilityInput| { AbilityData::from_ability( &self @@ -768,7 +768,7 @@ impl<'a> AgentData<'a> { self.skill_set, self.body, Some(self.char_state), - context, + &contexts, ) .unwrap_or_default() .0, @@ -1437,7 +1437,7 @@ impl<'a> AgentData<'a> { enum ActionStateConditions { ConditionStaffCanShockwave = 0, } - let context = AbilityContext::from(self.stance); + let contexts = AbilityContext::from(self.stance); let extract_ability = |input: AbilityInput| { self.active_abilities .activate_ability( @@ -1446,7 +1446,7 @@ impl<'a> AgentData<'a> { self.skill_set, self.body, Some(self.char_state), - context, + &contexts, ) .unwrap_or_default() .0 diff --git a/voxygen/src/hud/diary.rs b/voxygen/src/hud/diary.rs index 6d690bd3f7..9c4c3fab3d 100644 --- a/voxygen/src/hud/diary.rs +++ b/voxygen/src/hud/diary.rs @@ -241,7 +241,7 @@ pub struct Diary<'a> { tooltip_manager: &'a mut TooltipManager, slot_manager: &'a mut SlotManager, pulse: f32, - context: AbilityContext, + contexts: &'a [AbilityContext], #[conrod(common_builder)] common: widget::CommonBuilder, @@ -287,7 +287,7 @@ impl<'a> Diary<'a> { tooltip_manager: &'a mut TooltipManager, slot_manager: &'a mut SlotManager, pulse: f32, - context: AbilityContext, + contexts: &'a [AbilityContext], ) -> Self { Self { show, @@ -309,7 +309,7 @@ impl<'a> Diary<'a> { tooltip_manager, slot_manager, pulse, - context, + contexts, common: widget::CommonBuilder::default(), created_btns_top_l: 0, created_btns_top_r: 0, @@ -853,7 +853,7 @@ impl<'a> Widget for Diary<'a> { self.active_abilities, self.inventory, self.skill_set, - self.context, + self.contexts, ), image_source: self.imgs, slot_manager: Some(self.slot_manager), @@ -868,7 +868,7 @@ impl<'a> Widget for Diary<'a> { Some(self.inventory), Some(self.skill_set), ) - .ability_id(Some(self.inventory), Some(self.skill_set), self.context); + .ability_id(Some(self.inventory), Some(self.skill_set), self.contexts); let (ability_title, ability_desc) = if let Some(ability_id) = ability_id { util::ability_description(ability_id, self.localized_strings) } else { @@ -953,7 +953,7 @@ impl<'a> Widget for Diary<'a> { Ability::from(a).ability_id( Some(self.inventory), Some(self.skill_set), - self.context, + self.contexts, ), a, ) @@ -969,7 +969,7 @@ impl<'a> Widget for Diary<'a> { Ability::from(a).ability_id( Some(self.inventory), Some(self.skill_set), - self.context, + self.contexts, ), a, ) @@ -1080,7 +1080,7 @@ impl<'a> Widget for Diary<'a> { self.active_abilities, self.inventory, self.skill_set, - self.context, + self.contexts, ), image_source: self.imgs, slot_manager: Some(self.slot_manager), diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 34548b7ec9..c1ee1ef4ac 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -3018,7 +3018,7 @@ impl Hud { bodies.get(entity), ) { let stance = stances.get(entity); - let context = AbilityContext::from(stance); + let contexts = AbilityContext::from(stance); match Skillbar::new( client, &info, @@ -3044,7 +3044,7 @@ impl Hud { i18n, &msm, self.floaters.combo_floater, - context, + &contexts, combos.get(entity), char_states.get(entity), stance, @@ -3522,7 +3522,7 @@ impl Hud { bodies.get(entity), poises.get(entity), ) { - let context = AbilityContext::from(stances.get(entity)); + let contexts = AbilityContext::from(stances.get(entity)); for event in Diary::new( &self.show, client, @@ -3543,7 +3543,7 @@ impl Hud { tooltip_manager, &mut self.slot_manager, self.pulse, - context, + &contexts, ) .set(self.ids.diary, ui_widgets) { diff --git a/voxygen/src/hud/skillbar.rs b/voxygen/src/hud/skillbar.rs index 638ec938ad..1e9c160324 100644 --- a/voxygen/src/hud/skillbar.rs +++ b/voxygen/src/hud/skillbar.rs @@ -313,7 +313,7 @@ pub struct Skillbar<'a> { common: widget::CommonBuilder, msm: &'a MaterialStatManifest, combo_floater: Option, - context: AbilityContext, + contexts: &'a [AbilityContext], combo: Option<&'a Combo>, char_state: Option<&'a CharacterState>, stance: Option<&'a Stance>, @@ -346,7 +346,7 @@ impl<'a> Skillbar<'a> { localized_strings: &'a Localization, msm: &'a MaterialStatManifest, combo_floater: Option, - context: AbilityContext, + contexts: &'a [AbilityContext], combo: Option<&'a Combo>, char_state: Option<&'a CharacterState>, stance: Option<&'a Stance>, @@ -377,7 +377,7 @@ impl<'a> Skillbar<'a> { localized_strings, msm, combo_floater, - context, + contexts, combo, char_state, stance, @@ -940,7 +940,7 @@ impl<'a> Skillbar<'a> { self.skillset, self.active_abilities, self.body, - self.context, + self.contexts, self.combo, self.char_state, self.stance, @@ -1025,7 +1025,7 @@ impl<'a> Skillbar<'a> { // Helper let tooltip_text = |slot| { - let (hotbar, inventory, _, skill_set, active_abilities, _, context, _, _, _) = + let (hotbar, inventory, _, skill_set, active_abilities, _, contexts, _, _, _) = content_source; hotbar.get(slot).and_then(|content| match content { hotbar::SlotContents::Inventory(i, _) => inventory @@ -1039,7 +1039,7 @@ impl<'a> Skillbar<'a> { Ability::from(*a).ability_id( Some(inventory), Some(skill_set), - context, + contexts, ) }) }) @@ -1114,7 +1114,7 @@ impl<'a> Skillbar<'a> { Ability::from(a.primary).ability_id( Some(self.inventory), Some(self.skillset), - self.context, + self.contexts, ) }); @@ -1144,7 +1144,7 @@ impl<'a> Skillbar<'a> { Ability::from(a.secondary).ability_id( Some(self.inventory), Some(self.skillset), - self.context, + self.contexts, ) }); @@ -1166,7 +1166,7 @@ impl<'a> Skillbar<'a> { self.skillset, Some(self.body), self.char_state, - self.context, + self.contexts, ) }) .map_or(false, |(a, _)| { diff --git a/voxygen/src/hud/slots.rs b/voxygen/src/hud/slots.rs index 32770ba423..22d589ebcb 100644 --- a/voxygen/src/hud/slots.rs +++ b/voxygen/src/hud/slots.rs @@ -129,7 +129,7 @@ type HotbarSource<'a> = ( &'a SkillSet, Option<&'a ActiveAbilities>, &'a Body, - AbilityContext, + &'a [AbilityContext], Option<&'a Combo>, Option<&'a CharacterState>, Option<&'a Stance>, @@ -148,7 +148,7 @@ impl<'a> SlotKey, HotbarImageSource<'a>> for HotbarSlot { skillset, active_abilities, body, - context, + contexts, combo, char_state, stance, @@ -168,7 +168,7 @@ impl<'a> SlotKey, HotbarImageSource<'a>> for HotbarSlot { a.auxiliary_set(Some(inventory), Some(skillset)) .get(i) .and_then(|a| { - Ability::from(*a).ability_id(Some(inventory), Some(skillset), *context) + Ability::from(*a).ability_id(Some(inventory), Some(skillset), contexts) }) }); @@ -183,7 +183,7 @@ impl<'a> SlotKey, HotbarImageSource<'a>> for HotbarSlot { skillset, Some(body), *char_state, - *context, + contexts, ) }) .map(|(ability, _)| { @@ -240,7 +240,7 @@ type AbilitiesSource<'a> = ( &'a ActiveAbilities, &'a Inventory, &'a SkillSet, - AbilityContext, + &'a [AbilityContext], ); impl<'a> SlotKey, img_ids::Imgs> for AbilitySlot { @@ -248,7 +248,7 @@ impl<'a> SlotKey, img_ids::Imgs> for AbilitySlot { fn image_key( &self, - (active_abilities, inventory, skillset, context): &AbilitiesSource<'a>, + (active_abilities, inventory, skillset, contexts): &AbilitiesSource<'a>, ) -> Option<(Self::ImageKey, Option)> { let ability_id = match self { Self::Slot(index) => active_abilities @@ -257,9 +257,9 @@ impl<'a> SlotKey, img_ids::Imgs> for AbilitySlot { Some(inventory), Some(skillset), ) - .ability_id(Some(inventory), Some(skillset), *context), + .ability_id(Some(inventory), Some(skillset), contexts), Self::Ability(ability) => { - Ability::from(*ability).ability_id(Some(inventory), Some(skillset), *context) + Ability::from(*ability).ability_id(Some(inventory), Some(skillset), contexts) }, }; diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index f45db05275..4133c9f5fb 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -931,12 +931,12 @@ impl FigureMgr { let second_tool_spec = second_tool_spec.as_deref(); let hands = (active_tool_hand, second_tool_hand); - let context = AbilityContext::from(stance); + let contexts = AbilityContext::from(stance); let ability_id = character.and_then(|c| { c.ability_info() .and_then(|a| a.ability) - .and_then(|a| a.ability_id(inventory, skillset, context)) + .and_then(|a| a.ability_id(inventory, skillset, &contexts)) }); let move_dir = {