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