diff --git a/voxygen/src/ecs/sys/floater.rs b/voxygen/src/ecs/sys/floater.rs index c836c425d4..af6ed7d976 100644 --- a/voxygen/src/ecs/sys/floater.rs +++ b/voxygen/src/ecs/sys/floater.rs @@ -11,7 +11,6 @@ use specs::{Entities, Join, Read, ReadStorage, WriteStorage}; pub const HP_SHOWTIME: f32 = 3.0; pub const CRIT_SHOWTIME: f32 = 0.7; pub const MY_HP_SHOWTIME: f32 = 2.5; -pub const HP_ACCUMULATETIME: f32 = 1.0; #[derive(Default)] pub struct Sys; diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 755ed23a3f..f52aa8a96d 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -58,7 +58,6 @@ use crate::{ ecs::{ comp as vcomp, comp::{HpFloater, HpFloaterList}, - sys::floater, }, game_input::GameInput, hud::{img_ids::ImgsRot, prompt_dialog::DialogOutcomeEvent}, @@ -1433,7 +1432,6 @@ impl Hud { let hp_damage: f32 = damage_floaters.iter().map(|fl| fl.info.amount).sum(); - // .fold(0.0, |acc, f| f.info.amount.min(0.0) + acc); let hp_dmg_text = if global_state.settings.interface.sct_damage_rounding && hp_damage.abs() > 1.0 { @@ -1538,9 +1536,23 @@ impl Hud { }; let crit = floater.info.crit_mult.is_some(); let crit_mult = floater.info.crit_mult.unwrap_or(1.0); + + // Timer sets text transparency + let hp_fade = if crit { + ((crate::ecs::sys::floater::CRIT_SHOWTIME - floater.timer) * 0.75) + 0.5 + } else { + ((crate::ecs::sys::floater::MY_HP_SHOWTIME - floater.timer) * 0.25) + + 0.2 + }; + // Skip floater if fade is less than or equal to 0.0 + if hp_fade <= 0.0 { + continue; + } + // Increase font size based on fraction of maximum health // "flashes" by having a larger size in the first 100ms - // TODO: example + // TODO: Could have it so that crits not only fade away but decrease in + // size? let font_size = 30 + (max_hp_frac * 10.0 * if crit { 1.25 * crit_mult } else { 1.0 }) as u32 @@ -1584,13 +1596,6 @@ impl Hud { } else { (floater.rand as f64 - 0.5) * 0.2 * ui_widgets.win_w }; - // Timer sets text transparency - let hp_fade = if crit { - ((crate::ecs::sys::floater::CRIT_SHOWTIME - floater.timer) * 0.75) + 0.5 - } else { - ((crate::ecs::sys::floater::MY_HP_SHOWTIME - floater.timer) * 0.25) - + 0.2 - }; Text::new(&hp_dmg_text) .font_size(font_size) .font_id(self.fonts.cyri.conrod_id) @@ -2277,6 +2282,7 @@ impl Hud { let hp_damage: f32 = damage_floaters.iter().map(|fl| fl.info.amount).sum(); let hp_dmg_text = if global_state.settings.interface.sct_damage_rounding + && hp_damage.abs() > 1.0 { format!("{:.0}", hp_damage.abs()) } else { @@ -2358,6 +2364,7 @@ impl Hud { 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 + && floater.info.amount.abs() > 1.0 { format!("{:.0}", floater.info.amount.abs()) } else { @@ -2365,6 +2372,18 @@ impl Hud { }; let crit = floater.info.crit_mult.is_some(); let crit_mult = floater.info.crit_mult.unwrap_or(1.0); + // Timer sets text transparency + let fade = if crit { + ((crate::ecs::sys::floater::CRIT_SHOWTIME - floater.timer) * 0.75) + + 0.5 + } else { + ((crate::ecs::sys::floater::HP_SHOWTIME - floater.timer) * 0.25) + + 0.2 + }; + // Skip floater if fade is less than or equal to 0.0 + if fade <= 0.0 { + continue; + } // Increase font size based on fraction of maximum health // "flashes" by having a larger size in the first 100ms let font_size = 30 @@ -2402,14 +2421,7 @@ impl Hud { * (floater.rand as f64 - 0.5).signum()) }; - // Timer sets text transparency - let fade = if crit { - ((crate::ecs::sys::floater::CRIT_SHOWTIME - floater.timer) * 0.75) - + 0.5 - } else { - ((crate::ecs::sys::floater::HP_SHOWTIME - floater.timer) * 0.25) - + 0.2 - }; + Text::new(&hp_dmg_text) .font_size(font_size) .font_id(self.fonts.cyri.conrod_id) @@ -4518,7 +4530,12 @@ 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, client: &Client) { + pub fn handle_outcome( + &mut self, + outcome: &Outcome, + client: &Client, + global_state: &GlobalState, + ) { match outcome { Outcome::ExpChange { uid, exp, xp_pools } => { self.floaters.exp_floaters.push(ExpFloater { @@ -4605,7 +4622,11 @@ impl Hud { 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() => + if (if hit_me { + f.timer < global_state.settings.interface.sct_inc_dmg_accum_duration + } else { + f.timer < global_state.settings.interface.sct_dmg_accum_duration + } && f.info.crit_mult.is_none()) => { f.jump_timer = 0.0; f.info.amount += info.amount; diff --git a/voxygen/src/hud/settings_window/interface.rs b/voxygen/src/hud/settings_window/interface.rs index 9356276640..db75f6a058 100644 --- a/voxygen/src/hud/settings_window/interface.rs +++ b/voxygen/src/hud/settings_window/interface.rs @@ -88,6 +88,12 @@ widget_ids! { sct_batch_inc_radio, sct_round_dmg_text, sct_round_dmg_radio, + sct_dmg_accum_duration_slider, + sct_dmg_accum_duration_text, + sct_dmg_accum_duration_value, + sct_inc_dmg_accum_duration_slider, + sct_inc_dmg_accum_duration_text, + sct_inc_dmg_accum_duration_value, // speech_bubble_text, speech_bubble_self_text, @@ -714,13 +720,15 @@ impl<'a> Widget for Interface<'a> { O Show Damage Numbers O Show single Damage Numbers + // 0 to ??? seconds + O Damage Accumulation Duration: 0s ----I----5s O Show batched dealt Damage O Show incoming Damage - O Batch incoming Numbers + // 0 to ??? seconds + O Incoming Damage Accumulation Duration: 0s ----I----5s + 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 Text::new( @@ -758,6 +766,13 @@ impl<'a> Widget for Interface<'a> { .color(TEXT_COLOR) .set(state.ids.sct_show_text, ui); if self.global_state.settings.interface.sct { + let sct_dmg_accum_duration = + self.global_state.settings.interface.sct_dmg_accum_duration; + let sct_inc_dmg_accum_duration = self + .global_state + .settings + .interface + .sct_inc_dmg_accum_duration; // Toggle single damage numbers let show_sct_damage_batch = !ToggleButton::new( !self.global_state.settings.interface.sct_damage_batch, @@ -780,6 +795,45 @@ impl<'a> Widget for Interface<'a> { .graphics_for(state.ids.sct_single_dmg_radio) .color(TEXT_COLOR) .set(state.ids.sct_single_dmg_text, ui); + + if !show_sct_damage_batch { + Text::new( + self.localized_strings + .get("hud.settings.sct_dmg_accum_duration"), + ) + .down_from(state.ids.sct_single_dmg_radio, 8.0) + .right_from(state.ids.sct_single_dmg_radio, 10.0) + .font_size(self.fonts.cyri.scale(14)) + .font_id(self.fonts.cyri.conrod_id) + .color(TEXT_COLOR) + .set(state.ids.sct_dmg_accum_duration_text, ui); + + if let Some(new_val) = ImageSlider::continuous( + sct_dmg_accum_duration, + 0.0, + 2.0, + self.imgs.slider_indicator, + self.imgs.slider, + ) + .w_h(104.0, 22.0) + .down_from(state.ids.sct_dmg_accum_duration_text, 8.0) + .track_breadth(12.0) + .slider_length(10.0) + .pad_track((5.0, 5.0)) + .set(state.ids.sct_dmg_accum_duration_slider, ui) + { + events.push(SctDamageAccumDuration(new_val)); + } + + Text::new(&format!("{:.2}", sct_dmg_accum_duration,)) + .right_from(state.ids.sct_dmg_accum_duration_slider, 8.0) + .font_size(self.fonts.cyri.scale(14)) + .graphics_for(state.ids.sct_dmg_accum_duration_slider) + .font_id(self.fonts.cyri.conrod_id) + .color(TEXT_COLOR) + .set(state.ids.sct_dmg_accum_duration_value, ui); + } + // Toggle Batched Damage let show_sct_damage_batch = ToggleButton::new( show_sct_damage_batch, @@ -787,7 +841,17 @@ impl<'a> Widget for Interface<'a> { self.imgs.checkbox_checked, ) .w_h(18.0, 18.0) - .down_from(state.ids.sct_single_dmg_radio, 8.0) + .down_from( + if show_sct_damage_batch { + state.ids.sct_single_dmg_radio + } else { + state.ids.sct_dmg_accum_duration_slider + }, + 8.0, + ) + .and_if(!show_sct_damage_batch, |tb| { + tb.left_from(state.ids.sct_dmg_accum_duration_slider, 10.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_show_batch_radio, ui); @@ -797,6 +861,7 @@ impl<'a> Widget for Interface<'a> { !self.global_state.settings.interface.sct_damage_batch, )) } + Text::new(self.localized_strings.get("hud.settings.cumulated_damage")) .right_from(state.ids.sct_show_batch_radio, 10.0) .font_size(self.fonts.cyri.scale(14)) @@ -823,6 +888,45 @@ impl<'a> Widget for Interface<'a> { .graphics_for(state.ids.sct_inc_dmg_radio) .color(TEXT_COLOR) .set(state.ids.sct_inc_dmg_text, ui); + + if !show_sct_player_batch { + Text::new( + self.localized_strings + .get("hud.settings.sct_inc_dmg_accum_duration"), + ) + .down_from(state.ids.sct_inc_dmg_radio, 8.0) + .right_from(state.ids.sct_inc_dmg_radio, 10.0) + .font_size(self.fonts.cyri.scale(14)) + .font_id(self.fonts.cyri.conrod_id) + .color(TEXT_COLOR) + .set(state.ids.sct_inc_dmg_accum_duration_text, ui); + + if let Some(new_val) = ImageSlider::continuous( + sct_inc_dmg_accum_duration, + 0.0, + 2.0, + self.imgs.slider_indicator, + self.imgs.slider, + ) + .w_h(104.0, 22.0) + .down_from(state.ids.sct_inc_dmg_accum_duration_text, 8.0) + .track_breadth(12.0) + .slider_length(10.0) + .pad_track((5.0, 5.0)) + .set(state.ids.sct_inc_dmg_accum_duration_slider, ui) + { + events.push(SctIncomingDamageAccumDuration(new_val)); + } + + Text::new(&format!("{:.2}", sct_inc_dmg_accum_duration,)) + .right_from(state.ids.sct_inc_dmg_accum_duration_slider, 8.0) + .font_size(self.fonts.cyri.scale(14)) + .graphics_for(state.ids.sct_inc_dmg_accum_duration_slider) + .font_id(self.fonts.cyri.conrod_id) + .color(TEXT_COLOR) + .set(state.ids.sct_inc_dmg_accum_duration_value, ui); + } + // Toggle Batched Incoming Damage let show_sct_player_batch = ToggleButton::new( show_sct_player_batch, @@ -830,7 +934,17 @@ impl<'a> Widget for Interface<'a> { self.imgs.checkbox_checked, ) .w_h(18.0, 18.0) - .down_from(state.ids.sct_inc_dmg_radio, 8.0) + .down_from( + if show_sct_player_batch { + state.ids.sct_inc_dmg_radio + } else { + state.ids.sct_inc_dmg_accum_duration_slider + }, + 8.0, + ) + .and_if(!show_sct_player_batch, |tb| { + tb.left_from(state.ids.sct_inc_dmg_accum_duration_slider, 10.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_batch_inc_radio, ui); diff --git a/voxygen/src/session/mod.rs b/voxygen/src/session/mod.rs index 87611625e1..a125ae1c9f 100644 --- a/voxygen/src/session/mod.rs +++ b/voxygen/src/session/mod.rs @@ -1579,7 +1579,8 @@ impl PlayState for SessionState { for outcome in outcomes { self.scene .handle_outcome(&outcome, &scene_data, &mut global_state.audio); - self.hud.handle_outcome(&outcome, scene_data.client); + self.hud + .handle_outcome(&outcome, scene_data.client, &global_state); } } } diff --git a/voxygen/src/session/settings_change.rs b/voxygen/src/session/settings_change.rs index 589d658be3..45a7ca9287 100644 --- a/voxygen/src/session/settings_change.rs +++ b/voxygen/src/session/settings_change.rs @@ -99,6 +99,8 @@ pub enum Interface { SctPlayerBatch(bool), SctDamageBatch(bool), SctRoundDamage(bool), + SctDamageAccumDuration(f32), + SctIncomingDamageAccumDuration(f32), SpeechBubbleSelf(bool), SpeechBubbleDarkMode(bool), SpeechBubbleIcon(bool), @@ -467,6 +469,12 @@ impl SettingsChange { Interface::SctRoundDamage(sct_round_damage) => { settings.interface.sct_damage_rounding = sct_round_damage; }, + Interface::SctDamageAccumDuration(sct_dmg_accum_duration) => { + settings.interface.sct_dmg_accum_duration = sct_dmg_accum_duration; + }, + Interface::SctIncomingDamageAccumDuration(sct_inc_dmg_accum_duration) => { + settings.interface.sct_inc_dmg_accum_duration = sct_inc_dmg_accum_duration; + }, Interface::SpeechBubbleSelf(sbdm) => { settings.interface.speech_bubble_self = sbdm; }, diff --git a/voxygen/src/settings/interface.rs b/voxygen/src/settings/interface.rs index 025382efc7..1a31006459 100644 --- a/voxygen/src/settings/interface.rs +++ b/voxygen/src/settings/interface.rs @@ -18,6 +18,8 @@ pub struct InterfaceSettings { pub sct_player_batch: bool, pub sct_damage_batch: bool, pub sct_damage_rounding: bool, + pub sct_dmg_accum_duration: f32, + pub sct_inc_dmg_accum_duration: f32, pub speech_bubble_self: bool, pub speech_bubble_dark_mode: bool, pub speech_bubble_icon: bool, @@ -59,6 +61,8 @@ impl Default for InterfaceSettings { sct_player_batch: false, sct_damage_batch: false, sct_damage_rounding: false, + sct_dmg_accum_duration: 1.0, + sct_inc_dmg_accum_duration: 1.0, speech_bubble_self: true, speech_bubble_dark_mode: false, speech_bubble_icon: true,