use parking_lot::lock_api::RwLockReadGuard; use parking_lot::{RawRwLock, RwLock}; use std::sync::Arc; use crate::dynamic_data::models::pokemon::Pokemon; use crate::{ValueIdentifiable, ValueIdentifier}; /// A list of Pokemon belonging to a trainer. #[derive(Debug)] pub struct PokemonParty { /// A unique identifier so we know what value this is. identifier: ValueIdentifier, /// The underlying list of Pokemon. pokemon: RwLock>>>, } impl PokemonParty { /// Instantiates a party with a set size. pub fn new(size: usize) -> Self { let mut pokemon = Vec::with_capacity(size); for _i in 0..size { pokemon.push(None); } Self { identifier: Default::default(), pokemon: RwLock::new(pokemon), } } /// Instantiates a party with a list. pub fn new_from_vec(pokemon: Vec>>) -> Self { Self { identifier: Default::default(), pokemon: RwLock::new(pokemon), } } /// Gets a Pokemon at an index in the party. pub fn at(&self, index: usize) -> Option> { let read_lock = self.pokemon.read(); let opt = read_lock.get(index); if let Some(v) = opt { v.clone() } else { None } } /// Swaps two Pokemon in the party around. pub fn switch(&self, a: usize, b: usize) { self.pokemon.write().swap(a, b); } /// Sets the Pokemon at an index to a Pokemon, returning the old Pokemon. pub fn swap_into(&self, index: usize, pokemon: Option>) -> Option> { let mut party = self.pokemon.write(); if index >= party.len() { return pokemon; } let old = party[index].as_ref().cloned(); party[index] = pokemon; old } /// Whether or not the party still has Pokemon that can be used in battle. pub fn has_usable_pokemon(&self) -> bool { for pokemon in self.pokemon.read().iter().flatten() { if pokemon.is_usable() { return true; } } false } /// Get the length of the underlying list of Pokemon. pub fn length(&self) -> usize { self.pokemon.read().len() } /// Gets the underlying list of Pokemon. pub fn pokemon(&self) -> RwLockReadGuard<'_, RawRwLock, Vec>>> { self.pokemon.read() } /// Makes sure there are no empty spots in the party anymore, leaving the length the same. pub fn pack_party(&self) { let mut first_empty = None; let mut i = 0; let mut party = self.pokemon.write(); loop { if party[i].is_none() { if first_empty.is_none() { first_empty = Some(i) } } else if first_empty.is_some() { party.swap(first_empty.unwrap(), i); i = first_empty.unwrap(); first_empty = None; } i += 1; if i >= party.len() { break; } } } /// Checks if the party contains a given pokemon. pub fn has_pokemon(&self, pokemon: &Pokemon) -> bool { for p in self.pokemon.read().iter().flatten() { if std::ptr::eq(p.as_ref(), pokemon) { return true; } } false } } impl ValueIdentifiable for PokemonParty { fn value_identifier(&self) -> ValueIdentifier { self.identifier } }