2021-02-17 13:03:20 +00:00
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
2020-12-13 17:11:55 +00:00
|
|
|
use crate::uid::Uid;
|
2021-02-17 13:03:20 +00:00
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
2020-12-12 01:45:46 +00:00
|
|
|
use hashbrown::HashMap;
|
2020-08-10 22:54:45 +00:00
|
|
|
use serde::{Deserialize, Serialize};
|
2021-02-17 13:03:20 +00:00
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
2021-01-07 20:25:12 +00:00
|
|
|
use specs::{Component, DerefFlaggedStorage};
|
2021-02-17 13:03:20 +00:00
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
2020-08-10 22:54:45 +00:00
|
|
|
use specs_idvs::IdvStorage;
|
2021-02-17 13:03:20 +00:00
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
2020-12-12 01:45:46 +00:00
|
|
|
use std::{cmp::Ordering, time::Duration};
|
2020-08-10 22:54:45 +00:00
|
|
|
|
2020-10-19 03:00:35 +00:00
|
|
|
/// De/buff Kind.
|
2020-10-27 01:17:46 +00:00
|
|
|
/// This is used to determine what effects a buff will have
|
2020-12-22 15:40:57 +00:00
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize, Deserialize, PartialOrd, Ord)]
|
2020-10-19 03:00:35 +00:00
|
|
|
pub enum BuffKind {
|
2021-04-15 21:34:24 +00:00
|
|
|
/// Does damage to a creature over time
|
2021-04-24 19:01:36 +00:00
|
|
|
/// Strength should be 10x the DPS of the debuff
|
2021-04-15 20:32:38 +00:00
|
|
|
Burning,
|
2020-08-10 22:54:45 +00:00
|
|
|
/// Restores health/time for some period
|
2021-04-24 19:01:36 +00:00
|
|
|
/// Strength should be 10x the healing per second
|
2020-10-24 20:12:37 +00:00
|
|
|
Regeneration,
|
2020-10-27 21:27:19 +00:00
|
|
|
/// Restores health/time for some period for consumables
|
2021-04-24 19:01:36 +00:00
|
|
|
/// Strength should be 10x the healing per second
|
2020-10-27 21:27:19 +00:00
|
|
|
Saturation,
|
2020-10-01 00:40:46 +00:00
|
|
|
/// Lowers health over time for some duration
|
2021-04-24 19:01:36 +00:00
|
|
|
/// Strength should be 10x the DPS of the debuff
|
2020-10-24 20:12:37 +00:00
|
|
|
Bleeding,
|
2021-03-20 17:29:57 +00:00
|
|
|
/// Lower a creature's max health over time
|
2021-04-24 19:01:36 +00:00
|
|
|
/// Strength only affects the target max health, 0.5 targets 50% of base
|
|
|
|
/// max, 1.0 targets 100% of base max
|
2020-10-24 20:12:37 +00:00
|
|
|
Cursed,
|
2020-12-04 22:24:56 +00:00
|
|
|
/// Applied when drinking a potion
|
2021-04-24 19:01:36 +00:00
|
|
|
/// Strength should be 10x the healing per second
|
2020-11-05 20:02:54 +00:00
|
|
|
Potion,
|
2020-12-04 22:24:56 +00:00
|
|
|
/// Applied when sitting at a campfire
|
2021-04-24 19:01:36 +00:00
|
|
|
/// Strength is fraction of health resotred per second
|
2020-12-04 22:24:56 +00:00
|
|
|
CampfireHeal,
|
StaminaPlus buff, modifying stamina via buffs
trying to fix this, coming back to this later
please remember to change potion back future self!
this ALMOST works. maybe MR ready, kinda jank tho
so close, and yet so far...
IT WORKS IT WORKS IT WORKS IT WORKS IT WORKS IT WO
did the same with health, ill fix this garbage l8r
think we're basically done here
whoops forgot to change the food back
fixing and cleaning up part 1
fixed everything part 2 now with buff images
ran clippy + fmt, fixed items that i modified
bracket bulldozing, boldly
hopefully this should be good?
need to rebase real quick
please let me be done
StaminaPlus buff, modifying stamina via buffs
trying to fix this, coming back to this later
please remember to change potion back future self!
this ALMOST works. maybe MR ready, kinda jank tho
so close, and yet so far...
IT WORKS IT WORKS IT WORKS IT WORKS IT WORKS IT WO
did the same with health, ill fix this garbage l8r
think we're basically done here
whoops forgot to change the food back
fixing and cleaning up part 1
fixed everything part 2 now with buff images
ran clippy + fmt, fixed items that i modified
hopefully this should be good?
cargo clippy fmt stuff
deleted an extraneous file?? how did that even...?
2021-01-26 22:47:55 +00:00
|
|
|
/// Raises maximum stamina
|
2021-04-24 19:01:36 +00:00
|
|
|
/// Strength should be 10x the effect to max energy
|
StaminaPlus buff, modifying stamina via buffs
trying to fix this, coming back to this later
please remember to change potion back future self!
this ALMOST works. maybe MR ready, kinda jank tho
so close, and yet so far...
IT WORKS IT WORKS IT WORKS IT WORKS IT WORKS IT WO
did the same with health, ill fix this garbage l8r
think we're basically done here
whoops forgot to change the food back
fixing and cleaning up part 1
fixed everything part 2 now with buff images
ran clippy + fmt, fixed items that i modified
bracket bulldozing, boldly
hopefully this should be good?
need to rebase real quick
please let me be done
StaminaPlus buff, modifying stamina via buffs
trying to fix this, coming back to this later
please remember to change potion back future self!
this ALMOST works. maybe MR ready, kinda jank tho
so close, and yet so far...
IT WORKS IT WORKS IT WORKS IT WORKS IT WORKS IT WO
did the same with health, ill fix this garbage l8r
think we're basically done here
whoops forgot to change the food back
fixing and cleaning up part 1
fixed everything part 2 now with buff images
ran clippy + fmt, fixed items that i modified
hopefully this should be good?
cargo clippy fmt stuff
deleted an extraneous file?? how did that even...?
2021-01-26 22:47:55 +00:00
|
|
|
IncreaseMaxEnergy,
|
|
|
|
/// Raises maximum health
|
2021-04-24 19:01:36 +00:00
|
|
|
/// Strength should be 10x the effect to max health
|
StaminaPlus buff, modifying stamina via buffs
trying to fix this, coming back to this later
please remember to change potion back future self!
this ALMOST works. maybe MR ready, kinda jank tho
so close, and yet so far...
IT WORKS IT WORKS IT WORKS IT WORKS IT WORKS IT WO
did the same with health, ill fix this garbage l8r
think we're basically done here
whoops forgot to change the food back
fixing and cleaning up part 1
fixed everything part 2 now with buff images
ran clippy + fmt, fixed items that i modified
bracket bulldozing, boldly
hopefully this should be good?
need to rebase real quick
please let me be done
StaminaPlus buff, modifying stamina via buffs
trying to fix this, coming back to this later
please remember to change potion back future self!
this ALMOST works. maybe MR ready, kinda jank tho
so close, and yet so far...
IT WORKS IT WORKS IT WORKS IT WORKS IT WORKS IT WO
did the same with health, ill fix this garbage l8r
think we're basically done here
whoops forgot to change the food back
fixing and cleaning up part 1
fixed everything part 2 now with buff images
ran clippy + fmt, fixed items that i modified
hopefully this should be good?
cargo clippy fmt stuff
deleted an extraneous file?? how did that even...?
2021-01-26 22:47:55 +00:00
|
|
|
IncreaseMaxHealth,
|
2021-02-28 20:02:03 +00:00
|
|
|
/// Makes you immune to attacks
|
2021-04-24 19:01:36 +00:00
|
|
|
/// Strength does not affect this buff
|
2021-02-28 20:02:03 +00:00
|
|
|
Invulnerability,
|
2021-03-04 03:43:11 +00:00
|
|
|
/// Reduces incoming damage
|
2021-04-24 19:01:36 +00:00
|
|
|
/// Strength scales the damage reduction non-linearly. 0.5 provides 50% DR,
|
|
|
|
/// 1.0 provides 67% DR
|
2021-03-04 03:43:11 +00:00
|
|
|
ProtectingWard,
|
2021-04-16 17:44:11 +00:00
|
|
|
/// Reduces movement speed and causes bleeding damage
|
2021-04-24 19:01:36 +00:00
|
|
|
/// Strength scales the movement speed debuff non-linearly. 0.5 is 50%
|
|
|
|
/// speed, 1.0 is 33% speed. Bleeding is at 10x the value of the strength.
|
2021-04-16 17:44:11 +00:00
|
|
|
Crippled,
|
2021-04-24 19:01:36 +00:00
|
|
|
/// Increases movement speed and gives health regeneration
|
|
|
|
/// Strength scales the movement speed linearly. 0.5 is 150% speed, 1.0 is
|
|
|
|
/// 200% speed. Provides regeneration at 10x the value of the strength
|
|
|
|
Frenzied,
|
2020-10-24 20:12:37 +00:00
|
|
|
}
|
|
|
|
|
2021-02-17 13:03:20 +00:00
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
2020-10-24 20:12:37 +00:00
|
|
|
impl BuffKind {
|
2021-02-20 20:37:46 +00:00
|
|
|
/// Checks if buff is buff or debuff
|
2020-10-24 20:12:37 +00:00
|
|
|
pub fn is_buff(self) -> bool {
|
|
|
|
match self {
|
2021-02-20 20:37:46 +00:00
|
|
|
BuffKind::Regeneration => true,
|
|
|
|
BuffKind::Saturation => true,
|
|
|
|
BuffKind::Bleeding => false,
|
|
|
|
BuffKind::Cursed => false,
|
|
|
|
BuffKind::Potion => true,
|
|
|
|
BuffKind::CampfireHeal => true,
|
|
|
|
BuffKind::IncreaseMaxEnergy => true,
|
|
|
|
BuffKind::IncreaseMaxHealth => true,
|
2021-02-28 20:02:03 +00:00
|
|
|
BuffKind::Invulnerability => true,
|
2021-03-04 03:43:11 +00:00
|
|
|
BuffKind::ProtectingWard => true,
|
2021-04-15 20:32:38 +00:00
|
|
|
BuffKind::Burning => false,
|
2021-04-16 17:44:11 +00:00
|
|
|
BuffKind::Crippled => false,
|
2021-04-24 19:01:36 +00:00
|
|
|
BuffKind::Frenzied => true,
|
2020-10-24 20:12:37 +00:00
|
|
|
}
|
|
|
|
}
|
2021-02-20 20:37:46 +00:00
|
|
|
|
|
|
|
/// Checks if buff should queue
|
|
|
|
pub fn queues(self) -> bool { matches!(self, BuffKind::Saturation) }
|
2020-10-24 20:12:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Struct used to store data relevant to a buff
|
2021-02-17 13:03:20 +00:00
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
2020-10-27 21:27:19 +00:00
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
2020-10-24 20:12:37 +00:00
|
|
|
pub struct BuffData {
|
|
|
|
pub strength: f32,
|
|
|
|
pub duration: Option<Duration>,
|
2020-08-10 22:54:45 +00:00
|
|
|
}
|
|
|
|
|
2021-02-17 13:03:20 +00:00
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
2020-12-04 22:24:56 +00:00
|
|
|
impl BuffData {
|
|
|
|
pub fn new(strength: f32, duration: Option<Duration>) -> Self { Self { strength, duration } }
|
|
|
|
}
|
|
|
|
|
2020-08-10 22:54:45 +00:00
|
|
|
/// De/buff category ID.
|
2020-10-19 03:00:35 +00:00
|
|
|
/// Similar to `BuffKind`, but to mark a category (for more generic usage, like
|
2020-08-10 22:54:45 +00:00
|
|
|
/// positive/negative buffs).
|
2021-02-17 13:03:20 +00:00
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
2020-10-02 19:09:19 +00:00
|
|
|
#[derive(Clone, Copy, Eq, PartialEq, Debug, Serialize, Deserialize)]
|
2020-10-24 20:12:37 +00:00
|
|
|
pub enum BuffCategory {
|
2020-08-10 22:54:45 +00:00
|
|
|
Natural,
|
2020-10-01 00:40:46 +00:00
|
|
|
Physical,
|
2020-08-10 22:54:45 +00:00
|
|
|
Magical,
|
|
|
|
Divine,
|
2020-10-13 00:48:25 +00:00
|
|
|
PersistOnDeath,
|
2021-02-26 23:15:24 +00:00
|
|
|
FromAura(bool), // bool used to check if buff recently set by aura
|
2020-08-10 22:54:45 +00:00
|
|
|
}
|
|
|
|
|
2021-02-17 13:03:20 +00:00
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
2020-10-24 23:07:38 +00:00
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
|
|
pub enum ModifierKind {
|
|
|
|
Additive,
|
2020-12-04 22:24:56 +00:00
|
|
|
Fractional,
|
2020-10-24 23:07:38 +00:00
|
|
|
}
|
|
|
|
|
2020-08-10 22:54:45 +00:00
|
|
|
/// Data indicating and configuring behaviour of a de/buff.
|
2021-02-17 13:03:20 +00:00
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
2020-08-10 22:54:45 +00:00
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
2020-10-01 00:40:46 +00:00
|
|
|
pub enum BuffEffect {
|
|
|
|
/// Periodically damages or heals entity
|
2020-12-04 22:24:56 +00:00
|
|
|
HealthChangeOverTime {
|
|
|
|
rate: f32,
|
|
|
|
accumulated: f32,
|
|
|
|
kind: ModifierKind,
|
|
|
|
},
|
2020-10-24 23:07:38 +00:00
|
|
|
/// Changes maximum health by a certain amount
|
2021-03-04 03:43:11 +00:00
|
|
|
MaxHealthModifier { value: f32, kind: ModifierKind },
|
StaminaPlus buff, modifying stamina via buffs
trying to fix this, coming back to this later
please remember to change potion back future self!
this ALMOST works. maybe MR ready, kinda jank tho
so close, and yet so far...
IT WORKS IT WORKS IT WORKS IT WORKS IT WORKS IT WO
did the same with health, ill fix this garbage l8r
think we're basically done here
whoops forgot to change the food back
fixing and cleaning up part 1
fixed everything part 2 now with buff images
ran clippy + fmt, fixed items that i modified
bracket bulldozing, boldly
hopefully this should be good?
need to rebase real quick
please let me be done
StaminaPlus buff, modifying stamina via buffs
trying to fix this, coming back to this later
please remember to change potion back future self!
this ALMOST works. maybe MR ready, kinda jank tho
so close, and yet so far...
IT WORKS IT WORKS IT WORKS IT WORKS IT WORKS IT WO
did the same with health, ill fix this garbage l8r
think we're basically done here
whoops forgot to change the food back
fixing and cleaning up part 1
fixed everything part 2 now with buff images
ran clippy + fmt, fixed items that i modified
hopefully this should be good?
cargo clippy fmt stuff
deleted an extraneous file?? how did that even...?
2021-01-26 22:47:55 +00:00
|
|
|
/// Changes maximum stamina by a certain amount
|
2021-03-04 03:43:11 +00:00
|
|
|
MaxEnergyModifier { value: f32, kind: ModifierKind },
|
|
|
|
/// Reduces damage after armor is accounted for by this fraction
|
|
|
|
DamageReduction(f32),
|
2021-03-20 17:29:57 +00:00
|
|
|
/// Gradually changes an entities max health over time
|
|
|
|
MaxHealthChangeOverTime {
|
|
|
|
rate: f32,
|
|
|
|
accumulated: f32,
|
|
|
|
kind: ModifierKind,
|
|
|
|
target_fraction: f32,
|
|
|
|
},
|
2021-04-16 17:44:11 +00:00
|
|
|
/// Modifies move speed of target
|
|
|
|
MovementSpeed(f32),
|
2020-08-10 22:54:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Actual de/buff.
|
|
|
|
/// 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
|
2020-10-19 03:00:35 +00:00
|
|
|
/// uncursing).
|
2020-08-10 22:54:45 +00:00
|
|
|
///
|
2020-10-19 03:00:35 +00:00
|
|
|
/// Buff has a kind, which is used to determine the effects in a builder
|
|
|
|
/// function.
|
2020-08-10 22:54:45 +00:00
|
|
|
///
|
|
|
|
/// To provide more classification info when needed,
|
|
|
|
/// buff can be in one or more buff category.
|
2021-02-17 13:03:20 +00:00
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
2020-08-10 22:54:45 +00:00
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
|
|
pub struct Buff {
|
2020-10-19 03:00:35 +00:00
|
|
|
pub kind: BuffKind,
|
2020-10-24 20:12:37 +00:00
|
|
|
pub data: BuffData,
|
|
|
|
pub cat_ids: Vec<BuffCategory>,
|
2020-08-10 22:54:45 +00:00
|
|
|
pub time: Option<Duration>,
|
2020-10-01 00:40:46 +00:00
|
|
|
pub effects: Vec<BuffEffect>,
|
2020-10-03 18:48:56 +00:00
|
|
|
pub source: BuffSource,
|
2020-08-10 22:54:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Information about whether buff addition or removal was requested.
|
|
|
|
/// This to implement "on_add" and "on_remove" hooks for constant buffs.
|
2021-02-17 13:03:20 +00:00
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
2020-10-24 20:12:37 +00:00
|
|
|
#[derive(Clone, Debug)]
|
2020-08-10 22:54:45 +00:00
|
|
|
pub enum BuffChange {
|
|
|
|
/// Adds this buff.
|
|
|
|
Add(Buff),
|
|
|
|
/// Removes all buffs with this ID.
|
2020-10-19 03:00:35 +00:00
|
|
|
RemoveByKind(BuffKind),
|
|
|
|
/// Removes all buffs with this ID, but not debuffs.
|
2020-10-24 20:12:37 +00:00
|
|
|
RemoveFromController(BuffKind),
|
2020-10-02 19:09:19 +00:00
|
|
|
/// Removes buffs of these indices (first vec is for active buffs, second is
|
2020-10-19 03:00:35 +00:00
|
|
|
/// for inactive buffs), should only be called when buffs expire
|
2020-10-24 20:12:37 +00:00
|
|
|
RemoveById(Vec<BuffId>),
|
2020-10-02 19:09:19 +00:00
|
|
|
/// 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
|
2020-10-27 21:27:19 +00:00
|
|
|
/// required, third vec is of categories that will not be removed)
|
2020-10-13 00:48:25 +00:00
|
|
|
RemoveByCategory {
|
2020-10-24 20:12:37 +00:00
|
|
|
all_required: Vec<BuffCategory>,
|
|
|
|
any_required: Vec<BuffCategory>,
|
|
|
|
none_required: Vec<BuffCategory>,
|
2020-10-13 00:48:25 +00:00
|
|
|
},
|
2020-08-10 22:54:45 +00:00
|
|
|
}
|
|
|
|
|
2021-02-17 13:03:20 +00:00
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
2020-10-24 20:12:37 +00:00
|
|
|
impl Buff {
|
|
|
|
/// Builder function for buffs
|
|
|
|
pub fn new(
|
|
|
|
kind: BuffKind,
|
|
|
|
data: BuffData,
|
|
|
|
cat_ids: Vec<BuffCategory>,
|
|
|
|
source: BuffSource,
|
|
|
|
) -> Self {
|
2021-04-16 17:44:11 +00:00
|
|
|
// Normalized nonlinear scaling
|
|
|
|
let nn_scaling = |a| a / (a + 0.5);
|
2020-10-24 20:12:37 +00:00
|
|
|
let (effects, time) = match kind {
|
|
|
|
BuffKind::Bleeding => (
|
|
|
|
vec![BuffEffect::HealthChangeOverTime {
|
|
|
|
rate: -data.strength,
|
|
|
|
accumulated: 0.0,
|
2020-12-04 22:24:56 +00:00
|
|
|
kind: ModifierKind::Additive,
|
2020-10-24 20:12:37 +00:00
|
|
|
}],
|
|
|
|
data.duration,
|
|
|
|
),
|
2020-11-05 20:02:54 +00:00
|
|
|
BuffKind::Regeneration | BuffKind::Saturation | BuffKind::Potion => (
|
2020-10-24 20:12:37 +00:00
|
|
|
vec![BuffEffect::HealthChangeOverTime {
|
|
|
|
rate: data.strength,
|
|
|
|
accumulated: 0.0,
|
2020-12-04 22:24:56 +00:00
|
|
|
kind: ModifierKind::Additive,
|
|
|
|
}],
|
|
|
|
data.duration,
|
|
|
|
),
|
|
|
|
BuffKind::CampfireHeal => (
|
|
|
|
vec![BuffEffect::HealthChangeOverTime {
|
|
|
|
rate: data.strength,
|
|
|
|
accumulated: 0.0,
|
|
|
|
kind: ModifierKind::Fractional,
|
2020-10-24 20:12:37 +00:00
|
|
|
}],
|
|
|
|
data.duration,
|
2020-11-05 20:56:45 +00:00
|
|
|
),
|
2020-10-24 20:12:37 +00:00
|
|
|
BuffKind::Cursed => (
|
2021-03-20 17:29:57 +00:00
|
|
|
vec![
|
|
|
|
BuffEffect::MaxHealthChangeOverTime {
|
|
|
|
rate: -10.0,
|
|
|
|
accumulated: 0.0,
|
|
|
|
kind: ModifierKind::Additive,
|
|
|
|
target_fraction: 1.0 - data.strength,
|
|
|
|
},
|
|
|
|
BuffEffect::HealthChangeOverTime {
|
|
|
|
rate: -10.0,
|
|
|
|
accumulated: 0.0,
|
|
|
|
kind: ModifierKind::Additive,
|
|
|
|
},
|
|
|
|
],
|
2020-10-24 20:12:37 +00:00
|
|
|
data.duration,
|
|
|
|
),
|
StaminaPlus buff, modifying stamina via buffs
trying to fix this, coming back to this later
please remember to change potion back future self!
this ALMOST works. maybe MR ready, kinda jank tho
so close, and yet so far...
IT WORKS IT WORKS IT WORKS IT WORKS IT WORKS IT WO
did the same with health, ill fix this garbage l8r
think we're basically done here
whoops forgot to change the food back
fixing and cleaning up part 1
fixed everything part 2 now with buff images
ran clippy + fmt, fixed items that i modified
bracket bulldozing, boldly
hopefully this should be good?
need to rebase real quick
please let me be done
StaminaPlus buff, modifying stamina via buffs
trying to fix this, coming back to this later
please remember to change potion back future self!
this ALMOST works. maybe MR ready, kinda jank tho
so close, and yet so far...
IT WORKS IT WORKS IT WORKS IT WORKS IT WORKS IT WO
did the same with health, ill fix this garbage l8r
think we're basically done here
whoops forgot to change the food back
fixing and cleaning up part 1
fixed everything part 2 now with buff images
ran clippy + fmt, fixed items that i modified
hopefully this should be good?
cargo clippy fmt stuff
deleted an extraneous file?? how did that even...?
2021-01-26 22:47:55 +00:00
|
|
|
BuffKind::IncreaseMaxEnergy => (
|
|
|
|
vec![BuffEffect::MaxEnergyModifier {
|
|
|
|
value: data.strength,
|
|
|
|
kind: ModifierKind::Additive,
|
|
|
|
}],
|
|
|
|
data.duration,
|
|
|
|
),
|
|
|
|
BuffKind::IncreaseMaxHealth => (
|
|
|
|
vec![BuffEffect::MaxHealthModifier {
|
|
|
|
value: data.strength,
|
|
|
|
kind: ModifierKind::Additive,
|
|
|
|
}],
|
|
|
|
data.duration,
|
|
|
|
),
|
2021-03-04 03:43:11 +00:00
|
|
|
BuffKind::Invulnerability => (vec![BuffEffect::DamageReduction(1.0)], data.duration),
|
|
|
|
BuffKind::ProtectingWard => (
|
|
|
|
vec![BuffEffect::DamageReduction(
|
|
|
|
// Causes non-linearity in effect strength, but necessary to allow for tool
|
|
|
|
// power and other things to affect the strength. 0.5 also still provides 50%
|
|
|
|
// damage reduction.
|
2021-04-16 17:44:11 +00:00
|
|
|
nn_scaling(data.strength),
|
2021-03-04 03:43:11 +00:00
|
|
|
)],
|
|
|
|
data.duration,
|
|
|
|
),
|
2021-04-15 20:32:38 +00:00
|
|
|
BuffKind::Burning => (
|
|
|
|
vec![BuffEffect::HealthChangeOverTime {
|
|
|
|
rate: -data.strength,
|
|
|
|
accumulated: 0.0,
|
|
|
|
kind: ModifierKind::Additive,
|
|
|
|
}],
|
|
|
|
data.duration,
|
|
|
|
),
|
2021-04-16 17:44:11 +00:00
|
|
|
BuffKind::Crippled => (
|
|
|
|
vec![
|
|
|
|
BuffEffect::MovementSpeed(1.0 - nn_scaling(data.strength)),
|
|
|
|
BuffEffect::HealthChangeOverTime {
|
2021-05-01 13:36:45 +00:00
|
|
|
rate: -data.strength * 40.0,
|
2021-04-16 17:44:11 +00:00
|
|
|
accumulated: 0.0,
|
|
|
|
kind: ModifierKind::Additive,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
data.duration,
|
|
|
|
),
|
2021-04-24 19:01:36 +00:00
|
|
|
BuffKind::Frenzied => (
|
|
|
|
vec![
|
|
|
|
BuffEffect::MovementSpeed(1.0 + data.strength),
|
|
|
|
BuffEffect::HealthChangeOverTime {
|
2021-04-28 22:41:04 +00:00
|
|
|
rate: data.strength * 100.0,
|
2021-04-24 19:01:36 +00:00
|
|
|
accumulated: 0.0,
|
|
|
|
kind: ModifierKind::Additive,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
data.duration,
|
|
|
|
),
|
2020-10-24 20:12:37 +00:00
|
|
|
};
|
|
|
|
Buff {
|
|
|
|
kind,
|
|
|
|
data,
|
|
|
|
cat_ids,
|
|
|
|
time,
|
|
|
|
effects,
|
|
|
|
source,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-17 13:03:20 +00:00
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
2020-10-25 01:20:03 +00:00
|
|
|
impl PartialOrd for Buff {
|
|
|
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
2020-10-27 01:17:46 +00:00
|
|
|
if self == other {
|
|
|
|
Some(Ordering::Equal)
|
|
|
|
} else if self.data.strength > other.data.strength {
|
2020-10-25 01:20:03 +00:00
|
|
|
Some(Ordering::Greater)
|
|
|
|
} else if self.data.strength < other.data.strength {
|
|
|
|
Some(Ordering::Less)
|
|
|
|
} else if compare_duration(self.time, other.time) {
|
|
|
|
Some(Ordering::Greater)
|
|
|
|
} else if compare_duration(other.time, self.time) {
|
|
|
|
Some(Ordering::Less)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-17 13:03:20 +00:00
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
2020-10-25 01:20:03 +00:00
|
|
|
fn compare_duration(a: Option<Duration>, b: Option<Duration>) -> bool {
|
|
|
|
a.map_or(true, |dur_a| b.map_or(false, |dur_b| dur_a > dur_b))
|
|
|
|
}
|
|
|
|
|
2021-02-17 13:03:20 +00:00
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
2020-10-25 01:20:03 +00:00
|
|
|
impl PartialEq for Buff {
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
2020-10-27 01:17:46 +00:00
|
|
|
self.data.strength == other.data.strength && self.time == other.time
|
2020-10-25 01:20:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-10 22:54:45 +00:00
|
|
|
/// Source of the de/buff
|
2021-02-17 13:03:20 +00:00
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
2020-08-10 22:54:45 +00:00
|
|
|
#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)]
|
|
|
|
pub enum BuffSource {
|
|
|
|
/// Applied by a character
|
|
|
|
Character { by: Uid },
|
|
|
|
/// Applied by world, like a poisonous fumes from a swamp
|
|
|
|
World,
|
|
|
|
/// Applied by command
|
|
|
|
Command,
|
|
|
|
/// Applied by an item
|
|
|
|
Item,
|
|
|
|
/// Applied by another buff (like an after-effect)
|
|
|
|
Buff,
|
|
|
|
/// Some other source
|
|
|
|
Unknown,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Component holding all de/buffs that gets resolved each tick.
|
|
|
|
/// On each tick, remaining time of buffs get lowered and
|
2020-10-01 00:40:46 +00:00
|
|
|
/// buff effect of each buff is applied or not, depending on the `BuffEffect`
|
2020-10-01 01:35:57 +00:00
|
|
|
/// (specs system will decide based on `BuffEffect`, to simplify
|
|
|
|
/// implementation). TODO: Something like `once` flag for `Buff` to remove the
|
|
|
|
/// dependence on `BuffEffect` enum?
|
2020-08-10 22:54:45 +00:00
|
|
|
///
|
|
|
|
/// In case of one-time buffs, buff effects will be applied on addition
|
|
|
|
/// and undone on removal of the buff (by the specs system).
|
|
|
|
/// Example could be decreasing max health, which, if repeated each tick,
|
|
|
|
/// would be probably an undesired effect).
|
2021-02-17 13:03:20 +00:00
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
2020-08-10 22:54:45 +00:00
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
|
|
|
|
pub struct Buffs {
|
2020-10-24 20:17:49 +00:00
|
|
|
/// Uid used for synchronization
|
2020-10-24 20:12:37 +00:00
|
|
|
id_counter: u64,
|
2020-10-24 20:17:49 +00:00
|
|
|
/// Maps Kinds of buff to Id's of currently applied buffs of that kind
|
2020-10-24 20:12:37 +00:00
|
|
|
pub kinds: HashMap<BuffKind, Vec<BuffId>>,
|
2020-10-24 20:17:49 +00:00
|
|
|
// All currently applied buffs stored by Id
|
2020-10-24 20:12:37 +00:00
|
|
|
pub buffs: HashMap<BuffId, Buff>,
|
2020-08-10 22:54:45 +00:00
|
|
|
}
|
|
|
|
|
2021-02-17 13:03:20 +00:00
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
2020-10-24 20:12:37 +00:00
|
|
|
impl Buffs {
|
|
|
|
fn sort_kind(&mut self, kind: BuffKind) {
|
|
|
|
if let Some(buff_order) = self.kinds.get_mut(&kind) {
|
2020-10-25 01:20:03 +00:00
|
|
|
if buff_order.is_empty() {
|
2020-10-24 20:12:37 +00:00
|
|
|
self.kinds.remove(&kind);
|
|
|
|
} else {
|
|
|
|
let buffs = &self.buffs;
|
2020-10-25 01:20:03 +00:00
|
|
|
// Intentionally sorted in reverse so that the strongest buffs are earlier in
|
|
|
|
// the vector
|
2021-04-25 16:01:21 +00:00
|
|
|
buff_order
|
|
|
|
.sort_by(|a, b| buffs[&b].partial_cmp(&buffs[&a]).unwrap_or(Ordering::Equal));
|
2020-10-24 20:12:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn remove_kind(&mut self, kind: BuffKind) {
|
|
|
|
if let Some(buff_ids) = self.kinds.get_mut(&kind) {
|
|
|
|
for id in buff_ids {
|
|
|
|
self.buffs.remove(id);
|
|
|
|
}
|
|
|
|
self.kinds.remove(&kind);
|
2020-10-01 17:33:35 +00:00
|
|
|
}
|
2020-10-24 20:12:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn force_insert(&mut self, id: BuffId, buff: Buff) -> BuffId {
|
|
|
|
let kind = buff.kind;
|
|
|
|
self.kinds.entry(kind).or_default().push(id);
|
|
|
|
self.buffs.insert(id, buff);
|
|
|
|
self.sort_kind(kind);
|
|
|
|
id
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn insert(&mut self, buff: Buff) -> BuffId {
|
|
|
|
self.id_counter += 1;
|
|
|
|
self.force_insert(self.id_counter, buff)
|
|
|
|
}
|
|
|
|
|
2020-12-04 22:24:56 +00:00
|
|
|
pub fn contains(&self, kind: BuffKind) -> bool { self.kinds.contains_key(&kind) }
|
|
|
|
|
2020-10-24 20:12:37 +00:00
|
|
|
// Iterate through buffs of a given kind in effect order (most powerful first)
|
|
|
|
pub fn iter_kind(&self, kind: BuffKind) -> impl Iterator<Item = (BuffId, &Buff)> + '_ {
|
|
|
|
self.kinds
|
|
|
|
.get(&kind)
|
|
|
|
.map(|ids| ids.iter())
|
2020-10-25 01:20:03 +00:00
|
|
|
.unwrap_or_else(|| (&[]).iter())
|
2020-10-24 20:12:37 +00:00
|
|
|
.map(move |id| (*id, &self.buffs[id]))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Iterates through all active buffs (the most powerful buff of each kind)
|
|
|
|
pub fn iter_active(&self) -> impl Iterator<Item = &Buff> + '_ {
|
|
|
|
self.kinds
|
|
|
|
.values()
|
2021-04-25 16:01:21 +00:00
|
|
|
.filter_map(move |ids| self.buffs.get(&ids[0]))
|
2020-10-24 20:12:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Gets most powerful buff of a given kind
|
|
|
|
// pub fn get_active_kind(&self, kind: BuffKind) -> Buff
|
|
|
|
pub fn remove(&mut self, buff_id: BuffId) {
|
2021-04-25 16:01:21 +00:00
|
|
|
if let Some(kind) = self.buffs.remove(&buff_id) {
|
|
|
|
let kind = kind.kind;
|
|
|
|
self.kinds
|
|
|
|
.get_mut(&kind)
|
|
|
|
.map(|ids| ids.retain(|id| *id != buff_id));
|
|
|
|
self.sort_kind(kind);
|
|
|
|
}
|
2020-10-01 17:33:35 +00:00
|
|
|
}
|
2021-02-20 20:37:46 +00:00
|
|
|
|
|
|
|
/// Returns an immutable reference to the buff kinds on an entity, and a
|
|
|
|
/// mutable reference to the buffs
|
|
|
|
pub fn parts(&mut self) -> (&HashMap<BuffKind, Vec<BuffId>>, &mut HashMap<BuffId, Buff>) {
|
|
|
|
(&self.kinds, &mut self.buffs)
|
|
|
|
}
|
2020-10-01 17:33:35 +00:00
|
|
|
}
|
|
|
|
|
2021-02-17 13:03:20 +00:00
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
2020-10-24 20:12:37 +00:00
|
|
|
pub type BuffId = u64;
|
|
|
|
|
2021-02-17 13:03:20 +00:00
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
2020-08-10 22:54:45 +00:00
|
|
|
impl Component for Buffs {
|
2021-01-07 20:25:12 +00:00
|
|
|
type Storage = DerefFlaggedStorage<Self, IdvStorage<Self>>;
|
2020-08-10 22:54:45 +00:00
|
|
|
}
|