Address review

- Change hp_pulse to not be framerate dependent
- Change some of the HpFloater checks to be inside the find() function
- Remove unnecessary join
- Add back option for showing incoming damage + add option for
  experience accumulation
- Change `ExpFloater`s to not store the owner, as they are only shown
  for the player (will have to see if the implementation is correct so
  that it may be applied to the other floaters)
- Rename `Outcome::Damage` to `Outcome::HealthChange` and `DamageInfo`
  to `HealthChangeInfo`
- Update some outdated comments/documentation
This commit is contained in:
Socksonme 2022-06-15 00:11:58 +03:00
parent 8feaea5cdf
commit 2c5fd06d0b
12 changed files with 269 additions and 179 deletions

View File

@ -26,6 +26,7 @@
"hud.settings.toggle_bar_experience": "Toggle Experience Bar",
"hud.settings.scrolling_combat_text": "Scrolling Combat Text",
"hud.settings.damage_accumulation_duration": "Damage Accumulation Duration",
"hud.settings.incoming_damage": "Incoming Damage",
"hud.settings.incoming_damage_accumulation_duration": "Incoming Damage Accumulation Duration",
"hud.settings.round_damage": "Round Damage",
"hud.settings.speech_bubble": "Speech Bubble",
@ -34,6 +35,8 @@
"hud.settings.speech_bubble_icon": "Speech Bubble Icon",
"hud.settings.energybar_numbers": "Energybar Numbers",
"hud.settings.always_show_bars": "Always show Energybars",
"hud.settings.experience_numbers": "Experience Numbers",
"hud.settings.accumulate_experience": "Accumulate Experience Numbers",
"hud.settings.values": "Values",
"hud.settings.percentages": "Percentages",
"hud.settings.chat": "Chat",

View File

