2020-12-01 00:28:00 +00:00
|
|
|
use common::{
|
2020-10-13 00:48:25 +00:00
|
|
|
comp::{
|
2021-06-30 21:51:28 +00:00
|
|
|
body::{object, Body},
|
2021-06-20 05:37:22 +00:00
|
|
|
buff::{
|
|
|
|
Buff, BuffCategory, BuffChange, BuffData, BuffEffect, BuffId, BuffKind, BuffSource,
|
|
|
|
Buffs,
|
|
|
|
},
|
2021-06-18 20:35:30 +00:00
|
|
|
fluid_dynamics::{Fluid, LiquidKind},
|
2021-06-30 21:51:28 +00:00
|
|
|
Energy, Health, HealthChange, HealthSource, Inventory, LightEmitter, ModifierKind,
|
|
|
|
PhysicsState, Stats,
|
2020-10-13 00:48:25 +00:00
|
|
|
},
|
2020-10-01 02:32:38 +00:00
|
|
|
event::{EventBus, ServerEvent},
|
2020-12-01 00:28:00 +00:00
|
|
|
resources::DeltaTime,
|
2021-06-20 05:37:22 +00:00
|
|
|
terrain::SpriteKind,
|
2021-01-08 19:12:09 +00:00
|
|
|
Damage, DamageSource,
|
2020-08-10 22:54:45 +00:00
|
|
|
};
|
2021-03-08 22:40:02 +00:00
|
|
|
use common_ecs::{Job, Origin, Phase, System};
|
2021-05-30 16:40:11 +00:00
|
|
|
use hashbrown::HashMap;
|
2021-02-22 19:03:18 +00:00
|
|
|
use specs::{
|
2021-03-04 14:00:16 +00:00
|
|
|
shred::ResourceId, Entities, Join, Read, ReadStorage, SystemData, World, WriteStorage,
|
2021-02-22 19:03:18 +00:00
|
|
|
};
|
2020-08-10 22:54:45 +00:00
|
|
|
use std::time::Duration;
|
|
|
|
|
2021-02-22 19:03:18 +00:00
|
|
|
#[derive(SystemData)]
|
2021-02-22 21:02:37 +00:00
|
|
|
pub struct ReadData<'a> {
|
2021-02-22 19:03:18 +00:00
|
|
|
entities: Entities<'a>,
|
|
|
|
dt: Read<'a, DeltaTime>,
|
|
|
|
server_bus: Read<'a, EventBus<ServerEvent>>,
|
|
|
|
inventories: ReadStorage<'a, Inventory>,
|
2021-03-20 17:29:57 +00:00
|
|
|
healths: ReadStorage<'a, Health>,
|
2021-05-13 05:34:51 +00:00
|
|
|
physics_states: ReadStorage<'a, PhysicsState>,
|
2021-05-21 00:52:29 +00:00
|
|
|
energies: ReadStorage<'a, Energy>,
|
2021-02-22 19:03:18 +00:00
|
|
|
}
|
|
|
|
|
2021-03-04 14:00:16 +00:00
|
|
|
#[derive(Default)]
|
2020-08-10 22:54:45 +00:00
|
|
|
pub struct Sys;
|
2021-03-08 11:13:59 +00:00
|
|
|
impl<'a> System<'a> for Sys {
|
2020-08-10 22:54:45 +00:00
|
|
|
type SystemData = (
|
2021-02-22 21:02:37 +00:00
|
|
|
ReadData<'a>,
|
2020-08-10 22:54:45 +00:00
|
|
|
WriteStorage<'a, Buffs>,
|
2021-02-28 20:02:03 +00:00
|
|
|
WriteStorage<'a, Stats>,
|
2021-06-30 21:51:28 +00:00
|
|
|
WriteStorage<'a, Body>,
|
|
|
|
WriteStorage<'a, LightEmitter>,
|
2020-08-10 22:54:45 +00:00
|
|
|
);
|
|
|
|
|
2021-03-04 14:00:16 +00:00
|
|
|
const NAME: &'static str = "buff";
|
|
|
|
const ORIGIN: Origin = Origin::Common;
|
|
|
|
const PHASE: Phase = Phase::Create;
|
|
|
|
|
2021-06-30 21:51:28 +00:00
|
|
|
fn run(
|
|
|
|
_job: &mut Job<Self>,
|
|
|
|
(read_data, mut buffs, mut stats, mut bodies, mut light_emitters): Self::SystemData,
|
|
|
|
) {
|
2021-02-22 21:02:37 +00:00
|
|
|
let mut server_emitter = read_data.server_bus.emitter();
|
|
|
|
let dt = read_data.dt.0;
|
2020-10-19 03:00:35 +00:00
|
|
|
// Set to false to avoid spamming server
|
2020-10-25 01:20:03 +00:00
|
|
|
buffs.set_event_emission(false);
|
2021-02-28 20:02:03 +00:00
|
|
|
stats.set_event_emission(false);
|
2021-06-30 21:51:28 +00:00
|
|
|
for (entity, mut body, physics_state) in
|
|
|
|
(&read_data.entities, &mut bodies, &read_data.physics_states).join()
|
|
|
|
{
|
|
|
|
// Put out underwater campfires. Logically belongs here since this system also
|
|
|
|
// removes burning, but campfires don't have healths/stats/energies/buffs, so
|
|
|
|
// this needs a separate loop.
|
|
|
|
if matches!(*body, Body::Object(object::Body::CampfireLit))
|
|
|
|
&& matches!(
|
|
|
|
physics_state.in_fluid,
|
|
|
|
Some(Fluid::Liquid {
|
|
|
|
kind: LiquidKind::Water,
|
|
|
|
..
|
|
|
|
})
|
|
|
|
)
|
|
|
|
{
|
|
|
|
*body = Body::Object(object::Body::Campfire);
|
|
|
|
light_emitters.remove(entity);
|
|
|
|
}
|
|
|
|
}
|
2021-06-16 21:40:18 +00:00
|
|
|
for (entity, mut buff_comp, energy, mut stat, health, physics_state) in (
|
2021-02-28 20:02:03 +00:00
|
|
|
&read_data.entities,
|
|
|
|
&mut buffs,
|
2021-05-21 00:52:29 +00:00
|
|
|
&read_data.energies,
|
2021-02-28 20:02:03 +00:00
|
|
|
&mut stats,
|
2021-03-20 17:29:57 +00:00
|
|
|
&read_data.healths,
|
2021-06-16 21:40:18 +00:00
|
|
|
read_data.physics_states.maybe(),
|
2021-02-28 20:02:03 +00:00
|
|
|
)
|
|
|
|
.join()
|
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
|
|
|
{
|
2021-06-20 05:37:22 +00:00
|
|
|
// Apply buffs to entity based off of their current physics_state
|
|
|
|
if let Some(physics_state) = physics_state {
|
|
|
|
if matches!(
|
|
|
|
physics_state.on_ground.and_then(|b| b.get_sprite()),
|
|
|
|
Some(SpriteKind::EnsnaringVines)
|
|
|
|
) {
|
2021-06-22 01:50:31 +00:00
|
|
|
// If on ensnaring vines, apply ensnared debuff
|
2021-06-20 05:37:22 +00:00
|
|
|
server_emitter.emit(ServerEvent::Buff {
|
|
|
|
entity,
|
|
|
|
buff_change: BuffChange::Add(Buff::new(
|
|
|
|
BuffKind::Ensnared,
|
2021-06-24 01:31:45 +00:00
|
|
|
BuffData::new(1.0, Some(Duration::from_secs_f32(1.0))),
|
2021-06-20 05:37:22 +00:00
|
|
|
Vec::new(),
|
|
|
|
BuffSource::World,
|
|
|
|
)),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if matches!(
|
|
|
|
physics_state.in_fluid,
|
|
|
|
Some(Fluid::Liquid {
|
|
|
|
kind: LiquidKind::Lava,
|
|
|
|
..
|
|
|
|
})
|
|
|
|
) {
|
2021-06-22 01:50:31 +00:00
|
|
|
// If in lava fluid, apply burning debuff
|
2021-06-20 05:37:22 +00:00
|
|
|
server_emitter.emit(ServerEvent::Buff {
|
|
|
|
entity,
|
|
|
|
buff_change: BuffChange::Add(Buff::new(
|
|
|
|
BuffKind::Burning,
|
|
|
|
BuffData::new(200.0, None),
|
|
|
|
vec![BuffCategory::Natural],
|
|
|
|
BuffSource::World,
|
|
|
|
)),
|
|
|
|
});
|
|
|
|
} else if matches!(
|
|
|
|
physics_state.in_fluid,
|
|
|
|
Some(Fluid::Liquid {
|
|
|
|
kind: LiquidKind::Water,
|
|
|
|
..
|
|
|
|
})
|
2021-06-22 01:50:31 +00:00
|
|
|
) && buff_comp.kinds.contains_key(&BuffKind::Burning)
|
|
|
|
{
|
|
|
|
// If in water fluid and currently burning, remove burning debuffs
|
|
|
|
server_emitter.emit(ServerEvent::Buff {
|
|
|
|
entity,
|
|
|
|
buff_change: BuffChange::RemoveByKind(BuffKind::Burning),
|
|
|
|
});
|
2021-06-20 05:37:22 +00:00
|
|
|
}
|
2021-06-16 21:40:18 +00:00
|
|
|
}
|
|
|
|
|
2021-05-30 16:40:11 +00:00
|
|
|
let (buff_comp_kinds, buff_comp_buffs): (
|
|
|
|
&HashMap<BuffKind, Vec<BuffId>>,
|
|
|
|
&mut HashMap<BuffId, Buff>,
|
|
|
|
) = buff_comp.parts();
|
2020-10-24 20:12:37 +00:00
|
|
|
let mut expired_buffs = Vec::<BuffId>::new();
|
2021-06-16 21:40:18 +00:00
|
|
|
|
2021-02-20 20:37:46 +00:00
|
|
|
// For each buff kind present on entity, if the buff kind queues, only ticks
|
|
|
|
// duration of strongest buff of that kind, else it ticks durations of all buffs
|
|
|
|
// of that kind. Any buffs whose durations expire are marked expired.
|
|
|
|
for (kind, ids) in buff_comp_kinds.iter() {
|
|
|
|
if kind.queues() {
|
|
|
|
if let Some((Some(buff), id)) =
|
|
|
|
ids.get(0).map(|id| (buff_comp_buffs.get_mut(id), id))
|
2020-10-24 20:12:37 +00:00
|
|
|
{
|
2021-06-20 05:37:22 +00:00
|
|
|
tick_buff(*id, buff, dt, |id| expired_buffs.push(id));
|
2021-02-20 20:37:46 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (id, buff) in buff_comp_buffs
|
|
|
|
.iter_mut()
|
|
|
|
.filter(|(i, _)| ids.iter().any(|id| id == *i))
|
|
|
|
{
|
2021-06-20 05:37:22 +00:00
|
|
|
tick_buff(*id, buff, dt, |id| expired_buffs.push(id));
|
2020-10-24 20:12:37 +00:00
|
|
|
}
|
2020-10-19 03:00:35 +00:00
|
|
|
}
|
|
|
|
}
|
2020-08-10 22:54:45 +00:00
|
|
|
|
2021-05-06 18:50:16 +00:00
|
|
|
let damage_reduction = Damage::compute_damage_reduction(
|
|
|
|
read_data.inventories.get(entity),
|
|
|
|
Some(&stat),
|
|
|
|
None,
|
|
|
|
);
|
2021-02-28 20:02:03 +00:00
|
|
|
if (damage_reduction - 1.0).abs() < f32::EPSILON {
|
|
|
|
for (id, buff) in buff_comp.buffs.iter() {
|
|
|
|
if !buff.kind.is_buff() {
|
|
|
|
expired_buffs.push(*id);
|
2020-10-25 18:42:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-21 00:52:29 +00:00
|
|
|
// Call to reset stats to base values
|
2021-03-20 17:29:57 +00:00
|
|
|
stat.reset_temp_modifiers();
|
2020-10-24 23:07:38 +00:00
|
|
|
|
|
|
|
// Iterator over the lists of buffs by kind
|
2021-01-07 20:25:12 +00:00
|
|
|
let buff_comp = &mut *buff_comp;
|
2020-10-24 20:12:37 +00:00
|
|
|
for buff_ids in buff_comp.kinds.values() {
|
2020-10-24 23:07:38 +00:00
|
|
|
// Get the strongest of this buff kind
|
2020-10-24 20:12:37 +00:00
|
|
|
if let Some(buff) = buff_comp.buffs.get_mut(&buff_ids[0]) {
|
2020-10-24 23:07:38 +00:00
|
|
|
// Get buff owner?
|
2020-10-24 20:12:37 +00:00
|
|
|
let buff_owner = if let BuffSource::Character { by: owner } = buff.source {
|
|
|
|
Some(owner)
|
2020-10-19 03:00:35 +00:00
|
|
|
} else {
|
2020-10-24 20:12:37 +00:00
|
|
|
None
|
2020-10-19 03:00:35 +00:00
|
|
|
};
|
2020-10-24 23:07:38 +00:00
|
|
|
|
2020-10-24 20:12:37 +00:00
|
|
|
// Now, execute the buff, based on it's delta
|
|
|
|
for effect in &mut buff.effects {
|
|
|
|
match effect {
|
2020-12-04 22:24:56 +00:00
|
|
|
BuffEffect::HealthChangeOverTime {
|
|
|
|
rate,
|
|
|
|
accumulated,
|
|
|
|
kind,
|
|
|
|
} => {
|
2021-02-22 19:03:18 +00:00
|
|
|
*accumulated += *rate * dt;
|
2021-03-20 17:29:57 +00:00
|
|
|
// Apply health change only once per second, per health, or
|
2020-10-24 20:12:37 +00:00
|
|
|
// when a buff is removed
|
2021-03-20 17:29:57 +00:00
|
|
|
if accumulated.abs() > rate.abs().min(10.0)
|
2020-10-24 20:12:37 +00:00
|
|
|
|| buff.time.map_or(false, |dur| dur == Duration::default())
|
|
|
|
{
|
|
|
|
let cause = if *accumulated > 0.0 {
|
2020-11-05 01:21:42 +00:00
|
|
|
HealthSource::Heal { by: buff_owner }
|
2020-10-24 20:12:37 +00:00
|
|
|
} else {
|
2020-11-05 01:21:42 +00:00
|
|
|
HealthSource::Damage {
|
2021-01-18 05:46:53 +00:00
|
|
|
kind: DamageSource::Buff(buff.kind),
|
2020-11-05 01:21:42 +00:00
|
|
|
by: buff_owner,
|
|
|
|
}
|
2020-10-24 20:12:37 +00:00
|
|
|
};
|
2020-12-04 22:24:56 +00:00
|
|
|
let amount = match *kind {
|
|
|
|
ModifierKind::Additive => *accumulated as i32,
|
|
|
|
ModifierKind::Fractional => {
|
|
|
|
(health.maximum() as f32 * *accumulated) as i32
|
|
|
|
},
|
|
|
|
};
|
2020-10-24 20:12:37 +00:00
|
|
|
server_emitter.emit(ServerEvent::Damage {
|
2020-11-02 00:26:01 +00:00
|
|
|
entity,
|
2020-12-04 22:24:56 +00:00
|
|
|
change: HealthChange { amount, cause },
|
2020-10-24 20:12:37 +00:00
|
|
|
});
|
|
|
|
*accumulated = 0.0;
|
|
|
|
};
|
|
|
|
},
|
2020-10-24 23:07:38 +00:00
|
|
|
BuffEffect::MaxHealthModifier { value, kind } => match kind {
|
|
|
|
ModifierKind::Additive => {
|
2021-07-05 02:43:29 +00:00
|
|
|
stat.max_health_modifier *=
|
|
|
|
1.0 + *value / (health.base_max() as f32);
|
2020-12-04 22:24:56 +00:00
|
|
|
},
|
|
|
|
ModifierKind::Fractional => {
|
2021-03-20 17:29:57 +00:00
|
|
|
stat.max_health_modifier *= *value;
|
2020-10-24 23:07:38 +00:00
|
|
|
},
|
|
|
|
},
|
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
|
|
|
BuffEffect::MaxEnergyModifier { value, kind } => match kind {
|
|
|
|
ModifierKind::Additive => {
|
2021-05-21 00:52:29 +00:00
|
|
|
stat.max_energy_modifier += *value / (energy.base_max() as f32);
|
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
|
|
|
},
|
|
|
|
ModifierKind::Fractional => {
|
2021-05-21 00:52:29 +00:00
|
|
|
stat.max_energy_modifier *= *value;
|
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
|
|
|
},
|
|
|
|
},
|
2021-03-04 03:43:11 +00:00
|
|
|
BuffEffect::DamageReduction(dr) => {
|
2021-03-16 19:17:08 +00:00
|
|
|
stat.damage_reduction = stat.damage_reduction.max(*dr).min(1.0);
|
2021-02-28 20:02:03 +00:00
|
|
|
},
|
2021-03-20 17:29:57 +00:00
|
|
|
BuffEffect::MaxHealthChangeOverTime {
|
|
|
|
rate,
|
|
|
|
kind,
|
|
|
|
target_fraction,
|
2021-07-05 02:43:29 +00:00
|
|
|
achieved_fraction,
|
2021-03-20 17:29:57 +00:00
|
|
|
} => {
|
2021-07-05 02:43:29 +00:00
|
|
|
// Current fraction uses information from last tick, which is
|
|
|
|
// necessary as buffs from this tick are not guaranteed to have
|
|
|
|
// finished applying
|
|
|
|
let current_fraction =
|
|
|
|
health.maximum() as f32 / health.base_max() as f32;
|
|
|
|
|
|
|
|
// If achieved_fraction not initialized, initialize it to health
|
|
|
|
// fraction
|
|
|
|
if achieved_fraction.is_none() {
|
|
|
|
*achieved_fraction = Some(current_fraction)
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(achieved_fraction) = achieved_fraction {
|
|
|
|
// Percentage change that should be applied to max_health
|
|
|
|
let health_tick = match kind {
|
2021-03-20 17:29:57 +00:00
|
|
|
ModifierKind::Additive => {
|
2021-07-05 02:43:29 +00:00
|
|
|
// `rate * dt` is amount of health, dividing by base max
|
|
|
|
// creates fraction
|
|
|
|
*rate * dt / health.base_max() as f32
|
2021-03-20 17:29:57 +00:00
|
|
|
},
|
|
|
|
ModifierKind::Fractional => {
|
2021-07-05 02:43:29 +00:00
|
|
|
// `rate * dt` is the fraction
|
|
|
|
*rate * dt
|
2021-03-20 17:29:57 +00:00
|
|
|
},
|
2021-07-05 02:43:29 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
let potential_fraction = *achieved_fraction + health_tick;
|
|
|
|
|
2021-07-05 03:00:13 +00:00
|
|
|
// Potential progress towards target fraction, if
|
|
|
|
// target_fraction ~ 1.0 then set progress to 1.0 to avoid
|
|
|
|
// divide by zero
|
|
|
|
let progress = if (1.0 - *target_fraction).abs() > f32::EPSILON
|
|
|
|
{
|
|
|
|
(1.0 - potential_fraction) / (1.0 - *target_fraction)
|
|
|
|
} else {
|
|
|
|
1.0
|
|
|
|
};
|
2021-07-05 02:43:29 +00:00
|
|
|
|
|
|
|
// Change achieved_fraction depending on what other buffs have
|
|
|
|
// occurred
|
|
|
|
if progress > 1.0 {
|
|
|
|
// If potential fraction already beyond target fraction,
|
|
|
|
// simply multiply max_health_modifier by the target
|
|
|
|
// fraction, and set achieved fraction to target_fraction
|
|
|
|
*achieved_fraction = *target_fraction;
|
|
|
|
} else {
|
|
|
|
// Else have not achieved target yet, update
|
|
|
|
// achieved_fraction
|
|
|
|
*achieved_fraction = potential_fraction;
|
2021-03-20 17:29:57 +00:00
|
|
|
}
|
2021-07-05 02:43:29 +00:00
|
|
|
|
|
|
|
// Apply achieved_fraction to max_health_modifier
|
|
|
|
stat.max_health_modifier *= *achieved_fraction;
|
2021-03-20 17:29:57 +00:00
|
|
|
}
|
|
|
|
},
|
2021-05-30 20:40:25 +00:00
|
|
|
BuffEffect::MovementSpeed(speed) => {
|
|
|
|
stat.move_speed_modifier *= *speed;
|
2021-04-16 17:44:11 +00:00
|
|
|
},
|
2021-05-30 20:40:25 +00:00
|
|
|
BuffEffect::AttackSpeed(speed) => {
|
|
|
|
stat.attack_speed_modifier *= *speed;
|
2021-05-30 16:40:11 +00:00
|
|
|
},
|
2021-05-24 00:45:22 +00:00
|
|
|
BuffEffect::GroundFriction(gf) => {
|
|
|
|
stat.friction_modifier *= *gf;
|
|
|
|
},
|
2020-10-24 20:12:37 +00:00
|
|
|
};
|
|
|
|
}
|
2020-10-19 03:00:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-24 20:12:37 +00:00
|
|
|
// Remove buffs that expire
|
|
|
|
if !expired_buffs.is_empty() {
|
2020-10-19 03:00:35 +00:00
|
|
|
server_emitter.emit(ServerEvent::Buff {
|
2020-10-25 01:20:03 +00:00
|
|
|
entity,
|
2020-10-24 20:12:37 +00:00
|
|
|
buff_change: BuffChange::RemoveById(expired_buffs),
|
2020-10-19 03:00:35 +00:00
|
|
|
});
|
|
|
|
}
|
2020-10-11 21:39:52 +00:00
|
|
|
|
2020-10-31 22:34:08 +00:00
|
|
|
// Remove buffs that don't persist on death
|
|
|
|
if health.is_dead {
|
2020-10-13 00:48:25 +00:00
|
|
|
server_emitter.emit(ServerEvent::Buff {
|
2020-10-25 01:20:03 +00:00
|
|
|
entity,
|
2020-10-13 00:48:25 +00:00
|
|
|
buff_change: BuffChange::RemoveByCategory {
|
2020-10-24 20:12:37 +00:00
|
|
|
all_required: vec![],
|
|
|
|
any_required: vec![],
|
|
|
|
none_required: vec![BuffCategory::PersistOnDeath],
|
2020-10-13 00:48:25 +00:00
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
2020-08-10 22:54:45 +00:00
|
|
|
}
|
2020-10-27 01:17:46 +00:00
|
|
|
// Turned back to true
|
2020-10-25 01:20:03 +00:00
|
|
|
buffs.set_event_emission(true);
|
2021-02-28 20:02:03 +00:00
|
|
|
stats.set_event_emission(true);
|
2020-08-10 22:54:45 +00:00
|
|
|
}
|
|
|
|
}
|
2021-02-20 20:37:46 +00:00
|
|
|
|
2021-06-22 01:50:31 +00:00
|
|
|
fn tick_buff(id: u64, buff: &mut Buff, dt: f32, mut expire_buff: impl FnMut(u64)) {
|
2021-02-26 23:15:24 +00:00
|
|
|
// If a buff is recently applied from an aura, do not tick duration
|
2021-02-26 22:35:49 +00:00
|
|
|
if buff
|
|
|
|
.cat_ids
|
|
|
|
.iter()
|
|
|
|
.any(|cat_id| matches!(cat_id, BuffCategory::FromAura(true)))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2021-02-20 20:37:46 +00:00
|
|
|
if let Some(remaining_time) = &mut buff.time {
|
|
|
|
if let Some(new_duration) = remaining_time.checked_sub(Duration::from_secs_f32(dt)) {
|
|
|
|
// The buff still continues.
|
|
|
|
*remaining_time = new_duration;
|
|
|
|
} else {
|
|
|
|
// checked_sub returns None when remaining time
|
|
|
|
// went below 0, so set to 0
|
|
|
|
*remaining_time = Duration::default();
|
|
|
|
// The buff has expired.
|
|
|
|
// Remove it.
|
|
|
|
expire_buff(id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|