Reworked bow

This commit is contained in:
Sam 2021-05-15 22:09:39 -05:00
parent abca6de49b
commit 3f16d15bbb
21 changed files with 148 additions and 210 deletions

View File

@ -23,10 +23,10 @@
], ],
), ),
Tool(Bow): ( Tool(Bow): (
primary: "common.abilities.bow.basic", primary: "common.abilities.bow.charged",
secondary: "common.abilities.bow.charged", secondary: "common.abilities.bow.repeater",
abilities: [ abilities: [
(Some(Bow(UnlockRepeater)), "common.abilities.bow.repeater"), (Some(Bow(UnlockRepeater)), "common.abilities.bow.shotgun"),
], ],
), ),
Custom("Husk"): ( Custom("Husk"): (

View File

@ -1,18 +1,19 @@
ChargedRanged( ChargedRanged(
energy_cost: 1, energy_cost: 0,
energy_drain: 300, energy_drain: 0,
initial_damage: 10, initial_regen: 50,
scaled_damage: 190, scaled_regen: 150,
initial_knockback: 10.0, initial_damage: 0,
scaled_damage: 300,
initial_knockback: 0.0,
scaled_knockback: 10.0, scaled_knockback: 10.0,
speed: 1.0, speed: 1.0,
buildup_duration: 0.1, buildup_duration: 0.2,
charge_duration: 1.5, charge_duration: 3.0,
recover_duration: 0.5, recover_duration: 0.3,
projectile_body: Object(MultiArrow), projectile_body: Object(Arrow),
projectile_light: None, projectile_light: None,
initial_projectile_speed: 120.0, initial_projectile_speed: 100.0,
scaled_projectile_speed: 160.0, scaled_projectile_speed: 150.0,
move_speed: 0.3, move_speed: 0.5,
damage_kind: Piercing,
) )

View File

@ -1,10 +1,10 @@
RepeaterRanged( RepeaterRanged(
energy_cost: 450, energy_cost: 50,
movement_duration: 0.3,
buildup_duration: 0.2, buildup_duration: 0.2,
shoot_duration: 0.2, shoot_duration: 1.0,
recover_duration: 0.8, recover_duration: 0.8,
leap: Some(5.0), max_speed: 5.0,
half_speed_at: 4,
projectile: Arrow( projectile: Arrow(
damage: 40.0, damage: 40.0,
knockback: 5.0, knockback: 5.0,
@ -12,6 +12,5 @@ RepeaterRanged(
), ),
projectile_body: Object(Arrow), projectile_body: Object(Arrow),
projectile_light: None, projectile_light: None,
projectile_speed: 120.0, projectile_speed: 100.0,
reps_remaining: 3,
) )

View File

@ -1,13 +1,14 @@
BasicRanged( BasicRanged(
energy_cost: 0, energy_cost: 350,
buildup_duration: 0.4, buildup_duration: 0.4,
recover_duration: 0.3, recover_duration: 0.3,
projectile: Arrow( projectile: Arrow(
damage: 90.0, damage: 50.0,
knockback: 5.0, knockback: 5.0,
energy_regen: 40, energy_regen: 0,
), ),
projectile_body: Object(Arrow), projectile_body: Object(Arrow),
projectile_light: None, projectile_light: None,
projectile_speed: 120.0, projectile_speed: 60.0,
num_projectiles: 8,
) )

View File

@ -10,4 +10,5 @@ BasicRanged(
projectile_body: Object(Arrow), projectile_body: Object(Arrow),
projectile_light: None, projectile_light: None,
projectile_speed: 100.0, projectile_speed: 100.0,
num_projectiles: 1,
) )

View File

@ -14,4 +14,5 @@ BasicRanged(
}),*/ }),*/
projectile_gravity: Some(Gravity(0.15)), projectile_gravity: Some(Gravity(0.15)),
projectile_speed: 60.0, projectile_speed: 60.0,
num_projectiles: 1,
) )

View File

@ -14,4 +14,5 @@ BasicRanged(
}),*/ }),*/
projectile_gravity: Some(Gravity(0.15)), projectile_gravity: Some(Gravity(0.15)),
projectile_speed: 60.0, projectile_speed: 60.0,
num_projectiles: 1,
) )

View File

