Heavy stance required abilities

This commit is contained in:
Sam 2022-12-15 21:51:03 -05:00
parent e73236819a
commit a3d655970e
28 changed files with 277 additions and 219 deletions

View File

@ -1,39 +1,9 @@
ComboMelee2(
strikes: [
(
melee_constructor: (
kind: Slash(
damage: 5,
poise: 0,
knockback: 0,
energy_regen: 5,
),
range: 3.0,
angle: 45.0,
),
buildup_duration: 0.15,
swing_duration: 0.05,
hit_timing: 0.5,
recover_duration: 0.1,
ori_modifier: 0.6,
),
(
melee_constructor: (
kind: Slash(
damage: 10,
poise: 0,
knockback: 0,
energy_regen: 7.5,
),
range: 3.0,
angle: 45.0,
),
buildup_duration: 0.1,
swing_duration: 0.1,
hit_timing: 0.5,
recover_duration: 0.2,
ori_modifier: 0.6,
),
],
energy_cost_per_strike: 0,
)
SelfBuff(
buildup_duration: 0.2,
cast_duration: 0.2,
recover_duration: 0.6,
buff_kind: Fortitude,
buff_strength: 1.0,
buff_duration: Some(30.0),
energy_cost: 25,
)

View File

@ -1,39 +1,26 @@
ComboMelee2(
strikes: [
(
melee_constructor: (
kind: Slash(
damage: 5,
poise: 0,
knockback: 0,
energy_regen: 5,
),
range: 3.0,
angle: 45.0,
),
buildup_duration: 0.15,
swing_duration: 0.05,
hit_timing: 0.5,
recover_duration: 0.1,
ori_modifier: 0.6,
DiveMelee(
energy_cost: 25,
vertical_speed: 5,
buildup_duration: Some(0.2),
movement_duration: 5,
swing_duration: 0.1,
recover_duration: 0.3,
melee_constructor: (
kind: Slash(
damage: 30,
poise: 40,
knockback: 0,
energy_regen: 0,
),
(
melee_constructor: (
kind: Slash(
damage: 10,
poise: 0,
knockback: 0,
energy_regen: 7.5,
),
range: 3.0,
angle: 45.0,
),
buildup_duration: 0.1,
swing_duration: 0.1,
hit_timing: 0.5,
recover_duration: 0.2,
ori_modifier: 0.6,
),
],
energy_cost_per_strike: 0,
)
scaled: Some(Slash(
damage: 5,
poise: 10,
knockback: 0,
energy_regen: 0,
)),
range: 2.0,
angle: 45.0,
multi_target: Some(Normal),
),
max_scaling: 6,
)

View File

@ -63,7 +63,7 @@ buff-title-ensnared = Ensnared
buff-desc-ensnared = Vines grasp at your legs, impeding your movement.
## Fortitude
buff-title-fortitude = Fortitude
buff-desc-fortitude = You can withstand staggers.
buff-desc-fortitude = You can withstand staggers, and as you take more damage you stagger others more easily.
## Parried
buff-title-parried = Parried
buff-desc-parried = You were parried and now are slow to recover.

View File

@ -56,6 +56,7 @@ pub struct AttackerInfo<'a> {
pub energy: Option<&'a Energy>,
pub combo: Option<&'a Combo>,
pub inventory: Option<&'a Inventory>,
pub stats: Option<&'a Stats>,
}
#[cfg(not(target_arch = "wasm32"))]
@ -294,7 +295,11 @@ impl Attack {
// that health change amount is greater than 0 would fail.
let reduced_damage =
applied_damage * damage_reduction / (1.0 - damage_reduction);
let poise = reduced_damage * CRUSHING_POISE_FRACTION;
let poise = reduced_damage
* CRUSHING_POISE_FRACTION
* attacker
.and_then(|a| a.stats)
.map_or(1.0, |s| s.poise_damage_modifier);
let change = -Poise::apply_poise_reduction(
poise,
target.inventory,
@ -369,6 +374,7 @@ impl Attack {
time,
attacker.map(|a| a.uid),
target.stats,
target.health,
applied_damage,
strength_modifier,
)),
@ -401,7 +407,10 @@ impl Attack {
msm,
target.char_state,
target.stats,
) * strength_modifier;
) * strength_modifier
* attacker
.and_then(|a| a.stats)
.map_or(1.0, |s| s.poise_damage_modifier);
if change.abs() > Poise::POISE_EPSILON {
let poise_change = PoiseChange {
amount: change,
@ -561,6 +570,7 @@ impl Attack {
time,
attacker.map(|a| a.uid),
target.stats,
target.health,
accumulated_damage,
strength_modifier,
)),
@ -593,7 +603,10 @@ impl Attack {
msm,
target.char_state,
target.stats,
) * strength_modifier;
) * strength_modifier
* attacker
.and_then(|a| a.stats)
.map_or(1.0, |s| s.poise_damage_modifier);
if change.abs() > Poise::POISE_EPSILON {
let poise_change = PoiseChange {
amount: change,
@ -1082,7 +1095,8 @@ impl CombatBuff {
self,
time: Time,
uid: Option<Uid>,
stats: Option<&Stats>,
tgt_stats: Option<&Stats>,
tgt_health: Option<&Health>,
damage: f32,
strength_modifier: f32,
) -> Buff {
@ -1102,7 +1116,8 @@ impl CombatBuff {
Vec::new(),
source,
time,
stats,
tgt_stats,
tgt_health,
)
}
}

View File

@ -777,6 +777,7 @@ pub enum CharacterAbility {
DiveMelee {
energy_cost: f32,
vertical_speed: f32,
buildup_duration: Option<f32>,
movement_duration: f32,
swing_duration: f32,
recover_duration: f32,
@ -893,11 +894,15 @@ impl CharacterAbility {
&& update.energy.try_change_by(-*energy_cost).is_ok()
},
CharacterAbility::DiveMelee {
buildup_duration,
energy_cost,
vertical_speed,
..
} => {
data.vel.0.z < -*vertical_speed
// If either falling fast enough or is on ground and able to be activated from
// ground
(data.vel.0.z < -*vertical_speed
|| (data.physics.on_ground.is_some() && buildup_duration.is_some()))
&& update.energy.try_change_by(-*energy_cost).is_ok()
},
CharacterAbility::ComboMelee { .. }
@ -1425,12 +1430,14 @@ impl CharacterAbility {
ref mut energy_cost,
vertical_speed: _,
movement_duration: _,
ref mut buildup_duration,
ref mut swing_duration,
ref mut recover_duration,
ref mut melee_constructor,
max_scaling: _,
meta: _,
} => {
*buildup_duration = buildup_duration.map(|b| b / stats.speed);
*swing_duration /= stats.speed;
*recover_duration /= stats.speed;
*energy_cost /= stats.energy_efficiency;
@ -2744,6 +2751,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState {
exhausted: false,
}),
CharacterAbility::DiveMelee {
buildup_duration,
movement_duration,
swing_duration,
recover_duration,
@ -2754,6 +2762,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState {
meta: _,
} => CharacterState::DiveMelee(dive_melee::Data {
static_data: dive_melee::StaticData {
buildup_duration: buildup_duration.map(|b| Duration::from_secs_f32(b)),
movement_duration: Duration::from_secs_f32(*movement_duration),
swing_duration: Duration::from_secs_f32(*swing_duration),
recover_duration: Duration::from_secs_f32(*recover_duration),
@ -2763,7 +2772,11 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState {
ability_info,
},
timer: Duration::default(),
stage_section: StageSection::Movement,
stage_section: if data.vel.0.z < 0.0 || buildup_duration.is_none() {
StageSection::Movement
} else {
StageSection::Buildup
},
exhausted: false,
max_vertical_speed: 0.0,
}),

View File

@ -1,6 +1,6 @@
#![allow(clippy::nonstandard_macro_braces)] //tmp as of false positive !?
use crate::{
comp::{aura::AuraKey, Stats},
comp::{aura::AuraKey, Health, Stats},
resources::{Secs, Time},
uid::Uid,
};
@ -56,10 +56,13 @@ pub enum BuffKind {
/// Strength scales strength of both effects linearly. 0.5 is a 50%
/// increase, 1.0 is a 100% increase.
Hastened,
// TODO: Consider non linear scaling?
/// Increases resistance to incoming poise over time
/// Strength scales the resistance linearly, values over 1 will usually do
/// nothing. 0.5 is 50%, 1.0 is 100%.
/// Increases resistance to incoming poise, and poise damage dealt as health
/// is lost from the time the buff activated
/// Strength scales the resistance non-linearly. 0.5 provides 50%, 1.0
/// provides 67%
/// Strength scales the poise damage increase linearly, a strength of 1.0
/// and n health less from activation will cause poise damage to increase by
/// n%
Fortitude,
// Debuffs
/// Does damage to a creature over time
@ -214,6 +217,8 @@ pub enum BuffEffect {
PoiseReduction(f32),
/// Reduces amount healed by consumables
HealReduction(f32),
/// Increases poise damage dealt when health is lost
PoiseDamageFromLostHealth { initial_health: f32, strength: f32 },
}
/// Actual de/buff.
@ -272,6 +277,7 @@ impl Buff {
source: BuffSource,
time: Time,
stats: Option<&Stats>,
health: Option<&Health>,
) -> Self {
// Normalized nonlinear scaling
let nn_scaling = |a| a / (a + 0.5);
@ -367,7 +373,13 @@ impl Buff {
BuffEffect::MovementSpeed(1.0 + data.strength),
BuffEffect::AttackSpeed(1.0 + data.strength),
],
BuffKind::Fortitude => vec![BuffEffect::PoiseReduction(data.strength)],
BuffKind::Fortitude => vec![
BuffEffect::PoiseReduction(nn_scaling(data.strength)),
BuffEffect::PoiseDamageFromLostHealth {
initial_health: health.map_or(0.0, |h| h.current()),
strength: data.strength,
},
],
BuffKind::Parried => vec![BuffEffect::AttackSpeed(0.5)],
BuffKind::PotionSickness => vec![BuffEffect::HealReduction(data.strength)],
};

View File

@ -56,6 +56,7 @@ pub struct Stats {
pub attack_speed_modifier: f32,
pub friction_modifier: f32,
pub max_energy_modifiers: StatsModifier,
pub poise_damage_modifier: f32,
}
impl Stats {
@ -70,6 +71,7 @@ impl Stats {
attack_speed_modifier: 1.0,
friction_modifier: 1.0,
max_energy_modifiers: StatsModifier::default(),
poise_damage_modifier: 1.0,
}
}
@ -79,14 +81,8 @@ impl Stats {
/// Resets temporary modifiers to default values
pub fn reset_temp_modifiers(&mut self) {
self.damage_reduction = 0.0;
self.poise_reduction = 0.0;
self.heal_multiplier = 1.0;
self.max_health_modifiers = StatsModifier::default();
self.move_speed_modifier = 1.0;
self.attack_speed_modifier = 1.0;
self.friction_modifier = 1.0;
self.max_energy_modifiers = StatsModifier::default();
// TODO: Figure out how to avoid clone
*self = Self::new(self.name.clone());
}
}

View File

@ -146,7 +146,6 @@ pub struct JoinData<'a> {
pub terrain: &'a TerrainGrid,
pub mount_data: Option<&'a Is<Rider>>,
pub stance: Option<&'a Stance>,
pub time: &'a Time,
}
pub struct JoinStruct<'a> {
@ -174,7 +173,6 @@ pub struct JoinStruct<'a> {
pub terrain: &'a TerrainGrid,
pub mount_data: Option<&'a Is<Rider>>,
pub stance: Option<&'a Stance>,
pub time: &'a Time,
}
impl<'a> JoinData<'a> {
@ -216,7 +214,6 @@ impl<'a> JoinData<'a> {
active_abilities: j.active_abilities,
mount_data: j.mount_data,
stance: j.stance,
time: j.time,
}
}
}

View File

@ -18,11 +18,9 @@ pub struct StaticData {
pub energy_drain: f32,
/// Energy cost per attack
pub energy_cost: f32,
/// The state can optionally have a buildup strike that applies after buildup before charging
pub buildup_strike: Option<(
Duration,
MeleeConstructor,
)>,
/// The state can optionally have a buildup strike that applies after
/// buildup before charging
pub buildup_strike: Option<(Duration, MeleeConstructor)>,
/// How long it takes to charge the weapon to max damage and knockback
pub charge_duration: Duration,
/// How long the weapon is swinging for
@ -74,10 +72,8 @@ impl CharacterBehavior for Data {
} else {
let crit_data = get_crit_data(data, self.static_data.ability_info);
let buff_strength = get_buff_strength(data, self.static_data.ability_info);
data.updater.insert(
data.entity,
strike.create_melee(crit_data, buff_strength),
);
data.updater
.insert(data.entity, strike.create_melee(crit_data, buff_strength));
if let CharacterState::ChargedMelee(c) = &mut update.character {
c.stage_section = StageSection::Charge;

View File

@ -76,7 +76,8 @@ pub struct StaticData {
pub strikes: Vec<Strike<Duration>>,
/// The amount of energy consumed with each swing
pub energy_cost_per_strike: f32,
/// Whether or not the state should progress through all strikes automatically once the state is entered
/// Whether or not the state should progress through all strikes
/// automatically once the state is entered
pub auto_progress: bool,
pub ability_info: AbilityInfo,
}
@ -133,7 +134,9 @@ impl CharacterBehavior for Data {
if let Some(movement) = strike_data.movement.swing {
handle_forced_movement(data, &mut update, movement);
}
if input_is_pressed(data, self.static_data.ability_info.input) || self.static_data.auto_progress {
if input_is_pressed(data, self.static_data.ability_info.input)
|| self.static_data.auto_progress
{
if let CharacterState::ComboMelee2(c) = &mut update.character {
// Only have the next strike skip the recover period of this strike if not
// every strike in the combo is complete yet

View File

@ -11,6 +11,8 @@ use std::time::Duration;
/// Separated out to condense update portions of character state
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct StaticData {
/// If Some(_), the state can be activated on the ground
pub buildup_duration: Option<Duration>,
/// How long the state is moving
pub movement_duration: Duration,
/// How long the weapon swings
@ -51,6 +53,28 @@ impl CharacterBehavior for Data {
}
match self.stage_section {
StageSection::Buildup => {
handle_orientation(data, &mut update, 0.5, None);
handle_move(data, &mut update, 0.3);
if let Some(buildup_duration) = self.static_data.buildup_duration {
if self.timer < buildup_duration {
if let CharacterState::DiveMelee(c) = &mut update.character {
c.timer = tick_attack_or_default(data, self.timer, None);
}
} else {
if let CharacterState::DiveMelee(c) = &mut update.character {
c.timer = Duration::default();
c.stage_section = StageSection::Action;
}
}
} else {
if let CharacterState::DiveMelee(c) = &mut update.character {
c.timer = Duration::default();
c.stage_section = StageSection::Action;
}
}
},
StageSection::Movement => {
handle_move(data, &mut update, 1.0);
if data.physics.on_ground.is_some() {

View File

@ -92,9 +92,9 @@ impl CharacterBehavior for Data {
Some(max) => self.current_strike < max,
None => input_is_pressed(data, self.static_data.ability_info.input),
} && update
.energy
.try_change_by(-self.static_data.energy_cost)
.is_ok()
.energy
.try_change_by(-self.static_data.energy_cost)
.is_ok()
{
if let CharacterState::RapidMelee(c) = &mut update.character {
c.timer = Duration::default();

View File

@ -72,6 +72,7 @@ impl CharacterBehavior for Data {
BuffSource::Character { by: *data.uid },
*data.time,
Some(data.stats),
data.health,
);
output_events.emit_server(ServerEvent::Buff {
entity: data.entity,

View File

@ -2,7 +2,7 @@ use crate::{
astar::Astar,
combat,
comp::{
ability::{Ability, AbilityInput, AbilityMeta, Capability, AbilityInitEvent},
ability::{Ability, AbilityInitEvent, AbilityInput, AbilityMeta, Capability},
arthropod, biped_large, biped_small, bird_medium,
character_state::OutputEvents,
controller::InventoryManip,
@ -471,7 +471,9 @@ pub fn handle_forced_movement(
data.inputs.move_dir.reflected(Vec2::from(*data.ori))
} else {
data.inputs.move_dir
}.try_normalized().unwrap_or_else(|| -Vec2::from(*data.ori));
}
.try_normalized()
.unwrap_or_else(|| -Vec2::from(*data.ori));
update.vel.0 += direction * strength * accel * data.dt.0;
}
},
@ -485,7 +487,9 @@ pub fn handle_forced_movement(
data.inputs.move_dir.reflected(Vec2::from(*data.ori))
} else {
data.inputs.move_dir
}.try_normalized().unwrap_or_else(|| Vec2::from(*data.ori));
}
.try_normalized()
.unwrap_or_else(|| Vec2::from(*data.ori));
let direction = direction.reflected(Vec2::from(*data.ori).rotated_z(PI / 2.));
update.vel.0 += direction * strength * accel * data.dt.0;
}
@ -1060,7 +1064,12 @@ pub fn handle_jump(
.is_some()
}
fn handle_ability(data: &JoinData<'_>, update: &mut StateUpdate, output_events: &mut OutputEvents, input: InputKind) -> bool {
fn handle_ability(
data: &JoinData<'_>,
update: &mut StateUpdate,
output_events: &mut OutputEvents,
input: InputKind,
) -> bool {
let context = AbilityContext::from(data.stance);
if let Some(ability_input) = input.into() {
if let Some((ability, from_offhand)) = data
@ -1084,7 +1093,10 @@ fn handle_ability(data: &JoinData<'_>, update: &mut StateUpdate, output_events:
if let Some(init_event) = ability.ability_meta().init_event {
match init_event {
AbilityInitEvent::EnterStance(stance) => {
output_events.emit_server(ServerEvent::ChangeStance { entity: data.entity, stance });
output_events.emit_server(ServerEvent::ChangeStance {
entity: data.entity,
stance,
});
},
}
}
@ -1428,7 +1440,12 @@ impl AbilityInfo {
tool,
hand,
input,
input_attr: data.controller.queued_inputs.get(&input).map(|x| x.1).or_else(|| data.controller.held_inputs.get(&input).copied()),
input_attr: data
.controller
.queued_inputs
.get(&input)
.map(|x| x.1)
.or_else(|| data.controller.held_inputs.get(&input).copied()),
ability_meta,
ability,
}

View File

@ -241,6 +241,7 @@ fn activate_aura(
source,
*read_data.time,
stats,
Some(health),
)),
});
}

View File

@ -215,6 +215,7 @@ impl<'a> System<'a> for Sys {
energy: read_data.energies.get(entity),
combo: read_data.combos.get(entity),
inventory: read_data.inventories.get(entity),
stats: read_data.stats.get(entity),
}
});

View File

@ -151,6 +151,7 @@ impl<'a> System<'a> for Sys {
BuffSource::World,
*read_data.time,
Some(&stat),
Some(&health),
)),
});
}
@ -168,6 +169,7 @@ impl<'a> System<'a> for Sys {
BuffSource::World,
*read_data.time,
Some(&stat),
Some(&health),
)),
});
}
@ -185,6 +187,7 @@ impl<'a> System<'a> for Sys {
BuffSource::World,
*read_data.time,
Some(&stat),
Some(&health),
)),
});
// When standing on IceSpike also apply Frozen
@ -197,6 +200,7 @@ impl<'a> System<'a> for Sys {
BuffSource::World,
*read_data.time,
Some(&stat),
Some(&health),
)),
});
}
@ -217,6 +221,7 @@ impl<'a> System<'a> for Sys {
BuffSource::World,
*read_data.time,
Some(&stat),
Some(&health),
)),
});
} else if matches!(
@ -296,6 +301,7 @@ impl<'a> System<'a> for Sys {
buff.source,
*read_data.time,
Some(&stat),
Some(&health),
)),
});
}
@ -573,5 +579,12 @@ fn execute_effect(
BuffEffect::HealReduction(red) => {
stat.heal_multiplier *= 1.0 - *red;
},
BuffEffect::PoiseDamageFromLostHealth {
initial_health,
strength,
} => {
let lost_health = (*initial_health - health.current()).max(0.0);
stat.poise_damage_modifier *= lost_health / 100.0 * *strength;
},
};
}

