Rework in line with PkmnLib for moving towards Result
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Deukhoofd 2023-06-22 16:40:51 +02:00
parent 2df5feab26
commit 5e0bd632b9
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
58 changed files with 1901 additions and 1345 deletions

View File

@ -12,3 +12,6 @@ opt-level = "s"
lto = false lto = false
debug-assertions = true debug-assertions = true
[profile.release.package."*"]
opt-level = "s"
debug-assertions = false

View File

@ -1,12 +1,13 @@
pub use crate::script; pub use crate::script;
pub use alloc::boxed::Box; pub use alloc::boxed::Box;
pub use alloc::rc::Rc; pub use alloc::rc::Rc;
pub use alloc::vec::Vec;
pub use atomic_float::AtomicF32; pub use atomic_float::AtomicF32;
pub use core::any::Any; pub use core::any::Any;
pub use core::sync::atomic::{AtomicBool, AtomicI8, AtomicU32, Ordering}; pub use core::sync::atomic::{AtomicBool, AtomicI8, AtomicU32, Ordering};
pub use pkmn_lib_interface::app_interface::list::ImmutableList;
pub use pkmn_lib_interface::app_interface::{ pub use pkmn_lib_interface::app_interface::{
get_volatile_as, BattleSide, DamageSource, DynamicLibrary, EffectParameter, ExecutingMove, get_volatile_as, BattleSide, DamageSource, DynamicLibrary, EffectParameter, ExecutingMove,
Gender, MoveCategory, MoveData, Party, Pokemon, Statistic, StringKey, TurnChoice, Gender, MoveCategory, MoveData, Party, Pokemon, Statistic, StringKey, TurnChoice,
}; };
pub use pkmn_lib_interface::handling::{Script, ScriptCapabilities, ScriptOwner}; pub use pkmn_lib_interface::handling::{Script, ScriptCapabilities, ScriptOwner};
pub use pkmn_lib_interface::PkmnResult;

View File

@ -1,4 +1,5 @@
use crate::common_usings::*; use crate::common_usings::*;
use pkmn_lib_interface::PkmnResult;
script!(Acrobatics, "acrobatics"); script!(Acrobatics, "acrobatics");
@ -21,14 +22,15 @@ impl Script for Acrobatics {
_target: Pokemon, _target: Pokemon,
_hit: u8, _hit: u8,
base_power: &mut u8, base_power: &mut u8,
) { ) -> PkmnResult<()> {
if mv.user().held_item().is_none() { if mv.user().held_item()?.is_none() {
if *base_power >= 128_u8 { if *base_power >= 128_u8 {
*base_power = 255 *base_power = 255
} else { } else {
*base_power *= 2; *base_power *= 2;
} }
} }
Ok(())
} }
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
@ -47,11 +49,11 @@ mod tests {
mv.expect_user().returning(move || { mv.expect_user().returning(move || {
let mut user = MockPokemon::new(); let mut user = MockPokemon::new();
user.expect_held_item().returning(move || { user.expect_held_item().returning(move || {
if has_held_item { Ok(if has_held_item {
Some(Rc::new(MockItem::new())) Some(Rc::new(MockItem::new()))
} else { } else {
None None
} })
}); });
Rc::new(user) Rc::new(user)
}); });
@ -64,7 +66,9 @@ mod tests {
let script = Acrobatics::new(); let script = Acrobatics::new();
let mut base_power = 50u8; let mut base_power = 50u8;
script.change_base_power(mv, Rc::new(MockPokemon::new()), 0, &mut base_power); script
.change_base_power(mv, Rc::new(MockPokemon::new()), 0, &mut base_power)
.unwrap();
assert_eq!(100, base_power); assert_eq!(100, base_power);
} }
@ -74,7 +78,9 @@ mod tests {
let script = Acrobatics::new(); let script = Acrobatics::new();
let mut base_power = 200u8; let mut base_power = 200u8;
script.change_base_power(mv, Rc::new(MockPokemon::new()), 0, &mut base_power); script
.change_base_power(mv, Rc::new(MockPokemon::new()), 0, &mut base_power)
.unwrap();
assert_eq!(255, base_power); assert_eq!(255, base_power);
} }
@ -84,7 +90,9 @@ mod tests {
let script = Acrobatics::new(); let script = Acrobatics::new();
let mut base_power = 50u8; let mut base_power = 50u8;
script.change_base_power(mv, Rc::new(MockPokemon::new()), 0, &mut base_power); script
.change_base_power(mv, Rc::new(MockPokemon::new()), 0, &mut base_power)
.unwrap();
assert_eq!(50, base_power); assert_eq!(50, base_power);
} }
} }

View File

@ -1,5 +1,6 @@
use crate::common_usings::*; use crate::common_usings::*;
use core::mem::transmute; use core::mem::transmute;
use pkmn_lib_interface::PkmnResult;
pub struct Acupressure {} pub struct Acupressure {}
@ -22,14 +23,15 @@ impl Script for Acupressure {
&[ScriptCapabilities::OnSecondaryEffect] &[ScriptCapabilities::OnSecondaryEffect]
} }
fn on_secondary_effect(&self, mv: ExecutingMove, target: Pokemon, hit: u8) { fn on_secondary_effect(&self, mv: ExecutingMove, target: Pokemon, hit: u8) -> PkmnResult<()> {
if target.equals(&mv.user()) { if target.equals(&mv.user()) {
mv.get_hit_data(&target, hit).fail(); mv.get_hit_data(&target, hit)?.fail()?;
return; return Ok(());
} }
let rand_stat: Statistic = let rand_stat: Statistic =
unsafe { transmute(target.battle().unwrap().random().get_between(1, 6) as u8) }; unsafe { transmute(target.battle()?.unwrap().random().get_between(1, 6)? as u8) };
target.change_stat_boost(rand_stat, 2, false); target.change_stat_boost(rand_stat, 2, false)?;
Ok(())
} }
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
@ -56,13 +58,13 @@ mod tests {
mv.expect_user().returning_st(move || user.clone()); mv.expect_user().returning_st(move || user.clone());
let mut hit_data = MockHitData::new(); let mut hit_data = MockHitData::new();
hit_data.expect_fail().once(); hit_data.expect_fail().returning(|| Ok(())).once();
let hit_data = Rc::new(hit_data); let hit_data = Rc::new(hit_data);
mv.expect_get_hit_data() mv.expect_get_hit_data()
.returning_st(move |_, _| hit_data.clone()); .returning_st(move |_, _| Ok(hit_data.clone()));
let script = Acupressure::new(); let script = Acupressure::new();
script.on_secondary_effect(Rc::new(mv), u, 0); script.on_secondary_effect(Rc::new(mv), u, 0).unwrap();
} }
#[test] #[test]
@ -76,11 +78,11 @@ mod tests {
random.expect_get_between().returning_st(|low, high| { random.expect_get_between().returning_st(|low, high| {
assert_eq!(1, low); assert_eq!(1, low);
assert_eq!(6, high); assert_eq!(6, high);
1 Ok(1)
}); });
Rc::new(random) Rc::new(random)
}); });
Some(Rc::new(battle)) Ok(Some(Rc::new(battle)))
}); });
user.expect_change_stat_boost() user.expect_change_stat_boost()
.once() .once()
@ -88,7 +90,7 @@ mod tests {
assert_eq!(Statistic::Attack, stat); assert_eq!(Statistic::Attack, stat);
assert_eq!(2, amount); assert_eq!(2, amount);
assert!(!self_inflicted); assert!(!self_inflicted);
true Ok(true)
}); });
let user = Rc::new(user); let user = Rc::new(user);
@ -98,6 +100,6 @@ mod tests {
mv.expect_user().returning_st(move || user.clone()); mv.expect_user().returning_st(move || user.clone());
let script = Acupressure::new(); let script = Acupressure::new();
script.on_secondary_effect(Rc::new(mv), u, 0); script.on_secondary_effect(Rc::new(mv), u, 0).unwrap();
} }
} }

View File

@ -1,4 +1,5 @@
use crate::common_usings::*; use crate::common_usings::*;
use pkmn_lib_interface::PkmnResult;
pub struct AfterYou {} pub struct AfterYou {}
@ -21,15 +22,16 @@ impl Script for AfterYou {
&[ScriptCapabilities::OnSecondaryEffect] &[ScriptCapabilities::OnSecondaryEffect]
} }
fn on_secondary_effect(&self, mv: ExecutingMove, target: Pokemon, hit: u8) { fn on_secondary_effect(&self, mv: ExecutingMove, target: Pokemon, hit: u8) -> PkmnResult<()> {
if !target if !target
.battle() .battle()?
.unwrap() .unwrap()
.choice_queue() .choice_queue()
.move_pokemon_choice_next(&target) .move_pokemon_choice_next(&target)?
{ {
mv.get_hit_data(&target, hit).fail() mv.get_hit_data(&target, hit)?.fail()?
} }
Ok(())
} }
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
@ -53,7 +55,7 @@ mod tests {
choice_queue choice_queue
.expect_move_pokemon_choice_next() .expect_move_pokemon_choice_next()
.once() .once()
.return_const(true); .returning_st(move |_| Ok(true));
Rc::new(choice_queue) Rc::new(choice_queue)
}); });
@ -62,11 +64,13 @@ mod tests {
target target
.expect_battle() .expect_battle()
.once() .once()
.return_once_st(move || Some(battle)); .return_once_st(move || Ok(Some(battle)));
let target = Rc::new(target); let target = Rc::new(target);
let script = AfterYou::new(); let script = AfterYou::new();
script.on_secondary_effect(Rc::new(MockExecutingMove::new()), target, 0); script
.on_secondary_effect(Rc::new(MockExecutingMove::new()), target, 0)
.unwrap();
} }
#[test] #[test]
@ -77,7 +81,7 @@ mod tests {
choice_queue choice_queue
.expect_move_pokemon_choice_next() .expect_move_pokemon_choice_next()
.once() .once()
.return_const(false); .returning_st(move |_| Ok(false));
Rc::new(choice_queue) Rc::new(choice_queue)
}); });
@ -86,18 +90,18 @@ mod tests {
target target
.expect_battle() .expect_battle()
.once() .once()
.return_once_st(move || Some(battle)); .return_once_st(move || Ok(Some(battle)));
let target = Rc::new(target); let target = Rc::new(target);
let mut mv = MockExecutingMove::new(); let mut mv = MockExecutingMove::new();
mv.expect_get_hit_data().once().returning_st(move |_, _| { mv.expect_get_hit_data().once().returning_st(move |_, _| {
let mut hit = MockHitData::new(); let mut hit = MockHitData::new();
hit.expect_fail().once(); hit.expect_fail().returning(|| Ok(())).once();
Rc::new(hit) Ok(Rc::new(hit))
}); });
let mv = Rc::new(mv); let mv = Rc::new(mv);
let script = AfterYou::new(); let script = AfterYou::new();
script.on_secondary_effect(mv, target, 0); script.on_secondary_effect(mv, target, 0).unwrap();
} }
} }

View File

