poke_engine/
state.rs

1use crate::abilities::Abilities;
2use crate::choices::{Choice, Choices, MoveCategory, MOVES};
3use crate::define_enum_with_from_str;
4use crate::instruction::{
5    BoostInstruction, ChangeSideConditionInstruction, ChangeStatInstruction, ChangeType,
6    ChangeVolatileStatusDurationInstruction, EnableMoveInstruction, Instruction,
7    RemoveVolatileStatusInstruction, StateInstructions,
8};
9use crate::items::Items;
10use crate::pokemon::PokemonName;
11use core::panic;
12use std::collections::HashSet;
13use std::ops::{Index, IndexMut};
14use std::str::FromStr;
15
16fn common_pkmn_stat_calc(stat: u16, ev: u16, level: u16) -> u16 {
17    // 31 IV always used
18    ((2 * stat + 31 + (ev / 4)) * level) / 100
19}
20
21fn multiply_boost(boost_num: i8, stat_value: i16) -> i16 {
22    match boost_num {
23        -6 => stat_value * 2 / 8,
24        -5 => stat_value * 2 / 7,
25        -4 => stat_value * 2 / 6,
26        -3 => stat_value * 2 / 5,
27        -2 => stat_value * 2 / 4,
28        -1 => stat_value * 2 / 3,
29        0 => stat_value,
30        1 => stat_value * 3 / 2,
31        2 => stat_value * 4 / 2,
32        3 => stat_value * 5 / 2,
33        4 => stat_value * 6 / 2,
34        5 => stat_value * 7 / 2,
35        6 => stat_value * 8 / 2,
36        _ => panic!("Invalid boost number: {}", boost_num),
37    }
38}
39
40#[derive(Debug, Clone)]
41pub struct DamageDealt {
42    pub damage: i16,
43    pub move_category: MoveCategory,
44    pub hit_substitute: bool,
45}
46
47impl Default for DamageDealt {
48    fn default() -> DamageDealt {
49        DamageDealt {
50            damage: 0,
51            move_category: MoveCategory::Physical,
52            hit_substitute: false,
53        }
54    }
55}
56
57#[derive(Debug, PartialEq, Eq, Copy, Clone)]
58pub enum LastUsedMove {
59    Move(PokemonMoveIndex),
60    Switch(PokemonIndex),
61    None,
62}
63
64#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
65pub enum MoveChoice {
66    MoveTera(PokemonMoveIndex),
67    Move(PokemonMoveIndex),
68    Switch(PokemonIndex),
69    None,
70}
71
72impl MoveChoice {
73    pub fn to_string(&self, side: &Side) -> String {
74        match self {
75            MoveChoice::MoveTera(index) => {
76                format!("{}-tera", side.get_active_immutable().moves[index].id).to_lowercase()
77            }
78            MoveChoice::Move(index) => {
79                format!("{}", side.get_active_immutable().moves[index].id).to_lowercase()
80            }
81            MoveChoice::Switch(index) => {
82                format!("switch {}", side.pokemon[*index].id).to_lowercase()
83            }
84            MoveChoice::None => "No Move".to_string(),
85        }
86    }
87}
88
89define_enum_with_from_str! {
90    #[repr(u8)]
91    #[derive(Debug, PartialEq, Copy, Clone)]
92    SideMovesFirst {
93        SideOne,
94        SideTwo,
95        SpeedTie
96    }
97}
98
99define_enum_with_from_str! {
100    #[repr(u8)]
101    #[derive(Debug, PartialEq, Clone)]
102    PokemonNature {
103        HARDY,
104        LONELY,
105        ADAMANT,
106        NAUGHTY,
107        BRAVE,
108        BOLD,
109        DOCILE,
110        IMPISH,
111        LAX,
112        RELAXED,
113        MODEST,
114        MILD,
115        BASHFUL,
116        RASH,
117        QUIET,
118        CALM,
119        GENTLE,
120        CAREFUL,
121        QUIRKY,
122        SASSY,
123        TIMID,
124        HASTY,
125        JOLLY,
126        NAIVE,
127        SERIOUS
128    }
129}
130
131define_enum_with_from_str! {
132    #[repr(u8)]
133    #[derive(Debug, PartialEq, Copy, Clone)]
134    PokemonStatus {
135        NONE,
136        BURN,
137        SLEEP,
138        FREEZE,
139        PARALYZE,
140        POISON,
141        TOXIC,
142    }
143}
144
145define_enum_with_from_str! {
146    #[repr(u8)]
147    #[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
148    PokemonVolatileStatus {
149        NONE,
150        AQUARING,
151        ATTRACT,
152        AUTOTOMIZE,
153        BANEFULBUNKER,
154        BIDE,
155        BOUNCE,
156        BURNINGBULWARK,
157        CHARGE,
158        CONFUSION,
159        CURSE,
160        DEFENSECURL,
161        DESTINYBOND,
162        DIG,
163        DISABLE,
164        DIVE,
165        ELECTRIFY,
166        ELECTROSHOT,
167        EMBARGO,
168        ENCORE,
169        ENDURE,
170        FLASHFIRE,
171        FLINCH,
172        FLY,
173        FOCUSENERGY,
174        FOLLOWME,
175        FORESIGHT,
176        FREEZESHOCK,
177        GASTROACID,
178        GEOMANCY,
179        GLAIVERUSH,
180        GRUDGE,
181        HEALBLOCK,
182        HELPINGHAND,
183        ICEBURN,
184        IMPRISON,
185        INGRAIN,
186        KINGSSHIELD,
187        LASERFOCUS,
188        LEECHSEED,
189        LIGHTSCREEN,
190        LOCKEDMOVE,
191        MAGICCOAT,
192        MAGNETRISE,
193        MAXGUARD,
194        METEORBEAM,
195        MINIMIZE,
196        MIRACLEEYE,
197        MUSTRECHARGE,
198        NIGHTMARE,
199        NORETREAT,
200        OCTOLOCK,
201        PARTIALLYTRAPPED,
202        PERISH4,
203        PERISH3,
204        PERISH2,
205        PERISH1,
206        PHANTOMFORCE,
207        POWDER,
208        POWERSHIFT,
209        POWERTRICK,
210        PROTECT,
211        PROTOSYNTHESISATK,
212        PROTOSYNTHESISDEF,
213        PROTOSYNTHESISSPA,
214        PROTOSYNTHESISSPD,
215        PROTOSYNTHESISSPE,
216        QUARKDRIVEATK,
217        QUARKDRIVEDEF,
218        QUARKDRIVESPA,
219        QUARKDRIVESPD,
220        QUARKDRIVESPE,
221        RAGE,
222        RAGEPOWDER,
223        RAZORWIND,
224        REFLECT,
225        ROOST,
226        SALTCURE,
227        SHADOWFORCE,
228        SKULLBASH,
229        SKYATTACK,
230        SKYDROP,
231        SILKTRAP,
232        SLOWSTART,
233        SMACKDOWN,
234        SNATCH,
235        SOLARBEAM,
236        SOLARBLADE,
237        SPARKLINGARIA,
238        SPIKYSHIELD,
239        SPOTLIGHT,
240        STOCKPILE,
241        SUBSTITUTE,
242        SYRUPBOMB,
243        TARSHOT,
244        TAUNT,
245        TELEKINESIS,
246        THROATCHOP,
247        TRUANT,
248        TORMENT,
249        TYPECHANGE,
250        UNBURDEN,
251        UPROAR,
252        YAWN,
253        YAWNSLEEPTHISTURN,
254    },
255    default = NONE
256}
257
258#[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)]
259pub enum PokemonSideCondition {
260    AuroraVeil,
261    CraftyShield,
262    HealingWish,
263    LightScreen,
264    LuckyChant,
265    LunarDance,
266    MatBlock,
267    Mist,
268    Protect,
269    QuickGuard,
270    Reflect,
271    Safeguard,
272    Spikes,
273    Stealthrock,
274    StickyWeb,
275    Tailwind,
276    ToxicCount,
277    ToxicSpikes,
278    WideGuard,
279}
280
281#[derive(Debug, PartialEq, Copy, Clone)]
282pub enum SideReference {
283    SideOne,
284    SideTwo,
285}
286
287impl SideReference {
288    pub fn get_other_side(&self) -> SideReference {
289        match self {
290            SideReference::SideOne => SideReference::SideTwo,
291            SideReference::SideTwo => SideReference::SideOne,
292        }
293    }
294}
295
296define_enum_with_from_str! {
297    #[repr(u8)]
298    #[derive(Debug, PartialEq, Copy, Clone)]
299    Weather {
300        NONE,
301        SUN,
302        RAIN,
303        SAND,
304        HAIL,
305        SNOW,
306        HARSHSUN,
307        HEAVYRAIN,
308    }
309}
310
311#[derive(Debug, PartialEq, Clone)]
312pub struct StateWeather {
313    pub weather_type: Weather,
314    pub turns_remaining: i8,
315}
316
317define_enum_with_from_str! {
318    #[repr(u8)]
319    #[derive(Debug, PartialEq, Copy, Clone)]
320    Terrain {
321        NONE,
322        ELECTRICTERRAIN,
323        PSYCHICTERRAIN,
324        MISTYTERRAIN,
325        GRASSYTERRAIN,
326    }
327}
328
329#[derive(Debug, PartialEq, Clone)]
330pub struct StateTerrain {
331    pub terrain_type: Terrain,
332    pub turns_remaining: i8,
333}
334
335#[derive(Debug, PartialEq, Clone)]
336pub struct StateTrickRoom {
337    pub active: bool,
338    pub turns_remaining: i8,
339}
340
341define_enum_with_from_str! {
342    #[repr(u8)]
343    #[derive(Debug, Clone, Copy, PartialEq)]
344    PokemonType {
345        NORMAL,
346        FIRE,
347        WATER,
348        ELECTRIC,
349        GRASS,
350        ICE,
351        FIGHTING,
352        POISON,
353        GROUND,
354        FLYING,
355        PSYCHIC,
356        BUG,
357        ROCK,
358        GHOST,
359        DRAGON,
360        DARK,
361        STEEL,
362        FAIRY,
363        STELLAR,
364        TYPELESS,
365    },
366    default = TYPELESS
367}
368
369#[derive(Debug, PartialEq, Clone, Copy)]
370pub enum PokemonBoostableStat {
371    Attack,
372    Defense,
373    SpecialAttack,
374    SpecialDefense,
375    Speed,
376    Evasion,
377    Accuracy,
378}
379
380#[derive(Debug, Clone)]
381pub struct VolatileStatusDurations {
382    pub confusion: i8,
383    pub encore: i8,
384    pub lockedmove: i8,
385}
386
387impl Default for VolatileStatusDurations {
388    fn default() -> VolatileStatusDurations {
389        VolatileStatusDurations {
390            confusion: 0,
391            encore: 0,
392            lockedmove: 0,
393        }
394    }
395}
396
397impl VolatileStatusDurations {
398    pub fn serialize(&self) -> String {
399        format!("{};{};{}", self.confusion, self.encore, self.lockedmove)
400    }
401    pub fn deserialize(serialized: &str) -> VolatileStatusDurations {
402        let split: Vec<&str> = serialized.split(";").collect();
403        VolatileStatusDurations {
404            confusion: split[0].parse::<i8>().unwrap(),
405            encore: split[1].parse::<i8>().unwrap(),
406            lockedmove: split[2].parse::<i8>().unwrap(),
407        }
408    }
409}
410
411#[derive(Debug, PartialEq, Clone)]
412pub struct SideConditions {
413    pub aurora_veil: i8,
414    pub crafty_shield: i8,
415    pub healing_wish: i8,
416    pub light_screen: i8,
417    pub lucky_chant: i8,
418    pub lunar_dance: i8,
419    pub mat_block: i8,
420    pub mist: i8,
421    pub protect: i8,
422    pub quick_guard: i8,
423    pub reflect: i8,
424    pub safeguard: i8,
425    pub spikes: i8,
426    pub stealth_rock: i8,
427    pub sticky_web: i8,
428    pub tailwind: i8,
429    pub toxic_count: i8,
430    pub toxic_spikes: i8,
431    pub wide_guard: i8,
432}
433
434impl Default for SideConditions {
435    fn default() -> SideConditions {
436        SideConditions {
437            aurora_veil: 0,
438            crafty_shield: 0,
439            healing_wish: 0,
440            light_screen: 0,
441            lucky_chant: 0,
442            lunar_dance: 0,
443            mat_block: 0,
444            mist: 0,
445            protect: 0,
446            quick_guard: 0,
447            reflect: 0,
448            safeguard: 0,
449            spikes: 0,
450            stealth_rock: 0,
451            sticky_web: 0,
452            tailwind: 0,
453            toxic_count: 0,
454            toxic_spikes: 0,
455            wide_guard: 0,
456        }
457    }
458}
459
460#[derive(Debug, Copy, PartialEq, Clone, Eq, Hash)]
461pub enum PokemonMoveIndex {
462    M0,
463    M1,
464    M2,
465    M3,
466}
467
468#[derive(Debug, Clone)]
469pub struct PokemonMoves {
470    pub m0: Move,
471    pub m1: Move,
472    pub m2: Move,
473    pub m3: Move,
474}
475
476impl Index<&PokemonMoveIndex> for PokemonMoves {
477    type Output = Move;
478
479    fn index(&self, index: &PokemonMoveIndex) -> &Self::Output {
480        match index {
481            PokemonMoveIndex::M0 => &self.m0,
482            PokemonMoveIndex::M1 => &self.m1,
483            PokemonMoveIndex::M2 => &self.m2,
484            PokemonMoveIndex::M3 => &self.m3,
485        }
486    }
487}
488
489impl IndexMut<&PokemonMoveIndex> for PokemonMoves {
490    fn index_mut(&mut self, index: &PokemonMoveIndex) -> &mut Self::Output {
491        match index {
492            PokemonMoveIndex::M0 => &mut self.m0,
493            PokemonMoveIndex::M1 => &mut self.m1,
494            PokemonMoveIndex::M2 => &mut self.m2,
495            PokemonMoveIndex::M3 => &mut self.m3,
496        }
497    }
498}
499
500pub struct PokemonMoveIterator<'a> {
501    pub pokemon_move: &'a PokemonMoves,
502    pub pokemon_move_index: PokemonMoveIndex,
503    pub index: usize,
504}
505
506impl<'a> Iterator for PokemonMoveIterator<'a> {
507    type Item = &'a Move;
508
509    fn next(&mut self) -> Option<Self::Item> {
510        match self.index {
511            0 => {
512                self.index += 1;
513                self.pokemon_move_index = PokemonMoveIndex::M0;
514                Some(&self.pokemon_move.m0)
515            }
516            1 => {
517                self.index += 1;
518                self.pokemon_move_index = PokemonMoveIndex::M1;
519                Some(&self.pokemon_move.m1)
520            }
521            2 => {
522                self.index += 1;
523                self.pokemon_move_index = PokemonMoveIndex::M2;
524                Some(&self.pokemon_move.m2)
525            }
526            3 => {
527                self.index += 1;
528                self.pokemon_move_index = PokemonMoveIndex::M3;
529                Some(&self.pokemon_move.m3)
530            }
531            _ => None,
532        }
533    }
534}
535
536impl<'a> IntoIterator for &'a PokemonMoves {
537    type Item = &'a Move;
538    type IntoIter = PokemonMoveIterator<'a>;
539
540    fn into_iter(self) -> Self::IntoIter {
541        PokemonMoveIterator {
542            pokemon_move: &self,
543            pokemon_move_index: PokemonMoveIndex::M0,
544            index: 0,
545        }
546    }
547}
548
549#[derive(Debug, Clone)]
550pub struct Move {
551    pub id: Choices,
552    pub disabled: bool,
553    pub pp: i8,
554    pub choice: Choice,
555}
556
557impl Default for Move {
558    fn default() -> Move {
559        Move {
560            id: Choices::NONE,
561            disabled: false,
562            pp: 32,
563            choice: Choice::default(),
564        }
565    }
566}
567
568#[derive(Debug, Clone)]
569pub struct Pokemon {
570    pub id: PokemonName,
571    pub level: i8,
572    pub types: (PokemonType, PokemonType),
573    pub base_types: (PokemonType, PokemonType),
574    pub hp: i16,
575    pub maxhp: i16,
576    pub ability: Abilities,
577    pub base_ability: Abilities,
578    pub item: Items,
579    pub nature: PokemonNature,
580    pub evs: (u8, u8, u8, u8, u8, u8),
581    pub attack: i16,
582    pub defense: i16,
583    pub special_attack: i16,
584    pub special_defense: i16,
585    pub speed: i16,
586    pub status: PokemonStatus,
587    pub rest_turns: i8,
588    pub sleep_turns: i8,
589    pub weight_kg: f32,
590    pub terastallized: bool,
591    pub tera_type: PokemonType,
592    pub moves: PokemonMoves,
593}
594
595impl Pokemon {
596    pub fn recalculate_stats(
597        &mut self,
598        side_ref: &SideReference,
599        instructions: &mut StateInstructions,
600    ) {
601        // recalculate stats from base-stats and push any changes made to the StateInstructions
602        let stats = self.calculate_stats_from_base_stats();
603        if stats.1 != self.attack {
604            let ins = Instruction::ChangeAttack(ChangeStatInstruction {
605                side_ref: *side_ref,
606                amount: stats.1 - self.attack,
607            });
608            self.attack = stats.1;
609            instructions.instruction_list.push(ins);
610        }
611        if stats.2 != self.defense {
612            let ins = Instruction::ChangeDefense(ChangeStatInstruction {
613                side_ref: *side_ref,
614                amount: stats.2 - self.defense,
615            });
616            self.defense = stats.2;
617            instructions.instruction_list.push(ins);
618        }
619        if stats.3 != self.special_attack {
620            let ins = Instruction::ChangeSpecialAttack(ChangeStatInstruction {
621                side_ref: *side_ref,
622                amount: stats.3 - self.special_attack,
623            });
624            self.special_attack = stats.3;
625            instructions.instruction_list.push(ins);
626        }
627        if stats.4 != self.special_defense {
628            let ins = Instruction::ChangeSpecialDefense(ChangeStatInstruction {
629                side_ref: *side_ref,
630                amount: stats.4 - self.special_defense,
631            });
632            self.special_defense = stats.4;
633            instructions.instruction_list.push(ins);
634        }
635        if stats.5 != self.speed {
636            let ins = Instruction::ChangeSpeed(ChangeStatInstruction {
637                side_ref: *side_ref,
638                amount: stats.5 - self.speed,
639            });
640            self.speed = stats.5;
641            instructions.instruction_list.push(ins);
642        }
643    }
644    pub fn calculate_stats_from_base_stats(&self) -> (i16, i16, i16, i16, i16, i16) {
645        let base_stats = self.id.base_stats();
646        (
647            (common_pkmn_stat_calc(base_stats.0 as u16, self.evs.0 as u16, self.level as u16)
648                + self.level as u16
649                + 10) as i16,
650            (common_pkmn_stat_calc(base_stats.1 as u16, self.evs.1 as u16, self.level as u16) + 5)
651                as i16,
652            (common_pkmn_stat_calc(base_stats.2 as u16, self.evs.2 as u16, self.level as u16) + 5)
653                as i16,
654            (common_pkmn_stat_calc(base_stats.3 as u16, self.evs.3 as u16, self.level as u16) + 5)
655                as i16,
656            (common_pkmn_stat_calc(base_stats.4 as u16, self.evs.4 as u16, self.level as u16) + 5)
657                as i16,
658            (common_pkmn_stat_calc(base_stats.5 as u16, self.evs.5 as u16, self.level as u16) + 5)
659                as i16,
660        )
661    }
662    pub fn get_stat_from_boostable_stat(&self, stat: PokemonBoostableStat) -> i16 {
663        match stat {
664            PokemonBoostableStat::Attack => self.attack,
665            PokemonBoostableStat::Defense => self.defense,
666            PokemonBoostableStat::SpecialAttack => self.special_attack,
667            PokemonBoostableStat::SpecialDefense => self.special_defense,
668            PokemonBoostableStat::Speed => self.speed,
669            _ => panic!("Not implemented"),
670        }
671    }
672    pub fn get_sleep_talk_choices(&self) -> Vec<Choice> {
673        let mut vec = Vec::with_capacity(4);
674        for p in self.moves.into_iter() {
675            if p.id != Choices::SLEEPTALK && p.id != Choices::NONE {
676                vec.push(p.choice.clone());
677            }
678        }
679        vec
680    }
681    pub fn replace_move(&mut self, move_index: PokemonMoveIndex, new_move_name: Choices) {
682        self.moves[&move_index].choice = MOVES.get(&new_move_name).unwrap().to_owned();
683        self.moves[&move_index].id = new_move_name;
684    }
685
686    pub fn add_available_moves(
687        &self,
688        vec: &mut Vec<MoveChoice>,
689        last_used_move: &LastUsedMove,
690        encored: bool,
691        can_tera: bool,
692    ) {
693        let mut iter = self.moves.into_iter();
694        while let Some(p) = iter.next() {
695            if !p.disabled && p.pp > 0 {
696                match last_used_move {
697                    LastUsedMove::Move(last_used_move) => {
698                        if encored && last_used_move != &iter.pokemon_move_index {
699                            continue;
700                        } else if (self.moves[last_used_move].id == Choices::BLOODMOON
701                            || self.moves[last_used_move].id == Choices::GIGATONHAMMER)
702                            && &iter.pokemon_move_index == last_used_move
703                        {
704                            continue;
705                        }
706                    }
707                    _ => {
708                        // there are some situations where you switched out and got encored into
709                        // a move from a different pokemon because you also have that move.
710                        // just assume nothing is locked in this case
711                    }
712                }
713                if self.item == Items::ASSAULTVEST
714                    && self.moves[&iter.pokemon_move_index].choice.category == MoveCategory::Status
715                {
716                    continue;
717                }
718                vec.push(MoveChoice::Move(iter.pokemon_move_index));
719                if can_tera {
720                    vec.push(MoveChoice::MoveTera(iter.pokemon_move_index));
721                }
722            }
723        }
724    }
725
726    pub fn add_move_from_choice(&self, vec: &mut Vec<MoveChoice>, choice: Choices) {
727        let mut iter = self.moves.into_iter();
728        while let Some(p) = iter.next() {
729            if p.id == choice {
730                vec.push(MoveChoice::Move(iter.pokemon_move_index));
731            }
732        }
733    }
734
735    #[cfg(feature = "terastallization")]
736    pub fn has_type(&self, pkmn_type: &PokemonType) -> bool {
737        if self.terastallized {
738            pkmn_type == &self.tera_type
739        } else {
740            pkmn_type == &self.types.0 || pkmn_type == &self.types.1
741        }
742    }
743
744    #[cfg(not(feature = "terastallization"))]
745    pub fn has_type(&self, pkmn_type: &PokemonType) -> bool {
746        pkmn_type == &self.types.0 || pkmn_type == &self.types.1
747    }
748
749    pub fn item_is_permanent(&self) -> bool {
750        match self.item {
751            Items::LUSTROUSGLOBE => self.id == PokemonName::PALKIAORIGIN,
752            Items::GRISEOUSCORE => self.id == PokemonName::GIRATINAORIGIN,
753            Items::ADAMANTCRYSTAL => self.id == PokemonName::DIALGAORIGIN,
754            Items::RUSTEDSWORD => {
755                self.id == PokemonName::ZACIANCROWNED || self.id == PokemonName::ZACIAN
756            }
757            Items::RUSTEDSHIELD => {
758                self.id == PokemonName::ZAMAZENTACROWNED || self.id == PokemonName::ZAMAZENTA
759            }
760            Items::SPLASHPLATE => self.id == PokemonName::ARCEUSWATER,
761            Items::TOXICPLATE => self.id == PokemonName::ARCEUSPOISON,
762            Items::EARTHPLATE => self.id == PokemonName::ARCEUSGROUND,
763            Items::STONEPLATE => self.id == PokemonName::ARCEUSROCK,
764            Items::INSECTPLATE => self.id == PokemonName::ARCEUSBUG,
765            Items::SPOOKYPLATE => self.id == PokemonName::ARCEUSGHOST,
766            Items::IRONPLATE => self.id == PokemonName::ARCEUSSTEEL,
767            Items::FLAMEPLATE => self.id == PokemonName::ARCEUSFIRE,
768            Items::MEADOWPLATE => self.id == PokemonName::ARCEUSGRASS,
769            Items::ZAPPLATE => self.id == PokemonName::ARCEUSELECTRIC,
770            Items::MINDPLATE => self.id == PokemonName::ARCEUSPSYCHIC,
771            Items::ICICLEPLATE => self.id == PokemonName::ARCEUSICE,
772            Items::DRACOPLATE => self.id == PokemonName::ARCEUSDRAGON,
773            Items::DREADPLATE => self.id == PokemonName::ARCEUSDARK,
774            Items::FISTPLATE => self.id == PokemonName::ARCEUSFIGHTING,
775            Items::BLANKPLATE => self.id == PokemonName::ARCEUS,
776            Items::SKYPLATE => self.id == PokemonName::ARCEUSFLYING,
777            Items::PIXIEPLATE => self.id == PokemonName::ARCEUSFAIRY,
778            Items::BUGMEMORY => self.id == PokemonName::SILVALLYBUG,
779            Items::FIGHTINGMEMORY => self.id == PokemonName::SILVALLYFIGHTING,
780            Items::GHOSTMEMORY => self.id == PokemonName::SILVALLYGHOST,
781            Items::PSYCHICMEMORY => self.id == PokemonName::SILVALLYPSYCHIC,
782            Items::FLYINGMEMORY => self.id == PokemonName::SILVALLYFLYING,
783            Items::STEELMEMORY => self.id == PokemonName::SILVALLYSTEEL,
784            Items::ICEMEMORY => self.id == PokemonName::SILVALLYICE,
785            Items::POISONMEMORY => self.id == PokemonName::SILVALLYPOISON,
786            Items::FIREMEMORY => self.id == PokemonName::SILVALLYFIRE,
787            Items::DRAGONMEMORY => self.id == PokemonName::SILVALLYDRAGON,
788            Items::GROUNDMEMORY => self.id == PokemonName::SILVALLYGROUND,
789            Items::WATERMEMORY => self.id == PokemonName::SILVALLYWATER,
790            Items::DARKMEMORY => self.id == PokemonName::SILVALLYDARK,
791            Items::ROCKMEMORY => self.id == PokemonName::SILVALLYROCK,
792            Items::GRASSMEMORY => self.id == PokemonName::SILVALLYGRASS,
793            Items::FAIRYMEMORY => self.id == PokemonName::SILVALLYFAIRY,
794            Items::ELECTRICMEMORY => self.id == PokemonName::SILVALLYELECTRIC,
795            Items::CORNERSTONEMASK => {
796                self.id == PokemonName::OGERPONCORNERSTONE
797                    || self.id == PokemonName::OGERPONCORNERSTONETERA
798            }
799            Items::HEARTHFLAMEMASK => {
800                self.id == PokemonName::OGERPONHEARTHFLAME
801                    || self.id == PokemonName::OGERPONHEARTHFLAMETERA
802            }
803            Items::WELLSPRINGMASK => {
804                self.id == PokemonName::OGERPONWELLSPRING
805                    || self.id == PokemonName::OGERPONWELLSPRINGTERA
806            }
807            _ => false,
808        }
809    }
810
811    pub fn item_can_be_removed(&self) -> bool {
812        if self.ability == Abilities::STICKYHOLD {
813            return false;
814        }
815        !self.item_is_permanent()
816    }
817
818    pub fn is_grounded(&self) -> bool {
819        if self.item == Items::IRONBALL {
820            return true;
821        }
822        if self.has_type(&PokemonType::FLYING)
823            || self.ability == Abilities::LEVITATE
824            || self.item == Items::AIRBALLOON
825        {
826            return false;
827        }
828        true
829    }
830
831    pub fn volatile_status_can_be_applied(
832        &self,
833        volatile_status: &PokemonVolatileStatus,
834        active_volatiles: &HashSet<PokemonVolatileStatus>,
835        first_move: bool,
836    ) -> bool {
837        if active_volatiles.contains(volatile_status) || self.hp == 0 {
838            return false;
839        }
840        match volatile_status {
841            PokemonVolatileStatus::LEECHSEED => {
842                if self.has_type(&PokemonType::GRASS)
843                    || active_volatiles.contains(&PokemonVolatileStatus::SUBSTITUTE)
844                {
845                    return false;
846                }
847                true
848            }
849            PokemonVolatileStatus::CONFUSION => {
850                if active_volatiles.contains(&PokemonVolatileStatus::SUBSTITUTE) {
851                    return false;
852                }
853                true
854            }
855            PokemonVolatileStatus::SUBSTITUTE => self.hp > self.maxhp / 4,
856            PokemonVolatileStatus::FLINCH => {
857                if !first_move || [Abilities::INNERFOCUS].contains(&self.ability) {
858                    return false;
859                }
860                true
861            }
862            PokemonVolatileStatus::PROTECT => first_move,
863            PokemonVolatileStatus::TAUNT
864            | PokemonVolatileStatus::TORMENT
865            | PokemonVolatileStatus::ENCORE
866            | PokemonVolatileStatus::DISABLE
867            | PokemonVolatileStatus::HEALBLOCK
868            | PokemonVolatileStatus::ATTRACT => self.ability != Abilities::AROMAVEIL,
869            PokemonVolatileStatus::YAWN => {
870                // immunity to yawn via sleep immunity is handled in `get_instructions_from_volatile_statuses`
871                !active_volatiles.contains(&PokemonVolatileStatus::YAWNSLEEPTHISTURN)
872            }
873            _ => true,
874        }
875    }
876
877    pub fn immune_to_stats_lowered_by_opponent(
878        &self,
879        stat: &PokemonBoostableStat,
880        volatiles: &HashSet<PokemonVolatileStatus>,
881    ) -> bool {
882        if [
883            Abilities::CLEARBODY,
884            Abilities::WHITESMOKE,
885            Abilities::FULLMETALBODY,
886        ]
887        .contains(&self.ability)
888            || ([Items::CLEARAMULET].contains(&self.item))
889        {
890            return true;
891        }
892
893        if volatiles.contains(&PokemonVolatileStatus::SUBSTITUTE) {
894            return true;
895        }
896
897        if stat == &PokemonBoostableStat::Attack && self.ability == Abilities::HYPERCUTTER {
898            return true;
899        } else if stat == &PokemonBoostableStat::Accuracy && self.ability == Abilities::KEENEYE {
900            return true;
901        }
902
903        false
904    }
905}
906
907impl Default for Pokemon {
908    fn default() -> Pokemon {
909        Pokemon {
910            id: PokemonName::NONE,
911            level: 100,
912            types: (PokemonType::NORMAL, PokemonType::TYPELESS),
913            base_types: (PokemonType::NORMAL, PokemonType::TYPELESS),
914            hp: 100,
915            maxhp: 100,
916            ability: Abilities::NONE,
917            base_ability: Abilities::NONE,
918            item: Items::NONE,
919            nature: PokemonNature::SERIOUS,
920            evs: (85, 85, 85, 85, 85, 85),
921            attack: 100,
922            defense: 100,
923            special_attack: 100,
924            special_defense: 100,
925            speed: 100,
926            status: PokemonStatus::NONE,
927            rest_turns: 0,
928            sleep_turns: 0,
929            weight_kg: 1.0,
930            terastallized: false,
931            tera_type: PokemonType::NORMAL,
932            moves: PokemonMoves {
933                m0: Default::default(),
934                m1: Default::default(),
935                m2: Default::default(),
936                m3: Default::default(),
937            },
938        }
939    }
940}
941
942#[derive(Debug, Copy, PartialEq, Clone, Eq, Hash)]
943pub enum PokemonIndex {
944    P0,
945    P1,
946    P2,
947    P3,
948    P4,
949    P5,
950}
951
952pub fn pokemon_index_iter() -> PokemonIndexIterator {
953    PokemonIndexIterator { index: 0 }
954}
955
956pub struct PokemonIndexIterator {
957    index: usize,
958}
959
960impl Iterator for PokemonIndexIterator {
961    type Item = PokemonIndex;
962
963    fn next(&mut self) -> Option<Self::Item> {
964        match self.index {
965            0 => {
966                self.index += 1;
967                Some(PokemonIndex::P0)
968            }
969            1 => {
970                self.index += 1;
971                Some(PokemonIndex::P1)
972            }
973            2 => {
974                self.index += 1;
975                Some(PokemonIndex::P2)
976            }
977            3 => {
978                self.index += 1;
979                Some(PokemonIndex::P3)
980            }
981            4 => {
982                self.index += 1;
983                Some(PokemonIndex::P4)
984            }
985            5 => {
986                self.index += 1;
987                Some(PokemonIndex::P5)
988            }
989            _ => None,
990        }
991    }
992}
993
994#[derive(Debug, Clone)]
995pub struct SidePokemon {
996    pub p0: Pokemon,
997    pub p1: Pokemon,
998    pub p2: Pokemon,
999    pub p3: Pokemon,
1000    pub p4: Pokemon,
1001    pub p5: Pokemon,
1002}
1003
1004impl<'a> IntoIterator for &'a SidePokemon {
1005    type Item = &'a Pokemon;
1006    type IntoIter = SidePokemonIterator<'a>;
1007
1008    fn into_iter(self) -> Self::IntoIter {
1009        SidePokemonIterator {
1010            side_pokemon: &self,
1011            pokemon_index: PokemonIndex::P0,
1012            index: 0,
1013        }
1014    }
1015}
1016
1017pub struct SidePokemonIterator<'a> {
1018    pub side_pokemon: &'a SidePokemon,
1019    pub pokemon_index: PokemonIndex,
1020    pub index: usize,
1021}
1022
1023impl<'a> Iterator for SidePokemonIterator<'a> {
1024    type Item = &'a Pokemon;
1025
1026    fn next(&mut self) -> Option<Self::Item> {
1027        match self.index {
1028            0 => {
1029                self.index += 1;
1030                self.pokemon_index = PokemonIndex::P0;
1031                Some(&self.side_pokemon.p0)
1032            }
1033            1 => {
1034                self.index += 1;
1035                self.pokemon_index = PokemonIndex::P1;
1036                Some(&self.side_pokemon.p1)
1037            }
1038            2 => {
1039                self.index += 1;
1040                self.pokemon_index = PokemonIndex::P2;
1041                Some(&self.side_pokemon.p2)
1042            }
1043            3 => {
1044                self.index += 1;
1045                self.pokemon_index = PokemonIndex::P3;
1046                Some(&self.side_pokemon.p3)
1047            }
1048            4 => {
1049                self.index += 1;
1050                self.pokemon_index = PokemonIndex::P4;
1051                Some(&self.side_pokemon.p4)
1052            }
1053            5 => {
1054                self.index += 1;
1055                self.pokemon_index = PokemonIndex::P5;
1056                Some(&self.side_pokemon.p5)
1057            }
1058            _ => None,
1059        }
1060    }
1061}
1062
1063impl Index<PokemonIndex> for SidePokemon {
1064    type Output = Pokemon;
1065
1066    fn index(&self, index: PokemonIndex) -> &Self::Output {
1067        match index {
1068            PokemonIndex::P0 => &self.p0,
1069            PokemonIndex::P1 => &self.p1,
1070            PokemonIndex::P2 => &self.p2,
1071            PokemonIndex::P3 => &self.p3,
1072            PokemonIndex::P4 => &self.p4,
1073            PokemonIndex::P5 => &self.p5,
1074        }
1075    }
1076}
1077
1078impl Index<&PokemonIndex> for SidePokemon {
1079    type Output = Pokemon;
1080
1081    fn index(&self, index: &PokemonIndex) -> &Self::Output {
1082        match index {
1083            PokemonIndex::P0 => &self.p0,
1084            PokemonIndex::P1 => &self.p1,
1085            PokemonIndex::P2 => &self.p2,
1086            PokemonIndex::P3 => &self.p3,
1087            PokemonIndex::P4 => &self.p4,
1088            PokemonIndex::P5 => &self.p5,
1089        }
1090    }
1091}
1092
1093impl IndexMut<PokemonIndex> for SidePokemon {
1094    fn index_mut(&mut self, index: PokemonIndex) -> &mut Self::Output {
1095        match index {
1096            PokemonIndex::P0 => &mut self.p0,
1097            PokemonIndex::P1 => &mut self.p1,
1098            PokemonIndex::P2 => &mut self.p2,
1099            PokemonIndex::P3 => &mut self.p3,
1100            PokemonIndex::P4 => &mut self.p4,
1101            PokemonIndex::P5 => &mut self.p5,
1102        }
1103    }
1104}
1105
1106#[derive(Debug, Clone)]
1107pub struct Side {
1108    pub active_index: PokemonIndex,
1109    pub baton_passing: bool,
1110    pub pokemon: SidePokemon,
1111    pub side_conditions: SideConditions,
1112    pub volatile_status_durations: VolatileStatusDurations,
1113    pub wish: (i8, i16),
1114    pub future_sight: (i8, PokemonIndex),
1115    pub force_switch: bool,
1116    pub force_trapped: bool,
1117    pub slow_uturn_move: bool,
1118    pub volatile_statuses: HashSet<PokemonVolatileStatus>,
1119    pub substitute_health: i16,
1120    pub attack_boost: i8,
1121    pub defense_boost: i8,
1122    pub special_attack_boost: i8,
1123    pub special_defense_boost: i8,
1124    pub speed_boost: i8,
1125    pub accuracy_boost: i8,
1126    pub evasion_boost: i8,
1127    pub last_used_move: LastUsedMove,
1128    pub damage_dealt: DamageDealt,
1129    pub switch_out_move_second_saved_move: Choices,
1130}
1131
1132impl Side {
1133    pub fn calculate_highest_stat(&self) -> PokemonBoostableStat {
1134        let mut highest_stat = PokemonBoostableStat::Attack;
1135        let mut highest_stat_value = self.calculate_boosted_stat(PokemonBoostableStat::Attack);
1136        for stat in [
1137            PokemonBoostableStat::Defense,
1138            PokemonBoostableStat::SpecialAttack,
1139            PokemonBoostableStat::SpecialDefense,
1140            PokemonBoostableStat::Speed,
1141        ] {
1142            let stat_value = self.calculate_boosted_stat(stat);
1143            if stat_value > highest_stat_value {
1144                highest_stat = stat;
1145                highest_stat_value = stat_value;
1146            }
1147        }
1148        highest_stat
1149    }
1150    pub fn get_boost_from_boost_enum(&self, boost_enum: &PokemonBoostableStat) -> i8 {
1151        match boost_enum {
1152            PokemonBoostableStat::Attack => self.attack_boost,
1153            PokemonBoostableStat::Defense => self.defense_boost,
1154            PokemonBoostableStat::SpecialAttack => self.special_attack_boost,
1155            PokemonBoostableStat::SpecialDefense => self.special_defense_boost,
1156            PokemonBoostableStat::Speed => self.speed_boost,
1157            PokemonBoostableStat::Evasion => self.evasion_boost,
1158            PokemonBoostableStat::Accuracy => self.accuracy_boost,
1159        }
1160    }
1161
1162    pub fn calculate_boosted_stat(&self, stat: PokemonBoostableStat) -> i16 {
1163        /*
1164        In Gen4, simple doubles the effective boost, without it visually being doubled
1165        It will not boost beyond an effective value of 6 though.
1166        */
1167        let active = self.get_active_immutable();
1168        match stat {
1169            PokemonBoostableStat::Attack => {
1170                #[cfg(feature = "gen4")]
1171                let boost = if active.ability == Abilities::SIMPLE {
1172                    (self.attack_boost * 2).min(6).max(-6)
1173                } else {
1174                    self.attack_boost
1175                };
1176
1177                #[cfg(not(feature = "gen4"))]
1178                let boost = self.attack_boost;
1179
1180                multiply_boost(boost, active.attack)
1181            }
1182            PokemonBoostableStat::Defense => {
1183                #[cfg(feature = "gen4")]
1184                let boost = if active.ability == Abilities::SIMPLE {
1185                    (self.defense_boost * 2).min(6).max(-6)
1186                } else {
1187                    self.defense_boost
1188                };
1189                #[cfg(not(feature = "gen4"))]
1190                let boost = self.defense_boost;
1191
1192                multiply_boost(boost, active.defense)
1193            }
1194            PokemonBoostableStat::SpecialAttack => {
1195                #[cfg(feature = "gen4")]
1196                let boost = if active.ability == Abilities::SIMPLE {
1197                    (self.special_attack_boost * 2).min(6).max(-6)
1198                } else {
1199                    self.special_attack_boost
1200                };
1201                #[cfg(not(feature = "gen4"))]
1202                let boost = self.special_attack_boost;
1203
1204                multiply_boost(boost, active.special_attack)
1205            }
1206            PokemonBoostableStat::SpecialDefense => {
1207                #[cfg(feature = "gen4")]
1208                let boost = if active.ability == Abilities::SIMPLE {
1209                    (self.special_defense_boost * 2).min(6).max(-6)
1210                } else {
1211                    self.special_defense_boost
1212                };
1213                #[cfg(not(feature = "gen4"))]
1214                let boost = self.special_defense_boost;
1215
1216                multiply_boost(boost, active.special_defense)
1217            }
1218            PokemonBoostableStat::Speed => {
1219                #[cfg(feature = "gen4")]
1220                let boost = if active.ability == Abilities::SIMPLE {
1221                    (self.speed_boost * 2).min(6).max(-6)
1222                } else {
1223                    self.speed_boost
1224                };
1225                #[cfg(not(feature = "gen4"))]
1226                let boost = self.speed_boost;
1227
1228                multiply_boost(boost, active.speed)
1229            }
1230            _ => {
1231                panic!("Not implemented")
1232            }
1233        }
1234    }
1235
1236    pub fn has_alive_non_rested_sleeping_pkmn(&self) -> bool {
1237        for p in self.pokemon.into_iter() {
1238            if p.status == PokemonStatus::SLEEP && p.hp > 0 && p.rest_turns == 0 {
1239                return true;
1240            }
1241        }
1242        false
1243    }
1244
1245    #[cfg(not(feature = "terastallization"))]
1246    pub fn can_use_tera(&self) -> bool {
1247        false
1248    }
1249
1250    #[cfg(feature = "terastallization")]
1251    pub fn can_use_tera(&self) -> bool {
1252        for p in self.pokemon.into_iter() {
1253            if p.terastallized {
1254                return false;
1255            }
1256        }
1257        true
1258    }
1259
1260    fn toggle_force_switch(&mut self) {
1261        self.force_switch = !self.force_switch;
1262    }
1263
1264    pub fn add_switches(&self, vec: &mut Vec<MoveChoice>) {
1265        let mut iter = self.pokemon.into_iter();
1266        while let Some(p) = iter.next() {
1267            if p.hp > 0 && iter.pokemon_index != self.active_index {
1268                vec.push(MoveChoice::Switch(iter.pokemon_index));
1269            }
1270        }
1271        if vec.len() == 0 {
1272            vec.push(MoveChoice::None);
1273        }
1274    }
1275
1276    pub fn trapped(&self, opponent_active: &Pokemon) -> bool {
1277        let active_pkmn = self.get_active_immutable();
1278        if self
1279            .volatile_statuses
1280            .contains(&PokemonVolatileStatus::LOCKEDMOVE)
1281        {
1282            return true;
1283        }
1284        if active_pkmn.item == Items::SHEDSHELL || active_pkmn.has_type(&PokemonType::GHOST) {
1285            return false;
1286        } else if self
1287            .volatile_statuses
1288            .contains(&PokemonVolatileStatus::PARTIALLYTRAPPED)
1289        {
1290            return true;
1291        } else if opponent_active.ability == Abilities::SHADOWTAG {
1292            return true;
1293        } else if opponent_active.ability == Abilities::ARENATRAP && active_pkmn.is_grounded() {
1294            return true;
1295        } else if opponent_active.ability == Abilities::MAGNETPULL
1296            && active_pkmn.has_type(&PokemonType::STEEL)
1297        {
1298            return true;
1299        }
1300        false
1301    }
1302
1303    pub fn get_active(&mut self) -> &mut Pokemon {
1304        &mut self.pokemon[self.active_index]
1305    }
1306
1307    pub fn get_active_immutable(&self) -> &Pokemon {
1308        &self.pokemon[self.active_index]
1309    }
1310
1311    pub fn num_fainted_pkmn(&self) -> i8 {
1312        let mut count = 0;
1313        for p in self.pokemon.into_iter() {
1314            if p.hp == 0 {
1315                count += 1;
1316            }
1317        }
1318        count
1319    }
1320
1321    pub fn visible_alive_pkmn(&self) -> i8 {
1322        let mut count = 0;
1323        for p in self.pokemon.into_iter() {
1324            if p.hp > 0 {
1325                count += 1;
1326            }
1327        }
1328        count
1329    }
1330
1331    pub fn get_alive_pkmn_indices(&self) -> Vec<PokemonIndex> {
1332        let mut vec = Vec::with_capacity(6);
1333        let mut iter = self.pokemon.into_iter();
1334
1335        while let Some(p) = iter.next() {
1336            if p.hp > 0 && iter.pokemon_index != self.active_index {
1337                vec.push(iter.pokemon_index.clone());
1338            }
1339        }
1340
1341        vec
1342    }
1343
1344    pub fn get_side_condition(&self, side_condition: PokemonSideCondition) -> i8 {
1345        match side_condition {
1346            PokemonSideCondition::AuroraVeil => self.side_conditions.aurora_veil,
1347            PokemonSideCondition::CraftyShield => self.side_conditions.crafty_shield,
1348            PokemonSideCondition::HealingWish => self.side_conditions.healing_wish,
1349            PokemonSideCondition::LightScreen => self.side_conditions.light_screen,
1350            PokemonSideCondition::LuckyChant => self.side_conditions.lucky_chant,
1351            PokemonSideCondition::LunarDance => self.side_conditions.lunar_dance,
1352            PokemonSideCondition::MatBlock => self.side_conditions.mat_block,
1353            PokemonSideCondition::Mist => self.side_conditions.mist,
1354            PokemonSideCondition::Protect => self.side_conditions.protect,
1355            PokemonSideCondition::QuickGuard => self.side_conditions.quick_guard,
1356            PokemonSideCondition::Reflect => self.side_conditions.reflect,
1357            PokemonSideCondition::Safeguard => self.side_conditions.safeguard,
1358            PokemonSideCondition::Spikes => self.side_conditions.spikes,
1359            PokemonSideCondition::Stealthrock => self.side_conditions.stealth_rock,
1360            PokemonSideCondition::StickyWeb => self.side_conditions.sticky_web,
1361            PokemonSideCondition::Tailwind => self.side_conditions.tailwind,
1362            PokemonSideCondition::ToxicCount => self.side_conditions.toxic_count,
1363            PokemonSideCondition::ToxicSpikes => self.side_conditions.toxic_spikes,
1364            PokemonSideCondition::WideGuard => self.side_conditions.wide_guard,
1365        }
1366    }
1367
1368    pub fn update_side_condition(&mut self, side_condition: PokemonSideCondition, amount: i8) {
1369        match side_condition {
1370            PokemonSideCondition::AuroraVeil => self.side_conditions.aurora_veil += amount,
1371            PokemonSideCondition::CraftyShield => self.side_conditions.crafty_shield += amount,
1372            PokemonSideCondition::HealingWish => self.side_conditions.healing_wish += amount,
1373            PokemonSideCondition::LightScreen => self.side_conditions.light_screen += amount,
1374            PokemonSideCondition::LuckyChant => self.side_conditions.lucky_chant += amount,
1375            PokemonSideCondition::LunarDance => self.side_conditions.lunar_dance += amount,
1376            PokemonSideCondition::MatBlock => self.side_conditions.mat_block += amount,
1377            PokemonSideCondition::Mist => self.side_conditions.mist += amount,
1378            PokemonSideCondition::Protect => self.side_conditions.protect += amount,
1379            PokemonSideCondition::QuickGuard => self.side_conditions.quick_guard += amount,
1380            PokemonSideCondition::Reflect => self.side_conditions.reflect += amount,
1381            PokemonSideCondition::Safeguard => self.side_conditions.safeguard += amount,
1382            PokemonSideCondition::Spikes => self.side_conditions.spikes += amount,
1383            PokemonSideCondition::Stealthrock => self.side_conditions.stealth_rock += amount,
1384            PokemonSideCondition::StickyWeb => self.side_conditions.sticky_web += amount,
1385            PokemonSideCondition::Tailwind => self.side_conditions.tailwind += amount,
1386            PokemonSideCondition::ToxicCount => self.side_conditions.toxic_count += amount,
1387            PokemonSideCondition::ToxicSpikes => self.side_conditions.toxic_spikes += amount,
1388            PokemonSideCondition::WideGuard => self.side_conditions.wide_guard += amount,
1389        }
1390    }
1391}
1392
1393impl Default for Side {
1394    fn default() -> Side {
1395        Side {
1396            active_index: PokemonIndex::P0,
1397            baton_passing: false,
1398            pokemon: SidePokemon {
1399                p0: Pokemon {
1400                    ..Pokemon::default()
1401                },
1402                p1: Pokemon {
1403                    ..Pokemon::default()
1404                },
1405                p2: Pokemon {
1406                    ..Pokemon::default()
1407                },
1408                p3: Pokemon {
1409                    ..Pokemon::default()
1410                },
1411                p4: Pokemon {
1412                    ..Pokemon::default()
1413                },
1414                p5: Pokemon {
1415                    ..Pokemon::default()
1416                },
1417            },
1418            substitute_health: 0,
1419            attack_boost: 0,
1420            defense_boost: 0,
1421            special_attack_boost: 0,
1422            special_defense_boost: 0,
1423            speed_boost: 0,
1424            accuracy_boost: 0,
1425            side_conditions: SideConditions {
1426                ..Default::default()
1427            },
1428            volatile_status_durations: VolatileStatusDurations::default(),
1429            volatile_statuses: HashSet::<PokemonVolatileStatus>::new(),
1430            wish: (0, 0),
1431            future_sight: (0, PokemonIndex::P0),
1432            force_switch: false,
1433            slow_uturn_move: false,
1434            force_trapped: false,
1435            last_used_move: LastUsedMove::None,
1436            damage_dealt: DamageDealt::default(),
1437            switch_out_move_second_saved_move: Choices::NONE,
1438            evasion_boost: 0,
1439        }
1440    }
1441}
1442
1443#[derive(Debug, Clone)]
1444pub struct State {
1445    pub side_one: Side,
1446    pub side_two: Side,
1447    pub weather: StateWeather,
1448    pub terrain: StateTerrain,
1449    pub trick_room: StateTrickRoom,
1450    pub team_preview: bool,
1451    pub use_last_used_move: bool,
1452    pub use_damage_dealt: bool,
1453}
1454
1455impl Default for State {
1456    fn default() -> State {
1457        let mut s = State {
1458            side_one: Side::default(),
1459            side_two: Side::default(),
1460            weather: StateWeather {
1461                weather_type: Weather::NONE,
1462                turns_remaining: -1,
1463            },
1464            terrain: StateTerrain {
1465                terrain_type: Terrain::NONE,
1466                turns_remaining: 0,
1467            },
1468            trick_room: StateTrickRoom {
1469                active: false,
1470                turns_remaining: 0,
1471            },
1472            team_preview: false,
1473            use_damage_dealt: false,
1474            use_last_used_move: false,
1475        };
1476
1477        // many tests rely on the speed of side 2's active pokemon being greater than side_one's
1478        s.side_two.get_active().speed += 1;
1479        s
1480    }
1481}
1482
1483impl State {
1484    pub fn battle_is_over(&self) -> f32 {
1485        //  0 if battle is not over
1486        //  1 if side one has won
1487        // -1 if side two has won
1488        if self.side_one.pokemon.into_iter().all(|p| p.hp <= 0) {
1489            return -1.0;
1490        }
1491        if self.side_two.pokemon.into_iter().all(|p| p.hp <= 0) {
1492            return 1.0;
1493        }
1494        0.0
1495    }
1496
1497    pub fn get_all_options(&self) -> (Vec<MoveChoice>, Vec<MoveChoice>) {
1498        let mut side_one_options: Vec<MoveChoice> = Vec::with_capacity(9);
1499        let mut side_two_options: Vec<MoveChoice> = Vec::with_capacity(9);
1500
1501        let side_one_active = self.side_one.get_active_immutable();
1502        let side_two_active = self.side_two.get_active_immutable();
1503
1504        if self.side_one.force_switch {
1505            self.side_one.add_switches(&mut side_one_options);
1506            if self.side_two.switch_out_move_second_saved_move == Choices::NONE {
1507                side_two_options.push(MoveChoice::None);
1508            } else {
1509                self.side_two.get_active_immutable().add_move_from_choice(
1510                    &mut side_two_options,
1511                    self.side_two.switch_out_move_second_saved_move,
1512                );
1513            }
1514            return (side_one_options, side_two_options);
1515        }
1516
1517        if self.side_two.force_switch {
1518            self.side_two.add_switches(&mut side_two_options);
1519            if self.side_one.switch_out_move_second_saved_move == Choices::NONE {
1520                side_one_options.push(MoveChoice::None);
1521            } else {
1522                self.side_one.get_active_immutable().add_move_from_choice(
1523                    &mut side_one_options,
1524                    self.side_one.switch_out_move_second_saved_move,
1525                );
1526            }
1527            return (side_one_options, side_two_options);
1528        }
1529
1530        let side_one_force_switch = self.side_one.get_active_immutable().hp <= 0;
1531        let side_two_force_switch = self.side_two.get_active_immutable().hp <= 0;
1532
1533        if side_one_force_switch && side_two_force_switch {
1534            self.side_one.add_switches(&mut side_one_options);
1535            self.side_two.add_switches(&mut side_two_options);
1536            return (side_one_options, side_two_options);
1537        }
1538        if side_one_force_switch {
1539            self.side_one.add_switches(&mut side_one_options);
1540            side_two_options.push(MoveChoice::None);
1541            return (side_one_options, side_two_options);
1542        }
1543        if side_two_force_switch {
1544            side_one_options.push(MoveChoice::None);
1545            self.side_two.add_switches(&mut side_two_options);
1546            return (side_one_options, side_two_options);
1547        }
1548
1549        if self
1550            .side_one
1551            .volatile_statuses
1552            .contains(&PokemonVolatileStatus::MUSTRECHARGE)
1553        {
1554            side_one_options.push(MoveChoice::None);
1555        } else {
1556            let encored = self
1557                .side_one
1558                .volatile_statuses
1559                .contains(&PokemonVolatileStatus::ENCORE);
1560            self.side_one.get_active_immutable().add_available_moves(
1561                &mut side_one_options,
1562                &self.side_one.last_used_move,
1563                encored,
1564                self.side_one.can_use_tera(),
1565            );
1566            if !self.side_one.trapped(side_two_active) {
1567                self.side_one.add_switches(&mut side_one_options);
1568            }
1569        }
1570
1571        if self
1572            .side_two
1573            .volatile_statuses
1574            .contains(&PokemonVolatileStatus::MUSTRECHARGE)
1575        {
1576            side_two_options.push(MoveChoice::None);
1577        } else {
1578            let encored = self
1579                .side_two
1580                .volatile_statuses
1581                .contains(&PokemonVolatileStatus::ENCORE);
1582            self.side_two.get_active_immutable().add_available_moves(
1583                &mut side_two_options,
1584                &self.side_two.last_used_move,
1585                encored,
1586                self.side_two.can_use_tera(),
1587            );
1588            if !self.side_two.trapped(side_one_active) {
1589                self.side_two.add_switches(&mut side_two_options);
1590            }
1591        }
1592
1593        if side_one_options.len() == 0 {
1594            side_one_options.push(MoveChoice::None);
1595        }
1596        if side_two_options.len() == 0 {
1597            side_two_options.push(MoveChoice::None);
1598        }
1599
1600        (side_one_options, side_two_options)
1601    }
1602
1603    pub fn get_side(&mut self, side_ref: &SideReference) -> &mut Side {
1604        match side_ref {
1605            SideReference::SideOne => &mut self.side_one,
1606            SideReference::SideTwo => &mut self.side_two,
1607        }
1608    }
1609
1610    pub fn get_side_immutable(&self, side_ref: &SideReference) -> &Side {
1611        match side_ref {
1612            SideReference::SideOne => &self.side_one,
1613            SideReference::SideTwo => &self.side_two,
1614        }
1615    }
1616
1617    pub fn get_both_sides(&mut self, side_ref: &SideReference) -> (&mut Side, &mut Side) {
1618        match side_ref {
1619            SideReference::SideOne => (&mut self.side_one, &mut self.side_two),
1620            SideReference::SideTwo => (&mut self.side_two, &mut self.side_one),
1621        }
1622    }
1623
1624    pub fn get_both_sides_immutable(&self, side_ref: &SideReference) -> (&Side, &Side) {
1625        match side_ref {
1626            SideReference::SideOne => (&self.side_one, &self.side_two),
1627            SideReference::SideTwo => (&self.side_two, &self.side_one),
1628        }
1629    }
1630
1631    pub fn re_enable_disabled_moves(
1632        &mut self,
1633        side_ref: &SideReference,
1634        vec_to_add_to: &mut Vec<Instruction>,
1635    ) {
1636        let active = self.get_side(side_ref).get_active();
1637        if active.moves.m0.disabled {
1638            active.moves.m0.disabled = false;
1639            vec_to_add_to.push(Instruction::EnableMove(EnableMoveInstruction {
1640                side_ref: *side_ref,
1641                move_index: PokemonMoveIndex::M0,
1642            }));
1643        }
1644        if active.moves.m1.disabled {
1645            active.moves.m1.disabled = false;
1646            vec_to_add_to.push(Instruction::EnableMove(EnableMoveInstruction {
1647                side_ref: *side_ref,
1648                move_index: PokemonMoveIndex::M1,
1649            }));
1650        }
1651        if active.moves.m2.disabled {
1652            active.moves.m2.disabled = false;
1653            vec_to_add_to.push(Instruction::EnableMove(EnableMoveInstruction {
1654                side_ref: *side_ref,
1655                move_index: PokemonMoveIndex::M2,
1656            }));
1657        }
1658        if active.moves.m3.disabled {
1659            active.moves.m3.disabled = false;
1660            vec_to_add_to.push(Instruction::EnableMove(EnableMoveInstruction {
1661                side_ref: *side_ref,
1662                move_index: PokemonMoveIndex::M3,
1663            }));
1664        }
1665    }
1666
1667    pub fn reset_toxic_count(
1668        &mut self,
1669        side_ref: &SideReference,
1670        vec_to_add_to: &mut Vec<Instruction>,
1671    ) {
1672        let side = self.get_side(side_ref);
1673        if side.side_conditions.toxic_count > 0 {
1674            vec_to_add_to.push(Instruction::ChangeSideCondition(
1675                ChangeSideConditionInstruction {
1676                    side_ref: *side_ref,
1677                    side_condition: PokemonSideCondition::ToxicCount,
1678                    amount: -1 * side.side_conditions.toxic_count,
1679                },
1680            ));
1681            side.side_conditions.toxic_count = 0;
1682        }
1683    }
1684
1685    pub fn remove_volatile_statuses_on_switch(
1686        &mut self,
1687        side_ref: &SideReference,
1688        instructions: &mut Vec<Instruction>,
1689        baton_passing: bool,
1690    ) {
1691        let side = self.get_side(side_ref);
1692
1693        // Take ownership of the current set to avoid borrow conflicts
1694        // since we may need to modify the side in the loop
1695        let mut volatile_statuses = std::mem::take(&mut side.volatile_statuses);
1696
1697        volatile_statuses.retain(|pkmn_volatile_status| {
1698            let should_retain = match pkmn_volatile_status {
1699                PokemonVolatileStatus::SUBSTITUTE => baton_passing,
1700                PokemonVolatileStatus::LEECHSEED => baton_passing,
1701                PokemonVolatileStatus::TYPECHANGE => {
1702                    let active = side.get_active();
1703                    if active.base_types != active.types {
1704                        instructions.push(Instruction::ChangeType(ChangeType {
1705                            side_ref: *side_ref,
1706                            new_types: active.base_types,
1707                            old_types: active.types,
1708                        }));
1709                        active.types = active.base_types;
1710                    }
1711                    false
1712                }
1713                // While you can't switch out of a locked move you can be forced out in other ways
1714                PokemonVolatileStatus::LOCKEDMOVE => {
1715                    instructions.push(Instruction::ChangeVolatileStatusDuration(
1716                        ChangeVolatileStatusDurationInstruction {
1717                            side_ref: *side_ref,
1718                            volatile_status: *pkmn_volatile_status,
1719                            amount: -1 * side.volatile_status_durations.lockedmove,
1720                        },
1721                    ));
1722                    side.volatile_status_durations.lockedmove = 0;
1723                    false
1724                }
1725                _ => false,
1726            };
1727
1728            if !should_retain {
1729                instructions.push(Instruction::RemoveVolatileStatus(
1730                    RemoveVolatileStatusInstruction {
1731                        side_ref: *side_ref,
1732                        volatile_status: *pkmn_volatile_status,
1733                    },
1734                ));
1735            }
1736            should_retain
1737        });
1738
1739        // Clean up by re-setting the volatile statuses
1740        side.volatile_statuses = volatile_statuses;
1741    }
1742
1743    pub fn reset_boosts(&mut self, side_ref: &SideReference, vec_to_add_to: &mut Vec<Instruction>) {
1744        let side = self.get_side(side_ref);
1745
1746        if side.attack_boost != 0 {
1747            vec_to_add_to.push(Instruction::Boost(BoostInstruction {
1748                side_ref: *side_ref,
1749                stat: PokemonBoostableStat::Attack,
1750                amount: -1 * side.attack_boost,
1751            }));
1752            side.attack_boost = 0;
1753        }
1754
1755        if side.defense_boost != 0 {
1756            vec_to_add_to.push(Instruction::Boost(BoostInstruction {
1757                side_ref: *side_ref,
1758                stat: PokemonBoostableStat::Defense,
1759                amount: -1 * side.defense_boost,
1760            }));
1761            side.defense_boost = 0;
1762        }
1763
1764        if side.special_attack_boost != 0 {
1765            vec_to_add_to.push(Instruction::Boost(BoostInstruction {
1766                side_ref: *side_ref,
1767                stat: PokemonBoostableStat::SpecialAttack,
1768                amount: -1 * side.special_attack_boost,
1769            }));
1770            side.special_attack_boost = 0;
1771        }
1772
1773        if side.special_defense_boost != 0 {
1774            vec_to_add_to.push(Instruction::Boost(BoostInstruction {
1775                side_ref: *side_ref,
1776                stat: PokemonBoostableStat::SpecialDefense,
1777                amount: -1 * side.special_defense_boost,
1778            }));
1779            side.special_defense_boost = 0;
1780        }
1781
1782        if side.speed_boost != 0 {
1783            vec_to_add_to.push(Instruction::Boost(BoostInstruction {
1784                side_ref: *side_ref,
1785                stat: PokemonBoostableStat::Speed,
1786                amount: -1 * side.speed_boost,
1787            }));
1788            side.speed_boost = 0;
1789        }
1790
1791        if side.evasion_boost != 0 {
1792            vec_to_add_to.push(Instruction::Boost(BoostInstruction {
1793                side_ref: *side_ref,
1794                stat: PokemonBoostableStat::Evasion,
1795                amount: -1 * side.evasion_boost,
1796            }));
1797            side.evasion_boost = 0;
1798        }
1799
1800        if side.accuracy_boost != 0 {
1801            vec_to_add_to.push(Instruction::Boost(BoostInstruction {
1802                side_ref: *side_ref,
1803                stat: PokemonBoostableStat::Accuracy,
1804                amount: -1 * side.accuracy_boost,
1805            }));
1806            side.accuracy_boost = 0;
1807        }
1808    }
1809
1810    pub fn terrain_is_active(&self, terrain: &Terrain) -> bool {
1811        &self.terrain.terrain_type == terrain && self.terrain.turns_remaining > 0
1812    }
1813
1814    pub fn weather_is_active(&self, weather: &Weather) -> bool {
1815        let s1_active = self.side_one.get_active_immutable();
1816        let s2_active = self.side_two.get_active_immutable();
1817        &self.weather.weather_type == weather
1818            && s1_active.ability != Abilities::AIRLOCK
1819            && s1_active.ability != Abilities::CLOUDNINE
1820            && s2_active.ability != Abilities::AIRLOCK
1821            && s2_active.ability != Abilities::CLOUDNINE
1822    }
1823
1824    fn _state_contains_any_move(&self, moves: &[Choices]) -> bool {
1825        for s in [&self.side_one, &self.side_two] {
1826            for pkmn in s.pokemon.into_iter() {
1827                for mv in pkmn.moves.into_iter() {
1828                    if moves.contains(&mv.id) {
1829                        return true;
1830                    }
1831                }
1832            }
1833        }
1834
1835        false
1836    }
1837
1838    pub fn set_damage_dealt_flag(&mut self) {
1839        if self._state_contains_any_move(&[
1840            Choices::COUNTER,
1841            Choices::MIRRORCOAT,
1842            Choices::METALBURST,
1843            Choices::COMEUPPANCE,
1844            Choices::FOCUSPUNCH,
1845        ]) {
1846            self.use_damage_dealt = true
1847        }
1848    }
1849
1850    pub fn set_last_used_move_flag(&mut self) {
1851        if self._state_contains_any_move(&[
1852            Choices::ENCORE,
1853            Choices::FAKEOUT,
1854            Choices::FIRSTIMPRESSION,
1855            Choices::BLOODMOON,
1856            Choices::GIGATONHAMMER,
1857        ]) {
1858            self.use_last_used_move = true
1859        }
1860    }
1861
1862    pub fn set_conditional_mechanics(&mut self) {
1863        /*
1864        These mechanics are not always relevant but when they are it
1865        is important that they are enabled. Enabling them all the time would
1866        suffer about a 20% performance hit.
1867        */
1868        self.set_damage_dealt_flag();
1869        self.set_last_used_move_flag();
1870    }
1871
1872    fn damage(&mut self, side_ref: &SideReference, amount: i16) {
1873        let active = self.get_side(&side_ref).get_active();
1874
1875        active.hp -= amount;
1876    }
1877
1878    fn heal(&mut self, side_ref: &SideReference, amount: i16) {
1879        let active = self.get_side(&side_ref).get_active();
1880
1881        active.hp += amount;
1882    }
1883
1884    fn switch(
1885        &mut self,
1886        side_ref: &SideReference,
1887        next_active_index: PokemonIndex,
1888        _: PokemonIndex,
1889    ) {
1890        let side = self.get_side(&side_ref);
1891        side.active_index = next_active_index;
1892    }
1893
1894    fn reverse_switch(
1895        &mut self,
1896        side_ref: &SideReference,
1897        _: PokemonIndex,
1898        previous_active_index: PokemonIndex,
1899    ) {
1900        let side = self.get_side(&side_ref);
1901        side.active_index = previous_active_index;
1902    }
1903
1904    fn apply_volatile_status(
1905        &mut self,
1906        side_ref: &SideReference,
1907        volatile_status: PokemonVolatileStatus,
1908    ) {
1909        self.get_side(&side_ref)
1910            .volatile_statuses
1911            .insert(volatile_status);
1912    }
1913
1914    fn remove_volatile_status(
1915        &mut self,
1916        side_ref: &SideReference,
1917        volatile_status: PokemonVolatileStatus,
1918    ) {
1919        self.get_side(&side_ref)
1920            .volatile_statuses
1921            .remove(&volatile_status);
1922    }
1923
1924    fn change_status(
1925        &mut self,
1926        side_ref: &SideReference,
1927        pokemon_index: PokemonIndex,
1928        new_status: PokemonStatus,
1929    ) {
1930        let pkmn = &mut self.get_side(&side_ref).pokemon[pokemon_index];
1931        pkmn.status = new_status;
1932    }
1933
1934    fn apply_boost(&mut self, side_ref: &SideReference, stat: &PokemonBoostableStat, amount: i8) {
1935        let side = self.get_side(&side_ref);
1936        match stat {
1937            PokemonBoostableStat::Attack => side.attack_boost += amount,
1938            PokemonBoostableStat::Defense => side.defense_boost += amount,
1939            PokemonBoostableStat::SpecialAttack => side.special_attack_boost += amount,
1940            PokemonBoostableStat::SpecialDefense => side.special_defense_boost += amount,
1941            PokemonBoostableStat::Speed => side.speed_boost += amount,
1942            PokemonBoostableStat::Evasion => side.evasion_boost += amount,
1943            PokemonBoostableStat::Accuracy => side.accuracy_boost += amount,
1944        }
1945    }
1946
1947    fn increment_side_condition(
1948        &mut self,
1949        side_ref: &SideReference,
1950        side_condition: &PokemonSideCondition,
1951        amount: i8,
1952    ) {
1953        let side = self.get_side(&side_ref);
1954
1955        match side_condition {
1956            PokemonSideCondition::AuroraVeil => side.side_conditions.aurora_veil += amount,
1957            PokemonSideCondition::CraftyShield => side.side_conditions.crafty_shield += amount,
1958            PokemonSideCondition::HealingWish => side.side_conditions.healing_wish += amount,
1959            PokemonSideCondition::LightScreen => side.side_conditions.light_screen += amount,
1960            PokemonSideCondition::LuckyChant => side.side_conditions.lucky_chant += amount,
1961            PokemonSideCondition::LunarDance => side.side_conditions.lunar_dance += amount,
1962            PokemonSideCondition::MatBlock => side.side_conditions.mat_block += amount,
1963            PokemonSideCondition::Mist => side.side_conditions.mist += amount,
1964            PokemonSideCondition::Protect => side.side_conditions.protect += amount,
1965            PokemonSideCondition::QuickGuard => side.side_conditions.quick_guard += amount,
1966            PokemonSideCondition::Reflect => side.side_conditions.reflect += amount,
1967            PokemonSideCondition::Safeguard => side.side_conditions.safeguard += amount,
1968            PokemonSideCondition::Spikes => side.side_conditions.spikes += amount,
1969            PokemonSideCondition::Stealthrock => side.side_conditions.stealth_rock += amount,
1970            PokemonSideCondition::StickyWeb => side.side_conditions.sticky_web += amount,
1971            PokemonSideCondition::Tailwind => side.side_conditions.tailwind += amount,
1972            PokemonSideCondition::ToxicCount => side.side_conditions.toxic_count += amount,
1973            PokemonSideCondition::ToxicSpikes => side.side_conditions.toxic_spikes += amount,
1974            PokemonSideCondition::WideGuard => side.side_conditions.wide_guard += amount,
1975        }
1976    }
1977
1978    fn increment_volatile_status_duration(
1979        &mut self,
1980        side_ref: &SideReference,
1981        volatile_status: &PokemonVolatileStatus,
1982        amount: i8,
1983    ) {
1984        let side = self.get_side(&side_ref);
1985        match volatile_status {
1986            PokemonVolatileStatus::CONFUSION => {
1987                side.volatile_status_durations.confusion += amount;
1988            }
1989            PokemonVolatileStatus::LOCKEDMOVE => {
1990                side.volatile_status_durations.lockedmove += amount;
1991            }
1992            PokemonVolatileStatus::ENCORE => {
1993                side.volatile_status_durations.encore += amount;
1994            }
1995            _ => panic!(
1996                "Invalid volatile status for increment_volatile_status_duration: {:?}",
1997                volatile_status
1998            ),
1999        }
2000    }
2001
2002    fn change_types(
2003        &mut self,
2004        side_reference: &SideReference,
2005        new_types: (PokemonType, PokemonType),
2006    ) {
2007        self.get_side(side_reference).get_active().types = new_types;
2008    }
2009
2010    fn change_item(&mut self, side_reference: &SideReference, new_item: Items) {
2011        self.get_side(side_reference).get_active().item = new_item;
2012    }
2013
2014    fn change_weather(&mut self, weather_type: Weather, turns_remaining: i8) {
2015        self.weather.weather_type = weather_type;
2016        self.weather.turns_remaining = turns_remaining;
2017    }
2018
2019    fn change_terrain(&mut self, terrain_type: Terrain, turns_remaining: i8) {
2020        self.terrain.terrain_type = terrain_type;
2021        self.terrain.turns_remaining = turns_remaining;
2022    }
2023
2024    fn enable_move(&mut self, side_reference: &SideReference, move_index: &PokemonMoveIndex) {
2025        self.get_side(side_reference).get_active().moves[move_index].disabled = false;
2026    }
2027
2028    fn disable_move(&mut self, side_reference: &SideReference, move_index: &PokemonMoveIndex) {
2029        self.get_side(side_reference).get_active().moves[move_index].disabled = true;
2030    }
2031
2032    fn set_wish(&mut self, side_reference: &SideReference, wish_amount_change: i16) {
2033        self.get_side(side_reference).wish.0 = 2;
2034        self.get_side(side_reference).wish.1 += wish_amount_change;
2035    }
2036
2037    fn unset_wish(&mut self, side_reference: &SideReference, wish_amount_change: i16) {
2038        self.get_side(side_reference).wish.0 = 0;
2039        self.get_side(side_reference).wish.1 -= wish_amount_change;
2040    }
2041
2042    fn increment_wish(&mut self, side_reference: &SideReference) {
2043        self.get_side(side_reference).wish.0 += 1;
2044    }
2045
2046    fn decrement_wish(&mut self, side_reference: &SideReference) {
2047        self.get_side(side_reference).wish.0 -= 1;
2048    }
2049
2050    fn set_future_sight(&mut self, side_reference: &SideReference, pokemon_index: PokemonIndex) {
2051        let side = self.get_side(side_reference);
2052        side.future_sight.0 = 3;
2053        side.future_sight.1 = pokemon_index;
2054    }
2055
2056    fn unset_future_sight(
2057        &mut self,
2058        side_reference: &SideReference,
2059        previous_pokemon_index: PokemonIndex,
2060    ) {
2061        let side = self.get_side(side_reference);
2062        side.future_sight.0 = 0;
2063        side.future_sight.1 = previous_pokemon_index;
2064    }
2065
2066    fn increment_future_sight(&mut self, side_reference: &SideReference) {
2067        self.get_side(side_reference).future_sight.0 += 1;
2068    }
2069
2070    fn decrement_future_sight(&mut self, side_reference: &SideReference) {
2071        self.get_side(side_reference).future_sight.0 -= 1;
2072    }
2073
2074    fn damage_substitute(&mut self, side_reference: &SideReference, amount: i16) {
2075        self.get_side(side_reference).substitute_health -= amount;
2076    }
2077
2078    fn heal_substitute(&mut self, side_reference: &SideReference, amount: i16) {
2079        self.get_side(side_reference).substitute_health += amount;
2080    }
2081
2082    fn set_substitute_health(&mut self, side_reference: &SideReference, amount: i16) {
2083        self.get_side(side_reference).substitute_health += amount;
2084    }
2085
2086    fn decrement_rest_turn(&mut self, side_reference: &SideReference) {
2087        self.get_side(side_reference).get_active().rest_turns -= 1;
2088    }
2089
2090    fn increment_rest_turn(&mut self, side_reference: &SideReference) {
2091        self.get_side(side_reference).get_active().rest_turns += 1;
2092    }
2093
2094    fn set_rest_turn(
2095        &mut self,
2096        side_reference: &SideReference,
2097        pokemon_index: PokemonIndex,
2098        amount: i8,
2099    ) {
2100        self.get_side(side_reference).pokemon[pokemon_index].rest_turns = amount;
2101    }
2102
2103    fn set_sleep_turn(
2104        &mut self,
2105        side_reference: &SideReference,
2106        pokemon_index: PokemonIndex,
2107        amount: i8,
2108    ) {
2109        self.get_side(side_reference).pokemon[pokemon_index].sleep_turns = amount;
2110    }
2111
2112    fn toggle_trickroom(&mut self, new_turns_remaining: i8) {
2113        self.trick_room.active = !self.trick_room.active;
2114        self.trick_room.turns_remaining = new_turns_remaining;
2115    }
2116
2117    fn set_last_used_move(&mut self, side_reference: &SideReference, last_used_move: LastUsedMove) {
2118        match side_reference {
2119            SideReference::SideOne => self.side_one.last_used_move = last_used_move,
2120            SideReference::SideTwo => self.side_two.last_used_move = last_used_move,
2121        }
2122    }
2123
2124    fn decrement_pp(
2125        &mut self,
2126        side_reference: &SideReference,
2127        move_index: &PokemonMoveIndex,
2128        amount: &i8,
2129    ) {
2130        match side_reference {
2131            SideReference::SideOne => self.side_one.get_active().moves[move_index].pp -= amount,
2132            SideReference::SideTwo => self.side_two.get_active().moves[move_index].pp -= amount,
2133        }
2134    }
2135
2136    fn increment_pp(
2137        &mut self,
2138        side_reference: &SideReference,
2139        move_index: &PokemonMoveIndex,
2140        amount: &i8,
2141    ) {
2142        match side_reference {
2143            SideReference::SideOne => self.side_one.get_active().moves[move_index].pp += amount,
2144            SideReference::SideTwo => self.side_two.get_active().moves[move_index].pp += amount,
2145        }
2146    }
2147
2148    fn set_damage_dealt(
2149        side: &mut Side,
2150        damage_change: i16,
2151        move_category: MoveCategory,
2152        toggle_hit_substitute: bool,
2153    ) {
2154        side.damage_dealt.damage += damage_change;
2155        side.damage_dealt.move_category = move_category;
2156        if toggle_hit_substitute {
2157            side.damage_dealt.hit_substitute = !side.damage_dealt.hit_substitute;
2158        }
2159    }
2160
2161    pub fn apply_instructions(&mut self, instructions: &Vec<Instruction>) {
2162        for i in instructions {
2163            self.apply_one_instruction(i)
2164        }
2165    }
2166
2167    pub fn apply_one_instruction(&mut self, instruction: &Instruction) {
2168        match instruction {
2169            Instruction::Damage(instruction) => {
2170                self.damage(&instruction.side_ref, instruction.damage_amount)
2171            }
2172            Instruction::Switch(instruction) => self.switch(
2173                &instruction.side_ref,
2174                instruction.next_index,
2175                instruction.previous_index,
2176            ),
2177            Instruction::ApplyVolatileStatus(instruction) => {
2178                self.apply_volatile_status(&instruction.side_ref, instruction.volatile_status)
2179            }
2180            Instruction::RemoveVolatileStatus(instruction) => {
2181                self.remove_volatile_status(&instruction.side_ref, instruction.volatile_status)
2182            }
2183            Instruction::ChangeStatus(instruction) => self.change_status(
2184                &instruction.side_ref,
2185                instruction.pokemon_index,
2186                instruction.new_status,
2187            ),
2188            Instruction::Boost(instruction) => {
2189                self.apply_boost(&instruction.side_ref, &instruction.stat, instruction.amount)
2190            }
2191            Instruction::ChangeSideCondition(instruction) => self.increment_side_condition(
2192                &instruction.side_ref,
2193                &instruction.side_condition,
2194                instruction.amount,
2195            ),
2196            Instruction::ChangeVolatileStatusDuration(instruction) => self
2197                .increment_volatile_status_duration(
2198                    &instruction.side_ref,
2199                    &instruction.volatile_status,
2200                    instruction.amount,
2201                ),
2202            Instruction::ChangeWeather(instruction) => self.change_weather(
2203                instruction.new_weather,
2204                instruction.new_weather_turns_remaining,
2205            ),
2206            Instruction::DecrementWeatherTurnsRemaining => {
2207                self.weather.turns_remaining -= 1;
2208            }
2209            Instruction::ChangeTerrain(instruction) => self.change_terrain(
2210                instruction.new_terrain,
2211                instruction.new_terrain_turns_remaining,
2212            ),
2213            Instruction::DecrementTerrainTurnsRemaining => {
2214                self.terrain.turns_remaining -= 1;
2215            }
2216            Instruction::ChangeType(instruction) => {
2217                self.change_types(&instruction.side_ref, instruction.new_types)
2218            }
2219            Instruction::ChangeAbility(instruction) => {
2220                self.get_side(&instruction.side_ref).get_active().ability =
2221                    instruction.new_ability.clone();
2222            }
2223            Instruction::Heal(instruction) => {
2224                self.heal(&instruction.side_ref, instruction.heal_amount)
2225            }
2226            Instruction::ChangeItem(instruction) => {
2227                self.change_item(&instruction.side_ref, instruction.new_item)
2228            }
2229            Instruction::ChangeAttack(instruction) => {
2230                self.get_side(&instruction.side_ref).get_active().attack += instruction.amount;
2231            }
2232            Instruction::ChangeDefense(instruction) => {
2233                self.get_side(&instruction.side_ref).get_active().defense += instruction.amount;
2234            }
2235            Instruction::ChangeSpecialAttack(instruction) => {
2236                self.get_side(&instruction.side_ref)
2237                    .get_active()
2238                    .special_attack += instruction.amount;
2239            }
2240            Instruction::ChangeSpecialDefense(instruction) => {
2241                self.get_side(&instruction.side_ref)
2242                    .get_active()
2243                    .special_defense += instruction.amount;
2244            }
2245            Instruction::ChangeSpeed(instruction) => {
2246                self.get_side(&instruction.side_ref).get_active().speed += instruction.amount;
2247            }
2248            Instruction::EnableMove(instruction) => {
2249                self.enable_move(&instruction.side_ref, &instruction.move_index)
2250            }
2251            Instruction::DisableMove(instruction) => {
2252                self.disable_move(&instruction.side_ref, &instruction.move_index)
2253            }
2254            Instruction::ChangeWish(instruction) => {
2255                self.set_wish(&instruction.side_ref, instruction.wish_amount_change);
2256            }
2257            Instruction::DecrementWish(instruction) => {
2258                self.decrement_wish(&instruction.side_ref);
2259            }
2260            Instruction::SetFutureSight(instruction) => {
2261                self.set_future_sight(&instruction.side_ref, instruction.pokemon_index);
2262            }
2263            Instruction::DecrementFutureSight(instruction) => {
2264                self.decrement_future_sight(&instruction.side_ref);
2265            }
2266            Instruction::DamageSubstitute(instruction) => {
2267                self.damage_substitute(&instruction.side_ref, instruction.damage_amount);
2268            }
2269            Instruction::ChangeSubstituteHealth(instruction) => {
2270                self.set_substitute_health(&instruction.side_ref, instruction.health_change);
2271            }
2272            Instruction::SetRestTurns(instruction) => {
2273                self.set_rest_turn(
2274                    &instruction.side_ref,
2275                    instruction.pokemon_index,
2276                    instruction.new_turns,
2277                );
2278            }
2279            Instruction::SetSleepTurns(instruction) => {
2280                self.set_sleep_turn(
2281                    &instruction.side_ref,
2282                    instruction.pokemon_index,
2283                    instruction.new_turns,
2284                );
2285            }
2286            Instruction::DecrementRestTurns(instruction) => {
2287                self.decrement_rest_turn(&instruction.side_ref);
2288            }
2289            Instruction::ToggleTrickRoom(instruction) => {
2290                self.toggle_trickroom(instruction.new_trickroom_turns_remaining)
2291            }
2292            Instruction::DecrementTrickRoomTurnsRemaining => {
2293                self.trick_room.turns_remaining -= 1;
2294            }
2295            Instruction::ToggleSideOneForceSwitch => self.side_one.toggle_force_switch(),
2296            Instruction::ToggleSideTwoForceSwitch => self.side_two.toggle_force_switch(),
2297            Instruction::SetSideOneMoveSecondSwitchOutMove(instruction) => {
2298                self.side_one.switch_out_move_second_saved_move = instruction.new_choice;
2299            }
2300            Instruction::SetSideTwoMoveSecondSwitchOutMove(instruction) => {
2301                self.side_two.switch_out_move_second_saved_move = instruction.new_choice;
2302            }
2303            Instruction::ToggleBatonPassing(instruction) => match instruction.side_ref {
2304                SideReference::SideOne => {
2305                    self.side_one.baton_passing = !self.side_one.baton_passing
2306                }
2307                SideReference::SideTwo => {
2308                    self.side_two.baton_passing = !self.side_two.baton_passing
2309                }
2310            },
2311            Instruction::ToggleTerastallized(instruction) => match instruction.side_ref {
2312                SideReference::SideOne => self.side_one.get_active().terastallized ^= true,
2313                SideReference::SideTwo => self.side_two.get_active().terastallized ^= true,
2314            },
2315            Instruction::SetLastUsedMove(instruction) => {
2316                self.set_last_used_move(&instruction.side_ref, instruction.last_used_move)
2317            }
2318            Instruction::SetDamageDealtSideOne(instruction) => State::set_damage_dealt(
2319                &mut self.side_one,
2320                instruction.damage_change,
2321                instruction.move_category,
2322                instruction.toggle_hit_substitute,
2323            ),
2324            Instruction::SetDamageDealtSideTwo(instruction) => State::set_damage_dealt(
2325                &mut self.side_two,
2326                instruction.damage_change,
2327                instruction.move_category,
2328                instruction.toggle_hit_substitute,
2329            ),
2330            Instruction::DecrementPP(instruction) => self.decrement_pp(
2331                &instruction.side_ref,
2332                &instruction.move_index,
2333                &instruction.amount,
2334            ),
2335            Instruction::FormeChange(instruction) => {
2336                self.get_side(&instruction.side_ref).get_active().id = instruction.new_forme;
2337            }
2338        }
2339    }
2340
2341    pub fn reverse_instructions(&mut self, instructions: &Vec<Instruction>) {
2342        for i in instructions.iter().rev() {
2343            self.reverse_one_instruction(i);
2344        }
2345    }
2346
2347    pub fn reverse_one_instruction(&mut self, instruction: &Instruction) {
2348        match instruction {
2349            Instruction::Damage(instruction) => {
2350                self.heal(&instruction.side_ref, instruction.damage_amount)
2351            }
2352            Instruction::Switch(instruction) => self.reverse_switch(
2353                &instruction.side_ref,
2354                instruction.next_index,
2355                instruction.previous_index,
2356            ),
2357            Instruction::ApplyVolatileStatus(instruction) => {
2358                self.remove_volatile_status(&instruction.side_ref, instruction.volatile_status)
2359            }
2360            Instruction::RemoveVolatileStatus(instruction) => {
2361                self.apply_volatile_status(&instruction.side_ref, instruction.volatile_status)
2362            }
2363            Instruction::ChangeStatus(instruction) => self.change_status(
2364                &instruction.side_ref,
2365                instruction.pokemon_index,
2366                instruction.old_status,
2367            ),
2368            Instruction::Boost(instruction) => self.apply_boost(
2369                &instruction.side_ref,
2370                &instruction.stat,
2371                -1 * instruction.amount,
2372            ),
2373            Instruction::ChangeSideCondition(instruction) => self.increment_side_condition(
2374                &instruction.side_ref,
2375                &instruction.side_condition,
2376                -1 * instruction.amount,
2377            ),
2378            Instruction::ChangeVolatileStatusDuration(instruction) => self
2379                .increment_volatile_status_duration(
2380                    &instruction.side_ref,
2381                    &instruction.volatile_status,
2382                    -1 * instruction.amount,
2383                ),
2384            Instruction::ChangeWeather(instruction) => self.change_weather(
2385                instruction.previous_weather,
2386                instruction.previous_weather_turns_remaining,
2387            ),
2388            Instruction::DecrementWeatherTurnsRemaining => {
2389                self.weather.turns_remaining += 1;
2390            }
2391            Instruction::ChangeTerrain(instruction) => self.change_terrain(
2392                instruction.previous_terrain,
2393                instruction.previous_terrain_turns_remaining,
2394            ),
2395            Instruction::DecrementTerrainTurnsRemaining => {
2396                self.terrain.turns_remaining += 1;
2397            }
2398            Instruction::ChangeType(instruction) => {
2399                self.change_types(&instruction.side_ref, instruction.old_types)
2400            }
2401            Instruction::ChangeAbility(instruction) => {
2402                self.get_side(&instruction.side_ref).get_active().ability =
2403                    instruction.old_ability.clone();
2404            }
2405            Instruction::EnableMove(instruction) => {
2406                self.disable_move(&instruction.side_ref, &instruction.move_index)
2407            }
2408            Instruction::DisableMove(instruction) => {
2409                self.enable_move(&instruction.side_ref, &instruction.move_index)
2410            }
2411            Instruction::Heal(instruction) => {
2412                self.damage(&instruction.side_ref, instruction.heal_amount)
2413            }
2414            Instruction::ChangeItem(instruction) => {
2415                self.change_item(&instruction.side_ref, instruction.current_item)
2416            }
2417            Instruction::ChangeAttack(instruction) => {
2418                self.get_side(&instruction.side_ref).get_active().attack -= instruction.amount;
2419            }
2420            Instruction::ChangeDefense(instruction) => {
2421                self.get_side(&instruction.side_ref).get_active().defense -= instruction.amount;
2422            }
2423            Instruction::ChangeSpecialAttack(instruction) => {
2424                self.get_side(&instruction.side_ref)
2425                    .get_active()
2426                    .special_attack -= instruction.amount;
2427            }
2428            Instruction::ChangeSpecialDefense(instruction) => {
2429                self.get_side(&instruction.side_ref)
2430                    .get_active()
2431                    .special_defense -= instruction.amount;
2432            }
2433            Instruction::ChangeSpeed(instruction) => {
2434                self.get_side(&instruction.side_ref).get_active().speed -= instruction.amount;
2435            }
2436            Instruction::ChangeWish(instruction) => {
2437                self.unset_wish(&instruction.side_ref, instruction.wish_amount_change)
2438            }
2439            Instruction::DecrementWish(instruction) => self.increment_wish(&instruction.side_ref),
2440            Instruction::SetFutureSight(instruction) => {
2441                self.unset_future_sight(&instruction.side_ref, instruction.previous_pokemon_index)
2442            }
2443            Instruction::DecrementFutureSight(instruction) => {
2444                self.increment_future_sight(&instruction.side_ref)
2445            }
2446            Instruction::DamageSubstitute(instruction) => {
2447                self.heal_substitute(&instruction.side_ref, instruction.damage_amount);
2448            }
2449            Instruction::ChangeSubstituteHealth(instruction) => {
2450                self.set_substitute_health(&instruction.side_ref, -1 * instruction.health_change);
2451            }
2452            Instruction::SetRestTurns(instruction) => {
2453                self.set_rest_turn(
2454                    &instruction.side_ref,
2455                    instruction.pokemon_index,
2456                    instruction.previous_turns,
2457                );
2458            }
2459            Instruction::SetSleepTurns(instruction) => {
2460                self.set_sleep_turn(
2461                    &instruction.side_ref,
2462                    instruction.pokemon_index,
2463                    instruction.previous_turns,
2464                );
2465            }
2466            Instruction::DecrementRestTurns(instruction) => {
2467                self.increment_rest_turn(&instruction.side_ref);
2468            }
2469            Instruction::ToggleTrickRoom(instruction) => {
2470                self.toggle_trickroom(instruction.previous_trickroom_turns_remaining)
2471            }
2472            Instruction::DecrementTrickRoomTurnsRemaining => {
2473                self.trick_room.turns_remaining += 1;
2474            }
2475            Instruction::ToggleSideOneForceSwitch => self.side_one.toggle_force_switch(),
2476            Instruction::ToggleSideTwoForceSwitch => self.side_two.toggle_force_switch(),
2477            Instruction::SetSideOneMoveSecondSwitchOutMove(instruction) => {
2478                self.side_one.switch_out_move_second_saved_move = instruction.previous_choice;
2479            }
2480            Instruction::SetSideTwoMoveSecondSwitchOutMove(instruction) => {
2481                self.side_two.switch_out_move_second_saved_move = instruction.previous_choice;
2482            }
2483            Instruction::ToggleBatonPassing(instruction) => match instruction.side_ref {
2484                SideReference::SideOne => {
2485                    self.side_one.baton_passing = !self.side_one.baton_passing
2486                }
2487                SideReference::SideTwo => {
2488                    self.side_two.baton_passing = !self.side_two.baton_passing
2489                }
2490            },
2491            Instruction::ToggleTerastallized(instruction) => match instruction.side_ref {
2492                SideReference::SideOne => self.side_one.get_active().terastallized ^= true,
2493                SideReference::SideTwo => self.side_two.get_active().terastallized ^= true,
2494            },
2495            Instruction::SetLastUsedMove(instruction) => {
2496                self.set_last_used_move(&instruction.side_ref, instruction.previous_last_used_move)
2497            }
2498            Instruction::SetDamageDealtSideOne(instruction) => State::set_damage_dealt(
2499                &mut self.side_one,
2500                -1 * instruction.damage_change,
2501                instruction.previous_move_category,
2502                instruction.toggle_hit_substitute,
2503            ),
2504            Instruction::SetDamageDealtSideTwo(instruction) => State::set_damage_dealt(
2505                &mut self.side_two,
2506                -1 * instruction.damage_change,
2507                instruction.previous_move_category,
2508                instruction.toggle_hit_substitute,
2509            ),
2510            Instruction::DecrementPP(instruction) => self.increment_pp(
2511                &instruction.side_ref,
2512                &instruction.move_index,
2513                &instruction.amount,
2514            ),
2515            Instruction::FormeChange(instruction) => {
2516                self.get_side(&instruction.side_ref).get_active().id = instruction.previous_forme;
2517            }
2518        }
2519    }
2520}
2521
2522impl Move {
2523    pub fn serialize(&self) -> String {
2524        format!("{:?};{};{}", self.id, self.disabled, self.pp)
2525    }
2526    pub fn deserialize(serialized: &str) -> Move {
2527        let split: Vec<&str> = serialized.split(";").collect();
2528        Move {
2529            id: Choices::from_str(split[0]).unwrap(),
2530            disabled: split[1].parse::<bool>().unwrap(),
2531            pp: split[2].parse::<i8>().unwrap(),
2532            choice: MOVES
2533                .get(&Choices::from_str(split[0]).unwrap())
2534                .unwrap()
2535                .to_owned(),
2536        }
2537    }
2538}
2539
2540impl Pokemon {
2541    pub fn serialize(&self) -> String {
2542        let evs_str = format!(
2543            "{};{};{};{};{};{}",
2544            self.evs.0, self.evs.1, self.evs.2, self.evs.3, self.evs.4, self.evs.5
2545        );
2546        format!(
2547            "{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}",
2548            self.id,
2549            self.level,
2550            self.types.0.to_string(),
2551            self.types.1.to_string(),
2552            self.base_types.0.to_string(),
2553            self.base_types.1.to_string(),
2554            self.hp,
2555            self.maxhp,
2556            self.ability.to_string(),
2557            self.base_ability.to_string(),
2558            self.item.to_string(),
2559            self.nature.to_string(),
2560            evs_str,
2561            self.attack,
2562            self.defense,
2563            self.special_attack,
2564            self.special_defense,
2565            self.speed,
2566            self.status.to_string(),
2567            self.rest_turns,
2568            self.sleep_turns,
2569            self.weight_kg,
2570            self.moves.m0.serialize(),
2571            self.moves.m1.serialize(),
2572            self.moves.m2.serialize(),
2573            self.moves.m3.serialize(),
2574            self.terastallized,
2575            self.tera_type.to_string(),
2576        )
2577    }
2578
2579    pub fn deserialize(serialized: &str) -> Pokemon {
2580        let split: Vec<&str> = serialized.split(",").collect();
2581        let evs = if split[12] != "" {
2582            let mut ev_iter = split[12].split(";");
2583            (
2584                ev_iter.next().unwrap().parse::<u8>().unwrap(),
2585                ev_iter.next().unwrap().parse::<u8>().unwrap(),
2586                ev_iter.next().unwrap().parse::<u8>().unwrap(),
2587                ev_iter.next().unwrap().parse::<u8>().unwrap(),
2588                ev_iter.next().unwrap().parse::<u8>().unwrap(),
2589                ev_iter.next().unwrap().parse::<u8>().unwrap(),
2590            )
2591        } else {
2592            (85, 85, 85, 85, 85, 85)
2593        };
2594        Pokemon {
2595            id: PokemonName::from_str(split[0]).unwrap(),
2596            level: split[1].parse::<i8>().unwrap(),
2597            types: (
2598                PokemonType::from_str(split[2]).unwrap(),
2599                PokemonType::from_str(split[3]).unwrap(),
2600            ),
2601            base_types: (
2602                PokemonType::from_str(split[4]).unwrap(),
2603                PokemonType::from_str(split[5]).unwrap(),
2604            ),
2605            hp: split[6].parse::<i16>().unwrap(),
2606            maxhp: split[7].parse::<i16>().unwrap(),
2607            ability: Abilities::from_str(split[8]).unwrap(),
2608            base_ability: Abilities::from_str(split[9]).unwrap(),
2609            item: Items::from_str(split[10]).unwrap(),
2610            nature: PokemonNature::from_str(split[11]).unwrap(),
2611            evs,
2612            attack: split[13].parse::<i16>().unwrap(),
2613            defense: split[14].parse::<i16>().unwrap(),
2614            special_attack: split[15].parse::<i16>().unwrap(),
2615            special_defense: split[16].parse::<i16>().unwrap(),
2616            speed: split[17].parse::<i16>().unwrap(),
2617            status: PokemonStatus::from_str(split[18]).unwrap(),
2618            rest_turns: split[19].parse::<i8>().unwrap(),
2619            sleep_turns: split[20].parse::<i8>().unwrap(),
2620            weight_kg: split[21].parse::<f32>().unwrap(),
2621            moves: PokemonMoves {
2622                m0: Move::deserialize(split[22]),
2623                m1: Move::deserialize(split[23]),
2624                m2: Move::deserialize(split[24]),
2625                m3: Move::deserialize(split[25]),
2626            },
2627            terastallized: split[26].parse::<bool>().unwrap(),
2628            tera_type: PokemonType::from_str(split[27]).unwrap(),
2629        }
2630    }
2631}
2632
2633impl LastUsedMove {
2634    pub fn serialize(&self) -> String {
2635        match self {
2636            LastUsedMove::Move(move_index) => format!("move:{}", move_index.serialize()),
2637            LastUsedMove::Switch(pkmn_index) => format!("switch:{}", pkmn_index.serialize()),
2638            LastUsedMove::None => "move:none".to_string(),
2639        }
2640    }
2641    pub fn deserialize(serialized: &str) -> LastUsedMove {
2642        let split: Vec<&str> = serialized.split(":").collect();
2643        match split[0] {
2644            "move" => {
2645                if split[1] == "none" {
2646                    LastUsedMove::None
2647                } else {
2648                    LastUsedMove::Move(PokemonMoveIndex::deserialize(split[1]))
2649                }
2650            }
2651            "switch" => LastUsedMove::Switch(PokemonIndex::deserialize(split[1])),
2652            _ => panic!("Invalid LastUsedMove: {}", serialized),
2653        }
2654    }
2655}
2656
2657impl PokemonIndex {
2658    pub fn serialize(&self) -> String {
2659        match self {
2660            PokemonIndex::P0 => "0".to_string(),
2661            PokemonIndex::P1 => "1".to_string(),
2662            PokemonIndex::P2 => "2".to_string(),
2663            PokemonIndex::P3 => "3".to_string(),
2664            PokemonIndex::P4 => "4".to_string(),
2665            PokemonIndex::P5 => "5".to_string(),
2666        }
2667    }
2668
2669    pub fn deserialize(serialized: &str) -> PokemonIndex {
2670        match serialized {
2671            "0" => PokemonIndex::P0,
2672            "1" => PokemonIndex::P1,
2673            "2" => PokemonIndex::P2,
2674            "3" => PokemonIndex::P3,
2675            "4" => PokemonIndex::P4,
2676            "5" => PokemonIndex::P5,
2677            _ => panic!("Invalid PokemonIndex: {}", serialized),
2678        }
2679    }
2680}
2681
2682impl PokemonMoveIndex {
2683    pub fn serialize(&self) -> String {
2684        match self {
2685            PokemonMoveIndex::M0 => "0".to_string(),
2686            PokemonMoveIndex::M1 => "1".to_string(),
2687            PokemonMoveIndex::M2 => "2".to_string(),
2688            PokemonMoveIndex::M3 => "3".to_string(),
2689        }
2690    }
2691
2692    pub fn deserialize(serialized: &str) -> PokemonMoveIndex {
2693        match serialized {
2694            "0" => PokemonMoveIndex::M0,
2695            "1" => PokemonMoveIndex::M1,
2696            "2" => PokemonMoveIndex::M2,
2697            "3" => PokemonMoveIndex::M3,
2698            _ => panic!("Invalid PokemonMoveIndex: {}", serialized),
2699        }
2700    }
2701}
2702
2703impl SideConditions {
2704    pub fn serialize(&self) -> String {
2705        format!(
2706            "{};{};{};{};{};{};{};{};{};{};{};{};{};{};{};{};{};{};{}",
2707            self.aurora_veil,
2708            self.crafty_shield,
2709            self.healing_wish,
2710            self.light_screen,
2711            self.lucky_chant,
2712            self.lunar_dance,
2713            self.mat_block,
2714            self.mist,
2715            self.protect,
2716            self.quick_guard,
2717            self.reflect,
2718            self.safeguard,
2719            self.spikes,
2720            self.stealth_rock,
2721            self.sticky_web,
2722            self.tailwind,
2723            self.toxic_count,
2724            self.toxic_spikes,
2725            self.wide_guard,
2726        )
2727    }
2728    pub fn deserialize(serialized: &str) -> SideConditions {
2729        let split: Vec<&str> = serialized.split(";").collect();
2730        SideConditions {
2731            aurora_veil: split[0].parse::<i8>().unwrap(),
2732            crafty_shield: split[1].parse::<i8>().unwrap(),
2733            healing_wish: split[2].parse::<i8>().unwrap(),
2734            light_screen: split[3].parse::<i8>().unwrap(),
2735            lucky_chant: split[4].parse::<i8>().unwrap(),
2736            lunar_dance: split[5].parse::<i8>().unwrap(),
2737            mat_block: split[6].parse::<i8>().unwrap(),
2738            mist: split[7].parse::<i8>().unwrap(),
2739            protect: split[8].parse::<i8>().unwrap(),
2740            quick_guard: split[9].parse::<i8>().unwrap(),
2741            reflect: split[10].parse::<i8>().unwrap(),
2742            safeguard: split[11].parse::<i8>().unwrap(),
2743            spikes: split[12].parse::<i8>().unwrap(),
2744            stealth_rock: split[13].parse::<i8>().unwrap(),
2745            sticky_web: split[14].parse::<i8>().unwrap(),
2746            tailwind: split[15].parse::<i8>().unwrap(),
2747            toxic_count: split[16].parse::<i8>().unwrap(),
2748            toxic_spikes: split[17].parse::<i8>().unwrap(),
2749            wide_guard: split[18].parse::<i8>().unwrap(),
2750        }
2751    }
2752}
2753
2754impl Side {
2755    pub fn serialize(&self) -> String {
2756        let mut vs_string = String::new();
2757        for vs in &self.volatile_statuses {
2758            vs_string.push_str(&vs.to_string());
2759            vs_string.push_str(":");
2760        }
2761        format!(
2762            "{}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}",
2763            self.pokemon.p0.serialize(),
2764            self.pokemon.p1.serialize(),
2765            self.pokemon.p2.serialize(),
2766            self.pokemon.p3.serialize(),
2767            self.pokemon.p4.serialize(),
2768            self.pokemon.p5.serialize(),
2769            self.active_index.serialize(),
2770            self.side_conditions.serialize(),
2771            vs_string,
2772            self.volatile_status_durations.serialize(),
2773            self.substitute_health,
2774            self.attack_boost,
2775            self.defense_boost,
2776            self.special_attack_boost,
2777            self.special_defense_boost,
2778            self.speed_boost,
2779            self.accuracy_boost,
2780            self.evasion_boost,
2781            self.wish.0,
2782            self.wish.1,
2783            self.future_sight.0,
2784            self.future_sight.1.serialize(),
2785            self.force_switch,
2786            self.switch_out_move_second_saved_move.to_string(),
2787            self.baton_passing,
2788            self.force_trapped,
2789            self.last_used_move.serialize(),
2790            self.slow_uturn_move,
2791        )
2792    }
2793    pub fn deserialize(serialized: &str) -> Side {
2794        let split: Vec<&str> = serialized.split("=").collect();
2795
2796        let mut vs_hashset = HashSet::new();
2797        if split[8] != "" {
2798            for item in split[8].split(":") {
2799                vs_hashset.insert(PokemonVolatileStatus::from_str(item).unwrap());
2800            }
2801        }
2802        Side {
2803            pokemon: SidePokemon {
2804                p0: Pokemon::deserialize(split[0]),
2805                p1: Pokemon::deserialize(split[1]),
2806                p2: Pokemon::deserialize(split[2]),
2807                p3: Pokemon::deserialize(split[3]),
2808                p4: Pokemon::deserialize(split[4]),
2809                p5: Pokemon::deserialize(split[5]),
2810            },
2811            active_index: PokemonIndex::deserialize(split[6]),
2812            side_conditions: SideConditions::deserialize(split[7]),
2813            volatile_statuses: vs_hashset,
2814            volatile_status_durations: VolatileStatusDurations::deserialize(split[9]),
2815            substitute_health: split[10].parse::<i16>().unwrap(),
2816            attack_boost: split[11].parse::<i8>().unwrap(),
2817            defense_boost: split[12].parse::<i8>().unwrap(),
2818            special_attack_boost: split[13].parse::<i8>().unwrap(),
2819            special_defense_boost: split[14].parse::<i8>().unwrap(),
2820            speed_boost: split[15].parse::<i8>().unwrap(),
2821            accuracy_boost: split[16].parse::<i8>().unwrap(),
2822            evasion_boost: split[17].parse::<i8>().unwrap(),
2823            wish: (
2824                split[18].parse::<i8>().unwrap(),
2825                split[19].parse::<i16>().unwrap(),
2826            ),
2827            future_sight: (
2828                split[20].parse::<i8>().unwrap(),
2829                PokemonIndex::deserialize(split[21]),
2830            ),
2831            force_switch: split[22].parse::<bool>().unwrap(),
2832            switch_out_move_second_saved_move: Choices::from_str(split[23]).unwrap(),
2833            baton_passing: split[24].parse::<bool>().unwrap(),
2834            force_trapped: split[25].parse::<bool>().unwrap(),
2835            last_used_move: LastUsedMove::deserialize(split[26]),
2836            damage_dealt: DamageDealt::default(),
2837            slow_uturn_move: split[27].parse::<bool>().unwrap(),
2838        }
2839    }
2840}
2841
2842impl StateWeather {
2843    pub fn serialize(&self) -> String {
2844        format!("{:?};{}", self.weather_type, self.turns_remaining)
2845    }
2846    pub fn deserialize(serialized: &str) -> StateWeather {
2847        let split: Vec<&str> = serialized.split(";").collect();
2848        StateWeather {
2849            weather_type: Weather::from_str(split[0]).unwrap(),
2850            turns_remaining: split[1].parse::<i8>().unwrap(),
2851        }
2852    }
2853}
2854
2855impl StateTerrain {
2856    pub fn serialize(&self) -> String {
2857        format!("{:?};{}", self.terrain_type, self.turns_remaining)
2858    }
2859    pub fn deserialize(serialized: &str) -> StateTerrain {
2860        let split: Vec<&str> = serialized.split(";").collect();
2861        StateTerrain {
2862            terrain_type: Terrain::from_str(split[0]).unwrap(),
2863            turns_remaining: split[1].parse::<i8>().unwrap(),
2864        }
2865    }
2866}
2867
2868impl StateTrickRoom {
2869    pub fn serialize(&self) -> String {
2870        format!("{};{}", self.active, self.turns_remaining)
2871    }
2872    pub fn deserialize(serialized: &str) -> StateTrickRoom {
2873        let split: Vec<&str> = serialized.split(";").collect();
2874        StateTrickRoom {
2875            active: split[0].parse::<bool>().unwrap(),
2876            turns_remaining: split[1].parse::<i8>().unwrap(),
2877        }
2878    }
2879}
2880
2881impl State {
2882    pub fn serialize(&self) -> String {
2883        format!(
2884            "{}/{}/{}/{}/{}/{}",
2885            self.side_one.serialize(),
2886            self.side_two.serialize(),
2887            self.weather.serialize(),
2888            self.terrain.serialize(),
2889            self.trick_room.serialize(),
2890            self.team_preview
2891        )
2892    }
2893
2894    /// ```
2895    ///
2896    /// /*
2897    /// This doctest does its best to show the format of the serialized state.
2898    ///
2899    /// Roughly, the format for a state is:
2900    ///     side1/side2/weather/terrain/trick_room/team_preview
2901    ///
2902    /// Where the format for a side is:
2903    ///     p0=p1=p2=p3=p4=p5=active_index=side_conditions=wish0=wish1=force_switch=switch_out_move_second_saved_move=baton_passing=force_trapped=last_used_move=slow_uturn_move
2904    ///
2905    /// And the format for a pokemon is:
2906    ///    id,level,type1,type2,hp,maxhp,ability,item,attack,defense,special_attack,special_defense,speed,attack_boost,defense_boost,special_attack_boost,special_defense_boost,speed_boost,accuracy_boost,evasion_boost,status,substitute_health,rest_turns,weight_kg,volatile_statuses,m0,m1,m2,m3
2907    ///
2908    /// There's more to it, follow the code below to see a full example of a serialized state.
2909    /// */
2910    ///
2911    /// if cfg!(feature = "gen2") {
2912    ///    return;
2913    /// }
2914    ///
2915    /// use poke_engine::abilities::Abilities;
2916    /// use poke_engine::items::Items;
2917    /// use poke_engine::pokemon::PokemonName;
2918    /// use poke_engine::state::State;
2919    ///
2920    /// let serialized_state = concat!(
2921    ///
2922    /// // SIDE 1
2923    ///
2924    /// // POKEMON 1
2925    ///
2926    /// // name
2927    /// "alakazam,",
2928    ///
2929    /// // level
2930    /// "100,",
2931    ///
2932    /// // type1
2933    /// "Psychic,",
2934    ///
2935    /// // type2
2936    /// "Typeless,",
2937    ///
2938    /// // base_types 1 and 2. These are needed to revert to the correct type when switching out after being typechanged
2939    /// "Psychic,",
2940    /// "Typeless,",
2941    ///
2942    /// // hp
2943    /// "251,",
2944    ///
2945    /// // maxhp
2946    /// "251,",
2947    ///
2948    /// // ability
2949    /// "MAGICGUARD,",
2950    ///
2951    /// // base ability. This is needed to revert to the correct ability when switching out after having the ability changed
2952    /// "MAGICGUARD,",
2953    ///
2954    /// // item
2955    /// "LIFEORB,",
2956    ///
2957    /// // nature
2958    /// "SERIOUS,",
2959    ///
2960    /// // EVs split by `;`. Leave blank for default EVs (85 in all)
2961    /// "252;0;252;0;4;0,",
2962    /// // ",", left blank for default EVs
2963    ///
2964    /// // attack,defense,special attack,special defense,speed
2965    /// // note these are final stats, not base stats
2966    /// "121,148,353,206,365,",
2967    ///
2968    /// // status
2969    /// "None,",
2970    ///
2971    /// // rest_turns
2972    /// "0,",
2973    ///
2974    /// // sleep_turns
2975    /// "0,",
2976    ///
2977    /// // weight_kg
2978    /// "25.5,",
2979    ///
2980    /// // moves 1 through 4 (move_id;disabled;pp)
2981    /// "PSYCHIC;false;16,GRASSKNOT;false;32,SHADOWBALL;false;24,HIDDENPOWERFIRE70;false;24,",
2982    ///
2983    /// // terastallized
2984    /// "false,",
2985    ///
2986    /// // tera_type
2987    /// "Normal=",
2988    ///
2989    /// // all remaining Pokémon shown in 1 line for brevity
2990    /// "skarmory,100,Steel,Flying,Steel,Flying,271,271,STURDY,STURDY,CUSTAPBERRY,SERIOUS,,259,316,104,177,262,None,0,0,25.5,STEALTHROCK;false;32,SPIKES;false;32,BRAVEBIRD;false;24,THIEF;false;40,false,Normal=",
2991    /// "tyranitar,100,Rock,Dark,Rock,Dark,404,404,SANDSTREAM,SANDSTREAM,CHOPLEBERRY,SERIOUS,,305,256,203,327,159,None,0,0,25.5,CRUNCH;false;24,SUPERPOWER;false;8,THUNDERWAVE;false;32,PURSUIT;false;32,false,Normal=",
2992    /// "mamoswine,100,Ice,Ground,Ice,Ground,362,362,THICKFAT,THICKFAT,NEVERMELTICE,SERIOUS,,392,196,158,176,241,None,0,0,25.5,ICESHARD;false;48,EARTHQUAKE;false;16,SUPERPOWER;false;8,ICICLECRASH;false;16,false,Normal=",
2993    /// "jellicent,100,Water,Ghost,Water,Ghost,404,404,WATERABSORB,WATERABSORB,AIRBALLOON,SERIOUS,,140,237,206,246,180,None,0,0,25.5,TAUNT;false;32,NIGHTSHADE;false;24,WILLOWISP;false;24,RECOVER;false;16,false,Normal=",
2994    /// "excadrill,100,Ground,Steel,Ground,Steel,362,362,SANDFORCE,SANDFORCE,CHOICESCARF,SERIOUS,,367,156,122,168,302,None,0,0,25.5,EARTHQUAKE;false;16,IRONHEAD;false;24,ROCKSLIDE;false;16,RAPIDSPIN;false;64,false,Normal=",
2995    ///
2996    /// // active-index. This is the index of the active Pokémon in the side's Pokémon array
2997    /// "0=",
2998    ///
2999    /// // side conditions are integers
3000    /// "0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;=",
3001    ///
3002    /// // volatile_statuses (delimited by ":")
3003    /// "=",
3004    ///
3005    /// // some volatile statuses have durations associated with them, delimited by ;
3006    /// "0;0;0=",
3007    ///
3008    /// // substitute_health
3009    /// "0=",
3010    ///
3011    /// // For the active pokemon:
3012    /// // attack_boost,defense_boost,special attack_boost,special defense_boost,speed_boost,accuracy_boost,evasion_boost
3013    /// "0=0=0=0=0=0=0=",
3014    ///
3015    /// // wish condition is represented by 2 integers, the first is how many wish turns remaining, the second is the amount of HP to heal
3016    /// "0=",
3017    /// "0=",
3018    ///
3019    /// // future sight is represented by the PokemonIndex of the pokemon that used futuresight, and the number of turns remaining until it hits
3020    /// "0=",
3021    /// "0=",
3022    ///
3023    /// // a boolean representing if the side is forced to switch
3024    /// "false=",
3025    ///
3026    /// // a 'saved moved' that a pokemon may be waiting to use after the opponent finished their uturn/volt switch/etc.
3027    /// "NONE=",
3028    ///
3029    /// // a b=oolean representing if the side is baton passing
3030    /// "false=",
3031    ///
3032    /// // a boolean representing if the side is force trapped. This is only ever externally provided and never changed by the engine
3033    /// "false=",
3034    ///
3035    /// // last used move is a string that can be either "move:move_name" or "switch:pokemon_index"
3036    /// "switch:0=",
3037    ///
3038    /// // a boolean representing if the side is slow uturning.
3039    /// // This is only ever set externally. It is used to know if the opposing side has a stored move to use after uturn.
3040    /// "false/",
3041    ///
3042    /// // SIDE 2, all in one line for brevity
3043    /// "terrakion,100,Rock,Fighting,Rock,Fighting,323,323,JUSTIFIED,JUSTIFIED,FOCUSSASH,SERIOUS,,357,216,163,217,346,None,0,0,25.5,CLOSECOMBAT;false;8,STONEEDGE;false;8,STEALTHROCK;false;32,TAUNT;false;32,false,Normal=lucario,100,Fighting,Steel,Fighting,Steel,281,281,JUSTIFIED,JUSTIFIED,LIFEORB,SERIOUS,,350,176,241,177,279,None,0,0,25.5,CLOSECOMBAT;false;8,EXTREMESPEED;false;8,SWORDSDANCE;false;32,CRUNCH;false;24,false,Normal=breloom,100,Grass,Fighting,Grass,Fighting,262,262,TECHNICIAN,TECHNICIAN,LIFEORB,SERIOUS,,394,196,141,156,239,None,0,0,25.5,MACHPUNCH;false;48,BULLETSEED;false;48,SWORDSDANCE;false;32,LOWSWEEP;false;32,false,Normal=keldeo,100,Water,Fighting,Water,Fighting,323,323,JUSTIFIED,JUSTIFIED,LEFTOVERS,SERIOUS,,163,216,357,217,346,None,0,0,25.5,SECRETSWORD;false;16,HYDROPUMP;false;8,SCALD;false;24,SURF;false;24,false,Normal=conkeldurr,100,Fighting,Typeless,Fighting,Typeless,414,414,GUTS,GUTS,LEFTOVERS,SERIOUS,,416,226,132,167,126,None,0,0,25.5,MACHPUNCH;false;48,DRAINPUNCH;false;16,ICEPUNCH;false;24,THUNDERPUNCH;false;24,false,Normal=toxicroak,100,Poison,Fighting,Poison,Fighting,307,307,DRYSKIN,DRYSKIN,LIFEORB,SERIOUS,,311,166,189,167,295,None,0,0,25.5,DRAINPUNCH;false;16,SUCKERPUNCH;false;8,SWORDSDANCE;false;32,ICEPUNCH;false;24,false,Normal=0=0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;==0;0;0=0=0=0=0=0=0=0=0=0=0=0=0=false=NONE=false=false=switch:0=false/",
3044    ///
3045    /// // weather is a string representing the weather type and the number of turns remaining
3046    /// "none;5/",
3047    ///
3048    /// // terrain is a string representing the terrain type and the number of turns remaining
3049    /// "none;5/",
3050    ///
3051    /// // trick room is a boolean representing if trick room is active and the number of turns remaining
3052    /// "false;5/",
3053    ///
3054    /// // team preview is a boolean representing if the team preview is active
3055    /// "false"
3056    ///
3057    /// );
3058    ///
3059    /// let state = State::deserialize(serialized_state);
3060    ///
3061    /// assert_eq!(state.side_one.get_active_immutable().id, PokemonName::ALAKAZAM);
3062    /// assert_eq!(state.side_one.get_active_immutable().weight_kg, 25.5);
3063    /// assert_eq!(state.side_one.substitute_health, 0);
3064    /// assert_eq!(state.side_two.get_active_immutable().id, PokemonName::TERRAKION);
3065    /// assert_eq!(state.trick_room.active, false);
3066    /// assert_eq!(state.team_preview, false);
3067    ///
3068    /// #[cfg(not(any(feature = "gen1", feature = "gen2")))]
3069    /// {
3070    ///     assert_eq!(state.side_two.get_active_immutable().item, Items::FOCUSSASH);
3071    ///     assert_eq!(state.side_two.get_active_immutable().ability, Abilities::JUSTIFIED);
3072    ///     assert_eq!(state.side_one.get_active_immutable().item, Items::LIFEORB);
3073    ///     assert_eq!(state.side_one.get_active_immutable().ability, Abilities::MAGICGUARD);
3074    /// }
3075    ///
3076    /// // the same state, but all in one line
3077    /// let serialized_state = "alakazam,100,Psychic,Typeless,Psychic,Typeless,251,251,MAGICGUARD,MAGICGUARD,LIFEORB,SERIOUS,252;0;252;0;4;0,121,148,353,206,365,None,0,0,25.5,PSYCHIC;false;16,GRASSKNOT;false;32,SHADOWBALL;false;24,HIDDENPOWERFIRE70;false;24,false,Normal=skarmory,100,Steel,Flying,Steel,Flying,271,271,STURDY,STURDY,CUSTAPBERRY,SERIOUS,,259,316,104,177,262,None,0,0,25.5,STEALTHROCK;false;32,SPIKES;false;32,BRAVEBIRD;false;24,THIEF;false;40,false,Normal=tyranitar,100,Rock,Dark,Rock,Dark,404,404,SANDSTREAM,SANDSTREAM,CHOPLEBERRY,SERIOUS,,305,256,203,327,159,None,0,0,25.5,CRUNCH;false;24,SUPERPOWER;false;8,THUNDERWAVE;false;32,PURSUIT;false;32,false,Normal=mamoswine,100,Ice,Ground,Ice,Ground,362,362,THICKFAT,THICKFAT,NEVERMELTICE,SERIOUS,,392,196,158,176,241,None,0,0,25.5,ICESHARD;false;48,EARTHQUAKE;false;16,SUPERPOWER;false;8,ICICLECRASH;false;16,false,Normal=jellicent,100,Water,Ghost,Water,Ghost,404,404,WATERABSORB,WATERABSORB,AIRBALLOON,SERIOUS,,140,237,206,246,180,None,0,0,25.5,TAUNT;false;32,NIGHTSHADE;false;24,WILLOWISP;false;24,RECOVER;false;16,false,Normal=excadrill,100,Ground,Steel,Ground,Steel,362,362,SANDFORCE,SANDFORCE,CHOICESCARF,SERIOUS,,367,156,122,168,302,None,0,0,25.5,EARTHQUAKE;false;16,IRONHEAD;false;24,ROCKSLIDE;false;16,RAPIDSPIN;false;64,false,Normal=0=0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;==0;0;0=0=0=0=0=0=0=0=0=0=0=0=0=false=NONE=false=false=switch:0=false/terrakion,100,Rock,Fighting,Rock,Fighting,323,323,JUSTIFIED,JUSTIFIED,FOCUSSASH,SERIOUS,,357,216,163,217,346,None,0,0,25.5,CLOSECOMBAT;false;8,STONEEDGE;false;8,STEALTHROCK;false;32,TAUNT;false;32,false,Normal=lucario,100,Fighting,Steel,Fighting,Steel,281,281,JUSTIFIED,JUSTIFIED,LIFEORB,SERIOUS,,350,176,241,177,279,None,0,0,25.5,CLOSECOMBAT;false;8,EXTREMESPEED;false;8,SWORDSDANCE;false;32,CRUNCH;false;24,false,Normal=breloom,100,Grass,Fighting,Grass,Fighting,262,262,TECHNICIAN,TECHNICIAN,LIFEORB,SERIOUS,,394,196,141,156,239,None,0,0,25.5,MACHPUNCH;false;48,BULLETSEED;false;48,SWORDSDANCE;false;32,LOWSWEEP;false;32,false,Normal=keldeo,100,Water,Fighting,Water,Fighting,323,323,JUSTIFIED,JUSTIFIED,LEFTOVERS,SERIOUS,,163,216,357,217,346,None,0,0,25.5,SECRETSWORD;false;16,HYDROPUMP;false;8,SCALD;false;24,SURF;false;24,false,Normal=conkeldurr,100,Fighting,Typeless,Fighting,Typeless,414,414,GUTS,GUTS,LEFTOVERS,SERIOUS,,416,226,132,167,126,None,0,0,25.5,MACHPUNCH;false;48,DRAINPUNCH;false;16,ICEPUNCH;false;24,THUNDERPUNCH;false;24,false,Normal=toxicroak,100,Poison,Fighting,Poison,Fighting,307,307,DRYSKIN,DRYSKIN,LIFEORB,SERIOUS,,311,166,189,167,295,None,0,0,25.5,DRAINPUNCH;false;16,SUCKERPUNCH;false;8,SWORDSDANCE;false;32,ICEPUNCH;false;24,false,Normal=0=0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;==0;0;0=0=0=0=0=0=0=0=0=0=0=0=0=false=NONE=false=false=switch:0=false/none;5/none;5/false;5/false";
3078    /// let state2 = State::deserialize(serialized_state);
3079    /// assert_eq!(state.serialize(), state2.serialize());
3080    ///
3081    /// ```
3082    pub fn deserialize(serialized: &str) -> State {
3083        let split: Vec<&str> = serialized.split("/").collect();
3084        let mut state = State {
3085            side_one: Side::deserialize(split[0]),
3086            side_two: Side::deserialize(split[1]),
3087            weather: StateWeather::deserialize(split[2]),
3088            terrain: StateTerrain::deserialize(split[3]),
3089            trick_room: StateTrickRoom::deserialize(split[4]),
3090            team_preview: split[5].parse::<bool>().unwrap(),
3091            use_damage_dealt: false,
3092            use_last_used_move: false,
3093        };
3094        state.set_conditional_mechanics();
3095        state
3096    }
3097}