View File

@ -201,7 +201,6 @@ impl<'a> System<'a> for Sys {
terrain: &read_data.terrain,
mount_data: read_data.is_riders.get(entity),
stance: read_data.stances.get(entity),
time: &read_data.time,
};
for action in actions {
@ -274,7 +273,7 @@ impl Sys {
for (input, attr) in state_update.queued_inputs {
join.controller
.queued_inputs
.insert(input, (*join.time, attr));
.insert(input, (Time(0.0), attr));
join.controller.held_inputs.insert(input, attr);
}
for input in state_update.used_inputs {
@ -283,7 +282,7 @@ impl Sys {
for input in state_update.removed_inputs {
join.controller.held_inputs.remove(&input);
}
join.controller.cull_queued_inputs(*join.time);
join.controller.cull_queued_inputs(Time(0.0));
if state_update.swap_equipped_weapons {
output_events.emit_server(ServerEvent::InventoryManip(
join.entity,

View File

@ -191,6 +191,7 @@ impl<'a> System<'a> for Sys {
energy: read_data.energies.get(attacker),
combo: read_data.combos.get(attacker),
inventory: read_data.inventories.get(attacker),
stats: read_data.stats.get(attacker),
});
let target_info = TargetInfo {

View File

@ -298,6 +298,7 @@ fn dispatch_hit(
energy: read_data.energies.get(entity),
combo: read_data.combos.get(entity),
inventory: read_data.inventories.get(entity),
stats: read_data.stats.get(entity),
});
let target_info = TargetInfo {

View File

@ -198,6 +198,7 @@ impl<'a> System<'a> for Sys {
energy: read_data.energies.get(entity),
combo: read_data.combos.get(entity),
inventory: read_data.inventories.get(entity),
stats: read_data.stats.get(entity),
});
let target_info = TargetInfo {

View File

@ -3541,6 +3541,7 @@ fn cast_buff(kind: &str, data: BuffData, server: &mut Server, target: EcsEntity)
let ecs = &server.state.ecs();
let mut buffs_all = ecs.write_storage::<comp::Buffs>();
let stats = ecs.read_storage::<comp::Stats>();
let healths = ecs.read_storage::<comp::Health>();
let time = ecs.read_resource::<Time>();
if let Some(mut buffs) = buffs_all.get_mut(target) {
buffs.insert(
@ -3551,6 +3552,7 @@ fn cast_buff(kind: &str, data: BuffData, server: &mut Server, target: EcsEntity)
BuffSource::Command,
*time,
stats.get(target),
healths.get(target),
),
*time,
);

View File

@ -865,18 +865,18 @@ pub fn handle_explosion(server: &Server, pos: Vec3<f32>, explosion: Explosion, o
let uid_allocator = &ecs.read_resource::<UidAllocator>();
let players = &ecs.read_storage::<Player>();
let buffs = &ecs.read_storage::<comp::Buffs>();
let stats = &ecs.read_storage::<comp::Stats>();
for (
entity_b,
pos_b,
health_b,
(body_b_maybe, stats_b_maybe, ori_b_maybe, char_state_b_maybe, uid_b),
(body_b_maybe, ori_b_maybe, char_state_b_maybe, uid_b),
) in (
&ecs.entities(),
&ecs.read_storage::<Pos>(),
&ecs.read_storage::<Health>(),
(
ecs.read_storage::<Body>().maybe(),
ecs.read_storage::<Stats>().maybe(),
ecs.read_storage::<comp::Ori>().maybe(),
ecs.read_storage::<CharacterState>().maybe(),
&ecs.read_storage::<Uid>(),
@ -927,13 +927,14 @@ pub fn handle_explosion(server: &Server, pos: Vec3<f32>, explosion: Explosion, o
energy: energies.get(entity),
combo: combos.get(entity),
inventory: inventories.get(entity),
stats: stats.get(entity),
});
let target_info = combat::TargetInfo {
entity: entity_b,
uid: *uid_b,
inventory: inventories.get(entity_b),
stats: stats_b_maybe,
stats: stats.get(entity_b),
health: Some(health_b),
pos: pos_b.0,
ori: ori_b_maybe,
@ -1159,15 +1160,16 @@ pub fn handle_buff(server: &mut Server, entity: EcsEntity, buff_change: buff::Bu
}
},
BuffChange::Refresh(kind) => {
let (buff_comp_kinds, buff_comp_buffs) = buffs.parts();
if let Some(buff_ids) = buff_comp_kinds.get(&kind) {
for id in buff_ids {
if let Some(buff) = buff_comp_buffs.get_mut(id) {
// Resets buff timer to the original duration
buff.time = buff.data.duration;
}
}
}
buffs
.buffs
.values_mut()
.filter(|b| b.kind == kind)
.for_each(|buff| {
// Resets buff so that its remaining duration is equal to its original
// duration
buff.start_time = *time;
buff.end_time = buff.data.duration.map(|dur| Time(time.0 + dur.0));
})
},
}
}
@ -1303,6 +1305,7 @@ pub fn handle_parry_hook(server: &Server, defender: EcsEntity, attacker: Option<
};
let time = ecs.read_resource::<Time>();
let stats = ecs.read_storage::<comp::Stats>();
let healths = ecs.read_storage::<comp::Health>();
let buff = buff::Buff::new(
BuffKind::Parried,
data,
@ -1310,6 +1313,7 @@ pub fn handle_parry_hook(server: &Server, defender: EcsEntity, attacker: Option<
source,
*time,
stats.get(attacker),
healths.get(attacker),
);
server_eventbus.emit_now(ServerEvent::Buff {
entity: attacker,

View File

@ -224,6 +224,7 @@ impl StateExt for State {
Effect::Buff(buff) => {
let time = self.ecs().read_resource::<Time>();
let stats = self.ecs().read_storage::<comp::Stats>();
let healths = self.ecs().read_storage::<comp::Health>();
self.ecs()
.write_storage::<comp::Buffs>()
.get_mut(entity)
@ -236,6 +237,7 @@ impl StateExt for State {
comp::BuffSource::Item,
*time,
stats.get(entity),
healths.get(entity),
),
*time,
)

View File

@ -3,6 +3,7 @@ use super::{
CharacterSkeleton, SkeletonAttr,
};
use common::states::utils::{AbilityInfo, StageSection};
use core::f32::consts::PI;
pub struct DiveMeleeAnimation;
impl Animation for DiveMeleeAnimation {
@ -81,6 +82,54 @@ impl Animation for DiveMeleeAnimation {
next.control.orientation.rotate_x(move3 * -1.2);
next.control.position += Vec3::new(0.0, move3 * 4.0, move3 * -8.0);
},
Some("common.abilities.sword.heavy_pillar_thrust") => {
let (move1, move2, move3) = match stage_section {
Some(StageSection::Buildup) => (anim_time.powf(0.5), 0.0, 0.0),
Some(StageSection::Movement) => (anim_time.min(1.0).powf(0.5), 0.0, 0.0),
Some(StageSection::Action) => (1.0, anim_time.powi(2), 0.0),
Some(StageSection::Recover) => (1.0, 1.0, anim_time.powi(4)),
_ => (0.0, 0.0, 0.0),
};
let move1alt1 = move1.min(0.5) * 2.0;
let move1alt2 = (move1.max(0.5) - 0.5) * 2.0;
let pullback = 1.0 - move3;
let move1 = move1 * pullback;
let move1alt1 = move1alt1 * pullback;
let move1alt2 = move1alt2 * pullback;
let move2 = move2 * pullback;
next.hand_l.position = Vec3::new(s_a.shl.0, s_a.shl.1, s_a.shl.2);
next.hand_l.orientation = Quaternion::rotation_x(s_a.shl.3 + move1alt2 * PI)
* Quaternion::rotation_y(s_a.shl.4);
next.hand_r.position = Vec3::new(
-s_a.sc.0 + 6.0 + move1alt1 * -12.0,
-4.0 + move1alt1 * 3.0,
-2.0,
);
next.hand_r.orientation =
Quaternion::rotation_x(0.9 + move1 * 0.5 + move1alt1 * PI);
next.control.position = Vec3::new(s_a.sc.0, s_a.sc.1, s_a.sc.2);
next.control.orientation = Quaternion::rotation_x(s_a.sc.3);
next.control.position += Vec3::new(
move1 * 6.0,
(1.0 - (move1 - 0.5).abs() * 2.0) * 3.0,
move1 * 22.0,
);
next.control.orientation.rotate_x(move1 * -1.5);
next.chest.orientation = Quaternion::rotation_x(move2 * -0.4);
next.head.orientation = Quaternion::rotation_x(move2 * 0.2);
next.belt.orientation = Quaternion::rotation_x(move2 * 0.4);
next.shorts.orientation = Quaternion::rotation_x(move2 * 0.8);
next.control.orientation.rotate_x(move2 * -0.4);
next.control.position += Vec3::new(0.0, 0.0, move2 * -10.0);
next.belt.position += Vec3::new(0.0, move2 * 2.0, move2 * 0.0);
next.shorts.position += Vec3::new(0.0, move2 * 4.0, move2 * 1.0);
next.chest.position += Vec3::new(0.0, move2 * -2.5, 0.0);
},
_ => {},
}

View File

@ -109,53 +109,6 @@ impl Animation for FinisherMeleeAnimation {
next.control.position += Vec3::new(0.0, 0.0, move3 * 4.0);
next.control.orientation.rotate_x(move3 * 0.6);
},
Some("common.abilities.sword.crippling_finisher") => {
let (move1, move2, move3) = match stage_section {
Some(StageSection::Buildup) => (anim_time.powf(0.5), 0.0, 0.0),
Some(StageSection::Action) => (1.0, anim_time.powi(2), 0.0),
Some(StageSection::Recover) => (1.0, 1.0, anim_time.powi(4)),
_ => (0.0, 0.0, 0.0),
};
let move1alt1 = move1.min(0.5) * 2.0;
let move1alt2 = (move1.max(0.5) - 0.5) * 2.0;
let pullback = 1.0 - move3;
let move1 = move1 * pullback;
let move1alt1 = move1alt1 * pullback;
let move1alt2 = move1alt2 * pullback;
let move2 = move2 * pullback;
next.hand_l.position = Vec3::new(s_a.shl.0, s_a.shl.1, s_a.shl.2);
next.hand_l.orientation = Quaternion::rotation_x(s_a.shl.3 + move1alt2 * PI)
* Quaternion::rotation_y(s_a.shl.4);
next.hand_r.position = Vec3::new(
-s_a.sc.0 + 6.0 + move1alt1 * -12.0,
-4.0 + move1alt1 * 3.0,
-2.0,
);
next.hand_r.orientation =
Quaternion::rotation_x(0.9 + move1 * 0.5 + move1alt1 * PI);
next.control.position = Vec3::new(s_a.sc.0, s_a.sc.1, s_a.sc.2);
next.control.orientation = Quaternion::rotation_x(s_a.sc.3);
next.control.position += Vec3::new(
move1 * 6.0,
(1.0 - (move1 - 0.5).abs() * 2.0) * 3.0,
move1 * 22.0,
);
next.control.orientation.rotate_x(move1 * -1.5);
next.chest.orientation = Quaternion::rotation_x(move2 * -0.4);
next.head.orientation = Quaternion::rotation_x(move2 * 0.2);
next.belt.orientation = Quaternion::rotation_x(move2 * 0.4);
next.shorts.orientation = Quaternion::rotation_x(move2 * 0.8);
next.control.orientation.rotate_x(move2 * -0.4);
next.control.position += Vec3::new(0.0, 0.0, move2 * -10.0);
next.belt.position += Vec3::new(0.0, move2 * 2.0, move2 * 0.0);
next.shorts.position += Vec3::new(0.0, move2 * 4.0, move2 * 1.0);
next.chest.position += Vec3::new(0.0, move2 * -2.5, 0.0);
},
Some("common.abilities.sword.cleaving_finisher") => {
let (move1, move2, move3) = match stage_section {
Some(StageSection::Buildup) => (anim_time.powf(0.5), 0.0, 0.0),

View File

@ -29,6 +29,40 @@ impl Animation for SelfBuffAnimation {
next.second.orientation = Quaternion::rotation_z(0.0);
match ability_id {
Some("common.abilities.sword.heavy_fortitude") => {
let (move1, move2, move3) = match stage_section {
Some(StageSection::Movement) => (anim_time.powf(0.25), 0.0, 0.0),
Some(StageSection::Action) => (1.0, anim_time.powi(2), 0.0),
Some(StageSection::Recover) => (1.0, 1.0, anim_time.powi(4)),
_ => (0.0, 0.0, 0.0),
};
let pullback = 1.0 - move3;
let move1 = move1 * pullback;
let move2 = move2 * pullback;
next.hand_l.position = Vec3::new(s_a.shl.0, s_a.shl.1, s_a.shl.2);
next.hand_l.orientation =
Quaternion::rotation_x(s_a.shl.3) * Quaternion::rotation_y(s_a.shl.4);
next.hand_r.position =
Vec3::new(-s_a.sc.0 + 6.0 + move1 * -12.0, -4.0 + move1 * 3.0, -2.0);
next.hand_r.orientation = Quaternion::rotation_x(0.9 + move1 * 0.5);
next.control.position = Vec3::new(s_a.sc.0, s_a.sc.1, s_a.sc.2);
next.control.orientation = Quaternion::rotation_x(s_a.sc.3);
next.foot_l.position += Vec3::new(move1 * 1.0, move1 * 2.0, 0.0);
next.chest.orientation = Quaternion::rotation_z(move1 * -0.4);
next.head.orientation = Quaternion::rotation_z(move1 * 0.2);
next.shorts.orientation = Quaternion::rotation_z(move1 * 0.3);
next.belt.orientation = Quaternion::rotation_z(move1 * 0.1);
next.control.orientation.rotate_x(move1 * 0.4 + move2 * 0.6);
next.control.orientation.rotate_z(move1 * 0.4);
next.foot_r.position += Vec3::new(move2 * -1.0, move2 * -2.0, 0.0);
next.control.position += Vec3::new(move2 * 5.0, move2 * 7.0, move2 * 5.0);
next.chest.position += Vec3::new(0.0, 0.0, move2 * -1.0);
next.shorts.orientation.rotate_x(move2 * 0.2);
next.shorts.position += Vec3::new(0.0, move2 * 1.0, 0.0);
},
Some("common.abilities.sword.defensive_bulwark") => {
let (move1, move2, move3) = match stage_section {
Some(StageSection::Movement) => (anim_time.powf(0.25), 0.0, 0.0),
@ -67,40 +101,6 @@ impl Animation for SelfBuffAnimation {
next.shorts.orientation.rotate_x(move2 * 0.2);
next.control.orientation.rotate_z(move2 * 0.4);
},
Some("common.abilities.sword.heavy_fortitude") => {
let (move1, move2, move3) = match stage_section {
Some(StageSection::Movement) => (anim_time.powf(0.25), 0.0, 0.0),
Some(StageSection::Action) => (1.0, anim_time.powi(2), 0.0),
Some(StageSection::Recover) => (1.0, 1.0, anim_time.powi(4)),
_ => (0.0, 0.0, 0.0),
};
let pullback = 1.0 - move3;
let move1 = move1 * pullback;
let move2 = move2 * pullback;
next.hand_l.position = Vec3::new(s_a.shl.0, s_a.shl.1, s_a.shl.2);
next.hand_l.orientation =
Quaternion::rotation_x(s_a.shl.3) * Quaternion::rotation_y(s_a.shl.4);
next.hand_r.position =
Vec3::new(-s_a.sc.0 + 6.0 + move1 * -12.0, -4.0 + move1 * 3.0, -2.0);
next.hand_r.orientation = Quaternion::rotation_x(0.9 + move1 * 0.5);
next.control.position = Vec3::new(s_a.sc.0, s_a.sc.1, s_a.sc.2);
next.control.orientation = Quaternion::rotation_x(s_a.sc.3);
next.foot_l.position += Vec3::new(move1 * 1.0, move1 * 2.0, 0.0);
next.chest.orientation = Quaternion::rotation_z(move1 * -0.4);
next.head.orientation = Quaternion::rotation_z(move1 * 0.2);
next.shorts.orientation = Quaternion::rotation_z(move1 * 0.3);
next.belt.orientation = Quaternion::rotation_z(move1 * 0.1);
next.control.orientation.rotate_x(move1 * 0.4 + move2 * 0.6);
next.control.orientation.rotate_z(move1 * 0.4);
next.foot_r.position += Vec3::new(move2 * -1.0, move2 * -2.0, 0.0);
next.control.position += Vec3::new(move2 * 5.0, move2 * 7.0, move2 * 5.0);
next.chest.position += Vec3::new(0.0, 0.0, move2 * -1.0);
next.shorts.orientation.rotate_x(move2 * 0.2);
next.shorts.position += Vec3::new(0.0, move2 * 1.0, 0.0);
},
Some("common.abilities.sword.mobility_agility") => {
let (move1, move2, move3) = match stage_section {
Some(StageSection::Movement) => (anim_time.powf(0.25), 0.0, 0.0),

View File

@ -250,7 +250,7 @@ pub trait Animation {
let update_fn: common_dynlib::Symbol<
fn(
&Self::Skeleton,
Self::Dependency<'a>,
Self::Dependency<'_>,
f32,
&mut f32,
&<Self::Skeleton as Skeleton>::Attr,