add maxhealthmodifier

oops variable
This commit is contained in:
Adam Whitehurst
2020-10-24 16:07:38 -07:00
committed by Sam
parent 8aad7adab8
commit f759895d63
6 changed files with 76 additions and 52 deletions

View File

@ -49,13 +49,19 @@ pub enum BuffCategory {
PersistOnDeath, PersistOnDeath,
} }
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum ModifierKind {
Additive,
Multiplicative,
}
/// Data indicating and configuring behaviour of a de/buff. /// Data indicating and configuring behaviour of a de/buff.
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub enum BuffEffect { pub enum BuffEffect {
/// Periodically damages or heals entity /// Periodically damages or heals entity
HealthChangeOverTime { rate: f32, accumulated: f32 }, HealthChangeOverTime { rate: f32, accumulated: f32 },
/// Changes name on_add/on_remove /// Changes maximum health by a certain amount
NameChange { prefix: String }, MaxHealthModifier { value: f32, kind: ModifierKind },
} }
/// Actual de/buff. /// Actual de/buff.
@ -125,8 +131,9 @@ impl Buff {
data.duration, data.duration,
), ),
BuffKind::Cursed => ( BuffKind::Cursed => (
vec![BuffEffect::NameChange { vec![BuffEffect::MaxHealthModifier {
prefix: String::from("Cursed "), value: -100.,
kind: ModifierKind::Additive,
}], }],
data.duration, data.duration,
), ),

View File

