mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
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:
parent
634a3095d6
commit
94f193fbe0
@ -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,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -274,6 +274,7 @@ impl<'a> System<'a> for Sys {
|
||||
by: damage_contributor,
|
||||
cause,
|
||||
time: *read_data.time,
|
||||
crit: None,
|
||||
},
|
||||
});
|
||||
*accumulated = 0.0;
|
||||
|
@ -1056,6 +1056,7 @@ fn handle_health(
|
||||
amount: hp - health.current(),
|
||||
by: None,
|
||||
cause: None,
|
||||
crit: None,
|
||||
time: *time,
|
||||
};
|
||||
health.change_by(change);
|
||||
|
@ -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) {
|
||||
|
@ -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, .. } => {
|
||||
let sfx_trigger_item = triggers.get_key_value(&SfxEvent::Damage);
|
||||
audio.emit_sfx(sfx_trigger_item, *pos, Some(1.5), false);
|
||||
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);
|
||||
|
@ -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;
|
||||
f.info.crit = info.crit;
|
||||
// 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 {
|
||||
|
Loading…
Reference in New Issue
Block a user