Add Exp-Bar

This commit is contained in:
Monty Marz 2022-11-22 11:52:39 +00:00
parent 1a92bd7fe1
commit 3abfa4d2cc
12 changed files with 179 additions and 12 deletions

View File

@ -36,6 +36,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Doors now animate opening when entities are near them. - Doors now animate opening when entities are near them.
- Musical instruments can now be crafted, looted and played - Musical instruments can now be crafted, looted and played
- NPCs now move to their target's last known position. - NPCs now move to their target's last known position.
- Experience bar below the hotbar
### Changed ### Changed

BIN
assets/voxygen/element/ui/skillbar/exp_frame.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
assets/voxygen/element/ui/skillbar/exp_frame_bg.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
assets/voxygen/element/ui/skillbar/selected_exp_frame.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
assets/voxygen/element/ui/skillbar/selected_exp_frame_bg.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -4,6 +4,7 @@ hud-skill-not_unlocked = Not yet unlocked
hud-skill-req_sp ={"\u000A"} hud-skill-req_sp ={"\u000A"}
Requires { $number } SP Requires { $number } SP
hud-skill-set_as_exp_bar = Set as Experience Bar
hud-skill-inc_health_title = Increase Health hud-skill-inc_health_title = Increase Health
hud-skill-inc_health = Increases max health by { $boost }{ $SP } hud-skill-inc_health = Increases max health by { $boost }{ $SP }
hud-skill-inc_energy_title = Increase Energy hud-skill-inc_energy_title = Increase Energy

View File

