Loads of work to replace panics with results.
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
@@ -22,8 +22,8 @@ use crate::static_data::TypeIdentifier;
|
||||
use crate::static_data::{Ability, Statistic};
|
||||
use crate::static_data::{ClampedStatisticSet, StatisticSet};
|
||||
use crate::utils::Random;
|
||||
use crate::{script_hook, StringKey, ValueIdentifiable, ValueIdentifier};
|
||||
use anyhow::Result;
|
||||
use crate::{script_hook, PkmnError, StringKey, ValueIdentifiable, ValueIdentifier};
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
|
||||
/// An individual Pokemon as we know and love them.
|
||||
#[derive(Debug)]
|
||||
@@ -142,7 +142,7 @@ impl Pokemon {
|
||||
.static_data()
|
||||
.natures()
|
||||
.get_nature(nature)
|
||||
.unwrap_or_else(|| panic!("Unknown nature name was given: {}.", &nature));
|
||||
.ok_or(PkmnError::InvalidNatureName { nature: nature.clone() })?;
|
||||
let mut pokemon = Self {
|
||||
identifier: Default::default(),
|
||||
library,
|
||||
@@ -180,7 +180,7 @@ impl Pokemon {
|
||||
volatile: Default::default(),
|
||||
script_source_data: Default::default(),
|
||||
};
|
||||
pokemon.recalculate_flat_stats();
|
||||
pokemon.recalculate_flat_stats()?;
|
||||
let health = pokemon.flat_stats().hp();
|
||||
pokemon.current_health = AtomicU32::new(health);
|
||||
|
||||
@@ -257,20 +257,19 @@ impl Pokemon {
|
||||
self.held_item.write().take()
|
||||
}
|
||||
/// Makes the Pokemon uses its held item.
|
||||
pub fn consume_held_item(&self) -> bool {
|
||||
pub fn consume_held_item(&self) -> Result<bool> {
|
||||
if self.held_item.read().is_none() {
|
||||
return false;
|
||||
return Ok(false);
|
||||
}
|
||||
let script = self
|
||||
.library
|
||||
.load_item_script(self.held_item.read().as_ref().unwrap())
|
||||
.unwrap();
|
||||
.load_item_script(self.held_item.read().as_ref().ok_or(PkmnError::UnableToAcquireLock)?)?;
|
||||
if script.is_none() {
|
||||
return false;
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
// TODO: the entire item use part.
|
||||
todo!();
|
||||
bail!("Not implemented yet.")
|
||||
}
|
||||
|
||||
/// The remaining health points of the Pokemon.
|
||||
@@ -331,7 +330,7 @@ impl Pokemon {
|
||||
self.stat_boost.get_stat(stat)
|
||||
}
|
||||
/// Change a boosted stat by a certain amount.
|
||||
pub fn change_stat_boost(&self, stat: Statistic, mut diff_amount: i8, self_inflicted: bool) -> bool {
|
||||
pub fn change_stat_boost(&self, stat: Statistic, mut diff_amount: i8, self_inflicted: bool) -> Result<bool> {
|
||||
let mut prevent = false;
|
||||
script_hook!(
|
||||
prevent_stat_boost_change,
|
||||
@@ -343,7 +342,7 @@ impl Pokemon {
|
||||
&mut prevent
|
||||
);
|
||||
if prevent {
|
||||
return false;
|
||||
return Ok(false);
|
||||
}
|
||||
script_hook!(
|
||||
change_stat_boost_change,
|
||||
@@ -354,7 +353,7 @@ impl Pokemon {
|
||||
&mut diff_amount
|
||||
);
|
||||
if diff_amount == 0 {
|
||||
return false;
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
let mut changed = false;
|
||||
@@ -378,9 +377,9 @@ impl Pokemon {
|
||||
new_value,
|
||||
})
|
||||
}
|
||||
self.recalculate_boosted_stats();
|
||||
self.recalculate_boosted_stats()?;
|
||||
}
|
||||
changed
|
||||
Ok(changed)
|
||||
}
|
||||
|
||||
/// The [individual values](https://bulbapedia.bulbagarden.net/wiki/Individual_values) of the Pokemon.
|
||||
@@ -416,15 +415,21 @@ impl Pokemon {
|
||||
self.override_ability.is_some()
|
||||
}
|
||||
/// Returns the currently active ability.
|
||||
pub fn active_ability(&self) -> Arc<dyn Ability> {
|
||||
pub fn active_ability(&self) -> Result<Arc<dyn Ability>> {
|
||||
if let Some(v) = &self.override_ability {
|
||||
return v.clone();
|
||||
return Ok(v.clone());
|
||||
}
|
||||
self.library
|
||||
|
||||
let form = self.form();
|
||||
let ability = form.get_ability(self.ability_index);
|
||||
Ok(self
|
||||
.library
|
||||
.static_data()
|
||||
.abilities()
|
||||
.get(self.form().get_ability(self.ability_index))
|
||||
.unwrap()
|
||||
.get(ability)
|
||||
.ok_or(PkmnError::InvalidAbilityName {
|
||||
ability: ability.clone(),
|
||||
})?)
|
||||
}
|
||||
|
||||
/// The script for the status.
|
||||
@@ -450,22 +455,23 @@ impl Pokemon {
|
||||
/// Calculates the flat stats on the Pokemon. This should be called when for example the base
|
||||
/// stats, level, nature, IV, or EV changes. This has a side effect of recalculating the boosted
|
||||
/// stats, as those depend on the flat stats.
|
||||
pub fn recalculate_flat_stats(&self) {
|
||||
pub fn recalculate_flat_stats(&self) -> Result<()> {
|
||||
self.library
|
||||
.stat_calculator()
|
||||
.calculate_flat_stats(self, &self.flat_stats);
|
||||
self.recalculate_boosted_stats();
|
||||
.calculate_flat_stats(self, &self.flat_stats)?;
|
||||
self.recalculate_boosted_stats()?;
|
||||
Ok(())
|
||||
}
|
||||
/// Calculates the boosted stats on the Pokemon, _without_ recalculating the flat stats.
|
||||
/// This should be called when a stat boost changes.
|
||||
pub fn recalculate_boosted_stats(&self) {
|
||||
pub fn recalculate_boosted_stats(&self) -> Result<()> {
|
||||
self.library
|
||||
.stat_calculator()
|
||||
.calculate_boosted_stats(self, &self.boosted_stats);
|
||||
.calculate_boosted_stats(self, &self.boosted_stats)
|
||||
}
|
||||
|
||||
/// Change the species of the Pokemon.
|
||||
pub fn change_species(&self, species: Arc<dyn Species>, form: Arc<dyn Form>) {
|
||||
pub fn change_species(&self, species: Arc<dyn Species>, form: Arc<dyn Form>) -> Result<()> {
|
||||
*self.species.write() = species.clone();
|
||||
*self.form.write() = form.clone();
|
||||
|
||||
@@ -474,7 +480,16 @@ impl Pokemon {
|
||||
// If we're in battle, use the battle random for predictability
|
||||
let r = self.battle_data.read();
|
||||
if let Some(data) = r.deref() {
|
||||
let mut random = data.battle().unwrap().random().get_rng().lock().unwrap();
|
||||
let mut random = match data
|
||||
.battle()
|
||||
.ok_or(anyhow!("Battle not set"))?
|
||||
.random()
|
||||
.get_rng()
|
||||
.lock()
|
||||
{
|
||||
Ok(v) => v,
|
||||
Err(_) => return Err(PkmnError::UnableToAcquireLock.into()),
|
||||
};
|
||||
*self.gender.write() = species.get_random_gender(random.deref_mut());
|
||||
} else {
|
||||
// If we're not in battle, just use a new random.
|
||||
@@ -495,12 +510,13 @@ impl Pokemon {
|
||||
})
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Change the form of the Pokemon.
|
||||
pub fn change_form(&self, form: &Arc<dyn Form>) {
|
||||
pub fn change_form(&self, form: &Arc<dyn Form>) -> Result<()> {
|
||||
if self.form().value_identifier() == form.value_identifier() {
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
*self.form.write() = form.clone();
|
||||
|
||||
@@ -514,21 +530,21 @@ impl Pokemon {
|
||||
self.weight.store(form.weight(), Ordering::SeqCst);
|
||||
self.height.store(form.height(), Ordering::SeqCst);
|
||||
|
||||
let ability = self.active_ability()?;
|
||||
let ability_script = self
|
||||
.library
|
||||
.load_script(self.into(), ScriptCategory::Ability, self.active_ability().name())
|
||||
.unwrap();
|
||||
.load_script(self.into(), ScriptCategory::Ability, ability.name())?;
|
||||
if let Some(ability_script) = ability_script {
|
||||
self.ability_script
|
||||
.set(ability_script)
|
||||
.as_ref()
|
||||
// Ensure the ability script gets initialized with the parameters for the ability.
|
||||
.on_initialize(&self.library, self.active_ability().parameters().to_vec())
|
||||
.on_initialize(&self.library, ability.parameters().to_vec())
|
||||
} else {
|
||||
self.ability_script.clear();
|
||||
}
|
||||
let old_health = self.max_health();
|
||||
self.recalculate_flat_stats();
|
||||
self.recalculate_flat_stats()?;
|
||||
let diff_health = (self.max_health() - old_health) as i32;
|
||||
if self.current_health() == 0 && (self.current_health() as i32) < -diff_health {
|
||||
self.current_health.store(0, Ordering::SeqCst);
|
||||
@@ -547,7 +563,8 @@ impl Pokemon {
|
||||
form: form.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Whether or not the Pokemon is useable in a battle.
|
||||
@@ -657,8 +674,14 @@ impl Pokemon {
|
||||
script_hook!(on_remove, self,);
|
||||
|
||||
if !battle.can_slot_be_filled(battle_data.battle_side_index(), battle_data.index()) {
|
||||
battle.sides()[battle_data.battle_side_index() as usize]
|
||||
.mark_slot_as_unfillable(battle_data.index());
|
||||
battle
|
||||
.sides()
|
||||
.get(battle_data.battle_side_index() as usize)
|
||||
.ok_or(PkmnError::IndexOutOfBounds {
|
||||
index: battle_data.battle_side_index() as usize,
|
||||
len: battle.sides().len(),
|
||||
})?
|
||||
.mark_slot_as_unfillable(battle_data.index())?;
|
||||
}
|
||||
|
||||
battle.validate_battle_state()?;
|
||||
@@ -695,14 +718,22 @@ impl Pokemon {
|
||||
}
|
||||
|
||||
/// Learn a move.
|
||||
pub fn learn_move(&self, move_name: &StringKey, learn_method: MoveLearnMethod) {
|
||||
pub fn learn_move(&self, move_name: &StringKey, learn_method: MoveLearnMethod) -> Result<()> {
|
||||
let mut learned_moves = self.learned_moves().write();
|
||||
let move_pos = learned_moves.iter().position(|a| a.is_none());
|
||||
if move_pos.is_none() {
|
||||
panic!("No more moves with an empty space found.");
|
||||
bail!("No more moves with an empty space found.");
|
||||
}
|
||||
let move_data = self.library.static_data().moves().get(move_name).unwrap();
|
||||
let move_data = self
|
||||
.library
|
||||
.static_data()
|
||||
.moves()
|
||||
.get(move_name)
|
||||
.ok_or(PkmnError::InvalidMoveName {
|
||||
move_name: move_name.clone(),
|
||||
})?;
|
||||
learned_moves[move_pos.unwrap()] = Some(Arc::new(LearnedMove::new(move_data, learn_method)));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Removes the current non-volatile status from the Pokemon.
|
||||
@@ -711,7 +742,7 @@ impl Pokemon {
|
||||
}
|
||||
|
||||
/// Increases the level by a certain amount
|
||||
pub fn change_level_by(&self, amount: LevelInt) {
|
||||
pub fn change_level_by(&self, amount: LevelInt) -> Result<()> {
|
||||
self.level
|
||||
.fetch_update(Ordering::SeqCst, Ordering::Relaxed, |x| {
|
||||
let max_level = self.library().static_data().settings().maximum_level();
|
||||
@@ -721,8 +752,8 @@ impl Pokemon {
|
||||
Some(x + amount)
|
||||
}
|
||||
})
|
||||
.expect("Failed to change level.");
|
||||
self.recalculate_flat_stats();
|
||||
.ok();
|
||||
self.recalculate_flat_stats()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -770,14 +801,14 @@ impl PokemonBattleData {
|
||||
}
|
||||
|
||||
impl ScriptSource for Pokemon {
|
||||
fn get_script_count(&self) -> usize {
|
||||
fn get_script_count(&self) -> Result<usize> {
|
||||
let mut c = 3;
|
||||
if let Some(battle_data) = &self.battle_data.read().deref() {
|
||||
if let Some(battle) = battle_data.battle() {
|
||||
c += battle.sides()[battle_data.battle_side_index() as usize].get_script_count();
|
||||
c += battle.sides()[battle_data.battle_side_index() as usize].get_script_count()?;
|
||||
}
|
||||
}
|
||||
c
|
||||
Ok(c)
|
||||
}
|
||||
|
||||
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> {
|
||||
@@ -791,13 +822,14 @@ impl ScriptSource for Pokemon {
|
||||
scripts.push((&self.volatile).into());
|
||||
}
|
||||
|
||||
fn collect_scripts(&self, scripts: &mut Vec<ScriptWrapper>) {
|
||||
fn collect_scripts(&self, scripts: &mut Vec<ScriptWrapper>) -> Result<()> {
|
||||
self.get_own_scripts(scripts);
|
||||
if let Some(battle_data) = &self.battle_data.read().deref() {
|
||||
if let Some(battle) = battle_data.battle() {
|
||||
battle.sides()[battle_data.battle_side_index() as usize].collect_scripts(scripts);
|
||||
battle.sides()[battle_data.battle_side_index() as usize].collect_scripts(scripts)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -883,8 +915,10 @@ pub mod test {
|
||||
static_lib.expect_natures().return_const(Box::new(nature_lib));
|
||||
|
||||
let mut stat_calculator = MockBattleStatCalculator::new();
|
||||
stat_calculator.expect_calculate_flat_stats().returning(|_, _| {});
|
||||
stat_calculator.expect_calculate_boosted_stats().returning(|_, _| {});
|
||||
stat_calculator.expect_calculate_flat_stats().returning(|_, _| Ok(()));
|
||||
stat_calculator
|
||||
.expect_calculate_boosted_stats()
|
||||
.returning(|_, _| Ok(()));
|
||||
|
||||
let mut lib = MockDynamicLibrary::new();
|
||||
lib.expect_static_data().return_const(Box::new(static_lib));
|
||||
|
||||
Reference in New Issue
Block a user