@ -1,12 +1,13 @@
use crate::common_usings::*; use crate::common_usings::*;
use alloc::vec::Vec; use alloc::vec::Vec;
use pkmn_lib_interface::PkmnResult;
script!(Assist, "assist"); script!(Assist, "assist");
impl Assist { impl Assist {
/// Gets all the learned moves from the entire party, except the ones from the user, and the ones /// Gets all the learned moves from the entire party, except the ones from the user, and the ones
/// that are not allowed to be copied. /// that are not allowed to be copied.
fn get_party_moves(party: &Party, user: &Pokemon) -> Vec<MoveData> { fn get_party_moves(party: &Party, user: &Pokemon) -> PkmnResult<Vec<MoveData>> {
let mut possible_moves = Vec::new(); let mut possible_moves = Vec::new();
// Iterate over every mon in the party // Iterate over every mon in the party
for mon in party.into_iter().flatten() { for mon in party.into_iter().flatten() {
@ -16,7 +17,7 @@ impl Assist {
} }
// Iterate over all moves. We make the assumption of 4 moves. // Iterate over all moves. We make the assumption of 4 moves.
for move_index in 0..4 { for move_index in 0..4 {
let mv = mon.get_learned_move(move_index); let mv = mon.get_learned_move(move_index)?;
if let Some(mv) = mv { if let Some(mv) = mv {
// Make sure we can copy the move, otherwise add it as possible move. // Make sure we can copy the move, otherwise add it as possible move.
if crate::utils::copyable_moves::can_copy_move(&mv.move_data()) { if crate::utils::copyable_moves::can_copy_move(&mv.move_data()) {
@ -25,7 +26,7 @@ impl Assist {
} }
} }
} }
possible_moves Ok(possible_moves)
} }
} }
@ -42,24 +43,25 @@ impl Script for Assist {
&[ScriptCapabilities::ChangeMove] &[ScriptCapabilities::ChangeMove]
} }
fn change_move(&self, choice: TurnChoice, move_name: &mut StringKey) { fn change_move(&self, choice: TurnChoice, move_name: &mut StringKey) -> PkmnResult<()> {
let user = choice.user(); let user = choice.user();
let battle = user.battle().unwrap(); let battle = user.battle()?.unwrap();
let party = battle.find_party_for_pokemon(&user); let party = battle.find_party_for_pokemon(&user)?;
if party.is_none() { if party.is_none() {
choice.fail(); choice.fail()?;
return; return Ok(());
} }
let party = party.unwrap().party(); let party = party.unwrap().party();
let possible_moves = Self::get_party_moves(&party, &user); let possible_moves = Self::get_party_moves(&party, &user)?;
if possible_moves.is_empty() { if possible_moves.is_empty() {
choice.fail(); choice.fail()?;
return; return Ok(());
} }
let random = battle.random().get_max(possible_moves.len() as i32); let random = battle.random().get_max(possible_moves.len() as i32)?;
*move_name = possible_moves[random as usize].name(); *move_name = possible_moves[random as usize].name();
Ok(())
} }
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
@ -93,9 +95,9 @@ mod tests {
.returning_st(move || moves.get(index).unwrap().clone()); .returning_st(move || moves.get(index).unwrap().clone());
Rc::new(move_data) Rc::new(move_data)
}); });
Some(Rc::new(learned_move)) Ok(Some(Rc::new(learned_move)))
} else { } else {
None Ok(None)
} }
}); });
mon.expect_equals().return_const(equals_user); mon.expect_equals().return_const(equals_user);
@ -105,16 +107,19 @@ mod tests {
#[test] #[test]
fn get_party_moves_returns_moves_from_party_length_1() { fn get_party_moves_returns_moves_from_party_length_1() {
let mut party = MockParty::new(); let mut party = MockParty::new();
party.expect_length().once().return_const(1usize); party
.expect_length()
.once()
.returning_st(move || Ok(1usize));
party party
.expect_get_pokemon() .expect_get_pokemon()
.times(1) .times(1)
.returning_st(move |_| Some(mock_pokemon_with_moves(vec!["tackle".into()], false))); .returning_st(move |_| Ok(Some(mock_pokemon_with_moves(vec!["tackle".into()], false))));
let party: Party = Rc::new(party); let party: Party = Rc::new(party);
let user: Pokemon = Rc::new(MockPokemon::new()); let user: Pokemon = Rc::new(MockPokemon::new());
let moves = Assist::get_party_moves(&party, &user); let moves = Assist::get_party_moves(&party, &user).unwrap();
assert_eq!(1, moves.len()); assert_eq!(1, moves.len());
assert_eq!(moves[0].name(), "tackle".into()) assert_eq!(moves[0].name(), "tackle".into())
} }
@ -122,35 +127,38 @@ mod tests {
#[test] #[test]
fn get_party_moves_returns_moves_from_party_length_7() { fn get_party_moves_returns_moves_from_party_length_7() {
let mut party = MockParty::new(); let mut party = MockParty::new();
party.expect_length().once().return_const(3usize); party
.expect_length()
.once()
.returning_st(move || Ok(3usize));
party party
.expect_get_pokemon() .expect_get_pokemon()
.times(3) .times(3)
.returning_st(move |index| { .returning_st(move |index| {
if index == 0 { if index == 0 {
Some(mock_pokemon_with_moves( Ok(Some(mock_pokemon_with_moves(
vec!["move1".into(), "move2".into(), "move3".into()], vec!["move1".into(), "move2".into(), "move3".into()],
false, false,
)) )))
} else if index == 1 { } else if index == 1 {
Some(mock_pokemon_with_moves( Ok(Some(mock_pokemon_with_moves(
vec!["move1".into(), "move4".into()], vec!["move1".into(), "move4".into()],
false, false,
)) )))
} else if index == 2 { } else if index == 2 {
Some(mock_pokemon_with_moves( Ok(Some(mock_pokemon_with_moves(
vec!["move2".into(), "move5".into()], vec!["move2".into(), "move5".into()],
false, false,
)) )))
} else { } else {
None Ok(None)
} }
}); });
let party: Party = Rc::new(party); let party: Party = Rc::new(party);
let user: Pokemon = Rc::new(MockPokemon::new()); let user: Pokemon = Rc::new(MockPokemon::new());
let moves = Assist::get_party_moves(&party, &user); let moves = Assist::get_party_moves(&party, &user).unwrap();
assert_eq!(7, moves.len()); assert_eq!(7, moves.len());
assert_eq!(moves[0].name(), "move1".into()); assert_eq!(moves[0].name(), "move1".into());
assert_eq!(moves[1].name(), "move2".into()); assert_eq!(moves[1].name(), "move2".into());
@ -164,12 +172,15 @@ mod tests {
#[test] #[test]
fn get_party_moves_ignores_user() { fn get_party_moves_ignores_user() {
let mut party = MockParty::new(); let mut party = MockParty::new();
party.expect_length().once().return_const(3usize); party
.expect_length()
.once()
.returning_st(move || Ok(3usize));
party party
.expect_get_pokemon() .expect_get_pokemon()
.times(3) .times(3)
.returning_st(move |index| { .returning_st(move |index| {
if index == 0 { Ok(if index == 0 {
Some(mock_pokemon_with_moves( Some(mock_pokemon_with_moves(
vec!["move1".into(), "move2".into(), "move3".into()], vec!["move1".into(), "move2".into(), "move3".into()],
false, false,
@ -186,13 +197,13 @@ mod tests {
)) ))
} else { } else {
None None
} })
}); });
let party: Party = Rc::new(party); let party: Party = Rc::new(party);
let user: Pokemon = Rc::new(MockPokemon::new()); let user: Pokemon = Rc::new(MockPokemon::new());
let moves = Assist::get_party_moves(&party, &user); let moves = Assist::get_party_moves(&party, &user).unwrap();
assert_eq!(5, moves.len()); assert_eq!(5, moves.len());
assert_eq!(moves[0].name(), "move1".into()); assert_eq!(moves[0].name(), "move1".into());
assert_eq!(moves[1].name(), "move2".into()); assert_eq!(moves[1].name(), "move2".into());
@ -204,26 +215,31 @@ mod tests {
#[test] #[test]
fn get_party_moves_ignores_non_copyable_move() { fn get_party_moves_ignores_non_copyable_move() {
let mut party = MockParty::new(); let mut party = MockParty::new();
party.expect_length().once().return_const(1usize);
party party
.expect_get_pokemon() .expect_length()
.times(1) .once()
.returning_st(move |_| Some(mock_pokemon_with_moves(vec!["chatter".into()], false))); .returning_st(move || Ok(1usize));
party.expect_get_pokemon().times(1).returning_st(move |_| {
Ok(Some(mock_pokemon_with_moves(vec!["chatter".into()], false)))
});
let party: Party = Rc::new(party); let party: Party = Rc::new(party);
let user: Pokemon = Rc::new(MockPokemon::new()); let user: Pokemon = Rc::new(MockPokemon::new());
let moves = Assist::get_party_moves(&party, &user); let moves = Assist::get_party_moves(&party, &user).unwrap();
assert_eq!(0, moves.len()); assert_eq!(0, moves.len());
} }
#[test] #[test]
fn if_moves_found_assist_uses_that_move() { fn if_moves_found_assist_uses_that_move() {
let mut party = MockParty::new(); let mut party = MockParty::new();
party.expect_length().once().return_const(1usize); party
.expect_length()
.once()
.returning_st(move || Ok(1usize));
party party
.expect_get_pokemon() .expect_get_pokemon()
.times(1) .times(1)
.returning_st(move |_| Some(mock_pokemon_with_moves(vec!["tackle".into()], false))); .returning_st(move |_| Ok(Some(mock_pokemon_with_moves(vec!["tackle".into()], false))));
let party: Party = Rc::new(party); let party: Party = Rc::new(party);
@ -243,16 +259,16 @@ mod tests {
let mut p = MockBattleParty::new(); let mut p = MockBattleParty::new();
p.expect_party().returning_st(move || party.clone()); p.expect_party().returning_st(move || party.clone());
Some(Rc::new(p)) Ok(Some(Rc::new(p)))
}); });
battle.expect_random().returning_st(|| { battle.expect_random().returning_st(|| {
let mut random = MockBattleRandom::new(); let mut random = MockBattleRandom::new();
random.expect_get_max().return_const(0); random.expect_get_max().returning_st(move |_| Ok(0));
Rc::new(random) Rc::new(random)
}); });
Some(Rc::new(battle)) Ok(Some(Rc::new(battle)))
}); });
Rc::new(user) Rc::new(user)
@ -270,7 +286,7 @@ mod tests {
let mut move_name: StringKey = "".into(); let mut move_name: StringKey = "".into();
let script = Assist::new(); let script = Assist::new();
script.change_move(choice_data, &mut move_name); script.change_move(choice_data, &mut move_name).unwrap();
assert_eq!(move_name, "tackle".into()) assert_eq!(move_name, "tackle".into())
} }
} }

View File

@ -1,4 +1,5 @@
use crate::common_usings::*; use crate::common_usings::*;
use pkmn_lib_interface::PkmnResult;
script!(Assurance, "assurance"); script!(Assurance, "assurance");
@ -18,20 +19,22 @@ impl Script for Assurance {
] ]
} }
fn on_before_turn(&self, choice: TurnChoice) { fn on_before_turn(&self, choice: TurnChoice) -> PkmnResult<()> {
if let TurnChoice::Move(data) = &choice { if let TurnChoice::Move(data) = &choice {
let side: BattleSide = choice let side: BattleSide = choice
.user() .user()
.battle() .battle()?
.unwrap() .unwrap()
.sides() .sides()
.get(data.target_side() as u32) .get(data.target_side() as usize)
.unwrap(); .unwrap()
.clone();
side.add_volatile(Box::new(AssuranceData { side.add_volatile(Box::new(AssuranceData {
for_position: data.target_index(), for_position: data.target_index(),
has_hit: AtomicBool::new(false), has_hit: AtomicBool::new(false),
})); }))?;
} }
Ok(())
} }
fn change_base_power( fn change_base_power(
@ -40,15 +43,16 @@ impl Script for Assurance {
target: Pokemon, target: Pokemon,
_hit: u8, _hit: u8,
base_power: &mut u8, base_power: &mut u8,
) { ) -> PkmnResult<()> {
if let Some(s) = get_volatile_as::<AssuranceData>( if let Some(s) = get_volatile_as::<AssuranceData>(
target.battle_side().as_ref(), target.battle_side()?.as_ref(),
AssuranceData::get_const_name(), AssuranceData::get_const_name(),
) { )? {
if s.has_hit.load(Ordering::Relaxed) { if s.has_hit.load(Ordering::Relaxed) {
*base_power *= 2; *base_power *= 2;
} }
} }
Ok(())
} }
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
@ -79,9 +83,10 @@ impl Script for AssuranceData {
&[ScriptCapabilities::OnEndTurn, ScriptCapabilities::OnDamage] &[ScriptCapabilities::OnEndTurn, ScriptCapabilities::OnDamage]
} }
fn on_end_turn(&self) { fn on_end_turn(&self) -> PkmnResult<()> {
let side = self.get_owner().unwrap().as_side(); let side = self.get_owner().unwrap().as_side();
side.remove_volatile(self); side.remove_volatile(self)?;
Ok(())
} }
fn on_damage( fn on_damage(
@ -90,10 +95,11 @@ impl Script for AssuranceData {
_source: DamageSource, _source: DamageSource,
_old_health: u32, _old_health: u32,
_new_health: u32, _new_health: u32,
) { ) -> PkmnResult<()> {
if pokemon.battle_index() == self.for_position { if pokemon.battle_index()? == self.for_position {
self.has_hit.store(true, Ordering::Relaxed); self.has_hit.store(true, Ordering::Relaxed);
} }
Ok(())
} }
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {

View File

@ -1,5 +1,6 @@
use crate::common_usings::*; use crate::common_usings::*;
use crate::pokemon::infatuated::Infatuated; use crate::pokemon::infatuated::Infatuated;
use pkmn_lib_interface::PkmnResult;
script!(Attract, "attract"); script!(Attract, "attract");
@ -16,19 +17,22 @@ impl Script for Attract {
&[ScriptCapabilities::OnSecondaryEffect] &[ScriptCapabilities::OnSecondaryEffect]
} }
fn on_secondary_effect(&self, mv: ExecutingMove, target: Pokemon, hit: u8) { fn on_secondary_effect(&self, mv: ExecutingMove, target: Pokemon, hit: u8) -> PkmnResult<()> {
let user_gender = mv.user().gender(); let user_gender = mv.user().gender()?;
let target_gender = target.gender(); let target_gender = target.gender()?;
// If the move is used on a Pokémon that is the same gender as the user, it will fail // If the move is used on a Pokémon that is the same gender as the user, it will fail
if target_gender == user_gender { if target_gender == user_gender {
return mv.get_hit_data(&target, hit).fail(); mv.get_hit_data(&target, hit)?.fail()?;
return Ok(());
} }
// It will also fail if used by or on a gender-unknown Pokémon // It will also fail if used by or on a gender-unknown Pokémon
if user_gender == Gender::Genderless || target_gender == Gender::Genderless { if user_gender == Gender::Genderless || target_gender == Gender::Genderless {
return mv.get_hit_data(&target, hit).fail(); mv.get_hit_data(&target, hit)?.fail()?;
return Ok(());
} }
// If the target is the opposite gender of the Pokémon who launched the move, the target becomes infatuated // If the target is the opposite gender of the Pokémon who launched the move, the target becomes infatuated
target.add_volatile_by_name(Infatuated::get_const_name()); target.add_volatile_by_name(Infatuated::get_const_name())?;
Ok(())
} }
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {

View File

@ -2,6 +2,7 @@ use crate::common_usings::*;
use crate::moves::light_screen::LightScreenEffect; use crate::moves::light_screen::LightScreenEffect;
use crate::moves::reflect::ReflectEffect; use crate::moves::reflect::ReflectEffect;
use crate::weather::hail::Hail; use crate::weather::hail::Hail;
use pkmn_lib_interface::PkmnResult;
script!(AuroraVeil, "aurora_veil"); script!(AuroraVeil, "aurora_veil");
@ -18,21 +19,27 @@ impl Script for AuroraVeil {
&[ScriptCapabilities::OnSecondaryEffect] &[ScriptCapabilities::OnSecondaryEffect]
} }
fn on_secondary_effect(&self, mv: ExecutingMove, target: Pokemon, hit: u8) { fn on_secondary_effect(&self, mv: ExecutingMove, target: Pokemon, hit: u8) -> PkmnResult<()> {
if target.battle().unwrap().has_weather(Hail::get_const_name()) { if target
return mv.get_hit_data(&target, hit).fail(); .battle()?
.unwrap()
.has_weather(Hail::get_const_name())?
{
mv.get_hit_data(&target, hit)?.fail()?;
return Ok(());
} }
let binding = target.battle_side(); let binding = target.battle_side()?;
let script = binding let script = binding
.add_volatile(Box::new(AuroraVeilEffect::new())) .add_volatile(Box::new(AuroraVeilEffect::new()))?
.as_any() .as_any()
.downcast_ref::<AuroraVeilEffect>() .downcast_ref::<AuroraVeilEffect>()
.unwrap(); .unwrap();
if mv.user().has_held_item("light_clay") { if mv.user().has_held_item("light_clay")? {
script.turns.store(8, Ordering::SeqCst); script.turns.store(8, Ordering::SeqCst);
} else { } else {
script.turns.store(5, Ordering::SeqCst); script.turns.store(5, Ordering::SeqCst);
} }
Ok(())
} }
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
@ -66,30 +73,32 @@ impl Script for AuroraVeilEffect {
target: Pokemon, target: Pokemon,
hit: u8, hit: u8,
damage: &mut u32, damage: &mut u32,
) { ) -> PkmnResult<()> {
if mv.get_hit_data(&target, hit).is_critical() { if mv.get_hit_data(&target, hit)?.is_critical()? {
return; return Ok(());
} }
let side = self.get_owner().unwrap().as_side(); let side = self.get_owner().unwrap().as_side();
if side.has_volatile(ReflectEffect::get_const_name()) if side.has_volatile(ReflectEffect::get_const_name())?
&& mv.use_move().category() == MoveCategory::Physical && mv.use_move().category() == MoveCategory::Physical
{ {
return; return Ok(());
} }
if side.has_volatile(LightScreenEffect::get_const_name()) if side.has_volatile(LightScreenEffect::get_const_name())?
&& mv.use_move().category() == MoveCategory::Special && mv.use_move().category() == MoveCategory::Special
{ {
return; return Ok(());
} }
let mut modifier = 2.0; let mut modifier = 2.0;
if target.battle().unwrap().pokemon_per_side() > 1 { if target.battle()?.unwrap().pokemon_per_side()? > 1 {
modifier = 1.5 modifier = 1.5
} }
*damage = (*damage as f32 / modifier) as u32; *damage = (*damage as f32 / modifier) as u32;
Ok(())
} }
fn on_end_turn(&self) { fn on_end_turn(&self) -> PkmnResult<()> {
todo!() // TODO
Ok(())
} }
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {

View File

@ -1,4 +1,5 @@
use crate::common_usings::*; use crate::common_usings::*;
use pkmn_lib_interface::PkmnResult;
script!(Automize, "automize"); script!(Automize, "automize");
@ -15,18 +16,19 @@ impl Script for Automize {
&[ScriptCapabilities::OnSecondaryEffect] &[ScriptCapabilities::OnSecondaryEffect]
} }
fn on_secondary_effect(&self, mv: ExecutingMove, _target: Pokemon, _hit: u8) { fn on_secondary_effect(&self, mv: ExecutingMove, _target: Pokemon, _hit: u8) -> PkmnResult<()> {
let user = mv.user(); let user = mv.user();
let stats = user.boosted_stats(); let stats = user.boosted_stats();
let original_speed = stats.speed(); let original_speed = stats.speed()?;
let original_weight = user.weight(); let original_weight = user.weight()?;
user.change_stat_boost(Statistic::Speed, 2, true); user.change_stat_boost(Statistic::Speed, 2, true)?;
if user.boosted_stats().speed() != original_speed { if user.boosted_stats().speed()? != original_speed {
user.set_weight(original_weight - 100.0); user.set_weight(original_weight - 100.0);
if user.weight() != original_weight { if user.weight()? != original_weight {
// TODO: Became nimble dialog. // TODO: Became nimble dialog.
} }
} }
Ok(())
} }
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {

View File

@ -1,4 +1,6 @@
use crate::common_usings::*; use crate::common_usings::*;
use alloc::vec::Vec;
use pkmn_lib_interface::PkmnResult;
script!( script!(
ChangeAllTargetStats, ChangeAllTargetStats,
@ -27,22 +29,24 @@ impl Script for ChangeAllTargetStats {
fn on_initialize( fn on_initialize(
&self, &self,
_library: DynamicLibrary, _library: DynamicLibrary,
parameters: Option<ImmutableList<Rc<EffectParameter>>>, parameters: Option<Vec<Rc<EffectParameter>>>,
) { ) -> PkmnResult<()> {
self.amount.store( self.amount.store(
parameters.unwrap().get(0).unwrap().as_int() as i8, parameters.unwrap().get(0).unwrap().as_int() as i8,
Ordering::SeqCst, Ordering::SeqCst,
); );
Ok(())
} }
fn on_secondary_effect(&self, mv: ExecutingMove, target: Pokemon, _hit: u8) { fn on_secondary_effect(&self, mv: ExecutingMove, target: Pokemon, _hit: u8) -> PkmnResult<()> {
let user = mv.user(); let user = mv.user();
let amount = self.amount.load(Ordering::SeqCst); let amount = self.amount.load(Ordering::SeqCst);
target.change_stat_boost(Statistic::Attack, amount, user.equals(&target)); target.change_stat_boost(Statistic::Attack, amount, user.equals(&target))?;
target.change_stat_boost(Statistic::Defense, amount, user.equals(&target)); target.change_stat_boost(Statistic::Defense, amount, user.equals(&target))?;
target.change_stat_boost(Statistic::SpecialAttack, amount, user.equals(&target)); target.change_stat_boost(Statistic::SpecialAttack, amount, user.equals(&target))?;
target.change_stat_boost(Statistic::SpecialDefense, amount, user.equals(&target)); target.change_stat_boost(Statistic::SpecialDefense, amount, user.equals(&target))?;
target.change_stat_boost(Statistic::Speed, amount, user.equals(&target)); target.change_stat_boost(Statistic::Speed, amount, user.equals(&target))?;
Ok(())
} }
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {

View File

@ -36,20 +36,22 @@ macro_rules! change_stat_effect {
fn on_initialize( fn on_initialize(
&self, &self,
_library: DynamicLibrary, _library: DynamicLibrary,
parameters: Option<ImmutableList<Rc<EffectParameter>>>, parameters: Option<Vec<Rc<EffectParameter>>>,
) { ) -> PkmnResult<()> {
self.amount.store( self.amount.store(
parameters.unwrap().get(0).unwrap().as_int() as i8, parameters.unwrap().get(0).unwrap().as_int() as i8,
Ordering::SeqCst, Ordering::SeqCst,
); );
Ok(())
} }
fn on_secondary_effect(&self, mv: ExecutingMove, target: Pokemon, _hit: u8) { fn on_secondary_effect(&self, mv: ExecutingMove, target: Pokemon, _hit: u8) -> PkmnResult<()> {
target.change_stat_boost( target.change_stat_boost(
Statistic::$stat, Statistic::$stat,
self.amount.load(Ordering::SeqCst), self.amount.load(Ordering::SeqCst),
mv.user().equals(&target), mv.user().equals(&target),
); )?;
Ok(())
} }
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {

View File

@ -15,21 +15,19 @@ impl Script for CurePartyStatus {
&[ScriptCapabilities::OnSecondaryEffect] &[ScriptCapabilities::OnSecondaryEffect]
} }
fn on_secondary_effect(&self, mv: ExecutingMove, _target: Pokemon, _hit: u8) { fn on_secondary_effect(&self, mv: ExecutingMove, _target: Pokemon, _hit: u8) -> PkmnResult<()> {
let user = mv.user(); let user = mv.user();
user.clear_status(); user.clear_status();
let party = user.battle().unwrap().find_party_for_pokemon(&user); let party = user.battle()?.unwrap().find_party_for_pokemon(&user)?;
if let Some(party) = party { if let Some(party) = party {
let p = party.party(); let p = party.party();
for index in 0..p.length() { for mon in p.as_ref().into_iter().flatten() {
let mon = p.get_pokemon(index); if !mon.equals(&user) {
if let Some(mon) = mon { mon.clear_status();
if !mon.equals(&user) {
mon.clear_status();
}
} }
} }
} }
Ok(())
} }
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {

View File

@ -23,22 +23,24 @@ impl Script for Drain {
fn on_initialize( fn on_initialize(
&self, &self,
_library: DynamicLibrary, _library: DynamicLibrary,
parameters: Option<ImmutableList<Rc<EffectParameter>>>, parameters: Option<Vec<Rc<EffectParameter>>>,
) { ) -> PkmnResult<()> {
self.heal_modifier.store( self.heal_modifier.store(
parameters.unwrap().get(0).unwrap().as_float(), parameters.unwrap().get(0).unwrap().as_float(),
Ordering::SeqCst, Ordering::SeqCst,
); );
Ok(())
} }
fn on_secondary_effect(&self, mv: ExecutingMove, target: Pokemon, hit: u8) { fn on_secondary_effect(&self, mv: ExecutingMove, target: Pokemon, hit: u8) -> PkmnResult<()> {
let hit_data = mv.get_hit_data(&target, hit); let hit_data = mv.get_hit_data(&target, hit)?;
let damage = hit_data.damage(); let damage = hit_data.damage()?;
let mut modifier = self.heal_modifier.load(Ordering::SeqCst); let mut modifier = self.heal_modifier.load(Ordering::SeqCst);
if mv.user().has_held_item("big_root") { if mv.user().has_held_item("big_root")? {
modifier *= 1.3; modifier *= 1.3;
} }
mv.user().heal((damage as f32 * modifier) as u32, false); mv.user().heal((damage as f32 * modifier) as u32, false)?;
Ok(())
} }
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {

View File

@ -15,8 +15,14 @@ impl Script for Flinch {
&[ScriptCapabilities::OnSecondaryEffect] &[ScriptCapabilities::OnSecondaryEffect]
} }
fn on_secondary_effect(&self, _move: ExecutingMove, target: Pokemon, _hit: u8) { fn on_secondary_effect(
target.add_volatile(Box::new(FlinchEffect::new())); &self,
_move: ExecutingMove,
target: Pokemon,
_hit: u8,
) -> PkmnResult<()> {
target.add_volatile(Box::new(FlinchEffect::new()))?;
Ok(())
} }
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
@ -39,9 +45,10 @@ impl Script for FlinchEffect {
&[ScriptCapabilities::PreventMove] &[ScriptCapabilities::PreventMove]
} }
fn prevent_move(&self, mv: ExecutingMove, prevent: &mut bool) { fn prevent_move(&self, mv: ExecutingMove, prevent: &mut bool) -> PkmnResult<()> {
*prevent = true; *prevent = true;
mv.user().remove_volatile(self); mv.user().remove_volatile(self)?;
Ok(())
} }
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {

View File

@ -28,16 +28,17 @@ impl Script for HealEachEndOfTurn {
fn on_initialize( fn on_initialize(
&self, &self,
_library: DynamicLibrary, _library: DynamicLibrary,
parameters: Option<ImmutableList<Rc<EffectParameter>>>, parameters: Option<Vec<Rc<EffectParameter>>>,
) { ) -> PkmnResult<()> {
self.heal_percent.store( self.heal_percent.store(
parameters.unwrap().get(0).unwrap().as_float() / 100.0, parameters.unwrap().get(0).unwrap().as_float() / 100.0,
Ordering::SeqCst, Ordering::SeqCst,
); );
Ok(())
} }
fn on_secondary_effect(&self, _mv: ExecutingMove, target: Pokemon, _hit: u8) { fn on_secondary_effect(&self, _mv: ExecutingMove, target: Pokemon, _hit: u8) -> PkmnResult<()> {
let script = target.add_volatile_by_name("heal_each_end_of_turn_effect"); let script = target.add_volatile_by_name("heal_each_end_of_turn_effect")?;
let amount = self.heal_percent.load(Ordering::SeqCst); let amount = self.heal_percent.load(Ordering::SeqCst);
script script
.as_any() .as_any()
@ -45,6 +46,7 @@ impl Script for HealEachEndOfTurn {
.unwrap() .unwrap()
.heal_percent .heal_percent
.store(amount, Ordering::SeqCst); .store(amount, Ordering::SeqCst);
Ok(())
} }
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {

View File

@ -21,17 +21,23 @@ impl Script for MultiHitMove {
&[ScriptCapabilities::ChangeNumberOfHits] &[ScriptCapabilities::ChangeNumberOfHits]
} }
fn change_number_of_hits(&self, choice: TurnChoice, number_of_hits: &mut u8) { fn change_number_of_hits(&self, choice: TurnChoice, number_of_hits: &mut u8) -> PkmnResult<()> {
// 35% chance that it will hit 2 times, a 35% chance it will hit 3 times, a 15% chance it // 35% chance that it will hit 2 times, a 35% chance it will hit 3 times, a 15% chance it
// will hit 4 times, and a 15% chance it will hit 5 times. // will hit 4 times, and a 15% chance it will hit 5 times.
let rand_value = choice.user().battle().unwrap().random().get_between(0, 100); let rand_value = choice
.user()
.battle()?
.unwrap()
.random()
.get_between(0, 100)?;
*number_of_hits = match rand_value { *number_of_hits = match rand_value {
0..=34 => 2, 0..=34 => 2,
35..=69 => 3, 35..=69 => 3,
70..=84 => 4, 70..=84 => 4,
85..=100 => 5, 85..=100 => 5,
_ => *number_of_hits, _ => *number_of_hits,
} };
Ok(())
} }
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {

View File

@ -20,12 +20,23 @@ impl Script for Struggle {
] ]
} }
fn change_number_of_hits(&self, _choice: TurnChoice, number_of_hits: &mut u8) { fn change_number_of_hits(
*number_of_hits = 1 &self,
_choice: TurnChoice,
number_of_hits: &mut u8,
) -> PkmnResult<()> {
*number_of_hits = 1;
Ok(())
} }
fn is_invulnerable(&self, _move: ExecutingMove, _target: Pokemon, invulnerable: &mut bool) { fn is_invulnerable(
&self,
_move: ExecutingMove,
_target: Pokemon,
invulnerable: &mut bool,
) -> PkmnResult<()> {
*invulnerable = false; *invulnerable = false;
Ok(())
} }
fn change_effectiveness( fn change_effectiveness(
@ -34,16 +45,18 @@ impl Script for Struggle {
_target: Pokemon, _target: Pokemon,
_hit: u8, _hit: u8,
effectiveness: &mut f32, effectiveness: &mut f32,
) { ) -> PkmnResult<()> {
*effectiveness = 1.0; *effectiveness = 1.0;
Ok(())
} }
fn on_secondary_effect(&self, mv: ExecutingMove, _target: Pokemon, _hit: u8) { fn on_secondary_effect(&self, mv: ExecutingMove, _target: Pokemon, _hit: u8) -> PkmnResult<()> {
let mut damage = mv.user().max_health() / 4; let mut damage = mv.user().max_health()? / 4;
if damage == 0 { if damage == 0 {
damage = 1 damage = 1
} }
mv.user().damage(damage, DamageSource::Struggle); mv.user().damage(damage, DamageSource::Struggle)?;
Ok(())
} }
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {

View File

@ -21,15 +21,16 @@ impl Script for HealEachEndOfTurnEffect {
&[ScriptCapabilities::OnEndTurn] &[ScriptCapabilities::OnEndTurn]
} }
fn on_end_turn(&self) { fn on_end_turn(&self) -> PkmnResult<()> {
if let Some(ScriptOwner::Pokemon(pokemon)) = self.get_owner() { if let Some(ScriptOwner::Pokemon(pokemon)) = self.get_owner() {
let mut amount = let mut amount =
pokemon.max_health() as f32 * self.heal_percent.load(Ordering::Relaxed); pokemon.max_health()? as f32 * self.heal_percent.load(Ordering::Relaxed);
if pokemon.has_held_item("big_root") { if pokemon.has_held_item("big_root")? {
amount *= 1.3; amount *= 1.3;
} }
pokemon.heal(amount as u32, false); pokemon.heal(amount as u32, false)?;
} }
Ok(())
} }
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {

View File

@ -15,10 +15,11 @@ impl Script for Infatuated {
&[ScriptCapabilities::PreventMove] &[ScriptCapabilities::PreventMove]
} }
fn prevent_move(&self, mv: ExecutingMove, prevent: &mut bool) { fn prevent_move(&self, mv: ExecutingMove, prevent: &mut bool) -> PkmnResult<()> {
if mv.user().battle().unwrap().random().get_max(2) == 0 { if mv.user().battle()?.unwrap().random().get_max(2)? == 0 {
*prevent = true *prevent = true
} }
Ok(())
} }
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {

View File

@ -4,6 +4,7 @@ use crate::pokemon::*;
use alloc::boxed::Box; use alloc::boxed::Box;
use pkmn_lib_interface::app_interface::{get_hash, StringKey}; use pkmn_lib_interface::app_interface::{get_hash, StringKey};
use pkmn_lib_interface::handling::{Script, ScriptCategory}; use pkmn_lib_interface::handling::{Script, ScriptCategory};
use pkmn_lib_interface::println;
macro_rules! resolve_match { macro_rules! resolve_match {
( (
@ -24,10 +25,11 @@ macro_rules! resolve_match {
} }
pub fn get_script(category: ScriptCategory, name: &StringKey) -> Option<Box<dyn Script>> { pub fn get_script(category: ScriptCategory, name: &StringKey) -> Option<Box<dyn Script>> {
println!("Getting script {:?}", name);
match category { match category {
ScriptCategory::Move => { ScriptCategory::Move => {
resolve_match! { resolve_match! {
name.hash(), name.hash().unwrap(),
acrobatics::Acrobatics, acrobatics::Acrobatics,
acupressure::Acupressure, acupressure::Acupressure,
after_you::AfterYou, after_you::AfterYou,
@ -54,13 +56,13 @@ pub fn get_script(category: ScriptCategory, name: &StringKey) -> Option<Box<dyn
ScriptCategory::Status => {} ScriptCategory::Status => {}
ScriptCategory::Pokemon => { ScriptCategory::Pokemon => {
resolve_match! { resolve_match! {
name.hash(), name.hash().unwrap(),
infatuated::Infatuated, infatuated::Infatuated,
pokemon::heal_each_end_of_turn::HealEachEndOfTurnEffect, pokemon::heal_each_end_of_turn::HealEachEndOfTurnEffect,
} }
} }
ScriptCategory::Battle => { ScriptCategory::Battle => {
resolve_match! {name.hash(), crate::util_scripts::ForceEffectTriggerScript,} resolve_match! {name.hash().unwrap(), crate::util_scripts::ForceEffectTriggerScript,}
} }
ScriptCategory::Side => {} ScriptCategory::Side => {}
ScriptCategory::ItemBattleTrigger => {} ScriptCategory::ItemBattleTrigger => {}

View File

@ -27,9 +27,10 @@ impl Script for ForceEffectTriggerScript {
_target: Pokemon, _target: Pokemon,
_hit: u8, _hit: u8,
chance: &mut f32, chance: &mut f32,
) { ) -> PkmnResult<()> {
// Set to 50_000% chance. // Set to 50_000% chance.
*chance = 50_000.0; *chance = 50_000.0;
Ok(())
} }
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {

View File

@ -5,7 +5,7 @@ macro_rules! non_copyable {
$mv:ident, $mv:ident,
$($move_name:literal),+ $($move_name:literal),+
) => { ) => {
match $mv.name().hash() { match $mv.name().hash().unwrap() {
0 0
$( $(
| const { get_hash($move_name) } | const { get_hash($move_name) }

View File

@ -8,12 +8,11 @@ edition = "2021"
mock_data = ["mockall"] mock_data = ["mockall"]
[dependencies] [dependencies]
cstr_core = { version = "0.2.6", features = ["nightly"]} cstr_core = { version = "0.2.6", features = ["nightly"] }
enumflags2 = { version = "0.7.5", default-features = false } enumflags2 = { version = "0.7.5", default-features = false }
spin = { version = "0.9.4", default-features = false, features = ["rwlock"] } spin = { version = "0.9.4", default-features = false, features = ["rwlock"] }
paste = { version = "1.0.7" } paste = { version = "1.0.7" }
hashbrown = { version = "0.12.3" } hashbrown = { version = "0.13.2" }
dlmalloc = { version = "0.2.4", features = ["global"] } dlmalloc = { version = "0.2.4", features = ["global"] }
mockall = { version = "0.11.2", optional = true, features = ["nightly"] } mockall = { version = "0.11.2", optional = true, features = ["nightly"] }
num-traits = { version = "0.2", default-features = false }

View File

@ -1,28 +1,28 @@
use alloc::rc::Rc; use alloc::rc::Rc;
use crate::app_interface::list::ImmutableList;
use crate::app_interface::{ use crate::app_interface::{
BattleParty, BattleRandom, BattleSide, ChoiceQueue, DynamicLibrary, Pokemon, StringKey, BattleParty, BattleRandom, BattleSide, ChoiceQueue, DynamicLibrary, Pokemon, StringKey,
}; };
use alloc::vec::Vec;
#[cfg_attr(feature = "mock_data", mockall::automock)] #[cfg_attr(feature = "mock_data", mockall::automock)]
pub trait BattleTrait { pub trait BattleTrait {
fn library(&self) -> DynamicLibrary; fn library(&self) -> DynamicLibrary;
fn parties(&self) -> ImmutableList<BattleParty>; fn parties(&self) -> Vec<BattleParty>;
fn sides(&self) -> ImmutableList<BattleSide>; fn sides(&self) -> Vec<BattleSide>;
fn random(&self) -> BattleRandom; fn random(&self) -> BattleRandom;
fn choice_queue(&self) -> ChoiceQueue; fn choice_queue(&self) -> ChoiceQueue;
fn get_pokemon(&self, side: u8, index: u8) -> Option<Pokemon>; fn get_pokemon(&self, side: u8, index: u8) -> PkmnResult<Option<Pokemon>>;
fn find_party_for_pokemon(&self, pokemon: &Pokemon) -> Option<BattleParty>; fn find_party_for_pokemon(&self, pokemon: &Pokemon) -> PkmnResult<Option<BattleParty>>;
fn weather_name(&self) -> Option<StringKey>; fn weather_name(&self) -> PkmnResult<Option<StringKey>>;
fn has_weather(&self, name: &str) -> bool; fn has_weather(&self, name: &str) -> PkmnResult<bool>;
fn can_flee(&self) -> bool; fn can_flee(&self) -> PkmnResult<bool>;
fn number_of_sides(&self) -> u8; fn number_of_sides(&self) -> PkmnResult<u8>;
fn pokemon_per_side(&self) -> u8; fn pokemon_per_side(&self) -> PkmnResult<u8>;
fn has_ended(&self) -> bool; fn has_ended(&self) -> PkmnResult<bool>;
fn has_ended_conclusively(&self) -> bool; fn has_ended_conclusively(&self) -> PkmnResult<bool>;
fn winning_side(&self) -> u8; fn winning_side(&self) -> PkmnResult<u8>;
fn current_turn(&self) -> u32; fn current_turn(&self) -> PkmnResult<u32>;
} }
pub type Battle = Rc<dyn BattleTrait>; pub type Battle = Rc<dyn BattleTrait>;
@ -33,26 +33,26 @@ pub type MockBattle = MockBattleTrait;
mod implementation { mod implementation {
use super::*; use super::*;
use crate::app_interface::dynamic_data::dynamic_library::DynamicLibraryImpl; use crate::app_interface::dynamic_data::dynamic_library::DynamicLibraryImpl;
use crate::app_interface::list::{
BattlePartyImmutableList, BattleSideImmutableList, ImmutableListWasm,
};
use crate::app_interface::PokemonImpl; use crate::app_interface::PokemonImpl;
use crate::app_interface::{ use crate::app_interface::{
BattleParty, BattlePartyImpl, BattleRandom, BattleRandomImpl, BattleSide, BattleSideImpl, BattleParty, BattlePartyImpl, BattleRandom, BattleRandomImpl, BattleSide, BattleSideImpl,
ChoiceQueue, ChoiceQueueImpl, Pokemon, ChoiceQueue, ChoiceQueueImpl, Pokemon,
}; };
use crate::handling::cached_value::CachedValue; use crate::handling::cached_value::CachedValue;
use crate::handling::ffi_array::FFIArray;
use crate::handling::wasm_result::WasmResult;
use crate::handling::Cacheable; use crate::handling::Cacheable;
use crate::{ use crate::{
cached_value, cached_value_getters, wasm_value_getters_extern, wasm_value_getters_funcs, cached_value, cached_value_getters, wasm_value_getters_extern, wasm_value_getters_funcs,
ExternRef, ExternalReferenceType, StringKey, VecExternRef, ExternRef, ExternalReferenceType, PkmnResult, StringKey,
}; };
use alloc::vec::Vec;
struct BattleInner { struct BattleInner {
reference: ExternRef<BattleImpl>, reference: ExternRef<BattleImpl>,
library: CachedValue<DynamicLibrary>, library: CachedValue<DynamicLibrary>,
parties: CachedValue<ImmutableList<BattleParty>>, parties: CachedValue<Vec<BattleParty>>,
sides: CachedValue<ImmutableList<BattleSide>>, sides: CachedValue<Vec<BattleSide>>,
random: CachedValue<Rc<BattleRandomImpl>>, random: CachedValue<Rc<BattleRandomImpl>>,
choice_queue: CachedValue<Rc<ChoiceQueueImpl>>, choice_queue: CachedValue<Rc<ChoiceQueueImpl>>,
} }
@ -69,21 +69,39 @@ mod implementation {
inner: Rc::new(BattleInner { inner: Rc::new(BattleInner {
reference, reference,
library: cached_value!({ library: cached_value!({
Rc::new(battle_get_library(reference).get_value().unwrap()) Rc::new(battle_get_library(reference).unwrap().get_value().unwrap())
}), }),
parties: cached_value!({ parties: cached_value!({
let reference = battle_get_parties(reference); let parties: FFIArray<ExternRef<BattlePartyImpl>> =
Rc::new(BattlePartyImmutableList::from_ref(reference)) FFIArray::from_u64(battle_get_parties(reference).unwrap());
let parties =
Vec::from_raw_parts(parties.ptr(), parties.len(), parties.len());
let parties = parties
.into_iter()
.map::<BattleParty, _>(|r| Rc::new(BattlePartyImpl::new(r)))
.collect::<Vec<_>>();
parties
}), }),
sides: cached_value!({ sides: cached_value!({
let reference = battle_get_sides(reference); let sides: FFIArray<ExternRef<BattleSideImpl>> =
Rc::new(BattleSideImmutableList::from_ref(reference)) FFIArray::from_u64(battle_get_sides(reference).unwrap());
let sides = Vec::from_raw_parts(sides.ptr(), sides.len(), sides.len());
let sides = sides
.into_iter()
.map::<BattleSide, _>(|r| Rc::new(BattleSideImpl::new(r)))
.collect::<Vec<_>>();
sides
}), }),
random: cached_value!({ random: cached_value!({
Rc::new(battle_get_random(reference).get_value().unwrap()) Rc::new(battle_get_random(reference).unwrap().get_value().unwrap())
}), }),
choice_queue: cached_value!({ choice_queue: cached_value!({
Rc::new(battle_get_choice_queue(reference).get_value().unwrap()) Rc::new(
battle_get_choice_queue(reference)
.unwrap()
.get_value()
.unwrap(),
)
}), }),
}), }),
}) })
@ -94,46 +112,53 @@ mod implementation {
impl BattleTrait for BattleImpl { impl BattleTrait for BattleImpl {
cached_value_getters! { cached_value_getters! {
fn library(&self) -> DynamicLibrary; fn library(&self) -> DynamicLibrary;
fn parties(&self) -> ImmutableList<BattleParty>; fn parties(&self) -> Vec<BattleParty>;
fn sides(&self) -> ImmutableList<BattleSide>; fn sides(&self) -> Vec<BattleSide>;
fn random(&self) -> BattleRandom; fn random(&self) -> BattleRandom;
fn choice_queue(&self) -> ChoiceQueue; fn choice_queue(&self) -> ChoiceQueue;
} }
fn get_pokemon(&self, side: u8, index: u8) -> Option<Pokemon> { fn get_pokemon(&self, side: u8, index: u8) -> PkmnResult<Option<Pokemon>> {
unsafe { unsafe {
let v = battle_get_pokemon(self.inner.reference, side, index).get_value(); let v = battle_get_pokemon(self.inner.reference, side, index)
.as_res()?
.get_value();
if let Some(v) = v { if let Some(v) = v {
Some(Rc::new(v)) Ok(Some(Rc::new(v)))
} else { } else {
None Ok(None)
} }
} }
} }
fn find_party_for_pokemon(&self, pokemon: &Pokemon) -> Option<BattleParty> { fn find_party_for_pokemon(&self, pokemon: &Pokemon) -> PkmnResult<Option<BattleParty>> {
unsafe { unsafe {
let b = let b =
battle_find_party_for_pokemon(self.inner.reference, pokemon.reference().into()) battle_find_party_for_pokemon(self.inner.reference, pokemon.reference().into())
.as_res()?
.get_value(); .get_value();
if let Some(b) = b { Ok(if let Some(b) = b {
Some(Rc::new(b)) Some(Rc::new(b))
} else { } else {
None None
} })
} }
} }
fn weather_name(&self) -> Option<StringKey> { fn weather_name(&self) -> PkmnResult<Option<StringKey>> {
unsafe { battle_get_weather_name(self.inner.reference).get_value() } unsafe {
Ok(battle_get_weather_name(self.inner.reference)
.as_res()?
.get_value())
}
} }
fn has_weather(&self, name: &str) -> bool { fn has_weather(&self, name: &str) -> PkmnResult<bool> {
if let Some(weather) = self.weather_name() { if let Some(weather) = self.weather_name()? {
if weather.equals_str(name) { if weather.equals_str(name) {
return true; return Ok(true);
} }
} }
false Ok(false)
} }
wasm_value_getters_funcs! { wasm_value_getters_funcs! {
@ -170,24 +195,29 @@ mod implementation {
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
extern "wasm" { extern "wasm" {
fn battle_get_library(r: ExternRef<BattleImpl>) -> ExternRef<DynamicLibraryImpl>; fn battle_get_library(
fn battle_get_parties(r: ExternRef<BattleImpl>) -> VecExternRef<BattlePartyImpl>; r: ExternRef<BattleImpl>,
fn battle_get_sides(r: ExternRef<BattleImpl>) -> VecExternRef<BattleSideImpl>; ) -> WasmResult<ExternRef<DynamicLibraryImpl>>;
fn battle_get_random(r: ExternRef<BattleImpl>) -> ExternRef<BattleRandomImpl>; fn battle_get_parties(r: ExternRef<BattleImpl>) -> WasmResult<u64>;
fn battle_get_choice_queue(r: ExternRef<BattleImpl>) -> ExternRef<ChoiceQueueImpl>; fn battle_get_sides(r: ExternRef<BattleImpl>) -> WasmResult<u64>;
fn battle_get_random(r: ExternRef<BattleImpl>) -> WasmResult<ExternRef<BattleRandomImpl>>;
fn battle_get_choice_queue(
r: ExternRef<BattleImpl>,
) -> WasmResult<ExternRef<ChoiceQueueImpl>>;
fn battle_get_pokemon( fn battle_get_pokemon(
r: ExternRef<BattleImpl>, r: ExternRef<BattleImpl>,
side: u8, side: u8,
index: u8, index: u8,
) -> ExternRef<PokemonImpl>; ) -> WasmResult<ExternRef<PokemonImpl>>;
fn battle_find_party_for_pokemon( fn battle_find_party_for_pokemon(
r: ExternRef<BattleImpl>, r: ExternRef<BattleImpl>,
mon: ExternRef<PokemonImpl>, mon: ExternRef<PokemonImpl>,
) -> ExternRef<BattlePartyImpl>; ) -> WasmResult<ExternRef<BattlePartyImpl>>;
fn battle_get_weather_name(r: ExternRef<BattleImpl>) -> ExternRef<StringKey>; fn battle_get_weather_name(r: ExternRef<BattleImpl>) -> WasmResult<ExternRef<StringKey>>;
} }
} }
use crate::PkmnResult;
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
pub use implementation::*; pub use implementation::*;

View File

@ -15,6 +15,7 @@ mod implementation {
use crate::app_interface::{BattlePartyTrait, Party, PartyImpl}; use crate::app_interface::{BattlePartyTrait, Party, PartyImpl};
use crate::handling::cached_value::CachedValue; use crate::handling::cached_value::CachedValue;
use crate::handling::extern_ref::{ExternRef, ExternalReferenceType}; use crate::handling::extern_ref::{ExternRef, ExternalReferenceType};
use crate::handling::wasm_result::WasmResult;
use crate::handling::Cacheable; use crate::handling::Cacheable;
use crate::{cached_value, cached_value_getters}; use crate::{cached_value, cached_value_getters};
use alloc::rc::Rc; use alloc::rc::Rc;
@ -35,7 +36,12 @@ mod implementation {
inner: Rc::new(BattlePartyInner { inner: Rc::new(BattlePartyInner {
reference, reference,
party: cached_value!({ party: cached_value!({
Rc::new(battle_party_get_party(reference).get_value().unwrap()) Rc::new(
battle_party_get_party(reference)
.unwrap()
.get_value()
.unwrap(),
)
}), }),
}), }),
}) })
@ -59,7 +65,9 @@ mod implementation {
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
extern "wasm" { extern "wasm" {
fn battle_party_get_party(r: ExternRef<BattlePartyImpl>) -> ExternRef<PartyImpl>; fn battle_party_get_party(
r: ExternRef<BattlePartyImpl>,
) -> WasmResult<ExternRef<PartyImpl>>;
} }
} }

View File

@ -1,10 +1,11 @@
use crate::PkmnResult;
use alloc::rc::Rc; use alloc::rc::Rc;
#[cfg_attr(feature = "mock_data", mockall::automock)] #[cfg_attr(feature = "mock_data", mockall::automock)]
pub trait BattleRandomTrait { pub trait BattleRandomTrait {
fn get(&self) -> i32; fn get(&self) -> PkmnResult<i32>;
fn get_max(&self, max: i32) -> i32; fn get_max(&self, max: i32) -> PkmnResult<i32>;
fn get_between(&self, min: i32, max: i32) -> i32; fn get_between(&self, min: i32, max: i32) -> PkmnResult<i32>;
} }
pub type BattleRandom = Rc<dyn BattleRandomTrait>; pub type BattleRandom = Rc<dyn BattleRandomTrait>;
@ -17,6 +18,7 @@ pub use implementation::*;
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
mod implementation { mod implementation {
use super::*; use super::*;
use crate::handling::wasm_result::WasmResult;
use crate::{ExternRef, ExternalReferenceType}; use crate::{ExternRef, ExternalReferenceType};
#[derive(Clone)] #[derive(Clone)]
@ -26,16 +28,16 @@ mod implementation {
impl BattleRandomTrait for BattleRandomImpl { impl BattleRandomTrait for BattleRandomImpl {
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
fn get(&self) -> i32 { fn get(&self) -> PkmnResult<i32> {
unsafe { battle_random_get(self.reference) } unsafe { battle_random_get(self.reference).as_res() }
} }
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
fn get_max(&self, max: i32) -> i32 { fn get_max(&self, max: i32) -> PkmnResult<i32> {
unsafe { battle_random_get_max(self.reference, max) } unsafe { battle_random_get_max(self.reference, max).as_res() }
} }
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
fn get_between(&self, min: i32, max: i32) -> i32 { fn get_between(&self, min: i32, max: i32) -> PkmnResult<i32> {
unsafe { battle_random_get_between(self.reference, min, max) } unsafe { battle_random_get_between(self.reference, min, max).as_res() }
} }
// TODO: effect_chance() // TODO: effect_chance()
} }
@ -48,9 +50,13 @@ mod implementation {
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
extern "wasm" { extern "wasm" {
fn battle_random_get(r: ExternRef<BattleRandomImpl>) -> i32; fn battle_random_get(r: ExternRef<BattleRandomImpl>) -> WasmResult<i32>;
fn battle_random_get_max(r: ExternRef<BattleRandomImpl>, max: i32) -> i32; fn battle_random_get_max(r: ExternRef<BattleRandomImpl>, max: i32) -> WasmResult<i32>;
fn battle_random_get_between(r: ExternRef<BattleRandomImpl>, min: i32, max: i32) -> i32; fn battle_random_get_between(
r: ExternRef<BattleRandomImpl>,
min: i32,
max: i32,
) -> WasmResult<i32>;
} }
} }

View File

@ -6,8 +6,8 @@ pub trait BattleSideTrait: WithVolatile {
fn pokemon_per_side(&self) -> u8; fn pokemon_per_side(&self) -> u8;
fn battle(&self) -> Battle; fn battle(&self) -> Battle;
fn get_pokemon(&self, index: usize) -> Option<Pokemon>; fn get_pokemon(&self, index: usize) -> Option<Pokemon>;
fn has_fled_battle(&self) -> bool; fn has_fled_battle(&self) -> PkmnResult<bool>;
fn is_defeated(&self) -> bool; fn is_defeated(&self) -> PkmnResult<bool>;
} }
pub type BattleSide = Rc<dyn BattleSideTrait>; pub type BattleSide = Rc<dyn BattleSideTrait>;
@ -18,10 +18,11 @@ mod implementation {
use crate::app_interface::{BattleImpl, PokemonImpl}; use crate::app_interface::{BattleImpl, PokemonImpl};
use crate::handling::cached_value::CachedValue; use crate::handling::cached_value::CachedValue;
use crate::handling::extern_ref::{ExternRef, ExternalReferenceType}; use crate::handling::extern_ref::{ExternRef, ExternalReferenceType};
use crate::handling::wasm_result::{WasmResult, WasmVoidResult};
use crate::handling::{Cacheable, Script}; use crate::handling::{Cacheable, Script};
use crate::{ use crate::{
cached_value, cached_value_getters, wasm_value_getters_extern, wasm_value_getters_funcs, cached_value, cached_value_getters, wasm_value_getters_extern, wasm_value_getters_funcs,
ScriptPtr, PkmnResult, ScriptPtr,
}; };
use alloc::boxed::Box; use alloc::boxed::Box;
use cstr_core::{c_char, CString}; use cstr_core::{c_char, CString};
@ -43,10 +44,17 @@ mod implementation {
Self::from_ref(reference, &|reference| Self { Self::from_ref(reference, &|reference| Self {
inner: Rc::new(BattleSideInner { inner: Rc::new(BattleSideInner {
reference, reference,
side_index: cached_value!({ battleside_get_side_index(reference) }), side_index: cached_value!({ battleside_get_side_index(reference).unwrap() }),
pokemon_per_side: cached_value!({ battleside_get_pokemon_per_side(reference) }), pokemon_per_side: cached_value!({
battleside_get_pokemon_per_side(reference).unwrap()
}),
battle: cached_value!({ battle: cached_value!({
Rc::new(battleside_get_battle(reference).get_value().unwrap()) Rc::new(
battleside_get_battle(reference)
.unwrap()
.get_value()
.unwrap(),
)
}), }),
}), }),
}) })
@ -62,7 +70,9 @@ mod implementation {
fn get_pokemon(&self, index: usize) -> Option<Pokemon> { fn get_pokemon(&self, index: usize) -> Option<Pokemon> {
unsafe { unsafe {
let p = battleside_get_pokemon(self.inner.reference, index).get_value(); let p = battleside_get_pokemon(self.inner.reference, index)
.unwrap()
.get_value();
if let Some(p) = p { if let Some(p) = p {
Some(Rc::new(p)) Some(Rc::new(p))
} else { } else {
@ -79,39 +89,51 @@ mod implementation {
} }
impl WithVolatile for BattleSideImpl { impl WithVolatile for BattleSideImpl {
fn has_volatile(&self, script_name: &str) -> bool { fn has_volatile(&self, script_name: &str) -> PkmnResult<bool> {
unsafe { unsafe {
let script_name = CString::new(script_name).unwrap(); let script_name = CString::new(script_name).unwrap();
battleside_has_volatile(self.inner.reference, script_name.as_ptr()) battleside_has_volatile(self.inner.reference, script_name.as_ptr()).as_res()
} }
} }
fn add_volatile(&self, script: Box<dyn Script>) -> &dyn Script { fn add_volatile(&self, script: Box<dyn Script>) -> PkmnResult<&dyn Script> {
unsafe { unsafe {
battleside_add_volatile(self.inner.reference, ScriptPtr::new(script)) Ok(
.val() battleside_add_volatile(self.inner.reference, ScriptPtr::new(script))
.unwrap() .as_res()?
.val()
.unwrap(),
)
} }
} }
fn add_volatile_by_name(&self, script_name: &str) -> &dyn Script { fn add_volatile_by_name(&self, script_name: &str) -> PkmnResult<&dyn Script> {
unsafe { unsafe {
let ptr = CString::new(script_name).unwrap(); let ptr = CString::new(script_name).unwrap();
battleside_add_volatile_by_name(self.inner.reference, ptr.as_ptr()) Ok(
.val() battleside_add_volatile_by_name(self.inner.reference, ptr.as_ptr())
.unwrap() .as_res()?
.val()
.unwrap(),
)
} }
} }
fn remove_volatile(&self, script: &dyn Script) { fn remove_volatile(&self, script: &dyn Script) -> PkmnResult<()> {
unsafe { unsafe {
let name = CString::new(script.get_name()).unwrap(); let name = CString::new(script.get_name()).unwrap();
battleside_remove_volatile(self.inner.reference, name.as_ptr()); battleside_remove_volatile(self.inner.reference, name.as_ptr()).as_res()
} }
} }
fn get_volatile_script(&self, script_name: &str) -> Option<&dyn Script> { fn get_volatile_script(&self, script_name: &str) -> PkmnResult<Option<&dyn Script>> {
let script_name = CString::new(script_name).unwrap(); let script_name = CString::new(script_name).unwrap();
unsafe { battleside_get_volatile(self.inner.reference, script_name.as_ptr()).val() } unsafe {
Ok(
battleside_get_volatile(self.inner.reference, script_name.as_ptr())
.as_res()?
.val(),
)
}
} }
} }
@ -130,24 +152,38 @@ mod implementation {
} }
extern "wasm" { extern "wasm" {
fn battleside_get_side_index(r: ExternRef<BattleSideImpl>) -> u8; fn battleside_get_side_index(r: ExternRef<BattleSideImpl>) -> WasmResult<u8>;
fn battleside_get_pokemon_per_side(r: ExternRef<BattleSideImpl>) -> u8; fn battleside_get_pokemon_per_side(r: ExternRef<BattleSideImpl>) -> WasmResult<u8>;
fn battleside_get_battle(r: ExternRef<BattleSideImpl>) -> ExternRef<BattleImpl>; fn battleside_get_battle(r: ExternRef<BattleSideImpl>)
-> WasmResult<ExternRef<BattleImpl>>;
fn battleside_get_pokemon( fn battleside_get_pokemon(
r: ExternRef<BattleSideImpl>, r: ExternRef<BattleSideImpl>,
index: usize, index: usize,
) -> ExternRef<PokemonImpl>; ) -> WasmResult<ExternRef<PokemonImpl>>;
fn battleside_add_volatile_by_name( fn battleside_add_volatile_by_name(
r: ExternRef<BattleSideImpl>, r: ExternRef<BattleSideImpl>,
name: *const c_char, name: *const c_char,
) -> ScriptPtr; ) -> WasmResult<ScriptPtr>;
fn battleside_add_volatile(r: ExternRef<BattleSideImpl>, script: ScriptPtr) -> ScriptPtr; fn battleside_add_volatile(
fn battleside_has_volatile(r: ExternRef<BattleSideImpl>, name: *const c_char) -> bool; r: ExternRef<BattleSideImpl>,
fn battleside_remove_volatile(r: ExternRef<BattleSideImpl>, name: *const c_char); script: ScriptPtr,
fn battleside_get_volatile(r: ExternRef<BattleSideImpl>, name: *const c_char) -> ScriptPtr; ) -> WasmResult<ScriptPtr>;
fn battleside_has_volatile(
r: ExternRef<BattleSideImpl>,
name: *const c_char,
) -> WasmResult<bool>;
fn battleside_remove_volatile(
r: ExternRef<BattleSideImpl>,
name: *const c_char,
) -> WasmVoidResult;
fn battleside_get_volatile(
r: ExternRef<BattleSideImpl>,
name: *const c_char,
) -> WasmResult<ScriptPtr>;
} }
} }
use crate::PkmnResult;
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
pub use implementation::*; pub use implementation::*;

View File

@ -3,7 +3,7 @@ use alloc::rc::Rc;
#[cfg_attr(feature = "mock_data", mockall::automock)] #[cfg_attr(feature = "mock_data", mockall::automock)]
pub trait ChoiceQueueTrait { pub trait ChoiceQueueTrait {
fn move_pokemon_choice_next(&self, pokemon: &Pokemon) -> bool; fn move_pokemon_choice_next(&self, pokemon: &Pokemon) -> PkmnResult<bool>;
} }
pub type ChoiceQueue = Rc<dyn ChoiceQueueTrait>; pub type ChoiceQueue = Rc<dyn ChoiceQueueTrait>;
@ -14,7 +14,8 @@ pub type MockChoiceQueue = MockChoiceQueueTrait;
mod implementation { mod implementation {
use super::*; use super::*;
use crate::app_interface::PokemonImpl; use crate::app_interface::PokemonImpl;
use crate::{ExternRef, ExternalReferenceType}; use crate::handling::wasm_result::WasmResult;
use crate::{ExternRef, ExternalReferenceType, PkmnResult};
#[derive(Clone)] #[derive(Clone)]
pub struct ChoiceQueueImpl { pub struct ChoiceQueueImpl {
@ -28,9 +29,10 @@ mod implementation {
} }
impl ChoiceQueueTrait for ChoiceQueueImpl { impl ChoiceQueueTrait for ChoiceQueueImpl {
fn move_pokemon_choice_next(&self, pokemon: &Pokemon) -> bool { fn move_pokemon_choice_next(&self, pokemon: &Pokemon) -> PkmnResult<bool> {
unsafe { unsafe {
choice_queue_move_pokemon_choice_next(self.reference, pokemon.reference().into()) choice_queue_move_pokemon_choice_next(self.reference, pokemon.reference().into())
.as_res()
} }
} }
} }
@ -45,9 +47,10 @@ mod implementation {
fn choice_queue_move_pokemon_choice_next( fn choice_queue_move_pokemon_choice_next(
r: ExternRef<ChoiceQueueImpl>, r: ExternRef<ChoiceQueueImpl>,
pokemon: ExternRef<PokemonImpl>, pokemon: ExternRef<PokemonImpl>,
) -> bool; ) -> WasmResult<bool>;
} }
} }
use crate::PkmnResult;
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
pub use implementation::*; pub use implementation::*;

View File

@ -15,6 +15,7 @@ mod implementation {
use crate::cached_value; use crate::cached_value;
use crate::handling::cached_value::CachedValue; use crate::handling::cached_value::CachedValue;
use crate::handling::extern_ref::{ExternRef, ExternalReferenceType}; use crate::handling::extern_ref::{ExternRef, ExternalReferenceType};
use crate::handling::wasm_result::WasmResult;
use crate::handling::Cacheable; use crate::handling::Cacheable;
use alloc::rc::Rc; use alloc::rc::Rc;
@ -36,7 +37,12 @@ mod implementation {
inner: Rc::new(DynamicLibraryInner { inner: Rc::new(DynamicLibraryInner {
ptr, ptr,
static_data: cached_value!({ static_data: cached_value!({
Rc::new(dynamic_library_get_static_data(ptr).get_value().unwrap()) Rc::new(
dynamic_library_get_static_data(ptr)
.unwrap()
.get_value()
.unwrap(),
)
}), }),
}), }),
}) })
@ -58,7 +64,7 @@ mod implementation {
extern "wasm" { extern "wasm" {
fn dynamic_library_get_static_data( fn dynamic_library_get_static_data(
ptr: ExternRef<DynamicLibraryImpl>, ptr: ExternRef<DynamicLibraryImpl>,
) -> ExternRef<StaticDataImpl>; ) -> WasmResult<ExternRef<StaticDataImpl>>;
} }
} }

View File

@ -1,5 +1,6 @@
use crate::app_interface::{LearnedMove, MoveData, Pokemon}; use crate::app_interface::{LearnedMove, MoveData, Pokemon};
use crate::handling::Script; use crate::handling::Script;
use alloc::boxed::Box;
use alloc::rc::Rc; use alloc::rc::Rc;
#[cfg_attr(feature = "mock_data", mockall::automock)] #[cfg_attr(feature = "mock_data", mockall::automock)]
@ -8,25 +9,25 @@ pub trait ExecutingMoveTrait {
fn user(&self) -> Pokemon; fn user(&self) -> Pokemon;
fn chosen_move(&self) -> LearnedMove; fn chosen_move(&self) -> LearnedMove;
fn use_move(&self) -> MoveData; fn use_move(&self) -> MoveData;
fn move_script<'a>(&'a self) -> Option<&'a dyn Script>; fn move_script<'a>(&'a self) -> PkmnResult<Option<&'a Box<dyn Script>>>;
fn number_of_targets(&self) -> usize; fn number_of_targets(&self) -> PkmnResult<usize>;
fn is_pokemon_target(&self, pokemon: &Pokemon) -> bool; fn is_pokemon_target(&self, pokemon: &Pokemon) -> PkmnResult<bool>;
fn get_hit_data(&self, pokemon: &Pokemon, hit: u8) -> HitData; fn get_hit_data(&self, pokemon: &Pokemon, hit: u8) -> PkmnResult<HitData>;
} }
#[cfg_attr(feature = "mock_data", mockall::automock)] #[cfg_attr(feature = "mock_data", mockall::automock)]
pub trait HitDataTrait { pub trait HitDataTrait {
fn is_critical(&self) -> bool; fn is_critical(&self) -> PkmnResult<bool>;
fn base_power(&self) -> u8; fn base_power(&self) -> PkmnResult<u8>;
fn effectiveness(&self) -> f32; fn effectiveness(&self) -> PkmnResult<f32>;
fn damage(&self) -> u32; fn damage(&self) -> PkmnResult<u32>;
fn move_type(&self) -> u8; fn move_type(&self) -> PkmnResult<u8>;
fn has_failed(&self) -> bool; fn has_failed(&self) -> PkmnResult<bool>;
fn set_critical(&self, critical: bool); fn set_critical(&self, critical: bool) -> PkmnResult<()>;
fn set_effectiveness(&self, effectiveness: f32); fn set_effectiveness(&self, effectiveness: f32) -> PkmnResult<()>;
fn set_damage(&self, damage: u32); fn set_damage(&self, damage: u32) -> PkmnResult<()>;
fn set_move_type(&self, move_type: u8); fn set_move_type(&self, move_type: u8) -> PkmnResult<()>;
fn fail(&self); fn fail(&self) -> PkmnResult<()>;
} }
pub type ExecutingMove = Rc<dyn ExecutingMoveTrait>; pub type ExecutingMove = Rc<dyn ExecutingMoveTrait>;
@ -37,6 +38,7 @@ pub type HitData = Rc<dyn HitDataTrait>;
#[cfg(feature = "mock_data")] #[cfg(feature = "mock_data")]
pub type MockHitData = MockHitDataTrait; pub type MockHitData = MockHitDataTrait;
use crate::PkmnResult;
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
pub use implementation::*; pub use implementation::*;
@ -44,10 +46,12 @@ pub use implementation::*;
mod implementation { mod implementation {
use super::*; use super::*;
use crate::app_interface::{LearnedMoveImpl, MoveDataImpl, PokemonImpl}; use crate::app_interface::{LearnedMoveImpl, MoveDataImpl, PokemonImpl};
use crate::cached_value;
use crate::handling::cached_value::CachedValue; use crate::handling::cached_value::CachedValue;
use crate::handling::extern_ref::{ExternRef, ExternalReferenceType}; use crate::handling::extern_ref::{ExternRef, ExternalReferenceType};
use crate::handling::temporary::Temporary; use crate::handling::temporary::Temporary;
use crate::handling::wasm_result::WasmResult;
use crate::{cached_value, PkmnResult};
use alloc::boxed::Box;
#[derive(Clone)] #[derive(Clone)]
pub struct ExecutingMoveImpl { pub struct ExecutingMoveImpl {
@ -71,20 +75,31 @@ mod implementation {
ExecutingMoveInner { ExecutingMoveInner {
reference, reference,
number_of_hits: cached_value!({ number_of_hits: cached_value!({
executing_move_get_number_of_hits(reference) executing_move_get_number_of_hits(reference).unwrap()
}), }),
user: cached_value!({ user: cached_value!({
Rc::new(executing_move_get_user(reference).get_value().unwrap()) Rc::new(
executing_move_get_user(reference)
.unwrap()
.get_value()
.unwrap(),
)
}), }),
chosen_move: cached_value!({ chosen_move: cached_value!({
Rc::new( Rc::new(
executing_move_get_chosen_move(reference) executing_move_get_chosen_move(reference)
.unwrap()
.get_value() .get_value()
.unwrap(), .unwrap(),
) )
}), }),
use_move: cached_value!({ use_move: cached_value!({
Rc::new(executing_move_get_use_move(reference).get_value().unwrap()) Rc::new(
executing_move_get_use_move(reference)
.unwrap()
.get_value()
.unwrap(),
)
}), }),
}, },
), ),
@ -106,31 +121,39 @@ mod implementation {
fn use_move(&self) -> MoveData { fn use_move(&self) -> MoveData {
self.inner.value().use_move.value() self.inner.value().use_move.value()
} }
fn move_script(&self) -> Option<&dyn Script> { fn move_script(&self) -> PkmnResult<Option<&Box<dyn Script>>> {
unsafe { executing_move_get_script(self.inner.value().reference).as_ref() } unsafe {
Ok(
(executing_move_get_script(self.inner.value().reference).as_res()?
as *const Box<dyn Script>)
.as_ref(),
)
}
} }
fn number_of_targets(&self) -> usize { fn number_of_targets(&self) -> PkmnResult<usize> {
unsafe { executing_move_get_number_of_targets(self.inner.value().reference) } unsafe { executing_move_get_number_of_targets(self.inner.value().reference).as_res() }
} }
fn is_pokemon_target(&self, pokemon: &Pokemon) -> bool { fn is_pokemon_target(&self, pokemon: &Pokemon) -> PkmnResult<bool> {
unsafe { unsafe {
executing_move_is_pokemon_target( executing_move_is_pokemon_target(
self.inner.value().reference, self.inner.value().reference,
pokemon.reference().into(), pokemon.reference().into(),
) )
.as_res()
} }
} }
fn get_hit_data(&self, pokemon: &Pokemon, hit: u8) -> HitData { fn get_hit_data(&self, pokemon: &Pokemon, hit: u8) -> PkmnResult<HitData> {
unsafe { unsafe {
Rc::new( Ok(Rc::new(
executing_move_get_hit_data( executing_move_get_hit_data(
self.inner.value().reference, self.inner.value().reference,
pokemon.reference().into(), pokemon.reference().into(),
hit, hit,
) )
.as_res()?
.get_value() .get_value()
.unwrap(), .unwrap(),
) ))
} }
} }
} }
@ -142,39 +165,39 @@ mod implementation {
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
impl HitDataTrait for HitDataImpl { impl HitDataTrait for HitDataImpl {
fn is_critical(&self) -> bool { fn is_critical(&self) -> PkmnResult<bool> {
unsafe { hit_data_is_critical(self.reference) } unsafe { hit_data_is_critical(self.reference).as_res() }
} }
fn base_power(&self) -> u8 { fn base_power(&self) -> PkmnResult<u8> {
unsafe { hit_data_get_base_power(self.reference) } unsafe { hit_data_get_base_power(self.reference).as_res() }
} }
fn effectiveness(&self) -> f32 { fn effectiveness(&self) -> PkmnResult<f32> {
unsafe { hit_data_get_effectiveness(self.reference) } unsafe { hit_data_get_effectiveness(self.reference).as_res() }
} }
fn damage(&self) -> u32 { fn damage(&self) -> PkmnResult<u32> {
unsafe { hit_data_get_damage(self.reference) } unsafe { hit_data_get_damage(self.reference).as_res() }
} }
fn move_type(&self) -> u8 { fn move_type(&self) -> PkmnResult<u8> {
unsafe { hit_data_get_move_type(self.reference) } unsafe { hit_data_get_move_type(self.reference).as_res() }
} }
fn has_failed(&self) -> bool { fn has_failed(&self) -> PkmnResult<bool> {
unsafe { hit_data_is_critical(self.reference) } unsafe { hit_data_is_critical(self.reference).as_res() }
} }
fn set_critical(&self, critical: bool) { fn set_critical(&self, critical: bool) -> PkmnResult<()> {
unsafe { hit_data_set_critical(self.reference, critical) } unsafe { hit_data_set_critical(self.reference, critical).as_res() }
} }
fn set_effectiveness(&self, effectiveness: f32) { fn set_effectiveness(&self, effectiveness: f32) -> PkmnResult<()> {
unsafe { hit_data_set_effectiveness(self.reference, effectiveness) } unsafe { hit_data_set_effectiveness(self.reference, effectiveness).as_res() }
} }
fn set_damage(&self, damage: u32) { fn set_damage(&self, damage: u32) -> PkmnResult<()> {
unsafe { hit_data_set_damage(self.reference, damage) } unsafe { hit_data_set_damage(self.reference, damage).as_res() }
} }
fn set_move_type(&self, move_type: u8) { fn set_move_type(&self, move_type: u8) -> PkmnResult<()> {
unsafe { hit_data_set_move_type(self.reference, move_type) } unsafe { hit_data_set_move_type(self.reference, move_type).as_res() }
} }
fn fail(&self) { fn fail(&self) -> PkmnResult<()> {
unsafe { hit_data_fail(self.reference) } unsafe { hit_data_fail(self.reference).as_res() }
} }
} }
@ -194,38 +217,47 @@ mod implementation {
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
extern "wasm" { extern "wasm" {
fn executing_move_get_number_of_targets(r: ExternRef<ExecutingMoveImpl>) -> usize; fn executing_move_get_number_of_targets(
fn executing_move_get_number_of_hits(r: ExternRef<ExecutingMoveImpl>) -> u8; r: ExternRef<ExecutingMoveImpl>,
fn executing_move_get_user(r: ExternRef<ExecutingMoveImpl>) -> ExternRef<PokemonImpl>; ) -> WasmResult<usize>;
fn executing_move_get_number_of_hits(r: ExternRef<ExecutingMoveImpl>) -> WasmResult<u8>;
fn executing_move_get_user(
r: ExternRef<ExecutingMoveImpl>,
) -> WasmResult<ExternRef<PokemonImpl>>;
fn executing_move_get_chosen_move( fn executing_move_get_chosen_move(
r: ExternRef<ExecutingMoveImpl>, r: ExternRef<ExecutingMoveImpl>,
) -> ExternRef<LearnedMoveImpl>; ) -> WasmResult<ExternRef<LearnedMoveImpl>>;
fn executing_move_get_use_move(r: ExternRef<ExecutingMoveImpl>) -> ExternRef<MoveDataImpl>; fn executing_move_get_use_move(
r: ExternRef<ExecutingMoveImpl>,
) -> WasmResult<ExternRef<MoveDataImpl>>;
#[allow(improper_ctypes)] #[allow(improper_ctypes)]
fn executing_move_get_script(r: ExternRef<ExecutingMoveImpl>) -> *const dyn Script; fn executing_move_get_script(r: ExternRef<ExecutingMoveImpl>) -> WasmResult<u32>;
fn executing_move_is_pokemon_target( fn executing_move_is_pokemon_target(
r: ExternRef<ExecutingMoveImpl>, r: ExternRef<ExecutingMoveImpl>,
pokemon: ExternRef<PokemonImpl>, pokemon: ExternRef<PokemonImpl>,
) -> bool; ) -> WasmResult<bool>;
fn executing_move_get_hit_data( fn executing_move_get_hit_data(
r: ExternRef<ExecutingMoveImpl>, r: ExternRef<ExecutingMoveImpl>,
target: ExternRef<PokemonImpl>, target: ExternRef<PokemonImpl>,
hit: u8, hit: u8,
) -> ExternRef<HitDataImpl>; ) -> WasmResult<ExternRef<HitDataImpl>>;
fn hit_data_is_critical(r: ExternRef<HitDataImpl>) -> bool; fn hit_data_is_critical(r: ExternRef<HitDataImpl>) -> WasmResult<bool>;
fn hit_data_get_base_power(r: ExternRef<HitDataImpl>) -> u8; fn hit_data_get_base_power(r: ExternRef<HitDataImpl>) -> WasmResult<u8>;
fn hit_data_get_effectiveness(r: ExternRef<HitDataImpl>) -> f32; fn hit_data_get_effectiveness(r: ExternRef<HitDataImpl>) -> WasmResult<f32>;
fn hit_data_get_damage(r: ExternRef<HitDataImpl>) -> u32; fn hit_data_get_damage(r: ExternRef<HitDataImpl>) -> WasmResult<u32>;
fn hit_data_get_move_type(r: ExternRef<HitDataImpl>) -> u8; fn hit_data_get_move_type(r: ExternRef<HitDataImpl>) -> WasmResult<u8>;
fn hit_data_has_failed(r: ExternRef<HitDataImpl>) -> bool; fn hit_data_has_failed(r: ExternRef<HitDataImpl>) -> WasmResult<bool>;
fn hit_data_set_critical(r: ExternRef<HitDataImpl>, critical: bool); fn hit_data_set_critical(r: ExternRef<HitDataImpl>, critical: bool) -> WasmResult<()>;
fn hit_data_set_base_power(r: ExternRef<HitDataImpl>, power: u8); fn hit_data_set_base_power(r: ExternRef<HitDataImpl>, power: u8) -> WasmResult<()>;
fn hit_data_set_effectiveness(r: ExternRef<HitDataImpl>, effectiveness: f32); fn hit_data_set_effectiveness(
fn hit_data_set_damage(r: ExternRef<HitDataImpl>, damage: u32); r: ExternRef<HitDataImpl>,
fn hit_data_set_move_type(r: ExternRef<HitDataImpl>, move_type: u8); effectiveness: f32,
fn hit_data_fail(r: ExternRef<HitDataImpl>); ) -> WasmResult<()>;
fn hit_data_set_damage(r: ExternRef<HitDataImpl>, damage: u32) -> WasmResult<()>;
fn hit_data_set_move_type(r: ExternRef<HitDataImpl>, move_type: u8) -> WasmResult<()>;
fn hit_data_fail(r: ExternRef<HitDataImpl>) -> WasmResult<()>;
} }
} }

View File

@ -29,6 +29,7 @@ mod implementation {
use crate::app_interface::MoveDataImpl; use crate::app_interface::MoveDataImpl;
use crate::handling::cached_value::CachedValue; use crate::handling::cached_value::CachedValue;
use crate::handling::extern_ref::{ExternRef, ExternalReferenceType}; use crate::handling::extern_ref::{ExternRef, ExternalReferenceType};
use crate::handling::wasm_result::WasmResult;
use crate::handling::Cacheable; use crate::handling::Cacheable;
use crate::{cached_value, cached_value_getters, wasm_value_getters}; use crate::{cached_value, cached_value_getters, wasm_value_getters};
use alloc::rc::Rc; use alloc::rc::Rc;
@ -58,9 +59,16 @@ mod implementation {
inner: Rc::new(LearnedMoveInner { inner: Rc::new(LearnedMoveInner {
reference, reference,
move_data: cached_value!({ move_data: cached_value!({
Rc::new(learned_move_get_move_data(reference).get_value().unwrap()) Rc::new(
learned_move_get_move_data(reference)
.unwrap()
.get_value()
.unwrap(),
)
}),
learn_method: cached_value!({
learned_move_get_learn_method(reference).unwrap()
}), }),
learn_method: cached_value!({ learned_move_get_learn_method(reference) }),
}), }),
}) })
} }
@ -92,10 +100,14 @@ mod implementation {
} }
extern "wasm" { extern "wasm" {
fn learned_move_get_move_data(r: ExternRef<LearnedMoveImpl>) -> ExternRef<MoveDataImpl>; fn learned_move_get_move_data(
fn learned_move_get_learn_method(r: ExternRef<LearnedMoveImpl>) -> MoveLearnMethod; r: ExternRef<LearnedMoveImpl>,
fn learned_move_restore_uses(r: ExternRef<LearnedMoveImpl>, uses: u8); ) -> WasmResult<ExternRef<MoveDataImpl>>;
fn learned_move_restore_all_uses(r: ExternRef<LearnedMoveImpl>); fn learned_move_get_learn_method(
r: ExternRef<LearnedMoveImpl>,
) -> WasmResult<MoveLearnMethod>;
fn learned_move_restore_uses(r: ExternRef<LearnedMoveImpl>, uses: u8) -> WasmResult<()>;
fn learned_move_restore_all_uses(r: ExternRef<LearnedMoveImpl>) -> WasmResult<()>;
} }
} }

View File

@ -5,8 +5,8 @@ use core::iter::IntoIterator;
#[cfg_attr(feature = "mock_data", mockall::automock)] #[cfg_attr(feature = "mock_data", mockall::automock)]
pub trait PartyTrait { pub trait PartyTrait {
fn get_pokemon(&self, index: usize) -> Option<Pokemon>; fn get_pokemon(&self, index: usize) -> PkmnResult<Option<Pokemon>>;
fn length(&self) -> usize; fn length(&self) -> PkmnResult<usize>;
} }
pub type Party = Rc<dyn PartyTrait>; pub type Party = Rc<dyn PartyTrait>;
@ -16,7 +16,10 @@ impl<'a> IntoIterator for &'a dyn PartyTrait {
type IntoIter = ExternIterator<'a, Self::Item>; type IntoIter = ExternIterator<'a, Self::Item>;
fn into_iter(self) -> Self::IntoIter { fn into_iter(self) -> Self::IntoIter {
ExternIterator::new(self.length(), Box::new(move |i| self.get_pokemon(i))) ExternIterator::new(
self.length().unwrap(),
Box::new(move |i| self.get_pokemon(i).unwrap()),
)
} }
} }
@ -28,6 +31,8 @@ mod implementation {
use super::*; use super::*;
use crate::app_interface::PokemonImpl; use crate::app_interface::PokemonImpl;
use crate::handling::extern_ref::{ExternRef, ExternalReferenceType}; use crate::handling::extern_ref::{ExternRef, ExternalReferenceType};
use crate::handling::wasm_result::WasmResult;
use crate::PkmnResult;
#[derive(Clone)] #[derive(Clone)]
pub struct PartyImpl { pub struct PartyImpl {
@ -41,19 +46,21 @@ mod implementation {
} }
impl PartyTrait for PartyImpl { impl PartyTrait for PartyImpl {
fn get_pokemon(&self, index: usize) -> Option<Pokemon> { fn get_pokemon(&self, index: usize) -> PkmnResult<Option<Pokemon>> {
unsafe { unsafe {
let v = party_get_pokemon(self.reference, index).get_value(); let v = party_get_pokemon(self.reference, index)
if let Some(v) = v { .as_res()?
.get_value();
Ok(if let Some(v) = v {
Some(Rc::new(v)) Some(Rc::new(v))
} else { } else {
None None
} })
} }
} }
fn length(&self) -> usize { fn length(&self) -> PkmnResult<usize> {
unsafe { party_get_length(self.reference) } unsafe { party_get_length(self.reference).as_res() }
} }
} }
@ -64,11 +71,15 @@ mod implementation {
} }
extern "wasm" { extern "wasm" {
fn party_get_pokemon(r: ExternRef<PartyImpl>, index: usize) -> ExternRef<PokemonImpl>; fn party_get_pokemon(
fn party_get_length(r: ExternRef<PartyImpl>) -> usize; r: ExternRef<PartyImpl>,
index: usize,
) -> WasmResult<ExternRef<PokemonImpl>>;
fn party_get_length(r: ExternRef<PartyImpl>) -> WasmResult<usize>;
} }
} }
use crate::utils::ExternIterator; use crate::utils::ExternIterator;
use crate::PkmnResult;
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
pub use implementation::*; pub use implementation::*;

View File

@ -8,36 +8,37 @@ use alloc::boxed::Box;
use alloc::rc::Rc; use alloc::rc::Rc;
use cstr_core::c_char; use cstr_core::c_char;
use crate::PkmnResult;
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
pub use implementation::*; pub use implementation::*;
pub trait PokemonTrait: WithVolatile { pub trait PokemonTrait: WithVolatile {
fn reference(&self) -> u32; fn reference(&self) -> u32;
fn species(&self) -> Species; fn species(&self) -> PkmnResult<Species>;
fn form(&self) -> Form; fn form(&self) -> PkmnResult<Form>;
fn active_ability(&self) -> Ability; fn active_ability(&self) -> PkmnResult<Ability>;
fn nature(&self) -> Nature; fn nature(&self) -> PkmnResult<Nature>;
fn display_species(&self) -> Species; fn display_species(&self) -> PkmnResult<Species>;
fn display_form(&self) -> Form; fn display_form(&self) -> PkmnResult<Form>;
fn held_item(&self) -> Option<Item>; fn held_item(&self) -> PkmnResult<Option<Item>>;
fn battle(&self) -> Option<Battle>; fn battle(&self) -> PkmnResult<Option<Battle>>;
fn level(&self) -> LevelInt; fn level(&self) -> PkmnResult<LevelInt>;
fn experience(&self) -> u32; fn experience(&self) -> PkmnResult<u32>;
fn unique_identifier(&self) -> u32; fn unique_identifier(&self) -> PkmnResult<u32>;
fn gender(&self) -> Gender; fn gender(&self) -> PkmnResult<Gender>;
fn coloring(&self) -> u8; fn coloring(&self) -> PkmnResult<u8>;
fn current_health(&self) -> u32; fn current_health(&self) -> PkmnResult<u32>;
fn weight(&self) -> f32; fn weight(&self) -> PkmnResult<f32>;
fn height(&self) -> f32; fn height(&self) -> PkmnResult<f32>;
fn nickname(&self) -> *const c_char; fn nickname(&self) -> PkmnResult<*const c_char>;
fn real_ability(&self) -> AbilityIndex; fn real_ability(&self) -> PkmnResult<AbilityIndex>;
fn types_length(&self) -> usize; fn types_length(&self) -> PkmnResult<usize>;
fn battle_side_index(&self) -> u8; fn battle_side_index(&self) -> PkmnResult<u8>;
fn battle_index(&self) -> u8; fn battle_index(&self) -> PkmnResult<u8>;
fn is_ability_overriden(&self) -> u8; fn is_ability_overriden(&self) -> PkmnResult<u8>;
fn allowed_experience_gain(&self) -> bool; fn allowed_experience_gain(&self) -> PkmnResult<bool>;
fn is_usable(&self) -> bool; fn is_usable(&self) -> PkmnResult<bool>;
fn library(&self) -> DynamicLibrary; fn library(&self) -> DynamicLibrary;
fn flat_stats(&self) -> StatisticSet<u32>; fn flat_stats(&self) -> StatisticSet<u32>;
@ -45,25 +46,30 @@ pub trait PokemonTrait: WithVolatile {
fn boosted_stats(&self) -> StatisticSet<u32>; fn boosted_stats(&self) -> StatisticSet<u32>;
fn individual_values(&self) -> ClampedStatisticSet<u8>; fn individual_values(&self) -> ClampedStatisticSet<u8>;
fn effort_values(&self) -> ClampedStatisticSet<u8>; fn effort_values(&self) -> ClampedStatisticSet<u8>;
fn has_held_item(&self, name: &str) -> bool; fn has_held_item(&self, name: &str) -> PkmnResult<bool>;
fn set_held_item(&self, item: &Item) -> Option<Item>; fn set_held_item(&self, item: &Item) -> PkmnResult<Option<Item>>;
fn remove_held_item(&self) -> Option<Item>; fn remove_held_item(&self) -> PkmnResult<Option<Item>>;
fn consume_held_item(&self) -> bool; fn consume_held_item(&self) -> PkmnResult<bool>;
fn max_health(&self) -> u32; fn max_health(&self) -> PkmnResult<u32>;
fn get_type(&self, index: usize) -> u8; fn get_type(&self, index: usize) -> PkmnResult<u8>;
fn has_type(&self, type_identifier: TypeIdentifier) -> bool; fn has_type(&self, type_identifier: TypeIdentifier) -> PkmnResult<bool>;
fn has_type_by_name(&self, type_name: &str) -> bool; fn has_type_by_name(&self, type_name: &str) -> PkmnResult<bool>;
fn get_learned_move(&self, index: usize) -> Option<LearnedMove>; fn get_learned_move(&self, index: usize) -> PkmnResult<Option<LearnedMove>>;
fn change_stat_boost(&self, stat: Statistic, diff_amount: i8, self_inflicted: bool) -> bool; fn change_stat_boost(
fn ability_script(&self) -> Option<&Box<dyn Script>>; &self,
stat: Statistic,
diff_amount: i8,
self_inflicted: bool,
) -> PkmnResult<bool>;
fn ability_script(&self) -> PkmnResult<Option<&Box<dyn Script>>>;
fn change_species(&self, species: Species, form: Form); fn change_species(&self, species: Species, form: Form);
fn change_form(&self, form: Form); fn change_form(&self, form: Form);
fn is_fainted(&self) -> bool; fn is_fainted(&self) -> PkmnResult<bool>;
fn damage(&self, damage: u32, source: DamageSource); fn damage(&self, damage: u32, source: DamageSource) -> PkmnResult<()>;
fn heal(&self, amount: u32, allow_revive: bool) -> bool; fn heal(&self, amount: u32, allow_revive: bool) -> PkmnResult<bool>;
fn set_weight(&self, weight: f32); fn set_weight(&self, weight: f32);
fn clear_status(&self); fn clear_status(&self);
fn battle_side(&self) -> BattleSide; fn battle_side(&self) -> PkmnResult<BattleSide>;
fn equals(&self, other: &Pokemon) -> bool; fn equals(&self, other: &Pokemon) -> bool;
} }
@ -84,6 +90,7 @@ pub enum DamageSource {
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
mod implementation { mod implementation {
use super::*; use super::*;
use core::mem::transmute;
use cstr_core::CString; use cstr_core::CString;
use crate::app_interface::dynamic_data::dynamic_library::DynamicLibraryImpl; use crate::app_interface::dynamic_data::dynamic_library::DynamicLibraryImpl;
@ -92,12 +99,13 @@ mod implementation {
StatisticSetImpl, StatisticSetImpl,
}; };
use crate::handling::cached_value::CachedValue; use crate::handling::cached_value::CachedValue;
use crate::handling::wasm_result::WasmResult;
use crate::handling::Cacheable; use crate::handling::Cacheable;
use crate::implementation::ScriptPtr; use crate::implementation::ScriptPtr;
use crate::{ use crate::{
cached_value, cached_value_getters, wasm_optional_reference_getters_extern, cached_value, cached_value_getters, wasm_optional_reference_getters_extern,
wasm_reference_getters_extern, wasm_value_getters_extern, wasm_value_getters_funcs, wasm_reference_getters_extern, wasm_value_getters_extern, wasm_value_getters_funcs,
ExternRef, ExternalReferenceType, ExternRef, ExternalReferenceType, PkmnResult,
}; };
struct PokemonInner { struct PokemonInner {
@ -134,90 +142,154 @@ mod implementation {
fn effort_values(&self) -> ClampedStatisticSet<u8>; fn effort_values(&self) -> ClampedStatisticSet<u8>;
} }
fn active_ability(&self) -> Ability { fn nickname(&self) -> PkmnResult<*const u8> {
unsafe { unsafe {
let nickname = pokemon_get_nickname(self.inner.reference).as_res()?;
Ok(nickname as *const u8)
}
}
fn species(&self) -> PkmnResult<Species> {
Ok(unsafe {
Rc::new(
pokemon_get_species(self.inner.reference)
.as_res()?
.get_value()
.unwrap(),
)
})
}
fn form(&self) -> PkmnResult<Form> {
Ok(unsafe {
Rc::new(
pokemon_get_form(self.inner.reference)
.as_res()?
.get_value()
.unwrap(),
)
})
}
fn active_ability(&self) -> PkmnResult<Ability> {
Ok(unsafe {
let implementation = pokemon_get_active_ability(self.reference()) let implementation = pokemon_get_active_ability(self.reference())
.as_res()?
.get_value() .get_value()
.unwrap(); .unwrap();
Rc::new(implementation) Rc::new(implementation)
} })
} }
fn held_item(&self) -> Option<Item> { fn nature(&self) -> PkmnResult<Nature> {
unsafe { Ok(unsafe {
let i = pokemon_get_held_item(self.inner.reference).get_value(); Rc::new(
if let Some(i) = i { pokemon_get_nature(self.inner.reference)
Some(Rc::new(i)) .as_res()?
} else { .get_value()
None .unwrap(),
} )
} })
} }
fn battle(&self) -> Option<Battle> { fn display_species(&self) -> PkmnResult<Species> {
unsafe { Ok(unsafe {
let b = pokemon_get_battle(self.reference()).get_value(); Rc::new(
if let Some(b) = b { pokemon_get_display_species(self.inner.reference)
Some(Rc::new(b)) .as_res()?
} else { .get_value()
None .unwrap(),
} )
} })
} }
fn has_held_item(&self, name: &str) -> bool { fn display_form(&self) -> PkmnResult<Form> {
let cstr = CString::new(name).unwrap(); Ok(unsafe {
unsafe { pokemon_has_held_item(self.inner.reference, cstr.as_ptr()) } Rc::new(
pokemon_get_display_form(self.inner.reference)
.as_res()?
.get_value()
.unwrap(),
)
})
} }
fn set_held_item(&self, item: &Item) -> Option<Item> { fn held_item(&self) -> PkmnResult<Option<Item>> {
unsafe { Ok(unsafe {
let i = pokemon_set_held_item(self.inner.reference, item.reference().into()) let i = pokemon_get_held_item(self.inner.reference)
.as_res()?
.get_value(); .get_value();
if let Some(i) = i { if let Some(i) = i {
Some(Rc::new(i)) Some(Rc::new(i))
} else { } else {
None None
} }
} })
} }
fn remove_held_item(&self) -> Option<Item> { fn battle(&self) -> PkmnResult<Option<Battle>> {
unsafe { Ok(unsafe {
let i = pokemon_remove_held_item(self.inner.reference).get_value(); let b = pokemon_get_battle(self.reference()).as_res()?.get_value();
if let Some(i) = i { if let Some(b) = b {
Some(Rc::new(i)) Some(Rc::new(b))
} else { } else {
None None
} }
})
}
fn has_held_item(&self, name: &str) -> PkmnResult<bool> {
let cstr = CString::new(name).unwrap();
unsafe { pokemon_has_held_item(self.inner.reference, cstr.as_ptr()).as_res() }
}
fn set_held_item(&self, item: &Item) -> PkmnResult<Option<Item>> {
unsafe {
let i = pokemon_set_held_item(self.inner.reference, item.reference().into())
.as_res()?
.get_value();
Ok(if let Some(i) = i {
Some(Rc::new(i))
} else {
None
})
} }
} }
fn consume_held_item(&self) -> bool { fn remove_held_item(&self) -> PkmnResult<Option<Item>> {
unsafe { pokemon_consume_held_item(self.inner.reference) } unsafe {
let i = pokemon_remove_held_item(self.inner.reference)
.as_res()?
.get_value();
Ok(if let Some(i) = i {
Some(Rc::new(i))
} else {
None
})
}
} }
fn max_health(&self) -> u32 { fn consume_held_item(&self) -> PkmnResult<bool> {
unsafe { pokemon_consume_held_item(self.inner.reference).as_res() }
}
fn max_health(&self) -> PkmnResult<u32> {
self.boosted_stats().hp() self.boosted_stats().hp()
} }
fn get_type(&self, index: usize) -> u8 { fn get_type(&self, index: usize) -> PkmnResult<u8> {
unsafe { pokemon_get_type(self.inner.reference, index) } unsafe { pokemon_get_type(self.inner.reference, index).as_res() }
} }
fn has_type(&self, type_identifier: TypeIdentifier) -> bool { fn has_type(&self, type_identifier: TypeIdentifier) -> PkmnResult<bool> {
unsafe { pokemon_has_type(self.inner.reference, type_identifier.into()) } unsafe { pokemon_has_type(self.inner.reference, type_identifier.into()).as_res() }
} }
fn has_type_by_name(&self, type_name: &str) -> bool { fn has_type_by_name(&self, type_name: &str) -> PkmnResult<bool> {
let type_identifier = self let type_identifier = self
.library() .library()
.data_library() .data_library()
.type_library() .type_library()
.get_type_from_name(type_name); .get_type_from_name(type_name)?;
if let Some(type_identifier) = type_identifier { if let Some(type_identifier) = type_identifier {
return self.has_type(type_identifier); return self.has_type(type_identifier);
} }
false Ok(false)
} }
fn get_learned_move(&self, index: usize) -> Option<LearnedMove> { fn get_learned_move(&self, index: usize) -> PkmnResult<Option<LearnedMove>> {
unsafe { unsafe {
let v = pokemon_get_learned_move(self.inner.reference, index).get_value(); let v = pokemon_get_learned_move(self.inner.reference, index)
if let Some(v) = v { .as_res()?
.get_value();
Ok(if let Some(v) = v {
Some(Rc::new(v)) Some(Rc::new(v))
} else { } else {
None None
} })
} }
} }
fn change_stat_boost( fn change_stat_boost(
@ -225,13 +297,18 @@ mod implementation {
stat: Statistic, stat: Statistic,
diff_amount: i8, diff_amount: i8,
self_inflicted: bool, self_inflicted: bool,
) -> bool { ) -> PkmnResult<bool> {
unsafe { unsafe {
pokemon_change_stat_boost(self.inner.reference, stat, diff_amount, self_inflicted) pokemon_change_stat_boost(self.inner.reference, stat, diff_amount, self_inflicted)
.as_res()
} }
} }
fn ability_script(&self) -> Option<&Box<dyn Script>> { fn ability_script(&self) -> PkmnResult<Option<&Box<dyn Script>>> {
unsafe { pokemon_get_ability_script(self.inner.reference).as_ref() } unsafe {
Ok((pokemon_get_ability_script(self.inner.reference).as_res()?
as *const Box<dyn Script>)
.as_ref())
}
} }
fn change_species(&self, species: Species, form: Form) { fn change_species(&self, species: Species, form: Form) {
unsafe { unsafe {
@ -245,81 +322,44 @@ mod implementation {
); );
} }
} }
fn change_form(&self, form: Form) { fn change_form(&self, form: Form) {
unsafe { unsafe {
let form_impl = form.as_any().downcast_ref_unchecked::<FormImpl>(); let form_impl = form.as_any().downcast_ref_unchecked::<FormImpl>();
pokemon_change_form(self.inner.reference, form_impl.reference()); pokemon_change_form(self.inner.reference, form_impl.reference());
} }
} }
fn is_fainted(&self) -> bool {
self.current_health() == 0 fn is_fainted(&self) -> PkmnResult<bool> {
Ok(self.current_health()? == 0)
} }
fn damage(&self, damage: u32, source: DamageSource) { fn damage(&self, damage: u32, source: DamageSource) -> PkmnResult<()> {
unsafe { pokemon_damage(self.inner.reference, damage, source) } unsafe { pokemon_damage(self.inner.reference, damage, source).as_res() }
} }
fn heal(&self, amount: u32, allow_revive: bool) -> bool {
unsafe { pokemon_heal(self.inner.reference, amount, allow_revive) } fn heal(&self, amount: u32, allow_revive: bool) -> PkmnResult<bool> {
unsafe { pokemon_heal(self.inner.reference, amount, allow_revive).as_res() }
} }
fn set_weight(&self, weight: f32) { fn set_weight(&self, weight: f32) {
unsafe { unsafe {
pokemon_set_weight(self.reference(), weight); pokemon_set_weight(self.reference(), weight);
} }
} }
fn nature(&self) -> Nature {
unsafe {
Rc::new(
pokemon_get_nature(self.inner.reference)
.get_value()
.unwrap(),
)
}
}
fn species(&self) -> Species {
unsafe {
Rc::new(
pokemon_get_species(self.inner.reference)
.get_value()
.unwrap(),
)
}
}
fn form(&self) -> Form {
unsafe { Rc::new(pokemon_get_form(self.inner.reference).get_value().unwrap()) }
}
fn clear_status(&self) { fn clear_status(&self) {
unsafe { unsafe {
pokemon_clear_status(self.reference()); pokemon_clear_status(self.reference());
} }
} }
fn display_species(&self) -> Species { fn battle_side(&self) -> PkmnResult<BattleSide> {
unsafe { Ok(self
Rc::new( .battle()?
pokemon_get_display_species(self.inner.reference)
.get_value()
.unwrap(),
)
}
}
fn display_form(&self) -> Form {
unsafe {
Rc::new(
pokemon_get_display_form(self.inner.reference)
.get_value()
.unwrap(),
)
}
}
fn battle_side(&self) -> BattleSide {
self.battle()
.unwrap() .unwrap()
.sides() .sides()
.get(self.battle_side_index() as u32) .get(self.battle_side_index()? as usize)
.unwrap() .unwrap()
.clone())
} }
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
@ -333,8 +373,6 @@ mod implementation {
fn current_health(&self) -> u32; fn current_health(&self) -> u32;
fn weight(&self) -> f32; fn weight(&self) -> f32;
fn height(&self) -> f32; fn height(&self) -> f32;
fn nickname(&self) -> *const c_char;
fn real_ability(&self) -> AbilityIndex;
fn types_length(&self) -> usize; fn types_length(&self) -> usize;
fn battle_side_index(&self) -> u8; fn battle_side_index(&self) -> u8;
fn battle_index(&self) -> u8; fn battle_index(&self) -> u8;
@ -349,45 +387,66 @@ mod implementation {
.get_internal_index() .get_internal_index()
.eq(&other.reference()) .eq(&other.reference())
} }
fn real_ability(&self) -> PkmnResult<AbilityIndex> {
unsafe {
let real_ability = pokemon_get_real_ability(self.reference()).as_res()?;
let split: (u8, u8) = transmute(real_ability);
Ok(AbilityIndex {
index: split.0,
hidden: split.1 == 1,
})
}
}
} }
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
impl WithVolatile for PokemonImpl { impl WithVolatile for PokemonImpl {
fn has_volatile(&self, script_name: &str) -> bool { fn has_volatile(&self, script_name: &str) -> PkmnResult<bool> {
unsafe { unsafe {
let ptr = CString::new(script_name).unwrap(); let ptr = CString::new(script_name).unwrap();
pokemon_has_volatile(self.inner.reference, ptr.as_ptr()) pokemon_has_volatile(self.inner.reference, ptr.as_ptr()).as_res()
} }
} }
fn add_volatile(&self, script: Box<dyn Script>) -> &dyn Script { fn add_volatile(&self, script: Box<dyn Script>) -> PkmnResult<&dyn Script> {
unsafe { unsafe {
pokemon_add_volatile(self.inner.reference, ScriptPtr::new(script)) Ok(
.val() pokemon_add_volatile(self.inner.reference, ScriptPtr::new(script))
.unwrap() .as_res()?
.val()
.unwrap(),
)
} }
} }
fn add_volatile_by_name(&self, script_name: &str) -> &dyn Script { fn add_volatile_by_name(&self, script_name: &str) -> PkmnResult<&dyn Script> {
unsafe { unsafe {
let ptr = CString::new(script_name).unwrap(); let ptr = CString::new(script_name).unwrap();
pokemon_add_volatile_by_name(self.inner.reference, ptr.as_ptr()) Ok(
.val() pokemon_add_volatile_by_name(self.inner.reference, ptr.as_ptr())
.unwrap() .as_res()?
.val()
.unwrap(),
)
} }
} }
fn remove_volatile(&self, script: &dyn Script) { fn remove_volatile(&self, script: &dyn Script) -> PkmnResult<()> {
unsafe { unsafe {
let name = CString::new(script.get_name()).unwrap(); let name = CString::new(script.get_name()).unwrap();
pokemon_remove_volatile(self.inner.reference, name.as_ptr()); pokemon_remove_volatile(self.inner.reference, name.as_ptr()).as_res()
} }
} }
fn get_volatile_script(&self, script_name: &str) -> Option<&dyn Script> { fn get_volatile_script(&self, script_name: &str) -> PkmnResult<Option<&dyn Script>> {
unsafe { unsafe {
let script_name = CString::new(script_name).unwrap(); let script_name = CString::new(script_name).unwrap();
pokemon_get_volatile(self.inner.reference, script_name.as_ptr()).val() Ok(
pokemon_get_volatile(self.inner.reference, script_name.as_ptr())
.as_res()?
.val(),
)
} }
} }
} }
@ -398,24 +457,41 @@ mod implementation {
inner: Rc::new(PokemonInner { inner: Rc::new(PokemonInner {
reference, reference,
library: cached_value!({ library: cached_value!({
Rc::new(pokemon_get_library(reference).get_value().unwrap()) Rc::new(pokemon_get_library(reference).unwrap().get_value().unwrap())
}), }),
flat_stats: cached_value!({ flat_stats: cached_value!({
Rc::new(pokemon_get_flat_stats(reference).get_value().unwrap()) Rc::new(
pokemon_get_flat_stats(reference)
.unwrap()
.get_value()
.unwrap(),
)
}), }),
stat_boosts: cached_value!({ stat_boosts: cached_value!({
pokemon_get_stat_boosts(reference).get_value().unwrap() pokemon_get_stat_boosts(reference)
.unwrap()
.get_value()
.unwrap()
}), }),
boosted_stats: cached_value!({ boosted_stats: cached_value!({
Rc::new(pokemon_get_boosted_stats(reference).get_value().unwrap()) Rc::new(
pokemon_get_boosted_stats(reference)
.unwrap()
.get_value()
.unwrap(),
)
}), }),
individual_values: cached_value!({ individual_values: cached_value!({
pokemon_get_individual_values(reference) pokemon_get_individual_values(reference)
.unwrap()
.get_value() .get_value()
.unwrap() .unwrap()
}), }),
effort_values: cached_value!({ effort_values: cached_value!({
pokemon_get_effort_values(reference).get_value().unwrap() pokemon_get_effort_values(reference)
.unwrap()
.get_value()
.unwrap()
}), }),
}), }),
}) })
@ -430,14 +506,14 @@ mod implementation {
PokemonImpl, Pokemon, PokemonImpl, Pokemon,
pub fn species(&self) -> SpeciesImpl; pub fn species(&self) -> SpeciesImpl;
pub fn form(&self) -> FormImpl; pub fn form(&self) -> FormImpl;
pub fn display_species(&self) -> SpeciesImpl;
pub fn display_form(&self) -> FormImpl;
pub fn active_ability(&self) -> AbilityImpl; pub fn active_ability(&self) -> AbilityImpl;
pub fn nature(&self) -> NatureImpl; pub fn nature(&self) -> NatureImpl;
} }
wasm_optional_reference_getters_extern! { wasm_optional_reference_getters_extern! {
PokemonImpl, Pokemon, PokemonImpl, Pokemon,
pub fn display_species(&self) -> Option<SpeciesImpl>;
pub fn display_form(&self) -> Option<FormImpl>;
pub fn held_item(&self) -> Option<ItemImpl>; pub fn held_item(&self) -> Option<ItemImpl>;
pub fn battle(&self) -> Option<BattleImpl>; pub fn battle(&self) -> Option<BattleImpl>;
} }
@ -452,8 +528,7 @@ mod implementation {
pub fn current_health(&self) -> u32; pub fn current_health(&self) -> u32;
pub fn weight(&self) -> f32; pub fn weight(&self) -> f32;
pub fn height(&self) -> f32; pub fn height(&self) -> f32;
pub fn nickname(&self) -> *const c_char; pub fn real_ability(&self) -> u16;
pub fn real_ability(&self) -> AbilityIndex;
pub fn types_length(&self) -> usize; pub fn types_length(&self) -> usize;
pub fn battle_side_index(&self) -> u8; pub fn battle_side_index(&self) -> u8;
pub fn battle_index(&self) -> u8; pub fn battle_index(&self) -> u8;
@ -477,58 +552,89 @@ mod implementation {
} }
extern "wasm" { extern "wasm" {
fn pokemon_get_library(r: ExternRef<PokemonImpl>) -> ExternRef<DynamicLibraryImpl>; fn pokemon_get_nickname(r: ExternRef<PokemonImpl>) -> WasmResult<u32>;
fn pokemon_get_flat_stats(r: ExternRef<PokemonImpl>) -> ExternRef<StatisticSetImpl<u32>>; fn pokemon_get_library(
fn pokemon_get_stat_boosts(r: ExternRef<PokemonImpl>) r: ExternRef<PokemonImpl>,
-> ExternRef<ClampedStatisticSet<i8>>; ) -> WasmResult<ExternRef<DynamicLibraryImpl>>;
fn pokemon_get_boosted_stats(r: ExternRef<PokemonImpl>) fn pokemon_get_flat_stats(
-> ExternRef<StatisticSetImpl<u32>>; r: ExternRef<PokemonImpl>,
) -> WasmResult<ExternRef<StatisticSetImpl<u32>>>;
fn pokemon_get_stat_boosts(
r: ExternRef<PokemonImpl>,
) -> WasmResult<ExternRef<ClampedStatisticSet<i8>>>;
fn pokemon_get_boosted_stats(
r: ExternRef<PokemonImpl>,
) -> WasmResult<ExternRef<StatisticSetImpl<u32>>>;
fn pokemon_get_individual_values( fn pokemon_get_individual_values(
r: ExternRef<PokemonImpl>, r: ExternRef<PokemonImpl>,
) -> ExternRef<ClampedStatisticSet<u8>>; ) -> WasmResult<ExternRef<ClampedStatisticSet<u8>>>;
fn pokemon_get_effort_values( fn pokemon_get_effort_values(
r: ExternRef<PokemonImpl>, r: ExternRef<PokemonImpl>,
) -> ExternRef<ClampedStatisticSet<u8>>; ) -> WasmResult<ExternRef<ClampedStatisticSet<u8>>>;
fn pokemon_has_held_item(r: ExternRef<PokemonImpl>, name: *const c_char) -> bool; fn pokemon_has_held_item(
r: ExternRef<PokemonImpl>,
name: *const c_char,
) -> WasmResult<bool>;
fn pokemon_set_held_item( fn pokemon_set_held_item(
r: ExternRef<PokemonImpl>, r: ExternRef<PokemonImpl>,
item: ExternRef<ItemImpl>, item: ExternRef<ItemImpl>,
) -> ExternRef<ItemImpl>; ) -> WasmResult<ExternRef<ItemImpl>>;
fn pokemon_remove_held_item(r: ExternRef<PokemonImpl>) -> ExternRef<ItemImpl>; fn pokemon_remove_held_item(r: ExternRef<PokemonImpl>) -> WasmResult<ExternRef<ItemImpl>>;
fn pokemon_consume_held_item(r: ExternRef<PokemonImpl>) -> bool; fn pokemon_consume_held_item(r: ExternRef<PokemonImpl>) -> WasmResult<bool>;
fn pokemon_get_type(r: ExternRef<PokemonImpl>, index: usize) -> u8; fn pokemon_get_type(r: ExternRef<PokemonImpl>, index: usize) -> WasmResult<u8>;
fn pokemon_has_type(r: ExternRef<PokemonImpl>, identifier: u8) -> bool; fn pokemon_has_type(r: ExternRef<PokemonImpl>, identifier: u8) -> WasmResult<bool>;
fn pokemon_get_learned_move( fn pokemon_get_learned_move(
r: ExternRef<PokemonImpl>, r: ExternRef<PokemonImpl>,
index: usize, index: usize,
) -> ExternRef<LearnedMoveImpl>; ) -> WasmResult<ExternRef<LearnedMoveImpl>>;
fn pokemon_change_stat_boost( fn pokemon_change_stat_boost(
r: ExternRef<PokemonImpl>, r: ExternRef<PokemonImpl>,
tat: Statistic, tat: Statistic,
diff_amount: i8, diff_amount: i8,
self_inflicted: bool, self_inflicted: bool,
) -> bool; ) -> WasmResult<bool>;
#[allow(improper_ctypes)] #[allow(improper_ctypes)]
fn pokemon_get_ability_script(r: ExternRef<PokemonImpl>) -> *const Box<dyn Script>; fn pokemon_get_ability_script(r: ExternRef<PokemonImpl>) -> WasmResult<u32>;
fn pokemon_change_species( fn pokemon_change_species(
r: ExternRef<PokemonImpl>, r: ExternRef<PokemonImpl>,
species: ExternRef<SpeciesImpl>, species: ExternRef<SpeciesImpl>,
form: ExternRef<FormImpl>, form: ExternRef<FormImpl>,
); ) -> WasmResult<()>;
fn pokemon_change_form(r: ExternRef<PokemonImpl>, form: ExternRef<FormImpl>); fn pokemon_change_form(
fn pokemon_damage(r: ExternRef<PokemonImpl>, damage: u32, source: DamageSource); r: ExternRef<PokemonImpl>,
fn pokemon_heal(r: ExternRef<PokemonImpl>, amount: u32, allow_revive: bool) -> bool; form: ExternRef<FormImpl>,
fn pokemon_set_weight(r: ExternRef<PokemonImpl>, weight: f32); ) -> WasmResult<()>;
fn pokemon_clear_status(r: ExternRef<PokemonImpl>); fn pokemon_damage(
r: ExternRef<PokemonImpl>,
damage: u32,
source: DamageSource,
) -> WasmResult<()>;
fn pokemon_heal(
r: ExternRef<PokemonImpl>,
amount: u32,
allow_revive: bool,
) -> WasmResult<bool>;
fn pokemon_set_weight(r: ExternRef<PokemonImpl>, weight: f32) -> WasmResult<()>;
fn pokemon_clear_status(r: ExternRef<PokemonImpl>) -> WasmResult<()>;
fn pokemon_add_volatile_by_name( fn pokemon_add_volatile_by_name(
r: ExternRef<PokemonImpl>, r: ExternRef<PokemonImpl>,
name: *const c_char, name: *const c_char,
) -> ScriptPtr; ) -> WasmResult<ScriptPtr>;
fn pokemon_add_volatile(r: ExternRef<PokemonImpl>, script: ScriptPtr) -> ScriptPtr; fn pokemon_add_volatile(
fn pokemon_has_volatile(r: ExternRef<PokemonImpl>, name: *const c_char) -> bool; r: ExternRef<PokemonImpl>,
fn pokemon_remove_volatile(r: ExternRef<PokemonImpl>, name: *const c_char); script: ScriptPtr,
fn pokemon_get_volatile(r: ExternRef<PokemonImpl>, name: *const c_char) -> ScriptPtr; ) -> WasmResult<ScriptPtr>;
fn pokemon_has_volatile(r: ExternRef<PokemonImpl>, name: *const c_char)
-> WasmResult<bool>;
fn pokemon_remove_volatile(
r: ExternRef<PokemonImpl>,
name: *const c_char,
) -> WasmResult<()>;
fn pokemon_get_volatile(
r: ExternRef<PokemonImpl>,
name: *const c_char,
) -> WasmResult<ScriptPtr>;
} }
} }
@ -537,30 +643,30 @@ mockall::mock!(
pub Pokemon {} pub Pokemon {}
impl PokemonTrait for Pokemon { impl PokemonTrait for Pokemon {
fn reference(&self) -> u32; fn reference(&self) -> u32;
fn species(&self) -> Species; fn species(&self) -> PkmnResult<Species>;
fn form(&self) -> Form; fn form(&self) -> PkmnResult<Form>;
fn active_ability(&self) -> Ability; fn active_ability(&self) -> PkmnResult<Ability>;
fn nature(&self) -> Nature; fn nature(&self) -> PkmnResult<Nature>;
fn display_species(&self) -> Species; fn display_species(&self) -> PkmnResult<Species>;
fn display_form(&self) -> Form; fn display_form(&self) -> PkmnResult<Form>;
fn held_item(&self) -> Option<Item>; fn held_item(&self) -> PkmnResult<Option<Item>>;
fn battle(&self) -> Option<Battle>; fn battle(&self) -> PkmnResult<Option<Battle>>;
fn level(&self) -> LevelInt; fn level(&self) -> PkmnResult<LevelInt>;
fn experience(&self) -> u32; fn experience(&self) -> PkmnResult<u32>;
fn unique_identifier(&self) -> u32; fn unique_identifier(&self) -> PkmnResult<u32>;
fn gender(&self) -> Gender; fn gender(&self) -> PkmnResult<Gender>;
fn coloring(&self) -> u8; fn coloring(&self) -> PkmnResult<u8>;
fn current_health(&self) -> u32; fn current_health(&self) -> PkmnResult<u32>;
fn weight(&self) -> f32; fn weight(&self) -> PkmnResult<f32>;
fn height(&self) -> f32; fn height(&self) -> PkmnResult<f32>;
fn nickname(&self) -> *const c_char; fn nickname(&self) -> PkmnResult<*const c_char>;
fn real_ability(&self) -> AbilityIndex; fn real_ability(&self) -> PkmnResult<AbilityIndex>;
fn types_length(&self) -> usize; fn types_length(&self) -> PkmnResult<usize>;
fn battle_side_index(&self) -> u8; fn battle_side_index(&self) -> PkmnResult<u8>;
fn battle_index(&self) -> u8; fn battle_index(&self) -> PkmnResult<u8>;
fn is_ability_overriden(&self) -> u8; fn is_ability_overriden(&self) -> PkmnResult<u8>;
fn allowed_experience_gain(&self) -> bool; fn allowed_experience_gain(&self) -> PkmnResult<bool>;
fn is_usable(&self) -> bool; fn is_usable(&self) -> PkmnResult<bool>;
fn library(&self) -> DynamicLibrary; fn library(&self) -> DynamicLibrary;
fn flat_stats(&self) -> StatisticSet<u32>; fn flat_stats(&self) -> StatisticSet<u32>;
@ -568,44 +674,44 @@ mockall::mock!(
fn boosted_stats(&self) -> StatisticSet<u32>; fn boosted_stats(&self) -> StatisticSet<u32>;
fn individual_values(&self) -> ClampedStatisticSet<u8>; fn individual_values(&self) -> ClampedStatisticSet<u8>;
fn effort_values(&self) -> ClampedStatisticSet<u8>; fn effort_values(&self) -> ClampedStatisticSet<u8>;
fn has_held_item(&self, name: &str) -> bool; fn has_held_item(&self, name: &str) -> PkmnResult<bool>;
fn set_held_item(&self, item: &Item) -> Option<Item>; fn set_held_item(&self, item: &Item) -> PkmnResult<Option<Item>>;
fn remove_held_item(&self) -> Option<Item>; fn remove_held_item(&self) -> PkmnResult<Option<Item>>;
fn consume_held_item(&self) -> bool; fn consume_held_item(&self) -> PkmnResult<bool>;
fn max_health(&self) -> u32; fn max_health(&self) -> PkmnResult<u32>;
fn get_type(&self, index: usize) -> u8; fn get_type(&self, index: usize) -> PkmnResult<u8>;
fn has_type(&self, type_identifier: TypeIdentifier) -> bool; fn has_type(&self, type_identifier: TypeIdentifier) -> PkmnResult<bool>;
fn has_type_by_name(&self, type_name: &str) -> bool; fn has_type_by_name(&self, type_name: &str) -> PkmnResult<bool>;
fn get_learned_move(&self, index: usize) -> Option<LearnedMove>; fn get_learned_move(&self, index: usize) -> PkmnResult<Option<LearnedMove>>;
fn change_stat_boost(&self, stat: Statistic, diff_amount: i8, self_inflicted: bool) -> bool; fn change_stat_boost(&self, stat: Statistic, diff_amount: i8, self_inflicted: bool) -> PkmnResult<bool>;
fn ability_script<'a>(&'a self) -> Option<&'a Box<dyn Script>>; fn ability_script<'a>(&'a self) -> PkmnResult<Option<&'a Box<dyn Script>>>;
fn change_species(&self, species: Species, form: Form); fn change_species(&self, species: Species, form: Form);
fn change_form(&self, form: Form); fn change_form(&self, form: Form);
fn is_fainted(&self) -> bool; fn is_fainted(&self) -> PkmnResult<bool>;
fn damage(&self, damage: u32, source: DamageSource); fn damage(&self, damage: u32, source: DamageSource) -> PkmnResult<()>;
fn heal(&self, amount: u32, allow_revive: bool) -> bool; fn heal(&self, amount: u32, allow_revive: bool) -> PkmnResult<bool>;
fn set_weight(&self, weight: f32); fn set_weight(&self, weight: f32);
fn clear_status(&self); fn clear_status(&self);
fn battle_side(&self) -> BattleSide; fn battle_side(&self) -> PkmnResult<BattleSide>;
fn equals(&self, other: &Pokemon) -> bool; fn equals(&self, other: &Pokemon) -> bool;
} }
); );
#[cfg(feature = "mock_data")] #[cfg(feature = "mock_data")]
impl WithVolatile for MockPokemon { impl WithVolatile for MockPokemon {
fn has_volatile(&self, _script_name: &str) -> bool { fn has_volatile(&self, _script_name: &str) -> PkmnResult<bool> {
unimplemented!() unimplemented!()
} }
fn add_volatile(&self, _script: Box<dyn Script>) -> &dyn Script { fn add_volatile(&self, _script: Box<dyn Script>) -> PkmnResult<&dyn Script> {
unimplemented!() unimplemented!()
} }
fn add_volatile_by_name(&self, _script_name: &str) -> &dyn Script { fn add_volatile_by_name(&self, _script_name: &str) -> PkmnResult<&dyn Script> {
unimplemented!() unimplemented!()
} }
fn remove_volatile(&self, _script: &dyn Script) { fn remove_volatile(&self, _script: &dyn Script) -> PkmnResult<()> {
unimplemented!() unimplemented!()
} }
fn get_volatile_script<'a>(&'a self, _script_name: &str) -> Option<&'a dyn Script> { fn get_volatile_script<'a>(&'a self, _script_name: &str) -> PkmnResult<Option<&'a dyn Script>> {
unimplemented!() unimplemented!()
} }
} }

View File

@ -1,5 +1,7 @@
use crate::app_interface::Statistic; use crate::app_interface::Statistic;
use crate::{ExternRef, ExternalReferenceType}; #[cfg(not(feature = "mock_data"))]
use crate::handling::wasm_result::WasmResult;
use crate::{ExternRef, ExternalReferenceType, PkmnResult};
use alloc::rc::Rc; use alloc::rc::Rc;
use core::convert::{TryFrom, TryInto}; use core::convert::{TryFrom, TryInto};
use core::fmt::Debug; use core::fmt::Debug;
@ -12,28 +14,28 @@ where
<T as TryFrom<i64>>::Error: Debug, <T as TryFrom<i64>>::Error: Debug,
<T as TryInto<i64>>::Error: Debug, <T as TryInto<i64>>::Error: Debug,
{ {
fn hp(&self) -> T { fn hp(&self) -> PkmnResult<T> {
self.get_stat(Statistic::Attack) self.get_stat(Statistic::Attack)
} }
fn attack(&self) -> T { fn attack(&self) -> PkmnResult<T> {
self.get_stat(Statistic::Attack) self.get_stat(Statistic::Attack)
} }
fn defense(&self) -> T { fn defense(&self) -> PkmnResult<T> {
self.get_stat(Statistic::Defense) self.get_stat(Statistic::Defense)
} }
fn special_attack(&self) -> T { fn special_attack(&self) -> PkmnResult<T> {
self.get_stat(Statistic::SpecialAttack) self.get_stat(Statistic::SpecialAttack)
} }
fn special_defense(&self) -> T { fn special_defense(&self) -> PkmnResult<T> {
self.get_stat(Statistic::SpecialDefense) self.get_stat(Statistic::SpecialDefense)
} }
fn speed(&self) -> T { fn speed(&self) -> PkmnResult<T> {
self.get_stat(Statistic::Speed) self.get_stat(Statistic::Speed)
} }
fn get_stat(&self, stat: Statistic) -> T; fn get_stat(&self, stat: Statistic) -> PkmnResult<T>;
fn set_stat(&self, stat: Statistic, value: T); fn set_stat(&self, stat: Statistic, value: T) -> PkmnResult<()>;
fn increase_stat(&self, stat: Statistic, value: T); fn increase_stat(&self, stat: Statistic, value: T) -> PkmnResult<()>;
fn decrease_stat(&self, stat: Statistic, value: T); fn decrease_stat(&self, stat: Statistic, value: T) -> PkmnResult<()>;
} }
pub type StatisticSet<T> = Rc<dyn StatisticSetTrait<T>>; pub type StatisticSet<T> = Rc<dyn StatisticSetTrait<T>>;
@ -74,24 +76,29 @@ where
<T as TryFrom<i64>>::Error: Debug, <T as TryFrom<i64>>::Error: Debug,
<T as TryInto<i64>>::Error: Debug, <T as TryInto<i64>>::Error: Debug,
{ {
fn get_stat(&self, stat: Statistic) -> T { fn get_stat(&self, stat: Statistic) -> PkmnResult<T> {
unsafe { unsafe {
statistic_set_get(self.reference.cast(), stat) Ok(statistic_set_get(self.reference.cast(), stat)
.as_res()?
.try_into() .try_into()
.unwrap() .unwrap())
} }
} }
fn set_stat(&self, stat: Statistic, value: T) { fn set_stat(&self, stat: Statistic, value: T) -> PkmnResult<()> {
unsafe { statistic_set_set(self.reference.cast(), stat, value.try_into().unwrap()) } unsafe {
statistic_set_set(self.reference.cast(), stat, value.try_into().unwrap()).as_res()
}
} }
fn increase_stat(&self, stat: Statistic, value: T) { fn increase_stat(&self, stat: Statistic, value: T) -> PkmnResult<()> {
unsafe { unsafe {
statistic_set_increase_stat(self.reference.cast(), stat, value.try_into().unwrap()) statistic_set_increase_stat(self.reference.cast(), stat, value.try_into().unwrap())
.as_res()
} }
} }
fn decrease_stat(&self, stat: Statistic, value: T) { fn decrease_stat(&self, stat: Statistic, value: T) -> PkmnResult<()> {
unsafe { unsafe {
statistic_set_decrease_stat(self.reference.cast(), stat, value.try_into().unwrap()) statistic_set_decrease_stat(self.reference.cast(), stat, value.try_into().unwrap())
.as_res()
} }
} }
} }
@ -136,62 +143,68 @@ where
} }
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
pub fn hp(&self) -> T { pub fn hp(&self) -> PkmnResult<T> {
self.get_stat(Statistic::HP) self.get_stat(Statistic::HP)
} }
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
pub fn attack(&self) -> T { pub fn attack(&self) -> PkmnResult<T> {
self.get_stat(Statistic::Attack) self.get_stat(Statistic::Attack)
} }
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
pub fn defense(&self) -> T { pub fn defense(&self) -> PkmnResult<T> {
self.get_stat(Statistic::Defense) self.get_stat(Statistic::Defense)
} }
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
pub fn special_attack(&self) -> T { pub fn special_attack(&self) -> PkmnResult<T> {
self.get_stat(Statistic::SpecialAttack) self.get_stat(Statistic::SpecialAttack)
} }
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
pub fn special_defense(&self) -> T { pub fn special_defense(&self) -> PkmnResult<T> {
self.get_stat(Statistic::SpecialDefense) self.get_stat(Statistic::SpecialDefense)
} }
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
pub fn speed(&self) -> T { pub fn speed(&self) -> PkmnResult<T> {
self.get_stat(Statistic::Speed) self.get_stat(Statistic::Speed)
} }
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
pub fn get_stat(&self, stat: Statistic) -> T { pub fn get_stat(&self, stat: Statistic) -> PkmnResult<T> {
unsafe { unsafe {
clamped_statistic_set_get(self.reference.cast(), stat) Ok(clamped_statistic_set_get(self.reference.cast(), stat)
.as_res()?
.try_into() .try_into()
.unwrap() .unwrap())
} }
} }
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
pub fn set_stat(&self, stat: Statistic, value: T) { pub fn set_stat(&self, stat: Statistic, value: T) -> PkmnResult<()> {
unsafe { clamped_statistic_set_set(self.reference.cast(), stat, value.try_into().unwrap()) } unsafe {
clamped_statistic_set_set(self.reference.cast(), stat, value.try_into().unwrap())
.as_res()
}
} }
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
pub fn increase_stat(&self, stat: Statistic, value: T) -> bool { pub fn increase_stat(&self, stat: Statistic, value: T) -> PkmnResult<bool> {
unsafe { unsafe {
clamped_statistic_set_increase_stat( clamped_statistic_set_increase_stat(
self.reference.cast(), self.reference.cast(),
stat, stat,
value.try_into().unwrap(), value.try_into().unwrap(),
) )
.as_res()
} }
} }
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
pub fn decrease_stat(&self, stat: Statistic, value: T) -> bool { pub fn decrease_stat(&self, stat: Statistic, value: T) -> PkmnResult<bool> {
unsafe { unsafe {
clamped_statistic_set_decrease_stat( clamped_statistic_set_decrease_stat(
self.reference.cast(), self.reference.cast(),
stat, stat,
value.try_into().unwrap(), value.try_into().unwrap(),
) )
.as_res()
} }
} }
} }
@ -210,33 +223,40 @@ where
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
extern "wasm" { extern "wasm" {
fn statistic_set_get(r: ExternRef<StatisticSetImpl<i64>>, stat: Statistic) -> i64; fn statistic_set_get(r: ExternRef<StatisticSetImpl<i64>>, stat: Statistic) -> WasmResult<i64>;
fn statistic_set_set(r: ExternRef<StatisticSetImpl<i64>>, stat: Statistic, value: i64); fn statistic_set_set(
r: ExternRef<StatisticSetImpl<i64>>,
stat: Statistic,
value: i64,
) -> WasmResult<()>;
fn statistic_set_increase_stat( fn statistic_set_increase_stat(
r: ExternRef<StatisticSetImpl<i64>>, r: ExternRef<StatisticSetImpl<i64>>,
stat: Statistic, stat: Statistic,
value: i64, value: i64,
); ) -> WasmResult<()>;
fn statistic_set_decrease_stat( fn statistic_set_decrease_stat(
r: ExternRef<StatisticSetImpl<i64>>, r: ExternRef<StatisticSetImpl<i64>>,
stat: Statistic, stat: Statistic,
value: i64, value: i64,
); ) -> WasmResult<()>;
fn clamped_statistic_set_get(r: ExternRef<ClampedStatisticSet<i64>>, stat: Statistic) -> i64; fn clamped_statistic_set_get(
r: ExternRef<ClampedStatisticSet<i64>>,
stat: Statistic,
) -> WasmResult<i64>;
fn clamped_statistic_set_set( fn clamped_statistic_set_set(
r: ExternRef<ClampedStatisticSet<i64>>, r: ExternRef<ClampedStatisticSet<i64>>,
stat: Statistic, stat: Statistic,
value: i64, value: i64,
); ) -> WasmResult<()>;
fn clamped_statistic_set_increase_stat( fn clamped_statistic_set_increase_stat(
r: ExternRef<ClampedStatisticSet<i64>>, r: ExternRef<ClampedStatisticSet<i64>>,
stat: Statistic, stat: Statistic,
value: i64, value: i64,
) -> bool; ) -> WasmResult<bool>;
fn clamped_statistic_set_decrease_stat( fn clamped_statistic_set_decrease_stat(
r: ExternRef<ClampedStatisticSet<i64>>, r: ExternRef<ClampedStatisticSet<i64>>,
stat: Statistic, stat: Statistic,
value: i64, value: i64,
) -> bool; ) -> WasmResult<bool>;
} }

View File

@ -25,13 +25,13 @@ impl TurnChoice {
pub fn user(&self) -> Pokemon { pub fn user(&self) -> Pokemon {
self.base().user() self.base().user()
} }
pub fn speed(&self) -> u32 { pub fn speed(&self) -> PkmnResult<u32> {
self.base().speed() self.base().speed()
} }
pub fn has_failed(&self) -> bool { pub fn has_failed(&self) -> PkmnResult<bool> {
self.base().has_failed() self.base().has_failed()
} }
pub fn fail(&self) { pub fn fail(&self) -> PkmnResult<()> {
self.base().fail() self.base().fail()
} }
} }
@ -40,9 +40,9 @@ impl TurnChoice {
pub trait BaseTurnChoiceDataTrait { pub trait BaseTurnChoiceDataTrait {
fn reference(&self) -> u32; fn reference(&self) -> u32;
fn user(&self) -> Pokemon; fn user(&self) -> Pokemon;
fn speed(&self) -> u32; fn speed(&self) -> PkmnResult<u32>;
fn has_failed(&self) -> bool; fn has_failed(&self) -> PkmnResult<bool>;
fn fail(&self); fn fail(&self) -> PkmnResult<()>;
} }
pub type BaseTurnChoiceData = Rc<dyn BaseTurnChoiceDataTrait>; pub type BaseTurnChoiceData = Rc<dyn BaseTurnChoiceDataTrait>;
@ -55,8 +55,8 @@ pub trait MoveTurnChoiceDataTrait {
fn used_move(&self) -> LearnedMove; fn used_move(&self) -> LearnedMove;
fn target_side(&self) -> u8; fn target_side(&self) -> u8;
fn target_index(&self) -> u8; fn target_index(&self) -> u8;
fn priority(&self) -> i8; fn priority(&self) -> PkmnResult<i8>;
fn move_script<'a>(&self) -> Option<&'a Box<dyn Script>>; fn move_script<'a>(&self) -> PkmnResult<Option<&'a Box<dyn Script>>>;
} }
#[cfg(feature = "mock_data")] #[cfg(feature = "mock_data")]
pub type MockMoveTurnChoiceData = MockMoveTurnChoiceDataTrait; pub type MockMoveTurnChoiceData = MockMoveTurnChoiceDataTrait;
@ -65,10 +65,11 @@ pub type MockMoveTurnChoiceData = MockMoveTurnChoiceDataTrait;
mod implementation { mod implementation {
use super::*; use super::*;
use crate::app_interface::{LearnedMoveImpl, PokemonImpl}; use crate::app_interface::{LearnedMoveImpl, PokemonImpl};
use crate::cached_value;
use crate::handling::cached_value::CachedValue; use crate::handling::cached_value::CachedValue;
use crate::handling::extern_ref::{ExternRef, ExternalReferenceType}; use crate::handling::extern_ref::{ExternRef, ExternalReferenceType};
use crate::handling::temporary::Temporary; use crate::handling::temporary::Temporary;
use crate::handling::wasm_result::WasmResult;
use crate::{cached_value, PkmnResult};
struct BaseTurnChoiceDataImpl { struct BaseTurnChoiceDataImpl {
reference: ExternRef<TurnChoice>, reference: ExternRef<TurnChoice>,
@ -83,14 +84,14 @@ mod implementation {
fn user(&self) -> Pokemon { fn user(&self) -> Pokemon {
self.user.value() self.user.value()
} }
fn speed(&self) -> u32 { fn speed(&self) -> PkmnResult<u32> {
unsafe { turn_choice_get_speed(self.reference) } unsafe { turn_choice_get_speed(self.reference).as_res() }
} }
fn has_failed(&self) -> bool { fn has_failed(&self) -> PkmnResult<bool> {
unsafe { turn_choice_has_failed(self.reference) } unsafe { turn_choice_has_failed(self.reference).as_res() }
} }
fn fail(&self) { fn fail(&self) -> PkmnResult<()> {
unsafe { turn_choice_fail(self.reference) } unsafe { turn_choice_fail(self.reference).as_res() }
} }
} }
@ -121,18 +122,24 @@ mod implementation {
fn target_index(&self) -> u8 { fn target_index(&self) -> u8 {
self.inner.value().target_index.value() self.inner.value().target_index.value()
} }
fn priority(&self) -> i8 { fn priority(&self) -> PkmnResult<i8> {
unsafe { turn_choice_move_priority(self.base().reference().into()) } unsafe { turn_choice_move_priority(self.base().reference().into()).as_res() }
} }
fn move_script<'a>(&self) -> Option<&'a Box<dyn Script>> { fn move_script<'a>(&self) -> PkmnResult<Option<&'a Box<dyn Script>>> {
unsafe { turn_choice_move_script(self.base().reference().into()).as_ref() } unsafe {
Ok(
(turn_choice_move_script(self.base().reference().into()).as_res()?
as *const Box<dyn Script>)
.as_ref(),
)
}
} }
} }
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
impl ExternalReferenceType for TurnChoice { impl ExternalReferenceType for TurnChoice {
fn from_extern_value(reference: ExternRef<Self>) -> Self { fn from_extern_value(reference: ExternRef<Self>) -> Self {
let kind = unsafe { turn_choice_get_kind(reference) }; let kind = unsafe { turn_choice_get_kind(reference).unwrap() };
match kind { match kind {
0 => TurnChoice::Move(Box::new(MoveTurnChoiceDataImpl { 0 => TurnChoice::Move(Box::new(MoveTurnChoiceDataImpl {
inner: Temporary::new( inner: Temporary::new(
@ -152,39 +159,50 @@ mod implementation {
base: Rc::new(BaseTurnChoiceDataImpl { base: Rc::new(BaseTurnChoiceDataImpl {
reference: reference.cast(), reference: reference.cast(),
user: cached_value!({ user: cached_value!({
Rc::new(turn_choice_get_user(reference.cast()).get_value().unwrap()) Rc::new(
turn_choice_get_user(reference.cast())
.unwrap()
.get_value()
.unwrap(),
)
}), }),
}), }),
used_move: cached_value!({ used_move: cached_value!({
Rc::new( Rc::new(
turn_choice_move_used_move(reference.cast()) turn_choice_move_used_move(reference.cast())
.unwrap()
.get_value() .get_value()
.unwrap(), .unwrap(),
) )
}), }),
target_side: cached_value!({ turn_choice_move_target_side(reference.cast()) }), target_side: cached_value!({
target_index: cached_value!({ turn_choice_move_target_index(reference.cast()) }), turn_choice_move_target_side(reference.cast()).unwrap()
}),
target_index: cached_value!({
turn_choice_move_target_index(reference.cast()).unwrap()
}),
} }
} }
} }
extern "wasm" { extern "wasm" {
fn turn_choice_get_kind(r: ExternRef<TurnChoice>) -> u8; fn turn_choice_get_kind(r: ExternRef<TurnChoice>) -> WasmResult<u8>;
fn turn_choice_get_user(r: ExternRef<TurnChoice>) -> ExternRef<PokemonImpl>; fn turn_choice_get_user(r: ExternRef<TurnChoice>) -> WasmResult<ExternRef<PokemonImpl>>;
fn turn_choice_get_speed(r: ExternRef<TurnChoice>) -> u32; fn turn_choice_get_speed(r: ExternRef<TurnChoice>) -> WasmResult<u32>;
fn turn_choice_has_failed(r: ExternRef<TurnChoice>) -> bool; fn turn_choice_has_failed(r: ExternRef<TurnChoice>) -> WasmResult<bool>;
fn turn_choice_fail(r: ExternRef<TurnChoice>); fn turn_choice_fail(r: ExternRef<TurnChoice>) -> WasmResult<()>;
fn turn_choice_move_used_move( fn turn_choice_move_used_move(
r: ExternRef<MoveTurnChoiceDataImpl>, r: ExternRef<MoveTurnChoiceDataImpl>,
) -> ExternRef<LearnedMoveImpl>; ) -> WasmResult<ExternRef<LearnedMoveImpl>>;
fn turn_choice_move_target_side(r: ExternRef<MoveTurnChoiceDataImpl>) -> u8; fn turn_choice_move_target_side(r: ExternRef<MoveTurnChoiceDataImpl>) -> WasmResult<u8>;
fn turn_choice_move_target_index(r: ExternRef<MoveTurnChoiceDataImpl>) -> u8; fn turn_choice_move_target_index(r: ExternRef<MoveTurnChoiceDataImpl>) -> WasmResult<u8>;
fn turn_choice_move_priority(r: ExternRef<MoveTurnChoiceDataImpl>) -> i8; fn turn_choice_move_priority(r: ExternRef<MoveTurnChoiceDataImpl>) -> WasmResult<i8>;
#[allow(improper_ctypes)] #[allow(improper_ctypes)]
fn turn_choice_move_script(r: ExternRef<MoveTurnChoiceDataImpl>) -> *const Box<dyn Script>; fn turn_choice_move_script(r: ExternRef<MoveTurnChoiceDataImpl>) -> WasmResult<u32>;
} }
} }
use crate::PkmnResult;
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
pub use implementation::*; pub use implementation::*;

View File

@ -1,22 +1,26 @@
use crate::handling::Script; use crate::handling::Script;
use crate::PkmnResult;
use alloc::boxed::Box; use alloc::boxed::Box;
pub trait WithVolatile { pub trait WithVolatile {
fn has_volatile(&self, script_name: &str) -> bool; fn has_volatile(&self, script_name: &str) -> PkmnResult<bool>;
fn add_volatile(&self, script: Box<dyn Script>) -> &dyn Script; fn add_volatile(&self, script: Box<dyn Script>) -> PkmnResult<&dyn Script>;
fn add_volatile_by_name(&self, script_name: &str) -> &dyn Script; fn add_volatile_by_name(&self, script_name: &str) -> PkmnResult<&dyn Script>;
fn remove_volatile(&self, script: &dyn Script); fn remove_volatile(&self, script: &dyn Script) -> PkmnResult<()>;
fn get_volatile_script(&self, script_name: &str) -> Option<&dyn Script>; fn get_volatile_script(&self, script_name: &str) -> PkmnResult<Option<&dyn Script>>;
} }
pub fn get_volatile_as<'a, T>(v: &'a dyn WithVolatile, script_name: &str) -> Option<&'a T> pub fn get_volatile_as<'a, T>(
v: &'a dyn WithVolatile,
script_name: &str,
) -> PkmnResult<Option<&'a T>>
where where
T: Script + 'static, T: Script + 'static,
{ {
let s = v.get_volatile_script(script_name); let s = v.get_volatile_script(script_name)?;
if let Some(s) = s { if let Some(s) = s {
Some(s.as_any().downcast_ref::<T>().unwrap()) Ok(Some(s.as_any().downcast_ref::<T>().unwrap()))
} else { } else {
None Ok(None)
} }
} }

View File

@ -1,204 +0,0 @@
use alloc::rc::Rc;
pub trait ImmutableListTrait<T> {
fn get(&self, index: u32) -> Option<T>;
}
pub type ImmutableList<T> = Rc<dyn ImmutableListTrait<T>>;
#[cfg(not(feature = "mock_data"))]
mod implementation {
use super::*;
use crate::app_interface::{
BattleParty, BattlePartyImpl, BattleSide, BattleSideImpl, EffectParameter, StringKey,
};
use crate::handling::extern_ref::{ExternalReferenceType, VecExternRef};
use alloc::boxed::Box;
use alloc::vec::Vec;
use core::marker::PhantomData;
pub(crate) struct ImmutableListInner<T: Clone> {
extern_ref: VecExternRef<T>,
resource_type: PhantomData<T>,
values: spin::RwLock<Vec<Option<Option<Rc<T>>>>>,
}
pub(crate) trait ImmutableListWasm<T: Clone + ExternalReferenceType> {
fn initialize(inner: *const ImmutableListInner<T>) -> Self
where
Self: Sized;
fn new(extern_ref: VecExternRef<T>) -> Self
where
Self: Sized,
{
let mut values = Vec::new();
values.resize(extern_ref.len() as usize, None);
let inner = Box::new(ImmutableListInner {
extern_ref,
resource_type: Default::default(),
values: spin::RwLock::new(values),
});
let inner_ptr = Box::into_raw(inner);
Self::initialize(inner_ptr)
}
fn from_ref(extern_ref: VecExternRef<T>) -> Self
where
Self: Sized,
{
unsafe {
if let None = CACHE {
CACHE = Some(hashbrown::HashMap::new());
}
let existing = CACHE
.as_ref()
.unwrap()
.get(&extern_ref.get_internal_index());
if let Some(v) = existing {
let inner = *v as *const ImmutableListInner<T>;
Self::initialize(inner)
} else {
let v = Self::new(extern_ref);
CACHE.as_mut().unwrap().insert(
extern_ref.get_internal_index(),
v.get_inner_ptr() as *const u8,
);
v
}
}
}
fn get_inner(&self) -> &ImmutableListInner<T> {
unsafe { self.get_inner_ptr().as_ref().unwrap() }
}
fn get_inner_ptr(&self) -> *const ImmutableListInner<T>;
fn get_cached(&self, index: u32) -> Option<Rc<T>> {
let inner = self.get_inner();
let rg = inner.values.read();
let v = rg.get(index as usize).unwrap();
if let Some(v) = v {
return v.clone();
}
return None;
}
fn get_value(&self, index: u32) -> Option<Rc<T>> {
if let Some(cached) = self.get_cached(index) {
return Some(cached);
}
let inner = self.get_inner();
let r = inner.extern_ref.at(index);
let value = r.get_value();
let value = if let Some(value) = value {
Some(Rc::new(value))
} else {
None
};
let mut wg = inner.values.write();
wg[index as usize] = Some(value);
let v = wg[index as usize].as_ref().unwrap().clone();
v
}
}
macro_rules! immutable_list_type {
($type_name:ident, $underlying:ident) => {
paste::paste! {
pub struct [<$type_name ImmutableList>] {
inner: *const ImmutableListInner<$underlying>,
}
impl ImmutableListWasm<$underlying> for [<$type_name ImmutableList>] {
fn initialize(inner: *const ImmutableListInner<$underlying>) -> Self
where
Self: Sized,
{
Self { inner }
}
fn get_inner_ptr(&self) -> *const ImmutableListInner<$underlying> {
self.inner
}
}
impl ImmutableListTrait<$type_name> for [<$type_name ImmutableList>] {
fn get(&self, index: u32) -> Option<$type_name> {
let v = self.get_value(index);
if let Some(v) = v {
Some(v)
} else {
None
}
}
}
}
};
}
immutable_list_type!(BattleSide, BattleSideImpl);
immutable_list_type!(BattleParty, BattlePartyImpl);
pub struct EffectParameterImmutableList {
inner: *const ImmutableListInner<EffectParameter>,
}
impl ImmutableListWasm<EffectParameter> for EffectParameterImmutableList {
fn initialize(inner: *const ImmutableListInner<EffectParameter>) -> Self
where
Self: Sized,
{
Self { inner }
}
fn get_inner_ptr(&self) -> *const ImmutableListInner<EffectParameter> {
self.inner
}
}
impl ImmutableListTrait<Rc<EffectParameter>> for EffectParameterImmutableList {
fn get(&self, index: u32) -> Option<Rc<EffectParameter>> {
let v = self.get_value(index);
if let Some(v) = v {
Some(v)
} else {
None
}
}
}
#[derive(Clone)]
pub struct StringKeyImmutableList {
inner: *const ImmutableListInner<StringKey>,
}
impl ImmutableListWasm<StringKey> for StringKeyImmutableList {
fn initialize(inner: *const ImmutableListInner<StringKey>) -> Self
where
Self: Sized,
{
Self { inner }
}
fn get_inner_ptr(&self) -> *const ImmutableListInner<StringKey> {
self.inner
}
}
impl ImmutableListTrait<Rc<StringKey>> for StringKeyImmutableList {
fn get(&self, index: u32) -> Option<Rc<StringKey>> {
let v = self.get_value(index);
if let Some(v) = v {
Some(v)
} else {
None
}
}
}
static mut CACHE: Option<hashbrown::HashMap<u32, *const u8>> = None;
}
#[cfg(not(feature = "mock_data"))]
pub use implementation::*;

View File

@ -1,5 +1,4 @@
pub mod dynamic_data; pub mod dynamic_data;
pub mod list;
pub mod static_data; pub mod static_data;
pub mod string_key; pub mod string_key;

View File

@ -9,7 +9,7 @@ pub trait AbilityTrait {
pub type Ability = Rc<dyn AbilityTrait>; pub type Ability = Rc<dyn AbilityTrait>;
#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
#[repr(C)] #[repr(C)]
pub struct AbilityIndex { pub struct AbilityIndex {
pub hidden: bool, pub hidden: bool,
@ -19,21 +19,20 @@ pub struct AbilityIndex {
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
mod implementation { mod implementation {
use super::*; use super::*;
use crate::app_interface::list::{
EffectParameterImmutableList, ImmutableList, ImmutableListWasm,
};
use crate::app_interface::{EffectParameter, StringKey}; use crate::app_interface::{EffectParameter, StringKey};
use crate::handling::cached_value::CachedValue; use crate::handling::cached_value::CachedValue;
use crate::handling::extern_ref::{ExternRef, ExternalReferenceType, VecExternRef}; use crate::handling::extern_ref::{ExternRef, ExternalReferenceType};
use crate::handling::Cacheable; use crate::handling::ffi_array::FFIArray;
use crate::handling::{Cacheable, WasmResult};
use crate::{cached_value, cached_value_getters}; use crate::{cached_value, cached_value_getters};
use alloc::rc::Rc; use alloc::rc::Rc;
use alloc::vec::Vec;
struct AbilityInner { struct AbilityInner {
reference: ExternRef<AbilityImpl>, reference: ExternRef<AbilityImpl>,
name: CachedValue<StringKey>, name: CachedValue<StringKey>,
effect: CachedValue<StringKey>, effect: CachedValue<StringKey>,
parameters: CachedValue<ImmutableList<Rc<EffectParameter>>>, parameters: CachedValue<Vec<Rc<EffectParameter>>>,
} }
#[derive(Clone)] #[derive(Clone)]
@ -47,12 +46,21 @@ mod implementation {
Self::from_ref(reference, &|reference| Self { Self::from_ref(reference, &|reference| Self {
inner: Rc::new(AbilityInner { inner: Rc::new(AbilityInner {
reference, reference,
name: cached_value!({ ability_get_name(reference).get_value().unwrap() }), name: cached_value!({
effect: cached_value!({ ability_get_effect(reference).get_value().unwrap() }), ability_get_name(reference).unwrap().get_value().unwrap()
}),
effect: cached_value!({
ability_get_effect(reference).unwrap().get_value().unwrap()
}),
parameters: cached_value!({ parameters: cached_value!({
Rc::new(EffectParameterImmutableList::from_ref( let pars: FFIArray<ExternRef<EffectParameter>> =
ability_get_parameters(reference), FFIArray::from_u64(ability_get_parameters(reference).unwrap());
)) let pars = Vec::from_raw_parts(pars.ptr(), pars.len(), pars.len());
let pars = pars
.into_iter()
.map(|r| Rc::new(EffectParameter::new(r).unwrap()))
.collect::<Vec<_>>();
pars
}), }),
}), }),
}) })
@ -77,9 +85,9 @@ mod implementation {
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
extern "wasm" { extern "wasm" {
fn ability_get_name(r: ExternRef<AbilityImpl>) -> ExternRef<StringKey>; fn ability_get_name(r: ExternRef<AbilityImpl>) -> WasmResult<ExternRef<StringKey>>;
fn ability_get_effect(r: ExternRef<AbilityImpl>) -> ExternRef<StringKey>; fn ability_get_effect(r: ExternRef<AbilityImpl>) -> WasmResult<ExternRef<StringKey>>;
fn ability_get_parameters(r: ExternRef<AbilityImpl>) -> VecExternRef<EffectParameter>; fn ability_get_parameters(r: ExternRef<AbilityImpl>) -> WasmResult<u64>;
} }
} }

View File

@ -35,7 +35,7 @@ mod implementation {
use crate::app_interface::{get_hash, StringKey}; use crate::app_interface::{get_hash, StringKey};
use crate::handling::cached_value::CachedValue; use crate::handling::cached_value::CachedValue;
use crate::handling::extern_ref::{ExternRef, ExternalReferenceType}; use crate::handling::extern_ref::{ExternRef, ExternalReferenceType};
use crate::handling::Cacheable; use crate::handling::{Cacheable, WasmResult};
use crate::{cached_value, cached_value_getters}; use crate::{cached_value, cached_value_getters};
use spin::RwLock; use spin::RwLock;
@ -60,24 +60,41 @@ mod implementation {
inner: Rc::new(StaticDataInner { inner: Rc::new(StaticDataInner {
reference, reference,
move_library: cached_value!({ move_library: cached_value!({
Rc::new(static_data_get_move_library(reference).get_value().unwrap()) Rc::new(
static_data_get_move_library(reference)
.unwrap()
.get_value()
.unwrap(),
)
}), }),
item_library: cached_value!({ item_library: cached_value!({
Rc::new(static_data_get_item_library(reference).get_value().unwrap()) Rc::new(
static_data_get_item_library(reference)
.unwrap()
.get_value()
.unwrap(),
)
}), }),
species_library: cached_value!({ species_library: cached_value!({
Rc::new( Rc::new(
static_data_get_species_library(reference) static_data_get_species_library(reference)
.unwrap()
.get_value() .get_value()
.unwrap(), .unwrap(),
) )
}), }),
type_library: cached_value!({ type_library: cached_value!({
Rc::new(static_data_get_type_library(reference).get_value().unwrap()) Rc::new(
static_data_get_type_library(reference)
.unwrap()
.get_value()
.unwrap(),
)
}), }),
settings: cached_value!({ settings: cached_value!({
Rc::new( Rc::new(
static_data_get_library_settings(reference) static_data_get_library_settings(reference)
.unwrap()
.get_value() .get_value()
.unwrap(), .unwrap(),
) )
@ -119,7 +136,9 @@ mod implementation {
pub(crate) fn new(ptr: ExternRef<LibrarySettingsImpl>) -> Self { pub(crate) fn new(ptr: ExternRef<LibrarySettingsImpl>) -> Self {
Self { Self {
inner: Rc::new(LibrarySettingsInner { inner: Rc::new(LibrarySettingsInner {
maximum_level: cached_value!({ library_settings_get_maximum_level(ptr) }), maximum_level: cached_value!({
library_settings_get_maximum_level(ptr).unwrap()
}),
}), }),
} }
} }
@ -142,21 +161,23 @@ mod implementation {
extern "wasm" { extern "wasm" {
fn static_data_get_move_library( fn static_data_get_move_library(
ptr: ExternRef<StaticDataImpl>, ptr: ExternRef<StaticDataImpl>,
) -> ExternRef<MoveLibraryImpl>; ) -> WasmResult<ExternRef<MoveLibraryImpl>>;
fn static_data_get_item_library( fn static_data_get_item_library(
ptr: ExternRef<StaticDataImpl>, ptr: ExternRef<StaticDataImpl>,
) -> ExternRef<ItemLibraryImpl>; ) -> WasmResult<ExternRef<ItemLibraryImpl>>;
fn static_data_get_species_library( fn static_data_get_species_library(
ptr: ExternRef<StaticDataImpl>, ptr: ExternRef<StaticDataImpl>,
) -> ExternRef<SpeciesLibraryImpl>; ) -> WasmResult<ExternRef<SpeciesLibraryImpl>>;
fn static_data_get_type_library( fn static_data_get_type_library(
ptr: ExternRef<StaticDataImpl>, ptr: ExternRef<StaticDataImpl>,
) -> ExternRef<TypeLibraryImpl>; ) -> WasmResult<ExternRef<TypeLibraryImpl>>;
fn static_data_get_library_settings( fn static_data_get_library_settings(
ptr: ExternRef<StaticDataImpl>, ptr: ExternRef<StaticDataImpl>,
) -> ExternRef<LibrarySettingsImpl>; ) -> WasmResult<ExternRef<LibrarySettingsImpl>>;
fn library_settings_get_maximum_level(ptr: ExternRef<LibrarySettingsImpl>) -> LevelInt; fn library_settings_get_maximum_level(
ptr: ExternRef<LibrarySettingsImpl>,
) -> WasmResult<LevelInt>;
} }
pub trait DataLibrary<T>: Cacheable pub trait DataLibrary<T>: Cacheable
@ -182,14 +203,16 @@ mod implementation {
where where
Self: Sized, Self: Sized,
{ {
if let Some(v) = self.get_cache().read().get(&name.hash()) { if let Some(v) = self.get_cache().read().get(&name.hash().unwrap()) {
return Some(v.clone()); return Some(v.clone());
} }
let index = Self::_get_ref_by_name(self.get_self_ref(), name.ptr()); let index = Self::_get_ref_by_name(self.get_self_ref(), name.ptr());
let v = Self::_from_external_ref_index(index); let v = Self::_from_external_ref_index(index);
if let Some(v) = &v { if let Some(v) = &v {
self.get_cache().write().insert(name.hash(), v.clone()); self.get_cache()
.write()
.insert(name.hash().unwrap(), v.clone());
} }
v v
} }
@ -242,7 +265,7 @@ mod mocked {
where where
Self: Sized, Self: Sized,
{ {
self.get_cache().read().get(&name.hash()).cloned() self.get_cache().read().get(&name.hash().unwrap()).cloned()
} }
fn get_by_hash(&self, hash: u32) -> Option<T> fn get_by_hash(&self, hash: u32) -> Option<T>

View File

@ -2,17 +2,17 @@ use crate::app_interface::TypeIdentifier;
use alloc::rc::Rc; use alloc::rc::Rc;
pub trait TypeLibraryTrait { pub trait TypeLibraryTrait {
fn get_type_from_name(&self, name: &str) -> Option<TypeIdentifier>; fn get_type_from_name(&self, name: &str) -> PkmnResult<Option<TypeIdentifier>>;
fn get_single_effectiveness( fn get_single_effectiveness(
&self, &self,
attacking_type: TypeIdentifier, attacking_type: TypeIdentifier,
defending_type: TypeIdentifier, defending_type: TypeIdentifier,
) -> f32; ) -> PkmnResult<f32>;
fn get_effectiveness( fn get_effectiveness(
&self, &self,
attacking_type: TypeIdentifier, attacking_type: TypeIdentifier,
defending_types: &[TypeIdentifier], defending_types: &[TypeIdentifier],
) -> f32; ) -> PkmnResult<f32>;
} }
pub type Typelibrary = Rc<dyn TypeLibraryTrait>; pub type Typelibrary = Rc<dyn TypeLibraryTrait>;
@ -21,6 +21,8 @@ pub type Typelibrary = Rc<dyn TypeLibraryTrait>;
mod implementation { mod implementation {
use super::*; use super::*;
use crate::handling::extern_ref::{ExternRef, ExternalReferenceType}; use crate::handling::extern_ref::{ExternRef, ExternalReferenceType};
use crate::handling::WasmResult;
use crate::PkmnResult;
use alloc::rc::Rc; use alloc::rc::Rc;
use alloc::string::{String, ToString}; use alloc::string::{String, ToString};
use cstr_core::{c_char, CString}; use cstr_core::{c_char, CString};
@ -51,35 +53,37 @@ mod implementation {
} }
impl TypeLibraryTrait for TypeLibraryImpl { impl TypeLibraryTrait for TypeLibraryImpl {
fn get_type_from_name(&self, name: &str) -> Option<TypeIdentifier> { fn get_type_from_name(&self, name: &str) -> PkmnResult<Option<TypeIdentifier>> {
if let Some(cached) = self.inner.name_to_type_cache.read().get(name) { if let Some(cached) = self.inner.name_to_type_cache.read().get(name) {
return Some(*cached); return Ok(Some(*cached));
} }
let cstr = CString::new(name).unwrap(); let cstr = CString::new(name).unwrap();
let v = unsafe { type_library_get_type_by_name(self.inner.reference, cstr.as_ptr()) }; let v = unsafe {
type_library_get_type_by_name(self.inner.reference, cstr.as_ptr()).as_res()?
};
if v == 255 { if v == 255 {
return None; return Ok(None);
} }
let v = v.into(); let v = v.into();
self.inner self.inner
.name_to_type_cache .name_to_type_cache
.write() .write()
.insert(name.to_string(), v); .insert(name.to_string(), v);
Some(v) Ok(Some(v))
} }
fn get_single_effectiveness( fn get_single_effectiveness(
&self, &self,
attacking_type: TypeIdentifier, attacking_type: TypeIdentifier,
defending_type: TypeIdentifier, defending_type: TypeIdentifier,
) -> f32 { ) -> PkmnResult<f32> {
if let Some(cached) = self if let Some(cached) = self
.inner .inner
.effectiveness_cache .effectiveness_cache
.read() .read()
.get(&(attacking_type, defending_type)) .get(&(attacking_type, defending_type))
{ {
return *cached; return Ok(*cached);
} }
let effectiveness = unsafe { let effectiveness = unsafe {
type_library_get_single_effectiveness( type_library_get_single_effectiveness(
@ -87,24 +91,25 @@ mod implementation {
attacking_type.into(), attacking_type.into(),
defending_type.into(), defending_type.into(),
) )
}; }
.as_res()?;
self.inner self.inner
.effectiveness_cache .effectiveness_cache
.write() .write()
.insert((attacking_type, defending_type), effectiveness); .insert((attacking_type, defending_type), effectiveness);
effectiveness Ok(effectiveness)
} }
fn get_effectiveness( fn get_effectiveness(
&self, &self,
attacking_type: TypeIdentifier, attacking_type: TypeIdentifier,
defending_types: &[TypeIdentifier], defending_types: &[TypeIdentifier],
) -> f32 { ) -> PkmnResult<f32> {
let mut f = 1.0; let mut f = 1.0;
for defending_type in defending_types { for defending_type in defending_types {
f *= self.get_single_effectiveness(attacking_type, *defending_type); f *= self.get_single_effectiveness(attacking_type, *defending_type)?;
} }
f Ok(f)
} }
} }
@ -123,10 +128,14 @@ mod implementation {
r: ExternRef<TypeLibraryImpl>, r: ExternRef<TypeLibraryImpl>,
attacking_type: u8, attacking_type: u8,
defending_type: u8, defending_type: u8,
) -> f32; ) -> WasmResult<f32>;
fn type_library_get_type_by_name(r: ExternRef<TypeLibraryImpl>, name: *const c_char) -> u8; fn type_library_get_type_by_name(
r: ExternRef<TypeLibraryImpl>,
name: *const c_char,
) -> WasmResult<u8>;
} }
} }
use crate::PkmnResult;
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
pub use implementation::*; pub use implementation::*;

View File

@ -1,9 +1,10 @@
use crate::app_interface::StringKey; use crate::app_interface::StringKey;
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
use crate::{ExternRef, ExternalReferenceType}; use crate::{handling::WasmResult, ExternRef, ExternalReferenceType, PkmnResult};
use core::fmt::{Display, Formatter}; use core::fmt::{Display, Formatter};
#[repr(u8)] #[repr(u8)]
#[derive(Copy, Clone)]
enum EffectParameterType { enum EffectParameterType {
None, None,
Bool, Bool,
@ -12,6 +13,12 @@ enum EffectParameterType {
String, String,
} }
impl Default for EffectParameterType {
fn default() -> Self {
Self::None
}
}
#[derive(Clone)] #[derive(Clone)]
pub enum EffectParameter { pub enum EffectParameter {
None, None,
@ -23,18 +30,18 @@ pub enum EffectParameter {
impl EffectParameter { impl EffectParameter {
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
pub(crate) fn new(ptr: ExternRef<Self>) -> Self { pub(crate) fn new(ptr: ExternRef<Self>) -> PkmnResult<Self> {
unsafe { Ok(unsafe {
match effect_parameter_get_type(ptr) { match effect_parameter_get_type(ptr).as_res()? {
EffectParameterType::None => Self::None, EffectParameterType::None => Self::None,
EffectParameterType::Bool => Self::Bool(effect_parameter_as_bool(ptr)), EffectParameterType::Bool => Self::Bool(effect_parameter_as_bool(ptr).as_res()?),
EffectParameterType::Int => Self::Int(effect_parameter_as_int(ptr)), EffectParameterType::Int => Self::Int(effect_parameter_as_int(ptr).as_res()?),
EffectParameterType::Float => Self::Float(effect_parameter_as_float(ptr)), EffectParameterType::Float => Self::Float(effect_parameter_as_float(ptr).as_res()?),
EffectParameterType::String => { EffectParameterType::String => {
Self::String(StringKey::new(effect_parameter_as_string(ptr))) Self::String(StringKey::new(effect_parameter_as_string(ptr).as_res()?))
} }
} }
} })
} }
pub fn as_bool(&self) -> bool { pub fn as_bool(&self) -> bool {
@ -72,7 +79,7 @@ impl ExternalReferenceType for EffectParameter {
where where
Self: Sized, Self: Sized,
{ {
EffectParameter::new(reference) EffectParameter::new(reference).unwrap()
} }
} }
@ -92,9 +99,13 @@ impl Display for EffectParameter {
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
extern "wasm" { extern "wasm" {
fn effect_parameter_get_type(ptr: ExternRef<EffectParameter>) -> EffectParameterType; fn effect_parameter_get_type(
fn effect_parameter_as_bool(ptr: ExternRef<EffectParameter>) -> bool; ptr: ExternRef<EffectParameter>,
fn effect_parameter_as_int(ptr: ExternRef<EffectParameter>) -> i64; ) -> WasmResult<EffectParameterType>;
fn effect_parameter_as_float(ptr: ExternRef<EffectParameter>) -> f32; fn effect_parameter_as_bool(ptr: ExternRef<EffectParameter>) -> WasmResult<bool>;
fn effect_parameter_as_string(ptr: ExternRef<EffectParameter>) -> ExternRef<StringKey>; fn effect_parameter_as_int(ptr: ExternRef<EffectParameter>) -> WasmResult<i64>;
fn effect_parameter_as_float(ptr: ExternRef<EffectParameter>) -> WasmResult<f32>;
fn effect_parameter_as_string(
ptr: ExternRef<EffectParameter>,
) -> WasmResult<ExternRef<StringKey>>;
} }

View File

@ -23,6 +23,12 @@ pub enum ItemCategory {
Mail, Mail,
} }
impl Default for ItemCategory {
fn default() -> Self {
Self::MiscItem
}
}
/// A battle item category defines how the item is categorized when in battle. /// A battle item category defines how the item is categorized when in battle.
#[repr(u8)] #[repr(u8)]
#[derive(Clone)] #[derive(Clone)]
@ -39,6 +45,12 @@ pub enum BattleItemCategory {
MiscBattleItem, MiscBattleItem,
} }
impl Default for BattleItemCategory {
fn default() -> Self {
Self::None
}
}
#[cfg_attr(feature = "mock_data", mockall::automock)] #[cfg_attr(feature = "mock_data", mockall::automock)]
pub trait ItemTrait { pub trait ItemTrait {
fn reference(&self) -> u32; fn reference(&self) -> u32;
@ -50,7 +62,7 @@ pub trait ItemTrait {
fn battle_category(&self) -> BattleItemCategory; fn battle_category(&self) -> BattleItemCategory;
/// The buying value of the item. /// The buying value of the item.
fn price(&self) -> i32; fn price(&self) -> i32;
fn has_flag(&self, flag: &StringKey) -> bool; fn has_flag(&self, flag: &StringKey) -> PkmnResult<bool>;
} }
pub type Item = Rc<dyn ItemTrait>; pub type Item = Rc<dyn ItemTrait>;
@ -62,8 +74,8 @@ mod implementation {
use crate::app_interface::{BattleItemCategory, ItemCategory, ItemTrait, StringKey}; use crate::app_interface::{BattleItemCategory, ItemCategory, ItemTrait, StringKey};
use crate::handling::cached_value::CachedValue; use crate::handling::cached_value::CachedValue;
use crate::handling::extern_ref::{ExternRef, ExternalReferenceType}; use crate::handling::extern_ref::{ExternRef, ExternalReferenceType};
use crate::handling::Cacheable; use crate::handling::{Cacheable, WasmResult};
use crate::{cached_value, cached_value_getters}; use crate::{cached_value, cached_value_getters, PkmnResult};
use alloc::rc::Rc; use alloc::rc::Rc;
struct ItemInner { struct ItemInner {
@ -86,10 +98,12 @@ mod implementation {
Self::from_ref(reference, &|reference| Self { Self::from_ref(reference, &|reference| Self {
inner: Rc::new(ItemInner { inner: Rc::new(ItemInner {
reference, reference,
name: cached_value!({ StringKey::new(item_get_name(reference)) }), name: cached_value!({ StringKey::new(item_get_name(reference).unwrap()) }),
category: cached_value!({ item_get_category(reference) }), category: cached_value!({ item_get_category(reference).unwrap() }),
battle_category: cached_value!({ item_get_battle_category(reference) }), battle_category: cached_value!({
price: cached_value!({ item_get_price(reference) }), item_get_battle_category(reference).unwrap()
}),
price: cached_value!({ item_get_price(reference).unwrap() }),
}), }),
}) })
} }
@ -116,8 +130,8 @@ mod implementation {
fn price(&self) -> i32; fn price(&self) -> i32;
} }
fn has_flag(&self, flag: &StringKey) -> bool { fn has_flag(&self, flag: &StringKey) -> PkmnResult<bool> {
unsafe { item_has_flag(self.inner.reference, flag.ptr()) } unsafe { item_has_flag(self.inner.reference, flag.ptr()).as_res() }
} }
} }
@ -131,13 +145,14 @@ mod implementation {
} }
extern "wasm" { extern "wasm" {
fn item_get_name(ptr: ExternRef<ItemImpl>) -> ExternRef<StringKey>; fn item_get_name(ptr: ExternRef<ItemImpl>) -> WasmResult<ExternRef<StringKey>>;
fn item_get_category(ptr: ExternRef<ItemImpl>) -> ItemCategory; fn item_get_category(ptr: ExternRef<ItemImpl>) -> WasmResult<ItemCategory>;
fn item_get_battle_category(ptr: ExternRef<ItemImpl>) -> BattleItemCategory; fn item_get_battle_category(ptr: ExternRef<ItemImpl>) -> WasmResult<BattleItemCategory>;
fn item_get_price(ptr: ExternRef<ItemImpl>) -> i32; fn item_get_price(ptr: ExternRef<ItemImpl>) -> WasmResult<i32>;
fn item_has_flag(ptr: ExternRef<ItemImpl>, flag: ExternRef<StringKey>) -> bool; fn item_has_flag(ptr: ExternRef<ItemImpl>, flag: ExternRef<StringKey>) -> WasmResult<bool>;
} }
} }
use crate::PkmnResult;
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
pub use implementation::*; pub use implementation::*;

View File

@ -9,6 +9,12 @@ pub enum MoveCategory {
Status = 2, Status = 2,
} }
impl Default for MoveCategory {
fn default() -> Self {
Self::Physical
}
}
#[repr(u8)] #[repr(u8)]
#[derive(Clone, Eq, PartialEq)] #[derive(Clone, Eq, PartialEq)]
pub enum MoveTarget { pub enum MoveTarget {
@ -29,6 +35,12 @@ pub enum MoveTarget {
OnSelf, OnSelf,
} }
impl Default for MoveTarget {
fn default() -> Self {
Self::Adjacent
}
}
#[cfg_attr(feature = "mock_data", mockall::automock)] #[cfg_attr(feature = "mock_data", mockall::automock)]
pub trait MoveDataTrait { pub trait MoveDataTrait {
fn name(&self) -> StringKey; fn name(&self) -> StringKey;
@ -39,7 +51,7 @@ pub trait MoveDataTrait {
fn base_usages(&self) -> u8; fn base_usages(&self) -> u8;
fn target(&self) -> MoveTarget; fn target(&self) -> MoveTarget;
fn priority(&self) -> i8; fn priority(&self) -> i8;
fn has_flag(&self, flag: &str) -> bool; fn has_flag(&self, flag: &str) -> PkmnResult<bool>;
} }
pub type MoveData = Rc<dyn MoveDataTrait>; pub type MoveData = Rc<dyn MoveDataTrait>;
@ -52,8 +64,8 @@ mod implementation {
use crate::app_interface::get_hash; use crate::app_interface::get_hash;
use crate::handling::cached_value::CachedValue; use crate::handling::cached_value::CachedValue;
use crate::handling::extern_ref::{ExternRef, ExternalReferenceType}; use crate::handling::extern_ref::{ExternRef, ExternalReferenceType};
use crate::handling::Cacheable; use crate::handling::{Cacheable, WasmResult};
use crate::{cached_value, cached_value_getters}; use crate::{cached_value, cached_value_getters, PkmnResult};
struct MoveDataInner { struct MoveDataInner {
ptr: ExternRef<MoveDataImpl>, ptr: ExternRef<MoveDataImpl>,
@ -77,14 +89,14 @@ mod implementation {
MoveDataImpl::from_ref(ptr, &|ptr| Self { MoveDataImpl::from_ref(ptr, &|ptr| Self {
inner: Rc::new(MoveDataInner { inner: Rc::new(MoveDataInner {
ptr, ptr,
name: cached_value!({ StringKey::new(move_data_get_name(ptr)) }), name: cached_value!({ StringKey::new(move_data_get_name(ptr).unwrap()) }),
move_type: cached_value!({ move_data_get_type(ptr) }), move_type: cached_value!({ move_data_get_type(ptr).unwrap() }),
category: cached_value!({ move_data_get_category(ptr) }), category: cached_value!({ move_data_get_category(ptr).unwrap() }),
base_power: cached_value!({ move_data_get_base_power(ptr) }), base_power: cached_value!({ move_data_get_base_power(ptr).unwrap() }),
accuracy: cached_value!({ move_data_get_accuracy(ptr) }), accuracy: cached_value!({ move_data_get_accuracy(ptr).unwrap() }),
base_usages: cached_value!({ move_data_get_base_power(ptr) }), base_usages: cached_value!({ move_data_get_base_power(ptr).unwrap() }),
target: cached_value!({ move_data_get_target(ptr) }), target: cached_value!({ move_data_get_target(ptr).unwrap() }),
priority: cached_value!({ move_data_get_priority(ptr) }), priority: cached_value!({ move_data_get_priority(ptr).unwrap() }),
}), }),
}) })
} }
@ -102,9 +114,9 @@ mod implementation {
fn priority(&self) -> i8; fn priority(&self) -> i8;
} }
fn has_flag(&self, flag: &str) -> bool { fn has_flag(&self, flag: &str) -> PkmnResult<bool> {
let hash = get_hash(flag); let hash = get_hash(flag);
unsafe { move_data_has_flag_by_hash(self.inner.ptr, hash) } unsafe { move_data_has_flag_by_hash(self.inner.ptr, hash).as_res() }
} }
} }
@ -117,17 +129,21 @@ mod implementation {
crate::handling::cacheable::cacheable!(MoveDataImpl); crate::handling::cacheable::cacheable!(MoveDataImpl);
extern "wasm" { extern "wasm" {
fn move_data_get_name(ptr: ExternRef<MoveDataImpl>) -> ExternRef<StringKey>; fn move_data_get_name(ptr: ExternRef<MoveDataImpl>) -> WasmResult<ExternRef<StringKey>>;
fn move_data_get_type(ptr: ExternRef<MoveDataImpl>) -> u8; fn move_data_get_type(ptr: ExternRef<MoveDataImpl>) -> WasmResult<u8>;
fn move_data_get_category(ptr: ExternRef<MoveDataImpl>) -> MoveCategory; fn move_data_get_category(ptr: ExternRef<MoveDataImpl>) -> WasmResult<MoveCategory>;
fn move_data_get_base_power(ptr: ExternRef<MoveDataImpl>) -> u8; fn move_data_get_base_power(ptr: ExternRef<MoveDataImpl>) -> WasmResult<u8>;
fn move_data_get_accuracy(ptr: ExternRef<MoveDataImpl>) -> u8; fn move_data_get_accuracy(ptr: ExternRef<MoveDataImpl>) -> WasmResult<u8>;
fn move_data_get_base_usages(ptr: ExternRef<MoveDataImpl>) -> u8; fn move_data_get_base_usages(ptr: ExternRef<MoveDataImpl>) -> WasmResult<u8>;
fn move_data_get_target(ptr: ExternRef<MoveDataImpl>) -> MoveTarget; fn move_data_get_target(ptr: ExternRef<MoveDataImpl>) -> WasmResult<MoveTarget>;
fn move_data_get_priority(ptr: ExternRef<MoveDataImpl>) -> i8; fn move_data_get_priority(ptr: ExternRef<MoveDataImpl>) -> WasmResult<i8>;
fn move_data_has_flag_by_hash(ptr: ExternRef<MoveDataImpl>, flag_hash: u32) -> bool; fn move_data_has_flag_by_hash(
ptr: ExternRef<MoveDataImpl>,
flag_hash: u32,
) -> WasmResult<bool>;
} }
} }
use crate::PkmnResult;
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
pub use implementation::*; pub use implementation::*;

View File

@ -14,7 +14,7 @@ pub type Nature = Rc<dyn NatureTrait>;
mod implementation { mod implementation {
use super::*; use super::*;
use crate::handling::extern_ref::{ExternRef, ExternalReferenceType}; use crate::handling::extern_ref::{ExternRef, ExternalReferenceType};
use crate::handling::Cacheable; use crate::handling::{Cacheable, WasmResult};
struct NatureInner { struct NatureInner {
reference: ExternRef<NatureImpl>, reference: ExternRef<NatureImpl>,
@ -41,10 +41,10 @@ mod implementation {
Self { Self {
inner: Rc::new(NatureInner { inner: Rc::new(NatureInner {
reference, reference,
increase_stat: nature_get_increase_stat(reference), increase_stat: nature_get_increase_stat(reference).unwrap(),
decrease_stat: nature_get_decrease_stat(reference), decrease_stat: nature_get_decrease_stat(reference).unwrap(),
increase_modifier: nature_get_increase_modifier(reference), increase_modifier: nature_get_increase_modifier(reference).unwrap(),
decrease_modifier: nature_get_decrease_modifier(reference), decrease_modifier: nature_get_decrease_modifier(reference).unwrap(),
}), }),
} }
}) })
@ -76,10 +76,10 @@ mod implementation {
} }
extern "wasm" { extern "wasm" {
fn nature_get_increase_stat(r: ExternRef<NatureImpl>) -> Statistic; fn nature_get_increase_stat(r: ExternRef<NatureImpl>) -> WasmResult<Statistic>;
fn nature_get_decrease_stat(r: ExternRef<NatureImpl>) -> Statistic; fn nature_get_decrease_stat(r: ExternRef<NatureImpl>) -> WasmResult<Statistic>;
fn nature_get_increase_modifier(r: ExternRef<NatureImpl>) -> f32; fn nature_get_increase_modifier(r: ExternRef<NatureImpl>) -> WasmResult<f32>;
fn nature_get_decrease_modifier(r: ExternRef<NatureImpl>) -> f32; fn nature_get_decrease_modifier(r: ExternRef<NatureImpl>) -> WasmResult<f32>;
} }
} }

View File

@ -1,27 +1,32 @@
use crate::app_interface::list::ImmutableList;
use crate::app_interface::{ImmutableStatisticSet, StringKey}; use crate::app_interface::{ImmutableStatisticSet, StringKey};
use alloc::rc::Rc; use alloc::rc::Rc;
use alloc::vec::Vec; use alloc::vec::Vec;
use core::any::Any; use core::any::Any;
#[repr(u8)] #[repr(u8)]
#[derive(Eq, PartialEq, Debug)] #[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub enum Gender { pub enum Gender {
Male = 0, Male = 0,
Female = 1, Female = 1,
Genderless = 2, Genderless = 2,
} }
impl Default for Gender {
fn default() -> Self {
Self::Genderless
}
}
pub trait FormTrait { pub trait FormTrait {
fn name(&self) -> StringKey; fn name(&self) -> StringKey;
fn height(&self) -> f32; fn height(&self) -> f32;
fn weight(&self) -> f32; fn weight(&self) -> f32;
fn base_experience(&self) -> u32; fn base_experience(&self) -> u32;
fn base_stats(&self) -> ImmutableStatisticSet; fn base_stats(&self) -> ImmutableStatisticSet;
fn abilities(&self) -> ImmutableList<Rc<StringKey>>; fn abilities(&self) -> Vec<Rc<StringKey>>;
fn hidden_abilities(&self) -> ImmutableList<Rc<StringKey>>; fn hidden_abilities(&self) -> Vec<Rc<StringKey>>;
fn types(&self) -> &Vec<u8>; fn types(&self) -> &Vec<u8>;
fn has_flag(&self, flag: &str) -> bool; fn has_flag(&self, flag: &str) -> PkmnResult<bool>;
fn as_any(&self) -> &dyn Any; fn as_any(&self) -> &dyn Any;
} }
@ -39,7 +44,7 @@ pub trait SpeciesTrait {
/// uncatchable. /// uncatchable.
fn capture_rate(&self) -> u8; fn capture_rate(&self) -> u8;
fn get_form(&self, form_name: &str) -> Option<Form>; fn get_form(&self, form_name: &str) -> Option<Form>;
fn has_flag(&self, flag: &str) -> bool; fn has_flag(&self, flag: &str) -> PkmnResult<bool>;
fn as_any(&self) -> &dyn Any; fn as_any(&self) -> &dyn Any;
} }
@ -50,13 +55,13 @@ pub type Species = Rc<dyn SpeciesTrait>;
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
mod implementation { mod implementation {
use super::*; use super::*;
use crate::app_interface::list::ImmutableListWasm;
use crate::app_interface::{get_hash, ImmutableStatisticSetImpl}; use crate::app_interface::{get_hash, ImmutableStatisticSetImpl};
use crate::handling::cached_value::CachedValue; use crate::handling::cached_value::CachedValue;
use crate::handling::extern_ref::{ExternRef, ExternalReferenceType, VecExternRef}; use crate::handling::extern_ref::{ExternRef, ExternalReferenceType};
use crate::handling::ffi_array::FFIArray; use crate::handling::ffi_array::FFIArray;
use crate::handling::wasm_result::WasmResult;
use crate::handling::Cacheable; use crate::handling::Cacheable;
use crate::{cached_value, cached_value_getters}; use crate::{cached_value, cached_value_getters, PkmnResult};
use spin::RwLock; use spin::RwLock;
struct FormInner { struct FormInner {
@ -67,8 +72,8 @@ mod implementation {
types: CachedValue<Vec<u8>>, types: CachedValue<Vec<u8>>,
base_experience: CachedValue<u32>, base_experience: CachedValue<u32>,
base_stats: CachedValue<ImmutableStatisticSet>, base_stats: CachedValue<ImmutableStatisticSet>,
abilities: CachedValue<ImmutableList<Rc<StringKey>>>, abilities: CachedValue<Vec<Rc<StringKey>>>,
hidden_abilities: CachedValue<ImmutableList<Rc<StringKey>>>, hidden_abilities: CachedValue<Vec<Rc<StringKey>>>,
// moves: CachedValue<LearnableMoves>, // moves: CachedValue<LearnableMoves>,
} }
@ -82,30 +87,38 @@ mod implementation {
Self::from_ref(reference, &|reference| Self { Self::from_ref(reference, &|reference| Self {
inner: Rc::new(FormInner { inner: Rc::new(FormInner {
reference, reference,
name: cached_value!({ form_get_name(reference).get_value().unwrap() }), name: cached_value!({ form_get_name(reference).unwrap().get_value().unwrap() }),
height: cached_value!({ form_get_height(reference) }), height: cached_value!({ form_get_height(reference).unwrap() }),
weight: cached_value!({ form_get_weight(reference) }), weight: cached_value!({ form_get_weight(reference).unwrap() }),
types: cached_value!({ types: cached_value!({
let raw = form_get_types(reference); let raw = FFIArray::from_u64(form_get_types(reference).unwrap());
Vec::from_raw_parts(raw.ptr(), raw.len(), raw.len()) Vec::from_raw_parts(raw.ptr(), raw.len(), raw.len())
}), }),
base_experience: cached_value!({ form_get_base_experience(reference) }), base_experience: cached_value!({
form_get_base_experience(reference).unwrap()
}),
base_stats: cached_value!({ base_stats: cached_value!({
Rc::new(form_get_base_stats(reference).get_value().unwrap()) Rc::new(form_get_base_stats(reference).unwrap().get_value().unwrap())
}), }),
abilities: cached_value!({ abilities: cached_value!({
Rc::new( let abilities: FFIArray<ExternRef<StringKey>> =
crate::app_interface::list::StringKeyImmutableList::from_ref( FFIArray::from_u64(form_get_abilities(reference).unwrap());
form_get_abilities(reference), let abilities =
), Vec::from_raw_parts(abilities.ptr(), abilities.len(), abilities.len());
) abilities
.into_iter()
.map::<Rc<StringKey>, _>(|r| Rc::new(StringKey::new(r)))
.collect()
}), }),
hidden_abilities: cached_value!({ hidden_abilities: cached_value!({
Rc::new( let abilities: FFIArray<ExternRef<StringKey>> =
crate::app_interface::list::StringKeyImmutableList::from_ref( FFIArray::from_u64(form_get_hidden_abilities(reference).unwrap());
form_get_hidden_abilities(reference), let abilities =
), Vec::from_raw_parts(abilities.ptr(), abilities.len(), abilities.len());
) abilities
.into_iter()
.map::<Rc<StringKey>, _>(|r| Rc::new(StringKey::new(r)))
.collect()
}), }),
}), }),
}) })
@ -123,16 +136,16 @@ mod implementation {
fn weight(&self) -> f32; fn weight(&self) -> f32;
fn base_experience(&self) -> u32; fn base_experience(&self) -> u32;
fn base_stats(&self) -> ImmutableStatisticSet; fn base_stats(&self) -> ImmutableStatisticSet;
fn abilities(&self) -> ImmutableList<Rc<StringKey>>; fn abilities(&self) -> Vec<Rc<StringKey>>;
fn hidden_abilities(&self) -> ImmutableList<Rc<StringKey>>; fn hidden_abilities(&self) -> Vec<Rc<StringKey>>;
} }
fn types(&self) -> &Vec<u8> { fn types(&self) -> &Vec<u8> {
self.inner.types.value_ref() self.inner.types.value_ref()
} }
fn has_flag(&self, flag: &str) -> bool { fn has_flag(&self, flag: &str) -> PkmnResult<bool> {
let hash = get_hash(flag); let hash = get_hash(flag);
unsafe { form_has_flag_by_hash(self.inner.reference, hash) } unsafe { form_has_flag_by_hash(self.inner.reference, hash).as_res() }
} }
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
@ -160,13 +173,18 @@ mod implementation {
Self { Self {
inner: Rc::new(SpeciesInner { inner: Rc::new(SpeciesInner {
reference, reference,
id: cached_value!({ species_get_id(reference) }), id: cached_value!({ species_get_id(reference).unwrap() }),
name: cached_value!({ species_get_name(reference).get_value().unwrap() }), name: cached_value!({
gender_rate: cached_value!({ species_get_gender_rate(reference) }), species_get_name(reference).unwrap().get_value().unwrap()
growth_rate: cached_value!({
species_get_growth_rate(reference).get_value().unwrap()
}), }),
capture_rate: cached_value!({ species_get_capture_rate(reference) }), gender_rate: cached_value!({ species_get_gender_rate(reference).unwrap() }),
growth_rate: cached_value!({
species_get_growth_rate(reference)
.unwrap()
.get_value()
.unwrap()
}),
capture_rate: cached_value!({ species_get_capture_rate(reference).unwrap() }),
forms: Default::default(), forms: Default::default(),
}), }),
} }
@ -198,7 +216,7 @@ mod implementation {
if let Some(v) = self.inner.forms.read().get(&hash) { if let Some(v) = self.inner.forms.read().get(&hash) {
v.clone() v.clone()
} else { } else {
let r = species_get_form_by_hash(self.inner.reference, hash); let r = species_get_form_by_hash(self.inner.reference, hash).unwrap();
let value = r.get_value(); let value = r.get_value();
let value: Option<Form> = if let Some(value) = value { let value: Option<Form> = if let Some(value) = value {
Some(Rc::new(value)) Some(Rc::new(value))
@ -211,9 +229,9 @@ mod implementation {
} }
} }
fn has_flag(&self, flag: &str) -> bool { fn has_flag(&self, flag: &str) -> PkmnResult<bool> {
let hash = get_hash(flag); let hash = get_hash(flag);
unsafe { species_has_flag_by_hash(self.inner.reference, hash) } unsafe { species_has_flag_by_hash(self.inner.reference, hash).as_res() }
} }
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
@ -237,25 +255,31 @@ mod implementation {
crate::handling::cacheable::cacheable!(SpeciesImpl); crate::handling::cacheable::cacheable!(SpeciesImpl);
extern "wasm" { extern "wasm" {
fn form_get_name(r: ExternRef<FormImpl>) -> ExternRef<StringKey>; fn form_get_name(r: ExternRef<FormImpl>) -> WasmResult<ExternRef<StringKey>>;
fn form_get_height(r: ExternRef<FormImpl>) -> f32; fn form_get_height(r: ExternRef<FormImpl>) -> WasmResult<f32>;
fn form_get_weight(r: ExternRef<FormImpl>) -> f32; fn form_get_weight(r: ExternRef<FormImpl>) -> WasmResult<f32>;
fn form_get_types(r: ExternRef<FormImpl>) -> FFIArray<u8>; fn form_get_types(r: ExternRef<FormImpl>) -> WasmResult<u64>;
fn form_get_base_experience(r: ExternRef<FormImpl>) -> u32; fn form_get_base_experience(r: ExternRef<FormImpl>) -> WasmResult<u32>;
fn form_get_base_stats(r: ExternRef<FormImpl>) -> ExternRef<ImmutableStatisticSetImpl>; fn form_get_base_stats(
fn form_get_abilities(r: ExternRef<FormImpl>) -> VecExternRef<StringKey>; r: ExternRef<FormImpl>,
fn form_get_hidden_abilities(r: ExternRef<FormImpl>) -> VecExternRef<StringKey>; ) -> WasmResult<ExternRef<ImmutableStatisticSetImpl>>;
fn form_has_flag_by_hash(r: ExternRef<FormImpl>, hash: u32) -> bool; fn form_get_abilities(r: ExternRef<FormImpl>) -> WasmResult<u64>;
fn form_get_hidden_abilities(r: ExternRef<FormImpl>) -> WasmResult<u64>;
fn form_has_flag_by_hash(r: ExternRef<FormImpl>, hash: u32) -> WasmResult<bool>;
fn species_get_id(r: ExternRef<SpeciesImpl>) -> u16; fn species_get_id(r: ExternRef<SpeciesImpl>) -> WasmResult<u16>;
fn species_get_name(r: ExternRef<SpeciesImpl>) -> ExternRef<StringKey>; fn species_get_name(r: ExternRef<SpeciesImpl>) -> WasmResult<ExternRef<StringKey>>;
fn species_get_gender_rate(r: ExternRef<SpeciesImpl>) -> f32; fn species_get_gender_rate(r: ExternRef<SpeciesImpl>) -> WasmResult<f32>;
fn species_get_growth_rate(r: ExternRef<SpeciesImpl>) -> ExternRef<StringKey>; fn species_get_growth_rate(r: ExternRef<SpeciesImpl>) -> WasmResult<ExternRef<StringKey>>;
fn species_get_capture_rate(r: ExternRef<SpeciesImpl>) -> u8; fn species_get_capture_rate(r: ExternRef<SpeciesImpl>) -> WasmResult<u8>;
fn species_get_form_by_hash(r: ExternRef<SpeciesImpl>, hash: u32) -> ExternRef<FormImpl>; fn species_get_form_by_hash(
fn species_has_flag_by_hash(r: ExternRef<SpeciesImpl>, flag_hash: u32) -> bool; r: ExternRef<SpeciesImpl>,
hash: u32,
) -> WasmResult<ExternRef<FormImpl>>;
fn species_has_flag_by_hash(r: ExternRef<SpeciesImpl>, flag_hash: u32) -> WasmResult<bool>;
} }
} }
use crate::PkmnResult;
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
pub use implementation::*; pub use implementation::*;

View File

@ -11,6 +11,12 @@ pub enum Statistic {
Speed = 5, Speed = 5,
} }
impl Default for Statistic {
fn default() -> Self {
Self::HP
}
}
pub trait ImmutableStatisticSetTrait { pub trait ImmutableStatisticSetTrait {
fn hp(&self) -> u16; fn hp(&self) -> u16;
fn attack(&self) -> u16; fn attack(&self) -> u16;
@ -28,7 +34,7 @@ mod implementation {
use crate::cached_value; use crate::cached_value;
use crate::handling::cached_value::CachedValue; use crate::handling::cached_value::CachedValue;
use crate::handling::extern_ref::{ExternRef, ExternalReferenceType}; use crate::handling::extern_ref::{ExternRef, ExternalReferenceType};
use crate::handling::Cacheable; use crate::handling::{Cacheable, WasmResult};
pub struct ImmutableStatisticSetInner { pub struct ImmutableStatisticSetInner {
reference: ExternRef<ImmutableStatisticSetImpl>, reference: ExternRef<ImmutableStatisticSetImpl>,
@ -56,21 +62,24 @@ mod implementation {
Self::from_ref(reference, &|reference| Self { Self::from_ref(reference, &|reference| Self {
inner: Rc::new(ImmutableStatisticSetInner { inner: Rc::new(ImmutableStatisticSetInner {
reference, reference,
hp: cached_value!({ static_statistics_set_get_stat(reference, Statistic::HP) }), hp: cached_value!({
static_statistics_set_get_stat(reference, Statistic::HP).unwrap()
}),
attack: cached_value!({ attack: cached_value!({
static_statistics_set_get_stat(reference, Statistic::Attack) static_statistics_set_get_stat(reference, Statistic::Attack).unwrap()
}), }),
defense: cached_value!({ defense: cached_value!({
static_statistics_set_get_stat(reference, Statistic::Defense) static_statistics_set_get_stat(reference, Statistic::Defense).unwrap()
}), }),
special_attack: cached_value!({ special_attack: cached_value!({
static_statistics_set_get_stat(reference, Statistic::SpecialAttack) static_statistics_set_get_stat(reference, Statistic::SpecialAttack).unwrap()
}), }),
special_defense: cached_value!({ special_defense: cached_value!({
static_statistics_set_get_stat(reference, Statistic::SpecialDefense) static_statistics_set_get_stat(reference, Statistic::SpecialDefense)
.unwrap()
}), }),
speed: cached_value!({ speed: cached_value!({
static_statistics_set_get_stat(reference, Statistic::Speed) static_statistics_set_get_stat(reference, Statistic::Speed).unwrap()
}), }),
}), }),
}) })
@ -110,7 +119,7 @@ mod implementation {
fn static_statistics_set_get_stat( fn static_statistics_set_get_stat(
r: ExternRef<ImmutableStatisticSetImpl>, r: ExternRef<ImmutableStatisticSetImpl>,
stat: Statistic, stat: Statistic,
) -> u16; ) -> WasmResult<u16>;
} }
} }
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]

View File

@ -1,7 +1,12 @@
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
use crate::alloc::string::ToString;
#[cfg(not(feature = "mock_data"))]
use crate::handling::wasm_result::WasmResult;
#[cfg(not(feature = "mock_data"))]
use crate::handling::Cacheable; use crate::handling::Cacheable;
use crate::PkmnResult;
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
use crate::{ExternRef, ExternalReferenceType}; use crate::{pkmn_err, ExternRef, ExternalReferenceType, PkmnErr};
use alloc::rc::Rc; use alloc::rc::Rc;
use core::cell::RefCell; use core::cell::RefCell;
use core::fmt::{Debug, Display, Formatter}; use core::fmt::{Debug, Display, Formatter};
@ -21,7 +26,10 @@ pub struct StringKey {
impl Debug for StringKey { impl Debug for StringKey {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "\"{}\"", self.str().to_str().unwrap()) match self.str() {
Ok(s) => write!(f, "\"{}\"", s.to_str().unwrap()),
Err(e) => write!(f, "Error: {}", e),
}
} }
} }
@ -45,41 +53,44 @@ impl StringKey {
} }
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
pub fn str(&self) -> &CString { pub fn str(&self) -> PkmnResult<&CString> {
if self.data.str.borrow().is_none() { if self.data.str.borrow().is_none() {
unsafe { unsafe {
self.data let ptr = string_key_get_str(self.ptr()).as_res()?;
.str let ptr = ptr as *mut cstr_core::c_char;
.replace(Some(CString::from_raw(string_key_get_str(self.ptr())))); self.data.str.replace(Some(CString::from_raw(ptr)));
} }
} }
unsafe { (*self.data.str.as_ptr()).as_ref().unwrap() } Ok(unsafe {
(*self.data.str.as_ptr())
.as_ref()
.ok_or(pkmn_err!("Stringkey was null"))?
})
} }
#[cfg(feature = "mock_data")] #[cfg(feature = "mock_data")]
pub fn str(&self) -> &CString { pub fn str(&self) -> PkmnResult<&CString> {
unsafe { (*self.data.str.as_ptr()).as_ref().unwrap() } Ok(unsafe { (*self.data.str.as_ptr()).as_ref().unwrap() })
} }
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
pub fn hash(&self) -> u32 { pub fn hash(&self) -> PkmnResult<u32> {
if self.data.hash.borrow().is_none() { if self.data.hash.borrow().is_none() {
unsafe { unsafe {
self.data let hash = string_key_get_hash(self.ptr()).as_res()?;
.hash self.data.hash.replace(Some(hash));
.replace(Some(string_key_get_hash(self.ptr())));
} }
} }
self.data.hash.borrow().unwrap() Ok(self.data.hash.borrow().unwrap())
} }
#[cfg(feature = "mock_data")] #[cfg(feature = "mock_data")]
pub fn hash(&self) -> u32 { pub fn hash(&self) -> PkmnResult<u32> {
self.data.hash.borrow().unwrap() Ok(self.data.hash.borrow().unwrap())
} }
pub fn equals_str(&self, other: &str) -> bool { pub fn equals_str(&self, other: &str) -> bool {
self.hash() == get_hash(other) self.hash().unwrap() == get_hash(other)
} }
} }
@ -107,15 +118,15 @@ impl ExternalReferenceType for StringKey {
impl Display for StringKey { impl Display for StringKey {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
let s = self.str(); let s = self.str().unwrap();
f.write_str(s.to_str().as_ref().unwrap()) f.write_str(s.to_str().as_ref().unwrap())
} }
} }
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
extern "wasm" { extern "wasm" {
fn string_key_get_str(ptr: ExternRef<StringKey>) -> *mut cstr_core::c_char; fn string_key_get_str(ptr: ExternRef<StringKey>) -> WasmResult<u32>;
fn string_key_get_hash(ptr: ExternRef<StringKey>) -> u32; fn string_key_get_hash(ptr: ExternRef<StringKey>) -> WasmResult<u32>;
} }
const CRC_TABLE: &[u32] = &[ const CRC_TABLE: &[u32] = &[

View File

@ -7,7 +7,7 @@ pub struct CachedValue<T> {
} }
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
impl<T> CachedValue<T> { impl<T: Clone> CachedValue<T> {
pub fn new(init_fn: Box<dyn Fn() -> T>) -> Self { pub fn new(init_fn: Box<dyn Fn() -> T>) -> Self {
Self { Self {
init_fn, init_fn,
@ -15,13 +15,15 @@ impl<T> CachedValue<T> {
} }
} }
#[inline(always)] fn init_if_empty(&self) -> T
fn init_if_empty(&self) { where
if self.value.is_none() { T: Clone,
unsafe { {
let s = self as *const Self as *mut Self; unsafe {
s.as_mut().unwrap().value.replace((self.init_fn)()); let s = self as *const Self as *mut Self;
} let v = (self.init_fn)();
s.as_mut().unwrap().value.replace(v.clone());
v
} }
} }
@ -30,8 +32,10 @@ impl<T> CachedValue<T> {
where where
T: Clone, T: Clone,
{ {
self.init_if_empty(); match self.value {
self.value.as_ref().unwrap().clone() Some(ref v) => v.clone(),
None => self.init_if_empty(),
}
} }
#[inline] #[inline]

View File

@ -1,8 +1,6 @@
use alloc::rc::Rc; use alloc::rc::Rc;
use core::cmp::Ordering; use core::cmp::Ordering;
use core::hash::{Hash, Hasher}; use core::hash::{Hash, Hasher};
#[cfg(not(feature = "mock_data"))]
use core::intrinsics::transmute;
use core::marker::PhantomData; use core::marker::PhantomData;
#[repr(C)] #[repr(C)]
@ -82,6 +80,15 @@ impl<T> Clone for ExternRef<T> {
impl<T> Copy for ExternRef<T> {} impl<T> Copy for ExternRef<T> {}
impl<T> Default for ExternRef<T> {
fn default() -> Self {
Self {
p: 0,
resource_type: Default::default(),
}
}
}
impl<T> Eq for ExternRef<T> {} impl<T> Eq for ExternRef<T> {}
impl<T> PartialEq<Self> for ExternRef<T> { impl<T> PartialEq<Self> for ExternRef<T> {
@ -117,70 +124,6 @@ impl<T> From<u32> for ExternRef<T> {
} }
} }
#[repr(C)]
pub struct VecExternRef<T> {
v: u64,
resource_type: PhantomData<T>,
}
impl<T> VecExternRef<T> {
pub fn is_null(&self) -> bool {
self.v == 0
}
#[cfg(not(feature = "mock_data"))]
pub(crate) fn get_internal_index(&self) -> u32 {
let v: (u32, u32) = unsafe { transmute(self.v) };
v.0
}
#[cfg(not(feature = "mock_data"))]
pub(crate) fn len(&self) -> u32 {
let v: (u32, u32) = unsafe { transmute(self.v) };
v.1
}
#[cfg(not(feature = "mock_data"))]
pub(crate) fn at(&self, index: u32) -> ExternRef<T> {
let p = unsafe { _vec_extern_ref_get_value(self.get_internal_index(), index) };
ExternRef {
p,
resource_type: Default::default(),
}
}
}
impl<T> Clone for VecExternRef<T> {
fn clone(&self) -> Self {
Self {
v: self.v,
resource_type: Default::default(),
}
}
}
impl<T> Copy for VecExternRef<T> {}
impl<T> Eq for VecExternRef<T> {}
impl<T> PartialEq<Self> for VecExternRef<T> {
fn eq(&self, other: &Self) -> bool {
u64::eq(&self.v, &other.v)
}
}
impl<T> PartialOrd<Self> for VecExternRef<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
u64::partial_cmp(&self.v, &other.v)
}
}
impl<T> Ord for VecExternRef<T> {
fn cmp(&self, other: &Self) -> Ordering {
u64::cmp(&self.v, &other.v)
}
}
pub trait ExternalReferenceType { pub trait ExternalReferenceType {
fn from_extern_value(reference: ExternRef<Self>) -> Self fn from_extern_value(reference: ExternRef<Self>) -> Self
where where
@ -222,8 +165,3 @@ macro_rules! impl_extern_ctor {
} }
}; };
} }
#[cfg(not(feature = "mock_data"))]
extern "wasm" {
fn _vec_extern_ref_get_value(extern_ref: u32, index: u32) -> u32;
}

View File

@ -19,6 +19,24 @@ impl<T> FFIArray<T> {
mem::forget(boxed_slice); mem::forget(boxed_slice);
r r
} }
#[cfg(not(feature = "mock_data"))]
pub(crate) fn from_u64(v: u64) -> Self {
let v: (u32, u32) = unsafe { core::mem::transmute(v) };
Self {
ptr: v.0 as *mut T,
len: v.1 as usize,
}
}
}
impl<T> Default for FFIArray<T> {
fn default() -> Self {
Self {
ptr: core::ptr::null_mut(),
len: 0,
}
}
} }
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]

View File

@ -8,6 +8,7 @@ pub mod ffi_array;
pub mod script; pub mod script;
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
pub(crate) mod temporary; pub(crate) mod temporary;
pub(crate) mod wasm_result;
pub use capabilities::*; pub use capabilities::*;
@ -15,6 +16,7 @@ pub use capabilities::*;
pub(crate) use cacheable::Cacheable; pub(crate) use cacheable::Cacheable;
pub use script::Script; pub use script::Script;
pub use script::ScriptOwner; pub use script::ScriptOwner;
pub use wasm_result::*;
#[repr(u8)] #[repr(u8)]
pub enum ScriptCategory { pub enum ScriptCategory {
@ -41,7 +43,7 @@ macro_rules! wasm_reference_getters_extern {
extern "wasm" { extern "wasm" {
$( $(
paste::paste!{ paste::paste!{
fn [<$type_name:snake _get_ $name>](r: ExternRef<$base_type>) -> ExternRef<$type>; fn [<$type_name:snake _get_ $name>](r: ExternRef<$base_type>) -> WasmResult<ExternRef<$type>>;
} }
)* )*
} }
@ -151,7 +153,7 @@ macro_rules! wasm_optional_reference_getters_extern {
extern "wasm" { extern "wasm" {
$( $(
paste::paste!{ paste::paste!{
fn [<$type_name:snake _get_ $name>](r: ExternRef<$base_type>) -> ExternRef<$type>; fn [<$type_name:snake _get_ $name>](r: ExternRef<$base_type>) -> WasmResult<ExternRef<$type>>;
} }
)* )*
} }
@ -228,7 +230,7 @@ macro_rules! wasm_value_getters_extern {
extern "wasm" { extern "wasm" {
$( $(
paste::paste!{ paste::paste!{
fn [<$type_name:snake _get_ $name>](r: ExternRef<$base_type>) -> $type; fn [<$type_name:snake _get_ $name>](r: ExternRef<$base_type>) -> WasmResult<$type>;
} }
)* )*
} }
@ -246,10 +248,10 @@ macro_rules! wasm_value_getters_funcs {
) => { ) => {
$( $(
$(#[$attr])* $(#[$attr])*
$v fn $name(&self) -> $type { $v fn $name(&self) -> PkmnResult<$type> {
paste::paste!{ paste::paste!{
unsafe{ unsafe{
[<$base_type:snake _get_ $name>](self.inner.reference) [<$base_type:snake _get_ $name>](self.inner.reference).as_res()
} }
} }
} }

View File

@ -1,4 +1,3 @@
use crate::app_interface::list::ImmutableList;
use crate::app_interface::{ use crate::app_interface::{
Battle, BattleSide, DamageSource, DynamicLibrary, EffectParameter, ExecutingMove, Item, Battle, BattleSide, DamageSource, DynamicLibrary, EffectParameter, ExecutingMove, Item,
Pokemon, Statistic, TurnChoice, TypeIdentifier, Pokemon, Statistic, TurnChoice, TypeIdentifier,
@ -6,8 +5,10 @@ use crate::app_interface::{
use crate::handling::ScriptCapabilities; use crate::handling::ScriptCapabilities;
use crate::StringKey; use crate::StringKey;
use alloc::rc::Rc; use alloc::rc::Rc;
use alloc::vec::Vec;
use core::any::Any; use core::any::Any;
use core::fmt::{Debug, Display, Formatter}; use core::fmt::{Debug, Display, Formatter};
type Result<T> = crate::result::PkmnResult<T>;
pub trait Script { pub trait Script {
fn new() -> Self fn new() -> Self
@ -18,58 +19,97 @@ pub trait Script {
/// This function is ran when a volatile effect is added while that volatile effect already is /// This function is ran when a volatile effect is added while that volatile effect already is
/// in place. Instead of adding the volatile effect twice, it will execute this function instead. /// in place. Instead of adding the volatile effect twice, it will execute this function instead.
fn stack(&self) {} fn stack(&self) -> Result<()> {
Ok(())
}
/// This function is ran when this script stops being in effect, and is removed from its owner. /// This function is ran when this script stops being in effect, and is removed from its owner.
fn on_remove(&self) {} fn on_remove(&self) -> Result<()> {
Ok(())
}
/// This function is ran when this script starts being in effect. /// This function is ran when this script starts being in effect.
fn on_initialize( fn on_initialize(
&self, &self,
_library: DynamicLibrary, _library: DynamicLibrary,
_parameters: Option<ImmutableList<Rc<EffectParameter>>>, _parameters: Option<Vec<Rc<EffectParameter>>>,
) { ) -> Result<()> {
Ok(())
} }
/// This function is ran just before the start of the turn. Everyone has made its choices here, /// This function is ran just before the start of the turn. Everyone has made its choices here,
/// and the turn is about to start. This is a great place to initialize data if you need to know /// and the turn is about to start. This is a great place to initialize data if you need to know
/// something has happened during a turn. /// something has happened during a turn.
fn on_before_turn(&self, _choice: TurnChoice) {} fn on_before_turn(&self, _choice: TurnChoice) -> Result<()> {
Ok(())
}
/// This function allows you to modify the effective speed of the Pokemon. This is ran before /// This function allows you to modify the effective speed of the Pokemon. This is ran before
/// turn ordering, so overriding here will allow you to put certain Pokemon before others. /// turn ordering, so overriding here will allow you to put certain Pokemon before others.
fn change_speed(&self, _choice: TurnChoice, _speed: &mut u32) {} fn change_speed(&self, _choice: TurnChoice, _speed: &mut u32) -> Result<()> {
Ok(())
}
/// This function allows you to modify the effective priority of the Pokemon. This is ran before /// This function allows you to modify the effective priority of the Pokemon. This is ran before
/// turn ordering, so overriding here will allow you to put certain Pokemon before others. Note /// turn ordering, so overriding here will allow you to put certain Pokemon before others. Note
/// that this is only relevant on move choices, as other turn choice types do not have a priority. /// that this is only relevant on move choices, as other turn choice types do not have a priority.
fn change_priority(&self, _choice: TurnChoice, _priority: &mut i8) {} fn change_priority(&self, _choice: TurnChoice, _priority: &mut i8) -> Result<()> {
Ok(())
}
/// This function allows you to change the move that is used during execution. This is useful for /// This function allows you to change the move that is used during execution. This is useful for
/// moves such as metronome, where the move chosen actually differs from the move used. /// moves such as metronome, where the move chosen actually differs from the move used.
fn change_move(&self, _choice: TurnChoice, _move_name: &mut StringKey) {} fn change_move(&self, _choice: TurnChoice, _move_name: &mut StringKey) -> Result<()> {
Ok(())
}
/// This function allows you to change a move into a multi-hit move. The number of hits set here /// This function allows you to change a move into a multi-hit move. The number of hits set here
/// gets used as the number of hits. If set to 0, this will behave as if the move missed on its /// gets used as the number of hits. If set to 0, this will behave as if the move missed on its
/// first hit. /// first hit.
fn change_number_of_hits(&self, _choice: TurnChoice, _number_of_hits: &mut u8) {} fn change_number_of_hits(&self, _choice: TurnChoice, _number_of_hits: &mut u8) -> Result<()> {
Ok(())
}
/// This function allows you to prevent a move from running. If this gets set to true, the move /// This function allows you to prevent a move from running. If this gets set to true, the move
/// ends execution here. No PP will be decreased in this case. /// ends execution here. No PP will be decreased in this case.
fn prevent_move(&self, _move: ExecutingMove, _prevent: &mut bool) {} fn prevent_move(&self, _move: ExecutingMove, _prevent: &mut bool) -> Result<()> {
Ok(())
}
/// This function makes the move fail. If the fail field gets set to true, the move ends execution, /// This function makes the move fail. If the fail field gets set to true, the move ends execution,
/// and fail events get triggered. /// and fail events get triggered.
fn fail_move(&self, _move: ExecutingMove, _fail: &mut bool) {} fn fail_move(&self, _move: ExecutingMove, _fail: &mut bool) -> Result<()> {
Ok(())
}
/// Similar to [`Self::prevent_move`]. This function will also stop execution, but PP will be /// Similar to [`Self::prevent_move`]. This function will also stop execution, but PP will be
/// decreased. /// decreased.
fn stop_before_move(&self, _move: ExecutingMove, _stop: &mut bool) {} fn stop_before_move(&self, _move: ExecutingMove, _stop: &mut bool) -> Result<()> {
Ok(())
}
/// This function runs just before the move starts its execution. /// This function runs just before the move starts its execution.
fn on_before_move(&self, _move: ExecutingMove) {} fn on_before_move(&self, _move: ExecutingMove) -> Result<()> {
Ok(())
}
/// This function allows a script to prevent a move that is targeted at its owner. If set to true /// This function allows a script to prevent a move that is targeted at its owner. If set to true
/// the move fails, and fail events get triggered. /// the move fails, and fail events get triggered.
fn fail_incoming_move(&self, _move: ExecutingMove, _target: Pokemon, _fail: &mut bool) {} fn fail_incoming_move(
&self,
_move: ExecutingMove,
_target: Pokemon,
_fail: &mut bool,
) -> Result<()> {
Ok(())
}
/// This function allows a script to make its owner invulnerable to an incoming move. /// This function allows a script to make its owner invulnerable to an incoming move.
fn is_invulnerable(&self, _move: ExecutingMove, _target: Pokemon, _invulnerable: &mut bool) {} fn is_invulnerable(
&self,
_move: ExecutingMove,
_target: Pokemon,
_invulnerable: &mut bool,
) -> Result<()> {
Ok(())
}
/// This function occurs when a move gets missed. This runs on the scripts belonging to the executing /// This function occurs when a move gets missed. This runs on the scripts belonging to the executing
/// move, which include the scripts that are attached to the owner of the script. /// move, which include the scripts that are attached to the owner of the script.
fn on_move_miss(&self, _move: ExecutingMove, _target: Pokemon) {} fn on_move_miss(&self, _move: ExecutingMove, _target: Pokemon) -> Result<()> {
Ok(())
}
/// This function allows the script to change the actual type that is used for the move on a target. /// This function allows the script to change the actual type that is used for the move on a target.
fn change_move_type( fn change_move_type(
&self, &self,
@ -77,7 +117,8 @@ pub trait Script {
_target: Pokemon, _target: Pokemon,
_hit: u8, _hit: u8,
_move_type: &mut TypeIdentifier, _move_type: &mut TypeIdentifier,
) { ) -> Result<()> {
Ok(())
} }
/// This function allows the script to change how effective a move is on a target. /// This function allows the script to change how effective a move is on a target.
fn change_effectiveness( fn change_effectiveness(
@ -86,7 +127,8 @@ pub trait Script {
_target: Pokemon, _target: Pokemon,
_hit: u8, _hit: u8,
_effectiveness: &mut f32, _effectiveness: &mut f32,
) { ) -> Result<()> {
Ok(())
} }
/// This function allows a script to block an outgoing move from being critical. /// This function allows a script to block an outgoing move from being critical.
fn block_critical( fn block_critical(
@ -95,7 +137,8 @@ pub trait Script {
_target: Pokemon, _target: Pokemon,
_hit: u8, _hit: u8,
_block_critical: &mut bool, _block_critical: &mut bool,
) { ) -> Result<()> {
Ok(())
} }
/// This function allows a script to block an incoming move from being critical. /// This function allows a script to block an incoming move from being critical.
fn block_incoming_critical( fn block_incoming_critical(
@ -104,7 +147,8 @@ pub trait Script {
_target: Pokemon, _target: Pokemon,
_hit: u8, _hit: u8,
_block_critical: &mut bool, _block_critical: &mut bool,
) { ) -> Result<()> {
Ok(())
} }
/// This function allows a script to modify the accuracy of a move used. This value represents /// This function allows a script to modify the accuracy of a move used. This value represents
/// the percentage accuracy, so anything above 100% will make it always hit. /// the percentage accuracy, so anything above 100% will make it always hit.
@ -114,7 +158,8 @@ pub trait Script {
_target: Pokemon, _target: Pokemon,
_hit: u8, _hit: u8,
_accuracy: &mut u8, _accuracy: &mut u8,
) { ) -> Result<()> {
Ok(())
} }
/// This function allows a script to change the critical stage of the move used. /// This function allows a script to change the critical stage of the move used.
@ -124,7 +169,8 @@ pub trait Script {
_target: Pokemon, _target: Pokemon,
_hit: u8, _hit: u8,
_stage: &mut u8, _stage: &mut u8,
) { ) -> Result<()> {
Ok(())
} }
/// This function allows a script to change the damage modifier of a critical hit. This will only /// This function allows a script to change the damage modifier of a critical hit. This will only
/// run when a hit is critical. /// run when a hit is critical.
@ -134,7 +180,8 @@ pub trait Script {
_target: Pokemon, _target: Pokemon,
_hit: u8, _hit: u8,
_modifier: &mut f32, _modifier: &mut f32,
) { ) -> Result<()> {
Ok(())
} }
/// This function allows a script to change the damage modifier of a Same Type Attack Bonus, which /// This function allows a script to change the damage modifier of a Same Type Attack Bonus, which
/// occurs when the user has the move type as one of its own types. /// occurs when the user has the move type as one of its own types.
@ -144,7 +191,8 @@ pub trait Script {
_target: Pokemon, _target: Pokemon,
_hit: u8, _hit: u8,
_modifier: &mut f32, _modifier: &mut f32,
) { ) -> Result<()> {
Ok(())
} }
/// This function allows a script to change the effective base power of a move hit. /// This function allows a script to change the effective base power of a move hit.
@ -154,7 +202,8 @@ pub trait Script {
_target: Pokemon, _target: Pokemon,
_hit: u8, _hit: u8,
_base_power: &mut u8, _base_power: &mut u8,
) { ) -> Result<()> {
Ok(())
} }
/// This function allows a script to bypass defensive stat boosts for a move hit. /// This function allows a script to bypass defensive stat boosts for a move hit.
fn bypass_defensive_stat_boost( fn bypass_defensive_stat_boost(
@ -163,7 +212,8 @@ pub trait Script {
_target: Pokemon, _target: Pokemon,
_hit: u8, _hit: u8,
_bypass: &mut bool, _bypass: &mut bool,
) { ) -> Result<()> {
Ok(())
} }
/// This function allows a script to bypass offensive stat boosts for a move hit. /// This function allows a script to bypass offensive stat boosts for a move hit.
fn bypass_offensive_stat_boost( fn bypass_offensive_stat_boost(
@ -172,7 +222,8 @@ pub trait Script {
_target: Pokemon, _target: Pokemon,
_hit: u8, _hit: u8,
_bypass: &mut bool, _bypass: &mut bool,
) { ) -> Result<()> {
Ok(())
} }
/// This function allows a script to change the actual offensive stat values used when calculating damage /// This function allows a script to change the actual offensive stat values used when calculating damage
fn change_offensive_stat_value( fn change_offensive_stat_value(
@ -181,7 +232,8 @@ pub trait Script {
_target: Pokemon, _target: Pokemon,
_hit: u8, _hit: u8,
_amount: &mut u32, _amount: &mut u32,
) { ) -> Result<()> {
Ok(())
} }
/// This function allows a script to change the actual defensive stat values used when calculating damage. /// This function allows a script to change the actual defensive stat values used when calculating damage.
fn change_defensive_stat_value( fn change_defensive_stat_value(
@ -190,7 +242,8 @@ pub trait Script {
_target: Pokemon, _target: Pokemon,
_hit: u8, _hit: u8,
_amount: &mut u32, _amount: &mut u32,
) { ) -> Result<()> {
Ok(())
} }
/// This function allows a script to change the raw modifier we retrieved from the stats of the /// This function allows a script to change the raw modifier we retrieved from the stats of the
@ -201,7 +254,8 @@ pub trait Script {
_target: Pokemon, _target: Pokemon,
_hit: u8, _hit: u8,
_modifier: &mut f32, _modifier: &mut f32,
) { ) -> Result<()> {
Ok(())
} }
/// This function allows a script to apply a raw multiplier to the damage done by a move. /// This function allows a script to apply a raw multiplier to the damage done by a move.
fn change_damage_modifier( fn change_damage_modifier(
@ -210,10 +264,19 @@ pub trait Script {
_target: Pokemon, _target: Pokemon,
_hit: u8, _hit: u8,
_modifier: &mut f32, _modifier: &mut f32,
) { ) -> Result<()> {
Ok(())
} }
/// This function allows a script to modify the outgoing damage done by a move. /// This function allows a script to modify the outgoing damage done by a move.
fn change_damage(&self, _move: ExecutingMove, _target: Pokemon, _hit: u8, _damage: &mut u32) {} fn change_damage(
&self,
_move: ExecutingMove,
_target: Pokemon,
_hit: u8,
_damage: &mut u32,
) -> Result<()> {
Ok(())
}
/// This function allows a script to modify the incoming damage done by a move. /// This function allows a script to modify the incoming damage done by a move.
fn change_incoming_damage( fn change_incoming_damage(
&self, &self,
@ -221,13 +284,18 @@ pub trait Script {
_target: Pokemon, _target: Pokemon,
_hit: u8, _hit: u8,
_damage: &mut u32, _damage: &mut u32,
) { ) -> Result<()> {
Ok(())
} }
/// This function triggers when an incoming hit happens. This triggers after the damage is done, /// This function triggers when an incoming hit happens. This triggers after the damage is done,
/// but before the secondary effect of the move happens. /// but before the secondary effect of the move happens.
fn on_incoming_hit(&self, _move: ExecutingMove, _target: Pokemon, _hit: u8) {} fn on_incoming_hit(&self, _move: ExecutingMove, _target: Pokemon, _hit: u8) -> Result<()> {
Ok(())
}
/// This function triggers when an opponent on the field faints. /// This function triggers when an opponent on the field faints.
fn on_opponent_faints(&self, _move: ExecutingMove, _target: Pokemon, _hit: u8) {} fn on_opponent_faints(&self, _move: ExecutingMove, _target: Pokemon, _hit: u8) -> Result<()> {
Ok(())
}
/// This function allows a script attached to a Pokemon or its parents to prevent stat boost /// This function allows a script attached to a Pokemon or its parents to prevent stat boost
/// changes on that Pokemon. /// changes on that Pokemon.
fn prevent_stat_boost_change( fn prevent_stat_boost_change(
@ -237,7 +305,8 @@ pub trait Script {
_amount: i8, _amount: i8,
_self_inflicted: bool, _self_inflicted: bool,
_prevent: &mut bool, _prevent: &mut bool,
) { ) -> Result<()> {
Ok(())
} }
/// This function allows a script attached to a Pokemon or its parents to modify the amount by /// This function allows a script attached to a Pokemon or its parents to modify the amount by
/// which the stat boost will change. If the stat boost is done by the user itself, self /// which the stat boost will change. If the stat boost is done by the user itself, self
@ -248,7 +317,8 @@ pub trait Script {
_stat: Statistic, _stat: Statistic,
_self_inflicted: bool, _self_inflicted: bool,
_amount: &mut i8, _amount: &mut i8,
) { ) -> Result<()> {
Ok(())
} }
/// This function allows a script attached to a Pokemon or its parents to prevent an incoming /// This function allows a script attached to a Pokemon or its parents to prevent an incoming
/// secondary effect. This means the move will still hit and do damage, but not trigger its /// secondary effect. This means the move will still hit and do damage, but not trigger its
@ -259,7 +329,8 @@ pub trait Script {
_target: Pokemon, _target: Pokemon,
_hit: u8, _hit: u8,
_prevent: &mut bool, _prevent: &mut bool,
) { ) -> Result<()> {
Ok(())
} }
/// This function allows a script attached to a move or its parents to change the chance the /// This function allows a script attached to a move or its parents to change the chance the
/// secondary effect of a move will trigger. The chance is depicted in percentage here, so /// secondary effect of a move will trigger. The chance is depicted in percentage here, so
@ -271,7 +342,8 @@ pub trait Script {
_target: Pokemon, _target: Pokemon,
_hit: u8, _hit: u8,
_chance: &mut f32, _chance: &mut f32,
) { ) -> Result<()> {
Ok(())
} }
/// This function allows a script attached to a Pokemon or its parents to change the chance the /// This function allows a script attached to a Pokemon or its parents to change the chance the
/// secondary effect of an incoming move will trigger. The chance is depicted in percentage here, /// secondary effect of an incoming move will trigger. The chance is depicted in percentage here,
@ -283,30 +355,49 @@ pub trait Script {
_target: Pokemon, _target: Pokemon,
_hit: u8, _hit: u8,
_chance: &mut f32, _chance: &mut f32,
) { ) -> Result<()> {
Ok(())
} }
/// This function triggers when the move uses its secondary effect. Moves should implement their /// This function triggers when the move uses its secondary effect. Moves should implement their
/// secondary effects here. Status moves should implement their actual functionality in this /// secondary effects here. Status moves should implement their actual functionality in this
/// function as well, as status moves effects are defined as secondary effects for simplicity. /// function as well, as status moves effects are defined as secondary effects for simplicity.
fn on_secondary_effect(&self, _move: ExecutingMove, _target: Pokemon, _hit: u8) {} fn on_secondary_effect(&self, _move: ExecutingMove, _target: Pokemon, _hit: u8) -> Result<()> {
Ok(())
}
/// This function triggers on a move or its parents when all hits on a target are finished. /// This function triggers on a move or its parents when all hits on a target are finished.
fn on_after_hits(&self, _move: ExecutingMove, _target: Pokemon) {} fn on_after_hits(&self, _move: ExecutingMove, _target: Pokemon) -> Result<()> {
Ok(())
}
/// This function prevents the Pokemon it is attached to from being able to switch out. /// This function prevents the Pokemon it is attached to from being able to switch out.
fn prevent_self_switch(&self, _choice: TurnChoice, _prevent: &mut bool) {} fn prevent_self_switch(&self, _choice: TurnChoice, _prevent: &mut bool) -> Result<()> {
Ok(())
}
/// This function allows the prevention of switching for any opponent. /// This function allows the prevention of switching for any opponent.
fn prevent_opponent_switch(&self, _choice: TurnChoice, _prevent: &mut bool) {} fn prevent_opponent_switch(&self, _choice: TurnChoice, _prevent: &mut bool) -> Result<()> {
Ok(())
}
/// This function is called on a move and its parents when the move fails. /// This function is called on a move and its parents when the move fails.
fn on_fail(&self, _target: Pokemon) {} fn on_fail(&self, _target: Pokemon) -> Result<()> {
Ok(())
}
/// This function is called on a script when an opponent fails. /// This function is called on a script when an opponent fails.
fn on_opponent_fail(&self, _target: Pokemon) {} fn on_opponent_fail(&self, _target: Pokemon) -> Result<()> {
Ok(())
}
/// This function allows preventing the running away of the Pokemon its attached to /// This function allows preventing the running away of the Pokemon its attached to
fn prevent_self_run_away(&self, _choice: TurnChoice, _prevent: &mut bool) {} fn prevent_self_run_away(&self, _choice: TurnChoice, _prevent: &mut bool) -> Result<()> {
Ok(())
}
/// This function prevents a Pokemon on another side than where its attached to from running away. /// This function prevents a Pokemon on another side than where its attached to from running away.
fn prevent_opponent_run_away(&self, _choice: TurnChoice, _prevent: &mut bool) {} fn prevent_opponent_run_away(&self, _choice: TurnChoice, _prevent: &mut bool) -> Result<()> {
Ok(())
}
/// This function id triggered on all scripts active in the battle after all choices have finished /// This function id triggered on all scripts active in the battle after all choices have finished
/// running. Note that choices are not active anymore here, so their scripts do not call this /// running. Note that choices are not active anymore here, so their scripts do not call this
/// function. /// function.
fn on_end_turn(&self) {} fn on_end_turn(&self) -> Result<()> {
Ok(())
}
/// This function is triggered on a Pokemon and its parents when the given Pokemon takes damage. /// This function is triggered on a Pokemon and its parents when the given Pokemon takes damage.
fn on_damage( fn on_damage(
&self, &self,
@ -314,16 +405,23 @@ pub trait Script {
_source: DamageSource, _source: DamageSource,
_old_health: u32, _old_health: u32,
_new_health: u32, _new_health: u32,
) { ) -> Result<()> {
Ok(())
} }
/// This function is triggered on a Pokemon and its parents when the given Pokemon faints. /// This function is triggered on a Pokemon and its parents when the given Pokemon faints.
fn on_faint(&self, _pokemon: Pokemon, _source: DamageSource) {} fn on_faint(&self, _pokemon: Pokemon, _source: DamageSource) -> Result<()> {
Ok(())
}
/// This function is triggered on a Pokemon and its parents when the given Pokemon is switched into /// This function is triggered on a Pokemon and its parents when the given Pokemon is switched into
/// the battlefield. /// the battlefield.
fn on_switch_in(&self, _pokemon: Pokemon) {} fn on_switch_in(&self, _pokemon: Pokemon) -> Result<()> {
Ok(())
}
/// This function is triggered on a Pokemon and its parents when the given Pokemon consumes the /// This function is triggered on a Pokemon and its parents when the given Pokemon consumes the
/// held item it had. /// held item it had.
fn on_after_held_item_consume(&self, _pokemon: Pokemon, _item: Item) {} fn on_after_held_item_consume(&self, _pokemon: Pokemon, _item: Item) -> Result<()> {
Ok(())
}
/// This function is triggered on a Pokemon and its parents when the given Pokemon gains experience, /// This function is triggered on a Pokemon and its parents when the given Pokemon gains experience,
/// and allows for changing this amount of experience. /// and allows for changing this amount of experience.
fn change_experience_gained( fn change_experience_gained(
@ -331,18 +429,35 @@ pub trait Script {
_fainted_mon: Pokemon, _fainted_mon: Pokemon,
_winning_mon: Pokemon, _winning_mon: Pokemon,
_amount: &mut u32, _amount: &mut u32,
) { ) -> Result<()> {
Ok(())
} }
/// This function is triggered on a Pokemon and its parents when the given Pokemon gains experience, /// This function is triggered on a Pokemon and its parents when the given Pokemon gains experience,
/// and allows for making the experience be shared across multiple Pokemon. /// and allows for making the experience be shared across multiple Pokemon.
fn share_experience(&self, _fainted_mon: Pokemon, _winning_mon: Pokemon, _shares: &mut bool) {} fn share_experience(
&self,
_fainted_mon: Pokemon,
_winning_mon: Pokemon,
_shares: &mut bool,
) -> Result<()> {
Ok(())
}
/// This function is triggered on a battle and its parents when something attempts to change the /// This function is triggered on a battle and its parents when something attempts to change the
/// weather, and allows for blocking the weather change. /// weather, and allows for blocking the weather change.
fn block_weather(&self, _battle: Battle, _blocked: &mut bool) {} fn block_weather(&self, _battle: Battle, _blocked: &mut bool) -> Result<()> {
Ok(())
}
/// This function is called when a Pokeball is thrown at a Pokemon, and allows modifying the catch /// This function is called when a Pokeball is thrown at a Pokemon, and allows modifying the catch
/// rate of this attempt. Pokeball modifier effects should be implemented here, as well as for /// rate of this attempt. Pokeball modifier effects should be implemented here, as well as for
/// example status effects that change capture rates. /// example status effects that change capture rates.
fn change_capture_rate_bonus(&self, _target: Pokemon, _pokeball: Item, _modifier: &mut u8) {} fn change_capture_rate_bonus(
&self,
_target: Pokemon,
_pokeball: Item,
_modifier: &mut u8,
) -> Result<()> {
Ok(())
}
fn as_any(&self) -> &dyn Any; fn as_any(&self) -> &dyn Any;

View File

@ -0,0 +1,90 @@
use crate::{pkmn_err, PkmnErr, PkmnResult};
use alloc::string::ToString;
use cstr_core::{c_char, CString};
#[repr(C)]
#[repr(packed)]
#[derive(Debug)]
pub struct WasmResult<T>
where
T: Default,
{
err_ptr: u32,
value: T,
}
pub type WasmVoidResult = WasmResult<()>;
impl<T> WasmResult<T>
where
T: Default,
{
pub fn unwrap(self) -> T {
unsafe {
if self.err_ptr == 0 {
self.value
} else {
let ptr = self.err_ptr as *mut c_char;
let s = CString::from_raw(ptr).to_string_lossy().to_string();
panic!("{}", s)
}
}
}
pub fn as_res(self) -> PkmnResult<T> {
PkmnResult::from(self)
}
pub fn ok(value: T) -> Self {
WasmResult { err_ptr: 0, value }
}
pub fn err(err: PkmnErr) -> Self {
let s: CString = err.into();
let ptr = s.into_raw();
WasmResult {
err_ptr: ptr as u32,
value: Default::default(),
}
}
pub fn from_res(res: PkmnResult<T>) -> Self {
WasmResult::from(res)
}
}
impl<T> From<WasmResult<T>> for crate::PkmnResult<T>
where
T: Default,
{
fn from(value: WasmResult<T>) -> Self {
unsafe {
if value.err_ptr == 0 {
Ok(value.value)
} else {
let ptr = value.err_ptr as *mut c_char;
let s = CString::from_raw(ptr).to_string_lossy().to_string();
Err(pkmn_err!(s))
}
}
}
}
impl<T> From<crate::PkmnResult<T>> for WasmResult<T>
where
T: Default,
{
fn from(value: PkmnResult<T>) -> Self {
match value {
Ok(value) => WasmResult { err_ptr: 0, value },
Err(e) => {
let s: CString = e.into();
let ptr = s.into_raw();
WasmResult {
err_ptr: ptr as u32,
value: Default::default(),
}
}
}
}
}

View File

@ -12,11 +12,13 @@
#![feature(thread_local)] #![feature(thread_local)]
#![feature(build_hasher_simple_hash_one)] #![feature(build_hasher_simple_hash_one)]
#![feature(adt_const_params)] #![feature(adt_const_params)]
#![feature(try_trait_v2)]
#![cfg_attr(not(feature = "mock_data"), no_std)] #![cfg_attr(not(feature = "mock_data"), no_std)]
#![allow(incomplete_features)] #![allow(incomplete_features)]
// These give false positives too often // These give false positives too often
#![allow(clippy::borrowed_box)] #![allow(clippy::borrowed_box)]
#![allow(clippy::needless_lifetimes)] #![allow(clippy::needless_lifetimes)]
#![allow(stable_features)]
extern crate alloc; extern crate alloc;
extern crate core; extern crate core;
@ -33,25 +35,28 @@ use alloc::boxed::Box;
#[allow(dead_code)] #[allow(dead_code)]
pub mod app_interface; pub mod app_interface;
pub mod handling; pub mod handling;
mod result;
pub mod utils; pub mod utils;
pub use result::*;
pub type LoadScriptFnType = Box<dyn Fn(ScriptCategory, &StringKey) -> Option<Box<dyn Script>>>; pub type LoadScriptFnType = Box<dyn Fn(ScriptCategory, &StringKey) -> Option<Box<dyn Script>>>;
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
mod implementation { mod implementation {
use super::LoadScriptFnType; use super::LoadScriptFnType;
use crate::app_interface::list::{EffectParameterImmutableList, ImmutableListWasm};
use crate::app_interface::{ use crate::app_interface::{
BattleImpl, DamageSource, DynamicLibraryImpl, EffectParameter, ExecutingMoveImpl, ItemImpl, BattleImpl, DamageSource, DynamicLibraryImpl, EffectParameter, ExecutingMoveImpl, ItemImpl,
PokemonImpl, Statistic, StringKey, TurnChoice, TypeIdentifier, PokemonImpl, Statistic, StringKey, TurnChoice, TypeIdentifier,
}; };
use crate::handling::extern_ref::ExternRef; use crate::handling::extern_ref::ExternRef;
use crate::handling::extern_ref::VecExternRef;
use crate::handling::ffi_array::FFIArray; use crate::handling::ffi_array::FFIArray;
use crate::handling::wasm_result::WasmVoidResult;
use crate::handling::{Script, ScriptCapabilities, ScriptCategory}; use crate::handling::{Script, ScriptCapabilities, ScriptCategory};
use alloc::boxed::Box; use alloc::boxed::Box;
use alloc::rc::Rc; use alloc::rc::Rc;
use alloc::vec::Vec;
use core::sync::atomic::{AtomicU32, Ordering}; use core::sync::atomic::{AtomicU32, Ordering};
use cstr_core::{c_char, CString}; use cstr_core::{c_char, CString};
use hashbrown::HashMap; use hashbrown::HashMap;
@ -86,7 +91,7 @@ mod implementation {
static mut SCRIPT_INDEX_COUNTER: AtomicU32 = AtomicU32::new(1); static mut SCRIPT_INDEX_COUNTER: AtomicU32 = AtomicU32::new(1);
#[repr(C)] #[repr(C)]
#[derive(Copy, Clone)] #[derive(Copy, Clone, Default)]
pub struct ScriptPtr { pub struct ScriptPtr {
index: u32, index: u32,
} }
@ -183,56 +188,64 @@ mod implementation {
FFIArray::new(c) FFIArray::new(c)
} }
fn script_stack(script: ScriptPtr) { fn script_stack(script: ScriptPtr) -> WasmVoidResult {
script.val().unwrap().stack(); WasmVoidResult::from_res(script.val().unwrap().stack())
} }
fn script_on_remove(script: ScriptPtr) { fn script_on_remove(script: ScriptPtr) -> WasmVoidResult {
script.val().unwrap().on_remove(); WasmVoidResult::from_res(script.val().unwrap().on_remove())
} }
fn script_on_initialize( fn script_on_initialize(
script: ScriptPtr, script: ScriptPtr,
library: ExternRef<DynamicLibraryImpl>, library: ExternRef<DynamicLibraryImpl>,
parameters: VecExternRef<EffectParameter>, parameters: u64,
) { ) -> WasmVoidResult {
let parameters = Rc::new(EffectParameterImmutableList::from_ref(parameters)); let parameters : FFIArray<ExternRef<EffectParameter>> = FFIArray::from_u64(parameters);
script.val().unwrap().on_initialize(library.not_null_rc(), Some(parameters)); let parameters = Vec::from_raw_parts(parameters.ptr(), parameters.len(), parameters.len());
let parameters = parameters.into_iter().map(|p| Rc::new(EffectParameter::new(p).unwrap())).collect::<Vec<_>>();
WasmVoidResult::from_res(script.val().unwrap().on_initialize(library.not_null_rc(), Some(parameters)))
} }
fn script_on_before_turn( fn script_on_before_turn(
script: ScriptPtr, script: ScriptPtr,
choice: ExternRef<TurnChoice>, choice: ExternRef<TurnChoice>,
) { ) -> WasmVoidResult {
script.val().unwrap().on_before_turn(choice.not_null()) WasmVoidResult::from_res(script.val().unwrap().on_before_turn(choice.not_null()))
} }
fn script_change_speed( fn script_change_speed(
script:ScriptPtr, script:ScriptPtr,
choice: ExternRef<TurnChoice>, choice: ExternRef<TurnChoice>,
speed: *mut u32, speed: *mut u32,
) { ) -> WasmVoidResult {
script.val().unwrap().change_speed(choice.not_null(), speed.as_mut().unwrap()) WasmVoidResult::from_res(script.val().unwrap().change_speed(choice.not_null(), speed.as_mut().unwrap()))
} }
fn script_change_priority( fn script_change_priority(
script: ScriptPtr, script: ScriptPtr,
choice: ExternRef<TurnChoice>, choice: ExternRef<TurnChoice>,
priority: *mut i8, priority: *mut i8,
) { ) -> WasmVoidResult {
script.val().unwrap().change_priority(choice.not_null(), priority.as_mut().unwrap()) WasmVoidResult::from_res(script.val().unwrap().change_priority(choice.not_null(), priority.as_mut().unwrap()))
} }
fn script_change_move( fn script_change_move(
script: ScriptPtr, script: ScriptPtr,
choice: ExternRef<TurnChoice>, choice: ExternRef<TurnChoice>,
mv: *mut ExternRef<StringKey>, mv: *mut ExternRef<StringKey>,
) { ) -> WasmVoidResult {
let old = mv.as_ref().unwrap().not_null(); let old = mv.as_ref().unwrap().not_null();
let mut new = old.clone(); let mut new = old.clone();
script.val().unwrap().change_move(choice.not_null(), &mut new); let res = script.val().unwrap().change_move(choice.not_null(), &mut new);
if old != new { match res {
*mv = new.ptr(); Ok(_) => {
if old != new {
*mv = new.ptr();
}
WasmVoidResult::ok(())
}
Err(e) => WasmVoidResult::err(e),
} }
} }
@ -240,39 +253,39 @@ mod implementation {
script: ScriptPtr, script: ScriptPtr,
choice: ExternRef<TurnChoice>, choice: ExternRef<TurnChoice>,
out: *mut u8, out: *mut u8,
) { ) -> WasmVoidResult {
script.val().unwrap().change_number_of_hits(choice.not_null(), out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().change_number_of_hits(choice.not_null(), out.as_mut().unwrap()))
} }
fn script_prevent_move( fn script_prevent_move(
script: ScriptPtr, script: ScriptPtr,
mv: ExternRef<ExecutingMoveImpl>, mv: ExternRef<ExecutingMoveImpl>,
out: *mut bool, out: *mut bool,
) { ) -> WasmVoidResult {
script.val().unwrap().prevent_move(mv.not_null_rc(), out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().prevent_move(mv.not_null_rc(), out.as_mut().unwrap()))
} }
fn script_fail_move( fn script_fail_move(
script: ScriptPtr, script: ScriptPtr,
mv: ExternRef<ExecutingMoveImpl>, mv: ExternRef<ExecutingMoveImpl>,
out: *mut bool, out: *mut bool,
) { ) -> WasmVoidResult {
script.val().unwrap().fail_move(mv.not_null_rc(), out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().fail_move(mv.not_null_rc(), out.as_mut().unwrap()))
} }
fn script_stop_before_move( fn script_stop_before_move(
script: ScriptPtr, script: ScriptPtr,
mv: ExternRef<ExecutingMoveImpl>, mv: ExternRef<ExecutingMoveImpl>,
out: *mut bool, out: *mut bool,
) { ) -> WasmVoidResult {
script.val().unwrap().stop_before_move(mv.not_null_rc(), out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().stop_before_move(mv.not_null_rc(), out.as_mut().unwrap()))
} }
fn script_on_before_move( fn script_on_before_move(
script: ScriptPtr, script: ScriptPtr,
mv: ExternRef<ExecutingMoveImpl>, mv: ExternRef<ExecutingMoveImpl>,
) { ) -> WasmVoidResult {
script.val().unwrap().on_before_move(mv.not_null_rc()); WasmVoidResult::from_res(script.val().unwrap().on_before_move(mv.not_null_rc()))
} }
fn script_fail_incoming_move( fn script_fail_incoming_move(
@ -280,8 +293,8 @@ mod implementation {
mv: ExternRef<ExecutingMoveImpl>, mv: ExternRef<ExecutingMoveImpl>,
target: ExternRef<PokemonImpl>, target: ExternRef<PokemonImpl>,
out: *mut bool, out: *mut bool,
) { ) -> WasmVoidResult {
script.val().unwrap().fail_incoming_move(mv.not_null_rc(), target.not_null_rc(), out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().fail_incoming_move(mv.not_null_rc(), target.not_null_rc(), out.as_mut().unwrap()))
} }
fn script_is_invulnerable( fn script_is_invulnerable(
@ -289,16 +302,16 @@ mod implementation {
mv: ExternRef<ExecutingMoveImpl>, mv: ExternRef<ExecutingMoveImpl>,
target: ExternRef<PokemonImpl>, target: ExternRef<PokemonImpl>,
out: *mut bool, out: *mut bool,
) { ) -> WasmVoidResult {
script.val().unwrap().is_invulnerable(mv.not_null_rc(), target.not_null_rc(), out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().is_invulnerable(mv.not_null_rc(), target.not_null_rc(), out.as_mut().unwrap()))
} }
fn script_on_move_miss( fn script_on_move_miss(
script: ScriptPtr, script: ScriptPtr,
mv: ExternRef<ExecutingMoveImpl>, mv: ExternRef<ExecutingMoveImpl>,
target: ExternRef<PokemonImpl>, target: ExternRef<PokemonImpl>,
) { ) -> WasmVoidResult {
script.val().unwrap().on_move_miss(mv.not_null_rc(), target.not_null_rc()); WasmVoidResult::from_res(script.val().unwrap().on_move_miss(mv.not_null_rc(), target.not_null_rc()))
} }
fn script_change_move_type( fn script_change_move_type(
@ -307,8 +320,8 @@ mod implementation {
target: ExternRef<PokemonImpl>, target: ExternRef<PokemonImpl>,
hit: u8, hit: u8,
out: *mut TypeIdentifier, out: *mut TypeIdentifier,
) { ) -> WasmVoidResult {
script.val().unwrap().change_move_type(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().change_move_type(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()))
} }
fn script_change_effectiveness( fn script_change_effectiveness(
@ -317,8 +330,8 @@ mod implementation {
target: ExternRef<PokemonImpl>, target: ExternRef<PokemonImpl>,
hit: u8, hit: u8,
out: *mut f32, out: *mut f32,
) { ) -> WasmVoidResult {
script.val().unwrap().change_effectiveness(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().change_effectiveness(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()))
} }
fn script_block_critical( fn script_block_critical(
@ -327,8 +340,8 @@ mod implementation {
target: ExternRef<PokemonImpl>, target: ExternRef<PokemonImpl>,
hit: u8, hit: u8,
out: *mut bool, out: *mut bool,
) { ) -> WasmVoidResult {
script.val().unwrap().block_critical(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().block_critical(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()))
} }
fn script_block_incoming_critical( fn script_block_incoming_critical(
@ -337,8 +350,8 @@ mod implementation {
target: ExternRef<PokemonImpl>, target: ExternRef<PokemonImpl>,
hit: u8, hit: u8,
out: *mut bool, out: *mut bool,
) { ) -> WasmVoidResult {
script.val().unwrap().block_incoming_critical(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().block_incoming_critical(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()))
} }
fn script_change_accuracy( fn script_change_accuracy(
@ -347,8 +360,8 @@ mod implementation {
target: ExternRef<PokemonImpl>, target: ExternRef<PokemonImpl>,
hit: u8, hit: u8,
out: *mut u8, out: *mut u8,
) { ) -> WasmVoidResult {
script.val().unwrap().change_accuracy(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().change_accuracy(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()))
} }
fn script_change_critical_stage( fn script_change_critical_stage(
@ -357,8 +370,8 @@ mod implementation {
target: ExternRef<PokemonImpl>, target: ExternRef<PokemonImpl>,
hit: u8, hit: u8,
out: *mut u8, out: *mut u8,
) { ) -> WasmVoidResult {
script.val().unwrap().change_critical_stage(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().change_critical_stage(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()))
} }
fn script_change_critical_modifier( fn script_change_critical_modifier(
@ -367,8 +380,8 @@ mod implementation {
target: ExternRef<PokemonImpl>, target: ExternRef<PokemonImpl>,
hit: u8, hit: u8,
out: *mut f32, out: *mut f32,
) { ) -> WasmVoidResult {
script.val().unwrap().change_critical_modifier(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().change_critical_modifier(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()))
} }
fn script_change_stab_modifier( fn script_change_stab_modifier(
@ -377,8 +390,8 @@ mod implementation {
target: ExternRef<PokemonImpl>, target: ExternRef<PokemonImpl>,
hit: u8, hit: u8,
out: *mut f32, out: *mut f32,
) { ) -> WasmVoidResult {
script.val().unwrap().change_stab_modifier(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().change_stab_modifier(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()))
} }
fn script_change_base_power( fn script_change_base_power(
@ -387,8 +400,8 @@ mod implementation {
target: ExternRef<PokemonImpl>, target: ExternRef<PokemonImpl>,
hit: u8, hit: u8,
out: *mut u8, out: *mut u8,
) { ) -> WasmVoidResult {
script.val().unwrap().change_base_power(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().change_base_power(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()))
} }
fn script_bypass_defensive_stat_boost( fn script_bypass_defensive_stat_boost(
@ -397,8 +410,8 @@ mod implementation {
target: ExternRef<PokemonImpl>, target: ExternRef<PokemonImpl>,
hit: u8, hit: u8,
out: *mut bool, out: *mut bool,
) { ) -> WasmVoidResult {
script.val().unwrap().bypass_defensive_stat_boost(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().bypass_defensive_stat_boost(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()))
} }
fn script_bypass_offensive_stat_boost( fn script_bypass_offensive_stat_boost(
@ -407,8 +420,8 @@ mod implementation {
target: ExternRef<PokemonImpl>, target: ExternRef<PokemonImpl>,
hit: u8, hit: u8,
out: *mut bool, out: *mut bool,
) { ) -> WasmVoidResult {
script.val().unwrap().bypass_offensive_stat_boost(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().bypass_offensive_stat_boost(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()))
} }
fn script_change_defensive_stat_value( fn script_change_defensive_stat_value(
@ -417,8 +430,8 @@ mod implementation {
target: ExternRef<PokemonImpl>, target: ExternRef<PokemonImpl>,
hit: u8, hit: u8,
out: *mut u32, out: *mut u32,
) { ) -> WasmVoidResult {
script.val().unwrap().change_defensive_stat_value(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().change_defensive_stat_value(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()))
} }
fn script_change_offensive_stat_value( fn script_change_offensive_stat_value(
@ -427,8 +440,8 @@ mod implementation {
target: ExternRef<PokemonImpl>, target: ExternRef<PokemonImpl>,
hit: u8, hit: u8,
out: *mut u32, out: *mut u32,
) { ) -> WasmVoidResult {
script.val().unwrap().change_offensive_stat_value(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().change_offensive_stat_value(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()))
} }
fn script_change_damage_stat_modifier( fn script_change_damage_stat_modifier(
@ -437,8 +450,8 @@ mod implementation {
target: ExternRef<PokemonImpl>, target: ExternRef<PokemonImpl>,
hit: u8, hit: u8,
out: *mut f32, out: *mut f32,
) { ) -> WasmVoidResult {
script.val().unwrap().change_damage_stat_modifier(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().change_damage_stat_modifier(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()))
} }
fn script_change_damage_modifier( fn script_change_damage_modifier(
@ -447,8 +460,8 @@ mod implementation {
target: ExternRef<PokemonImpl>, target: ExternRef<PokemonImpl>,
hit: u8, hit: u8,
out: *mut f32, out: *mut f32,
) { ) -> WasmVoidResult {
script.val().unwrap().change_damage_modifier(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().change_damage_modifier(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()))
} }
fn script_change_damage( fn script_change_damage(
@ -457,8 +470,8 @@ mod implementation {
target: ExternRef<PokemonImpl>, target: ExternRef<PokemonImpl>,
hit: u8, hit: u8,
out: *mut u32, out: *mut u32,
) { ) -> WasmVoidResult {
script.val().unwrap().change_damage(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().change_damage(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()))
} }
fn script_change_incoming_damage( fn script_change_incoming_damage(
@ -467,8 +480,8 @@ mod implementation {
target: ExternRef<PokemonImpl>, target: ExternRef<PokemonImpl>,
hit: u8, hit: u8,
out: *mut u32, out: *mut u32,
) { ) -> WasmVoidResult {
script.val().unwrap().change_incoming_damage(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().change_incoming_damage(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()))
} }
fn script_on_incoming_hit( fn script_on_incoming_hit(
@ -476,8 +489,8 @@ mod implementation {
mv: ExternRef<ExecutingMoveImpl>, mv: ExternRef<ExecutingMoveImpl>,
target: ExternRef<PokemonImpl>, target: ExternRef<PokemonImpl>,
hit: u8, hit: u8,
) { ) -> WasmVoidResult {
script.val().unwrap().on_incoming_hit(mv.not_null_rc(), target.not_null_rc(), hit); WasmVoidResult::from_res(script.val().unwrap().on_incoming_hit(mv.not_null_rc(), target.not_null_rc(), hit))
} }
fn script_on_opponent_faints( fn script_on_opponent_faints(
@ -485,8 +498,8 @@ mod implementation {
mv: ExternRef<ExecutingMoveImpl>, mv: ExternRef<ExecutingMoveImpl>,
target: ExternRef<PokemonImpl>, target: ExternRef<PokemonImpl>,
hit: u8, hit: u8,
) { ) -> WasmVoidResult {
script.val().unwrap().on_opponent_faints(mv.not_null_rc(), target.not_null_rc(), hit); WasmVoidResult::from_res(script.val().unwrap().on_opponent_faints(mv.not_null_rc(), target.not_null_rc(), hit))
} }
fn script_prevent_stat_boost_change( fn script_prevent_stat_boost_change(
@ -496,8 +509,8 @@ mod implementation {
amount: i8, amount: i8,
self_inflicted: u8, self_inflicted: u8,
out: *mut bool, out: *mut bool,
) { ) -> WasmVoidResult {
script.val().unwrap().prevent_stat_boost_change(target.not_null_rc(), stat, amount, self_inflicted == 1, out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().prevent_stat_boost_change(target.not_null_rc(), stat, amount, self_inflicted == 1, out.as_mut().unwrap()))
} }
fn script_prevent_secondary_effect( fn script_prevent_secondary_effect(
@ -506,8 +519,8 @@ mod implementation {
target: ExternRef<PokemonImpl>, target: ExternRef<PokemonImpl>,
hit: u8, hit: u8,
out: *mut bool, out: *mut bool,
) { ) -> WasmVoidResult {
script.val().unwrap().prevent_secondary_effect(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().prevent_secondary_effect(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()))
} }
fn script_change_effect_chance( fn script_change_effect_chance(
@ -516,8 +529,8 @@ mod implementation {
target: ExternRef<PokemonImpl>, target: ExternRef<PokemonImpl>,
hit: u8, hit: u8,
out: *mut f32, out: *mut f32,
) { ) -> WasmVoidResult {
script.val().unwrap().change_effect_chance(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().change_effect_chance(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()))
} }
fn script_change_incoming_effect_chance( fn script_change_incoming_effect_chance(
@ -526,8 +539,8 @@ mod implementation {
target: ExternRef<PokemonImpl>, target: ExternRef<PokemonImpl>,
hit: u8, hit: u8,
out: *mut f32, out: *mut f32,
) { ) -> WasmVoidResult {
script.val().unwrap().change_incoming_effect_chance(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().change_incoming_effect_chance(mv.not_null_rc(), target.not_null_rc(), hit, out.as_mut().unwrap()))
} }
fn script_on_secondary_effect( fn script_on_secondary_effect(
@ -535,68 +548,68 @@ mod implementation {
mv: ExternRef<ExecutingMoveImpl>, mv: ExternRef<ExecutingMoveImpl>,
target: ExternRef<PokemonImpl>, target: ExternRef<PokemonImpl>,
hit: u8, hit: u8,
) { ) -> WasmVoidResult {
script.val().unwrap().on_secondary_effect(mv.not_null_rc(), target.not_null_rc(), hit); WasmVoidResult::from_res(script.val().unwrap().on_secondary_effect(mv.not_null_rc(), target.not_null_rc(), hit))
} }
fn script_on_after_hits( fn script_on_after_hits(
script: ScriptPtr, script: ScriptPtr,
mv: ExternRef<ExecutingMoveImpl>, mv: ExternRef<ExecutingMoveImpl>,
target: ExternRef<PokemonImpl>, target: ExternRef<PokemonImpl>,
) { ) -> WasmVoidResult {
script.val().unwrap().on_after_hits(mv.not_null_rc(), target.not_null_rc()); WasmVoidResult::from_res(script.val().unwrap().on_after_hits(mv.not_null_rc(), target.not_null_rc()))
} }
fn script_prevent_self_switch( fn script_prevent_self_switch(
script: ScriptPtr, script: ScriptPtr,
choice: ExternRef<TurnChoice>, choice: ExternRef<TurnChoice>,
out: *mut bool, out: *mut bool,
) { ) -> WasmVoidResult {
script.val().unwrap().prevent_self_switch(choice.not_null(), out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().prevent_self_switch(choice.not_null(), out.as_mut().unwrap()))
} }
fn script_prevent_opponent_switch( fn script_prevent_opponent_switch(
script: ScriptPtr, script: ScriptPtr,
choice: ExternRef<TurnChoice>, choice: ExternRef<TurnChoice>,
out: *mut bool, out: *mut bool,
) { ) -> WasmVoidResult {
script.val().unwrap().prevent_opponent_switch(choice.not_null(), out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().prevent_opponent_switch(choice.not_null(), out.as_mut().unwrap()))
} }
fn script_on_fail( fn script_on_fail(
script: ScriptPtr, script: ScriptPtr,
pokemon: ExternRef<PokemonImpl>, pokemon: ExternRef<PokemonImpl>,
) { ) -> WasmVoidResult {
script.val().unwrap().on_fail(pokemon.not_null_rc()); WasmVoidResult::from_res(script.val().unwrap().on_fail(pokemon.not_null_rc()))
} }
fn script_on_opponent_fail( fn script_on_opponent_fail(
script: ScriptPtr, script: ScriptPtr,
pokemon: ExternRef<PokemonImpl>, pokemon: ExternRef<PokemonImpl>,
) { ) -> WasmVoidResult {
script.val().unwrap().on_opponent_fail(pokemon.not_null_rc()); WasmVoidResult::from_res(script.val().unwrap().on_opponent_fail(pokemon.not_null_rc()))
} }
fn script_prevent_self_run_away( fn script_prevent_self_run_away(
script: ScriptPtr, script: ScriptPtr,
choice: ExternRef<TurnChoice>, choice: ExternRef<TurnChoice>,
out: *mut bool, out: *mut bool,
) { ) -> WasmVoidResult {
script.val().unwrap().prevent_self_run_away(choice.not_null(), out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().prevent_self_run_away(choice.not_null(), out.as_mut().unwrap()))
} }
fn script_prevent_opponent_run_away( fn script_prevent_opponent_run_away(
script: ScriptPtr, script: ScriptPtr,
choice: ExternRef<TurnChoice>, choice: ExternRef<TurnChoice>,
out: *mut bool, out: *mut bool,
) { ) -> WasmVoidResult {
script.val().unwrap().prevent_opponent_run_away(choice.not_null(), out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().prevent_opponent_run_away(choice.not_null(), out.as_mut().unwrap()))
} }
fn script_on_end_turn( fn script_on_end_turn(
script: ScriptPtr, script: ScriptPtr,
) { ) -> WasmVoidResult {
script.val().unwrap().on_end_turn(); WasmVoidResult::from_res(script.val().unwrap().on_end_turn())
} }
fn script_on_damage( fn script_on_damage(
@ -605,31 +618,31 @@ mod implementation {
source: DamageSource, source: DamageSource,
old_health: u32, old_health: u32,
new_health: u32, new_health: u32,
) { ) -> WasmVoidResult {
script.val().unwrap().on_damage(pokemon.not_null_rc(), source, old_health, new_health); WasmVoidResult::from_res(script.val().unwrap().on_damage(pokemon.not_null_rc(), source, old_health, new_health))
} }
fn script_on_faint( fn script_on_faint(
script: ScriptPtr, script: ScriptPtr,
pokemon: ExternRef<PokemonImpl>, pokemon: ExternRef<PokemonImpl>,
source: DamageSource, source: DamageSource,
) { ) -> WasmVoidResult {
script.val().unwrap().on_faint(pokemon.not_null_rc(), source); WasmVoidResult::from_res(script.val().unwrap().on_faint(pokemon.not_null_rc(), source))
} }
fn script_on_switch_in( fn script_on_switch_in(
script: ScriptPtr, script: ScriptPtr,
pokemon: ExternRef<PokemonImpl>, pokemon: ExternRef<PokemonImpl>,
) { ) -> WasmVoidResult {
script.val().unwrap().on_switch_in(pokemon.not_null_rc()); WasmVoidResult::from_res(script.val().unwrap().on_switch_in(pokemon.not_null_rc()))
} }
fn script_on_after_held_item_consume( fn script_on_after_held_item_consume(
script: ScriptPtr, script: ScriptPtr,
pokemon: ExternRef<PokemonImpl>, pokemon: ExternRef<PokemonImpl>,
item: ExternRef<ItemImpl> item: ExternRef<ItemImpl>
) { ) -> WasmVoidResult {
script.val().unwrap().on_after_held_item_consume(pokemon.not_null_rc(), item.not_null_rc()); WasmVoidResult::from_res(script.val().unwrap().on_after_held_item_consume(pokemon.not_null_rc(), item.not_null_rc()))
} }
fn script_change_experience_gained( fn script_change_experience_gained(
@ -637,8 +650,12 @@ mod implementation {
fainted_pokemon: ExternRef<PokemonImpl>, fainted_pokemon: ExternRef<PokemonImpl>,
winning_pokemon: ExternRef<PokemonImpl>, winning_pokemon: ExternRef<PokemonImpl>,
out: *mut u32 out: *mut u32
) { ) -> WasmVoidResult {
script.val().unwrap().change_experience_gained(fainted_pokemon.not_null_rc(), winning_pokemon.not_null_rc(), out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().change_experience_gained(
fainted_pokemon.not_null_rc(),
winning_pokemon.not_null_rc(),
out.as_mut().unwrap()
))
} }
fn script_share_experience( fn script_share_experience(
@ -646,16 +663,20 @@ mod implementation {
fainted_pokemon: ExternRef<PokemonImpl>, fainted_pokemon: ExternRef<PokemonImpl>,
winning_pokemon: ExternRef<PokemonImpl>, winning_pokemon: ExternRef<PokemonImpl>,
out: *mut bool, out: *mut bool,
) { ) -> WasmVoidResult {
script.val().unwrap().share_experience(fainted_pokemon.not_null_rc(), winning_pokemon.not_null_rc(), out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().share_experience(
fainted_pokemon.not_null_rc(),
winning_pokemon.not_null_rc(),
out.as_mut().unwrap()
))
} }
fn script_block_weather( fn script_block_weather(
script: ScriptPtr, script: ScriptPtr,
battle: ExternRef<BattleImpl>, battle: ExternRef<BattleImpl>,
out: *mut bool, out: *mut bool,
) { ) -> WasmVoidResult {
script.val().unwrap().block_weather(battle.not_null_rc(), out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().block_weather(battle.not_null_rc(), out.as_mut().unwrap()))
} }
fn script_change_capture_rate_bonus( fn script_change_capture_rate_bonus(
@ -663,8 +684,12 @@ mod implementation {
target: ExternRef<PokemonImpl>, target: ExternRef<PokemonImpl>,
pokeball: ExternRef<ItemImpl>, pokeball: ExternRef<ItemImpl>,
out: *mut u8, out: *mut u8,
) { ) -> WasmVoidResult {
script.val().unwrap().change_capture_rate_bonus(target.not_null_rc(), pokeball.not_null_rc(), out.as_mut().unwrap()); WasmVoidResult::from_res(script.val().unwrap().change_capture_rate_bonus(
target.not_null_rc(),
pokeball.not_null_rc(),
out.as_mut().unwrap()
))
} }
} }
} }

View File

@ -0,0 +1,49 @@
use alloc::string::{String, ToString};
use core::fmt;
use core::fmt::{Debug, Display, Formatter};
use cstr_core::CString;
pub type PkmnResult<T> = Result<T, PkmnErr>;
pub struct PkmnErr {
pub file: &'static str,
pub line: u32,
pub message: String,
}
impl PkmnErr {
pub fn new(file: &'static str, line: u32, message: String) -> Self {
Self {
file,
line,
message,
}
}
}
impl Debug for PkmnErr {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "PkmnErr: {}:{}: {}", self.file, self.line, self.message)
}
}
impl Display for PkmnErr {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "PkmnErr: {}:{}: {}", self.file, self.line, self.message)
}
}
impl From<PkmnErr> for CString {
fn from(val: PkmnErr) -> Self {
CString::new(val.to_string()).unwrap()
}
}
#[macro_export]
macro_rules! pkmn_err {
($message: expr) => {
PkmnErr::new(file!(), line!(), $message.to_string())
};
}
pub use pkmn_err;

View File

@ -1,8 +1,23 @@
use alloc::boxed::Box; use alloc::boxed::Box;
#[macro_export]
#[cfg(feature = "mock_data")]
macro_rules! println {
($($args:tt)*) => {};
}
#[macro_export] #[macro_export]
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
macro_rules! println { ($($args:tt)*) => { crate::utils::print_raw(alloc::format!($($args)*).as_bytes()); } } macro_rules! println { ($($args:tt)*) => { pkmn_lib_interface::utils::print_raw(alloc::format!($($args)*).as_bytes()); } }
#[cfg(not(feature = "mock_data"))]
#[allow(unused_macros)]
macro_rules! println_crate { ($($args:tt)*) => { crate::utils::print_raw(alloc::format!($($args)*).as_bytes()); } }
#[cfg(not(feature = "mock_data"))]
#[allow(unused_macros)]
#[allow(unused_imports)]
pub(crate) use println_crate;
#[macro_export] #[macro_export]
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
@ -18,13 +33,14 @@ macro_rules! dbg {
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
mod implementation { mod implementation {
use alloc::alloc::alloc; use alloc::alloc::alloc;
use alloc::string::ToString;
use core::alloc::Layout; use core::alloc::Layout;
use core::panic::PanicInfo; use core::panic::PanicInfo;
use cstr_core::{c_char, CString}; use cstr_core::{c_char, CString};
extern "wasm" { extern "wasm" {
fn _print(s: *const u8); fn _print(s: *const u8);
fn _error(message: *const u8, file: *const u8, line: u32, position: u32); fn _error(message: *const u8);
} }
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
@ -40,18 +56,11 @@ mod implementation {
#[cfg(not(feature = "mock_data"))] #[cfg(not(feature = "mock_data"))]
#[cfg(not(test))] #[cfg(not(test))]
pub fn begin_panic_handler(panic_info: &PanicInfo<'_>) -> ! { pub fn begin_panic_handler(panic_info: &PanicInfo<'_>) -> ! {
let msg = CString::new(panic_info.message().unwrap().as_str().unwrap()).unwrap(); let payload = panic_info.to_string();
let mut line = 0; let msg = CString::new(payload.as_bytes()).unwrap();
let mut position = 0;
let mut file = CString::default();
if let Some(s) = panic_info.location() {
line = s.line();
position = s.column();
file = CString::new(s.file()).unwrap();
}
unsafe { unsafe {
_error(msg.as_ptr(), file.as_ptr(), line, position); _error(msg.as_ptr());
} }
loop {} loop {}
} }