This commit is contained in:
Sam 2024-02-19 12:59:42 -05:00
parent cc70685f7a
commit 89048e9530
33 changed files with 292 additions and 168 deletions

View File

@ -197,7 +197,7 @@
secondary: Simple(None, "common.abilities.hammer.wide_wallop"),
abilities: [
Simple(Hammer(ScornfulSwipe), "common.abilities.hammer.scornful_swipe"),
// Simple(Hammer(Tremor), "common.abilities.hammer.tremor"),
Simple(Hammer(Tremor), "common.abilities.hammer.tremor"),
// Simple(Hammer(VigorousBash), "common.abilities.hammer.vigorous_bash"),
// Simple(Hammer(Retaliate), "common.abilities.hammer.retaliate"),
// Simple(Hammer(SpineCracker), "common.abilities.hammer.spine_cracker"),

View File

@ -15,4 +15,6 @@ Shockwave(
damage_kind: Energy,
specifier: Fire,
ori_rate: 1.0,
timing: PostBuildup,
emit_outcome: true,
)

View File

@ -15,4 +15,6 @@ Shockwave(
damage_kind: Crushing,
specifier: Ground,
ori_rate: 1.0,
timing: PostBuildup,
emit_outcome: true,
)

View File

@ -21,4 +21,6 @@ Shockwave(
strength: Value(0.3),
chance: 1.0,
))),
timing: PostBuildup,
emit_outcome: true,
)

View File

@ -15,4 +15,6 @@ Shockwave(
damage_kind: Crushing,
specifier: Water,
ori_rate: 1.0,
timing: PostBuildup,
emit_outcome: true,
)

View File

@ -15,4 +15,6 @@ Shockwave(
damage_kind: Piercing,
specifier: Ground,
ori_rate: 1.0,
timing: PostBuildup,
emit_outcome: true,
)

View File

@ -15,4 +15,6 @@ Shockwave(
damage_kind: Crushing,
specifier: Steam,
ori_rate: 1.0,
timing: PostBuildup,
emit_outcome: true,
)

View File

@ -15,4 +15,6 @@ Shockwave(
damage_kind: Crushing,
specifier: Fire,
ori_rate: 1.0,
timing: PostBuildup,
emit_outcome: true,
)

View File

@ -15,4 +15,6 @@ Shockwave(
damage_kind: Crushing,
specifier: Water,
ori_rate: 1.0,
timing: PostBuildup,
emit_outcome: true,
)

View File

@ -21,4 +21,6 @@ Shockwave(
strength: DamageFraction(0.3),
chance: 1.0,
))),
timing: PostBuildup,
emit_outcome: true,
)

View File

@ -21,4 +21,6 @@ Shockwave(
strength: Value(0.3),
chance: 1.0,
))),
timing: PostBuildup,
emit_outcome: true,
)

View File

@ -21,4 +21,6 @@ Shockwave(
strength: Value(3.0),
chance: 1.0,
))),
timing: PostBuildup,
emit_outcome: true,
)

View File

@ -15,4 +15,6 @@ Shockwave(
damage_kind: Crushing,
specifier: Ground,
ori_rate: 1.0,
timing: PostBuildup,
emit_outcome: true,
)

View File

@ -21,4 +21,6 @@ Shockwave(
strength: DamageFraction(0.6),
chance: 1.0,
))),
timing: PostBuildup,
emit_outcome: true,
)

View File

@ -21,4 +21,6 @@ Shockwave(
strength: DamageFraction(0.06),
chance: 1,
))),
timing: PostBuildup,
emit_outcome: true,
)

View File

@ -21,5 +21,7 @@ Shockwave(
strength: Value(0.3),
chance: 1.0,
))),
timing: PostBuildup,
emit_outcome: true,
)

View File

@ -15,4 +15,6 @@ Shockwave(
damage_kind: Crushing,
specifier: Ground,
ori_rate: 1.0,
timing: PostBuildup,
emit_outcome: true,
)

View File

