mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
The currently active stance shows as a buff
This commit is contained in:
parent
d3a52bd63b
commit
191174aa30
@ -3,13 +3,13 @@ use super::{
|
||||
BUFF_COLOR, DEBUFF_COLOR, TEXT_COLOR,
|
||||
};
|
||||
use crate::{
|
||||
hud::{self, animation::animation_timer, BuffPosition},
|
||||
hud::{animation::animation_timer, BuffIcon, BuffIconKind, BuffPosition},
|
||||
ui::{fonts::Fonts, ImageFrame, Tooltip, TooltipManager, Tooltipable},
|
||||
GlobalState,
|
||||
};
|
||||
use i18n::Localization;
|
||||
|
||||
use common::comp::{BuffKind, Buffs, Energy, Health};
|
||||
use common::comp::{BuffKind, Buffs, CharacterState, Energy, Health, Inventory};
|
||||
use conrod_core::{
|
||||
color,
|
||||
image::Id,
|
||||
@ -41,10 +41,12 @@ pub struct BuffsBar<'a> {
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
localized_strings: &'a Localization,
|
||||
buffs: &'a Buffs,
|
||||
char_state: &'a CharacterState,
|
||||
pulse: f32,
|
||||
global_state: &'a GlobalState,
|
||||
health: &'a Health,
|
||||
energy: &'a Energy,
|
||||
inventory: &'a Inventory,
|
||||
}
|
||||
|
||||
impl<'a> BuffsBar<'a> {
|
||||
@ -55,10 +57,12 @@ impl<'a> BuffsBar<'a> {
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
localized_strings: &'a Localization,
|
||||
buffs: &'a Buffs,
|
||||
char_state: &'a CharacterState,
|
||||
pulse: f32,
|
||||
global_state: &'a GlobalState,
|
||||
health: &'a Health,
|
||||
energy: &'a Energy,
|
||||
inventory: &'a Inventory,
|
||||
) -> Self {
|
||||
Self {
|
||||
imgs,
|
||||
@ -68,10 +72,12 @@ impl<'a> BuffsBar<'a> {
|
||||
tooltip_manager,
|
||||
localized_strings,
|
||||
buffs,
|
||||
char_state,
|
||||
pulse,
|
||||
global_state,
|
||||
health,
|
||||
energy,
|
||||
inventory,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -102,7 +108,6 @@ impl<'a> Widget for BuffsBar<'a> {
|
||||
let widget::UpdateArgs { state, ui, .. } = args;
|
||||
let mut event = Vec::new();
|
||||
let localized_strings = self.localized_strings;
|
||||
let buffs = self.buffs;
|
||||
let buff_ani = animation_timer(self.pulse) + 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);
|
||||
@ -124,6 +129,7 @@ impl<'a> Widget for BuffsBar<'a> {
|
||||
.desc_font_size(self.fonts.cyri.scale(12))
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.desc_text_color(TEXT_COLOR);
|
||||
let buff_icons = BuffIcon::icons_vec(self.buffs, self.char_state, Some(self.inventory));
|
||||
if let BuffPosition::Bar = buff_position {
|
||||
let decayed_health = 1.0 - self.health.maximum() / self.health.base_max();
|
||||
let show_health = self.global_state.settings.interface.always_show_bars
|
||||
@ -150,16 +156,17 @@ impl<'a> Widget for BuffsBar<'a> {
|
||||
.set(state.ids.buffs_align, ui);
|
||||
|
||||
// Buffs and Debuffs
|
||||
let (buff_count, debuff_count) = buffs.iter_active().map(hud::get_buff_info).fold(
|
||||
(0, 0),
|
||||
|(buff_count, debuff_count), info| {
|
||||
if info.is_buff {
|
||||
(buff_count + 1, debuff_count)
|
||||
} else {
|
||||
(buff_count, debuff_count + 1)
|
||||
}
|
||||
},
|
||||
);
|
||||
let (buff_count, debuff_count) =
|
||||
buff_icons
|
||||
.iter()
|
||||
.fold((0, 0), |(buff_count, debuff_count), info| {
|
||||
if info.is_buff {
|
||||
(buff_count + 1, debuff_count)
|
||||
} else {
|
||||
(buff_count, debuff_count + 1)
|
||||
}
|
||||
});
|
||||
|
||||
// Limit displayed buffs
|
||||
let buff_count = buff_count.min(12);
|
||||
let debuff_count = debuff_count.min(12);
|
||||
@ -185,12 +192,7 @@ impl<'a> Widget for BuffsBar<'a> {
|
||||
.iter()
|
||||
.copied()
|
||||
.zip(state.ids.buff_timers.iter().copied())
|
||||
.zip(
|
||||
buffs
|
||||
.iter_active()
|
||||
.map(hud::get_buff_info)
|
||||
.filter(|info| info.is_buff),
|
||||
)
|
||||
.zip(buff_icons.iter().filter(|info| info.is_buff))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Sort the buffs by kind
|
||||
@ -200,13 +202,13 @@ impl<'a> Widget for BuffsBar<'a> {
|
||||
.iter()
|
||||
.enumerate()
|
||||
.for_each(|(i, ((id, timer_id), buff))| {
|
||||
let max_duration = buff.data.duration;
|
||||
let max_duration = buff.kind.max_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 = hud::get_buff_image(buff.kind, self.imgs);
|
||||
let buff_img = buff.kind.image(self.imgs);
|
||||
let buff_widget = Image::new(buff_img).w_h(40.0, 40.0);
|
||||
// Sort buffs into rows of 11 slots
|
||||
let x = i % 6;
|
||||
@ -227,9 +229,8 @@ impl<'a> Widget for BuffsBar<'a> {
|
||||
)
|
||||
.set(*id, ui);
|
||||
// Create Buff tooltip
|
||||
let title = hud::get_buff_title(buff.kind, localized_strings);
|
||||
let desc_txt = hud::get_buff_desc(buff.kind, buff.data, localized_strings);
|
||||
let remaining_time = hud::get_buff_time(*buff);
|
||||
let (title, desc_txt) = buff.kind.title_description(localized_strings);
|
||||
let remaining_time = buff.get_buff_time();
|
||||
let click_to_remove =
|
||||
format!("<{}>", &localized_strings.get_msg("buff-remove"));
|
||||
let desc = format!("{}\n\n{}\n\n{}", desc_txt, remaining_time, click_to_remove);
|
||||
@ -247,7 +248,10 @@ impl<'a> Widget for BuffsBar<'a> {
|
||||
.set(*timer_id, ui)
|
||||
.was_clicked()
|
||||
{
|
||||
event.push(Event::RemoveBuff(buff.kind));
|
||||
match buff.kind {
|
||||
BuffIconKind::Buff { kind, .. } => event.push(Event::RemoveBuff(kind)),
|
||||
BuffIconKind::Ability { .. } => todo!(),
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
@ -258,12 +262,7 @@ impl<'a> Widget for BuffsBar<'a> {
|
||||
.iter()
|
||||
.copied()
|
||||
.zip(state.ids.debuff_timers.iter().copied())
|
||||
.zip(
|
||||
buffs
|
||||
.iter_active()
|
||||
.map(hud::get_buff_info)
|
||||
.filter(|info| !info.is_buff),
|
||||
)
|
||||
.zip(buff_icons.iter().filter(|info| !info.is_buff))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Sort the debuffs by kind
|
||||
@ -273,13 +272,13 @@ impl<'a> Widget for BuffsBar<'a> {
|
||||
.iter()
|
||||
.enumerate()
|
||||
.for_each(|(i, ((id, timer_id), debuff))| {
|
||||
let max_duration = debuff.data.duration;
|
||||
let max_duration = debuff.kind.max_duration();
|
||||
let current_duration = debuff.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 debuff_img = hud::get_buff_image(debuff.kind, self.imgs);
|
||||
let debuff_img = debuff.kind.image(self.imgs);
|
||||
let debuff_widget = Image::new(debuff_img).w_h(40.0, 40.0);
|
||||
// Sort buffs into rows of 11 slots
|
||||
let x = i % 6;
|
||||
@ -300,9 +299,8 @@ impl<'a> Widget for BuffsBar<'a> {
|
||||
)
|
||||
.set(*id, ui);
|
||||
// Create Debuff tooltip
|
||||
let title = hud::get_buff_title(debuff.kind, localized_strings);
|
||||
let desc_txt = hud::get_buff_desc(debuff.kind, debuff.data, localized_strings);
|
||||
let remaining_time = hud::get_buff_time(*debuff);
|
||||
let (title, desc_txt) = debuff.kind.title_description(localized_strings);
|
||||
let remaining_time = debuff.get_buff_time();
|
||||
let desc = format!("{}\n\n{}", desc_txt, remaining_time);
|
||||
Image::new(self.get_duration_image(duration_percentage))
|
||||
.w_h(40.0, 40.0)
|
||||
@ -325,7 +323,7 @@ impl<'a> Widget for BuffsBar<'a> {
|
||||
.set(state.ids.align, ui);
|
||||
|
||||
// Buffs and Debuffs
|
||||
let buff_count = buffs.kinds.len().min(11);
|
||||
let buff_count = buff_icons.len().min(11);
|
||||
// Limit displayed buffs
|
||||
let buff_count = buff_count.min(20);
|
||||
|
||||
@ -349,7 +347,7 @@ impl<'a> Widget for BuffsBar<'a> {
|
||||
.copied()
|
||||
.zip(state.ids.buff_timers.iter().copied())
|
||||
.zip(state.ids.buff_txts.iter().copied())
|
||||
.zip(buffs.iter_active().map(hud::get_buff_info))
|
||||
.zip(buff_icons.iter())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Sort the buffs by kind
|
||||
@ -359,14 +357,14 @@ impl<'a> Widget for BuffsBar<'a> {
|
||||
.iter()
|
||||
.enumerate()
|
||||
.for_each(|(i, (((id, timer_id), txt_id), buff))| {
|
||||
let max_duration = buff.data.duration;
|
||||
let max_duration = buff.kind.max_duration();
|
||||
let current_duration = buff.dur;
|
||||
// Percentage to determine which frame of the timer overlay is displayed
|
||||
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;
|
||||
let buff_img = hud::get_buff_image(buff.kind, self.imgs);
|
||||
let buff_img = buff.kind.image(self.imgs);
|
||||
let buff_widget = Image::new(buff_img).w_h(40.0, 40.0);
|
||||
// Sort buffs into rows of 6 slots
|
||||
let x = i % 6;
|
||||
@ -386,9 +384,8 @@ impl<'a> Widget for BuffsBar<'a> {
|
||||
)
|
||||
.set(*id, ui);
|
||||
// Create Buff tooltip
|
||||
let title = hud::get_buff_title(buff.kind, localized_strings);
|
||||
let desc_txt = hud::get_buff_desc(buff.kind, buff.data, localized_strings);
|
||||
let remaining_time = hud::get_buff_time(*buff);
|
||||
let (title, desc_txt) = buff.kind.title_description(localized_strings);
|
||||
let remaining_time = buff.get_buff_time();
|
||||
let click_to_remove =
|
||||
format!("<{}>", &localized_strings.get_msg("buff-remove"));
|
||||
let desc = if buff.is_buff {
|
||||
@ -414,7 +411,10 @@ impl<'a> Widget for BuffsBar<'a> {
|
||||
.set(*timer_id, ui)
|
||||
.was_clicked()
|
||||
{
|
||||
event.push(Event::RemoveBuff(buff.kind));
|
||||
match buff.kind {
|
||||
BuffIconKind::Buff { kind, .. } => event.push(Event::RemoveBuff(kind)),
|
||||
BuffIconKind::Ability { .. } => todo!(),
|
||||
}
|
||||
}
|
||||
Text::new(&remaining_time)
|
||||
.down_from(*timer_id, 1.0)
|
||||
|
@ -8,7 +8,7 @@ use super::{
|
||||
|
||||
use crate::{
|
||||
game_input::GameInput,
|
||||
hud,
|
||||
hud::BuffIcon,
|
||||
settings::Settings,
|
||||
ui::{fonts::Fonts, ImageFrame, Tooltip, TooltipManager, Tooltipable},
|
||||
GlobalState,
|
||||
@ -355,6 +355,9 @@ impl<'a> Widget for Group<'a> {
|
||||
let uid_allocator = client_state.ecs().read_resource::<UidAllocator>();
|
||||
let bodies = client_state.ecs().read_storage::<common::comp::Body>();
|
||||
let poises = client_state.ecs().read_storage::<common::comp::Poise>();
|
||||
let char_states = client_state
|
||||
.ecs()
|
||||
.read_storage::<common::comp::CharacterState>();
|
||||
|
||||
// Keep track of the total number of widget ids we are using for buffs
|
||||
let mut total_buff_count = 0;
|
||||
@ -370,6 +373,7 @@ impl<'a> Widget for Group<'a> {
|
||||
let is_leader = uid == leader;
|
||||
let body = entity.and_then(|entity| bodies.get(entity));
|
||||
let poise = entity.and_then(|entity| poises.get(entity));
|
||||
let char_state = entity.and_then(|entity| char_states.get(entity));
|
||||
|
||||
if let (
|
||||
Some(stats),
|
||||
@ -379,8 +383,10 @@ impl<'a> Widget for Group<'a> {
|
||||
Some(energy),
|
||||
Some(body),
|
||||
Some(poise),
|
||||
) = (stats, skill_set, inventory, health, energy, body, poise)
|
||||
{
|
||||
Some(char_state),
|
||||
) = (
|
||||
stats, skill_set, inventory, health, energy, body, poise, char_state,
|
||||
) {
|
||||
let combat_rating = combat::combat_rating(
|
||||
inventory, health, energy, poise, skill_set, *body, self.msm,
|
||||
);
|
||||
@ -499,8 +505,9 @@ impl<'a> Widget for Group<'a> {
|
||||
.top_left_with_margins_on(state.ids.member_panels_bg[i], 26.0, 2.0)
|
||||
.set(state.ids.member_energy[i], ui);
|
||||
if let Some(buffs) = buffs {
|
||||
let buff_icons = BuffIcon::icons_vec(buffs, char_state, Some(inventory));
|
||||
// Limit displayed buffs to 11
|
||||
let buff_count = buffs.kinds.len().min(11);
|
||||
let buff_count = buff_icons.len().min(11);
|
||||
total_buff_count += buff_count;
|
||||
let gen = &mut ui.widget_id_generator();
|
||||
if state.ids.buffs.len() < total_buff_count {
|
||||
@ -520,9 +527,9 @@ impl<'a> Widget for Group<'a> {
|
||||
.copied()
|
||||
.zip(state.ids.buff_timers.iter().copied())
|
||||
.skip(total_buff_count - buff_count)
|
||||
.zip(buffs.iter_active().map(hud::get_buff_info))
|
||||
.zip(buff_icons.iter())
|
||||
.for_each(|((id, timer_id), buff)| {
|
||||
let max_duration = buff.data.duration;
|
||||
let max_duration = buff.kind.max_duration();
|
||||
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);
|
||||
let current_duration = buff.dur;
|
||||
@ -531,7 +538,7 @@ impl<'a> Widget for Group<'a> {
|
||||
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 = hud::get_buff_image(buff.kind, self.imgs);
|
||||
let buff_img = buff.kind.image(self.imgs);
|
||||
let buff_widget = Image::new(buff_img).w_h(15.0, 15.0);
|
||||
let buff_widget = if let Some(id) = prev_id {
|
||||
buff_widget.right_from(id, 1.0)
|
||||
@ -555,10 +562,9 @@ impl<'a> Widget for Group<'a> {
|
||||
)
|
||||
.set(id, ui);
|
||||
// Create Buff tooltip
|
||||
let title = hud::get_buff_title(buff.kind, localized_strings);
|
||||
let desc_txt =
|
||||
hud::get_buff_desc(buff.kind, buff.data, localized_strings);
|
||||
let remaining_time = hud::get_buff_time(buff);
|
||||
let (title, desc_txt) =
|
||||
buff.kind.title_description(localized_strings);
|
||||
let remaining_time = buff.get_buff_time();
|
||||
let desc = format!("{}\n\n{}", desc_txt, remaining_time);
|
||||
Image::new(match duration_percentage as u64 {
|
||||
875..=1000 => self.imgs.nothing, // 8/8
|
||||
|
@ -120,6 +120,7 @@ use rand::Rng;
|
||||
use specs::{Entity as EcsEntity, Join, WorldExt};
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
cmp::Ordering,
|
||||
collections::VecDeque,
|
||||
sync::Arc,
|
||||
time::{Duration, Instant},
|
||||
@ -449,13 +450,154 @@ impl<W: Positionable> Position for W {
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct BuffInfo {
|
||||
kind: BuffKind,
|
||||
data: BuffData,
|
||||
pub enum BuffIconKind<'a> {
|
||||
Buff { kind: BuffKind, data: BuffData },
|
||||
Ability { ability_id: &'a str },
|
||||
}
|
||||
|
||||
impl<'a> BuffIconKind<'a> {
|
||||
pub fn image(&self, imgs: &Imgs) -> conrod_core::image::Id {
|
||||
match self {
|
||||
Self::Buff { kind, .. } => get_buff_image(*kind, imgs),
|
||||
Self::Ability { ability_id, .. } => util::ability_image(imgs, ability_id),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn max_duration(&self) -> Option<Duration> {
|
||||
match self {
|
||||
Self::Buff { data, .. } => data.duration,
|
||||
Self::Ability { .. } => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn title_description<'b>(
|
||||
&self,
|
||||
localized_strings: &'b Localization,
|
||||
) -> (Cow<'b, str>, Cow<'b, str>) {
|
||||
match self {
|
||||
Self::Buff { kind, data } => (
|
||||
get_buff_title(*kind, localized_strings),
|
||||
get_buff_desc(*kind, *data, localized_strings),
|
||||
),
|
||||
Self::Ability { ability_id } => {
|
||||
util::ability_description(ability_id, localized_strings)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PartialOrd for BuffIconKind<'a> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
match (self, other) {
|
||||
(
|
||||
BuffIconKind::Buff { kind, .. },
|
||||
BuffIconKind::Buff {
|
||||
kind: other_kind, ..
|
||||
},
|
||||
) => Some(kind.cmp(other_kind)),
|
||||
(BuffIconKind::Buff { .. }, BuffIconKind::Ability { .. }) => Some(Ordering::Greater),
|
||||
(BuffIconKind::Ability { .. }, BuffIconKind::Buff { .. }) => Some(Ordering::Less),
|
||||
(
|
||||
BuffIconKind::Ability { ability_id },
|
||||
BuffIconKind::Ability {
|
||||
ability_id: other_id,
|
||||
},
|
||||
) => Some(ability_id.cmp(other_id)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Ord for BuffIconKind<'a> {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
// We know this is safe since we can look at the partialord implementation and
|
||||
// see that every variant is wrapped in Some
|
||||
self.partial_cmp(other).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PartialEq for BuffIconKind<'a> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(
|
||||
BuffIconKind::Buff { kind, .. },
|
||||
BuffIconKind::Buff {
|
||||
kind: other_kind, ..
|
||||
},
|
||||
) => kind == other_kind,
|
||||
(
|
||||
BuffIconKind::Ability { ability_id },
|
||||
BuffIconKind::Ability {
|
||||
ability_id: other_id,
|
||||
},
|
||||
) => ability_id == other_id,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Eq for BuffIconKind<'a> {}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct BuffIcon<'a> {
|
||||
kind: BuffIconKind<'a>,
|
||||
is_buff: bool,
|
||||
dur: Option<Duration>,
|
||||
}
|
||||
|
||||
impl<'a> BuffIcon<'a> {
|
||||
pub fn get_buff_time(&self) -> String {
|
||||
if let Some(dur) = self.dur {
|
||||
format!("{:.0}s", dur.as_secs_f32())
|
||||
} else {
|
||||
"".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn icons_vec(
|
||||
buffs: &comp::Buffs,
|
||||
char_state: &comp::CharacterState,
|
||||
inv: Option<&'a comp::Inventory>,
|
||||
) -> Vec<Self> {
|
||||
buffs
|
||||
.iter_active()
|
||||
.map(BuffIcon::from_buff)
|
||||
.chain(BuffIcon::from_char_state(char_state, inv).into_iter())
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn from_char_state(
|
||||
char_state: &comp::CharacterState,
|
||||
inv: Option<&'a comp::Inventory>,
|
||||
) -> Option<Self> {
|
||||
let ability_id = || {
|
||||
char_state
|
||||
.ability_info()
|
||||
.and_then(|info| info.ability)
|
||||
.and_then(|ability| ability.ability_id(inv))
|
||||
};
|
||||
use comp::CharacterState::*;
|
||||
match char_state {
|
||||
ComboMelee2(data) if data.static_data.is_stance => ability_id().map(|id| BuffIcon {
|
||||
kind: BuffIconKind::Ability { ability_id: id },
|
||||
is_buff: true,
|
||||
dur: None,
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn from_buff(buff: &comp::Buff) -> Self {
|
||||
Self {
|
||||
kind: BuffIconKind::Buff {
|
||||
kind: buff.kind,
|
||||
data: buff.data,
|
||||
},
|
||||
is_buff: buff.kind.is_buff(),
|
||||
dur: buff.time,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ExpFloater {
|
||||
pub owner: Uid,
|
||||
pub exp_change: u32,
|
||||
@ -1290,6 +1432,7 @@ impl Hud {
|
||||
let poises = ecs.read_storage::<comp::Poise>();
|
||||
let alignments = ecs.read_storage::<comp::Alignment>();
|
||||
let is_mount = ecs.read_storage::<Is<Mount>>();
|
||||
let char_states = ecs.read_storage::<comp::CharacterState>();
|
||||
|
||||
// Check if there was a persistence load error of the skillset, and if so
|
||||
// display a dialog prompt
|
||||
@ -1980,7 +2123,7 @@ impl Hud {
|
||||
&uids,
|
||||
&inventories,
|
||||
poises.maybe(),
|
||||
(alignments.maybe(), is_mount.maybe()),
|
||||
(alignments.maybe(), is_mount.maybe(), &char_states),
|
||||
)
|
||||
.join()
|
||||
.filter(|t| {
|
||||
@ -2003,7 +2146,7 @@ impl Hud {
|
||||
uid,
|
||||
inventory,
|
||||
poise,
|
||||
(alignment, is_mount),
|
||||
(alignment, is_mount, char_state),
|
||||
)| {
|
||||
// Use interpolated position if available
|
||||
let pos = interpolated.map_or(pos.0, |i| i.pos);
|
||||
@ -2054,6 +2197,8 @@ impl Hud {
|
||||
} else {
|
||||
0.0
|
||||
},
|
||||
inventory,
|
||||
char_state,
|
||||
});
|
||||
// Only render bubble if nearby or if its me and setting is on
|
||||
let bubble = if (dist_sqr < SPEECH_BUBBLE_RANGE.powi(2) && !is_me)
|
||||
@ -2598,6 +2743,7 @@ impl Hud {
|
||||
let stats = ecs.read_storage::<comp::Stats>();
|
||||
let skill_sets = ecs.read_storage::<comp::SkillSet>();
|
||||
let buffs = ecs.read_storage::<comp::Buffs>();
|
||||
let char_states = ecs.read_storage::<comp::CharacterState>();
|
||||
let msm = ecs.read_resource::<MaterialStatManifest>();
|
||||
if let (Some(player_stats), Some(skill_set)) = (stats.get(entity), skill_sets.get(entity)) {
|
||||
match Buttons::new(
|
||||
@ -2881,10 +3027,12 @@ impl Hud {
|
||||
}
|
||||
|
||||
// Buffs
|
||||
if let (Some(player_buffs), Some(health), Some(energy)) = (
|
||||
if let (Some(player_buffs), Some(health), Some(energy), Some(char_state), Some(inventory)) = (
|
||||
buffs.get(info.viewpoint_entity),
|
||||
healths.get(entity),
|
||||
energies.get(entity),
|
||||
char_states.get(entity),
|
||||
inventories.get(entity),
|
||||
) {
|
||||
for event in BuffsBar::new(
|
||||
&self.imgs,
|
||||
@ -2893,10 +3041,12 @@ impl Hud {
|
||||
tooltip_manager,
|
||||
i18n,
|
||||
player_buffs,
|
||||
char_state,
|
||||
self.pulse,
|
||||
global_state,
|
||||
health,
|
||||
energy,
|
||||
inventory,
|
||||
)
|
||||
.set(self.ids.buffs, ui_widgets)
|
||||
{
|
||||
@ -4548,15 +4698,6 @@ pub fn get_quality_col<I: ItemDesc + ?Sized>(item: &I) -> Color {
|
||||
Quality::Debug => QUALITY_DEBUG,
|
||||
}
|
||||
}
|
||||
// Get info about applied buffs
|
||||
fn get_buff_info(buff: &comp::Buff) -> BuffInfo {
|
||||
BuffInfo {
|
||||
kind: buff.kind,
|
||||
data: buff.data,
|
||||
is_buff: buff.kind.is_buff(),
|
||||
dur: buff.time,
|
||||
}
|
||||
}
|
||||
|
||||
fn try_hotbar_slot_from_input(input: GameInput) -> Option<hotbar::Slot> {
|
||||
Some(match input {
|
||||
@ -4721,14 +4862,6 @@ pub fn get_sprite_desc(sprite: SpriteKind, localized_strings: &Localization) ->
|
||||
Some(localized_strings.get_msg(i18n_key))
|
||||
}
|
||||
|
||||
pub fn get_buff_time(buff: BuffInfo) -> String {
|
||||
if let Some(dur) = buff.dur {
|
||||
format!("{:.0}s", dur.as_secs_f32())
|
||||
} else {
|
||||
"".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn angle_of_attack_text(
|
||||
fluid: Option<comp::Fluid>,
|
||||
velocity: Option<comp::Vel>,
|
||||
|
@ -5,11 +5,13 @@ use super::{
|
||||
};
|
||||
use crate::{
|
||||
game_input::GameInput,
|
||||
hud::{get_buff_image, get_buff_info},
|
||||
hud::BuffIcon,
|
||||
settings::{ControlSettings, InterfaceSettings},
|
||||
ui::{fonts::Fonts, Ingameable},
|
||||
};
|
||||
use common::comp::{Buffs, Energy, Health, SpeechBubble, SpeechBubbleType};
|
||||
use common::comp::{
|
||||
Buffs, CharacterState, Energy, Health, Inventory, SpeechBubble, SpeechBubbleType,
|
||||
};
|
||||
use conrod_core::{
|
||||
color,
|
||||
position::Align,
|
||||
@ -69,6 +71,8 @@ pub struct Info<'a> {
|
||||
pub buffs: &'a Buffs,
|
||||
pub energy: Option<&'a Energy>,
|
||||
pub combat_rating: f32,
|
||||
pub inventory: &'a Inventory,
|
||||
pub char_state: &'a CharacterState,
|
||||
}
|
||||
|
||||
/// Determines whether to show the healthbar
|
||||
@ -198,6 +202,8 @@ impl<'a> Widget for Overhead<'a> {
|
||||
buffs,
|
||||
energy,
|
||||
combat_rating,
|
||||
inventory,
|
||||
char_state,
|
||||
}) = self.info
|
||||
{
|
||||
// Used to set healthbar colours based on hp_percentage
|
||||
@ -227,7 +233,8 @@ impl<'a> Widget for Overhead<'a> {
|
||||
};
|
||||
// Buffs
|
||||
// Alignment
|
||||
let buff_count = buffs.kinds.len().min(11);
|
||||
let buff_icons = BuffIcon::icons_vec(buffs, char_state, Some(inventory));
|
||||
let buff_count = buff_icons.len().min(11);
|
||||
Rectangle::fill_with([168.0, 100.0], color::TRANSPARENT)
|
||||
.x_y(-1.0, name_y + 60.0)
|
||||
.parent(id)
|
||||
@ -252,18 +259,18 @@ impl<'a> Widget for Overhead<'a> {
|
||||
.iter()
|
||||
.copied()
|
||||
.zip(state.ids.buff_timers.iter().copied())
|
||||
.zip(buffs.iter_active().map(get_buff_info))
|
||||
.zip(buff_icons.iter())
|
||||
.enumerate()
|
||||
.for_each(|(i, ((id, timer_id), buff))| {
|
||||
// Limit displayed buffs
|
||||
let max_duration = buff.data.duration;
|
||||
let max_duration = buff.kind.max_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_img = buff.kind.image(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;
|
||||
|
Loading…
Reference in New Issue
Block a user