mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Address UX issues of contextual abilities.
This commit is contained in:
parent
e1f76e0127
commit
1782408676
@ -75,4 +75,6 @@ common-abilities-sword-reaching_charge = Charge
|
|||||||
common-abilities-sword-reaching_flurry = Lunging Flurry
|
common-abilities-sword-reaching_flurry = Lunging Flurry
|
||||||
.desc = Make multiple rapid thrusts at your foe.
|
.desc = Make multiple rapid thrusts at your foe.
|
||||||
common-abilities-sword-reaching_skewer = Skewer
|
common-abilities-sword-reaching_skewer = Skewer
|
||||||
.desc = Lunge forward with enough force to pierce multiple foes.
|
.desc = Lunge forward with enough force to pierce multiple foes.
|
||||||
|
veloren-core-pseudo_abilities-sword-stance_ability = Sword Stance Ability
|
||||||
|
.desc = When in a sword stance, this ability will have different effects.
|
@ -5,7 +5,7 @@ use crate::{
|
|||||||
self, aura, beam, buff,
|
self, aura, beam, buff,
|
||||||
inventory::{
|
inventory::{
|
||||||
item::{
|
item::{
|
||||||
tool::{AbilityContext, AbilityItem, Stats, ToolKind},
|
tool::{AbilityContext, AbilityItem, AuxiliaryAbilityKind, Stats, ToolKind},
|
||||||
ItemKind,
|
ItemKind,
|
||||||
},
|
},
|
||||||
slot::EquipSlot,
|
slot::EquipSlot,
|
||||||
@ -198,22 +198,25 @@ impl ActiveAbilities {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_unlocked_abilities<'a>(
|
pub fn iter_available_abilities<'a>(
|
||||||
inv: Option<&'a Inventory>,
|
inv: Option<&'a Inventory>,
|
||||||
skill_set: Option<&'a SkillSet>,
|
skill_set: Option<&'a SkillSet>,
|
||||||
equip_slot: EquipSlot,
|
equip_slot: EquipSlot,
|
||||||
context: Option<AbilityContext>,
|
|
||||||
) -> impl Iterator<Item = usize> + 'a {
|
) -> impl Iterator<Item = usize> + 'a {
|
||||||
inv.and_then(|inv| inv.equipped(equip_slot))
|
inv.and_then(|inv| inv.equipped(equip_slot))
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|i| &i.item_config_expect().abilities.abilities)
|
.flat_map(|i| &i.item_config_expect().abilities.abilities)
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter_map(move |(i, a)| {
|
.filter_map(move |(i, a)| match a {
|
||||||
a.ability(context).and_then(|(skill, _)| {
|
AuxiliaryAbilityKind::Simple(skill, _) => skill
|
||||||
skill
|
.map_or(true, |s| skill_set.map_or(false, |ss| ss.has_skill(s)))
|
||||||
.map_or(true, |s| skill_set.map_or(false, |ss| ss.has_skill(s)))
|
.then_some(i),
|
||||||
.then_some(i)
|
AuxiliaryAbilityKind::Contextualized(abilities) => abilities
|
||||||
})
|
.values()
|
||||||
|
.any(|(skill, _)| {
|
||||||
|
skill.map_or(true, |s| skill_set.map_or(false, |ss| ss.has_skill(s)))
|
||||||
|
})
|
||||||
|
.then_some(i),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,13 +224,12 @@ impl ActiveAbilities {
|
|||||||
inv: Option<&'a Inventory>,
|
inv: Option<&'a Inventory>,
|
||||||
skill_set: Option<&'a SkillSet>,
|
skill_set: Option<&'a SkillSet>,
|
||||||
) -> [AuxiliaryAbility; MAX_ABILITIES] {
|
) -> [AuxiliaryAbility; MAX_ABILITIES] {
|
||||||
let mut iter =
|
let mut iter = Self::iter_available_abilities(inv, skill_set, EquipSlot::ActiveMainhand)
|
||||||
Self::iter_unlocked_abilities(inv, skill_set, EquipSlot::ActiveMainhand, None)
|
.map(AuxiliaryAbility::MainWeapon)
|
||||||
.map(AuxiliaryAbility::MainWeapon)
|
.chain(
|
||||||
.chain(
|
Self::iter_available_abilities(inv, skill_set, EquipSlot::ActiveOffhand)
|
||||||
Self::iter_unlocked_abilities(inv, skill_set, EquipSlot::ActiveOffhand, None)
|
.map(AuxiliaryAbility::OffWeapon),
|
||||||
.map(AuxiliaryAbility::OffWeapon),
|
);
|
||||||
);
|
|
||||||
|
|
||||||
[(); MAX_ABILITIES].map(|()| iter.next().unwrap_or(AuxiliaryAbility::Empty))
|
[(); MAX_ABILITIES].map(|()| iter.next().unwrap_or(AuxiliaryAbility::Empty))
|
||||||
}
|
}
|
||||||
@ -263,6 +265,28 @@ impl Ability {
|
|||||||
.map(|i| &i.item_config_expect().abilities)
|
.map(|i| &i.item_config_expect().abilities)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let contextual_id = |auxiliary_kind: Option<&AuxiliaryAbilityKind<_>>, equip_slot| {
|
||||||
|
matches!(
|
||||||
|
auxiliary_kind,
|
||||||
|
Some(AuxiliaryAbilityKind::Contextualized(_))
|
||||||
|
)
|
||||||
|
.then_some(
|
||||||
|
match inv.and_then(|inv| inv.equipped(equip_slot)).and_then(|i| {
|
||||||
|
if let ItemKind::Tool(tool) = &*i.kind() {
|
||||||
|
Some(tool.kind)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Some(ToolKind::Sword) => {
|
||||||
|
Some("veloren.core.pseudo_abilities.sword.stance_ability")
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.flatten()
|
||||||
|
};
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Ability::ToolPrimary => ability_set(EquipSlot::ActiveMainhand)
|
Ability::ToolPrimary => ability_set(EquipSlot::ActiveMainhand)
|
||||||
.map(|abilities| abilities.primary.id.as_str()),
|
.map(|abilities| abilities.primary.id.as_str()),
|
||||||
@ -278,6 +302,10 @@ impl Ability {
|
|||||||
abilities
|
abilities
|
||||||
.auxiliary(index, context)
|
.auxiliary(index, context)
|
||||||
.map(|(_, ability)| ability.id.as_str())
|
.map(|(_, ability)| ability.id.as_str())
|
||||||
|
.or_else(|| contextual_id(
|
||||||
|
abilities.abilities.get(index),
|
||||||
|
EquipSlot::ActiveMainhand,
|
||||||
|
))
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
Ability::OffWeaponAux(index) => {
|
Ability::OffWeaponAux(index) => {
|
||||||
@ -285,6 +313,10 @@ impl Ability {
|
|||||||
abilities
|
abilities
|
||||||
.auxiliary(index, context)
|
.auxiliary(index, context)
|
||||||
.map(|(_, ability)| ability.id.as_str())
|
.map(|(_, ability)| ability.id.as_str())
|
||||||
|
.or_else(|| contextual_id(
|
||||||
|
abilities.abilities.get(index),
|
||||||
|
EquipSlot::ActiveOffhand,
|
||||||
|
))
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
Ability::Empty => None,
|
Ability::Empty => None,
|
||||||
|
@ -106,7 +106,7 @@ pub struct Data {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub const STANCE_ENTER_TIME: Duration = Duration::from_millis(250);
|
pub const STANCE_ENTER_TIME: Duration = Duration::from_millis(250);
|
||||||
pub const STANCE_LEAVE_TIME: Duration = Duration::from_secs(3);
|
pub const STANCE_LEAVE_TIME: Duration = Duration::from_secs(20);
|
||||||
|
|
||||||
impl CharacterBehavior for Data {
|
impl CharacterBehavior for Data {
|
||||||
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
|
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
|
||||||
@ -382,7 +382,7 @@ impl Data {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn next_strike(update: &mut StateUpdate) {
|
fn next_strike(update: &mut StateUpdate) {
|
||||||
if let CharacterState::ComboMelee2(c) = &mut update.character {
|
let revert_to_wield = if let CharacterState::ComboMelee2(c) = &mut update.character {
|
||||||
if update
|
if update
|
||||||
.energy
|
.energy
|
||||||
.try_change_by(-c.static_data.energy_cost_per_strike)
|
.try_change_by(-c.static_data.energy_cost_per_strike)
|
||||||
@ -392,6 +392,14 @@ fn next_strike(update: &mut StateUpdate) {
|
|||||||
c.start_next_strike = false;
|
c.start_next_strike = false;
|
||||||
c.timer = Duration::default();
|
c.timer = Duration::default();
|
||||||
c.stage_section = Some(StageSection::Buildup);
|
c.stage_section = Some(StageSection::Buildup);
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
if revert_to_wield {
|
||||||
|
update.character = CharacterState::Wielding(wielding::Data { is_sneaking: false });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -902,11 +902,10 @@ impl<'a> Widget for Diary<'a> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let main_weap_abilities = ActiveAbilities::iter_unlocked_abilities(
|
let main_weap_abilities = ActiveAbilities::iter_available_abilities(
|
||||||
Some(self.inventory),
|
Some(self.inventory),
|
||||||
Some(self.skill_set),
|
Some(self.skill_set),
|
||||||
EquipSlot::ActiveMainhand,
|
EquipSlot::ActiveMainhand,
|
||||||
self.context,
|
|
||||||
)
|
)
|
||||||
.map(AuxiliaryAbility::MainWeapon)
|
.map(AuxiliaryAbility::MainWeapon)
|
||||||
.map(|a| {
|
.map(|a| {
|
||||||
@ -915,11 +914,10 @@ impl<'a> Widget for Diary<'a> {
|
|||||||
a,
|
a,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
let off_weap_abilities = ActiveAbilities::iter_unlocked_abilities(
|
let off_weap_abilities = ActiveAbilities::iter_available_abilities(
|
||||||
Some(self.inventory),
|
Some(self.inventory),
|
||||||
Some(self.skill_set),
|
Some(self.skill_set),
|
||||||
EquipSlot::ActiveOffhand,
|
EquipSlot::ActiveOffhand,
|
||||||
self.context,
|
|
||||||
)
|
)
|
||||||
.map(AuxiliaryAbility::OffWeapon)
|
.map(AuxiliaryAbility::OffWeapon)
|
||||||
.map(|a| {
|
.map(|a| {
|
||||||
|
@ -368,6 +368,7 @@ pub fn ability_image(imgs: &img_ids::Imgs, ability_id: &str) -> image::Id {
|
|||||||
"common.abilities.sword.reaching_charge" => imgs.sword_reaching_charge,
|
"common.abilities.sword.reaching_charge" => imgs.sword_reaching_charge,
|
||||||
"common.abilities.sword.reaching_flurry" => imgs.sword_reaching_flurry,
|
"common.abilities.sword.reaching_flurry" => imgs.sword_reaching_flurry,
|
||||||
"common.abilities.sword.reaching_skewer" => imgs.sword_reaching_skewer,
|
"common.abilities.sword.reaching_skewer" => imgs.sword_reaching_skewer,
|
||||||
|
"veloren.core.pseudo_abilities.sword.stance_ability" => imgs.sword,
|
||||||
// Axe
|
// Axe
|
||||||
"common.abilities.axe.doublestrike" => imgs.twohaxe_m1,
|
"common.abilities.axe.doublestrike" => imgs.twohaxe_m1,
|
||||||
"common.abilities.axe.spin" => imgs.axespin,
|
"common.abilities.axe.spin" => imgs.axespin,
|
||||||
|
Loading…
Reference in New Issue
Block a user