Fixes to animations and making ability that the animation system thinks is being used more correct

This commit is contained in:
Sam 2023-05-19 11:47:55 -04:00
parent 38fb7b8cd5
commit 1cc99c9c4a
26 changed files with 246 additions and 117 deletions

View File

@ -6,7 +6,7 @@ FinisherMelee(
melee_constructor: (
kind: Slash(
damage: 60,
poise: 100,
poise: 20,
knockback: 0,
energy_regen: 0,
),

View File

@ -6,7 +6,7 @@ FinisherMelee(
melee_constructor: (
kind: Slash(
damage: 75,
poise: 100,
poise: 25,
knockback: 0,
energy_regen: 0,
),

View File

@ -9,8 +9,9 @@ ItemDef(
data: (
strength: 0.4,
duration: Some(20),
secondary_duration: Some(5),
),
cat_ids: [Natural],
cat_ids: [RemoveOnAttack],
)),
])

View File

@ -9,8 +9,9 @@ ItemDef(
data: (
strength: 0.4,
duration: Some(20),
secondary_duration: Some(5),
),
cat_ids: [Natural],
cat_ids: [RemoveOnAttack],
)),
])

View File

@ -10,7 +10,7 @@ ItemDef(
strength: 0.4,
duration: Some(20),
),
cat_ids: [Natural],
cat_ids: [RemoveOnAttack],
)),
])

View File

