128 lines
3.6 KiB
Rust
Executable File
128 lines
3.6 KiB
Rust
Executable File
use anyhow::Result;
|
|
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, VecExt};
|
|
|
|
/// 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<Vec<Option<Arc<Pokemon>>>>,
|
|
}
|
|
|
|
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<Option<Arc<Pokemon>>>) -> 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<Arc<Pokemon>> {
|
|
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<Arc<Pokemon>>) -> Result<Option<Arc<Pokemon>>> {
|
|
let mut party = self.pokemon.write();
|
|
if index >= party.len() {
|
|
return Ok(pokemon);
|
|
}
|
|
let value = party.get_mut_res(index)?;
|
|
let old = match pokemon {
|
|
Some(p) => value.replace(p),
|
|
None => value.take(),
|
|
};
|
|
Ok(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<Option<Arc<Pokemon>>>> {
|
|
self.pokemon.read()
|
|
}
|
|
|
|
/// Makes sure there are no empty spots in the party anymore, leaving the length the same.
|
|
pub fn pack_party(&self) -> Result<()> {
|
|
let mut first_empty = None;
|
|
let mut i = 0;
|
|
let mut party = self.pokemon.write();
|
|
loop {
|
|
if party.get_res(i)?.is_none() {
|
|
if first_empty.is_none() {
|
|
first_empty = Some(i)
|
|
}
|
|
} else if let Some(f) = first_empty {
|
|
party.swap(f, i);
|
|
i = f;
|
|
first_empty = None;
|
|
}
|
|
i += 1;
|
|
if i >= party.len() {
|
|
break;
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
/// 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
|
|
}
|
|
}
|