2020-12-16 23:30:33 +00:00
|
|
|
use crate::comp::{Body, Loadout};
|
2020-12-05 18:23:45 +00:00
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use specs::{Component, FlaggedStorage};
|
|
|
|
use specs_idvs::IdvStorage;
|
2020-12-16 23:30:33 +00:00
|
|
|
use vek::*;
|
2020-12-05 18:23:45 +00:00
|
|
|
|
2020-12-19 02:05:39 +00:00
|
|
|
/// A change in the poise component. Stores the amount as a signed
|
|
|
|
/// integer to allow for added or removed poise. Also has a field to
|
|
|
|
/// label where the poise change came from.
|
2020-12-06 02:29:46 +00:00
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
|
|
|
pub struct PoiseChange {
|
2020-12-19 02:05:39 +00:00
|
|
|
/// Value of the change in poise
|
2020-12-06 02:29:46 +00:00
|
|
|
pub amount: i32,
|
2020-12-19 02:05:39 +00:00
|
|
|
/// Source of change in poise
|
2020-12-06 02:29:46 +00:00
|
|
|
pub source: PoiseSource,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PoiseChange {
|
2020-12-19 02:05:39 +00:00
|
|
|
/// Alters poise damage as a result of armor poise damage reduction
|
2020-12-16 23:30:33 +00:00
|
|
|
pub fn modify_poise_damage(self, loadout: Option<&Loadout>) -> PoiseChange {
|
|
|
|
let mut poise_damage = self.amount as f32;
|
2020-12-06 02:29:46 +00:00
|
|
|
match self.source {
|
|
|
|
PoiseSource::Melee => {
|
|
|
|
// Armor
|
2020-12-16 23:30:33 +00:00
|
|
|
let poise_damage_reduction =
|
|
|
|
loadout.map_or(0.0, |l| l.get_poise_damage_reduction());
|
|
|
|
poise_damage *= 1.0 - poise_damage_reduction;
|
2020-12-06 02:29:46 +00:00
|
|
|
PoiseChange {
|
2020-12-16 23:30:33 +00:00
|
|
|
amount: poise_damage as i32,
|
2020-12-06 02:29:46 +00:00
|
|
|
source: PoiseSource::Melee,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
PoiseSource::Projectile => {
|
|
|
|
// Armor
|
|
|
|
let damage_reduction = loadout.map_or(0.0, |l| l.get_poise_damage_reduction());
|
|
|
|
poise_damage *= 1.0 - damage_reduction;
|
|
|
|
PoiseChange {
|
2020-12-16 23:30:33 +00:00
|
|
|
amount: poise_damage as i32,
|
2020-12-06 02:29:46 +00:00
|
|
|
source: PoiseSource::Projectile,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
PoiseSource::Shockwave => {
|
|
|
|
// Armor
|
|
|
|
let damage_reduction = loadout.map_or(0.0, |l| l.get_poise_damage_reduction());
|
|
|
|
poise_damage *= 1.0 - damage_reduction;
|
|
|
|
PoiseChange {
|
2020-12-16 23:30:33 +00:00
|
|
|
amount: poise_damage as i32,
|
2020-12-06 02:29:46 +00:00
|
|
|
source: PoiseSource::Shockwave,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
PoiseSource::Explosion => {
|
|
|
|
// Armor
|
|
|
|
let damage_reduction = loadout.map_or(0.0, |l| l.get_poise_damage_reduction());
|
|
|
|
poise_damage *= 1.0 - damage_reduction;
|
|
|
|
PoiseChange {
|
2020-12-16 23:30:33 +00:00
|
|
|
amount: poise_damage as i32,
|
2020-12-06 02:29:46 +00:00
|
|
|
source: PoiseSource::Explosion,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
PoiseSource::Falling => {
|
|
|
|
// Armor
|
|
|
|
let damage_reduction = loadout.map_or(0.0, |l| l.get_poise_damage_reduction());
|
|
|
|
if (damage_reduction - 1.0).abs() < f32::EPSILON {
|
|
|
|
poise_damage = 0.0;
|
|
|
|
}
|
|
|
|
PoiseChange {
|
2020-12-16 23:30:33 +00:00
|
|
|
amount: poise_damage as i32,
|
2020-12-06 02:29:46 +00:00
|
|
|
source: PoiseSource::Falling,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => PoiseChange {
|
|
|
|
amount: self.amount,
|
|
|
|
source: PoiseSource::Other,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-19 02:05:39 +00:00
|
|
|
/// Sources of poise change
|
2020-12-06 02:29:46 +00:00
|
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
|
|
|
pub enum PoiseSource {
|
|
|
|
LevelUp,
|
|
|
|
Melee,
|
|
|
|
Projectile,
|
|
|
|
Explosion,
|
|
|
|
Beam,
|
|
|
|
Shockwave,
|
|
|
|
Falling,
|
|
|
|
Revive,
|
2020-12-10 00:32:24 +00:00
|
|
|
Regen,
|
2020-12-06 02:29:46 +00:00
|
|
|
Other,
|
|
|
|
}
|
|
|
|
|
2020-12-19 02:05:39 +00:00
|
|
|
/// Poise component
|
2020-12-05 18:23:45 +00:00
|
|
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
|
|
|
pub struct Poise {
|
2020-12-19 02:05:39 +00:00
|
|
|
/// Base poise amount for this entity
|
2020-12-05 18:23:45 +00:00
|
|
|
base_max: u32,
|
2020-12-19 02:05:39 +00:00
|
|
|
/// Poise of entity at any given moment
|
2020-12-05 18:23:45 +00:00
|
|
|
current: u32,
|
2020-12-19 02:05:39 +00:00
|
|
|
/// Maximum poise of entity at a given time
|
2020-12-05 18:23:45 +00:00
|
|
|
maximum: u32,
|
2020-12-19 02:05:39 +00:00
|
|
|
/// Knockback direction of last change, for use as an effect in sys/stats.rs
|
2020-12-16 23:30:33 +00:00
|
|
|
knockback: Vec3<f32>,
|
2020-12-19 02:05:39 +00:00
|
|
|
/// Last poise change, storing time since last change
|
2020-12-16 23:30:33 +00:00
|
|
|
pub last_change: (f64, PoiseChange),
|
2020-12-19 02:05:39 +00:00
|
|
|
/// Rate of poise regeneration per tick. Starts at zero and accelerates.
|
2020-12-10 00:32:24 +00:00
|
|
|
pub regen_rate: f32,
|
2020-12-05 18:23:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for Poise {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
current: 0,
|
|
|
|
maximum: 0,
|
|
|
|
base_max: 0,
|
2020-12-16 23:30:33 +00:00
|
|
|
knockback: Vec3::zero(),
|
|
|
|
last_change: (0.0, PoiseChange {
|
|
|
|
amount: 0,
|
|
|
|
source: PoiseSource::Revive,
|
|
|
|
}),
|
2020-12-10 00:32:24 +00:00
|
|
|
regen_rate: 0.0,
|
2020-12-05 18:23:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-19 02:05:39 +00:00
|
|
|
/// States to define effects of a poise change
|
2020-12-05 18:23:45 +00:00
|
|
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
|
|
|
pub enum PoiseState {
|
2020-12-19 02:05:39 +00:00
|
|
|
/// No effect applied
|
2020-12-05 18:23:45 +00:00
|
|
|
Normal,
|
2020-12-19 02:05:39 +00:00
|
|
|
/// Poise reset, and target briefly stunned
|
2020-12-05 18:23:45 +00:00
|
|
|
Interrupted,
|
2020-12-19 02:05:39 +00:00
|
|
|
/// Poise reset, target stunned and knocked back horizontally
|
2020-12-05 18:23:45 +00:00
|
|
|
Stunned,
|
2020-12-19 02:05:39 +00:00
|
|
|
/// Poise reset, target staggered
|
2020-12-05 18:23:45 +00:00
|
|
|
Dazed,
|
2020-12-19 02:05:39 +00:00
|
|
|
/// Poise reset, target staggered and knocked back further
|
2020-12-05 18:23:45 +00:00
|
|
|
KnockedDown,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Poise {
|
2020-12-19 02:05:39 +00:00
|
|
|
/// Creates a new poise struct based on the body it is being assigned to
|
2020-12-05 18:23:45 +00:00
|
|
|
pub fn new(body: Body) -> Self {
|
|
|
|
let mut poise = Poise::default();
|
2020-12-19 02:05:39 +00:00
|
|
|
poise.update_base_max(Some(body));
|
|
|
|
poise.set_maximum(poise.base_max);
|
|
|
|
poise.set_to(poise.maximum, PoiseSource::Revive);
|
2020-12-05 18:23:45 +00:00
|
|
|
|
|
|
|
poise
|
|
|
|
}
|
|
|
|
|
2020-12-19 02:05:39 +00:00
|
|
|
/// Returns knockback as a Vec3
|
2020-12-16 23:30:33 +00:00
|
|
|
pub fn knockback(&self) -> Vec3<f32> { self.knockback }
|
|
|
|
|
2020-12-19 02:05:39 +00:00
|
|
|
/// Defines the poise states based on fraction of maximum poise
|
2020-12-05 18:23:45 +00:00
|
|
|
pub fn poise_state(&self) -> PoiseState {
|
2020-12-16 23:30:33 +00:00
|
|
|
if self.current >= 8 * self.maximum / 10 {
|
2020-12-05 18:23:45 +00:00
|
|
|
PoiseState::Normal
|
2020-12-16 23:30:33 +00:00
|
|
|
} else if self.current >= 7 * self.maximum / 10 {
|
2020-12-05 18:23:45 +00:00
|
|
|
PoiseState::Interrupted
|
2020-12-16 23:30:33 +00:00
|
|
|
} else if self.current >= 6 * self.maximum / 10 {
|
2020-12-05 18:23:45 +00:00
|
|
|
PoiseState::Stunned
|
2020-12-16 23:30:33 +00:00
|
|
|
} else if self.current >= 4 * self.maximum / 10 {
|
2020-12-05 18:23:45 +00:00
|
|
|
PoiseState::Dazed
|
|
|
|
} else {
|
|
|
|
PoiseState::KnockedDown
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-19 02:05:39 +00:00
|
|
|
/// Gets the current poise value
|
2020-12-05 18:23:45 +00:00
|
|
|
pub fn current(&self) -> u32 { self.current }
|
|
|
|
|
2020-12-19 02:05:39 +00:00
|
|
|
/// Gets the maximum poise value
|
2020-12-05 18:23:45 +00:00
|
|
|
pub fn maximum(&self) -> u32 { self.maximum }
|
|
|
|
|
2020-12-19 02:05:39 +00:00
|
|
|
/// Gets the base_max value
|
|
|
|
pub fn base_max(&self) -> u32 { self.base_max }
|
|
|
|
|
|
|
|
/// Sets the poise value to a provided value. First cuts off the value
|
|
|
|
/// at the maximum. In most cases change_by() should be used.
|
2020-12-16 23:30:33 +00:00
|
|
|
pub fn set_to(&mut self, amount: u32, cause: PoiseSource) {
|
2020-12-05 18:23:45 +00:00
|
|
|
let amount = amount.min(self.maximum);
|
2020-12-16 23:30:33 +00:00
|
|
|
self.last_change = (0.0, PoiseChange {
|
|
|
|
amount: amount as i32 - self.current as i32,
|
|
|
|
source: cause,
|
|
|
|
});
|
2020-12-05 18:23:45 +00:00
|
|
|
self.current = amount;
|
|
|
|
}
|
|
|
|
|
2020-12-19 02:05:39 +00:00
|
|
|
/// Changes the current poise due to an in-game effect.
|
2020-12-16 23:30:33 +00:00
|
|
|
pub fn change_by(&mut self, change: PoiseChange, impulse: Vec3<f32>) {
|
2020-12-06 02:29:46 +00:00
|
|
|
self.current = ((self.current as i32 + change.amount).max(0) as u32).min(self.maximum);
|
2020-12-16 23:30:33 +00:00
|
|
|
self.knockback = impulse;
|
|
|
|
self.last_change = (0.0, PoiseChange {
|
|
|
|
amount: change.amount,
|
|
|
|
source: change.source,
|
|
|
|
});
|
2020-12-05 18:23:45 +00:00
|
|
|
}
|
|
|
|
|
2020-12-19 02:05:39 +00:00
|
|
|
/// Resets current value to maximum
|
2020-12-05 18:23:45 +00:00
|
|
|
pub fn reset(&mut self) { self.current = self.maximum; }
|
|
|
|
|
2020-12-19 02:05:39 +00:00
|
|
|
/// Sets the maximum and updates the current value to max out at the new
|
|
|
|
/// maximum
|
2020-12-05 18:23:45 +00:00
|
|
|
pub fn set_maximum(&mut self, amount: u32) {
|
|
|
|
self.maximum = amount;
|
|
|
|
self.current = self.current.min(self.maximum);
|
|
|
|
}
|
|
|
|
|
2020-12-19 02:05:39 +00:00
|
|
|
/// Sets the `Poise` base_max
|
2020-12-05 18:23:45 +00:00
|
|
|
fn set_base_max(&mut self, amount: u32) {
|
|
|
|
self.base_max = amount;
|
|
|
|
self.current = self.current.min(self.maximum);
|
|
|
|
}
|
|
|
|
|
2020-12-19 02:05:39 +00:00
|
|
|
/// Resets the maximum to the base_max. Example use would be a potion
|
|
|
|
/// wearing off
|
2020-12-05 18:23:45 +00:00
|
|
|
pub fn reset_max(&mut self) { self.maximum = self.base_max; }
|
|
|
|
|
2020-12-19 02:05:39 +00:00
|
|
|
/// Sets the base_max based on the entity `Body`
|
|
|
|
pub fn update_base_max(&mut self, body: Option<Body>) {
|
2020-12-05 18:23:45 +00:00
|
|
|
if let Some(body) = body {
|
|
|
|
self.set_base_max(body.base_poise());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Component for Poise {
|
|
|
|
type Storage = FlaggedStorage<Self, IdvStorage<Self>>;
|
|
|
|
}
|