@ -15,4 +15,6 @@ Shockwave(
damage_kind: Crushing,
specifier: Water,
ori_rate: 0.0,
timing: PostBuildup,
emit_outcome: true,
)

View File

@ -15,4 +15,6 @@ Shockwave(
damage_kind: Crushing,
specifier: Ground,
ori_rate: 1.0,
timing: PostBuildup,
emit_outcome: true,
)

View File

@ -21,5 +21,7 @@ Shockwave(
strength: DamageFraction(0.3),
chance: 1.0,
))),
timing: PostBuildup,
emit_outcome: true,
)

View File

@ -15,4 +15,6 @@ Shockwave(
damage_kind: Crushing,
specifier: Ground,
ori_rate: 1.0,
timing: PostBuildup,
emit_outcome: true,
)

View File

@ -21,4 +21,6 @@ Shockwave(
strength: DamageFraction(0.1),
chance: 0.1,
))),
timing: PostBuildup,
emit_outcome: true,
)

View File

@ -15,4 +15,6 @@ Shockwave(
damage_kind: Energy,
specifier: Fire,
ori_rate: 1.0,
timing: PostBuildup,
emit_outcome: true,
)

View File

@ -0,0 +1,20 @@
Shockwave(
energy_cost: 0,
buildup_duration: 0.4,
swing_duration: 0.3,
recover_duration: 0.3,
damage: 30,
poise_damage: 40,
knockback: (strength: 15.0, direction: Up),
shockwave_angle: 60.0,
shockwave_vertical_angle: 45.0,
shockwave_speed: 10.0,
shockwave_duration: 1.5,
dodgeable: Jump,
move_efficiency: 0.0,
damage_kind: Crushing,
specifier: Ground,
ori_rate: 0.2,
timing: PostAction,
emit_outcome: false,
)

View File

@ -15,4 +15,6 @@ Shockwave(
damage_kind: Energy,
specifier: Fire,
ori_rate: 1.0,
timing: PostBuildup,
emit_outcome: true,
)

BIN
assets/voxygen/element/skills/hammer/tremor.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -386,3 +386,6 @@ common-abilities-hammer-wide_wallop = Wide Wallop
common-abilities-hammer-scornful_swipe = Scornful Swipe
.desc =
Bolster your fortitude and stamina by taunting your enemies before striking at them. If you fall to an enemy they become empowered.
common-abilities-hammer-tremor = Tremor
.desc =
Strike the earth with enough force that the ground beneath your foes trembles.

View File

