mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Overhauled dash melee.
This commit is contained in:
parent
cb817c0313
commit
ce7581037c
@ -61,6 +61,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- There is now a brief period after a character leaves the world where they cannot rejoin until their data is saved
|
- There is now a brief period after a character leaves the world where they cannot rejoin until their data is saved
|
||||||
- Certain uses of client-authoritative physics now subject the player to server-authoritative physics.
|
- Certain uses of client-authoritative physics now subject the player to server-authoritative physics.
|
||||||
- Dodge roll iframes and staff explosion are now unlocked by default, with points refunded for existing characters.
|
- Dodge roll iframes and staff explosion are now unlocked by default, with points refunded for existing characters.
|
||||||
|
- Dash melee now stops after hitting something. Infinite dash also now replaced with dash through.
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
|
@ -14,6 +14,6 @@ DashMelee(
|
|||||||
charge_duration: 3.0,
|
charge_duration: 3.0,
|
||||||
swing_duration: 0.35,
|
swing_duration: 0.35,
|
||||||
recover_duration: 1.2,
|
recover_duration: 1.2,
|
||||||
infinite_charge: true,
|
charge_through: true,
|
||||||
is_interruptible: true,
|
is_interruptible: true,
|
||||||
)
|
)
|
||||||
|
@ -14,6 +14,6 @@ DashMelee(
|
|||||||
charge_duration: 1.0,
|
charge_duration: 1.0,
|
||||||
swing_duration: 0.1,
|
swing_duration: 0.1,
|
||||||
recover_duration: 0.5,
|
recover_duration: 0.5,
|
||||||
infinite_charge: true,
|
charge_through: true,
|
||||||
is_interruptible: true,
|
is_interruptible: true,
|
||||||
)
|
)
|
||||||
|
@ -6,14 +6,14 @@ DashMelee(
|
|||||||
scaled_poise_damage: 0,
|
scaled_poise_damage: 0,
|
||||||
base_knockback: 8.0,
|
base_knockback: 8.0,
|
||||||
scaled_knockback: 7.0,
|
scaled_knockback: 7.0,
|
||||||
range: 5.0,
|
range: 4.0,
|
||||||
angle: 45.0,
|
angle: 60.0,
|
||||||
energy_drain: 600,
|
energy_drain: 300,
|
||||||
forward_speed: 3.0,
|
forward_speed: 3.0,
|
||||||
buildup_duration: 0.25,
|
buildup_duration: 0.25,
|
||||||
charge_duration: 0.6,
|
charge_duration: 1.2,
|
||||||
swing_duration: 0.1,
|
swing_duration: 0.1,
|
||||||
recover_duration: 0.5,
|
recover_duration: 0.5,
|
||||||
infinite_charge: true,
|
charge_through: true,
|
||||||
is_interruptible: true,
|
is_interruptible: true,
|
||||||
)
|
)
|
||||||
|
@ -11,9 +11,9 @@ DashMelee(
|
|||||||
energy_drain: 0,
|
energy_drain: 0,
|
||||||
forward_speed: 4.0,
|
forward_speed: 4.0,
|
||||||
buildup_duration: 0.25,
|
buildup_duration: 0.25,
|
||||||
charge_duration: 0.6,
|
charge_duration: 1.2,
|
||||||
swing_duration: 0.1,
|
swing_duration: 0.1,
|
||||||
recover_duration: 0.5,
|
recover_duration: 0.5,
|
||||||
infinite_charge: true,
|
charge_through: true,
|
||||||
is_interruptible: true,
|
is_interruptible: true,
|
||||||
)
|
)
|
||||||
|
@ -14,6 +14,6 @@ DashMelee(
|
|||||||
charge_duration: 1.0,
|
charge_duration: 1.0,
|
||||||
swing_duration: 0.1,
|
swing_duration: 0.1,
|
||||||
recover_duration: 0.8,
|
recover_duration: 0.8,
|
||||||
infinite_charge: true,
|
charge_through: true,
|
||||||
is_interruptible: false,
|
is_interruptible: false,
|
||||||
)
|
)
|
||||||
|
@ -11,9 +11,9 @@ DashMelee(
|
|||||||
energy_drain: 0,
|
energy_drain: 0,
|
||||||
forward_speed: 2.0,
|
forward_speed: 2.0,
|
||||||
buildup_duration: 0.5,
|
buildup_duration: 0.5,
|
||||||
charge_duration: 0.4,
|
charge_duration: 0.8,
|
||||||
swing_duration: 0.1,
|
swing_duration: 0.1,
|
||||||
recover_duration: 0.5,
|
recover_duration: 0.5,
|
||||||
infinite_charge: true,
|
charge_through: true,
|
||||||
is_interruptible: false,
|
is_interruptible: false,
|
||||||
)
|
)
|
||||||
|
@ -14,6 +14,6 @@ DashMelee(
|
|||||||
charge_duration: 1.2,
|
charge_duration: 1.2,
|
||||||
swing_duration: 0.1,
|
swing_duration: 0.1,
|
||||||
recover_duration: 1.1,
|
recover_duration: 1.1,
|
||||||
infinite_charge: true,
|
charge_through: true,
|
||||||
is_interruptible: false,
|
is_interruptible: false,
|
||||||
)
|
)
|
||||||
|
@ -11,9 +11,9 @@ DashMelee(
|
|||||||
energy_drain: 0,
|
energy_drain: 0,
|
||||||
forward_speed: 2.5,
|
forward_speed: 2.5,
|
||||||
buildup_duration: 1.2,
|
buildup_duration: 1.2,
|
||||||
charge_duration: 0.5,
|
charge_duration: 1.0,
|
||||||
swing_duration: 0.1,
|
swing_duration: 0.1,
|
||||||
recover_duration: 0.5,
|
recover_duration: 0.5,
|
||||||
infinite_charge: true,
|
charge_through: true,
|
||||||
is_interruptible: false,
|
is_interruptible: false,
|
||||||
)
|
)
|
||||||
|
@ -14,6 +14,6 @@ DashMelee(
|
|||||||
charge_duration: 1.2,
|
charge_duration: 1.2,
|
||||||
swing_duration: 0.1,
|
swing_duration: 0.1,
|
||||||
recover_duration: 1.1,
|
recover_duration: 1.1,
|
||||||
infinite_charge: true,
|
charge_through: true,
|
||||||
is_interruptible: false,
|
is_interruptible: false,
|
||||||
)
|
)
|
@ -189,8 +189,8 @@
|
|||||||
"hud.skill.sw_dash_cost": "Decreases the initial cost of the dash by 25%{SP}",
|
"hud.skill.sw_dash_cost": "Decreases the initial cost of the dash by 25%{SP}",
|
||||||
"hud.skill.sw_dash_speed_title": "Dash Speed",
|
"hud.skill.sw_dash_speed_title": "Dash Speed",
|
||||||
"hud.skill.sw_dash_speed": "Increases how fast you go while dashing by 30%{SP}",
|
"hud.skill.sw_dash_speed": "Increases how fast you go while dashing by 30%{SP}",
|
||||||
"hud.skill.sw_dash_inf_title": "Dash Infinite",
|
"hud.skill.sw_dash_charge_through_title": "Charge Through",
|
||||||
"hud.skill.sw_dash_inf": "Allows you to dash for as long as you have energy{SP}",
|
"hud.skill.sw_dash_charge_through": "Allows you to charge through the first enemies you hit{SP}",
|
||||||
"hud.skill.sw_dash_scale_title": "Dash Scaling Damage",
|
"hud.skill.sw_dash_scale_title": "Dash Scaling Damage",
|
||||||
"hud.skill.sw_dash_scale": "Increases the damage scaling from the dash by 20%{SP}",
|
"hud.skill.sw_dash_scale": "Increases the damage scaling from the dash by 20%{SP}",
|
||||||
"hud.skill.sw_spin_title": "Spin Unlock",
|
"hud.skill.sw_spin_title": "Spin Unlock",
|
||||||
|
@ -113,7 +113,7 @@ pub enum CharacterAbility {
|
|||||||
charge_duration: f32,
|
charge_duration: f32,
|
||||||
swing_duration: f32,
|
swing_duration: f32,
|
||||||
recover_duration: f32,
|
recover_duration: f32,
|
||||||
infinite_charge: bool,
|
charge_through: bool,
|
||||||
is_interruptible: bool,
|
is_interruptible: bool,
|
||||||
},
|
},
|
||||||
BasicBlock,
|
BasicBlock,
|
||||||
@ -650,7 +650,7 @@ impl CharacterAbility {
|
|||||||
ref mut base_damage,
|
ref mut base_damage,
|
||||||
ref mut scaled_damage,
|
ref mut scaled_damage,
|
||||||
ref mut forward_speed,
|
ref mut forward_speed,
|
||||||
ref mut infinite_charge,
|
ref mut charge_through,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
*is_interruptible = skillset.has_skill(Sword(InterruptingAttacks));
|
*is_interruptible = skillset.has_skill(Sword(InterruptingAttacks));
|
||||||
@ -669,7 +669,7 @@ impl CharacterAbility {
|
|||||||
if skillset.has_skill(Sword(DSpeed)) {
|
if skillset.has_skill(Sword(DSpeed)) {
|
||||||
*forward_speed *= 1.15;
|
*forward_speed *= 1.15;
|
||||||
}
|
}
|
||||||
*infinite_charge = skillset.has_skill(Sword(DInfinite));
|
*charge_through = skillset.has_skill(Sword(DInfinite));
|
||||||
},
|
},
|
||||||
SpinMelee {
|
SpinMelee {
|
||||||
ref mut is_interruptible,
|
ref mut is_interruptible,
|
||||||
@ -1212,7 +1212,7 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState {
|
|||||||
charge_duration,
|
charge_duration,
|
||||||
swing_duration,
|
swing_duration,
|
||||||
recover_duration,
|
recover_duration,
|
||||||
infinite_charge,
|
charge_through,
|
||||||
is_interruptible,
|
is_interruptible,
|
||||||
} => CharacterState::DashMelee(dash_melee::Data {
|
} => CharacterState::DashMelee(dash_melee::Data {
|
||||||
static_data: dash_melee::StaticData {
|
static_data: dash_melee::StaticData {
|
||||||
@ -1226,7 +1226,7 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState {
|
|||||||
angle: *angle,
|
angle: *angle,
|
||||||
energy_drain: *energy_drain,
|
energy_drain: *energy_drain,
|
||||||
forward_speed: *forward_speed,
|
forward_speed: *forward_speed,
|
||||||
infinite_charge: *infinite_charge,
|
charge_through: *charge_through,
|
||||||
buildup_duration: Duration::from_secs_f32(*buildup_duration),
|
buildup_duration: Duration::from_secs_f32(*buildup_duration),
|
||||||
charge_duration: Duration::from_secs_f32(*charge_duration),
|
charge_duration: Duration::from_secs_f32(*charge_duration),
|
||||||
swing_duration: Duration::from_secs_f32(*swing_duration),
|
swing_duration: Duration::from_secs_f32(*swing_duration),
|
||||||
@ -1236,7 +1236,7 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState {
|
|||||||
},
|
},
|
||||||
auto_charge: false,
|
auto_charge: false,
|
||||||
timer: Duration::default(),
|
timer: Duration::default(),
|
||||||
refresh_distance: 0.0,
|
charge_end_timer: Duration::from_secs_f32(*charge_duration),
|
||||||
stage_section: StageSection::Buildup,
|
stage_section: StageSection::Buildup,
|
||||||
exhausted: false,
|
exhausted: false,
|
||||||
}),
|
}),
|
||||||
|
@ -128,7 +128,7 @@ pub enum SwordSkill {
|
|||||||
DDamage,
|
DDamage,
|
||||||
DScaling,
|
DScaling,
|
||||||
DSpeed,
|
DSpeed,
|
||||||
DInfinite,
|
DInfinite, // Represents charge through, not migrated because laziness
|
||||||
// Spin upgrades
|
// Spin upgrades
|
||||||
UnlockSpin,
|
UnlockSpin,
|
||||||
SDamage,
|
SDamage,
|
||||||
|
@ -9,7 +9,6 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use vek::Vec3;
|
|
||||||
|
|
||||||
/// Separated out to condense update portions of character state
|
/// Separated out to condense update portions of character state
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
@ -34,8 +33,8 @@ pub struct StaticData {
|
|||||||
pub energy_drain: f32,
|
pub energy_drain: f32,
|
||||||
/// How quickly dasher moves forward
|
/// How quickly dasher moves forward
|
||||||
pub forward_speed: f32,
|
pub forward_speed: f32,
|
||||||
/// Whether state keeps charging after reaching max charge duration
|
/// Whether the state can charge through enemies and do a second hit
|
||||||
pub infinite_charge: bool,
|
pub charge_through: bool,
|
||||||
/// How long until state should deal damage
|
/// How long until state should deal damage
|
||||||
pub buildup_duration: Duration,
|
pub buildup_duration: Duration,
|
||||||
/// How long the state charges for until it reaches max damage
|
/// How long the state charges for until it reaches max damage
|
||||||
@ -60,12 +59,12 @@ pub struct Data {
|
|||||||
pub auto_charge: bool,
|
pub auto_charge: bool,
|
||||||
/// Timer for each stage
|
/// Timer for each stage
|
||||||
pub timer: Duration,
|
pub timer: Duration,
|
||||||
/// Distance used to limit how often another attack will be applied
|
|
||||||
pub refresh_distance: f32,
|
|
||||||
/// What section the character stage is in
|
/// What section the character stage is in
|
||||||
pub stage_section: StageSection,
|
pub stage_section: StageSection,
|
||||||
/// Whether the state should attempt attacking again
|
/// Whether the state should attempt attacking again
|
||||||
pub exhausted: bool,
|
pub exhausted: bool,
|
||||||
|
/// Time that charge should end (used for charge through)
|
||||||
|
pub charge_end_timer: Duration,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CharacterBehavior for Data {
|
impl CharacterBehavior for Data {
|
||||||
@ -97,8 +96,7 @@ impl CharacterBehavior for Data {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
StageSection::Charge => {
|
StageSection::Charge => {
|
||||||
if (self.static_data.infinite_charge
|
if self.timer < self.charge_end_timer
|
||||||
|| self.timer < self.static_data.charge_duration)
|
|
||||||
&& (input_is_pressed(data, self.static_data.ability_info.input)
|
&& (input_is_pressed(data, self.static_data.ability_info.input)
|
||||||
|| (self.auto_charge && self.timer < self.static_data.charge_duration))
|
|| (self.auto_charge && self.timer < self.static_data.charge_duration))
|
||||||
&& update.energy.current() > 0
|
&& update.energy.current() > 0
|
||||||
@ -120,62 +118,60 @@ impl CharacterBehavior for Data {
|
|||||||
// This logic basically just decides if a charge should end, and prevents the
|
// This logic basically just decides if a charge should end, and prevents the
|
||||||
// character state spamming attacks while checking if it has hit something
|
// character state spamming attacks while checking if it has hit something
|
||||||
if !self.exhausted {
|
if !self.exhausted {
|
||||||
// Hit attempt (also checks if player is moving)
|
// Hit attempt
|
||||||
if update.vel.0.distance_squared(Vec3::zero()) > 1.0 {
|
let poise = AttackEffect::new(
|
||||||
let poise = AttackEffect::new(
|
Some(GroupTarget::OutOfGroup),
|
||||||
Some(GroupTarget::OutOfGroup),
|
CombatEffect::Poise(
|
||||||
CombatEffect::Poise(
|
self.static_data.base_poise_damage as f32
|
||||||
self.static_data.base_poise_damage as f32
|
+ charge_frac * self.static_data.scaled_poise_damage as f32,
|
||||||
+ charge_frac * self.static_data.scaled_poise_damage as f32,
|
),
|
||||||
),
|
)
|
||||||
)
|
.with_requirement(CombatRequirement::AnyDamage);
|
||||||
.with_requirement(CombatRequirement::AnyDamage);
|
let knockback = AttackEffect::new(
|
||||||
let knockback = AttackEffect::new(
|
Some(GroupTarget::OutOfGroup),
|
||||||
Some(GroupTarget::OutOfGroup),
|
CombatEffect::Knockback(Knockback {
|
||||||
CombatEffect::Knockback(Knockback {
|
strength: self.static_data.base_knockback
|
||||||
strength: self.static_data.base_knockback
|
+ charge_frac * self.static_data.scaled_knockback,
|
||||||
+ charge_frac * self.static_data.scaled_knockback,
|
direction: KnockbackDir::Away,
|
||||||
direction: KnockbackDir::Away,
|
}),
|
||||||
}),
|
)
|
||||||
)
|
.with_requirement(CombatRequirement::AnyDamage);
|
||||||
.with_requirement(CombatRequirement::AnyDamage);
|
let buff = CombatEffect::Buff(CombatBuff::default_physical());
|
||||||
let buff = CombatEffect::Buff(CombatBuff::default_physical());
|
let damage = AttackDamage::new(
|
||||||
let damage = AttackDamage::new(
|
Damage {
|
||||||
Damage {
|
source: DamageSource::Melee,
|
||||||
source: DamageSource::Melee,
|
value: self.static_data.base_damage as f32
|
||||||
value: self.static_data.base_damage as f32
|
+ charge_frac * self.static_data.scaled_damage as f32,
|
||||||
+ charge_frac * self.static_data.scaled_damage as f32,
|
},
|
||||||
},
|
Some(GroupTarget::OutOfGroup),
|
||||||
Some(GroupTarget::OutOfGroup),
|
)
|
||||||
)
|
.with_effect(buff);
|
||||||
.with_effect(buff);
|
let (crit_chance, crit_mult) =
|
||||||
let (crit_chance, crit_mult) =
|
get_crit_data(data, self.static_data.ability_info);
|
||||||
get_crit_data(data, self.static_data.ability_info);
|
let attack = Attack::default()
|
||||||
let attack = Attack::default()
|
.with_damage(damage)
|
||||||
.with_damage(damage)
|
.with_crit(crit_chance, crit_mult)
|
||||||
.with_crit(crit_chance, crit_mult)
|
.with_effect(poise)
|
||||||
.with_effect(poise)
|
.with_effect(knockback)
|
||||||
.with_effect(knockback)
|
.with_combo_increment();
|
||||||
.with_combo_increment();
|
|
||||||
|
|
||||||
data.updater.insert(data.entity, Melee {
|
data.updater.insert(data.entity, Melee {
|
||||||
attack,
|
attack,
|
||||||
range: self.static_data.range,
|
range: self.static_data.range,
|
||||||
max_angle: self.static_data.angle.to_radians(),
|
max_angle: self.static_data.angle.to_radians(),
|
||||||
applied: false,
|
applied: false,
|
||||||
hit_count: 0,
|
hit_count: 0,
|
||||||
break_block: data
|
break_block: data
|
||||||
.inputs
|
.inputs
|
||||||
.select_pos
|
.select_pos
|
||||||
.map(|p| {
|
.map(|p| {
|
||||||
(
|
(
|
||||||
p.map(|e| e.floor() as i32),
|
p.map(|e| e.floor() as i32),
|
||||||
self.static_data.ability_info.tool,
|
self.static_data.ability_info.tool,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.filter(|(_, tool)| tool == &Some(ToolKind::Pick)),
|
.filter(|(_, tool)| tool == &Some(ToolKind::Pick)),
|
||||||
});
|
});
|
||||||
}
|
|
||||||
update.character = CharacterState::DashMelee(Data {
|
update.character = CharacterState::DashMelee(Data {
|
||||||
timer: self
|
timer: self
|
||||||
.timer
|
.timer
|
||||||
@ -185,56 +181,68 @@ impl CharacterBehavior for Data {
|
|||||||
..*self
|
..*self
|
||||||
})
|
})
|
||||||
} else if let Some(melee) = data.melee_attack {
|
} else if let Some(melee) = data.melee_attack {
|
||||||
// Creates timer ahead of time so xmac can look at line count
|
|
||||||
let timer = self
|
|
||||||
.timer
|
|
||||||
.checked_add(Duration::from_secs_f32(data.dt.0))
|
|
||||||
.unwrap_or_default();
|
|
||||||
// If melee attack has not applied yet, tick both duration and dsitance
|
|
||||||
if !melee.applied {
|
if !melee.applied {
|
||||||
|
// If melee attack has not applied, just tick duration
|
||||||
update.character = CharacterState::DashMelee(Data {
|
update.character = CharacterState::DashMelee(Data {
|
||||||
timer,
|
timer: self
|
||||||
refresh_distance: self.refresh_distance
|
.timer
|
||||||
+ data.dt.0 * data.vel.0.magnitude(),
|
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||||
|
.unwrap_or_default(),
|
||||||
..*self
|
..*self
|
||||||
})
|
});
|
||||||
// If melee attack has applied, but hit nothing, remove
|
|
||||||
// exhausted so it can attack again
|
|
||||||
} else if melee.hit_count == 0 {
|
} else if melee.hit_count == 0 {
|
||||||
|
// If melee attack has applied, but not hit anything, remove exhausted
|
||||||
|
// so it can attack again
|
||||||
update.character = CharacterState::DashMelee(Data {
|
update.character = CharacterState::DashMelee(Data {
|
||||||
timer,
|
timer: self
|
||||||
refresh_distance: 0.0,
|
.timer
|
||||||
|
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||||
|
.unwrap_or_default(),
|
||||||
exhausted: false,
|
exhausted: false,
|
||||||
..*self
|
..*self
|
||||||
})
|
});
|
||||||
// Else, melee attack applied and hit something, enter
|
} else if self.static_data.charge_through {
|
||||||
// cooldown
|
// If can charge through, set charge_end_timer to stop after a little
|
||||||
} else if self.refresh_distance < self.static_data.range {
|
// more time
|
||||||
|
let charge_end_timer =
|
||||||
|
if self.charge_end_timer != self.static_data.charge_duration {
|
||||||
|
self.charge_end_timer
|
||||||
|
} else {
|
||||||
|
self.timer
|
||||||
|
.checked_add(Duration::from_secs_f32(
|
||||||
|
0.2 * self.static_data.range
|
||||||
|
/ self.static_data.forward_speed,
|
||||||
|
))
|
||||||
|
.unwrap_or(self.static_data.charge_duration)
|
||||||
|
.min(self.static_data.charge_duration)
|
||||||
|
};
|
||||||
update.character = CharacterState::DashMelee(Data {
|
update.character = CharacterState::DashMelee(Data {
|
||||||
timer,
|
timer: self
|
||||||
refresh_distance: self.refresh_distance
|
.timer
|
||||||
+ data.dt.0 * data.vel.0.magnitude(),
|
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||||
|
.unwrap_or_default(),
|
||||||
|
charge_end_timer,
|
||||||
..*self
|
..*self
|
||||||
})
|
});
|
||||||
// Else cooldown has finished, remove exhausted
|
|
||||||
} else {
|
} else {
|
||||||
|
// Stop charging now and go to swing stage section
|
||||||
update.character = CharacterState::DashMelee(Data {
|
update.character = CharacterState::DashMelee(Data {
|
||||||
timer,
|
timer: Duration::default(),
|
||||||
refresh_distance: 0.0,
|
stage_section: StageSection::Swing,
|
||||||
exhausted: false,
|
exhausted: false,
|
||||||
..*self
|
..*self
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// If melee attack has not applied, just tick duration
|
||||||
update.character = CharacterState::DashMelee(Data {
|
update.character = CharacterState::DashMelee(Data {
|
||||||
timer: self
|
timer: self
|
||||||
.timer
|
.timer
|
||||||
.checked_add(Duration::from_secs_f32(data.dt.0))
|
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
refresh_distance: 0.0,
|
|
||||||
exhausted: false,
|
exhausted: false,
|
||||||
..*self
|
..*self
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Consumes energy if there's enough left and charge has not stopped
|
// Consumes energy if there's enough left and charge has not stopped
|
||||||
@ -247,12 +255,82 @@ impl CharacterBehavior for Data {
|
|||||||
update.character = CharacterState::DashMelee(Data {
|
update.character = CharacterState::DashMelee(Data {
|
||||||
timer: Duration::default(),
|
timer: Duration::default(),
|
||||||
stage_section: StageSection::Swing,
|
stage_section: StageSection::Swing,
|
||||||
|
exhausted: false,
|
||||||
..*self
|
..*self
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
StageSection::Swing => {
|
StageSection::Swing => {
|
||||||
if self.timer < self.static_data.swing_duration {
|
if self.static_data.charge_through && !self.exhausted {
|
||||||
|
// If can charge through and not exhausted, do one more melee attack
|
||||||
|
|
||||||
|
// Assumes charge got to charge_end_timer for damage calculations
|
||||||
|
let charge_frac = (self.charge_end_timer.as_secs_f32()
|
||||||
|
/ self.static_data.charge_duration.as_secs_f32())
|
||||||
|
.min(1.0);
|
||||||
|
|
||||||
|
let poise = AttackEffect::new(
|
||||||
|
Some(GroupTarget::OutOfGroup),
|
||||||
|
CombatEffect::Poise(
|
||||||
|
self.static_data.base_poise_damage as f32
|
||||||
|
+ charge_frac * self.static_data.scaled_poise_damage as f32,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.with_requirement(CombatRequirement::AnyDamage);
|
||||||
|
let knockback = AttackEffect::new(
|
||||||
|
Some(GroupTarget::OutOfGroup),
|
||||||
|
CombatEffect::Knockback(Knockback {
|
||||||
|
strength: self.static_data.base_knockback
|
||||||
|
+ charge_frac * self.static_data.scaled_knockback,
|
||||||
|
direction: KnockbackDir::Away,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.with_requirement(CombatRequirement::AnyDamage);
|
||||||
|
let buff = CombatEffect::Buff(CombatBuff::default_physical());
|
||||||
|
let damage = AttackDamage::new(
|
||||||
|
Damage {
|
||||||
|
source: DamageSource::Melee,
|
||||||
|
value: self.static_data.base_damage as f32
|
||||||
|
+ charge_frac * self.static_data.scaled_damage as f32,
|
||||||
|
},
|
||||||
|
Some(GroupTarget::OutOfGroup),
|
||||||
|
)
|
||||||
|
.with_effect(buff);
|
||||||
|
let (crit_chance, crit_mult) =
|
||||||
|
get_crit_data(data, self.static_data.ability_info);
|
||||||
|
let attack = Attack::default()
|
||||||
|
.with_damage(damage)
|
||||||
|
.with_crit(crit_chance, crit_mult)
|
||||||
|
.with_effect(poise)
|
||||||
|
.with_effect(knockback)
|
||||||
|
.with_combo_increment();
|
||||||
|
|
||||||
|
data.updater.insert(data.entity, Melee {
|
||||||
|
attack,
|
||||||
|
range: self.static_data.range,
|
||||||
|
max_angle: self.static_data.angle.to_radians(),
|
||||||
|
applied: false,
|
||||||
|
hit_count: 0,
|
||||||
|
break_block: data
|
||||||
|
.inputs
|
||||||
|
.select_pos
|
||||||
|
.map(|p| {
|
||||||
|
(
|
||||||
|
p.map(|e| e.floor() as i32),
|
||||||
|
self.static_data.ability_info.tool,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.filter(|(_, tool)| tool == &Some(ToolKind::Pick)),
|
||||||
|
});
|
||||||
|
update.character = CharacterState::DashMelee(Data {
|
||||||
|
timer: self
|
||||||
|
.timer
|
||||||
|
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||||
|
.unwrap_or_default(),
|
||||||
|
exhausted: true,
|
||||||
|
..*self
|
||||||
|
})
|
||||||
|
} else if self.timer < self.static_data.swing_duration {
|
||||||
// Swings
|
// Swings
|
||||||
update.character = CharacterState::DashMelee(Data {
|
update.character = CharacterState::DashMelee(Data {
|
||||||
timer: self
|
timer: self
|
||||||
|
@ -1387,7 +1387,7 @@ impl<'a> Widget for Diary<'a> {
|
|||||||
};
|
};
|
||||||
let skill = Skill::Sword(DInfinite);
|
let skill = Skill::Sword(DInfinite);
|
||||||
if create_skill_button(
|
if create_skill_button(
|
||||||
self.imgs.physical_infinite_skill,
|
self.imgs.physical_distance_skill,
|
||||||
state.skills_top_r[5],
|
state.skills_top_r[5],
|
||||||
&self.skill_set,
|
&self.skill_set,
|
||||||
skill,
|
skill,
|
||||||
@ -1396,9 +1396,13 @@ impl<'a> Widget for Diary<'a> {
|
|||||||
)
|
)
|
||||||
.with_tooltip(
|
.with_tooltip(
|
||||||
self.tooltip_manager,
|
self.tooltip_manager,
|
||||||
&self.localized_strings.get("hud.skill.sw_dash_inf_title"),
|
&self
|
||||||
|
.localized_strings
|
||||||
|
.get("hud.skill.sw_dash_charge_through_title"),
|
||||||
&add_sp_cost_tooltip(
|
&add_sp_cost_tooltip(
|
||||||
&self.localized_strings.get("hud.skill.sw_dash_inf"),
|
&self
|
||||||
|
.localized_strings
|
||||||
|
.get("hud.skill.sw_dash_charge_through"),
|
||||||
skill,
|
skill,
|
||||||
&self.skill_set,
|
&self.skill_set,
|
||||||
&self.localized_strings,
|
&self.localized_strings,
|
||||||
|
Loading…
Reference in New Issue
Block a user