Damage outcomes are now emitted with health change events

Being healed and damaged at the same time still leads to issues - needs to be sorted out
This commit is contained in:
socksonme 2022-01-22 22:15:12 +02:00 committed by Socksonme
parent 634a3095d6
commit 94f193fbe0
8 changed files with 75 additions and 34 deletions

View File

@ -239,20 +239,8 @@ impl Attack {
let applied_damage = -change.amount;
accumulated_damage += applied_damage;
// Could also check this when handling outcomes and display 0.0 damage
// differently?
if applied_damage != 0.0 {
emit_outcome(Outcome::Damage {
pos: target.pos,
info: DamageInfo {
target: target.uid,
by: attacker.map(|a| a.uid),
amount: change.amount,
crit: is_crit,
},
});
}
if change.amount.abs() > Health::HEALTH_EPSILON {
emit(ServerEvent::HealthChange {
entity: target.entity,
change,
@ -270,6 +258,7 @@ impl Attack {
by: attacker.map(|x| x.into()),
cause: Some(damage.damage.source),
time,
crit: None,
};
emit(ServerEvent::HealthChange {
entity: target.entity,
@ -367,6 +356,7 @@ impl Attack {
by: attacker.map(|a| a.into()),
cause: None,
time,
crit: None,
};
if change.amount.abs() > Health::HEALTH_EPSILON {
emit(ServerEvent::HealthChange {
@ -399,6 +389,7 @@ impl Attack {
by: attacker.map(|a| a.into()),
cause: None,
time,
crit: None,
};
if change.amount.abs() > Health::HEALTH_EPSILON {
emit(ServerEvent::HealthChange {
@ -510,6 +501,7 @@ impl Attack {
by: attacker.map(|a| a.into()),
cause: None,
time,
crit: None,
};
if change.amount.abs() > Health::HEALTH_EPSILON {
emit(ServerEvent::HealthChange {
@ -542,6 +534,7 @@ impl Attack {
by: attacker.map(|a| a.into()),
cause: None,
time,
crit: None,
};
if change.amount.abs() > Health::HEALTH_EPSILON {
emit(ServerEvent::HealthChange {
@ -854,6 +847,7 @@ impl Damage {
by: damage_contributor,
cause: Some(self.source),
time,
crit: Some(is_crit),
}
},
DamageSource::Falling => {
@ -866,6 +860,7 @@ impl Damage {
by: None,
cause: Some(self.source),
time,
crit: None,
}
},
DamageSource::Buff(_) | DamageSource::Other => HealthChange {
@ -873,6 +868,7 @@ impl Damage {
by: None,
cause: Some(self.source),
time,
crit: None,
},
}
}

View File

@ -24,6 +24,8 @@ pub struct HealthChange {
pub cause: Option<DamageSource>,
/// The time that the health change occurred at
pub time: Time,
/// Whether or not the health change was caused by a crit (None if it couldn't have been a crit)
pub crit: Option<bool>,
}
impl HealthChange {
@ -132,6 +134,7 @@ impl Health {
amount: 0.0,
by: None,
cause: None,
crit: None,
time: Time(0.0),
},
is_dead: false,
@ -210,6 +213,7 @@ impl Health {
amount: 0.0,
by: None,
cause: None,
crit: None,
time: Time(0.0),
},
is_dead: false,
@ -244,6 +248,7 @@ mod tests {
time: Time(123.0),
by: Some(damage_contrib),
cause: None,
crit: None,
};
health.change_by(health_change);
@ -269,6 +274,7 @@ mod tests {
time: Time(123.0),
by: Some(damage_contrib),
cause: None,
crit: None,
};
health.change_by(health_change);
@ -288,6 +294,7 @@ mod tests {
time: Time(123.0),
by: Some(damage_contrib),
cause: None,
crit: None,
};
health.change_by(health_change);
health.change_by(health_change);
@ -313,6 +320,7 @@ mod tests {
time: Time(10.0),
by: Some(damage_contrib1),
cause: None,
crit: None,
};
health.change_by(health_change);
@ -322,6 +330,7 @@ mod tests {
time: Time(100.0),
by: Some(damage_contrib2),
cause: None,
crit: None,
};
health.change_by(health_change);
@ -335,6 +344,7 @@ mod tests {
time: Time(620.0),
by: Some(damage_contrib2),
cause: None,
crit: None,
};
health.change_by(health_change);

View File

@ -1,4 +1,4 @@
use crate::{comp, uid::Uid};
use crate::{comp, uid::Uid, combat::DamageContributor};
use comp::{beam, item::Reagent, poise::PoiseState, skillset::SkillGroupKind, UtteranceKind};
use hashbrown::HashSet;
use serde::{Deserialize, Serialize};
@ -7,9 +7,9 @@ use vek::*;
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct DamageInfo {
pub amount: f32,
pub crit: bool,
pub crit: Option<bool>,
pub target: Uid,
pub by: Option<Uid>,
pub by: Option<DamageContributor>,
}
/// An outcome represents the final result of an instantaneous event. It implies

View File

@ -274,6 +274,7 @@ impl<'a> System<'a> for Sys {
by: damage_contributor,
cause,
time: *read_data.time,
crit: None,
},
});
*accumulated = 0.0;

View File

@ -1056,6 +1056,7 @@ fn handle_health(
amount: hp - health.current(),
by: None,
cause: None,
crit: None,
time: *time,
};
health.change_by(change);

View File

@ -23,7 +23,7 @@ use common::{
Player, Poise, Pos, SkillSet, Stats,
},
event::{EventBus, ServerEvent},
outcome::Outcome,
outcome::{DamageInfo, Outcome},
resources::Time,
rtsim::RtSimEntity,
terrain::{Block, BlockKind, TerrainGrid},
@ -66,6 +66,7 @@ pub fn handle_poise(server: &Server, entity: EcsEntity, change: comp::PoiseChang
pub fn handle_health_change(server: &Server, entity: EcsEntity, change: HealthChange) {
let ecs = &server.state.ecs();
let mut outcomes = ecs.write_resource::<Vec<Outcome>>();
if let Some(mut health) = ecs.write_storage::<Health>().get_mut(entity) {
health.change_by(change);
}
@ -76,6 +77,21 @@ pub fn handle_health_change(server: &Server, entity: EcsEntity, change: HealthCh
if let Some(agent) = ecs.write_storage::<Agent>().get_mut(entity) {
agent.inbox.push_front(AgentEvent::Hurt);
}
dbg!("hit");
dbg!(change);
// TODO: This will currently fuck up with healing
if let (Some(pos), Some(uid)) = (ecs.read_storage::<Pos>().get(entity), ecs.read_storage::<Uid>().get(entity)) {
dbg!(change.amount);
outcomes.push(Outcome::Damage{
pos: pos.0,
info: DamageInfo {
amount: change.amount,
crit: change.crit,
by: change.by,
target: *uid,
}
});
}
}
}
@ -576,6 +592,11 @@ pub fn handle_land_on_ground(server: &Server, entity: EcsEntity, vel: Vec3<f32>)
let change =
damage.calculate_health_change(damage_reduction, None, false, 0.0, 1.0, *time);
health.change_by(change);
let server_eventbus = ecs.read_resource::<EventBus<ServerEvent>>();
server_eventbus.emit_now(ServerEvent::HealthChange {
entity,
change,
});
}
// Handle poise change
if let Some(mut poise) = ecs.write_storage::<comp::Poise>().get_mut(entity) {

View File

@ -96,7 +96,7 @@ use common::{
object,
poise::PoiseState,
quadruped_low, quadruped_medium, quadruped_small, Body, CharacterAbilityType,
InventoryUpdateEvent, UtteranceKind,
InventoryUpdateEvent, UtteranceKind, Health,
},
outcome::Outcome,
terrain::{BlockKind, TerrainChunk},
@ -514,9 +514,11 @@ impl SfxMgr {
false,
);
},
Outcome::Damage { pos, .. } => {
Outcome::Damage { pos, info, .. } => {
if info.amount < Health::HEALTH_EPSILON {
let sfx_trigger_item = triggers.get_key_value(&SfxEvent::Damage);
audio.emit_sfx(sfx_trigger_item, *pos, Some(1.5), false);
}
},
Outcome::Death { pos, .. } => {
let sfx_trigger_item = triggers.get_key_value(&SfxEvent::Death);

View File

@ -1437,7 +1437,8 @@ impl Hud {
.last()
.expect("There must be at least one floater")
.info
.crit;
.crit
.map_or(false, |c| c);
// Increase font size based on fraction of maximum health
// "flashes" by having a larger size in the first 100ms
let font_size = 30
@ -1496,13 +1497,14 @@ impl Hud {
);
let max_hp_frac =
floater.info.amount.abs() as f32 / health.maximum() as f32;
let crit = floater.info.crit.map_or(false, |c| c);
// Increase font size based on fraction of maximum health
// "flashes" by having a larger size in the first 100ms
// TODO: example
let font_size = 30
+ ((max_hp_frac * 10.0) as u32)
* 3
* if floater.info.crit { 2 } else { 1 }
* if crit { 2 } else { 1 }
+ if floater.timer < 0.1 {
// TODO: Maybe change font size wrt crits here?
FLASH_MAX * (((1.0 - floater.timer / 0.1) * 10.0) as u32)
@ -1547,7 +1549,7 @@ impl Hud {
.font_id(self.fonts.cyri.conrod_id)
.color(if floater.info.amount < 0.0 {
// TODO: example
if floater.info.crit {
if crit {
Color::Rgba(1.0, 0.9, 0.1, hp_fade)
} else {
Color::Rgba(1.0, 0.1, 0.0, hp_fade)
@ -1569,7 +1571,7 @@ impl Hud {
.font_id(self.fonts.cyri.conrod_id)
.color(if floater.info.amount < 0.0 {
// TODO: example
if floater.info.crit {
if crit {
Color::Rgba(1.0, 0.9, 0.1, hp_fade)
} else {
Color::Rgba(1.0, 0.1, 0.0, hp_fade)
@ -2203,8 +2205,7 @@ impl Hud {
let floaters = &hpfl.floaters;
// Colors
// TODO: Add for crits as well?
// Maybe decrease increase blue for lighter colour?
// TODO: The crit colors and their names are pretty bad as it stands
const WHITE: Rgb<f32> = Rgb::new(1.0, 0.9, 0.8);
const LIGHT_OR: Rgb<f32> = Rgb::new(1.0, 0.925, 0.749);
const LIGHT_MED_OR: Rgb<f32> = Rgb::new(1.0, 0.85, 0.498);
@ -2268,7 +2269,8 @@ impl Hud {
.last()
.expect("There must be at least one floater")
.info
.crit;
.crit
.map_or(false, |c| c);
// Increase font size based on fraction of maximum health
// "flashes" by having a larger size in the first 100ms
let font_size = 30
@ -2337,18 +2339,19 @@ impl Hud {
// Calculate total change
let max_hp_frac = floater.info.amount.abs() as f32
/ health.map_or(1.0, |h| h.maximum() as f32);
let crit = floater.info.crit.map_or(false, |c| c);
// Increase font size based on fraction of maximum health
// "flashes" by having a larger size in the first 100ms
let font_size = 30
+ ((max_hp_frac * 10.0) as u32)
* 3
* if floater.info.crit { 2 } else { 1 }
* if crit { 2 } else { 1 }
+ if floater.timer < 0.1 {
FLASH_MAX * (((1.0 - floater.timer / 0.1) * 10.0) as u32)
} else {
0
};
let font_col = font_col(font_size, floater.info.crit);
let font_col = font_col(font_size, crit);
// Timer sets the widget offset
let y = (floater.timer as f64
/ crate::ecs::sys::floater::HP_SHOWTIME as f64
@ -4537,24 +4540,31 @@ impl Hud {
if let Some(entity) = ecs.entity_from_uid(info.target.0) {
if let Some(floater_list) = hp_floater_lists.get_mut(entity) {
let hit_me = my_uid.map_or(false, |&uid| info.target == uid);
if match info.by {
Some(by) => {
let by_me = my_uid.map_or(false, |&uid| by == uid);
let by_me = my_uid.map_or(false, |&uid| by.uid() == 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| info.target == uid) || by_me
hit_me || by_me
},
None => {
hit_me
},
None => false,
} {
// TODO: This will currently fuck up with healing
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.info.amount += info.amount;
// Only change the crit value if it's not None
if info.crit.is_some() {
f.info.crit = info.crit;
}
},
_ => {
floater_list.floaters.push(HpFloater {