use crate::{
combat::GroupTarget,
comp::buff::{BuffCategory, BuffData, BuffKind, BuffSource},
resources::{Secs, Time},
uid::Uid,
};
use serde::{Deserialize, Serialize};
use slotmap::{new_key_type, SlotMap};
use specs::{Component, DerefFlaggedStorage, VecStorage};
use std::collections::{HashMap, HashSet};
new_key_type! { pub struct AuraKey; }
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub enum AuraKind {
Buff {
kind: BuffKind,
data: BuffData,
category: BuffCategory,
source: BuffSource,
},
FriendlyFire,
ForcePvP,
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum AuraKindVariant {
Buff,
FriendlyFire,
ForcePvP,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Aura {
pub aura_kind: AuraKind,
pub radius: f32,
pub end_time: Option<Time>,
pub target: AuraTarget,
pub data: AuraData,
}
#[derive(Clone, Debug)]
pub enum AuraChange {
Add(Aura),
RemoveByKey(Vec<AuraKey>),
EnterAura(Uid, AuraKey, AuraKindVariant),
ExitAura(Uid, AuraKey, AuraKindVariant),
}
#[derive(Copy, Clone, Debug, Deserialize, Serialize)]
pub enum AuraTarget {
GroupOf(Uid),
NotGroupOf(Uid),
All,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub enum Specifier {
WardingAura,
HealingAura,
Frozen,
FieryAura,
}
impl From<(Option<GroupTarget>, Option<&Uid>)> for AuraTarget {
fn from((target, uid): (Option<GroupTarget>, Option<&Uid>)) -> Self {
match (target, uid) {
(Some(GroupTarget::InGroup), Some(uid)) => Self::GroupOf(*uid),
(Some(GroupTarget::OutOfGroup), Some(uid)) => Self::NotGroupOf(*uid),
_ => Self::All,
}
}
}
impl AsRef<AuraKindVariant> for AuraKind {
fn as_ref(&self) -> &AuraKindVariant {
match self {
AuraKind::Buff { .. } => &AuraKindVariant::Buff,
AuraKind::FriendlyFire => &AuraKindVariant::FriendlyFire,
AuraKind::ForcePvP => &AuraKindVariant::ForcePvP,
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AuraData {
pub duration: Option<Secs>,
}
impl AuraData {
#[must_use]
fn new(duration: Option<Secs>) -> Self { Self { duration } }
}
impl Aura {
pub fn new(
aura_kind: AuraKind,
radius: f32,
duration: Option<Secs>,
target: AuraTarget,
time: Time,
) -> Self {
Self {
aura_kind,
radius,
end_time: duration.map(|dur| Time(time.0 + dur.0)),
target,
data: AuraData::new(duration),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
pub struct Auras {
pub auras: SlotMap<AuraKey, Aura>,
}
impl Auras {
pub fn new(auras: Vec<Aura>) -> Self {
let mut auras_comp: SlotMap<AuraKey, Aura> = SlotMap::with_key();
for aura in auras {
auras_comp.insert(aura);
}
Self { auras: auras_comp }
}
pub fn insert(&mut self, aura: Aura) { self.auras.insert(aura); }
pub fn remove(&mut self, key: AuraKey) { self.auras.remove(key); }
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct AuraBuffConstructor {
pub kind: BuffKind,
pub strength: f32,
pub duration: Option<Secs>,
pub category: BuffCategory,
}
impl AuraBuffConstructor {
pub fn to_aura(
self,
uid: &Uid,
radius: f32,
duration: Option<Secs>,
target: AuraTarget,
time: Time,
) -> Aura {
let aura_kind = AuraKind::Buff {
kind: self.kind,
data: BuffData::new(self.strength, self.duration),
category: self.category,
source: BuffSource::Character { by: *uid },
};
Aura::new(aura_kind, radius, duration, target, time)
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub struct EnteredAuras {
pub auras: HashMap<AuraKindVariant, HashSet<(Uid, AuraKey)>>,
}
impl EnteredAuras {
pub fn flatten(&self) -> impl Iterator<Item = (Uid, AuraKey)> + '_ {
self.auras.values().flat_map(|i| i.iter().copied())
}
}
impl Component for Auras {
type Storage = DerefFlaggedStorage<Self, VecStorage<Self>>;
}
impl Component for EnteredAuras {
type Storage = DerefFlaggedStorage<Self, VecStorage<Self>>;
}