1use crate::{
2 combat::GroupTarget,
3 comp::buff::{BuffCategory, BuffData, BuffKind, BuffSource},
4 resources::{Secs, Time},
5 uid::Uid,
6};
7use serde::{Deserialize, Serialize};
8use slotmap::{SlotMap, new_key_type};
9use specs::{Component, DerefFlaggedStorage, VecStorage};
10use std::collections::{HashMap, HashSet};
11
12new_key_type! { pub struct AuraKey; }
13
14#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
17pub enum AuraKind {
18 Buff {
20 kind: BuffKind,
21 data: BuffData,
22 category: BuffCategory,
23 source: BuffSource,
24 },
25 FriendlyFire,
28 ForcePvP,
31 }
36
37#[derive(Clone, Copy, Debug, Serialize, Deserialize, Hash, PartialEq, Eq, PartialOrd, Ord)]
39pub enum AuraKindVariant {
40 Buff,
41 FriendlyFire,
42 ForcePvP,
43}
44
45#[derive(Clone, Debug, Serialize, Deserialize)]
49pub struct Aura {
50 pub aura_kind: AuraKind,
52 pub radius: f32,
54 pub end_time: Option<Time>,
56 pub target: AuraTarget,
62 pub data: AuraData,
65}
66
67#[derive(Clone, Debug)]
70pub enum AuraChange {
71 Add(Aura),
73 RemoveByKey(Vec<AuraKey>),
75 EnterAura(Uid, AuraKey, AuraKindVariant),
76 ExitAura(Uid, AuraKey, AuraKindVariant),
77}
78
79#[derive(Copy, Clone, Debug, Deserialize, Serialize)]
81pub enum AuraTarget {
82 GroupOf(Uid),
85 NotGroupOf(Uid),
89 All,
91}
92
93#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
94pub enum Specifier {
95 WardingAura,
96 HealingAura,
97 Frozen,
98 FieryAura,
99}
100
101impl From<(Option<GroupTarget>, Option<&Uid>)> for AuraTarget {
102 fn from((target, uid): (Option<GroupTarget>, Option<&Uid>)) -> Self {
103 match (target, uid) {
104 (Some(GroupTarget::InGroup), Some(uid)) => Self::GroupOf(*uid),
105 (Some(GroupTarget::OutOfGroup), Some(uid)) => Self::NotGroupOf(*uid),
106 _ => Self::All,
107 }
108 }
109}
110
111impl AsRef<AuraKindVariant> for AuraKind {
112 fn as_ref(&self) -> &AuraKindVariant {
113 match self {
114 AuraKind::Buff { .. } => &AuraKindVariant::Buff,
115 AuraKind::FriendlyFire => &AuraKindVariant::FriendlyFire,
116 AuraKind::ForcePvP => &AuraKindVariant::ForcePvP,
117 }
118 }
119}
120
121#[derive(Clone, Debug, Serialize, Deserialize)]
122pub struct AuraData {
123 pub duration: Option<Secs>,
124}
125
126impl AuraData {
127 #[must_use]
128 fn new(duration: Option<Secs>) -> Self { Self { duration } }
129}
130
131impl Aura {
132 pub fn new(
134 aura_kind: AuraKind,
135 radius: f32,
136 duration: Option<Secs>,
137 target: AuraTarget,
138 time: Time,
139 ) -> Self {
140 Self {
141 aura_kind,
142 radius,
143 end_time: duration.map(|dur| Time(time.0 + dur.0)),
144 target,
145 data: AuraData::new(duration),
146 }
147 }
148}
149
150#[derive(Clone, Debug, Serialize, Deserialize, Default)]
152pub struct Auras {
153 pub auras: SlotMap<AuraKey, Aura>,
154}
155
156impl Auras {
157 pub fn new(auras: Vec<Aura>) -> Self {
158 let mut auras_comp: SlotMap<AuraKey, Aura> = SlotMap::with_key();
159 for aura in auras {
160 auras_comp.insert(aura);
161 }
162 Self { auras: auras_comp }
163 }
164
165 pub fn insert(&mut self, aura: Aura) { self.auras.insert(aura); }
166
167 pub fn remove(&mut self, key: AuraKey) { self.auras.remove(key); }
168}
169
170#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq)]
171#[serde(deny_unknown_fields)]
172pub struct AuraBuffConstructor {
173 pub kind: BuffKind,
174 pub strength: f32,
175 pub duration: Option<Secs>,
176 pub category: BuffCategory,
177}
178
179impl AuraBuffConstructor {
180 pub fn to_aura(
181 self,
182 uid: &Uid,
183 radius: f32,
184 duration: Option<Secs>,
185 target: AuraTarget,
186 time: Time,
187 ) -> Aura {
188 let aura_kind = AuraKind::Buff {
189 kind: self.kind,
190 data: BuffData::new(self.strength, self.duration),
191 category: self.category,
192 source: BuffSource::Character { by: *uid },
193 };
194 Aura::new(aura_kind, radius, duration, target, time)
195 }
196}
197
198#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
200pub struct EnteredAuras {
201 pub auras: HashMap<AuraKindVariant, HashSet<(Uid, AuraKey)>>,
204}
205
206impl EnteredAuras {
207 pub fn flatten(&self) -> impl Iterator<Item = (Uid, AuraKey)> + '_ {
208 self.auras.values().flat_map(|i| i.iter().copied())
209 }
210}
211
212impl Component for Auras {
213 type Storage = DerefFlaggedStorage<Self, VecStorage<Self>>;
214}
215
216impl Component for EnteredAuras {
217 type Storage = DerefFlaggedStorage<Self, VecStorage<Self>>;
218}