2022-06-14 17:11:24 +00:00
|
|
|
use crate::dynamic_data::choices::TurnChoice;
|
2022-06-16 15:59:33 +00:00
|
|
|
use crate::dynamic_data::event_hooks::event_hook::{Event, EventHook};
|
2022-06-03 14:35:18 +00:00
|
|
|
use crate::dynamic_data::flow::choice_queue::ChoiceQueue;
|
2022-06-14 17:11:24 +00:00
|
|
|
use crate::dynamic_data::flow::target_resolver::is_valid_target;
|
2022-06-03 14:35:18 +00:00
|
|
|
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;
|
2022-06-14 17:11:24 +00:00
|
|
|
use crate::dynamic_data::models::pokemon::Pokemon;
|
2022-06-06 12:43:41 +00:00
|
|
|
use crate::dynamic_data::script_handling::script::Script;
|
2022-06-03 14:35:18 +00:00
|
|
|
use crate::dynamic_data::script_handling::script_set::ScriptSet;
|
2022-06-06 12:43:41 +00:00
|
|
|
use crate::dynamic_data::script_handling::volatile_scripts::VolatileScripts;
|
2022-06-12 15:57:39 +00:00
|
|
|
use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper};
|
2022-06-16 15:59:33 +00:00
|
|
|
use crate::{script_hook, PkmnResult, ScriptCategory, StringKey};
|
2022-06-12 15:57:39 +00:00
|
|
|
use parking_lot::RwLock;
|
2022-06-16 15:59:33 +00:00
|
|
|
use std::ops::{Deref, DerefMut};
|
2022-06-12 15:57:39 +00:00
|
|
|
use std::sync::Arc;
|
2022-06-03 14:35:18 +00:00
|
|
|
|
2022-06-06 12:43:41 +00:00
|
|
|
#[derive(Debug)]
|
2022-06-16 15:59:33 +00:00
|
|
|
pub struct Battle<'own, 'library> {
|
|
|
|
library: &'own DynamicLibrary,
|
|
|
|
parties: Vec<BattleParty<'own, 'library>>,
|
2022-06-03 14:35:18 +00:00
|
|
|
can_flee: bool,
|
|
|
|
number_of_sides: u8,
|
|
|
|
pokemon_per_side: u8,
|
2022-06-16 15:59:33 +00:00
|
|
|
sides: Vec<BattleSide<'own, 'library>>,
|
2022-06-03 14:35:18 +00:00
|
|
|
random: BattleRandom,
|
2022-06-16 15:59:33 +00:00
|
|
|
current_turn_queue: Option<Arc<RwLock<ChoiceQueue<'own, 'library>>>>,
|
2022-06-03 14:35:18 +00:00
|
|
|
has_ended: bool,
|
|
|
|
result: BattleResult,
|
|
|
|
event_hook: EventHook,
|
|
|
|
history_holder: Box<HistoryHolder>,
|
|
|
|
current_turn: u32,
|
2022-06-12 15:57:39 +00:00
|
|
|
volatile_scripts: Arc<RwLock<ScriptSet>>,
|
2022-06-16 15:59:33 +00:00
|
|
|
last_turn_time: chrono::Duration,
|
2022-06-12 16:41:49 +00:00
|
|
|
|
|
|
|
script_source_data: RwLock<ScriptSourceData>,
|
2022-06-03 14:35:18 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 15:59:33 +00:00
|
|
|
impl<'own, 'library> Battle<'own, 'library> {
|
2022-06-03 14:35:18 +00:00
|
|
|
pub fn new(
|
2022-06-16 15:59:33 +00:00
|
|
|
library: &'own DynamicLibrary,
|
|
|
|
parties: Vec<BattleParty<'own, 'library>>,
|
2022-06-03 14:35:18 +00:00
|
|
|
can_flee: bool,
|
|
|
|
number_of_sides: u8,
|
|
|
|
pokemon_per_side: u8,
|
|
|
|
random_seed: Option<u128>,
|
2022-06-04 10:40:32 +00:00
|
|
|
) -> Arc<RwLock<Self>> {
|
2022-06-03 14:35:18 +00:00
|
|
|
let random = if let Some(seed) = random_seed {
|
|
|
|
BattleRandom::new_with_seed(seed)
|
|
|
|
} else {
|
2022-06-04 10:40:32 +00:00
|
|
|
BattleRandom::default()
|
2022-06-03 14:35:18 +00:00
|
|
|
};
|
|
|
|
let sides = Vec::with_capacity(number_of_sides as usize);
|
2022-06-04 10:40:32 +00:00
|
|
|
let battle = Arc::new(RwLock::new(Self {
|
2022-06-03 14:35:18 +00:00
|
|
|
library,
|
|
|
|
parties,
|
|
|
|
can_flee,
|
|
|
|
number_of_sides,
|
|
|
|
pokemon_per_side,
|
|
|
|
sides,
|
|
|
|
random,
|
2022-06-11 15:22:46 +00:00
|
|
|
current_turn_queue: None,
|
2022-06-03 14:35:18 +00:00
|
|
|
has_ended: false,
|
|
|
|
result: BattleResult::Inconclusive,
|
|
|
|
event_hook: Default::default(),
|
|
|
|
history_holder: Box::new(HistoryHolder {}),
|
|
|
|
current_turn: 0,
|
2022-06-12 15:57:39 +00:00
|
|
|
volatile_scripts: Default::default(),
|
2022-06-16 15:59:33 +00:00
|
|
|
last_turn_time: chrono::Duration::zero(),
|
2022-06-12 16:41:49 +00:00
|
|
|
script_source_data: Default::default(),
|
2022-06-03 14:35:18 +00:00
|
|
|
}));
|
|
|
|
|
|
|
|
for i in 0..number_of_sides {
|
2022-06-16 15:59:33 +00:00
|
|
|
battle.write().sides[i as usize] = BattleSide::new(i, Arc::downgrade(&battle), pokemon_per_side);
|
2022-06-03 14:35:18 +00:00
|
|
|
}
|
|
|
|
battle
|
|
|
|
}
|
|
|
|
|
2022-06-16 15:59:33 +00:00
|
|
|
pub fn library(&self) -> &'own DynamicLibrary {
|
2022-06-06 12:43:41 +00:00
|
|
|
self.library
|
|
|
|
}
|
2022-06-16 15:59:33 +00:00
|
|
|
pub fn parties(&self) -> &Vec<BattleParty<'own, 'library>> {
|
2022-06-06 12:43:41 +00:00
|
|
|
&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
|
|
|
|
}
|
2022-06-16 15:59:33 +00:00
|
|
|
pub fn sides(&self) -> &Vec<BattleSide<'own, 'library>> {
|
2022-06-06 12:43:41 +00:00
|
|
|
&self.sides
|
|
|
|
}
|
2022-06-16 15:59:33 +00:00
|
|
|
pub fn sides_mut(&mut self) -> &mut Vec<BattleSide<'own, 'library>> {
|
2022-06-11 15:22:46 +00:00
|
|
|
&mut self.sides
|
|
|
|
}
|
|
|
|
|
2022-06-04 10:40:32 +00:00
|
|
|
pub fn random(&self) -> &BattleRandom {
|
|
|
|
&self.random
|
2022-06-03 14:35:18 +00:00
|
|
|
}
|
2022-06-06 12:43:41 +00:00
|
|
|
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
|
|
|
|
}
|
2022-06-16 15:59:33 +00:00
|
|
|
pub fn last_turn_time(&self) -> chrono::Duration {
|
2022-06-06 12:43:41 +00:00
|
|
|
self.last_turn_time
|
|
|
|
}
|
2022-06-16 15:59:33 +00:00
|
|
|
pub fn current_turn_queue(&self) -> &Option<Arc<RwLock<ChoiceQueue<'own, 'library>>>> {
|
2022-06-11 15:22:46 +00:00
|
|
|
&self.current_turn_queue
|
|
|
|
}
|
|
|
|
|
2022-06-16 15:59:33 +00:00
|
|
|
pub fn get_pokemon(&self, side: u8, index: u8) -> &Option<Arc<RwLock<Pokemon<'own, 'library>>>> {
|
2022-06-14 17:11:24 +00:00
|
|
|
let side = self.sides.get(side as usize);
|
|
|
|
if side.is_none() {
|
|
|
|
return &None;
|
|
|
|
}
|
|
|
|
let pokemon = side.unwrap().pokemon().get(index as usize);
|
|
|
|
if pokemon.is_none() {
|
|
|
|
return &None;
|
|
|
|
}
|
|
|
|
pokemon.unwrap()
|
|
|
|
}
|
|
|
|
|
2022-06-11 15:22:46 +00:00
|
|
|
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
|
2022-06-06 12:43:41 +00:00
|
|
|
}
|
2022-06-03 14:35:18 +00:00
|
|
|
|
2022-06-11 15:22:46 +00:00
|
|
|
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;
|
2022-06-03 14:35:18 +00:00
|
|
|
}
|
2022-06-14 17:11:24 +00:00
|
|
|
|
|
|
|
pub fn can_use(&self, choice: &TurnChoice) -> bool {
|
|
|
|
// If the user is not usable, we obviously can;t use the choice.
|
2022-06-16 15:59:33 +00:00
|
|
|
if !choice.user().read().is_usable() {
|
2022-06-14 17:11:24 +00:00
|
|
|
return false;
|
|
|
|
}
|
2022-06-16 15:59:33 +00:00
|
|
|
if let TurnChoice::Move(data) = choice {
|
2022-06-14 17:11:24 +00:00
|
|
|
// TODO: Hook to change number of PP needed.
|
2022-06-16 15:59:33 +00:00
|
|
|
if data.used_move().read().remaining_pp() < 1 {
|
2022-06-14 17:11:24 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if !is_valid_target(
|
2022-06-16 15:59:33 +00:00
|
|
|
data.target_side(),
|
|
|
|
data.target_index(),
|
|
|
|
data.used_move().read().move_data().target(),
|
|
|
|
choice.user().read().deref(),
|
2022-06-14 17:11:24 +00:00
|
|
|
) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
true
|
|
|
|
}
|
2022-06-16 15:59:33 +00:00
|
|
|
|
|
|
|
pub fn try_set_choice(&mut self, choice: TurnChoice<'own, 'library>) -> PkmnResult<bool> {
|
|
|
|
if !self.can_use(&choice) {
|
|
|
|
return Ok(false);
|
|
|
|
}
|
|
|
|
if !choice.user().read().is_on_battlefield() {
|
|
|
|
return Ok(false);
|
|
|
|
}
|
|
|
|
let side = choice.user().read().get_battle_side_index();
|
|
|
|
if side.is_none() {
|
|
|
|
return Ok(false);
|
|
|
|
}
|
|
|
|
self.sides[side.unwrap() as usize].set_choice(choice);
|
|
|
|
self.check_choices_set_and_run()?;
|
|
|
|
Ok(true)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn check_choices_set_and_run(&mut self) -> PkmnResult<()> {
|
|
|
|
for side in &self.sides {
|
|
|
|
if !side.all_choices_set() {
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
if !side.all_slots_filled() {
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let start_time = chrono::Utc::now();
|
|
|
|
let mut choices = Vec::with_capacity(self.number_of_sides as usize * self.pokemon_per_side as usize);
|
|
|
|
for side in &mut self.sides {
|
|
|
|
for choice in side.choices() {
|
|
|
|
if choice.is_none() {
|
|
|
|
panic!("Choice was none, but all choices were set? Logic error.");
|
|
|
|
}
|
|
|
|
let mut choice_guard = choice.as_ref().unwrap().write();
|
|
|
|
let c = choice_guard.deref();
|
|
|
|
if let TurnChoice::Move(data) = c {
|
|
|
|
let mut change_priority = data.priority();
|
|
|
|
script_hook!(change_priority, c, c, &mut change_priority);
|
|
|
|
if change_priority != data.priority() {
|
|
|
|
if let TurnChoice::Move(data) = choice_guard.deref_mut() {
|
|
|
|
*data.priority_mut() = change_priority;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut speed = choice_guard.speed();
|
|
|
|
let c = choice_guard.deref();
|
|
|
|
script_hook!(change_speed, c, c, &mut speed);
|
|
|
|
*choice_guard.speed_mut() = speed;
|
|
|
|
|
|
|
|
choice_guard.set_random_value(self.random.get() as u32);
|
|
|
|
choices.push(choice.as_ref().unwrap().clone());
|
|
|
|
}
|
|
|
|
side.reset_choices();
|
|
|
|
}
|
|
|
|
self.current_turn += 1;
|
|
|
|
|
|
|
|
choices.sort_unstable_by(|a, b| b.read().deref().cmp(a.read().deref()));
|
|
|
|
self.current_turn_queue = Some(Arc::new(RwLock::new(ChoiceQueue::new(choices))));
|
|
|
|
|
|
|
|
{
|
|
|
|
self.run_turn()?;
|
|
|
|
}
|
|
|
|
|
|
|
|
self.current_turn_queue = None;
|
|
|
|
self.event_hook.trigger(Event::EndTurn);
|
|
|
|
let end_time = chrono::Utc::now();
|
|
|
|
let time = end_time - start_time;
|
|
|
|
self.last_turn_time = time;
|
|
|
|
Ok(())
|
|
|
|
}
|
2022-06-06 12:43:41 +00:00
|
|
|
}
|
2022-06-06 11:54:59 +00:00
|
|
|
|
2022-06-16 15:59:33 +00:00
|
|
|
impl<'own, 'library> VolatileScripts<'own> for Battle<'own, 'library> {
|
2022-06-06 12:43:41 +00:00
|
|
|
fn volatile_scripts(&self) -> &Arc<RwLock<ScriptSet>> {
|
2022-06-12 15:57:39 +00:00
|
|
|
&self.volatile_scripts
|
2022-06-06 12:43:41 +00:00
|
|
|
}
|
|
|
|
|
2022-06-11 15:22:46 +00:00
|
|
|
fn load_volatile_script(&self, key: &StringKey) -> PkmnResult<Option<Box<dyn Script>>> {
|
2022-06-06 12:43:41 +00:00
|
|
|
self.library.load_script(ScriptCategory::Battle, key)
|
2022-06-06 11:54:59 +00:00
|
|
|
}
|
2022-06-03 14:35:18 +00:00
|
|
|
}
|
2022-06-12 15:57:39 +00:00
|
|
|
|
2022-06-16 15:59:33 +00:00
|
|
|
impl<'own, 'library> ScriptSource<'own> for Battle<'own, 'library> {
|
2022-06-12 15:57:39 +00:00
|
|
|
fn get_script_count(&self) -> usize {
|
2022-06-12 16:41:49 +00:00
|
|
|
1
|
2022-06-12 15:57:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> {
|
2022-06-12 16:41:49 +00:00
|
|
|
&self.script_source_data
|
2022-06-12 15:57:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|