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