mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added keyframes to repeater ranged.
This commit is contained in:
parent
97f580be2b
commit
7e0cc2d8e5
@ -74,18 +74,18 @@ pub enum CharacterAbility {
|
||||
projectile_speed: f32,
|
||||
},
|
||||
RepeaterRanged {
|
||||
movement_duration: Duration,
|
||||
energy_cost: u32,
|
||||
holdable: bool,
|
||||
prepare_duration: Duration,
|
||||
movement_duration: Duration,
|
||||
buildup_duration: Duration,
|
||||
shoot_duration: Duration,
|
||||
recover_duration: Duration,
|
||||
leap: Option<f32>,
|
||||
projectile: Projectile,
|
||||
projectile_body: Body,
|
||||
projectile_light: Option<LightEmitter>,
|
||||
projectile_gravity: Option<Gravity>,
|
||||
projectile_speed: f32,
|
||||
reps_remaining: u32,
|
||||
leap: bool,
|
||||
},
|
||||
Boost {
|
||||
duration: Duration,
|
||||
@ -584,29 +584,32 @@ impl From<&CharacterAbility> for CharacterState {
|
||||
CharacterAbility::RepeaterRanged {
|
||||
energy_cost: _,
|
||||
movement_duration,
|
||||
holdable,
|
||||
prepare_duration,
|
||||
buildup_duration,
|
||||
shoot_duration,
|
||||
recover_duration,
|
||||
leap,
|
||||
projectile,
|
||||
projectile_body,
|
||||
projectile_light,
|
||||
projectile_gravity,
|
||||
projectile_speed,
|
||||
reps_remaining,
|
||||
leap,
|
||||
} => CharacterState::RepeaterRanged(repeater_ranged::Data {
|
||||
prepare_timer: Duration::default(),
|
||||
holdable: *holdable,
|
||||
movement_duration: *movement_duration,
|
||||
prepare_duration: *prepare_duration,
|
||||
recover_duration: *recover_duration,
|
||||
projectile: projectile.clone(),
|
||||
projectile_body: *projectile_body,
|
||||
projectile_light: *projectile_light,
|
||||
projectile_gravity: *projectile_gravity,
|
||||
projectile_speed: *projectile_speed,
|
||||
static_data: repeater_ranged::StaticData {
|
||||
movement_duration: *movement_duration,
|
||||
buildup_duration: *buildup_duration,
|
||||
shoot_duration: *shoot_duration,
|
||||
recover_duration: *recover_duration,
|
||||
leap: *leap,
|
||||
projectile: projectile.clone(),
|
||||
projectile_body: *projectile_body,
|
||||
projectile_light: *projectile_light,
|
||||
projectile_gravity: *projectile_gravity,
|
||||
projectile_speed: *projectile_speed,
|
||||
},
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Movement,
|
||||
reps_remaining: *reps_remaining,
|
||||
leap: *leap,
|
||||
}),
|
||||
CharacterAbility::GroundShockwave {
|
||||
energy_cost: _,
|
||||
|
@ -325,10 +325,11 @@ impl Tool {
|
||||
},
|
||||
RepeaterRanged {
|
||||
energy_cost: 450,
|
||||
holdable: true,
|
||||
movement_duration: Duration::from_millis(200),
|
||||
prepare_duration: Duration::from_millis(50),
|
||||
buildup_duration: Duration::from_millis(100),
|
||||
shoot_duration: Duration::from_millis(100),
|
||||
recover_duration: Duration::from_millis(500),
|
||||
leap: Some(10.0),
|
||||
projectile: Projectile {
|
||||
hit_solid: vec![projectile::Effect::Stick],
|
||||
hit_entity: vec![
|
||||
@ -346,7 +347,6 @@ impl Tool {
|
||||
projectile_gravity: Some(Gravity(0.2)),
|
||||
projectile_speed: 100.0,
|
||||
reps_remaining: 5,
|
||||
leap: true,
|
||||
},
|
||||
],
|
||||
Dagger(_) => vec![BasicMelee {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
comp::{Body, CharacterState, Gravity, LightEmitter, Projectile, StateUpdate},
|
||||
event::ServerEvent,
|
||||
states::utils::*,
|
||||
states::utils::{StageSection, *},
|
||||
sys::character_behavior::*,
|
||||
util::dir::*,
|
||||
};
|
||||
@ -10,26 +10,37 @@ use std::time::Duration;
|
||||
use vek::Vec3;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Data {
|
||||
/// How long the state is moving
|
||||
/// Separated out to condense update portions of character state
|
||||
pub struct StaticData {
|
||||
/// How long the state is in movement
|
||||
pub movement_duration: Duration,
|
||||
/// Can you hold the ability beyond the prepare duration
|
||||
pub holdable: bool,
|
||||
/// How long we have to prepare the weapon
|
||||
pub prepare_duration: Duration,
|
||||
/// How long we prepared the weapon already
|
||||
pub prepare_timer: 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>,
|
||||
/// Projectile options
|
||||
pub projectile: Projectile,
|
||||
pub projectile_body: Body,
|
||||
pub projectile_light: Option<LightEmitter>,
|
||||
pub projectile_gravity: Option<Gravity>,
|
||||
pub projectile_speed: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Data {
|
||||
/// Struct containing data that does not change over the course of the
|
||||
/// character state
|
||||
pub static_data: StaticData,
|
||||
/// Timer for each stage
|
||||
pub timer: Duration,
|
||||
/// What section the character stage is in
|
||||
pub stage_section: StageSection,
|
||||
/// How many repetitions remaining
|
||||
pub reps_remaining: u32,
|
||||
/// Whether there should be a jump
|
||||
pub leap: bool,
|
||||
}
|
||||
|
||||
impl CharacterBehavior for Data {
|
||||
@ -39,131 +50,154 @@ impl CharacterBehavior for Data {
|
||||
handle_move(data, &mut update, 1.0);
|
||||
handle_jump(data, &mut update);
|
||||
|
||||
if self.reps_remaining > 0
|
||||
&& if self.holdable {
|
||||
data.inputs.holding_ability_key() || self.prepare_timer < self.prepare_duration
|
||||
} else {
|
||||
self.prepare_timer < self.prepare_duration
|
||||
}
|
||||
{
|
||||
// Prepare (draw the bow)
|
||||
update.character = CharacterState::RepeaterRanged(Data {
|
||||
movement_duration: self.movement_duration,
|
||||
prepare_timer: self.prepare_timer + Duration::from_secs_f32(data.dt.0),
|
||||
holdable: self.holdable,
|
||||
prepare_duration: self.prepare_duration,
|
||||
recover_duration: self.recover_duration,
|
||||
projectile: self.projectile.clone(),
|
||||
projectile_body: self.projectile_body,
|
||||
projectile_light: self.projectile_light,
|
||||
projectile_gravity: self.projectile_gravity,
|
||||
projectile_speed: self.projectile_speed,
|
||||
reps_remaining: self.reps_remaining,
|
||||
leap: self.leap,
|
||||
});
|
||||
} else if self.movement_duration != Duration::default() {
|
||||
// Jumping
|
||||
if self.leap {
|
||||
update.vel.0 = Vec3::new(data.vel.0[0], data.vel.0[1], 10.0);
|
||||
}
|
||||
match self.stage_section {
|
||||
StageSection::Movement => {
|
||||
// Jumping
|
||||
if let Some(leap_strength) = self.static_data.leap {
|
||||
update.vel.0 = Vec3::new(data.vel.0.x, data.vel.0.y, leap_strength);
|
||||
}
|
||||
if self.timer < self.static_data.movement_duration {
|
||||
// Do movement
|
||||
update.character = CharacterState::RepeaterRanged(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
stage_section: self.stage_section,
|
||||
reps_remaining: self.reps_remaining,
|
||||
});
|
||||
} else {
|
||||
// Transition to buildup
|
||||
update.character = CharacterState::RepeaterRanged(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Buildup,
|
||||
reps_remaining: self.reps_remaining,
|
||||
});
|
||||
}
|
||||
},
|
||||
StageSection::Buildup => {
|
||||
// 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.timer < self.static_data.buildup_duration {
|
||||
// Buildup to attack
|
||||
update.character = CharacterState::RepeaterRanged(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
stage_section: self.stage_section,
|
||||
reps_remaining: self.reps_remaining,
|
||||
});
|
||||
} else {
|
||||
// Transition to shoot
|
||||
update.character = CharacterState::RepeaterRanged(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Buildup,
|
||||
reps_remaining: self.reps_remaining,
|
||||
});
|
||||
}
|
||||
},
|
||||
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
|
||||
let mut projectile = self.static_data.projectile.clone();
|
||||
projectile.owner = Some(*data.uid);
|
||||
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),
|
||||
body: self.static_data.projectile_body,
|
||||
projectile,
|
||||
light: self.static_data.projectile_light,
|
||||
gravity: self.static_data.projectile_gravity,
|
||||
speed: self.static_data.projectile_speed,
|
||||
});
|
||||
|
||||
update.character = CharacterState::RepeaterRanged(Data {
|
||||
movement_duration: self
|
||||
.movement_duration
|
||||
.checked_sub(Duration::from_secs_f32(data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
prepare_timer: self.prepare_timer,
|
||||
holdable: self.holdable,
|
||||
prepare_duration: self.prepare_duration,
|
||||
recover_duration: self.recover_duration,
|
||||
projectile: self.projectile.clone(),
|
||||
projectile_body: self.projectile_body,
|
||||
projectile_light: self.projectile_light,
|
||||
projectile_gravity: self.projectile_gravity,
|
||||
projectile_speed: self.projectile_speed,
|
||||
reps_remaining: self.reps_remaining,
|
||||
leap: self.leap,
|
||||
});
|
||||
} else if self.recover_duration != Duration::default() {
|
||||
if self.leap {
|
||||
// Hover
|
||||
update.vel.0 = Vec3::new(data.vel.0[0], data.vel.0[1], data.vel.0[2] + 0.5);
|
||||
}
|
||||
|
||||
// Recovery
|
||||
update.character = CharacterState::RepeaterRanged(Data {
|
||||
movement_duration: Duration::default(),
|
||||
prepare_timer: self.prepare_timer,
|
||||
holdable: self.holdable,
|
||||
prepare_duration: self.prepare_duration,
|
||||
recover_duration: self
|
||||
.recover_duration
|
||||
.checked_sub(Duration::from_secs_f32(data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
projectile: self.projectile.clone(),
|
||||
projectile_body: self.projectile_body,
|
||||
projectile_light: self.projectile_light,
|
||||
projectile_gravity: self.projectile_gravity,
|
||||
projectile_speed: self.projectile_speed,
|
||||
reps_remaining: self.reps_remaining,
|
||||
leap: self.leap,
|
||||
});
|
||||
} else if self.reps_remaining > 0 {
|
||||
if self.leap {
|
||||
// Hover
|
||||
update.vel.0 = Vec3::new(data.vel.0[0], data.vel.0[1], data.vel.0[2] + 0.5);
|
||||
}
|
||||
|
||||
// Fire
|
||||
let mut projectile = self.projectile.clone();
|
||||
projectile.owner = Some(*data.uid);
|
||||
update.server_events.push_front(ServerEvent::Shoot {
|
||||
entity: data.entity,
|
||||
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],
|
||||
))
|
||||
.expect("That didn't work"),
|
||||
body: self.projectile_body,
|
||||
projectile,
|
||||
light: self.projectile_light,
|
||||
gravity: self.projectile_gravity,
|
||||
speed: self.projectile_speed,
|
||||
});
|
||||
|
||||
update.character = CharacterState::RepeaterRanged(Data {
|
||||
movement_duration: self.movement_duration,
|
||||
prepare_timer: self.prepare_timer,
|
||||
holdable: self.holdable,
|
||||
prepare_duration: self.prepare_duration,
|
||||
//recover_duration: self.recover_duration,
|
||||
recover_duration: self
|
||||
.recover_duration
|
||||
.checked_sub(Duration::from_secs_f32(data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
projectile: self.projectile.clone(),
|
||||
projectile_body: self.projectile_body,
|
||||
projectile_light: self.projectile_light,
|
||||
projectile_gravity: self.projectile_gravity,
|
||||
projectile_speed: self.projectile_speed,
|
||||
reps_remaining: self.reps_remaining - 1,
|
||||
leap: self.leap,
|
||||
});
|
||||
return update;
|
||||
} else {
|
||||
// Done
|
||||
update.character = CharacterState::Wielding;
|
||||
// Shoot projectiles
|
||||
update.character = CharacterState::RepeaterRanged(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
stage_section: self.stage_section,
|
||||
reps_remaining: self.reps_remaining - 1,
|
||||
});
|
||||
} else if self.timer < self.static_data.shoot_duration {
|
||||
// Finish shooting
|
||||
update.character = CharacterState::RepeaterRanged(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
stage_section: self.stage_section,
|
||||
reps_remaining: self.reps_remaining,
|
||||
});
|
||||
} else {
|
||||
// Transition to recover
|
||||
update.character = CharacterState::RepeaterRanged(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Buildup,
|
||||
reps_remaining: self.reps_remaining,
|
||||
});
|
||||
}
|
||||
},
|
||||
StageSection::Recover => {
|
||||
if !data.physics.on_ground {
|
||||
// Lands
|
||||
update.character = CharacterState::RepeaterRanged(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: self.timer,
|
||||
stage_section: self.stage_section,
|
||||
reps_remaining: self.reps_remaining,
|
||||
});
|
||||
} else if self.timer < self.static_data.recover_duration {
|
||||
// Recovers from attack
|
||||
update.character = CharacterState::RepeaterRanged(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: self
|
||||
.timer
|
||||
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
stage_section: self.stage_section,
|
||||
reps_remaining: self.reps_remaining,
|
||||
});
|
||||
} else {
|
||||
// Done
|
||||
update.character = CharacterState::Wielding;
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
// If it somehow ends up in an incorrect stage section
|
||||
update.character = CharacterState::Wielding;
|
||||
},
|
||||
}
|
||||
|
||||
update
|
||||
|
@ -365,4 +365,6 @@ pub enum StageSection {
|
||||
Recover,
|
||||
Charge,
|
||||
Cast,
|
||||
Shoot,
|
||||
Movement,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user