@ -157,6 +157,7 @@ impl Health {
}
#[cfg(not(target_arch = "wasm32"))]
/// Returns a boolean if the delta was not zero.
pub fn change_by(&mut self, change: HealthChange) -> bool {
let prev_health = i64::from(self.current);
self.current = (((self.current() + change.amount).clamp(0.0, f32::from(Self::MAX_HEALTH))
@ -185,7 +186,7 @@ impl Health {
(change.time.0 - last_damage_time.0) < DAMAGE_CONTRIB_PRUNE_SECS
});
}
delta.abs() > (Self::HEALTH_EPSILON * Self::SCALING_FACTOR_FLOAT) as i64
delta != 0
}
pub fn damage_contributions(&self) -> impl Iterator<Item = (&DamageContributor, &u64)> {

View File

@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize};
use vek::*;
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct DamageInfo {
pub struct HealthChangeInfo {
pub amount: f32,
pub crit: bool,
pub target: Uid,
@ -67,9 +67,9 @@ pub enum Outcome {
pos: Vec3<f32>,
body: comp::Body,
},
Damage {
HealthChange {
pos: Vec3<f32>,
info: DamageInfo,
info: HealthChangeInfo,
},
Death {
pos: Vec3<f32>,
@ -106,7 +106,7 @@ impl Outcome {
| Outcome::Beam { pos, .. }
| Outcome::SkillPointGain { pos, .. }
| Outcome::SummonedCreature { pos, .. }
| Outcome::Damage { pos, .. }
| Outcome::HealthChange { pos, .. }
| Outcome::Death { pos, .. }
| Outcome::Block { pos, .. }
| Outcome::PoiseChange { pos, .. }

View File

@ -23,7 +23,7 @@ use common::{
Player, Poise, Pos, SkillSet, Stats,
},
event::{EventBus, ServerEvent},
outcome::{DamageInfo, Outcome},
outcome::{HealthChangeInfo, Outcome},
resources::Time,
rtsim::RtSimEntity,
terrain::{Block, BlockKind, TerrainGrid},
@ -66,22 +66,18 @@ 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 outcomes = ecs.write_resource::<EventBus<Outcome>>();
let mut outcomes_emitter = outcomes.emitter();
let mut changed = false;
if let Some(mut health) = ecs.write_storage::<Health>().get_mut(entity) {
changed = health.change_by(change);
}
if let (Some(pos), Some(uid)) = (
if let (Some(pos), Some(uid), Some(mut health)) = (
ecs.read_storage::<Pos>().get(entity),
ecs.read_storage::<Uid>().get(entity),
ecs.write_storage::<Health>().get_mut(entity),
) {
// If the absolute health change amount was greater than the health epsilon,
// push a new Damage outcome
if changed {
outcomes_emitter.emit(Outcome::Damage {
let outcomes = ecs.write_resource::<EventBus<Outcome>>();
let mut outcomes_emitter = outcomes.emitter();
// If the change amount was not zero
if health.change_by(change) {
outcomes_emitter.emit(Outcome::HealthChange {
pos: pos.0,
info: DamageInfo {
info: HealthChangeInfo {
amount: change.amount,
by: change.by,
target: *uid,

View File

@ -514,7 +514,7 @@ impl SfxMgr {
false,
);
},
Outcome::Damage { pos, info, .. } => {
Outcome::HealthChange { pos, info, .. } => {
// Don't emit sound effects from positive damage (healing)
if info.amount < Health::HEALTH_EPSILON {
let sfx_trigger_item = triggers.get_key_value(&SfxEvent::Damage);

View File

@ -1,4 +1,4 @@
use common::{comp::Ori, outcome::DamageInfo};
use common::{comp::Ori, outcome::HealthChangeInfo};
use specs::Component;
use specs_idvs::IdvStorage;
use vek::*;
@ -10,7 +10,7 @@ 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,
pub info: HealthChangeInfo,
// Used for randomly offsetting
pub rand: f32,
}

View File

@ -44,14 +44,6 @@ impl<'a> System<'a> for Sys {
});
}
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);
}
// Remove floater lists on entities without health or without position
for entity in (&entities, !&healths, &hp_floater_lists)
.join()
@ -69,15 +61,21 @@ impl<'a> System<'a> for Sys {
}
// Maintain existing floaters
for (entity, HpFloaterList { floaters, .. }) in (&entities, &mut hp_floater_lists).join() {
for mut floater in floaters.iter_mut() {
for (entity, hp_floater_list) in (&entities, &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);
for mut floater in hp_floater_list.floaters.iter_mut() {
// Increment timer
floater.timer += dt.0;
floater.jump_timer += dt.0;
}
// Clear floaters if newest floater is past show time
if floaters.last().map_or(false, |f| {
if hp_floater_list.floaters.last().map_or(false, |f| {
f.timer
> if Some(entity) != my_entity.0 {
HP_SHOWTIME
@ -85,7 +83,7 @@ impl<'a> System<'a> for Sys {
MY_HP_SHOWTIME
}
}) {
floaters.clear();
hp_floater_list.floaters.clear();
}
}
}

View File

@ -451,7 +451,6 @@ pub struct BuffInfo {
}
pub struct ExpFloater {
pub owner: Uid,
pub exp_change: u32,
pub timer: f32,
pub jump_timer: f32,
@ -1331,9 +1330,7 @@ impl Hud {
if let Some(health) = healths.get(me) {
// Hurt Frame
let hp_percentage = health.current() / health.maximum() * 100.0;
self.hp_pulse += (dt.as_secs_f32() * 10.0 / hp_percentage)
.min(0.07)
.max(0.02);
self.hp_pulse += dt.as_secs_f32() * 10.0 / hp_percentage.max(3.0).min(7.0);
if hp_percentage < 10.0 && !health.is_dead {
let hurt_fade = (self.hp_pulse).sin() * 0.5 + 0.6; //Animation timer
Image::new(self.imgs.hurt_bg)
@ -1425,7 +1422,7 @@ impl Hud {
};
for floater in floaters {
let number_speed = 50.0; // Player Heal Speed
let number_speed = 50.0; // Player number speed
let player_sct_bg_id = player_sct_bg_id_walker.next(
&mut self.ids.player_sct_bgs,
&mut ui_widgets.widget_id_generator(),
@ -1523,82 +1520,76 @@ impl Hud {
f.timer -= dt.as_secs_f32();
f.jump_timer += dt.as_secs_f32();
});
// TODO:Change the other floaters as well if this is the right method
self.floaters.exp_floaters.retain(|f| f.timer > 0.0);
if let Some(uid) = uids.get(me) {
for floater in self
.floaters
.exp_floaters
.iter_mut()
.filter(|f| f.owner == *uid)
{
let number_speed = 50.0; // Number Speed for Single EXP
let player_sct_bg_id = player_sct_bg_id_walker.next(
&mut self.ids.player_sct_bgs,
&mut ui_widgets.widget_id_generator(),
);
let player_sct_id = player_sct_id_walker.next(
&mut self.ids.player_scts,
&mut ui_widgets.widget_id_generator(),
);
/*let player_sct_icon_id = player_sct_id_walker.next(
&mut self.ids.player_scts,
&mut ui_widgets.widget_id_generator(),
);*/
// Increase font size based on fraction of maximum Experience
// "flashes" by having a larger size in the first 100ms
let font_size_xp = 30
+ ((floater.exp_change as f32 / 300.0).min(1.0) * 50.0) as u32
+ if floater.jump_timer < 0.1 {
FLASH_MAX * (((1.0 - floater.jump_timer * 10.0) * 10.0) as u32)
} else {
0
};
let y = floater.timer as f64 * number_speed; // Timer sets the widget offset
//let fade = ((4.0 - floater.timer as f32) * 0.25) + 0.2; // Timer sets
// text transparency
let fade = floater.timer.min(1.0);
for floater in self.floaters.exp_floaters.iter_mut() {
let number_speed = 50.0; // Number Speed for Single EXP
let player_sct_bg_id = player_sct_bg_id_walker.next(
&mut self.ids.player_sct_bgs,
&mut ui_widgets.widget_id_generator(),
);
let player_sct_id = player_sct_id_walker.next(
&mut self.ids.player_scts,
&mut ui_widgets.widget_id_generator(),
);
/*let player_sct_icon_id = player_sct_id_walker.next(
&mut self.ids.player_scts,
&mut ui_widgets.widget_id_generator(),
);*/
// Increase font size based on fraction of maximum Experience
// "flashes" by having a larger size in the first 100ms
let font_size_xp = 30
+ ((floater.exp_change as f32 / 300.0).min(1.0) * 50.0) as u32
+ if floater.jump_timer < 0.1 {
FLASH_MAX * (((1.0 - floater.jump_timer * 10.0) * 10.0) as u32)
} else {
0
};
let y = floater.timer as f64 * number_speed; // Timer sets the widget offset
//let fade = ((4.0 - floater.timer as f32) * 0.25) + 0.2; // Timer sets
// text transparency
let fade = floater.timer.min(1.0);
if floater.exp_change > 0 {
let xp_pool = &floater.xp_pools;
// Don't show 0 Exp
let exp_string = &i18n
.get("hud.sct.experience")
.replace("{amount}", &floater.exp_change.max(1).to_string());
Text::new(exp_string)
.font_size(font_size_xp)
.font_id(self.fonts.cyri.conrod_id)
.color(Color::Rgba(0.0, 0.0, 0.0, fade))
.x_y(
ui_widgets.win_w * (0.5 * floater.rand_offset.0 as f64 - 0.25),
ui_widgets.win_h * (0.15 * floater.rand_offset.1 as f64) + y
- 3.0,
)
.set(player_sct_bg_id, ui_widgets);
Text::new(exp_string)
.font_size(font_size_xp)
.font_id(self.fonts.cyri.conrod_id)
.color(
if xp_pool.contains(&SkillGroupKind::Weapon(ToolKind::Pick)) {
Color::Rgba(0.18, 0.32, 0.9, fade)
} else {
Color::Rgba(0.59, 0.41, 0.67, fade)
},
)
.x_y(
ui_widgets.win_w * (0.5 * floater.rand_offset.0 as f64 - 0.25),
ui_widgets.win_h * (0.15 * floater.rand_offset.1 as f64) + y,
)
.set(player_sct_id, ui_widgets);
// Exp Source Image (TODO: fix widget id crash)
/*if xp_pool.contains(&SkillGroupKind::Weapon(ToolKind::Pick)) {
Image::new(self.imgs.pickaxe_ico)
.w_h(font_size_xp as f64, font_size_xp as f64)
.left_from(player_sct_id, 5.0)
.set(player_sct_icon_id, ui_widgets);
}*/
}
if floater.exp_change > 0 {
let xp_pool = &floater.xp_pools;
// Don't show 0 Exp
let exp_string = &i18n
.get("hud.sct.experience")
.replace("{amount}", &floater.exp_change.max(1).to_string());
Text::new(exp_string)
.font_size(font_size_xp)
.font_id(self.fonts.cyri.conrod_id)
.color(Color::Rgba(0.0, 0.0, 0.0, fade))
.x_y(
ui_widgets.win_w * (0.5 * floater.rand_offset.0 as f64 - 0.25),
ui_widgets.win_h * (0.15 * floater.rand_offset.1 as f64) + y - 3.0,
)
.set(player_sct_bg_id, ui_widgets);
Text::new(exp_string)
.font_size(font_size_xp)
.font_id(self.fonts.cyri.conrod_id)
.color(
if xp_pool.contains(&SkillGroupKind::Weapon(ToolKind::Pick)) {
Color::Rgba(0.18, 0.32, 0.9, fade)
} else {
Color::Rgba(0.59, 0.41, 0.67, fade)
},
)
.x_y(
ui_widgets.win_w * (0.5 * floater.rand_offset.0 as f64 - 0.25),
ui_widgets.win_h * (0.15 * floater.rand_offset.1 as f64) + y,
)
.set(player_sct_id, ui_widgets);
// Exp Source Image (TODO: fix widget id crash)
/*if xp_pool.contains(&SkillGroupKind::Weapon(ToolKind::Pick)) {
Image::new(self.imgs.pickaxe_ico)
.w_h(font_size_xp as f64, font_size_xp as f64)
.left_from(player_sct_id, 5.0)
.set(player_sct_icon_id, ui_widgets);
}*/
}
}
// Skill points
self.floaters
.skill_point_displays
@ -2172,7 +2163,7 @@ impl Hud {
};
for floater in floaters {
let number_speed = 250.0; // Single Numbers Speed
let number_speed = 250.0; // Enemy number speed
let sct_id = sct_walker
.next(&mut self.ids.scts, &mut ui_widgets.widget_id_generator());
let sct_bg_id = sct_bg_walker
@ -4353,22 +4344,28 @@ impl Hud {
let interface = &global_state.settings.interface;
match outcome {
Outcome::ExpChange { uid, exp, xp_pools } => {
match self.floaters.exp_floaters.last_mut() {
Some(floater)
if floater.timer > (EXP_FLOATER_LIFETIME - EXP_ACCUMULATION_DURATION)
&& floater.owner == *uid =>
{
floater.jump_timer = 0.0;
floater.exp_change += *exp;
},
_ => self.floaters.exp_floaters.push(ExpFloater {
owner: *uid,
exp_change: *exp,
timer: EXP_FLOATER_LIFETIME,
jump_timer: 0.0,
rand_offset: rand::thread_rng().gen::<(f32, f32)>(),
xp_pools: xp_pools.clone(),
}),
let ecs = client.state().ecs();
let uids = ecs.read_storage::<Uid>();
let me = client.entity();
if uids.get(me).map_or(false, |me| *me == *uid) {
match self.floaters.exp_floaters.last_mut() {
Some(floater)
if floater.timer
> (EXP_FLOATER_LIFETIME - EXP_ACCUMULATION_DURATION)
&& global_state.settings.interface.accum_experience =>
{
floater.jump_timer = 0.0;
floater.exp_change += *exp;
},
_ => self.floaters.exp_floaters.push(ExpFloater {
exp_change: *exp,
timer: EXP_FLOATER_LIFETIME,
jump_timer: 0.0,
rand_offset: rand::thread_rng().gen::<(f32, f32)>(),
xp_pools: xp_pools.clone(),
}),
}
}
},
Outcome::SkillPointGain {
@ -4395,7 +4392,7 @@ impl Hud {
timer: 1.0,
})
},
Outcome::Damage { info, .. } => {
Outcome::HealthChange { info, .. } => {
let ecs = client.state().ecs();
let mut hp_floater_lists = ecs.write_storage::<vcomp::HpFloaterList>();
let uids = ecs.read_storage::<Uid>();
@ -4404,7 +4401,9 @@ 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);
let hit_me = my_uid.map_or(false, |&uid| {
(info.target == uid) && global_state.settings.interface.sct_inc_dmg
});
if match info.by {
Some(by) => {
let by_me = my_uid.map_or(false, |&uid| by.uid() == uid);
@ -4437,26 +4436,27 @@ impl Hud {
// To separate healing and damage floaters alongside the crit and
// non-crit ones
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
}) && (hit_me
// Ignore crit floaters if damage isn't incoming
|| !f.info.crit)
});
let last_floater = if !info.crit || hit_me {
floater_list.floaters.iter_mut().rev().find(|f| {
(if info.amount < 0.0 {
f.info.amount < 0.0
} else {
f.info.amount > 0.0
}) && f.timer
< if hit_me {
interface.sct_inc_dmg_accum_duration
} else {
interface.sct_dmg_accum_duration
}
// Ignore crit floaters, unless the damage is incoming
&& (hit_me || !f.info.crit)
})
} else {
None
};
match last_floater {
Some(f)
if f.timer < if hit_me {
interface.sct_inc_dmg_accum_duration
} else {
interface.sct_dmg_accum_duration
}
// To avoid grouping up crits with non-crits
&& (!info.crit || hit_me) =>
{
Some(f) => {
f.jump_timer = 0.0;
f.info.amount += info.amount;
f.info.crit = info.crit;

View File

@ -82,6 +82,8 @@ widget_ids! {
sct_dmg_accum_duration_slider,
sct_dmg_accum_duration_text,
sct_dmg_accum_duration_value,
sct_show_inc_dmg_text,
sct_show_inc_dmg_radio,
sct_inc_dmg_accum_duration_slider,
sct_inc_dmg_accum_duration_text,
sct_inc_dmg_accum_duration_value,
@ -93,6 +95,10 @@ widget_ids! {
speech_bubble_dark_mode_button,
speech_bubble_icon_text,
speech_bubble_icon_button,
//
experience_numbers_title,
accum_experience_text,
accum_experience_button,
}
}
@ -710,10 +716,9 @@ impl<'a> Widget for Interface<'a> {
/*Scrolling Combat text
O Show Damage Numbers
O Damage Accumulation Duration: 0s ----I----2s
O Show incoming Damage
O Damage Accumulation Duration: 0s ----I----2s
O Show incoming Damage -- //TODO: add this back
O Incoming Damage Accumulation Duration: 0s ----I----2s
O Batch incoming Numbers
O Round Damage Numbers
*/
// SCT/ Scrolling Combat Text
@ -796,40 +801,67 @@ impl<'a> Widget for Interface<'a> {
.color(TEXT_COLOR)
.set(state.ids.sct_dmg_accum_duration_value, ui);
Text::new(
self.localized_strings
.get("hud.settings.incoming_damage_accumulation_duration"),
// Conditionally toggle incoming damage
let show_inc_dmg = ToggleButton::new(
self.global_state.settings.interface.sct_inc_dmg,
self.imgs.checkbox,
self.imgs.checkbox_checked,
)
.w_h(18.0, 18.0)
.down_from(state.ids.sct_dmg_accum_duration_slider, 8.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);
.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_inc_dmg_radio, 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));
if self.global_state.settings.interface.sct_inc_dmg != show_inc_dmg {
events.push(SctIncomingDamage(
!self.global_state.settings.interface.sct_inc_dmg,
))
}
Text::new(&format!("{:.2}", sct_inc_dmg_accum_duration,))
.right_from(state.ids.sct_inc_dmg_accum_duration_slider, 8.0)
Text::new(self.localized_strings.get("hud.settings.incoming_damage"))
.right_from(state.ids.sct_show_inc_dmg_radio, 10.0)
.font_size(self.fonts.cyri.scale(14))
.font_id(self.fonts.cyri.conrod_id)
.graphics_for(state.ids.sct_show_inc_dmg_radio)
.color(TEXT_COLOR)
.set(state.ids.sct_show_inc_dmg_text, ui);
if self.global_state.settings.interface.sct_inc_dmg {
Text::new(
self.localized_strings
.get("hud.settings.incoming_damage_accumulation_duration"),
)
.down_from(state.ids.sct_show_inc_dmg_radio, 8.0)
.right_from(state.ids.sct_show_inc_dmg_radio, 10.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);
.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);
}
// Round Damage
let show_sct_damage_rounding = ToggleButton::new(
@ -838,7 +870,15 @@ impl<'a> Widget for Interface<'a> {
self.imgs.checkbox_checked,
)
.w_h(18.0, 18.0)
.down_from(state.ids.sct_inc_dmg_accum_duration_slider, 8.0)
.down_from(
if self.global_state.settings.interface.sct_inc_dmg {
state.ids.sct_inc_dmg_accum_duration_slider
} else {
state.ids.sct_show_inc_dmg_radio
},
8.0,
)
.x_align_to(state.ids.sct_show_inc_dmg_radio, Align::Start)
.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);
@ -1072,6 +1112,46 @@ impl<'a> Widget for Interface<'a> {
.color(TEXT_COLOR)
.set(state.ids.always_show_bars_label, ui);
// Experience Numbers
Text::new(
self.localized_strings
.get("hud.settings.experience_numbers"),
)
.down_from(state.ids.always_show_bars_button, 20.0)
.font_size(self.fonts.cyri.scale(18))
.font_id(self.fonts.cyri.conrod_id)
.color(TEXT_COLOR)
.set(state.ids.experience_numbers_title, ui);
// Acuumulate Experience Gained
let accum_experience = ToggleButton::new(
self.global_state.settings.interface.accum_experience,
self.imgs.checkbox,
self.imgs.checkbox_checked,
)
.w_h(18.0, 18.0)
.down_from(state.ids.experience_numbers_title, 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.accum_experience_button, ui);
if self.global_state.settings.interface.accum_experience != accum_experience {
events.push(AccumExperience(
!self.global_state.settings.interface.accum_experience,
));
}
Text::new(
self.localized_strings
.get("hud.settings.accumulate_experience"),
)
.right_from(state.ids.accum_experience_button, 10.0)
.font_size(self.fonts.cyri.scale(14))
.font_id(self.fonts.cyri.conrod_id)
.graphics_for(state.ids.accum_experience_button)
.color(TEXT_COLOR)
.set(state.ids.accum_experience_text, ui);
// Reset the interface settings to the default settings
if Button::image(self.imgs.button)
.w_h(RESET_BUTTONS_WIDTH, RESET_BUTTONS_HEIGHT)

View File

@ -284,7 +284,7 @@ impl ParticleMgr {
| Outcome::ExpChange { .. }
| Outcome::SkillPointGain { .. }
| Outcome::ComboChange { .. }
| Outcome::Damage { .. }
| Outcome::HealthChange { .. }
| Outcome::PoiseChange { .. }
| Outcome::Utterance { .. }
| Outcome::Glider { .. } => {},

View File

@ -98,6 +98,7 @@ pub enum Interface {
Sct(bool),
SctRoundDamage(bool),
SctDamageAccumDuration(f32),
SctIncomingDamage(bool),
SctIncomingDamageAccumDuration(f32),
SpeechBubbleSelf(bool),
SpeechBubbleDarkMode(bool),
@ -135,6 +136,7 @@ pub enum Interface {
MapShowPeaks(bool),
MapShowBiomes(bool),
MapShowVoxelMap(bool),
AccumExperience(bool),
ResetInterfaceSettings,
}
@ -464,6 +466,9 @@ impl SettingsChange {
Interface::SctDamageAccumDuration(sct_dmg_accum_duration) => {
settings.interface.sct_dmg_accum_duration = sct_dmg_accum_duration;
},
Interface::SctIncomingDamage(sct_inc_dmg_accum_duration) => {
settings.interface.sct_inc_dmg = sct_inc_dmg_accum_duration;
},
Interface::SctIncomingDamageAccumDuration(sct_inc_dmg_accum_duration) => {
settings.interface.sct_inc_dmg_accum_duration = sct_inc_dmg_accum_duration;
},
@ -563,6 +568,9 @@ impl SettingsChange {
Interface::MapShowVoxelMap(map_show_voxel_map) => {
settings.interface.map_show_voxel_map = map_show_voxel_map;
},
Interface::AccumExperience(accum_experience) => {
settings.interface.accum_experience = accum_experience;
},
Interface::ResetInterfaceSettings => {
// Reset Interface Settings
let tmp = settings.interface.intro_show;

View File

@ -17,6 +17,7 @@ pub struct InterfaceSettings {
pub sct: bool,
pub sct_damage_rounding: bool,
pub sct_dmg_accum_duration: f32,
pub sct_inc_dmg: bool,
pub sct_inc_dmg_accum_duration: f32,
pub speech_bubble_self: bool,
pub speech_bubble_dark_mode: bool,
@ -45,6 +46,7 @@ pub struct InterfaceSettings {
pub minimap_show: bool,
pub minimap_face_north: bool,
pub minimap_zoom: f64,
pub accum_experience: bool,
}
impl Default for InterfaceSettings {
@ -58,6 +60,7 @@ impl Default for InterfaceSettings {
sct: true,
sct_damage_rounding: false,
sct_dmg_accum_duration: 0.45,
sct_inc_dmg: true,
sct_inc_dmg_accum_duration: 0.45,
speech_bubble_self: true,
speech_bubble_dark_mode: false,
@ -86,6 +89,7 @@ impl Default for InterfaceSettings {
minimap_show: true,
minimap_face_north: true,
minimap_zoom: 160.0,
accum_experience: true,
}
}
}