mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Stances change secondary abilities now. Contextual abilities try to fallback to no context if skill not owned for contextual ability.
This commit is contained in:
parent
b376228d45
commit
7ec9a7677f
@ -13,7 +13,17 @@
|
||||
Stance(Sword(Mobility)): (Some(Sword(MobilityStance)), "common.abilities.sword.mobility_combo"),
|
||||
Stance(Sword(Reaching)): (Some(Sword(ReachingStance)), "common.abilities.sword.reaching_combo"),
|
||||
}),
|
||||
secondary: Simple(None, "common.abilities.sword.balanced_thrust"),
|
||||
secondary: Contextualized({
|
||||
None: (None, "common.abilities.sword.balanced_thrust"),
|
||||
Stance(Sword(Offensive)): (Some(Sword(OffensiveAdvance)), "common.abilities.sword.offensive_advance"),
|
||||
Stance(Sword(Defensive)): (Some(Sword(DefensiveRetreat)), "common.abilities.sword.defensive_retreat"),
|
||||
Stance(Sword(Mobility)): (Some(Sword(MobilityFeint)), "common.abilities.sword.mobility_feint"),
|
||||
Stance(Sword(Heavy)): (Some(Sword(HeavyPommelStrike)), "common.abilities.sword.heavy_pommelstrike"),
|
||||
Stance(Sword(Parrying)): (Some(Sword(ParryingParry)), "common.abilities.sword.parrying_parry"),
|
||||
Stance(Sword(Reaching)): (Some(Sword(ReachingSkewer)), "common.abilities.sword.reaching_skewer"),
|
||||
Stance(Sword(Crippling)): (Some(Sword(CripplingGouge)), "common.abilities.sword.crippling_gouge"),
|
||||
Stance(Sword(Cleaving)): (Some(Sword(CleavingSpin)), "common.abilities.sword.cleaving_spin"),
|
||||
}),
|
||||
abilities: [
|
||||
Simple(Some(Sword(OffensiveStance)), "common.abilities.sword.offensive_stance"),
|
||||
Simple(Some(Sword(CripplingStance)), "common.abilities.sword.crippling_stance"),
|
||||
@ -35,24 +45,13 @@
|
||||
}),
|
||||
// Movementy ones
|
||||
Contextualized({
|
||||
Stance(Sword(Offensive)): (Some(Sword(OffensiveAdvance)), "common.abilities.sword.offensive_advance"),
|
||||
Stance(Sword(Crippling)): (Some(Sword(CripplingStrike)), "common.abilities.sword.crippling_strike"),
|
||||
Stance(Sword(Cleaving)): (Some(Sword(CleavingDive)), "common.abilities.sword.cleaving_dive"),
|
||||
Stance(Sword(Defensive)): (Some(Sword(DefensiveRetreat)), "common.abilities.sword.defensive_retreat"),
|
||||
Stance(Sword(Parrying)): (Some(Sword(ParryingRiposte)), "common.abilities.sword.parrying_riposte"),
|
||||
Stance(Sword(Heavy)): (Some(Sword(HeavyFortitude)), "common.abilities.sword.heavy_fortitude"),
|
||||
Stance(Sword(Mobility)): (Some(Sword(MobilityFeint)), "common.abilities.sword.mobility_feint"),
|
||||
Stance(Sword(Reaching)): (Some(Sword(ReachingCharge)), "common.abilities.sword.reaching_charge"),
|
||||
}),
|
||||
// Utilityy ones
|
||||
Contextualized({
|
||||
Stance(Sword(Crippling)): (Some(Sword(CripplingGouge)), "common.abilities.sword.crippling_gouge"),
|
||||
Stance(Sword(Cleaving)): (Some(Sword(CleavingSpin)), "common.abilities.sword.cleaving_spin"),
|
||||
Stance(Sword(Defensive)): (Some(Sword(DefensiveBulwark)), "common.abilities.sword.defensive_bulwark"),
|
||||
Stance(Sword(Parrying)): (Some(Sword(ParryingParry)), "common.abilities.sword.parrying_parry"),
|
||||
Stance(Sword(Heavy)): (Some(Sword(HeavyPommelStrike)), "common.abilities.sword.heavy_pommelstrike"),
|
||||
Stance(Sword(Mobility)): (Some(Sword(MobilityAgility)), "common.abilities.sword.mobility_agility"),
|
||||
Stance(Sword(Reaching)): (Some(Sword(ReachingSkewer)), "common.abilities.sword.reaching_skewer"),
|
||||
}),
|
||||
],
|
||||
),
|
||||
|
@ -6,7 +6,7 @@ use crate::{
|
||||
character_state::AttackImmunities,
|
||||
inventory::{
|
||||
item::{
|
||||
tool::{AbilityContext, AbilityItem, AbilityKind, Stats, ToolKind},
|
||||
tool::{AbilityContext, AbilityKind, Stats, ToolKind},
|
||||
ItemKind,
|
||||
},
|
||||
slot::EquipSlot,
|
||||
@ -163,41 +163,46 @@ impl ActiveAbilities {
|
||||
ability.adjusted_by_skills(skill_set, tool_kind)
|
||||
};
|
||||
|
||||
let unwrap_ability = |(skill_req, ability): (Option<Skill>, &AbilityItem)| {
|
||||
(skill_req, ability.ability.clone())
|
||||
};
|
||||
|
||||
let unlocked = |(s, a): (Option<Skill>, CharacterAbility)| {
|
||||
// If there is a skill requirement and the skillset does not contain the
|
||||
// required skill, return None
|
||||
s.map_or(true, |s| skill_set.has_skill(s)).then_some(a)
|
||||
};
|
||||
|
||||
match ability {
|
||||
Ability::ToolPrimary => ability_set(EquipSlot::ActiveMainhand)
|
||||
.and_then(|abilities| abilities.primary(context).map(unwrap_ability))
|
||||
.and_then(unlocked)
|
||||
.and_then(|abilities| {
|
||||
abilities
|
||||
.primary(Some(skill_set), context)
|
||||
.map(|a| a.ability.clone())
|
||||
})
|
||||
.map(|ability| (scale_ability(ability, EquipSlot::ActiveMainhand), false)),
|
||||
Ability::ToolSecondary => ability_set(EquipSlot::ActiveOffhand)
|
||||
.and_then(|abilities| abilities.secondary(context).map(unwrap_ability))
|
||||
.and_then(unlocked)
|
||||
.and_then(|abilities| {
|
||||
abilities
|
||||
.secondary(Some(skill_set), context)
|
||||
.map(|a| a.ability.clone())
|
||||
})
|
||||
.map(|ability| (scale_ability(ability, EquipSlot::ActiveOffhand), true))
|
||||
.or_else(|| {
|
||||
ability_set(EquipSlot::ActiveMainhand)
|
||||
.and_then(|abilities| abilities.secondary(context).map(unwrap_ability))
|
||||
.and_then(unlocked)
|
||||
.and_then(|abilities| {
|
||||
abilities
|
||||
.secondary(Some(skill_set), context)
|
||||
.map(|a| a.ability.clone())
|
||||
})
|
||||
.map(|ability| (scale_ability(ability, EquipSlot::ActiveMainhand), false))
|
||||
}),
|
||||
Ability::SpeciesMovement => matches!(body, Some(Body::Humanoid(_)))
|
||||
.then(CharacterAbility::default_roll)
|
||||
.map(|ability| (ability.adjusted_by_skills(skill_set, None), false)),
|
||||
Ability::MainWeaponAux(index) => ability_set(EquipSlot::ActiveMainhand)
|
||||
.and_then(|abilities| abilities.auxiliary(index, context).map(unwrap_ability))
|
||||
.and_then(unlocked)
|
||||
.and_then(|abilities| {
|
||||
abilities
|
||||
.auxiliary(index, Some(skill_set), context)
|
||||
.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, context).map(unwrap_ability))
|
||||
.and_then(unlocked)
|
||||
.and_then(|abilities| {
|
||||
abilities
|
||||
.auxiliary(index, Some(skill_set), context)
|
||||
.map(|a| a.ability.clone())
|
||||
})
|
||||
.map(|ability| (scale_ability(ability, EquipSlot::ActiveOffhand), true)),
|
||||
Ability::Empty => None,
|
||||
}
|
||||
@ -260,7 +265,12 @@ pub enum Ability {
|
||||
}
|
||||
|
||||
impl Ability {
|
||||
pub fn ability_id(self, inv: Option<&Inventory>, context: AbilityContext) -> Option<&str> {
|
||||
pub fn ability_id<'a>(
|
||||
self,
|
||||
inv: Option<&'a Inventory>,
|
||||
skillset: Option<&'a SkillSet>,
|
||||
context: AbilityContext,
|
||||
) -> Option<&'a str> {
|
||||
let ability_set = |equip_slot| {
|
||||
inv.and_then(|inv| inv.equipped(equip_slot))
|
||||
.map(|i| &i.item_config_expect().abilities)
|
||||
@ -287,20 +297,26 @@ impl Ability {
|
||||
|
||||
match self {
|
||||
Ability::ToolPrimary => ability_set(EquipSlot::ActiveMainhand)
|
||||
.and_then(|abilities| abilities.primary(context).map(|(_, a)| a.id.as_str())),
|
||||
.and_then(|abilities| abilities.primary(skillset, context).map(|a| a.id.as_str())),
|
||||
Ability::ToolSecondary => ability_set(EquipSlot::ActiveOffhand)
|
||||
.and_then(|abilities| abilities.secondary(context).map(|(_, a)| a.id.as_str()))
|
||||
.and_then(|abilities| {
|
||||
abilities
|
||||
.secondary(skillset, context)
|
||||
.map(|a| a.id.as_str())
|
||||
})
|
||||
.or_else(|| {
|
||||
ability_set(EquipSlot::ActiveMainhand).and_then(|abilities| {
|
||||
abilities.secondary(context).map(|(_, a)| a.id.as_str())
|
||||
abilities
|
||||
.secondary(skillset, context)
|
||||
.map(|a| a.id.as_str())
|
||||
})
|
||||
}),
|
||||
Ability::SpeciesMovement => None, // TODO: Make not None
|
||||
Ability::MainWeaponAux(index) => {
|
||||
ability_set(EquipSlot::ActiveMainhand).and_then(|abilities| {
|
||||
abilities
|
||||
.auxiliary(index, context)
|
||||
.map(|(_, ability)| ability.id.as_str())
|
||||
.auxiliary(index, skillset, context)
|
||||
.map(|a| a.id.as_str())
|
||||
.or_else(|| {
|
||||
contextual_id(abilities.abilities.get(index), EquipSlot::ActiveMainhand)
|
||||
})
|
||||
@ -309,8 +325,8 @@ impl Ability {
|
||||
Ability::OffWeaponAux(index) => {
|
||||
ability_set(EquipSlot::ActiveOffhand).and_then(|abilities| {
|
||||
abilities
|
||||
.auxiliary(index, context)
|
||||
.map(|(_, ability)| ability.id.as_str())
|
||||
.auxiliary(index, skillset, context)
|
||||
.map(|a| a.id.as_str())
|
||||
.or_else(|| {
|
||||
contextual_id(abilities.abilities.get(index), EquipSlot::ActiveOffhand)
|
||||
})
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
use crate::{
|
||||
assets::{self, Asset, AssetExt, AssetHandle},
|
||||
comp::{ability::Stance, skills::Skill, CharacterAbility},
|
||||
comp::{ability::Stance, skills::Skill, CharacterAbility, SkillSet},
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -317,10 +317,24 @@ impl<T> AbilityKind<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ability(&self, context: AbilityContext) -> Option<(Option<Skill>, &T)> {
|
||||
pub fn ability(&self, skillset: Option<&SkillSet>, context: AbilityContext) -> Option<&T> {
|
||||
let unlocked = |s: Option<Skill>, a| {
|
||||
// If there is a skill requirement and the skillset does not contain the
|
||||
// required skill, return None
|
||||
s.map_or(true, |s| skillset.map_or(false, |ss| ss.has_skill(s)))
|
||||
.then_some(a)
|
||||
};
|
||||
|
||||
match self {
|
||||
AbilityKind::Simple(s, a) => Some((*s, a)),
|
||||
AbilityKind::Contextualized(abilities) => abilities.get(&context).map(|(s, a)| (*s, a)),
|
||||
AbilityKind::Simple(s, a) => unlocked(*s, a),
|
||||
AbilityKind::Contextualized(abilities) => abilities
|
||||
.get(&context)
|
||||
.and_then(|(s, a)| unlocked(*s, a))
|
||||
.or_else(|| {
|
||||
abilities
|
||||
.get(&AbilityContext::None)
|
||||
.and_then(|(s, a)| unlocked(*s, a))
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -368,16 +382,23 @@ impl<T> AbilitySet<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn primary(&self, context: AbilityContext) -> Option<(Option<Skill>, &T)> {
|
||||
self.primary.ability(context)
|
||||
pub fn primary(&self, skillset: Option<&SkillSet>, context: AbilityContext) -> Option<&T> {
|
||||
self.primary.ability(skillset, context)
|
||||
}
|
||||
|
||||
pub fn secondary(&self, context: AbilityContext) -> Option<(Option<Skill>, &T)> {
|
||||
self.secondary.ability(context)
|
||||
pub fn secondary(&self, skillset: Option<&SkillSet>, context: AbilityContext) -> Option<&T> {
|
||||
self.secondary.ability(skillset, context)
|
||||
}
|
||||
|
||||
pub fn auxiliary(&self, index: usize, context: AbilityContext) -> Option<(Option<Skill>, &T)> {
|
||||
self.abilities.get(index).and_then(|a| a.ability(context))
|
||||
pub fn auxiliary(
|
||||
&self,
|
||||
index: usize,
|
||||
skillset: Option<&SkillSet>,
|
||||
context: AbilityContext,
|
||||
) -> Option<&T> {
|
||||
self.abilities
|
||||
.get(index)
|
||||
.and_then(|a| a.ability(skillset, context))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -869,7 +869,7 @@ impl<'a> Widget for Diary<'a> {
|
||||
Some(self.inventory),
|
||||
Some(self.skill_set),
|
||||
)
|
||||
.ability_id(Some(self.inventory), self.context);
|
||||
.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 {
|
||||
@ -951,7 +951,11 @@ impl<'a> Widget for Diary<'a> {
|
||||
.map(AuxiliaryAbility::MainWeapon)
|
||||
.map(|a| {
|
||||
(
|
||||
Ability::from(a).ability_id(Some(self.inventory), self.context),
|
||||
Ability::from(a).ability_id(
|
||||
Some(self.inventory),
|
||||
Some(self.skill_set),
|
||||
self.context,
|
||||
),
|
||||
a,
|
||||
)
|
||||
});
|
||||
@ -963,7 +967,11 @@ impl<'a> Widget for Diary<'a> {
|
||||
.map(AuxiliaryAbility::OffWeapon)
|
||||
.map(|a| {
|
||||
(
|
||||
Ability::from(a).ability_id(Some(self.inventory), self.context),
|
||||
Ability::from(a).ability_id(
|
||||
Some(self.inventory),
|
||||
Some(self.skill_set),
|
||||
self.context,
|
||||
),
|
||||
a,
|
||||
)
|
||||
});
|
||||
|
@ -1011,7 +1011,13 @@ impl<'a> Skillbar<'a> {
|
||||
.and_then(|a| {
|
||||
a.auxiliary_set(Some(inventory), Some(skill_set))
|
||||
.get(i)
|
||||
.and_then(|a| Ability::from(*a).ability_id(Some(inventory), context))
|
||||
.and_then(|a| {
|
||||
Ability::from(*a).ability_id(
|
||||
Some(inventory),
|
||||
Some(skill_set),
|
||||
context,
|
||||
)
|
||||
})
|
||||
})
|
||||
.map(|id| util::ability_description(id, self.localized_strings)),
|
||||
})
|
||||
@ -1080,9 +1086,13 @@ impl<'a> Skillbar<'a> {
|
||||
.right_from(state.ids.slot5, slot_offset)
|
||||
.set(state.ids.m1_slot_bg, ui);
|
||||
|
||||
let primary_ability_id = self
|
||||
.active_abilities
|
||||
.and_then(|a| Ability::from(a.primary).ability_id(Some(self.inventory), self.context));
|
||||
let primary_ability_id = self.active_abilities.and_then(|a| {
|
||||
Ability::from(a.primary).ability_id(
|
||||
Some(self.inventory),
|
||||
Some(self.skillset),
|
||||
self.context,
|
||||
)
|
||||
});
|
||||
|
||||
let (primary_ability_title, primary_ability_desc) =
|
||||
util::ability_description(primary_ability_id.unwrap_or(""), self.localized_strings);
|
||||
@ -1107,7 +1117,11 @@ impl<'a> Skillbar<'a> {
|
||||
.set(state.ids.m2_slot_bg, ui);
|
||||
|
||||
let secondary_ability_id = self.active_abilities.and_then(|a| {
|
||||
Ability::from(a.secondary).ability_id(Some(self.inventory), self.context)
|
||||
Ability::from(a.secondary).ability_id(
|
||||
Some(self.inventory),
|
||||
Some(self.skillset),
|
||||
self.context,
|
||||
)
|
||||
});
|
||||
|
||||
let (secondary_ability_title, secondary_ability_desc) =
|
||||
|
@ -153,7 +153,9 @@ impl<'a> SlotKey<HotbarSource<'a>, HotbarImageSource<'a>> for HotbarSlot {
|
||||
let ability_id = active_abilities.and_then(|a| {
|
||||
a.auxiliary_set(Some(inventory), Some(skillset))
|
||||
.get(i)
|
||||
.and_then(|a| Ability::from(*a).ability_id(Some(inventory), *context))
|
||||
.and_then(|a| {
|
||||
Ability::from(*a).ability_id(Some(inventory), Some(skillset), *context)
|
||||
})
|
||||
});
|
||||
|
||||
ability_id
|
||||
@ -236,8 +238,10 @@ impl<'a> SlotKey<AbilitiesSource<'a>, img_ids::Imgs> for AbilitySlot {
|
||||
Some(inventory),
|
||||
Some(skillset),
|
||||
)
|
||||
.ability_id(Some(inventory), *context),
|
||||
Self::Ability(ability) => Ability::from(*ability).ability_id(Some(inventory), *context),
|
||||
.ability_id(Some(inventory), Some(skillset), *context),
|
||||
Self::Ability(ability) => {
|
||||
Ability::from(*ability).ability_id(Some(inventory), Some(skillset), *context)
|
||||
},
|
||||
};
|
||||
|
||||
ability_id.map(|id| (String::from(id), None))
|
||||
|
@ -34,7 +34,8 @@ use common::{
|
||||
inventory::slot::EquipSlot,
|
||||
item::{tool::AbilityContext, Hands, ItemKind, ToolKind},
|
||||
Body, CharacterState, Collider, Controller, Health, Inventory, Item, ItemKey, Last,
|
||||
LightAnimation, LightEmitter, Ori, PhysicsState, PoiseState, Pos, Scale, Stance, Vel,
|
||||
LightAnimation, LightEmitter, Ori, PhysicsState, PoiseState, Pos, Scale, SkillSet, Stance,
|
||||
Vel,
|
||||
},
|
||||
link::Is,
|
||||
mounting::Rider,
|
||||
@ -747,7 +748,7 @@ impl FigureMgr {
|
||||
item,
|
||||
light_emitter,
|
||||
is_rider,
|
||||
(collider, stance),
|
||||
(collider, stance, skillset),
|
||||
),
|
||||
) in (
|
||||
&ecs.entities(),
|
||||
@ -768,6 +769,7 @@ impl FigureMgr {
|
||||
(
|
||||
ecs.read_storage::<Collider>().maybe(),
|
||||
ecs.read_storage::<Stance>().maybe(),
|
||||
ecs.read_storage::<SkillSet>().maybe(),
|
||||
),
|
||||
)
|
||||
.join()
|
||||
@ -925,7 +927,7 @@ impl FigureMgr {
|
||||
let ability_id = character.and_then(|c| {
|
||||
c.ability_info()
|
||||
.and_then(|a| a.ability)
|
||||
.and_then(|a| a.ability_id(inventory, context))
|
||||
.and_then(|a| a.ability_id(inventory, skillset, context))
|
||||
});
|
||||
|
||||
let move_dir = {
|
||||
|
Loading…
Reference in New Issue
Block a user