Basic implementation of evolutions
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2023-07-29 12:57:52 +02:00
parent 3f91f80982
commit d8b8559c2e
25 changed files with 437 additions and 115 deletions

View File

@@ -65,6 +65,7 @@ pub mod tests {
0.5,
&"test_growthrate".into(),
0,
120,
Arc::new(FormImpl::new(
&"default".into(),
0.0,
@@ -78,6 +79,7 @@ pub mod tests {
HashSet::new(),
)),
HashSet::new(),
Vec::new(),
))
}

View File

@@ -59,7 +59,7 @@ mod time_of_day;
/// A parameter for an effect. This is basically a simple way to dynamically store multiple different
/// primitives on data.
#[derive(PartialEq, Debug, Clone)]
pub enum EffectParameter {
pub enum Parameter {
/// A boolean value.
Bool(bool),
/// An integer value. Stored as a 64 bit int to deal with potentially large numbers.
@@ -70,37 +70,37 @@ pub enum EffectParameter {
String(StringKey),
}
impl From<bool> for EffectParameter {
impl From<bool> for Parameter {
fn from(b: bool) -> Self {
EffectParameter::Bool(b)
Parameter::Bool(b)
}
}
impl From<i64> for EffectParameter {
impl From<i64> for Parameter {
fn from(i: i64) -> Self {
EffectParameter::Int(i)
Parameter::Int(i)
}
}
impl From<f32> for EffectParameter {
impl From<f32> for Parameter {
fn from(f: f32) -> Self {
EffectParameter::Float(f)
Parameter::Float(f)
}
}
impl From<StringKey> for EffectParameter {
impl From<StringKey> for Parameter {
fn from(s: StringKey) -> Self {
EffectParameter::String(s)
Parameter::String(s)
}
}
impl Display for EffectParameter {
impl Display for Parameter {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
EffectParameter::Bool(v) => f.write_fmt(format_args!("EffectParameter::Bool({v})")),
EffectParameter::Int(v) => f.write_fmt(format_args!("EffectParameter::Int({v})")),
EffectParameter::Float(v) => f.write_fmt(format_args!("EffectParameter::Float({v})")),
EffectParameter::String(v) => f.write_fmt(format_args!("EffectParameter::String({v})")),
Parameter::Bool(v) => f.write_fmt(format_args!("EffectParameter::Bool({v})")),
Parameter::Int(v) => f.write_fmt(format_args!("EffectParameter::Int({v})")),
Parameter::Float(v) => f.write_fmt(format_args!("EffectParameter::Float({v})")),
Parameter::String(v) => f.write_fmt(format_args!("EffectParameter::String({v})")),
}
}
}

View File

@@ -1,4 +1,4 @@
use crate::static_data::EffectParameter;
use crate::static_data::Parameter;
use crate::StringKey;
use std::fmt::Debug;
use std::sync::Arc;
@@ -10,7 +10,7 @@ pub trait SecondaryEffect: Debug {
/// The name of the effect.
fn effect_name(&self) -> &StringKey;
/// A list of parameters for the effect.
fn parameters(&self) -> &Vec<Arc<EffectParameter>>;
fn parameters(&self) -> &Vec<Arc<Parameter>>;
}
/// A secondary effect is an effect on a move that happens after it hits.
@@ -21,12 +21,12 @@ pub struct SecondaryEffectImpl {
/// The name of the effect.
effect_name: StringKey,
/// A list of parameters for the effect.
parameters: Vec<Arc<EffectParameter>>,
parameters: Vec<Arc<Parameter>>,
}
impl SecondaryEffectImpl {
/// Instantiates a new Secondary Effect.
pub fn new(chance: f32, effect_name: StringKey, parameters: Vec<Arc<EffectParameter>>) -> Self {
pub fn new(chance: f32, effect_name: StringKey, parameters: Vec<Arc<Parameter>>) -> Self {
Self {
chance,
effect_name,
@@ -45,7 +45,7 @@ impl SecondaryEffect for SecondaryEffectImpl {
&self.effect_name
}
/// A list of parameters for the effect.
fn parameters(&self) -> &Vec<Arc<EffectParameter>> {
fn parameters(&self) -> &Vec<Arc<Parameter>> {
&self.parameters
}
}
@@ -66,7 +66,7 @@ pub(crate) mod tests {
impl SecondaryEffect for SecondaryEffect {
fn chance(&self) -> f32;
fn effect_name(&self) -> &StringKey;
fn parameters(&self) -> &Vec<Arc<EffectParameter>>;
fn parameters(&self) -> &Vec<Arc<Parameter >>;
}
}

View File

@@ -1,4 +1,4 @@
use crate::static_data::EffectParameter;
use crate::static_data::Parameter;
use crate::StringKey;
use std::fmt::Debug;
use std::sync::Arc;
@@ -10,7 +10,7 @@ pub trait Ability: Debug {
/// The name of the script effect of the ability.
fn effect(&self) -> &StringKey;
/// The parameters for the script effect of the ability.
fn parameters(&self) -> &Vec<Arc<EffectParameter>>;
fn parameters(&self) -> &Vec<Arc<Parameter>>;
}
/// An ability is a passive effect in battle that is attached to a Pokemon.
@@ -21,12 +21,12 @@ pub struct AbilityImpl {
/// The name of the script effect of the ability.
effect: StringKey,
/// The parameters for the script effect of the ability.
parameters: Vec<Arc<EffectParameter>>,
parameters: Vec<Arc<Parameter>>,
}
impl AbilityImpl {
/// Instantiates a new ability.
pub fn new(name: &StringKey, effect: &StringKey, parameters: Vec<Arc<EffectParameter>>) -> Self {
pub fn new(name: &StringKey, effect: &StringKey, parameters: Vec<Arc<Parameter>>) -> Self {
Self {
name: name.clone(),
effect: effect.clone(),
@@ -45,7 +45,7 @@ impl Ability for AbilityImpl {
&self.effect
}
/// The parameters for the script effect of the ability.
fn parameters(&self) -> &Vec<Arc<EffectParameter>> {
fn parameters(&self) -> &Vec<Arc<Parameter>> {
&self.parameters
}
}
@@ -74,7 +74,7 @@ pub(crate) mod tests {
impl Ability for Ability {
fn name(&self) -> &StringKey;
fn effect(&self) -> &StringKey;
fn parameters(&self) -> &Vec<Arc<EffectParameter>>;
fn parameters(&self) -> &Vec<Arc<Parameter >>;
}
}
}

View File

@@ -0,0 +1,118 @@
use crate::defines::LevelInt;
use crate::static_data::{Gender, Parameter};
use crate::StringKey;
use std::sync::Arc;
/// The different ways a Pokemon can evolve.
#[derive(Debug)]
pub enum EvolutionMethod {
/// Evolves when a certain level is reached.
Level {
/// The level at which the Pokemon evolves.
level: LevelInt,
},
/// Evolves when a certain level is reached, and the Pokemon is a specific gender.
LevelGender {
/// The level at which the Pokemon evolves.
level: LevelInt,
/// The gender the Pokemon needs to be.
gender: Gender,
},
/// Evolves when an item is used.
Item {
/// The item that needs to be used.
item: StringKey,
},
/// Evolves when an item is used, and the Pokemon is a specific gender.
ItemGender {
/// The item that needs to be used.
item: StringKey,
/// The gender the Pokemon needs to be.
gender: Gender,
},
/// Evolves if an item is held.
HoldItem {
/// The item that needs to be held.
item: StringKey,
},
/// Evolves if a held item is held, and it's day.
DayHoldItem {
/// The item that needs to be held.
item: StringKey,
},
/// Evolves if a held item is held, and it's night.
NightHoldItem {
/// The item that needs to be held.
item: StringKey,
},
/// Evolves if the Pokemon knows a certain move.
HasMove {
/// The move that needs to be known.
move_name: StringKey,
},
/// Evolves when above a certain happiness level.
Happiness {
/// The happiness level that needs to be reached.
happiness: u8,
},
/// Evolves when above a certain happiness level, and it's day.
HappinessDay {
/// The happiness level that needs to be reached.
happiness: u8,
},
/// Evolves when above a certain happiness level, and it's night.
HappinessNight {
/// The happiness level that needs to be reached.
happiness: u8,
},
/// Evolves when traded.
Trade,
/// Evolves when traded with a certain species.
TradeSpecies {
/// The species that needs to be traded with.
species: StringKey,
},
/// Evolves when traded while it's holding a certain item.
TradeItem {
/// The item that needs to be held.
item: StringKey,
},
/// Evolves in a certain location.
Location {
/// The location the Pokemon needs to be in.
location: StringKey,
},
/// A custom evolution method, implemented by the user.
Custom {
/// The name of the custom evolution method.
name: StringKey,
/// The parameters of the custom evolution method.
params: Vec<Arc<Parameter>>,
},
}
#[derive(Debug)]
/// Data about how and into which Pokemon a species can evolve.
pub struct EvolutionData {
/// The method of evolution.
method: EvolutionMethod,
/// The Pokemon the species evolves into.
to: StringKey,
}
impl EvolutionData {
/// Creates a new evolution data instance.
pub fn new(method: EvolutionMethod, to: StringKey) -> Self {
Self { method, to }
}
/// Returns the method of evolution.
pub fn method(&self) -> &EvolutionMethod {
&self.method
}
/// Returns the Pokemon the species evolves into.
pub fn to(&self) -> &StringKey {
&self.to
}
}

View File

@@ -1,6 +1,8 @@
#[doc(inline)]
pub use ability::*;
#[doc(inline)]
pub use evolution_data::*;
#[doc(inline)]
pub use form::*;
#[doc(inline)]
pub use gender::*;
@@ -19,6 +21,8 @@ pub(crate) mod tests {
/// An ability is a passive effect in battle that is attached to a Pokemon.
mod ability;
/// Data regarding into which Pokemon a species can evolve.
mod evolution_data;
/// A form is a variant of a specific species. A species always has at least one form, but can have
/// many more.
mod form;

View File

@@ -6,6 +6,7 @@ use hashbrown::{HashMap, HashSet};
use parking_lot::lock_api::RwLockReadGuard;
use parking_lot::{RawRwLock, RwLock};
use crate::static_data::species_data::evolution_data::EvolutionData;
use crate::static_data::Form;
use crate::static_data::Gender;
use crate::Random;
@@ -24,6 +25,8 @@ pub trait Species: Debug {
/// How hard it is to capture a Pokemon. 255 means this will be always caught, 0 means this is
/// uncatchable.
fn capture_rate(&self) -> u8;
/// The base happiness of the Pokemon.
fn base_happiness(&self) -> u8;
/// The forms that belong to this Pokemon.
fn forms(&self) -> RwLockReadGuard<'_, RawRwLock, HashMap<StringKey, Arc<dyn Form>>>;
/// The arbitrary flags that can be set on a Pokemon for script use.
@@ -42,6 +45,8 @@ pub trait Species: Debug {
fn has_flag(&self, key: &StringKey) -> bool;
/// Check whether the Pokemon has a specific flag set.
fn has_flag_by_hash(&self, key_hash: u32) -> bool;
/// The data regarding into which Pokemons this species can evolve, and how.
fn evolution_data(&self) -> &Vec<EvolutionData>;
}
/// The data belonging to a Pokemon with certain characteristics.
@@ -58,10 +63,14 @@ pub struct SpeciesImpl {
/// How hard it is to capture a Pokemon. 255 means this will be always caught, 0 means this is
/// uncatchable.
capture_rate: u8,
/// The base happiness of the Pokemon.
base_happiness: u8,
/// The forms that belong to this Pokemon.
forms: RwLock<HashMap<StringKey, Arc<dyn Form>>>,
/// The arbitrary flags that can be set on a Pokemon for script use.
flags: HashSet<StringKey>,
/// The data regarding into which Pokemons this species can evolve, and how.
evolution_data: Vec<EvolutionData>,
}
/// A cached String Key to get the default form.
@@ -80,8 +89,10 @@ impl SpeciesImpl {
gender_rate: f32,
growth_rate: &StringKey,
capture_rate: u8,
base_happiness: u8,
default_form: Arc<dyn Form>,
flags: HashSet<StringKey>,
evolution_data: Vec<EvolutionData>,
) -> Self {
let mut forms = HashMap::with_capacity(1);
forms.insert_unique_unchecked(get_default_key(), default_form);
@@ -91,8 +102,10 @@ impl SpeciesImpl {
gender_rate,
growth_rate: growth_rate.clone(),
capture_rate,
base_happiness,
forms: RwLock::new(forms),
flags,
evolution_data,
}
}
}
@@ -119,6 +132,11 @@ impl Species for SpeciesImpl {
fn capture_rate(&self) -> u8 {
self.capture_rate
}
fn base_happiness(&self) -> u8 {
self.base_happiness
}
/// The forms that belong to this Pokemon.
fn forms(&self) -> RwLockReadGuard<'_, RawRwLock, HashMap<StringKey, Arc<dyn Form>>> {
self.forms.read()
@@ -171,6 +189,10 @@ impl Species for SpeciesImpl {
fn has_flag_by_hash(&self, key_hash: u32) -> bool {
self.flags.contains::<u32>(&key_hash)
}
fn evolution_data(&self) -> &Vec<EvolutionData> {
&self.evolution_data
}
}
#[cfg(test)]
@@ -188,6 +210,7 @@ pub(crate) mod tests {
fn gender_rate(&self) -> f32;
fn growth_rate(&self) -> &StringKey;
fn capture_rate(&self) -> u8;
fn base_happiness(&self) -> u8;
fn forms(&self) -> RwLockReadGuard<'_, RawRwLock, HashMap<StringKey, Arc<dyn Form>>>;
fn flags(&self) -> &HashSet<StringKey>;
fn add_form(&self, id: StringKey, form: Arc<dyn Form>);
@@ -197,6 +220,7 @@ pub(crate) mod tests {
fn get_random_gender(&self, rand: &mut Random) -> Gender;
fn has_flag(&self, key: &StringKey) -> bool;
fn has_flag_by_hash(&self, key_hash: u32) -> bool;
fn evolution_data(&self) -> &Vec<EvolutionData>;
}
}
}