diff --git a/assets/voxygen/element/icons/skill_charge_3.vox b/assets/voxygen/element/icons/skill_charge_3.vox index 93eaf74626..dc30739204 100644 --- a/assets/voxygen/element/icons/skill_charge_3.vox +++ b/assets/voxygen/element/icons/skill_charge_3.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bd3f960fa3f1a26feb6ece373060873720d36f9644c4d3302461f97068685f84 -size 57509 +oid sha256:af880f99099b027bad51aa2e16ea622012d9f99a3ce3691909a041f5afa1c927 +size 63217 diff --git a/assets/voxygen/element/icons/staff_m2.vox b/assets/voxygen/element/icons/staff_m2.vox index 2ad23b82a8..74fb309158 100644 --- a/assets/voxygen/element/icons/staff_m2.vox +++ b/assets/voxygen/element/icons/staff_m2.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7b01ee5e7ae025ed6f82c40cd81d37472624c7d67164a8c42f76b4295e963c85 +oid sha256:b1dd296878391652f6c5151cee6eba5bf003e07360ecbe08f342f7ac631d103d size 60360 diff --git a/common/src/comp/energy.rs b/common/src/comp/energy.rs index 88164813e0..32169ddbff 100644 --- a/common/src/comp/energy.rs +++ b/common/src/comp/energy.rs @@ -5,6 +5,7 @@ use specs_idvs::IDVStorage; pub struct Energy { current: u32, maximum: u32, + pub regen_rate: f32, pub last_change: Option<(i32, f64, EnergySource)>, } @@ -12,14 +13,23 @@ pub struct Energy { pub enum EnergySource { CastSpell, LevelUp, + Regen, + Revive, Unknown, } +#[derive(Debug)] +pub enum StatChangeError { + Underflow, + Overflow, +} + impl Energy { pub fn new(amount: u32) -> Energy { Energy { current: amount, maximum: amount, + regen_rate: 0.0, last_change: None, } } @@ -43,6 +53,21 @@ impl Energy { self.last_change = Some((amount, 0.0, cause)); } + pub fn try_change_by( + &mut self, + amount: i32, + cause: EnergySource, + ) -> Result<(), StatChangeError> { + if self.current as i32 + amount < 0 { + Err(StatChangeError::Underflow) + } else if self.current as i32 + amount > self.maximum as i32 { + Err(StatChangeError::Overflow) + } else { + self.change_by(amount, cause); + Ok(()) + } + } + pub fn set_maximum(&mut self, amount: u32) { self.maximum = amount; self.current = self.current.min(self.maximum); diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index 5f2a631c89..21f6114608 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -26,7 +26,7 @@ pub use controller::{ ControlEvent, Controller, ControllerInputs, Input, InputState, InventoryManip, MountState, Mounting, }; -pub use energy::Energy; +pub use energy::{Energy, EnergySource}; pub use inputs::CanBuild; pub use inventory::{item, Inventory, InventoryUpdate, Item, ItemKind}; pub use last::Last; diff --git a/common/src/comp/stats.rs b/common/src/comp/stats.rs index 532f6cb8be..5d0adba2e6 100644 --- a/common/src/comp/stats.rs +++ b/common/src/comp/stats.rs @@ -76,6 +76,26 @@ impl Health { self.current = self.current.min(self.maximum); } } +#[derive(Debug)] +pub enum StatChangeError { + Underflow, + Overflow, +} +use std::error::Error; +use std::fmt; +impl fmt::Display for StatChangeError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + match self { + Self::Underflow => "insufficient stat quantity", + Self::Overflow => "stat quantity would overflow", + } + ) + } +} +impl Error for StatChangeError {} impl Exp { pub fn current(&self) -> u32 { @@ -164,10 +184,7 @@ impl Stats { current: 0, maximum: 50, }, - equipment: Equipment { - main: main, - alt: None, - }, + equipment: Equipment { main, alt: None }, is_dead: false, }; diff --git a/common/src/state.rs b/common/src/state.rs index a111a5f1fa..4bbaa5d3b4 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -39,7 +39,7 @@ pub struct DeltaTime(pub f32); /// upper limit. If delta time exceeds this value, the game's physics will begin to produce time /// lag. Ideally, we'd avoid such a situation. const MAX_DELTA_TIME: f32 = 1.0; -const HUMANOID_JUMP_ACCEL: f32 = 16.0; +const HUMANOID_JUMP_ACCEL: f32 = 26.0; #[derive(Default)] pub struct BlockChange { diff --git a/common/src/sys/controller.rs b/common/src/sys/controller.rs index f68839f571..c63f726055 100644 --- a/common/src/sys/controller.rs +++ b/common/src/sys/controller.rs @@ -2,8 +2,8 @@ use super::movement::ROLL_DURATION; use crate::{ comp::{ self, item, projectile, ActionState, ActionState::*, Body, CharacterState, ControlEvent, - Controller, ControllerInputs, HealthChange, HealthSource, ItemKind, Mounting, - MovementState, MovementState::*, PhysicsState, Projectile, Stats, Vel, + Controller, ControllerInputs, Energy, EnergySource, HealthChange, HealthSource, ItemKind, + Mounting, MovementState, MovementState::*, PhysicsState, Projectile, Stats, Vel, }, event::{Emitter, EventBus, LocalEvent, ServerEvent}, state::DeltaTime, @@ -16,6 +16,8 @@ use specs::{ use std::time::Duration; use vek::*; +const CHARGE_COST: i32 = 200; + /// # Controller System /// #### Responsible for validating controller inputs and setting new Character States /// ---- @@ -247,6 +249,7 @@ impl<'a> System<'a> for Sys { WriteStorage<'a, Controller>, WriteStorage<'a, CharacterState>, ReadStorage<'a, Stats>, + WriteStorage<'a, Energy>, ReadStorage<'a, Body>, ReadStorage<'a, Vel>, ReadStorage<'a, PhysicsState>, @@ -264,6 +267,7 @@ impl<'a> System<'a> for Sys { mut controllers, mut character_states, stats, + mut energies, bodies, velocities, physics_states, @@ -273,12 +277,24 @@ impl<'a> System<'a> for Sys { ) { let mut server_emitter = server_bus.emitter(); let mut local_emitter = local_bus.emitter(); - for (entity, uid, controller, mut character, stats, body, vel, physics, mount) in ( + for ( + entity, + uid, + controller, + mut character, + stats, + mut energy, + body, + vel, + physics, + mount, + ) in ( &entities, &uids, &mut controllers, &mut character_states, &stats, + &mut energies.restrict_mut(), &bodies, &velocities, &physics_states, @@ -579,9 +595,15 @@ impl<'a> System<'a> for Sys { // Try to charge if inputs.charge.is_pressed() && !inputs.charge.is_held_down() { - character.action = Charge { - time_left: Duration::from_millis(250), - }; + if energy + .get_mut_unchecked() + .try_change_by(-CHARGE_COST, EnergySource::CastSpell) + .is_ok() + { + character.action = Charge { + time_left: Duration::from_millis(250), + } + } continue; } diff --git a/common/src/sys/movement.rs b/common/src/sys/movement.rs index 5a96f68496..e7c93e3bbf 100644 --- a/common/src/sys/movement.rs +++ b/common/src/sys/movement.rs @@ -15,13 +15,13 @@ use vek::*; pub const ROLL_DURATION: Duration = Duration::from_millis(600); -const HUMANOID_ACCEL: f32 = 50.0; +const HUMANOID_ACCEL: f32 = 100.0; const HUMANOID_SPEED: f32 = 120.0; -const HUMANOID_AIR_ACCEL: f32 = 10.0; +const HUMANOID_AIR_ACCEL: f32 = 15.0; const HUMANOID_AIR_SPEED: f32 = 100.0; const HUMANOID_WATER_ACCEL: f32 = 70.0; const HUMANOID_WATER_SPEED: f32 = 120.0; -const HUMANOID_CLIMB_ACCEL: f32 = 5.0; +const HUMANOID_CLIMB_ACCEL: f32 = 10.0; const ROLL_SPEED: f32 = 17.0; const CHARGE_SPEED: f32 = 20.0; const GLIDE_ACCEL: f32 = 15.0; @@ -221,14 +221,9 @@ impl<'a> System<'a> for Sys { if inputs.climb_down.is_pressed() && !inputs.climb.is_pressed() { vel.0 -= dt.0 * vel.0.map(|e| e.abs().powf(1.5) * e.signum() * 6.0); } else if inputs.climb.is_pressed() && !inputs.climb_down.is_pressed() { - vel.0.z = (vel.0.z + dt.0 * GRAVITY * 1.25).min(CLIMB_SPEED); + vel.0.z = (vel.0.z + dt.0 * GRAVITY * 1.25).min(CLIMB_SPEED).max(0.0); } else { - vel.0.z = vel.0.z + dt.0 * GRAVITY * 1.5; - vel.0 = Lerp::lerp( - vel.0, - Vec3::zero(), - 30.0 * dt.0 / (1.0 - vel.0.z.min(0.0) * 5.0), - ); + vel.0.z = (vel.0.z - dt.0 * GRAVITY * 0.01).min(CLIMB_SPEED); } } diff --git a/common/src/sys/phys.rs b/common/src/sys/phys.rs index 955d229c22..cf913da4b6 100644 --- a/common/src/sys/phys.rs +++ b/common/src/sys/phys.rs @@ -11,14 +11,14 @@ use { vek::*, }; -pub const GRAVITY: f32 = 9.81 * 4.0; +pub const GRAVITY: f32 = 9.81 * 7.0; const BOUYANCY: f32 = 0.0; // Friction values used for linear damping. They are unitless quantities. The // value of these quantities must be between zero and one. They represent the // amount an object will slow down within 1/60th of a second. Eg. if the frction // is 0.01, and the speed is 1.0, then after 1/60th of a second the speed will // be 0.99. after 1 second the speed will be 0.54, which is 0.99 ^ 60. -const FRIC_GROUND: f32 = 0.08; +const FRIC_GROUND: f32 = 0.15; const FRIC_AIR: f32 = 0.0125; const FRIC_FLUID: f32 = 0.2; @@ -33,7 +33,7 @@ fn integrate_forces(dt: f32, mut lv: Vec3, grav: f32, damp: f32) -> Vec3 System<'a> for Sys { { // ...block-hop! pos.0.z = (pos.0.z + 0.1).ceil(); + vel.0.z = 0.0; on_ground = true; break; } else { diff --git a/common/src/sys/stats.rs b/common/src/sys/stats.rs index f4ac03e576..0564fd8bf2 100644 --- a/common/src/sys/stats.rs +++ b/common/src/sys/stats.rs @@ -1,22 +1,28 @@ use crate::{ - comp::{HealthSource, Stats}, + comp::{ActionState, CharacterState, Energy, EnergySource, HealthSource, Stats}, event::{EventBus, ServerEvent}, state::DeltaTime, }; -use specs::{Entities, Join, Read, System, WriteStorage}; +use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage}; -/// This system kills players -/// and handles players levelling up +const ENERGY_REGEN_ACCEL: f32 = 20.0; + +/// This system kills players, levels them up, and regenerates energy. pub struct Sys; impl<'a> System<'a> for Sys { type SystemData = ( Entities<'a>, Read<'a, DeltaTime>, Read<'a, EventBus>, + ReadStorage<'a, CharacterState>, WriteStorage<'a, Stats>, + WriteStorage<'a, Energy>, ); - fn run(&mut self, (entities, dt, server_event_bus, mut stats): Self::SystemData) { + fn run( + &mut self, + (entities, dt, server_event_bus, character_states, mut stats,mut energies): Self::SystemData, + ) { let mut server_event_emitter = server_event_bus.emitter(); // Increment last change timer @@ -27,7 +33,14 @@ impl<'a> System<'a> for Sys { stats.set_event_emission(true); // Mutates all stats every tick causing the server to resend this component for every entity every tick - for (entity, mut stats) in (&entities, &mut stats.restrict_mut()).join() { + for (entity, character_state, mut stats, mut energy) in ( + &entities, + &character_states, + &mut stats.restrict_mut(), + &mut energies.restrict_mut(), + ) + .join() + { let (set_dead, level_up) = { let stat = stats.get_unchecked(); ( @@ -58,6 +71,31 @@ impl<'a> System<'a> for Sys { stat.health .set_to(stat.health.maximum(), HealthSource::LevelUp) } + + // Accelerate recharging energy if not wielding. + match character_state.action { + ActionState::Idle => { + if { + let energy = energy.get_unchecked(); + energy.current() < energy.maximum() + } { + let mut energy = energy.get_mut_unchecked(); + // Have to account for Calc I differential equations due to acceleration + energy.change_by( + (energy.regen_rate * dt.0 + ENERGY_REGEN_ACCEL * dt.0.powf(2.0) / 2.0) + as i32, + EnergySource::Regen, + ); + energy.regen_rate += ENERGY_REGEN_ACCEL * dt.0; + } + } + // All other states do not regen and set the rate back to zero. + _ => { + if energy.get_unchecked().regen_rate != 0.0 { + energy.get_mut_unchecked().regen_rate = 0.0 + } + } + } } } } diff --git a/server/src/lib.rs b/server/src/lib.rs index 6bf0557244..7a7f85eeed 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -258,7 +258,7 @@ impl Server { state.write_component(entity, body); state.write_component(entity, comp::Stats::new(name, main)); - state.write_component(entity, comp::Energy::new(200)); + state.write_component(entity, comp::Energy::new(1000)); state.write_component(entity, comp::Controller::default()); state.write_component(entity, comp::Pos(spawn_point)); state.write_component(entity, comp::Vel(Vec3::zero())); @@ -434,6 +434,17 @@ impl Server { .map(|err| { error!("Failed to insert ForceUpdate on dead client: {:?}", err) }); + state + .ecs() + .write_storage::() + .get_mut(entity) + .map(|energy| { + energy.set_to(energy.maximum(), comp::EnergySource::Revive) + }); + let _ = state + .ecs() + .write_storage::() + .insert(entity, comp::CharacterState::default()); } else { // If not a player delete the entity if let Err(err) = state.delete_entity_recorded(entity) { @@ -613,11 +624,11 @@ impl Server { } ServerEvent::LandOnGround { entity, vel } => { - if vel.z <= -25.0 { + if vel.z <= -37.0 { if let Some(stats) = state.ecs().write_storage::().get_mut(entity) { - let falldmg = (vel.z / 5.0) as i32; + let falldmg = (vel.z / 2.5) as i32; if falldmg < 0 { stats.health.change_by(comp::HealthChange { amount: falldmg, @@ -1185,7 +1196,7 @@ impl StateExt for State { .with(comp::Controller::default()) .with(body) .with(stats) - .with(comp::Energy::new(100)) + .with(comp::Energy::new(500)) .with(comp::Gravity(1.0)) .with(comp::CharacterState::default()) } diff --git a/voxygen/src/hud/img_ids.rs b/voxygen/src/hud/img_ids.rs index 750534e663..27a19d6ef3 100644 --- a/voxygen/src/hud/img_ids.rs +++ b/voxygen/src/hud/img_ids.rs @@ -120,7 +120,7 @@ image_ids! { flyingrod_m1: "voxygen.element.icons.debug_wand_m1", flyingrod_m2: "voxygen.element.icons.debug_wand_m2", - charge: "voxygen.element.icons.skill_charge_2", + charge: "voxygen.element.icons.skill_charge_3", // Icons diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index e79965efd7..2b5eb02237 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -544,7 +544,7 @@ impl Hud { let own_level = stats .get(client.entity()) .map_or(0, |stats| stats.level.level()); - + //self.input = client.read_storage::(); if let Some(stats) = stats.get(me) { // Hurt Frame let hp_percentage = @@ -1653,10 +1653,12 @@ impl Hud { let energy = ecs.read_storage::(); let character_state = ecs.read_storage::(); let entity = client.entity(); - if let (Some(stats), Some(energy), Some(character_state)) = ( + let controller = ecs.read_storage::(); + if let (Some(stats), Some(energy), Some(character_state), Some(controller)) = ( stats.get(entity), energy.get(entity), character_state.get(entity), + controller.get(entity).map(|c| &c.inputs), ) { Skillbar::new( global_state, @@ -1666,6 +1668,7 @@ impl Hud { &energy, &character_state, self.pulse, + &controller, ) .set(self.ids.skillbar, ui_widgets); } diff --git a/voxygen/src/hud/skillbar.rs b/voxygen/src/hud/skillbar.rs index 2422c8b3d5..4cf7bb433c 100644 --- a/voxygen/src/hud/skillbar.rs +++ b/voxygen/src/hud/skillbar.rs @@ -3,7 +3,9 @@ use super::{ /*FOCUS_COLOR, RAGE_COLOR,*/ HP_COLOR, LOW_HP_COLOR, MANA_COLOR, TEXT_COLOR, XP_COLOR, }; use crate::GlobalState; -use common::comp::{item::Debug, item::Tool, ActionState, CharacterState, Energy, ItemKind, Stats}; +use common::comp::{ + item::Debug, item::Tool, ActionState, CharacterState, ControllerInputs, Energy, ItemKind, Stats, +}; use conrod_core::{ color, widget::{self, Button, Image, Rectangle, Text}, @@ -103,6 +105,7 @@ pub struct Skillbar<'a> { stats: &'a Stats, energy: &'a Energy, character_state: &'a CharacterState, + controller: &'a ControllerInputs, pulse: f32, #[conrod(common_builder)] common: widget::CommonBuilder, @@ -118,6 +121,7 @@ impl<'a> Skillbar<'a> { energy: &'a Energy, character_state: &'a CharacterState, pulse: f32, + controller: &'a ControllerInputs, ) -> Self { Self { imgs, @@ -129,6 +133,7 @@ impl<'a> Skillbar<'a> { common: widget::CommonBuilder::default(), character_state, pulse, + controller, } } } @@ -526,17 +531,32 @@ impl<'a> Widget for Skillbar<'a> { match self.character_state.action { ActionState::Attack { .. } => { - let fade_pulse = (self.pulse * 4.0/*speed factor*/).cos() * 0.5 + 0.6; //Animation timer; - Image::new(self.imgs.skillbar_slot_big) - .w_h(40.0 * scale, 40.0 * scale) - .top_left_with_margins_on(state.ids.hotbar_align, -40.0 * scale, 0.0) - .set(state.ids.m1_slot, ui); - Image::new(self.imgs.skillbar_slot_big_act) - .w_h(40.0 * scale, 40.0 * scale) - .middle_of(state.ids.m1_slot) - .color(Some(Color::Rgba(1.0, 1.0, 1.0, fade_pulse))) - .floating(true) - .set(state.ids.m1_slot_act, ui); + if self.controller.primary.is_pressed() { + let fade_pulse = (self.pulse * 4.0/*speed factor*/).cos() * 0.5 + 0.6; //Animation timer; + Image::new(self.imgs.skillbar_slot_big) + .w_h(40.0 * scale, 40.0 * scale) + .top_left_with_margins_on( + state.ids.hotbar_align, + -40.0 * scale, + 0.0, + ) + .set(state.ids.m1_slot, ui); + Image::new(self.imgs.skillbar_slot_big_act) + .w_h(40.0 * scale, 40.0 * scale) + .middle_of(state.ids.m1_slot) + .color(Some(Color::Rgba(1.0, 1.0, 1.0, fade_pulse))) + .floating(true) + .set(state.ids.m1_slot_act, ui); + } else { + Image::new(self.imgs.skillbar_slot_big) + .w_h(40.0 * scale, 40.0 * scale) + .top_left_with_margins_on( + state.ids.hotbar_align, + -40.0 * scale, + 0.0, + ) + .set(state.ids.m1_slot, ui); + } } _ => { Image::new(self.imgs.skillbar_slot_big) @@ -548,9 +568,8 @@ impl<'a> Widget for Skillbar<'a> { } } // M1 Slot - Image::new(self.imgs.skillbar_slot_big_bg) - .w_h(36.0 * scale, 36.0 * scale) + .w_h(38.0 * scale, 38.0 * scale) .color(match self.stats.equipment.main.as_ref().map(|i| &i.kind) { Some(ItemKind::Tool { kind, .. }) => match kind { Tool::Bow => Some(BG_COLOR_2), @@ -576,7 +595,7 @@ impl<'a> Widget for Skillbar<'a> { .w(match self.stats.equipment.main.as_ref().map(|i| &i.kind) { Some(ItemKind::Tool { kind, .. }) => match kind { Tool::Bow => 30.0 * scale, - Tool::Staff => 30.0 * scale, + Tool::Staff => 32.0 * scale, _ => 38.0 * scale, }, _ => 38.0 * scale, @@ -584,7 +603,7 @@ impl<'a> Widget for Skillbar<'a> { .h(match self.stats.equipment.main.as_ref().map(|i| &i.kind) { Some(ItemKind::Tool { kind, .. }) => match kind { Tool::Bow => 30.0 * scale, - Tool::Staff => 36.0 * scale, + Tool::Staff => 32.0 * scale, _ => 38.0 * scale, }, _ => 38.0 * scale, @@ -595,16 +614,43 @@ impl<'a> Widget for Skillbar<'a> { match self.character_state.action { ActionState::Block { .. } => { let fade_pulse = (self.pulse * 4.0/*speed factor*/).cos() * 0.5 + 0.6; //Animation timer; - Image::new(self.imgs.skillbar_slot_big) - .w_h(40.0 * scale, 40.0 * scale) - .right_from(state.ids.m1_slot, 0.0) - .set(state.ids.m2_slot, ui); - Image::new(self.imgs.skillbar_slot_big_act) - .w_h(40.0 * scale, 40.0 * scale) - .middle_of(state.ids.m2_slot) - .color(Some(Color::Rgba(1.0, 1.0, 1.0, fade_pulse))) - .floating(true) - .set(state.ids.m2_slot_act, ui); + if self.controller.secondary.is_pressed() { + Image::new(self.imgs.skillbar_slot_big) + .w_h(40.0 * scale, 40.0 * scale) + .right_from(state.ids.m1_slot, 0.0) + .set(state.ids.m2_slot, ui); + Image::new(self.imgs.skillbar_slot_big_act) + .w_h(40.0 * scale, 40.0 * scale) + .middle_of(state.ids.m2_slot) + .color(Some(Color::Rgba(1.0, 1.0, 1.0, fade_pulse))) + .floating(true) + .set(state.ids.m2_slot_act, ui); + } else { + Image::new(self.imgs.skillbar_slot_big) + .w_h(40.0 * scale, 40.0 * scale) + .right_from(state.ids.m1_slot, 0.0) + .set(state.ids.m2_slot, ui); + } + } + ActionState::Attack { .. } => { + let fade_pulse = (self.pulse * 4.0/*speed factor*/).cos() * 0.5 + 0.6; //Animation timer; + if self.controller.secondary.is_pressed() { + Image::new(self.imgs.skillbar_slot_big) + .w_h(40.0 * scale, 40.0 * scale) + .right_from(state.ids.m1_slot, 0.0) + .set(state.ids.m2_slot, ui); + Image::new(self.imgs.skillbar_slot_big_act) + .w_h(40.0 * scale, 40.0 * scale) + .middle_of(state.ids.m2_slot) + .color(Some(Color::Rgba(1.0, 1.0, 1.0, fade_pulse))) + .floating(true) + .set(state.ids.m2_slot_act, ui); + } else { + Image::new(self.imgs.skillbar_slot_big) + .w_h(40.0 * scale, 40.0 * scale) + .right_from(state.ids.m1_slot, 0.0) + .set(state.ids.m2_slot, ui); + } } _ => { Image::new(self.imgs.skillbar_slot_big) @@ -615,7 +661,7 @@ impl<'a> Widget for Skillbar<'a> { } Image::new(self.imgs.skillbar_slot_big_bg) - .w_h(36.0 * scale, 36.0 * scale) + .w_h(38.0 * scale, 38.0 * scale) .color(match self.stats.equipment.main.as_ref().map(|i| &i.kind) { Some(ItemKind::Tool { kind, .. }) => match kind { Tool::Bow => Some(BG_COLOR_2), @@ -726,14 +772,18 @@ impl<'a> Widget for Skillbar<'a> { } } Image::new(self.imgs.skillbar_slot_bg) - .w_h(19.0 * scale, 19.0 * scale) + .w_h(19.5 * scale, 19.5 * scale) .color(Some(BG_COLOR)) .middle_of(state.ids.slot1) .set(state.ids.slot1_bg, ui); // TODO: Changeable slot image Image::new(self.imgs.charge) .w_h(18.0 * scale, 18.0 * scale) - //.color(Some(BG_COLOR)) + .color(if self.energy.current() as f64 >= 200.0 { + Some(Color::Rgba(1.0, 1.0, 1.0, 1.0)) + } else { + Some(Color::Rgba(0.4, 0.4, 0.4, 1.0)) + }) .middle_of(state.ids.slot1_bg) .set(state.ids.slot1_icon, ui); // Slot 6 @@ -915,8 +965,8 @@ impl<'a> Widget for Skillbar<'a> { .set(state.ids.health_text, ui); let energy_text = format!( "{}/{}", - self.energy.current() as u32, - self.energy.maximum() as u32 + self.energy.current() as u32 / 10, //TODO Fix regeneration with smaller energy numbers instead of dividing by 10 here + self.energy.maximum() as u32 / 10 ); Text::new(&energy_text) .mid_top_with_margin_on(state.ids.energybar_bg, 6.0 * scale)