veloren/common/sys/src/aura.rs

150 lines
5.8 KiB
Rust
Raw Normal View History

2020-12-04 22:24:56 +00:00
use common::{
comp::{
2021-01-18 22:58:56 +00:00
aura::{AuraChange, AuraKey, AuraKind, AuraTarget},
buff,
group::Group,
Auras, BuffKind, Buffs, CharacterState, Health, Pos,
2020-12-04 22:24:56 +00:00
},
event::{EventBus, ServerEvent},
resources::DeltaTime,
2021-01-18 22:58:56 +00:00
uid::UidAllocator,
2020-12-04 22:24:56 +00:00
};
2021-01-18 22:58:56 +00:00
use specs::{saveload::MarkerAllocator, Entities, Join, Read, ReadStorage, System, WriteStorage};
2020-12-04 22:24:56 +00:00
use std::time::Duration;
pub struct Sys;
impl<'a> System<'a> for Sys {
#[allow(clippy::type_complexity)]
type SystemData = (
Entities<'a>,
Read<'a, DeltaTime>,
ReadStorage<'a, Pos>,
Read<'a, EventBus<ServerEvent>>,
ReadStorage<'a, CharacterState>,
WriteStorage<'a, Auras>,
WriteStorage<'a, Buffs>,
2021-01-14 12:21:55 +00:00
ReadStorage<'a, Health>,
2021-01-18 22:58:56 +00:00
ReadStorage<'a, Group>,
Read<'a, UidAllocator>,
2020-12-04 22:24:56 +00:00
);
fn run(
&mut self,
2021-01-18 22:58:56 +00:00
(
entities,
dt,
positions,
server_bus,
character_states,
mut auras,
mut buffs,
health,
groups,
uid_allocator,
): Self::SystemData,
2020-12-04 22:24:56 +00:00
) {
let mut server_emitter = server_bus.emitter();
auras.set_event_emission(false);
// Iterate through all entities with an aura
for (entity, pos, mut auras_comp) in (&entities, &positions, &mut auras).join() {
2020-12-04 22:24:56 +00:00
let mut expired_auras = Vec::<AuraKey>::new();
// Iterate through the auras attached to this entity
for (key, aura) in auras_comp.auras.iter_mut() {
// Tick the aura and subtract dt from it
if let Some(remaining_time) = &mut aura.duration {
if let Some(new_duration) =
remaining_time.checked_sub(Duration::from_secs_f32(dt.0))
{
*remaining_time = new_duration;
} else {
*remaining_time = Duration::default();
expired_auras.push(key);
}
}
2021-01-14 12:21:55 +00:00
for (
target_entity,
target_pos,
target_character_state_maybe,
target_buffs,
health,
) in (
&entities,
&positions,
character_states.maybe(),
&mut buffs,
&health,
)
.join()
2020-12-04 22:24:56 +00:00
{
// Ensure entity is within the aura radius
if target_pos.0.distance_squared(pos.0) < aura.radius.powi(2) {
2021-01-18 22:58:56 +00:00
if let AuraTarget::GroupOf(uid) = aura.target {
let same_group = uid_allocator
.retrieve_entity_internal(uid.into())
.and_then(|e| groups.get(e))
.map_or(false, |owner_group| {
Some(owner_group) == groups.get(target_entity)
});
if !same_group {
continue;
}
}
2020-12-04 22:24:56 +00:00
// TODO: When more aura kinds (besides Buff) are
// implemented, match on them here
match aura.aura_kind {
AuraKind::Buff {
kind,
data,
category,
source,
} => {
// Checks if the buff is not active so it isn't applied
// every tick, but rather only once it runs out
// TODO: Check for stronger buff of same kind so it can replace
// active buff.
if !target_buffs.contains(kind) {
// Conditions for different buffs are in this match
// statement
let apply_buff = match kind {
2021-01-14 12:21:55 +00:00
BuffKind::CampfireHeal => {
matches!(
target_character_state_maybe,
Some(CharacterState::Sit)
) && health.current() < health.maximum()
},
2020-12-04 22:24:56 +00:00
// Add other specific buff conditions here
_ => true,
};
if apply_buff {
use buff::*;
server_emitter.emit(ServerEvent::Buff {
entity: target_entity,
buff_change: BuffChange::Add(Buff::new(
kind,
data,
vec![category],
source,
)),
});
}
}
},
}
}
}
}
if !expired_auras.is_empty() {
server_emitter.emit(ServerEvent::Aura {
entity,
aura_change: AuraChange::RemoveByKey(expired_auras),
});
}
}
auras.set_event_emission(true);
}
}