@ -1172,7 +1172,6 @@ impl CombatBuff {
BuffData::new(
self.strength.to_strength(damage, strength_modifier),
Some(Secs(self.dur_secs as f64)),
None,
),
Vec::new(),
source,

View File

@ -6,7 +6,7 @@ use crate::{
character_state::AttackFilters,
inventory::{
item::{
tool::{AbilityContext, AbilityKind, Stats, ToolKind},
tool::{AbilityContext, AbilityItem, AbilityKind, Stats, ToolKind},
ItemKind,
},
slot::EquipSlot,
@ -149,7 +149,7 @@ impl ActiveAbilities {
char_state: Option<&CharacterState>,
contexts: &[AbilityContext],
// bool is from_offhand
) -> Option<(CharacterAbility, bool)> {
) -> Option<(CharacterAbility, bool, SpecifiedAbility)> {
let ability = self.get_ability(input, inv, Some(skill_set));
let ability_set = |equip_slot| {
@ -167,63 +167,116 @@ impl ActiveAbilities {
ability.adjusted_by_skills(skill_set, tool_kind)
};
let spec_ability = |context_index| SpecifiedAbility {
ability,
context_index,
};
match ability {
Ability::ToolGuard => ability_set(EquipSlot::ActiveMainhand)
.and_then(|abilities| {
abilities
.guard(Some(skill_set), contexts)
.map(|a| a.ability.clone())
.map(|(a, i)| (a.ability.clone(), i))
})
.map(|(ability, i)| {
(
scale_ability(ability, EquipSlot::ActiveMainhand),
true,
spec_ability(i),
)
})
.map(|ability| (scale_ability(ability, EquipSlot::ActiveMainhand), true))
.or_else(|| {
ability_set(EquipSlot::ActiveOffhand)
.and_then(|abilities| {
abilities
.secondary(Some(skill_set), contexts)
.map(|a| a.ability.clone())
.guard(Some(skill_set), contexts)
.map(|(a, i)| (a.ability.clone(), i))
})
.map(|(ability, i)| {
(
scale_ability(ability, EquipSlot::ActiveOffhand),
false,
spec_ability(i),
)
})
.map(|ability| (scale_ability(ability, EquipSlot::ActiveOffhand), false))
}),
Ability::ToolPrimary => ability_set(EquipSlot::ActiveMainhand)
.and_then(|abilities| {
abilities
.primary(Some(skill_set), contexts)
.map(|a| a.ability.clone())
.map(|(a, i)| (a.ability.clone(), i))
})
.map(|ability| (scale_ability(ability, EquipSlot::ActiveMainhand), false)),
.map(|(ability, i)| {
(
scale_ability(ability, EquipSlot::ActiveMainhand),
false,
spec_ability(i),
)
}),
Ability::ToolSecondary => ability_set(EquipSlot::ActiveOffhand)
.and_then(|abilities| {
abilities
.secondary(Some(skill_set), contexts)
.map(|a| a.ability.clone())
.map(|(a, i)| (a.ability.clone(), i))
})
.map(|(ability, i)| {
(
scale_ability(ability, EquipSlot::ActiveOffhand),
true,
spec_ability(i),
)
})
.map(|ability| (scale_ability(ability, EquipSlot::ActiveOffhand), true))
.or_else(|| {
ability_set(EquipSlot::ActiveMainhand)
.and_then(|abilities| {
abilities
.secondary(Some(skill_set), contexts)
.map(|a| a.ability.clone())
.map(|(a, i)| (a.ability.clone(), i))
})
.map(|(ability, i)| {
(
scale_ability(ability, EquipSlot::ActiveMainhand),
false,
spec_ability(i),
)
})
.map(|ability| (scale_ability(ability, EquipSlot::ActiveMainhand), false))
}),
Ability::SpeciesMovement => matches!(body, Some(Body::Humanoid(_)))
.then(|| CharacterAbility::default_roll(char_state))
.map(|ability| (ability.adjusted_by_skills(skill_set, None), false)),
.map(|ability| {
(
ability.adjusted_by_skills(skill_set, None),
false,
spec_ability(None),
)
}),
Ability::MainWeaponAux(index) => ability_set(EquipSlot::ActiveMainhand)
.and_then(|abilities| {
abilities
.auxiliary(index, Some(skill_set), contexts)
.map(|a| a.ability.clone())
.map(|(a, i)| (a.ability.clone(), i))
})
.map(|ability| (scale_ability(ability, EquipSlot::ActiveMainhand), false)),
.map(|(ability, i)| {
(
scale_ability(ability, EquipSlot::ActiveMainhand),
false,
spec_ability(i),
)
}),
Ability::OffWeaponAux(index) => ability_set(EquipSlot::ActiveOffhand)
.and_then(|abilities| {
abilities
.auxiliary(index, Some(skill_set), contexts)
.map(|a| a.ability.clone())
.map(|(a, i)| (a.ability.clone(), i))
})
.map(|ability| (scale_ability(ability, EquipSlot::ActiveOffhand), true)),
.map(|(ability, i)| {
(
scale_ability(ability, EquipSlot::ActiveOffhand),
true,
spec_ability(i),
)
}),
Ability::Empty => None,
}
}
@ -318,7 +371,7 @@ impl Ability {
.and_then(|abilities| {
abilities
.guard(skillset, contexts)
.map(|a| a.id.as_str())
.map(|a| a.0.id.as_str())
.or_else(|| {
abilities
.guard
@ -330,7 +383,7 @@ impl Ability {
ability_set(EquipSlot::ActiveOffhand).and_then(|abilities| {
abilities
.guard(skillset, contexts)
.map(|a| a.id.as_str())
.map(|a| a.0.id.as_str())
.or_else(|| {
abilities
.guard
@ -342,21 +395,21 @@ impl Ability {
Ability::ToolPrimary => ability_set(EquipSlot::ActiveMainhand).and_then(|abilities| {
abilities
.primary(skillset, contexts)
.map(|a| a.id.as_str())
.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)
.map(|a| a.id.as_str())
.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)
.map(|a| a.id.as_str())
.map(|a| a.0.id.as_str())
.or_else(|| contextual_id(Some(&abilities.secondary)))
})
}),
@ -365,7 +418,7 @@ impl Ability {
ability_set(EquipSlot::ActiveMainhand).and_then(|abilities| {
abilities
.auxiliary(index, skillset, contexts)
.map(|a| a.id.as_str())
.map(|a| a.0.id.as_str())
.or_else(|| contextual_id(abilities.abilities.get(index)))
})
},
@ -373,7 +426,7 @@ impl Ability {
ability_set(EquipSlot::ActiveOffhand).and_then(|abilities| {
abilities
.auxiliary(index, skillset, contexts)
.map(|a| a.id.as_str())
.map(|a| a.0.id.as_str())
.or_else(|| contextual_id(abilities.abilities.get(index)))
})
},
@ -396,6 +449,59 @@ impl From<GuardAbility> for Ability {
}
}
// Only use for specifying to the front end what ability is being used, do not
// actually use it for any logic in common or server
#[derive(Copy, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
pub struct SpecifiedAbility {
pub ability: Ability,
pub context_index: Option<usize>,
}
impl SpecifiedAbility {
pub fn ability_id(self, inv: Option<&Inventory>) -> Option<&str> {
let ability_set = |equip_slot| {
inv.and_then(|inv| inv.equipped(equip_slot))
.map(|i| &i.item_config_expect().abilities)
};
fn ability_id(spec_ability: SpecifiedAbility, ability: &AbilityKind<AbilityItem>) -> &str {
match ability {
AbilityKind::Simple(_, a) => a.id.as_str(),
AbilityKind::Contextualized {
pseudo_id,
abilities,
} => spec_ability
.context_index
.and_then(|i| abilities.get(i))
.map_or(pseudo_id.as_str(), |(_, (_, a))| a.id.as_str()),
}
}
match self.ability {
Ability::ToolPrimary => ability_set(EquipSlot::ActiveMainhand)
.map(|abilities| ability_id(self, &abilities.primary)),
Ability::ToolSecondary => ability_set(EquipSlot::ActiveOffhand)
.map(|abilities| ability_id(self, &abilities.secondary))
.or_else(|| {
ability_set(EquipSlot::ActiveMainhand)
.map(|abilities| ability_id(self, &abilities.secondary))
}),
Ability::ToolGuard => ability_set(EquipSlot::ActiveMainhand)
.and_then(|abilities| abilities.guard.as_ref().map(|a| ability_id(self, a)))
.or_else(|| {
ability_set(EquipSlot::ActiveOffhand)
.and_then(|abilities| abilities.guard.as_ref().map(|a| ability_id(self, a)))
}),
Ability::SpeciesMovement => None, // TODO: Make not None
Ability::MainWeaponAux(index) => ability_set(EquipSlot::ActiveMainhand)
.and_then(|abilities| abilities.abilities.get(index).map(|a| ability_id(self, a))),
Ability::OffWeaponAux(index) => ability_set(EquipSlot::ActiveOffhand)
.and_then(|abilities| abilities.abilities.get(index).map(|a| ability_id(self, a))),
Ability::Empty => None,
}
}
}
#[derive(Copy, Clone, Serialize, Deserialize, Debug)]
pub enum PrimaryAbility {
Tool,

View File

@ -158,11 +158,7 @@ impl AuraBuffConstructor {
) -> Aura {
let aura_kind = AuraKind::Buff {
kind: self.kind,
data: BuffData {
strength: self.strength,
duration: self.duration,
delay: None,
},
data: BuffData::new(self.strength, self.duration),
category: self.category,
source: BuffSource::Character { by: *uid },
};

View File

@ -74,6 +74,12 @@ pub enum BuffKind {
/// Provides immunity to burning and increases movement speed in lava.
/// Movement speed increases linearly with strength, 1.0 is a 100% increase.
// SalamanderAspect, TODO: Readd in second dwarven mine MR
/// Inflict burning on your attack
Flame,
/// Inflict frost on your attack
Frigid,
/// Gain Lifesteal on your attack
Lifesteal,
/// Guarantees that the next attack is a critical hit. Does this kind of
/// hackily by adding 100% to the crit, will need to be adjusted if we ever
/// allow double crits instead of treating 100 as a ceiling.
@ -118,12 +124,6 @@ pub enum BuffKind {
PotionSickness,
// Changed into another body.
Polymorphed(Body),
// Inflict burning on your attack
Flame,
// Inflict frost on your attack
Frigid,
// Gain Lifesteal on your attack
Lifesteal,
}
impl BuffKind {
@ -314,8 +314,8 @@ impl BuffKind {
None,
CombatEffect::Buff(CombatBuff {
kind: BuffKind::Burning,
dur_secs: 5.0,
strength: CombatBuffStrength::DamageFraction(0.2),
dur_secs: data.secondary_duration.map_or(5.0, |dur| dur.0 as f32),
strength: CombatBuffStrength::DamageFraction(data.strength),
chance: 1.0,
}),
))],
@ -323,14 +323,14 @@ impl BuffKind {
None,
CombatEffect::Buff(CombatBuff {
kind: BuffKind::Frozen,
dur_secs: 5.0,
strength: CombatBuffStrength::DamageFraction(0.2),
dur_secs: data.secondary_duration.map_or(5.0, |dur| dur.0 as f32),
strength: CombatBuffStrength::DamageFraction(data.strength),
chance: 1.0,
}),
))],
BuffKind::Lifesteal => vec![BuffEffect::BuffOnHit(AttackEffect::new(
None,
CombatEffect::Lifesteal(0.2),
CombatEffect::Lifesteal(data.strength),
))],
/*BuffKind::SalamanderAspect => vec![
BuffEffect::BuffImmunity(BuffKind::Burning),
@ -358,20 +358,34 @@ impl BuffKind {
// Struct used to store data relevant to a buff
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct BuffData {
pub strength: f32,
pub duration: Option<Secs>,
pub delay: Option<Secs>,
// Used for buffs that have rider buffs (e.g. Flame, Frigid)
pub secondary_duration: Option<Secs>,
}
impl BuffData {
pub fn new(strength: f32, duration: Option<Secs>, delay: Option<Secs>) -> Self {
pub fn new(strength: f32, duration: Option<Secs>) -> Self {
Self {
strength,
duration,
delay,
delay: None,
secondary_duration: None,
}
}
pub fn with_delay(mut self, delay: Secs) -> Self {
self.delay = Some(delay);
self
}
pub fn with_secondary_duration(mut self, sec_dur: Secs) -> Self {
self.secondary_duration = Some(sec_dur);
self
}
}
/// De/buff category ID.

View File

@ -342,7 +342,11 @@ impl<T> AbilityKind<T> {
}
}
pub fn ability(&self, skillset: Option<&SkillSet>, contexts: &[AbilityContext]) -> Option<&T> {
pub fn ability(
&self,
skillset: Option<&SkillSet>,
contexts: &[AbilityContext],
) -> Option<(&T, Option<usize>)> {
let unlocked = |s: Option<Skill>, a| {
// If there is a skill requirement and the skillset does not contain the
// required skill, return None
@ -351,18 +355,21 @@ impl<T> AbilityKind<T> {
};
match self {
AbilityKind::Simple(s, a) => unlocked(*s, a),
AbilityKind::Simple(s, a) => unlocked(*s, a).map(|a| (a, None)),
AbilityKind::Contextualized {
pseudo_id: _,
abilities,
} => abilities
.iter()
.filter_map(|(req_contexts, (s, a))| unlocked(*s, a).map(|a| (req_contexts, a)))
.find_map(|(req_contexts, a)| {
.enumerate()
.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))
.then_some(a)
.then_some((a, Some(i)))
}),
}
}
@ -465,13 +472,21 @@ impl<T> AbilitySet<T> {
}
}
pub fn guard(&self, skillset: Option<&SkillSet>, contexts: &[AbilityContext]) -> Option<&T> {
pub fn guard(
&self,
skillset: Option<&SkillSet>,
contexts: &[AbilityContext],
) -> Option<(&T, Option<usize>)> {
self.guard
.as_ref()
.and_then(|g| g.ability(skillset, contexts))
}
pub fn primary(&self, skillset: Option<&SkillSet>, contexts: &[AbilityContext]) -> Option<&T> {
pub fn primary(
&self,
skillset: Option<&SkillSet>,
contexts: &[AbilityContext],
) -> Option<(&T, Option<usize>)> {
self.primary.ability(skillset, contexts)
}
@ -479,7 +494,7 @@ impl<T> AbilitySet<T> {
&self,
skillset: Option<&SkillSet>,
contexts: &[AbilityContext],
) -> Option<&T> {
) -> Option<(&T, Option<usize>)> {
self.secondary.ability(skillset, contexts)
}
@ -488,7 +503,7 @@ impl<T> AbilitySet<T> {
index: usize,
skillset: Option<&SkillSet>,
contexts: &[AbilityContext],
) -> Option<&T> {
) -> Option<(&T, Option<usize>)> {
self.abilities
.get(index)
.and_then(|a| a.ability(skillset, contexts))

View File

@ -82,11 +82,10 @@ impl CharacterBehavior for Data {
// Creates buff
let buff = Buff::new(
self.static_data.buff_kind,
BuffData {
strength: self.static_data.buff_strength * scaling_factor,
duration: self.static_data.buff_duration,
delay: None,
},
BuffData::new(
self.static_data.buff_strength * scaling_factor,
self.static_data.buff_duration,
),
Vec::new(),
BuffSource::Character { by: *data.uid },
*data.time,

View File

@ -2,7 +2,7 @@ use crate::{
astar::Astar,
combat,
comp::{
ability::{Ability, AbilityInitEvent, AbilityInput, AbilityMeta, Capability, Stance},
ability::{AbilityInitEvent, AbilityMeta, Capability, SpecifiedAbility, Stance},
arthropod, biped_large, biped_small, bird_medium,
character_state::OutputEvents,
controller::InventoryManip,
@ -1206,7 +1206,7 @@ fn handle_ability(
) -> bool {
let contexts = AbilityContext::from(data.stance, data.inventory, data.combo);
if let Some(ability_input) = input.into() {
if let Some((ability, from_offhand)) = data
if let Some((ability, from_offhand, spec_ability)) = data
.active_abilities
.and_then(|a| {
a.activate_ability(
@ -1218,11 +1218,17 @@ fn handle_ability(
&contexts,
)
})
.filter(|(ability, _)| ability.requirements_paid(data, update))
.filter(|(ability, _, _)| ability.requirements_paid(data, update))
{
update.character = CharacterState::from((
&ability,
AbilityInfo::from_input(data, from_offhand, input, ability.ability_meta()),
AbilityInfo::new(
data,
from_offhand,
input,
Some(spec_ability),
ability.ability_meta(),
),
data,
));
if let Some(init_event) = ability.ability_meta().init_event {
@ -1508,14 +1514,15 @@ pub struct AbilityInfo {
pub input: InputKind,
pub input_attr: Option<InputAttr>,
pub ability_meta: AbilityMeta,
pub ability: Option<Ability>,
pub ability: Option<SpecifiedAbility>,
}
impl AbilityInfo {
pub fn from_input(
pub fn new(
data: &JoinData<'_>,
from_offhand: bool,
input: InputKind,
ability: Option<SpecifiedAbility>,
ability_meta: AbilityMeta,
) -> Self {
let tool_data = if from_offhand {
@ -1529,9 +1536,6 @@ impl AbilityInfo {
Some(HandInfo::from_main_tool(hands, from_offhand)),
)
});
let ability = Option::<AbilityInput>::from(input)
.zip(data.active_abilities)
.map(|(i, a)| a.get_ability(i, data.inventory, Some(data.skill_set)));
Self {
tool,

View File

@ -142,7 +142,7 @@ impl<'a> System<'a> for Sys {
entity,
buff_change: BuffChange::Add(Buff::new(
BuffKind::Ensnared,
BuffData::new(1.0, Some(Secs(1.0)), None),
BuffData::new(1.0, Some(Secs(1.0))),
Vec::new(),
BuffSource::World,
*read_data.time,
@ -160,7 +160,7 @@ impl<'a> System<'a> for Sys {
entity,
buff_change: BuffChange::Add(Buff::new(
BuffKind::Bleeding,
BuffData::new(1.0, Some(Secs(6.0)), None),
BuffData::new(1.0, Some(Secs(6.0))),
Vec::new(),
BuffSource::World,
*read_data.time,
@ -178,7 +178,7 @@ impl<'a> System<'a> for Sys {
entity,
buff_change: BuffChange::Add(Buff::new(
BuffKind::Bleeding,
BuffData::new(5.0, Some(Secs(3.0)), None),
BuffData::new(5.0, Some(Secs(3.0))),
Vec::new(),
BuffSource::World,
*read_data.time,
@ -196,7 +196,7 @@ impl<'a> System<'a> for Sys {
entity,
buff_change: BuffChange::Add(Buff::new(
BuffKind::Burning,
BuffData::new(10.0, None, None),
BuffData::new(10.0, None),
Vec::new(),
BuffSource::World,
*read_data.time,
@ -214,7 +214,7 @@ impl<'a> System<'a> for Sys {
entity,
buff_change: BuffChange::Add(Buff::new(
BuffKind::Bleeding,
BuffData::new(15.0, Some(Secs(0.1)), None),
BuffData::new(15.0, Some(Secs(0.1))),
Vec::new(),
BuffSource::World,
*read_data.time,
@ -227,7 +227,7 @@ impl<'a> System<'a> for Sys {
entity,
buff_change: BuffChange::Add(Buff::new(
BuffKind::Frozen,
BuffData::new(0.2, Some(Secs(1.0)), None),
BuffData::new(0.2, Some(Secs(1.0))),
Vec::new(),
BuffSource::World,
*read_data.time,
@ -245,7 +245,7 @@ impl<'a> System<'a> for Sys {
entity,
buff_change: BuffChange::Add(Buff::new(
BuffKind::Burning,
BuffData::new(20.0, None, None),
BuffData::new(20.0, None),
Vec::new(),
BuffSource::World,
*read_data.time,
@ -266,7 +266,7 @@ impl<'a> System<'a> for Sys {
entity,
buff_change: BuffChange::Add(Buff::new(
BuffKind::Burning,
BuffData::new(20.0, None, None),
BuffData::new(20.0, None),
vec![BuffCategory::Natural],
BuffSource::World,
*read_data.time,

View File

@ -1370,8 +1370,7 @@ impl<'a> AgentData<'a> {
Some(self.char_state),
&contexts,
)
.unwrap_or_default()
.0
.map_or(Default::default(), |a| a.0)
};
let (flamethrower, shockwave) = (
extract_ability(AbilityInput::Secondary),

View File

@ -220,8 +220,7 @@ impl<'a> AgentData<'a> {
Some(self.char_state),
&context,
)
.unwrap_or_default()
.0,
.map_or(Default::default(), |a| a.0),
)
}
}

View File

@ -1856,7 +1856,7 @@ fn handle_spawn_campfire(
Aura::new(
AuraKind::Buff {
kind: BuffKind::CampfireHeal,
data: BuffData::new(0.02, Some(Secs(1.0)), None),
data: BuffData::new(0.02, Some(Secs(1.0))),
category: BuffCategory::Natural,
source: BuffSource::World,
},
@ -1868,7 +1868,7 @@ fn handle_spawn_campfire(
Aura::new(
AuraKind::Buff {
kind: BuffKind::Burning,
data: BuffData::new(2.0, Some(Secs(10.0)), None),
data: BuffData::new(2.0, Some(Secs(10.0))),
category: BuffCategory::Natural,
source: BuffSource::World,
},
@ -3960,7 +3960,7 @@ fn handle_buff(
if let (Some(buff), strength, duration) = parse_cmd_args!(args, String, f32, f64) {
let strength = strength.unwrap_or(0.01);
let duration = duration.unwrap_or(1.0);
let buffdata = BuffData::new(strength, Some(Secs(duration)), None);
let buffdata = BuffData::new(strength, Some(Secs(duration)));
if buff != "all" {
cast_buff(&buff, buffdata, server, target)
} else {

View File

@ -394,7 +394,7 @@ pub fn handle_create_waypoint(server: &mut Server, pos: Vec3<f32>) {
Aura::new(
AuraKind::Buff {
kind: BuffKind::CampfireHeal,
data: BuffData::new(0.02, Some(Secs(1.0)), None),
data: BuffData::new(0.02, Some(Secs(1.0))),
category: BuffCategory::Natural,
source: BuffSource::World,
},
@ -406,7 +406,7 @@ pub fn handle_create_waypoint(server: &mut Server, pos: Vec3<f32>) {
Aura::new(
AuraKind::Buff {
kind: BuffKind::Burning,
data: BuffData::new(2.0, Some(Secs(10.0)), None),
data: BuffData::new(2.0, Some(Secs(10.0))),
category: BuffCategory::Natural,
source: BuffSource::World,
},

View File

@ -1399,7 +1399,7 @@ pub fn handle_parry_hook(
if let Some(attacker) = attacker && matches!(source, AttackSource::Melee){
// When attacker is parried, add the parried debuff for 2 seconds, which slows
// them
let data = buff::BuffData::new(1.0, Some(Secs(2.0)), None);
let data = buff::BuffData::new(1.0, Some(Secs(2.0)));
let source = if let Some(uid) = ecs.read_storage::<Uid>().get(defender) {
BuffSource::Character { by: *uid }
} else {

View File

@ -511,7 +511,7 @@ impl StateExt for State {
.with(Auras::new(vec![Aura::new(
AuraKind::Buff {
kind: BuffKind::Invulnerability,
data: BuffData::new(1.0, Some(Secs(1.0)), None),
data: BuffData::new(1.0, Some(Secs(1.0))),
category: BuffCategory::Natural,
source: BuffSource::World,
},

View File

@ -264,7 +264,7 @@ impl Animation for ChargeswingAnimation {
next.control.orientation =
Quaternion::rotation_x(s_a.ac.3 + move1 * -1.0 + tension / 30.0)
* Quaternion::rotation_y(s_a.ac.4)
* Quaternion::rotation_z(s_a.ac.5);
* Quaternion::rotation_z(s_a.ac.5 - move1 * PI);
next.control.orientation.rotate_x(move2 * -3.0);
next.control.position += Vec3::new(0.0, move2 * 8.0, move2 * -30.0);

View File

@ -912,7 +912,7 @@ impl Animation for ComboAnimation {
next.control.orientation =
Quaternion::rotation_x(s_a.ac.3 + move1 * -1.5)
* Quaternion::rotation_y(s_a.ac.4)
* Quaternion::rotation_z(s_a.ac.5 + move1 * 0.4);
* Quaternion::rotation_z(s_a.ac.5 + move1 * (0.4 - PI));
next.chest.orientation.rotate_z(move1 * 0.4);
next.head.orientation.rotate_z(move1 * -0.2);
@ -925,7 +925,7 @@ impl Animation for ComboAnimation {
next.shorts.orientation.rotate_z(move2 * 0.2);
next.control.orientation = next.control.orientation
* Quaternion::rotation_z(move2 * -0.5)
* Quaternion::rotation_x(move2 * -2.0);
* Quaternion::rotation_x(move2 * 2.0);
next.control.orientation.rotate_y(move2 * -0.7);
next.control.position += Vec3::new(move2 * 15.0, 0.0, move2 * -4.0);
},
@ -944,7 +944,7 @@ impl Animation for ComboAnimation {
next.shorts.orientation.rotate_z(move2 * -0.2);
next.control.orientation = next.control.orientation
* Quaternion::rotation_z(move2 * 0.5)
* Quaternion::rotation_x(move2 * -2.0);
* Quaternion::rotation_x(move2 * 2.0);
next.control.orientation.rotate_y(move2 * 0.7);
next.control.position += Vec3::new(move2 * -15.0, 0.0, move2 * -4.0);
},
@ -985,7 +985,7 @@ impl Animation for ComboAnimation {
Vec3::new(s_a.ac.0 + move1 * -1.0, s_a.ac.1 + move1 * -4.0, s_a.ac.2);
next.control.orientation = Quaternion::rotation_x(s_a.ac.3 + move1 * -0.4)
* Quaternion::rotation_y(s_a.ac.4 + move1 * -0.5)
* Quaternion::rotation_z(s_a.ac.5 + move1 * 1.5);
* Quaternion::rotation_z(s_a.ac.5 + move1 * (1.5 - PI));
next.control.orientation.rotate_z(move2 * -3.5);
next.control.position += Vec3::new(move2 * 12.0, move2 * 4.0, 0.0);
@ -1012,7 +1012,7 @@ impl Animation for ComboAnimation {
Vec3::new(s_a.ac.0 + move1 * -1.0, s_a.ac.1 + move1 * -4.0, s_a.ac.2);
next.control.orientation = Quaternion::rotation_x(s_a.ac.3 + move1 * 0.6)
* Quaternion::rotation_y(s_a.ac.4 + move1 * -0.5)
* Quaternion::rotation_z(s_a.ac.5 + move1 * 3.0);
* Quaternion::rotation_z(s_a.ac.5 + move1 * (3.0 - PI));
next.chest.orientation = Quaternion::rotation_z(move1 * 0.6);
next.head.orientation = Quaternion::rotation_z(move1 * -0.2);

View File

@ -161,7 +161,7 @@ impl Animation for FinisherMeleeAnimation {
next.control.position = Vec3::new(s_a.ac.0, s_a.ac.1, s_a.ac.2);
next.control.orientation = Quaternion::rotation_x(s_a.ac.3)
* Quaternion::rotation_y(s_a.ac.4)
* Quaternion::rotation_z(s_a.ac.5);
* Quaternion::rotation_z(s_a.ac.5 - move1 * PI);
next.control.orientation.rotate_x(move1 * 0.9);
next.chest.orientation.rotate_z(move1 * 1.2);
@ -199,7 +199,7 @@ impl Animation for FinisherMeleeAnimation {
next.control.position = Vec3::new(s_a.ac.0, s_a.ac.1, s_a.ac.2);
next.control.orientation = Quaternion::rotation_x(s_a.ac.3)
* Quaternion::rotation_y(s_a.ac.4)
* Quaternion::rotation_z(s_a.ac.5);
* Quaternion::rotation_z(s_a.ac.5 - move1 * PI);
next.control.orientation.rotate_x(move1 * 0.9);
next.chest.orientation.rotate_z(move1 * 1.2);

View File

@ -3,6 +3,7 @@ use super::{
CharacterSkeleton, SkeletonAttr,
};
use common::states::utils::{AbilityInfo, StageSection};
use core::f32::consts::PI;
pub struct SelfBuffAnimation;
impl Animation for SelfBuffAnimation {
@ -188,7 +189,7 @@ impl Animation for SelfBuffAnimation {
* Quaternion::rotation_z(s_a.ac.5);
next.control.orientation.rotate_z(move1 * -2.0);
next.control.orientation.rotate_x(move1 * -3.5);
next.control.orientation.rotate_x(move1 * 3.5);
next.control.position += Vec3::new(move1 * 14.0, move1 * -6.0, move1 * 15.0);
next.head.orientation.rotate_x(move2 * 0.6);
@ -248,7 +249,7 @@ impl Animation for SelfBuffAnimation {
next.control.position = Vec3::new(s_a.ac.0, s_a.ac.1, s_a.ac.2);
next.control.orientation = Quaternion::rotation_x(s_a.ac.3)
* Quaternion::rotation_y(s_a.ac.4)
* Quaternion::rotation_z(s_a.ac.5);
* Quaternion::rotation_z(s_a.ac.5 - move1 * PI);
next.control.orientation.rotate_z(move1 * -1.8);
next.control.orientation.rotate_y(move1 * 1.5);

View File

@ -1169,7 +1169,7 @@ impl<'a> Skillbar<'a> {
self.contexts,
)
})
.map_or(false, |(a, _)| {
.map_or(false, |(a, _, _)| {
self.energy.current() >= a.energy_cost()
&& self.combo.map_or(false, |c| c.counter() >= a.combo_cost())
&& a.ability_meta().requirements.requirements_met(self.stance)

View File

@ -186,7 +186,7 @@ impl<'a> SlotKey<HotbarSource<'a>, HotbarImageSource<'a>> for HotbarSlot {
contexts,
)
})
.map(|(ability, _)| {
.map(|(ability, _, _)| {
(
image,
if energy.current() >= ability.energy_cost()

View File

@ -37,11 +37,11 @@ use anim::{
use common::{
comp::{
inventory::slot::EquipSlot,
item::{tool::AbilityContext, Hands, ItemKind, ToolKind},
item::{Hands, ItemKind, ToolKind},
ship::{self, figuredata::VOXEL_COLLIDER_MANIFEST},
Body, CharacterActivity, CharacterState, Collider, Combo, Controller, Health, Inventory,
Item, ItemKey, Last, LightAnimation, LightEmitter, Object, Ori, PhysicsState, PoiseState,
Pos, Scale, SkillSet, Stance, Vel,
Body, CharacterActivity, CharacterState, Collider, Controller, Health, Inventory, Item,
ItemKey, Last, LightAnimation, LightEmitter, Object, Ori, PhysicsState, PoiseState, Pos,
Scale, Vel,
},
link::Is,
mounting::{Rider, VolumeRider},
@ -853,7 +853,7 @@ impl FigureMgr {
inventory,
item,
light_emitter,
(is_rider, is_volume_rider, collider, stance, skillset, combo),
(is_rider, is_volume_rider, collider),
),
) in (
&ecs.entities(),
@ -875,9 +875,6 @@ impl FigureMgr {
ecs.read_storage::<Is<Rider>>().maybe(),
ecs.read_storage::<Is<VolumeRider>>().maybe(),
ecs.read_storage::<Collider>().maybe(),
ecs.read_storage::<Stance>().maybe(),
ecs.read_storage::<SkillSet>().maybe(),
ecs.read_storage::<Combo>().maybe(),
),
)
.join()
@ -1038,12 +1035,10 @@ impl FigureMgr {
let second_tool_spec = second_tool_spec.as_deref();
let hands = (active_tool_hand, second_tool_hand);
let contexts = AbilityContext::from(stance, inventory, combo);
let ability_id = character.and_then(|c| {
c.ability_info()
.and_then(|a| a.ability)
.and_then(|a| a.ability_id(inventory, skillset, &contexts))
.and_then(|a| a.ability_id(inventory))
});
let move_dir = {