mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
fix: attacking
This commit is contained in:
parent
d383abf950
commit
1f4065ae32
@ -131,24 +131,6 @@ impl Component for CharacterState {
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
|
||||
pub struct Attacking {
|
||||
pub weapon: ToolData,
|
||||
pub time_active: Duration,
|
||||
}
|
||||
|
||||
impl Attacking {
|
||||
pub fn remaining_duration(&self) -> Duration {
|
||||
self.weapon
|
||||
.attack_duration()
|
||||
.checked_sub(self.time_active)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn tick_time_active(&mut self, dt: Duration) {
|
||||
self.time_active = self.time_active.checked_add(dt).unwrap_or_default();
|
||||
}
|
||||
|
||||
pub fn can_apply_damage(&self) -> bool {
|
||||
(self.time_active > self.weapon.attack_buildup_duration())
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for Attacking {
|
||||
|
@ -8,8 +8,8 @@ use std::{collections::VecDeque, time::Duration};
|
||||
pub struct State {
|
||||
/// How long the state has until exitting
|
||||
pub remaining_duration: Duration,
|
||||
///Whether damage can be applied
|
||||
pub can_apply_damage: bool,
|
||||
/// Whether the attack can deal more damage
|
||||
pub exhausted: bool,
|
||||
}
|
||||
|
||||
impl StateHandler for State {
|
||||
@ -22,7 +22,7 @@ impl StateHandler for State {
|
||||
};
|
||||
Self {
|
||||
remaining_duration: tool_data.attack_duration(),
|
||||
can_apply_damage: false,
|
||||
exhausted: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,26 +36,44 @@ impl StateHandler for State {
|
||||
server_events: VecDeque::new(),
|
||||
};
|
||||
|
||||
// // Tick down
|
||||
// update.character = CharacterState::BasicAttack(Some(State {
|
||||
// remaining_duration: self
|
||||
// .remaining_duration
|
||||
// .checked_sub(Duration::from_secs_f32(ecs_data.dt.0))
|
||||
// .unwrap_or_default(),
|
||||
// can_apply_damage: if let Some(Tool(data)) =
|
||||
// ecs_data.stats.equipment.main.as_ref().map(|i| i.kind)
|
||||
// {
|
||||
// (self.remaining_duration < data.attack_recover_duration())
|
||||
// } else {
|
||||
// false
|
||||
// },
|
||||
// }));
|
||||
let tool_kind = ecs_data.stats.equipment.main.as_ref().map(|i| i.kind);
|
||||
|
||||
// // Check if attack duration has expired
|
||||
// if self.remaining_duration == Duration::default() {
|
||||
// update.character = CharacterState::Wielded(None);
|
||||
// ecs_data.updater.remove::<Attacking>(*ecs_data.entity);
|
||||
// }
|
||||
let can_apply_damage = !self.exhausted
|
||||
&& if let Some(Tool(data)) = tool_kind {
|
||||
(self.remaining_duration < data.attack_recover_duration())
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let mut exhausted = self.exhausted;
|
||||
|
||||
if can_apply_damage {
|
||||
if let Some(Tool(data)) = tool_kind {
|
||||
ecs_data
|
||||
.updater
|
||||
.insert(*ecs_data.entity, Attacking { weapon: data });
|
||||
exhausted = true;
|
||||
}
|
||||
} else {
|
||||
ecs_data.updater.remove::<Attacking>(*ecs_data.entity);
|
||||
}
|
||||
|
||||
let remaining_duration = self
|
||||
.remaining_duration
|
||||
.checked_sub(Duration::from_secs_f32(ecs_data.dt.0))
|
||||
.unwrap_or_default();
|
||||
|
||||
// Tick down
|
||||
update.character = CharacterState::BasicAttack(Some(State {
|
||||
remaining_duration,
|
||||
exhausted,
|
||||
}));
|
||||
|
||||
// Check if attack duration has expired
|
||||
if remaining_duration == Duration::default() {
|
||||
update.character = CharacterState::Wielded(None);
|
||||
ecs_data.updater.remove::<Attacking>(*ecs_data.entity);
|
||||
}
|
||||
|
||||
update
|
||||
}
|
||||
|
@ -97,13 +97,9 @@ pub fn handle_jump(ecs_data: &EcsStateData, update: &mut StateUpdate) {
|
||||
|
||||
pub fn handle_primary(ecs_data: &EcsStateData, update: &mut StateUpdate) {
|
||||
if let Some(state) = ecs_data.ability_pool.primary {
|
||||
if ecs_data.inputs.primary.is_pressed() {
|
||||
update.character = state;
|
||||
if let Some(Tool(data)) = ecs_data.stats.equipment.main.as_ref().map(|i| i.kind) {
|
||||
ecs_data.updater.insert(*ecs_data.entity, Attacking {
|
||||
weapon: data,
|
||||
time_active: Duration::default(),
|
||||
});
|
||||
if let CharacterState::Wielded(_) = update.character {
|
||||
if ecs_data.inputs.primary.is_pressed() {
|
||||
update.character = state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -68,66 +68,56 @@ impl<'a> System<'a> for Sys {
|
||||
)
|
||||
.join()
|
||||
{
|
||||
attack.tick_time_active(Duration::from_secs_f32(dt.0));
|
||||
// Go through all other entities
|
||||
for (b, uid_b, pos_b, ori_b, scale_b_maybe, character_b, stats_b, body_b) in (
|
||||
&entities,
|
||||
&uids,
|
||||
&positions,
|
||||
&orientations,
|
||||
scales.maybe(),
|
||||
&character_states,
|
||||
&stats,
|
||||
&bodies,
|
||||
)
|
||||
.join()
|
||||
{
|
||||
// 2D versions
|
||||
let pos2 = Vec2::from(pos.0);
|
||||
let pos_b2: Vec2<f32> = Vec2::from(pos_b.0);
|
||||
let ori2 = Vec2::from(ori.0);
|
||||
|
||||
if attack.can_apply_damage() {
|
||||
// Go through all other entities
|
||||
for (b, uid_b, pos_b, ori_b, scale_b_maybe, character_b, stats_b, body_b) in (
|
||||
&entities,
|
||||
&uids,
|
||||
&positions,
|
||||
&orientations,
|
||||
scales.maybe(),
|
||||
&character_states,
|
||||
&stats,
|
||||
&bodies,
|
||||
)
|
||||
.join()
|
||||
// Scales
|
||||
let scale = scale_maybe.map_or(1.0, |s| s.0);
|
||||
let scale_b = scale_b_maybe.map_or(1.0, |s| s.0);
|
||||
let rad_b = body_b.radius() * scale_b;
|
||||
|
||||
// Check if it is a hit
|
||||
if entity != b
|
||||
&& !stats_b.is_dead
|
||||
// Spherical wedge shaped attack field
|
||||
&& pos.0.distance_squared(pos_b.0) < (rad_b + scale * ATTACK_RANGE).powi(2)
|
||||
&& ori2.angle_between(pos_b2 - pos2) < ATTACK_ANGLE.to_radians() / 2.0 + (rad_b / pos2.distance(pos_b2)).atan()
|
||||
{
|
||||
// 2D versions
|
||||
let pos2 = Vec2::from(pos.0);
|
||||
let pos_b2: Vec2<f32> = Vec2::from(pos_b.0);
|
||||
let ori2 = Vec2::from(ori.0);
|
||||
// Weapon gives base damage
|
||||
let mut dmg = attack.weapon.base_damage as i32;
|
||||
|
||||
// Scales
|
||||
let scale = scale_maybe.map_or(1.0, |s| s.0);
|
||||
let scale_b = scale_b_maybe.map_or(1.0, |s| s.0);
|
||||
let rad_b = body_b.radius() * scale_b;
|
||||
|
||||
// Check if it is a hit
|
||||
if entity != b
|
||||
&& !stats_b.is_dead
|
||||
// Spherical wedge shaped attack field
|
||||
&& pos.0.distance_squared(pos_b.0) < (rad_b + scale * ATTACK_RANGE).powi(2)
|
||||
&& ori2.angle_between(pos_b2 - pos2) < ATTACK_ANGLE.to_radians() / 2.0 + (rad_b / pos2.distance(pos_b2)).atan()
|
||||
// Block
|
||||
if character_b.is_block()
|
||||
&& ori_b.0.angle_between(pos.0 - pos_b.0) < BLOCK_ANGLE.to_radians() / 2.0
|
||||
{
|
||||
// Weapon gives base damage
|
||||
let mut dmg = attack.weapon.base_damage as i32;
|
||||
|
||||
// Block
|
||||
if character_b.is_block()
|
||||
&& ori_b.0.angle_between(pos.0 - pos_b.0)
|
||||
< BLOCK_ANGLE.to_radians() / 2.0
|
||||
{
|
||||
dmg = (dmg as f32 * (1.0 - BLOCK_EFFICIENCY)) as i32
|
||||
}
|
||||
|
||||
server_bus.emitter().emit(ServerEvent::Damage {
|
||||
uid: *uid_b,
|
||||
change: HealthChange {
|
||||
amount: -dmg,
|
||||
cause: HealthSource::Attack { by: *uid },
|
||||
},
|
||||
});
|
||||
dmg = (dmg as f32 * (1.0 - BLOCK_EFFICIENCY)) as i32
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if attack.remaining_duration() == Duration::default() {
|
||||
if let Some(character) = character_states.get_mut(entity) {
|
||||
*character = CharacterState::Wielded(None);
|
||||
server_bus.emitter().emit(ServerEvent::Damage {
|
||||
uid: *uid_b,
|
||||
change: HealthChange {
|
||||
amount: -dmg,
|
||||
cause: HealthSource::Attack { by: *uid },
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
attacking_storage.clear();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user