mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Cleaned up UI code. Removed stuff added for testing. Added 10% for melee attacks to inflict a bleeding debuff. Renamed BuffId to BuffKind. Fixed memory leak. Set event emission to false when timer is decremented.
This commit is contained in:
parent
fdf8decb18
commit
337cf6e137
@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Gave the axe a third attack
|
- Gave the axe a third attack
|
||||||
- A new secondary charged melee attack for the hammer
|
- A new secondary charged melee attack for the hammer
|
||||||
- Added Dutch translations
|
- Added Dutch translations
|
||||||
|
- Buff system
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -4957,7 +4957,6 @@ dependencies = [
|
|||||||
"guillotiere",
|
"guillotiere",
|
||||||
"hashbrown 0.7.2",
|
"hashbrown 0.7.2",
|
||||||
"image",
|
"image",
|
||||||
"inline_tweak",
|
|
||||||
"itertools",
|
"itertools",
|
||||||
"native-dialog",
|
"native-dialog",
|
||||||
"num 0.2.1",
|
"num 0.2.1",
|
||||||
@ -4989,7 +4988,6 @@ name = "veloren-voxygen-anim"
|
|||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"find_folder",
|
"find_folder",
|
||||||
"inline_tweak",
|
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libloading 0.6.3",
|
"libloading 0.6.3",
|
||||||
"notify",
|
"notify",
|
||||||
|
@ -37,7 +37,7 @@ use common::{
|
|||||||
terrain::{block::Block, neighbors, TerrainChunk, TerrainChunkSize},
|
terrain::{block::Block, neighbors, TerrainChunk, TerrainChunkSize},
|
||||||
vol::RectVolSize,
|
vol::RectVolSize,
|
||||||
};
|
};
|
||||||
use comp::BuffId;
|
use comp::BuffKind;
|
||||||
use futures_executor::block_on;
|
use futures_executor::block_on;
|
||||||
use futures_timer::Delay;
|
use futures_timer::Delay;
|
||||||
use futures_util::{select, FutureExt};
|
use futures_util::{select, FutureExt};
|
||||||
@ -632,7 +632,7 @@ impl Client {
|
|||||||
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::DisableLantern));
|
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::DisableLantern));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_buff(&mut self, buff_id: BuffId) {
|
pub fn remove_buff(&mut self, buff_id: BuffKind) {
|
||||||
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::RemoveBuff(
|
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::RemoveBuff(
|
||||||
buff_id,
|
buff_id,
|
||||||
)));
|
)));
|
||||||
@ -971,6 +971,11 @@ impl Client {
|
|||||||
|
|
||||||
// 4) Tick the client's LocalState
|
// 4) Tick the client's LocalState
|
||||||
self.state.tick(dt, add_foreign_systems, true);
|
self.state.tick(dt, add_foreign_systems, true);
|
||||||
|
// TODO: avoid emitting these in the first place
|
||||||
|
self.state
|
||||||
|
.ecs()
|
||||||
|
.fetch::<EventBus<common::event::ServerEvent>>()
|
||||||
|
.recv_all();
|
||||||
|
|
||||||
// 5) Terrain
|
// 5) Terrain
|
||||||
let pos = self
|
let pos = self
|
||||||
|
@ -4,17 +4,12 @@ use specs::{Component, FlaggedStorage};
|
|||||||
use specs_idvs::IdvStorage;
|
use specs_idvs::IdvStorage;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
/// De/buff ID.
|
/// De/buff Kind.
|
||||||
/// ID can be independant of an actual type/config of a `BuffEffect`.
|
/// This is used to determine what effects a buff will have, as well as
|
||||||
/// Therefore, information provided by `BuffId` can be incomplete/incorrect.
|
/// determine the strength and duration of the buff effects using the internal
|
||||||
///
|
/// values
|
||||||
/// For example, there could be two regeneration buffs, each with
|
|
||||||
/// different strength, but they could use the same `BuffId`,
|
|
||||||
/// making it harder to recognize which is which.
|
|
||||||
///
|
|
||||||
/// Also, this should be dehardcoded eventually.
|
|
||||||
#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)]
|
||||||
pub enum BuffId {
|
pub enum BuffKind {
|
||||||
/// Restores health/time for some period
|
/// Restores health/time for some period
|
||||||
Regeneration {
|
Regeneration {
|
||||||
strength: f32,
|
strength: f32,
|
||||||
@ -31,22 +26,21 @@ pub enum BuffId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// De/buff category ID.
|
/// De/buff category ID.
|
||||||
/// Similar to `BuffId`, but to mark a category (for more generic usage, like
|
/// Similar to `BuffKind`, but to mark a category (for more generic usage, like
|
||||||
/// positive/negative buffs).
|
/// positive/negative buffs).
|
||||||
#[derive(Clone, Copy, Eq, PartialEq, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Eq, PartialEq, Debug, Serialize, Deserialize)]
|
||||||
pub enum BuffCategoryId {
|
pub enum BuffCategoryId {
|
||||||
|
// Buff and debuff get added in builder function based off of the buff kind
|
||||||
|
Debuff,
|
||||||
|
Buff,
|
||||||
Natural,
|
Natural,
|
||||||
Physical,
|
Physical,
|
||||||
Magical,
|
Magical,
|
||||||
Divine,
|
Divine,
|
||||||
Debuff,
|
|
||||||
Buff,
|
|
||||||
PersistOnDeath,
|
PersistOnDeath,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data indicating and configuring behaviour of a de/buff.
|
/// Data indicating and configuring behaviour of a de/buff.
|
||||||
///
|
|
||||||
/// NOTE: Contents of this enum are WIP/Placeholder
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub enum BuffEffect {
|
pub enum BuffEffect {
|
||||||
/// Periodically damages or heals entity
|
/// Periodically damages or heals entity
|
||||||
@ -58,23 +52,16 @@ pub enum BuffEffect {
|
|||||||
/// Actual de/buff.
|
/// Actual de/buff.
|
||||||
/// Buff can timeout after some time if `time` is Some. If `time` is None,
|
/// Buff can timeout after some time if `time` is Some. If `time` is None,
|
||||||
/// Buff will last indefinitely, until removed manually (by some action, like
|
/// Buff will last indefinitely, until removed manually (by some action, like
|
||||||
/// uncursing). The `time` field might be moved into the `Buffs` component
|
/// uncursing).
|
||||||
/// (so that `Buff` does not own this information).
|
|
||||||
///
|
///
|
||||||
/// Buff has an id and data, which can be independent on each other.
|
/// Buff has a kind, which is used to determine the effects in a builder
|
||||||
/// This makes it hard to create buff stacking "helpers", as the system
|
/// function.
|
||||||
/// does not assume that the same id is always the same behaviour (data).
|
|
||||||
/// Therefore id=behaviour relationship has to be enforced elsewhere (if
|
|
||||||
/// desired).
|
|
||||||
///
|
///
|
||||||
/// To provide more classification info when needed,
|
/// To provide more classification info when needed,
|
||||||
/// buff can be in one or more buff category.
|
/// buff can be in one or more buff category.
|
||||||
///
|
|
||||||
/// `data` is separate, to make this system more flexible
|
|
||||||
/// (at the cost of the fact that id=behaviour relationship might not apply).
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct Buff {
|
pub struct Buff {
|
||||||
pub id: BuffId,
|
pub kind: BuffKind,
|
||||||
pub cat_ids: Vec<BuffCategoryId>,
|
pub cat_ids: Vec<BuffCategoryId>,
|
||||||
pub time: Option<Duration>,
|
pub time: Option<Duration>,
|
||||||
pub effects: Vec<BuffEffect>,
|
pub effects: Vec<BuffEffect>,
|
||||||
@ -88,10 +75,12 @@ pub enum BuffChange {
|
|||||||
/// Adds this buff.
|
/// Adds this buff.
|
||||||
Add(Buff),
|
Add(Buff),
|
||||||
/// Removes all buffs with this ID.
|
/// Removes all buffs with this ID.
|
||||||
RemoveById(BuffId),
|
RemoveByKind(BuffKind),
|
||||||
|
/// Removes all buffs with this ID, but not debuffs.
|
||||||
|
RemoveFromClient(BuffKind),
|
||||||
/// Removes buffs of these indices (first vec is for active buffs, second is
|
/// Removes buffs of these indices (first vec is for active buffs, second is
|
||||||
/// for inactive buffs)
|
/// for inactive buffs), should only be called when buffs expire
|
||||||
RemoveByIndex(Vec<usize>, Vec<usize>),
|
RemoveExpiredByIndex(Vec<usize>, Vec<usize>),
|
||||||
/// Removes buffs of these categories (first vec is of categories of which
|
/// Removes buffs of these categories (first vec is of categories of which
|
||||||
/// all are required, second vec is of categories of which at least one is
|
/// all are required, second vec is of categories of which at least one is
|
||||||
/// required, third vec is of categories that will not be removed)
|
/// required, third vec is of categories that will not be removed)
|
||||||
@ -139,37 +128,40 @@ pub struct Buffs {
|
|||||||
pub inactive_buffs: Vec<Buff>,
|
pub inactive_buffs: Vec<Buff>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Buffs {
|
|
||||||
/// This is a primitive check if a specific buff is present and active.
|
|
||||||
/// (for purposes like blocking usage of abilities or something like this).
|
|
||||||
pub fn has_buff_id(&self, id: &BuffId) -> bool {
|
|
||||||
self.active_buffs.iter().any(|buff| buff.id == *id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Buff {
|
impl Buff {
|
||||||
pub fn new(id: BuffId, cat_ids: Vec<BuffCategoryId>, source: BuffSource) -> Self {
|
/// Builder function for buffs
|
||||||
let (effects, time) = match id {
|
pub fn new(kind: BuffKind, cat_ids: Vec<BuffCategoryId>, source: BuffSource) -> Self {
|
||||||
BuffId::Bleeding { strength, duration } => (
|
let mut cat_ids = cat_ids;
|
||||||
vec![BuffEffect::HealthChangeOverTime {
|
let (effects, time) = match kind {
|
||||||
rate: -strength,
|
BuffKind::Bleeding { strength, duration } => {
|
||||||
accumulated: 0.0,
|
cat_ids.push(BuffCategoryId::Debuff);
|
||||||
}],
|
(
|
||||||
duration,
|
vec![BuffEffect::HealthChangeOverTime {
|
||||||
),
|
rate: -strength,
|
||||||
BuffId::Regeneration { strength, duration } => (
|
accumulated: 0.0,
|
||||||
vec![BuffEffect::HealthChangeOverTime {
|
}],
|
||||||
rate: strength,
|
duration,
|
||||||
accumulated: 0.0,
|
)
|
||||||
}],
|
},
|
||||||
duration,
|
BuffKind::Regeneration { strength, duration } => {
|
||||||
),
|
cat_ids.push(BuffCategoryId::Buff);
|
||||||
BuffId::Cursed { duration } => (
|
(
|
||||||
vec![BuffEffect::NameChange {
|
vec![BuffEffect::HealthChangeOverTime {
|
||||||
prefix: String::from("Cursed "),
|
rate: strength,
|
||||||
}],
|
accumulated: 0.0,
|
||||||
duration,
|
}],
|
||||||
),
|
duration,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
BuffKind::Cursed { duration } => {
|
||||||
|
cat_ids.push(BuffCategoryId::Debuff);
|
||||||
|
(
|
||||||
|
vec![BuffEffect::NameChange {
|
||||||
|
prefix: String::from("Cursed "),
|
||||||
|
}],
|
||||||
|
duration,
|
||||||
|
)
|
||||||
|
},
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cat_ids
|
cat_ids
|
||||||
@ -179,7 +171,7 @@ impl Buff {
|
|||||||
"Buff must have either buff or debuff category."
|
"Buff must have either buff or debuff category."
|
||||||
);
|
);
|
||||||
Buff {
|
Buff {
|
||||||
id,
|
kind,
|
||||||
cat_ids,
|
cat_ids,
|
||||||
time,
|
time,
|
||||||
effects,
|
effects,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
comp::{inventory::slot::Slot, BuffId},
|
comp::{inventory::slot::Slot, BuffKind},
|
||||||
sync::Uid,
|
sync::Uid,
|
||||||
util::Dir,
|
util::Dir,
|
||||||
};
|
};
|
||||||
@ -41,7 +41,7 @@ pub enum ControlEvent {
|
|||||||
Unmount,
|
Unmount,
|
||||||
InventoryManip(InventoryManip),
|
InventoryManip(InventoryManip),
|
||||||
GroupManip(GroupManip),
|
GroupManip(GroupManip),
|
||||||
RemoveBuff(BuffId),
|
RemoveBuff(BuffKind),
|
||||||
Respawn,
|
Respawn,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ pub use body::{
|
|||||||
biped_large, bird_medium, bird_small, dragon, fish_medium, fish_small, golem, humanoid, object,
|
biped_large, bird_medium, bird_small, dragon, fish_medium, fish_small, golem, humanoid, object,
|
||||||
quadruped_low, quadruped_medium, quadruped_small, theropod, AllBodies, Body, BodyData,
|
quadruped_low, quadruped_medium, quadruped_small, theropod, AllBodies, Body, BodyData,
|
||||||
};
|
};
|
||||||
pub use buff::{Buff, BuffCategoryId, BuffChange, BuffEffect, BuffId, BuffSource, Buffs};
|
pub use buff::{Buff, BuffCategoryId, BuffChange, BuffEffect, BuffKind, BuffSource, Buffs};
|
||||||
pub use character_state::{Attacking, CharacterState, StateUpdate};
|
pub use character_state::{Attacking, CharacterState, StateUpdate};
|
||||||
pub use chat::{
|
pub use chat::{
|
||||||
ChatMode, ChatMsg, ChatType, Faction, SpeechBubble, SpeechBubbleType, UnresolvedChatMsg,
|
ChatMode, ChatMsg, ChatType, Faction, SpeechBubble, SpeechBubbleType, UnresolvedChatMsg,
|
||||||
|
@ -684,7 +684,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
for (_invite, /*alignment,*/ agent, controller) in
|
for (_invite, /*alignment,*/ agent, controller) in
|
||||||
(&invites, /*&alignments,*/ &mut agents, &mut controllers).join()
|
(&invites, /*&alignments,*/ &mut agents, &mut controllers).join()
|
||||||
{
|
{
|
||||||
let accept = true; // set back to "matches!(alignment, Alignment::Npc)" when we got better NPC recruitment mechanics
|
let accept = false; // set back to "matches!(alignment, Alignment::Npc)" when we got better NPC recruitment mechanics
|
||||||
if accept {
|
if accept {
|
||||||
// Clear agent comp
|
// Clear agent comp
|
||||||
*agent = Agent::default();
|
*agent = Agent::default();
|
||||||
|
@ -23,33 +23,62 @@ impl<'a> System<'a> for Sys {
|
|||||||
|
|
||||||
fn run(&mut self, (dt, server_bus, uids, stats, mut buffs): Self::SystemData) {
|
fn run(&mut self, (dt, server_bus, uids, stats, mut buffs): Self::SystemData) {
|
||||||
let mut server_emitter = server_bus.emitter();
|
let mut server_emitter = server_bus.emitter();
|
||||||
for (uid, stat, mut buffs) in (&uids, &stats, &mut buffs.restrict_mut()).join() {
|
// Set to false to avoid spamming server
|
||||||
let buff_comp = buffs.get_mut_unchecked();
|
buffs.set_event_emission(false);
|
||||||
|
for (buff_comp, uid) in (&mut buffs, &uids).join() {
|
||||||
let (mut active_buff_indices_for_removal, mut inactive_buff_indices_for_removal) =
|
let (mut active_buff_indices_for_removal, mut inactive_buff_indices_for_removal) =
|
||||||
(Vec::<usize>::new(), Vec::<usize>::new());
|
(Vec::<usize>::new(), Vec::<usize>::new());
|
||||||
// Tick all de/buffs on a Buffs component.
|
|
||||||
for (i, active_buff) in buff_comp.active_buffs.iter_mut().enumerate() {
|
for (i, active_buff) in buff_comp.active_buffs.iter_mut().enumerate() {
|
||||||
// First, tick the buff and subtract delta from it
|
// Tick the buff and subtract delta from it
|
||||||
// and return how much "real" time the buff took (for tick independence).
|
if let Some(remaining_time) = &mut active_buff.time {
|
||||||
let buff_delta = if let Some(remaining_time) = &mut active_buff.time {
|
|
||||||
let pre_tick = remaining_time.as_secs_f32();
|
|
||||||
let new_duration = remaining_time.checked_sub(Duration::from_secs_f32(dt.0));
|
let new_duration = remaining_time.checked_sub(Duration::from_secs_f32(dt.0));
|
||||||
let post_tick = if let Some(dur) = new_duration {
|
if new_duration.is_some() {
|
||||||
// The buff still continues.
|
// The buff still continues.
|
||||||
*remaining_time -= Duration::from_secs_f32(dt.0);
|
*remaining_time -= Duration::from_secs_f32(dt.0);
|
||||||
dur.as_secs_f32()
|
|
||||||
} else {
|
} else {
|
||||||
// The buff has expired.
|
// The buff has expired.
|
||||||
// Remove it.
|
// Remove it.
|
||||||
active_buff_indices_for_removal.push(i);
|
active_buff_indices_for_removal.push(i);
|
||||||
0.0
|
active_buff.time = Some(Duration::default());
|
||||||
};
|
};
|
||||||
pre_tick - post_tick
|
}
|
||||||
} else {
|
}
|
||||||
// The buff is indefinite, and it takes full tick (delta).
|
|
||||||
dt.0
|
|
||||||
};
|
|
||||||
|
|
||||||
|
for (i, inactive_buff) in buff_comp.inactive_buffs.iter_mut().enumerate() {
|
||||||
|
// Tick the buff and subtract delta from it
|
||||||
|
if let Some(remaining_time) = &mut inactive_buff.time {
|
||||||
|
let new_duration = remaining_time.checked_sub(Duration::from_secs_f32(dt.0));
|
||||||
|
if new_duration.is_some() {
|
||||||
|
// The buff still continues.
|
||||||
|
*remaining_time -= Duration::from_secs_f32(dt.0);
|
||||||
|
} else {
|
||||||
|
// The buff has expired.
|
||||||
|
// Remove it.
|
||||||
|
inactive_buff_indices_for_removal.push(i);
|
||||||
|
inactive_buff.time = Some(Duration::default());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !active_buff_indices_for_removal.is_empty()
|
||||||
|
|| !inactive_buff_indices_for_removal.is_empty()
|
||||||
|
{
|
||||||
|
server_emitter.emit(ServerEvent::Buff {
|
||||||
|
uid: *uid,
|
||||||
|
buff_change: BuffChange::RemoveExpiredByIndex(
|
||||||
|
active_buff_indices_for_removal,
|
||||||
|
inactive_buff_indices_for_removal,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Set back to true after timer decrement
|
||||||
|
buffs.set_event_emission(true);
|
||||||
|
for (uid, stat, mut buffs) in (&uids, &stats, &mut buffs.restrict_mut()).join() {
|
||||||
|
let buff_comp = buffs.get_mut_unchecked();
|
||||||
|
// Tick all de/buffs on a Buffs component.
|
||||||
|
for active_buff in buff_comp.active_buffs.iter_mut() {
|
||||||
|
// Get buff owner
|
||||||
let buff_owner = if let BuffSource::Character { by: owner } = active_buff.source {
|
let buff_owner = if let BuffSource::Character { by: owner } = active_buff.source {
|
||||||
Some(owner)
|
Some(owner)
|
||||||
} else {
|
} else {
|
||||||
@ -60,12 +89,13 @@ impl<'a> System<'a> for Sys {
|
|||||||
match effect {
|
match effect {
|
||||||
// Only add an effect here if it is continuous or it is not immediate
|
// Only add an effect here if it is continuous or it is not immediate
|
||||||
BuffEffect::HealthChangeOverTime { rate, accumulated } => {
|
BuffEffect::HealthChangeOverTime { rate, accumulated } => {
|
||||||
*accumulated += *rate * buff_delta;
|
*accumulated += *rate * dt.0;
|
||||||
// Apply damage only once a second (with a minimum of 1 damage), or when a buff is removed
|
// Apply damage only once a second (with a minimum of 1 damage), or when
|
||||||
|
// a buff is removed
|
||||||
if accumulated.abs() > rate.abs().max(10.0)
|
if accumulated.abs() > rate.abs().max(10.0)
|
||||||
|| active_buff_indices_for_removal
|
|| active_buff
|
||||||
.iter()
|
.time
|
||||||
.any(|index| *index == i)
|
.map_or(false, |dur| dur == Duration::default())
|
||||||
{
|
{
|
||||||
let cause = if *accumulated > 0.0 {
|
let cause = if *accumulated > 0.0 {
|
||||||
HealthSource::Healing { by: buff_owner }
|
HealthSource::Healing { by: buff_owner }
|
||||||
@ -87,31 +117,6 @@ impl<'a> System<'a> for Sys {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i, inactive_buff) in buff_comp.inactive_buffs.iter_mut().enumerate() {
|
|
||||||
// First, tick the buff and subtract delta from it
|
|
||||||
// and return how much "real" time the buff took (for tick independence).
|
|
||||||
// TODO: handle delta for "indefinite" buffs, i.e. time since they got removed.
|
|
||||||
if let Some(remaining_time) = &mut inactive_buff.time {
|
|
||||||
let new_duration = remaining_time.checked_sub(Duration::from_secs_f32(dt.0));
|
|
||||||
if new_duration.is_some() {
|
|
||||||
// The buff still continues.
|
|
||||||
*remaining_time -= Duration::from_secs_f32(dt.0);
|
|
||||||
} else {
|
|
||||||
// The buff has expired.
|
|
||||||
// Remove it.
|
|
||||||
inactive_buff_indices_for_removal.push(i);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
server_emitter.emit(ServerEvent::Buff {
|
|
||||||
uid: *uid,
|
|
||||||
buff_change: BuffChange::RemoveByIndex(
|
|
||||||
active_buff_indices_for_removal,
|
|
||||||
inactive_buff_indices_for_removal,
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
if stat.is_dead {
|
if stat.is_dead {
|
||||||
server_emitter.emit(ServerEvent::Buff {
|
server_emitter.emit(ServerEvent::Buff {
|
||||||
uid: *uid,
|
uid: *uid,
|
||||||
|
@ -9,6 +9,7 @@ use crate::{
|
|||||||
sync::Uid,
|
sync::Uid,
|
||||||
util::Dir,
|
util::Dir,
|
||||||
};
|
};
|
||||||
|
use rand::{thread_rng, Rng};
|
||||||
use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, WriteStorage};
|
use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, WriteStorage};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
@ -151,37 +152,21 @@ impl<'a> System<'a> for Sys {
|
|||||||
cause,
|
cause,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
// Test for server event of buff, remove before merging
|
// Apply bleeding buff on melee hits with 10% chance
|
||||||
server_emitter.emit(ServerEvent::Buff {
|
// TODO: Don't have buff uniformly applied on all melee attacks
|
||||||
uid: *uid_b,
|
if thread_rng().gen::<f32>() < 0.1 {
|
||||||
buff_change: buff::BuffChange::Add(buff::Buff::new(
|
server_emitter.emit(ServerEvent::Buff {
|
||||||
buff::BuffId::Bleeding {
|
uid: *uid_b,
|
||||||
strength: attack.base_damage as f32,
|
buff_change: buff::BuffChange::Add(buff::Buff::new(
|
||||||
duration: Some(Duration::from_secs(30)),
|
buff::BuffKind::Bleeding {
|
||||||
},
|
strength: attack.base_damage as f32 / 10.0,
|
||||||
vec![buff::BuffCategoryId::Physical, buff::BuffCategoryId::Debuff],
|
duration: Some(Duration::from_secs(10)),
|
||||||
buff::BuffSource::Character { by: *uid },
|
},
|
||||||
)),
|
vec![buff::BuffCategoryId::Physical],
|
||||||
});
|
buff::BuffSource::Character { by: *uid },
|
||||||
server_emitter.emit(ServerEvent::Buff {
|
)),
|
||||||
uid: *uid_b,
|
});
|
||||||
buff_change: buff::BuffChange::Add(buff::Buff::new(
|
}
|
||||||
buff::BuffId::Regeneration {
|
|
||||||
strength: 1.0,
|
|
||||||
duration: Some(Duration::from_secs(60)),
|
|
||||||
},
|
|
||||||
vec![buff::BuffCategoryId::Physical, buff::BuffCategoryId::Buff],
|
|
||||||
buff::BuffSource::Character { by: *uid },
|
|
||||||
)),
|
|
||||||
});
|
|
||||||
server_emitter.emit(ServerEvent::Buff {
|
|
||||||
uid: *uid_b,
|
|
||||||
buff_change: buff::BuffChange::Add(buff::Buff::new(
|
|
||||||
buff::BuffId::Cursed { duration: None },
|
|
||||||
vec![buff::BuffCategoryId::Physical, buff::BuffCategoryId::Debuff],
|
|
||||||
buff::BuffSource::Character { by: *uid },
|
|
||||||
)),
|
|
||||||
});
|
|
||||||
attack.hit_count += 1;
|
attack.hit_count += 1;
|
||||||
}
|
}
|
||||||
if attack.knockback != 0.0 && damage.healthchange != 0.0 {
|
if attack.knockback != 0.0 && damage.healthchange != 0.0 {
|
||||||
|
@ -86,7 +86,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
ControlEvent::RemoveBuff(buff_id) => {
|
ControlEvent::RemoveBuff(buff_id) => {
|
||||||
server_emitter.emit(ServerEvent::Buff {
|
server_emitter.emit(ServerEvent::Buff {
|
||||||
uid: *uid,
|
uid: *uid,
|
||||||
buff_change: BuffChange::RemoveById(buff_id),
|
buff_change: BuffChange::RemoveFromClient(buff_id),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
ControlEvent::Unmount => server_emitter.emit(ServerEvent::Unmount(entity)),
|
ControlEvent::Unmount => server_emitter.emit(ServerEvent::Unmount(entity)),
|
||||||
|
@ -724,7 +724,7 @@ pub fn handle_buff(server: &mut Server, uid: Uid, buff_change: buff::BuffChange)
|
|||||||
// inactive buffs, or move active buff to
|
// inactive buffs, or move active buff to
|
||||||
// inactive buffs and add new buff to active
|
// inactive buffs and add new buff to active
|
||||||
// buffs.
|
// buffs.
|
||||||
if discriminant(&active_buff.id) == discriminant(&new_buff.id) {
|
if discriminant(&active_buff.kind) == discriminant(&new_buff.kind) {
|
||||||
duplicate_existed = true;
|
duplicate_existed = true;
|
||||||
// Determines if active buff is weaker than newer buff
|
// Determines if active buff is weaker than newer buff
|
||||||
if determine_replace_active_buff(
|
if determine_replace_active_buff(
|
||||||
@ -761,19 +761,40 @@ pub fn handle_buff(server: &mut Server, uid: Uid, buff_change: buff::BuffChange)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
BuffChange::RemoveByIndex(active_indices, inactive_indices) => {
|
BuffChange::RemoveExpiredByIndex(active_indices, inactive_indices) => {
|
||||||
active_buff_indices_for_removal = active_indices;
|
active_buff_indices_for_removal = active_indices;
|
||||||
inactive_buff_indices_for_removal = inactive_indices;
|
inactive_buff_indices_for_removal = inactive_indices;
|
||||||
},
|
},
|
||||||
BuffChange::RemoveById(id) => {
|
BuffChange::RemoveByKind(kind) => {
|
||||||
let some_predicate = |current_id: &buff::BuffId| *current_id == id;
|
|
||||||
for (i, buff) in buffs.active_buffs.iter().enumerate() {
|
for (i, buff) in buffs.active_buffs.iter().enumerate() {
|
||||||
if some_predicate(&buff.id) {
|
if discriminant(&kind) == discriminant(&buff.kind) {
|
||||||
active_buff_indices_for_removal.push(i);
|
active_buff_indices_for_removal.push(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (i, buff) in buffs.inactive_buffs.iter().enumerate() {
|
for (i, buff) in buffs.inactive_buffs.iter().enumerate() {
|
||||||
if some_predicate(&buff.id) {
|
if discriminant(&kind) == discriminant(&buff.kind) {
|
||||||
|
inactive_buff_indices_for_removal.push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
BuffChange::RemoveFromClient(kind) => {
|
||||||
|
for (i, buff) in buffs.active_buffs.iter().enumerate() {
|
||||||
|
if discriminant(&kind) == discriminant(&buff.kind)
|
||||||
|
&& buff
|
||||||
|
.cat_ids
|
||||||
|
.iter()
|
||||||
|
.any(|cat| *cat == buff::BuffCategoryId::Buff)
|
||||||
|
{
|
||||||
|
active_buff_indices_for_removal.push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i, buff) in buffs.inactive_buffs.iter().enumerate() {
|
||||||
|
if discriminant(&kind) == discriminant(&buff.kind)
|
||||||
|
&& buff
|
||||||
|
.cat_ids
|
||||||
|
.iter()
|
||||||
|
.any(|cat| *cat == buff::BuffCategoryId::Buff)
|
||||||
|
{
|
||||||
inactive_buff_indices_for_removal.push(i);
|
inactive_buff_indices_for_removal.push(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -830,11 +851,11 @@ pub fn handle_buff(server: &mut Server, uid: Uid, buff_change: buff::BuffChange)
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
let mut removed_active_buff_ids = Vec::new();
|
let mut removed_active_buff_kinds = Vec::new();
|
||||||
while !active_buff_indices_for_removal.is_empty() {
|
while !active_buff_indices_for_removal.is_empty() {
|
||||||
if let Some(i) = active_buff_indices_for_removal.pop() {
|
if let Some(i) = active_buff_indices_for_removal.pop() {
|
||||||
let buff = buffs.active_buffs.remove(i);
|
let buff = buffs.active_buffs.remove(i);
|
||||||
removed_active_buff_ids.push(buff.id);
|
removed_active_buff_kinds.push(buff.kind);
|
||||||
remove_buff_effects(buff, stats.get_mut(entity));
|
remove_buff_effects(buff, stats.get_mut(entity));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -845,19 +866,19 @@ pub fn handle_buff(server: &mut Server, uid: Uid, buff_change: buff::BuffChange)
|
|||||||
}
|
}
|
||||||
// Checks after buffs are removed so that it doesn't grab incorrect
|
// Checks after buffs are removed so that it doesn't grab incorrect
|
||||||
// index
|
// index
|
||||||
for buff_id in removed_active_buff_ids {
|
for buff_kind in removed_active_buff_kinds {
|
||||||
// Checks to verify that there are no active buffs with the same id
|
// Checks to verify that there are no active buffs with the same id
|
||||||
if buffs
|
if buffs
|
||||||
.active_buffs
|
.active_buffs
|
||||||
.iter()
|
.iter()
|
||||||
.any(|buff| discriminant(&buff.id) == discriminant(&buff_id))
|
.any(|buff| discriminant(&buff.kind) == discriminant(&buff_kind))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let mut new_active_buff = None::<buff::Buff>;
|
let mut new_active_buff = None::<buff::Buff>;
|
||||||
let mut replacement_buff_index = 0;
|
let mut replacement_buff_index = 0;
|
||||||
for (i, inactive_buff) in buffs.inactive_buffs.iter().enumerate() {
|
for (i, inactive_buff) in buffs.inactive_buffs.iter().enumerate() {
|
||||||
if discriminant(&buff_id) == discriminant(&inactive_buff.id) {
|
if discriminant(&buff_kind) == discriminant(&inactive_buff.kind) {
|
||||||
if let Some(ref buff) = new_active_buff {
|
if let Some(ref buff) = new_active_buff {
|
||||||
if determine_replace_active_buff(buff.clone(), inactive_buff.clone()) {
|
if determine_replace_active_buff(buff.clone(), inactive_buff.clone()) {
|
||||||
new_active_buff = Some(inactive_buff.clone());
|
new_active_buff = Some(inactive_buff.clone());
|
||||||
@ -880,16 +901,16 @@ pub fn handle_buff(server: &mut Server, uid: Uid, buff_change: buff::BuffChange)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn determine_replace_active_buff(active_buff: buff::Buff, new_buff: buff::Buff) -> bool {
|
fn determine_replace_active_buff(active_buff: buff::Buff, new_buff: buff::Buff) -> bool {
|
||||||
use buff::BuffId;
|
use buff::BuffKind;
|
||||||
match new_buff.id {
|
match new_buff.kind {
|
||||||
BuffId::Bleeding {
|
BuffKind::Bleeding {
|
||||||
strength: new_strength,
|
strength: new_strength,
|
||||||
duration: new_duration,
|
duration: new_duration,
|
||||||
} => {
|
} => {
|
||||||
if let BuffId::Bleeding {
|
if let BuffKind::Bleeding {
|
||||||
strength: active_strength,
|
strength: active_strength,
|
||||||
duration: _,
|
duration: _,
|
||||||
} = active_buff.id
|
} = active_buff.kind
|
||||||
{
|
{
|
||||||
new_strength > active_strength
|
new_strength > active_strength
|
||||||
|| (new_strength >= active_strength
|
|| (new_strength >= active_strength
|
||||||
@ -900,14 +921,14 @@ fn determine_replace_active_buff(active_buff: buff::Buff, new_buff: buff::Buff)
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
BuffId::Regeneration {
|
BuffKind::Regeneration {
|
||||||
strength: new_strength,
|
strength: new_strength,
|
||||||
duration: new_duration,
|
duration: new_duration,
|
||||||
} => {
|
} => {
|
||||||
if let BuffId::Regeneration {
|
if let BuffKind::Regeneration {
|
||||||
strength: active_strength,
|
strength: active_strength,
|
||||||
duration: _,
|
duration: _,
|
||||||
} = active_buff.id
|
} = active_buff.kind
|
||||||
{
|
{
|
||||||
new_strength > active_strength
|
new_strength > active_strength
|
||||||
|| (new_strength >= active_strength
|
|| (new_strength >= active_strength
|
||||||
@ -918,7 +939,7 @@ fn determine_replace_active_buff(active_buff: buff::Buff, new_buff: buff::Buff)
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
BuffId::Cursed {
|
BuffKind::Cursed {
|
||||||
duration: new_duration,
|
duration: new_duration,
|
||||||
} => new_duration.map_or(true, |new_dur| {
|
} => new_duration.map_or(true, |new_dur| {
|
||||||
active_buff.time.map_or(false, |act_dur| new_dur > act_dur)
|
active_buff.time.map_or(false, |act_dur| new_dur > act_dur)
|
||||||
|
@ -74,7 +74,6 @@ treeculler = "0.1.0"
|
|||||||
uvth = "3.1.1"
|
uvth = "3.1.1"
|
||||||
# vec_map = { version = "0.8.2" }
|
# vec_map = { version = "0.8.2" }
|
||||||
const-tweaker = {version = "0.3.1", optional = true}
|
const-tweaker = {version = "0.3.1", optional = true}
|
||||||
inline_tweak = "1.0.2"
|
|
||||||
itertools = "0.9.0"
|
itertools = "0.9.0"
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
|
@ -20,7 +20,6 @@ default = ["be-dyn-lib", "simd"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
common = {package = "veloren-common", path = "../../../common"}
|
common = {package = "veloren-common", path = "../../../common"}
|
||||||
find_folder = {version = "0.3.0", optional = true}
|
find_folder = {version = "0.3.0", optional = true}
|
||||||
inline_tweak = "1.0.2"
|
|
||||||
lazy_static = {version = "1.4.0", optional = true}
|
lazy_static = {version = "1.4.0", optional = true}
|
||||||
libloading = {version = "0.6.2", optional = true}
|
libloading = {version = "0.6.2", optional = true}
|
||||||
notify = {version = "5.0.0-pre.2", optional = true}
|
notify = {version = "5.0.0-pre.2", optional = true}
|
||||||
|
@ -9,14 +9,13 @@ use crate::{
|
|||||||
GlobalState,
|
GlobalState,
|
||||||
};
|
};
|
||||||
|
|
||||||
use common::comp::{BuffId, Buffs};
|
use common::comp::{BuffKind, Buffs};
|
||||||
use conrod_core::{
|
use conrod_core::{
|
||||||
color,
|
color,
|
||||||
widget::{self, Button, Image, Rectangle, Text},
|
widget::{self, Button, Image, Rectangle, Text},
|
||||||
widget_ids, Color, Colorable, Positionable, Sizeable, Widget, WidgetCommon,
|
widget_ids, Color, Colorable, Positionable, Sizeable, Widget, WidgetCommon,
|
||||||
};
|
};
|
||||||
use inline_tweak::*;
|
|
||||||
use std::time::Duration;
|
|
||||||
widget_ids! {
|
widget_ids! {
|
||||||
struct Ids {
|
struct Ids {
|
||||||
align,
|
align,
|
||||||
@ -77,7 +76,7 @@ pub struct State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
RemoveBuff(BuffId),
|
RemoveBuff(BuffKind),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Widget for BuffsBar<'a> {
|
impl<'a> Widget for BuffsBar<'a> {
|
||||||
@ -123,7 +122,7 @@ impl<'a> Widget for BuffsBar<'a> {
|
|||||||
if let BuffPosition::Bar = buff_position {
|
if let BuffPosition::Bar = buff_position {
|
||||||
// Alignment
|
// Alignment
|
||||||
Rectangle::fill_with([484.0, 100.0], color::TRANSPARENT)
|
Rectangle::fill_with([484.0, 100.0], color::TRANSPARENT)
|
||||||
.mid_bottom_with_margin_on(ui.window, tweak!(92.0))
|
.mid_bottom_with_margin_on(ui.window, 92.0)
|
||||||
.set(state.ids.align, ui);
|
.set(state.ids.align, ui);
|
||||||
Rectangle::fill_with([484.0 / 2.0, 90.0], color::TRANSPARENT)
|
Rectangle::fill_with([484.0 / 2.0, 90.0], color::TRANSPARENT)
|
||||||
.bottom_left_with_margins_on(state.ids.align, 0.0, 0.0)
|
.bottom_left_with_margins_on(state.ids.align, 0.0, 0.0)
|
||||||
@ -177,14 +176,18 @@ impl<'a> Widget for BuffsBar<'a> {
|
|||||||
)
|
)
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.for_each(|(i, ((id, timer_id), buff))| {
|
.for_each(|(i, ((id, timer_id), buff))| {
|
||||||
let max_duration = match buff.id {
|
let max_duration = match buff.kind {
|
||||||
BuffId::Regeneration { duration, .. } => duration.unwrap().as_secs_f32(),
|
BuffKind::Bleeding { duration, .. } => duration,
|
||||||
_ => 10.0,
|
BuffKind::Regeneration { duration, .. } => duration,
|
||||||
|
BuffKind::Cursed { duration } => duration,
|
||||||
};
|
};
|
||||||
let current_duration = buff.dur;
|
let current_duration = buff.dur;
|
||||||
let duration_percentage = (current_duration / max_duration * 1000.0) as u32; // Percentage to determine which frame of the timer overlay is displayed
|
let duration_percentage = current_duration.map_or(1000.0, |cur| {
|
||||||
let buff_img = match buff.id {
|
max_duration
|
||||||
BuffId::Regeneration { .. } => self.imgs.buff_plus_0,
|
.map_or(1000.0, |max| cur.as_secs_f32() / max.as_secs_f32() * 1000.0)
|
||||||
|
}) as u32; // Percentage to determine which frame of the timer overlay is displayed
|
||||||
|
let buff_img = match buff.kind {
|
||||||
|
BuffKind::Regeneration { .. } => self.imgs.buff_plus_0,
|
||||||
_ => self.imgs.missing_icon,
|
_ => self.imgs.missing_icon,
|
||||||
};
|
};
|
||||||
let buff_widget = Image::new(buff_img).w_h(20.0, 20.0);
|
let buff_widget = Image::new(buff_img).w_h(20.0, 20.0);
|
||||||
@ -197,30 +200,32 @@ impl<'a> Widget for BuffsBar<'a> {
|
|||||||
0.0 + x as f64 * (21.0),
|
0.0 + x as f64 * (21.0),
|
||||||
);
|
);
|
||||||
buff_widget
|
buff_widget
|
||||||
.color(if current_duration < 10.0 {
|
.color(
|
||||||
Some(pulsating_col)
|
if current_duration.map_or(false, |cur| cur.as_secs_f32() < 10.0) {
|
||||||
} else {
|
Some(pulsating_col)
|
||||||
Some(norm_col)
|
} else {
|
||||||
})
|
Some(norm_col)
|
||||||
|
},
|
||||||
|
)
|
||||||
.set(id, ui);
|
.set(id, ui);
|
||||||
// Create Buff tooltip
|
// Create Buff tooltip
|
||||||
let title = match buff.id {
|
let title = match buff.kind {
|
||||||
BuffId::Regeneration { .. } => {
|
BuffKind::Regeneration { .. } => {
|
||||||
*&localized_strings.get("buff.title.heal_test")
|
localized_strings.get("buff.title.heal_test")
|
||||||
},
|
},
|
||||||
_ => *&localized_strings.get("buff.title.missing"),
|
_ => localized_strings.get("buff.title.missing"),
|
||||||
};
|
};
|
||||||
let remaining_time = if current_duration == 10e6 as f32 {
|
let remaining_time = if current_duration.is_none() {
|
||||||
"Permanent".to_string()
|
"Permanent".to_string()
|
||||||
} else {
|
} else {
|
||||||
format!("Remaining: {:.0}s", current_duration)
|
format!("Remaining: {:.0}s", current_duration.unwrap().as_secs_f32())
|
||||||
};
|
};
|
||||||
let click_to_remove = format!("<{}>", &localized_strings.get("buff.remove"));
|
let click_to_remove = format!("<{}>", &localized_strings.get("buff.remove"));
|
||||||
let desc_txt = match buff.id {
|
let desc_txt = match buff.kind {
|
||||||
BuffId::Regeneration { .. } => {
|
BuffKind::Regeneration { .. } => {
|
||||||
*&localized_strings.get("buff.desc.heal_test")
|
localized_strings.get("buff.desc.heal_test")
|
||||||
},
|
},
|
||||||
_ => *&localized_strings.get("buff.desc.missing"),
|
_ => localized_strings.get("buff.desc.missing"),
|
||||||
};
|
};
|
||||||
let desc = format!("{}\n\n{}\n\n{}", desc_txt, remaining_time, click_to_remove);
|
let desc = format!("{}\n\n{}\n\n{}", desc_txt, remaining_time, click_to_remove);
|
||||||
// Timer overlay
|
// Timer overlay
|
||||||
@ -247,7 +252,7 @@ impl<'a> Widget for BuffsBar<'a> {
|
|||||||
.set(timer_id, ui)
|
.set(timer_id, ui)
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
event.push(Event::RemoveBuff(buff.id));
|
event.push(Event::RemoveBuff(buff.kind));
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
// Create Debuff Widgets
|
// Create Debuff Widgets
|
||||||
@ -266,21 +271,19 @@ impl<'a> Widget for BuffsBar<'a> {
|
|||||||
)
|
)
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.for_each(|(i, ((id, timer_id), debuff))| {
|
.for_each(|(i, ((id, timer_id), debuff))| {
|
||||||
let max_duration = match debuff.id {
|
let max_duration = match debuff.kind {
|
||||||
BuffId::Bleeding { duration, .. } => {
|
BuffKind::Bleeding { duration, .. } => duration,
|
||||||
duration.unwrap_or(Duration::from_secs(60)).as_secs_f32()
|
BuffKind::Regeneration { duration, .. } => duration,
|
||||||
},
|
BuffKind::Cursed { duration } => duration,
|
||||||
BuffId::Cursed { duration, .. } => {
|
|
||||||
duration.unwrap_or(Duration::from_secs(60)).as_secs_f32()
|
|
||||||
},
|
|
||||||
|
|
||||||
_ => 10.0,
|
|
||||||
};
|
};
|
||||||
let current_duration = debuff.dur;
|
let current_duration = debuff.dur;
|
||||||
let duration_percentage = current_duration / max_duration * 1000.0; // Percentage to determine which frame of the timer overlay is displayed
|
let duration_percentage = current_duration.map_or(1000.0, |cur| {
|
||||||
let debuff_img = match debuff.id {
|
max_duration
|
||||||
BuffId::Bleeding { .. } => self.imgs.debuff_bleed_0,
|
.map_or(1000.0, |max| cur.as_secs_f32() / max.as_secs_f32() * 1000.0)
|
||||||
BuffId::Cursed { .. } => self.imgs.debuff_skull_0,
|
}) as u32; // Percentage to determine which frame of the timer overlay is displayed
|
||||||
|
let debuff_img = match debuff.kind {
|
||||||
|
BuffKind::Bleeding { .. } => self.imgs.debuff_bleed_0,
|
||||||
|
BuffKind::Cursed { .. } => self.imgs.debuff_skull_0,
|
||||||
_ => self.imgs.missing_icon,
|
_ => self.imgs.missing_icon,
|
||||||
};
|
};
|
||||||
let debuff_widget = Image::new(debuff_img).w_h(20.0, 20.0);
|
let debuff_widget = Image::new(debuff_img).w_h(20.0, 20.0);
|
||||||
@ -294,29 +297,31 @@ impl<'a> Widget for BuffsBar<'a> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
debuff_widget
|
debuff_widget
|
||||||
.color(if current_duration < 10.0 {
|
.color(
|
||||||
Some(pulsating_col)
|
if current_duration.map_or(false, |cur| cur.as_secs_f32() < 10.0) {
|
||||||
} else {
|
Some(pulsating_col)
|
||||||
Some(norm_col)
|
} else {
|
||||||
})
|
Some(norm_col)
|
||||||
|
},
|
||||||
|
)
|
||||||
.set(id, ui);
|
.set(id, ui);
|
||||||
// Create Debuff tooltip
|
// Create Debuff tooltip
|
||||||
let title = match debuff.id {
|
let title = match debuff.kind {
|
||||||
BuffId::Bleeding { .. } => {
|
BuffKind::Bleeding { .. } => {
|
||||||
*&localized_strings.get("debuff.title.bleed_test")
|
localized_strings.get("debuff.title.bleed_test")
|
||||||
},
|
},
|
||||||
_ => *&localized_strings.get("buff.title.missing"),
|
_ => localized_strings.get("buff.title.missing"),
|
||||||
};
|
};
|
||||||
let remaining_time = if current_duration == 10e6 as f32 {
|
let remaining_time = if current_duration.is_none() {
|
||||||
"Permanent".to_string()
|
"Permanent".to_string()
|
||||||
} else {
|
} else {
|
||||||
format!("Remaining: {:.0}s", current_duration)
|
format!("Remaining: {:.0}s", current_duration.unwrap().as_secs_f32())
|
||||||
};
|
};
|
||||||
let desc_txt = match debuff.id {
|
let desc_txt = match debuff.kind {
|
||||||
BuffId::Bleeding { .. } => {
|
BuffKind::Bleeding { .. } => {
|
||||||
*&localized_strings.get("debuff.desc.bleed_test")
|
localized_strings.get("debuff.desc.bleed_test")
|
||||||
},
|
},
|
||||||
_ => *&localized_strings.get("debuff.desc.missing"),
|
_ => localized_strings.get("debuff.desc.missing"),
|
||||||
};
|
};
|
||||||
let desc = format!("{}\n\n{}", desc_txt, remaining_time);
|
let desc = format!("{}\n\n{}", desc_txt, remaining_time);
|
||||||
Image::new(match duration_percentage as u64 {
|
Image::new(match duration_percentage as u64 {
|
||||||
@ -346,7 +351,7 @@ impl<'a> Widget for BuffsBar<'a> {
|
|||||||
if let BuffPosition::Map = buff_position {
|
if let BuffPosition::Map = buff_position {
|
||||||
// Alignment
|
// Alignment
|
||||||
Rectangle::fill_with([210.0, 210.0], color::TRANSPARENT)
|
Rectangle::fill_with([210.0, 210.0], color::TRANSPARENT)
|
||||||
.top_right_with_margins_on(ui.window, 5.0, tweak!(270.0))
|
.top_right_with_margins_on(ui.window, 5.0, 270.0)
|
||||||
.set(state.ids.align, ui);
|
.set(state.ids.align, ui);
|
||||||
|
|
||||||
// Buffs and Debuffs
|
// Buffs and Debuffs
|
||||||
@ -376,18 +381,21 @@ impl<'a> Widget for BuffsBar<'a> {
|
|||||||
.zip(buffs.active_buffs.iter().map(get_buff_info))
|
.zip(buffs.active_buffs.iter().map(get_buff_info))
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.for_each(|(i, (((id, timer_id), txt_id), buff))| {
|
.for_each(|(i, (((id, timer_id), txt_id), buff))| {
|
||||||
let max_duration = match buff.id {
|
let max_duration = match buff.kind {
|
||||||
BuffId::Regeneration { duration, .. } => duration.unwrap().as_secs_f32(),
|
BuffKind::Bleeding { duration, .. } => duration,
|
||||||
BuffId::Bleeding { duration, .. } => duration.unwrap().as_secs_f32(),
|
BuffKind::Regeneration { duration, .. } => duration,
|
||||||
_ => 10e6,
|
BuffKind::Cursed { duration } => duration,
|
||||||
};
|
};
|
||||||
let current_duration = buff.dur;
|
let current_duration = buff.dur;
|
||||||
// Percentage to determine which frame of the timer overlay is displayed
|
// Percentage to determine which frame of the timer overlay is displayed
|
||||||
let duration_percentage = (current_duration / max_duration * 1000.0) as u32;
|
let duration_percentage = current_duration.map_or(1000.0, |cur| {
|
||||||
let buff_img = match buff.id {
|
max_duration
|
||||||
BuffId::Regeneration { .. } => self.imgs.buff_plus_0,
|
.map_or(1000.0, |max| cur.as_secs_f32() / max.as_secs_f32() * 1000.0)
|
||||||
BuffId::Bleeding { .. } => self.imgs.debuff_bleed_0,
|
}) as u32;
|
||||||
BuffId::Cursed { .. } => self.imgs.debuff_skull_0,
|
let buff_img = match buff.kind {
|
||||||
|
BuffKind::Regeneration { .. } => self.imgs.buff_plus_0,
|
||||||
|
BuffKind::Bleeding { .. } => self.imgs.debuff_bleed_0,
|
||||||
|
BuffKind::Cursed { .. } => self.imgs.debuff_skull_0,
|
||||||
};
|
};
|
||||||
let buff_widget = Image::new(buff_img).w_h(40.0, 40.0);
|
let buff_widget = Image::new(buff_img).w_h(40.0, 40.0);
|
||||||
// Sort buffs into rows of 6 slots
|
// Sort buffs into rows of 6 slots
|
||||||
@ -399,41 +407,43 @@ impl<'a> Widget for BuffsBar<'a> {
|
|||||||
0.0 + x as f64 * (42.0),
|
0.0 + x as f64 * (42.0),
|
||||||
);
|
);
|
||||||
buff_widget
|
buff_widget
|
||||||
.color(if current_duration < 10.0 {
|
.color(
|
||||||
Some(pulsating_col)
|
if current_duration.map_or(false, |cur| cur.as_secs_f32() < 10.0) {
|
||||||
} else {
|
Some(pulsating_col)
|
||||||
Some(norm_col)
|
} else {
|
||||||
})
|
Some(norm_col)
|
||||||
|
},
|
||||||
|
)
|
||||||
.set(id, ui);
|
.set(id, ui);
|
||||||
// Create Buff tooltip
|
// Create Buff tooltip
|
||||||
let title = match buff.id {
|
let title = match buff.kind {
|
||||||
BuffId::Regeneration { .. } => {
|
BuffKind::Regeneration { .. } => {
|
||||||
*&localized_strings.get("buff.title.heal_test")
|
localized_strings.get("buff.title.heal_test")
|
||||||
},
|
},
|
||||||
BuffId::Bleeding { .. } => {
|
BuffKind::Bleeding { .. } => {
|
||||||
*&localized_strings.get("debuff.title.bleed_test")
|
localized_strings.get("debuff.title.bleed_test")
|
||||||
},
|
},
|
||||||
_ => *&localized_strings.get("buff.title.missing"),
|
_ => localized_strings.get("buff.title.missing"),
|
||||||
};
|
};
|
||||||
let remaining_time = if current_duration == 10e6 as f32 {
|
let remaining_time = if current_duration.is_none() {
|
||||||
"".to_string()
|
"".to_string()
|
||||||
} else {
|
} else {
|
||||||
format!("{:.0}s", current_duration)
|
format!("{:.0}s", current_duration.unwrap().as_secs_f32())
|
||||||
};
|
};
|
||||||
let click_to_remove = format!("<{}>", &localized_strings.get("buff.remove"));
|
let click_to_remove = format!("<{}>", &localized_strings.get("buff.remove"));
|
||||||
let desc_txt = match buff.id {
|
let desc_txt = match buff.kind {
|
||||||
BuffId::Regeneration { .. } => {
|
BuffKind::Regeneration { .. } => {
|
||||||
*&localized_strings.get("buff.desc.heal_test")
|
localized_strings.get("buff.desc.heal_test")
|
||||||
},
|
},
|
||||||
BuffId::Bleeding { .. } => {
|
BuffKind::Bleeding { .. } => {
|
||||||
*&localized_strings.get("debuff.desc.bleed_test")
|
localized_strings.get("debuff.desc.bleed_test")
|
||||||
},
|
},
|
||||||
_ => *&localized_strings.get("buff.desc.missing"),
|
_ => localized_strings.get("buff.desc.missing"),
|
||||||
};
|
};
|
||||||
let desc = if buff.is_buff {
|
let desc = if buff.is_buff {
|
||||||
format!("{}\n\n{}", desc_txt, click_to_remove)
|
format!("{}\n\n{}", desc_txt, click_to_remove)
|
||||||
} else {
|
} else {
|
||||||
format!("{}", desc_txt)
|
desc_txt.to_string()
|
||||||
};
|
};
|
||||||
// Timer overlay
|
// Timer overlay
|
||||||
if Button::image(match duration_percentage as u64 {
|
if Button::image(match duration_percentage as u64 {
|
||||||
@ -442,7 +452,7 @@ impl<'a> Widget for BuffsBar<'a> {
|
|||||||
625..=749 => self.imgs.buff_1, // 6/8
|
625..=749 => self.imgs.buff_1, // 6/8
|
||||||
500..=624 => self.imgs.buff_2, // 5/8
|
500..=624 => self.imgs.buff_2, // 5/8
|
||||||
375..=499 => self.imgs.buff_3, // 4/8
|
375..=499 => self.imgs.buff_3, // 4/8
|
||||||
250..=374 => self.imgs.buff_4, //3/8
|
250..=374 => self.imgs.buff_4, // 3/8
|
||||||
125..=249 => self.imgs.buff_5, // 2/8
|
125..=249 => self.imgs.buff_5, // 2/8
|
||||||
0..=124 => self.imgs.buff_6, // 1/8
|
0..=124 => self.imgs.buff_6, // 1/8
|
||||||
_ => self.imgs.nothing,
|
_ => self.imgs.nothing,
|
||||||
@ -463,13 +473,11 @@ impl<'a> Widget for BuffsBar<'a> {
|
|||||||
.set(timer_id, ui)
|
.set(timer_id, ui)
|
||||||
.was_clicked()
|
.was_clicked()
|
||||||
{
|
{
|
||||||
if buff.is_buff {
|
event.push(Event::RemoveBuff(buff.kind));
|
||||||
event.push(Event::RemoveBuff(buff.id));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Text::new(&remaining_time)
|
Text::new(&remaining_time)
|
||||||
.down_from(timer_id, tweak!(1.0))
|
.down_from(timer_id, 1.0)
|
||||||
.font_size(self.fonts.cyri.scale(tweak!(10)))
|
.font_size(self.fonts.cyri.scale(10))
|
||||||
.font_id(self.fonts.cyri.conrod_id)
|
.font_id(self.fonts.cyri.conrod_id)
|
||||||
.graphics_for(timer_id)
|
.graphics_for(timer_id)
|
||||||
.color(TEXT_COLOR)
|
.color(TEXT_COLOR)
|
||||||
|
@ -14,7 +14,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use client::{self, Client};
|
use client::{self, Client};
|
||||||
use common::{
|
use common::{
|
||||||
comp::{group::Role, BuffId, Stats},
|
comp::{group::Role, BuffKind, Stats},
|
||||||
sync::{Uid, WorldSyncExt},
|
sync::{Uid, WorldSyncExt},
|
||||||
};
|
};
|
||||||
use conrod_core::{
|
use conrod_core::{
|
||||||
@ -23,7 +23,6 @@ use conrod_core::{
|
|||||||
widget::{self, Button, Image, Rectangle, Scrollbar, Text},
|
widget::{self, Button, Image, Rectangle, Scrollbar, Text},
|
||||||
widget_ids, Color, Colorable, Labelable, Positionable, Sizeable, Widget, WidgetCommon,
|
widget_ids, Color, Colorable, Labelable, Positionable, Sizeable, Widget, WidgetCommon,
|
||||||
};
|
};
|
||||||
use inline_tweak::*;
|
|
||||||
use specs::{saveload::MarkerAllocator, WorldExt};
|
use specs::{saveload::MarkerAllocator, WorldExt};
|
||||||
widget_ids! {
|
widget_ids! {
|
||||||
pub struct Ids {
|
pub struct Ids {
|
||||||
@ -329,7 +328,7 @@ impl<'a> Widget for Group<'a> {
|
|||||||
.ecs()
|
.ecs()
|
||||||
.read_resource::<common::sync::UidAllocator>();
|
.read_resource::<common::sync::UidAllocator>();
|
||||||
let offset = if self.global_state.settings.gameplay.toggle_debug {
|
let offset = if self.global_state.settings.gameplay.toggle_debug {
|
||||||
tweak!(320.0)
|
320.0
|
||||||
} else {
|
} else {
|
||||||
110.0
|
110.0
|
||||||
};
|
};
|
||||||
@ -467,21 +466,23 @@ impl<'a> Widget for Group<'a> {
|
|||||||
.skip(total_buff_count - buff_count)
|
.skip(total_buff_count - buff_count)
|
||||||
.zip(buffs.active_buffs.iter().map(get_buff_info))
|
.zip(buffs.active_buffs.iter().map(get_buff_info))
|
||||||
.for_each(|((id, timer_id), buff)| {
|
.for_each(|((id, timer_id), buff)| {
|
||||||
let max_duration = match buff.id {
|
let max_duration = match buff.kind {
|
||||||
BuffId::Regeneration { duration, .. } => {
|
BuffKind::Bleeding { duration, .. } => duration,
|
||||||
duration.unwrap().as_secs_f32()
|
BuffKind::Regeneration { duration, .. } => duration,
|
||||||
},
|
BuffKind::Cursed { duration } => duration,
|
||||||
_ => 10.0,
|
|
||||||
};
|
};
|
||||||
let pulsating_col = Color::Rgba(1.0, 1.0, 1.0, buff_ani);
|
let pulsating_col = Color::Rgba(1.0, 1.0, 1.0, buff_ani);
|
||||||
let norm_col = Color::Rgba(1.0, 1.0, 1.0, 1.0);
|
let norm_col = Color::Rgba(1.0, 1.0, 1.0, 1.0);
|
||||||
let current_duration = buff.dur;
|
let current_duration = buff.dur;
|
||||||
let duration_percentage =
|
let duration_percentage = current_duration.map_or(1000.0, |cur| {
|
||||||
(current_duration / max_duration * 1000.0) as u32; // Percentage to determine which frame of the timer overlay is displayed
|
max_duration.map_or(1000.0, |max| {
|
||||||
let buff_img = match buff.id {
|
cur.as_secs_f32() / max.as_secs_f32() * 1000.0
|
||||||
BuffId::Regeneration { .. } => self.imgs.buff_plus_0,
|
})
|
||||||
BuffId::Bleeding { .. } => self.imgs.debuff_bleed_0,
|
}) as u32; // Percentage to determine which frame of the timer overlay is displayed
|
||||||
BuffId::Cursed { .. } => self.imgs.debuff_skull_0,
|
let buff_img = match buff.kind {
|
||||||
|
BuffKind::Regeneration { .. } => self.imgs.buff_plus_0,
|
||||||
|
BuffKind::Bleeding { .. } => self.imgs.debuff_bleed_0,
|
||||||
|
BuffKind::Cursed { .. } => self.imgs.debuff_skull_0,
|
||||||
};
|
};
|
||||||
let buff_widget = Image::new(buff_img).w_h(15.0, 15.0);
|
let buff_widget = Image::new(buff_img).w_h(15.0, 15.0);
|
||||||
let buff_widget = if let Some(id) = prev_id {
|
let buff_widget = if let Some(id) = prev_id {
|
||||||
@ -495,35 +496,42 @@ impl<'a> Widget for Group<'a> {
|
|||||||
};
|
};
|
||||||
prev_id = Some(id);
|
prev_id = Some(id);
|
||||||
buff_widget
|
buff_widget
|
||||||
.color(if current_duration < 10.0 {
|
.color(
|
||||||
Some(pulsating_col)
|
if current_duration
|
||||||
} else {
|
.map_or(false, |cur| cur.as_secs_f32() < 10.0)
|
||||||
Some(norm_col)
|
{
|
||||||
})
|
Some(pulsating_col)
|
||||||
|
} else {
|
||||||
|
Some(norm_col)
|
||||||
|
},
|
||||||
|
)
|
||||||
.set(id, ui);
|
.set(id, ui);
|
||||||
// Create Buff tooltip
|
// Create Buff tooltip
|
||||||
let title = match buff.id {
|
let title = match buff.kind {
|
||||||
BuffId::Regeneration { .. } => {
|
BuffKind::Regeneration { .. } => {
|
||||||
*&localized_strings.get("buff.title.heal_test")
|
localized_strings.get("buff.title.heal_test")
|
||||||
},
|
},
|
||||||
BuffId::Bleeding { .. } => {
|
BuffKind::Bleeding { .. } => {
|
||||||
*&localized_strings.get("debuff.title.bleed_test")
|
localized_strings.get("debuff.title.bleed_test")
|
||||||
},
|
},
|
||||||
_ => *&localized_strings.get("buff.title.missing"),
|
_ => localized_strings.get("buff.title.missing"),
|
||||||
};
|
};
|
||||||
let remaining_time = if current_duration == 10e6 as f32 {
|
let remaining_time = if current_duration.is_none() {
|
||||||
"Permanent".to_string()
|
"Permanent".to_string()
|
||||||
} else {
|
} else {
|
||||||
format!("Remaining: {:.0}s", current_duration)
|
format!(
|
||||||
|
"Remaining: {:.0}s",
|
||||||
|
current_duration.unwrap().as_secs_f32()
|
||||||
|
)
|
||||||
};
|
};
|
||||||
let desc_txt = match buff.id {
|
let desc_txt = match buff.kind {
|
||||||
BuffId::Regeneration { .. } => {
|
BuffKind::Regeneration { .. } => {
|
||||||
*&localized_strings.get("buff.desc.heal_test")
|
localized_strings.get("buff.desc.heal_test")
|
||||||
},
|
},
|
||||||
BuffId::Bleeding { .. } => {
|
BuffKind::Bleeding { .. } => {
|
||||||
*&localized_strings.get("debuff.desc.bleed_test")
|
localized_strings.get("debuff.desc.bleed_test")
|
||||||
},
|
},
|
||||||
_ => *&localized_strings.get("buff.desc.missing"),
|
_ => localized_strings.get("buff.desc.missing"),
|
||||||
};
|
};
|
||||||
let desc = format!("{}\n\n{}", desc_txt, remaining_time);
|
let desc = format!("{}\n\n{}", desc_txt, remaining_time);
|
||||||
Image::new(match duration_percentage as u64 {
|
Image::new(match duration_percentage as u64 {
|
||||||
|
@ -62,7 +62,7 @@ use common::{
|
|||||||
comp,
|
comp,
|
||||||
comp::{
|
comp::{
|
||||||
item::{ItemDesc, Quality},
|
item::{ItemDesc, Quality},
|
||||||
BuffId,
|
BuffKind,
|
||||||
},
|
},
|
||||||
span,
|
span,
|
||||||
sync::Uid,
|
sync::Uid,
|
||||||
@ -274,9 +274,9 @@ widget_ids! {
|
|||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct BuffInfo {
|
pub struct BuffInfo {
|
||||||
id: comp::BuffId,
|
kind: comp::BuffKind,
|
||||||
is_buff: bool,
|
is_buff: bool,
|
||||||
dur: f32,
|
dur: Option<Duration>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DebugInfo {
|
pub struct DebugInfo {
|
||||||
@ -364,7 +364,7 @@ pub enum Event {
|
|||||||
KickMember(common::sync::Uid),
|
KickMember(common::sync::Uid),
|
||||||
LeaveGroup,
|
LeaveGroup,
|
||||||
AssignLeader(common::sync::Uid),
|
AssignLeader(common::sync::Uid),
|
||||||
RemoveBuff(BuffId),
|
RemoveBuff(BuffKind),
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Are these the possible layouts we want?
|
// TODO: Are these the possible layouts we want?
|
||||||
@ -1145,7 +1145,7 @@ impl Hud {
|
|||||||
let speech_bubbles = &self.speech_bubbles;
|
let speech_bubbles = &self.speech_bubbles;
|
||||||
|
|
||||||
// Render overhead name tags and health bars
|
// Render overhead name tags and health bars
|
||||||
for (pos, info, bubble, stats, buffs, height_offset, hpfl, in_group) in (
|
for (pos, info, bubble, stats, _, height_offset, hpfl, in_group) in (
|
||||||
&entities,
|
&entities,
|
||||||
&pos,
|
&pos,
|
||||||
interpolated.maybe(),
|
interpolated.maybe(),
|
||||||
@ -2728,14 +2728,11 @@ pub fn get_quality_col<I: ItemDesc>(item: &I) -> Color {
|
|||||||
// Get info about applied buffs
|
// Get info about applied buffs
|
||||||
fn get_buff_info(buff: &comp::Buff) -> BuffInfo {
|
fn get_buff_info(buff: &comp::Buff) -> BuffInfo {
|
||||||
BuffInfo {
|
BuffInfo {
|
||||||
id: buff.id,
|
kind: buff.kind,
|
||||||
is_buff: buff
|
is_buff: buff
|
||||||
.cat_ids
|
.cat_ids
|
||||||
.iter()
|
.iter()
|
||||||
.any(|cat| *cat == comp::BuffCategoryId::Buff),
|
.any(|cat| *cat == comp::BuffCategoryId::Buff),
|
||||||
dur: buff
|
dur: buff.time,
|
||||||
.time
|
|
||||||
.map(|dur| dur.as_secs_f32())
|
|
||||||
.unwrap_or(10e6 as f32),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,14 +8,13 @@ use crate::{
|
|||||||
settings::GameplaySettings,
|
settings::GameplaySettings,
|
||||||
ui::{fonts::ConrodVoxygenFonts, Ingameable},
|
ui::{fonts::ConrodVoxygenFonts, Ingameable},
|
||||||
};
|
};
|
||||||
use common::comp::{BuffId, Buffs, Energy, SpeechBubble, SpeechBubbleType, Stats};
|
use common::comp::{BuffKind, Buffs, Energy, SpeechBubble, SpeechBubbleType, Stats};
|
||||||
use conrod_core::{
|
use conrod_core::{
|
||||||
color,
|
color,
|
||||||
position::Align,
|
position::Align,
|
||||||
widget::{self, Image, Rectangle, Text},
|
widget::{self, Image, Rectangle, Text},
|
||||||
widget_ids, Color, Colorable, Positionable, Sizeable, Widget, WidgetCommon,
|
widget_ids, Color, Colorable, Positionable, Sizeable, Widget, WidgetCommon,
|
||||||
};
|
};
|
||||||
use inline_tweak::*;
|
|
||||||
const MAX_BUBBLE_WIDTH: f64 = 250.0;
|
const MAX_BUBBLE_WIDTH: f64 = 250.0;
|
||||||
|
|
||||||
widget_ids! {
|
widget_ids! {
|
||||||
@ -55,11 +54,6 @@ widget_ids! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*pub struct BuffInfo {
|
|
||||||
id: comp::BuffId,
|
|
||||||
dur: f32,
|
|
||||||
}*/
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct Info<'a> {
|
pub struct Info<'a> {
|
||||||
pub name: &'a str,
|
pub name: &'a str,
|
||||||
@ -211,8 +205,8 @@ impl<'a> Widget for Overhead<'a> {
|
|||||||
// Buffs
|
// Buffs
|
||||||
// Alignment
|
// Alignment
|
||||||
let buff_count = buffs.active_buffs.len().min(11);
|
let buff_count = buffs.active_buffs.len().min(11);
|
||||||
Rectangle::fill_with([tweak!(168.0), tweak!(100.0)], color::TRANSPARENT)
|
Rectangle::fill_with([168.0, 100.0], color::TRANSPARENT)
|
||||||
.x_y(-1.0, name_y + tweak!(60.0))
|
.x_y(-1.0, name_y + 60.0)
|
||||||
.parent(id)
|
.parent(id)
|
||||||
.set(state.ids.buffs_align, ui);
|
.set(state.ids.buffs_align, ui);
|
||||||
|
|
||||||
@ -239,18 +233,21 @@ impl<'a> Widget for Overhead<'a> {
|
|||||||
.enumerate()
|
.enumerate()
|
||||||
.for_each(|(i, ((id, timer_id), buff))| {
|
.for_each(|(i, ((id, timer_id), buff))| {
|
||||||
// Limit displayed buffs
|
// Limit displayed buffs
|
||||||
let max_duration = match buff.id {
|
let max_duration = match buff.kind {
|
||||||
BuffId::Regeneration { duration, .. } => {
|
BuffKind::Bleeding { duration, .. } => duration,
|
||||||
duration.unwrap().as_secs_f32()
|
BuffKind::Regeneration { duration, .. } => duration,
|
||||||
},
|
BuffKind::Cursed { duration } => duration,
|
||||||
_ => 10.0,
|
|
||||||
};
|
};
|
||||||
let current_duration = buff.dur;
|
let current_duration = buff.dur;
|
||||||
let duration_percentage = (current_duration / max_duration * 1000.0) as u32; // Percentage to determine which frame of the timer overlay is displayed
|
let duration_percentage = current_duration.map_or(1000.0, |cur| {
|
||||||
let buff_img = match buff.id {
|
max_duration.map_or(1000.0, |max| {
|
||||||
BuffId::Regeneration { .. } => self.imgs.buff_plus_0,
|
cur.as_secs_f32() / max.as_secs_f32() * 1000.0
|
||||||
BuffId::Bleeding { .. } => self.imgs.debuff_bleed_0,
|
})
|
||||||
BuffId::Cursed { .. } => self.imgs.debuff_skull_0,
|
}) as u32; // Percentage to determine which frame of the timer overlay is displayed
|
||||||
|
let buff_img = match buff.kind {
|
||||||
|
BuffKind::Regeneration { .. } => self.imgs.buff_plus_0,
|
||||||
|
BuffKind::Bleeding { .. } => self.imgs.debuff_bleed_0,
|
||||||
|
BuffKind::Cursed { .. } => self.imgs.debuff_skull_0,
|
||||||
};
|
};
|
||||||
let buff_widget = Image::new(buff_img).w_h(20.0, 20.0);
|
let buff_widget = Image::new(buff_img).w_h(20.0, 20.0);
|
||||||
// Sort buffs into rows of 5 slots
|
// Sort buffs into rows of 5 slots
|
||||||
@ -262,11 +259,13 @@ impl<'a> Widget for Overhead<'a> {
|
|||||||
0.0 + x as f64 * (21.0),
|
0.0 + x as f64 * (21.0),
|
||||||
);
|
);
|
||||||
buff_widget
|
buff_widget
|
||||||
.color(if current_duration < 10.0 {
|
.color(
|
||||||
Some(pulsating_col)
|
if current_duration.map_or(false, |cur| cur.as_secs_f32() < 10.0) {
|
||||||
} else {
|
Some(pulsating_col)
|
||||||
Some(norm_col)
|
} else {
|
||||||
})
|
Some(norm_col)
|
||||||
|
},
|
||||||
|
)
|
||||||
.set(id, ui);
|
.set(id, ui);
|
||||||
|
|
||||||
Image::new(match duration_percentage as u64 {
|
Image::new(match duration_percentage as u64 {
|
||||||
@ -275,7 +274,7 @@ impl<'a> Widget for Overhead<'a> {
|
|||||||
625..=749 => self.imgs.buff_1, // 6/8
|
625..=749 => self.imgs.buff_1, // 6/8
|
||||||
500..=624 => self.imgs.buff_2, // 5/8
|
500..=624 => self.imgs.buff_2, // 5/8
|
||||||
375..=499 => self.imgs.buff_3, // 4/8
|
375..=499 => self.imgs.buff_3, // 4/8
|
||||||
250..=374 => self.imgs.buff_4, //3/8
|
250..=374 => self.imgs.buff_4, // 3/8
|
||||||
125..=249 => self.imgs.buff_5, // 2/8
|
125..=249 => self.imgs.buff_5, // 2/8
|
||||||
0..=124 => self.imgs.buff_6, // 1/8
|
0..=124 => self.imgs.buff_6, // 1/8
|
||||||
_ => self.imgs.nothing,
|
_ => self.imgs.nothing,
|
||||||
|
@ -20,7 +20,6 @@ use conrod_core::{
|
|||||||
};
|
};
|
||||||
use core::convert::TryFrom;
|
use core::convert::TryFrom;
|
||||||
|
|
||||||
use inline_tweak::*;
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use std::iter::once;
|
use std::iter::once;
|
||||||
use winit::monitor::VideoMode;
|
use winit::monitor::VideoMode;
|
||||||
@ -2709,8 +2708,8 @@ impl<'a> Widget for SettingsWindow<'a> {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
for (i, language) in language_list.iter().enumerate() {
|
for (i, language) in language_list.iter().enumerate() {
|
||||||
let button_w = tweak!(400.0);
|
let button_w = 400.0;
|
||||||
let button_h = tweak!(50.0);
|
let button_h = 50.0;
|
||||||
let button = Button::image(if selected_language == &language.language_identifier {
|
let button = Button::image(if selected_language == &language.language_identifier {
|
||||||
self.imgs.selection
|
self.imgs.selection
|
||||||
} else {
|
} else {
|
||||||
@ -2727,7 +2726,7 @@ impl<'a> Widget for SettingsWindow<'a> {
|
|||||||
.hover_image(self.imgs.selection_hover)
|
.hover_image(self.imgs.selection_hover)
|
||||||
.press_image(self.imgs.selection_press)
|
.press_image(self.imgs.selection_press)
|
||||||
.label_color(TEXT_COLOR)
|
.label_color(TEXT_COLOR)
|
||||||
.label_font_size(self.fonts.cyri.scale(tweak!(22)))
|
.label_font_size(self.fonts.cyri.scale(22))
|
||||||
.label_font_id(self.fonts.cyri.conrod_id)
|
.label_font_id(self.fonts.cyri.conrod_id)
|
||||||
.label_y(conrod_core::position::Relative::Scalar(2.0))
|
.label_y(conrod_core::position::Relative::Scalar(2.0))
|
||||||
.set(state.ids.language_list[i], ui)
|
.set(state.ids.language_list[i], ui)
|
||||||
|
@ -27,7 +27,6 @@ use conrod_core::{
|
|||||||
widget::{self, Button, Image, Rectangle, Text},
|
widget::{self, Button, Image, Rectangle, Text},
|
||||||
widget_ids, Color, Colorable, Positionable, Sizeable, Widget, WidgetCommon,
|
widget_ids, Color, Colorable, Positionable, Sizeable, Widget, WidgetCommon,
|
||||||
};
|
};
|
||||||
use inline_tweak::*;
|
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
@ -347,9 +346,9 @@ impl<'a> Widget for Skillbar<'a> {
|
|||||||
.set(state.ids.bg, ui);
|
.set(state.ids.bg, ui);
|
||||||
// Level
|
// Level
|
||||||
let lvl_size = match self.stats.level.level() {
|
let lvl_size = match self.stats.level.level() {
|
||||||
11..=99 => tweak!(13),
|
11..=99 => 13,
|
||||||
100..=999 => tweak!(10),
|
100..=999 => 10,
|
||||||
_ => tweak!(14),
|
_ => 14,
|
||||||
};
|
};
|
||||||
Text::new(&level)
|
Text::new(&level)
|
||||||
.mid_top_with_margin_on(state.ids.bg, 3.0)
|
.mid_top_with_margin_on(state.ids.bg, 3.0)
|
||||||
@ -1009,11 +1008,11 @@ impl<'a> Widget for Skillbar<'a> {
|
|||||||
// TODO Don't show this if key bindings are changed
|
// TODO Don't show this if key bindings are changed
|
||||||
Image::new(self.imgs.m1_ico)
|
Image::new(self.imgs.m1_ico)
|
||||||
.w_h(16.0, 18.0)
|
.w_h(16.0, 18.0)
|
||||||
.mid_bottom_with_margin_on(state.ids.m1_content, tweak!(-11.0))
|
.mid_bottom_with_margin_on(state.ids.m1_content, -11.0)
|
||||||
.set(state.ids.m1_ico, ui);
|
.set(state.ids.m1_ico, ui);
|
||||||
Image::new(self.imgs.m2_ico)
|
Image::new(self.imgs.m2_ico)
|
||||||
.w_h(16.0, 18.0)
|
.w_h(16.0, 18.0)
|
||||||
.mid_bottom_with_margin_on(state.ids.m2_content, tweak!(-11.0))
|
.mid_bottom_with_margin_on(state.ids.m2_content, -11.0)
|
||||||
.set(state.ids.m2_ico, ui);
|
.set(state.ids.m2_ico, ui);
|
||||||
|
|
||||||
// Buffs
|
// Buffs
|
||||||
|
@ -18,7 +18,6 @@ use conrod_core::{
|
|||||||
widget_ids, Borderable, Color, Colorable, Labelable, Positionable, Sizeable, Widget,
|
widget_ids, Borderable, Color, Colorable, Labelable, Positionable, Sizeable, Widget,
|
||||||
};
|
};
|
||||||
use image::DynamicImage;
|
use image::DynamicImage;
|
||||||
//use inline_tweak::*;
|
|
||||||
use rand::{seq::SliceRandom, thread_rng, Rng};
|
use rand::{seq::SliceRandom, thread_rng, Rng};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user