use crate::dynamic_data::choices::TurnChoice; use crate::dynamic_data::event_hooks::event_hook::Event; use crate::dynamic_data::models::battle::Battle; use crate::dynamic_data::models::pokemon::Pokemon; use crate::dynamic_data::script_handling::ScriptSource; use crate::script_hook; use derive_getters::Getters; use std::sync::{Arc, RwLock, Weak}; #[derive(Getters, Debug)] pub struct BattleSide<'a> { index: u8, pokemon_per_side: u8, pokemon: Vec>>>>, choices: Vec>>>, fillable_slots: Vec, choices_set: u8, battle: Weak>>, has_fled: bool, } impl<'a> BattleSide<'a> { pub fn new(index: u8, battle: Weak>>, 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); for i in 0..pokemon_per_side { pokemon[i as usize] = None; choices[i as usize] = None; fillable_slots[i as usize] = true; } Self { index, pokemon_per_side, pokemon, choices, fillable_slots, choices_set: 0, battle, has_fled: false, } } pub fn all_choices_set(&self) -> bool { self.choices_set == self.pokemon_per_side } /// Returns true if there are slots that need to be filled with a new pokemon, that have parties /// responsible for them. Returns false if all slots are filled with usable pokemon, or slots are /// empty, but can't be filled by any party anymore. pub fn all_slots_filled(&self) -> bool { for pokemon in &self.pokemon { if (!pokemon.is_none() || !pokemon.as_ref().unwrap().read().unwrap().is_usable()) && self .battle .upgrade() .unwrap() .read() .unwrap() .can_slot_be_filled() { return false; } } true } pub fn set_choice(&mut self, choice: TurnChoice<'a>) { for (index, pokemon_slot) in self.pokemon.iter().enumerate() { if let Some(pokemon) = pokemon_slot { if pokemon.read().unwrap().unique_identifier() == choice.user().unique_identifier() { self.choices[index] = Some(Arc::new(choice)); self.choices_set += 1; return; } } } } 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>>>) { let old = &mut self.pokemon[index as usize]; if let Some(old_pokemon) = old { let mut p = old_pokemon.write().unwrap(); script_hook!(on_remove, p,); p.set_on_battlefield(false); } self.pokemon[index as usize] = pokemon; let pokemon = &self.pokemon[index as usize]; if let Some(pokemon_mutex) = pokemon { let mut pokemon = pokemon_mutex.write().unwrap(); pokemon.set_battle_data(self.battle.clone(), self.index); pokemon.set_on_battlefield(true); pokemon.set_battle_index(index); let battle = self.battle.upgrade().unwrap(); let battle = battle.read().unwrap(); for side in battle.sides() { if *side.index() == self.index { continue; } for opponent in side.pokemon().iter().flatten() { let mut opponent = opponent.write().unwrap(); opponent.mark_opponent_as_seen(*pokemon.unique_identifier()); pokemon.mark_opponent_as_seen(*opponent.unique_identifier()); } } battle.event_hook().trigger(Event::Switch { side_index: self.index, index, pokemon: Some(pokemon_mutex.clone()), }); script_hook!(on_switch_in, pokemon, &pokemon); } else { let battle = self.battle.upgrade().unwrap(); let battle = battle.read().unwrap(); battle.event_hook().trigger(Event::Switch { side_index: self.index, index, pokemon: None, }); } } pub fn is_pokemon_on_side(&self, pokemon: Arc>) -> bool { for p in self.pokemon.iter().flatten() { if p.read().unwrap().unique_identifier() == pokemon.unique_identifier() { return true; } } false } } impl<'a> ScriptSource for BattleSide<'a> { fn get_script_count(&self) { todo!() } }