use alloc::{
string::String,
vec::Vec,
};
use anyhow::Result;
use battler_data::Id;
use hashbrown::HashMap;
use num::Integer;
use serde::{
Deserialize,
Serialize,
};
use crate::{
battle::{
BattleRegistry,
MonHandle,
Player,
PlayerData,
SideContext,
},
config::Format,
dex::Dex,
effect::fxlang,
};
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct SideData {
pub name: String,
pub players: Vec<PlayerData>,
}
pub struct Side {
pub name: String,
pub index: usize,
pub conditions: HashMap<Id, fxlang::EffectState>,
pub slot_conditions: HashMap<usize, HashMap<Id, fxlang::EffectState>>,
pub total_fainted: u64,
}
impl Side {
pub fn new(
data: SideData,
index: usize,
format: &Format,
dex: &Dex,
registry: &BattleRegistry,
) -> Result<(Self, Vec<Player>)> {
let players = data
.players
.into_iter()
.enumerate()
.map(|(i, data)| Player::new(data, index, i, format, dex, registry))
.collect::<Result<Vec<_>, _>>()?;
Ok((
Self {
name: data.name,
index,
conditions: HashMap::default(),
slot_conditions: HashMap::default(),
total_fainted: 0,
},
players,
))
}
}
impl Side {
pub fn player_position_to_index(context: &SideContext, position: usize) -> Option<usize> {
context
.battle()
.players_on_side(context.side().index)
.find(|player| player.position == position)
.map(|player| player.index)
}
pub fn mon_in_position(
context: &mut SideContext,
position: usize,
) -> Result<Option<MonHandle>> {
let active_per_player = context.battle().format.battle_type.active_per_player();
let (player_position, position) = position.div_mod_floor(&active_per_player);
let player_context = match context.player_context(player_position) {
Err(_) => return Ok(None),
Ok(player_context) => player_context,
};
Ok(player_context.player().active_mon_handle(position))
}
pub fn mons_left(context: &mut SideContext) -> Result<usize> {
let mut count = 0;
for player in context
.battle()
.player_indices_on_side(context.side().index)
.collect::<Vec<_>>()
{
count += Player::mons_left(&context.as_battle_context_mut().player_context(player)?)?;
}
Ok(count)
}
pub fn health_percentage_left(context: &mut SideContext) -> Result<u64> {
let mut count = 0;
for player in context
.battle()
.player_indices_on_side(context.side().index)
.collect::<Vec<_>>()
{
count += Player::health_percentage_left(
&mut context.as_battle_context_mut().player_context(player)?,
)?;
}
Ok(count)
}
pub fn active_mons_count(context: &SideContext) -> usize {
context
.battle()
.players_on_side(context.side().index)
.map(|player| player.active_mon_handles().count())
.sum()
}
pub fn has_condition(context: &SideContext, condition: &Id) -> bool {
context.side().conditions.contains_key(condition)
}
}