1use crate::choices::{Choice, Choices, MoveCategory, MOVES};
2use crate::define_enum_with_from_str;
3use crate::engine::abilities::Abilities;
4use crate::engine::items::Items;
5use crate::engine::state::{PokemonVolatileStatus, Terrain, Weather};
6use crate::instruction::{BoostInstruction, EnableMoveInstruction, Instruction};
7use crate::pokemon::PokemonName;
8use std::collections::HashSet;
9use std::ops::{Index, IndexMut};
10use std::str::FromStr;
11
12#[derive(Debug, PartialEq, Copy, Clone)]
13pub enum SideReference {
14 SideOne,
15 SideTwo,
16}
17impl SideReference {
18 pub fn get_other_side(&self) -> SideReference {
19 match self {
20 SideReference::SideOne => SideReference::SideTwo,
21 SideReference::SideTwo => SideReference::SideOne,
22 }
23 }
24}
25
26#[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)]
27pub enum PokemonSideCondition {
28 AuroraVeil,
29 CraftyShield,
30 HealingWish,
31 LightScreen,
32 LuckyChant,
33 LunarDance,
34 MatBlock,
35 Mist,
36 Protect,
37 QuickGuard,
38 Reflect,
39 Safeguard,
40 Spikes,
41 Stealthrock,
42 StickyWeb,
43 Tailwind,
44 ToxicCount,
45 ToxicSpikes,
46 WideGuard,
47}
48
49#[derive(Debug, PartialEq, Eq, Copy, Clone)]
50pub enum LastUsedMove {
51 Move(PokemonMoveIndex),
52 Switch(PokemonIndex),
53 None,
54}
55impl LastUsedMove {
56 pub fn serialize(&self) -> String {
57 match self {
58 LastUsedMove::Move(move_index) => format!("move:{}", move_index.serialize()),
59 LastUsedMove::Switch(pkmn_index) => format!("switch:{}", pkmn_index.serialize()),
60 LastUsedMove::None => "move:none".to_string(),
61 }
62 }
63 pub fn deserialize(serialized: &str) -> LastUsedMove {
64 let split: Vec<&str> = serialized.split(":").collect();
65 match split[0] {
66 "move" => {
67 if split[1] == "none" {
68 LastUsedMove::None
69 } else {
70 LastUsedMove::Move(PokemonMoveIndex::deserialize(split[1]))
71 }
72 }
73 "switch" => LastUsedMove::Switch(PokemonIndex::deserialize(split[1])),
74 _ => panic!("Invalid LastUsedMove: {}", serialized),
75 }
76 }
77}
78
79#[derive(Debug, Copy, PartialEq, Clone, Eq, Hash)]
80pub enum PokemonMoveIndex {
81 M0,
82 M1,
83 M2,
84 M3,
85}
86impl PokemonMoveIndex {
87 pub fn serialize(&self) -> String {
88 match self {
89 PokemonMoveIndex::M0 => "0".to_string(),
90 PokemonMoveIndex::M1 => "1".to_string(),
91 PokemonMoveIndex::M2 => "2".to_string(),
92 PokemonMoveIndex::M3 => "3".to_string(),
93 }
94 }
95 pub fn deserialize(serialized: &str) -> PokemonMoveIndex {
96 match serialized {
97 "0" => PokemonMoveIndex::M0,
98 "1" => PokemonMoveIndex::M1,
99 "2" => PokemonMoveIndex::M2,
100 "3" => PokemonMoveIndex::M3,
101 _ => panic!("Invalid PokemonMoveIndex: {}", serialized),
102 }
103 }
104}
105
106#[derive(Debug, PartialEq, Clone, Copy)]
107pub enum PokemonBoostableStat {
108 Attack,
109 Defense,
110 SpecialAttack,
111 SpecialDefense,
112 Speed,
113 Evasion,
114 Accuracy,
115}
116
117define_enum_with_from_str! {
118 #[repr(u8)]
119 #[derive(Debug, PartialEq, Copy, Clone)]
120 PokemonStatus {
121 NONE,
122 BURN,
123 SLEEP,
124 FREEZE,
125 PARALYZE,
126 POISON,
127 TOXIC,
128 }
129}
130
131define_enum_with_from_str! {
132 #[repr(u8)]
133 #[derive(Debug, PartialEq, Copy, Clone)]
134 SideMovesFirst {
135 SideOne,
136 SideTwo,
137 SpeedTie
138 }
139}
140
141define_enum_with_from_str! {
142 #[repr(u8)]
143 #[derive(Debug, PartialEq, Clone)]
144 PokemonNature {
145 HARDY,
146 LONELY,
147 ADAMANT,
148 NAUGHTY,
149 BRAVE,
150 BOLD,
151 DOCILE,
152 IMPISH,
153 LAX,
154 RELAXED,
155 MODEST,
156 MILD,
157 BASHFUL,
158 RASH,
159 QUIET,
160 CALM,
161 GENTLE,
162 CAREFUL,
163 QUIRKY,
164 SASSY,
165 TIMID,
166 HASTY,
167 JOLLY,
168 NAIVE,
169 SERIOUS
170 }
171}
172
173define_enum_with_from_str! {
174 #[repr(u8)]
175 #[derive(Debug, Clone, Copy, PartialEq)]
176 PokemonType {
177 NORMAL,
178 FIRE,
179 WATER,
180 ELECTRIC,
181 GRASS,
182 ICE,
183 FIGHTING,
184 POISON,
185 GROUND,
186 FLYING,
187 PSYCHIC,
188 BUG,
189 ROCK,
190 GHOST,
191 DRAGON,
192 DARK,
193 STEEL,
194 FAIRY,
195 STELLAR,
196 TYPELESS,
197 },
198 default = TYPELESS
199}
200
201impl Index<&PokemonMoveIndex> for PokemonMoves {
202 type Output = Move;
203
204 fn index(&self, index: &PokemonMoveIndex) -> &Self::Output {
205 match index {
206 PokemonMoveIndex::M0 => &self.m0,
207 PokemonMoveIndex::M1 => &self.m1,
208 PokemonMoveIndex::M2 => &self.m2,
209 PokemonMoveIndex::M3 => &self.m3,
210 }
211 }
212}
213
214impl IndexMut<&PokemonMoveIndex> for PokemonMoves {
215 fn index_mut(&mut self, index: &PokemonMoveIndex) -> &mut Self::Output {
216 match index {
217 PokemonMoveIndex::M0 => &mut self.m0,
218 PokemonMoveIndex::M1 => &mut self.m1,
219 PokemonMoveIndex::M2 => &mut self.m2,
220 PokemonMoveIndex::M3 => &mut self.m3,
221 }
222 }
223}
224
225pub struct PokemonMoveIterator<'a> {
226 pub pokemon_move: &'a PokemonMoves,
227 pub pokemon_move_index: PokemonMoveIndex,
228 pub index: usize,
229}
230
231impl<'a> Iterator for PokemonMoveIterator<'a> {
232 type Item = &'a Move;
233
234 fn next(&mut self) -> Option<Self::Item> {
235 match self.index {
236 0 => {
237 self.index += 1;
238 self.pokemon_move_index = PokemonMoveIndex::M0;
239 Some(&self.pokemon_move.m0)
240 }
241 1 => {
242 self.index += 1;
243 self.pokemon_move_index = PokemonMoveIndex::M1;
244 Some(&self.pokemon_move.m1)
245 }
246 2 => {
247 self.index += 1;
248 self.pokemon_move_index = PokemonMoveIndex::M2;
249 Some(&self.pokemon_move.m2)
250 }
251 3 => {
252 self.index += 1;
253 self.pokemon_move_index = PokemonMoveIndex::M3;
254 Some(&self.pokemon_move.m3)
255 }
256 _ => None,
257 }
258 }
259}
260
261impl<'a> IntoIterator for &'a PokemonMoves {
262 type Item = &'a Move;
263 type IntoIter = PokemonMoveIterator<'a>;
264
265 fn into_iter(self) -> Self::IntoIter {
266 PokemonMoveIterator {
267 pokemon_move: &self,
268 pokemon_move_index: PokemonMoveIndex::M0,
269 index: 0,
270 }
271 }
272}
273
274#[derive(Debug, Copy, PartialEq, Clone, Eq, Hash)]
275#[repr(u8)]
276pub enum PokemonIndex {
277 P0,
278 P1,
279 P2,
280 P3,
281 P4,
282 P5,
283}
284impl PokemonIndex {
285 pub fn serialize(&self) -> String {
286 match self {
287 PokemonIndex::P0 => "0".to_string(),
288 PokemonIndex::P1 => "1".to_string(),
289 PokemonIndex::P2 => "2".to_string(),
290 PokemonIndex::P3 => "3".to_string(),
291 PokemonIndex::P4 => "4".to_string(),
292 PokemonIndex::P5 => "5".to_string(),
293 }
294 }
295 pub fn deserialize(serialized: &str) -> PokemonIndex {
296 match serialized {
297 "0" => PokemonIndex::P0,
298 "1" => PokemonIndex::P1,
299 "2" => PokemonIndex::P2,
300 "3" => PokemonIndex::P3,
301 "4" => PokemonIndex::P4,
302 "5" => PokemonIndex::P5,
303 _ => panic!("Invalid PokemonIndex: {}", serialized),
304 }
305 }
306}
307
308pub fn pokemon_index_iter() -> PokemonIndexIterator {
309 PokemonIndexIterator { index: 0 }
310}
311
312pub struct PokemonIndexIterator {
313 index: usize,
314}
315
316impl Iterator for PokemonIndexIterator {
317 type Item = PokemonIndex;
318
319 fn next(&mut self) -> Option<Self::Item> {
320 match self.index {
321 0 => {
322 self.index += 1;
323 Some(PokemonIndex::P0)
324 }
325 1 => {
326 self.index += 1;
327 Some(PokemonIndex::P1)
328 }
329 2 => {
330 self.index += 1;
331 Some(PokemonIndex::P2)
332 }
333 3 => {
334 self.index += 1;
335 Some(PokemonIndex::P3)
336 }
337 4 => {
338 self.index += 1;
339 Some(PokemonIndex::P4)
340 }
341 5 => {
342 self.index += 1;
343 Some(PokemonIndex::P5)
344 }
345 _ => None,
346 }
347 }
348}
349
350#[derive(Debug, Clone)]
351pub struct SidePokemon {
352 pub pkmn: [Pokemon; 6],
353}
354
355impl<'a> IntoIterator for &'a SidePokemon {
356 type Item = &'a Pokemon;
357 type IntoIter = SidePokemonIterator<'a>;
358
359 fn into_iter(self) -> Self::IntoIter {
360 SidePokemonIterator {
361 side_pokemon: &self,
362 pokemon_index: PokemonIndex::P0,
363 index: 0,
364 }
365 }
366}
367
368pub struct SidePokemonIterator<'a> {
369 pub side_pokemon: &'a SidePokemon,
370 pub pokemon_index: PokemonIndex,
371 pub index: usize,
372}
373
374impl<'a> Iterator for SidePokemonIterator<'a> {
375 type Item = &'a Pokemon;
376
377 fn next(&mut self) -> Option<Self::Item> {
378 match self.index {
379 0 => {
380 self.index += 1;
381 self.pokemon_index = PokemonIndex::P0;
382 Some(&self.side_pokemon.pkmn[0])
383 }
384 1 => {
385 self.index += 1;
386 self.pokemon_index = PokemonIndex::P1;
387 Some(&self.side_pokemon.pkmn[1])
388 }
389 2 => {
390 self.index += 1;
391 self.pokemon_index = PokemonIndex::P2;
392 Some(&self.side_pokemon.pkmn[2])
393 }
394 3 => {
395 self.index += 1;
396 self.pokemon_index = PokemonIndex::P3;
397 Some(&self.side_pokemon.pkmn[3])
398 }
399 4 => {
400 self.index += 1;
401 self.pokemon_index = PokemonIndex::P4;
402 Some(&self.side_pokemon.pkmn[4])
403 }
404 5 => {
405 self.index += 1;
406 self.pokemon_index = PokemonIndex::P5;
407 Some(&self.side_pokemon.pkmn[5])
408 }
409 _ => None,
410 }
411 }
412}
413
414impl Index<PokemonIndex> for SidePokemon {
415 type Output = Pokemon;
416
417 fn index(&self, index: PokemonIndex) -> &Self::Output {
418 &self.pkmn[index as usize]
419 }
420}
421
422impl Index<&PokemonIndex> for SidePokemon {
423 type Output = Pokemon;
424
425 fn index(&self, index: &PokemonIndex) -> &Self::Output {
426 &self.pkmn[*index as usize]
427 }
428}
429
430impl IndexMut<PokemonIndex> for SidePokemon {
431 fn index_mut(&mut self, index: PokemonIndex) -> &mut Self::Output {
432 &mut self.pkmn[index as usize]
433 }
434}
435
436impl Default for Side {
437 fn default() -> Side {
438 Side {
439 active_index: PokemonIndex::P0,
440 baton_passing: false,
441 shed_tailing: false,
442 pokemon: SidePokemon {
443 pkmn: [
444 Pokemon::default(),
445 Pokemon::default(),
446 Pokemon::default(),
447 Pokemon::default(),
448 Pokemon::default(),
449 Pokemon::default(),
450 ],
451 },
452 substitute_health: 0,
453 attack_boost: 0,
454 defense_boost: 0,
455 special_attack_boost: 0,
456 special_defense_boost: 0,
457 speed_boost: 0,
458 accuracy_boost: 0,
459 side_conditions: SideConditions {
460 ..Default::default()
461 },
462 volatile_status_durations: VolatileStatusDurations::default(),
463 volatile_statuses: HashSet::<PokemonVolatileStatus>::new(),
464 wish: (0, 0),
465 future_sight: (0, PokemonIndex::P0),
466 force_switch: false,
467 slow_uturn_move: false,
468 force_trapped: false,
469 last_used_move: LastUsedMove::None,
470 damage_dealt: DamageDealt::default(),
471 switch_out_move_second_saved_move: Choices::NONE,
472 evasion_boost: 0,
473 }
474 }
475}
476
477#[derive(Debug, Clone)]
478pub struct Move {
479 pub id: Choices,
480 pub disabled: bool,
481 pub pp: i8,
482 pub choice: Choice,
483}
484impl Move {
485 pub fn serialize(&self) -> String {
486 format!("{:?};{};{}", self.id, self.disabled, self.pp)
487 }
488 pub fn deserialize(serialized: &str) -> Move {
489 let split: Vec<&str> = serialized.split(";").collect();
490 Move {
491 id: Choices::from_str(split[0]).unwrap(),
492 disabled: split[1].parse::<bool>().unwrap(),
493 pp: split[2].parse::<i8>().unwrap(),
494 choice: MOVES
495 .get(&Choices::from_str(split[0]).unwrap())
496 .unwrap()
497 .to_owned(),
498 }
499 }
500}
501impl Default for Move {
502 fn default() -> Move {
503 Move {
504 id: Choices::NONE,
505 disabled: false,
506 pp: 32,
507 choice: Choice::default(),
508 }
509 }
510}
511
512#[derive(Debug, Clone)]
513pub struct DamageDealt {
514 pub damage: i16,
515 pub move_category: MoveCategory,
516 pub hit_substitute: bool,
517}
518
519impl Default for DamageDealt {
520 fn default() -> DamageDealt {
521 DamageDealt {
522 damage: 0,
523 move_category: MoveCategory::Physical,
524 hit_substitute: false,
525 }
526 }
527}
528
529#[derive(Debug, Clone)]
530pub struct PokemonMoves {
531 pub m0: Move,
532 pub m1: Move,
533 pub m2: Move,
534 pub m3: Move,
535}
536
537#[derive(Debug, PartialEq, Clone)]
538pub struct SideConditions {
539 pub aurora_veil: i8,
540 pub crafty_shield: i8,
541 pub healing_wish: i8,
542 pub light_screen: i8,
543 pub lucky_chant: i8,
544 pub lunar_dance: i8,
545 pub mat_block: i8,
546 pub mist: i8,
547 pub protect: i8,
548 pub quick_guard: i8,
549 pub reflect: i8,
550 pub safeguard: i8,
551 pub spikes: i8,
552 pub stealth_rock: i8,
553 pub sticky_web: i8,
554 pub tailwind: i8,
555 pub toxic_count: i8,
556 pub toxic_spikes: i8,
557 pub wide_guard: i8,
558}
559impl SideConditions {
560 pub fn pprint(&self) -> String {
561 let conditions = [
562 ("aurora_veil", self.aurora_veil),
563 ("crafty_shield", self.crafty_shield),
564 ("healing_wish", self.healing_wish),
565 ("light_screen", self.light_screen),
566 ("lucky_chant", self.lucky_chant),
567 ("lunar_dance", self.lunar_dance),
568 ("mat_block", self.mat_block),
569 ("mist", self.mist),
570 ("protect", self.protect),
571 ("quick_guard", self.quick_guard),
572 ("reflect", self.reflect),
573 ("safeguard", self.safeguard),
574 ("spikes", self.spikes),
575 ("stealth_rock", self.stealth_rock),
576 ("sticky_web", self.sticky_web),
577 ("tailwind", self.tailwind),
578 ("toxic_count", self.toxic_count),
579 ("toxic_spikes", self.toxic_spikes),
580 ("wide_guard", self.wide_guard),
581 ];
582
583 let mut output = String::new();
584 for (name, value) in conditions {
585 if value != 0 {
586 output.push_str(&format!("\n {}: {}", name, value));
587 }
588 }
589 if output.is_empty() {
590 return "none".to_string();
591 }
592 output
593 }
594 pub fn serialize(&self) -> String {
595 format!(
596 "{};{};{};{};{};{};{};{};{};{};{};{};{};{};{};{};{};{};{}",
597 self.aurora_veil,
598 self.crafty_shield,
599 self.healing_wish,
600 self.light_screen,
601 self.lucky_chant,
602 self.lunar_dance,
603 self.mat_block,
604 self.mist,
605 self.protect,
606 self.quick_guard,
607 self.reflect,
608 self.safeguard,
609 self.spikes,
610 self.stealth_rock,
611 self.sticky_web,
612 self.tailwind,
613 self.toxic_count,
614 self.toxic_spikes,
615 self.wide_guard,
616 )
617 }
618 pub fn deserialize(serialized: &str) -> SideConditions {
619 let split: Vec<&str> = serialized.split(";").collect();
620 SideConditions {
621 aurora_veil: split[0].parse::<i8>().unwrap(),
622 crafty_shield: split[1].parse::<i8>().unwrap(),
623 healing_wish: split[2].parse::<i8>().unwrap(),
624 light_screen: split[3].parse::<i8>().unwrap(),
625 lucky_chant: split[4].parse::<i8>().unwrap(),
626 lunar_dance: split[5].parse::<i8>().unwrap(),
627 mat_block: split[6].parse::<i8>().unwrap(),
628 mist: split[7].parse::<i8>().unwrap(),
629 protect: split[8].parse::<i8>().unwrap(),
630 quick_guard: split[9].parse::<i8>().unwrap(),
631 reflect: split[10].parse::<i8>().unwrap(),
632 safeguard: split[11].parse::<i8>().unwrap(),
633 spikes: split[12].parse::<i8>().unwrap(),
634 stealth_rock: split[13].parse::<i8>().unwrap(),
635 sticky_web: split[14].parse::<i8>().unwrap(),
636 tailwind: split[15].parse::<i8>().unwrap(),
637 toxic_count: split[16].parse::<i8>().unwrap(),
638 toxic_spikes: split[17].parse::<i8>().unwrap(),
639 wide_guard: split[18].parse::<i8>().unwrap(),
640 }
641 }
642}
643impl Default for SideConditions {
644 fn default() -> SideConditions {
645 SideConditions {
646 aurora_veil: 0,
647 crafty_shield: 0,
648 healing_wish: 0,
649 light_screen: 0,
650 lucky_chant: 0,
651 lunar_dance: 0,
652 mat_block: 0,
653 mist: 0,
654 protect: 0,
655 quick_guard: 0,
656 reflect: 0,
657 safeguard: 0,
658 spikes: 0,
659 stealth_rock: 0,
660 sticky_web: 0,
661 tailwind: 0,
662 toxic_count: 0,
663 toxic_spikes: 0,
664 wide_guard: 0,
665 }
666 }
667}
668
669#[derive(Debug, PartialEq, Clone)]
670pub struct StateWeather {
671 pub weather_type: Weather,
672 pub turns_remaining: i8,
673}
674impl StateWeather {
675 pub fn serialize(&self) -> String {
676 format!("{:?};{}", self.weather_type, self.turns_remaining)
677 }
678 pub fn deserialize(serialized: &str) -> StateWeather {
679 let split: Vec<&str> = serialized.split(";").collect();
680 StateWeather {
681 weather_type: Weather::from_str(split[0]).unwrap(),
682 turns_remaining: split[1].parse::<i8>().unwrap(),
683 }
684 }
685}
686
687#[derive(Debug, PartialEq, Clone)]
688pub struct StateTerrain {
689 pub terrain_type: Terrain,
690 pub turns_remaining: i8,
691}
692impl StateTerrain {
693 pub fn serialize(&self) -> String {
694 format!("{:?};{}", self.terrain_type, self.turns_remaining)
695 }
696 pub fn deserialize(serialized: &str) -> StateTerrain {
697 let split: Vec<&str> = serialized.split(";").collect();
698 StateTerrain {
699 terrain_type: Terrain::from_str(split[0]).unwrap(),
700 turns_remaining: split[1].parse::<i8>().unwrap(),
701 }
702 }
703}
704
705#[derive(Debug, PartialEq, Clone)]
706pub struct StateTrickRoom {
707 pub active: bool,
708 pub turns_remaining: i8,
709}
710impl StateTrickRoom {
711 pub fn serialize(&self) -> String {
712 format!("{};{}", self.active, self.turns_remaining)
713 }
714 pub fn deserialize(serialized: &str) -> StateTrickRoom {
715 let split: Vec<&str> = serialized.split(";").collect();
716 StateTrickRoom {
717 active: split[0].parse::<bool>().unwrap(),
718 turns_remaining: split[1].parse::<i8>().unwrap(),
719 }
720 }
721}
722
723#[derive(Debug, Clone)]
724pub struct VolatileStatusDurations {
725 pub confusion: i8,
726 pub encore: i8,
727 pub lockedmove: i8,
728 pub slowstart: i8,
729 pub taunt: i8,
730 pub yawn: i8,
731}
732
733impl Default for VolatileStatusDurations {
734 fn default() -> VolatileStatusDurations {
735 VolatileStatusDurations {
736 confusion: 0,
737 encore: 0,
738 lockedmove: 0,
739 slowstart: 0,
740 taunt: 0,
741 yawn: 0,
742 }
743 }
744}
745
746impl VolatileStatusDurations {
747 pub fn pprint(&self) -> String {
748 let durations = [
749 ("confusion", self.confusion),
750 ("encore", self.encore),
751 ("lockedmove", self.lockedmove),
752 ("slowstart", self.slowstart),
753 ("taunt", self.taunt),
754 ("yawn", self.yawn),
755 ];
756
757 let mut output = String::new();
758 for (name, value) in durations {
759 if value != 0 {
760 output.push_str(&format!("\n {}: {}", name, value));
761 }
762 }
763 if output.is_empty() {
764 return "none".to_string();
765 }
766 output
767 }
768
769 pub fn serialize(&self) -> String {
770 format!(
771 "{};{};{};{};{};{}",
772 self.confusion, self.encore, self.lockedmove, self.slowstart, self.taunt, self.yawn
773 )
774 }
775 pub fn deserialize(serialized: &str) -> VolatileStatusDurations {
776 let split: Vec<&str> = serialized.split(";").collect();
777 VolatileStatusDurations {
778 confusion: split[0].parse::<i8>().unwrap(),
779 encore: split[1].parse::<i8>().unwrap(),
780 lockedmove: split[2].parse::<i8>().unwrap(),
781 slowstart: split[3].parse::<i8>().unwrap(),
782 taunt: split[4].parse::<i8>().unwrap(),
783 yawn: split[5].parse::<i8>().unwrap(),
784 }
785 }
786}
787
788#[derive(Debug, Clone)]
789pub struct Pokemon {
790 pub id: PokemonName,
791 pub level: i8,
792 pub types: (PokemonType, PokemonType),
793 pub base_types: (PokemonType, PokemonType),
794 pub hp: i16,
795 pub maxhp: i16,
796 pub ability: Abilities,
797 pub base_ability: Abilities,
798 pub item: Items,
799 pub nature: PokemonNature,
800 pub evs: (u8, u8, u8, u8, u8, u8),
801 pub attack: i16,
802 pub defense: i16,
803 pub special_attack: i16,
804 pub special_defense: i16,
805 pub speed: i16,
806 pub status: PokemonStatus,
807 pub rest_turns: i8,
808 pub sleep_turns: i8,
809 pub weight_kg: f32,
810 pub terastallized: bool,
811 pub tera_type: PokemonType,
812 pub moves: PokemonMoves,
813}
814
815impl Default for Pokemon {
816 fn default() -> Pokemon {
817 Pokemon {
818 id: PokemonName::NONE,
819 level: 100,
820 types: (PokemonType::NORMAL, PokemonType::TYPELESS),
821 base_types: (PokemonType::NORMAL, PokemonType::TYPELESS),
822 hp: 100,
823 maxhp: 100,
824 ability: Abilities::NONE,
825 base_ability: Abilities::NONE,
826 item: Items::NONE,
827 nature: PokemonNature::SERIOUS,
828 evs: (85, 85, 85, 85, 85, 85),
829 attack: 100,
830 defense: 100,
831 special_attack: 100,
832 special_defense: 100,
833 speed: 100,
834 status: PokemonStatus::NONE,
835 rest_turns: 0,
836 sleep_turns: 0,
837 weight_kg: 1.0,
838 terastallized: false,
839 tera_type: PokemonType::NORMAL,
840 moves: PokemonMoves {
841 m0: Default::default(),
842 m1: Default::default(),
843 m2: Default::default(),
844 m3: Default::default(),
845 },
846 }
847 }
848}
849
850impl Pokemon {
851 pub fn replace_move(&mut self, move_index: PokemonMoveIndex, new_move_name: Choices) {
852 self.moves[&move_index].choice = MOVES.get(&new_move_name).unwrap().to_owned();
853 self.moves[&move_index].id = new_move_name;
854 }
855 pub fn get_sleep_talk_choices(&self) -> Vec<Choice> {
856 let mut vec = Vec::with_capacity(4);
857 for p in self.moves.into_iter() {
858 if p.id != Choices::SLEEPTALK && p.id != Choices::NONE {
859 vec.push(p.choice.clone());
860 }
861 }
862 vec
863 }
864
865 fn pprint_stats(&self) -> String {
866 format!(
867 "atk:{} def:{} spa:{} spd:{} spe:{}",
868 self.attack, self.defense, self.special_attack, self.special_defense, self.speed
869 )
870 }
871 pub fn pprint_concise(&self) -> String {
872 format!("{}:{}/{}", self.id, self.hp, self.maxhp)
873 }
874 pub fn pprint_verbose(&self) -> String {
875 let moves: Vec<String> = self
876 .moves
877 .into_iter()
878 .map(|m| format!("{:?}", m.id).to_lowercase())
879 .filter(|x| x != "none")
880 .collect();
881 format!(
882 "\n Name: {}\n HP: {}/{}\n Status: {:?}\n Ability: {:?}\n Item: {:?}\n Stats: {}\n Moves: {}",
883 self.id,
884 self.hp,
885 self.maxhp,
886 self.status,
887 self.ability,
888 self.item,
889 self.pprint_stats(),
890 moves.join(", ")
891 )
892 }
893}
894
895impl Pokemon {
896 pub fn serialize(&self) -> String {
897 let evs_str = format!(
898 "{};{};{};{};{};{}",
899 self.evs.0, self.evs.1, self.evs.2, self.evs.3, self.evs.4, self.evs.5
900 );
901 format!(
902 "{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}",
903 self.id,
904 self.level,
905 self.types.0.to_string(),
906 self.types.1.to_string(),
907 self.base_types.0.to_string(),
908 self.base_types.1.to_string(),
909 self.hp,
910 self.maxhp,
911 self.ability.to_string(),
912 self.base_ability.to_string(),
913 self.item.to_string(),
914 self.nature.to_string(),
915 evs_str,
916 self.attack,
917 self.defense,
918 self.special_attack,
919 self.special_defense,
920 self.speed,
921 self.status.to_string(),
922 self.rest_turns,
923 self.sleep_turns,
924 self.weight_kg,
925 self.moves.m0.serialize(),
926 self.moves.m1.serialize(),
927 self.moves.m2.serialize(),
928 self.moves.m3.serialize(),
929 self.terastallized,
930 self.tera_type.to_string(),
931 )
932 }
933
934 pub fn deserialize(serialized: &str) -> Pokemon {
935 let split: Vec<&str> = serialized.split(",").collect();
936 let evs = if split[12] != "" {
937 let mut ev_iter = split[12].split(";");
938 (
939 ev_iter.next().unwrap().parse::<u8>().unwrap(),
940 ev_iter.next().unwrap().parse::<u8>().unwrap(),
941 ev_iter.next().unwrap().parse::<u8>().unwrap(),
942 ev_iter.next().unwrap().parse::<u8>().unwrap(),
943 ev_iter.next().unwrap().parse::<u8>().unwrap(),
944 ev_iter.next().unwrap().parse::<u8>().unwrap(),
945 )
946 } else {
947 (85, 85, 85, 85, 85, 85)
948 };
949 Pokemon {
950 id: PokemonName::from_str(split[0]).unwrap(),
951 level: split[1].parse::<i8>().unwrap(),
952 types: (
953 PokemonType::from_str(split[2]).unwrap(),
954 PokemonType::from_str(split[3]).unwrap(),
955 ),
956 base_types: (
957 PokemonType::from_str(split[4]).unwrap(),
958 PokemonType::from_str(split[5]).unwrap(),
959 ),
960 hp: split[6].parse::<i16>().unwrap(),
961 maxhp: split[7].parse::<i16>().unwrap(),
962 ability: Abilities::from_str(split[8]).unwrap(),
963 base_ability: Abilities::from_str(split[9]).unwrap(),
964 item: Items::from_str(split[10]).unwrap(),
965 nature: PokemonNature::from_str(split[11]).unwrap(),
966 evs,
967 attack: split[13].parse::<i16>().unwrap(),
968 defense: split[14].parse::<i16>().unwrap(),
969 special_attack: split[15].parse::<i16>().unwrap(),
970 special_defense: split[16].parse::<i16>().unwrap(),
971 speed: split[17].parse::<i16>().unwrap(),
972 status: PokemonStatus::from_str(split[18]).unwrap(),
973 rest_turns: split[19].parse::<i8>().unwrap(),
974 sleep_turns: split[20].parse::<i8>().unwrap(),
975 weight_kg: split[21].parse::<f32>().unwrap(),
976 moves: PokemonMoves {
977 m0: Move::deserialize(split[22]),
978 m1: Move::deserialize(split[23]),
979 m2: Move::deserialize(split[24]),
980 m3: Move::deserialize(split[25]),
981 },
982 terastallized: split[26].parse::<bool>().unwrap(),
983 tera_type: PokemonType::from_str(split[27]).unwrap(),
984 }
985 }
986}
987
988#[derive(Debug, Clone)]
989pub struct Side {
990 pub active_index: PokemonIndex,
991 pub baton_passing: bool,
992 pub shed_tailing: bool,
993 pub pokemon: SidePokemon,
994 pub side_conditions: SideConditions,
995 pub volatile_status_durations: VolatileStatusDurations,
996 pub wish: (i8, i16),
997 pub future_sight: (i8, PokemonIndex),
998 pub force_switch: bool,
999 pub force_trapped: bool,
1000 pub slow_uturn_move: bool,
1001 pub volatile_statuses: HashSet<PokemonVolatileStatus>,
1002 pub substitute_health: i16,
1003 pub attack_boost: i8,
1004 pub defense_boost: i8,
1005 pub special_attack_boost: i8,
1006 pub special_defense_boost: i8,
1007 pub speed_boost: i8,
1008 pub accuracy_boost: i8,
1009 pub evasion_boost: i8,
1010 pub last_used_move: LastUsedMove,
1011 pub damage_dealt: DamageDealt,
1012 pub switch_out_move_second_saved_move: Choices,
1013}
1014impl Side {
1015 fn io_conditional_print(&self) -> String {
1016 let mut output = String::new();
1017 if self.baton_passing {
1018 output.push_str("\n baton_passing: true");
1019 }
1020 if self.wish.0 != 0 {
1021 output.push_str(&format!("\n wish: ({}, {})", self.wish.0, self.wish.1));
1022 }
1023 if self.future_sight.0 != 0 {
1024 output.push_str(&format!(
1025 "\n future_sight: ({}, {:?})",
1026 self.future_sight.0, self.pokemon[self.future_sight.1].id
1027 ));
1028 }
1029 if self
1030 .volatile_statuses
1031 .contains(&PokemonVolatileStatus::SUBSTITUTE)
1032 {
1033 output.push_str(&format!(
1034 "\n substitute_health: {}",
1035 self.substitute_health
1036 ));
1037 }
1038
1039 if !output.is_empty() {
1040 output.insert_str(0, "Extras:");
1041 output.push_str("\n");
1042 }
1043
1044 output
1045 }
1046 pub fn pprint(&self, available_choices: Vec<String>) -> String {
1047 let reserve = self
1048 .pokemon
1049 .into_iter()
1050 .map(|p| p.pprint_concise())
1051 .collect::<Vec<String>>();
1052 format!(
1053 "\nPokemon: {}\n\
1054 Active:{}\n\
1055 Boosts: {}\n\
1056 Last Used Move: {}\n\
1057 Volatiles: {:?}\n\
1058 VolatileDurations: {}\n\
1059 Side Conditions: {}\n\
1060 {}\
1061 Available Choices: {}",
1062 reserve.join(", "),
1063 self.get_active_immutable().pprint_verbose(),
1064 format!(
1065 "Attack:{}, Defense:{}, SpecialAttack:{}, SpecialDefense:{}, Speed:{}",
1066 self.attack_boost,
1067 self.defense_boost,
1068 self.special_attack_boost,
1069 self.special_defense_boost,
1070 self.speed_boost
1071 ),
1072 self.last_used_move.serialize(),
1073 self.volatile_statuses,
1074 self.volatile_status_durations.pprint(),
1075 self.side_conditions.pprint(),
1076 self.io_conditional_print(),
1077 available_choices.join(", ")
1078 )
1079 }
1080 pub fn serialize(&self) -> String {
1081 let mut vs_string = String::new();
1082 for vs in &self.volatile_statuses {
1083 vs_string.push_str(&vs.to_string());
1084 vs_string.push_str(":");
1085 }
1086 format!(
1087 "{}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}={}",
1088 self.pokemon.pkmn[0].serialize(),
1089 self.pokemon.pkmn[1].serialize(),
1090 self.pokemon.pkmn[2].serialize(),
1091 self.pokemon.pkmn[3].serialize(),
1092 self.pokemon.pkmn[4].serialize(),
1093 self.pokemon.pkmn[5].serialize(),
1094 self.active_index.serialize(),
1095 self.side_conditions.serialize(),
1096 vs_string,
1097 self.volatile_status_durations.serialize(),
1098 self.substitute_health,
1099 self.attack_boost,
1100 self.defense_boost,
1101 self.special_attack_boost,
1102 self.special_defense_boost,
1103 self.speed_boost,
1104 self.accuracy_boost,
1105 self.evasion_boost,
1106 self.wish.0,
1107 self.wish.1,
1108 self.future_sight.0,
1109 self.future_sight.1.serialize(),
1110 self.force_switch,
1111 self.switch_out_move_second_saved_move.to_string(),
1112 self.baton_passing,
1113 self.shed_tailing,
1114 self.force_trapped,
1115 self.last_used_move.serialize(),
1116 self.slow_uturn_move,
1117 )
1118 }
1119 pub fn deserialize(serialized: &str) -> Side {
1120 let split: Vec<&str> = serialized.split("=").collect();
1121
1122 let mut vs_hashset = HashSet::new();
1123 if split[8] != "" {
1124 for item in split[8].split(":") {
1125 vs_hashset.insert(PokemonVolatileStatus::from_str(item).unwrap());
1126 }
1127 }
1128 Side {
1129 pokemon: SidePokemon {
1130 pkmn: [
1131 Pokemon::deserialize(split[0]),
1132 Pokemon::deserialize(split[1]),
1133 Pokemon::deserialize(split[2]),
1134 Pokemon::deserialize(split[3]),
1135 Pokemon::deserialize(split[4]),
1136 Pokemon::deserialize(split[5]),
1137 ],
1138 },
1139 active_index: PokemonIndex::deserialize(split[6]),
1140 side_conditions: SideConditions::deserialize(split[7]),
1141 volatile_statuses: vs_hashset,
1142 volatile_status_durations: VolatileStatusDurations::deserialize(split[9]),
1143 substitute_health: split[10].parse::<i16>().unwrap(),
1144 attack_boost: split[11].parse::<i8>().unwrap(),
1145 defense_boost: split[12].parse::<i8>().unwrap(),
1146 special_attack_boost: split[13].parse::<i8>().unwrap(),
1147 special_defense_boost: split[14].parse::<i8>().unwrap(),
1148 speed_boost: split[15].parse::<i8>().unwrap(),
1149 accuracy_boost: split[16].parse::<i8>().unwrap(),
1150 evasion_boost: split[17].parse::<i8>().unwrap(),
1151 wish: (
1152 split[18].parse::<i8>().unwrap(),
1153 split[19].parse::<i16>().unwrap(),
1154 ),
1155 future_sight: (
1156 split[20].parse::<i8>().unwrap(),
1157 PokemonIndex::deserialize(split[21]),
1158 ),
1159 force_switch: split[22].parse::<bool>().unwrap(),
1160 switch_out_move_second_saved_move: Choices::from_str(split[23]).unwrap(),
1161 baton_passing: split[24].parse::<bool>().unwrap(),
1162 shed_tailing: split[25].parse::<bool>().unwrap(),
1163 force_trapped: split[26].parse::<bool>().unwrap(),
1164 last_used_move: LastUsedMove::deserialize(split[27]),
1165 damage_dealt: DamageDealt::default(),
1166 slow_uturn_move: split[28].parse::<bool>().unwrap(),
1167 }
1168 }
1169}
1170impl Side {
1171 pub fn visible_alive_pkmn(&self) -> i8 {
1172 let mut count = 0;
1173 for p in self.pokemon.into_iter() {
1174 if p.hp > 0 {
1175 count += 1;
1176 }
1177 }
1178 count
1179 }
1180 pub fn get_active(&mut self) -> &mut Pokemon {
1181 &mut self.pokemon[self.active_index]
1182 }
1183 pub fn get_active_immutable(&self) -> &Pokemon {
1184 &self.pokemon[self.active_index]
1185 }
1186 fn toggle_force_switch(&mut self) {
1187 self.force_switch = !self.force_switch;
1188 }
1189 pub fn get_side_condition(&self, side_condition: PokemonSideCondition) -> i8 {
1190 match side_condition {
1191 PokemonSideCondition::AuroraVeil => self.side_conditions.aurora_veil,
1192 PokemonSideCondition::CraftyShield => self.side_conditions.crafty_shield,
1193 PokemonSideCondition::HealingWish => self.side_conditions.healing_wish,
1194 PokemonSideCondition::LightScreen => self.side_conditions.light_screen,
1195 PokemonSideCondition::LuckyChant => self.side_conditions.lucky_chant,
1196 PokemonSideCondition::LunarDance => self.side_conditions.lunar_dance,
1197 PokemonSideCondition::MatBlock => self.side_conditions.mat_block,
1198 PokemonSideCondition::Mist => self.side_conditions.mist,
1199 PokemonSideCondition::Protect => self.side_conditions.protect,
1200 PokemonSideCondition::QuickGuard => self.side_conditions.quick_guard,
1201 PokemonSideCondition::Reflect => self.side_conditions.reflect,
1202 PokemonSideCondition::Safeguard => self.side_conditions.safeguard,
1203 PokemonSideCondition::Spikes => self.side_conditions.spikes,
1204 PokemonSideCondition::Stealthrock => self.side_conditions.stealth_rock,
1205 PokemonSideCondition::StickyWeb => self.side_conditions.sticky_web,
1206 PokemonSideCondition::Tailwind => self.side_conditions.tailwind,
1207 PokemonSideCondition::ToxicCount => self.side_conditions.toxic_count,
1208 PokemonSideCondition::ToxicSpikes => self.side_conditions.toxic_spikes,
1209 PokemonSideCondition::WideGuard => self.side_conditions.wide_guard,
1210 }
1211 }
1212 pub fn update_side_condition(&mut self, side_condition: PokemonSideCondition, amount: i8) {
1213 match side_condition {
1214 PokemonSideCondition::AuroraVeil => self.side_conditions.aurora_veil += amount,
1215 PokemonSideCondition::CraftyShield => self.side_conditions.crafty_shield += amount,
1216 PokemonSideCondition::HealingWish => self.side_conditions.healing_wish += amount,
1217 PokemonSideCondition::LightScreen => self.side_conditions.light_screen += amount,
1218 PokemonSideCondition::LuckyChant => self.side_conditions.lucky_chant += amount,
1219 PokemonSideCondition::LunarDance => self.side_conditions.lunar_dance += amount,
1220 PokemonSideCondition::MatBlock => self.side_conditions.mat_block += amount,
1221 PokemonSideCondition::Mist => self.side_conditions.mist += amount,
1222 PokemonSideCondition::Protect => self.side_conditions.protect += amount,
1223 PokemonSideCondition::QuickGuard => self.side_conditions.quick_guard += amount,
1224 PokemonSideCondition::Reflect => self.side_conditions.reflect += amount,
1225 PokemonSideCondition::Safeguard => self.side_conditions.safeguard += amount,
1226 PokemonSideCondition::Spikes => self.side_conditions.spikes += amount,
1227 PokemonSideCondition::Stealthrock => self.side_conditions.stealth_rock += amount,
1228 PokemonSideCondition::StickyWeb => self.side_conditions.sticky_web += amount,
1229 PokemonSideCondition::Tailwind => self.side_conditions.tailwind += amount,
1230 PokemonSideCondition::ToxicCount => self.side_conditions.toxic_count += amount,
1231 PokemonSideCondition::ToxicSpikes => self.side_conditions.toxic_spikes += amount,
1232 PokemonSideCondition::WideGuard => self.side_conditions.wide_guard += amount,
1233 }
1234 }
1235 pub fn get_alive_pkmn_indices(&self) -> Vec<PokemonIndex> {
1236 let mut vec = Vec::with_capacity(6);
1237 let mut iter = self.pokemon.into_iter();
1238
1239 while let Some(p) = iter.next() {
1240 if p.hp > 0 && iter.pokemon_index != self.active_index {
1241 vec.push(iter.pokemon_index.clone());
1242 }
1243 }
1244
1245 vec
1246 }
1247}
1248
1249#[derive(Debug, Clone)]
1250pub struct State {
1251 pub side_one: Side,
1252 pub side_two: Side,
1253 pub weather: StateWeather,
1254 pub terrain: StateTerrain,
1255 pub trick_room: StateTrickRoom,
1256 pub team_preview: bool,
1257 pub use_last_used_move: bool,
1258 pub use_damage_dealt: bool,
1259}
1260impl Default for State {
1261 fn default() -> State {
1262 let mut s = State {
1263 side_one: Side::default(),
1264 side_two: Side::default(),
1265 weather: StateWeather {
1266 weather_type: Weather::NONE,
1267 turns_remaining: -1,
1268 },
1269 terrain: StateTerrain {
1270 terrain_type: Terrain::NONE,
1271 turns_remaining: 0,
1272 },
1273 trick_room: StateTrickRoom {
1274 active: false,
1275 turns_remaining: 0,
1276 },
1277 team_preview: false,
1278 use_damage_dealt: false,
1279 use_last_used_move: false,
1280 };
1281
1282 s.side_two.get_active().speed += 1;
1284 s
1285 }
1286}
1287impl State {
1288 pub fn battle_is_over(&self) -> f32 {
1289 if self.side_one.pokemon.into_iter().all(|p| p.hp <= 0) {
1293 return -1.0;
1294 }
1295 if self.side_two.pokemon.into_iter().all(|p| p.hp <= 0) {
1296 return 1.0;
1297 }
1298 0.0
1299 }
1300
1301 pub fn get_side(&mut self, side_ref: &SideReference) -> &mut Side {
1302 match side_ref {
1303 SideReference::SideOne => &mut self.side_one,
1304 SideReference::SideTwo => &mut self.side_two,
1305 }
1306 }
1307
1308 pub fn get_side_immutable(&self, side_ref: &SideReference) -> &Side {
1309 match side_ref {
1310 SideReference::SideOne => &self.side_one,
1311 SideReference::SideTwo => &self.side_two,
1312 }
1313 }
1314
1315 pub fn get_both_sides(&mut self, side_ref: &SideReference) -> (&mut Side, &mut Side) {
1316 match side_ref {
1317 SideReference::SideOne => (&mut self.side_one, &mut self.side_two),
1318 SideReference::SideTwo => (&mut self.side_two, &mut self.side_one),
1319 }
1320 }
1321
1322 pub fn get_both_sides_immutable(&self, side_ref: &SideReference) -> (&Side, &Side) {
1323 match side_ref {
1324 SideReference::SideOne => (&self.side_one, &self.side_two),
1325 SideReference::SideTwo => (&self.side_two, &self.side_one),
1326 }
1327 }
1328
1329 pub fn reset_boosts(&mut self, side_ref: &SideReference, vec_to_add_to: &mut Vec<Instruction>) {
1330 let side = self.get_side(side_ref);
1331
1332 if side.attack_boost != 0 {
1333 vec_to_add_to.push(Instruction::Boost(BoostInstruction {
1334 side_ref: *side_ref,
1335 stat: PokemonBoostableStat::Attack,
1336 amount: -1 * side.attack_boost,
1337 }));
1338 side.attack_boost = 0;
1339 }
1340
1341 if side.defense_boost != 0 {
1342 vec_to_add_to.push(Instruction::Boost(BoostInstruction {
1343 side_ref: *side_ref,
1344 stat: PokemonBoostableStat::Defense,
1345 amount: -1 * side.defense_boost,
1346 }));
1347 side.defense_boost = 0;
1348 }
1349
1350 if side.special_attack_boost != 0 {
1351 vec_to_add_to.push(Instruction::Boost(BoostInstruction {
1352 side_ref: *side_ref,
1353 stat: PokemonBoostableStat::SpecialAttack,
1354 amount: -1 * side.special_attack_boost,
1355 }));
1356 side.special_attack_boost = 0;
1357 }
1358
1359 if side.special_defense_boost != 0 {
1360 vec_to_add_to.push(Instruction::Boost(BoostInstruction {
1361 side_ref: *side_ref,
1362 stat: PokemonBoostableStat::SpecialDefense,
1363 amount: -1 * side.special_defense_boost,
1364 }));
1365 side.special_defense_boost = 0;
1366 }
1367
1368 if side.speed_boost != 0 {
1369 vec_to_add_to.push(Instruction::Boost(BoostInstruction {
1370 side_ref: *side_ref,
1371 stat: PokemonBoostableStat::Speed,
1372 amount: -1 * side.speed_boost,
1373 }));
1374 side.speed_boost = 0;
1375 }
1376
1377 if side.evasion_boost != 0 {
1378 vec_to_add_to.push(Instruction::Boost(BoostInstruction {
1379 side_ref: *side_ref,
1380 stat: PokemonBoostableStat::Evasion,
1381 amount: -1 * side.evasion_boost,
1382 }));
1383 side.evasion_boost = 0;
1384 }
1385
1386 if side.accuracy_boost != 0 {
1387 vec_to_add_to.push(Instruction::Boost(BoostInstruction {
1388 side_ref: *side_ref,
1389 stat: PokemonBoostableStat::Accuracy,
1390 amount: -1 * side.accuracy_boost,
1391 }));
1392 side.accuracy_boost = 0;
1393 }
1394 }
1395
1396 pub fn re_enable_disabled_moves(
1397 &mut self,
1398 side_ref: &SideReference,
1399 vec_to_add_to: &mut Vec<Instruction>,
1400 ) {
1401 let active = self.get_side(side_ref).get_active();
1402 if active.moves.m0.disabled {
1403 active.moves.m0.disabled = false;
1404 vec_to_add_to.push(Instruction::EnableMove(EnableMoveInstruction {
1405 side_ref: *side_ref,
1406 move_index: PokemonMoveIndex::M0,
1407 }));
1408 }
1409 if active.moves.m1.disabled {
1410 active.moves.m1.disabled = false;
1411 vec_to_add_to.push(Instruction::EnableMove(EnableMoveInstruction {
1412 side_ref: *side_ref,
1413 move_index: PokemonMoveIndex::M1,
1414 }));
1415 }
1416 if active.moves.m2.disabled {
1417 active.moves.m2.disabled = false;
1418 vec_to_add_to.push(Instruction::EnableMove(EnableMoveInstruction {
1419 side_ref: *side_ref,
1420 move_index: PokemonMoveIndex::M2,
1421 }));
1422 }
1423 if active.moves.m3.disabled {
1424 active.moves.m3.disabled = false;
1425 vec_to_add_to.push(Instruction::EnableMove(EnableMoveInstruction {
1426 side_ref: *side_ref,
1427 move_index: PokemonMoveIndex::M3,
1428 }));
1429 }
1430 }
1431
1432 fn damage(&mut self, side_ref: &SideReference, amount: i16) {
1433 let active = self.get_side(&side_ref).get_active();
1434
1435 active.hp -= amount;
1436 }
1437
1438 fn heal(&mut self, side_ref: &SideReference, amount: i16) {
1439 let active = self.get_side(&side_ref).get_active();
1440
1441 active.hp += amount;
1442 }
1443
1444 fn switch(
1445 &mut self,
1446 side_ref: &SideReference,
1447 next_active_index: PokemonIndex,
1448 _: PokemonIndex,
1449 ) {
1450 let side = self.get_side(&side_ref);
1451 side.active_index = next_active_index;
1452 }
1453
1454 fn reverse_switch(
1455 &mut self,
1456 side_ref: &SideReference,
1457 _: PokemonIndex,
1458 previous_active_index: PokemonIndex,
1459 ) {
1460 let side = self.get_side(&side_ref);
1461 side.active_index = previous_active_index;
1462 }
1463
1464 fn apply_volatile_status(
1465 &mut self,
1466 side_ref: &SideReference,
1467 volatile_status: PokemonVolatileStatus,
1468 ) {
1469 self.get_side(&side_ref)
1470 .volatile_statuses
1471 .insert(volatile_status);
1472 }
1473
1474 fn remove_volatile_status(
1475 &mut self,
1476 side_ref: &SideReference,
1477 volatile_status: PokemonVolatileStatus,
1478 ) {
1479 self.get_side(&side_ref)
1480 .volatile_statuses
1481 .remove(&volatile_status);
1482 }
1483
1484 fn change_status(
1485 &mut self,
1486 side_ref: &SideReference,
1487 pokemon_index: PokemonIndex,
1488 new_status: PokemonStatus,
1489 ) {
1490 let pkmn = &mut self.get_side(&side_ref).pokemon[pokemon_index];
1491 pkmn.status = new_status;
1492 }
1493
1494 fn apply_boost(&mut self, side_ref: &SideReference, stat: &PokemonBoostableStat, amount: i8) {
1495 let side = self.get_side(&side_ref);
1496 match stat {
1497 PokemonBoostableStat::Attack => side.attack_boost += amount,
1498 PokemonBoostableStat::Defense => side.defense_boost += amount,
1499 PokemonBoostableStat::SpecialAttack => side.special_attack_boost += amount,
1500 PokemonBoostableStat::SpecialDefense => side.special_defense_boost += amount,
1501 PokemonBoostableStat::Speed => side.speed_boost += amount,
1502 PokemonBoostableStat::Evasion => side.evasion_boost += amount,
1503 PokemonBoostableStat::Accuracy => side.accuracy_boost += amount,
1504 }
1505 }
1506
1507 fn increment_side_condition(
1508 &mut self,
1509 side_ref: &SideReference,
1510 side_condition: &PokemonSideCondition,
1511 amount: i8,
1512 ) {
1513 let side = self.get_side(&side_ref);
1514
1515 match side_condition {
1516 PokemonSideCondition::AuroraVeil => side.side_conditions.aurora_veil += amount,
1517 PokemonSideCondition::CraftyShield => side.side_conditions.crafty_shield += amount,
1518 PokemonSideCondition::HealingWish => side.side_conditions.healing_wish += amount,
1519 PokemonSideCondition::LightScreen => side.side_conditions.light_screen += amount,
1520 PokemonSideCondition::LuckyChant => side.side_conditions.lucky_chant += amount,
1521 PokemonSideCondition::LunarDance => side.side_conditions.lunar_dance += amount,
1522 PokemonSideCondition::MatBlock => side.side_conditions.mat_block += amount,
1523 PokemonSideCondition::Mist => side.side_conditions.mist += amount,
1524 PokemonSideCondition::Protect => side.side_conditions.protect += amount,
1525 PokemonSideCondition::QuickGuard => side.side_conditions.quick_guard += amount,
1526 PokemonSideCondition::Reflect => side.side_conditions.reflect += amount,
1527 PokemonSideCondition::Safeguard => side.side_conditions.safeguard += amount,
1528 PokemonSideCondition::Spikes => side.side_conditions.spikes += amount,
1529 PokemonSideCondition::Stealthrock => side.side_conditions.stealth_rock += amount,
1530 PokemonSideCondition::StickyWeb => side.side_conditions.sticky_web += amount,
1531 PokemonSideCondition::Tailwind => side.side_conditions.tailwind += amount,
1532 PokemonSideCondition::ToxicCount => side.side_conditions.toxic_count += amount,
1533 PokemonSideCondition::ToxicSpikes => side.side_conditions.toxic_spikes += amount,
1534 PokemonSideCondition::WideGuard => side.side_conditions.wide_guard += amount,
1535 }
1536 }
1537
1538 fn increment_volatile_status_duration(
1539 &mut self,
1540 side_ref: &SideReference,
1541 volatile_status: &PokemonVolatileStatus,
1542 amount: i8,
1543 ) {
1544 let side = self.get_side(&side_ref);
1545 match volatile_status {
1546 PokemonVolatileStatus::CONFUSION => {
1547 side.volatile_status_durations.confusion += amount;
1548 }
1549 PokemonVolatileStatus::LOCKEDMOVE => {
1550 side.volatile_status_durations.lockedmove += amount;
1551 }
1552 PokemonVolatileStatus::ENCORE => {
1553 side.volatile_status_durations.encore += amount;
1554 }
1555 PokemonVolatileStatus::SLOWSTART => {
1556 side.volatile_status_durations.slowstart += amount;
1557 }
1558 PokemonVolatileStatus::TAUNT => {
1559 side.volatile_status_durations.taunt += amount;
1560 }
1561 PokemonVolatileStatus::YAWN => {
1562 side.volatile_status_durations.yawn += amount;
1563 }
1564 _ => panic!(
1565 "Invalid volatile status for increment_volatile_status_duration: {:?}",
1566 volatile_status
1567 ),
1568 }
1569 }
1570
1571 fn change_types(
1572 &mut self,
1573 side_reference: &SideReference,
1574 new_types: (PokemonType, PokemonType),
1575 ) {
1576 self.get_side(side_reference).get_active().types = new_types;
1577 }
1578
1579 fn change_item(&mut self, side_reference: &SideReference, new_item: Items) {
1580 self.get_side(side_reference).get_active().item = new_item;
1581 }
1582
1583 fn change_weather(&mut self, weather_type: Weather, turns_remaining: i8) {
1584 self.weather.weather_type = weather_type;
1585 self.weather.turns_remaining = turns_remaining;
1586 }
1587
1588 fn change_terrain(&mut self, terrain_type: Terrain, turns_remaining: i8) {
1589 self.terrain.terrain_type = terrain_type;
1590 self.terrain.turns_remaining = turns_remaining;
1591 }
1592
1593 fn enable_move(&mut self, side_reference: &SideReference, move_index: &PokemonMoveIndex) {
1594 self.get_side(side_reference).get_active().moves[move_index].disabled = false;
1595 }
1596
1597 fn disable_move(&mut self, side_reference: &SideReference, move_index: &PokemonMoveIndex) {
1598 self.get_side(side_reference).get_active().moves[move_index].disabled = true;
1599 }
1600
1601 fn set_wish(&mut self, side_reference: &SideReference, wish_amount_change: i16) {
1602 self.get_side(side_reference).wish.0 = 2;
1603 self.get_side(side_reference).wish.1 += wish_amount_change;
1604 }
1605
1606 fn unset_wish(&mut self, side_reference: &SideReference, wish_amount_change: i16) {
1607 self.get_side(side_reference).wish.0 = 0;
1608 self.get_side(side_reference).wish.1 -= wish_amount_change;
1609 }
1610
1611 fn increment_wish(&mut self, side_reference: &SideReference) {
1612 self.get_side(side_reference).wish.0 += 1;
1613 }
1614
1615 fn decrement_wish(&mut self, side_reference: &SideReference) {
1616 self.get_side(side_reference).wish.0 -= 1;
1617 }
1618
1619 fn set_future_sight(&mut self, side_reference: &SideReference, pokemon_index: PokemonIndex) {
1620 let side = self.get_side(side_reference);
1621 side.future_sight.0 = 3;
1622 side.future_sight.1 = pokemon_index;
1623 }
1624
1625 fn unset_future_sight(
1626 &mut self,
1627 side_reference: &SideReference,
1628 previous_pokemon_index: PokemonIndex,
1629 ) {
1630 let side = self.get_side(side_reference);
1631 side.future_sight.0 = 0;
1632 side.future_sight.1 = previous_pokemon_index;
1633 }
1634
1635 fn increment_future_sight(&mut self, side_reference: &SideReference) {
1636 self.get_side(side_reference).future_sight.0 += 1;
1637 }
1638
1639 fn decrement_future_sight(&mut self, side_reference: &SideReference) {
1640 self.get_side(side_reference).future_sight.0 -= 1;
1641 }
1642
1643 fn damage_substitute(&mut self, side_reference: &SideReference, amount: i16) {
1644 self.get_side(side_reference).substitute_health -= amount;
1645 }
1646
1647 fn heal_substitute(&mut self, side_reference: &SideReference, amount: i16) {
1648 self.get_side(side_reference).substitute_health += amount;
1649 }
1650
1651 fn set_substitute_health(&mut self, side_reference: &SideReference, amount: i16) {
1652 self.get_side(side_reference).substitute_health += amount;
1653 }
1654
1655 fn decrement_rest_turn(&mut self, side_reference: &SideReference) {
1656 self.get_side(side_reference).get_active().rest_turns -= 1;
1657 }
1658
1659 fn increment_rest_turn(&mut self, side_reference: &SideReference) {
1660 self.get_side(side_reference).get_active().rest_turns += 1;
1661 }
1662
1663 fn set_rest_turn(
1664 &mut self,
1665 side_reference: &SideReference,
1666 pokemon_index: PokemonIndex,
1667 amount: i8,
1668 ) {
1669 self.get_side(side_reference).pokemon[pokemon_index].rest_turns = amount;
1670 }
1671
1672 fn set_sleep_turn(
1673 &mut self,
1674 side_reference: &SideReference,
1675 pokemon_index: PokemonIndex,
1676 amount: i8,
1677 ) {
1678 self.get_side(side_reference).pokemon[pokemon_index].sleep_turns = amount;
1679 }
1680
1681 fn toggle_trickroom(&mut self, new_turns_remaining: i8) {
1682 self.trick_room.active = !self.trick_room.active;
1683 self.trick_room.turns_remaining = new_turns_remaining;
1684 }
1685
1686 fn set_last_used_move(&mut self, side_reference: &SideReference, last_used_move: LastUsedMove) {
1687 match side_reference {
1688 SideReference::SideOne => self.side_one.last_used_move = last_used_move,
1689 SideReference::SideTwo => self.side_two.last_used_move = last_used_move,
1690 }
1691 }
1692
1693 fn decrement_pp(
1694 &mut self,
1695 side_reference: &SideReference,
1696 move_index: &PokemonMoveIndex,
1697 amount: &i8,
1698 ) {
1699 match side_reference {
1700 SideReference::SideOne => self.side_one.get_active().moves[move_index].pp -= amount,
1701 SideReference::SideTwo => self.side_two.get_active().moves[move_index].pp -= amount,
1702 }
1703 }
1704
1705 fn increment_pp(
1706 &mut self,
1707 side_reference: &SideReference,
1708 move_index: &PokemonMoveIndex,
1709 amount: &i8,
1710 ) {
1711 match side_reference {
1712 SideReference::SideOne => self.side_one.get_active().moves[move_index].pp += amount,
1713 SideReference::SideTwo => self.side_two.get_active().moves[move_index].pp += amount,
1714 }
1715 }
1716
1717 pub fn apply_instructions(&mut self, instructions: &Vec<Instruction>) {
1718 for i in instructions {
1719 self.apply_one_instruction(i)
1720 }
1721 }
1722
1723 pub fn apply_one_instruction(&mut self, instruction: &Instruction) {
1724 match instruction {
1725 Instruction::Damage(instruction) => {
1726 self.damage(&instruction.side_ref, instruction.damage_amount)
1727 }
1728 Instruction::Switch(instruction) => self.switch(
1729 &instruction.side_ref,
1730 instruction.next_index,
1731 instruction.previous_index,
1732 ),
1733 Instruction::ApplyVolatileStatus(instruction) => {
1734 self.apply_volatile_status(&instruction.side_ref, instruction.volatile_status)
1735 }
1736 Instruction::RemoveVolatileStatus(instruction) => {
1737 self.remove_volatile_status(&instruction.side_ref, instruction.volatile_status)
1738 }
1739 Instruction::ChangeStatus(instruction) => self.change_status(
1740 &instruction.side_ref,
1741 instruction.pokemon_index,
1742 instruction.new_status,
1743 ),
1744 Instruction::Boost(instruction) => {
1745 self.apply_boost(&instruction.side_ref, &instruction.stat, instruction.amount)
1746 }
1747 Instruction::ChangeSideCondition(instruction) => self.increment_side_condition(
1748 &instruction.side_ref,
1749 &instruction.side_condition,
1750 instruction.amount,
1751 ),
1752 Instruction::ChangeVolatileStatusDuration(instruction) => self
1753 .increment_volatile_status_duration(
1754 &instruction.side_ref,
1755 &instruction.volatile_status,
1756 instruction.amount,
1757 ),
1758 Instruction::ChangeWeather(instruction) => self.change_weather(
1759 instruction.new_weather,
1760 instruction.new_weather_turns_remaining,
1761 ),
1762 Instruction::DecrementWeatherTurnsRemaining => {
1763 self.weather.turns_remaining -= 1;
1764 }
1765 Instruction::ChangeTerrain(instruction) => self.change_terrain(
1766 instruction.new_terrain,
1767 instruction.new_terrain_turns_remaining,
1768 ),
1769 Instruction::DecrementTerrainTurnsRemaining => {
1770 self.terrain.turns_remaining -= 1;
1771 }
1772 Instruction::ChangeType(instruction) => {
1773 self.change_types(&instruction.side_ref, instruction.new_types)
1774 }
1775 Instruction::ChangeAbility(instruction) => {
1776 let active = self.get_side(&instruction.side_ref).get_active();
1777 active.ability =
1778 Abilities::from(active.ability as i16 + instruction.ability_change);
1779 }
1780 Instruction::Heal(instruction) => {
1781 self.heal(&instruction.side_ref, instruction.heal_amount)
1782 }
1783 Instruction::ChangeItem(instruction) => {
1784 self.change_item(&instruction.side_ref, instruction.new_item)
1785 }
1786 Instruction::ChangeAttack(instruction) => {
1787 self.get_side(&instruction.side_ref).get_active().attack += instruction.amount;
1788 }
1789 Instruction::ChangeDefense(instruction) => {
1790 self.get_side(&instruction.side_ref).get_active().defense += instruction.amount;
1791 }
1792 Instruction::ChangeSpecialAttack(instruction) => {
1793 self.get_side(&instruction.side_ref)
1794 .get_active()
1795 .special_attack += instruction.amount;
1796 }
1797 Instruction::ChangeSpecialDefense(instruction) => {
1798 self.get_side(&instruction.side_ref)
1799 .get_active()
1800 .special_defense += instruction.amount;
1801 }
1802 Instruction::ChangeSpeed(instruction) => {
1803 self.get_side(&instruction.side_ref).get_active().speed += instruction.amount;
1804 }
1805 Instruction::EnableMove(instruction) => {
1806 self.enable_move(&instruction.side_ref, &instruction.move_index)
1807 }
1808 Instruction::DisableMove(instruction) => {
1809 self.disable_move(&instruction.side_ref, &instruction.move_index)
1810 }
1811 Instruction::ChangeWish(instruction) => {
1812 self.set_wish(&instruction.side_ref, instruction.wish_amount_change);
1813 }
1814 Instruction::DecrementWish(instruction) => {
1815 self.decrement_wish(&instruction.side_ref);
1816 }
1817 Instruction::SetFutureSight(instruction) => {
1818 self.set_future_sight(&instruction.side_ref, instruction.pokemon_index);
1819 }
1820 Instruction::DecrementFutureSight(instruction) => {
1821 self.decrement_future_sight(&instruction.side_ref);
1822 }
1823 Instruction::DamageSubstitute(instruction) => {
1824 self.damage_substitute(&instruction.side_ref, instruction.damage_amount);
1825 }
1826 Instruction::ChangeSubstituteHealth(instruction) => {
1827 self.set_substitute_health(&instruction.side_ref, instruction.health_change);
1828 }
1829 Instruction::SetRestTurns(instruction) => {
1830 self.set_rest_turn(
1831 &instruction.side_ref,
1832 instruction.pokemon_index,
1833 instruction.new_turns,
1834 );
1835 }
1836 Instruction::SetSleepTurns(instruction) => {
1837 self.set_sleep_turn(
1838 &instruction.side_ref,
1839 instruction.pokemon_index,
1840 instruction.new_turns,
1841 );
1842 }
1843 Instruction::DecrementRestTurns(instruction) => {
1844 self.decrement_rest_turn(&instruction.side_ref);
1845 }
1846 Instruction::ToggleTrickRoom(instruction) => {
1847 self.toggle_trickroom(instruction.new_trickroom_turns_remaining)
1848 }
1849 Instruction::DecrementTrickRoomTurnsRemaining => {
1850 self.trick_room.turns_remaining -= 1;
1851 }
1852 Instruction::ToggleSideOneForceSwitch => self.side_one.toggle_force_switch(),
1853 Instruction::ToggleSideTwoForceSwitch => self.side_two.toggle_force_switch(),
1854 Instruction::SetSideOneMoveSecondSwitchOutMove(instruction) => {
1855 self.side_one.switch_out_move_second_saved_move = instruction.new_choice;
1856 }
1857 Instruction::SetSideTwoMoveSecondSwitchOutMove(instruction) => {
1858 self.side_two.switch_out_move_second_saved_move = instruction.new_choice;
1859 }
1860 Instruction::ToggleBatonPassing(instruction) => match instruction.side_ref {
1861 SideReference::SideOne => {
1862 self.side_one.baton_passing = !self.side_one.baton_passing
1863 }
1864 SideReference::SideTwo => {
1865 self.side_two.baton_passing = !self.side_two.baton_passing
1866 }
1867 },
1868 Instruction::ToggleShedTailing(instruction) => match instruction.side_ref {
1869 SideReference::SideOne => self.side_one.shed_tailing = !self.side_one.shed_tailing,
1870 SideReference::SideTwo => self.side_two.shed_tailing = !self.side_two.shed_tailing,
1871 },
1872 Instruction::ToggleTerastallized(instruction) => match instruction.side_ref {
1873 SideReference::SideOne => self.side_one.get_active().terastallized ^= true,
1874 SideReference::SideTwo => self.side_two.get_active().terastallized ^= true,
1875 },
1876 Instruction::SetLastUsedMove(instruction) => {
1877 self.set_last_used_move(&instruction.side_ref, instruction.last_used_move)
1878 }
1879 Instruction::ChangeDamageDealtDamage(instruction) => {
1880 self.get_side(&instruction.side_ref).damage_dealt.damage +=
1881 instruction.damage_change
1882 }
1883 Instruction::ChangeDamageDealtMoveCatagory(instruction) => {
1884 self.get_side(&instruction.side_ref)
1885 .damage_dealt
1886 .move_category = instruction.move_category
1887 }
1888 Instruction::ToggleDamageDealtHitSubstitute(instruction) => {
1889 let side = self.get_side(&instruction.side_ref);
1890 side.damage_dealt.hit_substitute = !side.damage_dealt.hit_substitute;
1891 }
1892 Instruction::DecrementPP(instruction) => self.decrement_pp(
1893 &instruction.side_ref,
1894 &instruction.move_index,
1895 &instruction.amount,
1896 ),
1897 Instruction::FormeChange(instruction) => {
1898 let active = self.get_side(&instruction.side_ref).get_active();
1899 active.id = PokemonName::from(active.id as i16 + instruction.name_change);
1900 }
1901 }
1902 }
1903
1904 pub fn reverse_instructions(&mut self, instructions: &Vec<Instruction>) {
1905 for i in instructions.iter().rev() {
1906 self.reverse_one_instruction(i);
1907 }
1908 }
1909
1910 pub fn reverse_one_instruction(&mut self, instruction: &Instruction) {
1911 match instruction {
1912 Instruction::Damage(instruction) => {
1913 self.heal(&instruction.side_ref, instruction.damage_amount)
1914 }
1915 Instruction::Switch(instruction) => self.reverse_switch(
1916 &instruction.side_ref,
1917 instruction.next_index,
1918 instruction.previous_index,
1919 ),
1920 Instruction::ApplyVolatileStatus(instruction) => {
1921 self.remove_volatile_status(&instruction.side_ref, instruction.volatile_status)
1922 }
1923 Instruction::RemoveVolatileStatus(instruction) => {
1924 self.apply_volatile_status(&instruction.side_ref, instruction.volatile_status)
1925 }
1926 Instruction::ChangeStatus(instruction) => self.change_status(
1927 &instruction.side_ref,
1928 instruction.pokemon_index,
1929 instruction.old_status,
1930 ),
1931 Instruction::Boost(instruction) => self.apply_boost(
1932 &instruction.side_ref,
1933 &instruction.stat,
1934 -1 * instruction.amount,
1935 ),
1936 Instruction::ChangeSideCondition(instruction) => self.increment_side_condition(
1937 &instruction.side_ref,
1938 &instruction.side_condition,
1939 -1 * instruction.amount,
1940 ),
1941 Instruction::ChangeVolatileStatusDuration(instruction) => self
1942 .increment_volatile_status_duration(
1943 &instruction.side_ref,
1944 &instruction.volatile_status,
1945 -1 * instruction.amount,
1946 ),
1947 Instruction::ChangeWeather(instruction) => self.change_weather(
1948 instruction.previous_weather,
1949 instruction.previous_weather_turns_remaining,
1950 ),
1951 Instruction::DecrementWeatherTurnsRemaining => {
1952 self.weather.turns_remaining += 1;
1953 }
1954 Instruction::ChangeTerrain(instruction) => self.change_terrain(
1955 instruction.previous_terrain,
1956 instruction.previous_terrain_turns_remaining,
1957 ),
1958 Instruction::DecrementTerrainTurnsRemaining => {
1959 self.terrain.turns_remaining += 1;
1960 }
1961 Instruction::ChangeType(instruction) => {
1962 self.change_types(&instruction.side_ref, instruction.old_types)
1963 }
1964 Instruction::ChangeAbility(instruction) => {
1965 let active = self.get_side(&instruction.side_ref).get_active();
1966 active.ability =
1967 Abilities::from(active.ability as i16 - instruction.ability_change);
1968 }
1969 Instruction::EnableMove(instruction) => {
1970 self.disable_move(&instruction.side_ref, &instruction.move_index)
1971 }
1972 Instruction::DisableMove(instruction) => {
1973 self.enable_move(&instruction.side_ref, &instruction.move_index)
1974 }
1975 Instruction::Heal(instruction) => {
1976 self.damage(&instruction.side_ref, instruction.heal_amount)
1977 }
1978 Instruction::ChangeItem(instruction) => {
1979 self.change_item(&instruction.side_ref, instruction.current_item)
1980 }
1981 Instruction::ChangeAttack(instruction) => {
1982 self.get_side(&instruction.side_ref).get_active().attack -= instruction.amount;
1983 }
1984 Instruction::ChangeDefense(instruction) => {
1985 self.get_side(&instruction.side_ref).get_active().defense -= instruction.amount;
1986 }
1987 Instruction::ChangeSpecialAttack(instruction) => {
1988 self.get_side(&instruction.side_ref)
1989 .get_active()
1990 .special_attack -= instruction.amount;
1991 }
1992 Instruction::ChangeSpecialDefense(instruction) => {
1993 self.get_side(&instruction.side_ref)
1994 .get_active()
1995 .special_defense -= instruction.amount;
1996 }
1997 Instruction::ChangeSpeed(instruction) => {
1998 self.get_side(&instruction.side_ref).get_active().speed -= instruction.amount;
1999 }
2000 Instruction::ChangeWish(instruction) => {
2001 self.unset_wish(&instruction.side_ref, instruction.wish_amount_change)
2002 }
2003 Instruction::DecrementWish(instruction) => self.increment_wish(&instruction.side_ref),
2004 Instruction::SetFutureSight(instruction) => {
2005 self.unset_future_sight(&instruction.side_ref, instruction.previous_pokemon_index)
2006 }
2007 Instruction::DecrementFutureSight(instruction) => {
2008 self.increment_future_sight(&instruction.side_ref)
2009 }
2010 Instruction::DamageSubstitute(instruction) => {
2011 self.heal_substitute(&instruction.side_ref, instruction.damage_amount);
2012 }
2013 Instruction::ChangeSubstituteHealth(instruction) => {
2014 self.set_substitute_health(&instruction.side_ref, -1 * instruction.health_change);
2015 }
2016 Instruction::SetRestTurns(instruction) => {
2017 self.set_rest_turn(
2018 &instruction.side_ref,
2019 instruction.pokemon_index,
2020 instruction.previous_turns,
2021 );
2022 }
2023 Instruction::SetSleepTurns(instruction) => {
2024 self.set_sleep_turn(
2025 &instruction.side_ref,
2026 instruction.pokemon_index,
2027 instruction.previous_turns,
2028 );
2029 }
2030 Instruction::DecrementRestTurns(instruction) => {
2031 self.increment_rest_turn(&instruction.side_ref);
2032 }
2033 Instruction::ToggleTrickRoom(instruction) => {
2034 self.toggle_trickroom(instruction.previous_trickroom_turns_remaining)
2035 }
2036 Instruction::DecrementTrickRoomTurnsRemaining => {
2037 self.trick_room.turns_remaining += 1;
2038 }
2039 Instruction::ToggleSideOneForceSwitch => self.side_one.toggle_force_switch(),
2040 Instruction::ToggleSideTwoForceSwitch => self.side_two.toggle_force_switch(),
2041 Instruction::SetSideOneMoveSecondSwitchOutMove(instruction) => {
2042 self.side_one.switch_out_move_second_saved_move = instruction.previous_choice;
2043 }
2044 Instruction::SetSideTwoMoveSecondSwitchOutMove(instruction) => {
2045 self.side_two.switch_out_move_second_saved_move = instruction.previous_choice;
2046 }
2047 Instruction::ToggleBatonPassing(instruction) => match instruction.side_ref {
2048 SideReference::SideOne => {
2049 self.side_one.baton_passing = !self.side_one.baton_passing
2050 }
2051 SideReference::SideTwo => {
2052 self.side_two.baton_passing = !self.side_two.baton_passing
2053 }
2054 },
2055 Instruction::ToggleShedTailing(instruction) => match instruction.side_ref {
2056 SideReference::SideOne => self.side_one.shed_tailing = !self.side_one.shed_tailing,
2057 SideReference::SideTwo => self.side_two.shed_tailing = !self.side_two.shed_tailing,
2058 },
2059 Instruction::ToggleTerastallized(instruction) => match instruction.side_ref {
2060 SideReference::SideOne => self.side_one.get_active().terastallized ^= true,
2061 SideReference::SideTwo => self.side_two.get_active().terastallized ^= true,
2062 },
2063 Instruction::SetLastUsedMove(instruction) => {
2064 self.set_last_used_move(&instruction.side_ref, instruction.previous_last_used_move)
2065 }
2066 Instruction::ChangeDamageDealtDamage(instruction) => {
2067 self.get_side(&instruction.side_ref).damage_dealt.damage -=
2068 instruction.damage_change
2069 }
2070 Instruction::ChangeDamageDealtMoveCatagory(instruction) => {
2071 self.get_side(&instruction.side_ref)
2072 .damage_dealt
2073 .move_category = instruction.previous_move_category
2074 }
2075 Instruction::ToggleDamageDealtHitSubstitute(instruction) => {
2076 let side = self.get_side(&instruction.side_ref);
2077 side.damage_dealt.hit_substitute = !side.damage_dealt.hit_substitute;
2078 }
2079 Instruction::DecrementPP(instruction) => self.increment_pp(
2080 &instruction.side_ref,
2081 &instruction.move_index,
2082 &instruction.amount,
2083 ),
2084 Instruction::FormeChange(instruction) => {
2085 let active = self.get_side(&instruction.side_ref).get_active();
2086 active.id = PokemonName::from(active.id as i16 - instruction.name_change);
2087 }
2088 }
2089 }
2090}
2091impl State {
2092 pub fn pprint(&self) -> String {
2093 let (side_one_options, side_two_options) = self.root_get_all_options();
2094
2095 let mut side_one_choices = vec![];
2096 for option in side_one_options {
2097 side_one_choices.push(format!("{}", option.to_string(&self.side_one)).to_lowercase());
2098 }
2099 let mut side_two_choices = vec![];
2100 for option in side_two_options {
2101 side_two_choices.push(format!("{}", option.to_string(&self.side_two)).to_lowercase());
2102 }
2103 format!(
2104 "SideOne {}\n\nvs\n\nSideTwo {}\n\nState:\n Weather: {:?},{}\n Terrain: {:?},{}\n TrickRoom: {},{}\n UseLastUsedMove: {}\n UseDamageDealt: {}",
2105 self.side_one.pprint(side_one_choices),
2106 self.side_two.pprint(side_two_choices),
2107 self.weather.weather_type,
2108 self.weather.turns_remaining,
2109 self.terrain.terrain_type,
2110 self.terrain.turns_remaining,
2111 self.trick_room.active,
2112 self.trick_room.turns_remaining,
2113 self.use_last_used_move,
2114 self.use_damage_dealt,
2115 )
2116 }
2117
2118 pub fn serialize(&self) -> String {
2119 format!(
2120 "{}/{}/{}/{}/{}/{}",
2121 self.side_one.serialize(),
2122 self.side_two.serialize(),
2123 self.weather.serialize(),
2124 self.terrain.serialize(),
2125 self.trick_room.serialize(),
2126 self.team_preview
2127 )
2128 }
2129
2130 pub fn deserialize(serialized: &str) -> State {
2315 let split: Vec<&str> = serialized.split("/").collect();
2316 let mut state = State {
2317 side_one: Side::deserialize(split[0]),
2318 side_two: Side::deserialize(split[1]),
2319 weather: StateWeather::deserialize(split[2]),
2320 terrain: StateTerrain::deserialize(split[3]),
2321 trick_room: StateTrickRoom::deserialize(split[4]),
2322 team_preview: split[5].parse::<bool>().unwrap(),
2323 use_damage_dealt: false,
2324 use_last_used_move: false,
2325 };
2326 state.set_conditional_mechanics();
2327 state
2328 }
2329}