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