firecore_battle/default_engine/moves/
execution.rs1use rand::Rng;
2
3use serde::{Deserialize, Serialize};
4
5use pokedex::{
6 ailment::{Ailment, AilmentLength},
7 moves::Move,
8};
9
10use crate::{
11 engine::{BattlePokemon, MoveResult},
12 moves::{damage::DamageKind, MoveCancel, Percent},
13 pokemon::{
14 stat::{BattleStatType, Stage},
15 Indexed,
16 },
17};
18
19#[derive(Debug, Clone, Deserialize, Serialize)]
20pub enum MoveExecution {
21 Actions(Vec<MoveUse>),
23 Script,
25 None,
27}
28
29#[derive(Debug, Clone, Deserialize, Serialize)]
30#[serde(deny_unknown_fields)]
31pub enum MoveUse {
32 Damage(DamageKind),
33 Ailment(Option<(Ailment, AilmentLength)>, Percent),
34 Drain(DamageKind, i8),
35 Stat(BattleStatType, Stage),
36 Flinch,
37 Chance(Vec<Self>, Percent),
38}
39
40impl MoveExecution {
41 pub fn size(&self) -> usize {
42 match self {
43 Self::Actions(actions) => actions.iter().map(MoveUse::size).sum(),
44 Self::Script | Self::None => 1,
45 }
46 }
47}
48
49impl MoveUse {
50 pub fn size(&self) -> usize {
51 match self {
52 Self::Chance(uses, ..) => uses.iter().map(Self::size).sum(),
53 Self::Drain(..) => 2,
54 _ => 1,
55 }
56 }
57}
58
59pub fn move_usage<ID: Clone, R: Rng>(
60 user: &Indexed<ID, &BattlePokemon>,
61 random: &mut R,
62 results: &mut Vec<Indexed<ID, MoveResult>>,
63 actions: &[MoveUse],
64 m: &Move,
65 Indexed(target_id, target): Indexed<ID, &BattlePokemon>,
66) {
67 for action in actions {
68 match action {
69 MoveUse::Damage(kind) => {
70 results.push(Indexed(
71 target_id.clone(),
72 MoveResult::Damage(user.1.damage_kind(
73 random,
74 target,
75 *kind,
76 m.category,
77 m.pokemon_type,
78 m.crit_rate,
79 )),
80 ));
81 }
82 MoveUse::Ailment(effect, chance) => {
83 if random.gen_bool(*chance as f64 / 100.0) {
84 match effect {
85 Some((ailment, length)) => {
86 if target.ailment.is_none() {
87 results.push(Indexed(
88 target_id.clone(),
89 MoveResult::Ailment(Some(length.init(*ailment, random))),
90 ));
91 }
92 }
93 None => {
94 if target.ailment.is_some() {
95 results.push(Indexed(target_id.clone(), MoveResult::Ailment(None)))
96 }
97 }
98 }
99 }
100 }
101 MoveUse::Drain(kind, percent) => {
102 let result = user.1.damage_kind(
103 random,
104 target,
105 *kind,
106 m.category,
107 m.pokemon_type,
108 m.crit_rate,
109 );
110
111 let healing = (result.damage as f32 * *percent as f32 / 100.0) as i16;
112
113 results.push(Indexed(target_id.clone(), MoveResult::Damage(result)));
114 results.push(Indexed(user.0.clone(), MoveResult::Heal(healing)))
115 }
116 MoveUse::Stat(stat, stage) => {
117 if target.stages.can_change(*stat, *stage) {
118 results.push(Indexed(target_id.clone(), MoveResult::Stat(*stat, *stage)));
119 }
120 }
121 MoveUse::Flinch => results.push(Indexed(
125 target_id.clone(),
126 MoveResult::Cancel(MoveCancel::Flinch),
127 )),
128 MoveUse::Chance(actions, chance) => {
129 if random.gen_range(0..=100) < *chance {
130 move_usage(
131 user,
132 random,
133 results,
134 actions,
135 m,
136 Indexed(target_id.clone(), target),
137 );
138 }
139 }
140 }
141 }
142}