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 pokemon: SidePokemon,
1116    pub side_conditions: SideConditions,
1117    pub volatile_status_durations: VolatileStatusDurations,
1118    pub wish: (i8, i16),
1119    pub future_sight: (i8, PokemonIndex),
1120    pub force_switch: bool,
1121    pub force_trapped: bool,
1122    pub slow_uturn_move: bool,
1123    pub volatile_statuses: HashSet<PokemonVolatileStatus>,
1124    pub substitute_health: i16,
1125    pub attack_boost: i8,
1126    pub defense_boost: i8,
1127    pub special_attack_boost: i8,
1128    pub special_defense_boost: i8,
1129    pub speed_boost: i8,
1130    pub accuracy_boost: i8,
1131    pub evasion_boost: i8,
1132    pub last_used_move: LastUsedMove,
1133    pub damage_dealt: DamageDealt,
1134    pub switch_out_move_second_saved_move: Choices,
1135}
1136
1137impl Side {
1138    pub fn active_is_charging_move(&self) -> Option<PokemonMoveIndex> {
1139        for volatile in self.volatile_statuses.iter() {
1140            if let Some(choice) = charge_volatile_to_choice(volatile) {
1141                let mut iter = self.get_active_immutable().moves.into_iter();
1142                while let Some(mv) = iter.next() {
1143                    if mv.id == choice {
1144                        return Some(iter.pokemon_move_index);
1145                    }
1146                }
1147            }
1148        }
1149        None
1150    }
1151
1152    pub fn calculate_highest_stat(&self) -> PokemonBoostableStat {
1153        let mut highest_stat = PokemonBoostableStat::Attack;
1154        let mut highest_stat_value = self.calculate_boosted_stat(PokemonBoostableStat::Attack);
1155        for stat in [
1156            PokemonBoostableStat::Defense,
1157            PokemonBoostableStat::SpecialAttack,
1158            PokemonBoostableStat::SpecialDefense,
1159            PokemonBoostableStat::Speed,
1160        ] {
1161            let stat_value = self.calculate_boosted_stat(stat);
1162            if stat_value > highest_stat_value {
1163                highest_stat = stat;
1164                highest_stat_value = stat_value;
1165            }
1166        }
1167        highest_stat
1168    }
1169    pub fn get_boost_from_boost_enum(&self, boost_enum: &PokemonBoostableStat) -> i8 {
1170        match boost_enum {
1171            PokemonBoostableStat::Attack => self.attack_boost,
1172            PokemonBoostableStat::Defense => self.defense_boost,
1173            PokemonBoostableStat::SpecialAttack => self.special_attack_boost,
1174            PokemonBoostableStat::SpecialDefense => self.special_defense_boost,
1175            PokemonBoostableStat::Speed => self.speed_boost,
1176            PokemonBoostableStat::Evasion => self.evasion_boost,
1177            PokemonBoostableStat::Accuracy => self.accuracy_boost,
1178        }
1179    }
1180
1181    pub fn calculate_boosted_stat(&self, stat: PokemonBoostableStat) -> i16 {
1182        /*
1183        In Gen4, simple doubles the effective boost, without it visually being doubled
1184        It will not boost beyond an effective value of 6 though.
1185        */
1186        let active = self.get_active_immutable();
1187        match stat {
1188            PokemonBoostableStat::Attack => {
1189                #[cfg(feature = "gen4")]
1190                let boost = if active.ability == Abilities::SIMPLE {
1191                    (self.attack_boost * 2).min(6).max(-6)
1192                } else {
1193                    self.attack_boost
1194                };
1195
1196                #[cfg(not(feature = "gen4"))]
1197                let boost = self.attack_boost;
1198
1199                multiply_boost(boost, active.attack)
1200            }
1201            PokemonBoostableStat::Defense => {
1202                #[cfg(feature = "gen4")]
1203                let boost = if active.ability == Abilities::SIMPLE {
1204                    (self.defense_boost * 2).min(6).max(-6)
1205                } else {
1206                    self.defense_boost
1207                };
1208                #[cfg(not(feature = "gen4"))]
1209                let boost = self.defense_boost;
1210
1211                multiply_boost(boost, active.defense)
1212            }
1213            PokemonBoostableStat::SpecialAttack => {
1214                #[cfg(feature = "gen4")]
1215                let boost = if active.ability == Abilities::SIMPLE {
1216                    (self.special_attack_boost * 2).min(6).max(-6)
1217                } else {
1218                    self.special_attack_boost
1219                };
1220                #[cfg(not(feature = "gen4"))]
1221                let boost = self.special_attack_boost;
1222
1223                multiply_boost(boost, active.special_attack)
1224            }
1225            PokemonBoostableStat::SpecialDefense => {
1226                #[cfg(feature = "gen4")]
1227                let boost = if active.ability == Abilities::SIMPLE {
1228                    (self.special_defense_boost * 2).min(6).max(-6)
1229                } else {
1230                    self.special_defense_boost
1231                };
1232                #[cfg(not(feature = "gen4"))]
1233                let boost = self.special_defense_boost;
1234
1235                multiply_boost(boost, active.special_defense)
1236            }
1237            PokemonBoostableStat::Speed => {
1238                #[cfg(feature = "gen4")]
1239                let boost = if active.ability == Abilities::SIMPLE {
1240                    (self.speed_boost * 2).min(6).max(-6)
1241                } else {
1242                    self.speed_boost
1243                };
1244                #[cfg(not(feature = "gen4"))]
1245                let boost = self.speed_boost;
1246
1247                multiply_boost(boost, active.speed)
1248            }
1249            _ => {
1250                panic!("Not implemented")
1251            }
1252        }
1253    }
1254
1255    pub fn has_alive_non_rested_sleeping_pkmn(&self) -> bool {
1256        for p in self.pokemon.into_iter() {
1257            if p.status == PokemonStatus::SLEEP && p.hp > 0 && p.rest_turns == 0 {
1258                return true;
1259            }
1260        }
1261        false
1262    }
1263
1264    #[cfg(not(feature = "terastallization"))]
1265    pub fn can_use_tera(&self) -> bool {
1266        false
1267    }
1268
1269    #[cfg(feature = "terastallization")]
1270    pub fn can_use_tera(&self) -> bool {
1271        for p in self.pokemon.into_iter() {
1272            if p.terastallized {
1273                return false;
1274            }
1275        }
1276        true
1277    }
1278
1279    fn toggle_force_switch(&mut self) {
1280        self.force_switch = !self.force_switch;
1281    }
1282
1283    pub fn add_switches(&self, vec: &mut Vec<MoveChoice>) {
1284        let mut iter = self.pokemon.into_iter();
1285        while let Some(p) = iter.next() {
1286            if p.hp > 0 && iter.pokemon_index != self.active_index {
1287                vec.push(MoveChoice::Switch(iter.pokemon_index));
1288            }
1289        }
1290        if vec.len() == 0 {
1291            vec.push(MoveChoice::None);
1292        }
1293    }
1294
1295    pub fn trapped(&self, opponent_active: &Pokemon) -> bool {
1296        let active_pkmn = self.get_active_immutable();
1297        if self
1298            .volatile_statuses
1299            .contains(&PokemonVolatileStatus::LOCKEDMOVE)
1300        {
1301            return true;
1302        }
1303        if active_pkmn.item == Items::SHEDSHELL || active_pkmn.has_type(&PokemonType::GHOST) {
1304            return false;
1305        } else if self
1306            .volatile_statuses
1307            .contains(&PokemonVolatileStatus::PARTIALLYTRAPPED)
1308        {
1309            return true;
1310        } else if opponent_active.ability == Abilities::SHADOWTAG {
1311            return true;
1312        } else if opponent_active.ability == Abilities::ARENATRAP && active_pkmn.is_grounded() {
1313            return true;
1314        } else if opponent_active.ability == Abilities::MAGNETPULL
1315            && active_pkmn.has_type(&PokemonType::STEEL)
1316        {
1317            return true;
1318        }
1319        false
1320    }
1321
1322    pub fn get_active(&mut self) -> &mut Pokemon {
1323        &mut self.pokemon[self.active_index]
1324    }
1325
1326    pub fn get_active_immutable(&self) -> &Pokemon {
1327        &self.pokemon[self.active_index]
1328    }
1329
1330    pub fn num_fainted_pkmn(&self) -> i8 {
1331        let mut count = 0;
1332        for p in self.pokemon.into_iter() {
1333            if p.hp == 0 {
1334                count += 1;
1335            }
1336        }
1337        count
1338    }
1339
1340    pub fn visible_alive_pkmn(&self) -> i8 {
1341        let mut count = 0;
1342        for p in self.pokemon.into_iter() {
1343            if p.hp > 0 {
1344                count += 1;
1345            }
1346        }
1347        count
1348    }
1349
1350    pub fn get_alive_pkmn_indices(&self) -> Vec<PokemonIndex> {
1351        let mut vec = Vec::with_capacity(6);
1352        let mut iter = self.pokemon.into_iter();
1353
1354        while let Some(p) = iter.next() {
1355            if p.hp > 0 && iter.pokemon_index != self.active_index {
1356                vec.push(iter.pokemon_index.clone());
1357            }
1358        }
1359
1360        vec
1361    }
1362
1363    pub fn get_side_condition(&self, side_condition: PokemonSideCondition) -> i8 {
1364        match side_condition {
1365            PokemonSideCondition::AuroraVeil => self.side_conditions.aurora_veil,
1366            PokemonSideCondition::CraftyShield => self.side_conditions.crafty_shield,
1367            PokemonSideCondition::HealingWish => self.side_conditions.healing_wish,
1368            PokemonSideCondition::LightScreen => self.side_conditions.light_screen,
1369            PokemonSideCondition::LuckyChant => self.side_conditions.lucky_chant,
1370            PokemonSideCondition::LunarDance => self.side_conditions.lunar_dance,
1371            PokemonSideCondition::MatBlock => self.side_conditions.mat_block,
1372            PokemonSideCondition::Mist => self.side_conditions.mist,
1373            PokemonSideCondition::Protect => self.side_conditions.protect,
1374            PokemonSideCondition::QuickGuard => self.side_conditions.quick_guard,
1375            PokemonSideCondition::Reflect => self.side_conditions.reflect,
1376            PokemonSideCondition::Safeguard => self.side_conditions.safeguard,
1377            PokemonSideCondition::Spikes => self.side_conditions.spikes,
1378            PokemonSideCondition::Stealthrock => self.side_conditions.stealth_rock,
1379            PokemonSideCondition::StickyWeb => self.side_conditions.sticky_web,
1380            PokemonSideCondition::Tailwind => self.side_conditions.tailwind,
1381            PokemonSideCondition::ToxicCount => self.side_conditions.toxic_count,
1382            PokemonSideCondition::ToxicSpikes => self.side_conditions.toxic_spikes,
1383            PokemonSideCondition::WideGuard => self.side_conditions.wide_guard,
1384        }
1385    }
1386
1387    pub fn update_side_condition(&mut self, side_condition: PokemonSideCondition, amount: i8) {
1388        match side_condition {
1389            PokemonSideCondition::AuroraVeil => self.side_conditions.aurora_veil += amount,
1390            PokemonSideCondition::CraftyShield => self.side_conditions.crafty_shield += amount,
1391            PokemonSideCondition::HealingWish => self.side_conditions.healing_wish += amount,
1392            PokemonSideCondition::LightScreen => self.side_conditions.light_screen += amount,
1393            PokemonSideCondition::LuckyChant => self.side_conditions.lucky_chant += amount,
1394            PokemonSideCondition::LunarDance => self.side_conditions.lunar_dance += amount,
1395            PokemonSideCondition::MatBlock => self.side_conditions.mat_block += amount,
1396            PokemonSideCondition::Mist => self.side_conditions.mist += amount,
1397            PokemonSideCondition::Protect => self.side_conditions.protect += amount,
1398            PokemonSideCondition::QuickGuard => self.side_conditions.quick_guard += amount,
1399            PokemonSideCondition::Reflect => self.side_conditions.reflect += amount,
1400            PokemonSideCondition::Safeguard => self.side_conditions.safeguard += amount,
1401            PokemonSideCondition::Spikes => self.side_conditions.spikes += amount,
1402            PokemonSideCondition::Stealthrock => self.side_conditions.stealth_rock += amount,
1403            PokemonSideCondition::StickyWeb => self.side_conditions.sticky_web += amount,
1404            PokemonSideCondition::Tailwind => self.side_conditions.tailwind += amount,
1405            PokemonSideCondition::ToxicCount => self.side_conditions.toxic_count += amount,
1406            PokemonSideCondition::ToxicSpikes => self.side_conditions.toxic_spikes += amount,
1407            PokemonSideCondition::WideGuard => self.side_conditions.wide_guard += amount,
1408        }
1409    }
1410}
1411
1412impl Default for Side {
1413    fn default() -> Side {
1414        Side {
1415            active_index: PokemonIndex::P0,
1416            baton_passing: false,
1417            pokemon: SidePokemon {
1418                p0: Pokemon {
1419                    ..Pokemon::default()
1420                },
1421                p1: Pokemon {
1422                    ..Pokemon::default()
1423                },
1424                p2: Pokemon {
1425                    ..Pokemon::default()
1426                },
1427                p3: Pokemon {
1428                    ..Pokemon::default()
1429                },
1430                p4: Pokemon {
1431                    ..Pokemon::default()
1432                },
1433                p5: Pokemon {
1434                    ..Pokemon::default()
1435                },
1436            },
1437            substitute_health: 0,
1438            attack_boost: 0,
1439            defense_boost: 0,
1440            special_attack_boost: 0,
1441            special_defense_boost: 0,
1442            speed_boost: 0,
1443            accuracy_boost: 0,
1444            side_conditions: SideConditions {
1445                ..Default::default()
1446            },
1447            volatile_status_durations: VolatileStatusDurations::default(),
1448            volatile_statuses: HashSet::<PokemonVolatileStatus>::new(),
1449            wish: (0, 0),
1450            future_sight: (0, PokemonIndex::P0),
1451            force_switch: false,
1452            slow_uturn_move: false,
1453            force_trapped: false,
1454            last_used_move: LastUsedMove::None,
1455            damage_dealt: DamageDealt::default(),
1456            switch_out_move_second_saved_move: Choices::NONE,
1457            evasion_boost: 0,
1458        }
1459    }
1460}
1461
1462#[derive(Debug, Clone)]
1463pub struct State {
1464    pub side_one: Side,
1465    pub side_two: Side,
1466    pub weather: StateWeather,
1467    pub terrain: StateTerrain,
1468    pub trick_room: StateTrickRoom,
1469    pub team_preview: bool,
1470    pub use_last_used_move: bool,
1471    pub use_damage_dealt: bool,
1472}
1473
1474impl Default for State {
1475    fn default() -> State {
1476        let mut s = State {
1477            side_one: Side::default(),
1478            side_two: Side::default(),
1479            weather: StateWeather {
1480                weather_type: Weather::NONE,
1481                turns_remaining: -1,
1482            },
1483            terrain: StateTerrain {
1484                terrain_type: Terrain::NONE,
1485                turns_remaining: 0,
1486            },
1487            trick_room: StateTrickRoom {
1488                active: false,
1489                turns_remaining: 0,
1490            },
1491            team_preview: false,
1492            use_damage_dealt: false,
1493            use_last_used_move: false,
1494        };
1495
1496        // many tests rely on the speed of side 2's active pokemon being greater than side_one's
1497        s.side_two.get_active().speed += 1;
1498        s
1499    }
1500}
1501
1502impl State {
1503    pub fn battle_is_over(&self) -> f32 {
1504        //  0 if battle is not over
1505        //  1 if side one has won
1506        // -1 if side two has won
1507        if self.side_one.pokemon.into_iter().all(|p| p.hp <= 0) {
1508            return -1.0;
1509        }
1510        if self.side_two.pokemon.into_iter().all(|p| p.hp <= 0) {
1511            return 1.0;
1512        }
1513        0.0
1514    }
1515
1516    pub fn get_all_options(&self) -> (Vec<MoveChoice>, Vec<MoveChoice>) {
1517        let mut side_one_options: Vec<MoveChoice> = Vec::with_capacity(9);
1518        let mut side_two_options: Vec<MoveChoice> = Vec::with_capacity(9);
1519
1520        let side_one_active = self.side_one.get_active_immutable();
1521        let side_two_active = self.side_two.get_active_immutable();
1522
1523        if self.side_one.force_switch {
1524            self.side_one.add_switches(&mut side_one_options);
1525            if self.side_two.switch_out_move_second_saved_move == Choices::NONE {
1526                side_two_options.push(MoveChoice::None);
1527            } else {
1528                self.side_two.get_active_immutable().add_move_from_choice(
1529                    &mut side_two_options,
1530                    self.side_two.switch_out_move_second_saved_move,
1531                );
1532            }
1533            return (side_one_options, side_two_options);
1534        }
1535
1536        if self.side_two.force_switch {
1537            self.side_two.add_switches(&mut side_two_options);
1538            if self.side_one.switch_out_move_second_saved_move == Choices::NONE {
1539                side_one_options.push(MoveChoice::None);
1540            } else {
1541                self.side_one.get_active_immutable().add_move_from_choice(
1542                    &mut side_one_options,
1543                    self.side_one.switch_out_move_second_saved_move,
1544                );
1545            }
1546            return (side_one_options, side_two_options);
1547        }
1548
1549        let side_one_force_switch = self.side_one.get_active_immutable().hp <= 0;
1550        let side_two_force_switch = self.side_two.get_active_immutable().hp <= 0;
1551
1552        if side_one_force_switch && side_two_force_switch {
1553            self.side_one.add_switches(&mut side_one_options);
1554            self.side_two.add_switches(&mut side_two_options);
1555            return (side_one_options, side_two_options);
1556        }
1557        if side_one_force_switch {
1558            self.side_one.add_switches(&mut side_one_options);
1559            side_two_options.push(MoveChoice::None);
1560            return (side_one_options, side_two_options);
1561        }
1562        if side_two_force_switch {
1563            side_one_options.push(MoveChoice::None);
1564            self.side_two.add_switches(&mut side_two_options);
1565            return (side_one_options, side_two_options);
1566        }
1567
1568        if self
1569            .side_one
1570            .volatile_statuses
1571            .contains(&PokemonVolatileStatus::MUSTRECHARGE)
1572        {
1573            side_one_options.push(MoveChoice::None);
1574        } else if let Some(mv_index) = self.side_one.active_is_charging_move() {
1575            side_one_options.push(MoveChoice::Move(mv_index));
1576        } else {
1577            let encored = self
1578                .side_one
1579                .volatile_statuses
1580                .contains(&PokemonVolatileStatus::ENCORE);
1581            self.side_one.get_active_immutable().add_available_moves(
1582                &mut side_one_options,
1583                &self.side_one.last_used_move,
1584                encored,
1585                self.side_one.can_use_tera(),
1586            );
1587            if !self.side_one.trapped(side_two_active) {
1588                self.side_one.add_switches(&mut side_one_options);
1589            }
1590        }
1591
1592        if self
1593            .side_two
1594            .volatile_statuses
1595            .contains(&PokemonVolatileStatus::MUSTRECHARGE)
1596        {
1597            side_two_options.push(MoveChoice::None);
1598        } else if let Some(mv_index) = self.side_two.active_is_charging_move() {
1599            side_two_options.push(MoveChoice::Move(mv_index));
1600        } else {
1601            let encored = self
1602                .side_two
1603                .volatile_statuses
1604                .contains(&PokemonVolatileStatus::ENCORE);
1605            self.side_two.get_active_immutable().add_available_moves(
1606                &mut side_two_options,
1607                &self.side_two.last_used_move,
1608                encored,
1609                self.side_two.can_use_tera(),
1610            );
1611            if !self.side_two.trapped(side_one_active) {
1612                self.side_two.add_switches(&mut side_two_options);
1613            }
1614        }
1615
1616        if side_one_options.len() == 0 {
1617            side_one_options.push(MoveChoice::None);
1618        }
1619        if side_two_options.len() == 0 {
1620            side_two_options.push(MoveChoice::None);
1621        }
1622
1623        (side_one_options, side_two_options)
1624    }
1625
1626    pub fn get_side(&mut self, side_ref: &SideReference) -> &mut Side {
1627        match side_ref {
1628            SideReference::SideOne => &mut self.side_one,
1629            SideReference::SideTwo => &mut self.side_two,
1630        }
1631    }
1632
1633    pub fn get_side_immutable(&self, side_ref: &SideReference) -> &Side {
1634        match side_ref {
1635            SideReference::SideOne => &self.side_one,
1636            SideReference::SideTwo => &self.side_two,
1637        }
1638    }
1639
1640    pub fn get_both_sides(&mut self, side_ref: &SideReference) -> (&mut Side, &mut Side) {
1641        match side_ref {
1642            SideReference::SideOne => (&mut self.side_one, &mut self.side_two),
1643            SideReference::SideTwo => (&mut self.side_two, &mut self.side_one),
1644        }
1645    }
1646
1647    pub fn get_both_sides_immutable(&self, side_ref: &SideReference) -> (&Side, &Side) {
1648        match side_ref {
1649            SideReference::SideOne => (&self.side_one, &self.side_two),
1650            SideReference::SideTwo => (&self.side_two, &self.side_one),
1651        }
1652    }
1653
1654    pub fn re_enable_disabled_moves(
1655        &mut self,
1656        side_ref: &SideReference,
1657        vec_to_add_to: &mut Vec<Instruction>,
1658    ) {
1659        let active = self.get_side(side_ref).get_active();
1660        if active.moves.m0.disabled {
1661            active.moves.m0.disabled = false;
1662            vec_to_add_to.push(Instruction::EnableMove(EnableMoveInstruction {
1663                side_ref: *side_ref,
1664                move_index: PokemonMoveIndex::M0,
1665            }));
1666        }
1667        if active.moves.m1.disabled {
1668            active.moves.m1.disabled = false;
1669            vec_to_add_to.push(Instruction::EnableMove(EnableMoveInstruction {
1670                side_ref: *side_ref,
1671                move_index: PokemonMoveIndex::M1,
1672            }));
1673        }
1674        if active.moves.m2.disabled {
1675            active.moves.m2.disabled = false;
1676            vec_to_add_to.push(Instruction::EnableMove(EnableMoveInstruction {
1677                side_ref: *side_ref,
1678                move_index: PokemonMoveIndex::M2,
1679            }));
1680        }
1681        if active.moves.m3.disabled {
1682            active.moves.m3.disabled = false;
1683            vec_to_add_to.push(Instruction::EnableMove(EnableMoveInstruction {
1684                side_ref: *side_ref,
1685                move_index: PokemonMoveIndex::M3,
1686            }));
1687        }
1688    }
1689
1690    pub fn reset_toxic_count(
1691        &mut self,
1692        side_ref: &SideReference,
1693        vec_to_add_to: &mut Vec<Instruction>,
1694    ) {
1695        let side = self.get_side(side_ref);
1696        if side.side_conditions.toxic_count > 0 {
1697            vec_to_add_to.push(Instruction::ChangeSideCondition(
1698                ChangeSideConditionInstruction {
1699                    side_ref: *side_ref,
1700                    side_condition: PokemonSideCondition::ToxicCount,
1701                    amount: -1 * side.side_conditions.toxic_count,
1702                },
1703            ));
1704            side.side_conditions.toxic_count = 0;
1705        }
1706    }
1707
1708    pub fn remove_volatile_statuses_on_switch(
1709        &mut self,
1710        side_ref: &SideReference,
1711        instructions: &mut Vec<Instruction>,
1712        baton_passing: bool,
1713    ) {
1714        let side = self.get_side(side_ref);
1715
1716        // Take ownership of the current set to avoid borrow conflicts
1717        // since we may need to modify the side in the loop
1718        let mut volatile_statuses = std::mem::take(&mut side.volatile_statuses);
1719
1720        volatile_statuses.retain(|pkmn_volatile_status| {
1721            let should_retain = match pkmn_volatile_status {
1722                PokemonVolatileStatus::SUBSTITUTE => baton_passing,
1723                PokemonVolatileStatus::LEECHSEED => baton_passing,
1724                PokemonVolatileStatus::TYPECHANGE => {
1725                    let active = side.get_active();
1726                    if active.base_types != active.types {
1727                        instructions.push(Instruction::ChangeType(ChangeType {
1728                            side_ref: *side_ref,
1729                            new_types: active.base_types,
1730                            old_types: active.types,
1731                        }));
1732                        active.types = active.base_types;
1733                    }
1734                    false
1735                }
1736                // While you can't switch out of a locked move you can be forced out in other ways
1737                PokemonVolatileStatus::LOCKEDMOVE => {
1738                    instructions.push(Instruction::ChangeVolatileStatusDuration(
1739                        ChangeVolatileStatusDurationInstruction {
1740                            side_ref: *side_ref,
1741                            volatile_status: *pkmn_volatile_status,
1742                            amount: -1 * side.volatile_status_durations.lockedmove,
1743                        },
1744                    ));
1745                    side.volatile_status_durations.lockedmove = 0;
1746                    false
1747                }
1748                PokemonVolatileStatus::YAWN => {
1749                    instructions.push(Instruction::ChangeVolatileStatusDuration(
1750                        ChangeVolatileStatusDurationInstruction {
1751                            side_ref: *side_ref,
1752                            volatile_status: *pkmn_volatile_status,
1753                            amount: -1 * side.volatile_status_durations.yawn,
1754                        },
1755                    ));
1756                    side.volatile_status_durations.yawn = 0;
1757                    false
1758                }
1759                _ => false,
1760            };
1761
1762            if !should_retain {
1763                instructions.push(Instruction::RemoveVolatileStatus(
1764                    RemoveVolatileStatusInstruction {
1765                        side_ref: *side_ref,
1766                        volatile_status: *pkmn_volatile_status,
1767                    },
1768                ));
1769            }
1770            should_retain
1771        });
1772
1773        // Clean up by re-setting the volatile statuses
1774        side.volatile_statuses = volatile_statuses;
1775    }
1776
1777    pub fn reset_boosts(&mut self, side_ref: &SideReference, vec_to_add_to: &mut Vec<Instruction>) {
1778        let side = self.get_side(side_ref);
1779
1780        if side.attack_boost != 0 {
1781            vec_to_add_to.push(Instruction::Boost(BoostInstruction {
1782                side_ref: *side_ref,
1783                stat: PokemonBoostableStat::Attack,
1784                amount: -1 * side.attack_boost,
1785            }));
1786            side.attack_boost = 0;
1787        }
1788
1789        if side.defense_boost != 0 {
1790            vec_to_add_to.push(Instruction::Boost(BoostInstruction {
1791                side_ref: *side_ref,
1792                stat: PokemonBoostableStat::Defense,
1793                amount: -1 * side.defense_boost,
1794            }));
1795            side.defense_boost = 0;
1796        }
1797
1798        if side.special_attack_boost != 0 {
1799            vec_to_add_to.push(Instruction::Boost(BoostInstruction {
1800                side_ref: *side_ref,
1801                stat: PokemonBoostableStat::SpecialAttack,
1802                amount: -1 * side.special_attack_boost,
1803            }));
1804            side.special_attack_boost = 0;
1805        }
1806
1807        if side.special_defense_boost != 0 {
1808            vec_to_add_to.push(Instruction::Boost(BoostInstruction {
1809                side_ref: *side_ref,
1810                stat: PokemonBoostableStat::SpecialDefense,
1811                amount: -1 * side.special_defense_boost,
1812            }));
1813            side.special_defense_boost = 0;
1814        }
1815
1816        if side.speed_boost != 0 {
1817            vec_to_add_to.push(Instruction::Boost(BoostInstruction {
1818                side_ref: *side_ref,
1819                stat: PokemonBoostableStat::Speed,
1820                amount: -1 * side.speed_boost,
1821            }));
1822            side.speed_boost = 0;
1823        }
1824
1825        if side.evasion_boost != 0 {
1826            vec_to_add_to.push(Instruction::Boost(BoostInstruction {
1827                side_ref: *side_ref,
1828                stat: PokemonBoostableStat::Evasion,
1829                amount: -1 * side.evasion_boost,
1830            }));
1831            side.evasion_boost = 0;
1832        }
1833
1834        if side.accuracy_boost != 0 {
1835            vec_to_add_to.push(Instruction::Boost(BoostInstruction {
1836                side_ref: *side_ref,
1837                stat: PokemonBoostableStat::Accuracy,
1838                amount: -1 * side.accuracy_boost,
1839            }));
1840            side.accuracy_boost = 0;
1841        }
1842    }
1843
1844    pub fn terrain_is_active(&self, terrain: &Terrain) -> bool {
1845        &self.terrain.terrain_type == terrain && self.terrain.turns_remaining > 0
1846    }
1847
1848    pub fn weather_is_active(&self, weather: &Weather) -> bool {
1849        let s1_active = self.side_one.get_active_immutable();
1850        let s2_active = self.side_two.get_active_immutable();
1851        &self.weather.weather_type == weather
1852            && s1_active.ability != Abilities::AIRLOCK
1853            && s1_active.ability != Abilities::CLOUDNINE
1854            && s2_active.ability != Abilities::AIRLOCK
1855            && s2_active.ability != Abilities::CLOUDNINE
1856    }
1857
1858    fn _state_contains_any_move(&self, moves: &[Choices]) -> bool {
1859        for s in [&self.side_one, &self.side_two] {
1860            for pkmn in s.pokemon.into_iter() {
1861                for mv in pkmn.moves.into_iter() {
1862                    if moves.contains(&mv.id) {
1863                        return true;
1864                    }
1865                }
1866            }
1867        }
1868
1869        false
1870    }
1871
1872    pub fn set_damage_dealt_flag(&mut self) {
1873        if self._state_contains_any_move(&[
1874            Choices::COUNTER,
1875            Choices::MIRRORCOAT,
1876            Choices::METALBURST,
1877            Choices::COMEUPPANCE,
1878            Choices::FOCUSPUNCH,
1879        ]) {
1880            self.use_damage_dealt = true
1881        }
1882    }
1883
1884    pub fn set_last_used_move_flag(&mut self) {
1885        if self._state_contains_any_move(&[
1886            Choices::ENCORE,
1887            Choices::FAKEOUT,
1888            Choices::FIRSTIMPRESSION,
1889            Choices::BLOODMOON,
1890            Choices::GIGATONHAMMER,
1891        ]) {
1892            self.use_last_used_move = true
1893        }
1894    }
1895
1896    pub fn set_conditional_mechanics(&mut self) {
1897        /*
1898        These mechanics are not always relevant but when they are it
1899        is important that they are enabled. Enabling them all the time would
1900        suffer about a 20% performance hit.
1901        */
1902        self.set_damage_dealt_flag();
1903        self.set_last_used_move_flag();
1904    }
1905
1906    fn damage(&mut self, side_ref: &SideReference, amount: i16) {
1907        let active = self.get_side(&side_ref).get_active();
1908
1909        active.hp -= amount;
1910    }
1911
1912    fn heal(&mut self, side_ref: &SideReference, amount: i16) {
1913        let active = self.get_side(&side_ref).get_active();
1914
1915        active.hp += amount;
1916    }
1917
1918    fn switch(
1919        &mut self,
1920        side_ref: &SideReference,
1921        next_active_index: PokemonIndex,
1922        _: PokemonIndex,
1923    ) {
1924        let side = self.get_side(&side_ref);
1925        side.active_index = next_active_index;
1926    }
1927
1928    fn reverse_switch(
1929        &mut self,
1930        side_ref: &SideReference,
1931        _: PokemonIndex,
1932        previous_active_index: PokemonIndex,
1933    ) {
1934        let side = self.get_side(&side_ref);
1935        side.active_index = previous_active_index;
1936    }
1937
1938    fn apply_volatile_status(
1939        &mut self,
1940        side_ref: &SideReference,
1941        volatile_status: PokemonVolatileStatus,
1942    ) {
1943        self.get_side(&side_ref)
1944            .volatile_statuses
1945            .insert(volatile_status);
1946    }
1947
1948    fn remove_volatile_status(
1949        &mut self,
1950        side_ref: &SideReference,
1951        volatile_status: PokemonVolatileStatus,
1952    ) {
1953        self.get_side(&side_ref)
1954            .volatile_statuses
1955            .remove(&volatile_status);
1956    }
1957
1958    fn change_status(
1959        &mut self,
1960        side_ref: &SideReference,
1961        pokemon_index: PokemonIndex,
1962        new_status: PokemonStatus,
1963    ) {
1964        let pkmn = &mut self.get_side(&side_ref).pokemon[pokemon_index];
1965        pkmn.status = new_status;
1966    }
1967
1968    fn apply_boost(&mut self, side_ref: &SideReference, stat: &PokemonBoostableStat, amount: i8) {
1969        let side = self.get_side(&side_ref);
1970        match stat {
1971            PokemonBoostableStat::Attack => side.attack_boost += amount,
1972            PokemonBoostableStat::Defense => side.defense_boost += amount,
1973            PokemonBoostableStat::SpecialAttack => side.special_attack_boost += amount,
1974            PokemonBoostableStat::SpecialDefense => side.special_defense_boost += amount,
1975            PokemonBoostableStat::Speed => side.speed_boost += amount,
1976            PokemonBoostableStat::Evasion => side.evasion_boost += amount,
1977            PokemonBoostableStat::Accuracy => side.accuracy_boost += amount,
1978        }
1979    }
1980
1981    fn increment_side_condition(
1982        &mut self,
1983        side_ref: &SideReference,
1984        side_condition: &PokemonSideCondition,
1985        amount: i8,
1986    ) {
1987        let side = self.get_side(&side_ref);
1988
1989        match side_condition {
1990            PokemonSideCondition::AuroraVeil => side.side_conditions.aurora_veil += amount,
1991            PokemonSideCondition::CraftyShield => side.side_conditions.crafty_shield += amount,
1992            PokemonSideCondition::HealingWish => side.side_conditions.healing_wish += amount,
1993            PokemonSideCondition::LightScreen => side.side_conditions.light_screen += amount,
1994            PokemonSideCondition::LuckyChant => side.side_conditions.lucky_chant += amount,
1995            PokemonSideCondition::LunarDance => side.side_conditions.lunar_dance += amount,
1996            PokemonSideCondition::MatBlock => side.side_conditions.mat_block += amount,
1997            PokemonSideCondition::Mist => side.side_conditions.mist += amount,
1998            PokemonSideCondition::Protect => side.side_conditions.protect += amount,
1999            PokemonSideCondition::QuickGuard => side.side_conditions.quick_guard += amount,
2000            PokemonSideCondition::Reflect => side.side_conditions.reflect += amount,
2001            PokemonSideCondition::Safeguard => side.side_conditions.safeguard += amount,
2002            PokemonSideCondition::Spikes => side.side_conditions.spikes += amount,
2003            PokemonSideCondition::Stealthrock => side.side_conditions.stealth_rock += amount,
2004            PokemonSideCondition::StickyWeb => side.side_conditions.sticky_web += amount,
2005            PokemonSideCondition::Tailwind => side.side_conditions.tailwind += amount,
2006            PokemonSideCondition::ToxicCount => side.side_conditions.toxic_count += amount,
2007            PokemonSideCondition::ToxicSpikes => side.side_conditions.toxic_spikes += amount,
2008            PokemonSideCondition::WideGuard => side.side_conditions.wide_guard += amount,
2009        }
2010    }
2011
2012    fn increment_volatile_status_duration(
2013        &mut self,
2014        side_ref: &SideReference,
2015        volatile_status: &PokemonVolatileStatus,
2016        amount: i8,
2017    ) {
2018        let side = self.get_side(&side_ref);
2019        match volatile_status {
2020            PokemonVolatileStatus::CONFUSION => {
2021                side.volatile_status_durations.confusion += amount;
2022            }
2023            PokemonVolatileStatus::LOCKEDMOVE => {
2024                side.volatile_status_durations.lockedmove += amount;
2025            }
2026            PokemonVolatileStatus::ENCORE => {
2027                side.volatile_status_durations.encore += amount;
2028            }
2029            PokemonVolatileStatus::SLOWSTART => {
2030                side.volatile_status_durations.slowstart += amount;
2031            }
2032            PokemonVolatileStatus::YAWN => {
2033                side.volatile_status_durations.yawn += amount;
2034            }
2035            _ => panic!(
2036                "Invalid volatile status for increment_volatile_status_duration: {:?}",
2037                volatile_status
2038            ),
2039        }
2040    }
2041
2042    fn change_types(
2043        &mut self,
2044        side_reference: &SideReference,
2045        new_types: (PokemonType, PokemonType),
2046    ) {
2047        self.get_side(side_reference).get_active().types = new_types;
2048    }
2049
2050    fn change_item(&mut self, side_reference: &SideReference, new_item: Items) {
2051        self.get_side(side_reference).get_active().item = new_item;
2052    }
2053
2054    fn change_weather(&mut self, weather_type: Weather, turns_remaining: i8) {
2055        self.weather.weather_type = weather_type;
2056        self.weather.turns_remaining = turns_remaining;
2057    }
2058
2059    fn change_terrain(&mut self, terrain_type: Terrain, turns_remaining: i8) {
2060        self.terrain.terrain_type = terrain_type;
2061        self.terrain.turns_remaining = turns_remaining;
2062    }
2063
2064    fn enable_move(&mut self, side_reference: &SideReference, move_index: &PokemonMoveIndex) {
2065        self.get_side(side_reference).get_active().moves[move_index].disabled = false;
2066    }
2067
2068    fn disable_move(&mut self, side_reference: &SideReference, move_index: &PokemonMoveIndex) {
2069        self.get_side(side_reference).get_active().moves[move_index].disabled = true;
2070    }
2071
2072    fn set_wish(&mut self, side_reference: &SideReference, wish_amount_change: i16) {
2073        self.get_side(side_reference).wish.0 = 2;
2074        self.get_side(side_reference).wish.1 += wish_amount_change;
2075    }
2076
2077    fn unset_wish(&mut self, side_reference: &SideReference, wish_amount_change: i16) {
2078        self.get_side(side_reference).wish.0 = 0;
2079        self.get_side(side_reference).wish.1 -= wish_amount_change;
2080    }
2081
2082    fn increment_wish(&mut self, side_reference: &SideReference) {
2083        self.get_side(side_reference).wish.0 += 1;
2084    }
2085
2086    fn decrement_wish(&mut self, side_reference: &SideReference) {
2087        self.get_side(side_reference).wish.0 -= 1;
2088    }
2089
2090    fn set_future_sight(&mut self, side_reference: &SideReference, pokemon_index: PokemonIndex) {
2091        let side = self.get_side(side_reference);
2092        side.future_sight.0 = 3;
2093        side.future_sight.1 = pokemon_index;
2094    }
2095
2096    fn unset_future_sight(
2097        &mut self,
2098        side_reference: &SideReference,
2099        previous_pokemon_index: PokemonIndex,
2100    ) {
2101        let side = self.get_side(side_reference);
2102        side.future_sight.0 = 0;
2103        side.future_sight.1 = previous_pokemon_index;
2104    }
2105
2106    fn increment_future_sight(&mut self, side_reference: &SideReference) {
2107        self.get_side(side_reference).future_sight.0 += 1;
2108    }
2109
2110    fn decrement_future_sight(&mut self, side_reference: &SideReference) {
2111        self.get_side(side_reference).future_sight.0 -= 1;
2112    }
2113
2114    fn damage_substitute(&mut self, side_reference: &SideReference, amount: i16) {
2115        self.get_side(side_reference).substitute_health -= amount;
2116    }
2117
2118    fn heal_substitute(&mut self, side_reference: &SideReference, amount: i16) {
2119        self.get_side(side_reference).substitute_health += amount;
2120    }
2121
2122    fn set_substitute_health(&mut self, side_reference: &SideReference, amount: i16) {
2123        self.get_side(side_reference).substitute_health += amount;
2124    }
2125
2126    fn decrement_rest_turn(&mut self, side_reference: &SideReference) {
2127        self.get_side(side_reference).get_active().rest_turns -= 1;
2128    }
2129
2130    fn increment_rest_turn(&mut self, side_reference: &SideReference) {
2131        self.get_side(side_reference).get_active().rest_turns += 1;
2132    }
2133
2134    fn set_rest_turn(
2135        &mut self,
2136        side_reference: &SideReference,
2137        pokemon_index: PokemonIndex,
2138        amount: i8,
2139    ) {
2140        self.get_side(side_reference).pokemon[pokemon_index].rest_turns = amount;
2141    }
2142
2143    fn set_sleep_turn(
2144        &mut self,
2145        side_reference: &SideReference,
2146        pokemon_index: PokemonIndex,
2147        amount: i8,
2148    ) {
2149        self.get_side(side_reference).pokemon[pokemon_index].sleep_turns = amount;
2150    }
2151
2152    fn toggle_trickroom(&mut self, new_turns_remaining: i8) {
2153        self.trick_room.active = !self.trick_room.active;
2154        self.trick_room.turns_remaining = new_turns_remaining;
2155    }
2156
2157    fn set_last_used_move(&mut self, side_reference: &SideReference, last_used_move: LastUsedMove) {
2158        match side_reference {
2159            SideReference::SideOne => self.side_one.last_used_move = last_used_move,
2160            SideReference::SideTwo => self.side_two.last_used_move = last_used_move,
2161        }
2162    }
2163
2164    fn decrement_pp(
2165        &mut self,
2166        side_reference: &SideReference,
2167        move_index: &PokemonMoveIndex,
2168        amount: &i8,
2169    ) {
2170        match side_reference {
2171            SideReference::SideOne => self.side_one.get_active().moves[move_index].pp -= amount,
2172            SideReference::SideTwo => self.side_two.get_active().moves[move_index].pp -= amount,
2173        }
2174    }
2175
2176    fn increment_pp(
2177        &mut self,
2178        side_reference: &SideReference,
2179        move_index: &PokemonMoveIndex,
2180        amount: &i8,
2181    ) {
2182        match side_reference {
2183            SideReference::SideOne => self.side_one.get_active().moves[move_index].pp += amount,
2184            SideReference::SideTwo => self.side_two.get_active().moves[move_index].pp += amount,
2185        }
2186    }
2187
2188    fn set_damage_dealt(
2189        side: &mut Side,
2190        damage_change: i16,
2191        move_category: MoveCategory,
2192        toggle_hit_substitute: bool,
2193    ) {
2194        side.damage_dealt.damage += damage_change;
2195        side.damage_dealt.move_category = move_category;
2196        if toggle_hit_substitute {
2197            side.damage_dealt.hit_substitute = !side.damage_dealt.hit_substitute;
2198        }
2199    }
2200
2201    pub fn apply_instructions(&mut self, instructions: &Vec<Instruction>) {
2202        for i in instructions {
2203            self.apply_one_instruction(i)
2204        }
2205    }
2206
2207    pub fn apply_one_instruction(&mut self, instruction: &Instruction) {
2208        match instruction {
2209            Instruction::Damage(instruction) => {
2210                self.damage(&instruction.side_ref, instruction.damage_amount)
2211            }
2212            Instruction::Switch(instruction) => self.switch(
2213                &instruction.side_ref,
2214                instruction.next_index,
2215                instruction.previous_index,
2216            ),
2217            Instruction::ApplyVolatileStatus(instruction) => {
2218                self.apply_volatile_status(&instruction.side_ref, instruction.volatile_status)
2219            }
2220            Instruction::RemoveVolatileStatus(instruction) => {
2221                self.remove_volatile_status(&instruction.side_ref, instruction.volatile_status)
2222            }
2223            Instruction::ChangeStatus(instruction) => self.change_status(
2224                &instruction.side_ref,
2225                instruction.pokemon_index,
2226                instruction.new_status,
2227            ),
2228            Instruction::Boost(instruction) => {
2229                self.apply_boost(&instruction.side_ref, &instruction.stat, instruction.amount)
2230            }
2231            Instruction::ChangeSideCondition(instruction) => self.increment_side_condition(
2232                &instruction.side_ref,
2233                &instruction.side_condition,
2234                instruction.amount,
2235            ),
2236            Instruction::ChangeVolatileStatusDuration(instruction) => self
2237                .increment_volatile_status_duration(
2238                    &instruction.side_ref,
2239                    &instruction.volatile_status,
2240                    instruction.amount,
2241                ),
2242            Instruction::ChangeWeather(instruction) => self.change_weather(
2243                instruction.new_weather,
2244                instruction.new_weather_turns_remaining,
2245            ),
2246            Instruction::DecrementWeatherTurnsRemaining => {
2247                self.weather.turns_remaining -= 1;
2248            }
2249            Instruction::ChangeTerrain(instruction) => self.change_terrain(
2250                instruction.new_terrain,
2251                instruction.new_terrain_turns_remaining,
2252            ),
2253            Instruction::DecrementTerrainTurnsRemaining => {
2254                self.terrain.turns_remaining -= 1;
2255            }
2256            Instruction::ChangeType(instruction) => {
2257                self.change_types(&instruction.side_ref, instruction.new_types)
2258            }
2259            Instruction::ChangeAbility(instruction) => {
2260                self.get_side(&instruction.side_ref).get_active().ability =
2261                    instruction.new_ability.clone();
2262            }
2263            Instruction::Heal(instruction) => {
2264                self.heal(&instruction.side_ref, instruction.heal_amount)
2265            }
2266            Instruction::ChangeItem(instruction) => {
2267                self.change_item(&instruction.side_ref, instruction.new_item)
2268            }
2269            Instruction::ChangeAttack(instruction) => {
2270                self.get_side(&instruction.side_ref).get_active().attack += instruction.amount;
2271            }
2272            Instruction::ChangeDefense(instruction) => {
2273                self.get_side(&instruction.side_ref).get_active().defense += instruction.amount;
2274            }
2275            Instruction::ChangeSpecialAttack(instruction) => {
2276                self.get_side(&instruction.side_ref)
2277                    .get_active()
2278                    .special_attack += instruction.amount;
2279            }
2280            Instruction::ChangeSpecialDefense(instruction) => {
2281                self.get_side(&instruction.side_ref)
2282                    .get_active()
2283                    .special_defense += instruction.amount;
2284            }
2285            Instruction::ChangeSpeed(instruction) => {
2286                self.get_side(&instruction.side_ref).get_active().speed += instruction.amount;
2287            }
2288            Instruction::EnableMove(instruction) => {
2289                self.enable_move(&instruction.side_ref, &instruction.move_index)
2290            }
2291            Instruction::DisableMove(instruction) => {
2292                self.disable_move(&instruction.side_ref, &instruction.move_index)
2293            }
2294            Instruction::ChangeWish(instruction) => {
2295                self.set_wish(&instruction.side_ref, instruction.wish_amount_change);
2296            }
2297            Instruction::DecrementWish(instruction) => {
2298                self.decrement_wish(&instruction.side_ref);
2299            }
2300            Instruction::SetFutureSight(instruction) => {
2301                self.set_future_sight(&instruction.side_ref, instruction.pokemon_index);
2302            }
2303            Instruction::DecrementFutureSight(instruction) => {
2304                self.decrement_future_sight(&instruction.side_ref);
2305            }
2306            Instruction::DamageSubstitute(instruction) => {
2307                self.damage_substitute(&instruction.side_ref, instruction.damage_amount);
2308            }
2309            Instruction::ChangeSubstituteHealth(instruction) => {
2310                self.set_substitute_health(&instruction.side_ref, instruction.health_change);
2311            }
2312            Instruction::SetRestTurns(instruction) => {
2313                self.set_rest_turn(
2314                    &instruction.side_ref,
2315                    instruction.pokemon_index,
2316                    instruction.new_turns,
2317                );
2318            }
2319            Instruction::SetSleepTurns(instruction) => {
2320                self.set_sleep_turn(
2321                    &instruction.side_ref,
2322                    instruction.pokemon_index,
2323                    instruction.new_turns,
2324                );
2325            }
2326            Instruction::DecrementRestTurns(instruction) => {
2327                self.decrement_rest_turn(&instruction.side_ref);
2328            }
2329            Instruction::ToggleTrickRoom(instruction) => {
2330                self.toggle_trickroom(instruction.new_trickroom_turns_remaining)
2331            }
2332            Instruction::DecrementTrickRoomTurnsRemaining => {
2333                self.trick_room.turns_remaining -= 1;
2334            }
2335            Instruction::ToggleSideOneForceSwitch => self.side_one.toggle_force_switch(),
2336            Instruction::ToggleSideTwoForceSwitch => self.side_two.toggle_force_switch(),
2337            Instruction::SetSideOneMoveSecondSwitchOutMove(instruction) => {
2338                self.side_one.switch_out_move_second_saved_move = instruction.new_choice;
2339            }
2340            Instruction::SetSideTwoMoveSecondSwitchOutMove(instruction) => {
2341                self.side_two.switch_out_move_second_saved_move = instruction.new_choice;
2342            }
2343            Instruction::ToggleBatonPassing(instruction) => match instruction.side_ref {
2344                SideReference::SideOne => {
2345                    self.side_one.baton_passing = !self.side_one.baton_passing
2346                }
2347                SideReference::SideTwo => {
2348                    self.side_two.baton_passing = !self.side_two.baton_passing
2349                }
2350            },
2351            Instruction::ToggleTerastallized(instruction) => match instruction.side_ref {
2352                SideReference::SideOne => self.side_one.get_active().terastallized ^= true,
2353                SideReference::SideTwo => self.side_two.get_active().terastallized ^= true,
2354            },
2355            Instruction::SetLastUsedMove(instruction) => {
2356                self.set_last_used_move(&instruction.side_ref, instruction.last_used_move)
2357            }
2358            Instruction::SetDamageDealtSideOne(instruction) => State::set_damage_dealt(
2359                &mut self.side_one,
2360                instruction.damage_change,
2361                instruction.move_category,
2362                instruction.toggle_hit_substitute,
2363            ),
2364            Instruction::SetDamageDealtSideTwo(instruction) => State::set_damage_dealt(
2365                &mut self.side_two,
2366                instruction.damage_change,
2367                instruction.move_category,
2368                instruction.toggle_hit_substitute,
2369            ),
2370            Instruction::DecrementPP(instruction) => self.decrement_pp(
2371                &instruction.side_ref,
2372                &instruction.move_index,
2373                &instruction.amount,
2374            ),
2375            Instruction::FormeChange(instruction) => {
2376                self.get_side(&instruction.side_ref).get_active().id = instruction.new_forme;
2377            }
2378        }
2379    }
2380
2381    pub fn reverse_instructions(&mut self, instructions: &Vec<Instruction>) {
2382        for i in instructions.iter().rev() {
2383            self.reverse_one_instruction(i);
2384        }
2385    }
2386
2387    pub fn reverse_one_instruction(&mut self, instruction: &Instruction) {
2388        match instruction {
2389            Instruction::Damage(instruction) => {
2390                self.heal(&instruction.side_ref, instruction.damage_amount)
2391            }
2392            Instruction::Switch(instruction) => self.reverse_switch(
2393                &instruction.side_ref,
2394                instruction.next_index,
2395                instruction.previous_index,
2396            ),
2397            Instruction::ApplyVolatileStatus(instruction) => {
2398                self.remove_volatile_status(&instruction.side_ref, instruction.volatile_status)
2399            }
2400            Instruction::RemoveVolatileStatus(instruction) => {
2401                self.apply_volatile_status(&instruction.side_ref, instruction.volatile_status)
2402            }
2403            Instruction::ChangeStatus(instruction) => self.change_status(
2404                &instruction.side_ref,
2405                instruction.pokemon_index,
2406                instruction.old_status,
2407            ),
2408            Instruction::Boost(instruction) => self.apply_boost(
2409                &instruction.side_ref,
2410                &instruction.stat,
2411                -1 * instruction.amount,
2412            ),
2413            Instruction::ChangeSideCondition(instruction) => self.increment_side_condition(
2414                &instruction.side_ref,
2415                &instruction.side_condition,
2416                -1 * instruction.amount,
2417            ),
2418            Instruction::ChangeVolatileStatusDuration(instruction) => self
2419                .increment_volatile_status_duration(
2420                    &instruction.side_ref,
2421                    &instruction.volatile_status,
2422                    -1 * instruction.amount,
2423                ),
2424            Instruction::ChangeWeather(instruction) => self.change_weather(
2425                instruction.previous_weather,
2426                instruction.previous_weather_turns_remaining,
2427            ),
2428            Instruction::DecrementWeatherTurnsRemaining => {
2429                self.weather.turns_remaining += 1;
2430            }
2431            Instruction::ChangeTerrain(instruction) => self.change_terrain(
2432                instruction.previous_terrain,
2433                instruction.previous_terrain_turns_remaining,
2434            ),
2435            Instruction::DecrementTerrainTurnsRemaining => {
2436                self.terrain.turns_remaining += 1;
2437            }
2438            Instruction::ChangeType(instruction) => {
2439                self.change_types(&instruction.side_ref, instruction.old_types)
2440            }
2441            Instruction::ChangeAbility(instruction) => {
2442                self.get_side(&instruction.side_ref).get_active().ability =
2443                    instruction.old_ability.clone();
2444            }
2445            Instruction::EnableMove(instruction) => {
2446                self.disable_move(&instruction.side_ref, &instruction.move_index)
2447            }
2448            Instruction::DisableMove(instruction) => {
2449                self.enable_move(&instruction.side_ref, &instruction.move_index)
2450            }
2451            Instruction::Heal(instruction) => {
2452                self.damage(&instruction.side_ref, instruction.heal_amount)
2453            }
2454            Instruction::ChangeItem(instruction) => {
2455                self.change_item(&instruction.side_ref, instruction.current_item)
2456            }
2457            Instruction::ChangeAttack(instruction) => {
2458                self.get_side(&instruction.side_ref).get_active().attack -= instruction.amount;
2459            }
2460            Instruction::ChangeDefense(instruction) => {
2461                self.get_side(&instruction.side_ref).get_active().defense -= instruction.amount;
2462            }
2463            Instruction::ChangeSpecialAttack(instruction) => {
2464                self.get_side(&instruction.side_ref)
2465                    .get_active()
2466                    .special_attack -= instruction.amount;
2467            }
2468            Instruction::ChangeSpecialDefense(instruction) => {
2469                self.get_side(&instruction.side_ref)
2470                    .get_active()
2471                    .special_defense -= instruction.amount;
2472            }
2473            Instruction::ChangeSpeed(instruction) => {
2474                self.get_side(&instruction.side_ref).get_active().speed -= instruction.amount;
2475            }
2476            Instruction::ChangeWish(instruction) => {
2477                self.unset_wish(&instruction.side_ref, instruction.wish_amount_change)
2478            }
2479            Instruction::DecrementWish(instruction) => self.increment_wish(&instruction.side_ref),
2480            Instruction::SetFutureSight(instruction) => {
2481                self.unset_future_sight(&instruction.side_ref, instruction.previous_pokemon_index)
2482            }
2483            Instruction::DecrementFutureSight(instruction) => {
2484                self.increment_future_sight(&instruction.side_ref)
2485            }
2486            Instruction::DamageSubstitute(instruction) => {
2487                self.heal_substitute(&instruction.side_ref, instruction.damage_amount);
2488            }
2489            Instruction::ChangeSubstituteHealth(instruction) => {
2490                self.set_substitute_health(&instruction.side_ref, -1 * instruction.health_change);
2491            }
2492            Instruction::SetRestTurns(instruction) => {
2493                self.set_rest_turn(
2494                    &instruction.side_ref,
2495                    instruction.pokemon_index,
2496                    instruction.previous_turns,
2497                );
2498            }
2499            Instruction::SetSleepTurns(instruction) => {
2500                self.set_sleep_turn(
2501                    &instruction.side_ref,
2502                    instruction.pokemon_index,
2503                    instruction.previous_turns,
2504                );
2505            }
2506            Instruction::DecrementRestTurns(instruction) => {
2507                self.increment_rest_turn(&instruction.side_ref);
2508            }
2509            Instruction::ToggleTrickRoom(instruction) => {
2510                self.toggle_trickroom(instruction.previous_trickroom_turns_remaining)
2511            }
2512            Instruction::DecrementTrickRoomTurnsRemaining => {
2513                self.trick_room.turns_remaining += 1;
2514            }
2515            Instruction::ToggleSideOneForceSwitch => self.side_one.toggle_force_switch(),
2516            Instruction::ToggleSideTwoForceSwitch => self.side_two.toggle_force_switch(),
2517            Instruction::SetSideOneMoveSecondSwitchOutMove(instruction) => {
2518                self.side_one.switch_out_move_second_saved_move = instruction.previous_choice;
2519            }
2520            Instruction::SetSideTwoMoveSecondSwitchOutMove(instruction) => {
2521                self.side_two.switch_out_move_second_saved_move = instruction.previous_choice;
2522            }
2523            Instruction::ToggleBatonPassing(instruction) => match instruction.side_ref {
2524                SideReference::SideOne => {
2525                    self.side_one.baton_passing = !self.side_one.baton_passing
2526                }
2527                SideReference::SideTwo => {
2528                    self.side_two.baton_passing = !self.side_two.baton_passing
2529                }
2530            },
2531            Instruction::ToggleTerastallized(instruction) => match instruction.side_ref {
2532                SideReference::SideOne => self.side_one.get_active().terastallized ^= true,
2533                SideReference::SideTwo => self.side_two.get_active().terastallized ^= true,
2534            },
2535            Instruction::SetLastUsedMove(instruction) => {
2536                self.set_last_used_move(&instruction.side_ref, instruction.previous_last_used_move)
2537            }
2538            Instruction::SetDamageDealtSideOne(instruction) => State::set_damage_dealt(
2539                &mut self.side_one,
2540                -1 * instruction.damage_change,
2541                instruction.previous_move_category,
2542                instruction.toggle_hit_substitute,
2543            ),
2544            Instruction::SetDamageDealtSideTwo(instruction) => State::set_damage_dealt(
2545                &mut self.side_two,
2546                -1 * instruction.damage_change,
2547                instruction.previous_move_category,
2548                instruction.toggle_hit_substitute,
2549            ),
2550            Instruction::DecrementPP(instruction) => self.increment_pp(
2551                &instruction.side_ref,
2552                &instruction.move_index,
2553                &instruction.amount,
2554            ),
2555            Instruction::FormeChange(instruction) => {
2556                self.get_side(&instruction.side_ref).get_active().id = instruction.previous_forme;
2557            }
2558        }
2559    }
2560}
2561
2562impl Move {
2563    pub fn serialize(&self) -> String {
2564        format!("{:?};{};{}", self.id, self.disabled, self.pp)
2565    }
2566    pub fn deserialize(serialized: &str) -> Move {
2567        let split: Vec<&str> = serialized.split(";").collect();
2568        Move {
2569            id: Choices::from_str(split[0]).unwrap(),
2570            disabled: split[1].parse::<bool>().unwrap(),
2571            pp: split[2].parse::<i8>().unwrap(),
2572            choice: MOVES
2573                .get(&Choices::from_str(split[0]).unwrap())
2574                .unwrap()
2575                .to_owned(),
2576        }
2577    }
2578}
2579
2580impl Pokemon {
2581    pub fn serialize(&self) -> String {
2582        let evs_str = format!(
2583            "{};{};{};{};{};{}",
2584            self.evs.0, self.evs.1, self.evs.2, self.evs.3, self.evs.4, self.evs.5
2585        );
2586        format!(
2587            "{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}",
2588            self.id,
2589            self.level,
2590            self.types.0.to_string(),
2591            self.types.1.to_string(),
2592            self.base_types.0.to_string(),
2593            self.base_types.1.to_string(),
2594            self.hp,
2595            self.maxhp,
2596            self.ability.to_string(),
2597            self.base_ability.to_string(),
2598            self.item.to_string(),
2599            self.nature.to_string(),
2600            evs_str,
2601            self.attack,
2602            self.defense,
2603            self.special_attack,
2604            self.special_defense,
2605            self.speed,
2606            self.status.to_string(),
2607            self.rest_turns,
2608            self.sleep_turns,
2609            self.weight_kg,
2610            self.moves.m0.serialize(),
2611            self.moves.m1.serialize(),
2612            self.moves.m2.serialize(),
2613            self.moves.m3.serialize(),
2614            self.terastallized,
2615            self.tera_type.to_string(),
2616        )
2617    }
2618
2619    pub fn deserialize(serialized: &str) -> Pokemon {
2620        let split: Vec<&str> = serialized.split(",").collect();
2621        let evs = if split[12] != "" {
2622            let mut ev_iter = split[12].split(";");
2623            (
2624                ev_iter.next().unwrap().parse::<u8>().unwrap(),
2625                ev_iter.next().unwrap().parse::<u8>().unwrap(),
2626                ev_iter.next().unwrap().parse::<u8>().unwrap(),
2627                ev_iter.next().unwrap().parse::<u8>().unwrap(),
2628                ev_iter.next().unwrap().parse::<u8>().unwrap(),
2629                ev_iter.next().unwrap().parse::<u8>().unwrap(),
2630            )
2631        } else {
2632            (85, 85, 85, 85, 85, 85)
2633        };
2634        Pokemon {
2635            id: PokemonName::from_str(split[0]).unwrap(),
2636            level: split[1].parse::<i8>().unwrap(),
2637            types: (
2638                PokemonType::from_str(split[2]).unwrap(),
2639                PokemonType::from_str(split[3]).unwrap(),
2640            ),
2641            base_types: (
2642                PokemonType::from_str(split[4]).unwrap(),
2643                PokemonType::from_str(split[5]).unwrap(),
2644            ),
2645            hp: split[6].parse::<i16>().unwrap(),
2646            maxhp: split[7].parse::<i16>().unwrap(),
2647            ability: Abilities::from_str(split[8]).unwrap(),
2648            base_ability: Abilities::from_str(split[9]).unwrap(),
2649            item: Items::from_str(split[10]).unwrap(),
2650            nature: PokemonNature::from_str(split[11]).unwrap(),
2651            evs,
2652            attack: split[13].parse::<i16>().unwrap(),
2653            defense: split[14].parse::<i16>().unwrap(),
2654            special_attack: split[15].parse::<i16>().unwrap(),
2655            special_defense: split[16].parse::<i16>().unwrap(),
2656            speed: split[17].parse::<i16>().unwrap(),
2657            status: PokemonStatus::from_str(split[18]).unwrap(),
2658            rest_turns: split[19].parse::<i8>().unwrap(),
2659            sleep_turns: split[20].parse::<i8>().unwrap(),
2660            weight_kg: split[21].parse::<f32>().unwrap(),
2661            moves: PokemonMoves {
2662                m0: Move::deserialize(split[22]),
2663                m1: Move::deserialize(split[23]),
2664                m2: Move::deserialize(split[24]),
2665                m3: Move::deserialize(split[25]),
2666            },
2667            terastallized: split[26].parse::<bool>().unwrap(),
2668            tera_type: PokemonType::from_str(split[27]).unwrap(),
2669        }
2670    }
2671}
2672
2673impl LastUsedMove {
2674    pub fn serialize(&self) -> String {
2675        match self {
2676            LastUsedMove::Move(move_index) => format!("move:{}", move_index.serialize()),
2677            LastUsedMove::Switch(pkmn_index) => format!("switch:{}", pkmn_index.serialize()),
2678            LastUsedMove::None => "move:none".to_string(),
2679        }
2680    }
2681    pub fn deserialize(serialized: &str) -> LastUsedMove {
2682        let split: Vec<&str> = serialized.split(":").collect();
2683        match split[0] {
2684            "move" => {
2685                if split[1] == "none" {
2686                    LastUsedMove::None
2687                } else {
2688                    LastUsedMove::Move(PokemonMoveIndex::deserialize(split[1]))
2689                }
2690            }
2691            "switch" => LastUsedMove::Switch(PokemonIndex::deserialize(split[1])),
2692            _ => panic!("Invalid LastUsedMove: {}", serialized),
2693        }
2694    }
2695}
2696
2697impl PokemonIndex {
2698    pub fn serialize(&self) -> String {
2699        match self {
2700            PokemonIndex::P0 => "0".to_string(),
2701            PokemonIndex::P1 => "1".to_string(),
2702            PokemonIndex::P2 => "2".to_string(),
2703            PokemonIndex::P3 => "3".to_string(),
2704            PokemonIndex::P4 => "4".to_string(),
2705            PokemonIndex::P5 => "5".to_string(),
2706        }
2707    }
2708
2709    pub fn deserialize(serialized: &str) -> PokemonIndex {
2710        match serialized {
2711            "0" => PokemonIndex::P0,
2712            "1" => PokemonIndex::P1,
2713            "2" => PokemonIndex::P2,
2714            "3" => PokemonIndex::P3,
2715            "4" => PokemonIndex::P4,
2716            "5" => PokemonIndex::P5,
2717            _ => panic!("Invalid PokemonIndex: {}", serialized),
2718        }
2719    }
2720}
2721
2722impl PokemonMoveIndex {
2723    pub fn serialize(&self) -> String {
2724        match self {
2725            PokemonMoveIndex::M0 => "0".to_string(),
2726            PokemonMoveIndex::M1 => "1".to_string(),
2727            PokemonMoveIndex::M2 => "2".to_string(),
2728            PokemonMoveIndex::M3 => "3".to_string(),
2729        }
2730    }
2731
2732    pub fn deserialize(serialized: &str) -> PokemonMoveIndex {
2733        match serialized {
2734            "0" => PokemonMoveIndex::M0,
2735            "1" => PokemonMoveIndex::M1,
2736            "2" => PokemonMoveIndex::M2,
2737            "3" => PokemonMoveIndex::M3,
2738            _ => panic!("Invalid PokemonMoveIndex: {}", serialized),
2739        }
2740    }
2741}
2742
2743impl SideConditions {
2744    pub fn serialize(&self) -> String {
2745        format!(
2746            "{};{};{};{};{};{};{};{};{};{};{};{};{};{};{};{};{};{};{}",
2747            self.aurora_veil,
2748            self.crafty_shield,
2749            self.healing_wish,
2750            self.light_screen,
2751            self.lucky_chant,
2752            self.lunar_dance,
2753            self.mat_block,
2754            self.mist,
2755            self.protect,
2756            self.quick_guard,
2757            self.reflect,
2758            self.safeguard,
2759            self.spikes,
2760            self.stealth_rock,
2761            self.sticky_web,
2762            self.tailwind,
2763            self.toxic_count,
2764            self.toxic_spikes,
2765            self.wide_guard,
2766        )
2767    }
2768    pub fn deserialize(serialized: &str) -> SideConditions {
2769        let split: Vec<&str> = serialized.split(";").collect();
2770        SideConditions {
2771            aurora_veil: split[0].parse::<i8>().unwrap(),
2772            crafty_shield: split[1].parse::<i8>().unwrap(),
2773            healing_wish: split[2].parse::<i8>().unwrap(),
2774            light_screen: split[3].parse::<i8>().unwrap(),
2775            lucky_chant: split[4].parse::<i8>().unwrap(),
2776            lunar_dance: split[5].parse::<i8>().unwrap(),
2777            mat_block: split[6].parse::<i8>().unwrap(),
2778            mist: split[7].parse::<i8>().unwrap(),
2779            protect: split[8].parse::<i8>().unwrap(),
2780            quick_guard: split[9].parse::<i8>().unwrap(),
2781            reflect: split[10].parse::<i8>().unwrap(),
2782            safeguard: split[11].parse::<i8>().unwrap(),
2783            spikes: split[12].parse::<i8>().unwrap(),
2784            stealth_rock: split[13].parse::<i8>().unwrap(),
2785            sticky_web: split[14].parse::<i8>().unwrap(),
2786            tailwind: split[15].parse::<i8>().unwrap(),
2787            toxic_count: split[16].parse::<i8>().unwrap(),
2788            toxic_spikes: split[17].parse::<i8>().unwrap(),
2789            wide_guard: split[18].parse::<i8>().unwrap(),
2790        }
2791    }
2792}
2793
2794impl Side {
2795    pub fn serialize(&self) -> String {
2796        let mut vs_string = String::new();
2797        for vs in &self.volatile_statuses {
2798            vs_string.push_str(&vs.to_string());
2799            vs_string.push_str(":");
2800        }
2801        format!(
2802            "{}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}",
2803            self.pokemon.p0.serialize(),
2804            self.pokemon.p1.serialize(),
2805            self.pokemon.p2.serialize(),
2806            self.pokemon.p3.serialize(),
2807            self.pokemon.p4.serialize(),
2808            self.pokemon.p5.serialize(),
2809            self.active_index.serialize(),
2810            self.side_conditions.serialize(),
2811            vs_string,
2812            self.volatile_status_durations.serialize(),
2813            self.substitute_health,
2814            self.attack_boost,
2815            self.defense_boost,
2816            self.special_attack_boost,
2817            self.special_defense_boost,
2818            self.speed_boost,
2819            self.accuracy_boost,
2820            self.evasion_boost,
2821            self.wish.0,
2822            self.wish.1,
2823            self.future_sight.0,
2824            self.future_sight.1.serialize(),
2825            self.force_switch,
2826            self.switch_out_move_second_saved_move.to_string(),
2827            self.baton_passing,
2828            self.force_trapped,
2829            self.last_used_move.serialize(),
2830            self.slow_uturn_move,
2831        )
2832    }
2833    pub fn deserialize(serialized: &str) -> Side {
2834        let split: Vec<&str> = serialized.split("=").collect();
2835
2836        let mut vs_hashset = HashSet::new();
2837        if split[8] != "" {
2838            for item in split[8].split(":") {
2839                vs_hashset.insert(PokemonVolatileStatus::from_str(item).unwrap());
2840            }
2841        }
2842        Side {
2843            pokemon: SidePokemon {
2844                p0: Pokemon::deserialize(split[0]),
2845                p1: Pokemon::deserialize(split[1]),
2846                p2: Pokemon::deserialize(split[2]),
2847                p3: Pokemon::deserialize(split[3]),
2848                p4: Pokemon::deserialize(split[4]),
2849                p5: Pokemon::deserialize(split[5]),
2850            },
2851            active_index: PokemonIndex::deserialize(split[6]),
2852            side_conditions: SideConditions::deserialize(split[7]),
2853            volatile_statuses: vs_hashset,
2854            volatile_status_durations: VolatileStatusDurations::deserialize(split[9]),
2855            substitute_health: split[10].parse::<i16>().unwrap(),
2856            attack_boost: split[11].parse::<i8>().unwrap(),
2857            defense_boost: split[12].parse::<i8>().unwrap(),
2858            special_attack_boost: split[13].parse::<i8>().unwrap(),
2859            special_defense_boost: split[14].parse::<i8>().unwrap(),
2860            speed_boost: split[15].parse::<i8>().unwrap(),
2861            accuracy_boost: split[16].parse::<i8>().unwrap(),
2862            evasion_boost: split[17].parse::<i8>().unwrap(),
2863            wish: (
2864                split[18].parse::<i8>().unwrap(),
2865                split[19].parse::<i16>().unwrap(),
2866            ),
2867            future_sight: (
2868                split[20].parse::<i8>().unwrap(),
2869                PokemonIndex::deserialize(split[21]),
2870            ),
2871            force_switch: split[22].parse::<bool>().unwrap(),
2872            switch_out_move_second_saved_move: Choices::from_str(split[23]).unwrap(),
2873            baton_passing: split[24].parse::<bool>().unwrap(),
2874            force_trapped: split[25].parse::<bool>().unwrap(),
2875            last_used_move: LastUsedMove::deserialize(split[26]),
2876            damage_dealt: DamageDealt::default(),
2877            slow_uturn_move: split[27].parse::<bool>().unwrap(),
2878        }
2879    }
2880}
2881
2882impl StateWeather {
2883    pub fn serialize(&self) -> String {
2884        format!("{:?};{}", self.weather_type, self.turns_remaining)
2885    }
2886    pub fn deserialize(serialized: &str) -> StateWeather {
2887        let split: Vec<&str> = serialized.split(";").collect();
2888        StateWeather {
2889            weather_type: Weather::from_str(split[0]).unwrap(),
2890            turns_remaining: split[1].parse::<i8>().unwrap(),
2891        }
2892    }
2893}
2894
2895impl StateTerrain {
2896    pub fn serialize(&self) -> String {
2897        format!("{:?};{}", self.terrain_type, self.turns_remaining)
2898    }
2899    pub fn deserialize(serialized: &str) -> StateTerrain {
2900        let split: Vec<&str> = serialized.split(";").collect();
2901        StateTerrain {
2902            terrain_type: Terrain::from_str(split[0]).unwrap(),
2903            turns_remaining: split[1].parse::<i8>().unwrap(),
2904        }
2905    }
2906}
2907
2908impl StateTrickRoom {
2909    pub fn serialize(&self) -> String {
2910        format!("{};{}", self.active, self.turns_remaining)
2911    }
2912    pub fn deserialize(serialized: &str) -> StateTrickRoom {
2913        let split: Vec<&str> = serialized.split(";").collect();
2914        StateTrickRoom {
2915            active: split[0].parse::<bool>().unwrap(),
2916            turns_remaining: split[1].parse::<i8>().unwrap(),
2917        }
2918    }
2919}
2920
2921impl State {
2922    pub fn serialize(&self) -> String {
2923        format!(
2924            "{}/{}/{}/{}/{}/{}",
2925            self.side_one.serialize(),
2926            self.side_two.serialize(),
2927            self.weather.serialize(),
2928            self.terrain.serialize(),
2929            self.trick_room.serialize(),
2930            self.team_preview
2931        )
2932    }
2933
2934    /// ```
2935    ///
2936    /// /*
2937    /// This doctest does its best to show the format of the serialized state.
2938    ///
2939    /// Roughly, the format for a state is:
2940    ///     side1/side2/weather/terrain/trick_room/team_preview
2941    ///
2942    /// Where the format for a side is:
2943    ///     p0=p1=p2=p3=p4=p5=active_index=side_conditions=wish0=wish1=force_switch=switch_out_move_second_saved_move=baton_passing=force_trapped=last_used_move=slow_uturn_move
2944    ///
2945    /// And the format for a pokemon is:
2946    ///    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
2947    ///
2948    /// There's more to it, follow the code below to see a full example of a serialized state.
2949    /// */
2950    ///
2951    /// if cfg!(feature = "gen2") {
2952    ///    return;
2953    /// }
2954    ///
2955    /// use poke_engine::abilities::Abilities;
2956    /// use poke_engine::items::Items;
2957    /// use poke_engine::pokemon::PokemonName;
2958    /// use poke_engine::state::State;
2959    ///
2960    /// let serialized_state = concat!(
2961    ///
2962    /// // SIDE 1
2963    ///
2964    /// // POKEMON 1
2965    ///
2966    /// // name
2967    /// "alakazam,",
2968    ///
2969    /// // level
2970    /// "100,",
2971    ///
2972    /// // type1
2973    /// "Psychic,",
2974    ///
2975    /// // type2
2976    /// "Typeless,",
2977    ///
2978    /// // base_types 1 and 2. These are needed to revert to the correct type when switching out after being typechanged
2979    /// "Psychic,",
2980    /// "Typeless,",
2981    ///
2982    /// // hp
2983    /// "251,",
2984    ///
2985    /// // maxhp
2986    /// "251,",
2987    ///
2988    /// // ability
2989    /// "MAGICGUARD,",
2990    ///
2991    /// // base ability. This is needed to revert to the correct ability when switching out after having the ability changed
2992    /// "MAGICGUARD,",
2993    ///
2994    /// // item
2995    /// "LIFEORB,",
2996    ///
2997    /// // nature
2998    /// "SERIOUS,",
2999    ///
3000    /// // EVs split by `;`. Leave blank for default EVs (85 in all)
3001    /// "252;0;252;0;4;0,",
3002    /// // ",", left blank for default EVs
3003    ///
3004    /// // attack,defense,special attack,special defense,speed
3005    /// // note these are final stats, not base stats
3006    /// "121,148,353,206,365,",
3007    ///
3008    /// // status
3009    /// "None,",
3010    ///
3011    /// // rest_turns
3012    /// "0,",
3013    ///
3014    /// // sleep_turns
3015    /// "0,",
3016    ///
3017    /// // weight_kg
3018    /// "25.5,",
3019    ///
3020    /// // moves 1 through 4 (move_id;disabled;pp)
3021    /// "PSYCHIC;false;16,GRASSKNOT;false;32,SHADOWBALL;false;24,HIDDENPOWERFIRE70;false;24,",
3022    ///
3023    /// // terastallized
3024    /// "false,",
3025    ///
3026    /// // tera_type
3027    /// "Normal=",
3028    ///
3029    /// // all remaining Pokémon shown in 1 line for brevity
3030    /// "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=",
3031    /// "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=",
3032    /// "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=",
3033    /// "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=",
3034    /// "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=",
3035    ///
3036    /// // active-index. This is the index of the active Pokémon in the side's Pokémon array
3037    /// "0=",
3038    ///
3039    /// // side conditions are integers
3040    /// "0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;=",
3041    ///
3042    /// // volatile_statuses (delimited by ":")
3043    /// "=",
3044    ///
3045    /// // some volatile statuses have durations associated with them, delimited by ;
3046    /// "0;0;0;0;0=",
3047    ///
3048    /// // substitute_health
3049    /// "0=",
3050    ///
3051    /// // For the active pokemon:
3052    /// // attack_boost,defense_boost,special attack_boost,special defense_boost,speed_boost,accuracy_boost,evasion_boost
3053    /// "0=0=0=0=0=0=0=",
3054    ///
3055    /// // wish condition is represented by 2 integers, the first is how many wish turns remaining, the second is the amount of HP to heal
3056    /// "0=",
3057    /// "0=",
3058    ///
3059    /// // future sight is represented by the PokemonIndex of the pokemon that used futuresight, and the number of turns remaining until it hits
3060    /// "0=",
3061    /// "0=",
3062    ///
3063    /// // a boolean representing if the side is forced to switch
3064    /// "false=",
3065    ///
3066    /// // a 'saved moved' that a pokemon may be waiting to use after the opponent finished their uturn/volt switch/etc.
3067    /// "NONE=",
3068    ///
3069    /// // a b=oolean representing if the side is baton passing
3070    /// "false=",
3071    ///
3072    /// // a boolean representing if the side is force trapped. This is only ever externally provided and never changed by the engine
3073    /// "false=",
3074    ///
3075    /// // last used move is a string that can be either "move:move_name" or "switch:pokemon_index"
3076    /// "switch:0=",
3077    ///
3078    /// // a boolean representing if the side is slow uturning.
3079    /// // This is only ever set externally. It is used to know if the opposing side has a stored move to use after uturn.
3080    /// "false/",
3081    ///
3082    /// // SIDE 2, all in one line for brevity
3083    /// "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=switch:0=false/",
3084    ///
3085    /// // weather is a string representing the weather type and the number of turns remaining
3086    /// "none;5/",
3087    ///
3088    /// // terrain is a string representing the terrain type and the number of turns remaining
3089    /// "none;5/",
3090    ///
3091    /// // trick room is a boolean representing if trick room is active and the number of turns remaining
3092    /// "false;5/",
3093    ///
3094    /// // team preview is a boolean representing if the team preview is active
3095    /// "false"
3096    ///
3097    /// );
3098    ///
3099    /// let state = State::deserialize(serialized_state);
3100    ///
3101    /// assert_eq!(state.side_one.get_active_immutable().id, PokemonName::ALAKAZAM);
3102    /// assert_eq!(state.side_one.get_active_immutable().weight_kg, 25.5);
3103    /// assert_eq!(state.side_one.substitute_health, 0);
3104    /// assert_eq!(state.side_two.get_active_immutable().id, PokemonName::TERRAKION);
3105    /// assert_eq!(state.trick_room.active, false);
3106    /// assert_eq!(state.team_preview, false);
3107    ///
3108    /// #[cfg(not(any(feature = "gen1", feature = "gen2")))]
3109    /// {
3110    ///     assert_eq!(state.side_two.get_active_immutable().item, Items::FOCUSSASH);
3111    ///     assert_eq!(state.side_two.get_active_immutable().ability, Abilities::JUSTIFIED);
3112    ///     assert_eq!(state.side_one.get_active_immutable().item, Items::LIFEORB);
3113    ///     assert_eq!(state.side_one.get_active_immutable().ability, Abilities::MAGICGUARD);
3114    /// }
3115    ///
3116    /// // the same state, but all in one line
3117    /// 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=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=switch:0=false/none;5/none;5/false;5/false";
3118    /// let state2 = State::deserialize(serialized_state);
3119    /// assert_eq!(state.serialize(), state2.serialize());
3120    ///
3121    /// ```
3122    pub fn deserialize(serialized: &str) -> State {
3123        let split: Vec<&str> = serialized.split("/").collect();
3124        let mut state = State {
3125            side_one: Side::deserialize(split[0]),
3126            side_two: Side::deserialize(split[1]),
3127            weather: StateWeather::deserialize(split[2]),
3128            terrain: StateTerrain::deserialize(split[3]),
3129            trick_room: StateTrickRoom::deserialize(split[4]),
3130            team_preview: split[5].parse::<bool>().unwrap(),
3131            use_damage_dealt: false,
3132            use_last_used_move: false,
3133        };
3134        state.set_conditional_mechanics();
3135        state
3136    }
3137}