@ -20,6 +20,7 @@ use crate::{
}; };
use conrod_core::{ use conrod_core::{
color, image, color, image,
position::Relative,
widget::{self, Button, Image, Rectangle, State, Text}, widget::{self, Button, Image, Rectangle, State, Text},
widget_ids, Color, Colorable, Labelable, Positionable, Sizeable, UiCell, Widget, WidgetCommon, widget_ids, Color, Colorable, Labelable, Positionable, Sizeable, UiCell, Widget, WidgetCommon,
}; };
@ -70,6 +71,7 @@ widget_ids! {
exp_bar_content, exp_bar_content,
exp_bar_rank, exp_bar_rank,
exp_bar_txt, exp_bar_txt,
active_bar_checkbox,
tree_title_txt, tree_title_txt,
lock_imgs[], lock_imgs[],
available_pts_txt, available_pts_txt,
@ -341,6 +343,7 @@ pub enum Event {
ChangeSkillTree(SelectedSkillTree), ChangeSkillTree(SelectedSkillTree),
UnlockSkill(Skill), UnlockSkill(Skill),
ChangeSection(DiarySection), ChangeSection(DiarySection),
SelectExpBar(Option<SkillGroupKind>),
} }
#[derive(PartialEq, Eq)] #[derive(PartialEq, Eq)]
@ -672,6 +675,42 @@ impl<'a> Widget for Diary<'a> {
.color(Some(UI_HIGHLIGHT_0)) .color(Some(UI_HIGHLIGHT_0))
.middle_of(state.ids.exp_bar_bg) .middle_of(state.ids.exp_bar_bg)
.set(state.ids.exp_bar_frame, ui); .set(state.ids.exp_bar_frame, ui);
// Show as Exp bar below skillbar
let exp_selected =
self.global_state.settings.interface.xp_bar_skillgroup == Some(*sel_tab);
if Button::image(if !exp_selected {
self.imgs.checkbox
} else {
self.imgs.checkbox_checked
})
.w_h(24.0, 25.0)
.hover_image(if !exp_selected {
self.imgs.checkbox_mo
} else {
self.imgs.checkbox_checked_mo
})
.press_image(if !exp_selected {
self.imgs.checkbox_press
} else {
self.imgs.checkbox_checked
})
.top_right_with_margins_on(state.ids.exp_bar_frame, 50.0, -40.0)
.label(&self.localized_strings.get_msg("hud-skill-set_as_exp_bar"))
.label_font_size(self.fonts.cyri.scale(14))
.label_color(TEXT_COLOR)
.label_font_id(self.fonts.cyri.conrod_id)
.label_x(Relative::Scalar(87.0))
.label_y(Relative::Scalar(2.0))
.set(state.ids.active_bar_checkbox, ui)
.was_clicked()
{
if self.global_state.settings.interface.xp_bar_skillgroup != Some(*sel_tab) {
events.push(Event::SelectExpBar(Some(*sel_tab)));
} else {
events.push(Event::SelectExpBar(None));
}
}
// Show EXP bar text on hover // Show EXP bar text on hover
if ui if ui
.widget_input(state.ids.exp_bar_frame) .widget_input(state.ids.exp_bar_frame)

View File

@ -367,6 +367,10 @@ image_ids! {
skillbar_frame: "voxygen.element.ui.skillbar.frame", skillbar_frame: "voxygen.element.ui.skillbar.frame",
health_bg: "voxygen.element.ui.skillbar.health_bg", health_bg: "voxygen.element.ui.skillbar.health_bg",
health_frame: "voxygen.element.ui.skillbar.health_frame", health_frame: "voxygen.element.ui.skillbar.health_frame",
exp_frame: "voxygen.element.ui.skillbar.exp_frame",
exp_frame_bg: "voxygen.element.ui.skillbar.exp_frame_bg",
selected_exp: "voxygen.element.ui.skillbar.selected_exp_frame",
selected_exp_bg: "voxygen.element.ui.skillbar.selected_exp_frame_bg",
decayed_bg: "voxygen.element.ui.skillbar.decayed_bg", decayed_bg: "voxygen.element.ui.skillbar.decayed_bg",
energy_bg: "voxygen.element.ui.skillbar.energy_bg", energy_bg: "voxygen.element.ui.skillbar.energy_bg",
energy_frame: "voxygen.element.ui.skillbar.energy_frame", energy_frame: "voxygen.element.ui.skillbar.energy_frame",
@ -380,6 +384,7 @@ image_ids! {
m_click_ico: "voxygen.element.ui.generic.icons.m_click", m_click_ico: "voxygen.element.ui.generic.icons.m_click",
skillbar_slot: "voxygen.element.ui.skillbar.slot", skillbar_slot: "voxygen.element.ui.skillbar.slot",
// Other Icons/Art // Other Icons/Art
skull: "voxygen.element.ui.generic.icons.skull", skull: "voxygen.element.ui.generic.icons.skull",
skull_2: "voxygen.element.ui.generic.icons.skull_2", skull_2: "voxygen.element.ui.generic.icons.skull_2",

View File

@ -708,6 +708,8 @@ pub enum Event {
AssignLeader(Uid), AssignLeader(Uid),
RemoveBuff(BuffKind), RemoveBuff(BuffKind),
UnlockSkill(Skill), UnlockSkill(Skill),
SelectExpBar(Option<SkillGroupKind>),
RequestSiteInfo(SiteId), RequestSiteInfo(SiteId),
ChangeAbility(usize, AuxiliaryAbility), ChangeAbility(usize, AuxiliaryAbility),
@ -2887,7 +2889,7 @@ impl Hud {
bodies.get(entity), bodies.get(entity),
) { ) {
let context = AbilityContext::try_from(char_states.get(entity)); let context = AbilityContext::try_from(char_states.get(entity));
Skillbar::new( match Skillbar::new(
client, client,
&info, &info,
global_state, global_state,
@ -2916,7 +2918,14 @@ impl Hud {
combos.get(entity), combos.get(entity),
char_states.get(entity), char_states.get(entity),
) )
.set(self.ids.skillbar, ui_widgets); .set(self.ids.skillbar, ui_widgets)
{
Some(skillbar::Event::OpenDiary(skillgroup)) => {
self.show.diary(true);
self.show.open_skill_tree(skillgroup);
},
None => {},
}
} }
// Bag contents // Bag contents
if self.show.bag { if self.show.bag {
@ -3357,6 +3366,9 @@ impl Hud {
diary::Event::ChangeSection(section) => { diary::Event::ChangeSection(section) => {
self.show.diary_fields.section = section; self.show.diary_fields.section = section;
}, },
diary::Event::SelectExpBar(xp_bar) => {
events.push(Event::SelectExpBar(xp_bar))
},
} }
} }
} }

View File

@ -3,8 +3,8 @@ use super::{
img_ids::{Imgs, ImgsRot}, img_ids::{Imgs, ImgsRot},
item_imgs::ItemImgs, item_imgs::ItemImgs,
slots, util, BarNumbers, HudInfo, ShortcutNumbers, BLACK, CRITICAL_HP_COLOR, HP_COLOR, slots, util, BarNumbers, HudInfo, ShortcutNumbers, BLACK, CRITICAL_HP_COLOR, HP_COLOR,
LOW_HP_COLOR, POISEBAR_TICK_COLOR, POISE_COLOR, QUALITY_EPIC, STAMINA_COLOR, TEXT_COLOR, LOW_HP_COLOR, POISEBAR_TICK_COLOR, POISE_COLOR, QUALITY_EPIC, QUALITY_LEGENDARY, STAMINA_COLOR,
UI_HIGHLIGHT_0, TEXT_COLOR, UI_HIGHLIGHT_0, XP_COLOR,
}; };
use crate::{ use crate::{
game_input::GameInput, game_input::GameInput,
@ -24,7 +24,11 @@ use client::{self, Client};
use common::comp::{ use common::comp::{
self, self,
ability::AbilityInput, ability::AbilityInput,
item::{tool::AbilityContext, ItemDesc, MaterialStatManifest}, item::{
tool::{AbilityContext, ToolKind},
ItemDesc, MaterialStatManifest,
},
skillset::SkillGroupKind,
Ability, ActiveAbilities, Body, CharacterState, Combo, Energy, Health, Inventory, Poise, Ability, ActiveAbilities, Body, CharacterState, Combo, Energy, Health, Inventory, Poise,
PoiseState, SkillSet, PoiseState, SkillSet,
}; };
@ -66,9 +70,6 @@ widget_ids! {
// Level // Level
level_bg, level_bg,
level, level,
// Exp-Bar
exp_alignment,
exp_filling,
// HP-Bar // HP-Bar
hp_alignment, hp_alignment,
hp_filling, hp_filling,
@ -90,6 +91,14 @@ widget_ids! {
poise_txt_alignment, poise_txt_alignment,
poise_txt_bg, poise_txt_bg,
poise_txt, poise_txt,
// Exp-Bar
exp_frame_bg,
exp_frame,
exp_filling,
exp_img_frame_bg,
exp_img_frame,
exp_img,
exp_lvl,
// Combo Counter // Combo Counter
combo_align, combo_align,
combo_bg, combo_bg,
@ -250,6 +259,10 @@ fn slot_entries(state: &State, slot_offset: f64) -> [SlotEntry; 10] {
] ]
} }
pub enum Event {
OpenDiary(SkillGroupKind),
}
#[derive(WidgetCommon)] #[derive(WidgetCommon)]
pub struct Skillbar<'a> { pub struct Skillbar<'a> {
client: &'a Client, client: &'a Client,
@ -387,7 +400,7 @@ impl<'a> Skillbar<'a> {
} }
} }
fn show_stat_bars(&self, state: &State, ui: &mut UiCell) { fn show_stat_bars(&self, state: &State, ui: &mut UiCell) -> Option<Event> {
let (hp_percentage, energy_percentage, poise_percentage): (f64, f64, f64) = let (hp_percentage, energy_percentage, poise_percentage): (f64, f64, f64) =
if self.health.is_dead { if self.health.is_dead {
(0.0, 0.0, 0.0) (0.0, 0.0, 0.0)
@ -520,6 +533,83 @@ impl<'a> Skillbar<'a> {
.middle_of(state.ids.bg_poise) .middle_of(state.ids.bg_poise)
.set(state.ids.frame_poise, ui); .set(state.ids.frame_poise, ui);
} }
if self
.global_state
.settings
.interface
.xp_bar_skillgroup
.is_some()
{
let offset = -81.0;
let selected_experience = &self
.global_state
.settings
.interface
.xp_bar_skillgroup
.unwrap_or(SkillGroupKind::General);
let current_exp = self.skillset.available_experience(*selected_experience) as f64;
let max_exp = self.skillset.skill_point_cost(*selected_experience) as f64;
let exp_percentage = current_exp / max_exp.max(1.0);
let level = self.skillset.earned_sp(*selected_experience).to_string();
// Exp Bar
Image::new(self.imgs.exp_frame_bg)
.w_h(594.0, 8.0)
.mid_top_with_margin_on(state.ids.frame, -offset)
.color(Some(Color::Rgba(1.0, 1.0, 1.0, 0.9)))
.set(state.ids.exp_frame_bg, ui);
Image::new(self.imgs.exp_frame)
.w_h(594.0, 8.0)
.middle_of(state.ids.exp_frame_bg)
.set(state.ids.exp_frame, ui);
Image::new(self.imgs.bar_content)
.w_h(590.0 * exp_percentage, 4.0)
.color(Some(XP_COLOR))
.top_left_with_margins_on(state.ids.exp_frame, 2.0, 2.0)
.set(state.ids.exp_filling, ui);
// Exp Type and Level Display
Image::new(self.imgs.selected_exp_bg)
.w_h(34.0, 38.0)
.top_left_with_margins_on(state.ids.exp_frame, -39.0, 3.0)
.color(Some(Color::Rgba(1.0, 1.0, 1.0, 0.9)))
.set(state.ids.exp_img_frame_bg, ui);
if Button::image(self.imgs.selected_exp)
.w_h(34.0, 38.0)
.middle_of(state.ids.exp_img_frame_bg)
.set(state.ids.exp_img_frame, ui)
.was_clicked()
{
return Some(Event::OpenDiary(*selected_experience));
}
Text::new(&level)
.mid_bottom_with_margin_on(state.ids.exp_img_frame, 2.0)
.font_size(11)
.font_id(self.fonts.cyri.conrod_id)
.color(QUALITY_LEGENDARY)
.graphics_for(state.ids.exp_img_frame)
.set(state.ids.exp_lvl, ui);
Image::new(match selected_experience {
SkillGroupKind::General => self.imgs.swords_crossed,
SkillGroupKind::Weapon(ToolKind::Sword) => self.imgs.sword,
SkillGroupKind::Weapon(ToolKind::Hammer) => self.imgs.hammer,
SkillGroupKind::Weapon(ToolKind::Axe) => self.imgs.axe,
SkillGroupKind::Weapon(ToolKind::Sceptre) => self.imgs.sceptre,
SkillGroupKind::Weapon(ToolKind::Bow) => self.imgs.bow,
SkillGroupKind::Weapon(ToolKind::Staff) => self.imgs.staff,
SkillGroupKind::Weapon(ToolKind::Pick) => self.imgs.mining,
_ => self.imgs.nothing,
})
.w_h(24.0, 24.0)
.graphics_for(state.ids.exp_img_frame)
.mid_bottom_with_margin_on(state.ids.exp_img_frame, 13.0)
.set(state.ids.exp_img, ui);
}
// Bar Text // Bar Text
let bar_text = if self.health.is_dead { let bar_text = if self.health.is_dead {
Some(( Some((
@ -597,6 +687,7 @@ impl<'a> Skillbar<'a> {
.color(TEXT_COLOR) .color(TEXT_COLOR)
.set(state.ids.poise_txt, ui); .set(state.ids.poise_txt, ui);
} }
None
} }
fn show_slotbar(&mut self, state: &State, ui: &mut UiCell, slot_offset: f64) { fn show_slotbar(&mut self, state: &State, ui: &mut UiCell, slot_offset: f64) {
@ -910,7 +1001,7 @@ pub struct State {
} }
impl<'a> Widget for Skillbar<'a> { impl<'a> Widget for Skillbar<'a> {
type Event = (); type Event = Option<Event>;
type State = State; type State = State;
type Style = (); type Style = ();
@ -950,7 +1041,7 @@ impl<'a> Widget for Skillbar<'a> {
.set(state.ids.frame, ui); .set(state.ids.frame, ui);
// Health, Energy and Poise bars // Health, Energy and Poise bars
self.show_stat_bars(state, ui); let event = self.show_stat_bars(state, ui);
// Slots // Slots
self.show_slotbar(state, ui, slot_offset); self.show_slotbar(state, ui, slot_offset);
@ -959,5 +1050,6 @@ impl<'a> Widget for Skillbar<'a> {
if let Some(combo_floater) = self.combo_floater { if let Some(combo_floater) = self.combo_floater {
self.show_combo_counter(combo_floater, state, ui); self.show_combo_counter(combo_floater, state, ui);
} }
event
} }
} }

View File

@ -1474,6 +1474,9 @@ impl PlayState for SessionState {
self.client.borrow_mut().swap_slots(slot_a, slot_b); self.client.borrow_mut().swap_slots(slot_a, slot_b);
} }
}, },
HudEvent::SelectExpBar(skillgroup) => {
global_state.settings.interface.xp_bar_skillgroup = skillgroup;
},
HudEvent::SplitSwapSlots { HudEvent::SplitSwapSlots {
slot_a, slot_a,
slot_b, slot_b,

View File

@ -2,7 +2,7 @@ use crate::{
hud::{BarNumbers, BuffPosition, CrosshairType, Intro, ShortcutNumbers, XpBar}, hud::{BarNumbers, BuffPosition, CrosshairType, Intro, ShortcutNumbers, XpBar},
ui::ScaleMode, ui::ScaleMode,
}; };
use common::comp::skillset::SkillGroupKind;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
/// `InterfaceSettings` contains UI, HUD and Map options. /// `InterfaceSettings` contains UI, HUD and Map options.
@ -48,6 +48,7 @@ pub struct InterfaceSettings {
pub minimap_face_north: bool, pub minimap_face_north: bool,
pub minimap_zoom: f64, pub minimap_zoom: f64,
pub accum_experience: bool, pub accum_experience: bool,
pub xp_bar_skillgroup: Option<SkillGroupKind>,
} }
impl Default for InterfaceSettings { impl Default for InterfaceSettings {
@ -92,6 +93,7 @@ impl Default for InterfaceSettings {
minimap_face_north: true, minimap_face_north: true,
minimap_zoom: 160.0, minimap_zoom: 160.0,
accum_experience: true, accum_experience: true,
xp_bar_skillgroup: Some(SkillGroupKind::General),
} }
} }
} }