diff --git a/assets/voxygen/element/buttons/slot_skilltree.png b/assets/voxygen/element/buttons/slot_skilltree.png new file mode 100644 index 0000000000..d14ffceaec --- /dev/null +++ b/assets/voxygen/element/buttons/slot_skilltree.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fd419cde98ff5cca69ae489d65562431ba244f00607651d6a6b61d0f264a1c72 +size 2034 diff --git a/assets/voxygen/element/misc_bg/level_down.png b/assets/voxygen/element/misc_bg/level_down.png deleted file mode 100644 index bd773e7862..0000000000 --- a/assets/voxygen/element/misc_bg/level_down.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3faab75ba08e40084ca98966999883db632bf2e7ade80802ef5aadbf9c47d51d -size 256 diff --git a/assets/voxygen/element/misc_bg/level_up.png b/assets/voxygen/element/misc_bg/level_up.png index 90fe596915..86dbac49e8 100644 --- a/assets/voxygen/element/misc_bg/level_up.png +++ b/assets/voxygen/element/misc_bg/level_up.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1939158216f4b31a6769615efdd958c6eb7f98c42678e2423cde8c160d349188 -size 235 +oid sha256:93d2b33df712b59536784f1a0371d67c7b20d39b0aa4a7afe02a264afde6cc93 +size 10187 diff --git a/assets/voxygen/i18n/de_DE/_manifest.ron b/assets/voxygen/i18n/de_DE/_manifest.ron index 02f81f3753..f351c8a52d 100644 --- a/assets/voxygen/i18n/de_DE/_manifest.ron +++ b/assets/voxygen/i18n/de_DE/_manifest.ron @@ -100,6 +100,7 @@ "common.weapons.bow": "Bogen", "common.weapons.hammer": "Hammer", "common.weapons.sceptre": "Druiden Szepter", + "common.weapons.general": "Kampf", /// End Common section @@ -204,7 +205,8 @@ https://veloren.net/account/. // SCT outputs "hud.sct.experience": "{amount} Erf", - "hud.sct.block": "GEBLOCKT", + "hud.sct.block": "GEBLOCKT", + "hud.rank_up": "Neuer Rang", /// Respawn message "hud.press_key_to_respawn": r#"Drückt {key} um am letzten Lagerfeuer wiederbelebt zu werden."#, diff --git a/assets/voxygen/i18n/en/common.ron b/assets/voxygen/i18n/en/common.ron index 987228462f..0670c3615f 100644 --- a/assets/voxygen/i18n/en/common.ron +++ b/assets/voxygen/i18n/en/common.ron @@ -62,6 +62,7 @@ Is the client up to date?"#, "common.weapons.staff": "Staff", "common.weapons.bow": "Bow", "common.weapons.hammer": "Hammer", + "common.weapons.general": "General Combat", "common.weapons.sceptre": "Healing Sceptre", "common.rand_appearance": "Random appearance and name", }, diff --git a/assets/voxygen/i18n/en/hud/sct.ron b/assets/voxygen/i18n/en/hud/sct.ron index a3a3cfca33..d8ed744fd1 100644 --- a/assets/voxygen/i18n/en/hud/sct.ron +++ b/assets/voxygen/i18n/en/hud/sct.ron @@ -5,7 +5,8 @@ string_map: { // SCT outputs "hud.sct.experience": "{amount} Exp", - "hud.sct.block": "BLOCKED", + "hud.sct.block": "BLOCKED", + "hud.rank_up": "New Rank", }, diff --git a/common/src/comp/skills.rs b/common/src/comp/skills.rs index 0d812662d6..41f32ac140 100644 --- a/common/src/comp/skills.rs +++ b/common/src/comp/skills.rs @@ -544,11 +544,8 @@ impl Skill { /// Returns the cost in skill points of unlocking a particular skill pub fn skill_cost(self, level: Level) -> u16 { - use Skill::*; - match self { - General(GeneralSkill::HealthIncrease) => 1, - _ => level.unwrap_or(1), - } + // TODO: Better balance the costs later + level.unwrap_or(1) } /// Returns the maximum level a skill can reach, returns None if the skill diff --git a/common/src/outcome.rs b/common/src/outcome.rs index d57554bdd3..109ca557c2 100644 --- a/common/src/outcome.rs +++ b/common/src/outcome.rs @@ -33,6 +33,11 @@ pub enum Outcome { uid: Uid, exp: i32, }, + SkillPointGain { + uid: Uid, + skill_tree: comp::skills::SkillGroupType, + total_points: u16, + }, } impl Outcome { @@ -43,6 +48,7 @@ impl Outcome { Outcome::LevelUp { pos } => Some(*pos), Outcome::Beam { pos, .. } => Some(*pos), Outcome::ExpChange { .. } => None, + Outcome::SkillPointGain { .. } => None, } } } diff --git a/common/sys/src/stats.rs b/common/sys/src/stats.rs index b6feb7df45..af5ca5ef5f 100644 --- a/common/sys/src/stats.rs +++ b/common/sys/src/stats.rs @@ -5,11 +5,13 @@ use common::{ }, event::{EventBus, ServerEvent}, metrics::SysMetrics, + outcome::Outcome, resources::DeltaTime, span, + uid::Uid, }; use hashbrown::HashSet; -use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, WriteStorage}; +use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, Write, WriteStorage}; const ENERGY_REGEN_ACCEL: f32 = 10.0; @@ -26,6 +28,8 @@ impl<'a> System<'a> for Sys { WriteStorage<'a, Stats>, WriteStorage<'a, Health>, WriteStorage<'a, Energy>, + ReadStorage<'a, Uid>, + Write<'a, Vec>, ); fn run( @@ -39,6 +43,8 @@ impl<'a> System<'a> for Sys { mut stats, mut healths, mut energies, + uids, + mut outcomes, ): Self::SystemData, ) { let start_time = std::time::Instant::now(); @@ -53,8 +59,9 @@ impl<'a> System<'a> for Sys { healths.set_event_emission(true); // Update stats - for (entity, mut stats, mut health) in ( + for (entity, uid, mut stats, mut health) in ( &entities, + &uids, &mut stats.restrict_mut(), &mut healths.restrict_mut(), ) @@ -91,6 +98,11 @@ impl<'a> System<'a> for Sys { stat.skill_set .change_experience(skill_group, -(skill_group.skill_point_cost() as i32)); stat.skill_set.add_skill_points(skill_group, 1); + outcomes.push(Outcome::SkillPointGain { + uid: *uid, + skill_tree: skill_group, + total_points: stat.skill_set.get_earned_sp(skill_group), + }); } } } diff --git a/voxygen/src/audio/sfx/mod.rs b/voxygen/src/audio/sfx/mod.rs index edafdd363e..a93f9afc68 100644 --- a/voxygen/src/audio/sfx/mod.rs +++ b/voxygen/src/audio/sfx/mod.rs @@ -358,7 +358,7 @@ impl SfxMgr { audio.play_sfx(file_ref, *pos, None); } }, - Outcome::ExpChange { .. } => {}, + _ => {}, } } diff --git a/voxygen/src/hud/img_ids.rs b/voxygen/src/hud/img_ids.rs index fe498767a8..0dc0070fb6 100644 --- a/voxygen/src/hud/img_ids.rs +++ b/voxygen/src/hud/img_ids.rs @@ -69,6 +69,7 @@ image_ids! { diary_exp_frame: "voxygen.element.misc_bg.diary_exp_frame", // Skill Trees + slot_skills: "voxygen.element.buttons.slot_skilltree", swords_crossed: "voxygen.element.icons.swords_crossed", sceptre: "voxygen.element.icons.sceptre", sword: "voxygen.element.icons.sword", @@ -179,7 +180,6 @@ image_ids! { // Skillbar level_up: "voxygen.element.misc_bg.level_up", - level_down:"voxygen.element.misc_bg.level_down", bar_content: "voxygen.element.skillbar.bar_content", skillbar_bg: "voxygen.element.skillbar.bg", skillbar_frame: "voxygen.element.skillbar.frame", diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 4f2e1f56d0..6d17cca5f2 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -56,11 +56,12 @@ use crate::{ GlobalState, }; use client::Client; + use common::{ comp, comp::{ - item::{ItemDesc, Quality}, - skills::Skill, + item::{tool::ToolKind, ItemDesc, Quality}, + skills::{Skill, SkillGroupType}, BuffKind, }, outcome::Outcome, @@ -77,6 +78,7 @@ use conrod_core::{ widget_ids, Color, Colorable, Labelable, Positionable, Sizeable, Widget, }; use hashbrown::HashMap; +use inline_tweak::*; use rand::Rng; use specs::{Join, WorldExt}; use std::{ @@ -177,6 +179,13 @@ widget_ids! { // SCT player_scts[], player_sct_bgs[], + player_rank_up, + player_rank_up_txt_number, + player_rank_up_txt_0, + player_rank_up_txt_0_bg, + player_rank_up_txt_1, + player_rank_up_txt_1_bg, + player_rank_up_icon, sct_exp_bgs[], sct_exps[], sct_lvl_bg, @@ -293,6 +302,13 @@ pub struct ExpFloater { pub rand_offset: (f32, f32), } +pub struct SkillPointGain { + pub owner: Uid, + pub skill_tree: SkillGroupType, + pub total_points: u16, + pub timer: f32, +} + pub struct DebugInfo { pub tps: f64, pub frame_time: Duration, @@ -690,6 +706,7 @@ pub struct Hud { events: Vec, crosshair_opacity: f32, exp_floaters: Vec, + skill_point_displays: Vec, } impl Hud { @@ -789,6 +806,7 @@ impl Hud { events: Vec::new(), crosshair_opacity: 0.0, exp_floaters: Vec::new(), + skill_point_displays: Vec::new(), } } @@ -868,8 +886,7 @@ impl Hud { .graphics_for(ui_widgets.window) .color(Some(Color::Rgba(0.0, 0.0, 0.0, 1.0))) .set(self.ids.death_bg, ui_widgets); - } - // Crosshair + } // Crosshair let show_crosshair = (info.is_aiming || info.is_first_person) && !health.is_dead; self.crosshair_opacity = Lerp::lerp( self.crosshair_opacity, @@ -1084,17 +1101,16 @@ impl Hud { ); // 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 as f32 / 300.0).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 font_size_xp = + 30 + ((floater.exp_change as f32 / 300.0).min(1.0) * 50.0) as u32; 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 - + //let fade = ((4.0 - floater.timer as f32) * 0.25) + 0.2; // Timer sets + // text transparency + let fade = if floater.timer < 1.0 { + floater.timer as f32 + } else { + 1.0 + }; Text::new(&format!("{} Exp", floater.exp_change)) .font_size(font_size_xp) .font_id(self.fonts.cyri.conrod_id) @@ -1116,6 +1132,90 @@ impl Hud { floater.timer -= dt.as_secs_f32(); } } + // Skill points + self.skill_point_displays.retain(|d| d.timer > 0_f32); + if let Some(uid) = uids.get(me) { + if let Some(display) = self + .skill_point_displays + .iter_mut() + .find(|d| d.owner == *uid) + { + let fade = if display.timer < 1.0 { + display.timer as f32 + } else { + 1.0 + }; + // Background image + Image::new(self.imgs.level_up) + .w_h(328.0, 126.0) + .mid_top_with_margin_on(ui_widgets.window, tweak!(300.0)) + .graphics_for(ui_widgets.window) + .color(Some(Color::Rgba(1.0, 1.0, 1.0, fade))) + .set(self.ids.player_rank_up, ui_widgets); + // Rank Number + let rank = display.total_points; + Text::new(&format!("{}", rank)) + .font_size(tweak!(20)) + .font_id(self.fonts.cyri.conrod_id) + .color(Color::Rgba(1.0, 1.0, 1.0, fade)) + .mid_top_with_margin_on(self.ids.player_rank_up, tweak!(8.0)) + .set(self.ids.player_rank_up_txt_number, ui_widgets); + // Static "New Rank!" text + Text::new(&i18n.get("hud.rank_up")) + .font_size(tweak!(40)) + .font_id(self.fonts.cyri.conrod_id) + .color(Color::Rgba(0.0, 0.0, 0.0, fade)) + .mid_bottom_with_margin_on(self.ids.player_rank_up, tweak!(20.0)) + .set(self.ids.player_rank_up_txt_0_bg, ui_widgets); + Text::new(&i18n.get("hud.rank_up")) + .font_size(tweak!(40)) + .font_id(self.fonts.cyri.conrod_id) + .color(Color::Rgba(1.0, 1.0, 1.0, fade)) + .bottom_left_with_margins_on(self.ids.player_rank_up_txt_0_bg, 2.0, 2.0) + .set(self.ids.player_rank_up_txt_0, ui_widgets); + // Variable skilltree text + let skill = match display.skill_tree { + General => &i18n.get("common.weapons.general"), + Weapon(ToolKind::Hammer) => &i18n.get("common.weapons.hammer"), + Weapon(ToolKind::Axe) => &i18n.get("common.weapons.axe"), + Weapon(ToolKind::Sword) => &i18n.get("common.weapons.sword"), + Weapon(ToolKind::Sceptre) => &i18n.get("common.weapons.sceptre"), + Weapon(ToolKind::Bow) => &i18n.get("common.weapons.bow"), + Weapon(ToolKind::Staff) => &i18n.get("common.weapons.staff"), + _ => "Unknown", + }; + Text::new(skill) + .font_size(tweak!(20)) + .font_id(self.fonts.cyri.conrod_id) + .color(Color::Rgba(0.0, 0.0, 0.0, fade)) + .mid_top_with_margin_on(self.ids.player_rank_up, tweak!(45.0)) + .set(self.ids.player_rank_up_txt_1_bg, ui_widgets); + Text::new(skill) + .font_size(tweak!(20)) + .font_id(self.fonts.cyri.conrod_id) + .color(Color::Rgba(1.0, 1.0, 1.0, fade)) + .bottom_left_with_margins_on(self.ids.player_rank_up_txt_1_bg, 2.0, 2.0) + .set(self.ids.player_rank_up_txt_1, ui_widgets); + // Variable skilltree icon + use crate::hud::SkillGroupType::{General, Weapon}; + Image::new(match display.skill_tree { + General => self.imgs.swords_crossed, + Weapon(ToolKind::Hammer) => self.imgs.hammer, + Weapon(ToolKind::Axe) => self.imgs.axe, + Weapon(ToolKind::Sword) => self.imgs.sword, + Weapon(ToolKind::Sceptre) => self.imgs.sceptre, + Weapon(ToolKind::Bow) => self.imgs.bow, + Weapon(ToolKind::Staff) => self.imgs.staff, + _ => self.imgs.swords_crossed, + }) + .w_h(tweak!(20.0), tweak!(20.0)) + .left_from(self.ids.player_rank_up_txt_1_bg, tweak!(5.0)) + .color(Some(Color::Rgba(1.0, 1.0, 1.0, fade))) + .set(self.ids.player_rank_up_icon, ui_widgets); + + display.timer -= dt.as_secs_f32(); + } + } } // Pop speech bubbles @@ -2782,6 +2882,16 @@ impl Hud { timer: 4.0, rand_offset: rand::thread_rng().gen::<(f32, f32)>(), }), + Outcome::SkillPointGain { + uid, + skill_tree, + total_points, + } => self.skill_point_displays.push(SkillPointGain { + owner: *uid, + skill_tree: *skill_tree, + total_points: *total_points, + timer: 5.0, + }), _ => {}, } }