1#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, num_enum::TryFromPrimitive)]
5#[repr(i32)]
6#[non_exhaustive]
7pub enum ImplicitTargetSelector {
8 #[default]
9 None = 0,
10}
11
12#[derive(Clone, Copy, Debug, Eq, PartialEq)]
14#[repr(u8)]
15#[non_exhaustive]
16pub enum ImplicitTargetObject {
17 None,
18 Source,
19 Destination,
20 Unit,
21 UnitAndDestination,
22 GameObject,
23 GameObjectItem,
24 Item,
25 Corpse,
26 CorpseEnemy,
27 CorpseAlly,
28}
29
30#[derive(Clone, Copy, Debug, Eq, PartialEq)]
32#[repr(u8)]
33#[non_exhaustive]
34pub enum ImplicitTargetReference {
35 None,
36 Caster,
37 Target,
38 Last,
39 Source,
40 Destination,
41}
42
43#[derive(Clone, Copy, Debug, Eq, PartialEq)]
45#[repr(u8)]
46#[non_exhaustive]
47pub enum ImplicitTargetSelection {
48 NotImplemented,
49 Default,
50 Channel,
51 Nearby,
52 Cone,
53 Area,
54 Trajectory,
55 Line,
56}
57
58#[derive(Clone, Copy, Debug, Eq, PartialEq)]
60#[repr(u8)]
61#[non_exhaustive]
62pub enum ImplicitTargetCheck {
63 Default,
64 Entry,
65 Enemy,
66 Ally,
67 Party,
68 Raid,
69 RaidClass,
70 Passenger,
71 Summoned,
72}
73
74#[derive(Clone, Copy, Debug, Eq, PartialEq)]
76#[repr(u8)]
77#[non_exhaustive]
78pub enum ImplicitTargetDirection {
79 None,
80 Front,
81 Back,
82 Right,
83 Left,
84 FrontRight,
85 BackRight,
86 BackLeft,
87 FrontLeft,
88 Random,
89 Entry,
90}
91
92impl ImplicitTargetObject {
93 #[must_use]
94 pub const fn as_str(&self) -> &'static str {
95 match self {
96 Self::None => "none",
97 Self::Source => "source",
98 Self::Destination => "destination",
99 Self::Unit => "unit",
100 Self::UnitAndDestination => "unit and destination",
101 Self::GameObject => "game object",
102 Self::GameObjectItem => "game object item",
103 Self::Item => "item",
104 Self::Corpse => "corpse",
105 Self::CorpseEnemy => "enemy corpse",
106 Self::CorpseAlly => "ally corpse",
107 }
108 }
109}
110
111impl ImplicitTargetReference {
112 #[must_use]
113 pub const fn as_str(&self) -> &'static str {
114 match self {
115 Self::None => "none",
116 Self::Caster => "caster",
117 Self::Target => "target",
118 Self::Last => "last",
119 Self::Source => "source",
120 Self::Destination => "destination",
121 }
122 }
123}
124
125impl ImplicitTargetSelection {
126 #[must_use]
127 pub const fn as_str(&self) -> &'static str {
128 match self {
129 Self::NotImplemented => "not implemented",
130 Self::Default => "default",
131 Self::Channel => "channel",
132 Self::Nearby => "nearby",
133 Self::Cone => "cone",
134 Self::Area => "area",
135 Self::Trajectory => "trajectory",
136 Self::Line => "line",
137 }
138 }
139}
140
141impl ImplicitTargetCheck {
142 #[must_use]
143 pub const fn as_str(&self) -> &'static str {
144 match self {
145 Self::Default => "default",
146 Self::Entry => "entry",
147 Self::Enemy => "enemy",
148 Self::Ally => "ally",
149 Self::Party => "party",
150 Self::Raid => "raid",
151 Self::RaidClass => "raid class",
152 Self::Passenger => "passenger",
153 Self::Summoned => "summoned",
154 }
155 }
156}
157
158impl ImplicitTargetDirection {
159 #[must_use]
160 pub const fn as_str(&self) -> &'static str {
161 match self {
162 Self::None => "none",
163 Self::Front => "front",
164 Self::Back => "back",
165 Self::Right => "right",
166 Self::Left => "left",
167 Self::FrontRight => "front right",
168 Self::BackRight => "back right",
169 Self::BackLeft => "back left",
170 Self::FrontLeft => "front left",
171 Self::Random => "random",
172 Self::Entry => "entry",
173 }
174 }
175}
176
177#[derive(Clone, Copy, Debug, Eq, PartialEq)]
179pub struct ImplicitTargetSemantic {
180 pub object: ImplicitTargetObject,
181 pub reference: ImplicitTargetReference,
182 pub selection: ImplicitTargetSelection,
183 pub check: ImplicitTargetCheck,
184 pub direction: ImplicitTargetDirection,
185}
186
187const fn target(
188 object: ImplicitTargetObject,
189 reference: ImplicitTargetReference,
190 selection: ImplicitTargetSelection,
191 check: ImplicitTargetCheck,
192 direction: ImplicitTargetDirection,
193) -> ImplicitTargetSemantic {
194 ImplicitTargetSemantic {
195 object,
196 reference,
197 selection,
198 check,
199 direction,
200 }
201}
202
203use ImplicitTargetCheck as C;
204use ImplicitTargetDirection as D;
205use ImplicitTargetObject as O;
206use ImplicitTargetReference as R;
207use ImplicitTargetSelection as S;
208
209#[rustfmt::skip]
211pub const IMPLICIT_TARGET_SEMANTICS: &[ImplicitTargetSemantic] = &[
212 target(O::None, R::None, S::NotImplemented, C::Default, D::None),
213 target(O::Unit, R::Caster, S::Default, C::Default, D::None),
214 target(O::Unit, R::Caster, S::Nearby, C::Enemy, D::None),
215 target(O::Unit, R::Caster, S::Nearby, C::Ally, D::None),
216 target(O::Unit, R::Caster, S::Nearby, C::Party, D::None),
217 target(O::Unit, R::Caster, S::Default, C::Default, D::None),
218 target(O::Unit, R::Target, S::Default, C::Enemy, D::None),
219 target(O::Unit, R::Source, S::Area, C::Entry, D::None),
220 target(O::Unit, R::Destination, S::Area, C::Entry, D::None),
221 target(O::Destination, R::Caster, S::Default, C::Default, D::None),
222 target(O::None, R::None, S::NotImplemented, C::Default, D::None),
223 target(O::Unit, R::Source, S::NotImplemented, C::Default, D::None),
224 target(O::None, R::None, S::NotImplemented, C::Default, D::None),
225 target(O::None, R::None, S::NotImplemented, C::Default, D::None),
226 target(O::None, R::None, S::NotImplemented, C::Default, D::None),
227 target(O::Unit, R::Source, S::Area, C::Enemy, D::None),
228 target(O::Unit, R::Destination, S::Area, C::Enemy, D::None),
229 target(O::Destination, R::Caster, S::Default, C::Default, D::None),
230 target(O::Destination, R::Caster, S::Default, C::Default, D::None),
231 target(O::None, R::None, S::NotImplemented, C::Default, D::None),
232 target(O::Unit, R::Caster, S::Area, C::Party, D::None),
233 target(O::Unit, R::Target, S::Default, C::Ally, D::None),
234 target(O::Source, R::Caster, S::Default, C::Default, D::None),
235 target(O::GameObject, R::Target, S::Default, C::Default, D::None),
236 target(O::Unit, R::Caster, S::Cone, C::Enemy, D::Front),
237 target(O::Unit, R::Target, S::Default, C::Default, D::None),
238 target(O::GameObjectItem, R::Target, S::Default, C::Default, D::None),
239 target(O::Unit, R::Caster, S::Default, C::Default, D::None),
240 target(O::Destination, R::Destination, S::Default, C::Enemy, D::None),
241 target(O::Destination, R::Destination, S::Default, C::Ally, D::None),
242 target(O::Unit, R::Source, S::Area, C::Ally, D::None),
243 target(O::Unit, R::Destination, S::Area, C::Ally, D::None),
244 target(O::Destination, R::Caster, S::Default, C::Default, D::FrontLeft),
245 target(O::Unit, R::Source, S::Area, C::Party, D::None),
246 target(O::Unit, R::Destination, S::Area, C::Party, D::None),
247 target(O::Unit, R::Target, S::Default, C::Party, D::None),
248 target(O::Destination, R::Caster, S::NotImplemented, C::Default, D::None),
249 target(O::Unit, R::Last, S::Area, C::Party, D::None),
250 target(O::Unit, R::Caster, S::Nearby, C::Entry, D::None),
251 target(O::Destination, R::Caster, S::Default, C::Default, D::None),
252 target(O::GameObject, R::Caster, S::Nearby, C::Entry, D::None),
253 target(O::Destination, R::Caster, S::Default, C::Default, D::FrontRight),
254 target(O::Destination, R::Caster, S::Default, C::Default, D::BackRight),
255 target(O::Destination, R::Caster, S::Default, C::Default, D::BackLeft),
256 target(O::Destination, R::Caster, S::Default, C::Default, D::FrontLeft),
257 target(O::Unit, R::Target, S::Default, C::Ally, D::None),
258 target(O::Destination, R::Caster, S::Nearby, C::Entry, D::None),
259 target(O::Destination, R::Caster, S::Default, C::Default, D::Front),
260 target(O::Destination, R::Caster, S::Default, C::Default, D::Back),
261 target(O::Destination, R::Caster, S::Default, C::Default, D::Right),
262 target(O::Destination, R::Caster, S::Default, C::Default, D::Left),
263 target(O::GameObject, R::Source, S::Area, C::Default, D::None),
264 target(O::GameObject, R::Destination, S::Area, C::Default, D::None),
265 target(O::Destination, R::Target, S::Default, C::Enemy, D::None),
266 target(O::Unit, R::Caster, S::Cone, C::Enemy, D::Front),
267 target(O::Destination, R::Caster, S::Default, C::Default, D::None),
268 target(O::Unit, R::Caster, S::Area, C::Raid, D::None),
269 target(O::Unit, R::Target, S::Default, C::Raid, D::None),
270 target(O::Unit, R::Caster, S::Nearby, C::Raid, D::None),
271 target(O::Unit, R::Caster, S::Cone, C::Ally, D::Front),
272 target(O::Unit, R::Caster, S::Cone, C::Entry, D::Front),
273 target(O::Unit, R::Target, S::Area, C::RaidClass, D::None),
274 target(O::Destination, R::Caster, S::Default, C::Default, D::None),
275 target(O::Destination, R::Target, S::Default, C::Default, D::None),
276 target(O::Destination, R::Target, S::Default, C::Default, D::Front),
277 target(O::Destination, R::Target, S::Default, C::Default, D::Back),
278 target(O::Destination, R::Target, S::Default, C::Default, D::Right),
279 target(O::Destination, R::Target, S::Default, C::Default, D::Left),
280 target(O::Destination, R::Target, S::Default, C::Default, D::FrontRight),
281 target(O::Destination, R::Target, S::Default, C::Default, D::BackRight),
282 target(O::Destination, R::Target, S::Default, C::Default, D::BackLeft),
283 target(O::Destination, R::Target, S::Default, C::Default, D::FrontLeft),
284 target(O::Destination, R::Caster, S::Default, C::Default, D::Random),
285 target(O::Destination, R::Caster, S::Default, C::Default, D::Random),
286 target(O::Destination, R::Target, S::Default, C::Default, D::Random),
287 target(O::Destination, R::Target, S::Default, C::Default, D::Random),
288 target(O::Destination, R::Caster, S::Channel, C::Default, D::None),
289 target(O::Unit, R::Caster, S::Channel, C::Default, D::None),
290 target(O::Destination, R::Destination, S::Default, C::Default, D::Front),
291 target(O::Destination, R::Destination, S::Default, C::Default, D::Back),
292 target(O::Destination, R::Destination, S::Default, C::Default, D::Right),
293 target(O::Destination, R::Destination, S::Default, C::Default, D::Left),
294 target(O::Destination, R::Destination, S::Default, C::Default, D::FrontRight),
295 target(O::Destination, R::Destination, S::Default, C::Default, D::BackRight),
296 target(O::Destination, R::Destination, S::Default, C::Default, D::BackLeft),
297 target(O::Destination, R::Destination, S::Default, C::Default, D::FrontLeft),
298 target(O::Destination, R::Destination, S::Default, C::Default, D::Random),
299 target(O::Destination, R::Destination, S::Default, C::Default, D::None),
300 target(O::Destination, R::Destination, S::Default, C::Default, D::None),
301 target(O::Destination, R::Destination, S::Trajectory, C::Default, D::None),
302 target(O::Unit, R::Target, S::Default, C::Default, D::None),
303 target(O::Destination, R::Destination, S::Default, C::Default, D::Random),
304 target(O::Unit, R::Caster, S::Default, C::Default, D::None),
305 target(O::Corpse, R::Source, S::Area, C::Enemy, D::None),
306 target(O::Unit, R::Caster, S::Default, C::Default, D::None),
307 target(O::Unit, R::Target, S::Default, C::Passenger, D::None),
308 target(O::Unit, R::Caster, S::Default, C::Default, D::None),
309 target(O::Unit, R::Caster, S::Default, C::Default, D::None),
310 target(O::Unit, R::Caster, S::Default, C::Default, D::None),
311 target(O::Unit, R::Caster, S::Default, C::Default, D::None),
312 target(O::Unit, R::Caster, S::Default, C::Default, D::None),
313 target(O::Unit, R::Caster, S::Default, C::Default, D::None),
314 target(O::Unit, R::Caster, S::Default, C::Default, D::None),
315 target(O::Unit, R::Caster, S::Default, C::Default, D::None),
316 target(O::Unit, R::Caster, S::Cone, C::Enemy, D::Front),
317 target(O::Unit, R::Caster, S::Area, C::Default, D::None),
318 target(O::Destination, R::Caster, S::Default, C::Default, D::None),
319 target(O::Destination, R::Caster, S::Nearby, C::Entry, D::None),
320 target(O::GameObject, R::Caster, S::Cone, C::Enemy, D::Front),
321 target(O::GameObject, R::Caster, S::Cone, C::Ally, D::Front),
322 target(O::Unit, R::Caster, S::Cone, C::Entry, D::Front),
323 target(O::None, R::None, S::NotImplemented, C::Default, D::None),
324 target(O::Destination, R::Caster, S::Default, C::Default, D::None),
325 target(O::Destination, R::Target, S::Default, C::Default, D::None),
326 target(O::None, R::None, S::NotImplemented, C::Default, D::None),
327 target(O::Unit, R::Source, S::Area, C::Enemy, D::None),
328 target(O::UnitAndDestination, R::Last, S::Area, C::Enemy, D::None),
329 target(O::None, R::None, S::NotImplemented, C::Default, D::None),
330 target(O::Unit, R::Target, S::Area, C::Raid, D::None),
331 target(O::Corpse, R::Caster, S::Area, C::Raid, D::None),
332 target(O::Unit, R::Caster, S::Area, C::Summoned, D::None),
333 target(O::Corpse, R::Target, S::Default, C::Ally, D::None),
334 target(O::Unit, R::Caster, S::Area, C::Default, D::None),
335 target(O::Unit, R::Caster, S::Area, C::Default, D::None),
336 target(O::Unit, R::Caster, S::Default, C::Default, D::None),
337 target(O::Destination, R::Caster, S::Default, C::Default, D::None),
338 target(O::Unit, R::None, S::NotImplemented, C::Default, D::None),
339 target(O::Destination, R::None, S::NotImplemented, C::Default, D::None),
340 target(O::Unit, R::Caster, S::Cone, C::Ally, D::Front),
341 target(O::Unit, R::Caster, S::Cone, C::Enemy, D::Front),
342 target(O::Unit, R::Caster, S::Cone, C::Default, D::Front),
343 target(O::Destination, R::Caster, S::Default, C::Default, D::None),
344 target(O::Destination, R::Target, S::Default, C::Ally, D::None),
345 target(O::Unit, R::Destination, S::Line, C::Ally, D::None),
346 target(O::Unit, R::Destination, S::Line, C::Enemy, D::None),
347 target(O::Unit, R::Destination, S::Line, C::Default, D::None),
348 target(O::Unit, R::Caster, S::Cone, C::Ally, D::Front),
349 target(O::Destination, R::Caster, S::Default, C::Default, D::None),
350 target(O::Destination, R::Destination, S::Default, C::Default, D::None),
351 target(O::None, R::None, S::NotImplemented, C::Default, D::None),
352 target(O::Destination, R::None, S::NotImplemented, C::Default, D::None),
353 target(O::None, R::None, S::NotImplemented, C::Default, D::None),
354 target(O::Destination, R::Caster, S::Nearby, C::Entry, D::FrontRight),
355 target(O::None, R::None, S::NotImplemented, C::Default, D::None),
356 target(O::None, R::None, S::NotImplemented, C::Default, D::None),
357 target(O::None, R::None, S::NotImplemented, C::Default, D::None),
358 target(O::None, R::None, S::NotImplemented, C::Default, D::None),
359 target(O::None, R::None, S::NotImplemented, C::Default, D::None),
360 target(O::Destination, R::Destination, S::Default, C::Default, D::None),
361 target(O::Destination, R::Caster, S::Default, C::Default, D::Random),
362 target(O::Unit, R::Caster, S::Default, C::Default, D::None),
363 target(O::Unit, R::Caster, S::Area, C::Enemy, D::None),
364 target(O::None, R::None, S::NotImplemented, C::Default, D::None),
365];
366
367#[must_use]
369pub fn implicit_target_semantic(raw: i32) -> Option<&'static ImplicitTargetSemantic> {
370 usize::try_from(raw)
371 .ok()
372 .and_then(|index| IMPLICIT_TARGET_SEMANTICS.get(index))
373}
374
375#[cfg(test)]
376mod tests {
377 use googletest::prelude::*;
378
379 use super::*;
380
381 const TRINITY_SELECTOR_FINGERPRINT: u64 = 0x2c65_6d80_c2bb_9917;
382
383 fn selector_fingerprint() -> u64 {
384 IMPLICIT_TARGET_SEMANTICS
385 .iter()
386 .flat_map(|semantic| {
387 [
388 semantic.object as u8,
389 semantic.reference as u8,
390 semantic.selection as u8,
391 semantic.check as u8,
392 semantic.direction as u8,
393 ]
394 })
395 .fold(0xcbf2_9ce4_8422_2325, |hash, byte| {
396 (hash ^ u64::from(byte)).wrapping_mul(0x0000_0100_0000_01b3)
397 })
398 }
399
400 #[gtest]
401 fn complete_ordered_registry_matches_the_trinity_source_table() {
402 expect_that!(IMPLICIT_TARGET_SEMANTICS.len(), eq(153));
403 expect_that!(selector_fingerprint(), eq(TRINITY_SELECTOR_FINGERPRINT));
404 expect_that!(implicit_target_semantic(-1), eq(None));
405 expect_that!(implicit_target_semantic(153), eq(None));
406 }
407
408 #[gtest]
409 fn selector_axes_preserve_source_target_and_destination_area_origins() {
410 let source = implicit_target_semantic(15).expect("source area enemy");
411 let destination = implicit_target_semantic(16).expect("destination area enemy");
412
413 expect_that!(source.reference, eq(ImplicitTargetReference::Source));
414 expect_that!(
415 destination.reference,
416 eq(ImplicitTargetReference::Destination)
417 );
418 expect_that!(source.selection, eq(ImplicitTargetSelection::Area));
419 expect_that!(destination.selection, eq(ImplicitTargetSelection::Area));
420 }
421}