EXP bar and available points UI

fix overhead UI

Add WIP overhead difficulty indicator

readd commented out exp counter for later use

Wired skill information into UI.
This commit is contained in:
Monty Marz 2021-01-02 05:11:30 +01:00 committed by Sam
parent c0c45a1996
commit 48bd921d0a
16 changed files with 370 additions and 101 deletions

BIN
assets/voxygen/element/icons/indicator_bubble.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
assets/voxygen/element/misc_bg/diary_exp_bg.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
assets/voxygen/element/misc_bg/diary_exp_frame.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -37,12 +37,12 @@
(0.0, 0.0, 0.0), (90.0, 90.0, 0.0), 1.0,
),
Tool("example_general_combat_left"): VoxTrans(
"voxel.weapon.shield.wood-0",
(0.0, 0.0, 0.0), (90.0, 90.0, 0.0), 1.0,
"voxel.weapon.sword.long_2h_saurok",
(0.0, 0.0, 0.0), (85.0, -90.0, -40.0), 1.0,
),
Tool("example_general_combat_right"): VoxTrans(
"voxel.weapon.sword.long_2h_saurok",
(0.0, 0.0, 0.0), (90.0, 90.0, 0.0), 1.0,
(0.0, 0.0, 0.0), (125.0, 90.0, 80.0), 1.0,
),
// Bows
Tool("common.items.weapons.bow.starter_bow"): VoxTrans(

Binary file not shown.

View File

@ -220,6 +220,11 @@ pub enum SkillGroupType {
Weapon(ToolKind),
}
impl SkillGroupType {
/// Gets the cost in experience of earning a skill point
pub fn skill_point_cost(self) -> u16 { 300 }
}
/// A group of skills that have been unlocked by a player. Each skill group has
/// independent exp and skill points which are used to unlock skills in that
/// skill group.
@ -228,6 +233,7 @@ pub struct SkillGroup {
pub skill_group_type: SkillGroupType,
pub exp: u16,
pub available_sp: u16,
pub earned_sp: u16,
}
impl SkillGroup {
@ -236,6 +242,7 @@ impl SkillGroup {
skill_group_type,
exp: 0,
available_sp: 0,
earned_sp: 0,
}
}
}
@ -433,6 +440,7 @@ impl SkillSet {
.find(|x| x.skill_group_type == skill_group_type)
{
skill_group.available_sp += number_of_skill_points;
skill_group.earned_sp += number_of_skill_points;
} else {
warn!("Tried to add skill points to a skill group that player does not have");
}
@ -467,6 +475,33 @@ impl SkillSet {
self.skills.contains_key(s) && self.skills.get(s).map_or(false, |l_b| l_b >= l)
})
}
/// Gets the available points for a particular skill group
pub fn get_available_sp(&self, skill_group: SkillGroupType) -> u16 {
let mut skill_groups = self
.skill_groups
.iter()
.filter(|s_g| s_g.skill_group_type == skill_group);
skill_groups.next().map_or(0, |s_g| s_g.available_sp)
}
/// Gets the total earned points for a particular skill group
pub fn get_earned_sp(&self, skill_group: SkillGroupType) -> u16 {
let mut skill_groups = self
.skill_groups
.iter()
.filter(|s_g| s_g.skill_group_type == skill_group);
skill_groups.next().map_or(0, |s_g| s_g.earned_sp)
}
/// Gets the available experience for a particular skill group
pub fn get_experience(&self, skill_group: SkillGroupType) -> u16 {
let mut skill_groups = self
.skill_groups
.iter()
.filter(|s_g| s_g.skill_group_type == skill_group);
skill_groups.next().map_or(0, |s_g| s_g.exp)
}
}
impl Skill {

View File

@ -79,7 +79,7 @@ impl<'a> System<'a> for Sys {
let stat = stats.get_unchecked();
{
for skill_group in stat.skill_set.skill_groups.iter() {
if skill_group.exp >= 300 {
if skill_group.exp >= skill_group.skill_group_type.skill_point_cost() {
skills_to_level.insert(skill_group.skill_group_type);
}
}
@ -88,7 +88,8 @@ impl<'a> System<'a> for Sys {
if !skills_to_level.is_empty() {
let mut stat = stats.get_mut_unchecked();
for skill_group in skills_to_level.drain() {
stat.skill_set.change_experience(skill_group, -300);
stat.skill_set
.change_experience(skill_group, -(skill_group.skill_point_cost() as i32));
stat.skill_set.add_skill_points(skill_group, 1);
}
}

View File

@ -5,7 +5,7 @@ CREATE TABLE "_character_new" (
"character_id" INT NOT NULL,
"player_uuid" TEXT NOT NULL,
"alias" TEXT NOT NULL,
"waypoint" TEXT NOT NULL,
"waypoint" TEXT,
PRIMARY KEY("character_id"),
FOREIGN KEY("character_id") REFERENCES "body"("body_id"),
FOREIGN KEY("character_id") REFERENCES "item"("item_id")
@ -37,6 +37,7 @@ CREATE TABLE skill_group (
skill_group_type TEXT NOT NULL,
exp INTEGER NOT NULL,
available_sp INTEGER NOT NULL,
earned_sp INTEGER NOT NULL,
FOREIGN KEY(character_id) REFERENCES character(character_id),
PRIMARY KEY(character_id,skill_group_type)
);
@ -52,5 +53,5 @@ CREATE TABLE skill (
-- Inserts starting skill group for everyone
INSERT INTO skill_group
SELECT c.character_id, '"General"', 0, 0
SELECT c.character_id, '"General"', 0, 0, 0
FROM character c

View File

@ -381,6 +381,7 @@ fn convert_skill_groups_from_database(skill_groups: &[SkillGroup]) -> Vec<skills
skill_group_type,
exp: skill_group.exp as u16,
available_sp: skill_group.available_sp as u16,
earned_sp: skill_group.earned_sp as u16,
};
new_skill_groups.push(new_skill_group);
}
@ -414,6 +415,7 @@ pub fn convert_skill_groups_to_database(
skill_group_type: serde_json::to_string(&sg.skill_group_type).unwrap(),
exp: sg.exp as i32,
available_sp: sg.available_sp as i32,
earned_sp: sg.earned_sp as i32,
})
.collect();
db_skill_groups

View File

@ -64,4 +64,5 @@ pub struct SkillGroup {
pub skill_group_type: String,
pub exp: i32,
pub available_sp: i32,
pub earned_sp: i32,
}

View File

@ -46,6 +46,7 @@ table! {
skill_group_type -> Text,
exp -> Integer,
available_sp -> Integer,
earned_sp -> Integer,
}
}

View File

@ -335,7 +335,7 @@ impl<'a> Widget for Buttons<'a> {
.press_image(self.imgs.spellbook_press)
.with_tooltip(
self.tooltip_manager,
&localized_strings.get("hud.spell"),
&localized_strings.get("hud.diary"),
"",
&button_tooltip,
TEXT_COLOR,

View File

@ -1,7 +1,7 @@
use super::{
img_ids::{Imgs, ImgsRot},
item_imgs::{ItemImgs, ItemKey::Tool},
Show, TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN,
Show, QUALITY_LEGENDARY, TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN, XP_COLOR,
};
use crate::{
i18n::Localization,
@ -29,6 +29,13 @@ widget_ids! {
close,
title,
content_align,
exp_bar_bg,
exp_bar_frame,
exp_bar_content_align,
exp_bar_content,
exp_bar_rank,
exp_bar_txt,
available_pts_txt,
weapon_imgs[],
weapon_btns[],
skills_top_l_align,
@ -127,7 +134,8 @@ widget_ids! {
skill_sceptre_bomb_2,
skill_sceptre_bomb_3,
skill_sceptre_bomb_4,
general_combat_render,
general_combat_render_0,
general_combat_render_1,
skill_general_stat_0,
skill_general_stat_1,
skill_general_tree_0,
@ -162,6 +170,7 @@ pub struct Diary<'a> {
created_btns_top_r: usize,
created_btns_bot_l: usize,
created_btns_bot_r: usize,
hovering_exp_bar: bool,
}
impl<'a> Diary<'a> {
@ -191,6 +200,7 @@ impl<'a> Diary<'a> {
created_btns_top_r: 0,
created_btns_bot_l: 0,
created_btns_bot_r: 0,
hovering_exp_bar: false,
}
}
}
@ -204,16 +214,7 @@ impl<'a> Diary<'a> {
Achievements,
}*/
pub enum SelectedSkillTree {
None,
Sword,
Hammer,
Axe,
Sceptre,
Bow,
StaffFire,
GeneralCombat,
}
pub type SelectedSkillTree = skills::SkillGroupType;
const WEAPONS: [&str; 7] = [
"General Combat",
@ -227,7 +228,7 @@ const WEAPONS: [&str; 7] = [
pub enum Event {
Close,
ChangeWeaponTree(SelectedSkillTree),
ChangeSkillTree(SelectedSkillTree),
UnlockSkill(Skill),
}
@ -346,31 +347,35 @@ impl<'a> Widget for Diary<'a> {
// Weapon icons
if Button::image(match i.1 {
"General Combat" => match sel_tab {
SelectedSkillTree::GeneralCombat => self.imgs.wpn_icon_border_pressed,
SelectedSkillTree::General => self.imgs.wpn_icon_border_pressed,
_ => self.imgs.wpn_icon_border,
},
"Sword" => match sel_tab {
SelectedSkillTree::Sword => self.imgs.wpn_icon_border_pressed,
SelectedSkillTree::Weapon(ToolKind::Sword) => self.imgs.wpn_icon_border_pressed,
_ => self.imgs.wpn_icon_border,
},
"Hammer" => match sel_tab {
SelectedSkillTree::Hammer => self.imgs.wpn_icon_border_pressed,
SelectedSkillTree::Weapon(ToolKind::Hammer) => {
self.imgs.wpn_icon_border_pressed
},
_ => self.imgs.wpn_icon_border,
},
"Axe" => match sel_tab {
SelectedSkillTree::Axe => self.imgs.wpn_icon_border_pressed,
SelectedSkillTree::Weapon(ToolKind::Axe) => self.imgs.wpn_icon_border_pressed,
_ => self.imgs.wpn_icon_border,
},
"Sceptre" => match sel_tab {
SelectedSkillTree::Sceptre => self.imgs.wpn_icon_border_pressed,
SelectedSkillTree::Weapon(ToolKind::Sceptre) => {
self.imgs.wpn_icon_border_pressed
},
_ => self.imgs.wpn_icon_border,
},
"Bow" => match sel_tab {
SelectedSkillTree::Bow => self.imgs.wpn_icon_border_pressed,
SelectedSkillTree::Weapon(ToolKind::Bow) => self.imgs.wpn_icon_border_pressed,
_ => self.imgs.wpn_icon_border,
},
"Fire Staff" => match sel_tab {
SelectedSkillTree::StaffFire => self.imgs.wpn_icon_border_pressed,
SelectedSkillTree::Weapon(ToolKind::Staff) => self.imgs.wpn_icon_border_pressed,
_ => self.imgs.wpn_icon_border,
},
_ => self.imgs.wpn_icon_border,
@ -378,62 +383,70 @@ impl<'a> Widget for Diary<'a> {
.w_h(tweak!(50.0), tweak!(50.0))
.hover_image(match i.1 {
"General Combat" => match sel_tab {
SelectedSkillTree::GeneralCombat => self.imgs.wpn_icon_border_pressed,
SelectedSkillTree::General => self.imgs.wpn_icon_border_pressed,
_ => self.imgs.wpn_icon_border_mo,
},
"Sword" => match sel_tab {
SelectedSkillTree::Sword => self.imgs.wpn_icon_border_pressed,
SelectedSkillTree::Weapon(ToolKind::Sword) => self.imgs.wpn_icon_border_pressed,
_ => self.imgs.wpn_icon_border_mo,
},
"Hammer" => match sel_tab {
SelectedSkillTree::Hammer => self.imgs.wpn_icon_border_pressed,
SelectedSkillTree::Weapon(ToolKind::Hammer) => {
self.imgs.wpn_icon_border_pressed
},
_ => self.imgs.wpn_icon_border_mo,
},
"Axe" => match sel_tab {
SelectedSkillTree::Axe => self.imgs.wpn_icon_border_pressed,
SelectedSkillTree::Weapon(ToolKind::Axe) => self.imgs.wpn_icon_border_pressed,
_ => self.imgs.wpn_icon_border_mo,
},
"Sceptre" => match sel_tab {
SelectedSkillTree::Sceptre => self.imgs.wpn_icon_border_pressed,
SelectedSkillTree::Weapon(ToolKind::Sceptre) => {
self.imgs.wpn_icon_border_pressed
},
_ => self.imgs.wpn_icon_border_mo,
},
"Bow" => match sel_tab {
SelectedSkillTree::Bow => self.imgs.wpn_icon_border_pressed,
SelectedSkillTree::Weapon(ToolKind::Bow) => self.imgs.wpn_icon_border_pressed,
_ => self.imgs.wpn_icon_border_mo,
},
"Fire Staff" => match sel_tab {
SelectedSkillTree::StaffFire => self.imgs.wpn_icon_border_pressed,
SelectedSkillTree::Weapon(ToolKind::Staff) => self.imgs.wpn_icon_border_pressed,
_ => self.imgs.wpn_icon_border_mo,
},
_ => self.imgs.wpn_icon_border,
})
.press_image(match i.1 {
"General Combat" => match sel_tab {
SelectedSkillTree::GeneralCombat => self.imgs.wpn_icon_border_pressed,
SelectedSkillTree::General => self.imgs.wpn_icon_border_pressed,
_ => self.imgs.wpn_icon_border_press,
},
"Sword" => match sel_tab {
SelectedSkillTree::Sword => self.imgs.wpn_icon_border_pressed,
SelectedSkillTree::Weapon(ToolKind::Sword) => self.imgs.wpn_icon_border_pressed,
_ => self.imgs.wpn_icon_border_press,
},
"Hammer" => match sel_tab {
SelectedSkillTree::Hammer => self.imgs.wpn_icon_border_pressed,
SelectedSkillTree::Weapon(ToolKind::Hammer) => {
self.imgs.wpn_icon_border_pressed
},
_ => self.imgs.wpn_icon_border_press,
},
"Axe" => match sel_tab {
SelectedSkillTree::Axe => self.imgs.wpn_icon_border_pressed,
SelectedSkillTree::Weapon(ToolKind::Axe) => self.imgs.wpn_icon_border_pressed,
_ => self.imgs.wpn_icon_border_press,
},
"Sceptre" => match sel_tab {
SelectedSkillTree::Sceptre => self.imgs.wpn_icon_border_pressed,
SelectedSkillTree::Weapon(ToolKind::Sceptre) => {
self.imgs.wpn_icon_border_pressed
},
_ => self.imgs.wpn_icon_border_press,
},
"Bow" => match sel_tab {
SelectedSkillTree::Bow => self.imgs.wpn_icon_border_pressed,
SelectedSkillTree::Weapon(ToolKind::Bow) => self.imgs.wpn_icon_border_pressed,
_ => self.imgs.wpn_icon_border_press,
},
"Fire Staff" => match sel_tab {
SelectedSkillTree::StaffFire => self.imgs.wpn_icon_border_pressed,
SelectedSkillTree::Weapon(ToolKind::Staff) => self.imgs.wpn_icon_border_pressed,
_ => self.imgs.wpn_icon_border_press,
},
_ => self.imgs.wpn_icon_border,
@ -444,21 +457,84 @@ impl<'a> Widget for Diary<'a> {
{
match i.1 {
"General Combat" => {
events.push(Event::ChangeWeaponTree(SelectedSkillTree::GeneralCombat))
events.push(Event::ChangeSkillTree(SelectedSkillTree::General))
},
"Sword" => events.push(Event::ChangeWeaponTree(SelectedSkillTree::Sword)),
"Hammer" => events.push(Event::ChangeWeaponTree(SelectedSkillTree::Hammer)),
"Axe" => events.push(Event::ChangeWeaponTree(SelectedSkillTree::Axe)),
"Sceptre" => events.push(Event::ChangeWeaponTree(SelectedSkillTree::Sceptre)),
"Bow" => events.push(Event::ChangeWeaponTree(SelectedSkillTree::Bow)),
"Fire Staff" => {
events.push(Event::ChangeWeaponTree(SelectedSkillTree::StaffFire))
},
_ => events.push(Event::ChangeWeaponTree(SelectedSkillTree::None)),
"Sword" => events.push(Event::ChangeSkillTree(SelectedSkillTree::Weapon(
ToolKind::Sword,
))),
"Hammer" => events.push(Event::ChangeSkillTree(SelectedSkillTree::Weapon(
ToolKind::Hammer,
))),
"Axe" => events.push(Event::ChangeSkillTree(SelectedSkillTree::Weapon(
ToolKind::Axe,
))),
"Sceptre" => events.push(Event::ChangeSkillTree(SelectedSkillTree::Weapon(
ToolKind::Sceptre,
))),
"Bow" => events.push(Event::ChangeSkillTree(SelectedSkillTree::Weapon(
ToolKind::Bow,
))),
"Fire Staff" => events.push(Event::ChangeSkillTree(SelectedSkillTree::Weapon(
ToolKind::Staff,
))),
_ => events.push(Event::Close),
}
}
}
// Exp Bars and Rank Display
let current_exp = self.stats.skill_set.get_experience(*sel_tab) as f64;
let max_exp = sel_tab.skill_point_cost() as f64;
let exp_percentage = current_exp / max_exp;
let rank = self.stats.skill_set.get_earned_sp(*sel_tab);
let rank_txt = format!("{}", rank);
let exp_txt = format!("{}/{}", current_exp, max_exp);
let available_pts = self.stats.skill_set.get_available_sp(*sel_tab);
let available_pts_txt = format!("{} SP available!", available_pts);
Image::new(self.imgs.diary_exp_bg)
.w_h(480.0, 76.0)
.mid_bottom_with_margin_on(state.content_align, tweak!(10.0))
.set(state.exp_bar_bg, ui);
Rectangle::fill_with([400.0, 40.0], color::TRANSPARENT)
.top_left_with_margins_on(state.exp_bar_bg, 32.0, 40.0)
.set(state.exp_bar_content_align, ui);
Image::new(self.imgs.bar_content)
.w_h(400.0 * exp_percentage, 40.0)
.top_left_with_margins_on(state.exp_bar_content_align, 0.0, 0.0)
.color(Some(XP_COLOR))
.set(state.exp_bar_content, ui);
Image::new(self.imgs.diary_exp_frame)
.w_h(480.0, 76.0)
.color(Some(UI_HIGHLIGHT_0))
.middle_of(state.exp_bar_bg)
.set(state.exp_bar_frame, ui);
// Show EXP bar text on hover
self.hovering_exp_bar = ui
.widget_input(state.exp_bar_frame)
.mouse()
.map_or(false, |m| m.is_over());
if self.hovering_exp_bar {
Text::new(&exp_txt)
.mid_top_with_margin_on(state.exp_bar_frame, tweak!(47.0))
.font_id(self.fonts.cyri.conrod_id)
.font_size(self.fonts.cyri.scale(tweak!(14)))
.color(TEXT_COLOR)
.graphics_for(state.exp_bar_frame)
.set(state.exp_bar_txt, ui);
}
Text::new(&rank_txt)
.mid_top_with_margin_on(state.exp_bar_frame, tweak!(5.0))
.font_id(self.fonts.cyri.conrod_id)
.font_size(self.fonts.cyri.scale(tweak!(28)))
.color(TEXT_COLOR)
.set(state.exp_bar_rank, ui);
if available_pts > 0 {
Text::new(&available_pts_txt)
.mid_top_with_margin_on(state.content_align, tweak!(10.0))
.font_id(self.fonts.cyri.conrod_id)
.font_size(self.fonts.cyri.scale(tweak!(28)))
.color(QUALITY_LEGENDARY)
.set(state.available_pts_txt, ui);
}
// Skill Trees
// Alignment Placing
let x = tweak!(200.0);
@ -479,37 +555,37 @@ impl<'a> Widget for Diary<'a> {
// Number of skills per rectangle per weapon, start counting at 0
// Maximum of 9 skills/8 indices
let skills_top_l = match sel_tab {
SelectedSkillTree::GeneralCombat => 2,
SelectedSkillTree::Sword => 4,
SelectedSkillTree::Axe => 4,
SelectedSkillTree::Hammer => 4,
SelectedSkillTree::Bow => 2,
SelectedSkillTree::StaffFire => 4,
SelectedSkillTree::Sceptre => 6,
SelectedSkillTree::General => 2,
SelectedSkillTree::Weapon(ToolKind::Sword) => 4,
SelectedSkillTree::Weapon(ToolKind::Axe) => 4,
SelectedSkillTree::Weapon(ToolKind::Hammer) => 4,
SelectedSkillTree::Weapon(ToolKind::Bow) => 2,
SelectedSkillTree::Weapon(ToolKind::Staff) => 4,
SelectedSkillTree::Weapon(ToolKind::Sceptre) => 6,
_ => 0,
};
let skills_top_r = match sel_tab {
SelectedSkillTree::GeneralCombat => 6,
SelectedSkillTree::Sword => 6,
SelectedSkillTree::Axe => 5,
SelectedSkillTree::Hammer => 4,
SelectedSkillTree::Bow => 6,
SelectedSkillTree::StaffFire => 4,
SelectedSkillTree::Sceptre => 5,
SelectedSkillTree::General => 6,
SelectedSkillTree::Weapon(ToolKind::Sword) => 6,
SelectedSkillTree::Weapon(ToolKind::Axe) => 5,
SelectedSkillTree::Weapon(ToolKind::Hammer) => 4,
SelectedSkillTree::Weapon(ToolKind::Bow) => 6,
SelectedSkillTree::Weapon(ToolKind::Staff) => 4,
SelectedSkillTree::Weapon(ToolKind::Sceptre) => 5,
_ => 0,
};
let skills_bot_l = match sel_tab {
SelectedSkillTree::GeneralCombat => 4,
SelectedSkillTree::Sword => 5,
SelectedSkillTree::Axe => 5,
SelectedSkillTree::Hammer => 6,
SelectedSkillTree::Bow => 5,
SelectedSkillTree::StaffFire => 5,
SelectedSkillTree::General => 4,
SelectedSkillTree::Weapon(ToolKind::Sword) => 5,
SelectedSkillTree::Weapon(ToolKind::Axe) => 5,
SelectedSkillTree::Weapon(ToolKind::Hammer) => 6,
SelectedSkillTree::Weapon(ToolKind::Bow) => 5,
SelectedSkillTree::Weapon(ToolKind::Staff) => 5,
_ => 0,
};
let skills_bot_r = match sel_tab {
SelectedSkillTree::Sword => 1,
SelectedSkillTree::Bow => 1,
SelectedSkillTree::Weapon(ToolKind::Sword) => 1,
SelectedSkillTree::Weapon(ToolKind::Bow) => 1,
_ => 0,
};
// Update widget id array len
@ -614,16 +690,26 @@ impl<'a> Widget for Diary<'a> {
let art_size = [tweak!(320.0), tweak!(320.0)];
let skills = &self.stats.skill_set.skills;
match sel_tab {
SelectedSkillTree::GeneralCombat => {
SelectedSkillTree::General => {
use skills::{GeneralSkill::*, RollSkill::*, SkillGroupType::*};
use ToolKind::*;
// General Combat
Image::new(self.imgs.not_found)
.wh(art_size)
.middle_of(state.content_align)
.graphics_for(state.content_align)
.color(Some(Color::Rgba(1.0, 1.0, 1.0, tweak!(1.0))))
.set(state.general_combat_render, ui);
Image::new(
self.item_imgs
.img_id_or_not_found_img(Tool("example_general_combat_left".to_string())),
)
.wh(art_size)
.middle_of(state.content_align)
.color(Some(Color::Rgba(1.0, 1.0, 1.0, tweak!(1.0))))
.set(state.general_combat_render_0, ui);
Image::new(
self.item_imgs
.img_id_or_not_found_img(Tool("example_general_combat_right".to_string())),
)
.wh(art_size)
.middle_of(state.general_combat_render_0)
.color(Some(Color::Rgba(1.0, 1.0, 1.0, tweak!(1.0))))
.set(state.general_combat_render_1, ui);
// Top Left skills
// 5 1 6
// 3 0 4
@ -943,7 +1029,7 @@ impl<'a> Widget for Diary<'a> {
events.push(Event::UnlockSkill(skill));
};
},
SelectedSkillTree::Sword => {
SelectedSkillTree::Weapon(ToolKind::Sword) => {
use skills::SwordSkill::*;
// Sword
Image::new(
@ -952,7 +1038,6 @@ impl<'a> Widget for Diary<'a> {
)
.wh(art_size)
.middle_of(state.content_align)
.graphics_for(state.content_align)
.color(Some(Color::Rgba(1.0, 1.0, 1.0, tweak!(1.0))))
.set(state.sword_render, ui);
// Top Left skills
@ -1379,7 +1464,7 @@ impl<'a> Widget for Diary<'a> {
events.push(Event::UnlockSkill(skill));
};
},
SelectedSkillTree::Axe => {
SelectedSkillTree::Weapon(ToolKind::Axe) => {
use skills::AxeSkill::*;
// Axe
Image::new(
@ -1388,7 +1473,6 @@ impl<'a> Widget for Diary<'a> {
)
.wh(art_size)
.middle_of(state.content_align)
.graphics_for(state.content_align)
.color(Some(Color::Rgba(1.0, 1.0, 1.0, tweak!(1.0))))
.set(state.axe_render, ui);
// Top Left skills
@ -1762,7 +1846,7 @@ impl<'a> Widget for Diary<'a> {
events.push(Event::UnlockSkill(skill));
};
},
SelectedSkillTree::Hammer => {
SelectedSkillTree::Weapon(ToolKind::Hammer) => {
use skills::HammerSkill::*;
// Hammer
Image::new(
@ -1771,7 +1855,6 @@ impl<'a> Widget for Diary<'a> {
)
.wh(art_size)
.middle_of(state.content_align)
.graphics_for(state.content_align)
.color(Some(Color::Rgba(1.0, 1.0, 1.0, tweak!(1.0))))
.set(state.hammer_render, ui);
// Top Left skills
@ -2145,7 +2228,7 @@ impl<'a> Widget for Diary<'a> {
events.push(Event::UnlockSkill(skill));
};
},
SelectedSkillTree::Bow => {
SelectedSkillTree::Weapon(ToolKind::Bow) => {
use skills::BowSkill::*;
// Bow
Image::new(
@ -2154,7 +2237,6 @@ impl<'a> Widget for Diary<'a> {
)
.wh(art_size)
.middle_of(state.content_align)
.graphics_for(state.content_align)
.set(state.bow_render, ui);
// Top Left skills
// 5 1 6
@ -2528,7 +2610,7 @@ impl<'a> Widget for Diary<'a> {
events.push(Event::UnlockSkill(skill));
};
},
SelectedSkillTree::StaffFire => {
SelectedSkillTree::Weapon(ToolKind::Staff) => {
use skills::StaffSkill::*;
// Staff
Image::new(
@ -2537,7 +2619,6 @@ impl<'a> Widget for Diary<'a> {
)
.wh(art_size)
.middle_of(state.content_align)
.graphics_for(state.content_align)
.color(Some(Color::Rgba(1.0, 1.0, 1.0, tweak!(1.0))))
.set(state.staff_render, ui);
// Top Left skills
@ -2885,7 +2966,7 @@ impl<'a> Widget for Diary<'a> {
events.push(Event::UnlockSkill(skill));
};
},
SelectedSkillTree::Sceptre => {
SelectedSkillTree::Weapon(ToolKind::Sceptre) => {
use skills::SceptreSkill::*;
// Sceptre
Image::new(
@ -2894,7 +2975,6 @@ impl<'a> Widget for Diary<'a> {
)
.wh(art_size)
.middle_of(state.content_align)
.graphics_for(state.content_align)
.color(Some(Color::Rgba(1.0, 1.0, 1.0, tweak!(1.0))))
.set(state.sceptre_render, ui);
// Top Left skills

View File

@ -65,6 +65,8 @@ image_ids! {
// Diary Window
diary_bg: "voxygen.element.misc_bg.diary_bg",
diary_frame: "voxygen.element.misc_bg.diary_frame",
diary_exp_bg: "voxygen.element.misc_bg.diary_exp_bg",
diary_exp_frame: "voxygen.element.misc_bg.diary_exp_frame",
// Skill Trees
sceptre: "voxygen.element.icons.sceptre",
@ -184,6 +186,7 @@ image_ids! {
// Other Icons/Art
skull: "voxygen.element.icons.skull",
skull_2: "voxygen.element.icons.skull_2",
indicator_bubble: "voxygen.element.icons.indicator_bubble",
fireplace: "voxygen.element.misc_bg.fireplace",
// Crosshair

View File

@ -99,6 +99,7 @@ const LOW_HP_COLOR: Color = Color::Rgba(0.93, 0.59, 0.03, 1.0);
const CRITICAL_HP_COLOR: Color = Color::Rgba(0.79, 0.19, 0.17, 1.0);
const STAMINA_COLOR: Color = Color::Rgba(0.29, 0.62, 0.75, 0.9);
const ENEMY_HP_COLOR: Color = Color::Rgba(0.93, 0.1, 0.29, 1.0);
const XP_COLOR: Color = Color::Rgba(0.59, 0.41, 0.67, 1.0);
//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);
@ -756,7 +757,7 @@ impl Hud {
group_menu: false,
mini_map: true,
settings_tab: SettingsTab::Interface,
skilltreetab: SelectedSkillTree::GeneralCombat,
skilltreetab: SelectedSkillTree::General,
social_tab: SocialTab::Online,
want_grab: true,
ingame: true,
@ -1057,6 +1058,111 @@ impl Hud {
}
}
}
// EXP Numbers
/*if let (Some(floaters), Some(stats)) = (
Some(&*ecs.read_resource::<crate::ecs::MyExpFloaterList>())
.map(|l| &l.floaters)
.filter(|f| !f.is_empty()),
stats.get(me),
) {
// TODO replace with setting
let batched_sct = false;
if batched_sct {
let number_speed = 50.0; // Number Speed for Cumulated EXP
let player_sct_bg_id = player_sct_bg_id_walker.next(
&mut self.ids.player_sct_bgs,
&mut ui_widgets.widget_id_generator(),
);
let player_sct_id = player_sct_id_walker.next(
&mut self.ids.player_scts,
&mut ui_widgets.widget_id_generator(),
);
// Sum xp change
let exp_change = floaters.iter().fold(0, |acc, f| f.exp_change + acc);
// Can't fail since we filtered out empty lists above
let (timer, rand) = floaters
.last()
.map(|f| (f.timer, f.rand))
.expect("Impossible");
// Increase font size based on fraction of maximum health
// "flashes" by having a larger size in the first 100ms
let font_size_xp = 30
+ ((exp_change.abs() as f32 / stats.exp.maximum() as f32).min(1.0)
* 50.0) as u32
+ if timer < 0.1 {
FLASH_MAX * (((1.0 - timer / 0.1) * 10.0) as u32)
} else {
0
};
let y = timer as f64 * number_speed; // Timer sets the widget offset
let fade = ((4.0 - timer as f32) * 0.25) + 0.2; // Timer sets text transparency
Text::new(&format!("{} Exp", exp_change))
.font_size(font_size_xp)
.font_id(self.fonts.cyri.conrod_id)
.color(Color::Rgba(0.0, 0.0, 0.0, fade))
.x_y(
ui_widgets.win_w * (0.5 * rand.0 as f64 - 0.25),
ui_widgets.win_h * (0.15 * rand.1 as f64) + y - 3.0,
)
.set(player_sct_bg_id, ui_widgets);
Text::new(&format!("{} Exp", exp_change))
.font_size(font_size_xp)
.font_id(self.fonts.cyri.conrod_id)
.color(Color::Rgba(0.59, 0.41, 0.67, fade))
.x_y(
ui_widgets.win_w * (0.5 * rand.0 as f64 - 0.25),
ui_widgets.win_h * (0.15 * rand.1 as f64) + y,
)
.set(player_sct_id, ui_widgets);
} else {
for floater in floaters {
let number_speed = 50.0; // Number Speed for Single EXP
let player_sct_bg_id = player_sct_bg_id_walker.next(
&mut self.ids.player_sct_bgs,
&mut ui_widgets.widget_id_generator(),
);
let player_sct_id = player_sct_id_walker.next(
&mut self.ids.player_scts,
&mut ui_widgets.widget_id_generator(),
);
// Increase font size based on fraction of maximum health
// "flashes" by having a larger size in the first 100ms
let font_size_xp = 30
+ ((floater.exp_change.abs() as f32 / stats.exp.maximum() as f32)
.min(1.0)
* 50.0) as u32
+ if floater.timer < 0.1 {
FLASH_MAX * (((1.0 - floater.timer / 0.1) * 10.0) as u32)
} else {
0
};
let y = floater.timer as f64 * number_speed; // Timer sets the widget offset
let fade = ((4.0 - floater.timer as f32) * 0.25) + 0.2; // Timer sets text transparency
Text::new(&format!("{} Exp", floater.exp_change))
.font_size(font_size_xp)
.font_id(self.fonts.cyri.conrod_id)
.color(Color::Rgba(0.0, 0.0, 0.0, fade))
.x_y(
ui_widgets.win_w * (0.5 * floater.rand.0 as f64 - 0.25),
ui_widgets.win_h * (0.15 * floater.rand.1 as f64) + y - 3.0,
)
.set(player_sct_bg_id, ui_widgets);
Text::new(&format!("{} Exp", floater.exp_change))
.font_size(font_size_xp)
.font_id(self.fonts.cyri.conrod_id)
.color(Color::Rgba(0.59, 0.41, 0.67, fade))
.x_y(
ui_widgets.win_w * (0.5 * floater.rand.0 as f64 - 0.25),
ui_widgets.win_h * (0.15 * floater.rand.1 as f64) + y,
)
.set(player_sct_id, ui_widgets);
}
}
}*/
}
// Pop speech bubbles
@ -2222,7 +2328,7 @@ impl Hud {
self.show.want_grab = true;
self.force_ungrab = false;
},
diary::Event::ChangeWeaponTree(tree_sel) => {
diary::Event::ChangeSkillTree(tree_sel) => {
self.show.open_skill_tree(tree_sel)
},
diary::Event::UnlockSkill(skill) => events.push(Event::UnlockSkill(skill)),

View File

@ -1,6 +1,8 @@
use super::{
img_ids::Imgs, DEFAULT_NPC, ENEMY_HP_COLOR, FACTION_COLOR, GROUP_COLOR, GROUP_MEMBER, HP_COLOR,
LOW_HP_COLOR, REGION_COLOR, SAY_COLOR, STAMINA_COLOR, TELL_COLOR, TEXT_BG, TEXT_COLOR,
img_ids::Imgs, DEFAULT_NPC, FACTION_COLOR, GROUP_COLOR, GROUP_MEMBER, HP_COLOR, LOW_HP_COLOR,
QUALITY_ARTIFACT, QUALITY_COMMON, QUALITY_DEBUG, QUALITY_EPIC, QUALITY_HIGH, QUALITY_LEGENDARY,
QUALITY_LOW, QUALITY_MODERATE, REGION_COLOR, SAY_COLOR, STAMINA_COLOR, TELL_COLOR, TEXT_BG,
TEXT_COLOR, XP_COLOR, ENEMY_HP_COLOR
};
use crate::{
hud::get_buff_info,
@ -17,6 +19,8 @@ use conrod_core::{
};
const MAX_BUBBLE_WIDTH: f64 = 250.0;
use inline_tweak::*;
widget_ids! {
struct Ids {
// Speech bubble
@ -119,7 +123,8 @@ impl<'a> Ingameable for Overhead<'a> {
// - 2 Text::new for name
//
// If HP Info is shown:
// - 1 for level: either Text or Image
// - 1 for level: either Text or Image <-- Not used currently, will be replaced
// by something else
// - 3 for HP + fg + bg
// - 1 for HP text
// - If there's mana
@ -365,9 +370,34 @@ impl<'a> Widget for Overhead<'a> {
.color(Some(Color::Rgba(1.0, 1.0, 1.0, 0.99)))
.parent(id)
.set(state.ids.health_bar_fg, ui);
// TODO: Add strength comparison here, this is just an example
// Factors to take into account:
// Maximum HP
// Protection
// Mainhand Weapon DPS
// "Boss Factor" (?)
// For players: Highest skilltree rank
let indicator_col = match health_max as u32 {
0..=50 => QUALITY_LOW,
51..=100 => QUALITY_COMMON,
101..=150 => QUALITY_MODERATE,
151..=200 => QUALITY_HIGH,
201..=250 => QUALITY_EPIC,
251..=300 => QUALITY_LEGENDARY,
301..=350 => QUALITY_ARTIFACT,
351..=9999 => QUALITY_DEBUG,
_ => XP_COLOR,
};
Image::new(self.imgs.indicator_bubble)
.w_h(5.0 * BARSIZE, 5.0 * BARSIZE)
.x_y(tweak!(-37.0) * BARSIZE, MANA_BAR_Y + tweak!(7.5))
.color(Some(indicator_col))
.parent(id)
.set(state.ids.level, ui);
}
}
// Speech bubble
if let Some(bubble) = self.bubble {
let dark_mode = self.settings.speech_bubble_dark_mode;