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