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