From 51c0bd765f2e9f916697e16e61afa0591c70738a Mon Sep 17 00:00:00 2001 From: Sam Date: Sat, 2 Jan 2021 15:06:33 -0500 Subject: [PATCH] Database support for refunding skills. Nonfunctional xp floaters, squash when working. more icons, lock visuals --- assets/voxygen/element/icons/lock.png | 3 + .../voxygen/element/icons/swords_crossed.png | 3 + common/src/event.rs | 1 - common/src/outcome.rs | 7 +- server/src/events/entity_manipulation.rs | 47 +-- server/src/events/mod.rs | 3 +- server/src/persistence/character.rs | 15 + voxygen/src/audio/sfx/mod.rs | 1 + voxygen/src/hud/diary.rs | 383 +++++++++++------- voxygen/src/hud/img_ids.rs | 2 + voxygen/src/hud/mod.rs | 100 ++--- voxygen/src/menu/char_selection/ui/mod.rs | 4 +- 12 files changed, 315 insertions(+), 254 deletions(-) create mode 100644 assets/voxygen/element/icons/lock.png create mode 100644 assets/voxygen/element/icons/swords_crossed.png diff --git a/assets/voxygen/element/icons/lock.png b/assets/voxygen/element/icons/lock.png new file mode 100644 index 0000000000..d299acf183 --- /dev/null +++ b/assets/voxygen/element/icons/lock.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1f5168a25396796d3e7cca178e722f3b3ebb8503ab44ca03362fa8b616599958 +size 2438 diff --git a/assets/voxygen/element/icons/swords_crossed.png b/assets/voxygen/element/icons/swords_crossed.png new file mode 100644 index 0000000000..c1d791e6c6 --- /dev/null +++ b/assets/voxygen/element/icons/swords_crossed.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:79eb6661aa3e26aabd7b08540562cc5d290eb1d9dcd268e6f6233875b0ed7f7c +size 2163 diff --git a/common/src/event.rs b/common/src/event.rs index a4f13a97b8..cb9aa0d858 100644 --- a/common/src/event.rs +++ b/common/src/event.rs @@ -76,7 +76,6 @@ pub enum ServerEvent { Mount(EcsEntity, EcsEntity), Unmount(EcsEntity), Possess(Uid, Uid), - LevelUp(EcsEntity, u32), /// Inserts default components for a character when loading into the game InitCharacterData { entity: EcsEntity, diff --git a/common/src/outcome.rs b/common/src/outcome.rs index 97518b0a49..d57554bdd3 100644 --- a/common/src/outcome.rs +++ b/common/src/outcome.rs @@ -1,4 +1,4 @@ -use crate::comp; +use crate::{comp, uid::Uid}; use comp::item::Reagent; use serde::{Deserialize, Serialize}; use vek::*; @@ -29,6 +29,10 @@ pub enum Outcome { pos: Vec3, heal: bool, }, + ExpChange { + uid: Uid, + exp: i32, + }, } impl Outcome { @@ -38,6 +42,7 @@ impl Outcome { Outcome::ProjectileShot { pos, .. } => Some(*pos), Outcome::LevelUp { pos } => Some(*pos), Outcome::Beam { pos, .. } => Some(*pos), + Outcome::ExpChange { .. } => None, } } } diff --git a/server/src/events/entity_manipulation.rs b/server/src/events/entity_manipulation.rs index 3e4a6b5629..e296de6559 100644 --- a/server/src/events/entity_manipulation.rs +++ b/server/src/events/entity_manipulation.rs @@ -23,7 +23,7 @@ use common::{ Damage, DamageSource, Explosion, GroupTarget, RadiusEffect, }; use common_net::{ - msg::{PlayerListUpdate, ServerGeneral}, + msg::ServerGeneral, sync::WorldSyncExt, }; use common_sys::state::BlockChange; @@ -218,12 +218,12 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc num_not_pets_in_range += 1; } - entity + (entity, uid) }) .collect::>(); let exp = exp_reward / (num_not_pets_in_range as f32 + ATTACKER_EXP_WEIGHT); exp_reward = exp * ATTACKER_EXP_WEIGHT; - members_in_range.into_iter().for_each(|e| { + members_in_range.into_iter().for_each(|(e, uid)| { let (main_tool_kind, second_tool_kind) = if let Some(inventory) = state.ecs().read_storage::().get(e) { combat::get_weapons(inventory) @@ -251,11 +251,14 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc } } let num_pools = xp_pools.len() as f32; + let exp = (exp / num_pools).ceil() as i32; for pool in xp_pools.drain() { - stats - .skill_set - .change_experience(pool, (exp / num_pools).ceil() as i32); + stats.skill_set.change_experience(pool, exp); } + state + .ecs() + .write_resource::>() + .push(Outcome::ExpChange { uid: *uid, exp }); } }); } @@ -266,7 +269,9 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc } else { (None, None) }; - if let Some(mut attacker_stats) = stats.get_mut(attacker) { + if let (Some(mut attacker_stats), Some(attacker_uid)) = + (stats.get_mut(attacker), uids.get(attacker)) + { // TODO: Discuss whether we should give EXP by Player // Killing or not. // attacker_stats.exp.change_by(exp_reward.ceil() as i64); @@ -289,11 +294,17 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc } } let num_pools = xp_pools.len() as f32; + let exp = (exp_reward / num_pools).ceil() as i32; for pool in xp_pools.drain() { - attacker_stats - .skill_set - .change_experience(pool, (exp_reward / num_pools).ceil() as i32); + attacker_stats.skill_set.change_experience(pool, exp); } + state + .ecs() + .write_resource::>() + .push(Outcome::ExpChange { + uid: *attacker_uid, + exp, + }); } })(); @@ -737,22 +748,6 @@ pub fn handle_explosion( } } -pub fn handle_level_up(server: &mut Server, entity: EcsEntity, new_level: u32) { - let ecs = &server.state.ecs(); - if let Some((uid, pos)) = ecs - .read_storage::() - .get(entity) - .copied() - .zip(ecs.read_storage::().get(entity).map(|p| p.0)) - { - ecs.write_resource::>() - .push(Outcome::LevelUp { pos }); - server.state.notify_players(ServerGeneral::PlayerListUpdate( - PlayerListUpdate::LevelChange(uid, new_level), - )); - } -} - pub fn handle_aura(server: &mut Server, entity: EcsEntity, aura_change: aura::AuraChange) { let ecs = &server.state.ecs(); let mut auras_all = ecs.write_storage::(); diff --git a/server/src/events/mod.rs b/server/src/events/mod.rs index 99c0700e82..cd747048b9 100644 --- a/server/src/events/mod.rs +++ b/server/src/events/mod.rs @@ -9,7 +9,7 @@ use entity_creation::{ }; use entity_manipulation::{ handle_aura, handle_buff, handle_damage, handle_delete, handle_destroy, handle_energy_change, - handle_explosion, handle_knockback, handle_land_on_ground, handle_level_up, handle_respawn, + handle_explosion, handle_knockback, handle_land_on_ground, handle_respawn, }; use group_manip::handle_group; use interaction::{handle_lantern, handle_mount, handle_possess, handle_unmount}; @@ -105,7 +105,6 @@ impl Server { ServerEvent::UpdateCharacterData { entity, components } => { handle_loaded_character_data(self, entity, components); }, - ServerEvent::LevelUp(entity, new_level) => handle_level_up(self, entity, new_level), ServerEvent::ExitIngame { entity } => handle_exit_ingame(self, entity), ServerEvent::CreateNpc { pos, diff --git a/server/src/persistence/character.rs b/server/src/persistence/character.rs index 9151e909f6..7b935267a7 100644 --- a/server/src/persistence/character.rs +++ b/server/src/persistence/character.rs @@ -606,6 +606,21 @@ pub fn update( let db_skills = convert_skills_to_database(char_id, char_skill_set.skills); + let delete_count = diesel::delete( + schema::skill::dsl::skill.filter( + schema::skill::dsl::character_id.eq(char_id).and( + schema::skill::dsl::skill_type.ne_all( + db_skills + .iter() + .map(|x| x.skill_type.clone()) + .collect::>(), + ), + ), + ), + ) + .execute(&*connection)?; + trace!("Deleted {} skills", delete_count); + diesel::replace_into(schema::skill::dsl::skill) .values(&db_skills) .execute(&*connection)?; diff --git a/voxygen/src/audio/sfx/mod.rs b/voxygen/src/audio/sfx/mod.rs index de1e1bdc26..edafdd363e 100644 --- a/voxygen/src/audio/sfx/mod.rs +++ b/voxygen/src/audio/sfx/mod.rs @@ -358,6 +358,7 @@ impl SfxMgr { audio.play_sfx(file_ref, *pos, None); } }, + Outcome::ExpChange { .. } => {}, } } diff --git a/voxygen/src/hud/diary.rs b/voxygen/src/hud/diary.rs index 1f33886ed9..b6cecdf06b 100644 --- a/voxygen/src/hud/diary.rs +++ b/voxygen/src/hud/diary.rs @@ -35,6 +35,8 @@ widget_ids! { exp_bar_content, exp_bar_rank, exp_bar_txt, + tree_title_txt, + lock_imgs[], available_pts_txt, weapon_imgs[], weapon_btns[], @@ -216,7 +218,7 @@ impl<'a> Diary<'a> { pub type SelectedSkillTree = skills::SkillGroupType; -const WEAPONS: [&str; 7] = [ +const TREES: [&str; 7] = [ "General Combat", "Sword", "Hammer", @@ -317,168 +319,229 @@ impl<'a> Widget for Diary<'a> { // Skill Tree Selection state.update(|s| { s.weapon_btns - .resize(WEAPONS.len(), &mut ui.widget_id_generator()) + .resize(TREES.len(), &mut ui.widget_id_generator()) }); state.update(|s| { s.weapon_imgs - .resize(WEAPONS.len(), &mut ui.widget_id_generator()) + .resize(TREES.len(), &mut ui.widget_id_generator()) }); - for i in WEAPONS.iter().copied().enumerate() { + state.update(|s| { + s.lock_imgs + .resize(TREES.len(), &mut ui.widget_id_generator()) + }); + for i in TREES.iter().copied().enumerate() { + let locked = match i.1 { + "General Combat" => false, + "Sword" => true, + "Hammer" => true, + "Axe" => true, + "Sceptre" => true, + "Bow" => true, + "Fire Staff" => true, + _ => false, + }; + // Background weapon image - let img = Image::new(match i.1 { - "General Combat" => self.imgs.not_found, - "Sword" => self.imgs.sword, - "Hammer" => self.imgs.hammer, - "Axe" => self.imgs.axe, - "Sceptre" => self.imgs.sceptre, - "Bow" => self.imgs.bow, - "Fire Staff" => self.imgs.staff, - _ => self.imgs.nothing, - }); + let img = Image::new( + match i.1 { + "General Combat" => self.imgs.swords_crossed, + "Sword" => self.imgs.sword, + "Hammer" => self.imgs.hammer, + "Axe" => self.imgs.axe, + "Sceptre" => self.imgs.sceptre, + "Bow" => self.imgs.bow, + "Fire Staff" => self.imgs.staff, + _ => self.imgs.nothing, + } + ); let img = if i.0 == 0 { img.top_left_with_margins_on(state.content_align, tweak!(10.0), tweak!(5.0)) } else { img.down_from(state.weapon_btns[i.0 - 1], tweak!(5.0)) }; - + let tooltip_txt = if !locked {""} else {"Not yet unlocked"}; img.w_h(tweak!(50.0), tweak!(50.0)) .set(state.weapon_imgs[i.0], ui); + // Lock Image + if locked {Image::new(self.imgs.lock) + .w_h(50.0, 50.0) + .middle_of(state.weapon_imgs[i.0]) + .graphics_for(state.weapon_imgs[i.0]) + .color(Some(Color::Rgba(1.0, 1.0, 1.0, tweak!(0.8)))) + .set(state.lock_imgs[i.0], ui);} // Weapon icons - if Button::image(match i.1 { - "General Combat" => match sel_tab { - SelectedSkillTree::General => self.imgs.wpn_icon_border_pressed, - _ => self.imgs.wpn_icon_border, - }, - "Sword" => match sel_tab { - SelectedSkillTree::Weapon(ToolKind::Sword) => self.imgs.wpn_icon_border_pressed, - _ => self.imgs.wpn_icon_border, - }, - "Hammer" => match sel_tab { - SelectedSkillTree::Weapon(ToolKind::Hammer) => { - self.imgs.wpn_icon_border_pressed + if Button::image( + match i.1 { + "General Combat" => match sel_tab { + SelectedSkillTree::General => self.imgs.wpn_icon_border_pressed, + _ => self.imgs.wpn_icon_border, + }, + "Sword" => match sel_tab { + SelectedSkillTree::Weapon(ToolKind::Sword) => { + self.imgs.wpn_icon_border_pressed + }, + _ => self.imgs.wpn_icon_border, + }, + "Hammer" => match sel_tab { + SelectedSkillTree::Weapon(ToolKind::Hammer) => { + self.imgs.wpn_icon_border_pressed + }, + _ => self.imgs.wpn_icon_border, + }, + "Axe" => match sel_tab { + SelectedSkillTree::Weapon(ToolKind::Axe) => { + self.imgs.wpn_icon_border_pressed + }, + _ => self.imgs.wpn_icon_border, + }, + "Sceptre" => match sel_tab { + SelectedSkillTree::Weapon(ToolKind::Sceptre) => { + self.imgs.wpn_icon_border_pressed + }, + _ => self.imgs.wpn_icon_border, + }, + "Bow" => match sel_tab { + SelectedSkillTree::Weapon(ToolKind::Bow) => { + self.imgs.wpn_icon_border_pressed + }, + _ => self.imgs.wpn_icon_border, + }, + "Fire Staff" => match sel_tab { + SelectedSkillTree::Weapon(ToolKind::Staff) => { + self.imgs.wpn_icon_border_pressed + }, + _ => self.imgs.wpn_icon_border, }, _ => self.imgs.wpn_icon_border, - }, - "Axe" => match sel_tab { - SelectedSkillTree::Weapon(ToolKind::Axe) => self.imgs.wpn_icon_border_pressed, - _ => self.imgs.wpn_icon_border, - }, - "Sceptre" => match sel_tab { - SelectedSkillTree::Weapon(ToolKind::Sceptre) => { - self.imgs.wpn_icon_border_pressed - }, - _ => self.imgs.wpn_icon_border, - }, - "Bow" => match sel_tab { - SelectedSkillTree::Weapon(ToolKind::Bow) => self.imgs.wpn_icon_border_pressed, - _ => self.imgs.wpn_icon_border, - }, - "Fire Staff" => match sel_tab { - SelectedSkillTree::Weapon(ToolKind::Staff) => self.imgs.wpn_icon_border_pressed, - _ => self.imgs.wpn_icon_border, - }, - _ => self.imgs.wpn_icon_border, - }) + } + ) .w_h(tweak!(50.0), tweak!(50.0)) - .hover_image(match i.1 { - "General Combat" => match sel_tab { - SelectedSkillTree::General => self.imgs.wpn_icon_border_pressed, - _ => self.imgs.wpn_icon_border_mo, - }, - "Sword" => match sel_tab { - SelectedSkillTree::Weapon(ToolKind::Sword) => self.imgs.wpn_icon_border_pressed, - _ => self.imgs.wpn_icon_border_mo, - }, - "Hammer" => match sel_tab { - SelectedSkillTree::Weapon(ToolKind::Hammer) => { - self.imgs.wpn_icon_border_pressed + .hover_image( + match i.1 { + "General Combat" => match sel_tab { + SelectedSkillTree::General => self.imgs.wpn_icon_border_pressed, + _ => self.imgs.wpn_icon_border_mo, }, - _ => self.imgs.wpn_icon_border_mo, - }, - "Axe" => match sel_tab { - SelectedSkillTree::Weapon(ToolKind::Axe) => self.imgs.wpn_icon_border_pressed, - _ => self.imgs.wpn_icon_border_mo, - }, - "Sceptre" => match sel_tab { - SelectedSkillTree::Weapon(ToolKind::Sceptre) => { - self.imgs.wpn_icon_border_pressed + "Sword" => match sel_tab { + SelectedSkillTree::Weapon(ToolKind::Sword) => { + self.imgs.wpn_icon_border_pressed + }, + _ => self.imgs.wpn_icon_border_mo, }, - _ => self.imgs.wpn_icon_border_mo, - }, - "Bow" => match sel_tab { - SelectedSkillTree::Weapon(ToolKind::Bow) => self.imgs.wpn_icon_border_pressed, - _ => self.imgs.wpn_icon_border_mo, - }, - "Fire Staff" => match sel_tab { - 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::General => self.imgs.wpn_icon_border_pressed, - _ => self.imgs.wpn_icon_border_press, - }, - "Sword" => match sel_tab { - SelectedSkillTree::Weapon(ToolKind::Sword) => self.imgs.wpn_icon_border_pressed, - _ => self.imgs.wpn_icon_border_press, - }, - "Hammer" => match sel_tab { - SelectedSkillTree::Weapon(ToolKind::Hammer) => { - self.imgs.wpn_icon_border_pressed + "Hammer" => match sel_tab { + SelectedSkillTree::Weapon(ToolKind::Hammer) => { + self.imgs.wpn_icon_border_pressed + }, + _ => self.imgs.wpn_icon_border_mo, }, - _ => self.imgs.wpn_icon_border_press, - }, - "Axe" => match sel_tab { - SelectedSkillTree::Weapon(ToolKind::Axe) => self.imgs.wpn_icon_border_pressed, - _ => self.imgs.wpn_icon_border_press, - }, - "Sceptre" => match sel_tab { - SelectedSkillTree::Weapon(ToolKind::Sceptre) => { - self.imgs.wpn_icon_border_pressed + "Axe" => match sel_tab { + SelectedSkillTree::Weapon(ToolKind::Axe) => { + self.imgs.wpn_icon_border_pressed + }, + _ => self.imgs.wpn_icon_border_mo, }, - _ => self.imgs.wpn_icon_border_press, - }, - "Bow" => match sel_tab { - SelectedSkillTree::Weapon(ToolKind::Bow) => self.imgs.wpn_icon_border_pressed, - _ => self.imgs.wpn_icon_border_press, - }, - "Fire Staff" => match sel_tab { - SelectedSkillTree::Weapon(ToolKind::Staff) => self.imgs.wpn_icon_border_pressed, - _ => self.imgs.wpn_icon_border_press, - }, - _ => self.imgs.wpn_icon_border, - }) + "Sceptre" => match sel_tab { + SelectedSkillTree::Weapon(ToolKind::Sceptre) => { + self.imgs.wpn_icon_border_pressed + }, + _ => self.imgs.wpn_icon_border_mo, + }, + "Bow" => match sel_tab { + SelectedSkillTree::Weapon(ToolKind::Bow) => { + self.imgs.wpn_icon_border_pressed + }, + _ => self.imgs.wpn_icon_border_mo, + }, + "Fire Staff" => match sel_tab { + 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::General => self.imgs.wpn_icon_border_pressed, + _ => self.imgs.wpn_icon_border_press, + }, + "Sword" => match sel_tab { + SelectedSkillTree::Weapon(ToolKind::Sword) => { + self.imgs.wpn_icon_border_pressed + }, + _ => self.imgs.wpn_icon_border_press, + }, + "Hammer" => match sel_tab { + SelectedSkillTree::Weapon(ToolKind::Hammer) => { + self.imgs.wpn_icon_border_pressed + }, + _ => self.imgs.wpn_icon_border_press, + }, + "Axe" => match sel_tab { + SelectedSkillTree::Weapon(ToolKind::Axe) => { + self.imgs.wpn_icon_border_pressed + }, + _ => self.imgs.wpn_icon_border_press, + }, + "Sceptre" => match sel_tab { + SelectedSkillTree::Weapon(ToolKind::Sceptre) => { + self.imgs.wpn_icon_border_pressed + }, + _ => self.imgs.wpn_icon_border_press, + }, + "Bow" => match sel_tab { + SelectedSkillTree::Weapon(ToolKind::Bow) => { + self.imgs.wpn_icon_border_pressed + }, + _ => self.imgs.wpn_icon_border_press, + }, + "Fire Staff" => match sel_tab { + SelectedSkillTree::Weapon(ToolKind::Staff) => { + self.imgs.wpn_icon_border_pressed + }, + _ => self.imgs.wpn_icon_border_press, + }, + _ => self.imgs.wpn_icon_border, + } ) .middle_of(state.weapon_imgs[i.0]) + .with_tooltip( + self.tooltip_manager, + i.1, + &tooltip_txt, + &diary_tooltip, + TEXT_COLOR, + ) .set(state.weapon_btns[i.0], ui) .was_clicked() - { - match i.1 { - "General Combat" => { - events.push(Event::ChangeSkillTree(SelectedSkillTree::General)) - }, - "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), - } + { + match i.1 { + "General Combat" => { + events.push(Event::ChangeSkillTree(SelectedSkillTree::General)) + }, + "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 @@ -529,12 +592,28 @@ impl<'a> Widget for Diary<'a> { .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)) + .mid_top_with_margin_on(state.content_align, tweak!(42.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); } + let tree_title = match sel_tab { + SelectedSkillTree::General => "General Combat", + SelectedSkillTree::Weapon(ToolKind::Sword) => "Sword", + SelectedSkillTree::Weapon(ToolKind::Hammer) => "Hammer", + SelectedSkillTree::Weapon(ToolKind::Axe) => "Axe", + SelectedSkillTree::Weapon(ToolKind::Sceptre) => "Healing Sceptre", + SelectedSkillTree::Weapon(ToolKind::Bow) => "Bow", + SelectedSkillTree::Weapon(ToolKind::Staff) => "Fire Staff", + _ => "Unknown", + }; + Text::new(&tree_title) + .mid_top_with_margin_on(state.content_align, tweak!(2.0)) + .font_id(self.fonts.cyri.conrod_id) + .font_size(self.fonts.cyri.scale(tweak!(34))) + .color(TEXT_COLOR) + .set(state.tree_title_txt, ui); // Skill Trees // Alignment Placing let x = tweak!(200.0); @@ -715,7 +794,7 @@ impl<'a> Widget for Diary<'a> { // 3 0 4 // 8 2 7 let skill = Skill::General(HealthIncrease); - if Button::image(self.imgs.not_found) + if Button::image(self.imgs.swords_crossed) .w_h(tweak!(74.0), tweak!(74.0)) .middle_of(state.skills_top_l[0]) .label(&format!( @@ -741,7 +820,7 @@ impl<'a> Widget for Diary<'a> { events.push(Event::UnlockSkill(skill)); }; let skill = Skill::General(EnergyIncrease); - if Button::image(self.imgs.not_found) + if Button::image(self.imgs.swords_crossed) .w_h(tweak!(74.0), tweak!(74.0)) .middle_of(state.skills_top_l[1]) .label(&format!( @@ -768,7 +847,7 @@ impl<'a> Widget for Diary<'a> { }; // Top right skills let skill = Skill::UnlockGroup(Weapon(Sword)); - if Button::image(self.imgs.not_found) + if Button::image(self.imgs.swords_crossed) .w_h(tweak!(74.0), tweak!(74.0)) .middle_of(state.skills_top_r[0]) .label(&format!( @@ -794,7 +873,7 @@ impl<'a> Widget for Diary<'a> { events.push(Event::UnlockSkill(skill)); }; let skill = Skill::UnlockGroup(Weapon(Axe)); - if Button::image(self.imgs.not_found) + if Button::image(self.imgs.swords_crossed) .w_h(tweak!(74.0), tweak!(74.0)) .middle_of(state.skills_top_r[1]) .label(&format!( @@ -820,7 +899,7 @@ impl<'a> Widget for Diary<'a> { events.push(Event::UnlockSkill(skill)); }; let skill = Skill::UnlockGroup(Weapon(Hammer)); - if Button::image(self.imgs.not_found) + if Button::image(self.imgs.swords_crossed) .w_h(tweak!(74.0), tweak!(74.0)) .middle_of(state.skills_top_r[2]) .label(&format!( @@ -846,7 +925,7 @@ impl<'a> Widget for Diary<'a> { events.push(Event::UnlockSkill(skill)); }; let skill = Skill::UnlockGroup(Weapon(Bow)); - if Button::image(self.imgs.not_found) + if Button::image(self.imgs.swords_crossed) .w_h(tweak!(74.0), tweak!(74.0)) .middle_of(state.skills_top_r[3]) .label(&format!( @@ -872,7 +951,7 @@ impl<'a> Widget for Diary<'a> { events.push(Event::UnlockSkill(skill)); }; let skill = Skill::UnlockGroup(Weapon(Staff)); - if Button::image(self.imgs.not_found) + if Button::image(self.imgs.swords_crossed) .w_h(tweak!(74.0), tweak!(74.0)) .middle_of(state.skills_top_r[4]) .label(&format!( @@ -898,7 +977,7 @@ impl<'a> Widget for Diary<'a> { events.push(Event::UnlockSkill(skill)); }; let skill = Skill::UnlockGroup(Weapon(Sceptre)); - if Button::image(self.imgs.not_found) + if Button::image(self.imgs.swords_crossed) .w_h(tweak!(74.0), tweak!(74.0)) .middle_of(state.skills_top_r[5]) .label(&format!( @@ -925,7 +1004,7 @@ impl<'a> Widget for Diary<'a> { }; // Bottom left skills let skill = Skill::Roll(ImmuneMelee); - if Button::image(self.imgs.not_found) + if Button::image(self.imgs.swords_crossed) .w_h(tweak!(74.0), tweak!(74.0)) .middle_of(state.skills_bot_l[0]) .label(&format!( @@ -951,7 +1030,7 @@ impl<'a> Widget for Diary<'a> { events.push(Event::UnlockSkill(skill)); }; let skill = Skill::Roll(Cost); - if Button::image(self.imgs.not_found) + if Button::image(self.imgs.swords_crossed) .w_h(tweak!(74.0), tweak!(74.0)) .middle_of(state.skills_bot_l[1]) .label(&format!( @@ -977,7 +1056,7 @@ impl<'a> Widget for Diary<'a> { events.push(Event::UnlockSkill(skill)); }; let skill = Skill::Roll(Strength); - if Button::image(self.imgs.not_found) + if Button::image(self.imgs.swords_crossed) .w_h(tweak!(74.0), tweak!(74.0)) .middle_of(state.skills_bot_l[2]) .label(&format!( @@ -1003,7 +1082,7 @@ impl<'a> Widget for Diary<'a> { events.push(Event::UnlockSkill(skill)); }; let skill = Skill::Roll(Duration); - if Button::image(self.imgs.not_found) + if Button::image(self.imgs.swords_crossed) .w_h(tweak!(74.0), tweak!(74.0)) .middle_of(state.skills_bot_l[3]) .label(&format!( diff --git a/voxygen/src/hud/img_ids.rs b/voxygen/src/hud/img_ids.rs index 6332fce296..c0e0d3d18f 100644 --- a/voxygen/src/hud/img_ids.rs +++ b/voxygen/src/hud/img_ids.rs @@ -69,12 +69,14 @@ image_ids! { diary_exp_frame: "voxygen.element.misc_bg.diary_exp_frame", // Skill Trees + swords_crossed: "voxygen.element.icons.swords_crossed", sceptre: "voxygen.element.icons.sceptre", sword: "voxygen.element.icons.sword", axe: "voxygen.element.icons.axe", hammer: "voxygen.element.icons.hammer", bow: "voxygen.element.icons.bow", staff: "voxygen.element.icons.staff", + lock: "voxygen.element.icons.lock", wpn_icon_border: "voxygen.element.buttons.border", wpn_icon_border_mo: "voxygen.element.buttons.border_mo", wpn_icon_border_press: "voxygen.element.buttons.border_press", diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index f16877075c..14619594d7 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -63,6 +63,7 @@ use common::{ skills::Skill, BuffKind, }, + outcome::Outcome, span, terrain::TerrainChunk, uid::Uid, @@ -1059,16 +1060,26 @@ impl Hud { } } // EXP Numbers - /*if let (Some(floaters), Some(stats)) = ( - Some(&*ecs.read_resource::()) - .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 + if let Some(uid) = uids.get(me) { + for exp in ecs + .read_resource::>() + .iter() + .filter( + |o| matches!(o, Outcome::ExpChange { uid: uid_, .. } if uid == uid_ ), + ) + .filter_map(|o| { + if let Outcome::ExpChange { exp, .. } = o { + Some(exp) + } else { + None + } + }) + { + println!("{}", exp); + let number_speed = 50.0; // Number Speed for Single EXP + let timer = 100.0; // Fake number + let rand1 = 0.5; // Fake number + let rand2 = -0.1; // Fake number let player_sct_bg_id = player_sct_bg_id_walker.next( &mut self.ids.player_sct_bgs, &mut ui_widgets.widget_id_generator(), @@ -1077,18 +1088,10 @@ impl Hud { &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 + + ((*exp as f32 / 300.0 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 { @@ -1098,71 +1101,26 @@ impl Hud { 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)) + Text::new(&format!("{} Exp", exp)) .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, + ui_widgets.win_w * (0.5 * rand1 as f64 - 0.25), + ui_widgets.win_h * (0.15 * rand2 as f64) + y - 3.0, ) .set(player_sct_bg_id, ui_widgets); - Text::new(&format!("{} Exp", exp_change)) + Text::new(&format!("{} Exp", exp)) .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, + ui_widgets.win_w * (0.5 * rand1 as f64 - 0.25), + ui_widgets.win_h * (0.15 * rand2 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 diff --git a/voxygen/src/menu/char_selection/ui/mod.rs b/voxygen/src/menu/char_selection/ui/mod.rs index d9dbd0eaf9..b0e4a0d575 100644 --- a/voxygen/src/menu/char_selection/ui/mod.rs +++ b/voxygen/src/menu/char_selection/ui/mod.rs @@ -443,7 +443,9 @@ impl Controls { Button::new( select_button, Column::with_children(vec![ - Text::new(&character.character.alias).into(), + Text::new(&character.character.alias) + .size(fonts.cyri.scale(30)) + .into(), // TODO: only construct string once when characters // are // loaded