mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Add 3rd skill for hammer, bow, and axe minus skillbar UI stuff
This commit is contained in:
parent
5bcfb6bd0a
commit
951acfca21
@ -18,6 +18,7 @@ pub enum CharacterAbilityType {
|
||||
BasicMelee,
|
||||
BasicRanged,
|
||||
Boost,
|
||||
ChargedMelee,
|
||||
ChargedRanged,
|
||||
DashMelee,
|
||||
BasicBlock,
|
||||
@ -26,6 +27,7 @@ pub enum CharacterAbilityType {
|
||||
SpinMelee,
|
||||
GroundShockwave,
|
||||
BasicBeam,
|
||||
RepeaterRanged,
|
||||
}
|
||||
|
||||
impl From<&CharacterState> for CharacterAbilityType {
|
||||
@ -39,9 +41,11 @@ impl From<&CharacterState> for CharacterAbilityType {
|
||||
CharacterState::LeapMelee(_) => Self::LeapMelee,
|
||||
CharacterState::ComboMelee(data) => Self::ComboMelee(data.stage_section, data.stage),
|
||||
CharacterState::SpinMelee(_) => Self::SpinMelee,
|
||||
CharacterState::ChargedMelee(_) => Self::ChargedMelee,
|
||||
CharacterState::ChargedRanged(_) => Self::ChargedRanged,
|
||||
CharacterState::GroundShockwave(_) => Self::ChargedRanged,
|
||||
CharacterState::BasicBeam(_) => Self::BasicBeam,
|
||||
CharacterState::RepeaterRanged(_) => Self::RepeaterRanged,
|
||||
_ => Self::BasicMelee,
|
||||
}
|
||||
}
|
||||
@ -69,6 +73,20 @@ pub enum CharacterAbility {
|
||||
projectile_gravity: Option<Gravity>,
|
||||
projectile_speed: f32,
|
||||
},
|
||||
RepeaterRanged {
|
||||
movement_duration: Duration,
|
||||
energy_cost: u32,
|
||||
holdable: bool,
|
||||
prepare_duration: Duration,
|
||||
recover_duration: Duration,
|
||||
projectile: Projectile,
|
||||
projectile_body: Body,
|
||||
projectile_light: Option<LightEmitter>,
|
||||
projectile_gravity: Option<Gravity>,
|
||||
projectile_speed: f32,
|
||||
repetitions: u32,
|
||||
current_rep: u32,
|
||||
},
|
||||
Boost {
|
||||
duration: Duration,
|
||||
only_up: bool,
|
||||
@ -107,6 +125,10 @@ pub enum CharacterAbility {
|
||||
buildup_duration: Duration,
|
||||
recover_duration: Duration,
|
||||
base_damage: u32,
|
||||
range: f32,
|
||||
max_angle: f32,
|
||||
leap_speed: f32,
|
||||
leap_vert_speed: f32,
|
||||
},
|
||||
SpinMelee {
|
||||
buildup_duration: Duration,
|
||||
@ -122,6 +144,19 @@ pub enum CharacterAbility {
|
||||
forward_speed: f32,
|
||||
num_spins: u32,
|
||||
},
|
||||
ChargedMelee {
|
||||
energy_cost: u32,
|
||||
energy_drain: u32,
|
||||
initial_damage: u32,
|
||||
max_damage: u32,
|
||||
initial_knockback: f32,
|
||||
max_knockback: f32,
|
||||
prepare_duration: Duration,
|
||||
charge_duration: Duration,
|
||||
recover_duration: Duration,
|
||||
range: f32,
|
||||
max_angle: f32,
|
||||
},
|
||||
ChargedRanged {
|
||||
energy_cost: u32,
|
||||
energy_drain: u32,
|
||||
@ -203,6 +238,14 @@ impl CharacterAbility {
|
||||
.energy
|
||||
.try_change_by(-(*energy_cost as i32), EnergySource::Ability)
|
||||
.is_ok(),
|
||||
CharacterAbility::ChargedMelee { energy_cost, .. } => update
|
||||
.energy
|
||||
.try_change_by(-(*energy_cost as i32), EnergySource::Ability)
|
||||
.is_ok(),
|
||||
CharacterAbility::RepeaterRanged { energy_cost, .. } => update
|
||||
.energy
|
||||
.try_change_by(-(*energy_cost as i32), EnergySource::Ability)
|
||||
.is_ok(),
|
||||
CharacterAbility::GroundShockwave { energy_cost, .. } => update
|
||||
.energy
|
||||
.try_change_by(-(*energy_cost as i32), EnergySource::Ability)
|
||||
@ -424,6 +467,10 @@ impl From<&CharacterAbility> for CharacterState {
|
||||
buildup_duration,
|
||||
recover_duration,
|
||||
base_damage,
|
||||
range,
|
||||
max_angle,
|
||||
leap_speed,
|
||||
leap_vert_speed,
|
||||
} => CharacterState::LeapMelee(leap_melee::Data {
|
||||
initialize: true,
|
||||
exhausted: false,
|
||||
@ -431,6 +478,10 @@ impl From<&CharacterAbility> for CharacterState {
|
||||
buildup_duration: *buildup_duration,
|
||||
recover_duration: *recover_duration,
|
||||
base_damage: *base_damage,
|
||||
range: *range,
|
||||
max_angle: *max_angle,
|
||||
leap_speed: *leap_speed,
|
||||
leap_vert_speed: *leap_vert_speed,
|
||||
}),
|
||||
CharacterAbility::SpinMelee {
|
||||
buildup_duration,
|
||||
@ -465,6 +516,32 @@ impl From<&CharacterAbility> for CharacterState {
|
||||
stage_section: StageSection::Buildup,
|
||||
exhausted: false,
|
||||
}),
|
||||
CharacterAbility::ChargedMelee {
|
||||
energy_cost: _,
|
||||
energy_drain,
|
||||
initial_damage,
|
||||
max_damage,
|
||||
initial_knockback,
|
||||
max_knockback,
|
||||
prepare_duration,
|
||||
charge_duration,
|
||||
recover_duration,
|
||||
range,
|
||||
max_angle,
|
||||
} => CharacterState::ChargedMelee(charged_melee::Data {
|
||||
exhausted: false,
|
||||
energy_drain: *energy_drain,
|
||||
initial_damage: *initial_damage,
|
||||
max_damage: *max_damage,
|
||||
initial_knockback: *initial_knockback,
|
||||
max_knockback: *max_knockback,
|
||||
prepare_duration: *prepare_duration,
|
||||
charge_duration: *charge_duration,
|
||||
charge_timer: Duration::default(),
|
||||
recover_duration: *recover_duration,
|
||||
range: *range,
|
||||
max_angle: *max_angle,
|
||||
}),
|
||||
CharacterAbility::ChargedRanged {
|
||||
energy_cost: _,
|
||||
energy_drain,
|
||||
@ -497,6 +574,35 @@ impl From<&CharacterAbility> for CharacterState {
|
||||
initial_projectile_speed: *initial_projectile_speed,
|
||||
max_projectile_speed: *max_projectile_speed,
|
||||
}),
|
||||
CharacterAbility::RepeaterRanged {
|
||||
energy_cost: _,
|
||||
movement_duration,
|
||||
holdable,
|
||||
prepare_duration,
|
||||
recover_duration,
|
||||
projectile,
|
||||
projectile_body,
|
||||
projectile_light,
|
||||
projectile_gravity,
|
||||
projectile_speed,
|
||||
repetitions,
|
||||
current_rep,
|
||||
} => CharacterState::RepeaterRanged(repeater_ranged::Data {
|
||||
exhausted: false,
|
||||
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,
|
||||
repetitions: *repetitions,
|
||||
current_rep: *current_rep,
|
||||
initialize: true,
|
||||
}),
|
||||
CharacterAbility::GroundShockwave {
|
||||
energy_cost: _,
|
||||
buildup_duration,
|
||||
|
@ -69,6 +69,10 @@ pub enum CharacterState {
|
||||
SpinMelee(spin_melee::Data),
|
||||
/// A charged ranged attack (e.g. bow)
|
||||
ChargedRanged(charged_ranged::Data),
|
||||
/// A charged melee attack
|
||||
ChargedMelee(charged_melee::Data),
|
||||
/// A repeating ranged attack
|
||||
RepeaterRanged(repeater_ranged::Data),
|
||||
/// A ground shockwave attack
|
||||
GroundShockwave(ground_shockwave::Data),
|
||||
/// A continuous attack that affects all creatures in a cone originating
|
||||
@ -87,7 +91,9 @@ impl CharacterState {
|
||||
| CharacterState::BasicBlock
|
||||
| CharacterState::LeapMelee(_)
|
||||
| CharacterState::SpinMelee(_)
|
||||
| CharacterState::ChargedMelee(_)
|
||||
| CharacterState::ChargedRanged(_)
|
||||
| CharacterState::RepeaterRanged(_)
|
||||
| CharacterState::GroundShockwave(_)
|
||||
| CharacterState::BasicBeam(_)
|
||||
)
|
||||
@ -101,7 +107,9 @@ impl CharacterState {
|
||||
| CharacterState::ComboMelee(_)
|
||||
| CharacterState::LeapMelee(_)
|
||||
| CharacterState::SpinMelee(_)
|
||||
| CharacterState::ChargedMelee(_)
|
||||
| CharacterState::ChargedRanged(_)
|
||||
| CharacterState::RepeaterRanged(_)
|
||||
| CharacterState::GroundShockwave(_)
|
||||
| CharacterState::BasicBeam(_)
|
||||
)
|
||||
@ -115,7 +123,9 @@ impl CharacterState {
|
||||
| CharacterState::ComboMelee(_)
|
||||
| CharacterState::BasicBlock
|
||||
| CharacterState::LeapMelee(_)
|
||||
| CharacterState::ChargedMelee(_)
|
||||
| CharacterState::ChargedRanged(_)
|
||||
| CharacterState::RepeaterRanged(_)
|
||||
| CharacterState::GroundShockwave(_)
|
||||
| CharacterState::BasicBeam(_)
|
||||
)
|
||||
|
@ -226,6 +226,17 @@ impl Tool {
|
||||
forward_speed: 0.0,
|
||||
num_spins: 1,
|
||||
},
|
||||
LeapMelee {
|
||||
energy_cost: 300,
|
||||
movement_duration: Duration::from_millis(200),
|
||||
buildup_duration: Duration::from_millis(1000),
|
||||
recover_duration: Duration::from_millis(600),
|
||||
base_damage: (170.0 * self.base_power()) as u32,
|
||||
range: 3.5,
|
||||
max_angle: 50.0,
|
||||
leap_speed: 20.0,
|
||||
leap_vert_speed: 16.0,
|
||||
},
|
||||
],
|
||||
Hammer(_) => vec![
|
||||
BasicMelee {
|
||||
@ -237,12 +248,29 @@ impl Tool {
|
||||
range: 3.5,
|
||||
max_angle: 20.0,
|
||||
},
|
||||
ChargedMelee {
|
||||
energy_cost: 0,
|
||||
energy_drain: 300,
|
||||
initial_damage: (20.0 * self.base_power()) as u32,
|
||||
max_damage: (170.0 * self.base_power()) as u32,
|
||||
initial_knockback: 12.0,
|
||||
max_knockback: 60.0,
|
||||
prepare_duration: Duration::from_millis(200),
|
||||
charge_duration: Duration::from_millis(1200),
|
||||
recover_duration: Duration::from_millis(500),
|
||||
range: 3.5,
|
||||
max_angle: 30.0,
|
||||
},
|
||||
LeapMelee {
|
||||
energy_cost: 800,
|
||||
energy_cost: 700,
|
||||
movement_duration: Duration::from_millis(500),
|
||||
buildup_duration: Duration::from_millis(1000),
|
||||
recover_duration: Duration::from_millis(100),
|
||||
base_damage: (240.0 * self.base_power()) as u32,
|
||||
range: 4.5,
|
||||
max_angle: 360.0,
|
||||
leap_speed: 24.0,
|
||||
leap_vert_speed: 8.0,
|
||||
},
|
||||
],
|
||||
Farming(_) => vec![BasicMelee {
|
||||
@ -293,6 +321,31 @@ impl Tool {
|
||||
initial_projectile_speed: 100.0,
|
||||
max_projectile_speed: 500.0,
|
||||
},
|
||||
RepeaterRanged {
|
||||
energy_cost: 400,
|
||||
holdable: true,
|
||||
movement_duration: Duration::from_millis(200),
|
||||
prepare_duration: Duration::from_millis(1000),
|
||||
recover_duration: Duration::from_millis(1000),
|
||||
projectile: Projectile {
|
||||
hit_solid: vec![projectile::Effect::Stick],
|
||||
hit_entity: vec![
|
||||
projectile::Effect::Damage((-40.0 * self.base_power()) as i32),
|
||||
projectile::Effect::Knockback(10.0),
|
||||
projectile::Effect::RewardEnergy(50),
|
||||
projectile::Effect::Vanish,
|
||||
],
|
||||
time_left: Duration::from_secs(15),
|
||||
owner: None,
|
||||
ignore_group: true,
|
||||
},
|
||||
projectile_body: Body::Object(object::Body::Arrow),
|
||||
projectile_light: None,
|
||||
projectile_gravity: Some(Gravity(0.2)),
|
||||
projectile_speed: 100.0,
|
||||
repetitions: 4,
|
||||
current_rep: 0,
|
||||
},
|
||||
],
|
||||
Dagger(_) => vec![BasicMelee {
|
||||
energy_cost: 0,
|
||||
|
171
common/src/states/charged_melee.rs
Normal file
171
common/src/states/charged_melee.rs
Normal file
@ -0,0 +1,171 @@
|
||||
use crate::{
|
||||
comp::{Attacking, CharacterState, EnergySource, StateUpdate},
|
||||
states::utils::*,
|
||||
sys::character_behavior::*,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Data {
|
||||
/// Whether the attack fired already
|
||||
pub exhausted: bool,
|
||||
/// How much energy is drained per second when charging
|
||||
pub energy_drain: u32,
|
||||
/// How much damage is dealt with no charge
|
||||
pub initial_damage: u32,
|
||||
/// How much damage is dealt with max charge
|
||||
pub max_damage: u32,
|
||||
/// How much knockback there is with no charge
|
||||
pub initial_knockback: f32,
|
||||
/// How much knockback there is at max charge
|
||||
pub max_knockback: f32,
|
||||
/// How long the weapon needs to be prepared for
|
||||
pub prepare_duration: Duration,
|
||||
/// How long it takes to charge the weapon to max damage and knockback
|
||||
pub charge_duration: Duration,
|
||||
/// How long the state has been charging
|
||||
pub charge_timer: Duration,
|
||||
/// How long the state has until exiting
|
||||
pub recover_duration: Duration,
|
||||
/// Max range
|
||||
pub range: f32,
|
||||
/// Max angle (45.0 will give you a 90.0 angle window)
|
||||
pub max_angle: f32,
|
||||
}
|
||||
|
||||
impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
|
||||
handle_move(data, &mut update, 0.3);
|
||||
handle_jump(data, &mut update);
|
||||
|
||||
if self.prepare_duration != Duration::default() {
|
||||
// Prepare (draw the bow)
|
||||
update.character = CharacterState::ChargedMelee(Data {
|
||||
exhausted: self.exhausted,
|
||||
energy_drain: self.energy_drain,
|
||||
initial_damage: self.initial_damage,
|
||||
max_damage: self.max_damage,
|
||||
initial_knockback: self.initial_knockback,
|
||||
max_knockback: self.max_knockback,
|
||||
prepare_duration: self
|
||||
.prepare_duration
|
||||
.checked_sub(Duration::from_secs_f32(data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
charge_duration: self.charge_duration,
|
||||
charge_timer: self.charge_timer,
|
||||
recover_duration: self.recover_duration,
|
||||
range: self.range,
|
||||
max_angle: self.max_angle,
|
||||
});
|
||||
} else if data.inputs.secondary.is_pressed()
|
||||
&& self.charge_timer < self.charge_duration
|
||||
&& update.energy.current() > 0
|
||||
{
|
||||
// Charge the attack
|
||||
update.character = CharacterState::ChargedMelee(Data {
|
||||
exhausted: self.exhausted,
|
||||
energy_drain: self.energy_drain,
|
||||
initial_damage: self.initial_damage,
|
||||
max_damage: self.max_damage,
|
||||
initial_knockback: self.initial_knockback,
|
||||
max_knockback: self.max_knockback,
|
||||
prepare_duration: self.prepare_duration,
|
||||
charge_timer: self
|
||||
.charge_timer
|
||||
.checked_add(Duration::from_secs_f32(data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
charge_duration: self.charge_duration,
|
||||
recover_duration: self.recover_duration,
|
||||
range: self.range,
|
||||
max_angle: self.max_angle,
|
||||
});
|
||||
|
||||
// Consumes energy if there's enough left and RMB is held down
|
||||
update.energy.change_by(
|
||||
-(self.energy_drain as f32 * data.dt.0) as i32,
|
||||
EnergySource::Ability,
|
||||
);
|
||||
} else if data.inputs.secondary.is_pressed() {
|
||||
// Charge the attack
|
||||
update.character = CharacterState::ChargedMelee(Data {
|
||||
exhausted: self.exhausted,
|
||||
energy_drain: self.energy_drain,
|
||||
initial_damage: self.initial_damage,
|
||||
max_damage: self.max_damage,
|
||||
initial_knockback: self.initial_knockback,
|
||||
max_knockback: self.max_knockback,
|
||||
prepare_duration: self.prepare_duration,
|
||||
charge_timer: self.charge_timer,
|
||||
charge_duration: self.charge_duration,
|
||||
recover_duration: self.recover_duration,
|
||||
range: self.range,
|
||||
max_angle: self.max_angle,
|
||||
});
|
||||
|
||||
// Consumes energy if there's enough left and RMB is held down
|
||||
update.energy.change_by(
|
||||
-(self.energy_drain as f32 * data.dt.0 / 5.0) as i32,
|
||||
EnergySource::Ability,
|
||||
);
|
||||
} else if !self.exhausted {
|
||||
let charge_amount =
|
||||
(self.charge_timer.as_secs_f32() / self.charge_duration.as_secs_f32()).min(1.0);
|
||||
let damage = self.initial_damage as f32 + (charge_amount * (self.max_damage - self.initial_damage) as f32);
|
||||
// Hit attempt
|
||||
data.updater.insert(data.entity, Attacking {
|
||||
base_damage: damage as u32,
|
||||
base_heal: 0,
|
||||
range: self.range,
|
||||
max_angle: self.max_angle.to_radians(),
|
||||
applied: false,
|
||||
hit_count: 0,
|
||||
knockback: self.initial_knockback
|
||||
+ charge_amount * (self.max_knockback - self.initial_knockback),
|
||||
});
|
||||
|
||||
update.character = CharacterState::ChargedMelee(Data {
|
||||
exhausted: true,
|
||||
energy_drain: self.energy_drain,
|
||||
initial_damage: self.initial_damage,
|
||||
max_damage: self.max_damage,
|
||||
initial_knockback: self.initial_knockback,
|
||||
max_knockback: self.max_knockback,
|
||||
prepare_duration: self.prepare_duration,
|
||||
charge_timer: self.charge_timer,
|
||||
charge_duration: self.charge_duration,
|
||||
recover_duration: self.recover_duration,
|
||||
range: self.range,
|
||||
max_angle: self.max_angle,
|
||||
});
|
||||
} else if self.recover_duration != Duration::default() {
|
||||
// Recovery
|
||||
update.character = CharacterState::ChargedMelee(Data {
|
||||
exhausted: self.exhausted,
|
||||
energy_drain: self.energy_drain,
|
||||
initial_damage: self.initial_damage,
|
||||
max_damage: self.max_damage,
|
||||
initial_knockback: self.initial_knockback,
|
||||
max_knockback: self.max_knockback,
|
||||
prepare_duration: self.prepare_duration,
|
||||
charge_timer: self.charge_timer,
|
||||
charge_duration: self.charge_duration,
|
||||
recover_duration: self
|
||||
.recover_duration
|
||||
.checked_sub(Duration::from_secs_f32(data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
range: self.range,
|
||||
max_angle: self.max_angle,
|
||||
});
|
||||
} else {
|
||||
// Done
|
||||
update.character = CharacterState::Wielding;
|
||||
// Make sure attack component is removed
|
||||
data.updater.remove::<Attacking>(data.entity);
|
||||
}
|
||||
|
||||
update
|
||||
}
|
||||
}
|
@ -7,9 +7,8 @@ use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use vek::Vec3;
|
||||
|
||||
const LEAP_SPEED: f32 = 24.0;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
//#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct Data {
|
||||
/// How long the state is moving
|
||||
pub movement_duration: Duration,
|
||||
@ -21,6 +20,14 @@ pub struct Data {
|
||||
pub base_damage: u32,
|
||||
/// Whether the attack can deal more damage
|
||||
pub exhausted: bool,
|
||||
/// Max range
|
||||
pub range: f32,
|
||||
/// Max angle (45.0 will give you a 90.0 angle window)
|
||||
pub max_angle: f32,
|
||||
/// Leap speed
|
||||
pub leap_speed: f32,
|
||||
/// Leap vertical speed?
|
||||
pub leap_vert_speed: f32,
|
||||
pub initialize: bool,
|
||||
}
|
||||
|
||||
@ -37,13 +44,17 @@ impl CharacterBehavior for Data {
|
||||
|
||||
if self.movement_duration != Duration::default() {
|
||||
// Jumping
|
||||
update.vel.0 = Vec3::new(data.inputs.look_dir.x, data.inputs.look_dir.y, 8.0)
|
||||
* ((self.movement_duration.as_millis() as f32) / 250.0)
|
||||
//update.vel.0 = Vec3::new(data.inputs.look_dir.x, data.inputs.look_dir.y, 8.0)
|
||||
update.vel.0 = Vec3::new(
|
||||
data.inputs.look_dir.x,
|
||||
data.inputs.look_dir.y,
|
||||
self.leap_vert_speed,
|
||||
) * ((self.movement_duration.as_millis() as f32) / 250.0)
|
||||
+ (update.vel.0 * Vec3::new(2.0, 2.0, 0.0)
|
||||
+ 0.25 * data.inputs.move_dir.try_normalized().unwrap_or_default())
|
||||
.try_normalized()
|
||||
.unwrap_or_default()
|
||||
* LEAP_SPEED
|
||||
* self.leap_speed
|
||||
* (1.0 - data.inputs.look_dir.z.abs());
|
||||
|
||||
update.character = CharacterState::LeapMelee(Data {
|
||||
@ -55,6 +66,10 @@ impl CharacterBehavior for Data {
|
||||
recover_duration: self.recover_duration,
|
||||
base_damage: self.base_damage,
|
||||
exhausted: false,
|
||||
range: self.range,
|
||||
max_angle: self.max_angle,
|
||||
leap_speed: self.leap_speed,
|
||||
leap_vert_speed: self.leap_vert_speed,
|
||||
initialize: false,
|
||||
});
|
||||
} else if self.buildup_duration != Duration::default() && !data.physics.on_ground {
|
||||
@ -68,6 +83,10 @@ impl CharacterBehavior for Data {
|
||||
recover_duration: self.recover_duration,
|
||||
base_damage: self.base_damage,
|
||||
exhausted: false,
|
||||
range: self.range,
|
||||
max_angle: self.max_angle,
|
||||
leap_speed: self.leap_speed,
|
||||
leap_vert_speed: self.leap_vert_speed,
|
||||
initialize: false,
|
||||
});
|
||||
} else if !self.exhausted {
|
||||
@ -75,8 +94,9 @@ impl CharacterBehavior for Data {
|
||||
data.updater.insert(data.entity, Attacking {
|
||||
base_damage: self.base_damage,
|
||||
base_heal: 0,
|
||||
range: 4.5,
|
||||
max_angle: 360_f32.to_radians(),
|
||||
range: self.range,
|
||||
//range: 4.5,
|
||||
max_angle: self.max_angle.to_radians(),
|
||||
applied: false,
|
||||
hit_count: 0,
|
||||
knockback: 25.0,
|
||||
@ -88,6 +108,10 @@ impl CharacterBehavior for Data {
|
||||
recover_duration: self.recover_duration,
|
||||
base_damage: self.base_damage,
|
||||
exhausted: true,
|
||||
range: self.range,
|
||||
max_angle: self.max_angle,
|
||||
leap_speed: self.leap_speed,
|
||||
leap_vert_speed: self.leap_vert_speed,
|
||||
initialize: false,
|
||||
});
|
||||
} else if self.recover_duration != Duration::default() {
|
||||
@ -102,6 +126,10 @@ impl CharacterBehavior for Data {
|
||||
.unwrap_or_default(),
|
||||
base_damage: self.base_damage,
|
||||
exhausted: true,
|
||||
range: self.range,
|
||||
max_angle: self.max_angle,
|
||||
leap_speed: self.leap_speed,
|
||||
leap_vert_speed: self.leap_vert_speed,
|
||||
initialize: false,
|
||||
});
|
||||
} else {
|
||||
|
@ -3,6 +3,7 @@ pub mod basic_block;
|
||||
pub mod basic_melee;
|
||||
pub mod basic_ranged;
|
||||
pub mod boost;
|
||||
pub mod charged_melee;
|
||||
pub mod charged_ranged;
|
||||
pub mod climb;
|
||||
pub mod combo_melee;
|
||||
@ -14,6 +15,7 @@ pub mod glide_wield;
|
||||
pub mod ground_shockwave;
|
||||
pub mod idle;
|
||||
pub mod leap_melee;
|
||||
pub mod repeater_ranged;
|
||||
pub mod roll;
|
||||
pub mod sit;
|
||||
pub mod sneak;
|
||||
|
153
common/src/states/repeater_ranged.rs
Normal file
153
common/src/states/repeater_ranged.rs
Normal file
@ -0,0 +1,153 @@
|
||||
use crate::{
|
||||
comp::{Body, CharacterState, Gravity, LightEmitter, Projectile, StateUpdate},
|
||||
event::ServerEvent,
|
||||
states::utils::*,
|
||||
sys::character_behavior::*,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use vek::Vec3;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Data {
|
||||
/// How long the state is moving
|
||||
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 the state has until exiting
|
||||
pub recover_duration: Duration,
|
||||
pub projectile: Projectile,
|
||||
pub projectile_body: Body,
|
||||
pub projectile_light: Option<LightEmitter>,
|
||||
pub projectile_gravity: Option<Gravity>,
|
||||
pub projectile_speed: f32,
|
||||
/// Whether the attack fired already
|
||||
pub exhausted: bool,
|
||||
/// How many times to repeat
|
||||
pub repetitions: u32,
|
||||
/// Current repetition
|
||||
pub current_rep: u32,
|
||||
pub initialize: bool,
|
||||
}
|
||||
|
||||
impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate::from(data);
|
||||
|
||||
handle_move(data, &mut update, 1.0);
|
||||
handle_jump(data, &mut update);
|
||||
|
||||
if !self.exhausted
|
||||
&& 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,
|
||||
exhausted: false,
|
||||
repetitions: self.repetitions,
|
||||
current_rep: self.current_rep,
|
||||
initialize: false,
|
||||
});
|
||||
} else if self.movement_duration != Duration::default() {
|
||||
// Jumping
|
||||
update.vel.0 = Vec3::new(data.vel.0[0], data.vel.0[1], 10.0);
|
||||
|
||||
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,
|
||||
exhausted: false,
|
||||
repetitions: self.repetitions,
|
||||
current_rep: self.current_rep,
|
||||
initialize: false,
|
||||
});
|
||||
} else if !self.exhausted && self.current_rep < self.repetitions {
|
||||
let mut projectile = self.projectile.clone();
|
||||
projectile.owner = Some(*data.uid);
|
||||
update.server_events.push_front(ServerEvent::Shoot {
|
||||
entity: data.entity,
|
||||
dir: data.inputs.look_dir,
|
||||
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,
|
||||
exhausted: false,
|
||||
repetitions: self.repetitions,
|
||||
current_rep: self.current_rep + 1,
|
||||
initialize: false,
|
||||
});
|
||||
} else if self.recover_duration != Duration::default() {
|
||||
// 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,
|
||||
exhausted: true,
|
||||
repetitions: self.repetitions,
|
||||
current_rep: 0,
|
||||
initialize: false,
|
||||
});
|
||||
return update;
|
||||
} else {
|
||||
// Done
|
||||
update.character = CharacterState::Wielding;
|
||||
}
|
||||
|
||||
update
|
||||
}
|
||||
}
|
@ -261,7 +261,9 @@ impl<'a> System<'a> for Sys {
|
||||
CharacterState::DashMelee(data) => data.handle_event(&j, action),
|
||||
CharacterState::LeapMelee(data) => data.handle_event(&j, action),
|
||||
CharacterState::SpinMelee(data) => data.handle_event(&j, action),
|
||||
CharacterState::ChargedMelee(data) => data.handle_event(&j, action),
|
||||
CharacterState::ChargedRanged(data) => data.handle_event(&j, action),
|
||||
CharacterState::RepeaterRanged(data) => data.handle_event(&j, action),
|
||||
CharacterState::GroundShockwave(data) => data.handle_event(&j, action),
|
||||
CharacterState::BasicBeam(data) => data.handle_event(&j, action),
|
||||
};
|
||||
@ -291,7 +293,9 @@ impl<'a> System<'a> for Sys {
|
||||
CharacterState::DashMelee(data) => data.behavior(&j),
|
||||
CharacterState::LeapMelee(data) => data.behavior(&j),
|
||||
CharacterState::SpinMelee(data) => data.behavior(&j),
|
||||
CharacterState::ChargedMelee(data) => data.behavior(&j),
|
||||
CharacterState::ChargedRanged(data) => data.behavior(&j),
|
||||
CharacterState::RepeaterRanged(data) => data.behavior(&j),
|
||||
CharacterState::GroundShockwave(data) => data.behavior(&j),
|
||||
CharacterState::BasicBeam(data) => data.behavior(&j),
|
||||
};
|
||||
|
@ -112,7 +112,9 @@ impl<'a> System<'a> for Sys {
|
||||
| CharacterState::SpinMelee { .. }
|
||||
| CharacterState::ComboMelee { .. }
|
||||
| CharacterState::BasicRanged { .. }
|
||||
| CharacterState::ChargedMelee { .. }
|
||||
| CharacterState::ChargedRanged { .. }
|
||||
| CharacterState::RepeaterRanged { .. }
|
||||
| CharacterState::GroundShockwave { .. }
|
||||
| CharacterState::BasicBeam { .. } => {
|
||||
if energy.get_unchecked().regen_rate != 0.0 {
|
||||
|
@ -147,6 +147,22 @@ impl Animation for ChargeAnimation {
|
||||
* Quaternion::rotation_z(stop * -0.6);
|
||||
next.control.scale = Vec3::one();
|
||||
},
|
||||
Some(ToolKind::Hammer(_)) => {
|
||||
next.l_hand.position = Vec3::new(-8.0, -2.0 + stop * -1.0, 13.0);
|
||||
next.l_hand.orientation = Quaternion::rotation_x(2.1)
|
||||
* Quaternion::rotation_y(0.7)
|
||||
* Quaternion::rotation_z(-0.3);
|
||||
next.l_hand.scale = Vec3::one() * 1.05;
|
||||
next.r_hand.position = Vec3::new(-11.0, 2.0, 6.0);
|
||||
next.r_hand.orientation = Quaternion::rotation_x(1.8)
|
||||
* Quaternion::rotation_y(2.3)
|
||||
* Quaternion::rotation_z(0.3);
|
||||
next.r_hand.scale = Vec3::one() * 1.05;
|
||||
next.main.position = Vec3::new(-12.0, 1.0, 4.0);
|
||||
next.main.orientation = Quaternion::rotation_x(0.3)
|
||||
* Quaternion::rotation_y(0.3)
|
||||
* Quaternion::rotation_z(0.6);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ use super::{super::Animation, CharacterSkeleton, SkeletonAttr};
|
||||
use common::comp::item::{Hands, ToolKind};
|
||||
/* use std::f32::consts::PI; */
|
||||
use super::super::vek::*;
|
||||
use std::f32::consts::PI;
|
||||
|
||||
pub struct LeapAnimation;
|
||||
|
||||
@ -31,6 +32,19 @@ impl Animation for LeapAnimation {
|
||||
.sqrt())
|
||||
* ((anim_time as f32 * lab as f32 * 4.0).sin());
|
||||
|
||||
// Spin stuff here
|
||||
let foot = (((5.0)
|
||||
/ (1.1 + 3.9 * ((anim_time as f32 * lab as f32 * 10.32).sin()).powf(2.0 as f32)))
|
||||
.sqrt())
|
||||
* ((anim_time as f32 * lab as f32 * 10.32).sin());
|
||||
|
||||
let decel = (anim_time as f32 * 16.0 * lab as f32).min(PI / 2.0).sin();
|
||||
|
||||
let spin = (anim_time as f32 * 2.8 * lab as f32).sin();
|
||||
let spinhalf = (anim_time as f32 * 1.4 * lab as f32).sin();
|
||||
|
||||
// end spin stuff
|
||||
|
||||
if let Some(ToolKind::Hammer(_)) = active_tool_kind {
|
||||
next.l_hand.position = Vec3::new(-12.0, 0.0, 0.0);
|
||||
next.l_hand.orientation = Quaternion::rotation_x(-0.0) * Quaternion::rotation_y(0.0);
|
||||
@ -94,16 +108,119 @@ impl Animation for LeapAnimation {
|
||||
* Quaternion::rotation_y(0.0)
|
||||
* Quaternion::rotation_z(1.4 + slowersmooth * -0.4 + slower * 0.2);
|
||||
next.control.scale = Vec3::one();
|
||||
|
||||
next.lantern.position = Vec3::new(
|
||||
skeleton_attr.lantern.0,
|
||||
skeleton_attr.lantern.1,
|
||||
skeleton_attr.lantern.2,
|
||||
);
|
||||
next.glider.position = Vec3::new(0.0, 0.0, 10.0);
|
||||
next.glider.scale = Vec3::one() * 0.0;
|
||||
next.l_control.scale = Vec3::one();
|
||||
next.r_control.scale = Vec3::one();
|
||||
|
||||
next.torso.position = Vec3::new(0.0, 0.0, 0.0) * skeleton_attr.scaler;
|
||||
next.torso.orientation = Quaternion::rotation_z(0.0);
|
||||
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
|
||||
} else if let Some(ToolKind::Axe(_)) = active_tool_kind {
|
||||
//INTENTION: SWORD
|
||||
next.l_hand.position = Vec3::new(-0.75, -1.0, -2.5);
|
||||
next.l_hand.orientation = Quaternion::rotation_x(1.27);
|
||||
next.l_hand.scale = Vec3::one() * 1.04;
|
||||
next.r_hand.position = Vec3::new(0.75, -1.5, -5.5);
|
||||
next.r_hand.orientation = Quaternion::rotation_x(1.27);
|
||||
next.r_hand.scale = Vec3::one() * 1.05;
|
||||
//next.main.position = Vec3::new(0.0, 0.0, 10.0);
|
||||
next.main.position = Vec3::new(0.0, 0.0, -5.0);
|
||||
next.main.orientation = Quaternion::rotation_x(1.6)
|
||||
* Quaternion::rotation_y(0.0)
|
||||
* Quaternion::rotation_z(-0.4);
|
||||
next.main.scale = Vec3::one();
|
||||
|
||||
next.control.position = Vec3::new(-4.5 + spinhalf * 4.0, 11.0, 8.0);
|
||||
next.control.orientation = Quaternion::rotation_x(0.6 + spinhalf * -3.3)
|
||||
* Quaternion::rotation_y(0.2 + spin * -2.0)
|
||||
* Quaternion::rotation_z(1.4 + spin * 0.1);
|
||||
next.control.scale = Vec3::one();
|
||||
next.head.position = Vec3::new(
|
||||
0.0,
|
||||
-2.0 + skeleton_attr.head.0 + spin * -0.8,
|
||||
skeleton_attr.head.1,
|
||||
);
|
||||
next.head.orientation = Quaternion::rotation_z(spin * -0.25)
|
||||
* Quaternion::rotation_x(0.0 + spin * -0.1)
|
||||
* Quaternion::rotation_y(spin * -0.2);
|
||||
next.chest.position = Vec3::new(0.0, skeleton_attr.chest.0, skeleton_attr.chest.1);
|
||||
next.chest.orientation = Quaternion::rotation_z(spin * 0.1)
|
||||
* Quaternion::rotation_x(0.0 + spin * 0.1)
|
||||
* Quaternion::rotation_y(decel * -0.2);
|
||||
next.chest.scale = Vec3::one();
|
||||
|
||||
next.belt.position = Vec3::new(0.0, 0.0, -2.0);
|
||||
next.belt.orientation = next.chest.orientation * -0.1;
|
||||
next.belt.scale = Vec3::one();
|
||||
|
||||
next.shorts.position = Vec3::new(0.0, 0.0, -5.0);
|
||||
next.belt.orientation = next.chest.orientation * -0.08;
|
||||
next.shorts.scale = Vec3::one();
|
||||
next.torso.position = Vec3::new(0.0, 0.0, 0.1) * skeleton_attr.scaler;
|
||||
next.torso.orientation = Quaternion::rotation_z((spin * 7.0).max(0.3))
|
||||
* Quaternion::rotation_x(0.0)
|
||||
* Quaternion::rotation_y(0.3);
|
||||
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
|
||||
|
||||
// Stuff after the branch in the spin animation file
|
||||
|
||||
next.l_foot.position =
|
||||
Vec3::new(-skeleton_attr.foot.0, foot * 1.0, skeleton_attr.foot.2);
|
||||
next.l_foot.orientation = Quaternion::rotation_x(foot * -1.2);
|
||||
next.l_foot.scale = Vec3::one();
|
||||
|
||||
next.r_foot.position =
|
||||
Vec3::new(skeleton_attr.foot.0, foot * -1.0, skeleton_attr.foot.2);
|
||||
next.r_foot.orientation = Quaternion::rotation_x(foot * 1.2);
|
||||
next.r_foot.scale = Vec3::one();
|
||||
|
||||
next.l_shoulder.position = Vec3::new(-5.0, 0.0, 4.7);
|
||||
next.l_shoulder.orientation = Quaternion::rotation_x(0.0);
|
||||
next.l_shoulder.scale = Vec3::one() * 1.1;
|
||||
|
||||
next.r_shoulder.position = Vec3::new(5.0, 0.0, 4.7);
|
||||
next.r_shoulder.orientation = Quaternion::rotation_x(0.0);
|
||||
next.r_shoulder.scale = Vec3::one() * 1.1;
|
||||
|
||||
next.glider.position = Vec3::new(0.0, 5.0, 0.0);
|
||||
next.glider.orientation = Quaternion::rotation_y(0.0);
|
||||
next.glider.scale = Vec3::one() * 0.0;
|
||||
|
||||
next.lantern.position = Vec3::new(
|
||||
skeleton_attr.lantern.0,
|
||||
skeleton_attr.lantern.1,
|
||||
skeleton_attr.lantern.2,
|
||||
);
|
||||
next.lantern.orientation =
|
||||
Quaternion::rotation_x(spin * -0.7 + 0.4) * Quaternion::rotation_y(spin * 0.4);
|
||||
next.lantern.scale = Vec3::one() * 0.65;
|
||||
next.hold.scale = Vec3::one() * 0.0;
|
||||
|
||||
next.l_control.position = Vec3::new(0.0, 0.0, 0.0);
|
||||
next.l_control.orientation = Quaternion::rotation_x(0.0);
|
||||
next.l_control.scale = Vec3::one();
|
||||
|
||||
next.r_control.position = Vec3::new(0.0, 0.0, 0.0);
|
||||
next.r_control.orientation = Quaternion::rotation_x(0.0);
|
||||
next.r_control.scale = Vec3::one();
|
||||
}
|
||||
next.lantern.position = Vec3::new(
|
||||
skeleton_attr.lantern.0,
|
||||
skeleton_attr.lantern.1,
|
||||
skeleton_attr.lantern.2,
|
||||
);
|
||||
next.glider.position = Vec3::new(0.0, 0.0, 10.0);
|
||||
next.glider.scale = Vec3::one() * 0.0;
|
||||
next.l_control.scale = Vec3::one();
|
||||
next.r_control.scale = Vec3::one();
|
||||
|
||||
//next.lantern.position = Vec3::new(
|
||||
// skeleton_attr.lantern.0,
|
||||
// skeleton_attr.lantern.1,
|
||||
// skeleton_attr.lantern.2,
|
||||
//);
|
||||
//next.glider.position = Vec3::new(0.0, 0.0, 10.0);
|
||||
//next.glider.scale = Vec3::one() * 0.0;
|
||||
//next.l_control.scale = Vec3::one();
|
||||
//next.r_control.scale = Vec3::one();
|
||||
|
||||
next.second.scale = match (
|
||||
active_tool_kind.map(|tk| tk.hands()),
|
||||
@ -113,9 +230,9 @@ impl Animation for LeapAnimation {
|
||||
(_, _) => Vec3::zero(),
|
||||
};
|
||||
|
||||
next.torso.position = Vec3::new(0.0, 0.0, 0.0) * skeleton_attr.scaler;
|
||||
next.torso.orientation = Quaternion::rotation_z(0.0);
|
||||
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
|
||||
//next.torso.position = Vec3::new(0.0, 0.0, 0.0) * skeleton_attr.scaler;
|
||||
//next.torso.orientation = Quaternion::rotation_z(0.0);
|
||||
//next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
|
||||
next
|
||||
}
|
||||
}
|
||||
|
@ -724,6 +724,13 @@ impl<'a> Widget for Skillbar<'a> {
|
||||
Color::Rgba(0.3, 0.3, 0.3, 0.8)
|
||||
}
|
||||
},
|
||||
Some(ToolKind::Axe(_)) => {
|
||||
if self.energy.current() as f64 >= 100.0 {
|
||||
Color::Rgba(1.0, 1.0, 1.0, 1.0)
|
||||
} else {
|
||||
Color::Rgba(0.3, 0.3, 0.3, 0.8)
|
||||
}
|
||||
},
|
||||
_ => Color::Rgba(1.0, 1.0, 1.0, 1.0),
|
||||
})
|
||||
.set(state.ids.m2_content, ui);
|
||||
@ -785,6 +792,14 @@ impl<'a> Widget for Skillbar<'a> {
|
||||
.map(|i| i.item.kind())
|
||||
.and_then(|kind| match kind {
|
||||
ItemKind::Tool(Tool { kind, .. }) => match kind {
|
||||
ToolKind::Hammer(_) => Some((
|
||||
"Smash of Doom",
|
||||
"\nAn AOE attack with knockback. \nLeaps to position of \
|
||||
cursor.",
|
||||
)),
|
||||
ToolKind::Axe(_) => {
|
||||
Some(("Spin Leap", "\nA slashing running spin leap."))
|
||||
},
|
||||
ToolKind::Staff(_) => Some((
|
||||
"Firebomb",
|
||||
"\nWhirls a big fireball into the air. \nExplodes the ground \
|
||||
|
Loading…
Reference in New Issue
Block a user