@ -933,6 +933,8 @@ pub enum CharacterAbility {
specifier: comp::shockwave::FrontendSpecifier,
ori_rate: f32,
damage_effect: Option<CombatEffect>,
timing: shockwave::Timing,
emit_outcome: bool,
#[serde(default)]
meta: AbilityMeta,
},
@ -1532,6 +1534,8 @@ impl CharacterAbility {
specifier: _,
ori_rate: _,
ref mut damage_effect,
timing: _,
emit_outcome: _,
meta: _,
} => {
*buildup_duration /= stats.speed;
@ -2572,6 +2576,8 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState {
specifier,
ori_rate,
damage_effect,
timing,
emit_outcome,
meta: _,
} => CharacterState::Shockwave(shockwave::Data {
static_data: shockwave::StaticData {
@ -2592,6 +2598,8 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState {
damage_kind: *damage_kind,
specifier: *specifier,
ori_rate: *ori_rate,
timing: *timing,
emit_outcome: *emit_outcome,
},
timer: Duration::default(),
stage_section: StageSection::Buildup,

View File

@ -53,8 +53,12 @@ pub struct StaticData {
pub damage_kind: DamageKind,
/// Used to specify the shockwave to the frontend
pub specifier: shockwave::FrontendSpecifier,
/// Controls outcome emission
pub emit_outcome: bool,
/// How fast enemy can rotate
pub ori_rate: f32,
/// Timing of shockwave
pub timing: Timing,
}
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
@ -85,6 +89,111 @@ impl CharacterBehavior for Data {
});
} else {
// Attack
if matches!(self.static_data.timing, Timing::PostBuildup) {
self.attack(data, output_events);
}
// Transitions to swing
update.character = CharacterState::Shockwave(Data {
timer: Duration::default(),
stage_section: StageSection::Action,
..*self
});
}
},
StageSection::Action => {
if self.timer < self.static_data.swing_duration {
// Swings
update.character = CharacterState::Shockwave(Data {
timer: tick_attack_or_default(data, self.timer, None),
..*self
});
// Send local event used for frontend shenanigans
if self.static_data.emit_outcome {
match self.static_data.specifier {
shockwave::FrontendSpecifier::IceSpikes => {
output_events.emit_local(LocalEvent::CreateOutcome(
Outcome::FlashFreeze {
pos: data.pos.0
+ *data.ori.look_dir() * (data.body.max_radius()),
},
));
},
shockwave::FrontendSpecifier::Ground => {
output_events.emit_local(LocalEvent::CreateOutcome(
Outcome::GroundSlam {
pos: data.pos.0
+ *data.ori.look_dir() * (data.body.max_radius()),
},
));
},
shockwave::FrontendSpecifier::Steam => {
output_events.emit_local(LocalEvent::CreateOutcome(
Outcome::Steam {
pos: data.pos.0
+ *data.ori.look_dir() * (data.body.max_radius()),
},
));
},
shockwave::FrontendSpecifier::Fire => {
output_events.emit_local(LocalEvent::CreateOutcome(
Outcome::FireShockwave {
pos: data.pos.0
+ *data.ori.look_dir() * (data.body.max_radius()),
},
));
},
_ => {
output_events.emit_local(LocalEvent::CreateOutcome(
Outcome::Swoosh {
pos: data.pos.0
+ *data.ori.look_dir() * (data.body.max_radius()),
},
));
},
}
}
} else {
// Attack
if matches!(self.static_data.timing, Timing::PostAction) {
self.attack(data, output_events);
}
// Transitions to recover
update.character = CharacterState::Shockwave(Data {
timer: Duration::default(),
stage_section: StageSection::Recover,
..*self
});
}
},
StageSection::Recover => {
if self.timer < self.static_data.recover_duration {
// Recovers
update.character = CharacterState::Shockwave(Data {
timer: tick_attack_or_default(data, self.timer, None),
..*self
});
} else {
// Done
end_ability(data, &mut update);
}
},
_ => {
// If it somehow ends up in an incorrect stage section
end_ability(data, &mut update);
},
}
// At end of state logic so an interrupt isn't overwritten
handle_interrupts(data, &mut update, output_events);
update
}
}
impl Data {
fn attack(&self, data: &JoinData, output_events: &mut OutputEvents) {
let poise = AttackEffect::new(
Some(GroupTarget::OutOfGroup),
CombatEffect::Poise(self.static_data.poise_damage),
@ -129,89 +238,11 @@ impl CharacterBehavior for Data {
pos: *data.pos,
ori: *data.ori,
});
// Transitions to swing
update.character = CharacterState::Shockwave(Data {
timer: Duration::default(),
stage_section: StageSection::Action,
..*self
});
}
},
StageSection::Action => {
if self.timer < self.static_data.swing_duration {
// Swings
update.character = CharacterState::Shockwave(Data {
timer: tick_attack_or_default(data, self.timer, None),
..*self
});
// Send local event used for frontend shenanigans
match self.static_data.specifier {
shockwave::FrontendSpecifier::IceSpikes => {
output_events.emit_local(LocalEvent::CreateOutcome(
Outcome::FlashFreeze {
pos: data.pos.0
+ *data.ori.look_dir() * (data.body.max_radius()),
},
));
},
shockwave::FrontendSpecifier::Ground => {
output_events.emit_local(LocalEvent::CreateOutcome(
Outcome::GroundSlam {
pos: data.pos.0
+ *data.ori.look_dir() * (data.body.max_radius()),
},
));
},
shockwave::FrontendSpecifier::Steam => {
output_events.emit_local(LocalEvent::CreateOutcome(Outcome::Steam {
pos: data.pos.0 + *data.ori.look_dir() * (data.body.max_radius()),
}));
},
shockwave::FrontendSpecifier::Fire => {
output_events.emit_local(LocalEvent::CreateOutcome(
Outcome::FireShockwave {
pos: data.pos.0
+ *data.ori.look_dir() * (data.body.max_radius()),
},
));
},
_ => {
output_events.emit_local(LocalEvent::CreateOutcome(Outcome::Swoosh {
pos: data.pos.0 + *data.ori.look_dir() * (data.body.max_radius()),
}));
},
}
} else {
// Transitions to recover
update.character = CharacterState::Shockwave(Data {
timer: Duration::default(),
stage_section: StageSection::Recover,
..*self
});
}
},
StageSection::Recover => {
if self.timer < self.static_data.recover_duration {
// Recovers
update.character = CharacterState::Shockwave(Data {
timer: tick_attack_or_default(data, self.timer, None),
..*self
});
} else {
// Done
end_ability(data, &mut update);
}
},
_ => {
// If it somehow ends up in an incorrect stage section
end_ability(data, &mut update);
},
}
// At end of state logic so an interrupt isn't overwritten
handle_interrupts(data, &mut update, output_events);
update
}
}
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Timing {
PostBuildup,
PostAction,
}

