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,
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 (Some(GroupTarget::All), _) => Self::All,
107 _ => Self::All,
108 }
109 }
110}
111
112impl AsRef<AuraKindVariant> for AuraKind {
113 fn as_ref(&self) -> &AuraKindVariant {
114 match self {
115 AuraKind::Buff { .. } => &AuraKindVariant::Buff,
116 AuraKind::FriendlyFire => &AuraKindVariant::FriendlyFire,
117 AuraKind::ForcePvP => &AuraKindVariant::ForcePvP,
118 }
119 }
120}
121
122#[derive(Clone, Debug, Serialize, Deserialize)]
123pub struct AuraData {
124 pub duration: Option<Secs>,
125}
126
127impl AuraData {
128 #[must_use]
129 fn new(duration: Option<Secs>) -> Self { Self { duration } }
130}
131
132impl Aura {
133 pub fn new(
135 aura_kind: AuraKind,
136 radius: f32,
137 duration: Option<Secs>,
138 target: AuraTarget,
139 time: Time,
140 ) -> Self {
141 Self {
142 aura_kind,
143 radius,
144 end_time: duration.map(|dur| Time(time.0 + dur.0)),
145 target,
146 data: AuraData::new(duration),
147 }
148 }
149}
150
151#[derive(Clone, Debug, Serialize, Deserialize, Default)]
153pub struct Auras {
154 pub auras: SlotMap<AuraKey, Aura>,
155}
156
157impl Auras {
158 pub fn new(auras: Vec<Aura>) -> Self {
159 let mut auras_comp: SlotMap<AuraKey, Aura> = SlotMap::with_key();
160 for aura in auras {
161 auras_comp.insert(aura);
162 }
163 Self { auras: auras_comp }
164 }
165
166 pub fn insert(&mut self, aura: Aura) { self.auras.insert(aura); }
167
168 pub fn remove(&mut self, key: AuraKey) { self.auras.remove(key); }
169}
170
171#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
172#[serde(deny_unknown_fields)]
173pub struct AuraBuffConstructor {
174 pub kind: BuffKind,
175 pub strength: f32,
176 pub duration: Option<Secs>,
177 pub category: BuffCategory,
178}
179
180impl AuraBuffConstructor {
181 pub fn to_aura(
182 &self,
183 uid: &Uid,
184 radius: f32,
185 duration: Option<Secs>,
186 target: AuraTarget,
187 time: Time,
188 ) -> Aura {
189 let aura_kind = AuraKind::Buff {
190 kind: self.kind,
191 data: BuffData::new(self.strength, self.duration),
192 category: self.category.clone(),
193 source: BuffSource::Character { by: *uid },
194 };
195 Aura::new(aura_kind, radius, duration, target, time)
196 }
197}
198
199#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
201pub struct EnteredAuras {
202 pub auras: HashMap<AuraKindVariant, HashSet<(Uid, AuraKey)>>,
205}
206
207impl EnteredAuras {
208 pub fn flatten(&self) -> impl Iterator<Item = (Uid, AuraKey)> + '_ {
209 self.auras.values().flat_map(|i| i.iter().copied())
210 }
211}
212
213impl Component for Auras {
214 type Storage = DerefFlaggedStorage<Self, VecStorage<Self>>;
215}
216
217impl Component for EnteredAuras {
218 type Storage = DerefFlaggedStorage<Self, VecStorage<Self>>;
219}