poke_engine/
instruction.rs

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