wowlab_engine_combat/handler/can_cast/
reject.rs1use wowlab_types::sim::SimTime;
4
5#[derive(Clone, Copy, Debug)]
7pub(crate) enum CastReject {
8 NoTarget,
9 UnknownSpell,
10 Disabled,
11 PrimaryResource {
12 have: f64,
13 cost: f64,
14 },
15 SecondaryResource {
16 have: f64,
17 cost: f64,
18 },
19 Health {
20 have: f64,
21 cost: f64,
22 },
23 NoCharges,
24 Cooldown {
25 ready_at: f64,
26 now: f64,
27 },
28 CooldownCategory {
29 category: wowlab_types::data::CooldownCategoryId,
30 ready_at: SimTime,
31 now: SimTime,
32 },
33 ChargeCategory {
34 category: wowlab_types::data::CooldownCategoryId,
35 ready_at: SimTime,
36 now: SimTime,
37 },
38 StartRecoveryCategory {
39 category: wowlab_types::data::CooldownCategoryId,
40 ready_at: SimTime,
41 now: SimTime,
42 },
43 ExecuteRange {
44 target_health_pct: f64,
45 threshold_pct: f64,
46 },
47 GatingAuraUnknown {
48 aura_id: u32,
49 },
50 GatingAuraInactive {
51 aura_id: u32,
52 min_stacks: i32,
53 },
54 RequiresStealth,
55 RequiresBehindTarget,
56 RequiresUnshifted {
57 form: i64,
58 },
59 ShapeshiftRequired {
60 form: i64,
61 required_mask: u64,
62 },
63 ShapeshiftExcluded {
64 form: i64,
65 },
66 RequiresMainHand,
67 RequiresOffHand,
68 EquippedItemRequirement,
69 Moving,
70 SchoolLocked,
71 CrowdControlled,
72 AuraState,
73 OutOfRange,
74}
75
76impl std::fmt::Display for CastReject {
77 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
79 match *self {
80 Self::NoTarget => write!(f, "no target"),
81 Self::UnknownSpell => write!(f, "spell not in resolved set"),
82 Self::Disabled => write!(f, "disabled (masked or talent-gated off)"),
83 Self::PrimaryResource { have, cost } => {
84 write!(f, "primary resource {have:.0}/{cost:.0}")
85 }
86 Self::SecondaryResource { have, cost } => {
87 write!(f, "secondary resource {have:.0}/{cost:.0}")
88 }
89 Self::Health { have, cost } => write!(f, "health {have:.0}/{cost:.0}"),
90 Self::NoCharges => write!(f, "no charges available"),
91 Self::Cooldown { ready_at, now } => {
92 write!(f, "on cooldown ({:.2}s remaining)", ready_at - now)
93 }
94 Self::CooldownCategory {
95 category,
96 ready_at,
97 now,
98 } => write!(
99 f,
100 "cooldown category {} locked ({:.2}s remaining)",
101 category.raw(),
102 ready_at.saturating_sub(now).as_secs_f64()
103 ),
104 Self::ChargeCategory {
105 category,
106 ready_at,
107 now,
108 } => write!(
109 f,
110 "charge category {} locked ({:.2}s remaining)",
111 category.raw(),
112 ready_at.saturating_sub(now).as_secs_f64()
113 ),
114 Self::StartRecoveryCategory {
115 category,
116 ready_at,
117 now,
118 } => write!(
119 f,
120 "start-recovery category {} locked ({:.2}s remaining)",
121 category.raw(),
122 ready_at.saturating_sub(now).as_secs_f64()
123 ),
124 Self::ExecuteRange {
125 target_health_pct,
126 threshold_pct,
127 } => write!(
128 f,
129 "target at {target_health_pct:.0}%, above execute threshold {threshold_pct:.0}%"
130 ),
131 Self::GatingAuraUnknown { aura_id } => {
132 write!(f, "gating aura {aura_id} not resolved")
133 }
134 Self::GatingAuraInactive {
135 aura_id,
136 min_stacks,
137 } => write!(
138 f,
139 "gating aura {aura_id} inactive (need {min_stacks} stacks)"
140 ),
141 Self::RequiresStealth => write!(f, "requires stealth (stealthed flag = 0)"),
142 Self::RequiresBehindTarget => write!(f, "requires position behind target"),
143 Self::RequiresUnshifted { form } => {
144 write!(f, "requires no shapeshift (current form = {form})")
145 }
146 Self::ShapeshiftRequired {
147 form,
148 required_mask,
149 } => write!(
150 f,
151 "requires shapeshift form mask {required_mask:#x} (current form = {form})"
152 ),
153 Self::ShapeshiftExcluded { form } => {
154 write!(f, "excluded in shapeshift form {form}")
155 }
156 Self::RequiresMainHand => write!(f, "requires a main-hand weapon"),
157 Self::RequiresOffHand => write!(f, "requires an off-hand weapon"),
158 Self::EquippedItemRequirement => {
159 write!(f, "equipped weapon does not satisfy spell requirements")
160 }
161 Self::Moving => write!(f, "cannot cast while moving"),
162 Self::SchoolLocked => write!(f, "spell school is locked"),
163 Self::CrowdControlled => write!(f, "actor is crowd controlled"),
164 Self::AuraState => write!(f, "aura-state requirement is not satisfied"),
165 Self::OutOfRange => write!(f, "target out of range"),
166 }
167 }
168}