@ -10,4 +10,5 @@ BasicRanged(
projectile_body: Object(ClayRocket), projectile_body: Object(ClayRocket),
projectile_light: None, projectile_light: None,
projectile_speed: 30.0, projectile_speed: 30.0,
num_projectiles: 1,
) )

View File

@ -8,5 +8,6 @@ BasicRanged(
), ),
projectile_body: Object(FireworkPurple), projectile_body: Object(FireworkPurple),
projectile_speed: 100.0, projectile_speed: 100.0,
num_projectiles: 1,
) )

View File

@ -13,4 +13,5 @@ BasicRanged(
..Default::default() ..Default::default()
}),*/ }),*/
projectile_speed: 70.0, projectile_speed: 70.0,
num_projectiles: 1,
) )

View File

@ -10,4 +10,5 @@ BasicRanged(
projectile_body: Object(ArrowTurret), projectile_body: Object(ArrowTurret),
projectile_light: None, projectile_light: None,
projectile_speed: 130.0, projectile_speed: 130.0,
num_projectiles: 1,
) )

View File

@ -12,4 +12,5 @@ BasicRanged(
..Default::default() ..Default::default()
}),*/ }),*/
projectile_speed: 60.0, projectile_speed: 60.0,
num_projectiles: 1,
) )

View File

@ -9,4 +9,5 @@ BasicRanged(
..Default::default() ..Default::default()
}),*/ }),*/
projectile_speed: 100.0, projectile_speed: 100.0,
num_projectiles: 1,
) )

View File

@ -9,4 +9,5 @@ BasicRanged(
), ),
projectile_body: Object(BoltFire), projectile_body: Object(BoltFire),
projectile_speed: 60.0, projectile_speed: 60.0,
num_projectiles: 1,
) )

View File

@ -13,4 +13,5 @@ BasicRanged(
..Default::default() ..Default::default()
}),*/ }),*/
projectile_speed: 60.0, projectile_speed: 60.0,
num_projectiles: 1,
) )

View File

