mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Allow players to see own speech bubbles.
This commit is contained in:
parent
7364c5a31e
commit
e546a1d1a9
@ -30,6 +30,7 @@
|
||||
"hud.settings.incoming_damage": "Incoming Damage",
|
||||
"hud.settings.cumulated_incoming_damage": "Cumulated Incoming Damage",
|
||||
"hud.settings.speech_bubble": "Speech Bubble",
|
||||
"hud.settings.speech_bubble_self": "Show Own Speech Bubbles",
|
||||
"hud.settings.speech_bubble_dark_mode": "Speech Bubble Dark Mode",
|
||||
"hud.settings.speech_bubble_icon": "Speech Bubble Icon",
|
||||
"hud.settings.energybar_numbers": "Energybar Numbers",
|
||||
@ -38,7 +39,7 @@
|
||||
"hud.settings.percentages": "Percentages",
|
||||
"hud.settings.chat": "Chat",
|
||||
"hud.settings.background_opacity": "Background Opacity",
|
||||
"hud.settings.chat_character_name": "Character Names in chat",
|
||||
"hud.settings.chat_character_name": "Character Names in Chat",
|
||||
"hud.settings.loading_tips": "Loading Screen Tips",
|
||||
"hud.settings.reset_interface": "Reset to Defaults",
|
||||
|
||||
|
@ -1777,7 +1777,7 @@ impl Hud {
|
||||
let speech_bubbles = &self.speech_bubbles;
|
||||
|
||||
// Render overhead name tags and health bars
|
||||
for (pos, info, bubble, _, _, health, _, height_offset, hpfl, in_group) in (
|
||||
for (pos, info, bubble, _, _, health, _, height_offset, hpfl, in_group, is_me) in (
|
||||
&entities,
|
||||
&pos,
|
||||
interpolated.maybe(),
|
||||
@ -1797,8 +1797,7 @@ impl Hud {
|
||||
.join()
|
||||
.filter(|t| {
|
||||
let health = t.5;
|
||||
let entity = t.0;
|
||||
entity != me && !health.map_or(false, |h| h.is_dead)
|
||||
!health.map_or(false, |h| h.is_dead)
|
||||
})
|
||||
.filter_map(
|
||||
|(
|
||||
@ -1821,6 +1820,7 @@ impl Hud {
|
||||
// Use interpolated position if available
|
||||
let pos = interpolated.map_or(pos.0, |i| i.pos);
|
||||
let in_group = client.group_members().contains_key(uid);
|
||||
let is_me = entity == me;
|
||||
// TODO: once the site2 rework lands and merchants have dedicated stalls or
|
||||
// buildings, they no longer need to be emphasized via the higher overhead
|
||||
// text radius relative to other NPCs
|
||||
@ -1884,6 +1884,7 @@ impl Hud {
|
||||
body.height() * scale.map_or(1.0, |s| s.0) + 0.5,
|
||||
hpfl,
|
||||
in_group,
|
||||
is_me,
|
||||
)
|
||||
})
|
||||
},
|
||||
@ -1903,6 +1904,7 @@ impl Hud {
|
||||
info,
|
||||
bubble,
|
||||
in_group,
|
||||
is_me,
|
||||
&global_state.settings.interface,
|
||||
self.pulse,
|
||||
i18n,
|
||||
|
@ -81,6 +81,7 @@ pub struct Overhead<'a> {
|
||||
info: Option<Info<'a>>,
|
||||
bubble: Option<&'a SpeechBubble>,
|
||||
in_group: bool,
|
||||
is_me: bool,
|
||||
settings: &'a InterfaceSettings,
|
||||
pulse: f32,
|
||||
i18n: &'a Localization,
|
||||
@ -96,6 +97,7 @@ impl<'a> Overhead<'a> {
|
||||
info: Option<Info<'a>>,
|
||||
bubble: Option<&'a SpeechBubble>,
|
||||
in_group: bool,
|
||||
is_me: bool,
|
||||
settings: &'a InterfaceSettings,
|
||||
pulse: f32,
|
||||
i18n: &'a Localization,
|
||||
@ -106,6 +108,7 @@ impl<'a> Overhead<'a> {
|
||||
info,
|
||||
bubble,
|
||||
in_group,
|
||||
is_me,
|
||||
settings,
|
||||
pulse,
|
||||
i18n,
|
||||
@ -179,115 +182,119 @@ impl<'a> Widget for Overhead<'a> {
|
||||
const BARSIZE: f64 = 2.0; // Scaling
|
||||
const MANA_BAR_HEIGHT: f64 = BARSIZE * 1.5;
|
||||
const MANA_BAR_Y: f64 = MANA_BAR_HEIGHT / 2.0;
|
||||
if let Some(Info {
|
||||
name,
|
||||
health,
|
||||
buffs,
|
||||
energy,
|
||||
combat_rating,
|
||||
}) = self.info
|
||||
{
|
||||
// Used to set healthbar colours based on hp_percentage
|
||||
let hp_percentage = health.map_or(100.0, |h| {
|
||||
f64::from(h.current() / h.base_max().max(h.maximum()) * 100.0)
|
||||
});
|
||||
// Compare levels to decide if a skull is shown
|
||||
let health_current = health.map_or(1.0, |h| f64::from(h.current()));
|
||||
let health_max = health.map_or(1.0, |h| f64::from(h.maximum()));
|
||||
let name_y = if (health_current - health_max).abs() < 1e-6 {
|
||||
MANA_BAR_Y + 20.0
|
||||
} else {
|
||||
MANA_BAR_Y + 32.0
|
||||
};
|
||||
let font_size = if hp_percentage.abs() > 99.9 { 24 } else { 20 };
|
||||
// Show K for numbers above 10^3 and truncate them
|
||||
// Show M for numbers above 10^6 and truncate them
|
||||
let health_cur_txt = match health_current as u32 {
|
||||
0..=999 => format!("{:.0}", health_current.max(1.0)),
|
||||
1000..=999999 => format!("{:.0}K", (health_current / 1000.0).max(1.0)),
|
||||
_ => format!("{:.0}M", (health_current as f64 / 1.0e6).max(1.0)),
|
||||
};
|
||||
let health_max_txt = match health_max as u32 {
|
||||
0..=999 => format!("{:.0}", health_max.max(1.0)),
|
||||
1000..=999999 => format!("{:.0}K", (health_max / 1000.0).max(1.0)),
|
||||
_ => format!("{:.0}M", (health_max as f64 / 1.0e6).max(1.0)),
|
||||
};
|
||||
// Buffs
|
||||
// Alignment
|
||||
let buff_count = buffs.kinds.len().min(11);
|
||||
Rectangle::fill_with([168.0, 100.0], color::TRANSPARENT)
|
||||
.x_y(-1.0, name_y + 60.0)
|
||||
.parent(id)
|
||||
.set(state.ids.buffs_align, ui);
|
||||
// Only render info if not me
|
||||
if !self.is_me {
|
||||
if let Some(Info {
|
||||
name,
|
||||
health,
|
||||
buffs,
|
||||
energy,
|
||||
combat_rating,
|
||||
}) = self.info
|
||||
{
|
||||
// Used to set healthbar colours based on hp_percentage
|
||||
let hp_percentage = health.map_or(100.0, |h| {
|
||||
f64::from(h.current() / h.base_max().max(h.maximum()) * 100.0)
|
||||
});
|
||||
// Compare levels to decide if a skull is shown
|
||||
let health_current = health.map_or(1.0, |h| f64::from(h.current()));
|
||||
let health_max = health.map_or(1.0, |h| f64::from(h.maximum()));
|
||||
let name_y = if (health_current - health_max).abs() < 1e-6 {
|
||||
MANA_BAR_Y + 20.0
|
||||
} else {
|
||||
MANA_BAR_Y + 32.0
|
||||
};
|
||||
let font_size = if hp_percentage.abs() > 99.9 { 24 } else { 20 };
|
||||
// Show K for numbers above 10^3 and truncate them
|
||||
// Show M for numbers above 10^6 and truncate them
|
||||
let health_cur_txt = match health_current as u32 {
|
||||
0..=999 => format!("{:.0}", health_current.max(1.0)),
|
||||
1000..=999999 => format!("{:.0}K", (health_current / 1000.0).max(1.0)),
|
||||
_ => format!("{:.0}M", (health_current as f64 / 1.0e6).max(1.0)),
|
||||
};
|
||||
let health_max_txt = match health_max as u32 {
|
||||
0..=999 => format!("{:.0}", health_max.max(1.0)),
|
||||
1000..=999999 => format!("{:.0}K", (health_max / 1000.0).max(1.0)),
|
||||
_ => format!("{:.0}M", (health_max as f64 / 1.0e6).max(1.0)),
|
||||
};
|
||||
// Buffs
|
||||
// Alignment
|
||||
let buff_count = buffs.kinds.len().min(11);
|
||||
Rectangle::fill_with([168.0, 100.0], color::TRANSPARENT)
|
||||
.x_y(-1.0, name_y + 60.0)
|
||||
.parent(id)
|
||||
.set(state.ids.buffs_align, ui);
|
||||
|
||||
let gen = &mut ui.widget_id_generator();
|
||||
if state.ids.buffs.len() < buff_count {
|
||||
state.update(|state| state.ids.buffs.resize(buff_count, gen));
|
||||
};
|
||||
if state.ids.buff_timers.len() < buff_count {
|
||||
state.update(|state| state.ids.buff_timers.resize(buff_count, gen));
|
||||
};
|
||||
let gen = &mut ui.widget_id_generator();
|
||||
if state.ids.buffs.len() < buff_count {
|
||||
state.update(|state| state.ids.buffs.resize(buff_count, gen));
|
||||
};
|
||||
if state.ids.buff_timers.len() < buff_count {
|
||||
state.update(|state| state.ids.buff_timers.resize(buff_count, gen));
|
||||
};
|
||||
|
||||
let buff_ani = ((self.pulse * 4.0).cos() * 0.5 + 0.8) + 0.5; //Animation timer
|
||||
let pulsating_col = Color::Rgba(1.0, 1.0, 1.0, buff_ani);
|
||||
let norm_col = Color::Rgba(1.0, 1.0, 1.0, 1.0);
|
||||
// Create Buff Widgets
|
||||
if self.bubble.is_none() {
|
||||
state
|
||||
.ids
|
||||
.buffs
|
||||
.iter()
|
||||
.copied()
|
||||
.zip(state.ids.buff_timers.iter().copied())
|
||||
.zip(buffs.iter_active().map(get_buff_info))
|
||||
.enumerate()
|
||||
.for_each(|(i, ((id, timer_id), buff))| {
|
||||
// Limit displayed buffs
|
||||
let max_duration = buff.data.duration;
|
||||
let current_duration = buff.dur;
|
||||
let duration_percentage = current_duration.map_or(1000.0, |cur| {
|
||||
max_duration.map_or(1000.0, |max| {
|
||||
cur.as_secs_f32() / max.as_secs_f32() * 1000.0
|
||||
let buff_ani = ((self.pulse * 4.0).cos() * 0.5 + 0.8) + 0.5; //Animation timer
|
||||
let pulsating_col = Color::Rgba(1.0, 1.0, 1.0, buff_ani);
|
||||
let norm_col = Color::Rgba(1.0, 1.0, 1.0, 1.0);
|
||||
// Create Buff Widgets
|
||||
if self.bubble.is_none() {
|
||||
state
|
||||
.ids
|
||||
.buffs
|
||||
.iter()
|
||||
.copied()
|
||||
.zip(state.ids.buff_timers.iter().copied())
|
||||
.zip(buffs.iter_active().map(get_buff_info))
|
||||
.enumerate()
|
||||
.for_each(|(i, ((id, timer_id), buff))| {
|
||||
// Limit displayed buffs
|
||||
let max_duration = buff.data.duration;
|
||||
let current_duration = buff.dur;
|
||||
let duration_percentage = current_duration.map_or(1000.0, |cur| {
|
||||
max_duration.map_or(1000.0, |max| {
|
||||
cur.as_secs_f32() / max.as_secs_f32() * 1000.0
|
||||
})
|
||||
}) as u32; // Percentage to determine which frame of the timer overlay is displayed
|
||||
let buff_img = get_buff_image(buff.kind, self.imgs);
|
||||
let buff_widget = Image::new(buff_img).w_h(20.0, 20.0);
|
||||
// Sort buffs into rows of 5 slots
|
||||
let x = i % 5;
|
||||
let y = i / 5;
|
||||
let buff_widget = buff_widget.bottom_left_with_margins_on(
|
||||
state.ids.buffs_align,
|
||||
0.0 + y as f64 * (21.0),
|
||||
0.0 + x as f64 * (21.0),
|
||||
);
|
||||
buff_widget
|
||||
.color(
|
||||
if current_duration
|
||||
.map_or(false, |cur| cur.as_secs_f32() < 10.0)
|
||||
{
|
||||
Some(pulsating_col)
|
||||
} else {
|
||||
Some(norm_col)
|
||||
},
|
||||
)
|
||||
.set(id, ui);
|
||||
|
||||
Image::new(match duration_percentage as u64 {
|
||||
875..=1000 => self.imgs.nothing, // 8/8
|
||||
750..=874 => self.imgs.buff_0, // 7/8
|
||||
625..=749 => self.imgs.buff_1, // 6/8
|
||||
500..=624 => self.imgs.buff_2, // 5/8
|
||||
375..=499 => self.imgs.buff_3, // 4/8
|
||||
250..=374 => self.imgs.buff_4, // 3/8
|
||||
125..=249 => self.imgs.buff_5, // 2/8
|
||||
0..=124 => self.imgs.buff_6, // 1/8
|
||||
_ => self.imgs.nothing,
|
||||
})
|
||||
}) as u32; // Percentage to determine which frame of the timer overlay is displayed
|
||||
let buff_img = get_buff_image(buff.kind, self.imgs);
|
||||
let buff_widget = Image::new(buff_img).w_h(20.0, 20.0);
|
||||
// Sort buffs into rows of 5 slots
|
||||
let x = i % 5;
|
||||
let y = i / 5;
|
||||
let buff_widget = buff_widget.bottom_left_with_margins_on(
|
||||
state.ids.buffs_align,
|
||||
0.0 + y as f64 * (21.0),
|
||||
0.0 + x as f64 * (21.0),
|
||||
);
|
||||
buff_widget
|
||||
.color(
|
||||
if current_duration.map_or(false, |cur| cur.as_secs_f32() < 10.0) {
|
||||
Some(pulsating_col)
|
||||
} else {
|
||||
Some(norm_col)
|
||||
},
|
||||
)
|
||||
.set(id, ui);
|
||||
|
||||
Image::new(match duration_percentage as u64 {
|
||||
875..=1000 => self.imgs.nothing, // 8/8
|
||||
750..=874 => self.imgs.buff_0, // 7/8
|
||||
625..=749 => self.imgs.buff_1, // 6/8
|
||||
500..=624 => self.imgs.buff_2, // 5/8
|
||||
375..=499 => self.imgs.buff_3, // 4/8
|
||||
250..=374 => self.imgs.buff_4, // 3/8
|
||||
125..=249 => self.imgs.buff_5, // 2/8
|
||||
0..=124 => self.imgs.buff_6, // 1/8
|
||||
_ => self.imgs.nothing,
|
||||
})
|
||||
.w_h(20.0, 20.0)
|
||||
.middle_of(id)
|
||||
.set(timer_id, ui);
|
||||
});
|
||||
}
|
||||
// Name
|
||||
Text::new(name)
|
||||
.w_h(20.0, 20.0)
|
||||
.middle_of(id)
|
||||
.set(timer_id, ui);
|
||||
});
|
||||
}
|
||||
// Name
|
||||
Text::new(name)
|
||||
//Text::new(&format!("{} [{:?}]", name, combat_rating)) // <- Uncomment to debug combat ratings
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.font_size(font_size)
|
||||
@ -295,7 +302,7 @@ impl<'a> Widget for Overhead<'a> {
|
||||
.x_y(-1.0, name_y)
|
||||
.parent(id)
|
||||
.set(state.ids.name_bg, ui);
|
||||
Text::new(name)
|
||||
Text::new(name)
|
||||
//Text::new(&format!("{} [{:?}]", name, combat_rating)) // <- Uncomment to debug combat ratings
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.font_size(font_size)
|
||||
@ -310,292 +317,297 @@ impl<'a> Widget for Overhead<'a> {
|
||||
.parent(id)
|
||||
.set(state.ids.name, ui);
|
||||
|
||||
match health {
|
||||
Some(health)
|
||||
if should_show_healthbar(health) || decayed_health_displayed(health) =>
|
||||
{
|
||||
// Show HP Bar
|
||||
let hp_ani = (self.pulse * 4.0/* speed factor */).cos() * 0.5 + 1.0; //Animation timer
|
||||
let crit_hp_color: Color = Color::Rgba(0.93, 0.59, 0.03, hp_ani);
|
||||
let decayed_health = f64::from(1.0 - health.maximum() / health.base_max());
|
||||
// Background
|
||||
Image::new(if self.in_group {self.imgs.health_bar_group_bg} else {self.imgs.enemy_health_bg})
|
||||
match health {
|
||||
Some(health)
|
||||
if should_show_healthbar(health) || decayed_health_displayed(health) =>
|
||||
{
|
||||
// Show HP Bar
|
||||
let hp_ani = (self.pulse * 4.0/* speed factor */).cos() * 0.5 + 1.0; //Animation timer
|
||||
let crit_hp_color: Color = Color::Rgba(0.93, 0.59, 0.03, hp_ani);
|
||||
let decayed_health = f64::from(1.0 - health.maximum() / health.base_max());
|
||||
// Background
|
||||
Image::new(if self.in_group {self.imgs.health_bar_group_bg} else {self.imgs.enemy_health_bg})
|
||||
.w_h(84.0 * BARSIZE, 10.0 * BARSIZE)
|
||||
.x_y(0.0, MANA_BAR_Y + 6.5) //-25.5)
|
||||
.color(Some(Color::Rgba(0.1, 0.1, 0.1, 0.8)))
|
||||
.parent(id)
|
||||
.set(state.ids.health_bar_bg, ui);
|
||||
|
||||
// % HP Filling
|
||||
let size_factor = (hp_percentage / 100.0) * BARSIZE;
|
||||
let w = if self.in_group {
|
||||
82.0 * size_factor
|
||||
} else {
|
||||
73.0 * size_factor
|
||||
};
|
||||
let h = 6.0 * BARSIZE;
|
||||
let x = if self.in_group {
|
||||
(0.0 + (hp_percentage / 100.0 * 41.0 - 41.0)) * BARSIZE
|
||||
} else {
|
||||
(4.5 + (hp_percentage / 100.0 * 36.45 - 36.45)) * BARSIZE
|
||||
};
|
||||
Image::new(self.imgs.enemy_bar)
|
||||
.w_h(w, h)
|
||||
.x_y(x, MANA_BAR_Y + 8.0)
|
||||
.color(if self.in_group {
|
||||
// Different HP bar colors only for group members
|
||||
Some(match hp_percentage {
|
||||
x if (0.0..25.0).contains(&x) => crit_hp_color,
|
||||
x if (25.0..50.0).contains(&x) => LOW_HP_COLOR,
|
||||
_ => HP_COLOR,
|
||||
})
|
||||
} else {
|
||||
Some(ENEMY_HP_COLOR)
|
||||
})
|
||||
.parent(id)
|
||||
.set(state.ids.health_bar, ui);
|
||||
|
||||
if decayed_health > 0.0 {
|
||||
let x_decayed = if self.in_group {
|
||||
(0.0 - (decayed_health * 41.0 - 41.0)) * BARSIZE
|
||||
} else {
|
||||
(4.5 - (decayed_health * 36.45 - 36.45)) * BARSIZE
|
||||
};
|
||||
|
||||
let decay_bar_len = decayed_health
|
||||
* if self.in_group {
|
||||
82.0 * BARSIZE
|
||||
} else {
|
||||
73.0 * BARSIZE
|
||||
};
|
||||
Image::new(self.imgs.enemy_bar)
|
||||
.w_h(decay_bar_len, h)
|
||||
.x_y(x_decayed, MANA_BAR_Y + 8.0)
|
||||
.color(Some(QUALITY_EPIC))
|
||||
.parent(id)
|
||||
.set(state.ids.decay_bar, ui);
|
||||
}
|
||||
let mut txt = format!("{}/{}", health_cur_txt, health_max_txt);
|
||||
if health.is_dead {
|
||||
txt = self.i18n.get("hud.group.dead").to_string()
|
||||
};
|
||||
Text::new(&txt)
|
||||
.mid_top_with_margin_on(state.ids.health_bar_bg, 2.0)
|
||||
.font_size(10)
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.color(TEXT_COLOR)
|
||||
.parent(id)
|
||||
.set(state.ids.health_txt, ui);
|
||||
|
||||
// % Mana Filling
|
||||
if let Some(energy) = energy {
|
||||
let energy_factor = f64::from(energy.current() / energy.maximum());
|
||||
let size_factor = energy_factor * BARSIZE;
|
||||
// % HP Filling
|
||||
let size_factor = (hp_percentage / 100.0) * BARSIZE;
|
||||
let w = if self.in_group {
|
||||
80.0 * size_factor
|
||||
82.0 * size_factor
|
||||
} else {
|
||||
72.0 * size_factor
|
||||
73.0 * size_factor
|
||||
};
|
||||
let h = 6.0 * BARSIZE;
|
||||
let x = if self.in_group {
|
||||
((0.0 + (energy_factor * 40.0)) - 40.0) * BARSIZE
|
||||
(0.0 + (hp_percentage / 100.0 * 41.0 - 41.0)) * BARSIZE
|
||||
} else {
|
||||
((3.5 + (energy_factor * 36.5)) - 36.45) * BARSIZE
|
||||
(4.5 + (hp_percentage / 100.0 * 36.45 - 36.45)) * BARSIZE
|
||||
};
|
||||
Rectangle::fill_with([w, MANA_BAR_HEIGHT], STAMINA_COLOR)
|
||||
.x_y(
|
||||
x, MANA_BAR_Y, //-32.0,
|
||||
)
|
||||
Image::new(self.imgs.enemy_bar)
|
||||
.w_h(w, h)
|
||||
.x_y(x, MANA_BAR_Y + 8.0)
|
||||
.color(if self.in_group {
|
||||
// Different HP bar colors only for group members
|
||||
Some(match hp_percentage {
|
||||
x if (0.0..25.0).contains(&x) => crit_hp_color,
|
||||
x if (25.0..50.0).contains(&x) => LOW_HP_COLOR,
|
||||
_ => HP_COLOR,
|
||||
})
|
||||
} else {
|
||||
Some(ENEMY_HP_COLOR)
|
||||
})
|
||||
.parent(id)
|
||||
.set(state.ids.mana_bar, ui);
|
||||
}
|
||||
.set(state.ids.health_bar, ui);
|
||||
|
||||
// Foreground
|
||||
Image::new(if self.in_group {self.imgs.health_bar_group} else {self.imgs.enemy_health})
|
||||
if decayed_health > 0.0 {
|
||||
let x_decayed = if self.in_group {
|
||||
(0.0 - (decayed_health * 41.0 - 41.0)) * BARSIZE
|
||||
} else {
|
||||
(4.5 - (decayed_health * 36.45 - 36.45)) * BARSIZE
|
||||
};
|
||||
|
||||
let decay_bar_len = decayed_health
|
||||
* if self.in_group {
|
||||
82.0 * BARSIZE
|
||||
} else {
|
||||
73.0 * BARSIZE
|
||||
};
|
||||
Image::new(self.imgs.enemy_bar)
|
||||
.w_h(decay_bar_len, h)
|
||||
.x_y(x_decayed, MANA_BAR_Y + 8.0)
|
||||
.color(Some(QUALITY_EPIC))
|
||||
.parent(id)
|
||||
.set(state.ids.decay_bar, ui);
|
||||
}
|
||||
let mut txt = format!("{}/{}", health_cur_txt, health_max_txt);
|
||||
if health.is_dead {
|
||||
txt = self.i18n.get("hud.group.dead").to_string()
|
||||
};
|
||||
Text::new(&txt)
|
||||
.mid_top_with_margin_on(state.ids.health_bar_bg, 2.0)
|
||||
.font_size(10)
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.color(TEXT_COLOR)
|
||||
.parent(id)
|
||||
.set(state.ids.health_txt, ui);
|
||||
|
||||
// % Mana Filling
|
||||
if let Some(energy) = energy {
|
||||
let energy_factor = f64::from(energy.current() / energy.maximum());
|
||||
let size_factor = energy_factor * BARSIZE;
|
||||
let w = if self.in_group {
|
||||
80.0 * size_factor
|
||||
} else {
|
||||
72.0 * size_factor
|
||||
};
|
||||
let x = if self.in_group {
|
||||
((0.0 + (energy_factor * 40.0)) - 40.0) * BARSIZE
|
||||
} else {
|
||||
((3.5 + (energy_factor * 36.5)) - 36.45) * BARSIZE
|
||||
};
|
||||
Rectangle::fill_with([w, MANA_BAR_HEIGHT], STAMINA_COLOR)
|
||||
.x_y(
|
||||
x, MANA_BAR_Y, //-32.0,
|
||||
)
|
||||
.parent(id)
|
||||
.set(state.ids.mana_bar, ui);
|
||||
}
|
||||
|
||||
// Foreground
|
||||
Image::new(if self.in_group {self.imgs.health_bar_group} else {self.imgs.enemy_health})
|
||||
.w_h(84.0 * BARSIZE, 10.0 * BARSIZE)
|
||||
.x_y(0.0, MANA_BAR_Y + 6.5) //-25.5)
|
||||
.color(Some(Color::Rgba(1.0, 1.0, 1.0, 0.99)))
|
||||
.parent(id)
|
||||
.set(state.ids.health_bar_fg, ui);
|
||||
|
||||
let indicator_col = cr_color(combat_rating);
|
||||
let artifact_diffculty = 122.0;
|
||||
let indicator_col = cr_color(combat_rating);
|
||||
let artifact_diffculty = 122.0;
|
||||
|
||||
if combat_rating > artifact_diffculty && !self.in_group {
|
||||
let skull_ani =
|
||||
((self.pulse * 0.7/* speed factor */).cos() * 0.5 + 0.5) * 10.0; //Animation timer
|
||||
Image::new(if skull_ani as i32 == 1 && rand::random::<f32>() < 0.9 {
|
||||
self.imgs.skull_2
|
||||
if combat_rating > artifact_diffculty && !self.in_group {
|
||||
let skull_ani =
|
||||
((self.pulse * 0.7/* speed factor */).cos() * 0.5 + 0.5) * 10.0; //Animation timer
|
||||
Image::new(if skull_ani as i32 == 1 && rand::random::<f32>() < 0.9 {
|
||||
self.imgs.skull_2
|
||||
} else {
|
||||
self.imgs.skull
|
||||
})
|
||||
.w_h(18.0 * BARSIZE, 18.0 * BARSIZE)
|
||||
.x_y(-39.0 * BARSIZE, MANA_BAR_Y + 7.0)
|
||||
.color(Some(Color::Rgba(1.0, 1.0, 1.0, 1.0)))
|
||||
.parent(id)
|
||||
.set(state.ids.level_skull, ui);
|
||||
} else {
|
||||
self.imgs.skull
|
||||
})
|
||||
.w_h(18.0 * BARSIZE, 18.0 * BARSIZE)
|
||||
.x_y(-39.0 * BARSIZE, MANA_BAR_Y + 7.0)
|
||||
.color(Some(Color::Rgba(1.0, 1.0, 1.0, 1.0)))
|
||||
.parent(id)
|
||||
.set(state.ids.level_skull, ui);
|
||||
} else {
|
||||
Image::new(if self.in_group {
|
||||
self.imgs.nothing
|
||||
} else {
|
||||
self.imgs.combat_rating_ico
|
||||
})
|
||||
.w_h(7.0 * BARSIZE, 7.0 * BARSIZE)
|
||||
.x_y(-37.0 * BARSIZE, MANA_BAR_Y + 6.0)
|
||||
.color(Some(indicator_col))
|
||||
.parent(id)
|
||||
.set(state.ids.level, ui);
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
Image::new(if self.in_group {
|
||||
self.imgs.nothing
|
||||
} else {
|
||||
self.imgs.combat_rating_ico
|
||||
})
|
||||
.w_h(7.0 * BARSIZE, 7.0 * BARSIZE)
|
||||
.x_y(-37.0 * BARSIZE, MANA_BAR_Y + 6.0)
|
||||
.color(Some(indicator_col))
|
||||
.parent(id)
|
||||
.set(state.ids.level, ui);
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
// Speech bubble
|
||||
if let Some(bubble) = self.bubble {
|
||||
let dark_mode = self.settings.speech_bubble_dark_mode;
|
||||
let localizer = |s: &str, i| -> String { self.i18n.get_variation(s, i).to_string() };
|
||||
let bubble_contents: String = bubble.message(localizer);
|
||||
let (text_color, shadow_color) = bubble_color(bubble, dark_mode);
|
||||
let mut text = Text::new(&bubble_contents)
|
||||
.color(text_color)
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.font_size(18)
|
||||
.up_from(state.ids.name, 26.0)
|
||||
.x_align_to(state.ids.name, Align::Middle)
|
||||
.parent(id);
|
||||
|
||||
if let Some(w) = text.get_w(ui) {
|
||||
if w > MAX_BUBBLE_WIDTH {
|
||||
text = text.w(MAX_BUBBLE_WIDTH);
|
||||
// Only render if setting
|
||||
if !self.is_me || (self.is_me && self.settings.speech_bubble_self) {
|
||||
if let Some(bubble) = self.bubble {
|
||||
let dark_mode = self.settings.speech_bubble_dark_mode;
|
||||
let localizer = |s: &str, i| -> String { self.i18n.get_variation(s, i).to_string() };
|
||||
let bubble_contents: String = bubble.message(localizer);
|
||||
let (text_color, shadow_color) = bubble_color(bubble, dark_mode);
|
||||
let mut text = Text::new(&bubble_contents)
|
||||
.color(text_color)
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.font_size(18)
|
||||
.up_from(state.ids.name, 26.0)
|
||||
.x_align_to(state.ids.name, Align::Middle)
|
||||
.parent(id);
|
||||
|
||||
if let Some(w) = text.get_w(ui) {
|
||||
if w > MAX_BUBBLE_WIDTH {
|
||||
text = text.w(MAX_BUBBLE_WIDTH);
|
||||
}
|
||||
}
|
||||
}
|
||||
Image::new(if dark_mode {
|
||||
self.imgs.dark_bubble_top_left
|
||||
} else {
|
||||
self.imgs.speech_bubble_top_left
|
||||
})
|
||||
.w_h(16.0, 16.0)
|
||||
.top_left_with_margin_on(state.ids.speech_bubble_text, -20.0)
|
||||
.parent(id)
|
||||
.set(state.ids.speech_bubble_top_left, ui);
|
||||
Image::new(if dark_mode {
|
||||
self.imgs.dark_bubble_top
|
||||
} else {
|
||||
self.imgs.speech_bubble_top
|
||||
})
|
||||
.h(16.0)
|
||||
.padded_w_of(state.ids.speech_bubble_text, -4.0)
|
||||
.mid_top_with_margin_on(state.ids.speech_bubble_text, -20.0)
|
||||
.parent(id)
|
||||
.set(state.ids.speech_bubble_top, ui);
|
||||
Image::new(if dark_mode {
|
||||
self.imgs.dark_bubble_top_right
|
||||
} else {
|
||||
self.imgs.speech_bubble_top_right
|
||||
})
|
||||
.w_h(16.0, 16.0)
|
||||
.top_right_with_margin_on(state.ids.speech_bubble_text, -20.0)
|
||||
.parent(id)
|
||||
.set(state.ids.speech_bubble_top_right, ui);
|
||||
Image::new(if dark_mode {
|
||||
self.imgs.dark_bubble_left
|
||||
} else {
|
||||
self.imgs.speech_bubble_left
|
||||
})
|
||||
.w(16.0)
|
||||
.padded_h_of(state.ids.speech_bubble_text, -4.0)
|
||||
.mid_left_with_margin_on(state.ids.speech_bubble_text, -20.0)
|
||||
.parent(id)
|
||||
.set(state.ids.speech_bubble_left, ui);
|
||||
Image::new(if dark_mode {
|
||||
self.imgs.dark_bubble_mid
|
||||
} else {
|
||||
self.imgs.speech_bubble_mid
|
||||
})
|
||||
.padded_wh_of(state.ids.speech_bubble_text, -4.0)
|
||||
.top_left_with_margin_on(state.ids.speech_bubble_text, -4.0)
|
||||
.parent(id)
|
||||
.set(state.ids.speech_bubble_mid, ui);
|
||||
Image::new(if dark_mode {
|
||||
self.imgs.dark_bubble_right
|
||||
} else {
|
||||
self.imgs.speech_bubble_right
|
||||
})
|
||||
.w(16.0)
|
||||
.padded_h_of(state.ids.speech_bubble_text, -4.0)
|
||||
.mid_right_with_margin_on(state.ids.speech_bubble_text, -20.0)
|
||||
.parent(id)
|
||||
.set(state.ids.speech_bubble_right, ui);
|
||||
Image::new(if dark_mode {
|
||||
self.imgs.dark_bubble_bottom_left
|
||||
} else {
|
||||
self.imgs.speech_bubble_bottom_left
|
||||
})
|
||||
.w_h(16.0, 16.0)
|
||||
.bottom_left_with_margin_on(state.ids.speech_bubble_text, -20.0)
|
||||
.parent(id)
|
||||
.set(state.ids.speech_bubble_bottom_left, ui);
|
||||
Image::new(if dark_mode {
|
||||
self.imgs.dark_bubble_bottom
|
||||
} else {
|
||||
self.imgs.speech_bubble_bottom
|
||||
})
|
||||
.h(16.0)
|
||||
.padded_w_of(state.ids.speech_bubble_text, -4.0)
|
||||
.mid_bottom_with_margin_on(state.ids.speech_bubble_text, -20.0)
|
||||
.parent(id)
|
||||
.set(state.ids.speech_bubble_bottom, ui);
|
||||
Image::new(if dark_mode {
|
||||
self.imgs.dark_bubble_bottom_right
|
||||
} else {
|
||||
self.imgs.speech_bubble_bottom_right
|
||||
})
|
||||
.w_h(16.0, 16.0)
|
||||
.bottom_right_with_margin_on(state.ids.speech_bubble_text, -20.0)
|
||||
.parent(id)
|
||||
.set(state.ids.speech_bubble_bottom_right, ui);
|
||||
let tail = Image::new(if dark_mode {
|
||||
self.imgs.dark_bubble_tail
|
||||
} else {
|
||||
self.imgs.speech_bubble_tail
|
||||
})
|
||||
.parent(id)
|
||||
.mid_bottom_with_margin_on(state.ids.speech_bubble_text, -32.0);
|
||||
|
||||
if dark_mode {
|
||||
tail.w_h(22.0, 13.0)
|
||||
} else {
|
||||
tail.w_h(22.0, 28.0)
|
||||
}
|
||||
.set(state.ids.speech_bubble_tail, ui);
|
||||
|
||||
let mut text_shadow = Text::new(&bubble_contents)
|
||||
.color(shadow_color)
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.font_size(18)
|
||||
.x_relative_to(state.ids.speech_bubble_text, 1.0)
|
||||
.y_relative_to(state.ids.speech_bubble_text, -1.0)
|
||||
.parent(id);
|
||||
// Move text to front (conrod depth is lowest first; not a z-index)
|
||||
text.depth(text_shadow.get_depth() - 1.0)
|
||||
.set(state.ids.speech_bubble_text, ui);
|
||||
if let Some(w) = text_shadow.get_w(ui) {
|
||||
if w > MAX_BUBBLE_WIDTH {
|
||||
text_shadow = text_shadow.w(MAX_BUBBLE_WIDTH);
|
||||
}
|
||||
}
|
||||
text_shadow.set(state.ids.speech_bubble_shadow, ui);
|
||||
let icon = if self.settings.speech_bubble_icon {
|
||||
bubble_icon(bubble, self.imgs)
|
||||
} else {
|
||||
self.imgs.nothing
|
||||
};
|
||||
Image::new(icon)
|
||||
Image::new(if dark_mode {
|
||||
self.imgs.dark_bubble_top_left
|
||||
} else {
|
||||
self.imgs.speech_bubble_top_left
|
||||
})
|
||||
.w_h(16.0, 16.0)
|
||||
.top_left_with_margin_on(state.ids.speech_bubble_text, -16.0)
|
||||
// TODO: Figure out whether this should be parented.
|
||||
// .parent(id)
|
||||
.set(state.ids.speech_bubble_icon, ui);
|
||||
.top_left_with_margin_on(state.ids.speech_bubble_text, -20.0)
|
||||
.parent(id)
|
||||
.set(state.ids.speech_bubble_top_left, ui);
|
||||
Image::new(if dark_mode {
|
||||
self.imgs.dark_bubble_top
|
||||
} else {
|
||||
self.imgs.speech_bubble_top
|
||||
})
|
||||
.h(16.0)
|
||||
.padded_w_of(state.ids.speech_bubble_text, -4.0)
|
||||
.mid_top_with_margin_on(state.ids.speech_bubble_text, -20.0)
|
||||
.parent(id)
|
||||
.set(state.ids.speech_bubble_top, ui);
|
||||
Image::new(if dark_mode {
|
||||
self.imgs.dark_bubble_top_right
|
||||
} else {
|
||||
self.imgs.speech_bubble_top_right
|
||||
})
|
||||
.w_h(16.0, 16.0)
|
||||
.top_right_with_margin_on(state.ids.speech_bubble_text, -20.0)
|
||||
.parent(id)
|
||||
.set(state.ids.speech_bubble_top_right, ui);
|
||||
Image::new(if dark_mode {
|
||||
self.imgs.dark_bubble_left
|
||||
} else {
|
||||
self.imgs.speech_bubble_left
|
||||
})
|
||||
.w(16.0)
|
||||
.padded_h_of(state.ids.speech_bubble_text, -4.0)
|
||||
.mid_left_with_margin_on(state.ids.speech_bubble_text, -20.0)
|
||||
.parent(id)
|
||||
.set(state.ids.speech_bubble_left, ui);
|
||||
Image::new(if dark_mode {
|
||||
self.imgs.dark_bubble_mid
|
||||
} else {
|
||||
self.imgs.speech_bubble_mid
|
||||
})
|
||||
.padded_wh_of(state.ids.speech_bubble_text, -4.0)
|
||||
.top_left_with_margin_on(state.ids.speech_bubble_text, -4.0)
|
||||
.parent(id)
|
||||
.set(state.ids.speech_bubble_mid, ui);
|
||||
Image::new(if dark_mode {
|
||||
self.imgs.dark_bubble_right
|
||||
} else {
|
||||
self.imgs.speech_bubble_right
|
||||
})
|
||||
.w(16.0)
|
||||
.padded_h_of(state.ids.speech_bubble_text, -4.0)
|
||||
.mid_right_with_margin_on(state.ids.speech_bubble_text, -20.0)
|
||||
.parent(id)
|
||||
.set(state.ids.speech_bubble_right, ui);
|
||||
Image::new(if dark_mode {
|
||||
self.imgs.dark_bubble_bottom_left
|
||||
} else {
|
||||
self.imgs.speech_bubble_bottom_left
|
||||
})
|
||||
.w_h(16.0, 16.0)
|
||||
.bottom_left_with_margin_on(state.ids.speech_bubble_text, -20.0)
|
||||
.parent(id)
|
||||
.set(state.ids.speech_bubble_bottom_left, ui);
|
||||
Image::new(if dark_mode {
|
||||
self.imgs.dark_bubble_bottom
|
||||
} else {
|
||||
self.imgs.speech_bubble_bottom
|
||||
})
|
||||
.h(16.0)
|
||||
.padded_w_of(state.ids.speech_bubble_text, -4.0)
|
||||
.mid_bottom_with_margin_on(state.ids.speech_bubble_text, -20.0)
|
||||
.parent(id)
|
||||
.set(state.ids.speech_bubble_bottom, ui);
|
||||
Image::new(if dark_mode {
|
||||
self.imgs.dark_bubble_bottom_right
|
||||
} else {
|
||||
self.imgs.speech_bubble_bottom_right
|
||||
})
|
||||
.w_h(16.0, 16.0)
|
||||
.bottom_right_with_margin_on(state.ids.speech_bubble_text, -20.0)
|
||||
.parent(id)
|
||||
.set(state.ids.speech_bubble_bottom_right, ui);
|
||||
let tail = Image::new(if dark_mode {
|
||||
self.imgs.dark_bubble_tail
|
||||
} else {
|
||||
self.imgs.speech_bubble_tail
|
||||
})
|
||||
.parent(id)
|
||||
.mid_bottom_with_margin_on(state.ids.speech_bubble_text, -32.0);
|
||||
|
||||
if dark_mode {
|
||||
tail.w_h(22.0, 13.0)
|
||||
} else {
|
||||
tail.w_h(22.0, 28.0)
|
||||
}
|
||||
.set(state.ids.speech_bubble_tail, ui);
|
||||
|
||||
let mut text_shadow = Text::new(&bubble_contents)
|
||||
.color(shadow_color)
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.font_size(18)
|
||||
.x_relative_to(state.ids.speech_bubble_text, 1.0)
|
||||
.y_relative_to(state.ids.speech_bubble_text, -1.0)
|
||||
.parent(id);
|
||||
// Move text to front (conrod depth is lowest first; not a z-index)
|
||||
text.depth(text_shadow.get_depth() - 1.0)
|
||||
.set(state.ids.speech_bubble_text, ui);
|
||||
if let Some(w) = text_shadow.get_w(ui) {
|
||||
if w > MAX_BUBBLE_WIDTH {
|
||||
text_shadow = text_shadow.w(MAX_BUBBLE_WIDTH);
|
||||
}
|
||||
}
|
||||
text_shadow.set(state.ids.speech_bubble_shadow, ui);
|
||||
let icon = if self.settings.speech_bubble_icon {
|
||||
bubble_icon(bubble, self.imgs)
|
||||
} else {
|
||||
self.imgs.nothing
|
||||
};
|
||||
Image::new(icon)
|
||||
.w_h(16.0, 16.0)
|
||||
.top_left_with_margin_on(state.ids.speech_bubble_text, -16.0)
|
||||
// TODO: Figure out whether this should be parented.
|
||||
// .parent(id)
|
||||
.set(state.ids.speech_bubble_icon, ui);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,6 +88,8 @@ widget_ids! {
|
||||
sct_batch_inc_radio,
|
||||
//
|
||||
speech_bubble_text,
|
||||
speech_bubble_self_text,
|
||||
speech_bubble_self_button,
|
||||
speech_bubble_dark_mode_text,
|
||||
speech_bubble_dark_mode_button,
|
||||
speech_bubble_icon_text,
|
||||
@ -846,7 +848,7 @@ impl<'a> Widget for Interface<'a> {
|
||||
.set(state.ids.sct_batch_inc_text, ui);
|
||||
}
|
||||
|
||||
// Speech bubble dark mode
|
||||
// Speech bubbles
|
||||
Text::new(self.localized_strings.get("hud.settings.speech_bubble"))
|
||||
.down_from(
|
||||
if self.global_state.settings.interface.sct {
|
||||
@ -862,12 +864,38 @@ impl<'a> Widget for Interface<'a> {
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.color(TEXT_COLOR)
|
||||
.set(state.ids.speech_bubble_text, ui);
|
||||
|
||||
// Show own speech bubbles
|
||||
let speech_bubble_self = ToggleButton::new(
|
||||
self.global_state.settings.interface.speech_bubble_self,
|
||||
self.imgs.checkbox,
|
||||
self.imgs.checkbox_checked,
|
||||
)
|
||||
.down_from(state.ids.speech_bubble_text, 10.0)
|
||||
.w_h(18.0, 18.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.speech_bubble_self_button, ui);
|
||||
if self.global_state.settings.interface.speech_bubble_self != speech_bubble_self {
|
||||
events.push(SpeechBubbleSelf(speech_bubble_self));
|
||||
}
|
||||
Text::new(
|
||||
self.localized_strings
|
||||
.get("hud.settings.speech_bubble_self"),
|
||||
)
|
||||
.right_from(state.ids.speech_bubble_self_button, 10.0)
|
||||
.font_size(self.fonts.cyri.scale(15))
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.color(TEXT_COLOR)
|
||||
.set(state.ids.speech_bubble_self_text, ui);
|
||||
|
||||
// Speech bubble dark mode
|
||||
let speech_bubble_dark_mode = ToggleButton::new(
|
||||
self.global_state.settings.interface.speech_bubble_dark_mode,
|
||||
self.imgs.checkbox,
|
||||
self.imgs.checkbox_checked,
|
||||
)
|
||||
.down_from(state.ids.speech_bubble_text, 10.0)
|
||||
.down_from(state.ids.speech_bubble_self_button, 10.0)
|
||||
.w_h(18.0, 18.0)
|
||||
.hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
|
||||
.press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
|
||||
|
@ -93,6 +93,7 @@ pub enum Interface {
|
||||
Sct(bool),
|
||||
SctPlayerBatch(bool),
|
||||
SctDamageBatch(bool),
|
||||
SpeechBubbleSelf(bool),
|
||||
SpeechBubbleDarkMode(bool),
|
||||
SpeechBubbleIcon(bool),
|
||||
ToggleHelp(bool),
|
||||
@ -436,6 +437,9 @@ impl SettingsChange {
|
||||
Interface::SctDamageBatch(sct_damage_batch) => {
|
||||
settings.interface.sct_damage_batch = sct_damage_batch;
|
||||
},
|
||||
Interface::SpeechBubbleSelf(sbdm) => {
|
||||
settings.interface.speech_bubble_self = sbdm;
|
||||
},
|
||||
Interface::SpeechBubbleDarkMode(sbdm) => {
|
||||
settings.interface.speech_bubble_dark_mode = sbdm;
|
||||
},
|
||||
|
@ -16,6 +16,7 @@ pub struct InterfaceSettings {
|
||||
pub sct: bool,
|
||||
pub sct_player_batch: bool,
|
||||
pub sct_damage_batch: bool,
|
||||
pub speech_bubble_self: bool,
|
||||
pub speech_bubble_dark_mode: bool,
|
||||
pub speech_bubble_icon: bool,
|
||||
pub crosshair_opacity: f32,
|
||||
@ -54,6 +55,7 @@ impl Default for InterfaceSettings {
|
||||
sct: true,
|
||||
sct_player_batch: false,
|
||||
sct_damage_batch: false,
|
||||
speech_bubble_self: false,
|
||||
speech_bubble_dark_mode: false,
|
||||
speech_bubble_icon: true,
|
||||
crosshair_opacity: 0.6,
|
||||
|
Loading…
Reference in New Issue
Block a user