First chunk of battling is now fully working, along with integration tests! 🎉
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
2022-06-17 19:53:33 +02:00
parent 59cc150643
commit b6ddd1ee13
34 changed files with 1934 additions and 1293 deletions

View File

@@ -3,7 +3,7 @@ use crate::dynamic_data::event_hooks::event_hook::Event;
use crate::dynamic_data::libraries::dynamic_library::DynamicLibrary;
use crate::dynamic_data::models::battle::Battle;
use crate::dynamic_data::models::damage_source::DamageSource;
use crate::dynamic_data::models::learned_move::LearnedMove;
use crate::dynamic_data::models::learned_move::{LearnedMove, MoveLearnMethod};
use crate::dynamic_data::script_handling::script::{Script, ScriptContainer};
use crate::dynamic_data::script_handling::script_set::ScriptSet;
use crate::dynamic_data::script_handling::volatile_scripts::VolatileScripts;
@@ -16,7 +16,7 @@ use crate::static_data::species_data::form::Form;
use crate::static_data::species_data::gender::Gender;
use crate::static_data::species_data::species::Species;
use crate::static_data::statistic_set::{ClampedStatisticSet, StatisticSet};
use crate::static_data::statistics::Statistic;
use crate::static_data::DataLibrary;
use crate::utils::random::Random;
use crate::{script_hook, PkmnResult, ScriptCategory, StringKey};
use parking_lot::RwLock;
@@ -24,7 +24,7 @@ use std::sync::{Arc, Weak};
#[derive(Debug)]
pub struct PokemonBattleData<'pokemon, 'library> {
battle: Weak<RwLock<Battle<'pokemon, 'library>>>,
battle: *mut Battle<'pokemon, 'library>,
battle_side_index: u8,
index: u8,
on_battle_field: bool,
@@ -32,9 +32,13 @@ pub struct PokemonBattleData<'pokemon, 'library> {
}
impl<'pokemon, 'library> PokemonBattleData<'pokemon, 'library> {
pub fn battle(&mut self) -> &mut Weak<RwLock<Battle<'pokemon, 'library>>> {
&mut self.battle
pub fn battle_mut(&mut self) -> Option<&mut Battle<'pokemon, 'library>> {
unsafe { self.battle.as_mut() }
}
pub fn battle(&self) -> Option<&Battle<'pokemon, 'library>> {
unsafe { self.battle.as_ref() }
}
pub fn battle_side_index(&self) -> u8 {
self.battle_side_index
}
@@ -52,11 +56,11 @@ where
'own: 'library,
{
library: &'own DynamicLibrary,
species: &'own Species<'library>,
form: &'own Form<'library>,
species: &'own Species,
form: &'own Form,
display_species: Option<&'own Species<'library>>,
display_form: Option<&'own Form<'library>>,
display_species: Option<&'own Species>,
display_form: Option<&'own Form>,
level: LevelInt,
experience: u32,
@@ -84,7 +88,7 @@ where
battle_data: Option<PokemonBattleData<'own, 'library>>,
moves: [Option<LearnedMove<'library>>; MAX_MOVES],
moves: [Option<Arc<RwLock<LearnedMove<'library>>>>; MAX_MOVES],
allowed_experience: bool,
types: Vec<u8>,
@@ -116,14 +120,13 @@ impl<'own, 'library> Pokemon<'own, 'library> {
.static_data()
.growth_rates()
.calculate_experience(species.growth_rate(), level);
let health = form.get_base_stat(Statistic::HP) as u32;
let weight = form.weight();
let height = form.height();
let nature = library
.static_data()
.natures()
.get_nature(&nature)
.expect("Unknown nature name was given.");
.unwrap_or_else(|| panic!("Unknown nature name was given: {}.", &nature));
let mut pokemon = Self {
library,
species,
@@ -136,7 +139,7 @@ impl<'own, 'library> Pokemon<'own, 'library> {
gender,
coloring,
held_item: None,
current_health: health,
current_health: 1,
weight,
height,
stat_boost: Default::default(),
@@ -162,26 +165,29 @@ impl<'own, 'library> Pokemon<'own, 'library> {
script_source_data: Default::default(),
};
pokemon.recalculate_flat_stats();
let health = pokemon.flat_stats().hp();
pokemon.current_health = health;
pokemon
}
pub fn library(&self) -> &'own DynamicLibrary {
self.library
}
pub fn species(&self) -> &'own Species<'library> {
pub fn species(&self) -> &'own Species {
self.species
}
pub fn form(&self) -> &'own Form<'library> {
pub fn form(&self) -> &'own Form {
self.form
}
pub fn display_species(&self) -> &'own Species<'library> {
pub fn display_species(&self) -> &'own Species {
if let Some(v) = self.display_species {
v
} else {
self.species
}
}
pub fn display_form(&self) -> &'own Form<'library> {
pub fn display_form(&self) -> &'own Form {
if let Some(v) = self.display_form {
v
} else {
@@ -254,7 +260,7 @@ impl<'own, 'library> Pokemon<'own, 'library> {
pub fn types(&self) -> &Vec<u8> {
&self.types
}
pub fn learned_moves(&self) -> &[Option<LearnedMove>; MAX_MOVES] {
pub fn learned_moves(&self) -> &[Option<Arc<RwLock<LearnedMove<'library>>>>; MAX_MOVES] {
&self.moves
}
pub fn status(&self) -> &ScriptContainer {
@@ -276,9 +282,9 @@ impl<'own, 'library> Pokemon<'own, 'library> {
&self.effort_values
}
pub fn get_battle(&self) -> Option<&Weak<RwLock<Battle<'own, 'library>>>> {
pub fn get_battle(&self) -> Option<&Battle<'own, 'library>> {
if let Some(data) = &self.battle_data {
Some(&data.battle)
Some(&data.battle().unwrap())
} else {
None
}
@@ -298,7 +304,11 @@ impl<'own, 'library> Pokemon<'own, 'library> {
return v;
}
}
self.form.get_ability(self.ability_index)
self.library
.static_data()
.abilities()
.get(self.form.get_ability(self.ability_index))
.unwrap()
}
pub fn ability_script(&self) -> &ScriptContainer {
@@ -337,17 +347,8 @@ impl<'own, 'library> Pokemon<'own, 'library> {
// If we're in battle, use the battle random for predictability
if self.battle_data.is_some() {
let battle_data = self.battle_data.as_mut().unwrap();
self.gender = species.get_random_gender(
&mut battle_data
.battle
.upgrade()
.unwrap()
.read()
.random()
.get_rng()
.lock()
.unwrap(),
);
self.gender =
species.get_random_gender(&mut battle_data.battle().unwrap().random().get_rng().lock().unwrap());
} else {
// If we're not in battle, just use a new random.
self.gender = species.get_random_gender(&mut Random::default());
@@ -358,8 +359,8 @@ impl<'own, 'library> Pokemon<'own, 'library> {
self.gender = Gender::Genderless;
}
if let Some(battle_data) = &self.battle_data {
if let Some(battle) = battle_data.battle.upgrade() {
battle.read().event_hook().trigger(Event::SpeciesChange {
if let Some(battle) = battle_data.battle() {
battle.event_hook().trigger(Event::SpeciesChange {
pokemon: self,
species,
form,
@@ -408,11 +409,8 @@ impl<'own, 'library> Pokemon<'own, 'library> {
// TODO: consider form specific attacks?
if let Some(battle_data) = &self.battle_data {
if let Some(battle) = battle_data.battle.upgrade() {
battle
.read()
.event_hook()
.trigger(Event::FormChange { pokemon: self, form })
if let Some(battle) = battle_data.battle() {
battle.event_hook().trigger(Event::FormChange { pokemon: self, form })
}
}
}
@@ -425,7 +423,7 @@ impl<'own, 'library> Pokemon<'own, 'library> {
self.current_health == 0
}
pub fn set_battle_data(&mut self, battle: Weak<RwLock<Battle<'own, 'library>>>, battle_side_index: u8) {
pub fn set_battle_data(&mut self, battle: *mut Battle<'own, 'library>, battle_side_index: u8) {
if let Some(battle_data) = &mut self.battle_data {
battle_data.battle = battle;
battle_data.battle_side_index = battle_side_index;
@@ -485,8 +483,8 @@ impl<'own, 'library> Pokemon<'own, 'library> {
}
let new_health = self.current_health() - damage;
if let Some(battle_data) = &self.battle_data {
if let Some(battle) = battle_data.battle.upgrade() {
battle.read().event_hook().trigger(Event::Damage {
if let Some(battle) = battle_data.battle() {
battle.event_hook().trigger(Event::Damage {
pokemon: self,
source,
original_health: self.current_health(),
@@ -502,36 +500,56 @@ impl<'own, 'library> Pokemon<'own, 'library> {
}
}
pub fn on_faint(&self, source: DamageSource) {
if let Some(battle_data) = &self.battle_data {
if let Some(battle) = battle_data.battle.upgrade() {
battle.read().event_hook().trigger(Event::Faint { pokemon: self });
script_hook!(on_faint, self, self, source);
script_hook!(on_remove, self,);
}
// TODO: Experience gain
pub fn on_faint(&mut self, source: DamageSource) {
if self.battle_data.is_some() && self.battle_data.as_ref().unwrap().battle().is_some() {
self.battle_data
.as_ref()
.unwrap()
.battle()
.unwrap()
.event_hook()
.trigger(Event::Faint { pokemon: self });
script_hook!(on_faint, self, self, source);
script_hook!(on_remove, self,);
if let Some(battle) = battle_data.battle.upgrade() {
if !battle
.read()
.can_slot_be_filled(battle_data.battle_side_index, battle_data.index)
{
let mut battle = battle.write();
let side = &mut battle.sides_mut()[battle_data.battle_side_index as usize];
side.mark_slot_as_unfillable(self);
}
battle.write().validate_battle_state();
let side_index = self.battle_data.as_ref().unwrap().battle_side_index;
let index = self.battle_data.as_ref().unwrap().index;
if !self
.battle_data
.as_ref()
.unwrap()
.battle()
.unwrap()
.can_slot_be_filled(side_index, index)
{
self.battle_data.as_mut().unwrap().battle_mut().unwrap().sides_mut()[side_index as usize]
.mark_slot_as_unfillable(index);
}
self.battle_data
.as_mut()
.unwrap()
.battle_mut()
.unwrap()
.validate_battle_state();
}
}
pub fn learn_move(&mut self, move_name: &StringKey, learn_method: MoveLearnMethod) {
let move_pos = self.learned_moves().iter().position(|a| a.is_none());
if move_pos.is_none() {
panic!("No more moves with an empty space found.");
}
let move_data = self.library.static_data().moves().get(move_name).unwrap();
self.moves[move_pos.unwrap()] = Some(Arc::new(RwLock::new(LearnedMove::new(move_data, learn_method))));
}
}
impl<'own, 'library> ScriptSource<'own> for Pokemon<'own, 'library> {
fn get_script_count(&self) -> usize {
let mut c = 3;
if let Some(battle_data) = &self.battle_data {
if let Some(battle) = battle_data.battle.upgrade() {
c += battle.read().sides()[battle_data.battle_side_index as usize].get_script_count();
if let Some(battle) = battle_data.battle() {
c += battle.sides()[battle_data.battle_side_index as usize].get_script_count();
}
}
c
@@ -551,8 +569,8 @@ impl<'own, 'library> ScriptSource<'own> for Pokemon<'own, 'library> {
fn collect_scripts(&self, scripts: &mut Vec<ScriptWrapper>) {
self.get_own_scripts(scripts);
if let Some(battle_data) = &self.battle_data {
if let Some(battle) = battle_data.battle.upgrade() {
battle.read().sides()[battle_data.battle_side_index as usize].collect_scripts(scripts);
if let Some(battle) = battle_data.battle() {
battle.sides()[battle_data.battle_side_index as usize].collect_scripts(scripts);
}
}
}