Tons of code quality changes, added damage rounding option

This commit is contained in:
socksonme 2022-04-18 17:41:49 +03:00 committed by Socksonme
parent 64f0f05608
commit 5360a7c93e
13 changed files with 133 additions and 92 deletions

View File

@ -287,6 +287,7 @@ impl Attack {
by: attacker.map(|x| x.into()),
cause: Some(damage.damage.source),
time,
instance: damage.instance,
};
if change.abs() > Poise::POISE_EPSILON {
// If target is in a stunned state, apply extra poise damage as health
@ -378,6 +379,7 @@ impl Attack {
by: attacker.map(|x| x.into()),
cause: Some(damage.damage.source),
time,
instance: rand::random(),
};
emit(ServerEvent::PoiseChange {
entity: target.entity,
@ -525,6 +527,7 @@ impl Attack {
by: attacker.map(|x| x.into()),
cause: Some(attack_source.into()),
time,
instance: rand::random(),
};
emit(ServerEvent::PoiseChange {
entity: target.entity,

View File

@ -188,8 +188,7 @@ impl Health {
(change.time.0 - last_damage_time.0) < DAMAGE_CONTRIB_PRUNE_SECS
});
}
(self.current() - prev_health as f32 / Self::SCALING_FACTOR_FLOAT).abs()
> Self::HEALTH_EPSILON
(delta as f32 / Self::SCALING_FACTOR_FLOAT).abs() > Self::HEALTH_EPSILON
}
pub fn damage_contributions(&self) -> impl Iterator<Item = (&DamageContributor, &u64)> {

View File

@ -57,7 +57,7 @@ impl MeleeConstructor {
scaling the melee attack."
)
}
let instance = rand::random();
let attack = match self.kind {
Slash {
damage,
@ -80,7 +80,7 @@ impl MeleeConstructor {
value: damage,
},
Some(GroupTarget::OutOfGroup),
rand::random(),
instance,
)
.with_effect(buff);
@ -129,7 +129,7 @@ impl MeleeConstructor {
value: damage,
},
Some(GroupTarget::OutOfGroup),
rand::random(),
instance,
)
.with_effect(buff);
@ -172,7 +172,7 @@ impl MeleeConstructor {
value: damage,
},
Some(GroupTarget::OutOfGroup),
rand::random(),
instance,
);
if let Some(damage_effect) = self.damage_effect {
@ -213,7 +213,7 @@ impl MeleeConstructor {
value: damage,
},
None,
rand::random(),
instance,
)
.with_effect(lifesteal);
@ -248,6 +248,7 @@ impl MeleeConstructor {
value: damage,
},
Some(GroupTarget::OutOfGroup),
instance,
);
if let Some(damage_effect) = self.damage_effect {

View File

@ -29,6 +29,8 @@ pub struct PoiseChange {
pub cause: Option<DamageSource>,
/// The time that the poise change occurred at
pub time: Time,
/// A random instance number used to group up attacks
pub instance: u64,
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]

View File

@ -173,6 +173,7 @@ impl<'a> System<'a> for Sys {
by: None,
cause: None,
time: *read_data.time,
instance: rand::random(),
};
poise.change(poise_change);
poise.regen_rate = (poise.regen_rate + POISE_REGEN_ACCEL * dt).min(10.0);

View File

@ -615,6 +615,7 @@ pub fn handle_land_on_ground(server: &Server, entity: EcsEntity, vel: Vec3<f32>)
by: None,
cause: None,
time: *time,
instance: rand::random(),
};
poise.change(poise_change);
}

View File

