From 3abfa4d2cc1336bce4e440019760d3b8785e802c Mon Sep 17 00:00:00 2001 From: Monty Marz Date: Tue, 22 Nov 2022 11:52:39 +0000 Subject: [PATCH] Add Exp-Bar --- CHANGELOG.md | 1 + .../voxygen/element/ui/skillbar/exp_frame.png | 3 + .../element/ui/skillbar/exp_frame_bg.png | 3 + .../ui/skillbar/selected_exp_frame.png | 3 + .../ui/skillbar/selected_exp_frame_bg.png | 3 + assets/voxygen/i18n/en/hud/skills.ftl | 1 + voxygen/src/hud/diary.rs | 39 +++++++ voxygen/src/hud/img_ids.rs | 5 + voxygen/src/hud/mod.rs | 16 ++- voxygen/src/hud/skillbar.rs | 110 ++++++++++++++++-- voxygen/src/session/mod.rs | 3 + voxygen/src/settings/interface.rs | 4 +- 12 files changed, 179 insertions(+), 12 deletions(-) create mode 100644 assets/voxygen/element/ui/skillbar/exp_frame.png create mode 100644 assets/voxygen/element/ui/skillbar/exp_frame_bg.png create mode 100644 assets/voxygen/element/ui/skillbar/selected_exp_frame.png create mode 100644 assets/voxygen/element/ui/skillbar/selected_exp_frame_bg.png diff --git a/CHANGELOG.md b/CHANGELOG.md index 71f618726d..9d3d837ec5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. - Musical instruments can now be crafted, looted and played - NPCs now move to their target's last known position. +- Experience bar below the hotbar ### Changed diff --git a/assets/voxygen/element/ui/skillbar/exp_frame.png b/assets/voxygen/element/ui/skillbar/exp_frame.png new file mode 100644 index 0000000000..86d87f1a77 --- /dev/null +++ b/assets/voxygen/element/ui/skillbar/exp_frame.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3bfeeface1f6da5e4829bcd9d40517c4bd719a4869371e8d7935806714ed3dd5 +size 2870 diff --git a/assets/voxygen/element/ui/skillbar/exp_frame_bg.png b/assets/voxygen/element/ui/skillbar/exp_frame_bg.png new file mode 100644 index 0000000000..45e03efcba --- /dev/null +++ b/assets/voxygen/element/ui/skillbar/exp_frame_bg.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9c38521e8ef54a7972cdad840ec77b705a5664e01fc0f9cffa843c1218365e77 +size 2850 diff --git a/assets/voxygen/element/ui/skillbar/selected_exp_frame.png b/assets/voxygen/element/ui/skillbar/selected_exp_frame.png new file mode 100644 index 0000000000..5644c85f1a --- /dev/null +++ b/assets/voxygen/element/ui/skillbar/selected_exp_frame.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d2a525c84c1f1c30760a3daff52e021578bfe661a74a87b755b9c24624b68afc +size 3694 diff --git a/assets/voxygen/element/ui/skillbar/selected_exp_frame_bg.png b/assets/voxygen/element/ui/skillbar/selected_exp_frame_bg.png new file mode 100644 index 0000000000..bce7fb3fc5 --- /dev/null +++ b/assets/voxygen/element/ui/skillbar/selected_exp_frame_bg.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6878cccc2296ff1076853922f7faa165714c8844135ffe50535ae1183a40b49a +size 2853 diff --git a/assets/voxygen/i18n/en/hud/skills.ftl b/assets/voxygen/i18n/en/hud/skills.ftl index 690e587011..532d87ac29 100644 --- a/assets/voxygen/i18n/en/hud/skills.ftl +++ b/assets/voxygen/i18n/en/hud/skills.ftl @@ -4,6 +4,7 @@ hud-skill-not_unlocked = Not yet unlocked hud-skill-req_sp ={"\u000A"} Requires { $number } SP +hud-skill-set_as_exp_bar = Set as Experience Bar hud-skill-inc_health_title = Increase Health hud-skill-inc_health = Increases max health by { $boost }{ $SP } hud-skill-inc_energy_title = Increase Energy diff --git a/voxygen/src/hud/diary.rs b/voxygen/src/hud/diary.rs index b0312ae936..5b52c1698e 100644 --- a/voxygen/src/hud/diary.rs +++ b/voxygen/src/hud/diary.rs @@ -20,6 +20,7 @@ use crate::{ }; use conrod_core::{ color, image, + position::Relative, widget::{self, Button, Image, Rectangle, State, Text}, widget_ids, Color, Colorable, Labelable, Positionable, Sizeable, UiCell, Widget, WidgetCommon, }; @@ -70,6 +71,7 @@ widget_ids! { exp_bar_content, exp_bar_rank, exp_bar_txt, + active_bar_checkbox, tree_title_txt, lock_imgs[], available_pts_txt, @@ -341,6 +343,7 @@ pub enum Event { ChangeSkillTree(SelectedSkillTree), UnlockSkill(Skill), ChangeSection(DiarySection), + SelectExpBar(Option), } #[derive(PartialEq, Eq)] @@ -672,6 +675,42 @@ impl<'a> Widget for Diary<'a> { .color(Some(UI_HIGHLIGHT_0)) .middle_of(state.ids.exp_bar_bg) .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 if ui .widget_input(state.ids.exp_bar_frame) diff --git a/voxygen/src/hud/img_ids.rs b/voxygen/src/hud/img_ids.rs index 4d0ff51f7b..9979dd203d 100644 --- a/voxygen/src/hud/img_ids.rs +++ b/voxygen/src/hud/img_ids.rs @@ -367,6 +367,10 @@ image_ids! { skillbar_frame: "voxygen.element.ui.skillbar.frame", health_bg: "voxygen.element.ui.skillbar.health_bg", 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", energy_bg: "voxygen.element.ui.skillbar.energy_bg", energy_frame: "voxygen.element.ui.skillbar.energy_frame", @@ -380,6 +384,7 @@ image_ids! { m_click_ico: "voxygen.element.ui.generic.icons.m_click", skillbar_slot: "voxygen.element.ui.skillbar.slot", + // Other Icons/Art skull: "voxygen.element.ui.generic.icons.skull", skull_2: "voxygen.element.ui.generic.icons.skull_2", diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 0d5b3cc5fd..96e37ee39e 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -708,6 +708,8 @@ pub enum Event { AssignLeader(Uid), RemoveBuff(BuffKind), UnlockSkill(Skill), + SelectExpBar(Option), + RequestSiteInfo(SiteId), ChangeAbility(usize, AuxiliaryAbility), @@ -2887,7 +2889,7 @@ impl Hud { bodies.get(entity), ) { let context = AbilityContext::try_from(char_states.get(entity)); - Skillbar::new( + match Skillbar::new( client, &info, global_state, @@ -2916,7 +2918,14 @@ impl Hud { combos.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 if self.show.bag { @@ -3357,6 +3366,9 @@ impl Hud { diary::Event::ChangeSection(section) => { self.show.diary_fields.section = section; }, + diary::Event::SelectExpBar(xp_bar) => { + events.push(Event::SelectExpBar(xp_bar)) + }, } } } diff --git a/voxygen/src/hud/skillbar.rs b/voxygen/src/hud/skillbar.rs index 19f2aeae83..621ad994f3 100644 --- a/voxygen/src/hud/skillbar.rs +++ b/voxygen/src/hud/skillbar.rs @@ -3,8 +3,8 @@ use super::{ img_ids::{Imgs, ImgsRot}, item_imgs::ItemImgs, 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, - UI_HIGHLIGHT_0, + LOW_HP_COLOR, POISEBAR_TICK_COLOR, POISE_COLOR, QUALITY_EPIC, QUALITY_LEGENDARY, STAMINA_COLOR, + TEXT_COLOR, UI_HIGHLIGHT_0, XP_COLOR, }; use crate::{ game_input::GameInput, @@ -24,7 +24,11 @@ use client::{self, Client}; use common::comp::{ self, ability::AbilityInput, - item::{tool::AbilityContext, ItemDesc, MaterialStatManifest}, + item::{ + tool::{AbilityContext, ToolKind}, + ItemDesc, MaterialStatManifest, + }, + skillset::SkillGroupKind, Ability, ActiveAbilities, Body, CharacterState, Combo, Energy, Health, Inventory, Poise, PoiseState, SkillSet, }; @@ -66,9 +70,6 @@ widget_ids! { // Level level_bg, level, - // Exp-Bar - exp_alignment, - exp_filling, // HP-Bar hp_alignment, hp_filling, @@ -90,6 +91,14 @@ widget_ids! { poise_txt_alignment, poise_txt_bg, 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_align, combo_bg, @@ -250,6 +259,10 @@ fn slot_entries(state: &State, slot_offset: f64) -> [SlotEntry; 10] { ] } +pub enum Event { + OpenDiary(SkillGroupKind), +} + #[derive(WidgetCommon)] pub struct Skillbar<'a> { 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 { let (hp_percentage, energy_percentage, poise_percentage): (f64, f64, f64) = if self.health.is_dead { (0.0, 0.0, 0.0) @@ -520,6 +533,83 @@ impl<'a> Skillbar<'a> { .middle_of(state.ids.bg_poise) .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 let bar_text = if self.health.is_dead { Some(( @@ -597,6 +687,7 @@ impl<'a> Skillbar<'a> { .color(TEXT_COLOR) .set(state.ids.poise_txt, ui); } + None } 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> { - type Event = (); + type Event = Option; type State = State; type Style = (); @@ -950,7 +1041,7 @@ impl<'a> Widget for Skillbar<'a> { .set(state.ids.frame, ui); // Health, Energy and Poise bars - self.show_stat_bars(state, ui); + let event = self.show_stat_bars(state, ui); // Slots 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 { self.show_combo_counter(combo_floater, state, ui); } + event } } diff --git a/voxygen/src/session/mod.rs b/voxygen/src/session/mod.rs index 4b9e223ff2..786e5110d4 100644 --- a/voxygen/src/session/mod.rs +++ b/voxygen/src/session/mod.rs @@ -1474,6 +1474,9 @@ impl PlayState for SessionState { self.client.borrow_mut().swap_slots(slot_a, slot_b); } }, + HudEvent::SelectExpBar(skillgroup) => { + global_state.settings.interface.xp_bar_skillgroup = skillgroup; + }, HudEvent::SplitSwapSlots { slot_a, slot_b, diff --git a/voxygen/src/settings/interface.rs b/voxygen/src/settings/interface.rs index 518f462edb..716e0b6038 100644 --- a/voxygen/src/settings/interface.rs +++ b/voxygen/src/settings/interface.rs @@ -2,7 +2,7 @@ use crate::{ hud::{BarNumbers, BuffPosition, CrosshairType, Intro, ShortcutNumbers, XpBar}, ui::ScaleMode, }; - +use common::comp::skillset::SkillGroupKind; use serde::{Deserialize, Serialize}; /// `InterfaceSettings` contains UI, HUD and Map options. @@ -48,6 +48,7 @@ pub struct InterfaceSettings { pub minimap_face_north: bool, pub minimap_zoom: f64, pub accum_experience: bool, + pub xp_bar_skillgroup: Option, } impl Default for InterfaceSettings { @@ -92,6 +93,7 @@ impl Default for InterfaceSettings { minimap_face_north: true, minimap_zoom: 160.0, accum_experience: true, + xp_bar_skillgroup: Some(SkillGroupKind::General), } } }