diff --git a/assets/common/abilities/ability_set_manifest.ron b/assets/common/abilities/ability_set_manifest.ron index 12dff0e2ea..79e44b6ae7 100644 --- a/assets/common/abilities/ability_set_manifest.ron +++ b/assets/common/abilities/ability_set_manifest.ron @@ -13,99 +13,99 @@ primary: Contextualized( pseudo_id: "veloren.core.pseudo_abilities.sword.double_slash", abilities: [ - ([Stance(Sword(Heavy))], (None, "common.abilities.sword.heavy_double_slash")), - ([Stance(Sword(Agile))], (None, "common.abilities.sword.agile_double_slash")), - ([Stance(Sword(Defensive))], (None, "common.abilities.sword.defensive_double_slash")), - ([Stance(Sword(Crippling))], (None, "common.abilities.sword.crippling_double_slash")), - ([Stance(Sword(Cleaving))], (None, "common.abilities.sword.cleaving_double_slash")), - ([], (None, "common.abilities.sword.basic_double_slash")), + ((stance: Sword(Heavy)), (None, "common.abilities.sword.heavy_double_slash")), + ((stance: Sword(Agile)), (None, "common.abilities.sword.agile_double_slash")), + ((stance: Sword(Defensive)), (None, "common.abilities.sword.defensive_double_slash")), + ((stance: Sword(Crippling)), (None, "common.abilities.sword.crippling_double_slash")), + ((stance: Sword(Cleaving)), (None, "common.abilities.sword.cleaving_double_slash")), + ((), (None, "common.abilities.sword.basic_double_slash")), ], ), secondary: Contextualized( pseudo_id: "veloren.core.pseudo_abilities.sword.secondary_ability", abilities: [ - ([Stance(Sword(Heavy))], (None, "common.abilities.sword.heavy_slam")), - ([Stance(Sword(Agile)), DualWieldingSameKind], (None, "common.abilities.sword.agile_dual_perforate")), - ([Stance(Sword(Agile))], (None, "common.abilities.sword.agile_perforate")), - ([Stance(Sword(Defensive))], (None, "common.abilities.sword.defensive_vital_jab")), - ([Stance(Sword(Crippling))], (None, "common.abilities.sword.crippling_deep_rend")), - ([Stance(Sword(Cleaving)), DualWieldingSameKind], (None, "common.abilities.sword.cleaving_dual_spiral_slash")), - ([Stance(Sword(Cleaving))], (None, "common.abilities.sword.cleaving_spiral_slash")), - ([], (None, "common.abilities.sword.basic_thrust")), + ((stance: Sword(Heavy)), (None, "common.abilities.sword.heavy_slam")), + ((stance: Sword(Agile), dual_wielding_same_kind: true), (None, "common.abilities.sword.agile_dual_perforate")), + ((stance: Sword(Agile)), (None, "common.abilities.sword.agile_perforate")), + ((stance: Sword(Defensive)), (None, "common.abilities.sword.defensive_vital_jab")), + ((stance: Sword(Crippling)), (None, "common.abilities.sword.crippling_deep_rend")), + ((stance: Sword(Cleaving), dual_wielding_same_kind: true), (None, "common.abilities.sword.cleaving_dual_spiral_slash")), + ((stance: Sword(Cleaving)), (None, "common.abilities.sword.cleaving_spiral_slash")), + ((), (None, "common.abilities.sword.basic_thrust")), ], ), abilities: [ Contextualized( pseudo_id: "veloren.core.pseudo_abilities.sword.crescent_slash", abilities: [ - ([Stance(Sword(Heavy))], (Sword(CrescentSlash), "common.abilities.sword.heavy_crescent_slash")), - ([Stance(Sword(Agile))], (Sword(CrescentSlash), "common.abilities.sword.agile_crescent_slash")), - ([Stance(Sword(Defensive))], (Sword(CrescentSlash), "common.abilities.sword.defensive_crescent_slash")), - ([Stance(Sword(Crippling))], (Sword(CrescentSlash), "common.abilities.sword.crippling_crescent_slash")), - ([Stance(Sword(Cleaving))], (Sword(CrescentSlash), "common.abilities.sword.cleaving_crescent_slash")), - ([], (Sword(CrescentSlash), "common.abilities.sword.basic_crescent_slash")), + ((stance: Sword(Heavy)), (Sword(CrescentSlash), "common.abilities.sword.heavy_crescent_slash")), + ((stance: Sword(Agile)), (Sword(CrescentSlash), "common.abilities.sword.agile_crescent_slash")), + ((stance: Sword(Defensive)), (Sword(CrescentSlash), "common.abilities.sword.defensive_crescent_slash")), + ((stance: Sword(Crippling)), (Sword(CrescentSlash), "common.abilities.sword.crippling_crescent_slash")), + ((stance: Sword(Cleaving)), (Sword(CrescentSlash), "common.abilities.sword.cleaving_crescent_slash")), + ((), (Sword(CrescentSlash), "common.abilities.sword.basic_crescent_slash")), ], ), Contextualized( pseudo_id: "veloren.core.pseudo_abilities.sword.fell_strike", abilities: [ - ([Stance(Sword(Heavy))], (Sword(FellStrike), "common.abilities.sword.heavy_fell_strike")), - ([Stance(Sword(Agile))], (Sword(FellStrike), "common.abilities.sword.agile_fell_strike")), - ([Stance(Sword(Defensive))], (Sword(FellStrike), "common.abilities.sword.defensive_fell_strike")), - ([Stance(Sword(Crippling))], (Sword(FellStrike), "common.abilities.sword.crippling_fell_strike")), - ([Stance(Sword(Cleaving))], (Sword(FellStrike), "common.abilities.sword.cleaving_fell_strike")), - ([], (Sword(FellStrike), "common.abilities.sword.basic_fell_strike")), + ((stance: Sword(Heavy)), (Sword(FellStrike), "common.abilities.sword.heavy_fell_strike")), + ((stance: Sword(Agile)), (Sword(FellStrike), "common.abilities.sword.agile_fell_strike")), + ((stance: Sword(Defensive)), (Sword(FellStrike), "common.abilities.sword.defensive_fell_strike")), + ((stance: Sword(Crippling)), (Sword(FellStrike), "common.abilities.sword.crippling_fell_strike")), + ((stance: Sword(Cleaving)), (Sword(FellStrike), "common.abilities.sword.cleaving_fell_strike")), + ((), (Sword(FellStrike), "common.abilities.sword.basic_fell_strike")), ], ), Contextualized( pseudo_id: "veloren.core.pseudo_abilities.sword.skewer", abilities: [ - ([Stance(Sword(Heavy))], (Sword(Skewer), "common.abilities.sword.heavy_skewer")), - ([Stance(Sword(Agile))], (Sword(Skewer), "common.abilities.sword.agile_skewer")), - ([Stance(Sword(Defensive))], (Sword(Skewer), "common.abilities.sword.defensive_skewer")), - ([Stance(Sword(Crippling))], (Sword(Skewer), "common.abilities.sword.crippling_skewer")), - ([Stance(Sword(Cleaving))], (Sword(Skewer), "common.abilities.sword.cleaving_skewer")), - ([], (Sword(Skewer), "common.abilities.sword.basic_skewer")), + ((stance: Sword(Heavy)), (Sword(Skewer), "common.abilities.sword.heavy_skewer")), + ((stance: Sword(Agile)), (Sword(Skewer), "common.abilities.sword.agile_skewer")), + ((stance: Sword(Defensive)), (Sword(Skewer), "common.abilities.sword.defensive_skewer")), + ((stance: Sword(Crippling)), (Sword(Skewer), "common.abilities.sword.crippling_skewer")), + ((stance: Sword(Cleaving)), (Sword(Skewer), "common.abilities.sword.cleaving_skewer")), + ((), (Sword(Skewer), "common.abilities.sword.basic_skewer")), ], ), Contextualized( pseudo_id: "veloren.core.pseudo_abilities.sword.cascade", abilities: [ - ([Stance(Sword(Heavy))], (Sword(Cascade), "common.abilities.sword.heavy_cascade")), - ([Stance(Sword(Agile))], (Sword(Cascade), "common.abilities.sword.agile_cascade")), - ([Stance(Sword(Defensive))], (Sword(Cascade), "common.abilities.sword.defensive_cascade")), - ([Stance(Sword(Crippling))], (Sword(Cascade), "common.abilities.sword.crippling_cascade")), - ([Stance(Sword(Cleaving))], (Sword(Cascade), "common.abilities.sword.cleaving_cascade")), - ([], (Sword(Cascade), "common.abilities.sword.basic_cascade")), + ((stance: Sword(Heavy)), (Sword(Cascade), "common.abilities.sword.heavy_cascade")), + ((stance: Sword(Agile)), (Sword(Cascade), "common.abilities.sword.agile_cascade")), + ((stance: Sword(Defensive)), (Sword(Cascade), "common.abilities.sword.defensive_cascade")), + ((stance: Sword(Crippling)), (Sword(Cascade), "common.abilities.sword.crippling_cascade")), + ((stance: Sword(Cleaving)), (Sword(Cascade), "common.abilities.sword.cleaving_cascade")), + ((), (Sword(Cascade), "common.abilities.sword.basic_cascade")), ], ), Contextualized( pseudo_id: "veloren.core.pseudo_abilities.sword.cross_cut", abilities: [ - ([Stance(Sword(Heavy)), DualWieldingSameKind], (Sword(CrossCut), "common.abilities.sword.heavy_dual_cross_cut")), - ([Stance(Sword(Agile)), DualWieldingSameKind], (Sword(CrossCut), "common.abilities.sword.agile_dual_cross_cut")), - ([Stance(Sword(Defensive)), DualWieldingSameKind], (Sword(CrossCut), "common.abilities.sword.defensive_dual_cross_cut")), - ([Stance(Sword(Crippling)), DualWieldingSameKind], (Sword(CrossCut), "common.abilities.sword.crippling_dual_cross_cut")), - ([Stance(Sword(Cleaving)), DualWieldingSameKind], (Sword(CrossCut), "common.abilities.sword.cleaving_dual_cross_cut")), - ([DualWieldingSameKind], (Sword(CrossCut), "common.abilities.sword.basic_dual_cross_cut")), - ([Stance(Sword(Heavy))], (Sword(CrossCut), "common.abilities.sword.heavy_cross_cut")), - ([Stance(Sword(Agile))], (Sword(CrossCut), "common.abilities.sword.agile_cross_cut")), - ([Stance(Sword(Defensive))], (Sword(CrossCut), "common.abilities.sword.defensive_cross_cut")), - ([Stance(Sword(Crippling))], (Sword(CrossCut), "common.abilities.sword.crippling_cross_cut")), - ([Stance(Sword(Cleaving))], (Sword(CrossCut), "common.abilities.sword.cleaving_cross_cut")), - ([], (Sword(CrossCut), "common.abilities.sword.basic_cross_cut")), + ((stance: Sword(Heavy), dual_wielding_same_kind: true), (Sword(CrossCut), "common.abilities.sword.heavy_dual_cross_cut")), + ((stance: Sword(Agile), dual_wielding_same_kind: true), (Sword(CrossCut), "common.abilities.sword.agile_dual_cross_cut")), + ((stance: Sword(Defensive), dual_wielding_same_kind: true), (Sword(CrossCut), "common.abilities.sword.defensive_dual_cross_cut")), + ((stance: Sword(Crippling), dual_wielding_same_kind: true), (Sword(CrossCut), "common.abilities.sword.crippling_dual_cross_cut")), + ((stance: Sword(Cleaving), dual_wielding_same_kind: true), (Sword(CrossCut), "common.abilities.sword.cleaving_dual_cross_cut")), + ((dual_wielding_same_kind: true), (Sword(CrossCut), "common.abilities.sword.basic_dual_cross_cut")), + ((stance: Sword(Heavy)), (Sword(CrossCut), "common.abilities.sword.heavy_cross_cut")), + ((stance: Sword(Agile)), (Sword(CrossCut), "common.abilities.sword.agile_cross_cut")), + ((stance: Sword(Defensive)), (Sword(CrossCut), "common.abilities.sword.defensive_cross_cut")), + ((stance: Sword(Crippling)), (Sword(CrossCut), "common.abilities.sword.crippling_cross_cut")), + ((stance: Sword(Cleaving)), (Sword(CrossCut), "common.abilities.sword.cleaving_cross_cut")), + ((), (Sword(CrossCut), "common.abilities.sword.basic_cross_cut")), ], ), Contextualized( pseudo_id: "veloren.core.pseudo_abilities.sword.finisher", abilities: [ - ([Stance(Sword(Heavy))], (Sword(Finisher), "common.abilities.sword.heavy_guillotine")), - ([Stance(Sword(Agile))], (Sword(Finisher), "common.abilities.sword.agile_hundred_cuts")), - ([Stance(Sword(Defensive))], (Sword(Finisher), "common.abilities.sword.defensive_counter")), - ([Stance(Sword(Crippling))], (Sword(Finisher), "common.abilities.sword.crippling_mutilate")), - ([Stance(Sword(Cleaving)), DualWieldingSameKind], (Sword(Finisher), "common.abilities.sword.cleaving_dual_bladestorm")), - ([Stance(Sword(Cleaving))], (Sword(Finisher), "common.abilities.sword.cleaving_bladestorm")), - ([], (Sword(Finisher), "common.abilities.sword.basic_mighty_strike")), + ((stance: Sword(Heavy)), (Sword(Finisher), "common.abilities.sword.heavy_guillotine")), + ((stance: Sword(Agile)), (Sword(Finisher), "common.abilities.sword.agile_hundred_cuts")), + ((stance: Sword(Defensive)), (Sword(Finisher), "common.abilities.sword.defensive_counter")), + ((stance: Sword(Crippling)), (Sword(Finisher), "common.abilities.sword.crippling_mutilate")), + ((stance: Sword(Cleaving), dual_wielding_same_kind: true), (Sword(Finisher), "common.abilities.sword.cleaving_dual_bladestorm")), + ((stance: Sword(Cleaving)), (Sword(Finisher), "common.abilities.sword.cleaving_bladestorm")), + ((), (Sword(Finisher), "common.abilities.sword.basic_mighty_strike")), ], ), Simple(Sword(HeavySweep), "common.abilities.sword.heavy_sweep"), @@ -119,8 +119,8 @@ Contextualized( pseudo_id: "common.abilities.sword.cleaving_whirlwind_slice", abilities: [ - ([DualWieldingSameKind], (Sword(CleavingWhirlwindSlice), "common.abilities.sword.cleaving_dual_whirlwind_slice")), - ([], (Sword(CleavingWhirlwindSlice), "common.abilities.sword.cleaving_whirlwind_slice")), + ((dual_wielding_same_kind: true), (Sword(CleavingWhirlwindSlice), "common.abilities.sword.cleaving_dual_whirlwind_slice")), + ((), (Sword(CleavingWhirlwindSlice), "common.abilities.sword.cleaving_whirlwind_slice")), ], ), Simple(Sword(CleavingEarthSplitter), "common.abilities.sword.cleaving_earth_splitter"), @@ -130,8 +130,8 @@ Contextualized( pseudo_id: "common.abilities.sword.agile_flurry", abilities: [ - ([Stance(Sword(Agile)), DualWieldingSameKind], (Sword(AgileFlurry), "common.abilities.sword.agile_dual_flurry")), - ([Stance(Sword(Agile))], (Sword(AgileFlurry), "common.abilities.sword.agile_flurry")), + ((stance: Sword(Agile), dual_wielding_same_kind: true), (Sword(AgileFlurry), "common.abilities.sword.agile_dual_flurry")), + ((stance: Sword(Agile)), (Sword(AgileFlurry), "common.abilities.sword.agile_flurry")), ], ), Simple(Sword(DefensiveStalwartSword), "common.abilities.sword.defensive_stalwart_sword"), @@ -155,8 +155,8 @@ Contextualized( pseudo_id: "common.abilities.axe.execute", abilities: [ - ([Combo(50)], (Axe(Maelstrom), "common.abilities.axe.maelstrom")), - ([], (Axe(Execute), "common.abilities.axe.execute")), + ((combo: Some(50)), (Axe(Maelstrom), "common.abilities.axe.maelstrom")), + ((), (Axe(Execute), "common.abilities.axe.execute")), ], ), Simple(Axe(Rake), "common.abilities.axe.rake"), @@ -164,8 +164,8 @@ Contextualized( pseudo_id: "common.abilities.axe.fierce_raze", abilities: [ - ([DualWieldingSameKind], (Axe(FierceRaze), "common.abilities.axe.dual_fierce_raze")), - ([], (Axe(FierceRaze), "common.abilities.axe.fierce_raze")), + ((dual_wielding_same_kind: true), (Axe(FierceRaze), "common.abilities.axe.dual_fierce_raze")), + ((), (Axe(FierceRaze), "common.abilities.axe.fierce_raze")), ], ), Simple(Axe(Furor), "common.abilities.axe.furor"), @@ -173,8 +173,8 @@ Contextualized( pseudo_id: "common.abilities.axe.lacerate", abilities: [ - ([Combo(50)], (Axe(Riptide), "common.abilities.axe.riptide")), - ([], (Axe(Lacerate), "common.abilities.axe.lacerate")), + ((combo: Some(50)), (Axe(Riptide), "common.abilities.axe.riptide")), + ((), (Axe(Lacerate), "common.abilities.axe.lacerate")), ], ), Simple(Axe(SkullBash), "common.abilities.axe.skull_bash"), @@ -185,8 +185,8 @@ Contextualized( pseudo_id: "common.abilities.axe.bulkhead", abilities: [ - ([Combo(50)], (Axe(Capsize), "common.abilities.axe.capsize")), - ([], (Axe(Bulkhead), "common.abilities.axe.bulkhead")), + ((combo: Some(50)), (Axe(Capsize), "common.abilities.axe.capsize")), + ((), (Axe(Bulkhead), "common.abilities.axe.bulkhead")), ], ), ], diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index 81035c749a..4c93a97d25 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -149,7 +149,7 @@ impl ActiveAbilities { skill_set: &SkillSet, body: Option<&Body>, char_state: Option<&CharacterState>, - contexts: &[AbilityContext], + context: &AbilityContext, // bool is from_offhand ) -> Option<(CharacterAbility, bool, SpecifiedAbility)> { let ability = self.get_ability(input, inv, Some(skill_set)); @@ -206,7 +206,7 @@ impl ActiveAbilities { Ability::ToolPrimary => ability_set(EquipSlot::ActiveMainhand) .and_then(|abilities| { abilities - .primary(Some(skill_set), contexts) + .primary(Some(skill_set), context) .map(|(a, i)| (a.ability.clone(), i)) }) .map(|(ability, i)| { @@ -219,7 +219,7 @@ impl ActiveAbilities { Ability::ToolSecondary => ability_set(EquipSlot::ActiveOffhand) .and_then(|abilities| { abilities - .secondary(Some(skill_set), contexts) + .secondary(Some(skill_set), context) .map(|(a, i)| (a.ability.clone(), i)) }) .map(|(ability, i)| { @@ -233,7 +233,7 @@ impl ActiveAbilities { ability_set(EquipSlot::ActiveMainhand) .and_then(|abilities| { abilities - .secondary(Some(skill_set), contexts) + .secondary(Some(skill_set), context) .map(|(a, i)| (a.ability.clone(), i)) }) .map(|(ability, i)| { @@ -256,7 +256,7 @@ impl ActiveAbilities { Ability::MainWeaponAux(index) => ability_set(EquipSlot::ActiveMainhand) .and_then(|abilities| { abilities - .auxiliary(index, Some(skill_set), contexts) + .auxiliary(index, Some(skill_set), context) .map(|(a, i)| (a.ability.clone(), i)) }) .map(|(ability, i)| { @@ -269,7 +269,7 @@ impl ActiveAbilities { Ability::OffWeaponAux(index) => ability_set(EquipSlot::ActiveOffhand) .and_then(|abilities| { abilities - .auxiliary(index, Some(skill_set), contexts) + .auxiliary(index, Some(skill_set), context) .map(|(a, i)| (a.ability.clone(), i)) }) .map(|(ability, i)| { @@ -349,7 +349,7 @@ impl Ability { self, inv: Option<&'a Inventory>, skillset: Option<&'a SkillSet>, - contexts: &[AbilityContext], + context: &AbilityContext, ) -> Option<&'a str> { let ability_set = |equip_slot| { inv.and_then(|inv| inv.equipped(equip_slot)) @@ -396,21 +396,21 @@ impl Ability { }), Ability::ToolPrimary => ability_set(EquipSlot::ActiveMainhand).and_then(|abilities| { abilities - .primary(skillset, contexts) + .primary(skillset, context) .map(|a| a.0.id.as_str()) .or_else(|| contextual_id(Some(&abilities.primary))) }), Ability::ToolSecondary => ability_set(EquipSlot::ActiveOffhand) .and_then(|abilities| { abilities - .secondary(skillset, contexts) + .secondary(skillset, context) .map(|a| a.0.id.as_str()) .or_else(|| contextual_id(Some(&abilities.secondary))) }) .or_else(|| { ability_set(EquipSlot::ActiveMainhand).and_then(|abilities| { abilities - .secondary(skillset, contexts) + .secondary(skillset, context) .map(|a| a.0.id.as_str()) .or_else(|| contextual_id(Some(&abilities.secondary))) }) @@ -419,7 +419,7 @@ impl Ability { Ability::MainWeaponAux(index) => { ability_set(EquipSlot::ActiveMainhand).and_then(|abilities| { abilities - .auxiliary(index, skillset, contexts) + .auxiliary(index, skillset, context) .map(|a| a.0.id.as_str()) .or_else(|| contextual_id(abilities.abilities.get(index))) }) @@ -427,7 +427,7 @@ impl Ability { Ability::OffWeaponAux(index) => { ability_set(EquipSlot::ActiveOffhand).and_then(|abilities| { abilities - .auxiliary(index, skillset, contexts) + .auxiliary(index, skillset, context) .map(|a| a.0.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 513d564935..3a04c932ec 100644 --- a/common/src/comp/inventory/item/tool.rs +++ b/common/src/comp/inventory/item/tool.rs @@ -305,10 +305,13 @@ pub enum AbilityKind { Simple(Option, T), Contextualized { pseudo_id: String, - abilities: Vec<(Vec, (Option, T))>, + abilities: Vec<(AbilityContext, (Option, T))>, }, } +/// The contextual index indicates which entry in a contextual ability was used. +/// This should only be necessary for the frontend to distinguish between the +/// options when a contextual ability is used. #[derive(Clone, Debug, Serialize, Deserialize, Copy, Eq, PartialEq)] pub struct ContextualIndex(pub usize); @@ -339,7 +342,7 @@ impl AbilityKind { pseudo_id: pseudo_id.clone(), abilities: abilities .iter() - .map(|(c, (s, x))| (c.clone(), (*s, f(x)))) + .map(|(c, (s, x))| (*c, (*s, f(x)))) .collect(), }, } @@ -348,7 +351,7 @@ impl AbilityKind { pub fn ability( &self, skillset: Option<&SkillSet>, - contexts: &[AbilityContext], + context: &AbilityContext, ) -> Option<(&T, Option)> { let unlocked = |s: Option, a| { // If there is a skill requirement and the skillset does not contain the @@ -368,40 +371,34 @@ impl AbilityKind { .filter_map(|(i, (req_contexts, (s, a)))| { unlocked(*s, a).map(|a| (i, (req_contexts, a))) }) - .find_map(|(i, (req_contexts, a))| { - req_contexts - .iter() - .all(|req| req.fulfilled_by(contexts)) + .find_map(|(i, (req_context, a))| { + req_context + .fulfilled_by(context) .then_some((a, Some(ContextualIndex(i)))) }), } } } -#[derive(Clone, Debug, Serialize, Deserialize, Copy, Eq, PartialEq, Hash)] -pub enum AbilityContext { - /// Note, in this context `Stance::None` isn't intended to be used. e.g. - /// `AbilityContext::None` should always be used instead of - /// `AbilityContext::Stance(Stance::None)` in the ability map config - /// files(s). - Stance(Stance), - DualWieldingSameKind, - Combo(u32), +#[derive(Clone, Debug, Serialize, Deserialize, Copy, Eq, PartialEq, Hash, Default)] +pub struct AbilityContext { + /// Note, in this context `Stance::None` isn't intended to be used. e.g. the + /// stance field should be `None` instead of `Some(Stance::None)` in the + /// ability map config files(s). + pub stance: Option, + #[serde(default)] + pub dual_wielding_same_kind: bool, + pub combo: Option, } impl AbilityContext { - pub fn from( - stance: Option<&Stance>, - inv: Option<&Inventory>, - combo: Option<&Combo>, - ) -> Vec { - let mut contexts = Vec::new(); - match stance { - Some(Stance::None) => {}, - Some(stance) => contexts.push(AbilityContext::Stance(*stance)), - None => {}, - } - if let Some(inv) = inv { + pub fn from(stance: Option<&Stance>, inv: Option<&Inventory>, combo: Option<&Combo>) -> Self { + let stance = match stance { + Some(Stance::None) => None, + Some(stance) => Some(*stance), + None => None, + }; + let dual_wielding_same_kind = if let Some(inv) = inv { let tool_kind = |slot| { inv.equipped(slot).and_then(|i| { if let ItemKind::Tool(tool) = &*i.kind() { @@ -411,30 +408,33 @@ impl AbilityContext { } }) }; - if tool_kind(EquipSlot::ActiveMainhand) == tool_kind(EquipSlot::ActiveOffhand) { - contexts.push(AbilityContext::DualWieldingSameKind) - } + tool_kind(EquipSlot::ActiveMainhand) == tool_kind(EquipSlot::ActiveOffhand) + } else { + false + }; + let combo = combo.map(|c| c.counter()); + + AbilityContext { + stance, + dual_wielding_same_kind, + combo, } - if let Some(combo) = combo { - contexts.push(AbilityContext::Combo(combo.counter())); - } - contexts } - fn fulfilled_by(&self, contexts: &[AbilityContext]) -> bool { - match self { - Self::Stance(_) | Self::DualWieldingSameKind => contexts.contains(self), - Self::Combo(required) => contexts - .iter() - .filter_map(|context| { - if let Self::Combo(combo) = context { - Some(combo) - } else { - None - } - }) - .any(|combo| combo >= required), - } + fn fulfilled_by(&self, context: &AbilityContext) -> bool { + let AbilityContext { + stance, + dual_wielding_same_kind, + combo, + } = self; + // Either stance not required or context is in the same stance + let stance_check = stance.map_or(true, |s| context.stance.map_or(false, |c_s| c_s == s)); + // Either dual wield not required or context is dual wielding + let dual_wield_check = !dual_wielding_same_kind || context.dual_wielding_same_kind; + // Either no minimum combo needed or context has sufficient combo + let combo_check = combo.map_or(true, |c| context.combo.map_or(false, |c_c| c_c >= c)); + + stance_check && dual_wield_check && combo_check } } @@ -486,28 +486,28 @@ impl AbilitySet { pub fn primary( &self, skillset: Option<&SkillSet>, - contexts: &[AbilityContext], + context: &AbilityContext, ) -> Option<(&T, Option)> { - self.primary.ability(skillset, contexts) + self.primary.ability(skillset, context) } pub fn secondary( &self, skillset: Option<&SkillSet>, - contexts: &[AbilityContext], + context: &AbilityContext, ) -> Option<(&T, Option)> { - self.secondary.ability(skillset, contexts) + self.secondary.ability(skillset, context) } pub fn auxiliary( &self, index: usize, skillset: Option<&SkillSet>, - contexts: &[AbilityContext], + context: &AbilityContext, ) -> Option<(&T, Option)> { self.abilities .get(index) - .and_then(|a| a.ability(skillset, contexts)) + .and_then(|a| a.ability(skillset, context)) } } diff --git a/common/src/comp/stats.rs b/common/src/comp/stats.rs index 531086a08c..159c296173 100644 --- a/common/src/comp/stats.rs +++ b/common/src/comp/stats.rs @@ -65,9 +65,11 @@ pub struct Stats { pub attack_damage_modifier: f32, pub crit_chance_modifier: StatsModifier, pub swim_speed_modifier: f32, + // This adds effects to any attacks that the entity makes pub effects_on_attack: Vec, pub mitigations_penetration: f32, pub energy_reward_modifier: f32, + // This creates effects when the entity is damaged pub effects_on_damaged: Vec, } diff --git a/common/src/states/utils.rs b/common/src/states/utils.rs index 131c99ceb2..b5a29af7f4 100644 --- a/common/src/states/utils.rs +++ b/common/src/states/utils.rs @@ -1197,7 +1197,7 @@ fn handle_ability( output_events: &mut OutputEvents, input: InputKind, ) -> bool { - let contexts = AbilityContext::from(data.stance, data.inventory, data.combo); + let context = AbilityContext::from(data.stance, data.inventory, data.combo); if let Some(ability_input) = input.into() { if let Some((ability, from_offhand, spec_ability)) = data .active_abilities @@ -1208,7 +1208,7 @@ fn handle_ability( data.skill_set, Some(data.body), Some(data.character), - &contexts, + &context, ) }) .filter(|(ability, _, _)| ability.requirements_paid(data, update)) @@ -1609,8 +1609,9 @@ impl ScalingKind { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)] pub enum ComboConsumption { + #[default] All, Half, } @@ -1629,10 +1630,6 @@ impl ComboConsumption { } } -impl Default for ComboConsumption { - fn default() -> Self { Self::All } -} - fn loadout_change_hook(data: &JoinData<'_>, output_events: &mut OutputEvents, clear_combo: bool) { if clear_combo { // Reset combo to 0 diff --git a/server/agent/src/attack.rs b/server/agent/src/attack.rs index acf59d671d..eb27de8df3 100644 --- a/server/agent/src/attack.rs +++ b/server/agent/src/attack.rs @@ -1699,7 +1699,7 @@ impl<'a> AgentData<'a> { enum ActionStateConditions { ConditionStaffCanShockwave = 0, } - let contexts = AbilityContext::from(self.stance, Some(self.inventory), self.combo); + let context = AbilityContext::from(self.stance, Some(self.inventory), self.combo); let extract_ability = |input: AbilityInput| { self.active_abilities .activate_ability( @@ -1708,7 +1708,7 @@ impl<'a> AgentData<'a> { self.skill_set, self.body, Some(self.char_state), - &contexts, + &context, ) .map_or(Default::default(), |a| a.0) }; diff --git a/voxygen/src/hud/diary.rs b/voxygen/src/hud/diary.rs index 12a0ed9ca8..347cca0b96 100644 --- a/voxygen/src/hud/diary.rs +++ b/voxygen/src/hud/diary.rs @@ -225,7 +225,7 @@ pub struct Diary<'a> { tooltip_manager: &'a mut TooltipManager, slot_manager: &'a mut SlotManager, pulse: f32, - contexts: &'a [AbilityContext], + context: &'a AbilityContext, #[conrod(common_builder)] common: widget::CommonBuilder, @@ -271,7 +271,7 @@ impl<'a> Diary<'a> { tooltip_manager: &'a mut TooltipManager, slot_manager: &'a mut SlotManager, pulse: f32, - contexts: &'a [AbilityContext], + context: &'a AbilityContext, ) -> Self { Self { show, @@ -293,7 +293,7 @@ impl<'a> Diary<'a> { tooltip_manager, slot_manager, pulse, - contexts, + context, common: widget::CommonBuilder::default(), created_btns_top_l: 0, created_btns_top_r: 0, @@ -837,7 +837,7 @@ impl<'a> Widget for Diary<'a> { self.active_abilities, self.inventory, self.skill_set, - self.contexts, + self.context, ), image_source: self.imgs, slot_manager: Some(self.slot_manager), @@ -852,7 +852,7 @@ impl<'a> Widget for Diary<'a> { Some(self.inventory), Some(self.skill_set), ) - .ability_id(Some(self.inventory), Some(self.skill_set), self.contexts); + .ability_id(Some(self.inventory), Some(self.skill_set), self.context); let (ability_title, ability_desc) = if let Some(ability_id) = ability_id { util::ability_description(ability_id, self.localized_strings) } else { @@ -937,7 +937,7 @@ impl<'a> Widget for Diary<'a> { Ability::from(a).ability_id( Some(self.inventory), Some(self.skill_set), - self.contexts, + self.context, ), a, ) @@ -953,7 +953,7 @@ impl<'a> Widget for Diary<'a> { Ability::from(a).ability_id( Some(self.inventory), Some(self.skill_set), - self.contexts, + self.context, ), a, ) @@ -1064,7 +1064,7 @@ impl<'a> Widget for Diary<'a> { self.active_abilities, self.inventory, self.skill_set, - self.contexts, + self.context, ), 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 716fae21f7..283ddac7e5 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -3074,7 +3074,7 @@ impl Hud { bodies.get(entity), ) { let stance = stances.get(entity); - let contexts = AbilityContext::from(stance, Some(inventory), combo); + let context = AbilityContext::from(stance, Some(inventory), combo); match Skillbar::new( client, &info, @@ -3100,7 +3100,7 @@ impl Hud { i18n, &msm, self.floaters.combo_floater, - &contexts, + &context, combo, char_states.get(entity), stance, @@ -3582,7 +3582,7 @@ impl Hud { bodies.get(entity), poises.get(entity), ) { - let contexts = AbilityContext::from(stances.get(entity), Some(inventory), combo); + let context = AbilityContext::from(stances.get(entity), Some(inventory), combo); for event in Diary::new( &self.show, client, @@ -3603,7 +3603,7 @@ impl Hud { tooltip_manager, &mut self.slot_manager, self.pulse, - &contexts, + &context, ) .set(self.ids.diary, ui_widgets) { @@ -5195,7 +5195,6 @@ pub fn get_buff_desc(buff: BuffKind, data: BuffData, localized_strings: &Localiz BuffKind::Fortitude => localized_strings.get_msg("buff-desc-fortitude"), BuffKind::Reckless => localized_strings.get_msg("buff-desc-reckless"), // BuffKind::SalamanderAspect => localized_strings.get_msg("buff-desc-salamanderaspect"), - BuffKind::Polymorphed(_) => localized_strings.get_msg("buff-desc-polymorphed"), BuffKind::Flame => localized_strings.get_msg("buff-desc-flame"), BuffKind::Frigid => localized_strings.get_msg("buff-desc-frigid"), BuffKind::Lifesteal => localized_strings.get_msg("buff-desc-lifesteal"), @@ -5216,6 +5215,7 @@ pub fn get_buff_desc(buff: BuffKind, data: BuffData, localized_strings: &Localiz BuffKind::Poisoned => localized_strings.get_msg("buff-desc-poisoned"), BuffKind::Parried => localized_strings.get_msg("buff-desc-parried"), BuffKind::PotionSickness => localized_strings.get_msg("buff-desc-potionsickness"), + BuffKind::Polymorphed(_) => localized_strings.get_msg("buff-desc-polymorphed"), } } diff --git a/voxygen/src/hud/skillbar.rs b/voxygen/src/hud/skillbar.rs index 2f0356cdd4..80541ea8cc 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, - contexts: &'a [AbilityContext], + context: &'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, - contexts: &'a [AbilityContext], + context: &'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, - contexts, + context, combo, char_state, stance, @@ -940,7 +940,7 @@ impl<'a> Skillbar<'a> { self.skillset, self.active_abilities, self.body, - self.contexts, + self.context, self.combo, self.char_state, self.stance, @@ -1114,7 +1114,7 @@ impl<'a> Skillbar<'a> { Ability::from(a.primary).ability_id( Some(self.inventory), Some(self.skillset), - self.contexts, + self.context, ) }); @@ -1144,7 +1144,7 @@ impl<'a> Skillbar<'a> { Ability::from(a.secondary).ability_id( Some(self.inventory), Some(self.skillset), - self.contexts, + self.context, ) }); @@ -1166,7 +1166,7 @@ impl<'a> Skillbar<'a> { self.skillset, Some(self.body), self.char_state, - self.contexts, + self.context, ) }) .map_or(false, |(a, _, _)| { diff --git a/voxygen/src/hud/slots.rs b/voxygen/src/hud/slots.rs index 6b45ce31ae..3174d845b7 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, - &'a [AbilityContext], + &'a AbilityContext, Option<&'a Combo>, Option<&'a CharacterState>, Option<&'a Stance>, @@ -240,7 +240,7 @@ type AbilitiesSource<'a> = ( &'a ActiveAbilities, &'a Inventory, &'a SkillSet, - &'a [AbilityContext], + &'a AbilityContext, ); impl<'a> SlotKey, img_ids::Imgs> for AbilitySlot {