firecore_pokedex/
moves.rs

1//! Types and structs related to moves
2//!
3//! This module does not contain ways to execute moves, as the [battle](https://crates.io/crates/firecore-battle) crate does this.
4//!
5
6use alloc::string::String;
7use serde::{Deserialize, Serialize};
8use tinystr::TinyAsciiStr;
9
10use crate::{pokemon::stat::StatType, types::PokemonType, Identifiable, UNKNOWN_ID};
11
12pub mod owned;
13pub mod set;
14
15/// How powerful a [Move] is, in points. Some moves do not use power levels.
16pub type Power = u8;
17/// How accurate a [Move] is, in values 0 - 100.
18pub type Accuracy = u8;
19/// How many times a [Move] can be used before needing to be restored.
20pub type PP = u8;
21/// This determines whether the [Move] goes before another.
22/// The higher the value, the higher the priority.
23pub type Priority = i8;
24/// This helps determine if a [Move] should be a critical hit.
25/// The higher the value, the higher the chance of a critical hit.
26/// This maxes out at 4.
27pub type CriticalRate = u8;
28
29/// An identifier for a [Move].
30#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash, PartialOrd, Ord)]
31#[serde(transparent)]
32pub struct MoveId(pub TinyAsciiStr<16>);
33
34/// Moves that Pokemon use in battle.
35/// These can also have other uses too, such as triggering events in a world.
36#[derive(Debug, Clone, Deserialize, Serialize)]
37#[serde(deny_unknown_fields)]
38pub struct Move {
39    pub id: MoveId,
40
41    pub name: String,
42
43    pub category: MoveCategory,
44
45    /// The move's type.
46    #[serde(rename = "type")]
47    pub pokemon_type: PokemonType,
48    /// If this is [None], the move will always land.
49    pub accuracy: Option<Accuracy>,
50    pub power: Option<Power>,
51    pub pp: PP,
52    #[serde(default)]
53    pub priority: Priority,
54
55    #[serde(default)]
56    pub target: MoveTarget,
57
58    /// If the move makes contact with the target.
59    #[serde(default)]
60    pub contact: bool,
61
62    /// Increments the chance of whether a move should critical hit or not.
63    #[serde(default)]
64    pub crit_rate: CriticalRate,
65}
66
67// impl Identifier<Move> for MoveId {
68//     fn as_id(&self) -> &<Move as Identifiable>::Id {
69//         self
70//     }
71// }
72
73impl Identifiable for Move {
74    type Id = MoveId;
75
76    const UNKNOWN: Self::Id = MoveId(UNKNOWN_ID);
77
78    fn id(&self) -> &Self::Id {
79        &self.id
80    }
81
82    fn name(&self) -> &str {
83        &self.name
84    }
85}
86
87// use MoveCategory::{Physical, Special, Status};
88// use crate::pokemon::stat::StatType::{Attack, Defense, SpAttack, SpDefense};
89
90/// The category of a move.
91// /// [MoveCategory::Physical] and [MoveCategory::Special] are usually for moves that deal damage.
92// /// [Physical] deals physical damage ([Attack]) against a target pokemon's [Defense].
93// /// [Special] deals special damage ([SpAttack]) against a target pokemon's [SpDefense].
94// /// [MoveCategory::Status] moves usually afflict an ailment on a target pokemon or benefit the user pokemon.
95#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Deserialize, Serialize)]
96pub enum MoveCategory {
97    Status,
98    Physical,
99    Special,
100}
101
102impl MoveCategory {
103    /// Get a tuple of the attack and defense types of this category.
104    pub fn stats(&self) -> (StatType, StatType) {
105        (self.attack(), self.defense())
106    }
107    /// Get the attack type of this category.
108    pub fn attack(&self) -> StatType {
109        match self {
110            MoveCategory::Physical => StatType::Attack,
111            MoveCategory::Special => StatType::SpAttack,
112            MoveCategory::Status => unreachable!("Cannot get attack stat for status move!"),
113        }
114    }
115    /// Get the defense type of this category.
116    pub fn defense(&self) -> StatType {
117        match self {
118            MoveCategory::Physical => StatType::Defense,
119            MoveCategory::Special => StatType::SpDefense,
120            MoveCategory::Status => unreachable!("Cannot get defense stat for status move!"),
121        }
122    }
123}
124
125/// The target of a [Move].
126#[derive(Debug, Clone, Copy, Deserialize, Serialize)]
127pub enum MoveTarget {
128    Any,
129    Ally,
130    Allies,
131    UserOrAlly,
132    UserAndAllies,
133    // UserOrAllies,
134    User,
135    Opponent,
136    AllOpponents,
137    RandomOpponent,
138    AllOtherPokemon,
139    AllPokemon,
140    None,
141}
142
143impl Default for MoveTarget {
144    fn default() -> Self {
145        Self::None
146    }
147}
148
149impl MoveTarget {
150    pub fn needs_input(&self) -> bool {
151        match self {
152            MoveTarget::Ally | MoveTarget::Any | MoveTarget::Opponent | MoveTarget::UserOrAlly => {
153                true
154            }
155            _ => false,
156        }
157    }
158}
159
160impl Default for MoveId {
161    fn default() -> Self {
162        Self(UNKNOWN_ID)
163    }
164}
165
166impl From<TinyAsciiStr<16>> for MoveId {
167    fn from(str: TinyAsciiStr<16>) -> Self {
168        Self(str)
169    }
170}
171
172impl core::str::FromStr for MoveId {
173    type Err = tinystr::TinyStrError;
174
175    fn from_str(s: &str) -> Result<Self, Self::Err> {
176        s.parse().map(Self)
177    }
178}