A lot more work on WASM script execution
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
50
src/dynamic_data/choices.rs
Normal file → Executable file
50
src/dynamic_data/choices.rs
Normal file → Executable file
@@ -1,4 +1,4 @@
|
||||
use std::cmp::Ordering;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
use parking_lot::RwLock;
|
||||
@@ -20,7 +20,7 @@ struct CommonChoiceData {
|
||||
random_value: u32,
|
||||
/// Whether or not the choice has failed. A failed choice will stop running, and execute special
|
||||
/// fail handling during turn execution.
|
||||
has_failed: bool,
|
||||
has_failed: AtomicBool,
|
||||
/// The data we can use to retrieve scripts that are affecting this choice. This will be written
|
||||
/// to once: when we need to initialize it. After that, this is only used to read. To prevent a
|
||||
/// read while we're writing to it, this is a RwLock.
|
||||
@@ -85,13 +85,13 @@ impl TurnChoice {
|
||||
/// Gets whether or not the choice has failed. If we notice this when we execute the choice, we
|
||||
/// will not execute it.
|
||||
pub fn has_failed(&self) -> bool {
|
||||
self.choice_data().has_failed
|
||||
self.choice_data().has_failed.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
/// Fails the choice. This will prevent it from executing and run a specific fail handling during
|
||||
/// execution. Note that this can not be undone.
|
||||
pub fn fail(&mut self) {
|
||||
self.choice_data_mut().has_failed = true
|
||||
pub fn fail(&self) {
|
||||
self.choice_data().has_failed.store(true, Ordering::SeqCst)
|
||||
}
|
||||
|
||||
/// The random value of a turn choice gets set during the start of a choice, and is used for tie
|
||||
@@ -188,7 +188,7 @@ impl MoveChoice {
|
||||
user,
|
||||
speed: 0,
|
||||
random_value: 0,
|
||||
has_failed: false,
|
||||
has_failed: Default::default(),
|
||||
script_source_data: Default::default(),
|
||||
}),
|
||||
}
|
||||
@@ -259,7 +259,7 @@ impl ItemChoice {
|
||||
user,
|
||||
speed: 0,
|
||||
random_value: 0,
|
||||
has_failed: false,
|
||||
has_failed: Default::default(),
|
||||
script_source_data: Default::default(),
|
||||
}),
|
||||
}
|
||||
@@ -297,7 +297,7 @@ impl SwitchChoice {
|
||||
user,
|
||||
speed: 0,
|
||||
random_value: 0,
|
||||
has_failed: false,
|
||||
has_failed: Default::default(),
|
||||
script_source_data: Default::default(),
|
||||
}),
|
||||
}
|
||||
@@ -335,7 +335,7 @@ impl FleeChoice {
|
||||
user,
|
||||
speed: 0,
|
||||
random_value: 0,
|
||||
has_failed: false,
|
||||
has_failed: Default::default(),
|
||||
script_source_data: Default::default(),
|
||||
}),
|
||||
}
|
||||
@@ -373,7 +373,7 @@ impl PassChoice {
|
||||
user,
|
||||
speed: 0,
|
||||
random_value: 0,
|
||||
has_failed: false,
|
||||
has_failed: Default::default(),
|
||||
script_source_data: Default::default(),
|
||||
}),
|
||||
}
|
||||
@@ -405,68 +405,68 @@ impl PartialEq<Self> for TurnChoice {
|
||||
impl Eq for TurnChoice {}
|
||||
|
||||
impl PartialOrd for TurnChoice {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for TurnChoice {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::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 {
|
||||
if priority_compare != std::cmp::Ordering::Equal {
|
||||
return priority_compare;
|
||||
}
|
||||
let speed_compare = self.speed().cmp(&other.speed());
|
||||
if speed_compare != Ordering::Equal {
|
||||
if speed_compare != std::cmp::Ordering::Equal {
|
||||
return speed_compare;
|
||||
}
|
||||
return self.random_value().cmp(&other.random_value());
|
||||
}
|
||||
Ordering::Greater
|
||||
std::cmp::Ordering::Greater
|
||||
}
|
||||
TurnChoice::Item { .. } => {
|
||||
if let TurnChoice::Move { .. } = other {
|
||||
return Ordering::Less;
|
||||
return std::cmp::Ordering::Less;
|
||||
}
|
||||
if let TurnChoice::Item { .. } = other {
|
||||
let speed_compare = self.speed().cmp(&other.speed());
|
||||
if speed_compare != Ordering::Equal {
|
||||
if speed_compare != std::cmp::Ordering::Equal {
|
||||
return speed_compare;
|
||||
}
|
||||
return self.random_value().cmp(&other.random_value());
|
||||
}
|
||||
Ordering::Greater
|
||||
std::cmp::Ordering::Greater
|
||||
}
|
||||
TurnChoice::Switch { .. } => {
|
||||
if let TurnChoice::Move { .. } = other {
|
||||
return Ordering::Less;
|
||||
return std::cmp::Ordering::Less;
|
||||
}
|
||||
if let TurnChoice::Item { .. } = other {
|
||||
return Ordering::Less;
|
||||
return std::cmp::Ordering::Less;
|
||||
}
|
||||
if let TurnChoice::Switch { .. } = other {
|
||||
let speed_compare = self.speed().cmp(&other.speed());
|
||||
if speed_compare != Ordering::Equal {
|
||||
if speed_compare != std::cmp::Ordering::Equal {
|
||||
return speed_compare;
|
||||
}
|
||||
return self.random_value().cmp(&other.random_value());
|
||||
}
|
||||
Ordering::Greater
|
||||
std::cmp::Ordering::Greater
|
||||
}
|
||||
TurnChoice::Flee { .. } => {
|
||||
if let TurnChoice::Flee { .. } = other {
|
||||
let speed_compare = self.speed().cmp(&other.speed());
|
||||
if speed_compare != Ordering::Equal {
|
||||
if speed_compare != std::cmp::Ordering::Equal {
|
||||
return speed_compare;
|
||||
}
|
||||
return self.random_value().cmp(&other.random_value());
|
||||
}
|
||||
Ordering::Less
|
||||
std::cmp::Ordering::Less
|
||||
}
|
||||
TurnChoice::Pass(..) => Ordering::Less,
|
||||
TurnChoice::Pass(..) => std::cmp::Ordering::Less,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
0
src/dynamic_data/event_hooks.rs
Normal file → Executable file
0
src/dynamic_data/event_hooks.rs
Normal file → Executable file
41
src/dynamic_data/flow/choice_queue.rs
Normal file → Executable file
41
src/dynamic_data/flow/choice_queue.rs
Normal file → Executable file
@@ -1,5 +1,7 @@
|
||||
use crate::dynamic_data::choices::TurnChoice;
|
||||
use crate::dynamic_data::Pokemon;
|
||||
use parking_lot::lock_api::MappedRwLockReadGuard;
|
||||
use parking_lot::{RawRwLock, RwLock, RwLockReadGuard};
|
||||
|
||||
/// The ChoiceQueue is used to run choices one by one.
|
||||
///
|
||||
@@ -8,10 +10,11 @@ use crate::dynamic_data::Pokemon;
|
||||
/// helper functions to change the turn order while doing the execution. This is needed, as several
|
||||
/// moves in Pokemon actively mess with this order.
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))]
|
||||
pub struct ChoiceQueue {
|
||||
/// Our storage of turn choices. Starts out completely filled, then slowly empties as turns get
|
||||
/// executed.
|
||||
queue: Vec<Option<TurnChoice>>,
|
||||
queue: RwLock<Vec<Option<TurnChoice>>>,
|
||||
/// The current index of the turn we need to execute next.
|
||||
current: usize,
|
||||
}
|
||||
@@ -19,42 +22,47 @@ pub struct ChoiceQueue {
|
||||
impl ChoiceQueue {
|
||||
/// Initializes a ChoiceQueue. We expect the given queue to already be sorted here.
|
||||
pub(crate) fn new(queue: Vec<Option<TurnChoice>>) -> Self {
|
||||
Self { queue, current: 0 }
|
||||
Self {
|
||||
queue: RwLock::new(queue),
|
||||
current: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Dequeues the next turn choice to be executed. This gives ownership to the callee, and replaces
|
||||
/// our own reference to the turn choice with an empty spot. It also increments the current position
|
||||
/// by one.
|
||||
pub fn dequeue(&mut self) -> TurnChoice {
|
||||
let c = self.queue[self.current].take();
|
||||
let c = self.queue.write()[self.current].take();
|
||||
self.current += 1;
|
||||
c.unwrap()
|
||||
}
|
||||
|
||||
/// This reads what the next choice to execute will be, without modifying state.
|
||||
pub fn peek(&self) -> &TurnChoice {
|
||||
self.queue[self.current].as_ref().unwrap()
|
||||
pub fn peek(&self) -> MappedRwLockReadGuard<'_, RawRwLock, TurnChoice> {
|
||||
let read_lock = self.queue.read();
|
||||
RwLockReadGuard::map(read_lock, |a| a[self.current].as_ref().unwrap())
|
||||
}
|
||||
|
||||
/// Check if we have any choices remaining.
|
||||
pub fn has_next(&self) -> bool {
|
||||
self.current < self.queue.len()
|
||||
self.current < self.queue.read().len()
|
||||
}
|
||||
|
||||
/// This resorts the yet to be executed choices. This can be useful for dealing with situations
|
||||
/// such as Pokemon changing forms just after the very start of a turn, when turn order has
|
||||
/// technically already been decided.
|
||||
pub fn resort(&mut self) {
|
||||
let len = self.queue.len();
|
||||
self.queue[self.current..len].sort_unstable_by(|a, b| b.cmp(a));
|
||||
let len = self.queue.read().len();
|
||||
self.queue.write()[self.current..len].sort_unstable_by(|a, b| b.cmp(a));
|
||||
}
|
||||
|
||||
/// This moves the choice of a specific Pokemon up to the next choice to be executed.
|
||||
pub fn move_pokemon_choice_next(&mut self, pokemon: &Pokemon) -> bool {
|
||||
pub fn move_pokemon_choice_next(&self, pokemon: &Pokemon) -> bool {
|
||||
let mut queue_lock = self.queue.write();
|
||||
let mut desired_index = None;
|
||||
// Find the index for the choice we want to move up.
|
||||
for index in self.current..self.queue.len() {
|
||||
if let Some(choice) = &self.queue[index] {
|
||||
for index in self.current..queue_lock.len() {
|
||||
if let Some(choice) = &queue_lock[index] {
|
||||
if std::ptr::eq(choice.user().as_ref(), pokemon) {
|
||||
desired_index = Some(index);
|
||||
break;
|
||||
@@ -72,19 +80,20 @@ impl ChoiceQueue {
|
||||
}
|
||||
|
||||
// Take the choice we want to move forward out of it's place.
|
||||
let choice = self.queue[desired_index].take().unwrap();
|
||||
let choice = queue_lock[desired_index].take().unwrap();
|
||||
// Iterate backwards from the spot before the choice we want to move up, push them all back
|
||||
// by 1 spot.
|
||||
for index in (desired_index - 1)..self.current {
|
||||
self.queue.swap(index, index + 1);
|
||||
queue_lock.swap(index, index + 1);
|
||||
}
|
||||
// Place the choice that needs to be next in the next to be executed position.
|
||||
let _ = self.queue[self.current].insert(choice);
|
||||
let _ = queue_lock[self.current].insert(choice);
|
||||
true
|
||||
}
|
||||
|
||||
/// Internal helper function to be easily able to iterate over the yet to be executed choices.
|
||||
pub(crate) fn get_queue(&self) -> &[Option<TurnChoice>] {
|
||||
&self.queue[self.current..self.queue.len()]
|
||||
pub(crate) fn get_queue(&self) -> MappedRwLockReadGuard<'_, RawRwLock, [Option<TurnChoice>]> {
|
||||
let read_lock = self.queue.read();
|
||||
RwLockReadGuard::map(read_lock, |a| &a[self.current..self.queue.read().len()])
|
||||
}
|
||||
}
|
||||
|
||||
0
src/dynamic_data/flow/mod.rs
Normal file → Executable file
0
src/dynamic_data/flow/mod.rs
Normal file → Executable file
0
src/dynamic_data/flow/target_resolver.rs
Normal file → Executable file
0
src/dynamic_data/flow/target_resolver.rs
Normal file → Executable file
0
src/dynamic_data/flow/turn_runner.rs
Normal file → Executable file
0
src/dynamic_data/flow/turn_runner.rs
Normal file → Executable file
0
src/dynamic_data/libraries/battle_stat_calculator.rs
Normal file → Executable file
0
src/dynamic_data/libraries/battle_stat_calculator.rs
Normal file → Executable file
0
src/dynamic_data/libraries/damage_library.rs
Normal file → Executable file
0
src/dynamic_data/libraries/damage_library.rs
Normal file → Executable file
4
src/dynamic_data/libraries/dynamic_library.rs
Normal file → Executable file
4
src/dynamic_data/libraries/dynamic_library.rs
Normal file → Executable file
@@ -5,8 +5,8 @@ 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;
|
||||
use crate::dynamic_data::{ItemScript, ScriptResolver};
|
||||
use crate::dynamic_data::{Script, ScriptOwnerData};
|
||||
use crate::static_data::Item;
|
||||
use crate::static_data::StaticData;
|
||||
use crate::{PkmnResult, StringKey};
|
||||
@@ -75,7 +75,7 @@ impl DynamicLibrary {
|
||||
/// can be created with this combination, returns None.
|
||||
pub fn load_script(
|
||||
&self,
|
||||
owner: *const u8,
|
||||
owner: ScriptOwnerData,
|
||||
_category: ScriptCategory,
|
||||
_key: &StringKey,
|
||||
) -> PkmnResult<Option<Arc<dyn Script>>> {
|
||||
|
||||
0
src/dynamic_data/libraries/misc_library.rs
Normal file → Executable file
0
src/dynamic_data/libraries/misc_library.rs
Normal file → Executable file
0
src/dynamic_data/libraries/mod.rs
Normal file → Executable file
0
src/dynamic_data/libraries/mod.rs
Normal file → Executable file
6
src/dynamic_data/libraries/script_resolver.rs
Normal file → Executable file
6
src/dynamic_data/libraries/script_resolver.rs
Normal file → Executable file
@@ -1,7 +1,7 @@
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::dynamic_data::{ItemScript, Script};
|
||||
use crate::dynamic_data::{ItemScript, Script, ScriptOwnerData};
|
||||
use crate::static_data::Item;
|
||||
use crate::{PkmnResult, StringKey};
|
||||
|
||||
@@ -13,7 +13,7 @@ pub trait ScriptResolver: Debug {
|
||||
/// can be created with this combination, returns None.
|
||||
fn load_script(
|
||||
&self,
|
||||
owner: *const u8,
|
||||
owner: ScriptOwnerData,
|
||||
category: ScriptCategory,
|
||||
script_key: &StringKey,
|
||||
) -> PkmnResult<Option<Arc<dyn Script>>>;
|
||||
@@ -58,7 +58,7 @@ pub struct EmptyScriptResolver {}
|
||||
impl ScriptResolver for EmptyScriptResolver {
|
||||
fn load_script(
|
||||
&self,
|
||||
_owner: *const u8,
|
||||
_owner: ScriptOwnerData,
|
||||
_category: ScriptCategory,
|
||||
_script_key: &StringKey,
|
||||
) -> PkmnResult<Option<Arc<dyn Script>>> {
|
||||
|
||||
0
src/dynamic_data/mod.rs
Normal file → Executable file
0
src/dynamic_data/mod.rs
Normal file → Executable file
5
src/dynamic_data/models/battle.rs
Normal file → Executable file
5
src/dynamic_data/models/battle.rs
Normal file → Executable file
@@ -194,7 +194,7 @@ impl Battle {
|
||||
let mut winning_side = None;
|
||||
for (side_index, side) in self.sides.iter().enumerate() {
|
||||
// If any side has fled, the battle end.
|
||||
if side.has_fled() {
|
||||
if side.has_fled_battle() {
|
||||
let _w = self.result.write();
|
||||
unsafe {
|
||||
self.result.data_ptr().replace(BattleResult::Inconclusive);
|
||||
@@ -339,8 +339,7 @@ impl VolatileScriptsOwner for Battle {
|
||||
}
|
||||
|
||||
fn load_volatile_script(&self, key: &StringKey) -> PkmnResult<Option<Arc<dyn Script>>> {
|
||||
self.library
|
||||
.load_script((self as *const Self).cast(), ScriptCategory::Battle, key)
|
||||
self.library.load_script(self.into(), ScriptCategory::Battle, key)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
6
src/dynamic_data/models/battle_party.rs
Normal file → Executable file
6
src/dynamic_data/models/battle_party.rs
Normal file → Executable file
@@ -6,6 +6,7 @@ use crate::dynamic_data::models::pokemon_party::PokemonParty;
|
||||
/// A battle party is a wrapper around a party, with the indices for which the party is responsible
|
||||
/// on the field attached.
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))]
|
||||
pub struct BattleParty {
|
||||
/// The party the BattleParty is holding.
|
||||
party: Arc<PokemonParty>,
|
||||
@@ -47,4 +48,9 @@ impl BattleParty {
|
||||
pub fn get_pokemon(&self, index: usize) -> &Option<Arc<Pokemon>> {
|
||||
self.party.at(index)
|
||||
}
|
||||
|
||||
/// Gets the underlying Pokemon Party
|
||||
pub fn party(&self) -> &Arc<PokemonParty> {
|
||||
&self.party
|
||||
}
|
||||
}
|
||||
|
||||
1
src/dynamic_data/models/battle_random.rs
Normal file → Executable file
1
src/dynamic_data/models/battle_random.rs
Normal file → Executable file
@@ -9,6 +9,7 @@ use crate::utils::Random;
|
||||
|
||||
/// The RNG for a battle.
|
||||
#[derive(Default)]
|
||||
#[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))]
|
||||
pub struct BattleRandom {
|
||||
/// The actual underlying RNG. This is in a mutex, so it is thread safe, and can be ran
|
||||
/// predictably, with guaranteed the same outputs.
|
||||
|
||||
8
src/dynamic_data/models/battle_side.rs
Normal file → Executable file
8
src/dynamic_data/models/battle_side.rs
Normal file → Executable file
@@ -18,6 +18,7 @@ use crate::{script_hook, PkmnResult, StringKey};
|
||||
|
||||
/// A side on a battle.
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))]
|
||||
pub struct BattleSide {
|
||||
/// The index of the side on the battle.
|
||||
index: u8,
|
||||
@@ -239,11 +240,6 @@ impl BattleSide {
|
||||
true
|
||||
}
|
||||
|
||||
/// Checks whether the side has fled.
|
||||
pub fn has_fled(&self) -> bool {
|
||||
self.has_fled_battle
|
||||
}
|
||||
|
||||
/// Mark the side as fled.
|
||||
pub fn mark_as_fled(&mut self) {
|
||||
self.has_fled_battle = true;
|
||||
@@ -304,7 +300,7 @@ impl VolatileScriptsOwner for BattleSide {
|
||||
fn load_volatile_script(&self, key: &StringKey) -> PkmnResult<Option<Arc<dyn Script>>> {
|
||||
self.battle()
|
||||
.library()
|
||||
.load_script((self as *const Self).cast(), crate::ScriptCategory::Side, key)
|
||||
.load_script(self.into(), crate::ScriptCategory::Side, key)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
3
src/dynamic_data/models/executing_move.rs
Normal file → Executable file
3
src/dynamic_data/models/executing_move.rs
Normal file → Executable file
@@ -15,6 +15,7 @@ use crate::{PkmnResult, PokemonError};
|
||||
|
||||
/// A hit data is the data for a single hit, on a single target.
|
||||
#[derive(Default, Debug)]
|
||||
#[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))]
|
||||
pub struct HitData {
|
||||
/// Whether or not the hit is critical.
|
||||
critical: AtomicBool,
|
||||
@@ -158,7 +159,7 @@ impl ExecutingMove {
|
||||
}
|
||||
|
||||
/// Gets a hit data for a target, with a specific index.
|
||||
pub fn get_hit_data<'func>(&'func self, for_target: &'func Arc<Pokemon>, hit: u8) -> PkmnResult<&'func HitData> {
|
||||
pub fn get_hit_data(&self, for_target: &Pokemon, hit: u8) -> PkmnResult<&HitData> {
|
||||
for (index, target) in self.targets.iter().enumerate() {
|
||||
if let Some(target) = target {
|
||||
if std::ptr::eq(target.deref().deref(), for_target.deref().deref()) {
|
||||
|
||||
0
src/dynamic_data/models/learned_move.rs
Normal file → Executable file
0
src/dynamic_data/models/learned_move.rs
Normal file → Executable file
0
src/dynamic_data/models/mod.rs
Normal file → Executable file
0
src/dynamic_data/models/mod.rs
Normal file → Executable file
9
src/dynamic_data/models/pokemon.rs
Normal file → Executable file
9
src/dynamic_data/models/pokemon.rs
Normal file → Executable file
@@ -502,11 +502,7 @@ impl Pokemon {
|
||||
|
||||
let ability_script = self
|
||||
.library
|
||||
.load_script(
|
||||
(self as *const Self).cast(),
|
||||
ScriptCategory::Ability,
|
||||
self.active_ability().name(),
|
||||
)
|
||||
.load_script((&*self).into(), ScriptCategory::Ability, self.active_ability().name())
|
||||
.unwrap();
|
||||
if let Some(ability_script) = ability_script {
|
||||
self.ability_script
|
||||
@@ -772,8 +768,7 @@ impl VolatileScriptsOwner for Pokemon {
|
||||
}
|
||||
|
||||
fn load_volatile_script(&self, key: &StringKey) -> PkmnResult<Option<Arc<dyn Script>>> {
|
||||
self.library
|
||||
.load_script((self as *const Self).cast(), ScriptCategory::Pokemon, key)
|
||||
self.library.load_script(self.into(), ScriptCategory::Pokemon, key)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
0
src/dynamic_data/models/pokemon_builder.rs
Normal file → Executable file
0
src/dynamic_data/models/pokemon_builder.rs
Normal file → Executable file
13
src/dynamic_data/models/pokemon_party.rs
Normal file → Executable file
13
src/dynamic_data/models/pokemon_party.rs
Normal file → Executable file
@@ -4,6 +4,7 @@ use crate::dynamic_data::models::pokemon::Pokemon;
|
||||
|
||||
/// A list of Pokemon belonging to a trainer.
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))]
|
||||
pub struct PokemonParty {
|
||||
/// The underlying list of Pokemon.
|
||||
pokemon: Vec<Option<Arc<Pokemon>>>,
|
||||
@@ -89,4 +90,16 @@ impl PokemonParty {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if the party contains a given pokemon.
|
||||
pub fn has_pokemon(&self, pokemon: &Pokemon) -> bool {
|
||||
for p in &self.pokemon {
|
||||
if let Some(p) = p {
|
||||
if std::ptr::eq(p.as_ref(), pokemon) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
0
src/dynamic_data/script_handling/item_script.rs
Normal file → Executable file
0
src/dynamic_data/script_handling/item_script.rs
Normal file → Executable file
0
src/dynamic_data/script_handling/mod.rs
Normal file → Executable file
0
src/dynamic_data/script_handling/mod.rs
Normal file → Executable file
34
src/dynamic_data/script_handling/script.rs
Normal file → Executable file
34
src/dynamic_data/script_handling/script.rs
Normal file → Executable file
@@ -1,17 +1,17 @@
|
||||
use std::any::Any;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::ops::Deref;
|
||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||
use std::sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::thread::JoinHandle;
|
||||
|
||||
use parking_lot::{MappedRwLockReadGuard, RwLock, RwLockReadGuard};
|
||||
|
||||
use crate::dynamic_data::choices::TurnChoice;
|
||||
use crate::dynamic_data::DamageSource;
|
||||
use crate::dynamic_data::ExecutingMove;
|
||||
use crate::dynamic_data::Pokemon;
|
||||
use crate::dynamic_data::{Battle, DynamicLibrary};
|
||||
use crate::dynamic_data::{BattleSide, DamageSource};
|
||||
use crate::static_data::{EffectParameter, TypeIdentifier};
|
||||
use crate::static_data::{Item, Statistic};
|
||||
use crate::StringKey;
|
||||
@@ -543,3 +543,33 @@ mod tests {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Data to store references to their owning objects on scripts.
|
||||
pub enum ScriptOwnerData {
|
||||
/// A script attached to a Pokemon has a reference to that Pokemon.
|
||||
Pokemon(AtomicPtr<Pokemon>),
|
||||
/// A script attached to a Battle Side has a reference to that Battle Side.
|
||||
BattleSide(AtomicPtr<BattleSide>),
|
||||
/// A script attached to a Battle has a reference to that Battle.
|
||||
Battle(AtomicPtr<Battle>),
|
||||
/// A script also can have no owner.
|
||||
None,
|
||||
}
|
||||
|
||||
impl Into<ScriptOwnerData> for &Pokemon {
|
||||
fn into(self) -> ScriptOwnerData {
|
||||
ScriptOwnerData::Pokemon(AtomicPtr::new(self as *const Pokemon as *mut Pokemon))
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<ScriptOwnerData> for &BattleSide {
|
||||
fn into(self) -> ScriptOwnerData {
|
||||
ScriptOwnerData::BattleSide(AtomicPtr::new(self as *const BattleSide as *mut BattleSide))
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<ScriptOwnerData> for &Battle {
|
||||
fn into(self) -> ScriptOwnerData {
|
||||
ScriptOwnerData::Battle(AtomicPtr::new(self as *const Battle as *mut Battle))
|
||||
}
|
||||
}
|
||||
|
||||
0
src/dynamic_data/script_handling/script_set.rs
Normal file → Executable file
0
src/dynamic_data/script_handling/script_set.rs
Normal file → Executable file
10
src/dynamic_data/script_handling/volatile_scripts_owner.rs
Normal file → Executable file
10
src/dynamic_data/script_handling/volatile_scripts_owner.rs
Normal file → Executable file
@@ -22,13 +22,19 @@ pub trait VolatileScriptsOwner {
|
||||
}
|
||||
|
||||
/// Adds a volatile script by name.
|
||||
fn add_volatile_script(&mut self, key: &StringKey) -> PkmnResult<Option<ScriptContainer>> {
|
||||
fn add_volatile_script(&self, key: &StringKey) -> PkmnResult<Option<ScriptContainer>> {
|
||||
self.volatile_scripts()
|
||||
.stack_or_add(key, &|| self.load_volatile_script(key))
|
||||
}
|
||||
|
||||
/// Adds a volatile script by name.
|
||||
fn add_volatile_script_with_script(&self, script: Arc<dyn Script>) -> PkmnResult<Option<ScriptContainer>> {
|
||||
self.volatile_scripts()
|
||||
.stack_or_add(&script.name().clone(), &|| Ok(Some(script.clone())))
|
||||
}
|
||||
|
||||
/// Removes a volatile script by name.
|
||||
fn remove_volatile_script(&mut self, key: &StringKey) {
|
||||
fn remove_volatile_script(&self, key: &StringKey) {
|
||||
self.volatile_scripts().remove(key)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user