@ -126,6 +126,7 @@ pub trait StateExt {
) -> Result<(), specs::error::WrongGeneration>;
}
// TODO: Check if this is ok
impl StateExt for State {
fn apply_effect(&self, entity: EcsEntity, effects: Effect, source: Option<Uid>) {
let msm = self.ecs().read_resource::<MaterialStatManifest>();
@ -189,6 +190,7 @@ impl StateExt for State {
cause: None,
by: damage_contributor,
time: *time,
instance: rand::random(),
};
self.ecs()
.write_storage::<comp::Poise>()

View File

@ -8,6 +8,8 @@ use vek::*;
#[derive(Copy, Clone, Debug)]
pub struct HpFloater {
pub timer: f32,
// Used for the "jumping" animation of the HpFloater whenever it changes it's value
pub jump_timer: f32,
pub info: DamageInfo,
// Used for randomly offsetting
pub rand: f32,

View File

@ -47,7 +47,6 @@ impl<'a> System<'a> for Sys {
});
}
// TODO: avoid join??
for hp_floater_list in (&mut hp_floater_lists).join() {
// Increment timer for time since last damaged by me
hp_floater_list
@ -83,6 +82,7 @@ impl<'a> System<'a> for Sys {
for mut floater in floaters.iter_mut() {
// Increment timer
floater.timer += dt.0;
floater.jump_timer += dt.0;
}
// Clear floaters if newest floater is past show time

View File

@ -1434,9 +1434,14 @@ impl Hud {
damage_floaters.iter().map(|fl| fl.info.amount).sum();
// .fold(0.0, |acc, f| f.info.amount.min(0.0) + acc);
let hp_dmg_rounded_abs = hp_damage.round().abs() as u32;
let hp_dmg_text = if global_state.settings.interface.sct_damage_rounding
&& hp_damage.abs() > 1.0
{
format!("{:.0}", hp_damage.abs())
} else {
format!("{:.1}", hp_damage.abs())
};
// As to avoid ridiculously large damage numbers
// TODO: Might have to discuss this
let max_hp_frac = hp_damage
.abs()
.clamp(Health::HEALTH_EPSILON, health.maximum())
@ -1446,14 +1451,14 @@ impl Hud {
.last()
.expect("There must be at least one floater")
.timer;
let crit = damage_floaters
.iter()
.rev()
.find(|f| f.info.crit_mult.is_some())
.map_or(false, |f| f.info.crit_mult.is_some());
let crit_mult = damage_floaters
let jump_timer = damage_floaters
.last()
.map_or(1.0, |f| f.info.crit_mult.unwrap_or(1.0));
.expect("There must be at least one floater")
.jump_timer;
let (crit, crit_mult) =
damage_floaters.last().map_or((false, 1.0), |f| {
(f.info.crit_mult.is_some(), f.info.crit_mult.unwrap_or(1.0))
});
// Increase font size based on fraction of maximum health
// "flashes" by having a larger size in the first 100ms
@ -1461,9 +1466,9 @@ impl Hud {
+ ((max_hp_frac * 10.0 * if crit { 1.25 * crit_mult } else { 1.0 })
as u32)
* 3
+ if timer < 0.1 {
+ if jump_timer < 0.1 {
FLASH_MAX
* (((1.0 - timer / 0.1)
* (((1.0 - jump_timer / 0.1)
* 10.0
* if crit { 1.25 * crit_mult } else { 1.0 })
as u32)
@ -1475,7 +1480,7 @@ impl Hud {
// Timer sets text transparency
let hp_fade =
((crate::ecs::sys::floater::MY_HP_SHOWTIME - timer) * 0.25) + 0.2;
Text::new(&format!("{}", hp_dmg_rounded_abs))
Text::new(&hp_dmg_text)
.font_size(font_size)
.font_id(self.fonts.cyri.conrod_id)
.color(if hp_damage < 0.0 {
@ -1485,7 +1490,7 @@ impl Hud {
})
.mid_bottom_with_margin_on(ui_widgets.window, 297.0 + y)
.set(player_sct_bg_id, ui_widgets);
Text::new(&format!("{}", hp_dmg_rounded_abs))
Text::new(&hp_dmg_text)
.font_size(font_size)
.font_id(self.fonts.cyri.conrod_id)
.color(if hp_damage < 0.0 {
@ -1524,6 +1529,13 @@ impl Hud {
.abs()
.clamp(Health::HEALTH_EPSILON, health.maximum())
/ health.maximum();
let hp_dmg_text = if global_state.settings.interface.sct_damage_rounding
&& floater.info.amount.abs() > 1.0
{
format!("{:.0}", floater.info.amount.abs())
} else {
format!("{:.1}", floater.info.amount.abs())
};
let crit = floater.info.crit_mult.is_some();
let crit_mult = floater.info.crit_mult.unwrap_or(1.0);
// Increase font size based on fraction of maximum health
@ -1533,9 +1545,9 @@ impl Hud {
+ (max_hp_frac * 10.0 * if crit { 1.25 * crit_mult } else { 1.0 })
as u32
* 3
+ if floater.timer < 0.1 {
+ if floater.jump_timer < 0.1 {
FLASH_MAX
* (((1.0 - floater.timer / 0.1)
* (((1.0 - floater.jump_timer / 0.1)
* 10.0
* if crit { 1.25 * crit_mult } else { 1.0 })
as u32)
@ -1543,6 +1555,9 @@ impl Hud {
0
};
// Timer sets the widget offset
// TODO: Discuss if crits should stay in place?
// TODO: I feel like I'd prefer for crits to behave the same way for players
// and monsters
let y = if floater.info.amount < 0.0 {
floater.timer as f64
* number_speed
@ -1561,7 +1576,8 @@ impl Hud {
// Healing is offset randomly
let x = if crit {
// TODO: Too large diff
(floater.rand as f64 - 0.5) * 0.1 * ui_widgets.win_w
// See the second value as a minimum and the first as a maximum
(floater.rand as f64 - 0.5) * 0.08 * ui_widgets.win_w
+ (0.03 * ui_widgets.win_w * (floater.rand as f64 - 0.5).signum())
} else if floater.info.amount < 0.0 {
0.0
@ -1575,14 +1591,13 @@ impl Hud {
((crate::ecs::sys::floater::MY_HP_SHOWTIME - floater.timer) * 0.25)
+ 0.2
};
// TODO: Add options for floating/non-floating
Text::new(&format!("{:.1}", floater.info.amount.abs()))
Text::new(&hp_dmg_text)
.font_size(font_size)
.font_id(self.fonts.cyri.conrod_id)
.color(Color::Rgba(0.0, 0.0, 0.0, hp_fade))
.x_y(x, y - 3.0)
.set(player_sct_bg_id, ui_widgets);
Text::new(&format!("{:.1}", floater.info.amount.abs()))
Text::new(&hp_dmg_text)
.font_size(font_size)
.font_id(self.fonts.cyri.conrod_id)
.color(if floater.info.amount < 0.0 {
@ -2220,21 +2235,13 @@ impl Hud {
let floaters = &hpfl.floaters;
// Colors
// TODO: The crit colors and their names are pretty bad as it stands
//TODO: They don't stand out enough as they should, and they fade weirdly, such
// that they look transparent from the get-go
// TODO: Maybe make an array of colors for crits too?
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);
const MED_OR: Rgb<f32> = Rgb::new(1.0, 0.776, 0.247);
const DARK_ORANGE: Rgb<f32> = Rgb::new(1.0, 0.7, 0.0);
const RED_ORANGE: Rgb<f32> = Rgb::new(1.0, 0.349, 0.0);
const CWHITE: Rgb<f32> = Rgb::new(1.0, 0.9, 0.413);
const CLIGHT_YEL: Rgb<f32> = Rgb::new(1.0, 0.9, 0.353);
const CLIGHT_MED_YEL: Rgb<f32> = Rgb::new(1.0, 0.9, 0.256);
const CMED_YEL: Rgb<f32> = Rgb::new(1.0, 0.9, 0.184);
const CDARK_ORANGE: Rgb<f32> = Rgb::new(1.0, 0.9, 0.098);
const CRED_ORANGE: Rgb<f32> = Rgb::new(1.0, 0.9, 0.0);
const DAMAGE_COLORS: [Rgb<f32>; 6] = [
WHITE,
LIGHT_OR,
@ -2243,23 +2250,11 @@ impl Hud {
DARK_ORANGE,
RED_ORANGE,
];
const CDAMAGE_COLORS: [Rgb<f32>; 6] = [
CWHITE,
CLIGHT_YEL,
CLIGHT_MED_YEL,
CMED_YEL,
CDARK_ORANGE,
CRED_ORANGE,
];
// Largest value that select the first color is 40, then it shifts colors
// every 5
let font_col = |font_size: u32, crit: bool| {
if crit {
// TODO: This will probably be the way crit colours are handled (with a
// different algo for choosing the color)
// CDAMAGE_COLORS[(font_size.saturating_sub(72) / 5).min(5) as usize]
// TODO: Temporary
// TODO: Temporary color for crits
Rgb::new(1.0, 0.9, 0.0)
} else {
DAMAGE_COLORS[(font_size.saturating_sub(36) / 5).min(5) as usize]
@ -2281,7 +2276,13 @@ impl Hud {
// Ignores healing
let hp_damage: f32 =
damage_floaters.iter().map(|fl| fl.info.amount).sum();
let hp_dmg_rounded_abs = hp_damage.round().abs();
let hp_dmg_text = if global_state.settings.interface.sct_damage_rounding
{
format!("{:.0}", hp_damage.abs())
} else {
format!("{:.1}", hp_damage.abs())
};
let max_hp_frac = hp_damage
.abs()
.clamp(Health::HEALTH_EPSILON, health.map_or(1.0, |h| h.maximum()))
@ -2290,14 +2291,14 @@ impl Hud {
.last()
.expect("There must be at least one floater")
.timer;
let crit = damage_floaters
.iter()
.rev()
.find(|f| f.info.crit_mult.is_some())
.map_or(false, |f| f.info.crit_mult.is_some());
let crit_mult = damage_floaters
let jump_timer = damage_floaters
.last()
.map_or(1.0, |f| f.info.crit_mult.unwrap_or(1.0));
.expect("There must be at least one floater")
.jump_timer;
let (crit, crit_mult) =
damage_floaters.last().map_or((false, 1.0), |f| {
(f.info.crit_mult.is_some(), f.info.crit_mult.unwrap_or(1.0))
});
// Increase font size based on fraction of maximum health
// "flashes" by having a larger size in the first 100ms
@ -2305,9 +2306,9 @@ impl Hud {
+ ((max_hp_frac * 10.0 * if crit { 1.25 * crit_mult } else { 1.0 })
as u32)
* 3
+ if timer < 0.1 {
+ if jump_timer < 0.1 {
FLASH_MAX
* (((1.0 - timer / 0.1)
* (((1.0 - jump_timer / 0.1)
* 10.0
* if crit { 1.25 * crit_mult } else { 1.0 })
as u32)
@ -2324,15 +2325,14 @@ impl Hud {
// Timer sets text transparency
let fade =
((crate::ecs::sys::floater::HP_SHOWTIME - timer) * 0.25) + 0.2;
// TODO: Add options for floating/non-floating
Text::new(&format!("{}", hp_damage.abs()))
Text::new(&hp_dmg_text)
.font_size(font_size)
.font_id(self.fonts.cyri.conrod_id)
.color(Color::Rgba(0.0, 0.0, 0.0, fade))
.x_y(0.0, y - 3.0)
.position_ingame(ingame_pos)
.set(sct_bg_id, ui_widgets);
Text::new(&format!("{}", hp_damage.abs()))
Text::new(&hp_dmg_text)
.font_size(font_size)
.font_id(self.fonts.cyri.conrod_id)
.x_y(0.0, y)
@ -2357,6 +2357,12 @@ impl Hud {
Health::HEALTH_EPSILON,
health.map_or(1.0, |h| h.maximum()),
) / health.map_or(1.0, |h| h.maximum());
let hp_dmg_text = if global_state.settings.interface.sct_damage_rounding
{
format!("{:.0}", floater.info.amount.abs())
} else {
format!("{:.1}", floater.info.amount.abs())
};
let crit = floater.info.crit_mult.is_some();
let crit_mult = floater.info.crit_mult.unwrap_or(1.0);
// Increase font size based on fraction of maximum health
@ -2365,9 +2371,9 @@ impl Hud {
+ (max_hp_frac * 10.0 * if crit { 1.25 * crit_mult } else { 1.0 })
as u32
* 3
+ if floater.timer < 0.1 {
+ if floater.jump_timer < 0.1 {
FLASH_MAX
* (((1.0 - floater.timer / 0.1)
* (((1.0 - floater.jump_timer / 0.1)
* 10.0
* if crit { 1.25 * crit_mult } else { 1.0 })
as u32)
@ -2404,8 +2410,7 @@ impl Hud {
((crate::ecs::sys::floater::HP_SHOWTIME - floater.timer) * 0.25)
+ 0.2
};
// TODO: Add options for floating/non-floating
Text::new(&format!("{:.1}", floater.info.amount.abs()))
Text::new(&hp_dmg_text)
.font_size(font_size)
.font_id(self.fonts.cyri.conrod_id)
.color(if floater.info.amount < 0.0 {
@ -2416,7 +2421,7 @@ impl Hud {
.x_y(x, y - 3.0)
.position_ingame(ingame_pos)
.set(sct_bg_id, ui_widgets);
Text::new(&format!("{:.1}", floater.info.amount.abs()))
Text::new(&hp_dmg_text)
.font_size(font_size)
.font_id(self.fonts.cyri.conrod_id)
.x_y(x, y)
@ -4571,6 +4576,8 @@ impl Hud {
} {
// Group up damage from the same tick, with the same instance number and
// crit value
// Would you want to group up crits with the same instance number if you
// don't group the at all with the different setting?
for floater in floater_list.floaters.iter_mut().rev() {
if floater.timer > 0.0 {
break;
@ -4580,47 +4587,34 @@ impl Hud {
{
floater.info.amount += info.amount;
floater.info.crit_mult = info.crit_mult;
floater.info.crit_mult = if info.crit_mult.is_some() {
info.crit_mult
} else {
floater.info.crit_mult
};
return;
}
}
// To separate healing and damage floaters alongside the crit and
// non-crit ones
let last_floater = if info.amount < Health::HEALTH_EPSILON {
floater_list.floaters.iter_mut().rev().find(|f| {
f.info.amount < Health::HEALTH_EPSILON
&& info.crit_mult.is_some() == f.info.crit_mult.is_some()
})
} else {
floater_list.floaters.iter_mut().rev().find(|f| {
f.info.amount > Health::HEALTH_EPSILON
&& info.crit_mult.is_some() == f.info.crit_mult.is_some()
})
};
let last_floater = floater_list.floaters.iter_mut().rev().find(|f| {
(if info.amount < 0.0 {
f.info.amount < 0.0
} else {
f.info.amount > 0.0
}) && info.crit_mult.is_some() == f.info.crit_mult.is_some()
});
match last_floater {
Some(f)
// TODO: Change later so it's based on options
// TODO: Might have to discuss whether or not to create a new floater or every crit
if f.timer < floater::HP_ACCUMULATETIME && !f.info.crit_mult.is_some() =>
{
//TODO: Add "jumping" animation on floater when it changes its
// value
f.jump_timer = 0.0;
f.info.amount += info.amount;
f.info.crit_mult = info.crit_mult;
f.info.crit_mult = if info.crit_mult.is_some() {
info.crit_mult
} else {
f.info.crit_mult
};
},
_ => {
floater_list.floaters.push(HpFloater {
timer: 0.0,
jump_timer: 0.0,
info: *info,
rand: rand::random(),
});

View File

@ -86,6 +86,8 @@ widget_ids! {
sct_inc_dmg_radio,
sct_batch_inc_text,
sct_batch_inc_radio,
sct_round_dmg_text,
sct_round_dmg_radio,
//
speech_bubble_text,
speech_bubble_self_text,
@ -715,7 +717,9 @@ impl<'a> Widget for Interface<'a> {
O Show batched dealt Damage
O Show incoming Damage
O Batch incoming Numbers
O Round Damage Numbers
TODO: Do something like https://gitlab.com/veloren/veloren/-/issues/836
TODO: Scrollbar::x_axis for duration
Number Display Duration: 1s ----I----5s
*/
// SCT/ Scrolling Combat Text
@ -846,13 +850,39 @@ impl<'a> Widget for Interface<'a> {
.graphics_for(state.ids.sct_batch_inc_radio)
.color(TEXT_COLOR)
.set(state.ids.sct_batch_inc_text, ui);
// Round Damage
let show_sct_damage_rounding = ToggleButton::new(
self.global_state.settings.interface.sct_damage_rounding,
self.imgs.checkbox,
self.imgs.checkbox_checked,
)
.w_h(18.0, 18.0)
.down_from(state.ids.sct_batch_inc_radio, 8.0)
.hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
.press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
.set(state.ids.sct_round_dmg_radio, ui);
if self.global_state.settings.interface.sct_damage_rounding != show_sct_damage_rounding
{
events.push(SctRoundDamage(
!self.global_state.settings.interface.sct_damage_rounding,
))
}
Text::new(self.localized_strings.get("hud.settings.round_damage"))
.right_from(state.ids.sct_round_dmg_radio, 10.0)
.font_size(self.fonts.cyri.scale(14))
.font_id(self.fonts.cyri.conrod_id)
.graphics_for(state.ids.sct_round_dmg_radio)
.color(TEXT_COLOR)
.set(state.ids.sct_round_dmg_text, ui);
}
// Speech bubbles
Text::new(self.localized_strings.get("hud.settings.speech_bubble"))
.down_from(
if self.global_state.settings.interface.sct {
state.ids.sct_batch_inc_radio
state.ids.sct_round_dmg_radio
} else {
state.ids.sct_show_radio
},

View File

@ -98,6 +98,7 @@ pub enum Interface {
Sct(bool),
SctPlayerBatch(bool),
SctDamageBatch(bool),
SctRoundDamage(bool),
SpeechBubbleSelf(bool),
SpeechBubbleDarkMode(bool),
SpeechBubbleIcon(bool),
@ -463,6 +464,9 @@ impl SettingsChange {
Interface::SctDamageBatch(sct_damage_batch) => {
settings.interface.sct_damage_batch = sct_damage_batch;
},
Interface::SctRoundDamage(sct_round_damage) => {
settings.interface.sct_damage_rounding = sct_round_damage;
},
Interface::SpeechBubbleSelf(sbdm) => {
settings.interface.speech_bubble_self = sbdm;
},

View File

@ -17,6 +17,7 @@ pub struct InterfaceSettings {
pub sct: bool,
pub sct_player_batch: bool,
pub sct_damage_batch: bool,
pub sct_damage_rounding: bool,
pub speech_bubble_self: bool,
pub speech_bubble_dark_mode: bool,
pub speech_bubble_icon: bool,
@ -57,6 +58,7 @@ impl Default for InterfaceSettings {
sct: true,
sct_player_batch: false,
sct_damage_batch: false,
sct_damage_rounding: false,
speech_bubble_self: true,
speech_bubble_dark_mode: false,
speech_bubble_icon: true,