poke_engine/
state.rs

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