226 lines
7.6 KiB
Rust
Executable File
226 lines
7.6 KiB
Rust
Executable File
use hashbrown::HashSet;
|
|
#[cfg(feature = "serde")]
|
|
use serde::{Deserialize, Serialize};
|
|
use std::fmt::Debug;
|
|
use std::sync::Arc;
|
|
|
|
use crate::static_data::{SecondaryEffect, TypeIdentifier};
|
|
use crate::StringKey;
|
|
|
|
/// The move category defines what global kind of move this move is.
|
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
|
|
#[repr(u8)]
|
|
pub enum MoveCategory {
|
|
/// A physical move uses the physical attack stats and physical defense stats to calculate damage.
|
|
Physical = 0,
|
|
/// A special move uses the special attack stats and special defense stats to calculate damage.
|
|
Special = 1,
|
|
/// A status move does not do damage, and only runs a secondary effect.
|
|
Status = 2,
|
|
}
|
|
|
|
/// The move target defines what kind of targets the move can touch.
|
|
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
|
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
#[repr(u8)]
|
|
pub enum MoveTarget {
|
|
/// Adjacent allows a move to target any Pokemon that is either directly to the left or right of
|
|
/// the user, opposed to the user, or left or right of the slot that is opposing the user.
|
|
#[default]
|
|
Adjacent = 0,
|
|
/// AdjacentAlly allows a move to target any Pokemon that is directly to the left or right of
|
|
/// the user.
|
|
AdjacentAlly,
|
|
/// AdjacentAllySelf allows a move to target any Pokemon that is either directly to the left or
|
|
/// right of the user, or the user itself.
|
|
AdjacentAllySelf,
|
|
/// AdjacentOpponent allows a move to target any Pokemon that is either the opponent, or directly
|
|
/// to the left or right of it.
|
|
AdjacentOpponent,
|
|
|
|
/// All makes the move target everything on the field.
|
|
All,
|
|
/// AllAdjacent makes the move target everything adjacent on the field.
|
|
AllAdjacent,
|
|
/// AllAdjacentOpponent makes the move target everything adjacent to the opponent, and the opponent.
|
|
AllAdjacentOpponent,
|
|
/// AllAlly targets all Pokemon on the same side as the user.
|
|
AllAlly,
|
|
/// AllOpponent targets all Pokemon on an opposing side from the user.
|
|
AllOpponent,
|
|
|
|
/// Any allows a move to target a single Pokemon, in any position.
|
|
Any,
|
|
|
|
/// RandomOpponent allows a move to target a single Pokemon, in a random position.
|
|
RandomOpponent,
|
|
/// SelfUse makes the move target the user itself.
|
|
#[cfg_attr(feature = "serde", serde(rename = "Self"))]
|
|
SelfUse,
|
|
}
|
|
|
|
/// A move is the skill Pokémon primarily use in battle. This is the data related to that.
|
|
pub trait MoveData: Debug {
|
|
/// The name of the move.
|
|
fn name(&self) -> &StringKey;
|
|
/// The attacking type of the move.
|
|
fn move_type(&self) -> TypeIdentifier;
|
|
/// The category of the move.
|
|
fn category(&self) -> MoveCategory;
|
|
/// The base power, not considering any modifiers, the move has.
|
|
fn base_power(&self) -> u8;
|
|
/// The accuracy of the move in percentage. Should be 255 for moves that always hit.
|
|
fn accuracy(&self) -> u8;
|
|
/// The number of times the move can be used. This can be modified on actually learned moves using
|
|
/// PP-Ups
|
|
fn base_usages(&self) -> u8;
|
|
/// How the move handles targets.
|
|
fn target(&self) -> MoveTarget;
|
|
|
|
/// The priority of the move. A higher priority means the move should go before other moves.
|
|
fn priority(&self) -> i8;
|
|
|
|
/// The optional secondary effect the move has.
|
|
fn secondary_effect(&self) -> &Option<Arc<dyn SecondaryEffect>>;
|
|
|
|
/// Arbitrary flags that can be applied to the move.
|
|
fn has_flag(&self, key: &StringKey) -> bool;
|
|
|
|
/// Arbitrary flags that can be applied to the move.
|
|
fn has_flag_by_hash(&self, key_hash: u32) -> bool;
|
|
}
|
|
|
|
/// A move is the skill Pokémon primarily use in battle. This is the data related to that.
|
|
#[derive(Debug)]
|
|
pub struct MoveDataImpl {
|
|
/// The name of the move.
|
|
name: StringKey,
|
|
/// The attacking type of the move.
|
|
move_type: TypeIdentifier,
|
|
/// The category of the move.
|
|
category: MoveCategory,
|
|
/// The base power, not considering any modifiers, the move has.
|
|
base_power: u8,
|
|
/// The accuracy of the move in percentage. Should be 255 for moves that always hit.
|
|
accuracy: u8,
|
|
/// The number of times the move can be used. This can be modified on actually learned moves using
|
|
/// PP-Ups
|
|
base_usages: u8,
|
|
/// How the move handles targets.
|
|
target: MoveTarget,
|
|
/// The priority of the move. A higher priority means the move should go before other moves.
|
|
priority: i8,
|
|
/// The optional secondary effect the move has.
|
|
secondary_effect: Option<Arc<dyn SecondaryEffect>>,
|
|
/// Arbitrary flags that can be applied to the move.
|
|
flags: HashSet<StringKey>,
|
|
}
|
|
|
|
impl MoveDataImpl {
|
|
/// Instantiates a new move.
|
|
pub fn new(
|
|
name: &StringKey,
|
|
move_type: TypeIdentifier,
|
|
category: MoveCategory,
|
|
base_power: u8,
|
|
accuracy: u8,
|
|
base_usages: u8,
|
|
target: MoveTarget,
|
|
priority: i8,
|
|
secondary_effect: Option<Arc<dyn SecondaryEffect>>,
|
|
flags: HashSet<StringKey>,
|
|
) -> Self {
|
|
Self {
|
|
name: name.clone(),
|
|
move_type,
|
|
category,
|
|
base_power,
|
|
accuracy,
|
|
base_usages,
|
|
target,
|
|
priority,
|
|
secondary_effect,
|
|
flags,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl MoveData for MoveDataImpl {
|
|
/// The name of the move.
|
|
fn name(&self) -> &StringKey {
|
|
&self.name
|
|
}
|
|
/// The attacking type of the move.
|
|
fn move_type(&self) -> TypeIdentifier {
|
|
self.move_type
|
|
}
|
|
/// The category of the move.
|
|
fn category(&self) -> MoveCategory {
|
|
self.category
|
|
}
|
|
/// The base power, not considering any modifiers, the move has.
|
|
fn base_power(&self) -> u8 {
|
|
self.base_power
|
|
}
|
|
/// The accuracy of the move in percentage. Should be 255 for moves that always hit.
|
|
fn accuracy(&self) -> u8 {
|
|
self.accuracy
|
|
}
|
|
/// The number of times the move can be used. This can be modified on actually learned moves using
|
|
/// PP-Ups
|
|
fn base_usages(&self) -> u8 {
|
|
self.base_usages
|
|
}
|
|
/// How the move handles targets.
|
|
fn target(&self) -> MoveTarget {
|
|
self.target
|
|
}
|
|
|
|
/// The priority of the move. A higher priority means the move should go before other moves.
|
|
fn priority(&self) -> i8 {
|
|
self.priority
|
|
}
|
|
|
|
/// The optional secondary effect the move has.
|
|
fn secondary_effect(&self) -> &Option<Arc<dyn SecondaryEffect>> {
|
|
&self.secondary_effect
|
|
}
|
|
|
|
/// Checks if the move has a specific flag.
|
|
fn has_flag(&self, key: &StringKey) -> bool {
|
|
self.flags.contains::<StringKey>(key)
|
|
}
|
|
|
|
/// Checks if the move has a specific flag.
|
|
fn has_flag_by_hash(&self, key_hash: u32) -> bool {
|
|
self.flags.contains::<u32>(&key_hash)
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
#[allow(clippy::indexing_slicing)]
|
|
#[allow(clippy::unwrap_used)]
|
|
pub(crate) mod tests {
|
|
use super::*;
|
|
|
|
mockall::mock! {
|
|
#[derive(Debug)]
|
|
pub MoveData{}
|
|
impl MoveData for MoveData {
|
|
fn name(&self) -> &StringKey;
|
|
fn move_type(&self) -> TypeIdentifier;
|
|
fn category(&self) -> MoveCategory;
|
|
fn base_power(&self) -> u8;
|
|
fn accuracy(&self) -> u8;
|
|
fn base_usages(&self) -> u8;
|
|
fn target(&self) -> MoveTarget;
|
|
fn priority(&self) -> i8;
|
|
fn secondary_effect(&self) -> &Option<Arc<dyn SecondaryEffect>>;
|
|
fn has_flag(&self, key: &StringKey) -> bool;
|
|
fn has_flag_by_hash(&self, key_hash: u32) -> bool;
|
|
}
|
|
}
|
|
}
|