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, 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,
32 }
37
38#[derive(Clone, Copy, Debug, Serialize, Deserialize, Hash, PartialEq, Eq, PartialOrd, Ord)]
40pub enum AuraKindVariant {
41 Buff,
42 FriendlyFire,
43 ForcePvP,
44}
45
46#[derive(Clone, Debug, Serialize, Deserialize)]
50pub struct Aura {
51 pub aura_kind: AuraKind,
53 pub radius: f32,
55 pub end_time: Option<Time>,
57 pub target: AuraTarget,
63 pub data: AuraData,
66}
67
68#[derive(Clone, Debug)]
71pub enum AuraChange {
72 Add(Aura),
74 RemoveByKey(Vec<AuraKey>),
76 EnterAura(Uid, AuraKey, AuraKindVariant),
77 ExitAura(Uid, AuraKey, AuraKindVariant),
78}
79
80#[derive(Copy, Clone, Debug, Deserialize, Serialize)]
82pub enum AuraTarget {
83 GroupOf(Uid),
86 NotGroupOf(Uid),
90 All,
92}
93
94#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
95pub enum Specifier {
96 WardingAura,
97 HealingAura,
98 Frozen,
99 FieryAura,
100}
101
102impl From<(Option<GroupTarget>, Option<&Uid>)> for AuraTarget {
103 fn from((target, uid): (Option<GroupTarget>, Option<&Uid>)) -> Self {
104 match (target, uid) {
105 (Some(GroupTarget::InGroup), Some(uid)) => Self::GroupOf(*uid),
106 (Some(GroupTarget::OutOfGroup), Some(uid)) => Self::NotGroupOf(*uid),
107 (Some(GroupTarget::All), _) => Self::All,
108 _ => Self::All,
109 }
110 }
111}
112
113impl AsRef<AuraKindVariant> for AuraKind {
114 fn as_ref(&self) -> &AuraKindVariant {
115 match self {
116 AuraKind::Buff { .. } => &AuraKindVariant::Buff,
117 AuraKind::FriendlyFire => &AuraKindVariant::FriendlyFire,
118 AuraKind::ForcePvP => &AuraKindVariant::ForcePvP,
119 }
120 }
121}
122
123#[derive(Clone, Debug, Serialize, Deserialize)]
124pub struct AuraData {
125 pub duration: Option<Secs>,
126}
127
128impl AuraData {
129 #[must_use]
130 fn new(duration: Option<Secs>) -> Self { Self { duration } }
131}
132
133impl Aura {
134 pub fn new(
136 aura_kind: AuraKind,
137 radius: f32,
138 duration: Option<Secs>,
139 target: AuraTarget,
140 time: Time,
141 ) -> Self {
142 Self {
143 aura_kind,
144 radius,
145 end_time: duration.map(|dur| Time(time.0 + dur.0)),
146 target,
147 data: AuraData::new(duration),
148 }
149 }
150}
151
152#[derive(Clone, Debug, Serialize, Deserialize, Default)]
154pub struct Auras {
155 pub auras: SlotMap<AuraKey, Aura>,
156}
157
158impl Auras {
159 pub fn new(auras: Vec<Aura>) -> Self {
160 let mut auras_comp: SlotMap<AuraKey, Aura> = SlotMap::with_key();
161 for aura in auras {
162 auras_comp.insert(aura);
163 }
164 Self { auras: auras_comp }
165 }
166
167 pub fn insert(&mut self, aura: Aura) { self.auras.insert(aura); }
168
169 pub fn remove(&mut self, key: AuraKey) { self.auras.remove(key); }
170}
171
172#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
173#[serde(deny_unknown_fields)]
174pub struct AuraBuffConstructor {
175 pub kind: BuffKind,
176 pub strength: f32,
177 pub duration: Option<Secs>,
178 pub category: BuffCategory,
179}
180
181impl AuraBuffConstructor {
182 pub fn to_aura(
183 &self,
184 uid: &Uid,
185 radius: f32,
186 duration: Option<Secs>,
187 target: AuraTarget,
188 time: Time,
189 ) -> Aura {
190 let aura_kind = AuraKind::Buff {
191 kind: self.kind,
192 data: BuffData::new(self.strength, self.duration),
193 category: self.category.clone(),
194 source: BuffSource::Character { by: *uid },
195 };
196 Aura::new(aura_kind, radius, duration, target, time)
197 }
198}
199
200#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
202pub struct EnteredAuras {
203 pub auras: HashMap<AuraKindVariant, HashSet<(Uid, AuraKey)>>,
206}
207
208impl EnteredAuras {
209 pub fn flatten(&self) -> impl Iterator<Item = (Uid, AuraKey)> + '_ {
210 self.auras.values().flat_map(|i| i.iter().copied())
211 }
212}
213
214impl Component for Auras {
215 type Storage = DerefFlaggedStorage<Self, VecStorage<Self>>;
216}
217
218impl Component for EnteredAuras {
219 type Storage = DerefFlaggedStorage<Self, VecStorage<Self>>;
220}