veloren/common/src/combat.rs

187 lines
5.7 KiB
Rust
Raw Normal View History

use crate::{
comp::{HealthChange, HealthSource, Loadout},
sync::Uid,
2020-10-18 18:21:58 +00:00
util::Dir,
};
use serde::{Deserialize, Serialize};
2020-10-18 18:21:58 +00:00
use vek::*;
pub const BLOCK_EFFICIENCY: f32 = 0.9;
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Damages {
pub enemy: Option<Damage>,
pub group: Option<Damage>,
}
impl Damages {
pub fn new(enemy: Option<Damage>, group: Option<Damage>) -> Self { Damages { enemy, group } }
}
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Damage {
Melee(f32),
Healing(f32),
Projectile(f32),
Explosion(f32),
Falling(f32),
Shockwave(f32),
Energy(f32),
}
impl Damage {
pub fn modify_damage(
self,
block: bool,
loadout: Option<&Loadout>,
uid: Option<Uid>,
) -> HealthChange {
match self {
Damage::Melee(damage) => {
let mut damage = damage;
// Critical hit
let mut critdamage = 0.0;
if rand::random() {
critdamage = damage * 0.3;
}
// Block
if block {
damage *= 1.0 - BLOCK_EFFICIENCY
}
// Armor
let damage_reduction = if let Some(loadout) = loadout {
loadout.get_damage_reduction()
} else {
0.0
};
damage *= 1.0 - damage_reduction;
// Critical damage applies after armor for melee
if (damage_reduction - 1.0).abs() > f32::EPSILON {
damage += critdamage;
}
HealthChange {
amount: -damage as i32,
cause: HealthSource::Attack { by: uid.unwrap() },
}
},
Damage::Projectile(damage) => {
let mut damage = damage;
// Critical hit
if rand::random() {
damage *= 1.2;
}
// Block
if block {
damage *= 1.0 - BLOCK_EFFICIENCY
}
// Armor
let damage_reduction = if let Some(loadout) = loadout {
loadout.get_damage_reduction()
} else {
0.0
};
damage *= 1.0 - damage_reduction;
HealthChange {
amount: -damage as i32,
cause: HealthSource::Projectile { owner: uid },
}
},
Damage::Explosion(damage) => {
let mut damage = damage;
// Block
if block {
damage *= 1.0 - BLOCK_EFFICIENCY
}
// Armor
let damage_reduction = if let Some(loadout) = loadout {
loadout.get_damage_reduction()
} else {
0.0
};
damage *= 1.0 - damage_reduction;
HealthChange {
amount: -damage as i32,
cause: HealthSource::Explosion { owner: uid },
}
},
Damage::Shockwave(damage) => {
let mut damage = damage;
// Armor
let damage_reduction = if let Some(loadout) = loadout {
loadout.get_damage_reduction()
} else {
0.0
};
damage *= 1.0 - damage_reduction;
HealthChange {
amount: -damage as i32,
cause: HealthSource::Attack { by: uid.unwrap() },
}
},
Damage::Energy(damage) => {
let mut damage = damage;
// Armor
let damage_reduction = if let Some(loadout) = loadout {
loadout.get_damage_reduction()
} else {
0.0
};
damage *= 1.0 - damage_reduction;
HealthChange {
amount: -damage as i32,
cause: HealthSource::Energy { owner: uid },
}
},
Damage::Healing(heal) => HealthChange {
amount: heal as i32,
cause: HealthSource::Healing { by: uid },
},
Damage::Falling(damage) => {
let mut damage = damage;
// Armor
let damage_reduction = if let Some(loadout) = loadout {
loadout.get_damage_reduction()
} else {
0.0
};
if (damage_reduction - 1.0).abs() < f32::EPSILON {
damage = 0.0;
}
HealthChange {
amount: -damage as i32,
cause: HealthSource::World,
}
},
}
}
}
2020-10-18 18:21:58 +00:00
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Knockback {
Away(f32),
Towards(f32),
Up(f32),
TowardsUp(f32),
}
impl Knockback {
pub fn get_knockback(self, dir: Dir) -> Vec3<f32> {
match self {
Knockback::Away(strength) => strength * *Dir::slerp(dir, Dir::new(Vec3::unit_z()), 0.5),
Knockback::Towards(strength) => {
strength * *Dir::slerp(-dir, Dir::new(Vec3::unit_z()), 0.5)
},
Knockback::Up(strength) => strength * Vec3::unit_z(),
Knockback::TowardsUp(strength) => {
strength * *Dir::slerp(-dir, Dir::new(Vec3::unit_z()), 0.85)
},
}
}
}