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