mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Extract buff executor into own function
This commit is contained in:
parent
7ea720b2ef
commit
54c48c7112
@ -11,10 +11,10 @@ use common::{
|
||||
Energy, Group, Health, HealthChange, Inventory, LightEmitter, ModifierKind, PhysicsState,
|
||||
Stats,
|
||||
},
|
||||
event::{EventBus, ServerEvent},
|
||||
event::{Emitter, EventBus, ServerEvent},
|
||||
resources::{DeltaTime, Time},
|
||||
terrain::SpriteKind,
|
||||
uid::UidAllocator,
|
||||
uid::{Uid, UidAllocator},
|
||||
Damage, DamageSource,
|
||||
};
|
||||
use common_base::prof_span;
|
||||
@ -22,8 +22,8 @@ use common_ecs::{Job, Origin, ParMode, Phase, System};
|
||||
use hashbrown::HashMap;
|
||||
use rayon::iter::ParallelIterator;
|
||||
use specs::{
|
||||
saveload::MarkerAllocator, shred::ResourceId, Entities, Join, ParJoin, Read, ReadExpect,
|
||||
ReadStorage, SystemData, World, WriteStorage,
|
||||
saveload::MarkerAllocator, shred::ResourceId, Entities, Entity, Join, ParJoin, Read,
|
||||
ReadExpect, ReadStorage, SystemData, World, WriteStorage,
|
||||
};
|
||||
use std::time::Duration;
|
||||
|
||||
@ -257,165 +257,19 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
// Now, execute the buff, based on it's delta
|
||||
for effect in &mut buff.effects {
|
||||
match effect {
|
||||
BuffEffect::HealthChangeOverTime {
|
||||
rate,
|
||||
accumulated,
|
||||
kind,
|
||||
instance,
|
||||
} => {
|
||||
*accumulated += *rate * dt;
|
||||
// Apply health change only once per second, per health, or
|
||||
// when a buff is removed
|
||||
if accumulated.abs() > rate.abs().min(1.0)
|
||||
|| buff.time.map_or(false, |dur| dur == Duration::default())
|
||||
{
|
||||
let (cause, by) = if *accumulated != 0.0 {
|
||||
(Some(DamageSource::Buff(buff.kind)), buff_owner)
|
||||
} else {
|
||||
(None, None)
|
||||
};
|
||||
let amount = match *kind {
|
||||
ModifierKind::Additive => *accumulated,
|
||||
ModifierKind::Fractional => health.maximum() * *accumulated,
|
||||
};
|
||||
let damage_contributor = by.and_then(|uid| {
|
||||
read_data.uid_allocator.retrieve_entity_internal(uid.0).map(
|
||||
|entity| {
|
||||
DamageContributor::new(
|
||||
uid,
|
||||
read_data.groups.get(entity).cloned(),
|
||||
)
|
||||
},
|
||||
)
|
||||
});
|
||||
server_emitter.emit(ServerEvent::HealthChange {
|
||||
entity,
|
||||
change: HealthChange {
|
||||
amount,
|
||||
by: damage_contributor,
|
||||
cause,
|
||||
time: *read_data.time,
|
||||
crit: false,
|
||||
instance: *instance,
|
||||
},
|
||||
});
|
||||
*accumulated = 0.0;
|
||||
};
|
||||
},
|
||||
BuffEffect::EnergyChangeOverTime {
|
||||
rate,
|
||||
accumulated,
|
||||
kind,
|
||||
} => {
|
||||
*accumulated += *rate * dt;
|
||||
// Apply energy change only once per second, per energy, or
|
||||
// when a buff is removed
|
||||
if accumulated.abs() > rate.abs().min(10.0)
|
||||
|| buff.time.map_or(false, |dur| dur == Duration::default())
|
||||
{
|
||||
let amount = match *kind {
|
||||
ModifierKind::Additive => *accumulated,
|
||||
ModifierKind::Fractional => {
|
||||
energy.maximum() as f32 * *accumulated
|
||||
},
|
||||
};
|
||||
server_emitter.emit(ServerEvent::EnergyChange {
|
||||
entity,
|
||||
change: amount,
|
||||
});
|
||||
*accumulated = 0.0;
|
||||
};
|
||||
},
|
||||
BuffEffect::MaxHealthModifier { value, kind } => match kind {
|
||||
ModifierKind::Additive => {
|
||||
stat.max_health_modifiers.add_mod += *value;
|
||||
},
|
||||
ModifierKind::Fractional => {
|
||||
stat.max_health_modifiers.mult_mod *= *value;
|
||||
},
|
||||
},
|
||||
BuffEffect::MaxEnergyModifier { value, kind } => match kind {
|
||||
ModifierKind::Additive => {
|
||||
stat.max_energy_modifiers.add_mod += *value;
|
||||
},
|
||||
ModifierKind::Fractional => {
|
||||
stat.max_energy_modifiers.mult_mod *= *value;
|
||||
},
|
||||
},
|
||||
BuffEffect::DamageReduction(dr) => {
|
||||
stat.damage_reduction = stat.damage_reduction.max(*dr).min(1.0);
|
||||
},
|
||||
BuffEffect::MaxHealthChangeOverTime {
|
||||
rate,
|
||||
kind,
|
||||
target_fraction,
|
||||
achieved_fraction,
|
||||
} => {
|
||||
// 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() / health.base_max();
|
||||
|
||||
// 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 {
|
||||
ModifierKind::Additive => {
|
||||
// `rate * dt` is amount of health, dividing by base max
|
||||
// creates fraction
|
||||
*rate * dt / health.base_max() as f32
|
||||
},
|
||||
ModifierKind::Fractional => {
|
||||
// `rate * dt` is the fraction
|
||||
*rate * dt
|
||||
},
|
||||
};
|
||||
|
||||
let potential_fraction = *achieved_fraction + health_tick;
|
||||
|
||||
// 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
|
||||
};
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Apply achieved_fraction to max_health_modifier
|
||||
stat.max_health_modifiers.mult_mod *= *achieved_fraction;
|
||||
}
|
||||
},
|
||||
BuffEffect::MovementSpeed(speed) => {
|
||||
stat.move_speed_modifier *= *speed;
|
||||
},
|
||||
BuffEffect::AttackSpeed(speed) => {
|
||||
stat.attack_speed_modifier *= *speed;
|
||||
},
|
||||
BuffEffect::GroundFriction(gf) => {
|
||||
stat.friction_modifier *= *gf;
|
||||
},
|
||||
};
|
||||
execute_effect(
|
||||
effect,
|
||||
buff.kind,
|
||||
buff.time,
|
||||
&read_data,
|
||||
&mut *stat,
|
||||
health,
|
||||
energy,
|
||||
entity,
|
||||
buff_owner,
|
||||
&mut server_emitter,
|
||||
dt,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -446,6 +300,175 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
}
|
||||
|
||||
fn execute_effect(
|
||||
effect: &mut BuffEffect,
|
||||
buff_kind: BuffKind,
|
||||
buff_time: Option<std::time::Duration>,
|
||||
read_data: &ReadData,
|
||||
stat: &mut Stats,
|
||||
health: &Health,
|
||||
energy: &Energy,
|
||||
entity: Entity,
|
||||
buff_owner: Option<Uid>,
|
||||
server_emitter: &mut Emitter<ServerEvent>,
|
||||
dt: f32,
|
||||
) {
|
||||
match effect {
|
||||
BuffEffect::HealthChangeOverTime {
|
||||
rate,
|
||||
accumulated,
|
||||
kind,
|
||||
instance,
|
||||
} => {
|
||||
*accumulated += *rate * dt;
|
||||
// Apply health change only once per second, per health, or
|
||||
// when a buff is removed
|
||||
if accumulated.abs() > rate.abs().min(1.0)
|
||||
|| buff_time.map_or(false, |dur| dur == Duration::default())
|
||||
{
|
||||
let (cause, by) = if *accumulated != 0.0 {
|
||||
(Some(DamageSource::Buff(buff_kind)), buff_owner)
|
||||
} else {
|
||||
(None, None)
|
||||
};
|
||||
let amount = match *kind {
|
||||
ModifierKind::Additive => *accumulated,
|
||||
ModifierKind::Fractional => health.maximum() * *accumulated,
|
||||
};
|
||||
let damage_contributor = by.and_then(|uid| {
|
||||
read_data
|
||||
.uid_allocator
|
||||
.retrieve_entity_internal(uid.0)
|
||||
.map(|entity| {
|
||||
DamageContributor::new(uid, read_data.groups.get(entity).cloned())
|
||||
})
|
||||
});
|
||||
server_emitter.emit(ServerEvent::HealthChange {
|
||||
entity,
|
||||
change: HealthChange {
|
||||
amount,
|
||||
by: damage_contributor,
|
||||
cause,
|
||||
time: *read_data.time,
|
||||
crit: false,
|
||||
instance: *instance,
|
||||
},
|
||||
});
|
||||
*accumulated = 0.0;
|
||||
};
|
||||
},
|
||||
BuffEffect::EnergyChangeOverTime {
|
||||
rate,
|
||||
accumulated,
|
||||
kind,
|
||||
} => {
|
||||
*accumulated += *rate * dt;
|
||||
// Apply energy change only once per second, per energy, or
|
||||
// when a buff is removed
|
||||
if accumulated.abs() > rate.abs().min(10.0)
|
||||
|| buff_time.map_or(false, |dur| dur == Duration::default())
|
||||
{
|
||||
let amount = match *kind {
|
||||
ModifierKind::Additive => *accumulated,
|
||||
ModifierKind::Fractional => energy.maximum() as f32 * *accumulated,
|
||||
};
|
||||
server_emitter.emit(ServerEvent::EnergyChange {
|
||||
entity,
|
||||
change: amount,
|
||||
});
|
||||
*accumulated = 0.0;
|
||||
};
|
||||
},
|
||||
BuffEffect::MaxHealthModifier { value, kind } => match kind {
|
||||
ModifierKind::Additive => {
|
||||
stat.max_health_modifiers.add_mod += *value;
|
||||
},
|
||||
ModifierKind::Fractional => {
|
||||
stat.max_health_modifiers.mult_mod *= *value;
|
||||
},
|
||||
},
|
||||
BuffEffect::MaxEnergyModifier { value, kind } => match kind {
|
||||
ModifierKind::Additive => {
|
||||
stat.max_energy_modifiers.add_mod += *value;
|
||||
},
|
||||
ModifierKind::Fractional => {
|
||||
stat.max_energy_modifiers.mult_mod *= *value;
|
||||
},
|
||||
},
|
||||
BuffEffect::DamageReduction(dr) => {
|
||||
stat.damage_reduction = stat.damage_reduction.max(*dr).min(1.0);
|
||||
},
|
||||
BuffEffect::MaxHealthChangeOverTime {
|
||||
rate,
|
||||
kind,
|
||||
target_fraction,
|
||||
achieved_fraction,
|
||||
} => {
|
||||
// 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() / health.base_max();
|
||||
|
||||
// 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 {
|
||||
ModifierKind::Additive => {
|
||||
// `rate * dt` is amount of health, dividing by base max
|
||||
// creates fraction
|
||||
*rate * dt / health.base_max() as f32
|
||||
},
|
||||
ModifierKind::Fractional => {
|
||||
// `rate * dt` is the fraction
|
||||
*rate * dt
|
||||
},
|
||||
};
|
||||
|
||||
let potential_fraction = *achieved_fraction + health_tick;
|
||||
|
||||
// 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
|
||||
};
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Apply achieved_fraction to max_health_modifier
|
||||
stat.max_health_modifiers.mult_mod *= *achieved_fraction;
|
||||
}
|
||||
},
|
||||
BuffEffect::MovementSpeed(speed) => {
|
||||
stat.move_speed_modifier *= *speed;
|
||||
},
|
||||
BuffEffect::AttackSpeed(speed) => {
|
||||
stat.attack_speed_modifier *= *speed;
|
||||
},
|
||||
BuffEffect::GroundFriction(gf) => {
|
||||
stat.friction_modifier *= *gf;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn tick_buff(id: u64, buff: &mut Buff, dt: f32, mut expire_buff: impl FnMut(u64)) {
|
||||
// If a buff is recently applied from an aura, do not tick duration
|
||||
if buff
|
||||
|
Loading…
Reference in New Issue
Block a user