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