1use crate::{Class, HasItemDefindex, ItemSlot};
2use num_enum::{TryFromPrimitive, TryFromPrimitiveError};
3use serde::{Deserialize, Serialize};
4use strum::{Display, EnumCount, EnumIter, EnumString};
5
6#[derive(
8 Debug,
9 Clone,
10 Copy,
11 Eq,
12 PartialEq,
13 Ord,
14 PartialOrd,
15 Hash,
16 Display,
17 Deserialize,
18 Serialize,
19 EnumString,
20 EnumIter,
21 EnumCount,
22)]
23#[allow(missing_docs)]
24pub enum StockWeapon {
25 #[strum(serialize = "Bat")]
26 Bat,
27 #[strum(serialize = "Bottle")]
28 Bottle,
29 #[strum(serialize = "Fire Axe")]
30 FireAxe,
31 #[strum(serialize = "Kukri")]
32 Kukri,
33 #[strum(serialize = "Knife")]
34 Knife,
35 #[strum(serialize = "Fists")]
36 Fists,
37 #[strum(serialize = "Shovel")]
38 Shovel,
39 #[strum(serialize = "Wrench")]
40 Wrench,
41 #[strum(serialize = "Bonesaw")]
42 Bonesaw,
43 #[strum(serialize = "Shotgun")]
44 Shotgun,
45 #[strum(serialize = "Scattergun")]
46 Scattergun,
47 #[strum(serialize = "Sniper Rifle")]
48 SniperRifle,
49 #[strum(serialize = "Minigun")]
50 Minigun,
51 #[strum(serialize = "SMG")]
52 SMG,
53 #[strum(serialize = "Syringe Gun")]
54 SyringeGun,
55 #[strum(serialize = "Rocket Launcher")]
56 RocketLauncher,
57 #[strum(serialize = "Grenade Launcher")]
58 GrenadeLauncher,
59 #[strum(serialize = "Stickybomb Launcher")]
60 StickybombLauncher,
61 #[strum(serialize = "Flame Thrower")]
62 FlameThrower,
63 #[strum(serialize = "Pistol")]
64 Pistol,
65 #[strum(serialize = "Revolver")]
66 Revolver,
67 #[strum(serialize = "Construction PDA")]
68 ConstructionPDA,
69 #[strum(serialize = "Destruction PDA")]
70 DestructionPDA,
71 #[strum(serialize = "Disguise Kit")]
72 DisguiseKit,
73 #[strum(serialize = "PDA")]
74 PDA,
75 #[strum(serialize = "Medi Gun")]
76 MediGun,
77 #[strum(serialize = "Invis Watch")]
78 InvisWatch,
79}
80
81impl HasItemDefindex for StockWeapon {
82 fn defindex(&self) -> u32 {
87 self.defindexes()
88 .first()
89 .copied()
90 .unwrap() }
92
93 fn from_defindex(defindex: u32) -> Option<Self> {
96 match defindex {
97 0 | 190 => Some(Self::Bat),
98 1 | 191 => Some(Self::Bottle),
99 2 | 192 => Some(Self::FireAxe),
100 3 | 193 => Some(Self::Kukri),
101 4 | 194 => Some(Self::Knife),
102 5 | 195 => Some(Self::Fists),
103 6 | 196 => Some(Self::Shovel),
104 7 | 197 => Some(Self::Wrench),
105 8 | 198 => Some(Self::Bonesaw),
106 9 | 10 | 11 | 12 | 199 => Some(Self::Shotgun),
107 13 | 200 => Some(Self::Scattergun),
108 14 | 201 => Some(Self::SniperRifle),
109 15 | 202 => Some(Self::Minigun),
110 16 | 203 => Some(Self::SMG),
111 17 | 204 => Some(Self::SyringeGun),
112 18 | 205 => Some(Self::RocketLauncher),
113 19 | 206 => Some(Self::GrenadeLauncher),
114 20 | 207 => Some(Self::StickybombLauncher),
115 21 | 208 => Some(Self::FlameThrower),
116 22 | 23 | 209 => Some(Self::Pistol),
117 24 | 210 => Some(Self::Revolver),
118 25 | 737 => Some(Self::ConstructionPDA),
119 26 => Some(Self::DestructionPDA),
120 27 => Some(Self::DisguiseKit),
121 28 => Some(Self::PDA),
122 29 | 211 => Some(Self::MediGun),
123 30 | 212 => Some(Self::InvisWatch),
124 _ => None,
125 }
126 }
127}
128
129impl StockWeapon {
130 pub fn defindexes(&self) -> &'static [u32] {
132 match self {
133 Self::Bat => &[0, 190],
134 Self::Bottle => &[1, 191],
135 Self::FireAxe => &[2, 192],
136 Self::Kukri => &[3, 193],
137 Self::Knife => &[4, 194],
138 Self::Fists => &[5, 195],
139 Self::Shovel => &[6, 196],
140 Self::Wrench => &[7, 197],
141 Self::Bonesaw => &[8, 198],
142 Self::Shotgun => &[9, 10, 11, 12, 199],
143 Self::Scattergun => &[13, 200],
144 Self::SniperRifle => &[14, 201],
145 Self::Minigun => &[15, 202],
146 Self::SMG => &[16, 203],
147 Self::SyringeGun => &[17, 204],
148 Self::RocketLauncher => &[18, 205],
149 Self::GrenadeLauncher => &[19, 206],
150 Self::StickybombLauncher => &[20, 207],
151 Self::FlameThrower => &[21, 208],
152 Self::Pistol => &[22, 23, 209],
153 Self::Revolver => &[24, 210],
154 Self::ConstructionPDA => &[25, 737],
155 Self::DestructionPDA => &[26],
156 Self::DisguiseKit => &[27],
157 Self::PDA => &[28],
158 Self::MediGun => &[29, 211],
159 Self::InvisWatch => &[30, 212],
160 }
161 }
162
163 pub fn econ_defindex(&self) -> Option<u32> {
168 match self {
169 Self::Bat => Some(190),
170 Self::Bottle => Some(191),
171 Self::FireAxe => Some(192),
172 Self::Kukri => Some(193),
173 Self::Knife => Some(194),
174 Self::Fists => Some(195),
175 Self::Shovel => Some(196),
176 Self::Wrench => Some(197),
177 Self::Bonesaw => Some(198),
178 Self::Shotgun => Some(199),
179 Self::Scattergun => Some(200),
180 Self::SniperRifle => Some(201),
181 Self::Minigun => Some(202),
182 Self::SMG => Some(203),
183 Self::SyringeGun => Some(204),
184 Self::RocketLauncher => Some(205),
185 Self::GrenadeLauncher => Some(206),
186 Self::StickybombLauncher => Some(207),
187 Self::FlameThrower => Some(208),
188 Self::Pistol => Some(209),
189 Self::Revolver => Some(210),
190 _ => None,
191 }
192 }
193
194 pub fn used_by_classes(&self) -> &'static [Class] {
196 match self {
197 Self::Bat |
198 Self::Scattergun => &[Class::Scout],
199 Self::Bottle |
200 Self::GrenadeLauncher |
201 Self::StickybombLauncher => &[Class::Demoman],
202 Self::FireAxe |
203 Self::FlameThrower => &[Class::Pyro],
204 Self::Kukri |
205 Self::SniperRifle |
206 Self::SMG => &[Class::Sniper],
207 Self::Knife |
208 Self::Revolver |
209 Self::DisguiseKit |
210 Self::InvisWatch => &[Class::Spy],
211 Self::Fists |
212 Self::Minigun => &[Class::Heavy],
213 Self::Shovel |
214 Self::RocketLauncher => &[Class::Soldier],
215 Self::Wrench |
216 Self::ConstructionPDA |
217 Self::DestructionPDA |
218 Self::PDA => &[Class::Engineer],
219 Self::Bonesaw |
220 Self::SyringeGun |
221 Self::MediGun => &[Class::Medic],
222 Self::Shotgun => &[Class::Soldier, Class::Pyro, Class::Engineer, Class::Heavy],
223 Self::Pistol => &[Class::Scout, Class::Engineer],
224 }
225 }
226
227 pub fn used_by_class(&self, class: Class) -> bool {
229 self.used_by_classes().contains(&class)
230 }
231
232 pub fn class_stock_weapons(class: Class) -> &'static [StockWeapon] {
234 match class {
235 Class::Scout => &[Self::Scattergun, Self::Pistol, Self::Bat],
236 Class::Demoman => &[Self::GrenadeLauncher, Self::StickybombLauncher, Self::Bottle],
237 Class::Pyro => &[Self::FlameThrower, Self::Shotgun, Self::FireAxe],
238 Class::Sniper => &[Self::SniperRifle, Self::SMG, Self::Kukri],
239 Class::Spy => &[Self::Revolver, Self::Knife, Self::DisguiseKit, Self::InvisWatch],
240 Class::Heavy => &[Self::Minigun, Self::Shotgun, Self::Fists],
241 Class::Soldier => &[Self::RocketLauncher, Self::Shotgun, Self::Shovel],
242 Class::Engineer => &[Self::Shotgun, Self::Pistol, Self::Wrench, Self::ConstructionPDA, Self::DestructionPDA],
243 Class::Medic => &[Self::SyringeGun, Self::MediGun, Self::Bonesaw],
244 }
245 }
246
247 pub fn item_slot(&self) -> ItemSlot {
252 match self {
253 Self::Bat => ItemSlot::Melee,
254 Self::Scattergun => ItemSlot::Primary,
255 Self::Bottle => ItemSlot::Secondary,
256 Self::FireAxe => ItemSlot::Melee,
257 Self::FlameThrower => ItemSlot::Primary,
258 Self::Kukri => ItemSlot::Melee,
259 Self::Knife => ItemSlot::Melee,
260 Self::Fists => ItemSlot::Melee,
261 Self::Shovel => ItemSlot::Melee,
262 Self::Wrench => ItemSlot::Melee,
263 Self::Bonesaw => ItemSlot::Melee,
264 Self::SMG => ItemSlot::Secondary,
265 Self::SyringeGun => ItemSlot::Primary,
266 Self::RocketLauncher => ItemSlot::Primary,
267 Self::GrenadeLauncher => ItemSlot::Primary,
268 Self::StickybombLauncher => ItemSlot::Secondary,
269 Self::SniperRifle => ItemSlot::Primary,
270 Self::Minigun => ItemSlot::Primary,
271 Self::Pistol => ItemSlot::Secondary,
272 Self::Revolver => ItemSlot::Primary,
273 Self::DisguiseKit => ItemSlot::PDA,
274 Self::InvisWatch => ItemSlot::PDA2,
275 Self::MediGun => ItemSlot::Secondary,
276 Self::ConstructionPDA => ItemSlot::PDA,
277 Self::DestructionPDA => ItemSlot::PDA2,
278 Self::PDA => ItemSlot::Building,
279 Self::Shotgun => ItemSlot::Secondary,
280 }
281 }
282}
283
284impl TryFromPrimitive for StockWeapon {
286 const NAME: &'static str = "StockWeapon";
287 type Primitive = u32;
288 type Error = TryFromPrimitiveError<StockWeapon>;
289
290 fn try_from_primitive(number: u32) -> Result<Self, Self::Error> {
291 Self::from_defindex(number)
292 .ok_or(TryFromPrimitiveError { number })
293 }
294}
295
296impl TryFrom<u32> for StockWeapon {
297 type Error = TryFromPrimitiveError<StockWeapon>;
298
299 fn try_from(value: u32) -> Result<Self, Self::Error> {
300 Self::try_from_primitive(value)
301 }
302}
303
304impl TryFrom<&u32> for StockWeapon {
305 type Error = TryFromPrimitiveError<StockWeapon>;
306
307 fn try_from(value: &u32) -> Result<Self, Self::Error> {
308 Self::try_from_primitive(*value)
309 }
310}
311
312#[cfg(test)]
313mod tests {
314 use super::*;
315
316 #[test]
317 fn tries_from_primitive() {
318 let weapon = StockWeapon::try_from(0).unwrap();
319
320 assert_eq!(weapon, StockWeapon::Bat);
321 }
322}