mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Readd ranged and debug boost. Add bouncing while running in first person
This commit is contained in:
parent
1e9f081f10
commit
87acc01d48
@ -393,11 +393,11 @@ impl Client {
|
||||
{
|
||||
if last_character_states
|
||||
.get(entity)
|
||||
.map(|&l| !client_character_state.equals(&l.0))
|
||||
.map(|l| !client_character_state.equals(&l.0))
|
||||
.unwrap_or(true)
|
||||
{
|
||||
let _ = last_character_states
|
||||
.insert(entity, comp::Last(*client_character_state));
|
||||
.insert(entity, comp::Last(client_character_state.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,27 @@
|
||||
use crate::{
|
||||
comp::{CharacterState, Item, ToolData},
|
||||
comp::{Body, CharacterState, Item, Projectile, ToolData},
|
||||
states::*,
|
||||
};
|
||||
use specs::{Component, DenseVecStorage, FlaggedStorage, HashMapStorage};
|
||||
use std::time::Duration;
|
||||
use vek::vec::Vec3;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||
pub enum CharacterAbility {
|
||||
BasicAttack {
|
||||
BasicMelee {
|
||||
buildup_duration: Duration,
|
||||
recover_duration: Duration,
|
||||
base_damage: u32,
|
||||
},
|
||||
BasicRanged {
|
||||
recover_duration: Duration,
|
||||
projectile: Projectile,
|
||||
projectile_body: Body,
|
||||
},
|
||||
Boost {
|
||||
duration: Duration,
|
||||
only_up: bool,
|
||||
},
|
||||
BasicBlock,
|
||||
Roll,
|
||||
ChargeAttack,
|
||||
@ -26,7 +36,7 @@ impl Component for CharacterAbility {
|
||||
type Storage = DenseVecStorage<Self>;
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||
pub struct ItemConfig {
|
||||
pub item: Item,
|
||||
pub primary_ability: Option<CharacterAbility>,
|
||||
@ -35,7 +45,7 @@ pub struct ItemConfig {
|
||||
pub dodge_ability: Option<CharacterAbility>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Default, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, PartialEq, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct Loadout {
|
||||
pub active_item: Option<ItemConfig>,
|
||||
pub second_item: Option<ItemConfig>,
|
||||
@ -48,39 +58,52 @@ pub struct Loadout {
|
||||
pub foot: Option<Item>,
|
||||
}
|
||||
|
||||
impl From<CharacterAbility> for CharacterState {
|
||||
fn from(ability: CharacterAbility) -> Self {
|
||||
impl From<&CharacterAbility> for CharacterState {
|
||||
fn from(ability: &CharacterAbility) -> Self {
|
||||
match ability {
|
||||
CharacterAbility::BasicAttack {
|
||||
CharacterAbility::BasicMelee {
|
||||
buildup_duration,
|
||||
recover_duration,
|
||||
base_damage,
|
||||
} => CharacterState::BasicAttack(basic_attack::Data {
|
||||
} => CharacterState::BasicMelee(basic_melee::Data {
|
||||
exhausted: false,
|
||||
buildup_duration,
|
||||
recover_duration,
|
||||
base_damage,
|
||||
buildup_duration: *buildup_duration,
|
||||
recover_duration: *recover_duration,
|
||||
base_damage: *base_damage,
|
||||
}),
|
||||
CharacterAbility::BasicBlock { .. } => CharacterState::BasicBlock,
|
||||
CharacterAbility::Roll { .. } => CharacterState::Roll(roll::Data {
|
||||
CharacterAbility::BasicRanged {
|
||||
recover_duration,
|
||||
projectile,
|
||||
projectile_body,
|
||||
} => CharacterState::BasicRanged(basic_ranged::Data {
|
||||
exhausted: false,
|
||||
prepare_timer: Duration::default(),
|
||||
recover_duration: *recover_duration,
|
||||
projectile: projectile.clone(),
|
||||
projectile_body: *projectile_body,
|
||||
}),
|
||||
CharacterAbility::Boost { duration, only_up } => CharacterState::Boost(boost::Data {
|
||||
duration: *duration,
|
||||
only_up: *only_up,
|
||||
}),
|
||||
CharacterAbility::BasicBlock => CharacterState::BasicBlock,
|
||||
CharacterAbility::Roll => CharacterState::Roll(roll::Data {
|
||||
remaining_duration: Duration::from_millis(600),
|
||||
}),
|
||||
CharacterAbility::ChargeAttack => CharacterState::ChargeAttack(charge_attack::Data {
|
||||
remaining_duration: Duration::from_millis(600),
|
||||
}),
|
||||
CharacterAbility::ChargeAttack { .. } => {
|
||||
CharacterState::ChargeAttack(charge_attack::Data {
|
||||
remaining_duration: Duration::from_millis(600),
|
||||
})
|
||||
},
|
||||
CharacterAbility::TimedCombo {
|
||||
buildup_duration,
|
||||
recover_duration,
|
||||
base_damage,
|
||||
} => CharacterState::TimedCombo(timed_combo::Data {
|
||||
buildup_duration,
|
||||
recover_duration,
|
||||
buildup_duration: *buildup_duration,
|
||||
recover_duration: *recover_duration,
|
||||
stage: 0,
|
||||
stage_exhausted: false,
|
||||
stage_time_active: Duration::default(),
|
||||
base_damage,
|
||||
base_damage: *base_damage,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ pub struct StateUpdate {
|
||||
pub server_events: VecDeque<ServerEvent>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum CharacterState {
|
||||
Idle,
|
||||
Climb,
|
||||
@ -34,8 +34,12 @@ pub enum CharacterState {
|
||||
ChargeAttack(charge_attack::Data),
|
||||
/// A dodge where player can roll
|
||||
Roll(roll::Data),
|
||||
/// A basic attacking state
|
||||
BasicAttack(basic_attack::Data),
|
||||
/// A basic melee attack (e.g. sword)
|
||||
BasicMelee(basic_melee::Data),
|
||||
/// A basic ranged attack (e.g. bow)
|
||||
BasicRanged(basic_ranged::Data),
|
||||
/// A force will boost you into a direction for some duration
|
||||
Boost(boost::Data),
|
||||
/// A three-stage attack where play must click at appropriate times
|
||||
/// to continue attack chain.
|
||||
TimedCombo(timed_combo::Data),
|
||||
@ -48,7 +52,7 @@ impl CharacterState {
|
||||
pub fn is_wield(&self) -> bool {
|
||||
match self {
|
||||
CharacterState::Wielding
|
||||
| CharacterState::BasicAttack(_)
|
||||
| CharacterState::BasicMelee(_)
|
||||
| CharacterState::TimedCombo(_)
|
||||
| CharacterState::BasicBlock => true,
|
||||
_ => false,
|
||||
@ -57,7 +61,8 @@ impl CharacterState {
|
||||
|
||||
pub fn is_attack(&self) -> bool {
|
||||
match self {
|
||||
CharacterState::BasicAttack(_)
|
||||
CharacterState::BasicMelee(_)
|
||||
| CharacterState::BasicRanged(_)
|
||||
| CharacterState::TimedCombo(_)
|
||||
| CharacterState::ChargeAttack(_) => true,
|
||||
_ => false,
|
||||
|
@ -1,6 +1,9 @@
|
||||
use crate::{
|
||||
assets::{self, Asset},
|
||||
comp::{body::humanoid, CharacterAbility},
|
||||
comp::{
|
||||
body::{humanoid, object},
|
||||
projectile, Body, CharacterAbility, HealthChange, HealthSource, Projectile,
|
||||
},
|
||||
effect::Effect,
|
||||
terrain::{Block, BlockKind},
|
||||
};
|
||||
@ -37,35 +40,61 @@ impl ToolData {
|
||||
use ToolKind::*;
|
||||
|
||||
match self.kind {
|
||||
Sword(_) => vec![BasicAttack {
|
||||
Sword(_) => vec![BasicMelee {
|
||||
buildup_duration: Duration::from_millis(100),
|
||||
recover_duration: Duration::from_millis(500),
|
||||
base_damage: 60,
|
||||
}],
|
||||
Axe => vec![BasicAttack {
|
||||
Axe => vec![BasicMelee {
|
||||
buildup_duration: Duration::from_millis(700),
|
||||
recover_duration: Duration::from_millis(100),
|
||||
base_damage: 80,
|
||||
}],
|
||||
Hammer => vec![BasicAttack {
|
||||
Hammer => vec![BasicMelee {
|
||||
buildup_duration: Duration::from_millis(700),
|
||||
recover_duration: Duration::from_millis(300),
|
||||
base_damage: 100,
|
||||
}],
|
||||
Bow => vec![],
|
||||
Dagger => vec![BasicAttack {
|
||||
Bow => vec![BasicRanged {
|
||||
projectile: Projectile {
|
||||
hit_ground: vec![projectile::Effect::Stick],
|
||||
hit_wall: vec![projectile::Effect::Stick],
|
||||
hit_entity: vec![
|
||||
projectile::Effect::Damage(HealthChange {
|
||||
// TODO: This should not be fixed (?)
|
||||
amount: -30,
|
||||
cause: HealthSource::Item,
|
||||
}),
|
||||
projectile::Effect::Vanish,
|
||||
],
|
||||
time_left: Duration::from_secs(15),
|
||||
owner: None,
|
||||
},
|
||||
projectile_body: Body::Object(object::Body::Arrow),
|
||||
recover_duration: Duration::from_millis(300),
|
||||
}],
|
||||
Dagger => vec![BasicMelee {
|
||||
buildup_duration: Duration::from_millis(100),
|
||||
recover_duration: Duration::from_millis(400),
|
||||
base_damage: 50,
|
||||
}],
|
||||
Staff => vec![BasicAttack {
|
||||
Staff => vec![BasicMelee {
|
||||
buildup_duration: Duration::from_millis(400),
|
||||
recover_duration: Duration::from_millis(300),
|
||||
base_damage: 70,
|
||||
}],
|
||||
Shield => vec![],
|
||||
Debug(kind) => match kind {
|
||||
Boost => vec![],
|
||||
DebugKind::Boost => vec![
|
||||
CharacterAbility::Boost {
|
||||
duration: Duration::from_millis(100),
|
||||
only_up: false,
|
||||
},
|
||||
CharacterAbility::Boost {
|
||||
duration: Duration::from_millis(100),
|
||||
only_up: true,
|
||||
},
|
||||
],
|
||||
Possess => vec![],
|
||||
},
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use specs::{Component, FlaggedStorage};
|
||||
use specs_idvs::IDVStorage;
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Effect {
|
||||
Damage(comp::HealthChange),
|
||||
Vanish,
|
||||
@ -11,15 +11,15 @@ pub enum Effect {
|
||||
Possess,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Projectile {
|
||||
pub owner: Uid,
|
||||
// TODO: use SmallVec for these effects
|
||||
pub hit_ground: Vec<Effect>,
|
||||
pub hit_wall: Vec<Effect>,
|
||||
pub hit_entity: Vec<Effect>,
|
||||
/// Time left until the projectile will despawn
|
||||
pub time_left: Duration,
|
||||
pub owner: Option<Uid>,
|
||||
}
|
||||
|
||||
impl Component for Projectile {
|
||||
|
@ -18,7 +18,7 @@ impl CharacterBehavior for Data {
|
||||
vel: *data.vel,
|
||||
ori: *data.ori,
|
||||
energy: *data.energy,
|
||||
character: *data.character,
|
||||
character: data.character.clone(),
|
||||
local_events: VecDeque::new(),
|
||||
server_events: VecDeque::new(),
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
comp::{Attacking, CharacterState, EnergySource, StateUpdate},
|
||||
states::{utils::*, wielding},
|
||||
states::utils::*,
|
||||
sys::character_behavior::*,
|
||||
};
|
||||
use std::{collections::VecDeque, time::Duration};
|
||||
@ -24,16 +24,16 @@ impl CharacterBehavior for Data {
|
||||
vel: *data.vel,
|
||||
ori: *data.ori,
|
||||
energy: *data.energy,
|
||||
character: *data.character,
|
||||
character: data.character.clone(),
|
||||
local_events: VecDeque::new(),
|
||||
server_events: VecDeque::new(),
|
||||
};
|
||||
|
||||
handle_move(data, &mut update);
|
||||
|
||||
// Build up
|
||||
if self.buildup_duration != Duration::default() {
|
||||
update.character = CharacterState::BasicAttack(Data {
|
||||
// Build up
|
||||
update.character = CharacterState::BasicMelee(Data {
|
||||
buildup_duration: self
|
||||
.buildup_duration
|
||||
.checked_sub(Duration::from_secs_f32(data.dt.0))
|
||||
@ -42,9 +42,8 @@ impl CharacterBehavior for Data {
|
||||
base_damage: self.base_damage,
|
||||
exhausted: false,
|
||||
});
|
||||
}
|
||||
// Hit attempt
|
||||
else if !self.exhausted {
|
||||
} else if !self.exhausted {
|
||||
// Hit attempt
|
||||
if let Some(tool) = unwrap_tool_data(data) {
|
||||
data.updater.insert(data.entity, Attacking {
|
||||
base_damage: self.base_damage,
|
||||
@ -53,16 +52,15 @@ impl CharacterBehavior for Data {
|
||||
});
|
||||
}
|
||||
|
||||
update.character = CharacterState::BasicAttack(Data {
|
||||
update.character = CharacterState::BasicMelee(Data {
|
||||
buildup_duration: self.buildup_duration,
|
||||
recover_duration: self.recover_duration,
|
||||
base_damage: self.base_damage,
|
||||
exhausted: true,
|
||||
});
|
||||
}
|
||||
// Recovery
|
||||
else if self.recover_duration != Duration::default() {
|
||||
update.character = CharacterState::BasicAttack(Data {
|
||||
} else if self.recover_duration != Duration::default() {
|
||||
// Recovery
|
||||
update.character = CharacterState::BasicMelee(Data {
|
||||
buildup_duration: self.buildup_duration,
|
||||
recover_duration: self
|
||||
.recover_duration
|
||||
@ -71,16 +69,11 @@ impl CharacterBehavior for Data {
|
||||
base_damage: self.base_damage,
|
||||
exhausted: true,
|
||||
});
|
||||
}
|
||||
// Done
|
||||
else {
|
||||
if let Some(tool) = unwrap_tool_data(data) {
|
||||
update.character = CharacterState::Wielding;
|
||||
// Make sure attack component is removed
|
||||
data.updater.remove::<Attacking>(data.entity);
|
||||
} else {
|
||||
update.character = CharacterState::Idle;
|
||||
}
|
||||
} else {
|
||||
// Done
|
||||
update.character = CharacterState::Wielding;
|
||||
// Make sure attack component is removed
|
||||
data.updater.remove::<Attacking>(data.entity);
|
||||
}
|
||||
|
||||
// Grant energy on successful hit
|
87
common/src/states/basic_ranged.rs
Normal file
87
common/src/states/basic_ranged.rs
Normal file
@ -0,0 +1,87 @@
|
||||
use crate::{
|
||||
comp::{Attacking, Body, CharacterState, EnergySource, Gravity, Projectile, StateUpdate},
|
||||
event::ServerEvent,
|
||||
states::{utils::*, wielding},
|
||||
sys::character_behavior::*,
|
||||
};
|
||||
use std::{collections::VecDeque, time::Duration};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Data {
|
||||
/// How long we prepared the weapon already
|
||||
pub prepare_timer: Duration,
|
||||
/// How long the state has until exiting
|
||||
pub recover_duration: Duration,
|
||||
/// Projectile
|
||||
pub projectile: Projectile,
|
||||
/// Projectile
|
||||
pub projectile_body: Body,
|
||||
/// Whether the attack fired already
|
||||
pub exhausted: bool,
|
||||
}
|
||||
|
||||
impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
pos: *data.pos,
|
||||
vel: *data.vel,
|
||||
ori: *data.ori,
|
||||
energy: *data.energy,
|
||||
character: data.character.clone(),
|
||||
local_events: VecDeque::new(),
|
||||
server_events: VecDeque::new(),
|
||||
};
|
||||
|
||||
handle_move(data, &mut update);
|
||||
handle_jump(data, &mut update);
|
||||
|
||||
if !self.exhausted
|
||||
&& (data.inputs.primary.is_pressed() | data.inputs.secondary.is_pressed())
|
||||
{
|
||||
// Prepare (draw the bow)
|
||||
update.character = CharacterState::BasicRanged(Data {
|
||||
prepare_timer: self.prepare_timer + Duration::from_secs_f32(data.dt.0),
|
||||
recover_duration: self.recover_duration,
|
||||
projectile: self.projectile.clone(),
|
||||
projectile_body: self.projectile_body,
|
||||
exhausted: false,
|
||||
});
|
||||
} else if !self.exhausted {
|
||||
// Fire
|
||||
update.server_events.push_front(ServerEvent::Shoot {
|
||||
entity: data.entity,
|
||||
dir: data.inputs.look_dir,
|
||||
body: self.projectile_body,
|
||||
light: None,
|
||||
projectile: self.projectile.clone(),
|
||||
gravity: Some(Gravity(0.1)),
|
||||
});
|
||||
|
||||
update.character = CharacterState::BasicRanged(Data {
|
||||
prepare_timer: self.prepare_timer,
|
||||
recover_duration: self.recover_duration,
|
||||
projectile: self.projectile.clone(),
|
||||
projectile_body: self.projectile_body,
|
||||
exhausted: true,
|
||||
});
|
||||
} else if self.recover_duration != Duration::default() {
|
||||
// Recovery
|
||||
update.character = CharacterState::BasicRanged(Data {
|
||||
prepare_timer: self.prepare_timer,
|
||||
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,
|
||||
exhausted: true,
|
||||
});
|
||||
return update;
|
||||
} else {
|
||||
// Done
|
||||
update.character = CharacterState::Wielding;
|
||||
}
|
||||
|
||||
update
|
||||
}
|
||||
}
|
59
common/src/states/boost.rs
Normal file
59
common/src/states/boost.rs
Normal file
@ -0,0 +1,59 @@
|
||||
use crate::{
|
||||
comp::{Attacking, CharacterState, EnergySource, StateUpdate},
|
||||
states::{utils::*, wielding},
|
||||
sys::character_behavior::*,
|
||||
};
|
||||
use std::{collections::VecDeque, time::Duration};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Data {
|
||||
/// How long the state has until exiting
|
||||
pub duration: Duration,
|
||||
pub only_up: bool,
|
||||
}
|
||||
|
||||
impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
pos: *data.pos,
|
||||
vel: *data.vel,
|
||||
ori: *data.ori,
|
||||
energy: *data.energy,
|
||||
character: data.character.clone(),
|
||||
local_events: VecDeque::new(),
|
||||
server_events: VecDeque::new(),
|
||||
};
|
||||
|
||||
handle_move(data, &mut update);
|
||||
|
||||
// Still going
|
||||
if self.duration != Duration::default() {
|
||||
if self.only_up {
|
||||
update.vel.0.z = 30.0;
|
||||
} else {
|
||||
update.vel.0 = data.inputs.look_dir * 30.0;
|
||||
}
|
||||
update.character = CharacterState::Boost(Data {
|
||||
duration: self
|
||||
.duration
|
||||
.checked_sub(Duration::from_secs_f32(data.dt.0))
|
||||
.unwrap_or_default(),
|
||||
only_up: self.only_up,
|
||||
});
|
||||
}
|
||||
// Done
|
||||
else {
|
||||
update.character = CharacterState::Wielding;
|
||||
}
|
||||
|
||||
// Grant energy on successful hit
|
||||
if let Some(attack) = data.attacking {
|
||||
if attack.applied && attack.hit_count > 0 {
|
||||
data.updater.remove::<Attacking>(data.entity);
|
||||
update.energy.change_by(100, EnergySource::HitEnemy);
|
||||
}
|
||||
}
|
||||
|
||||
update
|
||||
}
|
||||
}
|
@ -21,7 +21,7 @@ impl CharacterBehavior for Data {
|
||||
pos: *data.pos,
|
||||
vel: *data.vel,
|
||||
ori: *data.ori,
|
||||
character: *data.character,
|
||||
character: data.character.clone(),
|
||||
energy: *data.energy,
|
||||
local_events: VecDeque::new(),
|
||||
server_events: VecDeque::new(),
|
||||
|
@ -24,7 +24,7 @@ impl CharacterBehavior for Data {
|
||||
pos: *data.pos,
|
||||
vel: *data.vel,
|
||||
ori: *data.ori,
|
||||
character: *data.character,
|
||||
character: data.character.clone(),
|
||||
energy: *data.energy,
|
||||
local_events: VecDeque::new(),
|
||||
server_events: VecDeque::new(),
|
||||
|
@ -14,7 +14,7 @@ pub struct Data {
|
||||
impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
character: *data.character,
|
||||
character: data.character.clone(),
|
||||
pos: *data.pos,
|
||||
vel: *data.vel,
|
||||
ori: *data.ori,
|
||||
|
@ -20,7 +20,7 @@ impl CharacterBehavior for Data {
|
||||
vel: *data.vel,
|
||||
ori: *data.ori,
|
||||
energy: *data.energy,
|
||||
character: *data.character,
|
||||
character: data.character.clone(),
|
||||
local_events: VecDeque::new(),
|
||||
server_events: VecDeque::new(),
|
||||
};
|
||||
|
@ -10,7 +10,7 @@ pub struct Data;
|
||||
impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
character: *data.character,
|
||||
character: data.character.clone(),
|
||||
pos: *data.pos,
|
||||
vel: *data.vel,
|
||||
ori: *data.ori,
|
||||
|
@ -1,6 +1,7 @@
|
||||
// Module declarations
|
||||
pub mod basic_attack;
|
||||
pub mod basic_block;
|
||||
pub mod basic_melee;
|
||||
pub mod basic_ranged;
|
||||
pub mod boost;
|
||||
pub mod charge_attack;
|
||||
pub mod climb;
|
||||
pub mod equipping;
|
||||
|
@ -15,7 +15,7 @@ pub struct Data {
|
||||
impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
character: *data.character,
|
||||
character: data.character.clone(),
|
||||
pos: *data.pos,
|
||||
vel: *data.vel,
|
||||
ori: *data.ori,
|
||||
|
@ -11,7 +11,7 @@ pub struct Data;
|
||||
impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
character: *data.character,
|
||||
character: data.character.clone(),
|
||||
pos: *data.pos,
|
||||
vel: *data.vel,
|
||||
ori: *data.ori,
|
||||
|
@ -26,7 +26,7 @@ impl CharacterBehavior for Data {
|
||||
vel: *data.vel,
|
||||
ori: *data.ori,
|
||||
energy: *data.energy,
|
||||
character: *data.character,
|
||||
character: data.character.clone(),
|
||||
local_events: VecDeque::new(),
|
||||
server_events: VecDeque::new(),
|
||||
};
|
||||
|
@ -33,7 +33,7 @@ impl CharacterBehavior for Data {
|
||||
vel: *data.vel,
|
||||
ori: *data.ori,
|
||||
energy: *data.energy,
|
||||
character: *data.character,
|
||||
character: data.character.clone(),
|
||||
local_events: VecDeque::new(),
|
||||
server_events: VecDeque::new(),
|
||||
};
|
||||
|
@ -195,7 +195,7 @@ pub fn attempt_primary_ability(data: &JoinData, update: &mut StateUpdate) {
|
||||
.loadout
|
||||
.active_item
|
||||
.as_ref()
|
||||
.and_then(|i| i.primary_ability)
|
||||
.and_then(|i| i.primary_ability.as_ref())
|
||||
{
|
||||
update.character = ability.into();
|
||||
}
|
||||
@ -217,7 +217,7 @@ pub fn attempt_secondary_ability(data: &JoinData, update: &mut StateUpdate) {
|
||||
.loadout
|
||||
.active_item
|
||||
.as_ref()
|
||||
.and_then(|i| i.secondary_ability)
|
||||
.and_then(|i| i.secondary_ability.as_ref())
|
||||
{
|
||||
update.character = ability.into();
|
||||
}
|
||||
@ -246,7 +246,7 @@ pub fn attempt_dodge_ability(data: &JoinData, update: &mut StateUpdate) {
|
||||
.loadout
|
||||
.active_item
|
||||
.as_ref()
|
||||
.and_then(|i| i.dodge_ability)
|
||||
.and_then(|i| i.dodge_ability.as_ref())
|
||||
{
|
||||
update.character = ability.into();
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ pub struct Data;
|
||||
impl CharacterBehavior for Data {
|
||||
fn behavior(&self, data: &JoinData) -> StateUpdate {
|
||||
let mut update = StateUpdate {
|
||||
character: *data.character,
|
||||
character: data.character.clone(),
|
||||
pos: *data.pos,
|
||||
vel: *data.vel,
|
||||
ori: *data.ori,
|
||||
|
@ -182,7 +182,9 @@ impl<'a> System<'a> for Sys {
|
||||
CharacterState::Equipping(data) => data.behavior(&j),
|
||||
CharacterState::ChargeAttack(data) => data.behavior(&j),
|
||||
CharacterState::TripleStrike(data) => data.behavior(&j),
|
||||
CharacterState::BasicAttack(data) => data.behavior(&j),
|
||||
CharacterState::BasicMelee(data) => data.behavior(&j),
|
||||
CharacterState::BasicRanged(data) => data.behavior(&j),
|
||||
CharacterState::Boost(data) => data.behavior(&j),
|
||||
CharacterState::TimedCombo(data) => data.behavior(&j),
|
||||
|
||||
// Do not use default match.
|
||||
|
@ -77,8 +77,11 @@ impl<'a> System<'a> for Sys {
|
||||
entity,
|
||||
cause: HealthSource::World,
|
||||
}),
|
||||
projectile::Effect::Possess => server_emitter
|
||||
.emit(ServerEvent::Possess(projectile.owner.into(), other)),
|
||||
projectile::Effect::Possess => {
|
||||
if let Some(owner) = projectile.owner {
|
||||
server_emitter.emit(ServerEvent::Possess(owner.into(), other));
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
@ -283,17 +283,17 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(&character_state) = character_state {
|
||||
if let Some(&character_state) = character_state.as_ref() {
|
||||
if last_character_state
|
||||
.get(entity)
|
||||
.map(|&l| !character_state.equals(&l.0))
|
||||
.map(|l| !character_state.equals(&l.0))
|
||||
.unwrap_or(true)
|
||||
{
|
||||
let _ = last_character_state.insert(entity, Last(character_state));
|
||||
let _ = last_character_state.insert(entity, Last(character_state.clone()));
|
||||
send_msg(
|
||||
ServerMsg::EntityCharacterState {
|
||||
entity: uid.into(),
|
||||
character_state,
|
||||
character_state: character_state.clone(),
|
||||
},
|
||||
entity,
|
||||
pos,
|
||||
@ -367,7 +367,7 @@ pub fn send_initial_unsynced_components(
|
||||
if let Some(&ori) = ori {
|
||||
client.notify(ServerMsg::EntityOri { entity, ori });
|
||||
}
|
||||
if let Some(&character_state) = character_state {
|
||||
if let Some(character_state) = character_state.cloned() {
|
||||
client.notify(ServerMsg::EntityCharacterState {
|
||||
entity,
|
||||
character_state,
|
||||
|
@ -112,7 +112,7 @@ impl<'a> TrackedComps<'a> {
|
||||
.map(|c| comps.push(c.into()));
|
||||
self.character_state
|
||||
.get(entity)
|
||||
.copied()
|
||||
.cloned()
|
||||
.map(|c| comps.push(c.into()));
|
||||
|
||||
EntityPackage { uid, comps }
|
||||
|
@ -543,7 +543,7 @@ impl<'a> Widget for Skillbar<'a> {
|
||||
// M1 Slot
|
||||
|
||||
match self.character_state {
|
||||
CharacterState::BasicAttack { .. } => {
|
||||
CharacterState::BasicMelee { .. } => {
|
||||
if self.controller.primary.is_pressed() {
|
||||
let fade_pulse = (self.pulse * 4.0/* speed factor */).cos() * 0.5 + 0.6; //Animation timer;
|
||||
Image::new(self.imgs.skillbar_slot_big)
|
||||
@ -654,7 +654,7 @@ impl<'a> Widget for Skillbar<'a> {
|
||||
.set(state.ids.m2_slot, ui);
|
||||
}
|
||||
},*/
|
||||
CharacterState::BasicAttack { .. } => {
|
||||
CharacterState::BasicMelee { .. } => {
|
||||
let fade_pulse = (self.pulse * 4.0/* speed factor */).cos() * 0.5 + 0.6; //Animation timer;
|
||||
if self.controller.secondary.is_pressed() {
|
||||
Image::new(self.imgs.skillbar_slot_big)
|
||||
|
@ -6,7 +6,7 @@ use crate::{
|
||||
};
|
||||
use common::{
|
||||
assets::watch::ReloadIndicator,
|
||||
comp::{Body, CharacterState, ItemKind, Loadout},
|
||||
comp::{Body, CharacterState, ItemKind, Loadout, ToolKind},
|
||||
};
|
||||
use hashbrown::{hash_map::Entry, HashMap};
|
||||
use std::{
|
||||
@ -17,23 +17,26 @@ use std::{
|
||||
#[derive(PartialEq, Eq, Hash, Clone)]
|
||||
enum FigureKey {
|
||||
Simple(Body),
|
||||
Complex(
|
||||
Body,
|
||||
Option<Loadout>,
|
||||
CameraMode,
|
||||
Option<CharacterStateCacheKey>,
|
||||
),
|
||||
Complex(Body, CameraMode, Option<CharacterCacheKey>),
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Clone)]
|
||||
struct CharacterStateCacheKey {
|
||||
struct CharacterCacheKey {
|
||||
state: Discriminant<CharacterState>, // TODO: Can this be simplified?
|
||||
active_tool: Option<Discriminant<ToolKind>>, // TODO: Can this be simplified?
|
||||
}
|
||||
|
||||
impl From<&CharacterState> for CharacterStateCacheKey {
|
||||
fn from(cs: &CharacterState) -> Self {
|
||||
impl CharacterCacheKey {
|
||||
fn from(cs: &CharacterState, loadout: &Loadout) -> Self {
|
||||
Self {
|
||||
state: discriminant(&cs),
|
||||
active_tool: if let Some(ItemKind::Tool(tool)) =
|
||||
loadout.active_item.as_ref().map(|i| &i.item.kind)
|
||||
{
|
||||
Some(discriminant(&tool.kind))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -67,12 +70,11 @@ impl<Skel: Skeleton> FigureModelCache<Skel> {
|
||||
for<'a> &'a common::comp::Body: std::convert::TryInto<Skel::Attr>,
|
||||
Skel::Attr: Default,
|
||||
{
|
||||
let key = if loadout.is_some() {
|
||||
let key = if let Some(loadout) = loadout {
|
||||
FigureKey::Complex(
|
||||
body,
|
||||
loadout.cloned(),
|
||||
camera_mode,
|
||||
character_state.map(|cs| CharacterStateCacheKey::from(cs)),
|
||||
character_state.map(|cs| CharacterCacheKey::from(cs, loadout)),
|
||||
)
|
||||
} else {
|
||||
FigureKey::Simple(body)
|
||||
|
@ -468,7 +468,25 @@ impl FigureMgr {
|
||||
skeleton_attr,
|
||||
)
|
||||
},
|
||||
CharacterState::BasicAttack(_) => {
|
||||
CharacterState::BasicMelee(_) => {
|
||||
anim::character::AttackAnimation::update_skeleton(
|
||||
&target_base,
|
||||
(active_tool_kind, time),
|
||||
state.state_time,
|
||||
&mut state_animation_rate,
|
||||
skeleton_attr,
|
||||
)
|
||||
},
|
||||
CharacterState::BasicRanged(_) => {
|
||||
anim::character::AttackAnimation::update_skeleton(
|
||||
&target_base,
|
||||
(active_tool_kind, time),
|
||||
state.state_time,
|
||||
&mut state_animation_rate,
|
||||
skeleton_attr,
|
||||
)
|
||||
},
|
||||
CharacterState::Boost(_) => {
|
||||
anim::character::AttackAnimation::update_skeleton(
|
||||
&target_base,
|
||||
(active_tool_kind, time),
|
||||
|
@ -188,6 +188,13 @@ impl Scene {
|
||||
.get(scene_data.player_entity)
|
||||
.map_or(false, |cs| cs.is_dodge());
|
||||
|
||||
let player_running = scene_data
|
||||
.state
|
||||
.ecs()
|
||||
.read_storage::<comp::Vel>()
|
||||
.get(scene_data.player_entity)
|
||||
.map_or(false, |v| v.0.magnitude_squared() > 0.5);
|
||||
|
||||
let player_scale = match scene_data
|
||||
.state
|
||||
.ecs()
|
||||
@ -211,9 +218,11 @@ impl Scene {
|
||||
let up = match self.camera.get_mode() {
|
||||
CameraMode::FirstPerson => {
|
||||
if player_rolling {
|
||||
player_scale * 0.8_f32
|
||||
player_scale * 0.8
|
||||
} else if player_running {
|
||||
player_scale * 1.6 + (scene_data.state.get_time() as f32 * 17.0).sin() * 0.05
|
||||
} else {
|
||||
player_scale * 1.6_f32
|
||||
player_scale * 1.6
|
||||
}
|
||||
},
|
||||
CameraMode::ThirdPerson => 1.2,
|
||||
|
Loading…
Reference in New Issue
Block a user