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)] struct CommonChoiceData<'user, 'library> { user: Arc>>, speed: u32, random_value: u32, has_failed: bool, script_source_data: RwLock, } #[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(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> { 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>> { &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 { 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) { 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) { 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>>, target_side: u8, target_index: u8, script: ScriptContainer, priority: i8, choice_data: Box>, } impl<'user, 'library> MoveChoice<'user, 'library> { pub fn new( user: Arc>>, used_move: Arc>>, 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>> { &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>> { &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 { &self.choice_data.script_source_data } fn get_own_scripts(&self, scripts: &mut Vec) { scripts.push((&self.script).into()); } fn collect_scripts(&self, scripts: &mut Vec) { self.get_own_scripts(scripts); self.choice_data.user.read().collect_scripts(scripts); } } #[derive(Debug)] pub struct ItemChoice<'user, 'library> { choice_data: Box>, } impl<'user, 'library> ScriptSource<'user> for ItemChoice<'user, 'library> { fn get_script_count(&self) -> usize { 0 } fn get_script_source_data(&self) -> &RwLock { &self.choice_data.script_source_data } fn get_own_scripts(&self, _scripts: &mut Vec) {} fn collect_scripts(&self, scripts: &mut Vec) { self.choice_data.user.read().collect_scripts(scripts); } } #[derive(Debug)] pub struct SwitchChoice<'user, 'library> { choice_data: Box>, } impl<'user, 'library> ScriptSource<'user> for SwitchChoice<'user, 'library> { fn get_script_count(&self) -> usize { 0 } fn get_script_source_data(&self) -> &RwLock { &self.choice_data.script_source_data } fn get_own_scripts(&self, _scripts: &mut Vec) {} fn collect_scripts(&self, scripts: &mut Vec) { self.choice_data.user.read().collect_scripts(scripts); } } #[derive(Debug)] pub struct FleeChoice<'user, 'library> { choice_data: Box>, } impl<'user, 'library> ScriptSource<'user> for FleeChoice<'user, 'library> { fn get_script_count(&self) -> usize { 0 } fn get_script_source_data(&self) -> &RwLock { &self.choice_data.script_source_data } fn get_own_scripts(&self, _scripts: &mut Vec) {} fn collect_scripts(&self, scripts: &mut Vec) { self.choice_data.user.read().collect_scripts(scripts); } } #[derive(Debug)] pub struct PassChoice<'user, 'library> { choice_data: Box>, } impl<'user, 'library> ScriptSource<'user> for PassChoice<'user, 'library> { fn get_script_count(&self) -> usize { 0 } fn get_script_source_data(&self) -> &RwLock { &self.choice_data.script_source_data } fn get_own_scripts(&self, _scripts: &mut Vec) {} fn collect_scripts(&self, scripts: &mut Vec) { self.choice_data.user.read().collect_scripts(scripts); } } impl<'user, 'library> PartialEq 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 { 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, } } }