@ -79,19 +79,19 @@ pub enum CharacterAbility {
projectile_body: Body, projectile_body: Body,
projectile_light: Option<LightEmitter>, projectile_light: Option<LightEmitter>,
projectile_speed: f32, projectile_speed: f32,
num_projectiles: u32,
}, },
RepeaterRanged { RepeaterRanged {
energy_cost: f32, energy_cost: f32,
movement_duration: f32,
buildup_duration: f32, buildup_duration: f32,
shoot_duration: f32, shoot_duration: f32,
recover_duration: f32, recover_duration: f32,
leap: Option<f32>, max_speed: f32,
half_speed_at: u32,
projectile: ProjectileConstructor, projectile: ProjectileConstructor,
projectile_body: Body, projectile_body: Body,
projectile_light: Option<LightEmitter>, projectile_light: Option<LightEmitter>,
projectile_speed: f32, projectile_speed: f32,
reps_remaining: u32,
}, },
Boost { Boost {
movement_duration: f32, movement_duration: f32,
@ -201,6 +201,8 @@ pub enum CharacterAbility {
ChargedRanged { ChargedRanged {
energy_cost: f32, energy_cost: f32,
energy_drain: f32, energy_drain: f32,
initial_regen: f32,
scaled_regen: f32,
initial_damage: f32, initial_damage: f32,
scaled_damage: f32, scaled_damage: f32,
initial_knockback: f32, initial_knockback: f32,
@ -214,7 +216,6 @@ pub enum CharacterAbility {
initial_projectile_speed: f32, initial_projectile_speed: f32,
scaled_projectile_speed: f32, scaled_projectile_speed: f32,
move_speed: f32, move_speed: f32,
damage_kind: DamageKind,
}, },
Shockwave { Shockwave {
energy_cost: f32, energy_cost: f32,
@ -340,14 +341,9 @@ impl CharacterAbility {
.energy .energy
.try_change_by(-(*energy_cost as i32), EnergySource::Ability) .try_change_by(-(*energy_cost as i32), EnergySource::Ability)
.is_ok(), .is_ok(),
CharacterAbility::RepeaterRanged { // Consumes energy within state, so value only checked before entering state
energy_cost, leap, .. CharacterAbility::RepeaterRanged { energy_cost, .. } => {
} => { update.energy.current() as f32 >= *energy_cost
(leap.is_none() || update.vel.0.z >= 0.0)
&& update
.energy
.try_change_by(-(*energy_cost as i32), EnergySource::Ability)
.is_ok()
}, },
CharacterAbility::LeapMelee { energy_cost, .. } => { CharacterAbility::LeapMelee { energy_cost, .. } => {
update.vel.0.z >= 0.0 update.vel.0.z >= 0.0
@ -414,14 +410,12 @@ impl CharacterAbility {
*projectile = projectile.modified_projectile(power, 1_f32, 1_f32); *projectile = projectile.modified_projectile(power, 1_f32, 1_f32);
}, },
RepeaterRanged { RepeaterRanged {
ref mut movement_duration,
ref mut buildup_duration, ref mut buildup_duration,
ref mut shoot_duration, ref mut shoot_duration,
ref mut recover_duration, ref mut recover_duration,
ref mut projectile, ref mut projectile,
.. ..
} => { } => {
*movement_duration /= speed;
*buildup_duration /= speed; *buildup_duration /= speed;
*shoot_duration /= speed; *shoot_duration /= speed;
*recover_duration /= speed; *recover_duration /= speed;
@ -1000,7 +994,6 @@ impl CharacterAbility {
ref mut energy_cost, ref mut energy_cost,
ref mut buildup_duration, ref mut buildup_duration,
ref mut projectile, ref mut projectile,
ref mut reps_remaining,
ref mut projectile_speed, ref mut projectile_speed,
.. ..
} => { } => {
@ -1014,9 +1007,6 @@ impl CharacterAbility {
if !skillset.has_skill(Bow(RGlide)) { if !skillset.has_skill(Bow(RGlide)) {
*buildup_duration = 0.001; *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)) { if let Ok(Some(level)) = skillset.skill_level(Bow(RCost)) {
*energy_cost *= 0.70_f32.powi(level.into()); *energy_cost *= 0.70_f32.powi(level.into());
} }
@ -1233,6 +1223,7 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState {
projectile_light, projectile_light,
projectile_speed, projectile_speed,
energy_cost: _, energy_cost: _,
num_projectiles,
} => CharacterState::BasicRanged(basic_ranged::Data { } => CharacterState::BasicRanged(basic_ranged::Data {
static_data: basic_ranged::StaticData { static_data: basic_ranged::StaticData {
buildup_duration: Duration::from_secs_f32(*buildup_duration), buildup_duration: Duration::from_secs_f32(*buildup_duration),
@ -1241,6 +1232,7 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState {
projectile_body: *projectile_body, projectile_body: *projectile_body,
projectile_light: *projectile_light, projectile_light: *projectile_light,
projectile_speed: *projectile_speed, projectile_speed: *projectile_speed,
num_projectiles: *num_projectiles,
ability_info, ability_info,
}, },
timer: Duration::default(), timer: Duration::default(),
@ -1500,6 +1492,8 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState {
CharacterAbility::ChargedRanged { CharacterAbility::ChargedRanged {
energy_cost: _, energy_cost: _,
energy_drain, energy_drain,
initial_regen,
scaled_regen,
initial_damage, initial_damage,
scaled_damage, scaled_damage,
initial_knockback, initial_knockback,
@ -1513,13 +1507,14 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState {
initial_projectile_speed, initial_projectile_speed,
scaled_projectile_speed, scaled_projectile_speed,
move_speed, move_speed,
damage_kind,
} => CharacterState::ChargedRanged(charged_ranged::Data { } => CharacterState::ChargedRanged(charged_ranged::Data {
static_data: charged_ranged::StaticData { static_data: charged_ranged::StaticData {
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),
recover_duration: Duration::from_secs_f32(*recover_duration), recover_duration: Duration::from_secs_f32(*recover_duration),
energy_drain: *energy_drain, energy_drain: *energy_drain,
initial_regen: *initial_regen,
scaled_regen: *scaled_regen,
initial_damage: *initial_damage, initial_damage: *initial_damage,
scaled_damage: *scaled_damage, scaled_damage: *scaled_damage,
speed: *speed, speed: *speed,
@ -1531,31 +1526,31 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState {
scaled_projectile_speed: *scaled_projectile_speed, scaled_projectile_speed: *scaled_projectile_speed,
move_speed: *move_speed, move_speed: *move_speed,
ability_info, ability_info,
damage_kind: *damage_kind,
}, },
timer: Duration::default(), timer: Duration::default(),
stage_section: StageSection::Buildup, stage_section: StageSection::Buildup,
exhausted: false, exhausted: false,
}), }),
CharacterAbility::RepeaterRanged { CharacterAbility::RepeaterRanged {
energy_cost: _, energy_cost,
movement_duration,
buildup_duration, buildup_duration,
shoot_duration, shoot_duration,
recover_duration, recover_duration,
leap, max_speed,
half_speed_at,
projectile, projectile,
projectile_body, projectile_body,
projectile_light, projectile_light,
projectile_speed, projectile_speed,
reps_remaining,
} => CharacterState::RepeaterRanged(repeater_ranged::Data { } => CharacterState::RepeaterRanged(repeater_ranged::Data {
static_data: repeater_ranged::StaticData { static_data: repeater_ranged::StaticData {
movement_duration: Duration::from_secs_f32(*movement_duration),
buildup_duration: Duration::from_secs_f32(*buildup_duration), buildup_duration: Duration::from_secs_f32(*buildup_duration),
shoot_duration: Duration::from_secs_f32(*shoot_duration), shoot_duration: Duration::from_secs_f32(*shoot_duration),
recover_duration: Duration::from_secs_f32(*recover_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: *projectile,
projectile_body: *projectile_body, projectile_body: *projectile_body,
projectile_light: *projectile_light, projectile_light: *projectile_light,
@ -1563,8 +1558,9 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState {
ability_info, ability_info,
}, },
timer: Duration::default(), timer: Duration::default(),
stage_section: StageSection::Movement, stage_section: StageSection::Buildup,
reps_remaining: *reps_remaining, projectiles_fired: 0,
speed: 1.0,
}), }),
CharacterAbility::Shockwave { CharacterAbility::Shockwave {
energy_cost: _, energy_cost: _,

View File

@ -12,7 +12,7 @@ use specs::Component;
use specs_idvs::IdvStorage; use specs_idvs::IdvStorage;
use std::time::Duration; use std::time::Duration;
#[derive(Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub enum Effect { pub enum Effect {
Attack(Attack), Attack(Attack),
Explode(Explosion), Explode(Explosion),
@ -21,7 +21,7 @@ pub enum Effect {
Possess, Possess,
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Projectile { pub struct Projectile {
// TODO: use SmallVec for these effects // TODO: use SmallVec for these effects
pub hit_solid: Vec<Effect>, pub hit_solid: Vec<Effect>,

View File

@ -5,7 +5,9 @@ use crate::{
behavior::{CharacterBehavior, JoinData}, behavior::{CharacterBehavior, JoinData},
utils::*, utils::*,
}, },
util::Dir,
}; };
use rand::{thread_rng, Rng};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::time::Duration; use std::time::Duration;
@ -21,6 +23,8 @@ pub struct StaticData {
pub projectile_body: Body, pub projectile_body: Body,
pub projectile_light: Option<LightEmitter>, pub projectile_light: Option<LightEmitter>,
pub projectile_speed: f32, pub projectile_speed: f32,
/// How many projectiles are simultaneously fired
pub num_projectiles: u32,
/// What key is used to press ability /// What key is used to press ability
pub ability_info: AbilityInfo, pub ability_info: AbilityInfo,
} }
@ -76,15 +80,22 @@ impl CharacterBehavior for Data {
crit_chance, crit_chance,
crit_mult, 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 { update.server_events.push_front(ServerEvent::Shoot {
entity: data.entity, entity: data.entity,
dir: data.inputs.look_dir, dir,
body: self.static_data.projectile_body, body: self.static_data.projectile_body,
projectile, projectile: projectile.clone(),
light: self.static_data.projectile_light, light: self.static_data.projectile_light,
speed: self.static_data.projectile_speed, speed: self.static_data.projectile_speed,
object: None, object: None,
}); });
}
update.character = CharacterState::BasicRanged(Data { update.character = CharacterState::BasicRanged(Data {
exhausted: true, exhausted: true,

View File

@ -1,11 +1,7 @@
use crate::{ use crate::{
combat::{
Attack, AttackDamage, AttackEffect, CombatBuff, CombatEffect, CombatRequirement, Damage,
DamageKind, DamageSource, GroupTarget, Knockback, KnockbackDir,
},
comp::{ comp::{
projectile, Body, CharacterState, EnergyChange, EnergySource, LightEmitter, Projectile, projectile::ProjectileConstructor, Body, CharacterState, EnergyChange, EnergySource,
StateUpdate, LightEmitter, StateUpdate,
}, },
event::ServerEvent, event::ServerEvent,
states::{ states::{
@ -27,6 +23,10 @@ pub struct StaticData {
pub recover_duration: Duration, pub recover_duration: Duration,
/// How much energy is drained per second when charging /// How much energy is drained per second when charging
pub energy_drain: f32, 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 /// How much damage is dealt with no charge
pub initial_damage: f32, pub initial_damage: f32,
/// How much the damage scales as it is charged /// How much the damage scales as it is charged
@ -46,8 +46,6 @@ pub struct StaticData {
pub move_speed: f32, pub move_speed: f32,
/// What key is used to press ability /// What key is used to press ability
pub ability_info: AbilityInfo, pub ability_info: AbilityInfo,
/// What kind of damage the attack does
pub damage_kind: DamageKind,
} }
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
@ -96,45 +94,19 @@ impl CharacterBehavior for Data {
let charge_frac = (self.timer.as_secs_f32() let charge_frac = (self.timer.as_secs_f32()
/ self.static_data.charge_duration.as_secs_f32()) / self.static_data.charge_duration.as_secs_f32())
.min(1.0); .min(1.0);
let knockback = AttackEffect::new( let arrow = ProjectileConstructor::Arrow {
Some(GroupTarget::OutOfGroup), damage: self.static_data.initial_damage as f32
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
+ charge_frac * self.static_data.scaled_damage as f32, + charge_frac * self.static_data.scaled_damage as f32,
}, knockback: self.static_data.initial_knockback
Some(GroupTarget::OutOfGroup), + charge_frac * self.static_data.scaled_knockback,
) energy_regen: self.static_data.initial_regen
.with_effect(buff); + charge_frac * self.static_data.scaled_regen,
};
// Fire
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 projectile =
.with_damage(damage) arrow.create_projectile(Some(*data.uid), crit_chance, crit_mult);
.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,
};
update.server_events.push_front(ServerEvent::Shoot { update.server_events.push_front(ServerEvent::Shoot {
entity: data.entity, entity: data.entity,
dir: data.inputs.look_dir, dir: data.inputs.look_dir,
@ -166,7 +138,7 @@ impl CharacterBehavior for Data {
..*self ..*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 { update.energy.change_by(EnergyChange {
amount: -(self.static_data.energy_drain as f32 amount: -(self.static_data.energy_drain as f32
* data.dt.0 * data.dt.0

View File

@ -1,29 +1,32 @@
use crate::{ use crate::{
comp::{Body, CharacterState, LightEmitter, ProjectileConstructor, StateUpdate}, comp::{
Body, CharacterState, EnergyChange, EnergySource, LightEmitter, ProjectileConstructor,
StateUpdate,
},
event::ServerEvent, event::ServerEvent,
states::{ states::{
behavior::{CharacterBehavior, JoinData}, behavior::{CharacterBehavior, JoinData},
utils::{StageSection, *}, utils::{StageSection, *},
}, },
util::dir::*,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::time::Duration; use std::time::Duration;
use vek::Vec3;
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
/// Separated out to condense update portions of character state /// Separated out to condense update portions of character state
pub struct StaticData { pub struct StaticData {
/// How long the state is in movement
pub movement_duration: Duration,
/// How long we've readied the weapon /// How long we've readied the weapon
pub buildup_duration: Duration, pub buildup_duration: Duration,
/// How long the state is shooting /// How long the state is shooting
pub shoot_duration: Duration, pub shoot_duration: Duration,
/// How long the state has until exiting /// How long the state has until exiting
pub recover_duration: Duration, pub recover_duration: Duration,
/// Whether there should be a jump and how strong the leap is /// Energy cost per projectile
pub leap: Option<f32>, 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 /// Projectile options
pub projectile: ProjectileConstructor, pub projectile: ProjectileConstructor,
pub projectile_body: Body, pub projectile_body: Body,
@ -42,64 +45,20 @@ pub struct Data {
pub timer: Duration, pub timer: Duration,
/// What section the character stage is in /// What section the character stage is in
pub stage_section: StageSection, pub stage_section: StageSection,
/// How many repetitions remaining /// Speed of the state while in shoot section
pub reps_remaining: u32, pub speed: f32,
/// Number of projectiles fired so far
pub projectiles_fired: u32,
} }
impl CharacterBehavior for Data { impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate { fn behavior(&self, data: &JoinData) -> StateUpdate {
let mut update = StateUpdate::from(data); let mut update = StateUpdate::from(data);
handle_orientation(data, &mut update, 1.0); handle_orientation(data, &mut update, 1.0);
handle_move(data, &mut update, 1.0); handle_move(data, &mut update, 0.1);
handle_jump(data, &mut update, 1.0);
match self.stage_section { 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 => { 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 { if self.timer < self.static_data.buildup_duration {
// Buildup to attack // Buildup to attack
update.character = CharacterState::RepeaterRanged(Data { update.character = CharacterState::RepeaterRanged(Data {
@ -119,12 +78,19 @@ impl CharacterBehavior for Data {
} }
}, },
StageSection::Shoot => { StageSection::Shoot => {
// Aim gliding if self.timer < self.static_data.shoot_duration {
if self.static_data.leap.is_some() { // Draw projectile
update.vel.0 = Vec3::new(data.vel.0.x, data.vel.0.y, 0.0); update.character = CharacterState::RepeaterRanged(Data {
} timer: self
if self.reps_remaining > 0 { .timer
// Fire .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) = let (crit_chance, crit_mult) =
get_crit_data(data, self.static_data.ability_info); get_crit_data(data, self.static_data.ability_info);
let projectile = self.static_data.projectile.create_projectile( let projectile = self.static_data.projectile.create_projectile(
@ -135,22 +101,7 @@ impl CharacterBehavior for Data {
update.server_events.push_front(ServerEvent::Shoot { update.server_events.push_front(ServerEvent::Shoot {
entity: data.entity, entity: data.entity,
// Provides slight variation to projectile direction // Provides slight variation to projectile direction
dir: Dir::from_unnormalized(Vec3::new( dir: data.inputs.look_dir,
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),
body: self.static_data.projectile_body, body: self.static_data.projectile_body,
projectile, projectile,
light: self.static_data.projectile_light, light: self.static_data.projectile_light,
@ -158,22 +109,24 @@ impl CharacterBehavior for Data {
object: None, object: None,
}); });
// Shoot projectiles update.server_events.push_front(ServerEvent::EnergyChange {
update.character = CharacterState::RepeaterRanged(Data { entity: data.entity,
timer: self change: EnergyChange {
.timer amount: -self.static_data.energy_cost as i32,
.checked_add(Duration::from_secs_f32(data.dt.0)) source: EnergySource::Ability,
.unwrap_or_default(), },
reps_remaining: self.reps_remaining - 1,
..*self
}); });
} 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 { update.character = CharacterState::RepeaterRanged(Data {
timer: self timer: Duration::default(),
.timer speed: new_speed,
.checked_add(Duration::from_secs_f32(data.dt.0)) projectiles_fired: self.projectiles_fired + 1,
.unwrap_or_default(),
..*self ..*self
}); });
} else { } else {
@ -186,10 +139,7 @@ impl CharacterBehavior for Data {
} }
}, },
StageSection::Recover => { StageSection::Recover => {
if self.static_data.leap.is_some() && data.physics.on_ground { if self.timer < self.static_data.recover_duration {
// Done
update.character = CharacterState::Wielding;
} else if self.timer < self.static_data.recover_duration {
// Recover from attack // Recover from attack
update.character = CharacterState::RepeaterRanged(Data { update.character = CharacterState::RepeaterRanged(Data {
timer: self timer: self

View File

@ -1015,9 +1015,6 @@ impl FigureMgr {
StageSection::Buildup => { StageSection::Buildup => {
stage_time / s.static_data.buildup_duration.as_secs_f32() stage_time / s.static_data.buildup_duration.as_secs_f32()
}, },
StageSection::Movement => {
stage_time / s.static_data.movement_duration.as_secs_f32()
},
StageSection::Shoot => { StageSection::Shoot => {
stage_time / s.static_data.shoot_duration.as_secs_f32() stage_time / s.static_data.shoot_duration.as_secs_f32()
}, },