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