tf2_enum/
strange_part.rs

1
2use crate::{
3    Attributes,
4    AttributeDef,
5    EffectType,
6    HasItemDefindex,
7    KillEaterScoreType,
8    TryFromIntAttributeValue,
9};
10use crate::error::TryFromPrimitiveError;
11use num_enum::{IntoPrimitive, TryFromPrimitive};
12use serde_repr::{Deserialize_repr, Serialize_repr};
13use strum::{Display, EnumCount, EnumIter, EnumString};
14
15// Avoid repeating strings
16const STR_SCOUTS_KILLED: &str = "Strange Part: Scouts Killed";
17const STR_SNIPERS_KILLED: &str = "Strange Part: Snipers Killed";
18const STR_SOLDIERS_KILLED: &str = "Strange Part: Soldiers Killed";
19const STR_DEMOMEN_KILLED: &str = "Strange Part: Demomen Killed";
20const STR_HEAVIES_KILLED: &str = "Strange Part: Heavies Killed";
21const STR_PYROS_KILLED: &str = "Strange Part: Pyros Killed";
22const STR_SPIES_KILLED: &str = "Strange Part: Spies Killed";
23const STR_ENGINEERS_KILLED: &str = "Strange Part: Engineers Killed";
24const STR_MEDICS_KILLED: &str = "Strange Part: Medics Killed";
25const STR_BUILDINGS_DESTROYED: &str = "Strange Part: Buildings Destroyed";
26const STR_PROJECTILES_REFLECTED: &str = "Strange Part: Projectiles Reflected";
27const STR_HEADSHOT_KILLS: &str = "Strange Part: Headshot Kills";
28const STR_AIRBORNE_ENEMY_KILLS: &str = "Strange Part: Airborne Enemies Killed";
29const STR_GIB_KILLS: &str = "Strange Part: Gib Kills";
30const STR_KILLS_UNDER_A_FULL_MOON: &str = "Strange Part: Full Moon Kills";
31const STR_DOMINATIONS: &str = "Strange Part: Domination Kills";
32const STR_REVENGES: &str = "Strange Part: Revenge Kills";
33const STR_POSTHUMOUS_KILLS: &str = "Strange Part: Posthumous Kills";
34const STR_TEAMMATES_EXTINGUISHED: &str = "Strange Part: Teammates Extinguished";
35const STR_CRITICAL_KILLS: &str = "Strange Part: Critical Kills";
36const STR_KILLS_WHILE_EXPLOSIVE_JUMPING: &str = "Strange Part: Kills While Explosive Jumping";
37const STR_SAPPERS_REMOVED: &str = "Strange Part: Sappers Destroyed";
38const STR_CLOAKED_SPIES_KILLED: &str = "Strange Part: Cloaked Spies Killed";
39const STR_MEDICS_KILLED_THAT_HAVE_FULL_UBER_CHARGE: &str = "Strange Part: Medics Killed That Have Full ÜberCharge";
40const STR_ROBOTS_DESTROYED: &str = "Strange Part: Robots Destroyed";
41const STR_GIANT_ROBOTS_DESTROYED: &str = "Strange Part: Giant Robots Destroyed";
42const STR_KILLS_WHILE_LOW_HEALTH: &str = "Strange Part: Low-Health Kills";
43const STR_KILLS_DURING_HALLOWEEN: &str = "Strange Part: Halloween Kills";
44const STR_ROBOTS_KILLED_DURING_HALLOWEEN: &str = "Strange Part: Robots Destroyed During Halloween";
45const STR_DEFENDER_KILLS: &str = "Strange Part: Defender Kills";
46const STR_SUBMERGED_ENEMY_KILLS: &str = "Strange Part: Underwater Kills";
47const STR_KILLS_WHILE_INVULN_UBER_CHARGED: &str = "Strange Part: Kills While Übercharged";
48const STR_TANKS_DESTROYED: &str = "Strange Part: Tanks Destroyed";
49const STR_LONG_DISTANCE_KILLS: &str = "Strange Part: Long-Distance Kills";
50const STR_KILLS_DURING_VICTORY_TIME: &str = "Strange Part: Kills During Victory Time";
51const STR_ROBOT_SCOUTS_DESTROYED: &str = "Strange Part: Robot Scouts Destroyed";
52const STR_ROBOT_SPIES_DESTROYED: &str = "Strange Part: Robot Spies Destroyed";
53const STR_TAUNT_KILLS: &str = "Strange Part: Kills with a Taunt Attack";
54const STR_UNUSUAL_WEARING_PLAYER_KILLS: &str = "Strange Part: Unusual-Wearing Player Kills";
55const STR_BURNING_PLAYER_KILLS: &str = "Strange Part: Burning Enemy Kills";
56const STR_KILLSTREAKS_ENDED: &str = "Strange Part: Killstreaks Ended";
57const STR_FREEZECAM_TAUNT_APPEARANCES: &str = "Strange Cosmetic Part: Freezecam Taunt Appearances";
58const STR_DAMAGE_DEALT: &str = "Strange Part: Damage Dealt";
59const STR_FIRES_SURVIVED: &str = "Strange Cosmetic Part: Fires Survived";
60const STR_ALLIED_HEALING_DONE: &str = "Strange Part: Allied Healing Done";
61const STR_POINT_BLANK_KILLS: &str = "Strange Part: Point-Blank Kills";
62const STR_KILLS: &str = "Strange Cosmetic Part: Kills";
63const STR_FULL_HEALTH_KILLS: &str = "Strange Part: Full Health Kills";
64const STR_TAUNTING_PLAYER_KILLS: &str = "Strange Part: Taunting Player Kills";
65const STR_NOT_CRIT_NOR_MINI_CRIT_KILLS: &str = "Strange Part: Not Crit nor MiniCrit Kills";
66const STR_PLAYER_HITS: &str = "Strange Part: Player Hits";
67const STR_ASSISTS: &str = "Strange Cosmetic Part: Assists";
68
69/// Strange part. `repr` values are mapped to their `kill_eater_score_type` attribute value. Strings
70/// are the name of the `kill_eater_score_type`, **not** the name of the strange part.
71#[derive(
72    Debug,
73    Clone,
74    Copy,
75    Eq,
76    PartialEq,
77    Ord,
78    PartialOrd,
79    Hash,
80    Display,
81    Serialize_repr,
82    Deserialize_repr,
83    EnumString,
84    EnumIter,
85    EnumCount,
86    TryFromPrimitive,
87    IntoPrimitive,
88)]
89#[repr(u32)]
90#[allow(missing_docs)]
91pub enum StrangePart {
92    #[strum(serialize = "Scouts Killed")]
93    ScoutsKilled = 10,
94    #[strum(serialize = "Snipers Killed")]
95    SnipersKilled = 11,
96    #[strum(serialize = "Soldiers Killed")]
97    SoldiersKilled = 12,
98    #[strum(serialize = "Demomen Killed")]
99    DemomenKilled = 13,
100    #[strum(serialize = "Heavies Killed")]
101    HeaviesKilled = 14,
102    #[strum(serialize = "Pyros Killed")]
103    PyrosKilled = 15,
104    #[strum(serialize = "Spies Killed")]
105    SpiesKilled = 16,
106    #[strum(serialize = "Engineers Killed")]
107    EngineersKilled = 17,
108    #[strum(serialize = "Medics Killed")]
109    MedicsKilled = 18,
110    #[strum(serialize = "Buildings Destroyed")]
111    BuildingsDestroyed = 19,
112    #[strum(serialize = "Projectiles Reflected")]
113    ProjectilesReflected = 20,
114    #[strum(serialize = "Headshot Kills")]
115    HeadshotKills = 21,
116    #[strum(serialize = "Airborne Enemy Kills")]
117    AirborneEnemyKills = 22,
118    #[strum(serialize = "Gib Kills")]
119    GibKills = 23,
120    #[strum(serialize = "Kills Under A Full Moon")]
121    KillsUnderAFullMoon = 27,
122    #[strum(serialize = "Dominations")]
123    Dominations = 28,
124    #[strum(serialize = "Revenges")]
125    Revenges = 30,
126    #[strum(serialize = "Posthumous Kills")]
127    PosthumousKills = 31,
128    #[strum(serialize = "Teammates Extinguished")]
129    TeammatesExtinguished = 32,
130    #[strum(serialize = "Critical Kills")]
131    CriticalKills = 33,
132    #[strum(serialize = "Kills While Explosive-Jumping")]
133    KillsWhileExplosiveJumping = 34,
134    #[strum(serialize = "Sappers Removed")]
135    SappersRemoved = 36,
136    #[strum(serialize = "Cloaked Spies Killed")]
137    CloakedSpiesKilled = 37,
138    #[strum(serialize = "Medics Killed That Have Full ÜberCharge")]
139    MedicsKilledThatHaveFullUberCharge = 38,
140    #[strum(serialize = "Robots Destroyed")]
141    RobotsDestroyed = 39,
142    #[strum(serialize = "Giant Robots Destroyed")]
143    GiantRobotsDestroyed = 40,
144    #[strum(serialize = "Kills While Low Health")]
145    KillsWhileLowHealth = 44,
146    #[strum(serialize = "Kills During Halloween")]
147    KillsDuringHalloween = 45,
148    #[strum(serialize = "Robots Killed During Halloween")]
149    RobotsKilledDuringHalloween = 46,
150    #[strum(serialize = "Defender Kills")]
151    #[serde(alias = "Defenders Killed")]
152    DefenderKills = 47,
153    #[strum(serialize = "Submerged Enemy Kills")]
154    SubmergedEnemyKills = 48,
155    #[strum(serialize = "Kills While Invuln ÜberCharged")]
156    KillsWhileInvulnUberCharged = 49,
157    #[strum(serialize = "Tanks Destroyed")]
158    TanksDestroyed = 61,
159    #[strum(serialize = "Long-Distance Kills")]
160    LongDistanceKills = 62,
161    #[strum(serialize = "Kills during Victory Time")]
162    KillsDuringVictoryTime = 67,
163    #[strum(serialize = "Robot Scouts Destroyed")]
164    RobotScoutsDestroyed = 68,
165    #[strum(serialize = "Robot Spies Destroyed")]
166    RobotSpiesDestroyed = 74,
167    #[strum(serialize = "Taunt Kills")]
168    TauntKills = 77,
169    #[strum(serialize = "Unusual-Wearing Player Kills")]
170    UnusualWearingPlayerKills = 78,
171    #[strum(serialize = "Burning Player Kills")]
172    BurningPlayerKills = 79,
173    #[strum(serialize = "Killstreaks Ended")]
174    KillstreaksEnded = 80,
175    #[strum(serialize = "Freezecam Taunt Appearances")]
176    FreezecamTauntAppearances = 81,
177    #[strum(serialize = "Damage Dealt")]
178    DamageDealt = 82,
179    #[strum(serialize = "Fires Survived")]
180    FiresSurvived = 83,
181    #[strum(serialize = "Allied Healing Done")]
182    AlliedHealingDone = 84,
183    #[strum(serialize = "Point Blank Kills")]
184    PointBlankKills = 85,
185    #[strum(serialize = "Kills")]
186    Kills = 87,
187    #[strum(serialize = "Full Health Kills")]
188    FullHealthKills = 88,
189    #[strum(serialize = "Taunting Player Kills")]
190    TauntingPlayerKills = 89,
191    #[strum(serialize = "Not Crit nor MiniCrit Kills")]
192    NotCritNorMiniCritKills = 93,
193    #[strum(serialize = "Player Hits")]
194    #[serde(alias = "Players Hit")]
195    PlayerHits = 94,
196    #[strum(serialize = "Assists")]
197    Assists = 95,
198}
199
200impl StrangePart {
201    /// Gets the `kill_eater_score_type` attribute value for this [`StrangePart`].
202    pub fn score_type(&self) -> u32 {
203        u32::from(*self)
204    }
205    
206    /// Converts a `kill_eater_score_type` attribute value into a [`StrangePart`].
207    pub fn from_score_type(score_type: u32) -> Option<Self> {
208        Self::try_from(score_type).ok()
209    }
210    
211    /// Gets the name of the strange part for this [`StrangePart`].
212    pub fn strange_part_name(&self) -> &'static str {
213        match self {
214            Self::ScoutsKilled => STR_SCOUTS_KILLED,
215            Self::SnipersKilled => STR_SNIPERS_KILLED,
216            Self::SoldiersKilled => STR_SOLDIERS_KILLED,
217            Self::DemomenKilled => STR_DEMOMEN_KILLED,
218            Self::HeaviesKilled => STR_HEAVIES_KILLED,
219            Self::PyrosKilled => STR_PYROS_KILLED,
220            Self::SpiesKilled => STR_SPIES_KILLED,
221            Self::EngineersKilled => STR_ENGINEERS_KILLED,
222            Self::MedicsKilled => STR_MEDICS_KILLED,
223            Self::BuildingsDestroyed => STR_BUILDINGS_DESTROYED,
224            Self::ProjectilesReflected => STR_PROJECTILES_REFLECTED,
225            Self::HeadshotKills => STR_HEADSHOT_KILLS,
226            Self::AirborneEnemyKills => STR_AIRBORNE_ENEMY_KILLS,
227            Self::GibKills => STR_GIB_KILLS,
228            Self::KillsUnderAFullMoon => STR_KILLS_UNDER_A_FULL_MOON,
229            Self::Dominations => STR_DOMINATIONS,
230            Self::Revenges => STR_REVENGES,
231            Self::PosthumousKills => STR_POSTHUMOUS_KILLS,
232            Self::TeammatesExtinguished => STR_TEAMMATES_EXTINGUISHED,
233            Self::CriticalKills => STR_CRITICAL_KILLS,
234            Self::KillsWhileExplosiveJumping => STR_KILLS_WHILE_EXPLOSIVE_JUMPING,
235            Self::SappersRemoved => STR_SAPPERS_REMOVED,
236            Self::CloakedSpiesKilled => STR_CLOAKED_SPIES_KILLED,
237            Self::MedicsKilledThatHaveFullUberCharge => STR_MEDICS_KILLED_THAT_HAVE_FULL_UBER_CHARGE,
238            Self::RobotsDestroyed => STR_ROBOTS_DESTROYED,
239            Self::GiantRobotsDestroyed => STR_GIANT_ROBOTS_DESTROYED,
240            Self::KillsWhileLowHealth => STR_KILLS_WHILE_LOW_HEALTH,
241            Self::KillsDuringHalloween => STR_KILLS_DURING_HALLOWEEN,
242            Self::RobotsKilledDuringHalloween => STR_ROBOTS_KILLED_DURING_HALLOWEEN,
243            Self::DefenderKills => STR_DEFENDER_KILLS,
244            Self::SubmergedEnemyKills => STR_SUBMERGED_ENEMY_KILLS,
245            Self::KillsWhileInvulnUberCharged => STR_KILLS_WHILE_INVULN_UBER_CHARGED,
246            Self::TanksDestroyed => STR_TANKS_DESTROYED,
247            Self::LongDistanceKills => STR_LONG_DISTANCE_KILLS,
248            Self::KillsDuringVictoryTime => STR_KILLS_DURING_VICTORY_TIME,
249            Self::RobotScoutsDestroyed => STR_ROBOT_SCOUTS_DESTROYED,
250            Self::RobotSpiesDestroyed => STR_ROBOT_SPIES_DESTROYED,
251            Self::TauntKills => STR_TAUNT_KILLS,
252            Self::UnusualWearingPlayerKills => STR_UNUSUAL_WEARING_PLAYER_KILLS,
253            Self::BurningPlayerKills => STR_BURNING_PLAYER_KILLS,
254            Self::KillstreaksEnded => STR_KILLSTREAKS_ENDED,
255            Self::FreezecamTauntAppearances => STR_FREEZECAM_TAUNT_APPEARANCES,
256            Self::DamageDealt => STR_DAMAGE_DEALT,
257            Self::FiresSurvived => STR_FIRES_SURVIVED,
258            Self::AlliedHealingDone => STR_ALLIED_HEALING_DONE,
259            Self::PointBlankKills => STR_POINT_BLANK_KILLS,
260            Self::Kills => STR_KILLS,
261            Self::FullHealthKills => STR_FULL_HEALTH_KILLS,
262            Self::TauntingPlayerKills => STR_TAUNTING_PLAYER_KILLS,
263            Self::NotCritNorMiniCritKills => STR_NOT_CRIT_NOR_MINI_CRIT_KILLS,
264            Self::PlayerHits => STR_PLAYER_HITS,
265            Self::Assists => STR_ASSISTS,
266        }
267    }
268    
269    /// Gets the related [`StrangePart`] by its strange part name, if it exists.
270    pub fn from_strange_part_name(name: &str) -> Option<StrangePart> {
271        match name {
272            STR_SCOUTS_KILLED => Some(Self::ScoutsKilled),
273            STR_SNIPERS_KILLED => Some(Self::SnipersKilled),
274            STR_SOLDIERS_KILLED => Some(Self::SoldiersKilled),
275            STR_DEMOMEN_KILLED => Some(Self::DemomenKilled),
276            STR_HEAVIES_KILLED => Some(Self::HeaviesKilled),
277            STR_PYROS_KILLED => Some(Self::PyrosKilled),
278            STR_SPIES_KILLED => Some(Self::SpiesKilled),
279            STR_ENGINEERS_KILLED => Some(Self::EngineersKilled),
280            STR_MEDICS_KILLED => Some(Self::MedicsKilled),
281            STR_BUILDINGS_DESTROYED => Some(Self::BuildingsDestroyed),
282            STR_PROJECTILES_REFLECTED => Some(Self::ProjectilesReflected),
283            STR_HEADSHOT_KILLS => Some(Self::HeadshotKills),
284            STR_AIRBORNE_ENEMY_KILLS => Some(Self::AirborneEnemyKills),
285            STR_GIB_KILLS => Some(Self::GibKills),
286            STR_KILLS_UNDER_A_FULL_MOON => Some(Self::KillsUnderAFullMoon),
287            STR_DOMINATIONS => Some(Self::Dominations),
288            STR_REVENGES => Some(Self::Revenges),
289            STR_POSTHUMOUS_KILLS => Some(Self::PosthumousKills),
290            STR_TEAMMATES_EXTINGUISHED => Some(Self::TeammatesExtinguished),
291            STR_CRITICAL_KILLS => Some(Self::CriticalKills),
292            STR_KILLS_WHILE_EXPLOSIVE_JUMPING => Some(Self::KillsWhileExplosiveJumping),
293            STR_SAPPERS_REMOVED => Some(Self::SappersRemoved),
294            STR_CLOAKED_SPIES_KILLED => Some(Self::CloakedSpiesKilled),
295            STR_MEDICS_KILLED_THAT_HAVE_FULL_UBER_CHARGE => Some(Self::MedicsKilledThatHaveFullUberCharge),
296            STR_ROBOTS_DESTROYED => Some(Self::RobotsDestroyed),
297            STR_GIANT_ROBOTS_DESTROYED => Some(Self::GiantRobotsDestroyed),
298            STR_KILLS_WHILE_LOW_HEALTH => Some(Self::KillsWhileLowHealth),
299            STR_KILLS_DURING_HALLOWEEN => Some(Self::KillsDuringHalloween),
300            STR_ROBOTS_KILLED_DURING_HALLOWEEN => Some(Self::RobotsKilledDuringHalloween),
301            STR_DEFENDER_KILLS => Some(Self::DefenderKills),
302            STR_SUBMERGED_ENEMY_KILLS => Some(Self::SubmergedEnemyKills),
303            STR_KILLS_WHILE_INVULN_UBER_CHARGED => Some(Self::KillsWhileInvulnUberCharged),
304            STR_TANKS_DESTROYED => Some(Self::TanksDestroyed),
305            STR_LONG_DISTANCE_KILLS => Some(Self::LongDistanceKills),
306            STR_KILLS_DURING_VICTORY_TIME => Some(Self::KillsDuringVictoryTime),
307            STR_ROBOT_SCOUTS_DESTROYED => Some(Self::RobotScoutsDestroyed),
308            STR_ROBOT_SPIES_DESTROYED => Some(Self::RobotSpiesDestroyed),
309            STR_TAUNT_KILLS => Some(Self::TauntKills),
310            STR_UNUSUAL_WEARING_PLAYER_KILLS => Some(Self::UnusualWearingPlayerKills),
311            STR_BURNING_PLAYER_KILLS => Some(Self::BurningPlayerKills),
312            STR_KILLSTREAKS_ENDED => Some(Self::KillstreaksEnded),
313            STR_FREEZECAM_TAUNT_APPEARANCES => Some(Self::FreezecamTauntAppearances),
314            STR_DAMAGE_DEALT => Some(Self::DamageDealt),
315            STR_FIRES_SURVIVED => Some(Self::FiresSurvived),
316            STR_ALLIED_HEALING_DONE => Some(Self::AlliedHealingDone),
317            STR_POINT_BLANK_KILLS => Some(Self::PointBlankKills),
318            STR_KILLS => Some(Self::Kills),
319            STR_FULL_HEALTH_KILLS => Some(Self::FullHealthKills),
320            STR_TAUNTING_PLAYER_KILLS => Some(Self::TauntingPlayerKills),
321            STR_NOT_CRIT_NOR_MINI_CRIT_KILLS => Some(Self::NotCritNorMiniCritKills),
322            STR_PLAYER_HITS => Some(Self::PlayerHits),
323            STR_ASSISTS => Some(Self::Assists),
324            _ => None,
325        }
326    }
327    
328    /// Is this strange part for cosmetics?
329    pub fn is_cosmetic_part(&self) -> bool {
330        matches!(self, Self::Kills | Self::FullHealthKills | Self::Assists | Self::FreezecamTauntAppearances)
331    }
332    
333    /// Converts this [`StrangePart`] into its related [`KillEaterScoreType`], if it exists.
334    pub fn kill_eater_score_type(&self) -> Option<KillEaterScoreType> {
335        KillEaterScoreType::try_from(*self).ok()
336    }
337}
338
339impl Attributes for StrangePart {
340    const DEFINDEX: &'static [u32] = &[
341        380,
342        382,
343        384,
344    ];
345    const USES_FLOAT_VALUE: bool = true;
346    /// Represents the "kill_eater_user_score_type_1", "kill_eater_user_score_type_2", and
347    /// "kill_eater_user_score_type_3", attributes.
348    const ATTRIBUTES: &'static [AttributeDef] = &[
349        AttributeDef {
350            defindex: 380,
351            name: "kill eater user score type 1",
352            attribute_class: Some("kill_eater_user_score_type_1"),
353            description_string: None,
354            description_format: None,
355            effect_type: EffectType::Positive,
356            hidden: true,
357            stored_as_integer: false,
358        },
359        AttributeDef {
360            defindex: 382,
361            name: "kill eater user score type 2",
362            attribute_class: Some("kill_eater_user_score_type_2"),
363            description_string: None,
364            description_format: None,
365            effect_type: EffectType::Positive,
366            hidden: true,
367            stored_as_integer: false,
368        },
369        AttributeDef {
370            defindex: 384,
371            name: "kill eater user score type 3",
372            attribute_class: Some("kill_eater_user_score_type_3"),
373            description_string: None,
374            description_format: None,
375            effect_type: EffectType::Positive,
376            hidden: true,
377            stored_as_integer: false,
378        },
379    ];
380    
381    /// Gets the attribute float value.
382    fn attribute_float_value(&self) -> Option<f32> {
383        Some((*self as u32) as f32)
384    }
385}
386
387impl TryFromIntAttributeValue for StrangePart {}
388
389impl HasItemDefindex for StrangePart {
390    /// Gets the `defindex` for the [`StrangePart`].
391    fn defindex(&self) -> u32 {
392        match self {
393            Self::ScoutsKilled => 6003,
394            Self::SnipersKilled => 6005,
395            Self::SoldiersKilled => 6002,
396            Self::DemomenKilled => 6001,
397            Self::HeaviesKilled => 6000,
398            Self::PyrosKilled => 6006,
399            Self::SpiesKilled => 6008,
400            Self::EngineersKilled => 6004,
401            Self::MedicsKilled => 6007,
402            Self::BuildingsDestroyed => 6009,
403            Self::ProjectilesReflected => 6010,
404            Self::HeadshotKills => 6011,
405            Self::AirborneEnemyKills => 6012,
406            Self::GibKills => 6013,
407            Self::KillsUnderAFullMoon => 6015,
408            Self::Dominations => 6016,
409            Self::Revenges => 6018,
410            Self::PosthumousKills => 6019,
411            Self::TeammatesExtinguished => 6020,
412            Self::CriticalKills => 6021,
413            Self::KillsWhileExplosiveJumping => 6022,
414            Self::SappersRemoved => 6025,
415            Self::CloakedSpiesKilled => 6024,
416            Self::MedicsKilledThatHaveFullUberCharge => 6023,
417            Self::RobotsDestroyed => 6026,
418            Self::GiantRobotsDestroyed => 6028,
419            Self::KillsWhileLowHealth => 6032,
420            Self::KillsDuringHalloween => 6033,
421            Self::RobotsKilledDuringHalloween => 6034,
422            Self::DefenderKills => 6035,
423            Self::SubmergedEnemyKills => 6036,
424            Self::KillsWhileInvulnUberCharged => 6037,
425            Self::TanksDestroyed => 6038,
426            Self::LongDistanceKills => 6039,
427            Self::KillsDuringVictoryTime => 6041,
428            Self::RobotScoutsDestroyed => 6042,
429            Self::RobotSpiesDestroyed => 6048,
430            Self::TauntKills => 6051,
431            Self::UnusualWearingPlayerKills => 6052,
432            Self::BurningPlayerKills => 6053,
433            Self::KillstreaksEnded => 6054,
434            Self::FreezecamTauntAppearances => 6055,
435            Self::DamageDealt => 6056,
436            Self::FiresSurvived => 6057,
437            Self::AlliedHealingDone => 6058,
438            Self::PointBlankKills => 6059,
439            Self::Kills => 6060,
440            Self::FullHealthKills => 6061,
441            Self::TauntingPlayerKills => 6062,
442            Self::NotCritNorMiniCritKills => 6063,
443            Self::PlayerHits => 6064,
444            Self::Assists => 6065,
445        }
446    }
447    
448    /// Converts a `defindex` into its related [`StrangePart`], if it exists.
449    fn from_defindex(defindex: u32) -> Option<Self> {
450        match defindex {
451            6003 => Some(Self::ScoutsKilled),
452            6005 => Some(Self::SnipersKilled),
453            6002 => Some(Self::SoldiersKilled),
454            6001 => Some(Self::DemomenKilled),
455            6000 => Some(Self::HeaviesKilled),
456            6006 => Some(Self::PyrosKilled),
457            6008 => Some(Self::SpiesKilled),
458            6004 => Some(Self::EngineersKilled),
459            6007 => Some(Self::MedicsKilled),
460            6009 => Some(Self::BuildingsDestroyed),
461            6010 => Some(Self::ProjectilesReflected),
462            6011 => Some(Self::HeadshotKills),
463            6012 => Some(Self::AirborneEnemyKills),
464            6013 => Some(Self::GibKills),
465            6015 => Some(Self::KillsUnderAFullMoon),
466            6016 => Some(Self::Dominations),
467            6018 => Some(Self::Revenges),
468            6019 => Some(Self::PosthumousKills),
469            6020 => Some(Self::TeammatesExtinguished),
470            6021 => Some(Self::CriticalKills),
471            6022 => Some(Self::KillsWhileExplosiveJumping),
472            6025 => Some(Self::SappersRemoved),
473            6024 => Some(Self::CloakedSpiesKilled),
474            6023 => Some(Self::MedicsKilledThatHaveFullUberCharge),
475            6026 => Some(Self::RobotsDestroyed),
476            6028 => Some(Self::GiantRobotsDestroyed),
477            6032 => Some(Self::KillsWhileLowHealth),
478            6033 => Some(Self::KillsDuringHalloween),
479            6034 => Some(Self::RobotsKilledDuringHalloween),
480            6035 => Some(Self::DefenderKills),
481            6036 => Some(Self::SubmergedEnemyKills),
482            6037 => Some(Self::KillsWhileInvulnUberCharged),
483            6038 => Some(Self::TanksDestroyed),
484            6039 => Some(Self::LongDistanceKills),
485            6041 => Some(Self::KillsDuringVictoryTime),
486            6042 => Some(Self::RobotScoutsDestroyed),
487            6048 => Some(Self::RobotSpiesDestroyed),
488            6051 => Some(Self::TauntKills),
489            6052 => Some(Self::UnusualWearingPlayerKills),
490            6053 => Some(Self::BurningPlayerKills),
491            6054 => Some(Self::KillstreaksEnded),
492            6055 => Some(Self::FreezecamTauntAppearances),
493            6056 => Some(Self::DamageDealt),
494            6057 => Some(Self::FiresSurvived),
495            6058 => Some(Self::AlliedHealingDone),
496            6059 => Some(Self::PointBlankKills),
497            6060 => Some(Self::Kills),
498            6061 => Some(Self::FullHealthKills),
499            6062 => Some(Self::TauntingPlayerKills),
500            6063 => Some(Self::NotCritNorMiniCritKills),
501            6064 => Some(Self::PlayerHits),
502            6065 => Some(Self::Assists),
503            _ => None,
504        }
505    }
506}
507
508impl TryFrom<KillEaterScoreType> for StrangePart {
509    type Error = TryFromPrimitiveError<Self>;
510    
511    fn try_from(part: KillEaterScoreType) -> Result<Self, Self::Error> {
512        StrangePart::try_from(part as u32)
513    }
514}
515
516impl TryFrom<&KillEaterScoreType> for StrangePart {
517    type Error = TryFromPrimitiveError<Self>;
518    
519    fn try_from(part: &KillEaterScoreType) -> Result<Self, Self::Error> {
520        StrangePart::try_from(*part as u32)
521    }
522}
523
524#[cfg(test)]
525mod tests {
526    use super::*;
527    use std::str::FromStr;
528    
529    #[test]
530    fn from_str_converts() {
531        assert_eq!(
532            StrangePart::MedicsKilledThatHaveFullUberCharge,
533            StrangePart::from_str("Medics Killed That Have Full ÜberCharge").unwrap()
534        );
535    }
536    
537    #[test]
538    fn serializes_player_hits_correctly() {
539        let player_hits = StrangePart::PlayerHits;
540        let serialized = player_hits.to_string();
541
542        assert_eq!(serialized, "Player Hits");
543        assert_eq!(StrangePart::from_str("Player Hits").unwrap(), StrangePart::PlayerHits);
544    }
545    
546    #[test]
547    fn serializes_defender_kills_correctly() {
548        let defender_kills = StrangePart::DefenderKills;
549        let serialized = defender_kills.to_string();
550
551        assert_eq!(serialized, "Defender Kills");
552        assert_eq!(StrangePart::from_str("Defender Kills").unwrap(), StrangePart::DefenderKills);
553    }
554    
555    #[test]
556    fn attribute_slices_are_equal_length() {
557        assert_eq!(StrangePart::DEFINDEX.len(), StrangePart::ATTRIBUTES.len());
558    }
559}