mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Reworked bow
This commit is contained in:
parent
abca6de49b
commit
3f16d15bbb
@ -23,10 +23,10 @@
|
||||
],
|
||||
),
|
||||
Tool(Bow): (
|
||||
primary: "common.abilities.bow.basic",
|
||||
secondary: "common.abilities.bow.charged",
|
||||
primary: "common.abilities.bow.charged",
|
||||
secondary: "common.abilities.bow.repeater",
|
||||
abilities: [
|
||||
(Some(Bow(UnlockRepeater)), "common.abilities.bow.repeater"),
|
||||
(Some(Bow(UnlockRepeater)), "common.abilities.bow.shotgun"),
|
||||
],
|
||||
),
|
||||
Custom("Husk"): (
|
||||
|
@ -1,18 +1,19 @@
|
||||
ChargedRanged(
|
||||
energy_cost: 1,
|
||||
energy_drain: 300,
|
||||
initial_damage: 10,
|
||||
scaled_damage: 190,
|
||||
initial_knockback: 10.0,
|
||||
energy_cost: 0,
|
||||
energy_drain: 0,
|
||||
initial_regen: 50,
|
||||
scaled_regen: 150,
|
||||
initial_damage: 0,
|
||||
scaled_damage: 300,
|
||||
initial_knockback: 0.0,
|
||||
scaled_knockback: 10.0,
|
||||
speed: 1.0,
|
||||
buildup_duration: 0.1,
|
||||
charge_duration: 1.5,
|
||||
recover_duration: 0.5,
|
||||
projectile_body: Object(MultiArrow),
|
||||
buildup_duration: 0.2,
|
||||
charge_duration: 3.0,
|
||||
recover_duration: 0.3,
|
||||
projectile_body: Object(Arrow),
|
||||
projectile_light: None,
|
||||
initial_projectile_speed: 120.0,
|
||||
scaled_projectile_speed: 160.0,
|
||||
move_speed: 0.3,
|
||||
damage_kind: Piercing,
|
||||
initial_projectile_speed: 100.0,
|
||||
scaled_projectile_speed: 150.0,
|
||||
move_speed: 0.5,
|
||||
)
|
||||
|
@ -1,10 +1,10 @@
|
||||
RepeaterRanged(
|
||||
energy_cost: 450,
|
||||
movement_duration: 0.3,
|
||||
energy_cost: 50,
|
||||
buildup_duration: 0.2,
|
||||
shoot_duration: 0.2,
|
||||
shoot_duration: 1.0,
|
||||
recover_duration: 0.8,
|
||||
leap: Some(5.0),
|
||||
max_speed: 5.0,
|
||||
half_speed_at: 4,
|
||||
projectile: Arrow(
|
||||
damage: 40.0,
|
||||
knockback: 5.0,
|
||||
@ -12,6 +12,5 @@ RepeaterRanged(
|
||||
),
|
||||
projectile_body: Object(Arrow),
|
||||
projectile_light: None,
|
||||
projectile_speed: 120.0,
|
||||
reps_remaining: 3,
|
||||
projectile_speed: 100.0,
|
||||
)
|
||||
|
@ -1,13 +1,14 @@
|
||||
BasicRanged(
|
||||
energy_cost: 0,
|
||||
energy_cost: 350,
|
||||
buildup_duration: 0.4,
|
||||
recover_duration: 0.3,
|
||||
projectile: Arrow(
|
||||
damage: 90.0,
|
||||
damage: 50.0,
|
||||
knockback: 5.0,
|
||||
energy_regen: 40,
|
||||
energy_regen: 0,
|
||||
),
|
||||
projectile_body: Object(Arrow),
|
||||
projectile_light: None,
|
||||
projectile_speed: 120.0,
|
||||
projectile_speed: 60.0,
|
||||
num_projectiles: 8,
|
||||
)
|
@ -10,4 +10,5 @@ BasicRanged(
|
||||
projectile_body: Object(Arrow),
|
||||
projectile_light: None,
|
||||
projectile_speed: 100.0,
|
||||
num_projectiles: 1,
|
||||
)
|
||||
|
@ -14,4 +14,5 @@ BasicRanged(
|
||||
}),*/
|
||||
projectile_gravity: Some(Gravity(0.15)),
|
||||
projectile_speed: 60.0,
|
||||
num_projectiles: 1,
|
||||
)
|
||||
|
@ -14,4 +14,5 @@ BasicRanged(
|
||||
}),*/
|
||||
projectile_gravity: Some(Gravity(0.15)),
|
||||
projectile_speed: 60.0,
|
||||
num_projectiles: 1,
|
||||
)
|
||||
|
@ -10,4 +10,5 @@ BasicRanged(
|
||||
projectile_body: Object(ClayRocket),
|
||||
projectile_light: None,
|
||||
projectile_speed: 30.0,
|
||||
num_projectiles: 1,
|
||||
)
|
||||
|
@ -8,5 +8,6 @@ BasicRanged(
|
||||
),
|
||||
projectile_body: Object(FireworkPurple),
|
||||
projectile_speed: 100.0,
|
||||
num_projectiles: 1,
|
||||
)
|
||||
|
||||
|
@ -13,4 +13,5 @@ BasicRanged(
|
||||
..Default::default()
|
||||
}),*/
|
||||
projectile_speed: 70.0,
|
||||
num_projectiles: 1,
|
||||
)
|
||||
|
@ -10,4 +10,5 @@ BasicRanged(
|
||||
projectile_body: Object(ArrowTurret),
|
||||
projectile_light: None,
|
||||
projectile_speed: 130.0,
|
||||
num_projectiles: 1,
|
||||
)
|
||||
|
@ -12,4 +12,5 @@ BasicRanged(
|
||||
..Default::default()
|
||||
}),*/
|
||||
projectile_speed: 60.0,
|
||||
num_projectiles: 1,
|
||||
)
|
||||
|
@ -9,4 +9,5 @@ BasicRanged(
|
||||
..Default::default()
|
||||
}),*/
|
||||
projectile_speed: 100.0,
|
||||
num_projectiles: 1,
|
||||
)
|
@ -9,4 +9,5 @@ BasicRanged(
|
||||
),
|
||||
projectile_body: Object(BoltFire),
|
||||
projectile_speed: 60.0,
|
||||
num_projectiles: 1,
|
||||
)
|
||||
|
@ -13,4 +13,5 @@ BasicRanged(
|
||||
..Default::default()
|
||||
}),*/
|
||||
projectile_speed: 60.0,
|
||||
num_projectiles: 1,
|
||||
)
|
||||
|
@ -79,19 +79,19 @@ pub enum CharacterAbility {
|
||||
projectile_body: Body,
|
||||
projectile_light: Option<LightEmitter>,
|
||||
projectile_speed: f32,
|
||||
num_projectiles: u32,
|
||||
},
|
||||
RepeaterRanged {
|
||||
energy_cost: f32,
|
||||
movement_duration: f32,
|
||||
buildup_duration: f32,
|
||||
shoot_duration: f32,
|
||||
recover_duration: f32,
|
||||
leap: Option<f32>,
|
||||
max_speed: f32,
|
||||
half_speed_at: u32,
|
||||
projectile: ProjectileConstructor,
|
||||
projectile_body: Body,
|
||||
projectile_light: Option<LightEmitter>,
|
||||
projectile_speed: f32,
|
||||
reps_remaining: u32,
|
||||
},
|
||||
Boost {
|
||||
movement_duration: f32,
|
||||
@ -201,6 +201,8 @@ pub enum CharacterAbility {
|
||||
ChargedRanged {
|
||||
energy_cost: f32,
|
||||
energy_drain: f32,
|
||||
initial_regen: f32,
|
||||
scaled_regen: f32,
|
||||
initial_damage: f32,
|
||||
scaled_damage: f32,
|
||||
initial_knockback: f32,
|
||||
@ -214,7 +216,6 @@ pub enum CharacterAbility {
|
||||
initial_projectile_speed: f32,
|
||||
scaled_projectile_speed: f32,
|
||||
move_speed: f32,
|
||||
damage_kind: DamageKind,
|
||||
},
|
||||
Shockwave {
|
||||
energy_cost: f32,
|
||||
@ -340,14 +341,9 @@ impl CharacterAbility {
|
||||
.energy
|
||||
.try_change_by(-(*energy_cost as i32), EnergySource::Ability)
|
||||
.is_ok(),
|
||||
CharacterAbility::RepeaterRanged {
|
||||
energy_cost, leap, ..
|
||||
} => {
|
||||
(leap.is_none() || update.vel.0.z >= 0.0)
|
||||
&& update
|
||||
.energy
|
||||
.try_change_by(-(*energy_cost as i32), EnergySource::Ability)
|
||||
.is_ok()
|
||||
// Consumes energy within state, so value only checked before entering state
|
||||
CharacterAbility::RepeaterRanged { energy_cost, .. } => {
|
||||
update.energy.current() as f32 >= *energy_cost
|
||||
},
|
||||
CharacterAbility::LeapMelee { energy_cost, .. } => {
|
||||
update.vel.0.z >= 0.0
|
||||
@ -414,14 +410,12 @@ impl CharacterAbility {
|
||||
*projectile = projectile.modified_projectile(power, 1_f32, 1_f32);
|
||||
},
|
||||
RepeaterRanged {
|
||||
ref mut movement_duration,
|
||||
ref mut buildup_duration,
|
||||
ref mut shoot_duration,
|
||||
ref mut recover_duration,
|
||||
ref mut projectile,
|
||||
..
|
||||
} => {
|
||||
*movement_duration /= speed;
|
||||
*buildup_duration /= speed;
|
||||
*shoot_duration /= speed;
|
||||
*recover_duration /= speed;
|
||||
@ -1000,7 +994,6 @@ impl CharacterAbility {
|
||||
ref mut energy_cost,
|
||||
ref mut buildup_duration,
|
||||
ref mut projectile,
|
||||
ref mut reps_remaining,
|
||||
ref mut projectile_speed,
|
||||
..
|
||||
} => {
|
||||
@ -1014,9 +1007,6 @@ impl CharacterAbility {
|
||||
if !skillset.has_skill(Bow(RGlide)) {
|
||||
*buildup_duration = 0.001;
|
||||
}
|
||||
if let Ok(Some(level)) = skillset.skill_level(Bow(RArrows)) {
|
||||
*reps_remaining += level as u32;
|
||||
}
|
||||
if let Ok(Some(level)) = skillset.skill_level(Bow(RCost)) {
|
||||
*energy_cost *= 0.70_f32.powi(level.into());
|
||||
}
|
||||
@ -1233,6 +1223,7 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState {
|
||||
projectile_light,
|
||||
projectile_speed,
|
||||
energy_cost: _,
|
||||
num_projectiles,
|
||||
} => CharacterState::BasicRanged(basic_ranged::Data {
|
||||
static_data: basic_ranged::StaticData {
|
||||
buildup_duration: Duration::from_secs_f32(*buildup_duration),
|
||||
@ -1241,6 +1232,7 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState {
|
||||
projectile_body: *projectile_body,
|
||||
projectile_light: *projectile_light,
|
||||
projectile_speed: *projectile_speed,
|
||||
num_projectiles: *num_projectiles,
|
||||
ability_info,
|
||||
},
|
||||
timer: Duration::default(),
|
||||
@ -1500,6 +1492,8 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState {
|
||||
CharacterAbility::ChargedRanged {
|
||||
energy_cost: _,
|
||||
energy_drain,
|
||||
initial_regen,
|
||||
scaled_regen,
|
||||
initial_damage,
|
||||
scaled_damage,
|
||||
initial_knockback,
|
||||
@ -1513,13 +1507,14 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState {
|
||||
initial_projectile_speed,
|
||||
scaled_projectile_speed,
|
||||
move_speed,
|
||||
damage_kind,
|
||||
} => CharacterState::ChargedRanged(charged_ranged::Data {
|
||||
static_data: charged_ranged::StaticData {
|
||||
buildup_duration: Duration::from_secs_f32(*buildup_duration),
|
||||
charge_duration: Duration::from_secs_f32(*charge_duration),
|
||||
recover_duration: Duration::from_secs_f32(*recover_duration),
|
||||
energy_drain: *energy_drain,
|
||||
initial_regen: *initial_regen,
|
||||
scaled_regen: *scaled_regen,
|
||||
initial_damage: *initial_damage,
|
||||
scaled_damage: *scaled_damage,
|
||||
speed: *speed,
|
||||
@ -1531,31 +1526,31 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState {
|
||||
scaled_projectile_speed: *scaled_projectile_speed,
|
||||
move_speed: *move_speed,
|
||||
ability_info,
|
||||
damage_kind: *damage_kind,
|
||||
},
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Buildup,
|
||||
exhausted: false,
|
||||
}),
|
||||
CharacterAbility::RepeaterRanged {
|
||||
energy_cost: _,
|
||||
movement_duration,
|
||||
energy_cost,
|
||||
buildup_duration,
|
||||
shoot_duration,
|
||||
recover_duration,
|
||||
leap,
|
||||
max_speed,
|
||||
half_speed_at,
|
||||
projectile,
|
||||
projectile_body,
|
||||
projectile_light,
|
||||
projectile_speed,
|
||||
reps_remaining,
|
||||
} => CharacterState::RepeaterRanged(repeater_ranged::Data {
|
||||
static_data: repeater_ranged::StaticData {
|
||||
movement_duration: Duration::from_secs_f32(*movement_duration),
|
||||
buildup_duration: Duration::from_secs_f32(*buildup_duration),
|
||||
shoot_duration: Duration::from_secs_f32(*shoot_duration),
|
||||
recover_duration: Duration::from_secs_f32(*recover_duration),
|
||||
leap: *leap,
|
||||
energy_cost: *energy_cost,
|
||||
// 1.0 is subtracted as 1.0 is added in state file
|
||||
max_speed: *max_speed - 1.0,
|
||||
half_speed_at: *half_speed_at,
|
||||
projectile: *projectile,
|
||||
projectile_body: *projectile_body,
|
||||
projectile_light: *projectile_light,
|
||||
@ -1563,8 +1558,9 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState {
|
||||
ability_info,
|
||||
},
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Movement,
|
||||
reps_remaining: *reps_remaining,
|
||||
stage_section: StageSection::Buildup,
|
||||
projectiles_fired: 0,
|
||||
speed: 1.0,
|
||||
}),
|
||||
CharacterAbility::Shockwave {
|
||||
energy_cost: _,
|
||||
|
@ -12,7 +12,7 @@ use specs::Component;
|
||||
use specs_idvs::IdvStorage;
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum Effect {
|
||||
Attack(Attack),
|
||||
Explode(Explosion),
|
||||
@ -21,7 +21,7 @@ pub enum Effect {
|
||||
Possess,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Projectile {
|
||||
// TODO: use SmallVec for these effects
|
||||
pub hit_solid: Vec<Effect>,
|
||||
|
@ -5,7 +5,9 @@ use crate::{
|
||||
behavior::{CharacterBehavior, JoinData},
|
||||
utils::*,
|
||||
},
|
||||
util::Dir,
|
||||
};
|
||||
use rand::{thread_rng, Rng};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
|
||||
@ -21,6 +23,8 @@ pub struct StaticData {
|
||||
pub projectile_body: Body,
|
||||
pub projectile_light: Option<LightEmitter>,
|
||||
pub projectile_speed: f32,
|
||||
/// How many projectiles are simultaneously fired
|
||||
pub num_projectiles: u32,
|
||||
/// What key is used to press ability
|
||||
pub ability_info: AbilityInfo,
|
||||
}
|
||||
@ -76,15 +80,22 @@ impl CharacterBehavior for Data {
|
||||
crit_chance,
|
||||
crit_mult,
|
||||
);
|
||||
for i in 0..self.static_data.num_projectiles {
|
||||
let dir = Dir::from_unnormalized(data.inputs.look_dir.map(|x| {
|
||||
let offset = (2.0 * thread_rng().gen::<f32>() - 1.0) * 0.03 * i as f32;
|
||||
x + offset
|
||||
}))
|
||||
.unwrap_or(data.inputs.look_dir);
|
||||
update.server_events.push_front(ServerEvent::Shoot {
|
||||
entity: data.entity,
|
||||
dir: data.inputs.look_dir,
|
||||
dir,
|
||||
body: self.static_data.projectile_body,
|
||||
projectile,
|
||||
projectile: projectile.clone(),
|
||||
light: self.static_data.projectile_light,
|
||||
speed: self.static_data.projectile_speed,
|
||||
object: None,
|
||||
});
|
||||
}
|
||||
|
||||
update.character = CharacterState::BasicRanged(Data {
|
||||
exhausted: true,
|
||||
|
@ -1,11 +1,7 @@
|
||||
use crate::{
|
||||
combat::{
|
||||
Attack, AttackDamage, AttackEffect, CombatBuff, CombatEffect, CombatRequirement, Damage,
|
||||
DamageKind, DamageSource, GroupTarget, Knockback, KnockbackDir,
|
||||
},
|
||||
comp::{
|
||||
projectile, Body, CharacterState, EnergyChange, EnergySource, LightEmitter, Projectile,
|
||||
StateUpdate,
|
||||
projectile::ProjectileConstructor, Body, CharacterState, EnergyChange, EnergySource,
|
||||
LightEmitter, StateUpdate,
|
||||
},
|
||||
event::ServerEvent,
|
||||
states::{
|
||||
@ -27,6 +23,10 @@ pub struct StaticData {
|
||||
pub recover_duration: Duration,
|
||||
/// How much energy is drained per second when charging
|
||||
pub energy_drain: f32,
|
||||
/// How much energy is gained with no charge
|
||||
pub initial_regen: f32,
|
||||
/// How much the energy gain scales as it is charged
|
||||
pub scaled_regen: f32,
|
||||
/// How much damage is dealt with no charge
|
||||
pub initial_damage: f32,
|
||||
/// How much the damage scales as it is charged
|
||||
@ -46,8 +46,6 @@ pub struct StaticData {
|
||||
pub move_speed: f32,
|
||||
/// What key is used to press ability
|
||||
pub ability_info: AbilityInfo,
|
||||
/// What kind of damage the attack does
|
||||
pub damage_kind: DamageKind,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
@ -96,45 +94,19 @@ impl CharacterBehavior for Data {
|
||||
let charge_frac = (self.timer.as_secs_f32()
|
||||
/ self.static_data.charge_duration.as_secs_f32())
|
||||
.min(1.0);
|
||||
let knockback = AttackEffect::new(
|
||||
Some(GroupTarget::OutOfGroup),
|
||||
CombatEffect::Knockback(Knockback {
|
||||
strength: self.static_data.initial_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::Projectile,
|
||||
kind: self.static_data.damage_kind,
|
||||
value: self.static_data.initial_damage as f32
|
||||
let arrow = ProjectileConstructor::Arrow {
|
||||
damage: self.static_data.initial_damage as f32
|
||||
+ charge_frac * self.static_data.scaled_damage as f32,
|
||||
},
|
||||
Some(GroupTarget::OutOfGroup),
|
||||
)
|
||||
.with_effect(buff);
|
||||
knockback: self.static_data.initial_knockback
|
||||
+ charge_frac * self.static_data.scaled_knockback,
|
||||
energy_regen: self.static_data.initial_regen
|
||||
+ charge_frac * self.static_data.scaled_regen,
|
||||
};
|
||||
// Fire
|
||||
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(knockback)
|
||||
.with_combo_increment();
|
||||
|
||||
// Fire
|
||||
let projectile = Projectile {
|
||||
hit_solid: vec![projectile::Effect::Stick],
|
||||
hit_entity: vec![
|
||||
projectile::Effect::Attack(attack),
|
||||
projectile::Effect::Vanish,
|
||||
],
|
||||
time_left: Duration::from_secs(15),
|
||||
owner: Some(*data.uid),
|
||||
ignore_group: true,
|
||||
};
|
||||
let projectile =
|
||||
arrow.create_projectile(Some(*data.uid), crit_chance, crit_mult);
|
||||
update.server_events.push_front(ServerEvent::Shoot {
|
||||
entity: data.entity,
|
||||
dir: data.inputs.look_dir,
|
||||
@ -166,7 +138,7 @@ impl CharacterBehavior for Data {
|
||||
..*self
|
||||
});
|
||||
|
||||
// Consumes energy if there's enough left and RMB is held down
|
||||
// Consumes energy if there's enough left and input is held down
|
||||
update.energy.change_by(EnergyChange {
|
||||
amount: -(self.static_data.energy_drain as f32
|
||||
* data.dt.0
|
||||
|
@ -1,29 +1,32 @@
|
||||
use crate::{
|
||||
comp::{Body, CharacterState, LightEmitter, ProjectileConstructor, StateUpdate},
|
||||
comp::{
|
||||
Body, CharacterState, EnergyChange, EnergySource, LightEmitter, ProjectileConstructor,
|
||||
StateUpdate,
|
||||
},
|
||||
event::ServerEvent,
|
||||
states::{
|
||||
behavior::{CharacterBehavior, JoinData},
|
||||
utils::{StageSection, *},
|
||||
},
|
||||
util::dir::*,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use vek::Vec3;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||
/// Separated out to condense update portions of character state
|
||||
pub struct StaticData {
|
||||
/// How long the state is in movement
|
||||
pub movement_duration: Duration,
|
||||
/// How long we've readied the weapon
|
||||
pub buildup_duration: Duration,
|
||||
/// How long the state is shooting
|
||||
pub shoot_duration: Duration,
|
||||
/// How long the state has until exiting
|
||||
pub recover_duration: Duration,
|
||||
/// Whether there should be a jump and how strong the leap is
|
||||
pub leap: Option<f32>,
|
||||
/// Energy cost per projectile
|
||||
pub energy_cost: f32,
|
||||
/// Max speed that can be reached
|
||||
pub max_speed: f32,
|
||||
/// Projectiles required to reach half of max speed
|
||||
pub half_speed_at: u32,
|
||||
/// Projectile options
|
||||
pub projectile: ProjectileConstructor,
|
||||
pub projectile_body: Body,
|
||||
@ -42,64 +45,20 @@ pub struct Data {
|
||||
pub timer: Duration,
|
||||
/// What section the character stage is in
|
||||
pub stage_section: StageSection,
|
||||
/// How many repetitions remaining
|
||||
pub reps_remaining: u32,
|
||||
/// Speed of the state while in shoot section
|
||||
pub speed: f32,
|
||||
/// Number of projectiles fired so far
|
||||
pub projectiles_fired: u32,
|
||||
}
|
||||
|
||||
impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
handle_orientation(data, &mut update, 1.0);
|
||||
handle_move(data, &mut update, 1.0);
|
||||
handle_jump(data, &mut update, 1.0);
|
||||
handle_move(data, &mut update, 0.1);
|
||||
|
||||
match self.stage_section {
|
||||
StageSection::Movement => {
|
||||
// Jumping
|
||||
if let Some(leap_strength) = self.static_data.leap {
|
||||
let progress = 1.0
|
||||
- self.timer.as_secs_f32()
|
||||
/ self.static_data.movement_duration.as_secs_f32();
|
||||
handle_forced_movement(
|
||||
data,
|
||||
&mut update,
|
||||
ForcedMovement::Leap {
|
||||
vertical: leap_strength,
|
||||
forward: 10.0,
|
||||
progress,
|
||||
direction: MovementDirection::Move,
|
||||
},
|
||||
1.0,
|
||||
);
|
||||
}
|
||||
if self.timer < self.static_data.movement_duration {
|
||||
// Do movement
|
||||
update.character = CharacterState::RepeaterRanged(Data {
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
..*self
|
||||
});
|
||||
} else {
|
||||
// Transition to buildup
|
||||
update.character = CharacterState::RepeaterRanged(Data {
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Buildup,
|
||||
..*self
|
||||
});
|
||||
}
|
||||
},
|
||||
StageSection::Buildup => {
|
||||
// Aim gliding
|
||||
if self.static_data.leap.is_some() {
|
||||
handle_forced_movement(
|
||||
data,
|
||||
&mut update,
|
||||
ForcedMovement::Hover { move_input: 0.1 },
|
||||
1.0,
|
||||
);
|
||||
}
|
||||
if self.timer < self.static_data.buildup_duration {
|
||||
// Buildup to attack
|
||||
update.character = CharacterState::RepeaterRanged(Data {
|
||||
@ -119,12 +78,19 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
},
|
||||
StageSection::Shoot => {
|
||||
// Aim gliding
|
||||
if self.static_data.leap.is_some() {
|
||||
update.vel.0 = Vec3::new(data.vel.0.x, data.vel.0.y, 0.0);
|
||||
}
|
||||
if self.reps_remaining > 0 {
|
||||
// Fire
|
||||
if self.timer < self.static_data.shoot_duration {
|
||||
// Draw projectile
|
||||
update.character = CharacterState::RepeaterRanged(Data {
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(data.dt.0 * self.speed))
|
||||
.unwrap_or_default(),
|
||||
..*self
|
||||
});
|
||||
} else if input_is_pressed(data, self.static_data.ability_info.input)
|
||||
&& update.energy.current() as f32 >= self.static_data.energy_cost
|
||||
{
|
||||
// Fire if input is pressed still
|
||||
let (crit_chance, crit_mult) =
|
||||
get_crit_data(data, self.static_data.ability_info);
|
||||
let projectile = self.static_data.projectile.create_projectile(
|
||||
@ -135,22 +101,7 @@ impl CharacterBehavior for Data {
|
||||
update.server_events.push_front(ServerEvent::Shoot {
|
||||
entity: data.entity,
|
||||
// Provides slight variation to projectile direction
|
||||
dir: Dir::from_unnormalized(Vec3::new(
|
||||
data.inputs.look_dir[0]
|
||||
+ (if self.reps_remaining % 2 == 0 {
|
||||
self.reps_remaining as f32 / 400.0
|
||||
} else {
|
||||
-1.0 * self.reps_remaining as f32 / 400.0
|
||||
}),
|
||||
data.inputs.look_dir[1]
|
||||
+ (if self.reps_remaining % 2 == 0 {
|
||||
-1.0 * self.reps_remaining as f32 / 400.0
|
||||
} else {
|
||||
self.reps_remaining as f32 / 400.0
|
||||
}),
|
||||
data.inputs.look_dir[2],
|
||||
))
|
||||
.unwrap_or(data.inputs.look_dir),
|
||||
dir: data.inputs.look_dir,
|
||||
body: self.static_data.projectile_body,
|
||||
projectile,
|
||||
light: self.static_data.projectile_light,
|
||||
@ -158,22 +109,24 @@ impl CharacterBehavior for Data {
|
||||
object: None,
|
||||
});
|
||||
|
||||
// Shoot projectiles
|
||||
update.character = CharacterState::RepeaterRanged(Data {
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
reps_remaining: self.reps_remaining - 1,
|
||||
..*self
|
||||
update.server_events.push_front(ServerEvent::EnergyChange {
|
||||
entity: data.entity,
|
||||
change: EnergyChange {
|
||||
amount: -self.static_data.energy_cost as i32,
|
||||
source: EnergySource::Ability,
|
||||
},
|
||||
});
|
||||
} else if self.timer < self.static_data.shoot_duration {
|
||||
// Finish shooting
|
||||
|
||||
let new_speed = 1.0
|
||||
+ self.projectiles_fired as f32
|
||||
/ (self.static_data.half_speed_at as f32
|
||||
+ self.projectiles_fired as f32)
|
||||
* self.static_data.max_speed;
|
||||
|
||||
update.character = CharacterState::RepeaterRanged(Data {
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
timer: Duration::default(),
|
||||
speed: new_speed,
|
||||
projectiles_fired: self.projectiles_fired + 1,
|
||||
..*self
|
||||
});
|
||||
} else {
|
||||
@ -186,10 +139,7 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
},
|
||||
StageSection::Recover => {
|
||||
if self.static_data.leap.is_some() && data.physics.on_ground {
|
||||
// Done
|
||||
update.character = CharacterState::Wielding;
|
||||
} else if self.timer < self.static_data.recover_duration {
|
||||
if self.timer < self.static_data.recover_duration {
|
||||
// Recover from attack
|
||||
update.character = CharacterState::RepeaterRanged(Data {
|
||||
timer: self
|
||||
|
@ -1015,9 +1015,6 @@ impl FigureMgr {
|
||||
StageSection::Buildup => {
|
||||
stage_time / s.static_data.buildup_duration.as_secs_f32()
|
||||
},
|
||||
StageSection::Movement => {
|
||||
stage_time / s.static_data.movement_duration.as_secs_f32()
|
||||
},
|
||||
StageSection::Shoot => {
|
||||
stage_time / s.static_data.shoot_duration.as_secs_f32()
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user