Loads more work on battling, initial stretch to run a turn done.
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
a33369afcc
commit
ff541b0696
17
Cargo.toml
17
Cargo.toml
|
@ -6,10 +6,13 @@ edition = "2018"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "pkmn_lib"
|
name = "pkmn_lib"
|
||||||
crate_type = ["cdylib"]
|
crate_type = ["rlib"]
|
||||||
|
path = "src/lib.rs"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
c_interface = []
|
c_interface = []
|
||||||
|
serde = ["dep:serde", "dep:serde_json"]
|
||||||
|
default = ["serde"]
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
opt-level = 0
|
opt-level = 0
|
||||||
|
@ -43,11 +46,15 @@ chrono = "0.4.19"
|
||||||
# Used for RNG
|
# Used for RNG
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
rand_pcg = "0.3.1"
|
rand_pcg = "0.3.1"
|
||||||
# Used for the hashmap!{} macro, creating a simple initializer pattern for hashmaps.
|
|
||||||
maplit = "1.0.2"
|
|
||||||
failure = "0.1.8"
|
failure = "0.1.8"
|
||||||
failure_derive = "0.1.8"
|
failure_derive = "0.1.8"
|
||||||
lazy_static = "1.4.0"
|
|
||||||
hashbrown = "0.12.1"
|
hashbrown = "0.12.1"
|
||||||
indexmap = "1.8.2"
|
indexmap = "1.8.2"
|
||||||
parking_lot = "0.12.1"
|
parking_lot = "0.12.1"
|
||||||
|
serde = { version = "1.0.137", optional = true, features = ["derive"] }
|
||||||
|
serde_json = { version = "1.0.81", optional = true }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
csv = "1.1.6"
|
||||||
|
project-root = "0.2.2"
|
||||||
|
syn = "1.0.96"
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
Main lifetimes:
|
||||||
|
- Library: the static data underlying everything. This has the longest lifetime.
|
||||||
|
- Pokemon: The lifetime of a Pokemon.
|
||||||
|
- Party: The lifetime of a party, as a Pokemon can be added or taken from a party, this is shorter than the lifetime of a pokemon
|
||||||
|
- Battle: The lifetime of a battle.
|
|
@ -0,0 +1 @@
|
||||||
|
max_width = 120
|
|
@ -249,9 +249,7 @@ impl<T: 'static> Deref for DeferredCleanup<T> {
|
||||||
type Target = T;
|
type Target = T;
|
||||||
|
|
||||||
fn deref(&self) -> &T {
|
fn deref(&self) -> &T {
|
||||||
self.with_value(
|
self.with_value(|value| unsafe_block!("The borrow of self protects the inner value" => &*value.get()))
|
||||||
|value| unsafe_block!("The borrow of self protects the inner value" => &*value.get()),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,10 +36,7 @@ enum Kind {
|
||||||
|
|
||||||
impl PkmnResult {
|
impl PkmnResult {
|
||||||
pub(super) fn ok() -> Self {
|
pub(super) fn ok() -> Self {
|
||||||
PkmnResult {
|
PkmnResult { kind: Kind::Ok, id: 0 }
|
||||||
kind: Kind::Ok,
|
|
||||||
id: 0,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn argument_null() -> Self {
|
pub(super) fn argument_null() -> Self {
|
||||||
|
@ -65,10 +62,7 @@ impl PkmnResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn context(self, e: impl Fail) -> Self {
|
pub(super) fn context(self, e: impl Fail) -> Self {
|
||||||
assert!(
|
assert!(self.as_err().is_some(), "context can only be attached to errors");
|
||||||
self.as_err().is_some(),
|
|
||||||
"context can only be attached to errors"
|
|
||||||
);
|
|
||||||
|
|
||||||
let err = Some(format_error(&e));
|
let err = Some(format_error(&e));
|
||||||
|
|
||||||
|
@ -105,8 +99,7 @@ impl PkmnResult {
|
||||||
.value
|
.value
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let extract_panic =
|
let extract_panic = || extract_panic(&e).map(|s| format!("internal panic with '{}'", s));
|
||||||
|| extract_panic(&e).map(|s| format!("internal panic with '{}'", s));
|
|
||||||
|
|
||||||
// Set the last error to the panic message if it's not already set
|
// Set the last error to the panic message if it's not already set
|
||||||
last_result
|
last_result
|
||||||
|
@ -124,9 +117,7 @@ impl PkmnResult {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn with_last_result<R>(
|
pub(super) fn with_last_result<R>(f: impl FnOnce(Option<(PkmnResult, Option<&str>)>) -> R) -> R {
|
||||||
f: impl FnOnce(Option<(PkmnResult, Option<&str>)>) -> R,
|
|
||||||
) -> R {
|
|
||||||
LAST_RESULT.with(|last_result| {
|
LAST_RESULT.with(|last_result| {
|
||||||
let last_result = last_result.borrow();
|
let last_result = last_result.borrow();
|
||||||
|
|
||||||
|
|
|
@ -1,32 +1,359 @@
|
||||||
use crate::dynamic_data::models::learned_move::LearnedMove;
|
use crate::dynamic_data::models::learned_move::LearnedMove;
|
||||||
use crate::dynamic_data::models::pokemon::Pokemon;
|
use crate::dynamic_data::models::pokemon::Pokemon;
|
||||||
|
use crate::dynamic_data::script_handling::script::ScriptContainer;
|
||||||
|
use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper};
|
||||||
|
use parking_lot::RwLock;
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum TurnChoice<'a> {
|
struct CommonChoiceData<'user, 'library> {
|
||||||
Move {
|
user: Arc<RwLock<Pokemon<'user, 'library>>>,
|
||||||
user: &'a Pokemon<'a>,
|
speed: u32,
|
||||||
used_move: Box<LearnedMove<'a>>,
|
random_value: u32,
|
||||||
target_side: u8,
|
has_failed: bool,
|
||||||
target_index: u8,
|
script_source_data: RwLock<ScriptSourceData>,
|
||||||
},
|
|
||||||
Item {
|
|
||||||
user: &'a Pokemon<'a>,
|
|
||||||
},
|
|
||||||
Switch {
|
|
||||||
user: &'a Pokemon<'a>,
|
|
||||||
},
|
|
||||||
Flee {
|
|
||||||
user: &'a Pokemon<'a>,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TurnChoice<'a> {
|
#[derive(Debug)]
|
||||||
pub fn user(&self) -> &'a Pokemon<'a> {
|
pub enum TurnChoice<'user, 'library> {
|
||||||
|
Move(MoveChoice<'user, 'library>),
|
||||||
|
Item(ItemChoice<'user, 'library>),
|
||||||
|
Switch(SwitchChoice<'user, 'library>),
|
||||||
|
Flee(FleeChoice<'user, 'library>),
|
||||||
|
Pass(PassChoice<'user, 'library>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'user, 'library> TurnChoice<'user, 'library> {
|
||||||
|
fn choice_data(&self) -> &CommonChoiceData<'user, 'library> {
|
||||||
match self {
|
match self {
|
||||||
TurnChoice::Move { user, .. } => user,
|
TurnChoice::Move(data) => &data.choice_data,
|
||||||
TurnChoice::Item { user, .. } => user,
|
TurnChoice::Item(data) => &data.choice_data,
|
||||||
TurnChoice::Switch { user, .. } => user,
|
TurnChoice::Switch(data) => &data.choice_data,
|
||||||
TurnChoice::Flee { user, .. } => user,
|
TurnChoice::Flee(data) => &data.choice_data,
|
||||||
|
TurnChoice::Pass(data) => &data.choice_data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn choice_data_mut(&mut self) -> &mut Box<CommonChoiceData<'user, 'library>> {
|
||||||
|
match self {
|
||||||
|
TurnChoice::Move(data) => &mut data.choice_data,
|
||||||
|
TurnChoice::Item(data) => &mut data.choice_data,
|
||||||
|
TurnChoice::Switch(data) => &mut data.choice_data,
|
||||||
|
TurnChoice::Flee(data) => &mut data.choice_data,
|
||||||
|
TurnChoice::Pass(data) => &mut data.choice_data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn user(&self) -> &Arc<RwLock<Pokemon<'user, 'library>>> {
|
||||||
|
&self.choice_data().user
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn speed(&self) -> u32 {
|
||||||
|
self.choice_data().speed
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn speed_mut(&mut self) -> &mut u32 {
|
||||||
|
&mut self.choice_data_mut().speed
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_failed(&self) -> bool {
|
||||||
|
self.choice_data().has_failed
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fail(&mut self) {
|
||||||
|
self.choice_data_mut().has_failed = true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn random_value(&self) -> u32 {
|
||||||
|
self.choice_data().random_value
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_random_value(&mut self, val: u32) {
|
||||||
|
self.choice_data_mut().random_value = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_move_turn_data<'b>(&'b mut self) -> &'b mut MoveChoice<'user, 'library> {
|
||||||
|
if let TurnChoice::Move(data) = self {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
panic!("Invalid turn choice");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'user, 'library> ScriptSource<'user> for TurnChoice<'user, 'library> {
|
||||||
|
fn get_script_count(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
TurnChoice::Move(data) => data.get_script_count(),
|
||||||
|
TurnChoice::Item(data) => data.get_script_count(),
|
||||||
|
TurnChoice::Switch(data) => data.get_script_count(),
|
||||||
|
TurnChoice::Flee(data) => data.get_script_count(),
|
||||||
|
TurnChoice::Pass(data) => data.get_script_count(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> {
|
||||||
|
match self {
|
||||||
|
TurnChoice::Move(data) => data.get_script_source_data(),
|
||||||
|
TurnChoice::Item(data) => data.get_script_source_data(),
|
||||||
|
TurnChoice::Switch(data) => data.get_script_source_data(),
|
||||||
|
TurnChoice::Flee(data) => data.get_script_source_data(),
|
||||||
|
TurnChoice::Pass(data) => data.get_script_source_data(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_own_scripts(&self, scripts: &mut Vec<ScriptWrapper>) {
|
||||||
|
match self {
|
||||||
|
TurnChoice::Move(data) => data.get_own_scripts(scripts),
|
||||||
|
TurnChoice::Item(data) => data.get_own_scripts(scripts),
|
||||||
|
TurnChoice::Switch(data) => data.get_own_scripts(scripts),
|
||||||
|
TurnChoice::Flee(data) => data.get_own_scripts(scripts),
|
||||||
|
TurnChoice::Pass(data) => data.get_own_scripts(scripts),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_scripts(&self, scripts: &mut Vec<ScriptWrapper>) {
|
||||||
|
match self {
|
||||||
|
TurnChoice::Move(data) => data.collect_scripts(scripts),
|
||||||
|
TurnChoice::Item(data) => data.collect_scripts(scripts),
|
||||||
|
TurnChoice::Switch(data) => data.collect_scripts(scripts),
|
||||||
|
TurnChoice::Flee(data) => data.collect_scripts(scripts),
|
||||||
|
TurnChoice::Pass(data) => data.collect_scripts(scripts),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct MoveChoice<'user, 'library> {
|
||||||
|
used_move: Arc<RwLock<LearnedMove<'library>>>,
|
||||||
|
target_side: u8,
|
||||||
|
target_index: u8,
|
||||||
|
script: ScriptContainer,
|
||||||
|
priority: i8,
|
||||||
|
choice_data: Box<CommonChoiceData<'user, 'library>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'user, 'library> MoveChoice<'user, 'library> {
|
||||||
|
pub fn new(
|
||||||
|
user: Arc<RwLock<Pokemon<'user, 'library>>>,
|
||||||
|
used_move: Arc<RwLock<LearnedMove<'library>>>,
|
||||||
|
target_side: u8,
|
||||||
|
target_index: u8,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
used_move,
|
||||||
|
target_side,
|
||||||
|
target_index,
|
||||||
|
script: Default::default(),
|
||||||
|
priority: 0,
|
||||||
|
choice_data: Box::new(CommonChoiceData {
|
||||||
|
user,
|
||||||
|
speed: 0,
|
||||||
|
random_value: 0,
|
||||||
|
has_failed: false,
|
||||||
|
script_source_data: Default::default(),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn used_move(&self) -> &Arc<RwLock<LearnedMove<'library>>> {
|
||||||
|
&self.used_move
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn target_side(&self) -> u8 {
|
||||||
|
self.target_side
|
||||||
|
}
|
||||||
|
pub fn target_index(&self) -> u8 {
|
||||||
|
self.target_index
|
||||||
|
}
|
||||||
|
pub fn priority(&self) -> i8 {
|
||||||
|
self.priority
|
||||||
|
}
|
||||||
|
pub fn user(&self) -> &Arc<RwLock<Pokemon<'user, 'library>>> {
|
||||||
|
&self.choice_data.user
|
||||||
|
}
|
||||||
|
pub fn script(&self) -> &ScriptContainer {
|
||||||
|
&self.script
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn priority_mut(&mut self) -> &mut i8 {
|
||||||
|
&mut self.priority
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'user, 'library> ScriptSource<'user> for MoveChoice<'user, 'library> {
|
||||||
|
fn get_script_count(&self) -> usize {
|
||||||
|
1 + self.choice_data.user.read().get_script_count()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> {
|
||||||
|
&self.choice_data.script_source_data
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_own_scripts(&self, scripts: &mut Vec<ScriptWrapper>) {
|
||||||
|
scripts.push((&self.script).into());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_scripts(&self, scripts: &mut Vec<ScriptWrapper>) {
|
||||||
|
self.get_own_scripts(scripts);
|
||||||
|
self.choice_data.user.read().collect_scripts(scripts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ItemChoice<'user, 'library> {
|
||||||
|
choice_data: Box<CommonChoiceData<'user, 'library>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'user, 'library> ScriptSource<'user> for ItemChoice<'user, 'library> {
|
||||||
|
fn get_script_count(&self) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> {
|
||||||
|
&self.choice_data.script_source_data
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_own_scripts(&self, _scripts: &mut Vec<ScriptWrapper>) {}
|
||||||
|
|
||||||
|
fn collect_scripts(&self, scripts: &mut Vec<ScriptWrapper>) {
|
||||||
|
self.choice_data.user.read().collect_scripts(scripts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SwitchChoice<'user, 'library> {
|
||||||
|
choice_data: Box<CommonChoiceData<'user, 'library>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'user, 'library> ScriptSource<'user> for SwitchChoice<'user, 'library> {
|
||||||
|
fn get_script_count(&self) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> {
|
||||||
|
&self.choice_data.script_source_data
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_own_scripts(&self, _scripts: &mut Vec<ScriptWrapper>) {}
|
||||||
|
|
||||||
|
fn collect_scripts(&self, scripts: &mut Vec<ScriptWrapper>) {
|
||||||
|
self.choice_data.user.read().collect_scripts(scripts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct FleeChoice<'user, 'library> {
|
||||||
|
choice_data: Box<CommonChoiceData<'user, 'library>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'user, 'library> ScriptSource<'user> for FleeChoice<'user, 'library> {
|
||||||
|
fn get_script_count(&self) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> {
|
||||||
|
&self.choice_data.script_source_data
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_own_scripts(&self, _scripts: &mut Vec<ScriptWrapper>) {}
|
||||||
|
|
||||||
|
fn collect_scripts(&self, scripts: &mut Vec<ScriptWrapper>) {
|
||||||
|
self.choice_data.user.read().collect_scripts(scripts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PassChoice<'user, 'library> {
|
||||||
|
choice_data: Box<CommonChoiceData<'user, 'library>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'user, 'library> ScriptSource<'user> for PassChoice<'user, 'library> {
|
||||||
|
fn get_script_count(&self) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> {
|
||||||
|
&self.choice_data.script_source_data
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_own_scripts(&self, _scripts: &mut Vec<ScriptWrapper>) {}
|
||||||
|
|
||||||
|
fn collect_scripts(&self, scripts: &mut Vec<ScriptWrapper>) {
|
||||||
|
self.choice_data.user.read().collect_scripts(scripts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'user, 'library> PartialEq<Self> for TurnChoice<'user, 'library> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
std::ptr::eq(self, other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'user, 'library> Eq for TurnChoice<'user, 'library> {}
|
||||||
|
|
||||||
|
impl<'user, 'library> PartialOrd for TurnChoice<'user, 'library> {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'user, 'library> Ord for TurnChoice<'user, 'library> {
|
||||||
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
|
match self {
|
||||||
|
TurnChoice::Move(data) => {
|
||||||
|
if let TurnChoice::Move(other_data) = other {
|
||||||
|
let priority_compare = data.priority.cmp(&other_data.priority);
|
||||||
|
if priority_compare != Ordering::Equal {
|
||||||
|
return priority_compare;
|
||||||
|
}
|
||||||
|
let speed_compare = self.speed().cmp(&other.speed());
|
||||||
|
if speed_compare != Ordering::Equal {
|
||||||
|
return speed_compare;
|
||||||
|
}
|
||||||
|
return self.random_value().cmp(&other.random_value());
|
||||||
|
}
|
||||||
|
Ordering::Greater
|
||||||
|
}
|
||||||
|
TurnChoice::Item { .. } => {
|
||||||
|
if let TurnChoice::Move { .. } = other {
|
||||||
|
return Ordering::Less;
|
||||||
|
}
|
||||||
|
if let TurnChoice::Item { .. } = other {
|
||||||
|
let speed_compare = self.speed().cmp(&other.speed());
|
||||||
|
if speed_compare != Ordering::Equal {
|
||||||
|
return speed_compare;
|
||||||
|
}
|
||||||
|
return self.random_value().cmp(&other.random_value());
|
||||||
|
}
|
||||||
|
Ordering::Greater
|
||||||
|
}
|
||||||
|
TurnChoice::Switch { .. } => {
|
||||||
|
if let TurnChoice::Move { .. } = other {
|
||||||
|
return Ordering::Less;
|
||||||
|
}
|
||||||
|
if let TurnChoice::Item { .. } = other {
|
||||||
|
return Ordering::Less;
|
||||||
|
}
|
||||||
|
if let TurnChoice::Switch { .. } = other {
|
||||||
|
let speed_compare = self.speed().cmp(&other.speed());
|
||||||
|
if speed_compare != Ordering::Equal {
|
||||||
|
return speed_compare;
|
||||||
|
}
|
||||||
|
return self.random_value().cmp(&other.random_value());
|
||||||
|
}
|
||||||
|
Ordering::Greater
|
||||||
|
}
|
||||||
|
TurnChoice::Flee { .. } => {
|
||||||
|
if let TurnChoice::Flee { .. } = other {
|
||||||
|
let speed_compare = self.speed().cmp(&other.speed());
|
||||||
|
if speed_compare != Ordering::Equal {
|
||||||
|
return speed_compare;
|
||||||
|
}
|
||||||
|
return self.random_value().cmp(&other.random_value());
|
||||||
|
}
|
||||||
|
Ordering::Less
|
||||||
|
}
|
||||||
|
TurnChoice::Pass(..) => Ordering::Less,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::dynamic_data::models::damage_source::DamageSource;
|
use crate::dynamic_data::models::damage_source::DamageSource;
|
||||||
|
use crate::dynamic_data::models::executing_move::ExecutingMove;
|
||||||
use crate::dynamic_data::models::pokemon::Pokemon;
|
use crate::dynamic_data::models::pokemon::Pokemon;
|
||||||
use crate::static_data::species_data::form::Form;
|
use crate::static_data::species_data::form::Form;
|
||||||
use crate::static_data::species_data::species::Species;
|
use crate::static_data::species_data::species::Species;
|
||||||
|
@ -9,12 +10,12 @@ pub struct EventHook {
|
||||||
evt_hook_function: Vec<fn(&Box<&Event>)>,
|
evt_hook_function: Vec<fn(&Box<&Event>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> EventHook {
|
impl<'battle, 'library> EventHook {
|
||||||
pub fn register_listener(&mut self, func: fn(&Box<&Event>)) {
|
pub fn register_listener(&mut self, func: fn(&Box<&Event>)) {
|
||||||
self.evt_hook_function.push(func);
|
self.evt_hook_function.push(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trigger<'b>(&self, evt: Event<'a, 'b>) {
|
pub fn trigger<'b>(&self, evt: Event<'b, 'battle, 'library>) {
|
||||||
let b = Box::new(&evt);
|
let b = Box::new(&evt);
|
||||||
for f in &self.evt_hook_function {
|
for f in &self.evt_hook_function {
|
||||||
f(&b);
|
f(&b);
|
||||||
|
@ -29,11 +30,11 @@ impl Debug for EventHook {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Event<'a, 'b> {
|
pub enum Event<'own, 'battle, 'library> {
|
||||||
Switch {
|
Switch {
|
||||||
side_index: u8,
|
side_index: u8,
|
||||||
index: u8,
|
index: u8,
|
||||||
pokemon: Option<&'a Pokemon<'b>>,
|
pokemon: Option<&'own Pokemon<'battle, 'library>>,
|
||||||
},
|
},
|
||||||
Swap {
|
Swap {
|
||||||
side_index: u8,
|
side_index: u8,
|
||||||
|
@ -41,21 +42,28 @@ pub enum Event<'a, 'b> {
|
||||||
index_b: u8,
|
index_b: u8,
|
||||||
},
|
},
|
||||||
SpeciesChange {
|
SpeciesChange {
|
||||||
pokemon: &'a Pokemon<'b>,
|
pokemon: &'own Pokemon<'battle, 'library>,
|
||||||
species: &'a Species<'b>,
|
species: &'own Species<'library>,
|
||||||
form: &'a Form<'b>,
|
form: &'own Form<'library>,
|
||||||
},
|
},
|
||||||
FormChange {
|
FormChange {
|
||||||
pokemon: &'a Pokemon<'b>,
|
pokemon: &'own Pokemon<'battle, 'library>,
|
||||||
form: &'a Form<'b>,
|
form: &'own Form<'library>,
|
||||||
},
|
},
|
||||||
Damage {
|
Damage {
|
||||||
pokemon: &'a Pokemon<'b>,
|
pokemon: &'own Pokemon<'battle, 'library>,
|
||||||
source: DamageSource,
|
source: DamageSource,
|
||||||
original_health: u32,
|
original_health: u32,
|
||||||
new_health: u32,
|
new_health: u32,
|
||||||
},
|
},
|
||||||
Faint {
|
Faint {
|
||||||
pokemon: &'a Pokemon<'b>,
|
pokemon: &'own Pokemon<'battle, 'library>,
|
||||||
},
|
},
|
||||||
|
MoveUse {
|
||||||
|
executing_move: &'own ExecutingMove<'own, 'battle, 'library>,
|
||||||
|
},
|
||||||
|
Miss {
|
||||||
|
user: &'own Pokemon<'battle, 'library>,
|
||||||
|
},
|
||||||
|
EndTurn,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,26 @@
|
||||||
|
use crate::dynamic_data::choices::TurnChoice;
|
||||||
use crate::dynamic_data::models::pokemon::Pokemon;
|
use crate::dynamic_data::models::pokemon::Pokemon;
|
||||||
|
use parking_lot::RwLock;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ChoiceQueue {
|
pub struct ChoiceQueue<'battle, 'library> {
|
||||||
queue: Vec<Arc<ChoiceQueue>>,
|
queue: Vec<Arc<RwLock<TurnChoice<'battle, 'library>>>>,
|
||||||
current: usize,
|
current: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChoiceQueue {
|
impl<'battle, 'library> ChoiceQueue<'battle, 'library> {
|
||||||
pub fn new(queue: Vec<Arc<ChoiceQueue>>) -> Self {
|
pub fn new(queue: Vec<Arc<RwLock<TurnChoice<'battle, 'library>>>>) -> Self {
|
||||||
Self { queue, current: 0 }
|
Self { queue, current: 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dequeue(&mut self) -> &Arc<ChoiceQueue> {
|
pub fn dequeue<'b>(&'b mut self) -> &'b Arc<RwLock<TurnChoice<'battle, 'library>>> {
|
||||||
let c = &self.queue[self.current];
|
let c = &self.queue[self.current];
|
||||||
self.current += 1;
|
self.current += 1;
|
||||||
c
|
c
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn peek(&mut self) -> &Arc<ChoiceQueue> {
|
pub fn peek(&mut self) -> &'battle Arc<RwLock<TurnChoice>> {
|
||||||
&self.queue[self.current]
|
&self.queue[self.current]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,4 +31,8 @@ impl ChoiceQueue {
|
||||||
pub fn move_pokemon_choice_next(&mut self, _pokemon: &Pokemon) {
|
pub fn move_pokemon_choice_next(&mut self, _pokemon: &Pokemon) {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_queue(&self) -> &Vec<Arc<RwLock<TurnChoice<'battle, 'library>>>> {
|
||||||
|
&self.queue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
pub mod choice_queue;
|
pub mod choice_queue;
|
||||||
pub mod target_resolver;
|
pub mod target_resolver;
|
||||||
|
pub mod turn_runner;
|
||||||
|
|
|
@ -5,11 +5,10 @@ use num_traits::abs;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub type TargetList<'a> = Vec<Option<Arc<RwLock<Pokemon<'a>>>>>;
|
pub type TargetList<'own, 'library> = Vec<Option<Arc<RwLock<Pokemon<'own, 'library>>>>>;
|
||||||
|
|
||||||
fn get_all_targets<'b>(battle: &Battle<'b>) -> TargetList<'b> {
|
fn get_all_targets<'b, 'library>(battle: &Battle<'b, 'library>) -> TargetList<'b, 'library> {
|
||||||
let mut v =
|
let mut v = Vec::with_capacity(battle.pokemon_per_side() as usize * battle.number_of_sides() as usize);
|
||||||
Vec::with_capacity(battle.pokemon_per_side() as usize * battle.number_of_sides() as usize);
|
|
||||||
for side in battle.sides() {
|
for side in battle.sides() {
|
||||||
for pokemon in side.pokemon() {
|
for pokemon in side.pokemon() {
|
||||||
v.push(pokemon.as_ref().cloned());
|
v.push(pokemon.as_ref().cloned());
|
||||||
|
@ -25,16 +24,13 @@ fn get_opposite_side(side: u8) -> u8 {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_all_adjacent<'b>(side: u8, index: u8, battle: &Battle<'b>) -> TargetList<'b> {
|
fn get_all_adjacent<'b, 'library>(side: u8, index: u8, battle: &Battle<'b, 'library>) -> TargetList<'b, 'library> {
|
||||||
let left = index as i32 - 1;
|
let left = index as i32 - 1;
|
||||||
let right = index + 1;
|
let right = index + 1;
|
||||||
if left < 0 && right >= battle.pokemon_per_side() {
|
if left < 0 && right >= battle.pokemon_per_side() {
|
||||||
return vec![
|
return vec![
|
||||||
battle.get_pokemon(side, index).as_ref().cloned(),
|
battle.get_pokemon(side, index).as_ref().cloned(),
|
||||||
battle
|
battle.get_pokemon(get_opposite_side(side), index).as_ref().cloned(),
|
||||||
.get_pokemon(get_opposite_side(side), index)
|
|
||||||
.as_ref()
|
|
||||||
.cloned(),
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
if left >= 0 {
|
if left >= 0 {
|
||||||
|
@ -43,19 +39,13 @@ fn get_all_adjacent<'b>(side: u8, index: u8, battle: &Battle<'b>) -> TargetList<
|
||||||
battle.get_pokemon(side, index).as_ref().cloned(),
|
battle.get_pokemon(side, index).as_ref().cloned(),
|
||||||
battle.get_pokemon(side, left as u8).as_ref().cloned(),
|
battle.get_pokemon(side, left as u8).as_ref().cloned(),
|
||||||
battle.get_pokemon(side, right).as_ref().cloned(),
|
battle.get_pokemon(side, right).as_ref().cloned(),
|
||||||
battle
|
battle.get_pokemon(get_opposite_side(side), index).as_ref().cloned(),
|
||||||
.get_pokemon(get_opposite_side(side), index)
|
|
||||||
.as_ref()
|
|
||||||
.cloned(),
|
|
||||||
]
|
]
|
||||||
} else {
|
} else {
|
||||||
vec![
|
vec![
|
||||||
battle.get_pokemon(side, index).as_ref().cloned(),
|
battle.get_pokemon(side, index).as_ref().cloned(),
|
||||||
battle.get_pokemon(side, left as u8).as_ref().cloned(),
|
battle.get_pokemon(side, left as u8).as_ref().cloned(),
|
||||||
battle
|
battle.get_pokemon(get_opposite_side(side), index).as_ref().cloned(),
|
||||||
.get_pokemon(get_opposite_side(side), index)
|
|
||||||
.as_ref()
|
|
||||||
.cloned(),
|
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -63,14 +53,15 @@ fn get_all_adjacent<'b>(side: u8, index: u8, battle: &Battle<'b>) -> TargetList<
|
||||||
vec![
|
vec![
|
||||||
battle.get_pokemon(side, index).as_ref().cloned(),
|
battle.get_pokemon(side, index).as_ref().cloned(),
|
||||||
battle.get_pokemon(side, right).as_ref().cloned(),
|
battle.get_pokemon(side, right).as_ref().cloned(),
|
||||||
battle
|
battle.get_pokemon(get_opposite_side(side), index).as_ref().cloned(),
|
||||||
.get_pokemon(get_opposite_side(side), index)
|
|
||||||
.as_ref()
|
|
||||||
.cloned(),
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_all_adjacent_opponent<'b>(side: u8, index: u8, battle: &Battle<'b>) -> TargetList<'b> {
|
fn get_all_adjacent_opponent<'b, 'library>(
|
||||||
|
side: u8,
|
||||||
|
index: u8,
|
||||||
|
battle: &Battle<'b, 'library>,
|
||||||
|
) -> TargetList<'b, 'library> {
|
||||||
let left = index as i32 - 1;
|
let left = index as i32 - 1;
|
||||||
let right = index + 1;
|
let right = index + 1;
|
||||||
if left < 0 && right >= battle.pokemon_per_side() {
|
if left < 0 && right >= battle.pokemon_per_side() {
|
||||||
|
@ -95,12 +86,12 @@ fn get_all_adjacent_opponent<'b>(side: u8, index: u8, battle: &Battle<'b>) -> Ta
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_targets<'b>(
|
pub fn resolve_targets<'b, 'library>(
|
||||||
side: u8,
|
side: u8,
|
||||||
index: u8,
|
index: u8,
|
||||||
target: MoveTarget,
|
target: MoveTarget,
|
||||||
battle: &Battle<'b>,
|
battle: &Battle<'b, 'library>,
|
||||||
) -> TargetList<'b> {
|
) -> TargetList<'b, 'library> {
|
||||||
match target {
|
match target {
|
||||||
MoveTarget::Adjacent
|
MoveTarget::Adjacent
|
||||||
| MoveTarget::AdjacentAlly
|
| MoveTarget::AdjacentAlly
|
||||||
|
|
|
@ -0,0 +1,344 @@
|
||||||
|
use crate::dynamic_data::choices::TurnChoice;
|
||||||
|
use crate::dynamic_data::event_hooks::event_hook::Event;
|
||||||
|
use crate::dynamic_data::flow::target_resolver::resolve_targets;
|
||||||
|
use crate::dynamic_data::models::battle::Battle;
|
||||||
|
use crate::dynamic_data::models::damage_source::DamageSource;
|
||||||
|
use crate::dynamic_data::models::executing_move::ExecutingMove;
|
||||||
|
use crate::dynamic_data::models::pokemon::Pokemon;
|
||||||
|
use crate::dynamic_data::script_handling::{ScriptSource, ScriptWrapper};
|
||||||
|
use crate::static_data::{DataLibrary, MoveCategory};
|
||||||
|
use crate::{run_scripts, script_hook, script_hook_on_lock, PkmnResult};
|
||||||
|
use parking_lot::RwLock;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
impl<'own, 'library> Battle<'own, 'library> {
|
||||||
|
pub(crate) fn run_turn(&mut self) -> PkmnResult<()> {
|
||||||
|
let cq = self.current_turn_queue();
|
||||||
|
let mut choice_queue = cq.as_ref().unwrap().write();
|
||||||
|
|
||||||
|
// We are now at the very beginning of a turn. We have assigned speeds and priorities to all
|
||||||
|
// choices, and put them in the correct order.
|
||||||
|
|
||||||
|
// The first thing to do is to run the on_before_turn script hook on every choice. This script hook
|
||||||
|
// is primarily intended to be used to reset variables on a script (for example scripts that need
|
||||||
|
// to check whether a pokemon was hit this turn. By resetting here, and setting a variable to true
|
||||||
|
// they can then know this later on.)
|
||||||
|
for choice in choice_queue.get_queue() {
|
||||||
|
let choice_guard = choice.read();
|
||||||
|
let c = choice_guard.deref();
|
||||||
|
script_hook!(on_before_turn, c, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we can properly begin executing choices.
|
||||||
|
// One by one dequeue the turns, and run them. If the battle has ended we do not want to
|
||||||
|
// continue running however.
|
||||||
|
while choice_queue.has_next() && !self.has_ended() {
|
||||||
|
let choice = choice_queue.dequeue().clone();
|
||||||
|
self.execute_choice(choice.clone())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the battle is not ended, we have arrived at the normal end of a turn. and thus want
|
||||||
|
// to run the end turn scripts.
|
||||||
|
|
||||||
|
// As we want all scripts to run exactly once, including those on the sides and battles,
|
||||||
|
// we can't just use the default script hook macro on each pokemon. Instead manually call
|
||||||
|
// the script functions on every script.
|
||||||
|
if !self.has_ended() {
|
||||||
|
let mut scripts;
|
||||||
|
for side in self.sides() {
|
||||||
|
for pokemon in side.pokemon().iter().flatten() {
|
||||||
|
scripts = Vec::new();
|
||||||
|
pokemon.read().get_own_scripts(&mut scripts);
|
||||||
|
run_scripts!(on_end_turn, scripts,);
|
||||||
|
}
|
||||||
|
scripts = Vec::new();
|
||||||
|
side.get_own_scripts(&mut scripts);
|
||||||
|
run_scripts!(on_end_turn, scripts,);
|
||||||
|
}
|
||||||
|
scripts = Vec::new();
|
||||||
|
self.get_own_scripts(&mut scripts);
|
||||||
|
run_scripts!(on_end_turn, scripts,);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute_choice(&self, choice: Arc<RwLock<TurnChoice<'own, 'library>>>) -> PkmnResult<()> {
|
||||||
|
let choice_guard = choice.read();
|
||||||
|
if let TurnChoice::Pass(..) = choice_guard.deref() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
if self.has_ended() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let user = choice_guard.user().read();
|
||||||
|
if !user.is_usable() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
if !user.is_on_battlefield() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.can_use(choice_guard.deref()) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
match choice_guard.deref() {
|
||||||
|
TurnChoice::Move(..) => self.execute_move_choice(&choice)?,
|
||||||
|
TurnChoice::Item(_) => {}
|
||||||
|
TurnChoice::Switch(_) => {}
|
||||||
|
TurnChoice::Flee(_) => {}
|
||||||
|
TurnChoice::Pass(_) => {}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute_move_choice<'func>(
|
||||||
|
&'func self,
|
||||||
|
choice: &'func Arc<RwLock<TurnChoice<'own, 'library>>>,
|
||||||
|
) -> PkmnResult<()> {
|
||||||
|
let mut write_guard = choice.write();
|
||||||
|
let choice = write_guard.get_move_turn_data();
|
||||||
|
let used_move = choice.used_move();
|
||||||
|
let move_data_lock = used_move.read();
|
||||||
|
let mut move_data = move_data_lock.move_data();
|
||||||
|
let mut move_name = move_data.name().clone();
|
||||||
|
script_hook!(change_move, choice, choice, &mut move_name);
|
||||||
|
if move_name != *move_data.name() {
|
||||||
|
move_data = self.library().static_data().moves().get(&move_name).unwrap();
|
||||||
|
// FIXME: also change the script on the choice.
|
||||||
|
}
|
||||||
|
let target_type = move_data.target();
|
||||||
|
let targets = resolve_targets(choice.target_side(), choice.target_index(), target_type, self);
|
||||||
|
|
||||||
|
let mut number_of_hits: u8 = 1;
|
||||||
|
script_hook!(change_number_of_hits, choice, choice, &mut number_of_hits);
|
||||||
|
if number_of_hits == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let mut executing_move = ExecutingMove::new(
|
||||||
|
&targets,
|
||||||
|
number_of_hits,
|
||||||
|
choice.user().clone(),
|
||||||
|
used_move.clone(),
|
||||||
|
move_data,
|
||||||
|
choice.script().clone(),
|
||||||
|
);
|
||||||
|
let mut prevented = false;
|
||||||
|
script_hook!(prevent_move, executing_move, &executing_move, &mut prevented);
|
||||||
|
if prevented {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
if !executing_move.chosen_move().write().try_use(1) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
self.event_hook().trigger(Event::MoveUse {
|
||||||
|
executing_move: &executing_move,
|
||||||
|
});
|
||||||
|
let mut fail = false;
|
||||||
|
script_hook!(fail_move, executing_move, &executing_move, &mut fail);
|
||||||
|
if fail {
|
||||||
|
// TODO: Add fail handling
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let mut stop = false;
|
||||||
|
script_hook!(stop_before_move, executing_move, &executing_move, &mut stop);
|
||||||
|
if stop {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
script_hook!(on_before_move, executing_move, &executing_move);
|
||||||
|
for target in targets.iter().flatten() {
|
||||||
|
self.handle_move_for_target(&mut executing_move, target)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_move_for_target(
|
||||||
|
&self,
|
||||||
|
executing_move: &mut ExecutingMove<'_, 'own, '_>,
|
||||||
|
target: &Arc<RwLock<Pokemon<'own, '_>>>,
|
||||||
|
) -> PkmnResult<()> {
|
||||||
|
{
|
||||||
|
let mut fail = false;
|
||||||
|
script_hook_on_lock!(fail_incoming_move, target, executing_move, target, &mut fail);
|
||||||
|
if fail {
|
||||||
|
// TODO: Add fail handling
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let mut invulnerable = false;
|
||||||
|
script_hook_on_lock!(is_invulnerable, target, executing_move, target, &mut invulnerable);
|
||||||
|
if invulnerable {
|
||||||
|
// TODO: Add fail handling
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let number_of_hits = executing_move.number_of_hits();
|
||||||
|
if number_of_hits == 0 {
|
||||||
|
script_hook_on_lock!(on_move_miss, target, executing_move, target);
|
||||||
|
self.event_hook().trigger(Event::Miss {
|
||||||
|
user: executing_move.user().read().deref(),
|
||||||
|
});
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let target_hit_stat = executing_move.get_index_of_target(target)?;
|
||||||
|
for hit_index in 0..number_of_hits {
|
||||||
|
if self.has_ended() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
if executing_move.user().read().is_fainted() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if target.read().is_fainted() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let mut hit_type = executing_move.use_move().move_type();
|
||||||
|
script_hook!(
|
||||||
|
change_move_type,
|
||||||
|
executing_move,
|
||||||
|
executing_move,
|
||||||
|
target,
|
||||||
|
hit_index,
|
||||||
|
&mut hit_type
|
||||||
|
);
|
||||||
|
executing_move
|
||||||
|
.get_hit_from_raw_index_mut(target_hit_stat + hit_index as usize)
|
||||||
|
.set_move_type(hit_type);
|
||||||
|
let mut effectiveness = self
|
||||||
|
.library()
|
||||||
|
.static_data()
|
||||||
|
.types()
|
||||||
|
.get_effectiveness(hit_type, target.read().types());
|
||||||
|
script_hook!(
|
||||||
|
change_effectiveness,
|
||||||
|
executing_move,
|
||||||
|
executing_move,
|
||||||
|
target,
|
||||||
|
hit_index,
|
||||||
|
&mut effectiveness
|
||||||
|
);
|
||||||
|
executing_move
|
||||||
|
.get_hit_from_raw_index_mut(target_hit_stat + hit_index as usize)
|
||||||
|
.set_effectiveness(effectiveness);
|
||||||
|
let mut block_critical = false;
|
||||||
|
script_hook!(
|
||||||
|
block_critical,
|
||||||
|
executing_move,
|
||||||
|
executing_move,
|
||||||
|
target,
|
||||||
|
hit_index,
|
||||||
|
&mut block_critical
|
||||||
|
);
|
||||||
|
script_hook_on_lock!(
|
||||||
|
block_incoming_critical,
|
||||||
|
target,
|
||||||
|
executing_move,
|
||||||
|
target,
|
||||||
|
hit_index,
|
||||||
|
&mut block_critical
|
||||||
|
);
|
||||||
|
|
||||||
|
if !block_critical {
|
||||||
|
let is_critical =
|
||||||
|
self.library()
|
||||||
|
.misc_library()
|
||||||
|
.is_critical(self, executing_move, target, hit_index);
|
||||||
|
executing_move
|
||||||
|
.get_hit_from_raw_index_mut(target_hit_stat + hit_index as usize)
|
||||||
|
.set_critical(is_critical);
|
||||||
|
}
|
||||||
|
let base_power = self.library().damage_calculator().get_base_power(
|
||||||
|
executing_move,
|
||||||
|
target,
|
||||||
|
hit_index,
|
||||||
|
executing_move.get_hit_data(target, hit_index)?,
|
||||||
|
);
|
||||||
|
executing_move
|
||||||
|
.get_hit_from_raw_index_mut(target_hit_stat + hit_index as usize)
|
||||||
|
.set_base_power(base_power);
|
||||||
|
let damage = self.library().damage_calculator().get_damage(
|
||||||
|
executing_move,
|
||||||
|
target,
|
||||||
|
hit_index,
|
||||||
|
executing_move.get_hit_data(target, hit_index)?,
|
||||||
|
);
|
||||||
|
executing_move
|
||||||
|
.get_hit_from_raw_index_mut(target_hit_stat + hit_index as usize)
|
||||||
|
.set_damage(damage);
|
||||||
|
|
||||||
|
if executing_move.use_move().category() == MoveCategory::Status {
|
||||||
|
if executing_move.use_move().has_secondary_effect() {
|
||||||
|
let secondary_effect_chance = executing_move.use_move().secondary_effect().chance();
|
||||||
|
if secondary_effect_chance == -1.0
|
||||||
|
|| self
|
||||||
|
.random()
|
||||||
|
.effect_chance(secondary_effect_chance, executing_move, target, hit_index)
|
||||||
|
{
|
||||||
|
script_hook!(on_secondary_effect, executing_move, executing_move, target, hit_index);
|
||||||
|
// TODO: on fail
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let mut damage = executing_move
|
||||||
|
.get_hit_from_raw_index(target_hit_stat + hit_index as usize)
|
||||||
|
.damage();
|
||||||
|
let current_health = target.read().current_health();
|
||||||
|
if damage > current_health {
|
||||||
|
damage = current_health;
|
||||||
|
executing_move
|
||||||
|
.get_hit_from_raw_index_mut(target_hit_stat + hit_index as usize)
|
||||||
|
.set_damage(damage);
|
||||||
|
}
|
||||||
|
if damage > 0 {
|
||||||
|
target.write().damage(damage, DamageSource::AttackDamage);
|
||||||
|
if !target.read().is_fainted() {
|
||||||
|
script_hook_on_lock!(on_incoming_hit, target, executing_move, target, hit_index);
|
||||||
|
} else {
|
||||||
|
script_hook!(on_opponent_faints, executing_move, executing_move, target, hit_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
if executing_move.use_move().has_secondary_effect() && !target.read().is_fainted() {
|
||||||
|
let mut prevent_secondary = false;
|
||||||
|
script_hook_on_lock!(
|
||||||
|
prevent_secondary_effect,
|
||||||
|
target,
|
||||||
|
executing_move,
|
||||||
|
target,
|
||||||
|
hit_index,
|
||||||
|
&mut prevent_secondary
|
||||||
|
);
|
||||||
|
if !prevent_secondary {
|
||||||
|
let secondary_effect_chance = executing_move.use_move().secondary_effect().chance();
|
||||||
|
if secondary_effect_chance == -1.0
|
||||||
|
|| self.random().effect_chance(
|
||||||
|
secondary_effect_chance,
|
||||||
|
executing_move,
|
||||||
|
target,
|
||||||
|
hit_index,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
script_hook!(
|
||||||
|
on_secondary_effect,
|
||||||
|
executing_move,
|
||||||
|
executing_move,
|
||||||
|
target,
|
||||||
|
hit_index
|
||||||
|
);
|
||||||
|
// TODO: on fail
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !executing_move.user().read().is_fainted() {
|
||||||
|
script_hook!(on_after_hits, executing_move, executing_move, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -37,8 +37,7 @@ impl BattleStatCalculator {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn calculate_boosted_stat(&self, pokemon: &Pokemon, stat: Statistic) -> u32 {
|
pub fn calculate_boosted_stat(&self, pokemon: &Pokemon, stat: Statistic) -> u32 {
|
||||||
(self.calculate_flat_stat(pokemon, stat) as f32
|
(self.calculate_flat_stat(pokemon, stat) as f32 * self.get_stat_boost_modifier(pokemon, stat)) as u32
|
||||||
* self.get_stat_boost_modifier(pokemon, stat)) as u32
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_health_stat(&self, pokemon: &Pokemon) -> u32 {
|
fn calculate_health_stat(&self, pokemon: &Pokemon) -> u32 {
|
||||||
|
|
|
@ -0,0 +1,275 @@
|
||||||
|
use crate::dynamic_data::models::executing_move::{ExecutingMove, HitData};
|
||||||
|
use crate::dynamic_data::models::pokemon::Pokemon;
|
||||||
|
use crate::dynamic_data::script_handling::ScriptSource;
|
||||||
|
use crate::static_data::{MoveCategory, Statistic};
|
||||||
|
use crate::{script_hook, script_hook_on_lock};
|
||||||
|
use parking_lot::RwLock;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub trait DamageLibrary: std::fmt::Debug {
|
||||||
|
fn has_randomness(&self) -> bool;
|
||||||
|
fn get_damage(
|
||||||
|
&self,
|
||||||
|
executing_move: &ExecutingMove,
|
||||||
|
target: &Arc<RwLock<Pokemon>>,
|
||||||
|
hit_number: u8,
|
||||||
|
hit_data: &HitData,
|
||||||
|
) -> u32;
|
||||||
|
|
||||||
|
fn get_base_power(
|
||||||
|
&self,
|
||||||
|
executing_move: &ExecutingMove,
|
||||||
|
target: &Arc<RwLock<Pokemon>>,
|
||||||
|
hit_number: u8,
|
||||||
|
hit_data: &HitData,
|
||||||
|
) -> u8;
|
||||||
|
|
||||||
|
fn get_stat_modifier(
|
||||||
|
&self,
|
||||||
|
executing_move: &ExecutingMove,
|
||||||
|
target: &Arc<RwLock<Pokemon>>,
|
||||||
|
hit_number: u8,
|
||||||
|
hit_data: &HitData,
|
||||||
|
) -> f32;
|
||||||
|
|
||||||
|
fn get_damage_modifier(
|
||||||
|
&self,
|
||||||
|
executing_move: &ExecutingMove,
|
||||||
|
target: &Arc<RwLock<Pokemon>>,
|
||||||
|
hit_number: u8,
|
||||||
|
hit_data: &HitData,
|
||||||
|
) -> f32;
|
||||||
|
}
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Gen7DamageLibrary {
|
||||||
|
has_randomness: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Gen7DamageLibrary {
|
||||||
|
pub fn new(has_randomness: bool) -> Self {
|
||||||
|
Self { has_randomness }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DamageLibrary for Gen7DamageLibrary {
|
||||||
|
fn has_randomness(&self) -> bool {
|
||||||
|
self.has_randomness
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_damage(
|
||||||
|
&self,
|
||||||
|
executing_move: &ExecutingMove,
|
||||||
|
target: &Arc<RwLock<Pokemon>>,
|
||||||
|
hit_number: u8,
|
||||||
|
hit_data: &HitData,
|
||||||
|
) -> u32 {
|
||||||
|
if executing_move.use_move().category() == MoveCategory::Status {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let level_modifier = ((2.0 * executing_move.user().read().level() as f32) / 5.0).floor() + 2.0;
|
||||||
|
let base_power = hit_data.base_power();
|
||||||
|
let stat_modifier = self.get_stat_modifier(executing_move, target, hit_number, hit_data);
|
||||||
|
let damage_modifier = self.get_damage_modifier(executing_move, target, hit_number, hit_data);
|
||||||
|
|
||||||
|
let mut float_damage = (level_modifier * base_power as f32).floor();
|
||||||
|
float_damage = (float_damage * stat_modifier).floor();
|
||||||
|
float_damage = (float_damage / 50.0).floor() + 2.0;
|
||||||
|
float_damage = (float_damage * damage_modifier).floor();
|
||||||
|
if executing_move.target_count() > 1 {
|
||||||
|
float_damage = (float_damage * 0.75).floor();
|
||||||
|
}
|
||||||
|
if hit_data.is_critical() {
|
||||||
|
let mut crit_modifier = 1.5;
|
||||||
|
script_hook!(
|
||||||
|
change_critical_modifier,
|
||||||
|
executing_move,
|
||||||
|
executing_move,
|
||||||
|
target,
|
||||||
|
hit_number,
|
||||||
|
&mut crit_modifier
|
||||||
|
);
|
||||||
|
float_damage = (float_damage * crit_modifier).floor();
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.has_randomness {
|
||||||
|
let battle = executing_move.user().read().get_battle().unwrap().upgrade().unwrap();
|
||||||
|
let random_percentage = 85 + battle.read().random().get_between(0, 16);
|
||||||
|
float_damage = (float_damage * (random_percentage as f32 / 100.0)).floor();
|
||||||
|
}
|
||||||
|
|
||||||
|
if executing_move.user().read().types().contains(&hit_data.move_type()) {
|
||||||
|
let mut stab_modifier = 1.5;
|
||||||
|
script_hook!(
|
||||||
|
change_stab_modifier,
|
||||||
|
executing_move,
|
||||||
|
executing_move,
|
||||||
|
target,
|
||||||
|
hit_number,
|
||||||
|
&mut stab_modifier
|
||||||
|
);
|
||||||
|
float_damage = (float_damage * stab_modifier).floor();
|
||||||
|
}
|
||||||
|
|
||||||
|
float_damage = (float_damage * hit_data.effectiveness()).floor();
|
||||||
|
let mut damage = if float_damage <= 0.0 {
|
||||||
|
if hit_data.effectiveness() == 0.0 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
} else if float_damage >= u32::MAX as f32 {
|
||||||
|
u32::MAX
|
||||||
|
} else {
|
||||||
|
float_damage as u32
|
||||||
|
};
|
||||||
|
|
||||||
|
script_hook!(
|
||||||
|
change_damage,
|
||||||
|
executing_move,
|
||||||
|
executing_move,
|
||||||
|
target,
|
||||||
|
hit_number,
|
||||||
|
&mut damage
|
||||||
|
);
|
||||||
|
script_hook_on_lock!(
|
||||||
|
change_incoming_damage,
|
||||||
|
target,
|
||||||
|
executing_move,
|
||||||
|
target,
|
||||||
|
hit_number,
|
||||||
|
&mut damage
|
||||||
|
);
|
||||||
|
damage
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_base_power(
|
||||||
|
&self,
|
||||||
|
executing_move: &ExecutingMove,
|
||||||
|
target: &Arc<RwLock<Pokemon>>,
|
||||||
|
hit_number: u8,
|
||||||
|
_hit_data: &HitData,
|
||||||
|
) -> u8 {
|
||||||
|
if executing_move.use_move().category() == MoveCategory::Status {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut base_power = executing_move.use_move().base_power();
|
||||||
|
script_hook!(
|
||||||
|
change_base_power,
|
||||||
|
executing_move,
|
||||||
|
executing_move,
|
||||||
|
target,
|
||||||
|
hit_number,
|
||||||
|
&mut base_power
|
||||||
|
);
|
||||||
|
base_power
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_stat_modifier(
|
||||||
|
&self,
|
||||||
|
executing_move: &ExecutingMove,
|
||||||
|
target: &Arc<RwLock<Pokemon>>,
|
||||||
|
hit_number: u8,
|
||||||
|
hit_data: &HitData,
|
||||||
|
) -> f32 {
|
||||||
|
let mut user = executing_move.user().clone();
|
||||||
|
script_hook!(
|
||||||
|
change_damage_stats_user,
|
||||||
|
executing_move,
|
||||||
|
executing_move,
|
||||||
|
target,
|
||||||
|
hit_number,
|
||||||
|
&mut user
|
||||||
|
);
|
||||||
|
let offensive_stat;
|
||||||
|
let defensive_stat;
|
||||||
|
if executing_move.use_move().category() == MoveCategory::Physical {
|
||||||
|
offensive_stat = Statistic::Attack;
|
||||||
|
defensive_stat = Statistic::Defense;
|
||||||
|
} else {
|
||||||
|
offensive_stat = Statistic::SpecialAttack;
|
||||||
|
defensive_stat = Statistic::SpecialDefense;
|
||||||
|
}
|
||||||
|
let mut bypass_defensive_stat_boost =
|
||||||
|
hit_data.is_critical() && target.read().stat_boost().get_stat(defensive_stat) > 0;
|
||||||
|
script_hook!(
|
||||||
|
bypass_defensive_stat_boost,
|
||||||
|
executing_move,
|
||||||
|
executing_move,
|
||||||
|
target,
|
||||||
|
hit_number,
|
||||||
|
&mut bypass_defensive_stat_boost
|
||||||
|
);
|
||||||
|
let mut bypass_offensive_stat_boost =
|
||||||
|
hit_data.is_critical() && user.read().stat_boost().get_stat(offensive_stat) > 0;
|
||||||
|
script_hook!(
|
||||||
|
bypass_offensive_stat_boost,
|
||||||
|
executing_move,
|
||||||
|
executing_move,
|
||||||
|
target,
|
||||||
|
hit_number,
|
||||||
|
&mut bypass_offensive_stat_boost
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut defensive_stat = if bypass_defensive_stat_boost {
|
||||||
|
target.read().flat_stats().get_stat(offensive_stat)
|
||||||
|
} else {
|
||||||
|
target.read().boosted_stats().get_stat(offensive_stat)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut offensive_stat = if bypass_offensive_stat_boost {
|
||||||
|
user.read().flat_stats().get_stat(offensive_stat)
|
||||||
|
} else {
|
||||||
|
user.read().boosted_stats().get_stat(offensive_stat)
|
||||||
|
};
|
||||||
|
|
||||||
|
script_hook!(
|
||||||
|
change_defensive_stat_value,
|
||||||
|
executing_move,
|
||||||
|
executing_move,
|
||||||
|
target,
|
||||||
|
hit_number,
|
||||||
|
&mut defensive_stat
|
||||||
|
);
|
||||||
|
script_hook!(
|
||||||
|
change_offensive_stat_value,
|
||||||
|
executing_move,
|
||||||
|
executing_move,
|
||||||
|
target,
|
||||||
|
hit_number,
|
||||||
|
&mut offensive_stat
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut stat_modifier = offensive_stat as f32 / defensive_stat as f32;
|
||||||
|
script_hook!(
|
||||||
|
change_damage_stat_modifier,
|
||||||
|
executing_move,
|
||||||
|
executing_move,
|
||||||
|
target,
|
||||||
|
hit_number,
|
||||||
|
&mut stat_modifier
|
||||||
|
);
|
||||||
|
|
||||||
|
stat_modifier
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_damage_modifier(
|
||||||
|
&self,
|
||||||
|
executing_move: &ExecutingMove,
|
||||||
|
target: &Arc<RwLock<Pokemon>>,
|
||||||
|
hit_number: u8,
|
||||||
|
_hit_data: &HitData,
|
||||||
|
) -> f32 {
|
||||||
|
let mut modifier = 1.0;
|
||||||
|
script_hook!(
|
||||||
|
change_damage_modifier,
|
||||||
|
executing_move,
|
||||||
|
executing_move,
|
||||||
|
target,
|
||||||
|
hit_number,
|
||||||
|
&mut modifier
|
||||||
|
);
|
||||||
|
modifier
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
use crate::dynamic_data::libraries::battle_stat_calculator::BattleStatCalculator;
|
use crate::dynamic_data::libraries::battle_stat_calculator::BattleStatCalculator;
|
||||||
|
use crate::dynamic_data::libraries::damage_library::DamageLibrary;
|
||||||
|
use crate::dynamic_data::libraries::misc_library::MiscLibrary;
|
||||||
use crate::dynamic_data::libraries::script_resolver::ScriptCategory;
|
use crate::dynamic_data::libraries::script_resolver::ScriptCategory;
|
||||||
use crate::dynamic_data::script_handling::item_script::ItemScript;
|
use crate::dynamic_data::script_handling::item_script::ItemScript;
|
||||||
use crate::dynamic_data::script_handling::script::Script;
|
use crate::dynamic_data::script_handling::script::Script;
|
||||||
|
@ -7,27 +9,30 @@ use crate::static_data::libraries::static_data::StaticData;
|
||||||
use crate::{PkmnResult, StringKey};
|
use crate::{PkmnResult, StringKey};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DynamicLibrary<'a> {
|
pub struct DynamicLibrary {
|
||||||
static_data: StaticData<'a>,
|
static_data: StaticData<'static>,
|
||||||
stat_calculator: BattleStatCalculator,
|
stat_calculator: BattleStatCalculator,
|
||||||
|
damage_calculator: Box<dyn DamageLibrary>,
|
||||||
|
misc_library: Box<dyn MiscLibrary<'static>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DynamicLibrary<'a> {
|
impl<'library> DynamicLibrary {
|
||||||
pub fn static_data(&self) -> &StaticData<'a> {
|
pub fn static_data(&self) -> &StaticData<'library> {
|
||||||
&self.static_data
|
&self.static_data
|
||||||
}
|
}
|
||||||
pub fn stat_calculator(&self) -> &BattleStatCalculator {
|
pub fn stat_calculator(&self) -> &BattleStatCalculator {
|
||||||
&self.stat_calculator
|
&self.stat_calculator
|
||||||
}
|
}
|
||||||
|
pub fn damage_calculator(&self) -> &Box<dyn DamageLibrary> {
|
||||||
pub fn load_script(
|
&self.damage_calculator
|
||||||
&self,
|
}
|
||||||
_category: ScriptCategory,
|
pub fn misc_library(&self) -> &Box<dyn MiscLibrary<'static>> {
|
||||||
_key: &StringKey,
|
&self.misc_library
|
||||||
) -> PkmnResult<Option<Box<dyn Script>>> {
|
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn load_script(&self, _category: ScriptCategory, _key: &StringKey) -> PkmnResult<Option<Box<dyn Script>>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
pub fn load_item_script(&self, _key: &Item) -> PkmnResult<Option<Box<dyn ItemScript>>> {
|
pub fn load_item_script(&self, _key: &Item) -> PkmnResult<Option<Box<dyn ItemScript>>> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
@ -36,13 +41,17 @@ impl<'a> DynamicLibrary<'a> {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod test {
|
pub mod test {
|
||||||
use crate::dynamic_data::libraries::battle_stat_calculator::BattleStatCalculator;
|
use crate::dynamic_data::libraries::battle_stat_calculator::BattleStatCalculator;
|
||||||
|
use crate::dynamic_data::libraries::damage_library::Gen7DamageLibrary;
|
||||||
use crate::dynamic_data::libraries::dynamic_library::DynamicLibrary;
|
use crate::dynamic_data::libraries::dynamic_library::DynamicLibrary;
|
||||||
|
use crate::dynamic_data::libraries::misc_library::Gen7MiscLibrary;
|
||||||
use crate::static_data::libraries::static_data;
|
use crate::static_data::libraries::static_data;
|
||||||
|
|
||||||
pub fn build<'a>() -> DynamicLibrary<'a> {
|
pub fn build<'library>() -> DynamicLibrary {
|
||||||
DynamicLibrary {
|
DynamicLibrary {
|
||||||
static_data: static_data::test::build(),
|
static_data: static_data::test::build(),
|
||||||
stat_calculator: BattleStatCalculator {},
|
stat_calculator: BattleStatCalculator {},
|
||||||
|
damage_calculator: Box::new(Gen7DamageLibrary::new(false)),
|
||||||
|
misc_library: Box::new(Gen7MiscLibrary::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,126 @@
|
||||||
|
use crate::dynamic_data::choices::{MoveChoice, SwitchChoice, TurnChoice};
|
||||||
|
use crate::dynamic_data::models::battle::Battle;
|
||||||
|
use crate::dynamic_data::models::executing_move::ExecutingMove;
|
||||||
|
use crate::dynamic_data::models::learned_move::{LearnedMove, MoveLearnMethod};
|
||||||
|
use crate::dynamic_data::models::pokemon::Pokemon;
|
||||||
|
use crate::dynamic_data::script_handling::ScriptSource;
|
||||||
|
use crate::static_data::{MoveCategory, MoveData, MoveTarget, SecondaryEffect};
|
||||||
|
use crate::{script_hook, StringKey};
|
||||||
|
use hashbrown::HashSet;
|
||||||
|
use parking_lot::RwLock;
|
||||||
|
use std::fmt::{Debug, Formatter};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub trait MiscLibrary<'library> {
|
||||||
|
fn is_critical(
|
||||||
|
&self,
|
||||||
|
battle: &Battle,
|
||||||
|
executing_move: &ExecutingMove,
|
||||||
|
target: &Arc<RwLock<Pokemon>>,
|
||||||
|
hit_number: u8,
|
||||||
|
) -> bool;
|
||||||
|
fn can_flee(&self, choice: &SwitchChoice) -> bool;
|
||||||
|
fn replacement_move<'func>(
|
||||||
|
&'func self,
|
||||||
|
user: &Arc<RwLock<Pokemon<'func, 'library>>>,
|
||||||
|
target_side: u8,
|
||||||
|
target_index: u8,
|
||||||
|
) -> TurnChoice<'func, 'library>;
|
||||||
|
// TODO: can evolve from level up?
|
||||||
|
// TODO: get time
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'library> Debug for dyn MiscLibrary<'library> {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_str("MiscLibrary")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Gen7MiscLibrary<'library> {
|
||||||
|
struggle_data: *const MoveData,
|
||||||
|
struggle_learned_move: Arc<RwLock<LearnedMove<'library>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'library> Gen7MiscLibrary<'library> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let struggle_data = Box::new(MoveData::new(
|
||||||
|
&StringKey::new("struggle"),
|
||||||
|
0,
|
||||||
|
MoveCategory::Physical,
|
||||||
|
50,
|
||||||
|
255,
|
||||||
|
10,
|
||||||
|
MoveTarget::Any,
|
||||||
|
0,
|
||||||
|
SecondaryEffect::new(-1.0, StringKey::new("struggle"), vec![]),
|
||||||
|
HashSet::new(),
|
||||||
|
));
|
||||||
|
let struggle_ptr = Box::into_raw(struggle_data);
|
||||||
|
let struggle_learned_move = Arc::new(RwLock::new(LearnedMove::new(
|
||||||
|
unsafe { &*struggle_ptr },
|
||||||
|
MoveLearnMethod::Unknown,
|
||||||
|
)));
|
||||||
|
Self {
|
||||||
|
struggle_data: struggle_ptr,
|
||||||
|
struggle_learned_move,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'library> Drop for Gen7MiscLibrary<'library> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
Box::from_raw(self.struggle_data as *mut MoveData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'library> MiscLibrary<'library> for Gen7MiscLibrary<'library> {
|
||||||
|
fn is_critical(
|
||||||
|
&self,
|
||||||
|
battle: &Battle,
|
||||||
|
executing_move: &ExecutingMove,
|
||||||
|
target: &Arc<RwLock<Pokemon>>,
|
||||||
|
hit_number: u8,
|
||||||
|
) -> bool {
|
||||||
|
if executing_move.use_move().category() == MoveCategory::Status {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let mut crit_stage = 0;
|
||||||
|
script_hook!(
|
||||||
|
change_critical_stage,
|
||||||
|
executing_move,
|
||||||
|
executing_move,
|
||||||
|
target,
|
||||||
|
hit_number,
|
||||||
|
&mut crit_stage
|
||||||
|
);
|
||||||
|
// Crit stage is an unsigned byte, so we only care about values of 0 or higher.
|
||||||
|
// For a critical stage of 3+ we always return true.
|
||||||
|
match crit_stage {
|
||||||
|
0 => battle.random().get_max(24) == 0,
|
||||||
|
1 => battle.random().get_max(8) == 0,
|
||||||
|
2 => battle.random().get_max(2) == 0,
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_flee(&self, _choice: &SwitchChoice) -> bool {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn replacement_move<'func>(
|
||||||
|
&'func self,
|
||||||
|
user: &Arc<RwLock<Pokemon<'func, 'library>>>,
|
||||||
|
target_side: u8,
|
||||||
|
target_index: u8,
|
||||||
|
) -> TurnChoice<'func, 'library> {
|
||||||
|
TurnChoice::Move(MoveChoice::new(
|
||||||
|
user.clone(),
|
||||||
|
self.struggle_learned_move.clone(),
|
||||||
|
target_side,
|
||||||
|
target_index,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
pub mod battle_stat_calculator;
|
pub mod battle_stat_calculator;
|
||||||
|
pub mod damage_library;
|
||||||
pub mod dynamic_library;
|
pub mod dynamic_library;
|
||||||
pub mod script_resolver;
|
pub mod script_resolver;
|
||||||
|
pub mod misc_library;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::dynamic_data::choices::TurnChoice;
|
use crate::dynamic_data::choices::TurnChoice;
|
||||||
use crate::dynamic_data::event_hooks::event_hook::EventHook;
|
use crate::dynamic_data::event_hooks::event_hook::{Event, EventHook};
|
||||||
use crate::dynamic_data::flow::choice_queue::ChoiceQueue;
|
use crate::dynamic_data::flow::choice_queue::ChoiceQueue;
|
||||||
use crate::dynamic_data::flow::target_resolver::is_valid_target;
|
use crate::dynamic_data::flow::target_resolver::is_valid_target;
|
||||||
use crate::dynamic_data::history::history_holder::HistoryHolder;
|
use crate::dynamic_data::history::history_holder::HistoryHolder;
|
||||||
|
@ -13,35 +13,36 @@ use crate::dynamic_data::script_handling::script::Script;
|
||||||
use crate::dynamic_data::script_handling::script_set::ScriptSet;
|
use crate::dynamic_data::script_handling::script_set::ScriptSet;
|
||||||
use crate::dynamic_data::script_handling::volatile_scripts::VolatileScripts;
|
use crate::dynamic_data::script_handling::volatile_scripts::VolatileScripts;
|
||||||
use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper};
|
use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper};
|
||||||
use crate::{PkmnResult, ScriptCategory, StringKey};
|
use crate::{script_hook, PkmnResult, ScriptCategory, StringKey};
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Battle<'a> {
|
pub struct Battle<'own, 'library> {
|
||||||
library: &'a DynamicLibrary<'a>,
|
library: &'own DynamicLibrary,
|
||||||
parties: Vec<BattleParty<'a>>,
|
parties: Vec<BattleParty<'own, 'library>>,
|
||||||
can_flee: bool,
|
can_flee: bool,
|
||||||
number_of_sides: u8,
|
number_of_sides: u8,
|
||||||
pokemon_per_side: u8,
|
pokemon_per_side: u8,
|
||||||
sides: Vec<BattleSide<'a>>,
|
sides: Vec<BattleSide<'own, 'library>>,
|
||||||
random: BattleRandom,
|
random: BattleRandom,
|
||||||
current_turn_queue: Option<ChoiceQueue>,
|
current_turn_queue: Option<Arc<RwLock<ChoiceQueue<'own, 'library>>>>,
|
||||||
has_ended: bool,
|
has_ended: bool,
|
||||||
result: BattleResult,
|
result: BattleResult,
|
||||||
event_hook: EventHook,
|
event_hook: EventHook,
|
||||||
history_holder: Box<HistoryHolder>,
|
history_holder: Box<HistoryHolder>,
|
||||||
current_turn: u32,
|
current_turn: u32,
|
||||||
volatile_scripts: Arc<RwLock<ScriptSet>>,
|
volatile_scripts: Arc<RwLock<ScriptSet>>,
|
||||||
last_turn_time: i64,
|
last_turn_time: chrono::Duration,
|
||||||
|
|
||||||
script_source_data: RwLock<ScriptSourceData>,
|
script_source_data: RwLock<ScriptSourceData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Battle<'a> {
|
impl<'own, 'library> Battle<'own, 'library> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
library: &'a DynamicLibrary<'a>,
|
library: &'own DynamicLibrary,
|
||||||
parties: Vec<BattleParty<'a>>,
|
parties: Vec<BattleParty<'own, 'library>>,
|
||||||
can_flee: bool,
|
can_flee: bool,
|
||||||
number_of_sides: u8,
|
number_of_sides: u8,
|
||||||
pokemon_per_side: u8,
|
pokemon_per_side: u8,
|
||||||
|
@ -68,21 +69,20 @@ impl<'a> Battle<'a> {
|
||||||
history_holder: Box::new(HistoryHolder {}),
|
history_holder: Box::new(HistoryHolder {}),
|
||||||
current_turn: 0,
|
current_turn: 0,
|
||||||
volatile_scripts: Default::default(),
|
volatile_scripts: Default::default(),
|
||||||
last_turn_time: 0,
|
last_turn_time: chrono::Duration::zero(),
|
||||||
script_source_data: Default::default(),
|
script_source_data: Default::default(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
for i in 0..number_of_sides {
|
for i in 0..number_of_sides {
|
||||||
battle.write().sides[i as usize] =
|
battle.write().sides[i as usize] = BattleSide::new(i, Arc::downgrade(&battle), pokemon_per_side);
|
||||||
BattleSide::new(i, Arc::downgrade(&battle), pokemon_per_side);
|
|
||||||
}
|
}
|
||||||
battle
|
battle
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn library(&self) -> &'a DynamicLibrary<'a> {
|
pub fn library(&self) -> &'own DynamicLibrary {
|
||||||
self.library
|
self.library
|
||||||
}
|
}
|
||||||
pub fn parties(&self) -> &Vec<BattleParty<'a>> {
|
pub fn parties(&self) -> &Vec<BattleParty<'own, 'library>> {
|
||||||
&self.parties
|
&self.parties
|
||||||
}
|
}
|
||||||
pub fn can_flee(&self) -> bool {
|
pub fn can_flee(&self) -> bool {
|
||||||
|
@ -94,10 +94,10 @@ impl<'a> Battle<'a> {
|
||||||
pub fn pokemon_per_side(&self) -> u8 {
|
pub fn pokemon_per_side(&self) -> u8 {
|
||||||
self.pokemon_per_side
|
self.pokemon_per_side
|
||||||
}
|
}
|
||||||
pub fn sides(&self) -> &Vec<BattleSide<'a>> {
|
pub fn sides(&self) -> &Vec<BattleSide<'own, 'library>> {
|
||||||
&self.sides
|
&self.sides
|
||||||
}
|
}
|
||||||
pub fn sides_mut(&mut self) -> &mut Vec<BattleSide<'a>> {
|
pub fn sides_mut(&mut self) -> &mut Vec<BattleSide<'own, 'library>> {
|
||||||
&mut self.sides
|
&mut self.sides
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,14 +119,14 @@ impl<'a> Battle<'a> {
|
||||||
pub fn current_turn(&self) -> u32 {
|
pub fn current_turn(&self) -> u32 {
|
||||||
self.current_turn
|
self.current_turn
|
||||||
}
|
}
|
||||||
pub fn last_turn_time(&self) -> i64 {
|
pub fn last_turn_time(&self) -> chrono::Duration {
|
||||||
self.last_turn_time
|
self.last_turn_time
|
||||||
}
|
}
|
||||||
pub fn current_turn_queue(&self) -> &Option<ChoiceQueue> {
|
pub fn current_turn_queue(&self) -> &Option<Arc<RwLock<ChoiceQueue<'own, 'library>>>> {
|
||||||
&self.current_turn_queue
|
&self.current_turn_queue
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_pokemon(&self, side: u8, index: u8) -> &Option<Arc<RwLock<Pokemon<'a>>>> {
|
pub fn get_pokemon(&self, side: u8, index: u8) -> &Option<Arc<RwLock<Pokemon<'own, 'library>>>> {
|
||||||
let side = self.sides.get(side as usize);
|
let side = self.sides.get(side as usize);
|
||||||
if side.is_none() {
|
if side.is_none() {
|
||||||
return &None;
|
return &None;
|
||||||
|
@ -183,34 +183,99 @@ impl<'a> Battle<'a> {
|
||||||
|
|
||||||
pub fn can_use(&self, choice: &TurnChoice) -> bool {
|
pub fn can_use(&self, choice: &TurnChoice) -> bool {
|
||||||
// If the user is not usable, we obviously can;t use the choice.
|
// If the user is not usable, we obviously can;t use the choice.
|
||||||
if !choice.user().is_usable() {
|
if !choice.user().read().is_usable() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if let TurnChoice::Move {
|
if let TurnChoice::Move(data) = choice {
|
||||||
used_move,
|
|
||||||
target_side,
|
|
||||||
target_index,
|
|
||||||
user,
|
|
||||||
} = choice
|
|
||||||
{
|
|
||||||
// TODO: Hook to change number of PP needed.
|
// TODO: Hook to change number of PP needed.
|
||||||
if used_move.remaining_pp() < 1 {
|
if data.used_move().read().remaining_pp() < 1 {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if !is_valid_target(
|
if !is_valid_target(
|
||||||
*target_side,
|
data.target_side(),
|
||||||
*target_index,
|
data.target_index(),
|
||||||
used_move.move_data().target(),
|
data.used_move().read().move_data().target(),
|
||||||
user,
|
choice.user().read().deref(),
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn try_set_choice(&mut self, choice: TurnChoice<'own, 'library>) -> PkmnResult<bool> {
|
||||||
|
if !self.can_use(&choice) {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
if !choice.user().read().is_on_battlefield() {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
let side = choice.user().read().get_battle_side_index();
|
||||||
|
if side.is_none() {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
self.sides[side.unwrap() as usize].set_choice(choice);
|
||||||
|
self.check_choices_set_and_run()?;
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_choices_set_and_run(&mut self) -> PkmnResult<()> {
|
||||||
|
for side in &self.sides {
|
||||||
|
if !side.all_choices_set() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
if !side.all_slots_filled() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let start_time = chrono::Utc::now();
|
||||||
|
let mut choices = Vec::with_capacity(self.number_of_sides as usize * self.pokemon_per_side as usize);
|
||||||
|
for side in &mut self.sides {
|
||||||
|
for choice in side.choices() {
|
||||||
|
if choice.is_none() {
|
||||||
|
panic!("Choice was none, but all choices were set? Logic error.");
|
||||||
|
}
|
||||||
|
let mut choice_guard = choice.as_ref().unwrap().write();
|
||||||
|
let c = choice_guard.deref();
|
||||||
|
if let TurnChoice::Move(data) = c {
|
||||||
|
let mut change_priority = data.priority();
|
||||||
|
script_hook!(change_priority, c, c, &mut change_priority);
|
||||||
|
if change_priority != data.priority() {
|
||||||
|
if let TurnChoice::Move(data) = choice_guard.deref_mut() {
|
||||||
|
*data.priority_mut() = change_priority;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut speed = choice_guard.speed();
|
||||||
|
let c = choice_guard.deref();
|
||||||
|
script_hook!(change_speed, c, c, &mut speed);
|
||||||
|
*choice_guard.speed_mut() = speed;
|
||||||
|
|
||||||
|
choice_guard.set_random_value(self.random.get() as u32);
|
||||||
|
choices.push(choice.as_ref().unwrap().clone());
|
||||||
|
}
|
||||||
|
side.reset_choices();
|
||||||
|
}
|
||||||
|
self.current_turn += 1;
|
||||||
|
|
||||||
|
choices.sort_unstable_by(|a, b| b.read().deref().cmp(a.read().deref()));
|
||||||
|
self.current_turn_queue = Some(Arc::new(RwLock::new(ChoiceQueue::new(choices))));
|
||||||
|
|
||||||
|
{
|
||||||
|
self.run_turn()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.current_turn_queue = None;
|
||||||
|
self.event_hook.trigger(Event::EndTurn);
|
||||||
|
let end_time = chrono::Utc::now();
|
||||||
|
let time = end_time - start_time;
|
||||||
|
self.last_turn_time = time;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> VolatileScripts<'a> for Battle<'a> {
|
impl<'own, 'library> VolatileScripts<'own> for Battle<'own, 'library> {
|
||||||
fn volatile_scripts(&self) -> &Arc<RwLock<ScriptSet>> {
|
fn volatile_scripts(&self) -> &Arc<RwLock<ScriptSet>> {
|
||||||
&self.volatile_scripts
|
&self.volatile_scripts
|
||||||
}
|
}
|
||||||
|
@ -220,7 +285,7 @@ impl<'a> VolatileScripts<'a> for Battle<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ScriptSource<'a> for Battle<'a> {
|
impl<'own, 'library> ScriptSource<'own> for Battle<'own, 'library> {
|
||||||
fn get_script_count(&self) -> usize {
|
fn get_script_count(&self) -> usize {
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use crate::dynamic_data::models::pokemon_party::PokemonParty;
|
use crate::dynamic_data::models::pokemon_party::PokemonParty;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BattleParty<'a> {
|
pub struct BattleParty<'own, 'library> {
|
||||||
party: &'a PokemonParty<'a>,
|
party: &'own PokemonParty<'own, 'library>,
|
||||||
responsible_indices: Vec<(u8, u8)>,
|
responsible_indices: Vec<(u8, u8)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> BattleParty<'a> {
|
impl<'own, 'library> BattleParty<'own, 'library> {
|
||||||
pub fn is_responsible_for_index(&self, side: u8, index: u8) -> bool {
|
pub fn is_responsible_for_index(&self, side: u8, index: u8) -> bool {
|
||||||
for responsible_index in &self.responsible_indices {
|
for responsible_index in &self.responsible_indices {
|
||||||
if responsible_index.0 == side && responsible_index.1 == index {
|
if responsible_index.0 == side && responsible_index.1 == index {
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
|
use crate::dynamic_data::models::executing_move::ExecutingMove;
|
||||||
|
use crate::dynamic_data::models::pokemon::Pokemon;
|
||||||
|
use crate::dynamic_data::script_handling::ScriptSource;
|
||||||
use crate::utils::random::Random;
|
use crate::utils::random::Random;
|
||||||
|
use crate::{script_hook, script_hook_on_lock};
|
||||||
|
use parking_lot::RwLock;
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
use std::sync::Mutex;
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct BattleRandom {
|
pub struct BattleRandom {
|
||||||
|
@ -27,6 +32,32 @@ impl BattleRandom {
|
||||||
pub fn get_between(&self, min: i32, max: i32) -> i32 {
|
pub fn get_between(&self, min: i32, max: i32) -> i32 {
|
||||||
return self.get_rng().lock().unwrap().get_between(min, max);
|
return self.get_rng().lock().unwrap().get_between(min, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn effect_chance(
|
||||||
|
&self,
|
||||||
|
mut chance: f32,
|
||||||
|
executing_move: &ExecutingMove,
|
||||||
|
target: &Arc<RwLock<Pokemon>>,
|
||||||
|
hit_number: u8,
|
||||||
|
) -> bool {
|
||||||
|
script_hook!(
|
||||||
|
change_effect_chance,
|
||||||
|
executing_move,
|
||||||
|
executing_move,
|
||||||
|
target,
|
||||||
|
hit_number,
|
||||||
|
&mut chance
|
||||||
|
);
|
||||||
|
script_hook_on_lock!(
|
||||||
|
change_incoming_effect_chance,
|
||||||
|
target,
|
||||||
|
executing_move,
|
||||||
|
target,
|
||||||
|
hit_number,
|
||||||
|
&mut chance
|
||||||
|
);
|
||||||
|
self.get_rng().lock().unwrap().get_float() < (chance / 100.0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for BattleRandom {
|
impl Debug for BattleRandom {
|
||||||
|
|
|
@ -13,22 +13,22 @@ use std::ops::Deref;
|
||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BattleSide<'a> {
|
pub struct BattleSide<'own, 'library> {
|
||||||
index: u8,
|
index: u8,
|
||||||
pokemon_per_side: u8,
|
pokemon_per_side: u8,
|
||||||
pokemon: Vec<Option<Arc<RwLock<Pokemon<'a>>>>>,
|
pokemon: Vec<Option<Arc<RwLock<Pokemon<'own, 'library>>>>>,
|
||||||
choices: Vec<Option<Arc<TurnChoice<'a>>>>,
|
choices: Vec<Option<Arc<RwLock<TurnChoice<'own, 'library>>>>>,
|
||||||
fillable_slots: Vec<bool>,
|
fillable_slots: Vec<bool>,
|
||||||
choices_set: u8,
|
choices_set: u8,
|
||||||
battle: Weak<RwLock<Battle<'a>>>,
|
battle: Weak<RwLock<Battle<'own, 'library>>>,
|
||||||
has_fled_battle: bool,
|
has_fled_battle: bool,
|
||||||
volatile_scripts: Arc<RwLock<ScriptSet>>,
|
volatile_scripts: Arc<RwLock<ScriptSet>>,
|
||||||
|
|
||||||
script_source_data: RwLock<ScriptSourceData>,
|
script_source_data: RwLock<ScriptSourceData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> BattleSide<'a> {
|
impl<'own, 'library> BattleSide<'own, 'library> {
|
||||||
pub fn new(index: u8, battle: Weak<RwLock<Battle<'a>>>, pokemon_per_side: u8) -> Self {
|
pub fn new(index: u8, battle: Weak<RwLock<Battle<'own, 'library>>>, pokemon_per_side: u8) -> Self {
|
||||||
let mut pokemon = Vec::with_capacity(pokemon_per_side as usize);
|
let mut pokemon = Vec::with_capacity(pokemon_per_side as usize);
|
||||||
let mut choices = Vec::with_capacity(pokemon_per_side as usize);
|
let mut choices = Vec::with_capacity(pokemon_per_side as usize);
|
||||||
let mut fillable_slots = Vec::with_capacity(pokemon_per_side as usize);
|
let mut fillable_slots = Vec::with_capacity(pokemon_per_side as usize);
|
||||||
|
@ -58,19 +58,23 @@ impl<'a> BattleSide<'a> {
|
||||||
pub fn pokemon_per_side(&self) -> u8 {
|
pub fn pokemon_per_side(&self) -> u8 {
|
||||||
self.pokemon_per_side
|
self.pokemon_per_side
|
||||||
}
|
}
|
||||||
pub fn pokemon(&self) -> &Vec<Option<Arc<RwLock<Pokemon<'a>>>>> {
|
pub fn pokemon(&self) -> &Vec<Option<Arc<RwLock<Pokemon<'own, 'library>>>>> {
|
||||||
&self.pokemon
|
&self.pokemon
|
||||||
}
|
}
|
||||||
pub fn choices(&self) -> &Vec<Option<Arc<TurnChoice<'a>>>> {
|
pub fn choices(&self) -> &Vec<Option<Arc<RwLock<TurnChoice<'own, 'library>>>>> {
|
||||||
&self.choices
|
&self.choices
|
||||||
}
|
}
|
||||||
|
pub fn choices_mut(&mut self) -> &mut Vec<Option<Arc<RwLock<TurnChoice<'own, 'library>>>>> {
|
||||||
|
&mut self.choices
|
||||||
|
}
|
||||||
|
|
||||||
pub fn fillable_slots(&self) -> &Vec<bool> {
|
pub fn fillable_slots(&self) -> &Vec<bool> {
|
||||||
&self.fillable_slots
|
&self.fillable_slots
|
||||||
}
|
}
|
||||||
pub fn choices_set(&self) -> u8 {
|
pub fn choices_set(&self) -> u8 {
|
||||||
self.choices_set
|
self.choices_set
|
||||||
}
|
}
|
||||||
pub fn battle(&self) -> &Weak<RwLock<Battle<'a>>> {
|
pub fn battle(&self) -> &Weak<RwLock<Battle<'own, 'library>>> {
|
||||||
&self.battle
|
&self.battle
|
||||||
}
|
}
|
||||||
pub fn has_fled_battle(&self) -> bool {
|
pub fn has_fled_battle(&self) -> bool {
|
||||||
|
@ -103,11 +107,11 @@ impl<'a> BattleSide<'a> {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_choice(&mut self, choice: TurnChoice<'a>) {
|
pub fn set_choice(&mut self, choice: TurnChoice<'own, 'library>) {
|
||||||
for (index, pokemon_slot) in self.pokemon.iter().enumerate() {
|
for (index, pokemon_slot) in self.pokemon.iter().enumerate() {
|
||||||
if let Some(pokemon) = pokemon_slot {
|
if let Some(pokemon) = pokemon_slot {
|
||||||
if pokemon.read().unique_identifier() == choice.user().unique_identifier() {
|
if std::ptr::eq(pokemon.data_ptr(), choice.user().data_ptr()) {
|
||||||
self.choices[index] = Some(Arc::new(choice));
|
self.choices[index] = Some(Arc::new(RwLock::new(choice)));
|
||||||
self.choices_set += 1;
|
self.choices_set += 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -115,11 +119,17 @@ impl<'a> BattleSide<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn reset_choices(&mut self) {
|
||||||
|
for i in 0..self.choices.len() {
|
||||||
|
self.choices[i] = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn force_clear_pokemon(&mut self, index: u8) {
|
pub fn force_clear_pokemon(&mut self, index: u8) {
|
||||||
self.pokemon[index as usize] = None;
|
self.pokemon[index as usize] = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_pokemon(&mut self, index: u8, pokemon: Option<Arc<RwLock<Pokemon<'a>>>>) {
|
pub fn set_pokemon(&mut self, index: u8, pokemon: Option<Arc<RwLock<Pokemon<'own, 'library>>>>) {
|
||||||
let old = &mut self.pokemon[index as usize];
|
let old = &mut self.pokemon[index as usize];
|
||||||
if let Some(old_pokemon) = old {
|
if let Some(old_pokemon) = old {
|
||||||
let mut p = old_pokemon.write();
|
let mut p = old_pokemon.write();
|
||||||
|
@ -163,7 +173,7 @@ impl<'a> BattleSide<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_pokemon_on_side(&self, pokemon: Arc<Pokemon<'a>>) -> bool {
|
pub fn is_pokemon_on_side(&self, pokemon: Arc<Pokemon<'own, 'library>>) -> bool {
|
||||||
for p in self.pokemon.iter().flatten() {
|
for p in self.pokemon.iter().flatten() {
|
||||||
if p.read().unique_identifier() == pokemon.unique_identifier() {
|
if p.read().unique_identifier() == pokemon.unique_identifier() {
|
||||||
return true;
|
return true;
|
||||||
|
@ -172,7 +182,7 @@ impl<'a> BattleSide<'a> {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mark_slot_as_unfillable(&mut self, pokemon: &Pokemon<'a>) {
|
pub fn mark_slot_as_unfillable(&mut self, pokemon: &Pokemon<'own, 'library>) {
|
||||||
for (i, slot) in self.pokemon.iter().enumerate() {
|
for (i, slot) in self.pokemon.iter().enumerate() {
|
||||||
if let Some(p) = slot {
|
if let Some(p) = slot {
|
||||||
if p.read().deref() as *const Pokemon == pokemon as *const Pokemon {
|
if p.read().deref() as *const Pokemon == pokemon as *const Pokemon {
|
||||||
|
@ -183,7 +193,7 @@ impl<'a> BattleSide<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_slot_unfillable(&self, pokemon: Arc<Pokemon<'a>>) -> bool {
|
pub fn is_slot_unfillable(&self, pokemon: Arc<Pokemon<'own, 'library>>) -> bool {
|
||||||
for (i, slot) in self.pokemon.iter().enumerate() {
|
for (i, slot) in self.pokemon.iter().enumerate() {
|
||||||
if let Some(p) = slot {
|
if let Some(p) = slot {
|
||||||
if p.read().unique_identifier() == pokemon.unique_identifier() {
|
if p.read().unique_identifier() == pokemon.unique_identifier() {
|
||||||
|
@ -263,7 +273,7 @@ impl<'a> BattleSide<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> VolatileScripts<'a> for BattleSide<'a> {
|
impl<'own, 'library> VolatileScripts<'own> for BattleSide<'own, 'library> {
|
||||||
fn volatile_scripts(&self) -> &Arc<RwLock<ScriptSet>> {
|
fn volatile_scripts(&self) -> &Arc<RwLock<ScriptSet>> {
|
||||||
&self.volatile_scripts
|
&self.volatile_scripts
|
||||||
}
|
}
|
||||||
|
@ -278,7 +288,7 @@ impl<'a> VolatileScripts<'a> for BattleSide<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ScriptSource<'a> for BattleSide<'a> {
|
impl<'own, 'library> ScriptSource<'own> for BattleSide<'own, 'library> {
|
||||||
fn get_script_count(&self) -> usize {
|
fn get_script_count(&self) -> usize {
|
||||||
self.battle.upgrade().unwrap().read().get_script_count() + 1
|
self.battle.upgrade().unwrap().read().get_script_count() + 1
|
||||||
}
|
}
|
||||||
|
@ -293,10 +303,6 @@ impl<'a> ScriptSource<'a> for BattleSide<'a> {
|
||||||
|
|
||||||
fn collect_scripts(&self, scripts: &mut Vec<ScriptWrapper>) {
|
fn collect_scripts(&self, scripts: &mut Vec<ScriptWrapper>) {
|
||||||
self.get_own_scripts(scripts);
|
self.get_own_scripts(scripts);
|
||||||
self.battle
|
self.battle.upgrade().unwrap().read().collect_scripts(scripts);
|
||||||
.upgrade()
|
|
||||||
.unwrap()
|
|
||||||
.read()
|
|
||||||
.collect_scripts(scripts);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::dynamic_data::flow::target_resolver::TargetList;
|
||||||
use crate::dynamic_data::models::learned_move::LearnedMove;
|
use crate::dynamic_data::models::learned_move::LearnedMove;
|
||||||
use crate::dynamic_data::models::pokemon::Pokemon;
|
use crate::dynamic_data::models::pokemon::Pokemon;
|
||||||
use crate::dynamic_data::script_handling::script::ScriptContainer;
|
use crate::dynamic_data::script_handling::script::ScriptContainer;
|
||||||
|
@ -5,9 +6,9 @@ use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, Scrip
|
||||||
use crate::static_data::MoveData;
|
use crate::static_data::MoveData;
|
||||||
use crate::{PkmnResult, PokemonError};
|
use crate::{PkmnResult, PokemonError};
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use std::ops::Deref;
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default, Debug)]
|
||||||
pub struct HitData {
|
pub struct HitData {
|
||||||
critical: bool,
|
critical: bool,
|
||||||
base_power: u8,
|
base_power: u8,
|
||||||
|
@ -57,24 +58,25 @@ impl HitData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ExecutingMove<'a, 'b> {
|
#[derive(Debug)]
|
||||||
|
pub struct ExecutingMove<'own, 'battle, 'library> {
|
||||||
number_of_hits: u8,
|
number_of_hits: u8,
|
||||||
hits: Vec<HitData>,
|
hits: Vec<HitData>,
|
||||||
user: &'a Pokemon<'b>,
|
user: Arc<RwLock<Pokemon<'battle, 'library>>>,
|
||||||
chosen_move: &'a LearnedMove<'a>,
|
chosen_move: Arc<RwLock<LearnedMove<'library>>>,
|
||||||
use_move: &'a MoveData,
|
use_move: &'own MoveData,
|
||||||
script: ScriptContainer,
|
script: ScriptContainer,
|
||||||
targets: Vec<Option<&'a Pokemon<'b>>>,
|
targets: &'own TargetList<'battle, 'library>,
|
||||||
script_source_data: RwLock<ScriptSourceData>,
|
script_source_data: RwLock<ScriptSourceData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> ExecutingMove<'a, 'b> {
|
impl<'own, 'battle, 'library> ExecutingMove<'own, 'battle, 'library> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
targets: Vec<Option<&'a Pokemon<'b>>>,
|
targets: &'own TargetList<'battle, 'library>,
|
||||||
number_of_hits: u8,
|
number_of_hits: u8,
|
||||||
user: &'a Pokemon<'b>,
|
user: Arc<RwLock<Pokemon<'battle, 'library>>>,
|
||||||
chosen_move: &'a LearnedMove,
|
chosen_move: Arc<RwLock<LearnedMove<'library>>>,
|
||||||
use_move: &'a MoveData,
|
use_move: &'own MoveData,
|
||||||
script: ScriptContainer,
|
script: ScriptContainer,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let total_hits = number_of_hits as usize * targets.len();
|
let total_hits = number_of_hits as usize * targets.len();
|
||||||
|
@ -99,23 +101,28 @@ impl<'a, 'b> ExecutingMove<'a, 'b> {
|
||||||
pub fn number_of_hits(&self) -> u8 {
|
pub fn number_of_hits(&self) -> u8 {
|
||||||
self.number_of_hits
|
self.number_of_hits
|
||||||
}
|
}
|
||||||
pub fn user(&self) -> &'a Pokemon<'b> {
|
pub fn user(&self) -> &Arc<RwLock<Pokemon<'battle, 'library>>> {
|
||||||
self.user
|
&self.user
|
||||||
}
|
}
|
||||||
pub fn chosen_move(&self) -> &'a LearnedMove {
|
pub fn chosen_move(&self) -> &Arc<RwLock<LearnedMove<'library>>> {
|
||||||
self.chosen_move
|
&self.chosen_move
|
||||||
}
|
}
|
||||||
pub fn use_move(&self) -> &'a MoveData {
|
|
||||||
|
pub fn use_move(&self) -> &'own MoveData {
|
||||||
self.use_move
|
self.use_move
|
||||||
}
|
}
|
||||||
pub fn script(&self) -> &ScriptContainer {
|
pub fn script(&self) -> &ScriptContainer {
|
||||||
&self.script
|
&self.script
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_hit_data(&self, for_target: &Pokemon<'b>, hit: u8) -> PkmnResult<&HitData> {
|
pub fn get_hit_data<'func>(
|
||||||
|
&'func self,
|
||||||
|
for_target: &'func Arc<RwLock<Pokemon<'battle, 'library>>>,
|
||||||
|
hit: u8,
|
||||||
|
) -> PkmnResult<&'func HitData> {
|
||||||
for (index, target) in self.targets.iter().enumerate() {
|
for (index, target) in self.targets.iter().enumerate() {
|
||||||
if let Some(target) = target {
|
if let Some(target) = target {
|
||||||
if std::ptr::eq(target.deref(), for_target) {
|
if std::ptr::eq(target.data_ptr(), for_target.data_ptr()) {
|
||||||
let i = index * self.number_of_hits as usize + hit as usize;
|
let i = index * self.number_of_hits as usize + hit as usize;
|
||||||
return Ok(&self.hits[i]);
|
return Ok(&self.hits[i]);
|
||||||
}
|
}
|
||||||
|
@ -124,29 +131,39 @@ impl<'a, 'b> ExecutingMove<'a, 'b> {
|
||||||
Err(PokemonError::InvalidTargetRequested)
|
Err(PokemonError::InvalidTargetRequested)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_target_slice(&self, for_target: &Pokemon<'b>) -> PkmnResult<&[HitData]> {
|
pub fn is_pokemon_target(&self, pokemon: &Arc<RwLock<Pokemon<'battle, 'library>>>) -> bool {
|
||||||
|
for target in self.targets.iter().flatten() {
|
||||||
|
if std::ptr::eq(target.data_ptr(), pokemon.data_ptr()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_index_of_target(
|
||||||
|
&self,
|
||||||
|
for_target: &Arc<RwLock<Pokemon<'battle, 'library>>>,
|
||||||
|
) -> PkmnResult<usize> {
|
||||||
for (index, target) in self.targets.iter().enumerate() {
|
for (index, target) in self.targets.iter().enumerate() {
|
||||||
if let Some(target) = target {
|
if let Some(target) = target {
|
||||||
if std::ptr::eq(target.deref(), for_target) {
|
if std::ptr::eq(target.data_ptr(), for_target.data_ptr()) {
|
||||||
let i = index * self.number_of_hits as usize;
|
let i = index * self.number_of_hits as usize;
|
||||||
return Ok(&self.hits[i..i + self.number_of_hits as usize]);
|
return Ok(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(PokemonError::InvalidTargetRequested)
|
Err(PokemonError::InvalidTargetRequested)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_pokemon_target(&self, pokemon: &Pokemon<'b>) -> bool {
|
pub(crate) fn get_hit_from_raw_index(&self, index: usize) -> &HitData {
|
||||||
for target in self.targets.iter().flatten() {
|
&self.hits[index]
|
||||||
if std::ptr::eq(target.deref(), pokemon) {
|
}
|
||||||
return true;
|
pub(crate) fn get_hit_from_raw_index_mut(&mut self, index: usize) -> &mut HitData {
|
||||||
}
|
&mut self.hits[index]
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> ScriptSource<'a> for ExecutingMove<'a, 'b> {
|
impl<'own, 'battle, 'library> ScriptSource<'own> for ExecutingMove<'own, 'battle, 'library> {
|
||||||
fn get_script_count(&self) -> usize {
|
fn get_script_count(&self) -> usize {
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
@ -161,6 +178,6 @@ impl<'a, 'b> ScriptSource<'a> for ExecutingMove<'a, 'b> {
|
||||||
|
|
||||||
fn collect_scripts(&self, scripts: &mut Vec<ScriptWrapper>) {
|
fn collect_scripts(&self, scripts: &mut Vec<ScriptWrapper>) {
|
||||||
self.get_own_scripts(scripts);
|
self.get_own_scripts(scripts);
|
||||||
self.user.get_own_scripts(scripts);
|
self.user.read().get_own_scripts(scripts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::static_data::MoveData;
|
use crate::static_data::MoveData;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct LearnedMove<'a> {
|
pub struct LearnedMove<'library> {
|
||||||
move_data: &'a MoveData,
|
move_data: &'library MoveData,
|
||||||
max_pp: u8,
|
max_pp: u8,
|
||||||
remaining_pp: u8,
|
remaining_pp: u8,
|
||||||
learn_method: MoveLearnMethod,
|
learn_method: MoveLearnMethod,
|
||||||
|
@ -37,4 +37,12 @@ impl<'a> LearnedMove<'a> {
|
||||||
pub fn learn_method(&self) -> MoveLearnMethod {
|
pub fn learn_method(&self) -> MoveLearnMethod {
|
||||||
self.learn_method
|
self.learn_method
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn try_use(&mut self, amount: u8) -> bool {
|
||||||
|
if amount > self.remaining_pp {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
self.remaining_pp -= amount;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,3 +8,4 @@ pub mod executing_move;
|
||||||
pub mod learned_move;
|
pub mod learned_move;
|
||||||
pub mod pokemon;
|
pub mod pokemon;
|
||||||
pub mod pokemon_party;
|
pub mod pokemon_party;
|
||||||
|
pub mod pokemon_builder;
|
||||||
|
|
|
@ -23,44 +23,47 @@ use parking_lot::RwLock;
|
||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct PokemonBattleData<'a> {
|
pub struct PokemonBattleData<'pokemon, 'library> {
|
||||||
battle: Weak<RwLock<Battle<'a>>>,
|
battle: Weak<RwLock<Battle<'pokemon, 'library>>>,
|
||||||
battle_side_index: u8,
|
battle_side_index: u8,
|
||||||
index: u8,
|
index: u8,
|
||||||
on_battle_field: bool,
|
on_battle_field: bool,
|
||||||
seen_opponents: Vec<Weak<RwLock<Pokemon<'a>>>>,
|
seen_opponents: Vec<Weak<RwLock<Pokemon<'pokemon, 'library>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PokemonBattleData<'a> {
|
impl<'pokemon, 'library> PokemonBattleData<'pokemon, 'library> {
|
||||||
pub fn battle(&'a mut self) -> &'a mut Weak<RwLock<Battle<'a>>> {
|
pub fn battle(&mut self) -> &mut Weak<RwLock<Battle<'pokemon, 'library>>> {
|
||||||
&mut self.battle
|
&mut self.battle
|
||||||
}
|
}
|
||||||
pub fn battle_side_index(&self) -> u8 {
|
pub fn battle_side_index(&self) -> u8 {
|
||||||
self.battle_side_index
|
self.battle_side_index
|
||||||
}
|
}
|
||||||
pub fn on_battle_field(&'a mut self) -> &mut bool {
|
pub fn on_battle_field(&mut self) -> &mut bool {
|
||||||
&mut self.on_battle_field
|
&mut self.on_battle_field
|
||||||
}
|
}
|
||||||
pub fn seen_opponents(&'a mut self) -> &'a mut Vec<Weak<RwLock<Pokemon<'a>>>> {
|
pub fn seen_opponents(&mut self) -> &mut Vec<Weak<RwLock<Pokemon<'pokemon, 'library>>>> {
|
||||||
&mut self.seen_opponents
|
&mut self.seen_opponents
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Pokemon<'a> {
|
pub struct Pokemon<'own, 'library>
|
||||||
library: &'a DynamicLibrary<'a>,
|
where
|
||||||
species: &'a Species<'a>,
|
'own: 'library,
|
||||||
form: &'a Form<'a>,
|
{
|
||||||
|
library: &'own DynamicLibrary,
|
||||||
|
species: &'own Species<'library>,
|
||||||
|
form: &'own Form<'library>,
|
||||||
|
|
||||||
display_species: Option<&'a Species<'a>>,
|
display_species: Option<&'own Species<'library>>,
|
||||||
display_form: Option<&'a Form<'a>>,
|
display_form: Option<&'own Form<'library>>,
|
||||||
|
|
||||||
level: LevelInt,
|
level: LevelInt,
|
||||||
experience: u32,
|
experience: u32,
|
||||||
unique_identifier: u32,
|
unique_identifier: u32,
|
||||||
gender: Gender,
|
gender: Gender,
|
||||||
coloring: u8,
|
coloring: u8,
|
||||||
held_item: Option<&'a Item>,
|
held_item: Option<&'own Item>,
|
||||||
current_health: u32,
|
current_health: u32,
|
||||||
|
|
||||||
weight: f32,
|
weight: f32,
|
||||||
|
@ -71,7 +74,7 @@ pub struct Pokemon<'a> {
|
||||||
boosted_stats: StatisticSet<u32>,
|
boosted_stats: StatisticSet<u32>,
|
||||||
individual_values: ClampedStatisticSet<u8, 0, 31>,
|
individual_values: ClampedStatisticSet<u8, 0, 31>,
|
||||||
effort_values: ClampedStatisticSet<u8, 0, 252>,
|
effort_values: ClampedStatisticSet<u8, 0, 252>,
|
||||||
nature: &'a Nature,
|
nature: &'own Nature,
|
||||||
|
|
||||||
nickname: Option<String>,
|
nickname: Option<String>,
|
||||||
|
|
||||||
|
@ -79,9 +82,9 @@ pub struct Pokemon<'a> {
|
||||||
is_ability_overridden: bool,
|
is_ability_overridden: bool,
|
||||||
override_ability: Option<Ability>,
|
override_ability: Option<Ability>,
|
||||||
|
|
||||||
battle_data: Option<PokemonBattleData<'a>>,
|
battle_data: Option<PokemonBattleData<'own, 'library>>,
|
||||||
|
|
||||||
moves: [Option<LearnedMove<'a>>; MAX_MOVES],
|
moves: [Option<LearnedMove<'library>>; MAX_MOVES],
|
||||||
allowed_experience: bool,
|
allowed_experience: bool,
|
||||||
|
|
||||||
types: Vec<u8>,
|
types: Vec<u8>,
|
||||||
|
@ -96,18 +99,18 @@ pub struct Pokemon<'a> {
|
||||||
script_source_data: RwLock<ScriptSourceData>,
|
script_source_data: RwLock<ScriptSourceData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Pokemon<'a> {
|
impl<'own, 'library> Pokemon<'own, 'library> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
library: &'a DynamicLibrary,
|
library: &'own DynamicLibrary,
|
||||||
species: &'a Species,
|
species: &'own Species,
|
||||||
form: &'a Form,
|
form: &'own Form,
|
||||||
ability: AbilityIndex,
|
ability: AbilityIndex,
|
||||||
level: LevelInt,
|
level: LevelInt,
|
||||||
unique_identifier: u32,
|
unique_identifier: u32,
|
||||||
gender: Gender,
|
gender: Gender,
|
||||||
coloring: u8,
|
coloring: u8,
|
||||||
nature: &StringKey,
|
nature: &StringKey,
|
||||||
) -> Pokemon<'a> {
|
) -> Self {
|
||||||
// Calculate experience from the level for the specified growth rate.
|
// Calculate experience from the level for the specified growth rate.
|
||||||
let experience = library
|
let experience = library
|
||||||
.static_data()
|
.static_data()
|
||||||
|
@ -121,7 +124,7 @@ impl<'a> Pokemon<'a> {
|
||||||
.natures()
|
.natures()
|
||||||
.get_nature(&nature)
|
.get_nature(&nature)
|
||||||
.expect("Unknown nature name was given.");
|
.expect("Unknown nature name was given.");
|
||||||
let mut pokemon = Pokemon {
|
let mut pokemon = Self {
|
||||||
library,
|
library,
|
||||||
species,
|
species,
|
||||||
form,
|
form,
|
||||||
|
@ -162,23 +165,23 @@ impl<'a> Pokemon<'a> {
|
||||||
pokemon
|
pokemon
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn library(&self) -> &'a DynamicLibrary<'a> {
|
pub fn library(&self) -> &'own DynamicLibrary {
|
||||||
self.library
|
self.library
|
||||||
}
|
}
|
||||||
pub fn species(&self) -> &'a Species<'a> {
|
pub fn species(&self) -> &'own Species<'library> {
|
||||||
self.species
|
self.species
|
||||||
}
|
}
|
||||||
pub fn form(&self) -> &'a Form<'a> {
|
pub fn form(&self) -> &'own Form<'library> {
|
||||||
self.form
|
self.form
|
||||||
}
|
}
|
||||||
pub fn display_species(&self) -> &'a Species<'a> {
|
pub fn display_species(&self) -> &'own Species<'library> {
|
||||||
if let Some(v) = self.display_species {
|
if let Some(v) = self.display_species {
|
||||||
v
|
v
|
||||||
} else {
|
} else {
|
||||||
self.species
|
self.species
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn display_form(&self) -> &'a Form<'a> {
|
pub fn display_form(&self) -> &'own Form<'library> {
|
||||||
if let Some(v) = self.display_form {
|
if let Some(v) = self.display_form {
|
||||||
v
|
v
|
||||||
} else {
|
} else {
|
||||||
|
@ -201,7 +204,7 @@ impl<'a> Pokemon<'a> {
|
||||||
pub fn coloring(&self) -> u8 {
|
pub fn coloring(&self) -> u8 {
|
||||||
self.coloring
|
self.coloring
|
||||||
}
|
}
|
||||||
pub fn held_item(&self) -> Option<&'a Item> {
|
pub fn held_item(&self) -> Option<&'own Item> {
|
||||||
self.held_item
|
self.held_item
|
||||||
}
|
}
|
||||||
pub fn has_held_item(&self, name: &StringKey) -> bool {
|
pub fn has_held_item(&self, name: &StringKey) -> bool {
|
||||||
|
@ -211,7 +214,7 @@ impl<'a> Pokemon<'a> {
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
pub fn set_held_item(&mut self, item: &'a Item) {
|
pub fn set_held_item(&mut self, item: &'own Item) {
|
||||||
self.held_item = Some(item);
|
self.held_item = Some(item);
|
||||||
}
|
}
|
||||||
pub fn remove_held_item(&mut self) {
|
pub fn remove_held_item(&mut self) {
|
||||||
|
@ -221,10 +224,7 @@ impl<'a> Pokemon<'a> {
|
||||||
if self.held_item.is_none() {
|
if self.held_item.is_none() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let script = self
|
let script = self.library.load_item_script(self.held_item.unwrap()).unwrap();
|
||||||
.library
|
|
||||||
.load_item_script(self.held_item.unwrap())
|
|
||||||
.unwrap();
|
|
||||||
if script.is_none() {
|
if script.is_none() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -276,7 +276,7 @@ impl<'a> Pokemon<'a> {
|
||||||
&self.effort_values
|
&self.effort_values
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_battle(&self) -> Option<&Weak<RwLock<Battle<'a>>>> {
|
pub fn get_battle(&self) -> Option<&Weak<RwLock<Battle<'own, 'library>>>> {
|
||||||
if let Some(data) = &self.battle_data {
|
if let Some(data) = &self.battle_data {
|
||||||
Some(&data.battle)
|
Some(&data.battle)
|
||||||
} else {
|
} else {
|
||||||
|
@ -305,7 +305,7 @@ impl<'a> Pokemon<'a> {
|
||||||
&self.ability_script
|
&self.ability_script
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn seen_opponents(&self) -> Option<&Vec<Weak<RwLock<Pokemon<'a>>>>> {
|
pub fn seen_opponents(&self) -> Option<&Vec<Weak<RwLock<Pokemon<'own, 'library>>>>> {
|
||||||
if let Some(data) = &self.battle_data {
|
if let Some(data) = &self.battle_data {
|
||||||
Some(&data.seen_opponents)
|
Some(&data.seen_opponents)
|
||||||
} else {
|
} else {
|
||||||
|
@ -316,7 +316,7 @@ impl<'a> Pokemon<'a> {
|
||||||
self.allowed_experience
|
self.allowed_experience
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn nature(&self) -> &'a Nature {
|
pub fn nature(&self) -> &'own Nature {
|
||||||
self.nature
|
self.nature
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,7 +328,7 @@ impl<'a> Pokemon<'a> {
|
||||||
self.boosted_stats = self.library.stat_calculator().calculate_boosted_stats(self);
|
self.boosted_stats = self.library.stat_calculator().calculate_boosted_stats(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn change_species(&mut self, species: &'a Species, form: &'a Form) {
|
pub fn change_species(&mut self, species: &'own Species, form: &'own Form) {
|
||||||
self.species = species;
|
self.species = species;
|
||||||
self.form = form;
|
self.form = form;
|
||||||
|
|
||||||
|
@ -368,7 +368,7 @@ impl<'a> Pokemon<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn change_form(&mut self, form: &'a Form) {
|
pub fn change_form(&mut self, form: &'own Form) {
|
||||||
if std::ptr::eq(self.form, form) {
|
if std::ptr::eq(self.form, form) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -409,10 +409,10 @@ impl<'a> Pokemon<'a> {
|
||||||
|
|
||||||
if let Some(battle_data) = &self.battle_data {
|
if let Some(battle_data) = &self.battle_data {
|
||||||
if let Some(battle) = battle_data.battle.upgrade() {
|
if let Some(battle) = battle_data.battle.upgrade() {
|
||||||
battle.read().event_hook().trigger(Event::FormChange {
|
battle
|
||||||
pokemon: self,
|
.read()
|
||||||
form,
|
.event_hook()
|
||||||
})
|
.trigger(Event::FormChange { pokemon: self, form })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -425,7 +425,7 @@ impl<'a> Pokemon<'a> {
|
||||||
self.current_health == 0
|
self.current_health == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_battle_data(&mut self, battle: Weak<RwLock<Battle<'a>>>, battle_side_index: u8) {
|
pub fn set_battle_data(&mut self, battle: Weak<RwLock<Battle<'own, 'library>>>, battle_side_index: u8) {
|
||||||
if let Some(battle_data) = &mut self.battle_data {
|
if let Some(battle_data) = &mut self.battle_data {
|
||||||
battle_data.battle = battle;
|
battle_data.battle = battle;
|
||||||
battle_data.battle_side_index = battle_side_index;
|
battle_data.battle_side_index = battle_side_index;
|
||||||
|
@ -465,7 +465,7 @@ impl<'a> Pokemon<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mark_opponent_as_seen(&mut self, pokemon: Weak<RwLock<Pokemon<'a>>>) {
|
pub fn mark_opponent_as_seen(&mut self, pokemon: Weak<RwLock<Pokemon<'own, 'library>>>) {
|
||||||
if let Some(battle_data) = &mut self.battle_data {
|
if let Some(battle_data) = &mut self.battle_data {
|
||||||
for seen_opponent in &battle_data.seen_opponents {
|
for seen_opponent in &battle_data.seen_opponents {
|
||||||
if seen_opponent.ptr_eq(&pokemon) {
|
if seen_opponent.ptr_eq(&pokemon) {
|
||||||
|
@ -493,14 +493,7 @@ impl<'a> Pokemon<'a> {
|
||||||
new_health,
|
new_health,
|
||||||
});
|
});
|
||||||
// TODO: register history
|
// TODO: register history
|
||||||
script_hook!(
|
script_hook!(on_damage, self, self, source, self.current_health, new_health);
|
||||||
on_damage,
|
|
||||||
self,
|
|
||||||
self,
|
|
||||||
source,
|
|
||||||
self.current_health,
|
|
||||||
new_health
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.current_health = new_health;
|
self.current_health = new_health;
|
||||||
|
@ -512,10 +505,7 @@ impl<'a> Pokemon<'a> {
|
||||||
pub fn on_faint(&self, source: DamageSource) {
|
pub fn on_faint(&self, source: DamageSource) {
|
||||||
if let Some(battle_data) = &self.battle_data {
|
if let Some(battle_data) = &self.battle_data {
|
||||||
if let Some(battle) = battle_data.battle.upgrade() {
|
if let Some(battle) = battle_data.battle.upgrade() {
|
||||||
battle
|
battle.read().event_hook().trigger(Event::Faint { pokemon: self });
|
||||||
.read()
|
|
||||||
.event_hook()
|
|
||||||
.trigger(Event::Faint { pokemon: self });
|
|
||||||
script_hook!(on_faint, self, self, source);
|
script_hook!(on_faint, self, self, source);
|
||||||
script_hook!(on_remove, self,);
|
script_hook!(on_remove, self,);
|
||||||
}
|
}
|
||||||
|
@ -536,13 +526,12 @@ impl<'a> Pokemon<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ScriptSource<'a> for Pokemon<'a> {
|
impl<'own, 'library> ScriptSource<'own> for Pokemon<'own, 'library> {
|
||||||
fn get_script_count(&self) -> usize {
|
fn get_script_count(&self) -> usize {
|
||||||
let mut c = 3;
|
let mut c = 3;
|
||||||
if let Some(battle_data) = &self.battle_data {
|
if let Some(battle_data) = &self.battle_data {
|
||||||
if let Some(battle) = battle_data.battle.upgrade() {
|
if let Some(battle) = battle_data.battle.upgrade() {
|
||||||
c += battle.read().sides()[battle_data.battle_side_index as usize]
|
c += battle.read().sides()[battle_data.battle_side_index as usize].get_script_count();
|
||||||
.get_script_count();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c
|
c
|
||||||
|
@ -563,14 +552,13 @@ impl<'a> ScriptSource<'a> for Pokemon<'a> {
|
||||||
self.get_own_scripts(scripts);
|
self.get_own_scripts(scripts);
|
||||||
if let Some(battle_data) = &self.battle_data {
|
if let Some(battle_data) = &self.battle_data {
|
||||||
if let Some(battle) = battle_data.battle.upgrade() {
|
if let Some(battle) = battle_data.battle.upgrade() {
|
||||||
battle.read().sides()[battle_data.battle_side_index as usize]
|
battle.read().sides()[battle_data.battle_side_index as usize].collect_scripts(scripts);
|
||||||
.collect_scripts(scripts);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> VolatileScripts<'a> for Pokemon<'a> {
|
impl<'own, 'library> VolatileScripts<'own> for Pokemon<'own, 'library> {
|
||||||
fn volatile_scripts(&self) -> &Arc<RwLock<ScriptSet>> {
|
fn volatile_scripts(&self) -> &Arc<RwLock<ScriptSet>> {
|
||||||
&self.volatile
|
&self.volatile
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
use crate::defines::LevelInt;
|
||||||
|
use crate::dynamic_data::libraries::dynamic_library::DynamicLibrary;
|
||||||
|
use crate::dynamic_data::models::pokemon::Pokemon;
|
||||||
|
use crate::static_data::{AbilityIndex, DataLibrary, Gender};
|
||||||
|
use crate::StringKey;
|
||||||
|
|
||||||
|
pub struct PokemonBuilder<'own> {
|
||||||
|
library: &'own DynamicLibrary,
|
||||||
|
species: StringKey,
|
||||||
|
level: LevelInt,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'own> PokemonBuilder<'own> {
|
||||||
|
pub fn new(library: &'own DynamicLibrary, species: StringKey, level: LevelInt) -> Self {
|
||||||
|
Self {
|
||||||
|
library,
|
||||||
|
species,
|
||||||
|
level,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build<'func>(self) -> Pokemon<'own, 'own> {
|
||||||
|
let species = self.library.static_data().species().get(&self.species).unwrap();
|
||||||
|
let form = species.get_default_form();
|
||||||
|
Pokemon::new(
|
||||||
|
self.library,
|
||||||
|
species,
|
||||||
|
form,
|
||||||
|
AbilityIndex {
|
||||||
|
hidden: false,
|
||||||
|
index: 0,
|
||||||
|
},
|
||||||
|
self.level,
|
||||||
|
0,
|
||||||
|
Gender::Male,
|
||||||
|
0,
|
||||||
|
&"test_nature".into(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,11 +2,11 @@ use crate::dynamic_data::models::pokemon::Pokemon;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct PokemonParty<'a> {
|
pub struct PokemonParty<'pokemon, 'library> {
|
||||||
pokemon: Vec<Option<Arc<RwLock<Pokemon<'a>>>>>,
|
pokemon: Vec<Option<Arc<RwLock<Pokemon<'pokemon, 'library>>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PokemonParty<'a> {
|
impl<'own, 'library> PokemonParty<'own, 'library> {
|
||||||
pub fn new(size: usize) -> Self {
|
pub fn new(size: usize) -> Self {
|
||||||
let mut pokemon = Vec::with_capacity(size);
|
let mut pokemon = Vec::with_capacity(size);
|
||||||
for _i in 0..size {
|
for _i in 0..size {
|
||||||
|
@ -15,7 +15,7 @@ impl<'a> PokemonParty<'a> {
|
||||||
Self { pokemon }
|
Self { pokemon }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn at(&self, index: usize) -> &Option<Arc<RwLock<Pokemon<'a>>>> {
|
pub fn at(&self, index: usize) -> &Option<Arc<RwLock<Pokemon<'own, 'library>>>> {
|
||||||
let opt = self.pokemon.get(index);
|
let opt = self.pokemon.get(index);
|
||||||
if let Some(v) = opt {
|
if let Some(v) = opt {
|
||||||
v
|
v
|
||||||
|
@ -31,8 +31,8 @@ impl<'a> PokemonParty<'a> {
|
||||||
pub fn swap_into(
|
pub fn swap_into(
|
||||||
&mut self,
|
&mut self,
|
||||||
index: usize,
|
index: usize,
|
||||||
pokemon: Option<Arc<RwLock<Pokemon<'a>>>>,
|
pokemon: Option<Arc<RwLock<Pokemon<'own, 'library>>>>,
|
||||||
) -> Option<Arc<RwLock<Pokemon<'a>>>> {
|
) -> Option<Arc<RwLock<Pokemon<'own, 'library>>>> {
|
||||||
if index >= self.pokemon.len() {
|
if index >= self.pokemon.len() {
|
||||||
return pokemon;
|
return pokemon;
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ impl<'a> PokemonParty<'a> {
|
||||||
self.pokemon.len()
|
self.pokemon.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pokemon(&self) -> &Vec<Option<Arc<RwLock<Pokemon<'a>>>>> {
|
pub fn pokemon(&self) -> &Vec<Option<Arc<RwLock<Pokemon<'own, 'library>>>>> {
|
||||||
&self.pokemon
|
&self.pokemon
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,52 @@ macro_rules! script_hook {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! script_hook_on_lock {
|
||||||
|
($hook_name: ident, $source: ident, $($parameters: expr),*) => {
|
||||||
|
let mut aggregator = $source.read().get_script_iterator();
|
||||||
|
while let Some(script) = aggregator.get_next() {
|
||||||
|
let lock = &mut script.get();
|
||||||
|
let script = lock.as_mut().unwrap();
|
||||||
|
if script.is_suppressed() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
script.$hook_name($($parameters),*);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! run_scripts {
|
||||||
|
($hook_name: ident, $source: ident, $($parameters: expr),*) => {
|
||||||
|
for script in $source {
|
||||||
|
match script {
|
||||||
|
ScriptWrapper::Script(s) => {
|
||||||
|
if let Some(s) = s.upgrade() {
|
||||||
|
if let Some(s) = s.write().deref_mut() {
|
||||||
|
if !s.is_suppressed() {
|
||||||
|
s.$hook_name($($parameters),*);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ScriptWrapper::Set(s) => {
|
||||||
|
if let Some(s) = s.upgrade() {
|
||||||
|
for s in s.read().get_underlying() {
|
||||||
|
let mut s = s.1.get();
|
||||||
|
if let Some(s) = s.deref_mut() {
|
||||||
|
if !s.is_suppressed() {
|
||||||
|
s.$hook_name($($parameters),*);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct ScriptSourceData {
|
pub struct ScriptSourceData {
|
||||||
is_initialized: bool,
|
is_initialized: bool,
|
||||||
|
@ -310,25 +356,11 @@ mod tests {
|
||||||
let scripts = vec![ScriptWrapper::from(&set)];
|
let scripts = vec![ScriptWrapper::from(&set)];
|
||||||
let mut aggregator = ScriptAggregator::new(&scripts as *const Vec<ScriptWrapper>);
|
let mut aggregator = ScriptAggregator::new(&scripts as *const Vec<ScriptWrapper>);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
aggregator
|
aggregator.get_next().unwrap().get().as_mut().unwrap().name().str(),
|
||||||
.get_next()
|
|
||||||
.unwrap()
|
|
||||||
.get()
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.name()
|
|
||||||
.str(),
|
|
||||||
"test_a"
|
"test_a"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
aggregator
|
aggregator.get_next().unwrap().get().as_mut().unwrap().name().str(),
|
||||||
.get_next()
|
|
||||||
.unwrap()
|
|
||||||
.get()
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.name()
|
|
||||||
.str(),
|
|
||||||
"test_b"
|
"test_b"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -352,14 +384,7 @@ mod tests {
|
||||||
let scripts = vec![ScriptWrapper::from(&set)];
|
let scripts = vec![ScriptWrapper::from(&set)];
|
||||||
let mut aggregator = ScriptAggregator::new(&scripts as *const Vec<ScriptWrapper>);
|
let mut aggregator = ScriptAggregator::new(&scripts as *const Vec<ScriptWrapper>);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
aggregator
|
aggregator.get_next().unwrap().get().as_mut().unwrap().name().str(),
|
||||||
.get_next()
|
|
||||||
.unwrap()
|
|
||||||
.get()
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.name()
|
|
||||||
.str(),
|
|
||||||
"test_a"
|
"test_a"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -368,14 +393,7 @@ mod tests {
|
||||||
drop(mut_set);
|
drop(mut_set);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
aggregator
|
aggregator.get_next().unwrap().get().as_mut().unwrap().name().str(),
|
||||||
.get_next()
|
|
||||||
.unwrap()
|
|
||||||
.get()
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.name()
|
|
||||||
.str(),
|
|
||||||
"test_c"
|
"test_c"
|
||||||
);
|
);
|
||||||
assert!(aggregator.get_next().is_none());
|
assert!(aggregator.get_next().is_none());
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::dynamic_data::choices::TurnChoice;
|
use crate::dynamic_data::choices::{MoveChoice, TurnChoice};
|
||||||
use crate::dynamic_data::models::battle::Battle;
|
use crate::dynamic_data::models::battle::Battle;
|
||||||
use crate::dynamic_data::models::damage_source::DamageSource;
|
use crate::dynamic_data::models::damage_source::DamageSource;
|
||||||
use crate::dynamic_data::models::executing_move::ExecutingMove;
|
use crate::dynamic_data::models::executing_move::ExecutingMove;
|
||||||
|
@ -27,26 +27,27 @@ pub trait Script {
|
||||||
fn on_before_turn(&mut self, _choice: &TurnChoice) {}
|
fn on_before_turn(&mut self, _choice: &TurnChoice) {}
|
||||||
fn change_speed(&mut self, _choice: &TurnChoice, _speed: &mut u32) {}
|
fn change_speed(&mut self, _choice: &TurnChoice, _speed: &mut u32) {}
|
||||||
fn change_priority(&mut self, _choice: &TurnChoice, _priority: &mut i8) {}
|
fn change_priority(&mut self, _choice: &TurnChoice, _priority: &mut i8) {}
|
||||||
fn change_move(&mut self, _choice: &TurnChoice, _move_name: &mut StringKey) {}
|
fn change_move(&mut self, _choice: &MoveChoice, _move_name: &mut StringKey) {}
|
||||||
fn change_number_of_hits(&mut self, _choice: &TurnChoice, _number_of_hits: &mut u8) {}
|
fn change_number_of_hits(&mut self, _choice: &MoveChoice, _number_of_hits: &mut u8) {}
|
||||||
fn prevent_move(&mut self, _move: &ExecutingMove, _prevent: &mut bool) {}
|
fn prevent_move(&mut self, _move: &ExecutingMove, _prevent: &mut bool) {}
|
||||||
fn fail_move(&mut self, _move: &ExecutingMove, _fail: &mut bool) {}
|
fn fail_move(&mut self, _move: &ExecutingMove, _fail: &mut bool) {}
|
||||||
fn stop_before_move(&mut self, _move: &ExecutingMove, _stop: &mut bool) {}
|
fn stop_before_move(&mut self, _move: &ExecutingMove, _stop: &mut bool) {}
|
||||||
fn on_before_move(&mut self, _move: &ExecutingMove) {}
|
fn on_before_move(&mut self, _move: &ExecutingMove) {}
|
||||||
fn fail_incoming_move(&mut self, _move: &ExecutingMove, _target: &Pokemon, _fail: &mut bool) {}
|
fn fail_incoming_move(&mut self, _move: &ExecutingMove, _target: &Arc<RwLock<Pokemon>>, _fail: &mut bool) {}
|
||||||
fn is_invulnerable(
|
fn is_invulnerable(&mut self, _move: &ExecutingMove, _target: &Arc<RwLock<Pokemon>>, _invulnerable: &mut bool) {}
|
||||||
|
fn on_move_miss(&mut self, _move: &ExecutingMove, _target: &Arc<RwLock<Pokemon>>) {}
|
||||||
|
fn change_move_type(
|
||||||
&mut self,
|
&mut self,
|
||||||
_move: &ExecutingMove,
|
_move: &ExecutingMove,
|
||||||
_target: &Pokemon,
|
_target: &Arc<RwLock<Pokemon>>,
|
||||||
_invulnerable: &mut bool,
|
_hit: u8,
|
||||||
|
_move_type: &mut u8,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
fn on_move_miss(&mut self, _move: &ExecutingMove, _target: &Pokemon) {}
|
|
||||||
fn change_move_type(&mut self, _move: &ExecutingMove, _target: &Pokemon, _move_type: &mut u8) {}
|
|
||||||
fn change_effectiveness(
|
fn change_effectiveness(
|
||||||
&mut self,
|
&mut self,
|
||||||
_move: &ExecutingMove,
|
_move: &ExecutingMove,
|
||||||
_target: &Pokemon,
|
_target: &Arc<RwLock<Pokemon>>,
|
||||||
_hit: u8,
|
_hit: u8,
|
||||||
_effectiveness: &mut f32,
|
_effectiveness: &mut f32,
|
||||||
) {
|
) {
|
||||||
|
@ -54,7 +55,7 @@ pub trait Script {
|
||||||
fn block_critical(
|
fn block_critical(
|
||||||
&mut self,
|
&mut self,
|
||||||
_move: &ExecutingMove,
|
_move: &ExecutingMove,
|
||||||
_target: &Pokemon,
|
_target: &Arc<RwLock<Pokemon>>,
|
||||||
_hit: u8,
|
_hit: u8,
|
||||||
_block_critical: &mut bool,
|
_block_critical: &mut bool,
|
||||||
) {
|
) {
|
||||||
|
@ -62,7 +63,7 @@ pub trait Script {
|
||||||
fn block_incoming_critical(
|
fn block_incoming_critical(
|
||||||
&mut self,
|
&mut self,
|
||||||
_move: &ExecutingMove,
|
_move: &ExecutingMove,
|
||||||
_target: &Pokemon,
|
_target: &Arc<RwLock<Pokemon>>,
|
||||||
_hit: u8,
|
_hit: u8,
|
||||||
_block_critical: &mut bool,
|
_block_critical: &mut bool,
|
||||||
) {
|
) {
|
||||||
|
@ -70,7 +71,7 @@ pub trait Script {
|
||||||
fn change_critical_stage(
|
fn change_critical_stage(
|
||||||
&mut self,
|
&mut self,
|
||||||
_move: &ExecutingMove,
|
_move: &ExecutingMove,
|
||||||
_target: &Pokemon,
|
_target: &Arc<RwLock<Pokemon>>,
|
||||||
_hit: u8,
|
_hit: u8,
|
||||||
_stage: &mut u8,
|
_stage: &mut u8,
|
||||||
) {
|
) {
|
||||||
|
@ -78,7 +79,7 @@ pub trait Script {
|
||||||
fn change_critical_modifier(
|
fn change_critical_modifier(
|
||||||
&mut self,
|
&mut self,
|
||||||
_move: &ExecutingMove,
|
_move: &ExecutingMove,
|
||||||
_target: &Pokemon,
|
_target: &Arc<RwLock<Pokemon>>,
|
||||||
_hit: u8,
|
_hit: u8,
|
||||||
_modifier: &mut f32,
|
_modifier: &mut f32,
|
||||||
) {
|
) {
|
||||||
|
@ -86,7 +87,7 @@ pub trait Script {
|
||||||
fn change_stab_modifier(
|
fn change_stab_modifier(
|
||||||
&mut self,
|
&mut self,
|
||||||
_move: &ExecutingMove,
|
_move: &ExecutingMove,
|
||||||
_target: &Pokemon,
|
_target: &Arc<RwLock<Pokemon>>,
|
||||||
_hit: u8,
|
_hit: u8,
|
||||||
_modifier: &mut f32,
|
_modifier: &mut f32,
|
||||||
) {
|
) {
|
||||||
|
@ -95,7 +96,7 @@ pub trait Script {
|
||||||
fn change_base_power(
|
fn change_base_power(
|
||||||
&mut self,
|
&mut self,
|
||||||
_move: &ExecutingMove,
|
_move: &ExecutingMove,
|
||||||
_target: &Pokemon,
|
_target: &Arc<RwLock<Pokemon>>,
|
||||||
_hit: u8,
|
_hit: u8,
|
||||||
_base_power: &mut u8,
|
_base_power: &mut u8,
|
||||||
) {
|
) {
|
||||||
|
@ -103,48 +104,48 @@ pub trait Script {
|
||||||
fn change_damage_stats_user(
|
fn change_damage_stats_user(
|
||||||
&mut self,
|
&mut self,
|
||||||
_move: &ExecutingMove,
|
_move: &ExecutingMove,
|
||||||
_target: &Pokemon,
|
_target: &Arc<RwLock<Pokemon>>,
|
||||||
_hit: u8,
|
_hit: u8,
|
||||||
_stats_user: &mut Pokemon,
|
_stats_user: &mut Arc<RwLock<Pokemon>>,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
fn bypass_defensive_stat(
|
fn bypass_defensive_stat_boost(
|
||||||
&mut self,
|
&mut self,
|
||||||
_move: &ExecutingMove,
|
_move: &ExecutingMove,
|
||||||
_target: &Pokemon,
|
_target: &Arc<RwLock<Pokemon>>,
|
||||||
_hit: u8,
|
_hit: u8,
|
||||||
_bypass: &mut bool,
|
_bypass: &mut bool,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
fn bypass_offensive_stat(
|
fn bypass_offensive_stat_boost(
|
||||||
&mut self,
|
&mut self,
|
||||||
_move: &ExecutingMove,
|
_move: &ExecutingMove,
|
||||||
_target: &Pokemon,
|
_target: &Arc<RwLock<Pokemon>>,
|
||||||
_hit: u8,
|
_hit: u8,
|
||||||
_bypass: &mut bool,
|
_bypass: &mut bool,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
fn change_offensive_stat(
|
fn change_offensive_stat_value(
|
||||||
&mut self,
|
&mut self,
|
||||||
_move: &ExecutingMove,
|
_move: &ExecutingMove,
|
||||||
_target: &Pokemon,
|
_target: &Arc<RwLock<Pokemon>>,
|
||||||
_hit: u8,
|
_hit: u8,
|
||||||
_amount: &mut f32,
|
_amount: &mut u32,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
fn change_defensive_stat(
|
fn change_defensive_stat_value(
|
||||||
&mut self,
|
&mut self,
|
||||||
_move: &ExecutingMove,
|
_move: &ExecutingMove,
|
||||||
_target: &Pokemon,
|
_target: &Arc<RwLock<Pokemon>>,
|
||||||
_hit: u8,
|
_hit: u8,
|
||||||
_amount: &mut f32,
|
_amount: &mut u32,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change_stat_modifier(
|
fn change_damage_stat_modifier(
|
||||||
&mut self,
|
&mut self,
|
||||||
_move: &ExecutingMove,
|
_move: &ExecutingMove,
|
||||||
_target: &Pokemon,
|
_target: &Arc<RwLock<Pokemon>>,
|
||||||
_hit: u8,
|
_hit: u8,
|
||||||
_modifier: &mut f32,
|
_modifier: &mut f32,
|
||||||
) {
|
) {
|
||||||
|
@ -152,29 +153,22 @@ pub trait Script {
|
||||||
fn change_damage_modifier(
|
fn change_damage_modifier(
|
||||||
&mut self,
|
&mut self,
|
||||||
_move: &ExecutingMove,
|
_move: &ExecutingMove,
|
||||||
_target: &Pokemon,
|
_target: &Arc<RwLock<Pokemon>>,
|
||||||
_hit: u8,
|
_hit: u8,
|
||||||
_modifier: &mut f32,
|
_modifier: &mut f32,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
fn change_damage(
|
fn change_damage(&mut self, _move: &ExecutingMove, _target: &Arc<RwLock<Pokemon>>, _hit: u8, _damage: &mut u32) {}
|
||||||
&mut self,
|
|
||||||
_move: &ExecutingMove,
|
|
||||||
_target: &Pokemon,
|
|
||||||
_hit: u8,
|
|
||||||
_damage: &mut u32,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
fn change_incoming_damage(
|
fn change_incoming_damage(
|
||||||
&mut self,
|
&mut self,
|
||||||
_move: &ExecutingMove,
|
_move: &ExecutingMove,
|
||||||
_target: &Pokemon,
|
_target: &Arc<RwLock<Pokemon>>,
|
||||||
_hit: u8,
|
_hit: u8,
|
||||||
_damage: &mut u32,
|
_damage: &mut u32,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
fn on_incoming_hit(&mut self, _move: &ExecutingMove, _target: &Pokemon, _hit: u8) {}
|
fn on_incoming_hit(&mut self, _move: &ExecutingMove, _target: &Arc<RwLock<Pokemon>>, _hit: u8) {}
|
||||||
fn on_opponent_faints(&mut self, _move: &ExecutingMove, _target: &Pokemon, _hit: u8) {}
|
fn on_opponent_faints(&mut self, _move: &ExecutingMove, _target: &Arc<RwLock<Pokemon>>, _hit: u8) {}
|
||||||
fn prevent_stat_boost_change(
|
fn prevent_stat_boost_change(
|
||||||
&mut self,
|
&mut self,
|
||||||
_target: &Pokemon,
|
_target: &Pokemon,
|
||||||
|
@ -195,7 +189,7 @@ pub trait Script {
|
||||||
fn prevent_secondary_effect(
|
fn prevent_secondary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
_move: &ExecutingMove,
|
_move: &ExecutingMove,
|
||||||
_target: &Pokemon,
|
_target: &Arc<RwLock<Pokemon>>,
|
||||||
_hit: u8,
|
_hit: u8,
|
||||||
_prevent: &mut bool,
|
_prevent: &mut bool,
|
||||||
) {
|
) {
|
||||||
|
@ -203,21 +197,21 @@ pub trait Script {
|
||||||
fn change_effect_chance(
|
fn change_effect_chance(
|
||||||
&mut self,
|
&mut self,
|
||||||
_move: &ExecutingMove,
|
_move: &ExecutingMove,
|
||||||
_target: &Pokemon,
|
_target: &Arc<RwLock<Pokemon>>,
|
||||||
_hit: u8,
|
_hit: u8,
|
||||||
_chance: &mut f32,
|
_chance: &mut f32,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
fn change_incoming_effect_change(
|
fn change_incoming_effect_chance(
|
||||||
&mut self,
|
&mut self,
|
||||||
_move: &ExecutingMove,
|
_move: &ExecutingMove,
|
||||||
_target: &Pokemon,
|
_target: &Arc<RwLock<Pokemon>>,
|
||||||
_hit: u8,
|
_hit: u8,
|
||||||
_chance: &mut f32,
|
_chance: &mut f32,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
fn on_secondary_effect(&mut self, _move: &ExecutingMove, _target: &Pokemon, _hit: u8) {}
|
fn on_secondary_effect(&mut self, _move: &ExecutingMove, _target: &Arc<RwLock<Pokemon>>, _hit: u8) {}
|
||||||
fn on_after_hits(&mut self, _move: &ExecutingMove, _target: &Pokemon) {}
|
fn on_after_hits(&mut self, _move: &ExecutingMove, _target: &Arc<RwLock<Pokemon>>) {}
|
||||||
fn prevent_self_switch(&mut self, _choice: &TurnChoice, _prevent: &mut bool) {}
|
fn prevent_self_switch(&mut self, _choice: &TurnChoice, _prevent: &mut bool) {}
|
||||||
fn prevent_opponent_switch(&mut self, _choice: &TurnChoice, _prevent: &mut bool) {}
|
fn prevent_opponent_switch(&mut self, _choice: &TurnChoice, _prevent: &mut bool) {}
|
||||||
fn on_fail(&mut self, _target: &Pokemon) {}
|
fn on_fail(&mut self, _target: &Pokemon) {}
|
||||||
|
@ -225,39 +219,14 @@ pub trait Script {
|
||||||
fn prevent_self_run_away(&mut self, _choice: &TurnChoice, _prevent: &mut bool) {}
|
fn prevent_self_run_away(&mut self, _choice: &TurnChoice, _prevent: &mut bool) {}
|
||||||
fn prevent_opponent_run_away(&mut self, _choice: &TurnChoice, _prevent: &mut bool) {}
|
fn prevent_opponent_run_away(&mut self, _choice: &TurnChoice, _prevent: &mut bool) {}
|
||||||
fn on_end_turn(&mut self) {}
|
fn on_end_turn(&mut self) {}
|
||||||
fn on_damage(
|
fn on_damage(&mut self, _pokemon: &Pokemon, _source: DamageSource, _old_health: u32, _new_health: u32) {}
|
||||||
&mut self,
|
|
||||||
_pokemon: &Pokemon,
|
|
||||||
_source: DamageSource,
|
|
||||||
_old_health: u32,
|
|
||||||
_new_health: u32,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
fn on_faint(&mut self, _pokemon: &Pokemon, _source: DamageSource) {}
|
fn on_faint(&mut self, _pokemon: &Pokemon, _source: DamageSource) {}
|
||||||
fn on_switch_in(&mut self, _pokemon: &Pokemon) {}
|
fn on_switch_in(&mut self, _pokemon: &Pokemon) {}
|
||||||
fn on_after_held_item_consume(&mut self, _pokemon: &Pokemon, _item: &Item) {}
|
fn on_after_held_item_consume(&mut self, _pokemon: &Pokemon, _item: &Item) {}
|
||||||
fn change_experience_gained(
|
fn change_experience_gained(&mut self, _fainted_mon: &Pokemon, _winning_mon: &Pokemon, _amount: &mut u32) {}
|
||||||
&mut self,
|
fn share_experience(&mut self, _fainted_mon: &Pokemon, _winning_mon: &Pokemon, _shares: &mut bool) {}
|
||||||
_fainted_mon: &Pokemon,
|
|
||||||
_winning_mon: &Pokemon,
|
|
||||||
_amount: &mut u32,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
fn share_experience(
|
|
||||||
&mut self,
|
|
||||||
_fainted_mon: &Pokemon,
|
|
||||||
_winning_mon: &Pokemon,
|
|
||||||
_shares: &mut bool,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
fn block_weather(&mut self, _battle: &Battle, _blocked: &mut bool) {}
|
fn block_weather(&mut self, _battle: &Battle, _blocked: &mut bool) {}
|
||||||
fn change_capture_rate_bonus(
|
fn change_capture_rate_bonus(&mut self, _target: &Pokemon, _pokeball: &Item, _modifier: &mut u8) {}
|
||||||
&mut self,
|
|
||||||
_target: &Pokemon,
|
|
||||||
_pokeball: &Item,
|
|
||||||
_modifier: &mut u8,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn Any;
|
fn as_any(&self) -> &dyn Any;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,16 +16,11 @@ impl ScriptSet {
|
||||||
return lock.clone();
|
return lock.clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.scripts
|
self.scripts.insert(script.name().clone(), ScriptContainer::new(script));
|
||||||
.insert(script.name().clone(), ScriptContainer::new(script));
|
|
||||||
self.scripts.last().unwrap().1.clone()
|
self.scripts.last().unwrap().1.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stack_or_add<'b, F>(
|
pub fn stack_or_add<'b, F>(&mut self, key: &StringKey, instantiation: &'b F) -> PkmnResult<Option<ScriptContainer>>
|
||||||
&mut self,
|
|
||||||
key: &StringKey,
|
|
||||||
instantiation: &'b F,
|
|
||||||
) -> PkmnResult<Option<ScriptContainer>>
|
|
||||||
where
|
where
|
||||||
F: Fn() -> PkmnResult<Option<Box<dyn Script>>>,
|
F: Fn() -> PkmnResult<Option<Box<dyn Script>>>,
|
||||||
{
|
{
|
||||||
|
@ -76,4 +71,8 @@ impl ScriptSet {
|
||||||
pub fn count(&self) -> usize {
|
pub fn count(&self) -> usize {
|
||||||
self.scripts.len()
|
self.scripts.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_underlying(&self) -> &IndexMap<StringKey, ScriptContainer> {
|
||||||
|
&self.scripts
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
#![feature(test)]
|
#![feature(test)]
|
||||||
#![feature(bench_black_box)]
|
#![feature(bench_black_box)]
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
|
#![feature(once_cell)]
|
||||||
|
|
||||||
extern crate core;
|
extern crate core;
|
||||||
extern crate lazy_static;
|
|
||||||
|
|
||||||
use crate::dynamic_data::libraries::script_resolver::ScriptCategory;
|
use crate::dynamic_data::libraries::script_resolver::ScriptCategory;
|
||||||
|
|
||||||
|
@ -19,10 +19,7 @@ pub mod utils;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum PokemonError {
|
pub enum PokemonError {
|
||||||
ScriptNotFound {
|
ScriptNotFound { category: ScriptCategory, name: String },
|
||||||
category: ScriptCategory,
|
|
||||||
name: String,
|
|
||||||
},
|
|
||||||
MiscError,
|
MiscError,
|
||||||
InvalidTargetRequested,
|
InvalidTargetRequested,
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,11 +43,7 @@ pub mod tests {
|
||||||
let mut lib = AbilityLibrary::new(1);
|
let mut lib = AbilityLibrary::new(1);
|
||||||
lib.add(
|
lib.add(
|
||||||
&StringKey::new("test_ability"),
|
&StringKey::new("test_ability"),
|
||||||
Box::new(Ability::new(
|
Box::new(Ability::new(&"test_ability".into(), &"test_ability".into(), Vec::new())),
|
||||||
&"test_ability".into(),
|
|
||||||
&"test_ability".into(),
|
|
||||||
Vec::new(),
|
|
||||||
)),
|
|
||||||
);
|
);
|
||||||
// Drops borrow as mut
|
// Drops borrow as mut
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ pub mod tests {
|
||||||
use crate::static_data::moves::move_data::{MoveCategory, MoveData, MoveTarget};
|
use crate::static_data::moves::move_data::{MoveCategory, MoveData, MoveTarget};
|
||||||
use crate::static_data::moves::secondary_effect::SecondaryEffect;
|
use crate::static_data::moves::secondary_effect::SecondaryEffect;
|
||||||
use crate::StringKey;
|
use crate::StringKey;
|
||||||
use std::collections::HashSet;
|
use hashbrown::HashSet;
|
||||||
|
|
||||||
fn build_move() -> MoveData {
|
fn build_move() -> MoveData {
|
||||||
MoveData::new(
|
MoveData::new(
|
||||||
|
|
|
@ -27,12 +27,7 @@ impl<'a> DataLibrary<'a, Box<Species<'a>>> for SpeciesLibrary<'a> {
|
||||||
&self.list
|
&self.list
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_modify(
|
fn get_modify(&mut self) -> (&mut HashMap<StringKey, Box<Species<'a>>>, &mut Vec<StringKey>) {
|
||||||
&mut self,
|
|
||||||
) -> (
|
|
||||||
&mut HashMap<StringKey, Box<Species<'a>>>,
|
|
||||||
&mut Vec<StringKey>,
|
|
||||||
) {
|
|
||||||
(&mut self.map, &mut self.list)
|
(&mut self.map, &mut self.list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,8 +73,7 @@ pub mod test {
|
||||||
use crate::static_data::libraries::library_settings::LibrarySettings;
|
use crate::static_data::libraries::library_settings::LibrarySettings;
|
||||||
use crate::static_data::libraries::static_data::StaticData;
|
use crate::static_data::libraries::static_data::StaticData;
|
||||||
use crate::static_data::libraries::{
|
use crate::static_data::libraries::{
|
||||||
ability_library, growth_rate_library, item_library, move_library, species_library,
|
ability_library, growth_rate_library, item_library, move_library, species_library, type_library,
|
||||||
type_library,
|
|
||||||
};
|
};
|
||||||
use crate::static_data::natures;
|
use crate::static_data::natures;
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
use crate::static_data::SecondaryEffect;
|
use crate::static_data::SecondaryEffect;
|
||||||
use crate::StringKey;
|
use crate::StringKey;
|
||||||
use std::collections::HashSet;
|
use hashbrown::HashSet;
|
||||||
|
|
||||||
|
#[cfg(feature = "serde")]
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
|
||||||
pub enum MoveCategory {
|
pub enum MoveCategory {
|
||||||
Physical = 0,
|
Physical = 0,
|
||||||
Special = 1,
|
Special = 1,
|
||||||
|
@ -10,6 +15,7 @@ pub enum MoveCategory {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
pub enum MoveTarget {
|
pub enum MoveTarget {
|
||||||
Adjacent = 0,
|
Adjacent = 0,
|
||||||
AdjacentAlly,
|
AdjacentAlly,
|
||||||
|
@ -25,6 +31,7 @@ pub enum MoveTarget {
|
||||||
Any,
|
Any,
|
||||||
|
|
||||||
RandomOpponent,
|
RandomOpponent,
|
||||||
|
#[cfg_attr(feature = "serde", serde(rename = "Self"))]
|
||||||
SelfUse,
|
SelfUse,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +46,7 @@ pub struct MoveData {
|
||||||
target: MoveTarget,
|
target: MoveTarget,
|
||||||
priority: i8,
|
priority: i8,
|
||||||
secondary_effect: SecondaryEffect,
|
secondary_effect: SecondaryEffect,
|
||||||
flags: HashSet<String>,
|
flags: HashSet<StringKey>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MoveData {
|
impl MoveData {
|
||||||
|
@ -53,7 +60,7 @@ impl MoveData {
|
||||||
target: MoveTarget,
|
target: MoveTarget,
|
||||||
priority: i8,
|
priority: i8,
|
||||||
secondary_effect: SecondaryEffect,
|
secondary_effect: SecondaryEffect,
|
||||||
flags: HashSet<String>,
|
flags: HashSet<StringKey>,
|
||||||
) -> MoveData {
|
) -> MoveData {
|
||||||
MoveData {
|
MoveData {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
|
@ -99,7 +106,11 @@ impl MoveData {
|
||||||
&self.secondary_effect
|
&self.secondary_effect
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_flag(&self, key: &str) -> bool {
|
pub fn has_secondary_effect(&self) -> bool {
|
||||||
|
self.secondary_effect.effect_name() != &StringKey::empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_flag(&self, key: &StringKey) -> bool {
|
||||||
self.flags.contains(key)
|
self.flags.contains(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use crate::StringKey;
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
pub enum EffectParameter {
|
pub enum EffectParameter {
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
|
@ -9,7 +11,7 @@ pub enum EffectParameter {
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
pub struct SecondaryEffect {
|
pub struct SecondaryEffect {
|
||||||
chance: f32,
|
chance: f32,
|
||||||
effect_name: String,
|
effect_name: StringKey,
|
||||||
parameters: Vec<EffectParameter>,
|
parameters: Vec<EffectParameter>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,15 +19,11 @@ impl SecondaryEffect {
|
||||||
pub fn empty() -> SecondaryEffect {
|
pub fn empty() -> SecondaryEffect {
|
||||||
SecondaryEffect {
|
SecondaryEffect {
|
||||||
chance: 0.0,
|
chance: 0.0,
|
||||||
effect_name: "".to_string(),
|
effect_name: StringKey::empty(),
|
||||||
parameters: vec![],
|
parameters: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn new(
|
pub fn new(chance: f32, effect_name: StringKey, parameters: Vec<EffectParameter>) -> SecondaryEffect {
|
||||||
chance: f32,
|
|
||||||
effect_name: String,
|
|
||||||
parameters: Vec<EffectParameter>,
|
|
||||||
) -> SecondaryEffect {
|
|
||||||
SecondaryEffect {
|
SecondaryEffect {
|
||||||
chance,
|
chance,
|
||||||
effect_name,
|
effect_name,
|
||||||
|
@ -36,7 +34,7 @@ impl SecondaryEffect {
|
||||||
pub fn chance(&self) -> f32 {
|
pub fn chance(&self) -> f32 {
|
||||||
self.chance
|
self.chance
|
||||||
}
|
}
|
||||||
pub fn effect_name(&self) -> &str {
|
pub fn effect_name(&self) -> &StringKey {
|
||||||
&self.effect_name
|
&self.effect_name
|
||||||
}
|
}
|
||||||
pub fn parameters(&self) -> &Vec<EffectParameter> {
|
pub fn parameters(&self) -> &Vec<EffectParameter> {
|
||||||
|
@ -53,11 +51,11 @@ mod tests {
|
||||||
fn create_secondary_effect() {
|
fn create_secondary_effect() {
|
||||||
let empty = SecondaryEffect::empty();
|
let empty = SecondaryEffect::empty();
|
||||||
assert_approx_eq!(empty.chance(), 0.0);
|
assert_approx_eq!(empty.chance(), 0.0);
|
||||||
assert_eq!(empty.effect_name(), "");
|
assert_eq!(empty.effect_name(), &"".into());
|
||||||
assert_eq!(empty.parameters().len(), 0);
|
assert_eq!(empty.parameters().len(), 0);
|
||||||
let set = SecondaryEffect::new(50.0, "foo".to_string(), Vec::new());
|
let set = SecondaryEffect::new(50.0, "foo".into(), Vec::new());
|
||||||
assert_approx_eq!(set.chance(), 50.0);
|
assert_approx_eq!(set.chance(), 50.0);
|
||||||
assert_eq!(set.effect_name(), "foo");
|
assert_eq!(set.effect_name(), &"foo".into());
|
||||||
assert_eq!(set.parameters().len(), 0);
|
assert_eq!(set.parameters().len(), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,10 +95,7 @@ pub mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn create_nature_library_insert_and_retrieve() {
|
fn create_nature_library_insert_and_retrieve() {
|
||||||
let mut lib = NatureLibrary::new(2);
|
let mut lib = NatureLibrary::new(2);
|
||||||
lib.load_nature(
|
lib.load_nature("foo".into(), Nature::new(Statistic::HP, Statistic::Attack, 1.1, 0.9));
|
||||||
"foo".into(),
|
|
||||||
Nature::new(Statistic::HP, Statistic::Attack, 1.1, 0.9),
|
|
||||||
);
|
|
||||||
lib.load_nature(
|
lib.load_nature(
|
||||||
"bar".into(),
|
"bar".into(),
|
||||||
Nature::new(Statistic::Attack, Statistic::Defense, 1.1, 0.9),
|
Nature::new(Statistic::Attack, Statistic::Defense, 1.1, 0.9),
|
||||||
|
@ -113,10 +110,7 @@ pub mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn create_nature_library_insert_and_get_name() {
|
fn create_nature_library_insert_and_get_name() {
|
||||||
let mut lib = NatureLibrary::new(2);
|
let mut lib = NatureLibrary::new(2);
|
||||||
lib.load_nature(
|
lib.load_nature("foo".into(), Nature::new(Statistic::HP, Statistic::Attack, 1.1, 0.9));
|
||||||
"foo".into(),
|
|
||||||
Nature::new(Statistic::HP, Statistic::Attack, 1.1, 0.9),
|
|
||||||
);
|
|
||||||
lib.load_nature(
|
lib.load_nature(
|
||||||
"bar".into(),
|
"bar".into(),
|
||||||
Nature::new(Statistic::Attack, Statistic::Defense, 1.1, 0.9),
|
Nature::new(Statistic::Attack, Statistic::Defense, 1.1, 0.9),
|
||||||
|
|
|
@ -120,8 +120,7 @@ impl<'a> Form<'a> {
|
||||||
self.abilities[rand.get_between_unsigned(0, self.abilities.len() as u32) as usize]
|
self.abilities[rand.get_between_unsigned(0, self.abilities.len() as u32) as usize]
|
||||||
}
|
}
|
||||||
pub fn get_random_hidden_ability(&self, rand: &mut Random) -> &Ability {
|
pub fn get_random_hidden_ability(&self, rand: &mut Random) -> &Ability {
|
||||||
self.hidden_abilities
|
self.hidden_abilities[rand.get_between_unsigned(0, self.hidden_abilities.len() as u32) as usize]
|
||||||
[rand.get_between_unsigned(0, self.hidden_abilities.len() as u32) as usize]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_flag(&self, key: &StringKey) -> bool {
|
pub fn has_flag(&self, key: &StringKey) -> bool {
|
||||||
|
|
|
@ -3,6 +3,7 @@ use crate::static_data::Gender;
|
||||||
use crate::Random;
|
use crate::Random;
|
||||||
use crate::StringKey;
|
use crate::StringKey;
|
||||||
use hashbrown::{HashMap, HashSet};
|
use hashbrown::{HashMap, HashSet};
|
||||||
|
use std::lazy::SyncLazy;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Species<'a> {
|
pub struct Species<'a> {
|
||||||
|
@ -14,9 +15,8 @@ pub struct Species<'a> {
|
||||||
forms: HashMap<StringKey, Form<'a>>,
|
forms: HashMap<StringKey, Form<'a>>,
|
||||||
flags: HashSet<StringKey>,
|
flags: HashSet<StringKey>,
|
||||||
}
|
}
|
||||||
lazy_static::lazy_static! {
|
|
||||||
static ref DEFAULT_KEY: StringKey = StringKey::new("default");
|
static DEFAULT_KEY: SyncLazy<StringKey> = SyncLazy::new(|| StringKey::new("default"));
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Species<'a> {
|
impl<'a> Species<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
|
|
|
@ -18,14 +18,7 @@ impl<T> StatisticSet<T>
|
||||||
where
|
where
|
||||||
T: PrimInt,
|
T: PrimInt,
|
||||||
{
|
{
|
||||||
pub fn new(
|
pub fn new(hp: T, attack: T, defense: T, special_attack: T, special_defense: T, speed: T) -> Self {
|
||||||
hp: T,
|
|
||||||
attack: T,
|
|
||||||
defense: T,
|
|
||||||
special_attack: T,
|
|
||||||
special_defense: T,
|
|
||||||
speed: T,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
hp,
|
hp,
|
||||||
attack,
|
attack,
|
||||||
|
@ -117,21 +110,13 @@ impl<T, const MIN: i64, const MAX: i64> ClampedStatisticSet<T, MIN, MAX>
|
||||||
where
|
where
|
||||||
T: PrimInt,
|
T: PrimInt,
|
||||||
{
|
{
|
||||||
pub fn new(
|
pub fn new(hp: T, attack: T, defense: T, special_attack: T, special_defense: T, speed: T) -> Self {
|
||||||
hp: T,
|
|
||||||
attack: T,
|
|
||||||
defense: T,
|
|
||||||
special_attack: T,
|
|
||||||
special_defense: T,
|
|
||||||
speed: T,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
hp: cast(clamp(cast::<T, i64>(hp).unwrap(), MIN, MAX)).unwrap(),
|
hp: cast(clamp(cast::<T, i64>(hp).unwrap(), MIN, MAX)).unwrap(),
|
||||||
attack: cast(clamp(cast::<T, i64>(attack).unwrap(), MIN, MAX)).unwrap(),
|
attack: cast(clamp(cast::<T, i64>(attack).unwrap(), MIN, MAX)).unwrap(),
|
||||||
defense: cast(clamp(cast::<T, i64>(defense).unwrap(), MIN, MAX)).unwrap(),
|
defense: cast(clamp(cast::<T, i64>(defense).unwrap(), MIN, MAX)).unwrap(),
|
||||||
special_attack: cast(clamp(cast::<T, i64>(special_attack).unwrap(), MIN, MAX)).unwrap(),
|
special_attack: cast(clamp(cast::<T, i64>(special_attack).unwrap(), MIN, MAX)).unwrap(),
|
||||||
special_defense: cast(clamp(cast::<T, i64>(special_defense).unwrap(), MIN, MAX))
|
special_defense: cast(clamp(cast::<T, i64>(special_defense).unwrap(), MIN, MAX)).unwrap(),
|
||||||
.unwrap(),
|
|
||||||
speed: cast(clamp(cast::<T, i64>(speed).unwrap(), MIN, MAX)).unwrap(),
|
speed: cast(clamp(cast::<T, i64>(speed).unwrap(), MIN, MAX)).unwrap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -200,12 +185,8 @@ where
|
||||||
Statistic::HP => Self::change_stat(self.hp + value, &mut self.hp),
|
Statistic::HP => Self::change_stat(self.hp + value, &mut self.hp),
|
||||||
Statistic::Attack => Self::change_stat(self.attack + value, &mut self.attack),
|
Statistic::Attack => Self::change_stat(self.attack + value, &mut self.attack),
|
||||||
Statistic::Defense => Self::change_stat(self.defense + value, &mut self.defense),
|
Statistic::Defense => Self::change_stat(self.defense + value, &mut self.defense),
|
||||||
Statistic::SpecialAttack => {
|
Statistic::SpecialAttack => Self::change_stat(self.special_attack + value, &mut self.special_attack),
|
||||||
Self::change_stat(self.special_attack + value, &mut self.special_attack)
|
Statistic::SpecialDefense => Self::change_stat(self.special_defense + value, &mut self.special_defense),
|
||||||
}
|
|
||||||
Statistic::SpecialDefense => {
|
|
||||||
Self::change_stat(self.special_defense + value, &mut self.special_defense)
|
|
||||||
}
|
|
||||||
Statistic::Speed => Self::change_stat(self.speed + value, &mut self.speed),
|
Statistic::Speed => Self::change_stat(self.speed + value, &mut self.speed),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,12 +196,8 @@ where
|
||||||
Statistic::HP => Self::change_stat(self.hp - value, &mut self.hp),
|
Statistic::HP => Self::change_stat(self.hp - value, &mut self.hp),
|
||||||
Statistic::Attack => Self::change_stat(self.attack - value, &mut self.attack),
|
Statistic::Attack => Self::change_stat(self.attack - value, &mut self.attack),
|
||||||
Statistic::Defense => Self::change_stat(self.defense - value, &mut self.defense),
|
Statistic::Defense => Self::change_stat(self.defense - value, &mut self.defense),
|
||||||
Statistic::SpecialAttack => {
|
Statistic::SpecialAttack => Self::change_stat(self.special_attack - value, &mut self.special_attack),
|
||||||
Self::change_stat(self.special_attack - value, &mut self.special_attack)
|
Statistic::SpecialDefense => Self::change_stat(self.special_defense - value, &mut self.special_defense),
|
||||||
}
|
|
||||||
Statistic::SpecialDefense => {
|
|
||||||
Self::change_stat(self.special_defense - value, &mut self.special_defense)
|
|
||||||
}
|
|
||||||
Statistic::Speed => Self::change_stat(self.speed - value, &mut self.speed),
|
Statistic::Speed => Self::change_stat(self.speed - value, &mut self.speed),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
use std::lazy::SyncLazy;
|
||||||
use std::sync::{Arc, Mutex, Weak};
|
use std::sync::{Arc, Mutex, Weak};
|
||||||
|
|
||||||
/// StringKey is an immutable string that is used for indexing of hashmaps or equality a lot.
|
/// StringKey is an immutable string that is used for indexing of hashmaps or equality a lot.
|
||||||
|
@ -12,9 +13,8 @@ pub struct StringKey {
|
||||||
hash: u32,
|
hash: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
static STRING_CACHE: SyncLazy<Mutex<HashMap<u32, Weak<str>>>> = SyncLazy::new(|| Mutex::new(HashMap::new()));
|
||||||
static ref STRING_CACHE: Mutex<HashMap<u32, Weak<str>>> = Mutex::new(HashMap::new());
|
static EMPTY: SyncLazy<StringKey> = SyncLazy::new(|| StringKey::new(""));
|
||||||
}
|
|
||||||
|
|
||||||
impl StringKey {
|
impl StringKey {
|
||||||
pub const fn get_hash_const<const N: usize>(s: &[u8; N]) -> u32 {
|
pub const fn get_hash_const<const N: usize>(s: &[u8; N]) -> u32 {
|
||||||
|
@ -48,14 +48,15 @@ impl StringKey {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let v = Self {
|
let v = Self { str: s.into(), hash };
|
||||||
str: s.into(),
|
|
||||||
hash,
|
|
||||||
};
|
|
||||||
cache.insert(hash, Arc::downgrade(&v.str));
|
cache.insert(hash, Arc::downgrade(&v.str));
|
||||||
v
|
v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn empty() -> Self {
|
||||||
|
EMPTY.clone()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn str(&self) -> &str {
|
pub fn str(&self) -> &str {
|
||||||
&self.str
|
&self.str
|
||||||
}
|
}
|
||||||
|
@ -93,38 +94,35 @@ const fn to_lower(c: u8) -> u8 {
|
||||||
}
|
}
|
||||||
|
|
||||||
const CRC_TABLE: &[u32] = &[
|
const CRC_TABLE: &[u32] = &[
|
||||||
0, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
|
0, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4,
|
||||||
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
|
0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148,
|
||||||
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
|
0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
|
||||||
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
|
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1,
|
||||||
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
|
0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75,
|
||||||
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
|
0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599,
|
||||||
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
|
0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
|
||||||
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
|
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2,
|
||||||
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
|
0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162,
|
||||||
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
|
0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA,
|
||||||
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
|
0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
|
||||||
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
|
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73,
|
||||||
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
|
0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3,
|
||||||
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
|
0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
|
||||||
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
|
0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
|
||||||
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
|
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344,
|
||||||
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
|
0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0,
|
||||||
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
|
0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
|
||||||
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
|
0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
|
||||||
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
|
0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795,
|
||||||
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
|
0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31,
|
||||||
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
|
0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
|
||||||
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
|
0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
|
||||||
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
|
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6,
|
||||||
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
|
0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE,
|
||||||
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
|
0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66,
|
||||||
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
|
0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
|
||||||
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
|
0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37,
|
||||||
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
|
0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
|
||||||
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
|
|
||||||
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
|
|
||||||
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -0,0 +1,285 @@
|
||||||
|
{
|
||||||
|
"adaptability": {
|
||||||
|
"effect": "IncreasedStab"
|
||||||
|
},
|
||||||
|
"aerilate": {
|
||||||
|
"effect": "ChangeMoveType",
|
||||||
|
"parameters": ["normal", "flying"]
|
||||||
|
},
|
||||||
|
"aftermath": {
|
||||||
|
"effect": "Aftermath"
|
||||||
|
},
|
||||||
|
"air_lock": {
|
||||||
|
"effect": "SuppressWeather"
|
||||||
|
},
|
||||||
|
"analytic": {
|
||||||
|
"effect": "Analytic"
|
||||||
|
},
|
||||||
|
"anger_point": {
|
||||||
|
"effect": "AngerPoint"
|
||||||
|
},
|
||||||
|
"anticipation": {
|
||||||
|
"effect": "Anticipation"
|
||||||
|
},
|
||||||
|
"arena_trap": {
|
||||||
|
"effect": "ArenaTrap"
|
||||||
|
},
|
||||||
|
"aroma_veil": {
|
||||||
|
"effect": "AromaVeil"
|
||||||
|
},
|
||||||
|
"aura_break": {
|
||||||
|
"effect": "AuraBreal"
|
||||||
|
},
|
||||||
|
"bad_dreams": {
|
||||||
|
"effect": "BadDreams"
|
||||||
|
},
|
||||||
|
"battery": {
|
||||||
|
"effect": "Battery"
|
||||||
|
},
|
||||||
|
"battle_armor": {
|
||||||
|
"effect": "PreventCritical"
|
||||||
|
},
|
||||||
|
"battle_bond": {
|
||||||
|
"effect": "BattleBond"
|
||||||
|
},
|
||||||
|
"beast_boost": {
|
||||||
|
"effect": "BeastBoost"
|
||||||
|
},
|
||||||
|
"berserk": {
|
||||||
|
"effect": "Berserk"
|
||||||
|
},
|
||||||
|
"big_pecks": {
|
||||||
|
"effect": "PreventDefLowering"
|
||||||
|
},
|
||||||
|
"blaze": {
|
||||||
|
"effect": "PowerUpType",
|
||||||
|
"parameters": ["fire"]
|
||||||
|
},
|
||||||
|
"bulletproof": {
|
||||||
|
"effect": "Bulletproof"
|
||||||
|
},
|
||||||
|
"cheek_pouch": {
|
||||||
|
"effect": "CheekPouch"
|
||||||
|
},
|
||||||
|
"chlorophyll": {
|
||||||
|
"effect": "DoubleSpeedInWeather",
|
||||||
|
"parameters": ["HarshSunlight"]
|
||||||
|
},
|
||||||
|
"clear_body": {
|
||||||
|
"effect": "PreventStatLowering"
|
||||||
|
},
|
||||||
|
"cloud_nine": {
|
||||||
|
"effect": "SuppressWeather"
|
||||||
|
},
|
||||||
|
"color_change": {
|
||||||
|
"effect": "ColorChange"
|
||||||
|
},
|
||||||
|
"comatose": {},
|
||||||
|
"competitive": {},
|
||||||
|
"compound_eyes": {},
|
||||||
|
"contrary": {},
|
||||||
|
"corrosion": {},
|
||||||
|
"cursed_body": {},
|
||||||
|
"cute_charm": {},
|
||||||
|
"damp": {},
|
||||||
|
"dancer": {},
|
||||||
|
"dark_aura": {},
|
||||||
|
"dazzling": {},
|
||||||
|
"defeatist": {},
|
||||||
|
"defiant": {},
|
||||||
|
"delta_stream": {},
|
||||||
|
"desolate_land": {},
|
||||||
|
"disguise": {},
|
||||||
|
"download": {},
|
||||||
|
"drizzle": {},
|
||||||
|
"drought": {},
|
||||||
|
"dry_skin": {},
|
||||||
|
"early_bird": {},
|
||||||
|
"effect_spore": {},
|
||||||
|
"electric_surge": {},
|
||||||
|
"emergency_exit": {},
|
||||||
|
"fairy_aura": {},
|
||||||
|
"filter": {},
|
||||||
|
"flame_body": {},
|
||||||
|
"flare_boost": {},
|
||||||
|
"flash_fire": {},
|
||||||
|
"flower_gift": {},
|
||||||
|
"flower_veil": {},
|
||||||
|
"fluffy": {},
|
||||||
|
"forecast": {},
|
||||||
|
"forewarn": {},
|
||||||
|
"friend_guard": {},
|
||||||
|
"frisk": {},
|
||||||
|
"full_metal_body": {},
|
||||||
|
"fur_coat": {},
|
||||||
|
"gale_wings": {},
|
||||||
|
"galvanize": {},
|
||||||
|
"gluttony": {},
|
||||||
|
"gooey": {},
|
||||||
|
"grass_pelt": {},
|
||||||
|
"grassy_surge": {},
|
||||||
|
"guts": {},
|
||||||
|
"harvest": {},
|
||||||
|
"healer": {},
|
||||||
|
"heatproof": {},
|
||||||
|
"heavy_metal": {},
|
||||||
|
"honey_gather": {},
|
||||||
|
"huge_power": {},
|
||||||
|
"hustle": {},
|
||||||
|
"hydration": {},
|
||||||
|
"hyper_cutter": {},
|
||||||
|
"ice_body": {},
|
||||||
|
"illuminate": {},
|
||||||
|
"illusion": {},
|
||||||
|
"immunity": {},
|
||||||
|
"imposter": {},
|
||||||
|
"infiltrator": {},
|
||||||
|
"innards_out": {},
|
||||||
|
"inner_focus": {},
|
||||||
|
"insomnia": {},
|
||||||
|
"intimidate": {},
|
||||||
|
"iron_barbs": {},
|
||||||
|
"iron_fist": {},
|
||||||
|
"justified": {},
|
||||||
|
"keen_eye": {},
|
||||||
|
"klutz": {},
|
||||||
|
"leaf_guard": {},
|
||||||
|
"levitate": {},
|
||||||
|
"light_metal": {},
|
||||||
|
"lightning_rod": {},
|
||||||
|
"limber": {},
|
||||||
|
"liquid_ooze": {},
|
||||||
|
"liquid_voice": {},
|
||||||
|
"long_reach": {},
|
||||||
|
"magic_bounce": {},
|
||||||
|
"magic_guard": {},
|
||||||
|
"magician": {},
|
||||||
|
"magma_armor": {},
|
||||||
|
"magnet_pull": {},
|
||||||
|
"marvel_scale": {},
|
||||||
|
"mega_launcher": {},
|
||||||
|
"merciless": {},
|
||||||
|
"minus": {},
|
||||||
|
"misty_surge": {},
|
||||||
|
"mold_breaker": {},
|
||||||
|
"moody": {},
|
||||||
|
"motor_drive": {},
|
||||||
|
"moxie": {},
|
||||||
|
"multiscale": {},
|
||||||
|
"multitype": {},
|
||||||
|
"mummy": {},
|
||||||
|
"natural_cure": {},
|
||||||
|
"no_guard": {},
|
||||||
|
"normalize": {},
|
||||||
|
"oblivious": {},
|
||||||
|
"overcoat": {},
|
||||||
|
"overgrow": {},
|
||||||
|
"own_tempo": {},
|
||||||
|
"parental_bond": {},
|
||||||
|
"pickpocket": {},
|
||||||
|
"pickup": {},
|
||||||
|
"pixilate": {},
|
||||||
|
"plus": {},
|
||||||
|
"poison_heal": {},
|
||||||
|
"poison_point": {},
|
||||||
|
"poison_touch": {},
|
||||||
|
"power_construct": {},
|
||||||
|
"power_of_alchemy": {},
|
||||||
|
"prankster": {},
|
||||||
|
"pressure": {},
|
||||||
|
"primordial_sea": {},
|
||||||
|
"prism_armor": {},
|
||||||
|
"protean": {},
|
||||||
|
"psychic_surge": {},
|
||||||
|
"pure_power": {},
|
||||||
|
"queenly_majesty": {},
|
||||||
|
"quick_feet": {},
|
||||||
|
"rain_dish": {},
|
||||||
|
"rattled": {},
|
||||||
|
"receiver": {},
|
||||||
|
"reckless": {},
|
||||||
|
"refrigerate": {},
|
||||||
|
"regenerator": {},
|
||||||
|
"rivalry": {},
|
||||||
|
"rks_system": {},
|
||||||
|
"rock_head": {},
|
||||||
|
"rough_skin": {},
|
||||||
|
"run_away": {},
|
||||||
|
"sand_force": {},
|
||||||
|
"sand_rush": {},
|
||||||
|
"sand_stream": {},
|
||||||
|
"sand_veil": {},
|
||||||
|
"sap_sipper": {},
|
||||||
|
"schooling": {},
|
||||||
|
"scrappy": {},
|
||||||
|
"serene_grace": {},
|
||||||
|
"shadow_shield": {},
|
||||||
|
"shadow_tag": {},
|
||||||
|
"shed_skin": {},
|
||||||
|
"sheer_force": {},
|
||||||
|
"shell_armor": {},
|
||||||
|
"shield_dust": {},
|
||||||
|
"shields_down": {},
|
||||||
|
"simple": {},
|
||||||
|
"skill_link": {},
|
||||||
|
"slow_start": {},
|
||||||
|
"slush_rush": {},
|
||||||
|
"sniper": {},
|
||||||
|
"snow_cloak": {},
|
||||||
|
"snow_warning": {},
|
||||||
|
"solar_power": {},
|
||||||
|
"solid_rock": {},
|
||||||
|
"soul_heart": {},
|
||||||
|
"soundproof": {},
|
||||||
|
"speed_boost": {},
|
||||||
|
"stakeout": {},
|
||||||
|
"stall": {},
|
||||||
|
"stamina": {},
|
||||||
|
"stance_change": {},
|
||||||
|
"static": {},
|
||||||
|
"steadfast": {},
|
||||||
|
"steelworker": {},
|
||||||
|
"stench": {},
|
||||||
|
"sticky_hold": {},
|
||||||
|
"storm_drain": {},
|
||||||
|
"strong_jaw": {},
|
||||||
|
"sturdy": {},
|
||||||
|
"suction_cups": {},
|
||||||
|
"super_luck": {},
|
||||||
|
"surge_surfer": {},
|
||||||
|
"swarm": {},
|
||||||
|
"sweet_veil": {},
|
||||||
|
"swift_swim": {},
|
||||||
|
"symbiosis": {},
|
||||||
|
"synchronize": {},
|
||||||
|
"tangled_feet": {},
|
||||||
|
"tangling_hair": {},
|
||||||
|
"technician": {},
|
||||||
|
"telepathy": {},
|
||||||
|
"teravolt": {},
|
||||||
|
"thick_fat": {},
|
||||||
|
"tinted_lens": {},
|
||||||
|
"torrent": {},
|
||||||
|
"tough_claws": {},
|
||||||
|
"toxic_boost": {},
|
||||||
|
"trace": {},
|
||||||
|
"triage": {},
|
||||||
|
"truant": {},
|
||||||
|
"turboblaze": {},
|
||||||
|
"unaware": {},
|
||||||
|
"unburden": {},
|
||||||
|
"unnerve": {},
|
||||||
|
"victory_star": {},
|
||||||
|
"vital_spirit": {},
|
||||||
|
"volt_absorb": {},
|
||||||
|
"water_absorb": {},
|
||||||
|
"water_bubble": {},
|
||||||
|
"water_compaction": {},
|
||||||
|
"water_veil": {},
|
||||||
|
"weak_armor": {},
|
||||||
|
"white_smoke": {},
|
||||||
|
"wimp_out": {},
|
||||||
|
"wonder_guard": {},
|
||||||
|
"wonder_skin": {},
|
||||||
|
"zen_mode": {}
|
||||||
|
}
|
|
@ -0,0 +1,614 @@
|
||||||
|
{
|
||||||
|
"Erratic": [
|
||||||
|
0,
|
||||||
|
15,
|
||||||
|
52,
|
||||||
|
122,
|
||||||
|
237,
|
||||||
|
406,
|
||||||
|
637,
|
||||||
|
942,
|
||||||
|
1326,
|
||||||
|
1800,
|
||||||
|
2369,
|
||||||
|
3041,
|
||||||
|
3822,
|
||||||
|
4719,
|
||||||
|
5737,
|
||||||
|
6881,
|
||||||
|
8155,
|
||||||
|
9564,
|
||||||
|
11111,
|
||||||
|
12800,
|
||||||
|
14632,
|
||||||
|
16610,
|
||||||
|
18737,
|
||||||
|
21012,
|
||||||
|
23437,
|
||||||
|
26012,
|
||||||
|
28737,
|
||||||
|
31610,
|
||||||
|
34632,
|
||||||
|
37800,
|
||||||
|
41111,
|
||||||
|
44564,
|
||||||
|
48155,
|
||||||
|
51881,
|
||||||
|
55737,
|
||||||
|
59719,
|
||||||
|
63822,
|
||||||
|
68041,
|
||||||
|
72369,
|
||||||
|
76800,
|
||||||
|
81326,
|
||||||
|
85942,
|
||||||
|
90637,
|
||||||
|
95406,
|
||||||
|
100237,
|
||||||
|
105122,
|
||||||
|
110052,
|
||||||
|
115015,
|
||||||
|
120001,
|
||||||
|
125000,
|
||||||
|
131324,
|
||||||
|
137795,
|
||||||
|
144410,
|
||||||
|
151165,
|
||||||
|
158056,
|
||||||
|
165079,
|
||||||
|
172229,
|
||||||
|
179503,
|
||||||
|
186894,
|
||||||
|
194400,
|
||||||
|
202013,
|
||||||
|
209728,
|
||||||
|
217540,
|
||||||
|
225443,
|
||||||
|
233431,
|
||||||
|
241496,
|
||||||
|
249633,
|
||||||
|
257834,
|
||||||
|
267406,
|
||||||
|
276458,
|
||||||
|
286328,
|
||||||
|
296358,
|
||||||
|
305767,
|
||||||
|
316074,
|
||||||
|
326531,
|
||||||
|
336255,
|
||||||
|
346965,
|
||||||
|
357812,
|
||||||
|
367807,
|
||||||
|
378880,
|
||||||
|
390077,
|
||||||
|
400293,
|
||||||
|
411686,
|
||||||
|
423190,
|
||||||
|
433572,
|
||||||
|
445239,
|
||||||
|
457001,
|
||||||
|
467489,
|
||||||
|
479378,
|
||||||
|
491346,
|
||||||
|
501878,
|
||||||
|
513934,
|
||||||
|
526049,
|
||||||
|
536557,
|
||||||
|
548720,
|
||||||
|
560922,
|
||||||
|
571333,
|
||||||
|
583539,
|
||||||
|
591882,
|
||||||
|
600000
|
||||||
|
],
|
||||||
|
"Fast": [
|
||||||
|
0,
|
||||||
|
6,
|
||||||
|
21,
|
||||||
|
51,
|
||||||
|
100,
|
||||||
|
172,
|
||||||
|
274,
|
||||||
|
409,
|
||||||
|
583,
|
||||||
|
800,
|
||||||
|
1064,
|
||||||
|
1382,
|
||||||
|
1757,
|
||||||
|
2195,
|
||||||
|
2700,
|
||||||
|
3276,
|
||||||
|
3930,
|
||||||
|
4665,
|
||||||
|
5487,
|
||||||
|
6400,
|
||||||
|
7408,
|
||||||
|
8518,
|
||||||
|
9733,
|
||||||
|
11059,
|
||||||
|
12500,
|
||||||
|
14060,
|
||||||
|
15746,
|
||||||
|
17561,
|
||||||
|
19511,
|
||||||
|
21600,
|
||||||
|
23832,
|
||||||
|
26214,
|
||||||
|
28749,
|
||||||
|
31443,
|
||||||
|
34300,
|
||||||
|
37324,
|
||||||
|
40522,
|
||||||
|
43897,
|
||||||
|
47455,
|
||||||
|
51200,
|
||||||
|
55136,
|
||||||
|
59270,
|
||||||
|
63605,
|
||||||
|
68147,
|
||||||
|
72900,
|
||||||
|
77868,
|
||||||
|
83058,
|
||||||
|
88473,
|
||||||
|
94119,
|
||||||
|
100000,
|
||||||
|
106120,
|
||||||
|
112486,
|
||||||
|
119101,
|
||||||
|
125971,
|
||||||
|
133100,
|
||||||
|
140492,
|
||||||
|
148154,
|
||||||
|
156089,
|
||||||
|
164303,
|
||||||
|
172800,
|
||||||
|
181584,
|
||||||
|
190662,
|
||||||
|
200037,
|
||||||
|
209715,
|
||||||
|
219700,
|
||||||
|
229996,
|
||||||
|
240610,
|
||||||
|
251545,
|
||||||
|
262807,
|
||||||
|
274400,
|
||||||
|
286328,
|
||||||
|
298598,
|
||||||
|
311213,
|
||||||
|
324179,
|
||||||
|
337500,
|
||||||
|
351180,
|
||||||
|
365226,
|
||||||
|
379641,
|
||||||
|
394431,
|
||||||
|
409600,
|
||||||
|
425152,
|
||||||
|
441094,
|
||||||
|
457429,
|
||||||
|
474163,
|
||||||
|
491300,
|
||||||
|
508844,
|
||||||
|
526802,
|
||||||
|
545177,
|
||||||
|
563975,
|
||||||
|
583200,
|
||||||
|
602856,
|
||||||
|
622950,
|
||||||
|
643485,
|
||||||
|
664467,
|
||||||
|
685900,
|
||||||
|
707788,
|
||||||
|
730138,
|
||||||
|
752953,
|
||||||
|
776239,
|
||||||
|
800000
|
||||||
|
],
|
||||||
|
"MediumFast": [
|
||||||
|
0,
|
||||||
|
8,
|
||||||
|
27,
|
||||||
|
64,
|
||||||
|
125,
|
||||||
|
216,
|
||||||
|
343,
|
||||||
|
512,
|
||||||
|
729,
|
||||||
|
1000,
|
||||||
|
1331,
|
||||||
|
1728,
|
||||||
|
2197,
|
||||||
|
2744,
|
||||||
|
3375,
|
||||||
|
4096,
|
||||||
|
4913,
|
||||||
|
5832,
|
||||||
|
6859,
|
||||||
|
8000,
|
||||||
|
9261,
|
||||||
|
10648,
|
||||||
|
12167,
|
||||||
|
13824,
|
||||||
|
15625,
|
||||||
|
17576,
|
||||||
|
19683,
|
||||||
|
21952,
|
||||||
|
24389,
|
||||||
|
27000,
|
||||||
|
29791,
|
||||||
|
32768,
|
||||||
|
35937,
|
||||||
|
39304,
|
||||||
|
42875,
|
||||||
|
46656,
|
||||||
|
50653,
|
||||||
|
54872,
|
||||||
|
59319,
|
||||||
|
64000,
|
||||||
|
68921,
|
||||||
|
74088,
|
||||||
|
79507,
|
||||||
|
85184,
|
||||||
|
91125,
|
||||||
|
97336,
|
||||||
|
103823,
|
||||||
|
110592,
|
||||||
|
117649,
|
||||||
|
125000,
|
||||||
|
132651,
|
||||||
|
140608,
|
||||||
|
148877,
|
||||||
|
157464,
|
||||||
|
166375,
|
||||||
|
175616,
|
||||||
|
185193,
|
||||||
|
195112,
|
||||||
|
205379,
|
||||||
|
216000,
|
||||||
|
226981,
|
||||||
|
238328,
|
||||||
|
250047,
|
||||||
|
262144,
|
||||||
|
274625,
|
||||||
|
287496,
|
||||||
|
300763,
|
||||||
|
314432,
|
||||||
|
328509,
|
||||||
|
343000,
|
||||||
|
357911,
|
||||||
|
373248,
|
||||||
|
389017,
|
||||||
|
405224,
|
||||||
|
421875,
|
||||||
|
438976,
|
||||||
|
456533,
|
||||||
|
474552,
|
||||||
|
493039,
|
||||||
|
512000,
|
||||||
|
531441,
|
||||||
|
551368,
|
||||||
|
571787,
|
||||||
|
592704,
|
||||||
|
614125,
|
||||||
|
636056,
|
||||||
|
658503,
|
||||||
|
681472,
|
||||||
|
704969,
|
||||||
|
729000,
|
||||||
|
753571,
|
||||||
|
778688,
|
||||||
|
804357,
|
||||||
|
830584,
|
||||||
|
857375,
|
||||||
|
884736,
|
||||||
|
912673,
|
||||||
|
941192,
|
||||||
|
970299,
|
||||||
|
1000000
|
||||||
|
],
|
||||||
|
"MediumSlow": [
|
||||||
|
0,
|
||||||
|
9,
|
||||||
|
57,
|
||||||
|
96,
|
||||||
|
135,
|
||||||
|
179,
|
||||||
|
236,
|
||||||
|
314,
|
||||||
|
419,
|
||||||
|
560,
|
||||||
|
742,
|
||||||
|
973,
|
||||||
|
1261,
|
||||||
|
1612,
|
||||||
|
2035,
|
||||||
|
2535,
|
||||||
|
3120,
|
||||||
|
3798,
|
||||||
|
4575,
|
||||||
|
5460,
|
||||||
|
6458,
|
||||||
|
7577,
|
||||||
|
8825,
|
||||||
|
10208,
|
||||||
|
11735,
|
||||||
|
13411,
|
||||||
|
15244,
|
||||||
|
17242,
|
||||||
|
19411,
|
||||||
|
21760,
|
||||||
|
24294,
|
||||||
|
27021,
|
||||||
|
29949,
|
||||||
|
33084,
|
||||||
|
36435,
|
||||||
|
40007,
|
||||||
|
43808,
|
||||||
|
47846,
|
||||||
|
52127,
|
||||||
|
56660,
|
||||||
|
61450,
|
||||||
|
66505,
|
||||||
|
71833,
|
||||||
|
77440,
|
||||||
|
83335,
|
||||||
|
89523,
|
||||||
|
96012,
|
||||||
|
102810,
|
||||||
|
109923,
|
||||||
|
117360,
|
||||||
|
125126,
|
||||||
|
133229,
|
||||||
|
141677,
|
||||||
|
150476,
|
||||||
|
159635,
|
||||||
|
169159,
|
||||||
|
179056,
|
||||||
|
189334,
|
||||||
|
199999,
|
||||||
|
211060,
|
||||||
|
222522,
|
||||||
|
234393,
|
||||||
|
246681,
|
||||||
|
259392,
|
||||||
|
272535,
|
||||||
|
286115,
|
||||||
|
300140,
|
||||||
|
314618,
|
||||||
|
329555,
|
||||||
|
344960,
|
||||||
|
360838,
|
||||||
|
377197,
|
||||||
|
394045,
|
||||||
|
411388,
|
||||||
|
429235,
|
||||||
|
447591,
|
||||||
|
466464,
|
||||||
|
485862,
|
||||||
|
505791,
|
||||||
|
526260,
|
||||||
|
547274,
|
||||||
|
568841,
|
||||||
|
590969,
|
||||||
|
613664,
|
||||||
|
636935,
|
||||||
|
660787,
|
||||||
|
685228,
|
||||||
|
710266,
|
||||||
|
735907,
|
||||||
|
762160,
|
||||||
|
789030,
|
||||||
|
816525,
|
||||||
|
844653,
|
||||||
|
873420,
|
||||||
|
902835,
|
||||||
|
932903,
|
||||||
|
963632,
|
||||||
|
995030,
|
||||||
|
1027103,
|
||||||
|
1059860
|
||||||
|
],
|
||||||
|
"Slow": [
|
||||||
|
0,
|
||||||
|
10,
|
||||||
|
33,
|
||||||
|
80,
|
||||||
|
156,
|
||||||
|
270,
|
||||||
|
428,
|
||||||
|
640,
|
||||||
|
911,
|
||||||
|
1250,
|
||||||
|
1663,
|
||||||
|
2160,
|
||||||
|
2746,
|
||||||
|
3430,
|
||||||
|
4218,
|
||||||
|
5120,
|
||||||
|
6141,
|
||||||
|
7290,
|
||||||
|
8573,
|
||||||
|
10000,
|
||||||
|
11576,
|
||||||
|
13310,
|
||||||
|
15208,
|
||||||
|
17280,
|
||||||
|
19531,
|
||||||
|
21970,
|
||||||
|
24603,
|
||||||
|
27440,
|
||||||
|
30486,
|
||||||
|
33750,
|
||||||
|
37238,
|
||||||
|
40960,
|
||||||
|
44921,
|
||||||
|
49130,
|
||||||
|
53593,
|
||||||
|
58320,
|
||||||
|
63316,
|
||||||
|
68590,
|
||||||
|
74148,
|
||||||
|
80000,
|
||||||
|
86151,
|
||||||
|
92610,
|
||||||
|
99383,
|
||||||
|
106480,
|
||||||
|
113906,
|
||||||
|
121670,
|
||||||
|
129778,
|
||||||
|
138240,
|
||||||
|
147061,
|
||||||
|
156250,
|
||||||
|
165813,
|
||||||
|
175760,
|
||||||
|
186096,
|
||||||
|
196830,
|
||||||
|
207968,
|
||||||
|
219520,
|
||||||
|
231491,
|
||||||
|
243890,
|
||||||
|
256723,
|
||||||
|
270000,
|
||||||
|
283726,
|
||||||
|
297910,
|
||||||
|
312558,
|
||||||
|
327680,
|
||||||
|
343281,
|
||||||
|
359370,
|
||||||
|
375953,
|
||||||
|
393040,
|
||||||
|
410636,
|
||||||
|
428750,
|
||||||
|
447388,
|
||||||
|
466560,
|
||||||
|
486271,
|
||||||
|
506530,
|
||||||
|
527343,
|
||||||
|
548720,
|
||||||
|
570666,
|
||||||
|
593190,
|
||||||
|
616298,
|
||||||
|
640000,
|
||||||
|
664301,
|
||||||
|
689210,
|
||||||
|
714733,
|
||||||
|
740880,
|
||||||
|
767656,
|
||||||
|
795070,
|
||||||
|
823128,
|
||||||
|
851840,
|
||||||
|
881211,
|
||||||
|
911250,
|
||||||
|
941963,
|
||||||
|
973360,
|
||||||
|
1005446,
|
||||||
|
1038230,
|
||||||
|
1071718,
|
||||||
|
1105920,
|
||||||
|
1140841,
|
||||||
|
1176490,
|
||||||
|
1212873,
|
||||||
|
1250000
|
||||||
|
],
|
||||||
|
"Fluctuating": [
|
||||||
|
0,
|
||||||
|
4,
|
||||||
|
13,
|
||||||
|
32,
|
||||||
|
65,
|
||||||
|
112,
|
||||||
|
178,
|
||||||
|
276,
|
||||||
|
393,
|
||||||
|
540,
|
||||||
|
745,
|
||||||
|
967,
|
||||||
|
1230,
|
||||||
|
1591,
|
||||||
|
1957,
|
||||||
|
2457,
|
||||||
|
3046,
|
||||||
|
3732,
|
||||||
|
4526,
|
||||||
|
5440,
|
||||||
|
6482,
|
||||||
|
7666,
|
||||||
|
9003,
|
||||||
|
10506,
|
||||||
|
12187,
|
||||||
|
14060,
|
||||||
|
16140,
|
||||||
|
18439,
|
||||||
|
20974,
|
||||||
|
23760,
|
||||||
|
26811,
|
||||||
|
30146,
|
||||||
|
33780,
|
||||||
|
37731,
|
||||||
|
42017,
|
||||||
|
46656,
|
||||||
|
50653,
|
||||||
|
55969,
|
||||||
|
60505,
|
||||||
|
66560,
|
||||||
|
71677,
|
||||||
|
78533,
|
||||||
|
84277,
|
||||||
|
91998,
|
||||||
|
98415,
|
||||||
|
107069,
|
||||||
|
114205,
|
||||||
|
123863,
|
||||||
|
131766,
|
||||||
|
142500,
|
||||||
|
151222,
|
||||||
|
163105,
|
||||||
|
172697,
|
||||||
|
185807,
|
||||||
|
196322,
|
||||||
|
210739,
|
||||||
|
222231,
|
||||||
|
238036,
|
||||||
|
250562,
|
||||||
|
267840,
|
||||||
|
281456,
|
||||||
|
300293,
|
||||||
|
315059,
|
||||||
|
335544,
|
||||||
|
351520,
|
||||||
|
373744,
|
||||||
|
390991,
|
||||||
|
415050,
|
||||||
|
433631,
|
||||||
|
459620,
|
||||||
|
479600,
|
||||||
|
507617,
|
||||||
|
529063,
|
||||||
|
559209,
|
||||||
|
582187,
|
||||||
|
614566,
|
||||||
|
639146,
|
||||||
|
673863,
|
||||||
|
700115,
|
||||||
|
737280,
|
||||||
|
765275,
|
||||||
|
804997,
|
||||||
|
834809,
|
||||||
|
877201,
|
||||||
|
908905,
|
||||||
|
954084,
|
||||||
|
987754,
|
||||||
|
1035837,
|
||||||
|
1071552,
|
||||||
|
1122660,
|
||||||
|
1160499,
|
||||||
|
1214753,
|
||||||
|
1254796,
|
||||||
|
1312322,
|
||||||
|
1354652,
|
||||||
|
1415577,
|
||||||
|
1460276,
|
||||||
|
1524731,
|
||||||
|
1571884,
|
||||||
|
1640000
|
||||||
|
]
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,26 @@
|
||||||
|
Name|Increased|Decreased
|
||||||
|
Hardy||
|
||||||
|
Lonely|Attack|Defense
|
||||||
|
Brave|Attack|Speed
|
||||||
|
Adamant|Attack|SpecialAttack
|
||||||
|
Naughty|Attack|SpecialDefense
|
||||||
|
Bold|Defense|Attack
|
||||||
|
Docile||
|
||||||
|
Relaxed|Defense|Speed
|
||||||
|
Impish|Defense|SpecialAttack
|
||||||
|
Lax|Defense|SpecialDefense
|
||||||
|
Timid|Speed|Attack
|
||||||
|
Hasty|Speed|Defense
|
||||||
|
Serious||
|
||||||
|
Jolly|Speed|SpecialAttack
|
||||||
|
Naive|Speed|SpecialDefense
|
||||||
|
Modest|SpecialAttack|Attack
|
||||||
|
Mild|SpecialAttack|Defense
|
||||||
|
Quiet|SpecialAttack|Speed
|
||||||
|
Bashful||
|
||||||
|
Rash|SpecialAttack|SpecialDefense
|
||||||
|
Calm|SpecialDefense|Attack
|
||||||
|
Gentle|SpecialDefense|Defense
|
||||||
|
Sassy|SpecialDefense|Speed
|
||||||
|
Careful|SpecialDefense|SpecialAttack
|
||||||
|
Quirky||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,19 @@
|
||||||
|
Types|Normal|Fighting|Flying|Poison|Ground|Rock|Bug|Ghost|Steel|Fire|Water|Grass|Electric|Psychic|Ice|Dragon|Dark|Fairy
|
||||||
|
Normal|1|1|1|1|1|0.5|1|0|0.5|1|1|1|1|1|1|1|1|1
|
||||||
|
Fighting|2|1|0.5|0.5|1|2|0.5|0|2|1|1|1|1|0.5|2|1|2|0.5
|
||||||
|
Flying|1|2|1|1|1|0.5|2|1|0.5|1|1|2|0.5|1|1|1|1|1
|
||||||
|
Poison|1|1|1|0.5|0.5|0.5|1|0.5|0|1|1|2|1|1|1|1|1|2
|
||||||
|
Ground|1|1|0|2|1|2|0.5|1|2|2|1|0.5|2|1|1|1|1|1
|
||||||
|
Rock|1|0.5|2|1|0.5|1|2|1|0.5|2|1|1|1|1|2|1|1|1
|
||||||
|
Bug|1|0.5|0.5|0.5|1|1|1|0.5|0.5|0.5|1|2|1|2|1|1|2|0.5
|
||||||
|
Ghost|0|1|1|1|1|1|1|2|1|1|1|1|1|2|1|1|0.5|1
|
||||||
|
Steel|1|1|1|1|1|2|1|1|0.5|0.5|0.5|1|0.5|1|2|1|1|2
|
||||||
|
Fire|1|1|1|1|1|0.5|2|1|2|0.5|0.5|2|1|1|2|0.5|1|1
|
||||||
|
Water|1|1|1|1|2|2|1|1|1|2|0.5|0.5|1|1|1|0.5|1|1
|
||||||
|
Grass|1|1|0.5|0.5|2|2|0.5|1|0.5|0.5|2|0.5|1|1|1|0.5|1|1
|
||||||
|
Electric|1|1|2|1|0|1|1|1|1|1|2|0.5|0.5|1|1|0.5|1|1
|
||||||
|
Psychic|1|2|1|2|1|1|1|1|0.5|1|1|1|1|0.5|1|1|0|1
|
||||||
|
Ice|1|1|2|1|2|1|1|1|0.5|0.5|0.5|2|1|1|0.5|2|1|1
|
||||||
|
Dragon|1|1|1|1|1|1|1|1|0.5|1|1|1|1|1|1|2|1|0
|
||||||
|
Dark|1|0.5|1|1|1|1|1|2|1|1|1|1|1|2|1|1|0.5|0.5
|
||||||
|
Fairy|1|2|1|0.5|1|1|1|1|0.5|0.5|1|1|1|1|1|2|2|1
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
use hashbrown::HashSet;
|
||||||
|
use pkmn_lib::static_data::{DataLibrary, EffectParameter, MoveData, MoveLibrary, SecondaryEffect, TypeLibrary};
|
||||||
|
use pkmn_lib::StringKey;
|
||||||
|
use project_root::get_project_root;
|
||||||
|
use serde_json::Value;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
|
pub fn load_types(path: &String) -> TypeLibrary {
|
||||||
|
let mut type_library = TypeLibrary::new(18);
|
||||||
|
|
||||||
|
let mut reader = csv::ReaderBuilder::new()
|
||||||
|
.delimiter(b'|')
|
||||||
|
.from_path(path.to_string() + "Types.csv")
|
||||||
|
.unwrap();
|
||||||
|
let headers = reader.headers().unwrap();
|
||||||
|
for header in headers.iter().skip(1) {
|
||||||
|
type_library.register_type(&StringKey::new(header.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
|
for record in reader.records() {
|
||||||
|
let record = record.unwrap();
|
||||||
|
let offensive_type = record.get(0).unwrap();
|
||||||
|
let offensive_type_id = type_library.get_type_id(&StringKey::new(offensive_type.clone()));
|
||||||
|
|
||||||
|
for (i, v) in record.iter().skip(1).enumerate() {
|
||||||
|
let effectiveness = v.parse::<f32>().unwrap();
|
||||||
|
type_library.set_effectiveness(offensive_type_id, i as u8, effectiveness);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type_library
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_moves(path: &String, type_library: &TypeLibrary) -> MoveLibrary {
|
||||||
|
let mut file = File::open(path.to_string() + "Moves.json").unwrap();
|
||||||
|
let mut data = String::new();
|
||||||
|
file.read_to_string(&mut data).unwrap();
|
||||||
|
println!("1");
|
||||||
|
let json: Value = serde_json::from_str(&data).unwrap();
|
||||||
|
println!("a");
|
||||||
|
let data = json.as_object().unwrap().get("data").unwrap().as_array().unwrap();
|
||||||
|
println!("this");
|
||||||
|
let mut move_library = MoveLibrary::new(data.len());
|
||||||
|
println!("Heeere");
|
||||||
|
for move_data in data {
|
||||||
|
let move_data = move_data.as_object().unwrap();
|
||||||
|
let move_name = StringKey::new(move_data["name"].as_str().unwrap().clone());
|
||||||
|
println!("Loaded move {:?}", move_name);
|
||||||
|
let move_type = StringKey::new(move_data["type"].as_str().unwrap());
|
||||||
|
let move_type_id = type_library.get_type_id(&move_type);
|
||||||
|
let move_category = serde_json::from_value(move_data["category"].clone()).unwrap();
|
||||||
|
let base_power = move_data["power"].as_i64().unwrap() as u8;
|
||||||
|
let accuracy = move_data["accuracy"].as_i64().unwrap() as u8;
|
||||||
|
let pp = move_data["pp"].as_i64().unwrap() as u8;
|
||||||
|
let target = serde_json::from_value(move_data["target"].clone()).unwrap();
|
||||||
|
let priority = move_data["priority"].as_i64().unwrap() as i8;
|
||||||
|
let secondary_effect = if let Some(v) = move_data.get("effect") {
|
||||||
|
let mut chance = -1.0;
|
||||||
|
if let Some(chance_value) = v.get("chance") {
|
||||||
|
chance = chance_value.as_f64().unwrap() as f32;
|
||||||
|
}
|
||||||
|
let mut parameters = Vec::new();
|
||||||
|
if let Some(pars) = v.get("parameters") {
|
||||||
|
let pars = pars.as_array().unwrap();
|
||||||
|
for par in pars {
|
||||||
|
match par {
|
||||||
|
Value::Null => {
|
||||||
|
panic!("Unexpected type")
|
||||||
|
}
|
||||||
|
Value::Bool(b) => {
|
||||||
|
parameters.push(EffectParameter::Bool(*b));
|
||||||
|
}
|
||||||
|
Value::Number(n) => {
|
||||||
|
if n.is_f64() {
|
||||||
|
parameters.push(EffectParameter::Float(n.as_f64().unwrap() as f32));
|
||||||
|
} else {
|
||||||
|
parameters.push(EffectParameter::Int(n.as_i64().unwrap()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Value::String(s) => {
|
||||||
|
parameters.push(EffectParameter::String(s.clone()));
|
||||||
|
}
|
||||||
|
Value::Array(_) => {
|
||||||
|
panic!("Unexpected type")
|
||||||
|
}
|
||||||
|
Value::Object(_) => {
|
||||||
|
panic!("Unexpected type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondaryEffect::new(chance, StringKey::new(v["name"].as_str().unwrap().clone()), parameters)
|
||||||
|
} else {
|
||||||
|
SecondaryEffect::empty()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut flags = HashSet::new();
|
||||||
|
if let Some(f) = move_data.get("flags") {
|
||||||
|
let f = f.as_array().unwrap();
|
||||||
|
for flag in f {
|
||||||
|
flags.insert(StringKey::new(flag.as_str().unwrap()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
move_library.add(
|
||||||
|
&move_name,
|
||||||
|
MoveData::new(
|
||||||
|
&move_name.clone(),
|
||||||
|
move_type_id,
|
||||||
|
move_category,
|
||||||
|
base_power,
|
||||||
|
accuracy,
|
||||||
|
pp,
|
||||||
|
target,
|
||||||
|
priority,
|
||||||
|
secondary_effect,
|
||||||
|
flags,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
move_library
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore)]
|
||||||
|
fn test_type_library_loaded() {
|
||||||
|
let mut path = get_project_root().unwrap();
|
||||||
|
path.push("tests/data/");
|
||||||
|
let lib = load_types(&path.to_str().unwrap().to_string());
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
lib.get_effectiveness(
|
||||||
|
lib.get_type_id(&StringKey::new("fire")),
|
||||||
|
&vec![lib.get_type_id(&StringKey::new("grass")),]
|
||||||
|
),
|
||||||
|
2.0
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
use project_root::get_project_root;
|
||||||
|
|
||||||
|
pub mod library_loader;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore)]
|
||||||
|
fn run_integration_tests() {
|
||||||
|
let mut path = get_project_root().unwrap();
|
||||||
|
path.push("tests/data/");
|
||||||
|
let path = path.to_str().unwrap().to_string();
|
||||||
|
let type_library = library_loader::load_types(&path);
|
||||||
|
let move_library = library_loader::load_moves(&path, &type_library);
|
||||||
|
}
|
Loading…
Reference in New Issue