PkmnLib_rs/src/dynamic_data/models/battle.rs

197 lines
5.9 KiB
Rust

use crate::dynamic_data::event_hooks::event_hook::EventHook;
use crate::dynamic_data::flow::choice_queue::ChoiceQueue;
use crate::dynamic_data::history::history_holder::HistoryHolder;
use crate::dynamic_data::libraries::dynamic_library::DynamicLibrary;
use crate::dynamic_data::models::battle_party::BattleParty;
use crate::dynamic_data::models::battle_random::BattleRandom;
use crate::dynamic_data::models::battle_result::BattleResult;
use crate::dynamic_data::models::battle_side::BattleSide;
use crate::dynamic_data::script_handling::script::Script;
use crate::dynamic_data::script_handling::script_set::ScriptSet;
use crate::dynamic_data::script_handling::volatile_scripts::VolatileScripts;
use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper};
use crate::{PkmnResult, ScriptCategory, StringKey};
use parking_lot::RwLock;
use std::sync::Arc;
#[derive(Debug)]
pub struct Battle<'a> {
library: &'a DynamicLibrary<'a>,
parties: Vec<BattleParty<'a>>,
can_flee: bool,
number_of_sides: u8,
pokemon_per_side: u8,
sides: Vec<BattleSide<'a>>,
random: BattleRandom,
current_turn_queue: Option<ChoiceQueue>,
has_ended: bool,
result: BattleResult,
event_hook: EventHook,
history_holder: Box<HistoryHolder>,
current_turn: u32,
volatile_scripts: Arc<RwLock<ScriptSet>>,
last_turn_time: i64,
script_source_data: RwLock<ScriptSourceData>,
}
impl<'a> Battle<'a> {
pub fn new(
library: &'a DynamicLibrary<'a>,
parties: Vec<BattleParty<'a>>,
can_flee: bool,
number_of_sides: u8,
pokemon_per_side: u8,
random_seed: Option<u128>,
) -> Arc<RwLock<Self>> {
let random = if let Some(seed) = random_seed {
BattleRandom::new_with_seed(seed)
} else {
BattleRandom::default()
};
let sides = Vec::with_capacity(number_of_sides as usize);
let battle = Arc::new(RwLock::new(Self {
library,
parties,
can_flee,
number_of_sides,
pokemon_per_side,
sides,
random,
current_turn_queue: None,
has_ended: false,
result: BattleResult::Inconclusive,
event_hook: Default::default(),
history_holder: Box::new(HistoryHolder {}),
current_turn: 0,
volatile_scripts: Default::default(),
last_turn_time: 0,
script_source_data: Default::default(),
}));
for i in 0..number_of_sides {
battle.write().sides[i as usize] =
BattleSide::new(i, Arc::downgrade(&battle), pokemon_per_side);
}
battle
}
pub fn library(&self) -> &'a DynamicLibrary<'a> {
self.library
}
pub fn parties(&self) -> &Vec<BattleParty<'a>> {
&self.parties
}
pub fn can_flee(&self) -> bool {
self.can_flee
}
pub fn number_of_sides(&self) -> u8 {
self.number_of_sides
}
pub fn pokemon_per_side(&self) -> u8 {
self.pokemon_per_side
}
pub fn sides(&self) -> &Vec<BattleSide<'a>> {
&self.sides
}
pub fn sides_mut(&mut self) -> &mut Vec<BattleSide<'a>> {
&mut self.sides
}
pub fn random(&self) -> &BattleRandom {
&self.random
}
pub fn has_ended(&self) -> bool {
self.has_ended
}
pub fn result(&self) -> BattleResult {
self.result
}
pub fn event_hook(&self) -> &EventHook {
&self.event_hook
}
pub fn history_holder(&self) -> &Box<HistoryHolder> {
&self.history_holder
}
pub fn current_turn(&self) -> u32 {
self.current_turn
}
pub fn last_turn_time(&self) -> i64 {
self.last_turn_time
}
pub fn current_turn_queue(&self) -> &Option<ChoiceQueue> {
&self.current_turn_queue
}
pub fn can_slot_be_filled(&self, side: u8, index: u8) -> bool {
for party in &self.parties {
if party.is_responsible_for_index(side, index) && party.has_pokemon_not_in_field() {
return true;
}
}
false
}
pub fn validate_battle_state(&mut self) {
if self.has_ended {
return;
}
let mut surviving_side_exists = false;
let mut winning_side = None;
for (side_index, side) in self.sides.iter().enumerate() {
// If any side has fled, the battle end.
if side.has_fled() {
self.result = BattleResult::Inconclusive;
self.has_ended = true;
return;
}
// If the side is not defeated
if !side.is_defeated() {
// More than 1 surviving side. Battle is not ended
if surviving_side_exists {
return;
}
surviving_side_exists = true;
winning_side = Some(side_index as u8);
}
}
// Everyone died :(
if !surviving_side_exists {
self.result = BattleResult::Inconclusive;
}
// Someone survived, they won!
else {
self.result = BattleResult::Conclusive(winning_side.unwrap());
}
self.has_ended = true;
}
}
impl<'a> VolatileScripts<'a> for Battle<'a> {
fn volatile_scripts(&self) -> &Arc<RwLock<ScriptSet>> {
&self.volatile_scripts
}
fn load_volatile_script(&self, key: &StringKey) -> PkmnResult<Option<Box<dyn Script>>> {
self.library.load_script(ScriptCategory::Battle, key)
}
}
impl<'a> ScriptSource<'a> for Battle<'a> {
fn get_script_count(&self) -> usize {
1
}
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> {
&self.script_source_data
}
fn get_own_scripts(&self, scripts: &mut Vec<ScriptWrapper>) {
scripts.push((&self.volatile_scripts).into());
}
fn collect_scripts(&self, scripts: &mut Vec<ScriptWrapper>) {
self.get_own_scripts(scripts);
}
}