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
15
Cargo.toml
15
Cargo.toml
|
@ -6,10 +6,13 @@ edition = "2018"
|
|||
|
||||
[lib]
|
||||
name = "pkmn_lib"
|
||||
crate_type = ["cdylib"]
|
||||
crate_type = ["rlib"]
|
||||
path = "src/lib.rs"
|
||||
|
||||
[features]
|
||||
c_interface = []
|
||||
serde = ["dep:serde", "dep:serde_json"]
|
||||
default = ["serde"]
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 0
|
||||
|
@ -43,11 +46,15 @@ chrono = "0.4.19"
|
|||
# Used for RNG
|
||||
rand = "0.8.5"
|
||||
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_derive = "0.1.8"
|
||||
lazy_static = "1.4.0"
|
||||
hashbrown = "0.12.1"
|
||||
indexmap = "1.8.2"
|
||||
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;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
self.with_value(
|
||||
|value| unsafe_block!("The borrow of self protects the inner value" => &*value.get()),
|
||||
)
|
||||
self.with_value(|value| unsafe_block!("The borrow of self protects the inner value" => &*value.get()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,10 +36,7 @@ enum Kind {
|
|||
|
||||
impl PkmnResult {
|
||||
pub(super) fn ok() -> Self {
|
||||
PkmnResult {
|
||||
kind: Kind::Ok,
|
||||
id: 0,
|
||||
}
|
||||
PkmnResult { kind: Kind::Ok, id: 0 }
|
||||
}
|
||||
|
||||
pub(super) fn argument_null() -> Self {
|
||||
|
@ -65,10 +62,7 @@ impl PkmnResult {
|
|||
}
|
||||
|
||||
pub(super) fn context(self, e: impl Fail) -> Self {
|
||||
assert!(
|
||||
self.as_err().is_some(),
|
||||
"context can only be attached to errors"
|
||||
);
|
||||
assert!(self.as_err().is_some(), "context can only be attached to errors");
|
||||
|
||||
let err = Some(format_error(&e));
|
||||
|
||||
|
@ -105,8 +99,7 @@ impl PkmnResult {
|
|||
.value
|
||||
}
|
||||
Err(e) => {
|
||||
let extract_panic =
|
||||
|| extract_panic(&e).map(|s| format!("internal panic with '{}'", s));
|
||||
let extract_panic = || extract_panic(&e).map(|s| format!("internal panic with '{}'", s));
|
||||
|
||||
// Set the last error to the panic message if it's not already set
|
||||
last_result
|
||||
|
@ -124,9 +117,7 @@ impl PkmnResult {
|
|||
})
|
||||
}
|
||||
|
||||
pub(super) fn with_last_result<R>(
|
||||
f: impl FnOnce(Option<(PkmnResult, Option<&str>)>) -> R,
|
||||
) -> R {
|
||||
pub(super) fn with_last_result<R>(f: impl FnOnce(Option<(PkmnResult, Option<&str>)>) -> R) -> R {
|
||||
LAST_RESULT.with(|last_result| {
|
||||
let last_result = last_result.borrow();
|
||||
|
||||
|
|
|
@ -1,32 +1,359 @@
|
|||
use crate::dynamic_data::models::learned_move::LearnedMove;
|
||||
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)]
|
||||
pub enum TurnChoice<'a> {
|
||||
Move {
|
||||
user: &'a Pokemon<'a>,
|
||||
used_move: Box<LearnedMove<'a>>,
|
||||
target_side: u8,
|
||||
target_index: u8,
|
||||
},
|
||||
Item {
|
||||
user: &'a Pokemon<'a>,
|
||||
},
|
||||
Switch {
|
||||
user: &'a Pokemon<'a>,
|
||||
},
|
||||
Flee {
|
||||
user: &'a Pokemon<'a>,
|
||||
},
|
||||
struct CommonChoiceData<'user, 'library> {
|
||||
user: Arc<RwLock<Pokemon<'user, 'library>>>,
|
||||
speed: u32,
|
||||
random_value: u32,
|
||||
has_failed: bool,
|
||||
script_source_data: RwLock<ScriptSourceData>,
|
||||
}
|
||||
|
||||
impl<'a> TurnChoice<'a> {
|
||||
pub fn user(&self) -> &'a Pokemon<'a> {
|
||||
#[derive(Debug)]
|
||||
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 {
|
||||
TurnChoice::Move { user, .. } => user,
|
||||
TurnChoice::Item { user, .. } => user,
|
||||
TurnChoice::Switch { user, .. } => user,
|
||||
TurnChoice::Flee { user, .. } => user,
|
||||
TurnChoice::Move(data) => &data.choice_data,
|
||||
TurnChoice::Item(data) => &data.choice_data,
|
||||
TurnChoice::Switch(data) => &data.choice_data,
|
||||
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::executing_move::ExecutingMove;
|
||||
use crate::dynamic_data::models::pokemon::Pokemon;
|
||||
use crate::static_data::species_data::form::Form;
|
||||
use crate::static_data::species_data::species::Species;
|
||||
|
@ -9,12 +10,12 @@ pub struct EventHook {
|
|||
evt_hook_function: Vec<fn(&Box<&Event>)>,
|
||||
}
|
||||
|
||||
impl<'a> EventHook {
|
||||
impl<'battle, 'library> EventHook {
|
||||
pub fn register_listener(&mut self, func: fn(&Box<&Event>)) {
|
||||
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);
|
||||
for f in &self.evt_hook_function {
|
||||
f(&b);
|
||||
|
@ -29,11 +30,11 @@ impl Debug for EventHook {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Event<'a, 'b> {
|
||||
pub enum Event<'own, 'battle, 'library> {
|
||||
Switch {
|
||||
side_index: u8,
|
||||
index: u8,
|
||||
pokemon: Option<&'a Pokemon<'b>>,
|
||||
pokemon: Option<&'own Pokemon<'battle, 'library>>,
|
||||
},
|
||||
Swap {
|
||||
side_index: u8,
|
||||
|
@ -41,21 +42,28 @@ pub enum Event<'a, 'b> {
|
|||
index_b: u8,
|
||||
},
|
||||
SpeciesChange {
|
||||
pokemon: &'a Pokemon<'b>,
|
||||
species: &'a Species<'b>,
|
||||
form: &'a Form<'b>,
|
||||
pokemon: &'own Pokemon<'battle, 'library>,
|
||||
species: &'own Species<'library>,
|
||||
form: &'own Form<'library>,
|
||||
},
|
||||
FormChange {
|
||||
pokemon: &'a Pokemon<'b>,
|
||||
form: &'a Form<'b>,
|
||||
pokemon: &'own Pokemon<'battle, 'library>,
|
||||
form: &'own Form<'library>,
|
||||
},
|
||||
Damage {
|
||||
pokemon: &'a Pokemon<'b>,
|
||||
pokemon: &'own Pokemon<'battle, 'library>,
|
||||
source: DamageSource,
|
||||
original_health: u32,
|
||||
new_health: u32,
|
||||
},
|
||||
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 parking_lot::RwLock;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ChoiceQueue {
|
||||
queue: Vec<Arc<ChoiceQueue>>,
|
||||
pub struct ChoiceQueue<'battle, 'library> {
|
||||
queue: Vec<Arc<RwLock<TurnChoice<'battle, 'library>>>>,
|
||||
current: usize,
|
||||
}
|
||||
|
||||
impl ChoiceQueue {
|
||||
pub fn new(queue: Vec<Arc<ChoiceQueue>>) -> Self {
|
||||
impl<'battle, 'library> ChoiceQueue<'battle, 'library> {
|
||||
pub fn new(queue: Vec<Arc<RwLock<TurnChoice<'battle, 'library>>>>) -> Self {
|
||||
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];
|
||||
self.current += 1;
|
||||
c
|
||||
}
|
||||
|
||||
pub fn peek(&mut self) -> &Arc<ChoiceQueue> {
|
||||
pub fn peek(&mut self) -> &'battle Arc<RwLock<TurnChoice>> {
|
||||
&self.queue[self.current]
|
||||
}
|
||||
|
||||
|
@ -29,4 +31,8 @@ impl ChoiceQueue {
|
|||
pub fn move_pokemon_choice_next(&mut self, _pokemon: &Pokemon) {
|
||||
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 target_resolver;
|
||||
pub mod turn_runner;
|
||||
|
|
|
@ -5,11 +5,10 @@ use num_traits::abs;
|
|||
use parking_lot::RwLock;
|
||||
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> {
|
||||
let mut v =
|
||||
Vec::with_capacity(battle.pokemon_per_side() as usize * battle.number_of_sides() as usize);
|
||||
fn get_all_targets<'b, 'library>(battle: &Battle<'b, 'library>) -> TargetList<'b, 'library> {
|
||||
let mut v = Vec::with_capacity(battle.pokemon_per_side() as usize * battle.number_of_sides() as usize);
|
||||
for side in battle.sides() {
|
||||
for pokemon in side.pokemon() {
|
||||
v.push(pokemon.as_ref().cloned());
|
||||
|
@ -25,16 +24,13 @@ fn get_opposite_side(side: u8) -> u8 {
|
|||
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 right = index + 1;
|
||||
if left < 0 && right >= battle.pokemon_per_side() {
|
||||
return vec![
|
||||
battle.get_pokemon(side, index).as_ref().cloned(),
|
||||
battle
|
||||
.get_pokemon(get_opposite_side(side), index)
|
||||
.as_ref()
|
||||
.cloned(),
|
||||
battle.get_pokemon(get_opposite_side(side), index).as_ref().cloned(),
|
||||
];
|
||||
}
|
||||
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, left as u8).as_ref().cloned(),
|
||||
battle.get_pokemon(side, right).as_ref().cloned(),
|
||||
battle
|
||||
.get_pokemon(get_opposite_side(side), index)
|
||||
.as_ref()
|
||||
.cloned(),
|
||||
battle.get_pokemon(get_opposite_side(side), index).as_ref().cloned(),
|
||||
]
|
||||
} else {
|
||||
vec![
|
||||
battle.get_pokemon(side, index).as_ref().cloned(),
|
||||
battle.get_pokemon(side, left as u8).as_ref().cloned(),
|
||||
battle
|
||||
.get_pokemon(get_opposite_side(side), index)
|
||||
.as_ref()
|
||||
.cloned(),
|
||||
battle.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![
|
||||
battle.get_pokemon(side, index).as_ref().cloned(),
|
||||
battle.get_pokemon(side, right).as_ref().cloned(),
|
||||
battle
|
||||
.get_pokemon(get_opposite_side(side), index)
|
||||
.as_ref()
|
||||
.cloned(),
|
||||
battle.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 right = index + 1;
|
||||
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,
|
||||
index: u8,
|
||||
target: MoveTarget,
|
||||
battle: &Battle<'b>,
|
||||
) -> TargetList<'b> {
|
||||
battle: &Battle<'b, 'library>,
|
||||
) -> TargetList<'b, 'library> {
|
||||
match target {
|
||||
MoveTarget::Adjacent
|
||||
| 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 {
|
||||
(self.calculate_flat_stat(pokemon, stat) as f32
|
||||
* self.get_stat_boost_modifier(pokemon, stat)) as u32
|
||||
(self.calculate_flat_stat(pokemon, stat) as f32 * self.get_stat_boost_modifier(pokemon, stat)) as 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::damage_library::DamageLibrary;
|
||||
use crate::dynamic_data::libraries::misc_library::MiscLibrary;
|
||||
use crate::dynamic_data::libraries::script_resolver::ScriptCategory;
|
||||
use crate::dynamic_data::script_handling::item_script::ItemScript;
|
||||
use crate::dynamic_data::script_handling::script::Script;
|
||||
|
@ -7,27 +9,30 @@ use crate::static_data::libraries::static_data::StaticData;
|
|||
use crate::{PkmnResult, StringKey};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DynamicLibrary<'a> {
|
||||
static_data: StaticData<'a>,
|
||||
pub struct DynamicLibrary {
|
||||
static_data: StaticData<'static>,
|
||||
stat_calculator: BattleStatCalculator,
|
||||
damage_calculator: Box<dyn DamageLibrary>,
|
||||
misc_library: Box<dyn MiscLibrary<'static>>,
|
||||
}
|
||||
|
||||
impl<'a> DynamicLibrary<'a> {
|
||||
pub fn static_data(&self) -> &StaticData<'a> {
|
||||
impl<'library> DynamicLibrary {
|
||||
pub fn static_data(&self) -> &StaticData<'library> {
|
||||
&self.static_data
|
||||
}
|
||||
pub fn stat_calculator(&self) -> &BattleStatCalculator {
|
||||
&self.stat_calculator
|
||||
}
|
||||
|
||||
pub fn load_script(
|
||||
&self,
|
||||
_category: ScriptCategory,
|
||||
_key: &StringKey,
|
||||
) -> PkmnResult<Option<Box<dyn Script>>> {
|
||||
todo!()
|
||||
pub fn damage_calculator(&self) -> &Box<dyn DamageLibrary> {
|
||||
&self.damage_calculator
|
||||
}
|
||||
pub fn misc_library(&self) -> &Box<dyn MiscLibrary<'static>> {
|
||||
&self.misc_library
|
||||
}
|
||||
|
||||
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>>> {
|
||||
todo!()
|
||||
}
|
||||
|
@ -36,13 +41,17 @@ impl<'a> DynamicLibrary<'a> {
|
|||
#[cfg(test)]
|
||||
pub mod test {
|
||||
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::misc_library::Gen7MiscLibrary;
|
||||
use crate::static_data::libraries::static_data;
|
||||
|
||||
pub fn build<'a>() -> DynamicLibrary<'a> {
|
||||
pub fn build<'library>() -> DynamicLibrary {
|
||||
DynamicLibrary {
|
||||
static_data: static_data::test::build(),
|
||||
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 damage_library;
|
||||
pub mod dynamic_library;
|
||||
pub mod script_resolver;
|
||||
pub mod misc_library;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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::target_resolver::is_valid_target;
|
||||
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::volatile_scripts::VolatileScripts;
|
||||
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 std::ops::{Deref, DerefMut};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Battle<'a> {
|
||||
library: &'a DynamicLibrary<'a>,
|
||||
parties: Vec<BattleParty<'a>>,
|
||||
pub struct Battle<'own, 'library> {
|
||||
library: &'own DynamicLibrary,
|
||||
parties: Vec<BattleParty<'own, 'library>>,
|
||||
can_flee: bool,
|
||||
number_of_sides: u8,
|
||||
pokemon_per_side: u8,
|
||||
sides: Vec<BattleSide<'a>>,
|
||||
sides: Vec<BattleSide<'own, 'library>>,
|
||||
random: BattleRandom,
|
||||
current_turn_queue: Option<ChoiceQueue>,
|
||||
current_turn_queue: Option<Arc<RwLock<ChoiceQueue<'own, 'library>>>>,
|
||||
has_ended: bool,
|
||||
result: BattleResult,
|
||||
event_hook: EventHook,
|
||||
history_holder: Box<HistoryHolder>,
|
||||
current_turn: u32,
|
||||
volatile_scripts: Arc<RwLock<ScriptSet>>,
|
||||
last_turn_time: i64,
|
||||
last_turn_time: chrono::Duration,
|
||||
|
||||
script_source_data: RwLock<ScriptSourceData>,
|
||||
}
|
||||
|
||||
impl<'a> Battle<'a> {
|
||||
impl<'own, 'library> Battle<'own, 'library> {
|
||||
pub fn new(
|
||||
library: &'a DynamicLibrary<'a>,
|
||||
parties: Vec<BattleParty<'a>>,
|
||||
library: &'own DynamicLibrary,
|
||||
parties: Vec<BattleParty<'own, 'library>>,
|
||||
can_flee: bool,
|
||||
number_of_sides: u8,
|
||||
pokemon_per_side: u8,
|
||||
|
@ -68,21 +69,20 @@ impl<'a> Battle<'a> {
|
|||
history_holder: Box::new(HistoryHolder {}),
|
||||
current_turn: 0,
|
||||
volatile_scripts: Default::default(),
|
||||
last_turn_time: 0,
|
||||
last_turn_time: chrono::Duration::zero(),
|
||||
script_source_data: Default::default(),
|
||||
}));
|
||||
|
||||
for i in 0..number_of_sides {
|
||||
battle.write().sides[i as usize] =
|
||||
BattleSide::new(i, Arc::downgrade(&battle), pokemon_per_side);
|
||||
battle.write().sides[i as usize] = BattleSide::new(i, Arc::downgrade(&battle), pokemon_per_side);
|
||||
}
|
||||
battle
|
||||
}
|
||||
|
||||
pub fn library(&self) -> &'a DynamicLibrary<'a> {
|
||||
pub fn library(&self) -> &'own DynamicLibrary {
|
||||
self.library
|
||||
}
|
||||
pub fn parties(&self) -> &Vec<BattleParty<'a>> {
|
||||
pub fn parties(&self) -> &Vec<BattleParty<'own, 'library>> {
|
||||
&self.parties
|
||||
}
|
||||
pub fn can_flee(&self) -> bool {
|
||||
|
@ -94,10 +94,10 @@ impl<'a> Battle<'a> {
|
|||
pub fn pokemon_per_side(&self) -> u8 {
|
||||
self.pokemon_per_side
|
||||
}
|
||||
pub fn sides(&self) -> &Vec<BattleSide<'a>> {
|
||||
pub fn sides(&self) -> &Vec<BattleSide<'own, 'library>> {
|
||||
&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
|
||||
}
|
||||
|
||||
|
@ -119,14 +119,14 @@ impl<'a> Battle<'a> {
|
|||
pub fn current_turn(&self) -> u32 {
|
||||
self.current_turn
|
||||
}
|
||||
pub fn last_turn_time(&self) -> i64 {
|
||||
pub fn last_turn_time(&self) -> chrono::Duration {
|
||||
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
|
||||
}
|
||||
|
||||
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);
|
||||
if side.is_none() {
|
||||
return &None;
|
||||
|
@ -183,34 +183,99 @@ impl<'a> Battle<'a> {
|
|||
|
||||
pub fn can_use(&self, choice: &TurnChoice) -> bool {
|
||||
// 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;
|
||||
}
|
||||
if let TurnChoice::Move {
|
||||
used_move,
|
||||
target_side,
|
||||
target_index,
|
||||
user,
|
||||
} = choice
|
||||
{
|
||||
if let TurnChoice::Move(data) = choice {
|
||||
// TODO: Hook to change number of PP needed.
|
||||
if used_move.remaining_pp() < 1 {
|
||||
if data.used_move().read().remaining_pp() < 1 {
|
||||
return false;
|
||||
}
|
||||
if !is_valid_target(
|
||||
*target_side,
|
||||
*target_index,
|
||||
used_move.move_data().target(),
|
||||
user,
|
||||
data.target_side(),
|
||||
data.target_index(),
|
||||
data.used_move().read().move_data().target(),
|
||||
choice.user().read().deref(),
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
impl<'a> VolatileScripts<'a> for Battle<'a> {
|
||||
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<'own, 'library> VolatileScripts<'own> for Battle<'own, 'library> {
|
||||
fn volatile_scripts(&self) -> &Arc<RwLock<ScriptSet>> {
|
||||
&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 {
|
||||
1
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
use crate::dynamic_data::models::pokemon_party::PokemonParty;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BattleParty<'a> {
|
||||
party: &'a PokemonParty<'a>,
|
||||
pub struct BattleParty<'own, 'library> {
|
||||
party: &'own PokemonParty<'own, 'library>,
|
||||
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 {
|
||||
for responsible_index in &self.responsible_indices {
|
||||
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::{script_hook, script_hook_on_lock};
|
||||
use parking_lot::RwLock;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::sync::Mutex;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct BattleRandom {
|
||||
|
@ -27,6 +32,32 @@ impl BattleRandom {
|
|||
pub fn get_between(&self, min: i32, max: i32) -> i32 {
|
||||
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 {
|
||||
|
|
|
@ -13,22 +13,22 @@ use std::ops::Deref;
|
|||
use std::sync::{Arc, Weak};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BattleSide<'a> {
|
||||
pub struct BattleSide<'own, 'library> {
|
||||
index: u8,
|
||||
pokemon_per_side: u8,
|
||||
pokemon: Vec<Option<Arc<RwLock<Pokemon<'a>>>>>,
|
||||
choices: Vec<Option<Arc<TurnChoice<'a>>>>,
|
||||
pokemon: Vec<Option<Arc<RwLock<Pokemon<'own, 'library>>>>>,
|
||||
choices: Vec<Option<Arc<RwLock<TurnChoice<'own, 'library>>>>>,
|
||||
fillable_slots: Vec<bool>,
|
||||
choices_set: u8,
|
||||
battle: Weak<RwLock<Battle<'a>>>,
|
||||
battle: Weak<RwLock<Battle<'own, 'library>>>,
|
||||
has_fled_battle: bool,
|
||||
volatile_scripts: Arc<RwLock<ScriptSet>>,
|
||||
|
||||
script_source_data: RwLock<ScriptSourceData>,
|
||||
}
|
||||
|
||||
impl<'a> BattleSide<'a> {
|
||||
pub fn new(index: u8, battle: Weak<RwLock<Battle<'a>>>, pokemon_per_side: u8) -> Self {
|
||||
impl<'own, 'library> BattleSide<'own, 'library> {
|
||||
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 choices = 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 {
|
||||
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
|
||||
}
|
||||
pub fn choices(&self) -> &Vec<Option<Arc<TurnChoice<'a>>>> {
|
||||
pub fn choices(&self) -> &Vec<Option<Arc<RwLock<TurnChoice<'own, 'library>>>>> {
|
||||
&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> {
|
||||
&self.fillable_slots
|
||||
}
|
||||
pub fn choices_set(&self) -> u8 {
|
||||
self.choices_set
|
||||
}
|
||||
pub fn battle(&self) -> &Weak<RwLock<Battle<'a>>> {
|
||||
pub fn battle(&self) -> &Weak<RwLock<Battle<'own, 'library>>> {
|
||||
&self.battle
|
||||
}
|
||||
pub fn has_fled_battle(&self) -> bool {
|
||||
|
@ -103,11 +107,11 @@ impl<'a> BattleSide<'a> {
|
|||
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() {
|
||||
if let Some(pokemon) = pokemon_slot {
|
||||
if pokemon.read().unique_identifier() == choice.user().unique_identifier() {
|
||||
self.choices[index] = Some(Arc::new(choice));
|
||||
if std::ptr::eq(pokemon.data_ptr(), choice.user().data_ptr()) {
|
||||
self.choices[index] = Some(Arc::new(RwLock::new(choice)));
|
||||
self.choices_set += 1;
|
||||
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) {
|
||||
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];
|
||||
if let Some(old_pokemon) = old {
|
||||
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() {
|
||||
if p.read().unique_identifier() == pokemon.unique_identifier() {
|
||||
return true;
|
||||
|
@ -172,7 +182,7 @@ impl<'a> BattleSide<'a> {
|
|||
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() {
|
||||
if let Some(p) = slot {
|
||||
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() {
|
||||
if let Some(p) = slot {
|
||||
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>> {
|
||||
&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 {
|
||||
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>) {
|
||||
self.get_own_scripts(scripts);
|
||||
self.battle
|
||||
.upgrade()
|
||||
.unwrap()
|
||||
.read()
|
||||
.collect_scripts(scripts);
|
||||
self.battle.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::pokemon::Pokemon;
|
||||
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::{PkmnResult, PokemonError};
|
||||
use parking_lot::RwLock;
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Default, Debug)]
|
||||
pub struct HitData {
|
||||
critical: bool,
|
||||
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,
|
||||
hits: Vec<HitData>,
|
||||
user: &'a Pokemon<'b>,
|
||||
chosen_move: &'a LearnedMove<'a>,
|
||||
use_move: &'a MoveData,
|
||||
user: Arc<RwLock<Pokemon<'battle, 'library>>>,
|
||||
chosen_move: Arc<RwLock<LearnedMove<'library>>>,
|
||||
use_move: &'own MoveData,
|
||||
script: ScriptContainer,
|
||||
targets: Vec<Option<&'a Pokemon<'b>>>,
|
||||
targets: &'own TargetList<'battle, 'library>,
|
||||
script_source_data: RwLock<ScriptSourceData>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> ExecutingMove<'a, 'b> {
|
||||
impl<'own, 'battle, 'library> ExecutingMove<'own, 'battle, 'library> {
|
||||
pub fn new(
|
||||
targets: Vec<Option<&'a Pokemon<'b>>>,
|
||||
targets: &'own TargetList<'battle, 'library>,
|
||||
number_of_hits: u8,
|
||||
user: &'a Pokemon<'b>,
|
||||
chosen_move: &'a LearnedMove,
|
||||
use_move: &'a MoveData,
|
||||
user: Arc<RwLock<Pokemon<'battle, 'library>>>,
|
||||
chosen_move: Arc<RwLock<LearnedMove<'library>>>,
|
||||
use_move: &'own MoveData,
|
||||
script: ScriptContainer,
|
||||
) -> Self {
|
||||
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 {
|
||||
self.number_of_hits
|
||||
}
|
||||
pub fn user(&self) -> &'a Pokemon<'b> {
|
||||
self.user
|
||||
pub fn user(&self) -> &Arc<RwLock<Pokemon<'battle, 'library>>> {
|
||||
&self.user
|
||||
}
|
||||
pub fn chosen_move(&self) -> &'a LearnedMove {
|
||||
self.chosen_move
|
||||
pub fn chosen_move(&self) -> &Arc<RwLock<LearnedMove<'library>>> {
|
||||
&self.chosen_move
|
||||
}
|
||||
pub fn use_move(&self) -> &'a MoveData {
|
||||
|
||||
pub fn use_move(&self) -> &'own MoveData {
|
||||
self.use_move
|
||||
}
|
||||
pub fn script(&self) -> &ScriptContainer {
|
||||
&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() {
|
||||
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;
|
||||
return Ok(&self.hits[i]);
|
||||
}
|
||||
|
@ -124,29 +131,39 @@ impl<'a, 'b> ExecutingMove<'a, 'b> {
|
|||
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() {
|
||||
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;
|
||||
return Ok(&self.hits[i..i + self.number_of_hits as usize]);
|
||||
return Ok(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(PokemonError::InvalidTargetRequested)
|
||||
}
|
||||
|
||||
pub fn is_pokemon_target(&self, pokemon: &Pokemon<'b>) -> bool {
|
||||
for target in self.targets.iter().flatten() {
|
||||
if std::ptr::eq(target.deref(), pokemon) {
|
||||
return true;
|
||||
pub(crate) fn get_hit_from_raw_index(&self, index: usize) -> &HitData {
|
||||
&self.hits[index]
|
||||
}
|
||||
}
|
||||
false
|
||||
pub(crate) fn get_hit_from_raw_index_mut(&mut self, index: usize) -> &mut HitData {
|
||||
&mut self.hits[index]
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
1
|
||||
}
|
||||
|
@ -161,6 +178,6 @@ impl<'a, 'b> ScriptSource<'a> for ExecutingMove<'a, 'b> {
|
|||
|
||||
fn collect_scripts(&self, scripts: &mut Vec<ScriptWrapper>) {
|
||||
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;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LearnedMove<'a> {
|
||||
move_data: &'a MoveData,
|
||||
pub struct LearnedMove<'library> {
|
||||
move_data: &'library MoveData,
|
||||
max_pp: u8,
|
||||
remaining_pp: u8,
|
||||
learn_method: MoveLearnMethod,
|
||||
|
@ -37,4 +37,12 @@ impl<'a> LearnedMove<'a> {
|
|||
pub fn learn_method(&self) -> MoveLearnMethod {
|
||||
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 pokemon;
|
||||
pub mod pokemon_party;
|
||||
pub mod pokemon_builder;
|
||||
|
|
|
@ -23,44 +23,47 @@ use parking_lot::RwLock;
|
|||
use std::sync::{Arc, Weak};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PokemonBattleData<'a> {
|
||||
battle: Weak<RwLock<Battle<'a>>>,
|
||||
pub struct PokemonBattleData<'pokemon, 'library> {
|
||||
battle: Weak<RwLock<Battle<'pokemon, 'library>>>,
|
||||
battle_side_index: u8,
|
||||
index: u8,
|
||||
on_battle_field: bool,
|
||||
seen_opponents: Vec<Weak<RwLock<Pokemon<'a>>>>,
|
||||
seen_opponents: Vec<Weak<RwLock<Pokemon<'pokemon, 'library>>>>,
|
||||
}
|
||||
|
||||
impl<'a> PokemonBattleData<'a> {
|
||||
pub fn battle(&'a mut self) -> &'a mut Weak<RwLock<Battle<'a>>> {
|
||||
impl<'pokemon, 'library> PokemonBattleData<'pokemon, 'library> {
|
||||
pub fn battle(&mut self) -> &mut Weak<RwLock<Battle<'pokemon, 'library>>> {
|
||||
&mut self.battle
|
||||
}
|
||||
pub fn battle_side_index(&self) -> u8 {
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Pokemon<'a> {
|
||||
library: &'a DynamicLibrary<'a>,
|
||||
species: &'a Species<'a>,
|
||||
form: &'a Form<'a>,
|
||||
pub struct Pokemon<'own, 'library>
|
||||
where
|
||||
'own: 'library,
|
||||
{
|
||||
library: &'own DynamicLibrary,
|
||||
species: &'own Species<'library>,
|
||||
form: &'own Form<'library>,
|
||||
|
||||
display_species: Option<&'a Species<'a>>,
|
||||
display_form: Option<&'a Form<'a>>,
|
||||
display_species: Option<&'own Species<'library>>,
|
||||
display_form: Option<&'own Form<'library>>,
|
||||
|
||||
level: LevelInt,
|
||||
experience: u32,
|
||||
unique_identifier: u32,
|
||||
gender: Gender,
|
||||
coloring: u8,
|
||||
held_item: Option<&'a Item>,
|
||||
held_item: Option<&'own Item>,
|
||||
current_health: u32,
|
||||
|
||||
weight: f32,
|
||||
|
@ -71,7 +74,7 @@ pub struct Pokemon<'a> {
|
|||
boosted_stats: StatisticSet<u32>,
|
||||
individual_values: ClampedStatisticSet<u8, 0, 31>,
|
||||
effort_values: ClampedStatisticSet<u8, 0, 252>,
|
||||
nature: &'a Nature,
|
||||
nature: &'own Nature,
|
||||
|
||||
nickname: Option<String>,
|
||||
|
||||
|
@ -79,9 +82,9 @@ pub struct Pokemon<'a> {
|
|||
is_ability_overridden: bool,
|
||||
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,
|
||||
|
||||
types: Vec<u8>,
|
||||
|
@ -96,18 +99,18 @@ pub struct Pokemon<'a> {
|
|||
script_source_data: RwLock<ScriptSourceData>,
|
||||
}
|
||||
|
||||
impl<'a> Pokemon<'a> {
|
||||
impl<'own, 'library> Pokemon<'own, 'library> {
|
||||
pub fn new(
|
||||
library: &'a DynamicLibrary,
|
||||
species: &'a Species,
|
||||
form: &'a Form,
|
||||
library: &'own DynamicLibrary,
|
||||
species: &'own Species,
|
||||
form: &'own Form,
|
||||
ability: AbilityIndex,
|
||||
level: LevelInt,
|
||||
unique_identifier: u32,
|
||||
gender: Gender,
|
||||
coloring: u8,
|
||||
nature: &StringKey,
|
||||
) -> Pokemon<'a> {
|
||||
) -> Self {
|
||||
// Calculate experience from the level for the specified growth rate.
|
||||
let experience = library
|
||||
.static_data()
|
||||
|
@ -121,7 +124,7 @@ impl<'a> Pokemon<'a> {
|
|||
.natures()
|
||||
.get_nature(&nature)
|
||||
.expect("Unknown nature name was given.");
|
||||
let mut pokemon = Pokemon {
|
||||
let mut pokemon = Self {
|
||||
library,
|
||||
species,
|
||||
form,
|
||||
|
@ -162,23 +165,23 @@ impl<'a> Pokemon<'a> {
|
|||
pokemon
|
||||
}
|
||||
|
||||
pub fn library(&self) -> &'a DynamicLibrary<'a> {
|
||||
pub fn library(&self) -> &'own DynamicLibrary {
|
||||
self.library
|
||||
}
|
||||
pub fn species(&self) -> &'a Species<'a> {
|
||||
pub fn species(&self) -> &'own Species<'library> {
|
||||
self.species
|
||||
}
|
||||
pub fn form(&self) -> &'a Form<'a> {
|
||||
pub fn form(&self) -> &'own Form<'library> {
|
||||
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 {
|
||||
v
|
||||
} else {
|
||||
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 {
|
||||
v
|
||||
} else {
|
||||
|
@ -201,7 +204,7 @@ impl<'a> Pokemon<'a> {
|
|||
pub fn coloring(&self) -> u8 {
|
||||
self.coloring
|
||||
}
|
||||
pub fn held_item(&self) -> Option<&'a Item> {
|
||||
pub fn held_item(&self) -> Option<&'own Item> {
|
||||
self.held_item
|
||||
}
|
||||
pub fn has_held_item(&self, name: &StringKey) -> bool {
|
||||
|
@ -211,7 +214,7 @@ impl<'a> Pokemon<'a> {
|
|||
}
|
||||
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);
|
||||
}
|
||||
pub fn remove_held_item(&mut self) {
|
||||
|
@ -221,10 +224,7 @@ impl<'a> Pokemon<'a> {
|
|||
if self.held_item.is_none() {
|
||||
return false;
|
||||
}
|
||||
let script = self
|
||||
.library
|
||||
.load_item_script(self.held_item.unwrap())
|
||||
.unwrap();
|
||||
let script = self.library.load_item_script(self.held_item.unwrap()).unwrap();
|
||||
if script.is_none() {
|
||||
return false;
|
||||
}
|
||||
|
@ -276,7 +276,7 @@ impl<'a> Pokemon<'a> {
|
|||
&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 {
|
||||
Some(&data.battle)
|
||||
} else {
|
||||
|
@ -305,7 +305,7 @@ impl<'a> Pokemon<'a> {
|
|||
&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 {
|
||||
Some(&data.seen_opponents)
|
||||
} else {
|
||||
|
@ -316,7 +316,7 @@ impl<'a> Pokemon<'a> {
|
|||
self.allowed_experience
|
||||
}
|
||||
|
||||
pub fn nature(&self) -> &'a Nature {
|
||||
pub fn nature(&self) -> &'own Nature {
|
||||
self.nature
|
||||
}
|
||||
|
||||
|
@ -328,7 +328,7 @@ impl<'a> Pokemon<'a> {
|
|||
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.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) {
|
||||
return;
|
||||
}
|
||||
|
@ -409,10 +409,10 @@ impl<'a> Pokemon<'a> {
|
|||
|
||||
if let Some(battle_data) = &self.battle_data {
|
||||
if let Some(battle) = battle_data.battle.upgrade() {
|
||||
battle.read().event_hook().trigger(Event::FormChange {
|
||||
pokemon: self,
|
||||
form,
|
||||
})
|
||||
battle
|
||||
.read()
|
||||
.event_hook()
|
||||
.trigger(Event::FormChange { pokemon: self, form })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -425,7 +425,7 @@ impl<'a> Pokemon<'a> {
|
|||
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 {
|
||||
battle_data.battle = battle;
|
||||
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 {
|
||||
for seen_opponent in &battle_data.seen_opponents {
|
||||
if seen_opponent.ptr_eq(&pokemon) {
|
||||
|
@ -493,14 +493,7 @@ impl<'a> Pokemon<'a> {
|
|||
new_health,
|
||||
});
|
||||
// TODO: register history
|
||||
script_hook!(
|
||||
on_damage,
|
||||
self,
|
||||
self,
|
||||
source,
|
||||
self.current_health,
|
||||
new_health
|
||||
);
|
||||
script_hook!(on_damage, self, self, source, 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) {
|
||||
if let Some(battle_data) = &self.battle_data {
|
||||
if let Some(battle) = battle_data.battle.upgrade() {
|
||||
battle
|
||||
.read()
|
||||
.event_hook()
|
||||
.trigger(Event::Faint { pokemon: self });
|
||||
battle.read().event_hook().trigger(Event::Faint { pokemon: self });
|
||||
script_hook!(on_faint, self, self, source);
|
||||
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 {
|
||||
let mut c = 3;
|
||||
if let Some(battle_data) = &self.battle_data {
|
||||
if let Some(battle) = battle_data.battle.upgrade() {
|
||||
c += battle.read().sides()[battle_data.battle_side_index as usize]
|
||||
.get_script_count();
|
||||
c += battle.read().sides()[battle_data.battle_side_index as usize].get_script_count();
|
||||
}
|
||||
}
|
||||
c
|
||||
|
@ -563,14 +552,13 @@ impl<'a> ScriptSource<'a> for Pokemon<'a> {
|
|||
self.get_own_scripts(scripts);
|
||||
if let Some(battle_data) = &self.battle_data {
|
||||
if let Some(battle) = battle_data.battle.upgrade() {
|
||||
battle.read().sides()[battle_data.battle_side_index as usize]
|
||||
.collect_scripts(scripts);
|
||||
battle.read().sides()[battle_data.battle_side_index as usize].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>> {
|
||||
&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};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PokemonParty<'a> {
|
||||
pokemon: Vec<Option<Arc<RwLock<Pokemon<'a>>>>>,
|
||||
pub struct PokemonParty<'pokemon, 'library> {
|
||||
pokemon: Vec<Option<Arc<RwLock<Pokemon<'pokemon, 'library>>>>>,
|
||||
}
|
||||
|
||||
impl<'a> PokemonParty<'a> {
|
||||
impl<'own, 'library> PokemonParty<'own, 'library> {
|
||||
pub fn new(size: usize) -> Self {
|
||||
let mut pokemon = Vec::with_capacity(size);
|
||||
for _i in 0..size {
|
||||
|
@ -15,7 +15,7 @@ impl<'a> PokemonParty<'a> {
|
|||
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);
|
||||
if let Some(v) = opt {
|
||||
v
|
||||
|
@ -31,8 +31,8 @@ impl<'a> PokemonParty<'a> {
|
|||
pub fn swap_into(
|
||||
&mut self,
|
||||
index: usize,
|
||||
pokemon: Option<Arc<RwLock<Pokemon<'a>>>>,
|
||||
) -> Option<Arc<RwLock<Pokemon<'a>>>> {
|
||||
pokemon: Option<Arc<RwLock<Pokemon<'own, 'library>>>>,
|
||||
) -> Option<Arc<RwLock<Pokemon<'own, 'library>>>> {
|
||||
if index >= self.pokemon.len() {
|
||||
return pokemon;
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ impl<'a> PokemonParty<'a> {
|
|||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)]
|
||||
pub struct ScriptSourceData {
|
||||
is_initialized: bool,
|
||||
|
@ -310,25 +356,11 @@ mod tests {
|
|||
let scripts = vec![ScriptWrapper::from(&set)];
|
||||
let mut aggregator = ScriptAggregator::new(&scripts as *const Vec<ScriptWrapper>);
|
||||
assert_eq!(
|
||||
aggregator
|
||||
.get_next()
|
||||
.unwrap()
|
||||
.get()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.name()
|
||||
.str(),
|
||||
aggregator.get_next().unwrap().get().as_mut().unwrap().name().str(),
|
||||
"test_a"
|
||||
);
|
||||
assert_eq!(
|
||||
aggregator
|
||||
.get_next()
|
||||
.unwrap()
|
||||
.get()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.name()
|
||||
.str(),
|
||||
aggregator.get_next().unwrap().get().as_mut().unwrap().name().str(),
|
||||
"test_b"
|
||||
);
|
||||
|
||||
|
@ -352,14 +384,7 @@ mod tests {
|
|||
let scripts = vec![ScriptWrapper::from(&set)];
|
||||
let mut aggregator = ScriptAggregator::new(&scripts as *const Vec<ScriptWrapper>);
|
||||
assert_eq!(
|
||||
aggregator
|
||||
.get_next()
|
||||
.unwrap()
|
||||
.get()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.name()
|
||||
.str(),
|
||||
aggregator.get_next().unwrap().get().as_mut().unwrap().name().str(),
|
||||
"test_a"
|
||||
);
|
||||
|
||||
|
@ -368,14 +393,7 @@ mod tests {
|
|||
drop(mut_set);
|
||||
|
||||
assert_eq!(
|
||||
aggregator
|
||||
.get_next()
|
||||
.unwrap()
|
||||
.get()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.name()
|
||||
.str(),
|
||||
aggregator.get_next().unwrap().get().as_mut().unwrap().name().str(),
|
||||
"test_c"
|
||||
);
|
||||
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::damage_source::DamageSource;
|
||||
use crate::dynamic_data::models::executing_move::ExecutingMove;
|
||||
|
@ -27,26 +27,27 @@ pub trait Script {
|
|||
fn on_before_turn(&mut self, _choice: &TurnChoice) {}
|
||||
fn change_speed(&mut self, _choice: &TurnChoice, _speed: &mut u32) {}
|
||||
fn change_priority(&mut self, _choice: &TurnChoice, _priority: &mut i8) {}
|
||||
fn change_move(&mut self, _choice: &TurnChoice, _move_name: &mut StringKey) {}
|
||||
fn change_number_of_hits(&mut self, _choice: &TurnChoice, _number_of_hits: &mut u8) {}
|
||||
fn change_move(&mut self, _choice: &MoveChoice, _move_name: &mut StringKey) {}
|
||||
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 fail_move(&mut self, _move: &ExecutingMove, _fail: &mut bool) {}
|
||||
fn stop_before_move(&mut self, _move: &ExecutingMove, _stop: &mut bool) {}
|
||||
fn on_before_move(&mut self, _move: &ExecutingMove) {}
|
||||
fn fail_incoming_move(&mut self, _move: &ExecutingMove, _target: &Pokemon, _fail: &mut bool) {}
|
||||
fn is_invulnerable(
|
||||
fn fail_incoming_move(&mut self, _move: &ExecutingMove, _target: &Arc<RwLock<Pokemon>>, _fail: &mut bool) {}
|
||||
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,
|
||||
_move: &ExecutingMove,
|
||||
_target: &Pokemon,
|
||||
_invulnerable: &mut bool,
|
||||
_target: &Arc<RwLock<Pokemon>>,
|
||||
_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(
|
||||
&mut self,
|
||||
_move: &ExecutingMove,
|
||||
_target: &Pokemon,
|
||||
_target: &Arc<RwLock<Pokemon>>,
|
||||
_hit: u8,
|
||||
_effectiveness: &mut f32,
|
||||
) {
|
||||
|
@ -54,7 +55,7 @@ pub trait Script {
|
|||
fn block_critical(
|
||||
&mut self,
|
||||
_move: &ExecutingMove,
|
||||
_target: &Pokemon,
|
||||
_target: &Arc<RwLock<Pokemon>>,
|
||||
_hit: u8,
|
||||
_block_critical: &mut bool,
|
||||
) {
|
||||
|
@ -62,7 +63,7 @@ pub trait Script {
|
|||
fn block_incoming_critical(
|
||||
&mut self,
|
||||
_move: &ExecutingMove,
|
||||
_target: &Pokemon,
|
||||
_target: &Arc<RwLock<Pokemon>>,
|
||||
_hit: u8,
|
||||
_block_critical: &mut bool,
|
||||
) {
|
||||
|
@ -70,7 +71,7 @@ pub trait Script {
|
|||
fn change_critical_stage(
|
||||
&mut self,
|
||||
_move: &ExecutingMove,
|
||||
_target: &Pokemon,
|
||||
_target: &Arc<RwLock<Pokemon>>,
|
||||
_hit: u8,
|
||||
_stage: &mut u8,
|
||||
) {
|
||||
|
@ -78,7 +79,7 @@ pub trait Script {
|
|||
fn change_critical_modifier(
|
||||
&mut self,
|
||||
_move: &ExecutingMove,
|
||||
_target: &Pokemon,
|
||||
_target: &Arc<RwLock<Pokemon>>,
|
||||
_hit: u8,
|
||||
_modifier: &mut f32,
|
||||
) {
|
||||
|
@ -86,7 +87,7 @@ pub trait Script {
|
|||
fn change_stab_modifier(
|
||||
&mut self,
|
||||
_move: &ExecutingMove,
|
||||
_target: &Pokemon,
|
||||
_target: &Arc<RwLock<Pokemon>>,
|
||||
_hit: u8,
|
||||
_modifier: &mut f32,
|
||||
) {
|
||||
|
@ -95,7 +96,7 @@ pub trait Script {
|
|||
fn change_base_power(
|
||||
&mut self,
|
||||
_move: &ExecutingMove,
|
||||
_target: &Pokemon,
|
||||
_target: &Arc<RwLock<Pokemon>>,
|
||||
_hit: u8,
|
||||
_base_power: &mut u8,
|
||||
) {
|
||||
|
@ -103,48 +104,48 @@ pub trait Script {
|
|||
fn change_damage_stats_user(
|
||||
&mut self,
|
||||
_move: &ExecutingMove,
|
||||
_target: &Pokemon,
|
||||
_target: &Arc<RwLock<Pokemon>>,
|
||||
_hit: u8,
|
||||
_stats_user: &mut Pokemon,
|
||||
_stats_user: &mut Arc<RwLock<Pokemon>>,
|
||||
) {
|
||||
}
|
||||
fn bypass_defensive_stat(
|
||||
fn bypass_defensive_stat_boost(
|
||||
&mut self,
|
||||
_move: &ExecutingMove,
|
||||
_target: &Pokemon,
|
||||
_target: &Arc<RwLock<Pokemon>>,
|
||||
_hit: u8,
|
||||
_bypass: &mut bool,
|
||||
) {
|
||||
}
|
||||
fn bypass_offensive_stat(
|
||||
fn bypass_offensive_stat_boost(
|
||||
&mut self,
|
||||
_move: &ExecutingMove,
|
||||
_target: &Pokemon,
|
||||
_target: &Arc<RwLock<Pokemon>>,
|
||||
_hit: u8,
|
||||
_bypass: &mut bool,
|
||||
) {
|
||||
}
|
||||
fn change_offensive_stat(
|
||||
fn change_offensive_stat_value(
|
||||
&mut self,
|
||||
_move: &ExecutingMove,
|
||||
_target: &Pokemon,
|
||||
_target: &Arc<RwLock<Pokemon>>,
|
||||
_hit: u8,
|
||||
_amount: &mut f32,
|
||||
_amount: &mut u32,
|
||||
) {
|
||||
}
|
||||
fn change_defensive_stat(
|
||||
fn change_defensive_stat_value(
|
||||
&mut self,
|
||||
_move: &ExecutingMove,
|
||||
_target: &Pokemon,
|
||||
_target: &Arc<RwLock<Pokemon>>,
|
||||
_hit: u8,
|
||||
_amount: &mut f32,
|
||||
_amount: &mut u32,
|
||||
) {
|
||||
}
|
||||
|
||||
fn change_stat_modifier(
|
||||
fn change_damage_stat_modifier(
|
||||
&mut self,
|
||||
_move: &ExecutingMove,
|
||||
_target: &Pokemon,
|
||||
_target: &Arc<RwLock<Pokemon>>,
|
||||
_hit: u8,
|
||||
_modifier: &mut f32,
|
||||
) {
|
||||
|
@ -152,29 +153,22 @@ pub trait Script {
|
|||
fn change_damage_modifier(
|
||||
&mut self,
|
||||
_move: &ExecutingMove,
|
||||
_target: &Pokemon,
|
||||
_target: &Arc<RwLock<Pokemon>>,
|
||||
_hit: u8,
|
||||
_modifier: &mut f32,
|
||||
) {
|
||||
}
|
||||
fn change_damage(
|
||||
&mut self,
|
||||
_move: &ExecutingMove,
|
||||
_target: &Pokemon,
|
||||
_hit: u8,
|
||||
_damage: &mut u32,
|
||||
) {
|
||||
}
|
||||
fn change_damage(&mut self, _move: &ExecutingMove, _target: &Arc<RwLock<Pokemon>>, _hit: u8, _damage: &mut u32) {}
|
||||
fn change_incoming_damage(
|
||||
&mut self,
|
||||
_move: &ExecutingMove,
|
||||
_target: &Pokemon,
|
||||
_target: &Arc<RwLock<Pokemon>>,
|
||||
_hit: u8,
|
||||
_damage: &mut u32,
|
||||
) {
|
||||
}
|
||||
fn on_incoming_hit(&mut self, _move: &ExecutingMove, _target: &Pokemon, _hit: u8) {}
|
||||
fn on_opponent_faints(&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: &Arc<RwLock<Pokemon>>, _hit: u8) {}
|
||||
fn prevent_stat_boost_change(
|
||||
&mut self,
|
||||
_target: &Pokemon,
|
||||
|
@ -195,7 +189,7 @@ pub trait Script {
|
|||
fn prevent_secondary_effect(
|
||||
&mut self,
|
||||
_move: &ExecutingMove,
|
||||
_target: &Pokemon,
|
||||
_target: &Arc<RwLock<Pokemon>>,
|
||||
_hit: u8,
|
||||
_prevent: &mut bool,
|
||||
) {
|
||||
|
@ -203,21 +197,21 @@ pub trait Script {
|
|||
fn change_effect_chance(
|
||||
&mut self,
|
||||
_move: &ExecutingMove,
|
||||
_target: &Pokemon,
|
||||
_target: &Arc<RwLock<Pokemon>>,
|
||||
_hit: u8,
|
||||
_chance: &mut f32,
|
||||
) {
|
||||
}
|
||||
fn change_incoming_effect_change(
|
||||
fn change_incoming_effect_chance(
|
||||
&mut self,
|
||||
_move: &ExecutingMove,
|
||||
_target: &Pokemon,
|
||||
_target: &Arc<RwLock<Pokemon>>,
|
||||
_hit: u8,
|
||||
_chance: &mut f32,
|
||||
) {
|
||||
}
|
||||
fn on_secondary_effect(&mut self, _move: &ExecutingMove, _target: &Pokemon, _hit: u8) {}
|
||||
fn on_after_hits(&mut self, _move: &ExecutingMove, _target: &Pokemon) {}
|
||||
fn on_secondary_effect(&mut self, _move: &ExecutingMove, _target: &Arc<RwLock<Pokemon>>, _hit: u8) {}
|
||||
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_opponent_switch(&mut self, _choice: &TurnChoice, _prevent: &mut bool) {}
|
||||
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_opponent_run_away(&mut self, _choice: &TurnChoice, _prevent: &mut bool) {}
|
||||
fn on_end_turn(&mut self) {}
|
||||
fn on_damage(
|
||||
&mut self,
|
||||
_pokemon: &Pokemon,
|
||||
_source: DamageSource,
|
||||
_old_health: u32,
|
||||
_new_health: u32,
|
||||
) {
|
||||
}
|
||||
fn on_damage(&mut self, _pokemon: &Pokemon, _source: DamageSource, _old_health: u32, _new_health: u32) {}
|
||||
fn on_faint(&mut self, _pokemon: &Pokemon, _source: DamageSource) {}
|
||||
fn on_switch_in(&mut self, _pokemon: &Pokemon) {}
|
||||
fn on_after_held_item_consume(&mut self, _pokemon: &Pokemon, _item: &Item) {}
|
||||
fn change_experience_gained(
|
||||
&mut self,
|
||||
_fainted_mon: &Pokemon,
|
||||
_winning_mon: &Pokemon,
|
||||
_amount: &mut u32,
|
||||
) {
|
||||
}
|
||||
fn share_experience(
|
||||
&mut self,
|
||||
_fainted_mon: &Pokemon,
|
||||
_winning_mon: &Pokemon,
|
||||
_shares: &mut bool,
|
||||
) {
|
||||
}
|
||||
fn change_experience_gained(&mut self, _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 change_capture_rate_bonus(
|
||||
&mut self,
|
||||
_target: &Pokemon,
|
||||
_pokeball: &Item,
|
||||
_modifier: &mut u8,
|
||||
) {
|
||||
}
|
||||
fn change_capture_rate_bonus(&mut self, _target: &Pokemon, _pokeball: &Item, _modifier: &mut u8) {}
|
||||
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
}
|
||||
|
|
|
@ -16,16 +16,11 @@ impl ScriptSet {
|
|||
return lock.clone();
|
||||
}
|
||||
}
|
||||
self.scripts
|
||||
.insert(script.name().clone(), ScriptContainer::new(script));
|
||||
self.scripts.insert(script.name().clone(), ScriptContainer::new(script));
|
||||
self.scripts.last().unwrap().1.clone()
|
||||
}
|
||||
|
||||
pub fn stack_or_add<'b, F>(
|
||||
&mut self,
|
||||
key: &StringKey,
|
||||
instantiation: &'b F,
|
||||
) -> PkmnResult<Option<ScriptContainer>>
|
||||
pub fn stack_or_add<'b, F>(&mut self, key: &StringKey, instantiation: &'b F) -> PkmnResult<Option<ScriptContainer>>
|
||||
where
|
||||
F: Fn() -> PkmnResult<Option<Box<dyn Script>>>,
|
||||
{
|
||||
|
@ -76,4 +71,8 @@ impl ScriptSet {
|
|||
pub fn count(&self) -> usize {
|
||||
self.scripts.len()
|
||||
}
|
||||
|
||||
pub(crate) fn get_underlying(&self) -> &IndexMap<StringKey, ScriptContainer> {
|
||||
&self.scripts
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
#![feature(test)]
|
||||
#![feature(bench_black_box)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(once_cell)]
|
||||
|
||||
extern crate core;
|
||||
extern crate lazy_static;
|
||||
|
||||
use crate::dynamic_data::libraries::script_resolver::ScriptCategory;
|
||||
|
||||
|
@ -19,10 +19,7 @@ pub mod utils;
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum PokemonError {
|
||||
ScriptNotFound {
|
||||
category: ScriptCategory,
|
||||
name: String,
|
||||
},
|
||||
ScriptNotFound { category: ScriptCategory, name: String },
|
||||
MiscError,
|
||||
InvalidTargetRequested,
|
||||
}
|
||||
|
|
|
@ -43,11 +43,7 @@ pub mod tests {
|
|||
let mut lib = AbilityLibrary::new(1);
|
||||
lib.add(
|
||||
&StringKey::new("test_ability"),
|
||||
Box::new(Ability::new(
|
||||
&"test_ability".into(),
|
||||
&"test_ability".into(),
|
||||
Vec::new(),
|
||||
)),
|
||||
Box::new(Ability::new(&"test_ability".into(), &"test_ability".into(), Vec::new())),
|
||||
);
|
||||
// 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::secondary_effect::SecondaryEffect;
|
||||
use crate::StringKey;
|
||||
use std::collections::HashSet;
|
||||
use hashbrown::HashSet;
|
||||
|
||||
fn build_move() -> MoveData {
|
||||
MoveData::new(
|
||||
|
|
|
@ -27,12 +27,7 @@ impl<'a> DataLibrary<'a, Box<Species<'a>>> for SpeciesLibrary<'a> {
|
|||
&self.list
|
||||
}
|
||||
|
||||
fn get_modify(
|
||||
&mut self,
|
||||
) -> (
|
||||
&mut HashMap<StringKey, Box<Species<'a>>>,
|
||||
&mut Vec<StringKey>,
|
||||
) {
|
||||
fn get_modify(&mut self) -> (&mut HashMap<StringKey, Box<Species<'a>>>, &mut Vec<StringKey>) {
|
||||
(&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::static_data::StaticData;
|
||||
use crate::static_data::libraries::{
|
||||
ability_library, growth_rate_library, item_library, move_library, species_library,
|
||||
type_library,
|
||||
ability_library, growth_rate_library, item_library, move_library, species_library, type_library,
|
||||
};
|
||||
use crate::static_data::natures;
|
||||
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
use crate::static_data::SecondaryEffect;
|
||||
use crate::StringKey;
|
||||
use std::collections::HashSet;
|
||||
use hashbrown::HashSet;
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
|
||||
pub enum MoveCategory {
|
||||
Physical = 0,
|
||||
Special = 1,
|
||||
|
@ -10,6 +15,7 @@ pub enum MoveCategory {
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub enum MoveTarget {
|
||||
Adjacent = 0,
|
||||
AdjacentAlly,
|
||||
|
@ -25,6 +31,7 @@ pub enum MoveTarget {
|
|||
Any,
|
||||
|
||||
RandomOpponent,
|
||||
#[cfg_attr(feature = "serde", serde(rename = "Self"))]
|
||||
SelfUse,
|
||||
}
|
||||
|
||||
|
@ -39,7 +46,7 @@ pub struct MoveData {
|
|||
target: MoveTarget,
|
||||
priority: i8,
|
||||
secondary_effect: SecondaryEffect,
|
||||
flags: HashSet<String>,
|
||||
flags: HashSet<StringKey>,
|
||||
}
|
||||
|
||||
impl MoveData {
|
||||
|
@ -53,7 +60,7 @@ impl MoveData {
|
|||
target: MoveTarget,
|
||||
priority: i8,
|
||||
secondary_effect: SecondaryEffect,
|
||||
flags: HashSet<String>,
|
||||
flags: HashSet<StringKey>,
|
||||
) -> MoveData {
|
||||
MoveData {
|
||||
name: name.clone(),
|
||||
|
@ -99,7 +106,11 @@ impl MoveData {
|
|||
&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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use crate::StringKey;
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub enum EffectParameter {
|
||||
Bool(bool),
|
||||
|
@ -9,7 +11,7 @@ pub enum EffectParameter {
|
|||
#[derive(PartialEq, Debug)]
|
||||
pub struct SecondaryEffect {
|
||||
chance: f32,
|
||||
effect_name: String,
|
||||
effect_name: StringKey,
|
||||
parameters: Vec<EffectParameter>,
|
||||
}
|
||||
|
||||
|
@ -17,15 +19,11 @@ impl SecondaryEffect {
|
|||
pub fn empty() -> SecondaryEffect {
|
||||
SecondaryEffect {
|
||||
chance: 0.0,
|
||||
effect_name: "".to_string(),
|
||||
effect_name: StringKey::empty(),
|
||||
parameters: vec![],
|
||||
}
|
||||
}
|
||||
pub fn new(
|
||||
chance: f32,
|
||||
effect_name: String,
|
||||
parameters: Vec<EffectParameter>,
|
||||
) -> SecondaryEffect {
|
||||
pub fn new(chance: f32, effect_name: StringKey, parameters: Vec<EffectParameter>) -> SecondaryEffect {
|
||||
SecondaryEffect {
|
||||
chance,
|
||||
effect_name,
|
||||
|
@ -36,7 +34,7 @@ impl SecondaryEffect {
|
|||
pub fn chance(&self) -> f32 {
|
||||
self.chance
|
||||
}
|
||||
pub fn effect_name(&self) -> &str {
|
||||
pub fn effect_name(&self) -> &StringKey {
|
||||
&self.effect_name
|
||||
}
|
||||
pub fn parameters(&self) -> &Vec<EffectParameter> {
|
||||
|
@ -53,11 +51,11 @@ mod tests {
|
|||
fn create_secondary_effect() {
|
||||
let empty = SecondaryEffect::empty();
|
||||
assert_approx_eq!(empty.chance(), 0.0);
|
||||
assert_eq!(empty.effect_name(), "");
|
||||
assert_eq!(empty.effect_name(), &"".into());
|
||||
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_eq!(set.effect_name(), "foo");
|
||||
assert_eq!(set.effect_name(), &"foo".into());
|
||||
assert_eq!(set.parameters().len(), 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,10 +95,7 @@ pub mod tests {
|
|||
#[test]
|
||||
fn create_nature_library_insert_and_retrieve() {
|
||||
let mut lib = NatureLibrary::new(2);
|
||||
lib.load_nature(
|
||||
"foo".into(),
|
||||
Nature::new(Statistic::HP, Statistic::Attack, 1.1, 0.9),
|
||||
);
|
||||
lib.load_nature("foo".into(), Nature::new(Statistic::HP, Statistic::Attack, 1.1, 0.9));
|
||||
lib.load_nature(
|
||||
"bar".into(),
|
||||
Nature::new(Statistic::Attack, Statistic::Defense, 1.1, 0.9),
|
||||
|
@ -113,10 +110,7 @@ pub mod tests {
|
|||
#[test]
|
||||
fn create_nature_library_insert_and_get_name() {
|
||||
let mut lib = NatureLibrary::new(2);
|
||||
lib.load_nature(
|
||||
"foo".into(),
|
||||
Nature::new(Statistic::HP, Statistic::Attack, 1.1, 0.9),
|
||||
);
|
||||
lib.load_nature("foo".into(), Nature::new(Statistic::HP, Statistic::Attack, 1.1, 0.9));
|
||||
lib.load_nature(
|
||||
"bar".into(),
|
||||
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]
|
||||
}
|
||||
pub fn get_random_hidden_ability(&self, rand: &mut Random) -> &Ability {
|
||||
self.hidden_abilities
|
||||
[rand.get_between_unsigned(0, self.hidden_abilities.len() as u32) as usize]
|
||||
self.hidden_abilities[rand.get_between_unsigned(0, self.hidden_abilities.len() as u32) as usize]
|
||||
}
|
||||
|
||||
pub fn has_flag(&self, key: &StringKey) -> bool {
|
||||
|
|
|
@ -3,6 +3,7 @@ use crate::static_data::Gender;
|
|||
use crate::Random;
|
||||
use crate::StringKey;
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use std::lazy::SyncLazy;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Species<'a> {
|
||||
|
@ -14,9 +15,8 @@ pub struct Species<'a> {
|
|||
forms: HashMap<StringKey, Form<'a>>,
|
||||
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> {
|
||||
pub fn new(
|
||||
|
|
|
@ -18,14 +18,7 @@ impl<T> StatisticSet<T>
|
|||
where
|
||||
T: PrimInt,
|
||||
{
|
||||
pub fn new(
|
||||
hp: T,
|
||||
attack: T,
|
||||
defense: T,
|
||||
special_attack: T,
|
||||
special_defense: T,
|
||||
speed: T,
|
||||
) -> Self {
|
||||
pub fn new(hp: T, attack: T, defense: T, special_attack: T, special_defense: T, speed: T) -> Self {
|
||||
Self {
|
||||
hp,
|
||||
attack,
|
||||
|
@ -117,21 +110,13 @@ impl<T, const MIN: i64, const MAX: i64> ClampedStatisticSet<T, MIN, MAX>
|
|||
where
|
||||
T: PrimInt,
|
||||
{
|
||||
pub fn new(
|
||||
hp: T,
|
||||
attack: T,
|
||||
defense: T,
|
||||
special_attack: T,
|
||||
special_defense: T,
|
||||
speed: T,
|
||||
) -> Self {
|
||||
pub fn new(hp: T, attack: T, defense: T, special_attack: T, special_defense: T, speed: T) -> Self {
|
||||
Self {
|
||||
hp: cast(clamp(cast::<T, i64>(hp).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(),
|
||||
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))
|
||||
.unwrap(),
|
||||
special_defense: cast(clamp(cast::<T, i64>(special_defense).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::Attack => Self::change_stat(self.attack + value, &mut self.attack),
|
||||
Statistic::Defense => Self::change_stat(self.defense + value, &mut self.defense),
|
||||
Statistic::SpecialAttack => {
|
||||
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::SpecialAttack => 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::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::Attack => Self::change_stat(self.attack - value, &mut self.attack),
|
||||
Statistic::Defense => Self::change_stat(self.defense - value, &mut self.defense),
|
||||
Statistic::SpecialAttack => {
|
||||
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::SpecialAttack => 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::Speed => Self::change_stat(self.speed - value, &mut self.speed),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use hashbrown::HashMap;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::lazy::SyncLazy;
|
||||
use std::sync::{Arc, Mutex, Weak};
|
||||
|
||||
/// 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,
|
||||
}
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref STRING_CACHE: Mutex<HashMap<u32, Weak<str>>> = Mutex::new(HashMap::new());
|
||||
}
|
||||
static STRING_CACHE: SyncLazy<Mutex<HashMap<u32, Weak<str>>>> = SyncLazy::new(|| Mutex::new(HashMap::new()));
|
||||
static EMPTY: SyncLazy<StringKey> = SyncLazy::new(|| StringKey::new(""));
|
||||
|
||||
impl StringKey {
|
||||
pub const fn get_hash_const<const N: usize>(s: &[u8; N]) -> u32 {
|
||||
|
@ -48,14 +48,15 @@ impl StringKey {
|
|||
};
|
||||
}
|
||||
}
|
||||
let v = Self {
|
||||
str: s.into(),
|
||||
hash,
|
||||
};
|
||||
let v = Self { str: s.into(), hash };
|
||||
cache.insert(hash, Arc::downgrade(&v.str));
|
||||
v
|
||||
}
|
||||
|
||||
pub fn empty() -> Self {
|
||||
EMPTY.clone()
|
||||
}
|
||||
|
||||
pub fn str(&self) -> &str {
|
||||
&self.str
|
||||
}
|
||||
|
@ -93,38 +94,35 @@ const fn to_lower(c: u8) -> u8 {
|
|||
}
|
||||
|
||||
const CRC_TABLE: &[u32] = &[
|
||||
0, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
|
||||
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
|
||||
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
|
||||
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
|
||||
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
|
||||
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
|
||||
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
|
||||
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
|
||||
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
|
||||
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
|
||||
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
|
||||
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
|
||||
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
|
||||
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
|
||||
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
|
||||
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
|
||||
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
|
||||
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
|
||||
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
|
||||
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
|
||||
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
|
||||
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
|
||||
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
|
||||
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
|
||||
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
|
||||
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
|
||||
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
|
||||
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
|
||||
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
|
||||
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
|
||||
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
|
||||
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
|
||||
0, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4,
|
||||
0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148,
|
||||
0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
|
||||
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1,
|
||||
0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75,
|
||||
0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599,
|
||||
0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
|
||||
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2,
|
||||
0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162,
|
||||
0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA,
|
||||
0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
|
||||
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73,
|
||||
0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3,
|
||||
0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
|
||||
0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
|
||||
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344,
|
||||
0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0,
|
||||
0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
|
||||
0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
|
||||
0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795,
|
||||
0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31,
|
||||
0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
|
||||
0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
|
||||
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6,
|
||||
0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE,
|
||||
0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 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)]
|
||||
|
|
|
@ -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