poke_engine/
state.rs

1use crate::choices::{Choice, Choices, MoveCategory, MOVES};
2use crate::define_enum_with_from_str;
3use crate::engine::abilities::Abilities;
4use crate::engine::items::Items;
5use crate::engine::state::{PokemonVolatileStatus, Terrain, Weather};
6use crate::instruction::{BoostInstruction, EnableMoveInstruction, Instruction};
7use crate::pokemon::PokemonName;
8use std::collections::HashSet;
9use std::ops::{Index, IndexMut};
10use std::str::FromStr;
11
12#[derive(Debug, PartialEq, Copy, Clone)]
13pub enum SideReference {
14    SideOne,
15    SideTwo,
16}
17impl SideReference {
18    pub fn get_other_side(&self) -> SideReference {
19        match self {
20            SideReference::SideOne => SideReference::SideTwo,
21            SideReference::SideTwo => SideReference::SideOne,
22        }
23    }
24}
25
26#[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)]
27pub enum PokemonSideCondition {
28    AuroraVeil,
29    CraftyShield,
30    HealingWish,
31    LightScreen,
32    LuckyChant,
33    LunarDance,
34    MatBlock,
35    Mist,
36    Protect,
37    QuickGuard,
38    Reflect,
39    Safeguard,
40    Spikes,
41    Stealthrock,
42    StickyWeb,
43    Tailwind,
44    ToxicCount,
45    ToxicSpikes,
46    WideGuard,
47}
48
49#[derive(Debug, PartialEq, Eq, Copy, Clone)]
50pub enum LastUsedMove {
51    Move(PokemonMoveIndex),
52    Switch(PokemonIndex),
53    None,
54}
55impl LastUsedMove {
56    pub fn serialize(&self) -> String {
57        match self {
58            LastUsedMove::Move(move_index) => format!("move:{}", move_index.serialize()),
59            LastUsedMove::Switch(pkmn_index) => format!("switch:{}", pkmn_index.serialize()),
60            LastUsedMove::None => "move:none".to_string(),
61        }
62    }
63    pub fn deserialize(serialized: &str) -> LastUsedMove {
64        let split: Vec<&str> = serialized.split(":").collect();
65        match split[0] {
66            "move" => {
67                if split[1] == "none" {
68                    LastUsedMove::None
69                } else {
70                    LastUsedMove::Move(PokemonMoveIndex::deserialize(split[1]))
71                }
72            }
73            "switch" => LastUsedMove::Switch(PokemonIndex::deserialize(split[1])),
74            _ => panic!("Invalid LastUsedMove: {}", serialized),
75        }
76    }
77}
78
79#[derive(Debug, Copy, PartialEq, Clone, Eq, Hash)]
80pub enum PokemonMoveIndex {
81    M0,
82    M1,
83    M2,
84    M3,
85}
86impl PokemonMoveIndex {
87    pub fn serialize(&self) -> String {
88        match self {
89            PokemonMoveIndex::M0 => "0".to_string(),
90            PokemonMoveIndex::M1 => "1".to_string(),
91            PokemonMoveIndex::M2 => "2".to_string(),
92            PokemonMoveIndex::M3 => "3".to_string(),
93        }
94    }
95    pub fn deserialize(serialized: &str) -> PokemonMoveIndex {
96        match serialized {
97            "0" => PokemonMoveIndex::M0,
98            "1" => PokemonMoveIndex::M1,
99            "2" => PokemonMoveIndex::M2,
100            "3" => PokemonMoveIndex::M3,
101            _ => panic!("Invalid PokemonMoveIndex: {}", serialized),
102        }
103    }
104}
105
106#[derive(Debug, PartialEq, Clone, Copy)]
107pub enum PokemonBoostableStat {
108    Attack,
109    Defense,
110    SpecialAttack,
111    SpecialDefense,
112    Speed,
113    Evasion,
114    Accuracy,
115}
116
117define_enum_with_from_str! {
118    #[repr(u8)]
119    #[derive(Debug, PartialEq, Copy, Clone)]
120    PokemonStatus {
121        NONE,
122        BURN,
123        SLEEP,
124        FREEZE,
125        PARALYZE,
126        POISON,
127        TOXIC,
128    }
129}
130
131define_enum_with_from_str! {
132    #[repr(u8)]
133    #[derive(Debug, PartialEq, Copy, Clone)]
134    SideMovesFirst {
135        SideOne,
136        SideTwo,
137        SpeedTie
138    }
139}
140
141define_enum_with_from_str! {
142    #[repr(u8)]
143    #[derive(Debug, PartialEq, Clone)]
144    PokemonNature {
145        HARDY,
146        LONELY,
147        ADAMANT,
148        NAUGHTY,
149        BRAVE,
150        BOLD,
151        DOCILE,
152        IMPISH,
153        LAX,
154        RELAXED,
155        MODEST,
156        MILD,
157        BASHFUL,
158        RASH,
159        QUIET,
160        CALM,
161        GENTLE,
162        CAREFUL,
163        QUIRKY,
164        SASSY,
165        TIMID,
166        HASTY,
167        JOLLY,
168        NAIVE,
169        SERIOUS
170    }
171}
172
173define_enum_with_from_str! {
174    #[repr(u8)]
175    #[derive(Debug, Clone, Copy, PartialEq)]
176    PokemonType {
177        NORMAL,
178        FIRE,
179        WATER,
180        ELECTRIC,
181        GRASS,
182        ICE,
183        FIGHTING,
184        POISON,
185        GROUND,
186        FLYING,
187        PSYCHIC,
188        BUG,
189        ROCK,
190        GHOST,
191        DRAGON,
192        DARK,
193        STEEL,
194        FAIRY,
195        STELLAR,
196        TYPELESS,
197    },
198    default = TYPELESS
199}
200
201impl Index<&PokemonMoveIndex> for PokemonMoves {
202    type Output = Move;
203
204    fn index(&self, index: &PokemonMoveIndex) -> &Self::Output {
205        match index {
206            PokemonMoveIndex::M0 => &self.m0,
207            PokemonMoveIndex::M1 => &self.m1,
208            PokemonMoveIndex::M2 => &self.m2,
209            PokemonMoveIndex::M3 => &self.m3,
210        }
211    }
212}
213
214impl IndexMut<&PokemonMoveIndex> for PokemonMoves {
215    fn index_mut(&mut self, index: &PokemonMoveIndex) -> &mut Self::Output {
216        match index {
217            PokemonMoveIndex::M0 => &mut self.m0,
218            PokemonMoveIndex::M1 => &mut self.m1,
219            PokemonMoveIndex::M2 => &mut self.m2,
220            PokemonMoveIndex::M3 => &mut self.m3,
221        }
222    }
223}
224
225pub struct PokemonMoveIterator<'a> {
226    pub pokemon_move: &'a PokemonMoves,
227    pub pokemon_move_index: PokemonMoveIndex,
228    pub index: usize,
229}
230
231impl<'a> Iterator for PokemonMoveIterator<'a> {
232    type Item = &'a Move;
233
234    fn next(&mut self) -> Option<Self::Item> {
235        match self.index {
236            0 => {
237                self.index += 1;
238                self.pokemon_move_index = PokemonMoveIndex::M0;
239                Some(&self.pokemon_move.m0)
240            }
241            1 => {
242                self.index += 1;
243                self.pokemon_move_index = PokemonMoveIndex::M1;
244                Some(&self.pokemon_move.m1)
245            }
246            2 => {
247                self.index += 1;
248                self.pokemon_move_index = PokemonMoveIndex::M2;
249                Some(&self.pokemon_move.m2)
250            }
251            3 => {
252                self.index += 1;
253                self.pokemon_move_index = PokemonMoveIndex::M3;
254                Some(&self.pokemon_move.m3)
255            }
256            _ => None,
257        }
258    }
259}
260
261impl<'a> IntoIterator for &'a PokemonMoves {
262    type Item = &'a Move;
263    type IntoIter = PokemonMoveIterator<'a>;
264
265    fn into_iter(self) -> Self::IntoIter {
266        PokemonMoveIterator {
267            pokemon_move: &self,
268            pokemon_move_index: PokemonMoveIndex::M0,
269            index: 0,
270        }
271    }
272}
273
274#[derive(Debug, Copy, PartialEq, Clone, Eq, Hash)]
275#[repr(u8)]
276pub enum PokemonIndex {
277    P0,
278    P1,
279    P2,
280    P3,
281    P4,
282    P5,
283}
284impl PokemonIndex {
285    pub fn serialize(&self) -> String {
286        match self {
287            PokemonIndex::P0 => "0".to_string(),
288            PokemonIndex::P1 => "1".to_string(),
289            PokemonIndex::P2 => "2".to_string(),
290            PokemonIndex::P3 => "3".to_string(),
291            PokemonIndex::P4 => "4".to_string(),
292            PokemonIndex::P5 => "5".to_string(),
293        }
294    }
295    pub fn deserialize(serialized: &str) -> PokemonIndex {
296        match serialized {
297            "0" => PokemonIndex::P0,
298            "1" => PokemonIndex::P1,
299            "2" => PokemonIndex::P2,
300            "3" => PokemonIndex::P3,
301            "4" => PokemonIndex::P4,
302            "5" => PokemonIndex::P5,
303            _ => panic!("Invalid PokemonIndex: {}", serialized),
304        }
305    }
306}
307
308pub fn pokemon_index_iter() -> PokemonIndexIterator {
309    PokemonIndexIterator { index: 0 }
310}
311
312pub struct PokemonIndexIterator {
313    index: usize,
314}
315
316impl Iterator for PokemonIndexIterator {
317    type Item = PokemonIndex;
318
319    fn next(&mut self) -> Option<Self::Item> {
320        match self.index {
321            0 => {
322                self.index += 1;
323                Some(PokemonIndex::P0)
324            }
325            1 => {
326                self.index += 1;
327                Some(PokemonIndex::P1)
328            }
329            2 => {
330                self.index += 1;
331                Some(PokemonIndex::P2)
332            }
333            3 => {
334                self.index += 1;
335                Some(PokemonIndex::P3)
336            }
337            4 => {
338                self.index += 1;
339                Some(PokemonIndex::P4)
340            }
341            5 => {
342                self.index += 1;
343                Some(PokemonIndex::P5)
344            }
345            _ => None,
346        }
347    }
348}
349
350#[derive(Debug, Clone)]
351pub struct SidePokemon {
352    pub pkmn: [Pokemon; 6],
353}
354
355impl<'a> IntoIterator for &'a SidePokemon {
356    type Item = &'a Pokemon;
357    type IntoIter = SidePokemonIterator<'a>;
358
359    fn into_iter(self) -> Self::IntoIter {
360        SidePokemonIterator {
361            side_pokemon: &self,
362            pokemon_index: PokemonIndex::P0,
363            index: 0,
364        }
365    }
366}
367
368pub struct SidePokemonIterator<'a> {
369    pub side_pokemon: &'a SidePokemon,
370    pub pokemon_index: PokemonIndex,
371    pub index: usize,
372}
373
374impl<'a> Iterator for SidePokemonIterator<'a> {
375    type Item = &'a Pokemon;
376
377    fn next(&mut self) -> Option<Self::Item> {
378        match self.index {
379            0 => {
380                self.index += 1;
381                self.pokemon_index = PokemonIndex::P0;
382                Some(&self.side_pokemon.pkmn[0])
383            }
384            1 => {
385                self.index += 1;
386                self.pokemon_index = PokemonIndex::P1;
387                Some(&self.side_pokemon.pkmn[1])
388            }
389            2 => {
390                self.index += 1;
391                self.pokemon_index = PokemonIndex::P2;
392                Some(&self.side_pokemon.pkmn[2])
393            }
394            3 => {
395                self.index += 1;
396                self.pokemon_index = PokemonIndex::P3;
397                Some(&self.side_pokemon.pkmn[3])
398            }
399            4 => {
400                self.index += 1;
401                self.pokemon_index = PokemonIndex::P4;
402                Some(&self.side_pokemon.pkmn[4])
403            }
404            5 => {
405                self.index += 1;
406                self.pokemon_index = PokemonIndex::P5;
407                Some(&self.side_pokemon.pkmn[5])
408            }
409            _ => None,
410        }
411    }
412}
413
414impl Index<PokemonIndex> for SidePokemon {
415    type Output = Pokemon;
416
417    fn index(&self, index: PokemonIndex) -> &Self::Output {
418        &self.pkmn[index as usize]
419    }
420}
421
422impl Index<&PokemonIndex> for SidePokemon {
423    type Output = Pokemon;
424
425    fn index(&self, index: &PokemonIndex) -> &Self::Output {
426        &self.pkmn[*index as usize]
427    }
428}
429
430impl IndexMut<PokemonIndex> for SidePokemon {
431    fn index_mut(&mut self, index: PokemonIndex) -> &mut Self::Output {
432        &mut self.pkmn[index as usize]
433    }
434}
435
436impl Default for Side {
437    fn default() -> Side {
438        Side {
439            active_index: PokemonIndex::P0,
440            baton_passing: false,
441            shed_tailing: false,
442            pokemon: SidePokemon {
443                pkmn: [
444                    Pokemon::default(),
445                    Pokemon::default(),
446                    Pokemon::default(),
447                    Pokemon::default(),
448                    Pokemon::default(),
449                    Pokemon::default(),
450                ],
451            },
452            substitute_health: 0,
453            attack_boost: 0,
454            defense_boost: 0,
455            special_attack_boost: 0,
456            special_defense_boost: 0,
457            speed_boost: 0,
458            accuracy_boost: 0,
459            side_conditions: SideConditions {
460                ..Default::default()
461            },
462            volatile_status_durations: VolatileStatusDurations::default(),
463            volatile_statuses: HashSet::<PokemonVolatileStatus>::new(),
464            wish: (0, 0),
465            future_sight: (0, PokemonIndex::P0),
466            force_switch: false,
467            slow_uturn_move: false,
468            force_trapped: false,
469            last_used_move: LastUsedMove::None,
470            damage_dealt: DamageDealt::default(),
471            switch_out_move_second_saved_move: Choices::NONE,
472            evasion_boost: 0,
473        }
474    }
475}
476
477#[derive(Debug, Clone)]
478pub struct Move {
479    pub id: Choices,
480    pub disabled: bool,
481    pub pp: i8,
482    pub choice: Choice,
483}
484impl Move {
485    pub fn serialize(&self) -> String {
486        format!("{:?};{};{}", self.id, self.disabled, self.pp)
487    }
488    pub fn deserialize(serialized: &str) -> Move {
489        let split: Vec<&str> = serialized.split(";").collect();
490        Move {
491            id: Choices::from_str(split[0]).unwrap(),
492            disabled: split[1].parse::<bool>().unwrap(),
493            pp: split[2].parse::<i8>().unwrap(),
494            choice: MOVES
495                .get(&Choices::from_str(split[0]).unwrap())
496                .unwrap()
497                .to_owned(),
498        }
499    }
500}
501impl Default for Move {
502    fn default() -> Move {
503        Move {
504            id: Choices::NONE,
505            disabled: false,
506            pp: 32,
507            choice: Choice::default(),
508        }
509    }
510}
511
512#[derive(Debug, Clone)]
513pub struct DamageDealt {
514    pub damage: i16,
515    pub move_category: MoveCategory,
516    pub hit_substitute: bool,
517}
518
519impl Default for DamageDealt {
520    fn default() -> DamageDealt {
521        DamageDealt {
522            damage: 0,
523            move_category: MoveCategory::Physical,
524            hit_substitute: false,
525        }
526    }
527}
528
529#[derive(Debug, Clone)]
530pub struct PokemonMoves {
531    pub m0: Move,
532    pub m1: Move,
533    pub m2: Move,
534    pub m3: Move,
535}
536
537#[derive(Debug, PartialEq, Clone)]
538pub struct SideConditions {
539    pub aurora_veil: i8,
540    pub crafty_shield: i8,
541    pub healing_wish: i8,
542    pub light_screen: i8,
543    pub lucky_chant: i8,
544    pub lunar_dance: i8,
545    pub mat_block: i8,
546    pub mist: i8,
547    pub protect: i8,
548    pub quick_guard: i8,
549    pub reflect: i8,
550    pub safeguard: i8,
551    pub spikes: i8,
552    pub stealth_rock: i8,
553    pub sticky_web: i8,
554    pub tailwind: i8,
555    pub toxic_count: i8,
556    pub toxic_spikes: i8,
557    pub wide_guard: i8,
558}
559impl SideConditions {
560    pub fn pprint(&self) -> String {
561        let conditions = [
562            ("aurora_veil", self.aurora_veil),
563            ("crafty_shield", self.crafty_shield),
564            ("healing_wish", self.healing_wish),
565            ("light_screen", self.light_screen),
566            ("lucky_chant", self.lucky_chant),
567            ("lunar_dance", self.lunar_dance),
568            ("mat_block", self.mat_block),
569            ("mist", self.mist),
570            ("protect", self.protect),
571            ("quick_guard", self.quick_guard),
572            ("reflect", self.reflect),
573            ("safeguard", self.safeguard),
574            ("spikes", self.spikes),
575            ("stealth_rock", self.stealth_rock),
576            ("sticky_web", self.sticky_web),
577            ("tailwind", self.tailwind),
578            ("toxic_count", self.toxic_count),
579            ("toxic_spikes", self.toxic_spikes),
580            ("wide_guard", self.wide_guard),
581        ];
582
583        let mut output = String::new();
584        for (name, value) in conditions {
585            if value != 0 {
586                output.push_str(&format!("\n  {}: {}", name, value));
587            }
588        }
589        if output.is_empty() {
590            return "none".to_string();
591        }
592        output
593    }
594    pub fn serialize(&self) -> String {
595        format!(
596            "{};{};{};{};{};{};{};{};{};{};{};{};{};{};{};{};{};{};{}",
597            self.aurora_veil,
598            self.crafty_shield,
599            self.healing_wish,
600            self.light_screen,
601            self.lucky_chant,
602            self.lunar_dance,
603            self.mat_block,
604            self.mist,
605            self.protect,
606            self.quick_guard,
607            self.reflect,
608            self.safeguard,
609            self.spikes,
610            self.stealth_rock,
611            self.sticky_web,
612            self.tailwind,
613            self.toxic_count,
614            self.toxic_spikes,
615            self.wide_guard,
616        )
617    }
618    pub fn deserialize(serialized: &str) -> SideConditions {
619        let split: Vec<&str> = serialized.split(";").collect();
620        SideConditions {
621            aurora_veil: split[0].parse::<i8>().unwrap(),
622            crafty_shield: split[1].parse::<i8>().unwrap(),
623            healing_wish: split[2].parse::<i8>().unwrap(),
624            light_screen: split[3].parse::<i8>().unwrap(),
625            lucky_chant: split[4].parse::<i8>().unwrap(),
626            lunar_dance: split[5].parse::<i8>().unwrap(),
627            mat_block: split[6].parse::<i8>().unwrap(),
628            mist: split[7].parse::<i8>().unwrap(),
629            protect: split[8].parse::<i8>().unwrap(),
630            quick_guard: split[9].parse::<i8>().unwrap(),
631            reflect: split[10].parse::<i8>().unwrap(),
632            safeguard: split[11].parse::<i8>().unwrap(),
633            spikes: split[12].parse::<i8>().unwrap(),
634            stealth_rock: split[13].parse::<i8>().unwrap(),
635            sticky_web: split[14].parse::<i8>().unwrap(),
636            tailwind: split[15].parse::<i8>().unwrap(),
637            toxic_count: split[16].parse::<i8>().unwrap(),
638            toxic_spikes: split[17].parse::<i8>().unwrap(),
639            wide_guard: split[18].parse::<i8>().unwrap(),
640        }
641    }
642}
643impl Default for SideConditions {
644    fn default() -> SideConditions {
645        SideConditions {
646            aurora_veil: 0,
647            crafty_shield: 0,
648            healing_wish: 0,
649            light_screen: 0,
650            lucky_chant: 0,
651            lunar_dance: 0,
652            mat_block: 0,
653            mist: 0,
654            protect: 0,
655            quick_guard: 0,
656            reflect: 0,
657            safeguard: 0,
658            spikes: 0,
659            stealth_rock: 0,
660            sticky_web: 0,
661            tailwind: 0,
662            toxic_count: 0,
663            toxic_spikes: 0,
664            wide_guard: 0,
665        }
666    }
667}
668
669#[derive(Debug, PartialEq, Clone)]
670pub struct StateWeather {
671    pub weather_type: Weather,
672    pub turns_remaining: i8,
673}
674impl StateWeather {
675    pub fn serialize(&self) -> String {
676        format!("{:?};{}", self.weather_type, self.turns_remaining)
677    }
678    pub fn deserialize(serialized: &str) -> StateWeather {
679        let split: Vec<&str> = serialized.split(";").collect();
680        StateWeather {
681            weather_type: Weather::from_str(split[0]).unwrap(),
682            turns_remaining: split[1].parse::<i8>().unwrap(),
683        }
684    }
685}
686
687#[derive(Debug, PartialEq, Clone)]
688pub struct StateTerrain {
689    pub terrain_type: Terrain,
690    pub turns_remaining: i8,
691}
692impl StateTerrain {
693    pub fn serialize(&self) -> String {
694        format!("{:?};{}", self.terrain_type, self.turns_remaining)
695    }
696    pub fn deserialize(serialized: &str) -> StateTerrain {
697        let split: Vec<&str> = serialized.split(";").collect();
698        StateTerrain {
699            terrain_type: Terrain::from_str(split[0]).unwrap(),
700            turns_remaining: split[1].parse::<i8>().unwrap(),
701        }
702    }
703}
704
705#[derive(Debug, PartialEq, Clone)]
706pub struct StateTrickRoom {
707    pub active: bool,
708    pub turns_remaining: i8,
709}
710impl StateTrickRoom {
711    pub fn serialize(&self) -> String {
712        format!("{};{}", self.active, self.turns_remaining)
713    }
714    pub fn deserialize(serialized: &str) -> StateTrickRoom {
715        let split: Vec<&str> = serialized.split(";").collect();
716        StateTrickRoom {
717            active: split[0].parse::<bool>().unwrap(),
718            turns_remaining: split[1].parse::<i8>().unwrap(),
719        }
720    }
721}
722
723#[derive(Debug, Clone)]
724pub struct VolatileStatusDurations {
725    pub confusion: i8,
726    pub encore: i8,
727    pub lockedmove: i8,
728    pub slowstart: i8,
729    pub taunt: i8,
730    pub yawn: i8,
731}
732
733impl Default for VolatileStatusDurations {
734    fn default() -> VolatileStatusDurations {
735        VolatileStatusDurations {
736            confusion: 0,
737            encore: 0,
738            lockedmove: 0,
739            slowstart: 0,
740            taunt: 0,
741            yawn: 0,
742        }
743    }
744}
745
746impl VolatileStatusDurations {
747    pub fn pprint(&self) -> String {
748        let durations = [
749            ("confusion", self.confusion),
750            ("encore", self.encore),
751            ("lockedmove", self.lockedmove),
752            ("slowstart", self.slowstart),
753            ("taunt", self.taunt),
754            ("yawn", self.yawn),
755        ];
756
757        let mut output = String::new();
758        for (name, value) in durations {
759            if value != 0 {
760                output.push_str(&format!("\n  {}: {}", name, value));
761            }
762        }
763        if output.is_empty() {
764            return "none".to_string();
765        }
766        output
767    }
768
769    pub fn serialize(&self) -> String {
770        format!(
771            "{};{};{};{};{};{}",
772            self.confusion, self.encore, self.lockedmove, self.slowstart, self.taunt, self.yawn
773        )
774    }
775    pub fn deserialize(serialized: &str) -> VolatileStatusDurations {
776        let split: Vec<&str> = serialized.split(";").collect();
777        VolatileStatusDurations {
778            confusion: split[0].parse::<i8>().unwrap(),
779            encore: split[1].parse::<i8>().unwrap(),
780            lockedmove: split[2].parse::<i8>().unwrap(),
781            slowstart: split[3].parse::<i8>().unwrap(),
782            taunt: split[4].parse::<i8>().unwrap(),
783            yawn: split[5].parse::<i8>().unwrap(),
784        }
785    }
786}
787
788#[derive(Debug, Clone)]
789pub struct Pokemon {
790    pub id: PokemonName,
791    pub level: i8,
792    pub types: (PokemonType, PokemonType),
793    pub base_types: (PokemonType, PokemonType),
794    pub hp: i16,
795    pub maxhp: i16,
796    pub ability: Abilities,
797    pub base_ability: Abilities,
798    pub item: Items,
799    pub nature: PokemonNature,
800    pub evs: (u8, u8, u8, u8, u8, u8),
801    pub attack: i16,
802    pub defense: i16,
803    pub special_attack: i16,
804    pub special_defense: i16,
805    pub speed: i16,
806    pub status: PokemonStatus,
807    pub rest_turns: i8,
808    pub sleep_turns: i8,
809    pub weight_kg: f32,
810    pub terastallized: bool,
811    pub tera_type: PokemonType,
812    pub moves: PokemonMoves,
813}
814
815impl Default for Pokemon {
816    fn default() -> Pokemon {
817        Pokemon {
818            id: PokemonName::NONE,
819            level: 100,
820            types: (PokemonType::NORMAL, PokemonType::TYPELESS),
821            base_types: (PokemonType::NORMAL, PokemonType::TYPELESS),
822            hp: 100,
823            maxhp: 100,
824            ability: Abilities::NONE,
825            base_ability: Abilities::NONE,
826            item: Items::NONE,
827            nature: PokemonNature::SERIOUS,
828            evs: (85, 85, 85, 85, 85, 85),
829            attack: 100,
830            defense: 100,
831            special_attack: 100,
832            special_defense: 100,
833            speed: 100,
834            status: PokemonStatus::NONE,
835            rest_turns: 0,
836            sleep_turns: 0,
837            weight_kg: 1.0,
838            terastallized: false,
839            tera_type: PokemonType::NORMAL,
840            moves: PokemonMoves {
841                m0: Default::default(),
842                m1: Default::default(),
843                m2: Default::default(),
844                m3: Default::default(),
845            },
846        }
847    }
848}
849
850impl Pokemon {
851    pub fn replace_move(&mut self, move_index: PokemonMoveIndex, new_move_name: Choices) {
852        self.moves[&move_index].choice = MOVES.get(&new_move_name).unwrap().to_owned();
853        self.moves[&move_index].id = new_move_name;
854    }
855    pub fn get_sleep_talk_choices(&self) -> Vec<Choice> {
856        let mut vec = Vec::with_capacity(4);
857        for p in self.moves.into_iter() {
858            if p.id != Choices::SLEEPTALK && p.id != Choices::NONE {
859                vec.push(p.choice.clone());
860            }
861        }
862        vec
863    }
864
865    fn pprint_stats(&self) -> String {
866        format!(
867            "atk:{} def:{} spa:{} spd:{} spe:{}",
868            self.attack, self.defense, self.special_attack, self.special_defense, self.speed
869        )
870    }
871    pub fn pprint_concise(&self) -> String {
872        format!("{}:{}/{}", self.id, self.hp, self.maxhp)
873    }
874    pub fn pprint_verbose(&self) -> String {
875        let moves: Vec<String> = self
876            .moves
877            .into_iter()
878            .map(|m| format!("{:?}", m.id).to_lowercase())
879            .filter(|x| x != "none")
880            .collect();
881        format!(
882            "\n  Name: {}\n  HP: {}/{}\n  Status: {:?}\n  Ability: {:?}\n  Item: {:?}\n  Stats: {}\n  Moves: {}",
883            self.id,
884            self.hp,
885            self.maxhp,
886            self.status,
887            self.ability,
888            self.item,
889            self.pprint_stats(),
890            moves.join(", ")
891        )
892    }
893}
894
895impl Pokemon {
896    pub fn serialize(&self) -> String {
897        let evs_str = format!(
898            "{};{};{};{};{};{}",
899            self.evs.0, self.evs.1, self.evs.2, self.evs.3, self.evs.4, self.evs.5
900        );
901        format!(
902            "{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}",
903            self.id,
904            self.level,
905            self.types.0.to_string(),
906            self.types.1.to_string(),
907            self.base_types.0.to_string(),
908            self.base_types.1.to_string(),
909            self.hp,
910            self.maxhp,
911            self.ability.to_string(),
912            self.base_ability.to_string(),
913            self.item.to_string(),
914            self.nature.to_string(),
915            evs_str,
916            self.attack,
917            self.defense,
918            self.special_attack,
919            self.special_defense,
920            self.speed,
921            self.status.to_string(),
922            self.rest_turns,
923            self.sleep_turns,
924            self.weight_kg,
925            self.moves.m0.serialize(),
926            self.moves.m1.serialize(),
927            self.moves.m2.serialize(),
928            self.moves.m3.serialize(),
929            self.terastallized,
930            self.tera_type.to_string(),
931        )
932    }
933
934    pub fn deserialize(serialized: &str) -> Pokemon {
935        let split: Vec<&str> = serialized.split(",").collect();
936        let evs = if split[12] != "" {
937            let mut ev_iter = split[12].split(";");
938            (
939                ev_iter.next().unwrap().parse::<u8>().unwrap(),
940                ev_iter.next().unwrap().parse::<u8>().unwrap(),
941                ev_iter.next().unwrap().parse::<u8>().unwrap(),
942                ev_iter.next().unwrap().parse::<u8>().unwrap(),
943                ev_iter.next().unwrap().parse::<u8>().unwrap(),
944                ev_iter.next().unwrap().parse::<u8>().unwrap(),
945            )
946        } else {
947            (85, 85, 85, 85, 85, 85)
948        };
949        Pokemon {
950            id: PokemonName::from_str(split[0]).unwrap(),
951            level: split[1].parse::<i8>().unwrap(),
952            types: (
953                PokemonType::from_str(split[2]).unwrap(),
954                PokemonType::from_str(split[3]).unwrap(),
955            ),
956            base_types: (
957                PokemonType::from_str(split[4]).unwrap(),
958                PokemonType::from_str(split[5]).unwrap(),
959            ),
960            hp: split[6].parse::<i16>().unwrap(),
961            maxhp: split[7].parse::<i16>().unwrap(),
962            ability: Abilities::from_str(split[8]).unwrap(),
963            base_ability: Abilities::from_str(split[9]).unwrap(),
964            item: Items::from_str(split[10]).unwrap(),
965            nature: PokemonNature::from_str(split[11]).unwrap(),
966            evs,
967            attack: split[13].parse::<i16>().unwrap(),
968            defense: split[14].parse::<i16>().unwrap(),
969            special_attack: split[15].parse::<i16>().unwrap(),
970            special_defense: split[16].parse::<i16>().unwrap(),
971            speed: split[17].parse::<i16>().unwrap(),
972            status: PokemonStatus::from_str(split[18]).unwrap(),
973            rest_turns: split[19].parse::<i8>().unwrap(),
974            sleep_turns: split[20].parse::<i8>().unwrap(),
975            weight_kg: split[21].parse::<f32>().unwrap(),
976            moves: PokemonMoves {
977                m0: Move::deserialize(split[22]),
978                m1: Move::deserialize(split[23]),
979                m2: Move::deserialize(split[24]),
980                m3: Move::deserialize(split[25]),
981            },
982            terastallized: split[26].parse::<bool>().unwrap(),
983            tera_type: PokemonType::from_str(split[27]).unwrap(),
984        }
985    }
986}
987
988#[derive(Debug, Clone)]
989pub struct Side {
990    pub active_index: PokemonIndex,
991    pub baton_passing: bool,
992    pub shed_tailing: bool,
993    pub pokemon: SidePokemon,
994    pub side_conditions: SideConditions,
995    pub volatile_status_durations: VolatileStatusDurations,
996    pub wish: (i8, i16),
997    pub future_sight: (i8, PokemonIndex),
998    pub force_switch: bool,
999    pub force_trapped: bool,
1000    pub slow_uturn_move: bool,
1001    pub volatile_statuses: HashSet<PokemonVolatileStatus>,
1002    pub substitute_health: i16,
1003    pub attack_boost: i8,
1004    pub defense_boost: i8,
1005    pub special_attack_boost: i8,
1006    pub special_defense_boost: i8,
1007    pub speed_boost: i8,
1008    pub accuracy_boost: i8,
1009    pub evasion_boost: i8,
1010    pub last_used_move: LastUsedMove,
1011    pub damage_dealt: DamageDealt,
1012    pub switch_out_move_second_saved_move: Choices,
1013}
1014impl Side {
1015    fn io_conditional_print(&self) -> String {
1016        let mut output = String::new();
1017        if self.baton_passing {
1018            output.push_str("\n  baton_passing: true");
1019        }
1020        if self.wish.0 != 0 {
1021            output.push_str(&format!("\n  wish: ({}, {})", self.wish.0, self.wish.1));
1022        }
1023        if self.future_sight.0 != 0 {
1024            output.push_str(&format!(
1025                "\n  future_sight: ({}, {:?})",
1026                self.future_sight.0, self.pokemon[self.future_sight.1].id
1027            ));
1028        }
1029        if self
1030            .volatile_statuses
1031            .contains(&PokemonVolatileStatus::SUBSTITUTE)
1032        {
1033            output.push_str(&format!(
1034                "\n  substitute_health: {}",
1035                self.substitute_health
1036            ));
1037        }
1038
1039        if !output.is_empty() {
1040            output.insert_str(0, "Extras:");
1041            output.push_str("\n");
1042        }
1043
1044        output
1045    }
1046    pub fn pprint(&self, available_choices: Vec<String>) -> String {
1047        let reserve = self
1048            .pokemon
1049            .into_iter()
1050            .map(|p| p.pprint_concise())
1051            .collect::<Vec<String>>();
1052        format!(
1053            "\nPokemon: {}\n\
1054            Active:{}\n\
1055            Boosts: {}\n\
1056            Last Used Move: {}\n\
1057            Volatiles: {:?}\n\
1058            VolatileDurations: {}\n\
1059            Side Conditions: {}\n\
1060            {}\
1061            Available Choices: {}",
1062            reserve.join(", "),
1063            self.get_active_immutable().pprint_verbose(),
1064            format!(
1065                "Attack:{}, Defense:{}, SpecialAttack:{}, SpecialDefense:{}, Speed:{}",
1066                self.attack_boost,
1067                self.defense_boost,
1068                self.special_attack_boost,
1069                self.special_defense_boost,
1070                self.speed_boost
1071            ),
1072            self.last_used_move.serialize(),
1073            self.volatile_statuses,
1074            self.volatile_status_durations.pprint(),
1075            self.side_conditions.pprint(),
1076            self.io_conditional_print(),
1077            available_choices.join(", ")
1078        )
1079    }
1080    pub fn serialize(&self) -> String {
1081        let mut vs_string = String::new();
1082        for vs in &self.volatile_statuses {
1083            vs_string.push_str(&vs.to_string());
1084            vs_string.push_str(":");
1085        }
1086        format!(
1087            "{}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}",
1088            self.pokemon.pkmn[0].serialize(),
1089            self.pokemon.pkmn[1].serialize(),
1090            self.pokemon.pkmn[2].serialize(),
1091            self.pokemon.pkmn[3].serialize(),
1092            self.pokemon.pkmn[4].serialize(),
1093            self.pokemon.pkmn[5].serialize(),
1094            self.active_index.serialize(),
1095            self.side_conditions.serialize(),
1096            vs_string,
1097            self.volatile_status_durations.serialize(),
1098            self.substitute_health,
1099            self.attack_boost,
1100            self.defense_boost,
1101            self.special_attack_boost,
1102            self.special_defense_boost,
1103            self.speed_boost,
1104            self.accuracy_boost,
1105            self.evasion_boost,
1106            self.wish.0,
1107            self.wish.1,
1108            self.future_sight.0,
1109            self.future_sight.1.serialize(),
1110            self.force_switch,
1111            self.switch_out_move_second_saved_move.to_string(),
1112            self.baton_passing,
1113            self.shed_tailing,
1114            self.force_trapped,
1115            self.last_used_move.serialize(),
1116            self.slow_uturn_move,
1117        )
1118    }
1119    pub fn deserialize(serialized: &str) -> Side {
1120        let split: Vec<&str> = serialized.split("=").collect();
1121
1122        let mut vs_hashset = HashSet::new();
1123        if split[8] != "" {
1124            for item in split[8].split(":") {
1125                vs_hashset.insert(PokemonVolatileStatus::from_str(item).unwrap());
1126            }
1127        }
1128        Side {
1129            pokemon: SidePokemon {
1130                pkmn: [
1131                    Pokemon::deserialize(split[0]),
1132                    Pokemon::deserialize(split[1]),
1133                    Pokemon::deserialize(split[2]),
1134                    Pokemon::deserialize(split[3]),
1135                    Pokemon::deserialize(split[4]),
1136                    Pokemon::deserialize(split[5]),
1137                ],
1138            },
1139            active_index: PokemonIndex::deserialize(split[6]),
1140            side_conditions: SideConditions::deserialize(split[7]),
1141            volatile_statuses: vs_hashset,
1142            volatile_status_durations: VolatileStatusDurations::deserialize(split[9]),
1143            substitute_health: split[10].parse::<i16>().unwrap(),
1144            attack_boost: split[11].parse::<i8>().unwrap(),
1145            defense_boost: split[12].parse::<i8>().unwrap(),
1146            special_attack_boost: split[13].parse::<i8>().unwrap(),
1147            special_defense_boost: split[14].parse::<i8>().unwrap(),
1148            speed_boost: split[15].parse::<i8>().unwrap(),
1149            accuracy_boost: split[16].parse::<i8>().unwrap(),
1150            evasion_boost: split[17].parse::<i8>().unwrap(),
1151            wish: (
1152                split[18].parse::<i8>().unwrap(),
1153                split[19].parse::<i16>().unwrap(),
1154            ),
1155            future_sight: (
1156                split[20].parse::<i8>().unwrap(),
1157                PokemonIndex::deserialize(split[21]),
1158            ),
1159            force_switch: split[22].parse::<bool>().unwrap(),
1160            switch_out_move_second_saved_move: Choices::from_str(split[23]).unwrap(),
1161            baton_passing: split[24].parse::<bool>().unwrap(),
1162            shed_tailing: split[25].parse::<bool>().unwrap(),
1163            force_trapped: split[26].parse::<bool>().unwrap(),
1164            last_used_move: LastUsedMove::deserialize(split[27]),
1165            damage_dealt: DamageDealt::default(),
1166            slow_uturn_move: split[28].parse::<bool>().unwrap(),
1167        }
1168    }
1169}
1170impl Side {
1171    pub fn visible_alive_pkmn(&self) -> i8 {
1172        let mut count = 0;
1173        for p in self.pokemon.into_iter() {
1174            if p.hp > 0 {
1175                count += 1;
1176            }
1177        }
1178        count
1179    }
1180    pub fn get_active(&mut self) -> &mut Pokemon {
1181        &mut self.pokemon[self.active_index]
1182    }
1183    pub fn get_active_immutable(&self) -> &Pokemon {
1184        &self.pokemon[self.active_index]
1185    }
1186    fn toggle_force_switch(&mut self) {
1187        self.force_switch = !self.force_switch;
1188    }
1189    pub fn get_side_condition(&self, side_condition: PokemonSideCondition) -> i8 {
1190        match side_condition {
1191            PokemonSideCondition::AuroraVeil => self.side_conditions.aurora_veil,
1192            PokemonSideCondition::CraftyShield => self.side_conditions.crafty_shield,
1193            PokemonSideCondition::HealingWish => self.side_conditions.healing_wish,
1194            PokemonSideCondition::LightScreen => self.side_conditions.light_screen,
1195            PokemonSideCondition::LuckyChant => self.side_conditions.lucky_chant,
1196            PokemonSideCondition::LunarDance => self.side_conditions.lunar_dance,
1197            PokemonSideCondition::MatBlock => self.side_conditions.mat_block,
1198            PokemonSideCondition::Mist => self.side_conditions.mist,
1199            PokemonSideCondition::Protect => self.side_conditions.protect,
1200            PokemonSideCondition::QuickGuard => self.side_conditions.quick_guard,
1201            PokemonSideCondition::Reflect => self.side_conditions.reflect,
1202            PokemonSideCondition::Safeguard => self.side_conditions.safeguard,
1203            PokemonSideCondition::Spikes => self.side_conditions.spikes,
1204            PokemonSideCondition::Stealthrock => self.side_conditions.stealth_rock,
1205            PokemonSideCondition::StickyWeb => self.side_conditions.sticky_web,
1206            PokemonSideCondition::Tailwind => self.side_conditions.tailwind,
1207            PokemonSideCondition::ToxicCount => self.side_conditions.toxic_count,
1208            PokemonSideCondition::ToxicSpikes => self.side_conditions.toxic_spikes,
1209            PokemonSideCondition::WideGuard => self.side_conditions.wide_guard,
1210        }
1211    }
1212    pub fn update_side_condition(&mut self, side_condition: PokemonSideCondition, amount: i8) {
1213        match side_condition {
1214            PokemonSideCondition::AuroraVeil => self.side_conditions.aurora_veil += amount,
1215            PokemonSideCondition::CraftyShield => self.side_conditions.crafty_shield += amount,
1216            PokemonSideCondition::HealingWish => self.side_conditions.healing_wish += amount,
1217            PokemonSideCondition::LightScreen => self.side_conditions.light_screen += amount,
1218            PokemonSideCondition::LuckyChant => self.side_conditions.lucky_chant += amount,
1219            PokemonSideCondition::LunarDance => self.side_conditions.lunar_dance += amount,
1220            PokemonSideCondition::MatBlock => self.side_conditions.mat_block += amount,
1221            PokemonSideCondition::Mist => self.side_conditions.mist += amount,
1222            PokemonSideCondition::Protect => self.side_conditions.protect += amount,
1223            PokemonSideCondition::QuickGuard => self.side_conditions.quick_guard += amount,
1224            PokemonSideCondition::Reflect => self.side_conditions.reflect += amount,
1225            PokemonSideCondition::Safeguard => self.side_conditions.safeguard += amount,
1226            PokemonSideCondition::Spikes => self.side_conditions.spikes += amount,
1227            PokemonSideCondition::Stealthrock => self.side_conditions.stealth_rock += amount,
1228            PokemonSideCondition::StickyWeb => self.side_conditions.sticky_web += amount,
1229            PokemonSideCondition::Tailwind => self.side_conditions.tailwind += amount,
1230            PokemonSideCondition::ToxicCount => self.side_conditions.toxic_count += amount,
1231            PokemonSideCondition::ToxicSpikes => self.side_conditions.toxic_spikes += amount,
1232            PokemonSideCondition::WideGuard => self.side_conditions.wide_guard += amount,
1233        }
1234    }
1235    pub fn get_alive_pkmn_indices(&self) -> Vec<PokemonIndex> {
1236        let mut vec = Vec::with_capacity(6);
1237        let mut iter = self.pokemon.into_iter();
1238
1239        while let Some(p) = iter.next() {
1240            if p.hp > 0 && iter.pokemon_index != self.active_index {
1241                vec.push(iter.pokemon_index.clone());
1242            }
1243        }
1244
1245        vec
1246    }
1247}
1248
1249#[derive(Debug, Clone)]
1250pub struct State {
1251    pub side_one: Side,
1252    pub side_two: Side,
1253    pub weather: StateWeather,
1254    pub terrain: StateTerrain,
1255    pub trick_room: StateTrickRoom,
1256    pub team_preview: bool,
1257    pub use_last_used_move: bool,
1258    pub use_damage_dealt: bool,
1259}
1260impl Default for State {
1261    fn default() -> State {
1262        let mut s = State {
1263            side_one: Side::default(),
1264            side_two: Side::default(),
1265            weather: StateWeather {
1266                weather_type: Weather::NONE,
1267                turns_remaining: -1,
1268            },
1269            terrain: StateTerrain {
1270                terrain_type: Terrain::NONE,
1271                turns_remaining: 0,
1272            },
1273            trick_room: StateTrickRoom {
1274                active: false,
1275                turns_remaining: 0,
1276            },
1277            team_preview: false,
1278            use_damage_dealt: false,
1279            use_last_used_move: false,
1280        };
1281
1282        // many tests rely on the speed of side 2's active pokemon being greater than side_one's
1283        s.side_two.get_active().speed += 1;
1284        s
1285    }
1286}
1287impl State {
1288    pub fn battle_is_over(&self) -> f32 {
1289        //  0 if battle is not over
1290        //  1 if side one has won
1291        // -1 if side two has won
1292        if self.side_one.pokemon.into_iter().all(|p| p.hp <= 0) {
1293            return -1.0;
1294        }
1295        if self.side_two.pokemon.into_iter().all(|p| p.hp <= 0) {
1296            return 1.0;
1297        }
1298        0.0
1299    }
1300
1301    pub fn get_side(&mut self, side_ref: &SideReference) -> &mut Side {
1302        match side_ref {
1303            SideReference::SideOne => &mut self.side_one,
1304            SideReference::SideTwo => &mut self.side_two,
1305        }
1306    }
1307
1308    pub fn get_side_immutable(&self, side_ref: &SideReference) -> &Side {
1309        match side_ref {
1310            SideReference::SideOne => &self.side_one,
1311            SideReference::SideTwo => &self.side_two,
1312        }
1313    }
1314
1315    pub fn get_both_sides(&mut self, side_ref: &SideReference) -> (&mut Side, &mut Side) {
1316        match side_ref {
1317            SideReference::SideOne => (&mut self.side_one, &mut self.side_two),
1318            SideReference::SideTwo => (&mut self.side_two, &mut self.side_one),
1319        }
1320    }
1321
1322    pub fn get_both_sides_immutable(&self, side_ref: &SideReference) -> (&Side, &Side) {
1323        match side_ref {
1324            SideReference::SideOne => (&self.side_one, &self.side_two),
1325            SideReference::SideTwo => (&self.side_two, &self.side_one),
1326        }
1327    }
1328
1329    pub fn reset_boosts(&mut self, side_ref: &SideReference, vec_to_add_to: &mut Vec<Instruction>) {
1330        let side = self.get_side(side_ref);
1331
1332        if side.attack_boost != 0 {
1333            vec_to_add_to.push(Instruction::Boost(BoostInstruction {
1334                side_ref: *side_ref,
1335                stat: PokemonBoostableStat::Attack,
1336                amount: -1 * side.attack_boost,
1337            }));
1338            side.attack_boost = 0;
1339        }
1340
1341        if side.defense_boost != 0 {
1342            vec_to_add_to.push(Instruction::Boost(BoostInstruction {
1343                side_ref: *side_ref,
1344                stat: PokemonBoostableStat::Defense,
1345                amount: -1 * side.defense_boost,
1346            }));
1347            side.defense_boost = 0;
1348        }
1349
1350        if side.special_attack_boost != 0 {
1351            vec_to_add_to.push(Instruction::Boost(BoostInstruction {
1352                side_ref: *side_ref,
1353                stat: PokemonBoostableStat::SpecialAttack,
1354                amount: -1 * side.special_attack_boost,
1355            }));
1356            side.special_attack_boost = 0;
1357        }
1358
1359        if side.special_defense_boost != 0 {
1360            vec_to_add_to.push(Instruction::Boost(BoostInstruction {
1361                side_ref: *side_ref,
1362                stat: PokemonBoostableStat::SpecialDefense,
1363                amount: -1 * side.special_defense_boost,
1364            }));
1365            side.special_defense_boost = 0;
1366        }
1367
1368        if side.speed_boost != 0 {
1369            vec_to_add_to.push(Instruction::Boost(BoostInstruction {
1370                side_ref: *side_ref,
1371                stat: PokemonBoostableStat::Speed,
1372                amount: -1 * side.speed_boost,
1373            }));
1374            side.speed_boost = 0;
1375        }
1376
1377        if side.evasion_boost != 0 {
1378            vec_to_add_to.push(Instruction::Boost(BoostInstruction {
1379                side_ref: *side_ref,
1380                stat: PokemonBoostableStat::Evasion,
1381                amount: -1 * side.evasion_boost,
1382            }));
1383            side.evasion_boost = 0;
1384        }
1385
1386        if side.accuracy_boost != 0 {
1387            vec_to_add_to.push(Instruction::Boost(BoostInstruction {
1388                side_ref: *side_ref,
1389                stat: PokemonBoostableStat::Accuracy,
1390                amount: -1 * side.accuracy_boost,
1391            }));
1392            side.accuracy_boost = 0;
1393        }
1394    }
1395
1396    pub fn re_enable_disabled_moves(
1397        &mut self,
1398        side_ref: &SideReference,
1399        vec_to_add_to: &mut Vec<Instruction>,
1400    ) {
1401        let active = self.get_side(side_ref).get_active();
1402        if active.moves.m0.disabled {
1403            active.moves.m0.disabled = false;
1404            vec_to_add_to.push(Instruction::EnableMove(EnableMoveInstruction {
1405                side_ref: *side_ref,
1406                move_index: PokemonMoveIndex::M0,
1407            }));
1408        }
1409        if active.moves.m1.disabled {
1410            active.moves.m1.disabled = false;
1411            vec_to_add_to.push(Instruction::EnableMove(EnableMoveInstruction {
1412                side_ref: *side_ref,
1413                move_index: PokemonMoveIndex::M1,
1414            }));
1415        }
1416        if active.moves.m2.disabled {
1417            active.moves.m2.disabled = false;
1418            vec_to_add_to.push(Instruction::EnableMove(EnableMoveInstruction {
1419                side_ref: *side_ref,
1420                move_index: PokemonMoveIndex::M2,
1421            }));
1422        }
1423        if active.moves.m3.disabled {
1424            active.moves.m3.disabled = false;
1425            vec_to_add_to.push(Instruction::EnableMove(EnableMoveInstruction {
1426                side_ref: *side_ref,
1427                move_index: PokemonMoveIndex::M3,
1428            }));
1429        }
1430    }
1431
1432    fn damage(&mut self, side_ref: &SideReference, amount: i16) {
1433        let active = self.get_side(&side_ref).get_active();
1434
1435        active.hp -= amount;
1436    }
1437
1438    fn heal(&mut self, side_ref: &SideReference, amount: i16) {
1439        let active = self.get_side(&side_ref).get_active();
1440
1441        active.hp += amount;
1442    }
1443
1444    fn switch(
1445        &mut self,
1446        side_ref: &SideReference,
1447        next_active_index: PokemonIndex,
1448        _: PokemonIndex,
1449    ) {
1450        let side = self.get_side(&side_ref);
1451        side.active_index = next_active_index;
1452    }
1453
1454    fn reverse_switch(
1455        &mut self,
1456        side_ref: &SideReference,
1457        _: PokemonIndex,
1458        previous_active_index: PokemonIndex,
1459    ) {
1460        let side = self.get_side(&side_ref);
1461        side.active_index = previous_active_index;
1462    }
1463
1464    fn apply_volatile_status(
1465        &mut self,
1466        side_ref: &SideReference,
1467        volatile_status: PokemonVolatileStatus,
1468    ) {
1469        self.get_side(&side_ref)
1470            .volatile_statuses
1471            .insert(volatile_status);
1472    }
1473
1474    fn remove_volatile_status(
1475        &mut self,
1476        side_ref: &SideReference,
1477        volatile_status: PokemonVolatileStatus,
1478    ) {
1479        self.get_side(&side_ref)
1480            .volatile_statuses
1481            .remove(&volatile_status);
1482    }
1483
1484    fn change_status(
1485        &mut self,
1486        side_ref: &SideReference,
1487        pokemon_index: PokemonIndex,
1488        new_status: PokemonStatus,
1489    ) {
1490        let pkmn = &mut self.get_side(&side_ref).pokemon[pokemon_index];
1491        pkmn.status = new_status;
1492    }
1493
1494    fn apply_boost(&mut self, side_ref: &SideReference, stat: &PokemonBoostableStat, amount: i8) {
1495        let side = self.get_side(&side_ref);
1496        match stat {
1497            PokemonBoostableStat::Attack => side.attack_boost += amount,
1498            PokemonBoostableStat::Defense => side.defense_boost += amount,
1499            PokemonBoostableStat::SpecialAttack => side.special_attack_boost += amount,
1500            PokemonBoostableStat::SpecialDefense => side.special_defense_boost += amount,
1501            PokemonBoostableStat::Speed => side.speed_boost += amount,
1502            PokemonBoostableStat::Evasion => side.evasion_boost += amount,
1503            PokemonBoostableStat::Accuracy => side.accuracy_boost += amount,
1504        }
1505    }
1506
1507    fn increment_side_condition(
1508        &mut self,
1509        side_ref: &SideReference,
1510        side_condition: &PokemonSideCondition,
1511        amount: i8,
1512    ) {
1513        let side = self.get_side(&side_ref);
1514
1515        match side_condition {
1516            PokemonSideCondition::AuroraVeil => side.side_conditions.aurora_veil += amount,
1517            PokemonSideCondition::CraftyShield => side.side_conditions.crafty_shield += amount,
1518            PokemonSideCondition::HealingWish => side.side_conditions.healing_wish += amount,
1519            PokemonSideCondition::LightScreen => side.side_conditions.light_screen += amount,
1520            PokemonSideCondition::LuckyChant => side.side_conditions.lucky_chant += amount,
1521            PokemonSideCondition::LunarDance => side.side_conditions.lunar_dance += amount,
1522            PokemonSideCondition::MatBlock => side.side_conditions.mat_block += amount,
1523            PokemonSideCondition::Mist => side.side_conditions.mist += amount,
1524            PokemonSideCondition::Protect => side.side_conditions.protect += amount,
1525            PokemonSideCondition::QuickGuard => side.side_conditions.quick_guard += amount,
1526            PokemonSideCondition::Reflect => side.side_conditions.reflect += amount,
1527            PokemonSideCondition::Safeguard => side.side_conditions.safeguard += amount,
1528            PokemonSideCondition::Spikes => side.side_conditions.spikes += amount,
1529            PokemonSideCondition::Stealthrock => side.side_conditions.stealth_rock += amount,
1530            PokemonSideCondition::StickyWeb => side.side_conditions.sticky_web += amount,
1531            PokemonSideCondition::Tailwind => side.side_conditions.tailwind += amount,
1532            PokemonSideCondition::ToxicCount => side.side_conditions.toxic_count += amount,
1533            PokemonSideCondition::ToxicSpikes => side.side_conditions.toxic_spikes += amount,
1534            PokemonSideCondition::WideGuard => side.side_conditions.wide_guard += amount,
1535        }
1536    }
1537
1538    fn increment_volatile_status_duration(
1539        &mut self,
1540        side_ref: &SideReference,
1541        volatile_status: &PokemonVolatileStatus,
1542        amount: i8,
1543    ) {
1544        let side = self.get_side(&side_ref);
1545        match volatile_status {
1546            PokemonVolatileStatus::CONFUSION => {
1547                side.volatile_status_durations.confusion += amount;
1548            }
1549            PokemonVolatileStatus::LOCKEDMOVE => {
1550                side.volatile_status_durations.lockedmove += amount;
1551            }
1552            PokemonVolatileStatus::ENCORE => {
1553                side.volatile_status_durations.encore += amount;
1554            }
1555            PokemonVolatileStatus::SLOWSTART => {
1556                side.volatile_status_durations.slowstart += amount;
1557            }
1558            PokemonVolatileStatus::TAUNT => {
1559                side.volatile_status_durations.taunt += amount;
1560            }
1561            PokemonVolatileStatus::YAWN => {
1562                side.volatile_status_durations.yawn += amount;
1563            }
1564            _ => panic!(
1565                "Invalid volatile status for increment_volatile_status_duration: {:?}",
1566                volatile_status
1567            ),
1568        }
1569    }
1570
1571    fn change_types(
1572        &mut self,
1573        side_reference: &SideReference,
1574        new_types: (PokemonType, PokemonType),
1575    ) {
1576        self.get_side(side_reference).get_active().types = new_types;
1577    }
1578
1579    fn change_item(&mut self, side_reference: &SideReference, new_item: Items) {
1580        self.get_side(side_reference).get_active().item = new_item;
1581    }
1582
1583    fn change_weather(&mut self, weather_type: Weather, turns_remaining: i8) {
1584        self.weather.weather_type = weather_type;
1585        self.weather.turns_remaining = turns_remaining;
1586    }
1587
1588    fn change_terrain(&mut self, terrain_type: Terrain, turns_remaining: i8) {
1589        self.terrain.terrain_type = terrain_type;
1590        self.terrain.turns_remaining = turns_remaining;
1591    }
1592
1593    fn enable_move(&mut self, side_reference: &SideReference, move_index: &PokemonMoveIndex) {
1594        self.get_side(side_reference).get_active().moves[move_index].disabled = false;
1595    }
1596
1597    fn disable_move(&mut self, side_reference: &SideReference, move_index: &PokemonMoveIndex) {
1598        self.get_side(side_reference).get_active().moves[move_index].disabled = true;
1599    }
1600
1601    fn set_wish(&mut self, side_reference: &SideReference, wish_amount_change: i16) {
1602        self.get_side(side_reference).wish.0 = 2;
1603        self.get_side(side_reference).wish.1 += wish_amount_change;
1604    }
1605
1606    fn unset_wish(&mut self, side_reference: &SideReference, wish_amount_change: i16) {
1607        self.get_side(side_reference).wish.0 = 0;
1608        self.get_side(side_reference).wish.1 -= wish_amount_change;
1609    }
1610
1611    fn increment_wish(&mut self, side_reference: &SideReference) {
1612        self.get_side(side_reference).wish.0 += 1;
1613    }
1614
1615    fn decrement_wish(&mut self, side_reference: &SideReference) {
1616        self.get_side(side_reference).wish.0 -= 1;
1617    }
1618
1619    fn set_future_sight(&mut self, side_reference: &SideReference, pokemon_index: PokemonIndex) {
1620        let side = self.get_side(side_reference);
1621        side.future_sight.0 = 3;
1622        side.future_sight.1 = pokemon_index;
1623    }
1624
1625    fn unset_future_sight(
1626        &mut self,
1627        side_reference: &SideReference,
1628        previous_pokemon_index: PokemonIndex,
1629    ) {
1630        let side = self.get_side(side_reference);
1631        side.future_sight.0 = 0;
1632        side.future_sight.1 = previous_pokemon_index;
1633    }
1634
1635    fn increment_future_sight(&mut self, side_reference: &SideReference) {
1636        self.get_side(side_reference).future_sight.0 += 1;
1637    }
1638
1639    fn decrement_future_sight(&mut self, side_reference: &SideReference) {
1640        self.get_side(side_reference).future_sight.0 -= 1;
1641    }
1642
1643    fn damage_substitute(&mut self, side_reference: &SideReference, amount: i16) {
1644        self.get_side(side_reference).substitute_health -= amount;
1645    }
1646
1647    fn heal_substitute(&mut self, side_reference: &SideReference, amount: i16) {
1648        self.get_side(side_reference).substitute_health += amount;
1649    }
1650
1651    fn set_substitute_health(&mut self, side_reference: &SideReference, amount: i16) {
1652        self.get_side(side_reference).substitute_health += amount;
1653    }
1654
1655    fn decrement_rest_turn(&mut self, side_reference: &SideReference) {
1656        self.get_side(side_reference).get_active().rest_turns -= 1;
1657    }
1658
1659    fn increment_rest_turn(&mut self, side_reference: &SideReference) {
1660        self.get_side(side_reference).get_active().rest_turns += 1;
1661    }
1662
1663    fn set_rest_turn(
1664        &mut self,
1665        side_reference: &SideReference,
1666        pokemon_index: PokemonIndex,
1667        amount: i8,
1668    ) {
1669        self.get_side(side_reference).pokemon[pokemon_index].rest_turns = amount;
1670    }
1671
1672    fn set_sleep_turn(
1673        &mut self,
1674        side_reference: &SideReference,
1675        pokemon_index: PokemonIndex,
1676        amount: i8,
1677    ) {
1678        self.get_side(side_reference).pokemon[pokemon_index].sleep_turns = amount;
1679    }
1680
1681    fn toggle_trickroom(&mut self, new_turns_remaining: i8) {
1682        self.trick_room.active = !self.trick_room.active;
1683        self.trick_room.turns_remaining = new_turns_remaining;
1684    }
1685
1686    fn set_last_used_move(&mut self, side_reference: &SideReference, last_used_move: LastUsedMove) {
1687        match side_reference {
1688            SideReference::SideOne => self.side_one.last_used_move = last_used_move,
1689            SideReference::SideTwo => self.side_two.last_used_move = last_used_move,
1690        }
1691    }
1692
1693    fn decrement_pp(
1694        &mut self,
1695        side_reference: &SideReference,
1696        move_index: &PokemonMoveIndex,
1697        amount: &i8,
1698    ) {
1699        match side_reference {
1700            SideReference::SideOne => self.side_one.get_active().moves[move_index].pp -= amount,
1701            SideReference::SideTwo => self.side_two.get_active().moves[move_index].pp -= amount,
1702        }
1703    }
1704
1705    fn increment_pp(
1706        &mut self,
1707        side_reference: &SideReference,
1708        move_index: &PokemonMoveIndex,
1709        amount: &i8,
1710    ) {
1711        match side_reference {
1712            SideReference::SideOne => self.side_one.get_active().moves[move_index].pp += amount,
1713            SideReference::SideTwo => self.side_two.get_active().moves[move_index].pp += amount,
1714        }
1715    }
1716
1717    pub fn apply_instructions(&mut self, instructions: &Vec<Instruction>) {
1718        for i in instructions {
1719            self.apply_one_instruction(i)
1720        }
1721    }
1722
1723    pub fn apply_one_instruction(&mut self, instruction: &Instruction) {
1724        match instruction {
1725            Instruction::Damage(instruction) => {
1726                self.damage(&instruction.side_ref, instruction.damage_amount)
1727            }
1728            Instruction::Switch(instruction) => self.switch(
1729                &instruction.side_ref,
1730                instruction.next_index,
1731                instruction.previous_index,
1732            ),
1733            Instruction::ApplyVolatileStatus(instruction) => {
1734                self.apply_volatile_status(&instruction.side_ref, instruction.volatile_status)
1735            }
1736            Instruction::RemoveVolatileStatus(instruction) => {
1737                self.remove_volatile_status(&instruction.side_ref, instruction.volatile_status)
1738            }
1739            Instruction::ChangeStatus(instruction) => self.change_status(
1740                &instruction.side_ref,
1741                instruction.pokemon_index,
1742                instruction.new_status,
1743            ),
1744            Instruction::Boost(instruction) => {
1745                self.apply_boost(&instruction.side_ref, &instruction.stat, instruction.amount)
1746            }
1747            Instruction::ChangeSideCondition(instruction) => self.increment_side_condition(
1748                &instruction.side_ref,
1749                &instruction.side_condition,
1750                instruction.amount,
1751            ),
1752            Instruction::ChangeVolatileStatusDuration(instruction) => self
1753                .increment_volatile_status_duration(
1754                    &instruction.side_ref,
1755                    &instruction.volatile_status,
1756                    instruction.amount,
1757                ),
1758            Instruction::ChangeWeather(instruction) => self.change_weather(
1759                instruction.new_weather,
1760                instruction.new_weather_turns_remaining,
1761            ),
1762            Instruction::DecrementWeatherTurnsRemaining => {
1763                self.weather.turns_remaining -= 1;
1764            }
1765            Instruction::ChangeTerrain(instruction) => self.change_terrain(
1766                instruction.new_terrain,
1767                instruction.new_terrain_turns_remaining,
1768            ),
1769            Instruction::DecrementTerrainTurnsRemaining => {
1770                self.terrain.turns_remaining -= 1;
1771            }
1772            Instruction::ChangeType(instruction) => {
1773                self.change_types(&instruction.side_ref, instruction.new_types)
1774            }
1775            Instruction::ChangeAbility(instruction) => {
1776                let active = self.get_side(&instruction.side_ref).get_active();
1777                active.ability =
1778                    Abilities::from(active.ability as i16 + instruction.ability_change);
1779            }
1780            Instruction::Heal(instruction) => {
1781                self.heal(&instruction.side_ref, instruction.heal_amount)
1782            }
1783            Instruction::ChangeItem(instruction) => {
1784                self.change_item(&instruction.side_ref, instruction.new_item)
1785            }
1786            Instruction::ChangeAttack(instruction) => {
1787                self.get_side(&instruction.side_ref).get_active().attack += instruction.amount;
1788            }
1789            Instruction::ChangeDefense(instruction) => {
1790                self.get_side(&instruction.side_ref).get_active().defense += instruction.amount;
1791            }
1792            Instruction::ChangeSpecialAttack(instruction) => {
1793                self.get_side(&instruction.side_ref)
1794                    .get_active()
1795                    .special_attack += instruction.amount;
1796            }
1797            Instruction::ChangeSpecialDefense(instruction) => {
1798                self.get_side(&instruction.side_ref)
1799                    .get_active()
1800                    .special_defense += instruction.amount;
1801            }
1802            Instruction::ChangeSpeed(instruction) => {
1803                self.get_side(&instruction.side_ref).get_active().speed += instruction.amount;
1804            }
1805            Instruction::EnableMove(instruction) => {
1806                self.enable_move(&instruction.side_ref, &instruction.move_index)
1807            }
1808            Instruction::DisableMove(instruction) => {
1809                self.disable_move(&instruction.side_ref, &instruction.move_index)
1810            }
1811            Instruction::ChangeWish(instruction) => {
1812                self.set_wish(&instruction.side_ref, instruction.wish_amount_change);
1813            }
1814            Instruction::DecrementWish(instruction) => {
1815                self.decrement_wish(&instruction.side_ref);
1816            }
1817            Instruction::SetFutureSight(instruction) => {
1818                self.set_future_sight(&instruction.side_ref, instruction.pokemon_index);
1819            }
1820            Instruction::DecrementFutureSight(instruction) => {
1821                self.decrement_future_sight(&instruction.side_ref);
1822            }
1823            Instruction::DamageSubstitute(instruction) => {
1824                self.damage_substitute(&instruction.side_ref, instruction.damage_amount);
1825            }
1826            Instruction::ChangeSubstituteHealth(instruction) => {
1827                self.set_substitute_health(&instruction.side_ref, instruction.health_change);
1828            }
1829            Instruction::SetRestTurns(instruction) => {
1830                self.set_rest_turn(
1831                    &instruction.side_ref,
1832                    instruction.pokemon_index,
1833                    instruction.new_turns,
1834                );
1835            }
1836            Instruction::SetSleepTurns(instruction) => {
1837                self.set_sleep_turn(
1838                    &instruction.side_ref,
1839                    instruction.pokemon_index,
1840                    instruction.new_turns,
1841                );
1842            }
1843            Instruction::DecrementRestTurns(instruction) => {
1844                self.decrement_rest_turn(&instruction.side_ref);
1845            }
1846            Instruction::ToggleTrickRoom(instruction) => {
1847                self.toggle_trickroom(instruction.new_trickroom_turns_remaining)
1848            }
1849            Instruction::DecrementTrickRoomTurnsRemaining => {
1850                self.trick_room.turns_remaining -= 1;
1851            }
1852            Instruction::ToggleSideOneForceSwitch => self.side_one.toggle_force_switch(),
1853            Instruction::ToggleSideTwoForceSwitch => self.side_two.toggle_force_switch(),
1854            Instruction::SetSideOneMoveSecondSwitchOutMove(instruction) => {
1855                self.side_one.switch_out_move_second_saved_move = instruction.new_choice;
1856            }
1857            Instruction::SetSideTwoMoveSecondSwitchOutMove(instruction) => {
1858                self.side_two.switch_out_move_second_saved_move = instruction.new_choice;
1859            }
1860            Instruction::ToggleBatonPassing(instruction) => match instruction.side_ref {
1861                SideReference::SideOne => {
1862                    self.side_one.baton_passing = !self.side_one.baton_passing
1863                }
1864                SideReference::SideTwo => {
1865                    self.side_two.baton_passing = !self.side_two.baton_passing
1866                }
1867            },
1868            Instruction::ToggleShedTailing(instruction) => match instruction.side_ref {
1869                SideReference::SideOne => self.side_one.shed_tailing = !self.side_one.shed_tailing,
1870                SideReference::SideTwo => self.side_two.shed_tailing = !self.side_two.shed_tailing,
1871            },
1872            Instruction::ToggleTerastallized(instruction) => match instruction.side_ref {
1873                SideReference::SideOne => self.side_one.get_active().terastallized ^= true,
1874                SideReference::SideTwo => self.side_two.get_active().terastallized ^= true,
1875            },
1876            Instruction::SetLastUsedMove(instruction) => {
1877                self.set_last_used_move(&instruction.side_ref, instruction.last_used_move)
1878            }
1879            Instruction::ChangeDamageDealtDamage(instruction) => {
1880                self.get_side(&instruction.side_ref).damage_dealt.damage +=
1881                    instruction.damage_change
1882            }
1883            Instruction::ChangeDamageDealtMoveCatagory(instruction) => {
1884                self.get_side(&instruction.side_ref)
1885                    .damage_dealt
1886                    .move_category = instruction.move_category
1887            }
1888            Instruction::ToggleDamageDealtHitSubstitute(instruction) => {
1889                let side = self.get_side(&instruction.side_ref);
1890                side.damage_dealt.hit_substitute = !side.damage_dealt.hit_substitute;
1891            }
1892            Instruction::DecrementPP(instruction) => self.decrement_pp(
1893                &instruction.side_ref,
1894                &instruction.move_index,
1895                &instruction.amount,
1896            ),
1897            Instruction::FormeChange(instruction) => {
1898                let active = self.get_side(&instruction.side_ref).get_active();
1899                active.id = PokemonName::from(active.id as i16 + instruction.name_change);
1900            }
1901        }
1902    }
1903
1904    pub fn reverse_instructions(&mut self, instructions: &Vec<Instruction>) {
1905        for i in instructions.iter().rev() {
1906            self.reverse_one_instruction(i);
1907        }
1908    }
1909
1910    pub fn reverse_one_instruction(&mut self, instruction: &Instruction) {
1911        match instruction {
1912            Instruction::Damage(instruction) => {
1913                self.heal(&instruction.side_ref, instruction.damage_amount)
1914            }
1915            Instruction::Switch(instruction) => self.reverse_switch(
1916                &instruction.side_ref,
1917                instruction.next_index,
1918                instruction.previous_index,
1919            ),
1920            Instruction::ApplyVolatileStatus(instruction) => {
1921                self.remove_volatile_status(&instruction.side_ref, instruction.volatile_status)
1922            }
1923            Instruction::RemoveVolatileStatus(instruction) => {
1924                self.apply_volatile_status(&instruction.side_ref, instruction.volatile_status)
1925            }
1926            Instruction::ChangeStatus(instruction) => self.change_status(
1927                &instruction.side_ref,
1928                instruction.pokemon_index,
1929                instruction.old_status,
1930            ),
1931            Instruction::Boost(instruction) => self.apply_boost(
1932                &instruction.side_ref,
1933                &instruction.stat,
1934                -1 * instruction.amount,
1935            ),
1936            Instruction::ChangeSideCondition(instruction) => self.increment_side_condition(
1937                &instruction.side_ref,
1938                &instruction.side_condition,
1939                -1 * instruction.amount,
1940            ),
1941            Instruction::ChangeVolatileStatusDuration(instruction) => self
1942                .increment_volatile_status_duration(
1943                    &instruction.side_ref,
1944                    &instruction.volatile_status,
1945                    -1 * instruction.amount,
1946                ),
1947            Instruction::ChangeWeather(instruction) => self.change_weather(
1948                instruction.previous_weather,
1949                instruction.previous_weather_turns_remaining,
1950            ),
1951            Instruction::DecrementWeatherTurnsRemaining => {
1952                self.weather.turns_remaining += 1;
1953            }
1954            Instruction::ChangeTerrain(instruction) => self.change_terrain(
1955                instruction.previous_terrain,
1956                instruction.previous_terrain_turns_remaining,
1957            ),
1958            Instruction::DecrementTerrainTurnsRemaining => {
1959                self.terrain.turns_remaining += 1;
1960            }
1961            Instruction::ChangeType(instruction) => {
1962                self.change_types(&instruction.side_ref, instruction.old_types)
1963            }
1964            Instruction::ChangeAbility(instruction) => {
1965                let active = self.get_side(&instruction.side_ref).get_active();
1966                active.ability =
1967                    Abilities::from(active.ability as i16 - instruction.ability_change);
1968            }
1969            Instruction::EnableMove(instruction) => {
1970                self.disable_move(&instruction.side_ref, &instruction.move_index)
1971            }
1972            Instruction::DisableMove(instruction) => {
1973                self.enable_move(&instruction.side_ref, &instruction.move_index)
1974            }
1975            Instruction::Heal(instruction) => {
1976                self.damage(&instruction.side_ref, instruction.heal_amount)
1977            }
1978            Instruction::ChangeItem(instruction) => {
1979                self.change_item(&instruction.side_ref, instruction.current_item)
1980            }
1981            Instruction::ChangeAttack(instruction) => {
1982                self.get_side(&instruction.side_ref).get_active().attack -= instruction.amount;
1983            }
1984            Instruction::ChangeDefense(instruction) => {
1985                self.get_side(&instruction.side_ref).get_active().defense -= instruction.amount;
1986            }
1987            Instruction::ChangeSpecialAttack(instruction) => {
1988                self.get_side(&instruction.side_ref)
1989                    .get_active()
1990                    .special_attack -= instruction.amount;
1991            }
1992            Instruction::ChangeSpecialDefense(instruction) => {
1993                self.get_side(&instruction.side_ref)
1994                    .get_active()
1995                    .special_defense -= instruction.amount;
1996            }
1997            Instruction::ChangeSpeed(instruction) => {
1998                self.get_side(&instruction.side_ref).get_active().speed -= instruction.amount;
1999            }
2000            Instruction::ChangeWish(instruction) => {
2001                self.unset_wish(&instruction.side_ref, instruction.wish_amount_change)
2002            }
2003            Instruction::DecrementWish(instruction) => self.increment_wish(&instruction.side_ref),
2004            Instruction::SetFutureSight(instruction) => {
2005                self.unset_future_sight(&instruction.side_ref, instruction.previous_pokemon_index)
2006            }
2007            Instruction::DecrementFutureSight(instruction) => {
2008                self.increment_future_sight(&instruction.side_ref)
2009            }
2010            Instruction::DamageSubstitute(instruction) => {
2011                self.heal_substitute(&instruction.side_ref, instruction.damage_amount);
2012            }
2013            Instruction::ChangeSubstituteHealth(instruction) => {
2014                self.set_substitute_health(&instruction.side_ref, -1 * instruction.health_change);
2015            }
2016            Instruction::SetRestTurns(instruction) => {
2017                self.set_rest_turn(
2018                    &instruction.side_ref,
2019                    instruction.pokemon_index,
2020                    instruction.previous_turns,
2021                );
2022            }
2023            Instruction::SetSleepTurns(instruction) => {
2024                self.set_sleep_turn(
2025                    &instruction.side_ref,
2026                    instruction.pokemon_index,
2027                    instruction.previous_turns,
2028                );
2029            }
2030            Instruction::DecrementRestTurns(instruction) => {
2031                self.increment_rest_turn(&instruction.side_ref);
2032            }
2033            Instruction::ToggleTrickRoom(instruction) => {
2034                self.toggle_trickroom(instruction.previous_trickroom_turns_remaining)
2035            }
2036            Instruction::DecrementTrickRoomTurnsRemaining => {
2037                self.trick_room.turns_remaining += 1;
2038            }
2039            Instruction::ToggleSideOneForceSwitch => self.side_one.toggle_force_switch(),
2040            Instruction::ToggleSideTwoForceSwitch => self.side_two.toggle_force_switch(),
2041            Instruction::SetSideOneMoveSecondSwitchOutMove(instruction) => {
2042                self.side_one.switch_out_move_second_saved_move = instruction.previous_choice;
2043            }
2044            Instruction::SetSideTwoMoveSecondSwitchOutMove(instruction) => {
2045                self.side_two.switch_out_move_second_saved_move = instruction.previous_choice;
2046            }
2047            Instruction::ToggleBatonPassing(instruction) => match instruction.side_ref {
2048                SideReference::SideOne => {
2049                    self.side_one.baton_passing = !self.side_one.baton_passing
2050                }
2051                SideReference::SideTwo => {
2052                    self.side_two.baton_passing = !self.side_two.baton_passing
2053                }
2054            },
2055            Instruction::ToggleShedTailing(instruction) => match instruction.side_ref {
2056                SideReference::SideOne => self.side_one.shed_tailing = !self.side_one.shed_tailing,
2057                SideReference::SideTwo => self.side_two.shed_tailing = !self.side_two.shed_tailing,
2058            },
2059            Instruction::ToggleTerastallized(instruction) => match instruction.side_ref {
2060                SideReference::SideOne => self.side_one.get_active().terastallized ^= true,
2061                SideReference::SideTwo => self.side_two.get_active().terastallized ^= true,
2062            },
2063            Instruction::SetLastUsedMove(instruction) => {
2064                self.set_last_used_move(&instruction.side_ref, instruction.previous_last_used_move)
2065            }
2066            Instruction::ChangeDamageDealtDamage(instruction) => {
2067                self.get_side(&instruction.side_ref).damage_dealt.damage -=
2068                    instruction.damage_change
2069            }
2070            Instruction::ChangeDamageDealtMoveCatagory(instruction) => {
2071                self.get_side(&instruction.side_ref)
2072                    .damage_dealt
2073                    .move_category = instruction.previous_move_category
2074            }
2075            Instruction::ToggleDamageDealtHitSubstitute(instruction) => {
2076                let side = self.get_side(&instruction.side_ref);
2077                side.damage_dealt.hit_substitute = !side.damage_dealt.hit_substitute;
2078            }
2079            Instruction::DecrementPP(instruction) => self.increment_pp(
2080                &instruction.side_ref,
2081                &instruction.move_index,
2082                &instruction.amount,
2083            ),
2084            Instruction::FormeChange(instruction) => {
2085                let active = self.get_side(&instruction.side_ref).get_active();
2086                active.id = PokemonName::from(active.id as i16 - instruction.name_change);
2087            }
2088        }
2089    }
2090}
2091impl State {
2092    pub fn pprint(&self) -> String {
2093        let (side_one_options, side_two_options) = self.root_get_all_options();
2094
2095        let mut side_one_choices = vec![];
2096        for option in side_one_options {
2097            side_one_choices.push(format!("{}", option.to_string(&self.side_one)).to_lowercase());
2098        }
2099        let mut side_two_choices = vec![];
2100        for option in side_two_options {
2101            side_two_choices.push(format!("{}", option.to_string(&self.side_two)).to_lowercase());
2102        }
2103        format!(
2104            "SideOne {}\n\nvs\n\nSideTwo {}\n\nState:\n  Weather: {:?},{}\n  Terrain: {:?},{}\n  TrickRoom: {},{}\n  UseLastUsedMove: {}\n  UseDamageDealt: {}",
2105            self.side_one.pprint(side_one_choices),
2106            self.side_two.pprint(side_two_choices),
2107            self.weather.weather_type,
2108            self.weather.turns_remaining,
2109            self.terrain.terrain_type,
2110            self.terrain.turns_remaining,
2111            self.trick_room.active,
2112            self.trick_room.turns_remaining,
2113            self.use_last_used_move,
2114            self.use_damage_dealt,
2115        )
2116    }
2117
2118    pub fn serialize(&self) -> String {
2119        format!(
2120            "{}/{}/{}/{}/{}/{}",
2121            self.side_one.serialize(),
2122            self.side_two.serialize(),
2123            self.weather.serialize(),
2124            self.terrain.serialize(),
2125            self.trick_room.serialize(),
2126            self.team_preview
2127        )
2128    }
2129
2130    /// ```
2131    ///
2132    /// /*
2133    /// This doctest does its best to show the format of the serialized state.
2134    ///
2135    /// Roughly, the format for a state is:
2136    ///     side1/side2/weather/terrain/trick_room/team_preview
2137    ///
2138    /// Where the format for a side is:
2139    ///     p0=p1=p2=p3=p4=p5=active_index=side_conditions=wish0=wish1=force_switch=switch_out_move_second_saved_move=baton_passing=shed_tailing=force_trapped=last_used_move=slow_uturn_move
2140    ///
2141    /// And the format for a pokemon is:
2142    ///    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
2143    ///
2144    /// There's more to it, follow the code below to see a full example of a serialized state.
2145    /// */
2146    ///
2147    /// if cfg!(feature = "gen2") {
2148    ///    return;
2149    /// }
2150    ///
2151    /// use poke_engine::engine::abilities::Abilities;
2152    /// use poke_engine::engine::items::Items;
2153    /// use poke_engine::pokemon::PokemonName;
2154    /// use poke_engine::state::State;
2155    ///
2156    /// let serialized_state = concat!(
2157    ///
2158    /// // SIDE 1
2159    ///
2160    /// // POKEMON 1
2161    ///
2162    /// // name
2163    /// "alakazam,",
2164    ///
2165    /// // level
2166    /// "100,",
2167    ///
2168    /// // type1
2169    /// "Psychic,",
2170    ///
2171    /// // type2
2172    /// "Typeless,",
2173    ///
2174    /// // base_types 1 and 2. These are needed to revert to the correct type when switching out after being typechanged
2175    /// "Psychic,",
2176    /// "Typeless,",
2177    ///
2178    /// // hp
2179    /// "251,",
2180    ///
2181    /// // maxhp
2182    /// "251,",
2183    ///
2184    /// // ability
2185    /// "NONE,",
2186    ///
2187    /// // base ability. This is needed to revert to the correct ability when switching out after having the ability changed
2188    /// "NONE,",
2189    ///
2190    /// // item
2191    /// "LIFEORB,",
2192    ///
2193    /// // nature
2194    /// "SERIOUS,",
2195    ///
2196    /// // EVs split by `;`. Leave blank for default EVs (85 in all)
2197    /// "252;0;252;0;4;0,",
2198    /// // ",", left blank for default EVs
2199    ///
2200    /// // attack,defense,special attack,special defense,speed
2201    /// // note these are final stats, not base stats
2202    /// "121,148,353,206,365,",
2203    ///
2204    /// // status
2205    /// "None,",
2206    ///
2207    /// // rest_turns
2208    /// "0,",
2209    ///
2210    /// // sleep_turns
2211    /// "0,",
2212    ///
2213    /// // weight_kg
2214    /// "25.5,",
2215    ///
2216    /// // moves 1 through 4 (move_id;disabled;pp)
2217    /// "PSYCHIC;false;16,GRASSKNOT;false;32,SHADOWBALL;false;24,HIDDENPOWERFIRE70;false;24,",
2218    ///
2219    /// // terastallized
2220    /// "false,",
2221    ///
2222    /// // tera_type
2223    /// "Normal=",
2224    ///
2225    /// // all remaining Pokémon shown in 1 line for brevity
2226    /// "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=",
2227    /// "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=",
2228    /// "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=",
2229    /// "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=",
2230    /// "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=",
2231    ///
2232    /// // active-index. This is the index of the active Pokémon in the side's Pokémon array
2233    /// "0=",
2234    ///
2235    /// // side conditions are integers
2236    /// "0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;=",
2237    ///
2238    /// // volatile_statuses (delimited by ":")
2239    /// "=",
2240    ///
2241    /// // some volatile statuses have durations associated with them, delimited by ;
2242    /// "0;0;0;0;0;0=",
2243    ///
2244    /// // substitute_health
2245    /// "0=",
2246    ///
2247    /// // For the active pokemon:
2248    /// // attack_boost,defense_boost,special attack_boost,special defense_boost,speed_boost,accuracy_boost,evasion_boost
2249    /// "0=0=0=0=0=0=0=",
2250    ///
2251    /// // wish condition is represented by 2 integers, the first is how many wish turns remaining, the second is the amount of HP to heal
2252    /// "0=",
2253    /// "0=",
2254    ///
2255    /// // future sight is represented by the PokemonIndex of the pokemon that used futuresight, and the number of turns remaining until it hits
2256    /// "0=",
2257    /// "0=",
2258    ///
2259    /// // a boolean representing if the side is forced to switch
2260    /// "false=",
2261    ///
2262    /// // a 'saved moved' that a pokemon may be waiting to use after the opponent finished their uturn/volt switch/etc.
2263    /// "NONE=",
2264    ///
2265    /// // a boolean representing if the side is baton passing
2266    /// "false=",
2267    ///
2268    /// // a boolean representing if the side is shed tailing
2269    /// "false=",
2270    ///
2271    /// // a boolean representing if the side is force trapped. This is only ever externally provided and never changed by the engine
2272    /// "false=",
2273    ///
2274    /// // last used move is a string that can be either "move:move_name" or "switch:pokemon_index"
2275    /// "switch:0=",
2276    ///
2277    /// // a boolean representing if the side is slow uturning.
2278    /// // This is only ever set externally. It is used to know if the opposing side has a stored move to use after uturn.
2279    /// "false/",
2280    ///
2281    /// // SIDE 2, all in one line for brevity
2282    /// "terrakion,100,Rock,Fighting,Rock,Fighting,323,323,NONE,NONE,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,NONE,NONE,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,NONE,NONE,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=0=0=0=false=NONE=false=false=false=switch:0=false/",
2283    ///
2284    /// // weather is a string representing the weather type and the number of turns remaining
2285    /// "none;5/",
2286    ///
2287    /// // terrain is a string representing the terrain type and the number of turns remaining
2288    /// "none;5/",
2289    ///
2290    /// // trick room is a boolean representing if trick room is active and the number of turns remaining
2291    /// "false;5/",
2292    ///
2293    /// // team preview is a boolean representing if the team preview is active
2294    /// "false"
2295    ///
2296    /// );
2297    ///
2298    /// let state = State::deserialize(serialized_state);
2299    ///
2300    /// assert_eq!(state.side_one.get_active_immutable().id, PokemonName::ALAKAZAM);
2301    /// assert_eq!(state.side_one.get_active_immutable().weight_kg, 25.5);
2302    /// assert_eq!(state.side_one.substitute_health, 0);
2303    /// assert_eq!(state.side_two.get_active_immutable().id, PokemonName::TERRAKION);
2304    /// assert_eq!(state.trick_room.active, false);
2305    /// assert_eq!(state.team_preview, false);
2306    ///
2307    ///
2308    /// // the same state, but all in one line
2309    /// let serialized_state = "alakazam,100,Psychic,Typeless,Psychic,Typeless,251,251,NONE,NONE,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=0=0=0=false=NONE=false=false=false=switch:0=false/terrakion,100,Rock,Fighting,Rock,Fighting,323,323,NONE,NONE,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,NONE,NONE,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,NONE,NONE,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=0=0=0=false=NONE=false=false=false=switch:0=false/none;5/none;5/false;5/false";
2310    /// let state2 = State::deserialize(serialized_state);
2311    /// assert_eq!(state.serialize(), state2.serialize());
2312    ///
2313    /// ```
2314    pub fn deserialize(serialized: &str) -> State {
2315        let split: Vec<&str> = serialized.split("/").collect();
2316        let mut state = State {
2317            side_one: Side::deserialize(split[0]),
2318            side_two: Side::deserialize(split[1]),
2319            weather: StateWeather::deserialize(split[2]),
2320            terrain: StateTerrain::deserialize(split[3]),
2321            trick_room: StateTrickRoom::deserialize(split[4]),
2322            team_preview: split[5].parse::<bool>().unwrap(),
2323            use_damage_dealt: false,
2324            use_last_used_move: false,
2325        };
2326        state.set_conditional_mechanics();
2327        state
2328    }
2329}