poke_engine/
state.rs

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