mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Initial implementation of buffs UI
player buffs animation more testing debuffs sorting and display limit fix overhead buffs fix WIP buff removal function fmt Update buffs.rs Now with compiling: WIP group UI buffs positioning Update group.rs Update group.rs Small optimizations. Fixed positioning of buffs in group panel. Broke buff tooltips in group panel. buff frame visuals added setting for displaying buffs at minimap
This commit is contained in:
parent
007d3c09ac
commit
8fa398954d
@ -1,6 +1,6 @@
|
||||
ItemDef(
|
||||
name: "Apple Stick",
|
||||
description: "Restores 20 Health",
|
||||
description: "Restores 25 Health",
|
||||
kind: Consumable(
|
||||
kind: "AppleStick",
|
||||
effect: Health((
|
||||
|
BIN
assets/voxygen/element/animation/buff_frame/1.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/animation/buff_frame/1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/animation/buff_frame/2.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/animation/buff_frame/2.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/animation/buff_frame/3.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/animation/buff_frame/3.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/animation/buff_frame/4.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/animation/buff_frame/4.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/animation/buff_frame/5.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/animation/buff_frame/5.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/animation/buff_frame/6.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/animation/buff_frame/6.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/animation/buff_frame/7.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/animation/buff_frame/7.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/animation/buff_frame/8.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/animation/buff_frame/8.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/icons/de_buffs/debuff_bleed_0.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/icons/de_buffs/debuff_bleed_0.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -291,6 +291,8 @@ magically infused items?"#,
|
||||
"hud.settings.transparency": "Transparency",
|
||||
"hud.settings.hotbar": "Hotbar",
|
||||
"hud.settings.toggle_shortcuts": "Toggle Shortcuts",
|
||||
"hud.settings.buffs_skillbar": "Buffs at Skillbar",
|
||||
"hud.settings.buffs_mmap": "Buffs at Minimap",
|
||||
"hud.settings.toggle_bar_experience": "Toggle Experience Bar",
|
||||
"hud.settings.scrolling_combat_text": "Scrolling Combat Text",
|
||||
"hud.settings.single_damage_number": "Single Damage Numbers",
|
||||
@ -343,9 +345,9 @@ magically infused items?"#,
|
||||
"hud.settings.refresh_rate": "Refresh Rate",
|
||||
"hud.settings.save_window_size": "Save window size",
|
||||
"hud.settings.lighting_rendering_mode": "Lighting Rendering Mode",
|
||||
"hud.settings.lighting_rendering_mode.ashikhmin": "Type A",
|
||||
"hud.settings.lighting_rendering_mode.blinnphong": "Type B",
|
||||
"hud.settings.lighting_rendering_mode.lambertian": "Type L",
|
||||
"hud.settings.lighting_rendering_mode.ashikhmin": "Type A - High ",
|
||||
"hud.settings.lighting_rendering_mode.blinnphong": "Type B - Medium",
|
||||
"hud.settings.lighting_rendering_mode.lambertian": "Type L - Cheap",
|
||||
"hud.settings.shadow_rendering_mode": "Shadow Rendering Mode",
|
||||
"hud.settings.shadow_rendering_mode.none": "None",
|
||||
"hud.settings.shadow_rendering_mode.cheap": "Cheap",
|
||||
@ -509,6 +511,16 @@ Protection
|
||||
"esc_menu.quit_game": "Quit Game",
|
||||
/// End Escape Menu Section
|
||||
|
||||
/// Buffs and Debuffs
|
||||
"buff.remove": "Click to remove",
|
||||
"buff.title.missing": "Missing Title",
|
||||
"buff.desc.missing": "Missing Description",
|
||||
// Buffs
|
||||
"buff.title.heal_test": "Heal Test",
|
||||
"buff.desc.heal_test": "This is a test buff to test healing.",
|
||||
// Debuffs
|
||||
"debuff.title.bleed_test": "Bleed Test",
|
||||
"debuff.desc.bleed_test": "This is a test debuff to test bleeding.",
|
||||
},
|
||||
|
||||
|
||||
|
@ -37,6 +37,7 @@ use common::{
|
||||
terrain::{block::Block, neighbors, TerrainChunk, TerrainChunkSize},
|
||||
vol::RectVolSize,
|
||||
};
|
||||
use comp::BuffId;
|
||||
use futures_executor::block_on;
|
||||
use futures_timer::Delay;
|
||||
use futures_util::{select, FutureExt};
|
||||
@ -631,6 +632,12 @@ impl Client {
|
||||
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::DisableLantern));
|
||||
}
|
||||
|
||||
pub fn remove_buff(&mut self, buff_id: BuffId) {
|
||||
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::RemoveBuff(
|
||||
buff_id,
|
||||
)));
|
||||
}
|
||||
|
||||
pub fn max_group_size(&self) -> u32 { self.max_group_size }
|
||||
|
||||
pub fn group_invite(&self) -> Option<(Uid, std::time::Instant, std::time::Duration)> {
|
||||
|
@ -151,16 +151,10 @@ impl Buff {
|
||||
pub fn new(id: BuffId, cat_ids: Vec<BuffCategoryId>, source: BuffSource) -> Self {
|
||||
let (effects, time) = match id {
|
||||
BuffId::Bleeding { strength, duration } => (
|
||||
vec![
|
||||
BuffEffect::HealthChangeOverTime {
|
||||
rate: -strength,
|
||||
accumulated: 0.0,
|
||||
},
|
||||
// This effect is for testing purposes
|
||||
BuffEffect::NameChange {
|
||||
prefix: String::from("Injured "),
|
||||
},
|
||||
],
|
||||
vec![BuffEffect::HealthChangeOverTime {
|
||||
rate: -strength,
|
||||
accumulated: 0.0,
|
||||
}],
|
||||
duration,
|
||||
),
|
||||
BuffId::Regeneration { strength, duration } => (
|
||||
|
@ -1,4 +1,8 @@
|
||||
use crate::{comp::inventory::slot::Slot, sync::Uid, util::Dir};
|
||||
use crate::{
|
||||
comp::{inventory::slot::Slot, BuffId},
|
||||
sync::Uid,
|
||||
util::Dir,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specs::{Component, FlaggedStorage};
|
||||
use specs_idvs::IdvStorage;
|
||||
@ -37,6 +41,7 @@ pub enum ControlEvent {
|
||||
Unmount,
|
||||
InventoryManip(InventoryManip),
|
||||
GroupManip(GroupManip),
|
||||
RemoveBuff(BuffId),
|
||||
Respawn,
|
||||
}
|
||||
|
||||
|
@ -684,7 +684,7 @@ impl<'a> System<'a> for Sys {
|
||||
for (_invite, /*alignment,*/ agent, controller) in
|
||||
(&invites, /*&alignments,*/ &mut agents, &mut controllers).join()
|
||||
{
|
||||
let accept = false; // set back to "matches!(alignment, Alignment::Npc)" when we got better NPC recruitment mechanics
|
||||
let accept = true; // set back to "matches!(alignment, Alignment::Npc)" when we got better NPC recruitment mechanics
|
||||
if accept {
|
||||
// Clear agent comp
|
||||
*agent = Agent::default();
|
||||
|
@ -62,7 +62,7 @@ impl<'a> System<'a> for Sys {
|
||||
BuffEffect::HealthChangeOverTime { rate, accumulated } => {
|
||||
*accumulated += *rate * buff_delta;
|
||||
// Apply only 0.5 or higher damage
|
||||
if accumulated.abs() > 5.0 {
|
||||
if accumulated.abs() > 50.0 {
|
||||
let cause = if *accumulated > 0.0 {
|
||||
HealthSource::Healing { by: buff_owner }
|
||||
} else {
|
||||
|
@ -157,12 +157,31 @@ impl<'a> System<'a> for Sys {
|
||||
buff_change: buff::BuffChange::Add(buff::Buff::new(
|
||||
buff::BuffId::Bleeding {
|
||||
strength: attack.base_damage as f32,
|
||||
duration: Some(Duration::from_secs(10)),
|
||||
duration: Some(Duration::from_secs(30)),
|
||||
},
|
||||
vec![buff::BuffCategoryId::Physical, buff::BuffCategoryId::Debuff],
|
||||
buff::BuffSource::Character { by: *uid },
|
||||
)),
|
||||
});
|
||||
server_emitter.emit(ServerEvent::Buff {
|
||||
uid: *uid_b,
|
||||
buff_change: buff::BuffChange::Add(buff::Buff::new(
|
||||
buff::BuffId::Regeneration {
|
||||
strength: 100.0,
|
||||
duration: Some(Duration::from_secs(60)),
|
||||
},
|
||||
vec![buff::BuffCategoryId::Physical, buff::BuffCategoryId::Buff],
|
||||
buff::BuffSource::Character { by: *uid },
|
||||
)),
|
||||
});
|
||||
server_emitter.emit(ServerEvent::Buff {
|
||||
uid: *uid_b,
|
||||
buff_change: buff::BuffChange::Add(buff::Buff::new(
|
||||
buff::BuffId::Cursed { duration: None },
|
||||
vec![buff::BuffCategoryId::Physical, buff::BuffCategoryId::Debuff],
|
||||
buff::BuffSource::Character { by: *uid },
|
||||
)),
|
||||
});
|
||||
attack.hit_count += 1;
|
||||
}
|
||||
if attack.knockback != 0.0 && damage.healthchange != 0.0 {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
comp::{
|
||||
slot::{EquipSlot, Slot},
|
||||
CharacterState, ControlEvent, Controller, InventoryManip,
|
||||
BuffChange, CharacterState, ControlEvent, Controller, InventoryManip,
|
||||
},
|
||||
event::{EventBus, LocalEvent, ServerEvent},
|
||||
metrics::SysMetrics,
|
||||
@ -51,7 +51,7 @@ impl<'a> System<'a> for Sys {
|
||||
span!(_guard, "run", "controller::Sys::run");
|
||||
let mut server_emitter = server_bus.emitter();
|
||||
|
||||
for (entity, _uid, controller, character_state) in
|
||||
for (entity, uid, controller, character_state) in
|
||||
(&entities, &uids, &mut controllers, &mut character_states).join()
|
||||
{
|
||||
let mut inputs = &mut controller.inputs;
|
||||
@ -83,6 +83,12 @@ impl<'a> System<'a> for Sys {
|
||||
server_emitter.emit(ServerEvent::Mount(entity, mountee_entity));
|
||||
}
|
||||
},
|
||||
ControlEvent::RemoveBuff(buff_id) => {
|
||||
server_emitter.emit(ServerEvent::Buff {
|
||||
uid: *uid,
|
||||
buff_change: BuffChange::RemoveById(buff_id),
|
||||
});
|
||||
},
|
||||
ControlEvent::Unmount => server_emitter.emit(ServerEvent::Unmount(entity)),
|
||||
ControlEvent::EnableLantern => {
|
||||
server_emitter.emit(ServerEvent::EnableLantern(entity))
|
||||
|
@ -715,6 +715,7 @@ pub fn handle_buff(server: &mut Server, uid: Uid, buff_change: buff::BuffChange)
|
||||
add_buff_effects(new_buff.clone(), stats.get_mut(entity));
|
||||
buffs.active_buffs.push(new_buff);
|
||||
} else {
|
||||
let mut duplicate_existed = false;
|
||||
for i in 0..buffs.active_buffs.len() {
|
||||
let active_buff = &buffs.active_buffs[i];
|
||||
// Checks if new buff has the same id as an already active buff. If it
|
||||
@ -724,6 +725,7 @@ pub fn handle_buff(server: &mut Server, uid: Uid, buff_change: buff::BuffChange)
|
||||
// inactive buffs and add new buff to active
|
||||
// buffs.
|
||||
if discriminant(&active_buff.id) == discriminant(&new_buff.id) {
|
||||
duplicate_existed = true;
|
||||
if determine_replace_active_buff(
|
||||
active_buff.clone(),
|
||||
new_buff.clone(),
|
||||
@ -731,14 +733,21 @@ pub fn handle_buff(server: &mut Server, uid: Uid, buff_change: buff::BuffChange)
|
||||
active_buff_indices_for_removal.push(i);
|
||||
add_buff_effects(new_buff.clone(), stats.get_mut(entity));
|
||||
buffs.active_buffs.push(new_buff.clone());
|
||||
} else {
|
||||
buffs.inactive_buffs.push(new_buff.clone());
|
||||
} else if let Some(active_dur) = active_buff.time {
|
||||
if let Some(new_dur) = new_buff.time {
|
||||
if new_dur > active_dur {
|
||||
buffs.inactive_buffs.push(new_buff.clone());
|
||||
}
|
||||
} else {
|
||||
buffs.inactive_buffs.push(new_buff.clone());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
add_buff_effects(new_buff.clone(), stats.get_mut(entity));
|
||||
buffs.active_buffs.push(new_buff.clone());
|
||||
}
|
||||
}
|
||||
if !duplicate_existed {
|
||||
add_buff_effects(new_buff.clone(), stats.get_mut(entity));
|
||||
buffs.active_buffs.push(new_buff.clone());
|
||||
}
|
||||
}
|
||||
},
|
||||
BuffChange::RemoveByIndex(active_indices, inactive_indices) => {
|
||||
@ -871,7 +880,7 @@ fn determine_replace_active_buff(active_buff: buff::Buff, new_buff: buff::Buff)
|
||||
duration: _,
|
||||
} = active_buff.id
|
||||
{
|
||||
new_strength > active_strength
|
||||
new_strength >= active_strength
|
||||
} else {
|
||||
false
|
||||
}
|
||||
@ -885,7 +894,7 @@ fn determine_replace_active_buff(active_buff: buff::Buff, new_buff: buff::Buff)
|
||||
duration: _,
|
||||
} = active_buff.id
|
||||
{
|
||||
new_strength > active_strength
|
||||
new_strength >= active_strength
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
@ -1,20 +1,23 @@
|
||||
use super::{
|
||||
img_ids::{Imgs, ImgsRot},
|
||||
TEXT_COLOR,
|
||||
BUFF_COLOR, DEBUFF_COLOR, TEXT_COLOR,
|
||||
};
|
||||
use crate::{
|
||||
hud::{get_buff_info, BuffPosition},
|
||||
i18n::VoxygenLocalization,
|
||||
ui::{fonts::ConrodVoxygenFonts, ImageFrame, Tooltip, TooltipManager, Tooltipable},
|
||||
GlobalState,
|
||||
};
|
||||
use client::Client;
|
||||
use common::comp::{self, Buffs};
|
||||
|
||||
use crate::hud::BuffInfo;
|
||||
use common::comp::{BuffId, Buffs};
|
||||
use conrod_core::{
|
||||
color,
|
||||
widget::{self, Button, Image, Rectangle, Text},
|
||||
widget_ids, Color, Colorable, Positionable, Sizeable, Widget, WidgetCommon,
|
||||
widget::{self, Button, Image, Rectangle},
|
||||
widget_ids, Color, Positionable, Sizeable, Widget, WidgetCommon,
|
||||
};
|
||||
use inline_tweak::*;
|
||||
use std::time::Duration;
|
||||
widget_ids! {
|
||||
struct Ids {
|
||||
align,
|
||||
@ -22,51 +25,49 @@ widget_ids! {
|
||||
debuffs_align,
|
||||
buff_test,
|
||||
debuff_test,
|
||||
buffs[],
|
||||
buff_timers[],
|
||||
debuffs[],
|
||||
debuff_timers[],
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BuffInfo {
|
||||
id: comp::BuffId,
|
||||
is_buff: bool,
|
||||
dur: f32,
|
||||
}
|
||||
|
||||
#[derive(WidgetCommon)]
|
||||
pub struct BuffsBar<'a> {
|
||||
client: &'a Client,
|
||||
imgs: &'a Imgs,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
#[conrod(common_builder)]
|
||||
common: widget::CommonBuilder,
|
||||
global_state: &'a GlobalState,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
localized_strings: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
buffs: &'a Buffs,
|
||||
pulse: f32,
|
||||
global_state: &'a GlobalState,
|
||||
}
|
||||
|
||||
impl<'a> BuffsBar<'a> {
|
||||
#[allow(clippy::too_many_arguments)] // TODO: Pending review in #587
|
||||
pub fn new(
|
||||
client: &'a Client,
|
||||
imgs: &'a Imgs,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
global_state: &'a GlobalState,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
localized_strings: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
buffs: &'a Buffs,
|
||||
pulse: f32,
|
||||
global_state: &'a GlobalState,
|
||||
) -> Self {
|
||||
Self {
|
||||
client,
|
||||
imgs,
|
||||
fonts,
|
||||
common: widget::CommonBuilder::default(),
|
||||
global_state,
|
||||
rot_imgs,
|
||||
tooltip_manager,
|
||||
localized_strings,
|
||||
buffs,
|
||||
pulse,
|
||||
global_state,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -75,8 +76,12 @@ pub struct State {
|
||||
ids: Ids,
|
||||
}
|
||||
|
||||
pub enum Event {
|
||||
RemoveBuff(BuffId),
|
||||
}
|
||||
|
||||
impl<'a> Widget for BuffsBar<'a> {
|
||||
type Event = ();
|
||||
type Event = Vec<Event>;
|
||||
type State = State;
|
||||
type Style = ();
|
||||
|
||||
@ -91,7 +96,11 @@ impl<'a> Widget for BuffsBar<'a> {
|
||||
|
||||
fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
|
||||
let widget::UpdateArgs { state, ui, .. } = args;
|
||||
let mut event = Vec::new();
|
||||
let localized_strings = self.localized_strings;
|
||||
let buffs = self.buffs;
|
||||
let buff_ani = ((self.pulse * 4.0/* speed factor */).cos() * 0.5 + 0.8) + 0.5; //Animation timer
|
||||
let buff_position = self.global_state.settings.gameplay.buff_position;
|
||||
let buffs_tooltip = Tooltip::new({
|
||||
// Edge images [t, b, r, l]
|
||||
// Corner images [tr, tl, br, bl]
|
||||
@ -109,35 +118,230 @@ 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);
|
||||
// Alignment
|
||||
Rectangle::fill_with([484.0, 100.0], color::TRANSPARENT)
|
||||
.mid_bottom_with_margin_on(ui.window, tweak!(92.0))
|
||||
.set(state.ids.align, ui);
|
||||
Rectangle::fill_with([484.0 / 2.0, 90.0], color::TRANSPARENT)
|
||||
.bottom_left_with_margins_on(state.ids.align, 0.0, 0.0)
|
||||
.set(state.ids.debuffs_align, ui);
|
||||
Rectangle::fill_with([484.0 / 2.0, 90.0], color::TRANSPARENT)
|
||||
.bottom_right_with_margins_on(state.ids.align, 0.0, 0.0)
|
||||
.set(state.ids.buffs_align, ui);
|
||||
// Test Widgets
|
||||
Image::new(self.imgs.debuff_skull_0)
|
||||
.w_h(20.0, 20.0)
|
||||
.bottom_right_with_margins_on(state.ids.debuffs_align, 0.0, 1.0)
|
||||
.set(state.ids.debuff_test, ui);
|
||||
Image::new(self.imgs.buff_plus_0)
|
||||
.w_h(20.0, 20.0)
|
||||
.bottom_left_with_margins_on(state.ids.buffs_align, 0.0, 1.0)
|
||||
.set(state.ids.buff_test, ui);
|
||||
}
|
||||
}
|
||||
if let BuffPosition::Bar = buff_position {
|
||||
// Alignment
|
||||
Rectangle::fill_with([484.0, 100.0], color::TRANSPARENT)
|
||||
.mid_bottom_with_margin_on(ui.window, tweak!(92.0))
|
||||
.set(state.ids.align, ui);
|
||||
Rectangle::fill_with([484.0 / 2.0, 90.0], color::TRANSPARENT)
|
||||
.bottom_left_with_margins_on(state.ids.align, 0.0, 0.0)
|
||||
.set(state.ids.debuffs_align, ui);
|
||||
Rectangle::fill_with([484.0 / 2.0, 90.0], color::TRANSPARENT)
|
||||
.bottom_right_with_margins_on(state.ids.align, 0.0, 0.0)
|
||||
.set(state.ids.buffs_align, ui);
|
||||
|
||||
fn get_buff_info(buff: comp::Buff) -> BuffInfo {
|
||||
BuffInfo {
|
||||
id: buff.id,
|
||||
is_buff: buff
|
||||
.cat_ids
|
||||
.iter()
|
||||
.any(|cat| *cat == comp::BuffCategoryId::Buff),
|
||||
dur: buff.time.map(|dur| dur.as_secs_f32()).unwrap_or(100.0),
|
||||
// Buffs and Debuffs
|
||||
// Create two vecs to display buffs and debuffs separately
|
||||
let mut buffs_vec = Vec::<BuffInfo>::new();
|
||||
let mut debuffs_vec = Vec::<BuffInfo>::new();
|
||||
for buff in buffs.active_buffs.clone() {
|
||||
let info = get_buff_info(buff);
|
||||
if info.is_buff {
|
||||
buffs_vec.push(info);
|
||||
} else {
|
||||
debuffs_vec.push(info);
|
||||
}
|
||||
}
|
||||
if state.ids.buffs.len() < buffs_vec.len() {
|
||||
state.update(|state| {
|
||||
state
|
||||
.ids
|
||||
.buffs
|
||||
.resize(buffs_vec.len(), &mut ui.widget_id_generator())
|
||||
});
|
||||
};
|
||||
if state.ids.debuffs.len() < debuffs_vec.len() {
|
||||
state.update(|state| {
|
||||
state
|
||||
.ids
|
||||
.debuffs
|
||||
.resize(debuffs_vec.len(), &mut ui.widget_id_generator())
|
||||
});
|
||||
};
|
||||
if state.ids.buff_timers.len() < buffs_vec.len() {
|
||||
state.update(|state| {
|
||||
state
|
||||
.ids
|
||||
.buff_timers
|
||||
.resize(buffs_vec.len(), &mut ui.widget_id_generator())
|
||||
});
|
||||
};
|
||||
if state.ids.debuff_timers.len() < debuffs_vec.len() {
|
||||
state.update(|state| {
|
||||
state
|
||||
.ids
|
||||
.debuff_timers
|
||||
.resize(debuffs_vec.len(), &mut ui.widget_id_generator())
|
||||
});
|
||||
};
|
||||
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
|
||||
for (i, buff) in buffs_vec.iter().enumerate() {
|
||||
if i < 22 {
|
||||
// Limit displayed buffs
|
||||
let max_duration = match buff.id {
|
||||
BuffId::Regeneration { duration, .. } => duration.unwrap().as_secs_f32(),
|
||||
_ => 10.0,
|
||||
};
|
||||
let current_duration = buff.dur;
|
||||
let duration_percentage = (current_duration / max_duration * 1000.0) as u32; // Percentage to determine which frame of the timer overlay is displayed
|
||||
let buff_img = match buff.id {
|
||||
BuffId::Regeneration { .. } => self.imgs.buff_plus_0,
|
||||
_ => self.imgs.missing_icon,
|
||||
};
|
||||
let buff_widget = Image::new(buff_img).w_h(20.0, 20.0);
|
||||
// Sort buffs into rows of 11 slots
|
||||
let x = i % 11;
|
||||
let y = i / 11;
|
||||
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 < 10.0 {
|
||||
Some(pulsating_col)
|
||||
} else {
|
||||
Some(norm_col)
|
||||
})
|
||||
.set(state.ids.buffs[i], ui);
|
||||
// Create Buff tooltip
|
||||
let title = match buff.id {
|
||||
BuffId::Regeneration { .. } => {
|
||||
*&localized_strings.get("buff.title.heal_test")
|
||||
},
|
||||
_ => *&localized_strings.get("buff.title.missing"),
|
||||
};
|
||||
let remaining_time = if current_duration == 10e6 as f32 {
|
||||
"Permanent".to_string()
|
||||
} else {
|
||||
format!("Remaining: {:.0}s", current_duration)
|
||||
};
|
||||
let click_to_remove = format!("<{}>", &localized_strings.get("buff.remove"));
|
||||
let desc_txt = match buff.id {
|
||||
BuffId::Regeneration { .. } => {
|
||||
*&localized_strings.get("buff.desc.heal_test")
|
||||
},
|
||||
_ => *&localized_strings.get("buff.desc.missing"),
|
||||
};
|
||||
let desc = format!("{}\n\n{}\n\n{}", desc_txt, remaining_time, click_to_remove);
|
||||
// Timer overlay
|
||||
if Button::image(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(state.ids.buffs[i])
|
||||
.with_tooltip(
|
||||
self.tooltip_manager,
|
||||
title,
|
||||
&desc,
|
||||
&buffs_tooltip,
|
||||
BUFF_COLOR,
|
||||
)
|
||||
.set(state.ids.buff_timers[i], ui)
|
||||
.was_clicked()
|
||||
{
|
||||
event.push(Event::RemoveBuff(buff.id));
|
||||
};
|
||||
};
|
||||
}
|
||||
// Create Debuff Widgets
|
||||
for (i, debuff) in debuffs_vec.iter().enumerate() {
|
||||
if i < 22 {
|
||||
// Limit displayed buffs
|
||||
|
||||
let max_duration = match debuff.id {
|
||||
BuffId::Bleeding { duration, .. } => {
|
||||
duration.unwrap_or(Duration::from_secs(60)).as_secs_f32()
|
||||
},
|
||||
BuffId::Cursed { duration, .. } => {
|
||||
duration.unwrap_or(Duration::from_secs(60)).as_secs_f32()
|
||||
},
|
||||
|
||||
_ => 10.0,
|
||||
};
|
||||
let current_duration = debuff.dur;
|
||||
let duration_percentage = current_duration / max_duration * 1000.0; // Percentage to determine which frame of the timer overlay is displayed
|
||||
let debuff_img = match debuff.id {
|
||||
BuffId::Bleeding { .. } => self.imgs.debuff_bleed_0,
|
||||
BuffId::Cursed { .. } => self.imgs.debuff_skull_0,
|
||||
_ => self.imgs.missing_icon,
|
||||
};
|
||||
let debuff_widget = Image::new(debuff_img).w_h(20.0, 20.0);
|
||||
// Sort buffs into rows of 11 slots
|
||||
let x = i % 11;
|
||||
let y = i / 11;
|
||||
let debuff_widget = debuff_widget.bottom_right_with_margins_on(
|
||||
state.ids.debuffs_align,
|
||||
0.0 + y as f64 * (21.0),
|
||||
0.0 + x as f64 * (21.0),
|
||||
);
|
||||
|
||||
debuff_widget
|
||||
.color(if current_duration < 10.0 {
|
||||
Some(pulsating_col)
|
||||
} else {
|
||||
Some(norm_col)
|
||||
})
|
||||
.set(state.ids.debuffs[i], ui);
|
||||
// Create Debuff tooltip
|
||||
let title = match debuff.id {
|
||||
BuffId::Bleeding { .. } => {
|
||||
*&localized_strings.get("debuff.title.bleed_test")
|
||||
},
|
||||
_ => *&localized_strings.get("buff.title.missing"),
|
||||
};
|
||||
let remaining_time = if current_duration == 10e6 as f32 {
|
||||
"Permanent".to_string()
|
||||
} else {
|
||||
format!("Remaining: {:.0}s", current_duration)
|
||||
};
|
||||
let desc_txt = match debuff.id {
|
||||
BuffId::Bleeding { .. } => {
|
||||
*&localized_strings.get("debuff.desc.bleed_test")
|
||||
},
|
||||
_ => *&localized_strings.get("debuff.desc.missing"),
|
||||
};
|
||||
let desc = format!("{}\n\n{}", desc_txt, remaining_time);
|
||||
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(state.ids.debuffs[i])
|
||||
.with_tooltip(
|
||||
self.tooltip_manager,
|
||||
title,
|
||||
&desc,
|
||||
&buffs_tooltip,
|
||||
DEBUFF_COLOR,
|
||||
)
|
||||
.set(state.ids.debuff_timers[i], ui);
|
||||
};
|
||||
}
|
||||
}
|
||||
if let BuffPosition::Map = buff_position {
|
||||
// Alignment
|
||||
Rectangle::fill_with([tweak!(300.0), tweak!(280.0)], color::RED)
|
||||
.top_right_with_margins_on(ui.window, tweak!(5.0), tweak!(270.0))
|
||||
.set(state.ids.align, ui);
|
||||
}
|
||||
event
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,20 @@
|
||||
use super::{
|
||||
img_ids::Imgs, Show, BLACK, ERROR_COLOR, GROUP_COLOR, HP_COLOR, KILL_COLOR, LOW_HP_COLOR,
|
||||
STAMINA_COLOR, TEXT_COLOR, TEXT_COLOR_GREY, UI_HIGHLIGHT_0, UI_MAIN,
|
||||
img_ids::{Imgs, ImgsRot},
|
||||
Show, BLACK, BUFF_COLOR, DEBUFF_COLOR, ERROR_COLOR, GROUP_COLOR, HP_COLOR, KILL_COLOR,
|
||||
LOW_HP_COLOR, STAMINA_COLOR, TEXT_COLOR, TEXT_COLOR_GREY, UI_HIGHLIGHT_0, UI_MAIN,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
i18n::VoxygenLocalization, settings::Settings, ui::fonts::ConrodVoxygenFonts,
|
||||
window::GameInput, GlobalState,
|
||||
hud::{get_buff_info, BuffInfo},
|
||||
i18n::VoxygenLocalization,
|
||||
settings::Settings,
|
||||
ui::{fonts::ConrodVoxygenFonts, ImageFrame, Tooltip, TooltipManager, Tooltipable},
|
||||
window::GameInput,
|
||||
GlobalState,
|
||||
};
|
||||
use client::{self, Client};
|
||||
use common::{
|
||||
comp::{group::Role, Stats},
|
||||
comp::{group::Role, BuffId, Buffs, Stats},
|
||||
sync::{Uid, WorldSyncExt},
|
||||
};
|
||||
use conrod_core::{
|
||||
@ -18,8 +23,8 @@ use conrod_core::{
|
||||
widget::{self, Button, Image, Rectangle, Scrollbar, Text},
|
||||
widget_ids, Color, Colorable, Labelable, Positionable, Sizeable, Widget, WidgetCommon,
|
||||
};
|
||||
use inline_tweak::*;
|
||||
use specs::{saveload::MarkerAllocator, WorldExt};
|
||||
|
||||
widget_ids! {
|
||||
pub struct Ids {
|
||||
group_button,
|
||||
@ -44,6 +49,8 @@ widget_ids! {
|
||||
member_panels_txt[],
|
||||
member_health[],
|
||||
member_stam[],
|
||||
buffs[],
|
||||
buff_timers[],
|
||||
dead_txt[],
|
||||
health_txt[],
|
||||
timeout_bg,
|
||||
@ -63,10 +70,13 @@ pub struct Group<'a> {
|
||||
client: &'a Client,
|
||||
settings: &'a Settings,
|
||||
imgs: &'a Imgs,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
localized_strings: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
pulse: f32,
|
||||
global_state: &'a GlobalState,
|
||||
buffs: &'a Buffs,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
|
||||
#[conrod(common_builder)]
|
||||
common: widget::CommonBuilder,
|
||||
@ -79,20 +89,26 @@ impl<'a> Group<'a> {
|
||||
client: &'a Client,
|
||||
settings: &'a Settings,
|
||||
imgs: &'a Imgs,
|
||||
rot_imgs: &'a ImgsRot,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
localized_strings: &'a std::sync::Arc<VoxygenLocalization>,
|
||||
pulse: f32,
|
||||
global_state: &'a GlobalState,
|
||||
buffs: &'a Buffs,
|
||||
tooltip_manager: &'a mut TooltipManager,
|
||||
) -> Self {
|
||||
Self {
|
||||
show,
|
||||
client,
|
||||
settings,
|
||||
imgs,
|
||||
rot_imgs,
|
||||
fonts,
|
||||
localized_strings,
|
||||
pulse,
|
||||
global_state,
|
||||
buffs,
|
||||
tooltip_manager,
|
||||
common: widget::CommonBuilder::default(),
|
||||
}
|
||||
}
|
||||
@ -127,8 +143,27 @@ impl<'a> Widget for Group<'a> {
|
||||
#[allow(clippy::blocks_in_if_conditions)] // TODO: Pending review in #587
|
||||
fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
|
||||
let widget::UpdateArgs { state, ui, .. } = args;
|
||||
|
||||
let mut events = Vec::new();
|
||||
let localized_strings = self.localized_strings;
|
||||
//let buffs = self.buffs;
|
||||
let buff_ani = ((self.pulse * 4.0/* speed factor */).cos() * 0.5 + 0.8) + 0.5; //Animation timer
|
||||
let buffs_tooltip = Tooltip::new({
|
||||
// Edge images [t, b, r, l]
|
||||
// Corner images [tr, tl, br, bl]
|
||||
let edge = &self.rot_imgs.tt_side;
|
||||
let corner = &self.rot_imgs.tt_corner;
|
||||
ImageFrame::new(
|
||||
[edge.cw180, edge.none, edge.cw270, edge.cw90],
|
||||
[corner.none, corner.cw270, corner.cw90, corner.cw180],
|
||||
Color::Rgba(0.08, 0.07, 0.04, 1.0),
|
||||
5.0,
|
||||
)
|
||||
})
|
||||
.title_font_size(self.fonts.cyri.scale(15))
|
||||
.parent(ui.window)
|
||||
.desc_font_size(self.fonts.cyri.scale(12))
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.desc_text_color(TEXT_COLOR);
|
||||
|
||||
// Don't show pets
|
||||
let group_members = self
|
||||
@ -293,6 +328,7 @@ impl<'a> Widget for Group<'a> {
|
||||
let client_state = self.client.state();
|
||||
let stats = client_state.ecs().read_storage::<common::comp::Stats>();
|
||||
let energy = client_state.ecs().read_storage::<common::comp::Energy>();
|
||||
let buffs = client_state.ecs().read_storage::<common::comp::Buffs>();
|
||||
let uid_allocator = client_state
|
||||
.ecs()
|
||||
.read_resource::<common::sync::UidAllocator>();
|
||||
@ -302,6 +338,8 @@ impl<'a> Widget for Group<'a> {
|
||||
let entity = uid_allocator.retrieve_entity_internal(uid.into());
|
||||
let stats = entity.and_then(|entity| stats.get(entity));
|
||||
let energy = entity.and_then(|entity| energy.get(entity));
|
||||
let buffs = entity.and_then(|entity| buffs.get(entity));
|
||||
|
||||
if let Some(stats) = stats {
|
||||
let char_name = stats.name.to_string();
|
||||
let health_perc = stats.health.current() as f64 / stats.health.maximum() as f64;
|
||||
@ -317,7 +355,7 @@ impl<'a> Widget for Group<'a> {
|
||||
.top_left_with_margins_on(ui.window, offset, 20.0)
|
||||
} else {
|
||||
Image::new(self.imgs.member_bg)
|
||||
.down_from(state.ids.member_panels_bg[i - 1], 40.0)
|
||||
.down_from(state.ids.member_panels_bg[i - 1], 45.0)
|
||||
};
|
||||
let hp_ani = (self.pulse * 4.0/* speed factor */).cos() * 0.5 + 0.8; //Animation timer
|
||||
let crit_hp_color: Color = Color::Rgba(0.79, 0.19, 0.17, hp_ani);
|
||||
@ -386,19 +424,19 @@ impl<'a> Widget for Group<'a> {
|
||||
.set(state.ids.member_panels_frame[i], ui);
|
||||
// Panel Text
|
||||
Text::new(&char_name)
|
||||
.top_left_with_margins_on(state.ids.member_panels_frame[i], -22.0, 0.0)
|
||||
.font_size(20)
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.color(BLACK)
|
||||
.w(300.0) // limit name length display
|
||||
.set(state.ids.member_panels_txt_bg[i], ui);
|
||||
.top_left_with_margins_on(state.ids.member_panels_frame[i], -22.0, 0.0)
|
||||
.font_size(20)
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.color(BLACK)
|
||||
.w(300.0) // limit name length display
|
||||
.set(state.ids.member_panels_txt_bg[i], ui);
|
||||
Text::new(&char_name)
|
||||
.bottom_left_with_margins_on(state.ids.member_panels_txt_bg[i], 2.0, 2.0)
|
||||
.font_size(20)
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.color(if is_leader { ERROR_COLOR } else { GROUP_COLOR })
|
||||
.w(300.0) // limit name length display
|
||||
.set(state.ids.member_panels_txt[i], ui);
|
||||
.bottom_left_with_margins_on(state.ids.member_panels_txt_bg[i], 2.0, 2.0)
|
||||
.font_size(20)
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.color(if is_leader { ERROR_COLOR } else { GROUP_COLOR })
|
||||
.w(300.0) // limit name length display
|
||||
.set(state.ids.member_panels_txt[i], ui);
|
||||
if let Some(energy) = energy {
|
||||
let stam_perc = energy.current() as f64 / energy.maximum() as f64;
|
||||
// Stamina
|
||||
@ -408,44 +446,146 @@ 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_stam[i], ui);
|
||||
}
|
||||
} else {
|
||||
// Values N.A.
|
||||
if let Some(stats) = stats {
|
||||
if let Some(buffs) = buffs {
|
||||
let mut buffs_vec = Vec::<BuffInfo>::new();
|
||||
for buff in buffs.active_buffs.clone() {
|
||||
let info = get_buff_info(buff);
|
||||
buffs_vec.push(info);
|
||||
}
|
||||
state.update(|state| {
|
||||
state.ids.buffs.resize(
|
||||
state.ids.buffs.len() + buffs_vec.len(),
|
||||
&mut ui.widget_id_generator(),
|
||||
)
|
||||
});
|
||||
state.update(|state| {
|
||||
state.ids.buff_timers.resize(
|
||||
state.ids.buff_timers.len() + buffs_vec.len(),
|
||||
&mut ui.widget_id_generator(),
|
||||
)
|
||||
});
|
||||
// Create Buff Widgets
|
||||
for (x, buff) in buffs_vec.iter().enumerate() {
|
||||
if x < 11 {
|
||||
// Limit displayed buffs
|
||||
let max_duration = match buff.id {
|
||||
BuffId::Regeneration { duration, .. } => {
|
||||
duration.unwrap().as_secs_f32()
|
||||
},
|
||||
_ => 10.0,
|
||||
};
|
||||
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;
|
||||
let duration_percentage =
|
||||
(current_duration / max_duration * 1000.0) as u32; // Percentage to determine which frame of the timer overlay is displayed
|
||||
let buff_img = match buff.id {
|
||||
BuffId::Regeneration { .. } => self.imgs.buff_plus_0,
|
||||
BuffId::Bleeding { .. } => self.imgs.debuff_bleed_0,
|
||||
BuffId::Cursed { .. } => self.imgs.debuff_skull_0,
|
||||
};
|
||||
let buff_widget = Image::new(buff_img).w_h(20.0, 20.0);
|
||||
let buff_widget = if x == 0 {
|
||||
buff_widget.bottom_left_with_margins_on(
|
||||
state.ids.member_panels_frame[i],
|
||||
-21.0,
|
||||
1.0,
|
||||
)
|
||||
} else {
|
||||
buff_widget.right_from(state.ids.buffs[state.ids.buffs.len() - buffs_vec.len() + x - 1/*x - 1*/], 1.0)
|
||||
};
|
||||
buff_widget
|
||||
.color(if current_duration < 10.0 {
|
||||
Some(pulsating_col)
|
||||
} else {
|
||||
Some(norm_col)
|
||||
})
|
||||
.set(state.ids.buffs[state.ids.buffs.len() - buffs_vec.len() + x/*x*/], ui);
|
||||
// Create Buff tooltip
|
||||
let title = match buff.id {
|
||||
BuffId::Regeneration { .. } => {
|
||||
*&localized_strings.get("buff.title.heal_test")
|
||||
},
|
||||
BuffId::Bleeding { .. } => {
|
||||
*&localized_strings.get("debuff.title.bleed_test")
|
||||
},
|
||||
_ => *&localized_strings.get("buff.title.missing"),
|
||||
};
|
||||
let remaining_time = if current_duration == 10e6 as f32 {
|
||||
"Permanent".to_string()
|
||||
} else {
|
||||
format!("Remaining: {:.0}s", current_duration)
|
||||
};
|
||||
let desc_txt = match buff.id {
|
||||
BuffId::Regeneration { .. } => {
|
||||
*&localized_strings.get("buff.desc.heal_test")
|
||||
},
|
||||
BuffId::Bleeding { .. } => {
|
||||
*&localized_strings.get("debuff.desc.bleed_test")
|
||||
},
|
||||
_ => *&localized_strings.get("buff.desc.missing"),
|
||||
};
|
||||
let desc = format!("{}\n\n{}", desc_txt, remaining_time);
|
||||
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(state.ids.buffs[state.ids.buffs.len() - buffs_vec.len() + x/*x*/])
|
||||
.with_tooltip(
|
||||
self.tooltip_manager,
|
||||
title,
|
||||
&desc,
|
||||
&buffs_tooltip,
|
||||
if buff.is_buff {BUFF_COLOR} else {DEBUFF_COLOR},
|
||||
)
|
||||
.set(state.ids.buff_timers[state.ids.buffs.len() - buffs_vec.len() + x/*x*/], ui);
|
||||
};
|
||||
}
|
||||
} else {
|
||||
// Values N.A.
|
||||
Text::new(&stats.name.to_string())
|
||||
.top_left_with_margins_on(state.ids.member_panels_frame[i], -22.0, 0.0)
|
||||
.font_size(20)
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.color(GROUP_COLOR)
|
||||
.set(state.ids.member_panels_txt[i], ui);
|
||||
};
|
||||
let offset = if self.global_state.settings.gameplay.toggle_debug {
|
||||
210.0
|
||||
} else {
|
||||
110.0
|
||||
};
|
||||
let back = if i == 0 {
|
||||
Image::new(self.imgs.member_bg)
|
||||
.top_left_with_margins_on(ui.window, offset, 20.0)
|
||||
} else {
|
||||
Image::new(self.imgs.member_bg)
|
||||
.down_from(state.ids.member_panels_bg[i - 1], 40.0)
|
||||
};
|
||||
back.w_h(152.0, 36.0)
|
||||
.color(Some(TEXT_COLOR))
|
||||
.set(state.ids.member_panels_bg[i], ui);
|
||||
// Panel Frame
|
||||
Image::new(self.imgs.member_frame)
|
||||
.w_h(152.0, 36.0)
|
||||
.middle_of(state.ids.member_panels_bg[i])
|
||||
.color(Some(UI_HIGHLIGHT_0))
|
||||
.set(state.ids.member_panels_frame[i], ui);
|
||||
// Panel Text
|
||||
Text::new(&self.localized_strings.get("hud.group.out_of_range"))
|
||||
.mid_top_with_margin_on(state.ids.member_panels_bg[i], 3.0)
|
||||
.font_size(16)
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.color(TEXT_COLOR)
|
||||
.set(state.ids.dead_txt[i], ui);
|
||||
let offset = if self.global_state.settings.gameplay.toggle_debug {
|
||||
210.0
|
||||
} else {
|
||||
110.0
|
||||
};
|
||||
let back = if i == 0 {
|
||||
Image::new(self.imgs.member_bg)
|
||||
.top_left_with_margins_on(ui.window, offset, 20.0)
|
||||
} else {
|
||||
Image::new(self.imgs.member_bg)
|
||||
.down_from(state.ids.member_panels_bg[i - 1], 40.0)
|
||||
};
|
||||
back.w_h(152.0, 36.0)
|
||||
.color(Some(TEXT_COLOR))
|
||||
.set(state.ids.member_panels_bg[i], ui);
|
||||
// Panel Frame
|
||||
Image::new(self.imgs.member_frame)
|
||||
.w_h(152.0, 36.0)
|
||||
.middle_of(state.ids.member_panels_bg[i])
|
||||
.color(Some(UI_HIGHLIGHT_0))
|
||||
.set(state.ids.member_panels_frame[i], ui);
|
||||
// Panel Text
|
||||
Text::new(&self.localized_strings.get("hud.group.out_of_range"))
|
||||
.mid_top_with_margin_on(state.ids.member_panels_bg[i], 3.0)
|
||||
.font_size(16)
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.color(TEXT_COLOR)
|
||||
.set(state.ids.dead_txt[i], ui);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -272,6 +272,7 @@ image_ids! {
|
||||
hammerleap: "voxygen.element.icons.skill_hammerleap",
|
||||
skill_axe_leap_slash: "voxygen.element.icons.skill_axe_leap_slash",
|
||||
skill_bow_jump_burst: "voxygen.element.icons.skill_bow_jump_burst",
|
||||
missing_icon: "voxygen.element.icons.missing_icon_grey",
|
||||
|
||||
// Buttons
|
||||
button: "voxygen.element.buttons.button",
|
||||
@ -350,10 +351,22 @@ image_ids! {
|
||||
chat_world: "voxygen.element.icons.chat.world",
|
||||
|
||||
// Buffs
|
||||
buff_plus_0: "voxygen.element.de_buffs.buff_plus_0",
|
||||
buff_plus_0: "voxygen.element.icons.de_buffs.buff_plus_0",
|
||||
|
||||
// Debuffs
|
||||
debuff_skull_0: "voxygen.element.de_buffs.debuff_skull_0",
|
||||
debuff_skull_0: "voxygen.element.icons.de_buffs.debuff_skull_0",
|
||||
debuff_bleed_0: "voxygen.element.icons.de_buffs.debuff_bleed_0",
|
||||
|
||||
// Animation Frames
|
||||
// Buff Frame
|
||||
buff_0: "voxygen.element.animation.buff_frame.1",
|
||||
buff_1: "voxygen.element.animation.buff_frame.2",
|
||||
buff_2: "voxygen.element.animation.buff_frame.3",
|
||||
buff_3: "voxygen.element.animation.buff_frame.4",
|
||||
buff_4: "voxygen.element.animation.buff_frame.5",
|
||||
buff_5: "voxygen.element.animation.buff_frame.6",
|
||||
buff_6: "voxygen.element.animation.buff_frame.7",
|
||||
buff_7: "voxygen.element.animation.buff_frame.8",
|
||||
|
||||
<BlankGraphic>
|
||||
nothing: (),
|
||||
|
@ -105,7 +105,7 @@ impl<'a> Widget for MiniMap<'a> {
|
||||
fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
|
||||
let widget::UpdateArgs { state, ui, .. } = args;
|
||||
let zoom = state.zoom;
|
||||
const SCALE: f64 = 1.5;
|
||||
const SCALE: f64 = 1.5; // TODO Make this a setting
|
||||
if self.show.mini_map {
|
||||
Image::new(self.imgs.mmap_frame)
|
||||
.w_h(174.0 * SCALE, 190.0 * SCALE)
|
||||
|
@ -60,7 +60,10 @@ use client::Client;
|
||||
use common::{
|
||||
assets::Asset,
|
||||
comp,
|
||||
comp::item::{ItemDesc, Quality},
|
||||
comp::{
|
||||
item::{ItemDesc, Quality},
|
||||
BuffId,
|
||||
},
|
||||
span,
|
||||
sync::Uid,
|
||||
terrain::TerrainChunk,
|
||||
@ -97,6 +100,8 @@ const STAMINA_COLOR: Color = Color::Rgba(0.29, 0.62, 0.75, 0.9);
|
||||
//const TRANSPARENT: Color = Color::Rgba(0.0, 0.0, 0.0, 0.0);
|
||||
//const FOCUS_COLOR: Color = Color::Rgba(1.0, 0.56, 0.04, 1.0);
|
||||
//const RAGE_COLOR: Color = Color::Rgba(0.5, 0.04, 0.13, 1.0);
|
||||
const BUFF_COLOR: Color = Color::Rgba(0.06, 0.69, 0.12, 1.0);
|
||||
const DEBUFF_COLOR: Color = Color::Rgba(0.79, 0.19, 0.17, 1.0);
|
||||
|
||||
// Item Quality Colors
|
||||
const QUALITY_LOW: Color = Color::Rgba(0.41, 0.41, 0.41, 1.0); // Grey - Trash, can be sold to vendors
|
||||
@ -267,6 +272,13 @@ widget_ids! {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct BuffInfo {
|
||||
id: comp::BuffId,
|
||||
is_buff: bool,
|
||||
dur: f32,
|
||||
}
|
||||
|
||||
pub struct DebugInfo {
|
||||
pub tps: f64,
|
||||
pub frame_time: Duration,
|
||||
@ -318,6 +330,7 @@ pub enum Event {
|
||||
ChatTransp(f32),
|
||||
ChatCharName(bool),
|
||||
CrosshairType(CrosshairType),
|
||||
BuffPosition(BuffPosition),
|
||||
ToggleXpBar(XpBar),
|
||||
Intro(Intro),
|
||||
ToggleBarNumbers(BarNumbers),
|
||||
@ -351,6 +364,7 @@ pub enum Event {
|
||||
KickMember(common::sync::Uid),
|
||||
LeaveGroup,
|
||||
AssignLeader(common::sync::Uid),
|
||||
RemoveBuff(BuffId),
|
||||
}
|
||||
|
||||
// TODO: Are these the possible layouts we want?
|
||||
@ -391,6 +405,13 @@ pub enum ShortcutNumbers {
|
||||
On,
|
||||
Off,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
pub enum BuffPosition {
|
||||
Bar,
|
||||
Map,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
pub enum PressBehavior {
|
||||
Toggle = 0,
|
||||
@ -725,6 +746,7 @@ impl Hud {
|
||||
let ecs = client.state().ecs();
|
||||
let pos = ecs.read_storage::<comp::Pos>();
|
||||
let stats = ecs.read_storage::<comp::Stats>();
|
||||
let buffs = ecs.read_storage::<comp::Buffs>();
|
||||
let energy = ecs.read_storage::<comp::Energy>();
|
||||
let hp_floater_lists = ecs.read_storage::<vcomp::HpFloaterList>();
|
||||
let uids = ecs.read_storage::<common::sync::Uid>();
|
||||
@ -1123,11 +1145,12 @@ impl Hud {
|
||||
let speech_bubbles = &self.speech_bubbles;
|
||||
|
||||
// Render overhead name tags and health bars
|
||||
for (pos, info, bubble, stats, height_offset, hpfl, in_group) in (
|
||||
for (pos, info, bubble, stats, buffs, height_offset, hpfl, in_group) in (
|
||||
&entities,
|
||||
&pos,
|
||||
interpolated.maybe(),
|
||||
&stats,
|
||||
&buffs,
|
||||
energy.maybe(),
|
||||
scales.maybe(),
|
||||
&bodies,
|
||||
@ -1141,7 +1164,7 @@ impl Hud {
|
||||
entity != me && !stats.is_dead
|
||||
})
|
||||
.filter_map(
|
||||
|(entity, pos, interpolated, stats, energy, scale, body, hpfl, uid)| {
|
||||
|(entity, pos, interpolated, stats, buffs, energy, scale, body, hpfl, uid)| {
|
||||
// Use interpolated position if available
|
||||
let pos = interpolated.map_or(pos.0, |i| i.pos);
|
||||
let in_group = client.group_members().contains_key(uid);
|
||||
@ -1171,6 +1194,7 @@ impl Hud {
|
||||
let info = display_overhead_info.then(|| overhead::Info {
|
||||
name: &stats.name,
|
||||
stats,
|
||||
buffs,
|
||||
energy,
|
||||
});
|
||||
let bubble = if dist_sqr < SPEECH_BUBBLE_RANGE.powi(2) {
|
||||
@ -1185,6 +1209,7 @@ impl Hud {
|
||||
info,
|
||||
bubble,
|
||||
stats,
|
||||
buffs,
|
||||
body.height() * scale.map_or(1.0, |s| s.0) + 0.5,
|
||||
hpfl,
|
||||
in_group,
|
||||
@ -1760,22 +1785,48 @@ impl Hud {
|
||||
|
||||
// Buffs and Debuffs
|
||||
if let Some(player_buffs) = buffs.get(client.entity()) {
|
||||
match BuffsBar::new(
|
||||
client,
|
||||
for event in BuffsBar::new(
|
||||
&self.imgs,
|
||||
&self.fonts,
|
||||
global_state,
|
||||
&self.rot_imgs,
|
||||
tooltip_manager,
|
||||
&self.voxygen_i18n,
|
||||
&player_buffs,
|
||||
self.pulse,
|
||||
&global_state,
|
||||
)
|
||||
.set(self.ids.buffs, ui_widgets)
|
||||
{
|
||||
_ => {},
|
||||
match event {
|
||||
buffs::Event::RemoveBuff(buff_id) => events.push(Event::RemoveBuff(buff_id)),
|
||||
}
|
||||
}
|
||||
}
|
||||
// Group Window
|
||||
let buffs = buffs.get(client.entity()).unwrap();
|
||||
for event in Group::new(
|
||||
&mut self.show,
|
||||
client,
|
||||
&global_state.settings,
|
||||
&self.imgs,
|
||||
&self.rot_imgs,
|
||||
&self.fonts,
|
||||
&self.voxygen_i18n,
|
||||
self.pulse,
|
||||
&global_state,
|
||||
&buffs,
|
||||
tooltip_manager,
|
||||
)
|
||||
.set(self.ids.group_window, ui_widgets)
|
||||
{
|
||||
match event {
|
||||
group::Event::Accept => events.push(Event::AcceptInvite),
|
||||
group::Event::Decline => events.push(Event::DeclineInvite),
|
||||
group::Event::Kick(uid) => events.push(Event::KickMember(uid)),
|
||||
group::Event::LeaveGroup => events.push(Event::LeaveGroup),
|
||||
group::Event::AssignLeader(uid) => events.push(Event::AssignLeader(uid)),
|
||||
}
|
||||
}
|
||||
|
||||
// Popup (waypoint saved and similar notifications)
|
||||
Popup::new(
|
||||
&self.voxygen_i18n,
|
||||
@ -1850,8 +1901,8 @@ impl Hud {
|
||||
Some(stats),
|
||||
Some(loadout),
|
||||
Some(energy),
|
||||
Some(character_state),
|
||||
Some(controller),
|
||||
Some(_character_state),
|
||||
Some(_controller),
|
||||
Some(inventory),
|
||||
) = (
|
||||
stats.get(entity),
|
||||
@ -2018,6 +2069,9 @@ impl Hud {
|
||||
settings_window::Event::ToggleZoomInvert(zoom_inverted) => {
|
||||
events.push(Event::ToggleZoomInvert(zoom_inverted));
|
||||
},
|
||||
settings_window::Event::BuffPosition(buff_position) => {
|
||||
events.push(Event::BuffPosition(buff_position));
|
||||
},
|
||||
settings_window::Event::ToggleMouseYInvert(mouse_y_inverted) => {
|
||||
events.push(Event::ToggleMouseYInvert(mouse_y_inverted));
|
||||
},
|
||||
@ -2142,27 +2196,6 @@ impl Hud {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Group Window
|
||||
for event in Group::new(
|
||||
&mut self.show,
|
||||
client,
|
||||
&global_state.settings,
|
||||
&self.imgs,
|
||||
&self.fonts,
|
||||
&self.voxygen_i18n,
|
||||
self.pulse,
|
||||
&global_state,
|
||||
)
|
||||
.set(self.ids.group_window, ui_widgets)
|
||||
{
|
||||
match event {
|
||||
group::Event::Accept => events.push(Event::AcceptInvite),
|
||||
group::Event::Decline => events.push(Event::DeclineInvite),
|
||||
group::Event::Kick(uid) => events.push(Event::KickMember(uid)),
|
||||
group::Event::LeaveGroup => events.push(Event::LeaveGroup),
|
||||
group::Event::AssignLeader(uid) => events.push(Event::AssignLeader(uid)),
|
||||
}
|
||||
}
|
||||
|
||||
// Spellbook
|
||||
if self.show.spell {
|
||||
@ -2694,3 +2727,17 @@ pub fn get_quality_col<I: ItemDesc>(item: &I) -> Color {
|
||||
Quality::Debug => QUALITY_DEBUG,
|
||||
}
|
||||
}
|
||||
// Get info about applied buffs
|
||||
fn get_buff_info(buff: comp::Buff) -> BuffInfo {
|
||||
BuffInfo {
|
||||
id: buff.id,
|
||||
is_buff: buff
|
||||
.cat_ids
|
||||
.iter()
|
||||
.any(|cat| *cat == comp::BuffCategoryId::Buff),
|
||||
dur: buff
|
||||
.time
|
||||
.map(|dur| dur.as_secs_f32())
|
||||
.unwrap_or(10e6 as f32),
|
||||
}
|
||||
}
|
||||
|
@ -3,16 +3,19 @@ use super::{
|
||||
REGION_COLOR, SAY_COLOR, STAMINA_COLOR, TELL_COLOR, TEXT_BG, TEXT_COLOR,
|
||||
};
|
||||
use crate::{
|
||||
hud::{get_buff_info, BuffInfo},
|
||||
i18n::VoxygenLocalization,
|
||||
settings::GameplaySettings,
|
||||
ui::{fonts::ConrodVoxygenFonts, Ingameable},
|
||||
};
|
||||
use common::comp::{Energy, SpeechBubble, SpeechBubbleType, Stats};
|
||||
use common::comp::{BuffId, Buffs, Energy, SpeechBubble, SpeechBubbleType, Stats};
|
||||
use conrod_core::{
|
||||
color,
|
||||
position::Align,
|
||||
widget::{self, Image, Rectangle, Text},
|
||||
widget_ids, Color, Colorable, Positionable, Sizeable, Widget, WidgetCommon,
|
||||
};
|
||||
use inline_tweak::*;
|
||||
const MAX_BUBBLE_WIDTH: f64 = 250.0;
|
||||
|
||||
widget_ids! {
|
||||
@ -44,13 +47,24 @@ widget_ids! {
|
||||
health_txt,
|
||||
mana_bar,
|
||||
health_bar_fg,
|
||||
|
||||
// Buffs
|
||||
buffs_align,
|
||||
buffs[],
|
||||
buff_timers[],
|
||||
}
|
||||
}
|
||||
|
||||
/*pub struct BuffInfo {
|
||||
id: comp::BuffId,
|
||||
dur: f32,
|
||||
}*/
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Info<'a> {
|
||||
pub name: &'a str,
|
||||
pub stats: &'a Stats,
|
||||
pub buffs: &'a Buffs,
|
||||
pub energy: Option<&'a Energy>,
|
||||
}
|
||||
|
||||
@ -119,17 +133,21 @@ impl<'a> Ingameable for Overhead<'a> {
|
||||
// - 1 for HP text
|
||||
// - If there's mana
|
||||
// - 1 Rect::new for mana
|
||||
//
|
||||
// If there are Buffs
|
||||
// - 1 Alignment Rectangle
|
||||
// - 10 + 10 Buffs and Timer Overlays
|
||||
// If there's a speech bubble
|
||||
// - 2 Text::new for speech bubble
|
||||
// - 1 Image::new for icon
|
||||
// - 10 Image::new for speech bubble (9-slice + tail)
|
||||
self.info.map_or(0, |info| {
|
||||
2 + if show_healthbar(info.stats) {
|
||||
5 + if info.energy.is_some() { 1 } else { 0 }
|
||||
} else {
|
||||
0
|
||||
}
|
||||
2 + 1
|
||||
+ info.buffs.active_buffs.len().min(10) * 2
|
||||
+ if show_healthbar(info.stats) {
|
||||
5 + if info.energy.is_some() { 1 } else { 0 }
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}) + if self.bubble.is_some() { 13 } else { 0 }
|
||||
}
|
||||
}
|
||||
@ -155,6 +173,7 @@ impl<'a> Widget for Overhead<'a> {
|
||||
if let Some(Info {
|
||||
name,
|
||||
stats,
|
||||
buffs,
|
||||
energy,
|
||||
}) = self.info
|
||||
{
|
||||
@ -172,6 +191,11 @@ impl<'a> Widget for Overhead<'a> {
|
||||
} else {
|
||||
MANA_BAR_Y + 32.0
|
||||
};
|
||||
let mut buffs_vec = Vec::<BuffInfo>::new();
|
||||
for buff in buffs.active_buffs.clone() {
|
||||
let info = get_buff_info(buff);
|
||||
buffs_vec.push(info);
|
||||
}
|
||||
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
|
||||
@ -185,6 +209,79 @@ impl<'a> Widget for Overhead<'a> {
|
||||
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
|
||||
Rectangle::fill_with([tweak!(168.0), tweak!(100.0)], color::TRANSPARENT)
|
||||
.x_y(-1.0, name_y + tweak!(60.0))
|
||||
.parent(id)
|
||||
.set(state.ids.buffs_align, ui);
|
||||
if state.ids.buffs.len() < buffs_vec.len() {
|
||||
state.update(|state| {
|
||||
state
|
||||
.ids
|
||||
.buffs
|
||||
.resize(buffs_vec.len(), &mut ui.widget_id_generator())
|
||||
});
|
||||
};
|
||||
if state.ids.buff_timers.len() < buffs_vec.len() {
|
||||
state.update(|state| {
|
||||
state
|
||||
.ids
|
||||
.buff_timers
|
||||
.resize(buffs_vec.len(), &mut ui.widget_id_generator())
|
||||
});
|
||||
};
|
||||
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
|
||||
for (i, buff) in buffs_vec.iter().enumerate() {
|
||||
if i < 11 && self.bubble.is_none() {
|
||||
// Limit displayed buffs
|
||||
let max_duration = match buff.id {
|
||||
BuffId::Regeneration { duration, .. } => duration.unwrap().as_secs_f32(),
|
||||
_ => 10.0,
|
||||
};
|
||||
let current_duration = buff.dur;
|
||||
let duration_percentage = (current_duration / max_duration * 1000.0) as u32; // Percentage to determine which frame of the timer overlay is displayed
|
||||
let buff_img = match buff.id {
|
||||
BuffId::Regeneration { .. } => self.imgs.buff_plus_0,
|
||||
BuffId::Bleeding { .. } => self.imgs.debuff_bleed_0,
|
||||
BuffId::Cursed { .. } => self.imgs.debuff_skull_0,
|
||||
};
|
||||
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 < 10.0 {
|
||||
Some(pulsating_col)
|
||||
} else {
|
||||
Some(norm_col)
|
||||
})
|
||||
.set(state.ids.buffs[i], 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(state.ids.buffs[i])
|
||||
.set(state.ids.buff_timers[i], ui);
|
||||
};
|
||||
}
|
||||
// Name
|
||||
Text::new(name)
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
|
@ -4,6 +4,7 @@ use super::{
|
||||
TEXT_BIND_CONFLICT_COLOR, TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN,
|
||||
};
|
||||
use crate::{
|
||||
hud::BuffPosition,
|
||||
i18n::{list_localizations, LanguageMetadata, VoxygenLocalization},
|
||||
render::{AaMode, CloudMode, FluidMode, LightingMode, RenderMode, ShadowMapMode, ShadowMode},
|
||||
ui::{fonts::ConrodVoxygenFonts, ImageSlider, ScaleMode, ToggleButton},
|
||||
@ -159,6 +160,7 @@ widget_ids! {
|
||||
sfx_volume_text,
|
||||
audio_device_list,
|
||||
audio_device_text,
|
||||
//
|
||||
hotbar_title,
|
||||
bar_numbers_title,
|
||||
show_bar_numbers_none_button,
|
||||
@ -167,18 +169,20 @@ widget_ids! {
|
||||
show_bar_numbers_values_text,
|
||||
show_bar_numbers_percentage_button,
|
||||
show_bar_numbers_percentage_text,
|
||||
//
|
||||
show_shortcuts_button,
|
||||
show_shortcuts_text,
|
||||
show_xpbar_button,
|
||||
show_xpbar_text,
|
||||
show_bars_button,
|
||||
show_bars_text,
|
||||
placeholder,
|
||||
buff_pos_bar_button,
|
||||
buff_pos_bar_text,
|
||||
buff_pos_map_button,
|
||||
buff_pos_map_text,
|
||||
//
|
||||
chat_transp_title,
|
||||
chat_transp_text,
|
||||
chat_transp_slider,
|
||||
chat_char_name_text,
|
||||
chat_char_name_button,
|
||||
//
|
||||
sct_title,
|
||||
sct_show_text,
|
||||
sct_show_radio,
|
||||
@ -195,6 +199,7 @@ widget_ids! {
|
||||
sct_num_dur_text,
|
||||
sct_num_dur_slider,
|
||||
sct_num_dur_value,
|
||||
//
|
||||
speech_bubble_text,
|
||||
speech_bubble_dark_mode_text,
|
||||
speech_bubble_dark_mode_button,
|
||||
@ -261,6 +266,7 @@ pub enum Event {
|
||||
ToggleTips(bool),
|
||||
ToggleBarNumbers(BarNumbers),
|
||||
ToggleShortcutNumbers(ShortcutNumbers),
|
||||
BuffPosition(BuffPosition),
|
||||
ChangeTab(SettingsTab),
|
||||
Close,
|
||||
AdjustMousePan(u32),
|
||||
@ -829,11 +835,61 @@ impl<'a> Widget for SettingsWindow<'a> {
|
||||
.graphics_for(state.ids.show_shortcuts_button)
|
||||
.color(TEXT_COLOR)
|
||||
.set(state.ids.show_shortcuts_text, ui);
|
||||
|
||||
Rectangle::fill_with([60.0 * 4.0, 1.0 * 4.0], color::TRANSPARENT)
|
||||
.down_from(state.ids.show_shortcuts_text, 30.0)
|
||||
.set(state.ids.placeholder, ui);
|
||||
|
||||
// Buff Position
|
||||
// Buffs above skills
|
||||
if Button::image(match self.global_state.settings.gameplay.buff_position {
|
||||
BuffPosition::Bar => self.imgs.checkbox_checked,
|
||||
BuffPosition::Map => self.imgs.checkbox,
|
||||
})
|
||||
.w_h(18.0, 18.0)
|
||||
.hover_image(match self.global_state.settings.gameplay.buff_position {
|
||||
BuffPosition::Bar => self.imgs.checkbox_checked_mo,
|
||||
BuffPosition::Map => self.imgs.checkbox_mo,
|
||||
})
|
||||
.press_image(match self.global_state.settings.gameplay.buff_position {
|
||||
BuffPosition::Bar => self.imgs.checkbox_checked,
|
||||
BuffPosition::Map => self.imgs.checkbox_press,
|
||||
})
|
||||
.down_from(state.ids.show_shortcuts_button, 8.0)
|
||||
.set(state.ids.buff_pos_bar_button, ui)
|
||||
.was_clicked()
|
||||
{
|
||||
events.push(Event::BuffPosition(BuffPosition::Bar))
|
||||
}
|
||||
Text::new(&self.localized_strings.get("hud.settings.buffs_skillbar"))
|
||||
.right_from(state.ids.buff_pos_bar_button, 10.0)
|
||||
.font_size(self.fonts.cyri.scale(14))
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.graphics_for(state.ids.show_shortcuts_button)
|
||||
.color(TEXT_COLOR)
|
||||
.set(state.ids.buff_pos_bar_text, ui);
|
||||
// Buffs left from minimap
|
||||
if Button::image(match self.global_state.settings.gameplay.buff_position {
|
||||
BuffPosition::Map => self.imgs.checkbox_checked,
|
||||
BuffPosition::Bar => self.imgs.checkbox,
|
||||
})
|
||||
.w_h(18.0, 18.0)
|
||||
.hover_image(match self.global_state.settings.gameplay.buff_position {
|
||||
BuffPosition::Map => self.imgs.checkbox_checked_mo,
|
||||
BuffPosition::Bar => self.imgs.checkbox_mo,
|
||||
})
|
||||
.press_image(match self.global_state.settings.gameplay.buff_position {
|
||||
BuffPosition::Map => self.imgs.checkbox_checked,
|
||||
BuffPosition::Bar => self.imgs.checkbox_press,
|
||||
})
|
||||
.down_from(state.ids.buff_pos_bar_button, 8.0)
|
||||
.set(state.ids.buff_pos_map_button, ui)
|
||||
.was_clicked()
|
||||
{
|
||||
events.push(Event::BuffPosition(BuffPosition::Map))
|
||||
}
|
||||
Text::new(&self.localized_strings.get("hud.settings.buffs_mmap"))
|
||||
.right_from(state.ids.buff_pos_map_button, 10.0)
|
||||
.font_size(self.fonts.cyri.scale(14))
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.graphics_for(state.ids.show_shortcuts_button)
|
||||
.color(TEXT_COLOR)
|
||||
.set(state.ids.buff_pos_map_text, ui);
|
||||
// Content Right Side
|
||||
|
||||
/*Scrolling Combat text
|
||||
|
@ -894,6 +894,10 @@ impl PlayState for SessionState {
|
||||
global_state.settings.gameplay.shortcut_numbers = shortcut_numbers;
|
||||
global_state.settings.save_to_file_warn();
|
||||
},
|
||||
HudEvent::BuffPosition(buff_position) => {
|
||||
global_state.settings.gameplay.buff_position = buff_position;
|
||||
global_state.settings.save_to_file_warn();
|
||||
},
|
||||
HudEvent::UiScale(scale_change) => {
|
||||
global_state.settings.gameplay.ui_scale =
|
||||
self.hud.scale_change(scale_change);
|
||||
@ -921,6 +925,10 @@ impl PlayState for SessionState {
|
||||
global_state.settings.graphics.max_fps = fps;
|
||||
global_state.settings.save_to_file_warn();
|
||||
},
|
||||
HudEvent::RemoveBuff(buff_id) => {
|
||||
let mut client = self.client.borrow_mut();
|
||||
client.remove_buff(buff_id);
|
||||
},
|
||||
HudEvent::UseSlot(x) => self.client.borrow_mut().use_slot(x),
|
||||
HudEvent::SwapSlots(a, b) => self.client.borrow_mut().swap_slots(a, b),
|
||||
HudEvent::DropSlot(x) => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
hud::{BarNumbers, CrosshairType, Intro, PressBehavior, ShortcutNumbers, XpBar},
|
||||
hud::{BarNumbers, BuffPosition, CrosshairType, Intro, PressBehavior, ShortcutNumbers, XpBar},
|
||||
i18n,
|
||||
render::RenderMode,
|
||||
ui::ScaleMode,
|
||||
@ -507,6 +507,7 @@ pub struct GameplaySettings {
|
||||
pub intro_show: Intro,
|
||||
pub xp_bar: XpBar,
|
||||
pub shortcut_numbers: ShortcutNumbers,
|
||||
pub buff_position: BuffPosition,
|
||||
pub bar_numbers: BarNumbers,
|
||||
pub ui_scale: ScaleMode,
|
||||
pub free_look_behavior: PressBehavior,
|
||||
@ -537,6 +538,7 @@ impl Default for GameplaySettings {
|
||||
intro_show: Intro::Show,
|
||||
xp_bar: XpBar::Always,
|
||||
shortcut_numbers: ShortcutNumbers::On,
|
||||
buff_position: BuffPosition::Bar,
|
||||
bar_numbers: BarNumbers::Values,
|
||||
ui_scale: ScaleMode::RelativeToWindow([1920.0, 1080.0].into()),
|
||||
free_look_behavior: PressBehavior::Toggle,
|
||||
|
Loading…
Reference in New Issue
Block a user