View File

@ -1,11 +1,8 @@
use super::{
super::{vek::*, Animation},
CharacterSkeleton, SkeletonAttr,
};
use common::{
comp::item::Hands,
states::utils::{AbilityInfo, StageSection},
hammer_start, twist_back, twist_forward, CharacterSkeleton, SkeletonAttr,
};
use common::states::utils::StageSection;
pub struct Input {
pub attack: bool,
@ -13,13 +10,7 @@ pub struct Input {
pub struct ShockwaveAnimation;
impl Animation for ShockwaveAnimation {
type Dependency<'a> = (
Option<AbilityInfo>,
(Option<Hands>, Option<Hands>),
f32,
f32,
Option<StageSection>,
);
type Dependency<'a> = (Option<&'a str>, f32, f32, Option<StageSection>);
type Skeleton = CharacterSkeleton;
#[cfg(feature = "use-dyn-lib")]
@ -28,7 +19,7 @@ impl Animation for ShockwaveAnimation {
#[cfg_attr(feature = "be-dyn-lib", export_name = "character_shockwave")]
fn update_skeleton_inner(
skeleton: &Self::Skeleton,
(_ability_info, hands, _global_time, velocity, stage_section): Self::Dependency<'_>,
(ability_id, _global_time, velocity, stage_section): Self::Dependency<'_>,
anim_time: f32,
rate: &mut f32,
s_a: &SkeletonAttr,
@ -36,6 +27,11 @@ impl Animation for ShockwaveAnimation {
*rate = 1.0;
let mut next = (*skeleton).clone();
if matches!(stage_section, Some(StageSection::Action)) {
next.main_weapon_trail = true;
next.off_weapon_trail = true;
}
let (move1, move2, move3) = match stage_section {
Some(StageSection::Buildup) => (anim_time, 0.0, 0.0),
Some(StageSection::Action) => (1.0, anim_time, 0.0),
@ -43,13 +39,12 @@ impl Animation for ShockwaveAnimation {
_ => (0.0, 0.0, 0.0),
};
if matches!(
stage_section,
Some(StageSection::Action | StageSection::Recover)
) {
next.main_weapon_trail = true;
next.off_weapon_trail = true;
}
match ability_id {
Some(
"common.abilities.staff.fireshockwave"
| "common.abilities.sceptre.healingaura"
| "common.abilities.sceptre.wardingaura",
) => {
next.head.position = Vec3::new(0.0, s_a.head.0, s_a.head.1);
next.hand_l.position = Vec3::new(s_a.sthl.0, s_a.sthl.1, s_a.sthl.2);
@ -113,9 +108,35 @@ impl Animation for ShockwaveAnimation {
next.foot_r.orientation = Quaternion::rotation_y(move1 * -0.3 + move2 * 0.3)
* Quaternion::rotation_z(move1 * 0.4 + move2 * -0.4);
}
},
Some("common.abilities.hammer.tremor") => {
hammer_start(&mut next, s_a);
let (move1, move2, move3) = match stage_section {
Some(StageSection::Buildup) => (anim_time, 0.0, 0.0),
Some(StageSection::Action) => (1.0, anim_time, 0.0),
Some(StageSection::Recover) => (1.0, 1.0, anim_time),
_ => (0.0, 0.0, 0.0),
};
let pullback = 1.0 - move3;
let move1 = move1 * pullback;
let move2 = move2 * pullback;
if let (None, Some(Hands::Two)) = hands {
next.second = next.main;
twist_back(&mut next, move1, 1.4, 0.7, 0.5, 0.9);
next.foot_l.orientation.rotate_z(move1 * 1.4);
next.foot_l.position += Vec3::new(-1.0, -3.0, 0.0) * move1;
next.control.orientation.rotate_x(move1 * 2.6);
next.control.orientation.rotate_y(move1 * 0.8);
twist_forward(&mut next, move2, 2.1, 1.2, 0.9, 1.6);
next.foot_l.orientation.rotate_z(move2 * -1.4);
next.foot_l.position += Vec3::new(2.0, 7.0, 0.0) * move2;
next.control.orientation.rotate_z(move2 * 2.1);
next.control.orientation.rotate_x(move2 * -2.0);
next.control.orientation.rotate_z(move2 * 1.2);
next.control.position += Vec3::new(-16.0, 0.0, 0.0) * move2;
next.chest.orientation.rotate_x(-0.8 * move2);
},
_ => {},
}
next

View File

@ -318,6 +318,7 @@ image_ids! {
hammer_solid_smash: "voxygen.element.skills.hammer.solid_smash",
hammer_wide_wallop: "voxygen.element.skills.hammer.wide_wallop",
hammer_scornful_swipe: "voxygen.element.skills.hammer.scornful_swipe",
hammer_tremor: "voxygen.element.skills.hammer.tremor",
// Skilltree Icons
health_plus_skill: "voxygen.element.skills.skilltree.health_plus",
energy_plus_skill: "voxygen.element.skills.skilltree.energy_plus",

View File

@ -625,6 +625,7 @@ pub fn ability_image(imgs: &img_ids::Imgs, ability_id: &str) -> image::Id {
"common.abilities.hammer.solid_smash" => imgs.hammer_solid_smash,
"common.abilities.hammer.wide_wallop" => imgs.hammer_wide_wallop,
"common.abilities.hammer.scornful_swipe" => imgs.hammer_scornful_swipe,
"common.abilities.hammer.tremor" => imgs.hammer_tremor,
// Bow
"common.abilities.bow.charged" => imgs.bow_m1,
"common.abilities.bow.repeater" => imgs.bow_m2,

View File

@ -1652,13 +1652,7 @@ impl FigureMgr {
};
anim::character::ShockwaveAnimation::update_skeleton(
&target_base,
(
Some(s.static_data.ability_info),
hands,
time,
rel_vel.magnitude(),
Some(s.stage_section),
),
(ability_id, time, rel_vel.magnitude(), Some(s.stage_section)),
stage_progress,
&mut state_animation_rate,
skeleton_attr,
@ -1678,15 +1672,11 @@ impl FigureMgr {
},
_ => 0.0,
};
// ? Aura confirmed just shockwave
anim::character::ShockwaveAnimation::update_skeleton(
&target_base,
(
Some(s.static_data.ability_info),
hands,
time,
rel_vel.magnitude(),
Some(s.stage_section),
),
(ability_id, time, rel_vel.magnitude(), Some(s.stage_section)),
stage_progress,
&mut state_animation_rate,
skeleton_attr,