poke_engine/
instruction.rs

1use crate::abilities::Abilities;
2use crate::choices::{Choices, MoveCategory};
3use crate::items::Items;
4use crate::pokemon::PokemonName;
5use crate::state::SideReference;
6use crate::state::Terrain;
7use crate::state::Weather;
8use crate::state::{LastUsedMove, PokemonVolatileStatus};
9use crate::state::{PokemonBoostableStat, PokemonType};
10use crate::state::{PokemonIndex, PokemonSideCondition};
11use crate::state::{PokemonMoveIndex, PokemonStatus};
12use std::fmt;
13use std::fmt::Formatter;
14
15#[derive(PartialEq, Clone)]
16pub struct StateInstructions {
17    pub percentage: f32,
18    pub instruction_list: Vec<Instruction>,
19}
20
21impl Default for StateInstructions {
22    fn default() -> StateInstructions {
23        StateInstructions {
24            percentage: 100.0,
25            instruction_list: Vec::with_capacity(16),
26        }
27    }
28}
29
30impl fmt::Debug for StateInstructions {
31    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
32        let mut final_string = format!("\n\tPercentage: {}\n\tInstructions:", self.percentage);
33        for i in self.instruction_list.iter() {
34            final_string.push_str(format!("\n\t\t{:?}", i).as_str());
35        }
36        write!(f, "{}\n", final_string)
37    }
38}
39
40impl StateInstructions {
41    pub fn update_percentage(&mut self, modifier: f32) {
42        self.percentage *= modifier;
43    }
44}
45
46// https://stackoverflow.com/questions/50686411/whats-the-usual-way-to-create-a-vector-of-different-structs
47#[derive(PartialEq, Clone)]
48pub enum Instruction {
49    Switch(SwitchInstruction),
50    ApplyVolatileStatus(ApplyVolatileStatusInstruction),
51    RemoveVolatileStatus(RemoveVolatileStatusInstruction),
52    ChangeStatus(ChangeStatusInstruction),
53    Heal(HealInstruction),
54    Damage(DamageInstruction),
55    Boost(BoostInstruction),
56    ChangeSideCondition(ChangeSideConditionInstruction),
57    ChangeVolatileStatusDuration(ChangeVolatileStatusDurationInstruction),
58    ChangeWeather(ChangeWeather),
59    DecrementWeatherTurnsRemaining,
60    ChangeTerrain(ChangeTerrain),
61    DecrementTerrainTurnsRemaining,
62    ChangeType(ChangeType),
63    ChangeAbility(ChangeAbilityInstruction),
64    ChangeItem(ChangeItemInstruction),
65    ChangeAttack(ChangeStatInstruction),
66    ChangeDefense(ChangeStatInstruction),
67    ChangeSpecialAttack(ChangeStatInstruction),
68    ChangeSpecialDefense(ChangeStatInstruction),
69    ChangeSpeed(ChangeStatInstruction),
70    DisableMove(DisableMoveInstruction),
71    EnableMove(EnableMoveInstruction),
72    ChangeWish(ChangeWishInstruction),
73    DecrementWish(DecrementWishInstruction),
74    SetFutureSight(SetFutureSightInstruction),
75    DecrementFutureSight(DecrementFutureSightInstruction),
76    DamageSubstitute(DamageInstruction),
77    DecrementRestTurns(DecrementRestTurnsInstruction),
78    SetRestTurns(SetSleepTurnsInstruction),
79    SetSleepTurns(SetSleepTurnsInstruction),
80    ChangeSubstituteHealth(ChangeSubsituteHealthInstruction),
81    FormeChange(FormeChangeInstruction),
82    SetSideOneMoveSecondSwitchOutMove(SetSecondMoveSwitchOutMoveInstruction),
83    SetSideTwoMoveSecondSwitchOutMove(SetSecondMoveSwitchOutMoveInstruction),
84    ToggleBatonPassing(ToggleBatonPassingInstruction),
85    ToggleShedTailing(ToggleShedTailingInstruction),
86    SetLastUsedMove(SetLastUsedMoveInstruction),
87    SetDamageDealtSideOne(SetDamageDealtSideOneInstruction),
88    SetDamageDealtSideTwo(SetDamageDealtSideTwoInstruction),
89    DecrementPP(DecrementPPInstruction),
90    ToggleTrickRoom(ToggleTrickRoomInstruction),
91    DecrementTrickRoomTurnsRemaining,
92    ToggleSideOneForceSwitch,
93    ToggleSideTwoForceSwitch,
94    ToggleTerastallized(ToggleTerastallizedInstruction),
95}
96
97impl fmt::Debug for Instruction {
98    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
99        match self {
100            Instruction::Switch(s) => {
101                write!(
102                    f,
103                    "Switch {:?}: {:?} -> {:?}",
104                    s.side_ref, s.previous_index, s.next_index
105                )
106            }
107            Instruction::ApplyVolatileStatus(a) => {
108                write!(
109                    f,
110                    "ApplyVolatileStatus {:?}: {:?}",
111                    a.side_ref, a.volatile_status
112                )
113            }
114            Instruction::RemoveVolatileStatus(r) => {
115                write!(
116                    f,
117                    "RemoveVolatileStatus {:?}: {:?}",
118                    r.side_ref, r.volatile_status
119                )
120            }
121            Instruction::ChangeStatus(c) => {
122                write!(
123                    f,
124                    "ChangeStatus {:?}-{:?}: {:?} -> {:?}",
125                    c.side_ref, c.pokemon_index, c.old_status, c.new_status
126                )
127            }
128            Instruction::Heal(h) => {
129                write!(f, "Heal {:?}: {:?}", h.side_ref, h.heal_amount)
130            }
131            Instruction::Damage(d) => {
132                write!(f, "Damage {:?}: {}", d.side_ref, d.damage_amount)
133            }
134            Instruction::Boost(b) => {
135                write!(f, "Boost {:?} {:?}: {:?}", b.side_ref, b.stat, b.amount)
136            }
137            Instruction::ChangeSideCondition(c) => {
138                write!(
139                    f,
140                    "ChangeSideCondition {:?} {:?}: {:?}",
141                    c.side_ref, c.side_condition, c.amount
142                )
143            }
144            Instruction::ChangeVolatileStatusDuration(c) => {
145                write!(
146                    f,
147                    "ChangeVolatileStatusDuration {:?} {:?}: {:?}",
148                    c.side_ref, c.volatile_status, c.amount
149                )
150            }
151            Instruction::ChangeWeather(c) => {
152                write!(
153                    f,
154                    "ChangeWeather: {:?},{:?} -> {:?},{:?}",
155                    c.previous_weather,
156                    c.previous_weather_turns_remaining,
157                    c.new_weather,
158                    c.new_weather_turns_remaining
159                )
160            }
161            Instruction::DecrementWeatherTurnsRemaining => {
162                write!(f, "DecrementWeatherTurnsRemaining",)
163            }
164            Instruction::ChangeTerrain(c) => {
165                write!(
166                    f,
167                    "ChangeTerrain: {:?},{:?} -> {:?},{:?}",
168                    c.previous_terrain,
169                    c.previous_terrain_turns_remaining,
170                    c.new_terrain,
171                    c.new_terrain_turns_remaining
172                )
173            }
174            Instruction::DecrementTerrainTurnsRemaining => {
175                write!(f, "DecrementTerrainTurnsRemaining",)
176            }
177            Instruction::ChangeType(c) => {
178                write!(
179                    f,
180                    "ChangeType {:?}: {:?} -> {:?}",
181                    c.side_ref, c.old_types, c.new_types
182                )
183            }
184            Instruction::ChangeAbility(c) => {
185                write!(
186                    f,
187                    "ChangeAbility {:?}: {:?} -> {:?}",
188                    c.side_ref, c.old_ability, c.new_ability
189                )
190            }
191            Instruction::ChangeItem(c) => {
192                write!(
193                    f,
194                    "ChangeItem {:?}: {:?} -> {:?}",
195                    c.side_ref, c.current_item, c.new_item
196                )
197            }
198            Instruction::ChangeAttack(c) => {
199                write!(f, "ChangeAttack {:?}: {}", c.side_ref, c.amount)
200            }
201            Instruction::ChangeDefense(c) => {
202                write!(f, "ChangeDefense {:?}: {}", c.side_ref, c.amount)
203            }
204            Instruction::ChangeSpecialAttack(c) => {
205                write!(f, "ChangeSpecialAttack {:?}: {}", c.side_ref, c.amount)
206            }
207            Instruction::ChangeSpecialDefense(c) => {
208                write!(f, "ChangeSpecialDefense {:?}: {}", c.side_ref, c.amount)
209            }
210            Instruction::ChangeSpeed(c) => {
211                write!(f, "ChangeSpeed {:?}: {}", c.side_ref, c.amount)
212            }
213            Instruction::DisableMove(d) => {
214                write!(f, "DisableMove {:?}: {:?}", d.side_ref, d.move_index)
215            }
216            Instruction::EnableMove(e) => {
217                write!(f, "EnableMove {:?}: {:?}", e.side_ref, e.move_index)
218            }
219            Instruction::ChangeWish(s) => {
220                write!(f, "SetWish {:?}: {:?}", s.side_ref, s.wish_amount_change)
221            }
222            Instruction::DecrementWish(d) => {
223                write!(f, "DecrementWish {:?}", d.side_ref)
224            }
225            Instruction::SetFutureSight(s) => {
226                write!(
227                    f,
228                    "SetFutureSight {:?}: {:?} -> {:?}",
229                    s.side_ref, s.previous_pokemon_index, s.pokemon_index
230                )
231            }
232            Instruction::DecrementFutureSight(d) => {
233                write!(f, "DecrementFutureSight {:?}", d.side_ref)
234            }
235            Instruction::DamageSubstitute(d) => {
236                write!(
237                    f,
238                    "DamageSubstitute {:?}: {:?}",
239                    d.side_ref, d.damage_amount
240                )
241            }
242            Instruction::DecrementRestTurns(d) => {
243                write!(f, "DecrementRestTurns {:?}", d.side_ref)
244            }
245            Instruction::SetRestTurns(s) => {
246                write!(
247                    f,
248                    "SetRestTurns {:?}-{:?}: {:?} -> {:?}",
249                    s.side_ref, s.pokemon_index, s.previous_turns, s.new_turns
250                )
251            }
252            Instruction::SetSleepTurns(s) => {
253                write!(
254                    f,
255                    "SetSleepTurns {:?}-{:?}: {:?} -> {:?}",
256                    s.side_ref, s.pokemon_index, s.previous_turns, s.new_turns
257                )
258            }
259            Instruction::ChangeSubstituteHealth(s) => {
260                write!(
261                    f,
262                    "ChangeSubstituteHealth {:?}: {:?}",
263                    s.side_ref, s.health_change,
264                )
265            }
266            Instruction::FormeChange(s) => {
267                write!(
268                    f,
269                    "FormeChange {:?}: {:?} -> {:?}",
270                    s.side_ref, s.previous_forme, s.new_forme
271                )
272            }
273            Instruction::SetSideOneMoveSecondSwitchOutMove(s) => {
274                write!(
275                    f,
276                    "SideOneMoveSecondSwitchOutMove: {:?} -> {:?}",
277                    s.previous_choice, s.new_choice
278                )
279            }
280            Instruction::SetSideTwoMoveSecondSwitchOutMove(s) => {
281                write!(
282                    f,
283                    "SideTwoMoveSecondSwitchOutMove: {:?} -> {:?}",
284                    s.previous_choice, s.new_choice
285                )
286            }
287            Instruction::ToggleBatonPassing(s) => {
288                write!(f, "ToggleBatonPassing {:?}", s.side_ref)
289            }
290            Instruction::ToggleShedTailing(s) => {
291                write!(f, "ToggleShedTailing {:?}", s.side_ref)
292            }
293            Instruction::ToggleTerastallized(s) => {
294                write!(f, "ToggleTerastallized {:?}", s.side_ref)
295            }
296            Instruction::SetLastUsedMove(s) => {
297                write!(
298                    f,
299                    "SetLastUsedMove {:?}: {:?} -> {:?}",
300                    s.side_ref, s.previous_last_used_move, s.last_used_move
301                )
302            }
303            Instruction::SetDamageDealtSideOne(s) => {
304                write!(
305                    f,
306                    "SetDamageDealt SideOne: ({:?} -> {:?}) Damage Change: {:?} HitSub Change: {:?}",
307                    s.previous_move_category,
308                    s.move_category,
309                    s.damage_change,
310                    s.toggle_hit_substitute
311                )
312            }
313            Instruction::SetDamageDealtSideTwo(s) => {
314                write!(
315                    f,
316                    "SetDamageDealt SideTwo: ({:?} -> {:?}) Damage Change: {:?} HitSub Change: {:?}",
317                    s.previous_move_category,
318                    s.move_category,
319                    s.damage_change,
320                    s.toggle_hit_substitute
321                )
322            }
323            Instruction::DecrementPP(s) => {
324                write!(
325                    f,
326                    "DecrementPP {:?}: {:?} {}",
327                    s.side_ref, s.move_index, s.amount
328                )
329            }
330            Instruction::ToggleTrickRoom(i) => {
331                write!(
332                    f,
333                    "ToggleTrickRoom: {:?},{:?} -> {:?},{:?}",
334                    i.currently_active,
335                    i.previous_trickroom_turns_remaining,
336                    !i.currently_active,
337                    i.new_trickroom_turns_remaining,
338                )
339            }
340            Instruction::DecrementTrickRoomTurnsRemaining => {
341                write!(f, "DecrementTrickRoomTurnsRemaining")
342            }
343            Instruction::ToggleSideOneForceSwitch => {
344                write!(f, "ToggleSideOneForceSwitch")
345            }
346            Instruction::ToggleSideTwoForceSwitch => {
347                write!(f, "ToggleSideTwoForceSwitch")
348            }
349        }
350    }
351}
352
353#[derive(Debug, PartialEq, Clone)]
354pub struct SetDamageDealtSideOneInstruction {
355    pub damage_change: i16,
356    pub move_category: MoveCategory,
357    pub previous_move_category: MoveCategory,
358    pub toggle_hit_substitute: bool,
359}
360
361#[derive(Debug, PartialEq, Clone)]
362pub struct SetDamageDealtSideTwoInstruction {
363    pub damage_change: i16,
364    pub move_category: MoveCategory,
365    pub previous_move_category: MoveCategory,
366    pub toggle_hit_substitute: bool,
367}
368
369#[derive(Debug, PartialEq, Clone)]
370pub struct DecrementPPInstruction {
371    pub side_ref: SideReference,
372    pub move_index: PokemonMoveIndex,
373    pub amount: i8,
374}
375
376#[derive(Debug, PartialEq, Clone)]
377pub struct SetLastUsedMoveInstruction {
378    pub side_ref: SideReference,
379    pub last_used_move: LastUsedMove,
380    pub previous_last_used_move: LastUsedMove,
381}
382
383#[derive(Debug, PartialEq, Clone)]
384pub struct ToggleBatonPassingInstruction {
385    pub side_ref: SideReference,
386}
387
388#[derive(Debug, PartialEq, Clone)]
389pub struct ToggleShedTailingInstruction {
390    pub side_ref: SideReference,
391}
392
393#[derive(Debug, PartialEq, Clone)]
394pub struct DecrementRestTurnsInstruction {
395    pub side_ref: SideReference,
396}
397
398#[derive(Debug, PartialEq, Clone)]
399pub struct SetSleepTurnsInstruction {
400    pub side_ref: SideReference,
401    pub pokemon_index: PokemonIndex,
402    pub new_turns: i8,
403    pub previous_turns: i8,
404}
405
406#[derive(Debug, PartialEq, Clone)]
407pub struct SetSecondMoveSwitchOutMoveInstruction {
408    pub new_choice: Choices,
409    pub previous_choice: Choices,
410}
411
412#[derive(Debug, PartialEq, Clone)]
413pub struct ChangeWishInstruction {
414    pub side_ref: SideReference,
415    pub wish_amount_change: i16,
416}
417
418#[derive(Debug, PartialEq, Clone)]
419pub struct DecrementWishInstruction {
420    pub side_ref: SideReference,
421}
422
423#[derive(Debug, PartialEq, Clone)]
424pub struct SetFutureSightInstruction {
425    pub side_ref: SideReference,
426    pub pokemon_index: PokemonIndex,
427    pub previous_pokemon_index: PokemonIndex,
428}
429
430#[derive(Debug, PartialEq, Clone)]
431pub struct DecrementFutureSightInstruction {
432    pub side_ref: SideReference,
433}
434
435#[derive(Debug, PartialEq, Clone)]
436pub struct EnableMoveInstruction {
437    pub side_ref: SideReference,
438    pub move_index: PokemonMoveIndex,
439}
440
441#[derive(Debug, PartialEq, Clone)]
442pub struct DisableMoveInstruction {
443    pub side_ref: SideReference,
444    pub move_index: PokemonMoveIndex,
445}
446
447#[derive(Debug, PartialEq, Clone)]
448pub struct ChangeItemInstruction {
449    pub side_ref: SideReference,
450    pub current_item: Items,
451    pub new_item: Items,
452}
453
454#[derive(Debug, PartialEq, Clone)]
455pub struct ChangeStatInstruction {
456    pub side_ref: SideReference,
457    pub amount: i16,
458}
459
460#[derive(Debug, PartialEq, Clone)]
461pub struct HealInstruction {
462    pub side_ref: SideReference,
463    pub heal_amount: i16,
464}
465
466#[derive(Debug, PartialEq, Clone)]
467pub struct DamageInstruction {
468    pub side_ref: SideReference,
469    pub damage_amount: i16,
470}
471
472#[derive(Debug, PartialEq, Clone)]
473pub struct ChangeSubsituteHealthInstruction {
474    pub side_ref: SideReference,
475    pub health_change: i16,
476}
477
478#[derive(Debug, PartialEq, Clone)]
479pub struct FormeChangeInstruction {
480    pub side_ref: SideReference,
481    pub new_forme: PokemonName,
482    pub previous_forme: PokemonName,
483}
484
485#[derive(Debug, PartialEq, Clone)]
486pub struct SwitchInstruction {
487    pub side_ref: SideReference,
488    pub previous_index: PokemonIndex,
489    pub next_index: PokemonIndex,
490}
491
492// pokemon_index is present because even reserve pokemon can have their status
493// changed (i.e. healbell)
494#[derive(Debug, PartialEq, Clone)]
495pub struct ChangeStatusInstruction {
496    pub side_ref: SideReference,
497    pub pokemon_index: PokemonIndex,
498    pub old_status: PokemonStatus,
499    pub new_status: PokemonStatus,
500}
501
502#[derive(Debug, PartialEq, Clone)]
503pub struct ApplyVolatileStatusInstruction {
504    pub side_ref: SideReference,
505    pub volatile_status: PokemonVolatileStatus,
506}
507
508#[derive(Debug, PartialEq, Clone)]
509pub struct RemoveVolatileStatusInstruction {
510    pub side_ref: SideReference,
511    pub volatile_status: PokemonVolatileStatus,
512}
513
514#[derive(Debug, PartialEq, Clone)]
515pub struct BoostInstruction {
516    pub side_ref: SideReference,
517    pub stat: PokemonBoostableStat,
518    pub amount: i8,
519}
520
521#[derive(Debug, PartialEq, Clone)]
522pub struct ChangeSideConditionInstruction {
523    pub side_ref: SideReference,
524    pub side_condition: PokemonSideCondition,
525    pub amount: i8,
526}
527
528#[derive(Debug, PartialEq, Clone)]
529pub struct ChangeVolatileStatusDurationInstruction {
530    pub side_ref: SideReference,
531    pub volatile_status: PokemonVolatileStatus,
532    pub amount: i8,
533}
534
535#[derive(Debug, PartialEq, Clone)]
536pub struct ChangeWeather {
537    pub new_weather: Weather,
538    pub new_weather_turns_remaining: i8,
539    pub previous_weather: Weather,
540    pub previous_weather_turns_remaining: i8,
541}
542
543#[derive(Debug, PartialEq, Clone)]
544pub struct ChangeTerrain {
545    pub new_terrain: Terrain,
546    pub new_terrain_turns_remaining: i8,
547    pub previous_terrain: Terrain,
548    pub previous_terrain_turns_remaining: i8,
549}
550
551#[derive(Debug, PartialEq, Clone)]
552pub struct ToggleTrickRoomInstruction {
553    pub currently_active: bool,
554    pub new_trickroom_turns_remaining: i8,
555    pub previous_trickroom_turns_remaining: i8,
556}
557
558#[derive(Debug, PartialEq, Clone)]
559pub struct ToggleTerastallizedInstruction {
560    pub side_ref: SideReference,
561}
562
563#[derive(Debug, PartialEq, Clone)]
564pub struct ChangeType {
565    pub side_ref: SideReference,
566    pub new_types: (PokemonType, PokemonType),
567    pub old_types: (PokemonType, PokemonType),
568}
569
570#[derive(Debug, PartialEq, Clone)]
571pub struct ChangeAbilityInstruction {
572    pub side_ref: SideReference,
573    pub new_ability: Abilities,
574    pub old_ability: Abilities,
575}
576
577#[cfg(test)]
578mod test {
579    use super::Instruction;
580
581    // Make sure that the size of the Instruction enum doesn't change
582    #[test]
583    fn test_instruction_size() {
584        assert_eq!(size_of::<Instruction>(), 8);
585        assert_eq!(align_of::<Instruction>(), 2);
586    }
587}