@ -34,6 +34,7 @@ pub use body::{
}; };
pub use buff::{ pub use buff::{
Buff, BuffCategory, BuffChange, BuffData, BuffEffect, BuffId, BuffKind, BuffSource, Buffs, Buff, BuffCategory, BuffChange, BuffData, BuffEffect, BuffId, BuffKind, BuffSource, Buffs,
ModifierKind,
}; };
pub use character_state::{Attacking, CharacterState, StateUpdate}; pub use character_state::{Attacking, CharacterState, StateUpdate};
pub use chat::{ pub use chat::{

View File

@ -8,6 +8,7 @@ use specs::{Component, FlaggedStorage};
use specs_idvs::IdvStorage; use specs_idvs::IdvStorage;
use std::{error::Error, fmt}; use std::{error::Error, fmt};
/// Specifies what and how much changed current health
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
pub struct HealthChange { pub struct HealthChange {
pub amount: i32, pub amount: i32,
@ -33,6 +34,7 @@ pub enum HealthSource {
#[derive(Clone, Copy, Debug, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct Health { pub struct Health {
base_max: u32,
current: u32, current: u32,
maximum: u32, maximum: u32,
pub last_change: (f64, HealthChange), pub last_change: (f64, HealthChange),
@ -69,10 +71,18 @@ impl Health {
} }
// This is private because max hp is based on the level // This is private because max hp is based on the level
fn set_maximum(&mut self, amount: u32) { pub fn set_maximum(&mut self, amount: u32) {
self.maximum = amount; self.maximum = amount;
self.current = self.current.min(self.maximum); self.current = self.current.min(self.maximum);
} }
// This is private because max hp is based on the level
fn set_base_max(&mut self, amount: u32) {
self.base_max = amount;
self.current = self.current.min(self.maximum);
}
pub fn reset_max(&mut self) { self.maximum = self.base_max; }
} }
#[derive(Debug)] #[derive(Debug)]
pub enum StatChangeError { pub enum StatChangeError {
@ -149,6 +159,8 @@ impl Stats {
// TODO: Delete this once stat points will be a thing // TODO: Delete this once stat points will be a thing
pub fn update_max_hp(&mut self, body: Body) { pub fn update_max_hp(&mut self, body: Body) {
self.health
.set_base_max(body.base_health() + body.base_health_increase() * self.level.amount);
self.health self.health
.set_maximum(body.base_health() + body.base_health_increase() * self.level.amount); .set_maximum(body.base_health() + body.base_health_increase() * self.level.amount);
} }
@ -180,6 +192,7 @@ impl Stats {
health: Health { health: Health {
current: 0, current: 0,
maximum: 0, maximum: 0,
base_max: 0,
last_change: (0.0, HealthChange { last_change: (0.0, HealthChange {
amount: 0, amount: 0,
cause: HealthSource::Revive, cause: HealthSource::Revive,
@ -199,6 +212,7 @@ impl Stats {
}; };
stats.update_max_hp(body); stats.update_max_hp(body);
stats stats
.health .health
.set_to(stats.health.maximum(), HealthSource::Revive); .set_to(stats.health.maximum(), HealthSource::Revive);
@ -214,6 +228,7 @@ impl Stats {
health: Health { health: Health {
current: 0, current: 0,
maximum: 0, maximum: 0,
base_max: 0,
last_change: (0.0, HealthChange { last_change: (0.0, HealthChange {
amount: 0, amount: 0,
cause: HealthSource::Revive, cause: HealthSource::Revive,

View File

@ -1,7 +1,7 @@
use crate::{ use crate::{
comp::{ comp::{
BuffCategory, BuffChange, BuffEffect, BuffId, BuffSource, Buffs, HealthChange, BuffCategory, BuffChange, BuffEffect, BuffId, BuffSource, Buffs, HealthChange,
HealthSource, Stats, HealthSource, ModifierKind, Stats,
}, },
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
state::DeltaTime, state::DeltaTime,
@ -17,15 +17,15 @@ impl<'a> System<'a> for Sys {
Read<'a, DeltaTime>, Read<'a, DeltaTime>,
Read<'a, EventBus<ServerEvent>>, Read<'a, EventBus<ServerEvent>>,
ReadStorage<'a, Uid>, ReadStorage<'a, Uid>,
ReadStorage<'a, Stats>, WriteStorage<'a, Stats>,
WriteStorage<'a, Buffs>, WriteStorage<'a, Buffs>,
); );
fn run(&mut self, (dt, server_bus, uids, stats, mut buffs): Self::SystemData) { fn run(&mut self, (dt, server_bus, uids, mut stats, mut buffs): Self::SystemData) {
let mut server_emitter = server_bus.emitter(); let mut server_emitter = server_bus.emitter();
// Set to false to avoid spamming server // Set to false to avoid spamming server
buffs.set_event_emission(false); // buffs.set_event_emission(false);
for (buff_comp, uid, stat) in (&mut buffs, &uids, &stats).join() { for (buff_comp, uid, stat) in (&mut buffs, &uids, &mut stats).join() {
let mut expired_buffs = Vec::<BuffId>::new(); let mut expired_buffs = Vec::<BuffId>::new();
for (id, buff) in buff_comp.buffs.iter_mut() { for (id, buff) in buff_comp.buffs.iter_mut() {
// Tick the buff and subtract delta from it // Tick the buff and subtract delta from it
@ -36,6 +36,9 @@ impl<'a> System<'a> for Sys {
// The buff still continues. // The buff still continues.
*remaining_time = new_duration; *remaining_time = new_duration;
} else { } else {
// checked_sub returns None when remaining time
// went below 0, so set to 0
*remaining_time = Duration::default();
// The buff has expired. // The buff has expired.
// Remove it. // Remove it.
expired_buffs.push(*id); expired_buffs.push(*id);
@ -43,14 +46,20 @@ impl<'a> System<'a> for Sys {
} }
} }
// Call to reset stats to base values
stat.health.reset_max();
// Iterator over the lists of buffs by kind
for buff_ids in buff_comp.kinds.values() { for buff_ids in buff_comp.kinds.values() {
// Get the strongest of this buff kind
if let Some(buff) = buff_comp.buffs.get_mut(&buff_ids[0]) { if let Some(buff) = buff_comp.buffs.get_mut(&buff_ids[0]) {
// Get buff owner // Get buff owner?
let buff_owner = if let BuffSource::Character { by: owner } = buff.source { let buff_owner = if let BuffSource::Character { by: owner } = buff.source {
Some(owner) Some(owner)
} else { } else {
None None
}; };
// Now, execute the buff, based on it's delta // Now, execute the buff, based on it's delta
for effect in &mut buff.effects { for effect in &mut buff.effects {
match effect { match effect {
@ -77,7 +86,18 @@ impl<'a> System<'a> for Sys {
*accumulated = 0.0; *accumulated = 0.0;
}; };
}, },
BuffEffect::NameChange { .. } => {}, BuffEffect::MaxHealthModifier { value, kind } => match kind {
ModifierKind::Multiplicative => {
stat.health.set_maximum(
(stat.health.maximum() as f32 * *value) as u32,
);
},
ModifierKind::Additive => {
stat.health.set_maximum(
(stat.health.maximum() as f32 + *value) as u32,
);
},
},
}; };
} }
} }
@ -103,6 +123,6 @@ impl<'a> System<'a> for Sys {
}); });
} }
} }
buffs.set_event_emission(true); // buffs.set_event_emission(true);
} }
} }

View File

@ -152,19 +152,34 @@ impl<'a> System<'a> for Sys {
cause, cause,
}, },
}); });
use buff::*;
server_emitter.emit(ServerEvent::Buff {
uid: *uid_b,
buff_change: BuffChange::Add(Buff::new(
BuffKind::Cursed,
BuffData {
strength: attack.base_damage as f32 / 10.0,
duration: Some(Duration::from_secs(10)),
},
vec![BuffCategory::Physical],
BuffSource::Character { by: *uid },
)),
});
// Apply bleeding buff on melee hits with 10% chance // Apply bleeding buff on melee hits with 10% chance
// TODO: Don't have buff uniformly applied on all melee attacks // TODO: Don't have buff uniformly applied on all melee attacks
if thread_rng().gen::<f32>() < 0.1 { if thread_rng().gen::<f32>() < 0.1 {
server_emitter.emit(ServerEvent::Buff { server_emitter.emit(ServerEvent::Buff {
uid: *uid_b, uid: *uid_b,
buff_change: buff::BuffChange::Add(buff::Buff::new( buff_change: BuffChange::Add(Buff::new(
buff::BuffKind::Bleeding, BuffKind::Bleeding,
buff::BuffData { BuffData {
strength: attack.base_damage as f32 / 10.0, strength: attack.base_damage as f32 / 10.0,
duration: Some(Duration::from_secs(10)), duration: Some(Duration::from_secs(10)),
}, },
vec![buff::BuffCategory::Physical], vec![BuffCategory::Physical],
buff::BuffSource::Character { by: *uid }, BuffSource::Character { by: *uid },
)), )),
}); });
} }

View File

@ -704,7 +704,6 @@ pub fn handle_buff(server: &mut Server, uid: Uid, buff_change: buff::BuffChange)
let mut buffs_all = ecs.write_storage::<comp::Buffs>(); let mut buffs_all = ecs.write_storage::<comp::Buffs>();
if let Some(entity) = ecs.entity_from_uid(uid.into()) { if let Some(entity) = ecs.entity_from_uid(uid.into()) {
if let Some(buffs) = buffs_all.get_mut(entity) { if let Some(buffs) = buffs_all.get_mut(entity) {
let mut stats = ecs.write_storage::<comp::Stats>();
use buff::BuffChange; use buff::BuffChange;
match buff_change { match buff_change {
BuffChange::Add(new_buff) => { BuffChange::Add(new_buff) => {
@ -763,36 +762,3 @@ pub fn handle_buff(server: &mut Server, uid: Uid, buff_change: buff::BuffChange)
} }
} }
} }
fn add_buff_effects(buff: buff::Buff, mut stats: Option<&mut Stats>) {
for effect in &buff.effects {
use buff::BuffEffect;
match effect {
// Only add an effect here if it is immediate and is not continuous
BuffEffect::NameChange { prefix } => {
if let Some(ref mut stats) = stats {
let mut pref = String::from(prefix);
pref.push_str(&stats.name);
stats.name = pref;
}
},
BuffEffect::HealthChangeOverTime { .. } => {},
}
}
}
fn remove_buff_effects(buff: buff::Buff, mut stats: Option<&mut Stats>) {
for effect in &buff.effects {
#[allow(clippy::single_match)] // Remove clippy when there are more buff effects here
match effect {
// Only remove an effect here if its effect was not continuously
// applied
buff::BuffEffect::NameChange { prefix } => {
if let Some(ref mut stats) = stats {
stats.name = stats.name.replacen(prefix, "", 1);
}
},
_ => {},
}
}
}