HpFloaters are now created by Outcomes, touched up Damage Outcome

This commit is contained in:
socksonme 2022-01-20 23:05:49 +02:00 committed by Socksonme
parent bf6c6fb33d
commit aee7888a92
5 changed files with 75 additions and 73 deletions

View File

@ -238,9 +238,14 @@ impl Attack {
);
let applied_damage = -change.amount;
accumulated_damage += applied_damage;
// TODO: Check this out later
// if applied_damage > 0.0 {
//
// }
emit_outcome(Outcome::Damage {
pos: target.pos,
uid: target.uid,
target: target.uid,
by: attacker.map(|a| a.uid),
amount: applied_damage,
crit: is_crit,
});

View File

@ -60,10 +60,10 @@ pub enum Outcome {
},
Damage {
pos: Vec3<f32>,
/// The exact amount of damage delt,
/// excluding any sources of healing
amount: f32,
uid: Uid,
target: Uid,
by: Option<Uid>,
// TODO: Maybe seperate attack data/info into seperate struct?
crit: bool,
},
Death {

View File

@ -1,8 +1,7 @@
use crate::ecs::comp::{HpFloater, HpFloaterList};
use crate::ecs::comp::HpFloaterList;
use common::{
comp::{Health, Pos},
resources::{DeltaTime, PlayerEntity},
uid::Uid,
};
use common_ecs::{Job, Origin, Phase, System};
use specs::{Entities, Join, Read, ReadStorage, WriteStorage};
@ -19,7 +18,6 @@ impl<'a> System<'a> for Sys {
Entities<'a>,
Read<'a, PlayerEntity>,
Read<'a, DeltaTime>,
ReadStorage<'a, Uid>,
ReadStorage<'a, Pos>,
ReadStorage<'a, Health>,
WriteStorage<'a, HpFloaterList>,
@ -32,7 +30,7 @@ impl<'a> System<'a> for Sys {
#[allow(clippy::blocks_in_if_conditions)] // TODO: Pending review in #587
fn run(
_job: &mut Job<Self>,
(entities, my_entity, dt, uids, pos, healths, mut hp_floater_lists): Self::SystemData,
(entities, my_entity, dt, pos, healths, mut hp_floater_lists): Self::SystemData,
) {
// Add hp floater lists to all entities with health and a position
// Note: necessary in order to know last_hp
@ -48,70 +46,12 @@ impl<'a> System<'a> for Sys {
});
}
// Add hp floaters to all entities that have been damaged
let my_uid = my_entity.0.and_then(|entity| uids.get(entity));
for (entity, health, hp_floater_list) in (&entities, &healths, &mut hp_floater_lists).join()
{
for hp_floater_list in (&mut hp_floater_lists).join() {
// Increment timer for time since last damaged by me
hp_floater_list
.time_since_last_dmg_by_me
.as_mut()
.map(|t| *t += dt.0);
// Check if health has changed (won't work if damaged and then healed with
// equivalently in the same frame)
if (hp_floater_list.last_hp - health.current()).abs() > Health::HEALTH_EPSILON {
hp_floater_list.last_hp = health.current();
// TODO: What if multiple health changes occurred since last check here
// Also, If we make health store a vec of the last_changes (from say the last
// frame), what if the client receives the health component from
// two different server ticks at once, then one will be lost
// (tbf this is probably a rare occurance and the results
// would just be a transient glitch in the display of these damage numbers)
// (maybe health changes could be sent to the client as a list
// of events)
if match health.last_change.by.map(|x| x.uid()) {
// HealthSource::Damage { by: Some(by), .. }
// | HealthSource::Heal { by: Some(by) } => {
// let by_me = my_uid.map_or(false, |&uid| by == uid);
// // If the attack was by me also reset this timer
// if by_me {
// hp_floater_list.time_since_last_dmg_by_me = Some(0.0);
// }
// my_entity.0 == Some(entity) || by_me
// },
// HealthSource::Suicide => my_entity.0 == Some(entity),
// HealthSource::World => my_entity.0 == Some(entity),
// HealthSource::LevelUp => my_entity.0 == Some(entity),
// HealthSource::Command => true,
// HealthSource::Item => true,
// _ => false,
Some(by) => {
let by_me = my_uid.map_or(false, |&uid| by == uid);
// If the attack was by me also reset this timer
if by_me {
hp_floater_list.time_since_last_dmg_by_me = Some(0.0);
}
my_entity.0 == Some(entity) || by_me
},
None => false,
} {
let last_floater = hp_floater_list.floaters.last_mut();
match last_floater {
Some(f) if f.timer < HP_ACCUMULATETIME => {
//TODO: Add "jumping" animation on floater when it changes its value
f.hp_change += health.last_change.amount;
},
_ => {
hp_floater_list.floaters.push(HpFloater {
timer: 0.0,
hp_change: health.last_change.amount,
rand: rand::random(),
});
},
}
}
}
}
// Remove floater lists on entities without health or without position

View File

@ -54,7 +54,12 @@ use trade::Trade;
use crate::{
cmd::get_player_uuid,
ecs::{comp as vcomp, comp::HpFloaterList},
ecs::{comp as vcomp, comp::{HpFloater, HpFloaterList}, sys::floater},
ecs::{
comp as vcomp,
comp::{HpFloater, HpFloaterList},
sys::floater,
},
game_input::GameInput,
hud::{img_ids::ImgsRot, prompt_dialog::DialogOutcomeEvent},
render::UiDrawer,
@ -1416,14 +1421,17 @@ impl Hud {
&mut self.ids.player_scts,
&mut ui_widgets.widget_id_generator(),
);
// TODO: Change to use Outcome
// Calculate total change
// Ignores healing
let hp_damage: f32 = floaters.iter().map(|f| f.hp_change.min(0.0)).sum();
dbg!(hp_damage);
// .fold(0.0, |acc, f| f.hp_change.min(0.0) + acc);
let hp_dmg_rounded_abs = hp_damage.round().abs() as u32;
dbg!(hp_dmg_rounded_abs);
let max_hp_frac = hp_damage.abs() as f32 / health.maximum() as f32;
dbg!(max_hp_frac);
let timer = floaters
.last()
.expect("There must be at least one floater")
@ -1481,6 +1489,7 @@ impl Hud {
&mut ui_widgets.widget_id_generator(),
);
let max_hp_frac = floater.hp_change.abs() as f32 / health.maximum() as f32;
dbg!(max_hp_frac);
// Increase font size based on fraction of maximum health
// "flashes" by having a larger size in the first 100ms
let font_size = 30
@ -4437,7 +4446,7 @@ impl Hud {
pub fn camera_clamp(&mut self, camera_clamp: bool) { self.show.camera_clamp = camera_clamp; }
pub fn handle_outcome(&mut self, outcome: &Outcome) {
pub fn handle_outcome(&mut self, outcome: &Outcome, client: &Client) {
match outcome {
Outcome::ExpChange { uid, exp, xp_pools } => {
self.floaters.exp_floaters.push(ExpFloater {
@ -4473,9 +4482,57 @@ impl Hud {
})
},
Outcome::Damage {
uid, crit, amount, ..
by,
target,
crit,
amount,
..
} => {
dbg!(uid);
let ecs = client.state().ecs();
let mut hp_floater_lists = ecs.write_storage::<vcomp::HpFloaterList>();
let uids = ecs.read_storage::<Uid>();
let me = client.entity();
let my_uid = uids.get(me);
if let Some(entity) = ecs.entity_from_uid(target.0) {
if let Some(floater_list) = hp_floater_lists.get_mut(entity) {
if match by {
Some(by) => {
let by_me = my_uid.map_or(false, |&uid| *by == uid);
// If the attack was by me also reset this timer
if by_me {
floater_list.time_since_last_dmg_by_me = Some(0.0);
}
my_uid.map_or(false, |&uid| *target == uid) || by_me
},
None => false,
} {
let last_floater = floater_list.floaters.last_mut();
match last_floater {
Some(f) if f.timer < floater::HP_ACCUMULATETIME => {
//TODO: Add "jumping" animation on floater when it changes its
// value
f.hp_change += -*amount;
},
_ => {
floater_list.floaters.push(HpFloater {
timer: 0.0,
hp_change: -*amount,
rand: rand::random(),
});
},
}
} else {
dbg!("not by player/hit player");
}
} else {
dbg!("no floater list");
}
} else {
dbg!("no entity from target uid");
}
dbg!(target);
dbg!(crit);
dbg!(amount);
},

View File

@ -1579,7 +1579,7 @@ impl PlayState for SessionState {
for outcome in outcomes {
self.scene
.handle_outcome(&outcome, &scene_data, &mut global_state.audio);
self.hud.handle_outcome(&outcome);
self.hud.handle_outcome(&outcome, &scene_data.client);
}
}
}