Database support for refunding skills.

Nonfunctional xp floaters, squash when working.

more icons, lock visuals
This commit is contained in:
Sam 2021-01-02 15:06:33 -05:00
parent 48bd921d0a
commit 51c0bd765f
12 changed files with 315 additions and 254 deletions

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

Binary file not shown.

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

Binary file not shown.

View File

@ -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,

View File

@ -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<f32>,
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,
}
}
}

View File

@ -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::<Vec<_>>();
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::<comp::Inventory>().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::<Vec<Outcome>>()
.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::<Vec<Outcome>>()
.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::<Uid>()
.get(entity)
.copied()
.zip(ecs.read_storage::<Pos>().get(entity).map(|p| p.0))
{
ecs.write_resource::<Vec<Outcome>>()
.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::<comp::Auras>();

View File

@ -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,

View File

@ -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::<Vec<_>>(),
),
),
),
)
.execute(&*connection)?;
trace!("Deleted {} skills", delete_count);
diesel::replace_into(schema::skill::dsl::skill)
.values(&db_skills)
.execute(&*connection)?;

View File

@ -358,6 +358,7 @@ impl SfxMgr {
audio.play_sfx(file_ref, *pos, None);
}
},
Outcome::ExpChange { .. } => {},
}
}

View File

@ -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!(

View File

@ -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",

View File

@ -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::<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
if let Some(uid) = uids.get(me) {
for exp in ecs
.read_resource::<Vec<Outcome>>()
.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

View File

@ -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