fix: attacking

This commit is contained in:
timokoesters 2020-02-24 14:32:12 +01:00
parent d383abf950
commit 1f4065ae32
4 changed files with 85 additions and 99 deletions

View File

@ -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 {

View File

@ -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
}

View File

@ -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;
}
}
}

View File

@ -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();
}
}