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
debug-assertions = true
[profile.release.package."*"]
opt-level = "s"
debug-assertions = false

View File

@ -1,12 +1,13 @@
pub use crate::script;
pub use alloc::boxed::Box;
pub use alloc::rc::Rc;
pub use alloc::vec::Vec;
pub use atomic_float::AtomicF32;
pub use core::any::Any;
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::{
get_volatile_as, BattleSide, DamageSource, DynamicLibrary, EffectParameter, ExecutingMove,
Gender, MoveCategory, MoveData, Party, Pokemon, Statistic, StringKey, TurnChoice,
};
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 pkmn_lib_interface::PkmnResult;
script!(Acrobatics, "acrobatics");
@ -21,14 +22,15 @@ impl Script for Acrobatics {
_target: Pokemon,
_hit: u8,
base_power: &mut u8,
) {
if mv.user().held_item().is_none() {
) -> PkmnResult<()> {
if mv.user().held_item()?.is_none() {
if *base_power >= 128_u8 {
*base_power = 255
} else {
*base_power *= 2;
}
}
Ok(())
}
fn as_any(&self) -> &dyn Any {
@ -47,11 +49,11 @@ mod tests {
mv.expect_user().returning(move || {
let mut user = MockPokemon::new();
user.expect_held_item().returning(move || {
if has_held_item {
Ok(if has_held_item {
Some(Rc::new(MockItem::new()))
} else {
None
}
})
});
Rc::new(user)
});
@ -64,7 +66,9 @@ mod tests {
let script = Acrobatics::new();
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);
}
@ -74,7 +78,9 @@ mod tests {
let script = Acrobatics::new();
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);
}
@ -84,7 +90,9 @@ mod tests {
let script = Acrobatics::new();
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);
}
}

View File

@ -1,5 +1,6 @@
use crate::common_usings::*;
use core::mem::transmute;
use pkmn_lib_interface::PkmnResult;
pub struct Acupressure {}
@ -22,14 +23,15 @@ impl Script for Acupressure {
&[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()) {
mv.get_hit_data(&target, hit).fail();
return;
mv.get_hit_data(&target, hit)?.fail()?;
return Ok(());
}
let rand_stat: Statistic =
unsafe { transmute(target.battle().unwrap().random().get_between(1, 6) as u8) };
target.change_stat_boost(rand_stat, 2, false);
unsafe { transmute(target.battle()?.unwrap().random().get_between(1, 6)? as u8) };
target.change_stat_boost(rand_stat, 2, false)?;
Ok(())
}
fn as_any(&self) -> &dyn Any {
@ -56,13 +58,13 @@ mod tests {
mv.expect_user().returning_st(move || user.clone());
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);
mv.expect_get_hit_data()
.returning_st(move |_, _| hit_data.clone());
.returning_st(move |_, _| Ok(hit_data.clone()));
let script = Acupressure::new();
script.on_secondary_effect(Rc::new(mv), u, 0);
script.on_secondary_effect(Rc::new(mv), u, 0).unwrap();
}
#[test]
@ -76,11 +78,11 @@ mod tests {
random.expect_get_between().returning_st(|low, high| {
assert_eq!(1, low);
assert_eq!(6, high);
1
Ok(1)
});
Rc::new(random)
});
Some(Rc::new(battle))
Ok(Some(Rc::new(battle)))
});
user.expect_change_stat_boost()
.once()
@ -88,7 +90,7 @@ mod tests {
assert_eq!(Statistic::Attack, stat);
assert_eq!(2, amount);
assert!(!self_inflicted);
true
Ok(true)
});
let user = Rc::new(user);
@ -98,6 +100,6 @@ mod tests {
mv.expect_user().returning_st(move || user.clone());
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 pkmn_lib_interface::PkmnResult;
pub struct AfterYou {}
@ -21,15 +22,16 @@ impl Script for AfterYou {
&[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()
.battle()?
.unwrap()
.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 {
@ -53,7 +55,7 @@ mod tests {
choice_queue
.expect_move_pokemon_choice_next()
.once()
.return_const(true);
.returning_st(move |_| Ok(true));
Rc::new(choice_queue)
});
@ -62,11 +64,13 @@ mod tests {
target
.expect_battle()
.once()
.return_once_st(move || Some(battle));
.return_once_st(move || Ok(Some(battle)));
let target = Rc::new(target);
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]
@ -77,7 +81,7 @@ mod tests {
choice_queue
.expect_move_pokemon_choice_next()
.once()
.return_const(false);
.returning_st(move |_| Ok(false));
Rc::new(choice_queue)
});
@ -86,18 +90,18 @@ mod tests {
target
.expect_battle()
.once()
.return_once_st(move || Some(battle));
.return_once_st(move || Ok(Some(battle)));
let target = Rc::new(target);
let mut mv = MockExecutingMove::new();
mv.expect_get_hit_data().once().returning_st(move |_, _| {
let mut hit = MockHitData::new();
hit.expect_fail().once();
Rc::new(hit)
hit.expect_fail().returning(|| Ok(())).once();
Ok(Rc::new(hit))
});
let mv = Rc::new(mv);
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 alloc::vec::Vec;
use pkmn_lib_interface::PkmnResult;
script!(Assist, "assist");
impl Assist {
/// 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.
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();
// Iterate over every mon in the party
for mon in party.into_iter().flatten() {
@ -16,7 +17,7 @@ impl Assist {
}
// Iterate over all moves. We make the assumption of 4 moves.
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 {
// Make sure we can copy the move, otherwise add it as possible move.
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]
}
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 battle = user.battle().unwrap();
let party = battle.find_party_for_pokemon(&user);
let battle = user.battle()?.unwrap();
let party = battle.find_party_for_pokemon(&user)?;
if party.is_none() {
choice.fail();
return;
choice.fail()?;
return Ok(());
}
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() {
choice.fail();
return;
choice.fail()?;
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();
Ok(())
}
fn as_any(&self) -> &dyn Any {
@ -93,9 +95,9 @@ mod tests {
.returning_st(move || moves.get(index).unwrap().clone());
Rc::new(move_data)
});
Some(Rc::new(learned_move))
Ok(Some(Rc::new(learned_move)))
} else {
None
Ok(None)
}
});
mon.expect_equals().return_const(equals_user);
@ -105,16 +107,19 @@ mod tests {
#[test]
fn get_party_moves_returns_moves_from_party_length_1() {
let mut party = MockParty::new();
party.expect_length().once().return_const(1usize);
party
.expect_length()
.once()
.returning_st(move || Ok(1usize));
party
.expect_get_pokemon()
.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 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!(moves[0].name(), "tackle".into())
}
@ -122,35 +127,38 @@ mod tests {
#[test]
fn get_party_moves_returns_moves_from_party_length_7() {
let mut party = MockParty::new();
party.expect_length().once().return_const(3usize);
party
.expect_length()
.once()
.returning_st(move || Ok(3usize));
party
.expect_get_pokemon()
.times(3)
.returning_st(move |index| {
if index == 0 {
Some(mock_pokemon_with_moves(
Ok(Some(mock_pokemon_with_moves(
vec!["move1".into(), "move2".into(), "move3".into()],
false,
))
)))
} else if index == 1 {
Some(mock_pokemon_with_moves(
Ok(Some(mock_pokemon_with_moves(
vec!["move1".into(), "move4".into()],
false,
))
)))
} else if index == 2 {
Some(mock_pokemon_with_moves(
Ok(Some(mock_pokemon_with_moves(
vec!["move2".into(), "move5".into()],
false,
))
)))
} else {
None
Ok(None)
}
});
let party: Party = Rc::new(party);
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!(moves[0].name(), "move1".into());
assert_eq!(moves[1].name(), "move2".into());
@ -164,12 +172,15 @@ mod tests {
#[test]
fn get_party_moves_ignores_user() {
let mut party = MockParty::new();
party.expect_length().once().return_const(3usize);
party
.expect_length()
.once()
.returning_st(move || Ok(3usize));
party
.expect_get_pokemon()
.times(3)
.returning_st(move |index| {
if index == 0 {
Ok(if index == 0 {
Some(mock_pokemon_with_moves(
vec!["move1".into(), "move2".into(), "move3".into()],
false,
@ -186,13 +197,13 @@ mod tests {
))
} else {
None
}
})
});
let party: Party = Rc::new(party);
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!(moves[0].name(), "move1".into());
assert_eq!(moves[1].name(), "move2".into());
@ -204,26 +215,31 @@ mod tests {
#[test]
fn get_party_moves_ignores_non_copyable_move() {
let mut party = MockParty::new();
party.expect_length().once().return_const(1usize);
party
.expect_get_pokemon()
.times(1)
.returning_st(move |_| Some(mock_pokemon_with_moves(vec!["chatter".into()], false)));
.expect_length()
.once()
.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 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());
}
#[test]
fn if_moves_found_assist_uses_that_move() {
let mut party = MockParty::new();
party.expect_length().once().return_const(1usize);
party
.expect_length()
.once()
.returning_st(move || Ok(1usize));
party
.expect_get_pokemon()
.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);
@ -243,16 +259,16 @@ mod tests {
let mut p = MockBattleParty::new();
p.expect_party().returning_st(move || party.clone());
Some(Rc::new(p))
Ok(Some(Rc::new(p)))
});
battle.expect_random().returning_st(|| {
let mut random = MockBattleRandom::new();
random.expect_get_max().return_const(0);
random.expect_get_max().returning_st(move |_| Ok(0));
Rc::new(random)
});
Some(Rc::new(battle))
Ok(Some(Rc::new(battle)))
});
Rc::new(user)
@ -270,7 +286,7 @@ mod tests {
let mut move_name: StringKey = "".into();
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())
}
}

View File

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

View File

@ -1,5 +1,6 @@
use crate::common_usings::*;
use crate::pokemon::infatuated::Infatuated;
use pkmn_lib_interface::PkmnResult;
script!(Attract, "attract");
@ -16,19 +17,22 @@ impl Script for Attract {
&[ScriptCapabilities::OnSecondaryEffect]
}
fn on_secondary_effect(&self, mv: ExecutingMove, target: Pokemon, hit: u8) {
let user_gender = mv.user().gender();
let target_gender = target.gender();
fn on_secondary_effect(&self, mv: ExecutingMove, target: Pokemon, hit: u8) -> PkmnResult<()> {
let user_gender = mv.user().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 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
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
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 {

View File

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

View File

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

View File

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

View File

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

View File

@ -15,21 +15,19 @@ impl Script for CurePartyStatus {
&[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();
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 {
let p = party.party();
for index in 0..p.length() {
let mon = p.get_pokemon(index);
if let Some(mon) = mon {
if !mon.equals(&user) {
mon.clear_status();
}
for mon in p.as_ref().into_iter().flatten() {
if !mon.equals(&user) {
mon.clear_status();
}
}
}
Ok(())
}
fn as_any(&self) -> &dyn Any {

View File

@ -23,22 +23,24 @@ impl Script for Drain {
fn on_initialize(
&self,
_library: DynamicLibrary,
parameters: Option<ImmutableList<Rc<EffectParameter>>>,
) {
parameters: Option<Vec<Rc<EffectParameter>>>,
) -> PkmnResult<()> {
self.heal_modifier.store(
parameters.unwrap().get(0).unwrap().as_float(),
Ordering::SeqCst,
);
Ok(())
}
fn on_secondary_effect(&self, mv: ExecutingMove, target: Pokemon, hit: u8) {
let hit_data = mv.get_hit_data(&target, hit);
let damage = hit_data.damage();
fn on_secondary_effect(&self, mv: ExecutingMove, target: Pokemon, hit: u8) -> PkmnResult<()> {
let hit_data = mv.get_hit_data(&target, hit)?;
let damage = hit_data.damage()?;
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;
}
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 {

View File

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

View File

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

View File

@ -21,17 +21,23 @@ impl Script for MultiHitMove {
&[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
// 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 {
0..=34 => 2,
35..=69 => 3,
70..=84 => 4,
85..=100 => 5,
_ => *number_of_hits,
}
};
Ok(())
}
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) {
*number_of_hits = 1
fn change_number_of_hits(
&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;
Ok(())
}
fn change_effectiveness(
@ -34,16 +45,18 @@ impl Script for Struggle {
_target: Pokemon,
_hit: u8,
effectiveness: &mut f32,
) {
) -> PkmnResult<()> {
*effectiveness = 1.0;
Ok(())
}
fn on_secondary_effect(&self, mv: ExecutingMove, _target: Pokemon, _hit: u8) {
let mut damage = mv.user().max_health() / 4;
fn on_secondary_effect(&self, mv: ExecutingMove, _target: Pokemon, _hit: u8) -> PkmnResult<()> {
let mut damage = mv.user().max_health()? / 4;
if damage == 0 {
damage = 1
}
mv.user().damage(damage, DamageSource::Struggle);
mv.user().damage(damage, DamageSource::Struggle)?;
Ok(())
}
fn as_any(&self) -> &dyn Any {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,12 +8,11 @@ edition = "2021"
mock_data = ["mockall"]
[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 }
spin = { version = "0.9.4", default-features = false, features = ["rwlock"] }
paste = { version = "1.0.7" }
hashbrown = { version = "0.12.3" }
hashbrown = { version = "0.13.2" }
dlmalloc = { version = "0.2.4", features = ["global"] }
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 crate::app_interface::list::ImmutableList;
use crate::app_interface::{
BattleParty, BattleRandom, BattleSide, ChoiceQueue, DynamicLibrary, Pokemon, StringKey,
};
use alloc::vec::Vec;
#[cfg_attr(feature = "mock_data", mockall::automock)]
pub trait BattleTrait {
fn library(&self) -> DynamicLibrary;
fn parties(&self) -> ImmutableList<BattleParty>;
fn sides(&self) -> ImmutableList<BattleSide>;
fn parties(&self) -> Vec<BattleParty>;
fn sides(&self) -> Vec<BattleSide>;
fn random(&self) -> BattleRandom;
fn choice_queue(&self) -> ChoiceQueue;
fn get_pokemon(&self, side: u8, index: u8) -> Option<Pokemon>;
fn find_party_for_pokemon(&self, pokemon: &Pokemon) -> Option<BattleParty>;
fn weather_name(&self) -> Option<StringKey>;
fn has_weather(&self, name: &str) -> bool;
fn can_flee(&self) -> bool;
fn number_of_sides(&self) -> u8;
fn pokemon_per_side(&self) -> u8;
fn has_ended(&self) -> bool;
fn has_ended_conclusively(&self) -> bool;
fn winning_side(&self) -> u8;
fn current_turn(&self) -> u32;
fn get_pokemon(&self, side: u8, index: u8) -> PkmnResult<Option<Pokemon>>;
fn find_party_for_pokemon(&self, pokemon: &Pokemon) -> PkmnResult<Option<BattleParty>>;
fn weather_name(&self) -> PkmnResult<Option<StringKey>>;
fn has_weather(&self, name: &str) -> PkmnResult<bool>;
fn can_flee(&self) -> PkmnResult<bool>;
fn number_of_sides(&self) -> PkmnResult<u8>;
fn pokemon_per_side(&self) -> PkmnResult<u8>;
fn has_ended(&self) -> PkmnResult<bool>;
fn has_ended_conclusively(&self) -> PkmnResult<bool>;
fn winning_side(&self) -> PkmnResult<u8>;
fn current_turn(&self) -> PkmnResult<u32>;
}
pub type Battle = Rc<dyn BattleTrait>;
@ -33,26 +33,26 @@ pub type MockBattle = MockBattleTrait;
mod implementation {
use super::*;
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::{
BattleParty, BattlePartyImpl, BattleRandom, BattleRandomImpl, BattleSide, BattleSideImpl,
ChoiceQueue, ChoiceQueueImpl, Pokemon,
};
use crate::handling::cached_value::CachedValue;
use crate::handling::ffi_array::FFIArray;
use crate::handling::wasm_result::WasmResult;
use crate::handling::Cacheable;
use crate::{
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 {
reference: ExternRef<BattleImpl>,
library: CachedValue<DynamicLibrary>,
parties: CachedValue<ImmutableList<BattleParty>>,
sides: CachedValue<ImmutableList<BattleSide>>,
parties: CachedValue<Vec<BattleParty>>,
sides: CachedValue<Vec<BattleSide>>,
random: CachedValue<Rc<BattleRandomImpl>>,
choice_queue: CachedValue<Rc<ChoiceQueueImpl>>,
}
@ -69,21 +69,39 @@ mod implementation {
inner: Rc::new(BattleInner {
reference,
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!({
let reference = battle_get_parties(reference);
Rc::new(BattlePartyImmutableList::from_ref(reference))
let parties: FFIArray<ExternRef<BattlePartyImpl>> =
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!({
let reference = battle_get_sides(reference);
Rc::new(BattleSideImmutableList::from_ref(reference))
let sides: FFIArray<ExternRef<BattleSideImpl>> =
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!({
Rc::new(battle_get_random(reference).get_value().unwrap())
Rc::new(battle_get_random(reference).unwrap().get_value().unwrap())
}),
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 {
cached_value_getters! {
fn library(&self) -> DynamicLibrary;
fn parties(&self) -> ImmutableList<BattleParty>;
fn sides(&self) -> ImmutableList<BattleSide>;
fn parties(&self) -> Vec<BattleParty>;
fn sides(&self) -> Vec<BattleSide>;
fn random(&self) -> BattleRandom;
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 {
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 {
Some(Rc::new(v))
Ok(Some(Rc::new(v)))
} 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 {
let b =
battle_find_party_for_pokemon(self.inner.reference, pokemon.reference().into())
.as_res()?
.get_value();
if let Some(b) = b {
Ok(if let Some(b) = b {
Some(Rc::new(b))
} else {
None
}
})
}
}
fn weather_name(&self) -> Option<StringKey> {
unsafe { battle_get_weather_name(self.inner.reference).get_value() }
fn weather_name(&self) -> PkmnResult<Option<StringKey>> {
unsafe {
Ok(battle_get_weather_name(self.inner.reference)
.as_res()?
.get_value())
}
}
fn has_weather(&self, name: &str) -> bool {
if let Some(weather) = self.weather_name() {
fn has_weather(&self, name: &str) -> PkmnResult<bool> {
if let Some(weather) = self.weather_name()? {
if weather.equals_str(name) {
return true;
return Ok(true);
}
}
false
Ok(false)
}
wasm_value_getters_funcs! {
@ -170,24 +195,29 @@ mod implementation {
#[cfg(not(feature = "mock_data"))]
extern "wasm" {
fn battle_get_library(r: ExternRef<BattleImpl>) -> ExternRef<DynamicLibraryImpl>;
fn battle_get_parties(r: ExternRef<BattleImpl>) -> VecExternRef<BattlePartyImpl>;
fn battle_get_sides(r: ExternRef<BattleImpl>) -> VecExternRef<BattleSideImpl>;
fn battle_get_random(r: ExternRef<BattleImpl>) -> ExternRef<BattleRandomImpl>;
fn battle_get_choice_queue(r: ExternRef<BattleImpl>) -> ExternRef<ChoiceQueueImpl>;
fn battle_get_library(
r: ExternRef<BattleImpl>,
) -> WasmResult<ExternRef<DynamicLibraryImpl>>;
fn battle_get_parties(r: ExternRef<BattleImpl>) -> WasmResult<u64>;
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(
r: ExternRef<BattleImpl>,
side: u8,
index: u8,
) -> ExternRef<PokemonImpl>;
) -> WasmResult<ExternRef<PokemonImpl>>;
fn battle_find_party_for_pokemon(
r: ExternRef<BattleImpl>,
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"))]
pub use implementation::*;

View File

@ -15,6 +15,7 @@ mod implementation {
use crate::app_interface::{BattlePartyTrait, Party, PartyImpl};
use crate::handling::cached_value::CachedValue;
use crate::handling::extern_ref::{ExternRef, ExternalReferenceType};
use crate::handling::wasm_result::WasmResult;
use crate::handling::Cacheable;
use crate::{cached_value, cached_value_getters};
use alloc::rc::Rc;
@ -35,7 +36,12 @@ mod implementation {
inner: Rc::new(BattlePartyInner {
reference,
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"))]
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;
#[cfg_attr(feature = "mock_data", mockall::automock)]
pub trait BattleRandomTrait {
fn get(&self) -> i32;
fn get_max(&self, max: i32) -> i32;
fn get_between(&self, min: i32, max: i32) -> i32;
fn get(&self) -> PkmnResult<i32>;
fn get_max(&self, max: i32) -> PkmnResult<i32>;
fn get_between(&self, min: i32, max: i32) -> PkmnResult<i32>;
}
pub type BattleRandom = Rc<dyn BattleRandomTrait>;
@ -17,6 +18,7 @@ pub use implementation::*;
#[cfg(not(feature = "mock_data"))]
mod implementation {
use super::*;
use crate::handling::wasm_result::WasmResult;
use crate::{ExternRef, ExternalReferenceType};
#[derive(Clone)]
@ -26,16 +28,16 @@ mod implementation {
impl BattleRandomTrait for BattleRandomImpl {
#[cfg(not(feature = "mock_data"))]
fn get(&self) -> i32 {
unsafe { battle_random_get(self.reference) }
fn get(&self) -> PkmnResult<i32> {
unsafe { battle_random_get(self.reference).as_res() }
}
#[cfg(not(feature = "mock_data"))]
fn get_max(&self, max: i32) -> i32 {
unsafe { battle_random_get_max(self.reference, max) }
fn get_max(&self, max: i32) -> PkmnResult<i32> {
unsafe { battle_random_get_max(self.reference, max).as_res() }
}
#[cfg(not(feature = "mock_data"))]
fn get_between(&self, min: i32, max: i32) -> i32 {
unsafe { battle_random_get_between(self.reference, min, max) }
fn get_between(&self, min: i32, max: i32) -> PkmnResult<i32> {
unsafe { battle_random_get_between(self.reference, min, max).as_res() }
}
// TODO: effect_chance()
}
@ -48,9 +50,13 @@ mod implementation {
#[cfg(not(feature = "mock_data"))]
extern "wasm" {
fn battle_random_get(r: ExternRef<BattleRandomImpl>) -> i32;
fn battle_random_get_max(r: ExternRef<BattleRandomImpl>, max: i32) -> i32;
fn battle_random_get_between(r: ExternRef<BattleRandomImpl>, min: i32, max: i32) -> i32;
fn battle_random_get(r: ExternRef<BattleRandomImpl>) -> WasmResult<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,
) -> WasmResult<i32>;
}
}

View File

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

View File

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

View File

@ -15,6 +15,7 @@ mod implementation {
use crate::cached_value;
use crate::handling::cached_value::CachedValue;
use crate::handling::extern_ref::{ExternRef, ExternalReferenceType};
use crate::handling::wasm_result::WasmResult;
use crate::handling::Cacheable;
use alloc::rc::Rc;
@ -36,7 +37,12 @@ mod implementation {
inner: Rc::new(DynamicLibraryInner {
ptr,
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" {
fn dynamic_library_get_static_data(
ptr: ExternRef<DynamicLibraryImpl>,
) -> ExternRef<StaticDataImpl>;
) -> WasmResult<ExternRef<StaticDataImpl>>;
}
}

View File

@ -1,5 +1,6 @@
use crate::app_interface::{LearnedMove, MoveData, Pokemon};
use crate::handling::Script;
use alloc::boxed::Box;
use alloc::rc::Rc;
#[cfg_attr(feature = "mock_data", mockall::automock)]
@ -8,25 +9,25 @@ pub trait ExecutingMoveTrait {
fn user(&self) -> Pokemon;
fn chosen_move(&self) -> LearnedMove;
fn use_move(&self) -> MoveData;
fn move_script<'a>(&'a self) -> Option<&'a dyn Script>;
fn number_of_targets(&self) -> usize;
fn is_pokemon_target(&self, pokemon: &Pokemon) -> bool;
fn get_hit_data(&self, pokemon: &Pokemon, hit: u8) -> HitData;
fn move_script<'a>(&'a self) -> PkmnResult<Option<&'a Box<dyn Script>>>;
fn number_of_targets(&self) -> PkmnResult<usize>;
fn is_pokemon_target(&self, pokemon: &Pokemon) -> PkmnResult<bool>;
fn get_hit_data(&self, pokemon: &Pokemon, hit: u8) -> PkmnResult<HitData>;
}
#[cfg_attr(feature = "mock_data", mockall::automock)]
pub trait HitDataTrait {
fn is_critical(&self) -> bool;
fn base_power(&self) -> u8;
fn effectiveness(&self) -> f32;
fn damage(&self) -> u32;
fn move_type(&self) -> u8;
fn has_failed(&self) -> bool;
fn set_critical(&self, critical: bool);
fn set_effectiveness(&self, effectiveness: f32);
fn set_damage(&self, damage: u32);
fn set_move_type(&self, move_type: u8);
fn fail(&self);
fn is_critical(&self) -> PkmnResult<bool>;
fn base_power(&self) -> PkmnResult<u8>;
fn effectiveness(&self) -> PkmnResult<f32>;
fn damage(&self) -> PkmnResult<u32>;
fn move_type(&self) -> PkmnResult<u8>;
fn has_failed(&self) -> PkmnResult<bool>;
fn set_critical(&self, critical: bool) -> PkmnResult<()>;
fn set_effectiveness(&self, effectiveness: f32) -> PkmnResult<()>;
fn set_damage(&self, damage: u32) -> PkmnResult<()>;
fn set_move_type(&self, move_type: u8) -> PkmnResult<()>;
fn fail(&self) -> PkmnResult<()>;
}
pub type ExecutingMove = Rc<dyn ExecutingMoveTrait>;
@ -37,6 +38,7 @@ pub type HitData = Rc<dyn HitDataTrait>;
#[cfg(feature = "mock_data")]
pub type MockHitData = MockHitDataTrait;
use crate::PkmnResult;
#[cfg(not(feature = "mock_data"))]
pub use implementation::*;
@ -44,10 +46,12 @@ pub use implementation::*;
mod implementation {
use super::*;
use crate::app_interface::{LearnedMoveImpl, MoveDataImpl, PokemonImpl};
use crate::cached_value;
use crate::handling::cached_value::CachedValue;
use crate::handling::extern_ref::{ExternRef, ExternalReferenceType};
use crate::handling::temporary::Temporary;
use crate::handling::wasm_result::WasmResult;
use crate::{cached_value, PkmnResult};
use alloc::boxed::Box;
#[derive(Clone)]
pub struct ExecutingMoveImpl {
@ -71,20 +75,31 @@ mod implementation {
ExecutingMoveInner {
reference,
number_of_hits: cached_value!({
executing_move_get_number_of_hits(reference)
executing_move_get_number_of_hits(reference).unwrap()
}),
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!({
Rc::new(
executing_move_get_chosen_move(reference)
.unwrap()
.get_value()
.unwrap(),
)
}),
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 {
self.inner.value().use_move.value()
}
fn move_script(&self) -> Option<&dyn Script> {
unsafe { executing_move_get_script(self.inner.value().reference).as_ref() }
fn move_script(&self) -> PkmnResult<Option<&Box<dyn Script>>> {
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 {
unsafe { executing_move_get_number_of_targets(self.inner.value().reference) }
fn number_of_targets(&self) -> PkmnResult<usize> {
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 {
executing_move_is_pokemon_target(
self.inner.value().reference,
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 {
Rc::new(
Ok(Rc::new(
executing_move_get_hit_data(
self.inner.value().reference,
pokemon.reference().into(),
hit,
)
.as_res()?
.get_value()
.unwrap(),
)
))
}
}
}
@ -142,39 +165,39 @@ mod implementation {
#[cfg(not(feature = "mock_data"))]
impl HitDataTrait for HitDataImpl {
fn is_critical(&self) -> bool {
unsafe { hit_data_is_critical(self.reference) }
fn is_critical(&self) -> PkmnResult<bool> {
unsafe { hit_data_is_critical(self.reference).as_res() }
}
fn base_power(&self) -> u8 {
unsafe { hit_data_get_base_power(self.reference) }
fn base_power(&self) -> PkmnResult<u8> {
unsafe { hit_data_get_base_power(self.reference).as_res() }
}
fn effectiveness(&self) -> f32 {
unsafe { hit_data_get_effectiveness(self.reference) }
fn effectiveness(&self) -> PkmnResult<f32> {
unsafe { hit_data_get_effectiveness(self.reference).as_res() }
}
fn damage(&self) -> u32 {
unsafe { hit_data_get_damage(self.reference) }
fn damage(&self) -> PkmnResult<u32> {
unsafe { hit_data_get_damage(self.reference).as_res() }
}
fn move_type(&self) -> u8 {
unsafe { hit_data_get_move_type(self.reference) }
fn move_type(&self) -> PkmnResult<u8> {
unsafe { hit_data_get_move_type(self.reference).as_res() }
}
fn has_failed(&self) -> bool {
unsafe { hit_data_is_critical(self.reference) }
fn has_failed(&self) -> PkmnResult<bool> {
unsafe { hit_data_is_critical(self.reference).as_res() }
}
fn set_critical(&self, critical: bool) {
unsafe { hit_data_set_critical(self.reference, critical) }
fn set_critical(&self, critical: bool) -> PkmnResult<()> {
unsafe { hit_data_set_critical(self.reference, critical).as_res() }
}
fn set_effectiveness(&self, effectiveness: f32) {
unsafe { hit_data_set_effectiveness(self.reference, effectiveness) }
fn set_effectiveness(&self, effectiveness: f32) -> PkmnResult<()> {
unsafe { hit_data_set_effectiveness(self.reference, effectiveness).as_res() }
}
fn set_damage(&self, damage: u32) {
unsafe { hit_data_set_damage(self.reference, damage) }
fn set_damage(&self, damage: u32) -> PkmnResult<()> {
unsafe { hit_data_set_damage(self.reference, damage).as_res() }
}
fn set_move_type(&self, move_type: u8) {
unsafe { hit_data_set_move_type(self.reference, move_type) }
fn set_move_type(&self, move_type: u8) -> PkmnResult<()> {
unsafe { hit_data_set_move_type(self.reference, move_type).as_res() }
}
fn fail(&self) {
unsafe { hit_data_fail(self.reference) }
fn fail(&self) -> PkmnResult<()> {
unsafe { hit_data_fail(self.reference).as_res() }
}
}
@ -194,38 +217,47 @@ mod implementation {
#[cfg(not(feature = "mock_data"))]
extern "wasm" {
fn executing_move_get_number_of_targets(r: ExternRef<ExecutingMoveImpl>) -> usize;
fn executing_move_get_number_of_hits(r: ExternRef<ExecutingMoveImpl>) -> u8;
fn executing_move_get_user(r: ExternRef<ExecutingMoveImpl>) -> ExternRef<PokemonImpl>;
fn executing_move_get_number_of_targets(
r: ExternRef<ExecutingMoveImpl>,
) -> 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(
r: ExternRef<ExecutingMoveImpl>,
) -> ExternRef<LearnedMoveImpl>;
fn executing_move_get_use_move(r: ExternRef<ExecutingMoveImpl>) -> ExternRef<MoveDataImpl>;
) -> WasmResult<ExternRef<LearnedMoveImpl>>;
fn executing_move_get_use_move(
r: ExternRef<ExecutingMoveImpl>,
) -> WasmResult<ExternRef<MoveDataImpl>>;
#[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(
r: ExternRef<ExecutingMoveImpl>,
pokemon: ExternRef<PokemonImpl>,
) -> bool;
) -> WasmResult<bool>;
fn executing_move_get_hit_data(
r: ExternRef<ExecutingMoveImpl>,
target: ExternRef<PokemonImpl>,
hit: u8,
) -> ExternRef<HitDataImpl>;
) -> WasmResult<ExternRef<HitDataImpl>>;
fn hit_data_is_critical(r: ExternRef<HitDataImpl>) -> bool;
fn hit_data_get_base_power(r: ExternRef<HitDataImpl>) -> u8;
fn hit_data_get_effectiveness(r: ExternRef<HitDataImpl>) -> f32;
fn hit_data_get_damage(r: ExternRef<HitDataImpl>) -> u32;
fn hit_data_get_move_type(r: ExternRef<HitDataImpl>) -> u8;
fn hit_data_has_failed(r: ExternRef<HitDataImpl>) -> bool;
fn hit_data_is_critical(r: ExternRef<HitDataImpl>) -> WasmResult<bool>;
fn hit_data_get_base_power(r: ExternRef<HitDataImpl>) -> WasmResult<u8>;
fn hit_data_get_effectiveness(r: ExternRef<HitDataImpl>) -> WasmResult<f32>;
fn hit_data_get_damage(r: ExternRef<HitDataImpl>) -> WasmResult<u32>;
fn hit_data_get_move_type(r: ExternRef<HitDataImpl>) -> WasmResult<u8>;
fn hit_data_has_failed(r: ExternRef<HitDataImpl>) -> WasmResult<bool>;
fn hit_data_set_critical(r: ExternRef<HitDataImpl>, critical: bool);
fn hit_data_set_base_power(r: ExternRef<HitDataImpl>, power: u8);
fn hit_data_set_effectiveness(r: ExternRef<HitDataImpl>, effectiveness: f32);
fn hit_data_set_damage(r: ExternRef<HitDataImpl>, damage: u32);
fn hit_data_set_move_type(r: ExternRef<HitDataImpl>, move_type: u8);
fn hit_data_fail(r: ExternRef<HitDataImpl>);
fn hit_data_set_critical(r: ExternRef<HitDataImpl>, critical: bool) -> WasmResult<()>;
fn hit_data_set_base_power(r: ExternRef<HitDataImpl>, power: u8) -> WasmResult<()>;
fn hit_data_set_effectiveness(
r: ExternRef<HitDataImpl>,
effectiveness: f32,
) -> 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::handling::cached_value::CachedValue;
use crate::handling::extern_ref::{ExternRef, ExternalReferenceType};
use crate::handling::wasm_result::WasmResult;
use crate::handling::Cacheable;
use crate::{cached_value, cached_value_getters, wasm_value_getters};
use alloc::rc::Rc;
@ -58,9 +59,16 @@ mod implementation {
inner: Rc::new(LearnedMoveInner {
reference,
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" {
fn learned_move_get_move_data(r: ExternRef<LearnedMoveImpl>) -> ExternRef<MoveDataImpl>;
fn learned_move_get_learn_method(r: ExternRef<LearnedMoveImpl>) -> MoveLearnMethod;
fn learned_move_restore_uses(r: ExternRef<LearnedMoveImpl>, uses: u8);
fn learned_move_restore_all_uses(r: ExternRef<LearnedMoveImpl>);
fn learned_move_get_move_data(
r: ExternRef<LearnedMoveImpl>,
) -> WasmResult<ExternRef<MoveDataImpl>>;
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)]
pub trait PartyTrait {
fn get_pokemon(&self, index: usize) -> Option<Pokemon>;
fn length(&self) -> usize;
fn get_pokemon(&self, index: usize) -> PkmnResult<Option<Pokemon>>;
fn length(&self) -> PkmnResult<usize>;
}
pub type Party = Rc<dyn PartyTrait>;
@ -16,7 +16,10 @@ impl<'a> IntoIterator for &'a dyn PartyTrait {
type IntoIter = ExternIterator<'a, Self::Item>;
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 crate::app_interface::PokemonImpl;
use crate::handling::extern_ref::{ExternRef, ExternalReferenceType};
use crate::handling::wasm_result::WasmResult;
use crate::PkmnResult;
#[derive(Clone)]
pub struct PartyImpl {
@ -41,19 +46,21 @@ mod implementation {
}
impl PartyTrait for PartyImpl {
fn get_pokemon(&self, index: usize) -> Option<Pokemon> {
fn get_pokemon(&self, index: usize) -> PkmnResult<Option<Pokemon>> {
unsafe {
let v = party_get_pokemon(self.reference, index).get_value();
if let Some(v) = v {
let v = party_get_pokemon(self.reference, index)
.as_res()?
.get_value();
Ok(if let Some(v) = v {
Some(Rc::new(v))
} else {
None
}
})
}
}
fn length(&self) -> usize {
unsafe { party_get_length(self.reference) }
fn length(&self) -> PkmnResult<usize> {
unsafe { party_get_length(self.reference).as_res() }
}
}
@ -64,11 +71,15 @@ mod implementation {
}
extern "wasm" {
fn party_get_pokemon(r: ExternRef<PartyImpl>, index: usize) -> ExternRef<PokemonImpl>;
fn party_get_length(r: ExternRef<PartyImpl>) -> usize;
fn party_get_pokemon(
r: ExternRef<PartyImpl>,
index: usize,
) -> WasmResult<ExternRef<PokemonImpl>>;
fn party_get_length(r: ExternRef<PartyImpl>) -> WasmResult<usize>;
}
}
use crate::utils::ExternIterator;
use crate::PkmnResult;
#[cfg(not(feature = "mock_data"))]
pub use implementation::*;

View File

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

View File

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

View File

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

View File

@ -1,22 +1,26 @@
use crate::handling::Script;
use crate::PkmnResult;
use alloc::boxed::Box;
pub trait WithVolatile {
fn has_volatile(&self, script_name: &str) -> bool;
fn add_volatile(&self, script: Box<dyn Script>) -> &dyn Script;
fn add_volatile_by_name(&self, script_name: &str) -> &dyn Script;
fn remove_volatile(&self, script: &dyn Script);
fn get_volatile_script(&self, script_name: &str) -> Option<&dyn Script>;
fn has_volatile(&self, script_name: &str) -> PkmnResult<bool>;
fn add_volatile(&self, script: Box<dyn Script>) -> PkmnResult<&dyn Script>;
fn add_volatile_by_name(&self, script_name: &str) -> PkmnResult<&dyn Script>;
fn remove_volatile(&self, script: &dyn Script) -> PkmnResult<()>;
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
T: Script + 'static,
{
let s = v.get_volatile_script(script_name);
let s = v.get_volatile_script(script_name)?;
if let Some(s) = s {
Some(s.as_any().downcast_ref::<T>().unwrap())
Ok(Some(s.as_any().downcast_ref::<T>().unwrap()))
} 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 list;
pub mod static_data;
pub mod string_key;

View File

@ -9,7 +9,7 @@ pub trait AbilityTrait {
pub type Ability = Rc<dyn AbilityTrait>;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
#[repr(C)]
pub struct AbilityIndex {
pub hidden: bool,
@ -19,21 +19,20 @@ pub struct AbilityIndex {
#[cfg(not(feature = "mock_data"))]
mod implementation {
use super::*;
use crate::app_interface::list::{
EffectParameterImmutableList, ImmutableList, ImmutableListWasm,
};
use crate::app_interface::{EffectParameter, StringKey};
use crate::handling::cached_value::CachedValue;
use crate::handling::extern_ref::{ExternRef, ExternalReferenceType, VecExternRef};
use crate::handling::Cacheable;
use crate::handling::extern_ref::{ExternRef, ExternalReferenceType};
use crate::handling::ffi_array::FFIArray;
use crate::handling::{Cacheable, WasmResult};
use crate::{cached_value, cached_value_getters};
use alloc::rc::Rc;
use alloc::vec::Vec;
struct AbilityInner {
reference: ExternRef<AbilityImpl>,
name: CachedValue<StringKey>,
effect: CachedValue<StringKey>,
parameters: CachedValue<ImmutableList<Rc<EffectParameter>>>,
parameters: CachedValue<Vec<Rc<EffectParameter>>>,
}
#[derive(Clone)]
@ -47,12 +46,21 @@ mod implementation {
Self::from_ref(reference, &|reference| Self {
inner: Rc::new(AbilityInner {
reference,
name: cached_value!({ ability_get_name(reference).get_value().unwrap() }),
effect: cached_value!({ ability_get_effect(reference).get_value().unwrap() }),
name: cached_value!({
ability_get_name(reference).unwrap().get_value().unwrap()
}),
effect: cached_value!({
ability_get_effect(reference).unwrap().get_value().unwrap()
}),
parameters: cached_value!({
Rc::new(EffectParameterImmutableList::from_ref(
ability_get_parameters(reference),
))
let pars: FFIArray<ExternRef<EffectParameter>> =
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"))]
extern "wasm" {
fn ability_get_name(r: ExternRef<AbilityImpl>) -> ExternRef<StringKey>;
fn ability_get_effect(r: ExternRef<AbilityImpl>) -> ExternRef<StringKey>;
fn ability_get_parameters(r: ExternRef<AbilityImpl>) -> VecExternRef<EffectParameter>;
fn ability_get_name(r: ExternRef<AbilityImpl>) -> WasmResult<ExternRef<StringKey>>;
fn ability_get_effect(r: ExternRef<AbilityImpl>) -> WasmResult<ExternRef<StringKey>>;
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::handling::cached_value::CachedValue;
use crate::handling::extern_ref::{ExternRef, ExternalReferenceType};
use crate::handling::Cacheable;
use crate::handling::{Cacheable, WasmResult};
use crate::{cached_value, cached_value_getters};
use spin::RwLock;
@ -60,24 +60,41 @@ mod implementation {
inner: Rc::new(StaticDataInner {
reference,
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!({
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!({
Rc::new(
static_data_get_species_library(reference)
.unwrap()
.get_value()
.unwrap(),
)
}),
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!({
Rc::new(
static_data_get_library_settings(reference)
.unwrap()
.get_value()
.unwrap(),
)
@ -119,7 +136,9 @@ mod implementation {
pub(crate) fn new(ptr: ExternRef<LibrarySettingsImpl>) -> Self {
Self {
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" {
fn static_data_get_move_library(
ptr: ExternRef<StaticDataImpl>,
) -> ExternRef<MoveLibraryImpl>;
) -> WasmResult<ExternRef<MoveLibraryImpl>>;
fn static_data_get_item_library(
ptr: ExternRef<StaticDataImpl>,
) -> ExternRef<ItemLibraryImpl>;
) -> WasmResult<ExternRef<ItemLibraryImpl>>;
fn static_data_get_species_library(
ptr: ExternRef<StaticDataImpl>,
) -> ExternRef<SpeciesLibraryImpl>;
) -> WasmResult<ExternRef<SpeciesLibraryImpl>>;
fn static_data_get_type_library(
ptr: ExternRef<StaticDataImpl>,
) -> ExternRef<TypeLibraryImpl>;
) -> WasmResult<ExternRef<TypeLibraryImpl>>;
fn static_data_get_library_settings(
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
@ -182,14 +203,16 @@ mod implementation {
where
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());
}
let index = Self::_get_ref_by_name(self.get_self_ref(), name.ptr());
let v = Self::_from_external_ref_index(index);
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
}
@ -242,7 +265,7 @@ mod mocked {
where
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>

View File

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

View File

@ -1,9 +1,10 @@
use crate::app_interface::StringKey;
#[cfg(not(feature = "mock_data"))]
use crate::{ExternRef, ExternalReferenceType};
use crate::{handling::WasmResult, ExternRef, ExternalReferenceType, PkmnResult};
use core::fmt::{Display, Formatter};
#[repr(u8)]
#[derive(Copy, Clone)]
enum EffectParameterType {
None,
Bool,
@ -12,6 +13,12 @@ enum EffectParameterType {
String,
}
impl Default for EffectParameterType {
fn default() -> Self {
Self::None
}
}
#[derive(Clone)]
pub enum EffectParameter {
None,
@ -23,18 +30,18 @@ pub enum EffectParameter {
impl EffectParameter {
#[cfg(not(feature = "mock_data"))]
pub(crate) fn new(ptr: ExternRef<Self>) -> Self {
unsafe {
match effect_parameter_get_type(ptr) {
pub(crate) fn new(ptr: ExternRef<Self>) -> PkmnResult<Self> {
Ok(unsafe {
match effect_parameter_get_type(ptr).as_res()? {
EffectParameterType::None => Self::None,
EffectParameterType::Bool => Self::Bool(effect_parameter_as_bool(ptr)),
EffectParameterType::Int => Self::Int(effect_parameter_as_int(ptr)),
EffectParameterType::Float => Self::Float(effect_parameter_as_float(ptr)),
EffectParameterType::Bool => Self::Bool(effect_parameter_as_bool(ptr).as_res()?),
EffectParameterType::Int => Self::Int(effect_parameter_as_int(ptr).as_res()?),
EffectParameterType::Float => Self::Float(effect_parameter_as_float(ptr).as_res()?),
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 {
@ -72,7 +79,7 @@ impl ExternalReferenceType for EffectParameter {
where
Self: Sized,
{
EffectParameter::new(reference)
EffectParameter::new(reference).unwrap()
}
}
@ -92,9 +99,13 @@ impl Display for EffectParameter {
#[cfg(not(feature = "mock_data"))]
extern "wasm" {
fn effect_parameter_get_type(ptr: ExternRef<EffectParameter>) -> EffectParameterType;
fn effect_parameter_as_bool(ptr: ExternRef<EffectParameter>) -> bool;
fn effect_parameter_as_int(ptr: ExternRef<EffectParameter>) -> i64;
fn effect_parameter_as_float(ptr: ExternRef<EffectParameter>) -> f32;
fn effect_parameter_as_string(ptr: ExternRef<EffectParameter>) -> ExternRef<StringKey>;
fn effect_parameter_get_type(
ptr: ExternRef<EffectParameter>,
) -> WasmResult<EffectParameterType>;
fn effect_parameter_as_bool(ptr: ExternRef<EffectParameter>) -> WasmResult<bool>;
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,
}
impl Default for ItemCategory {
fn default() -> Self {
Self::MiscItem
}
}
/// A battle item category defines how the item is categorized when in battle.
#[repr(u8)]
#[derive(Clone)]
@ -39,6 +45,12 @@ pub enum BattleItemCategory {
MiscBattleItem,
}
impl Default for BattleItemCategory {
fn default() -> Self {
Self::None
}
}
#[cfg_attr(feature = "mock_data", mockall::automock)]
pub trait ItemTrait {
fn reference(&self) -> u32;
@ -50,7 +62,7 @@ pub trait ItemTrait {
fn battle_category(&self) -> BattleItemCategory;
/// The buying value of the item.
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>;
@ -62,8 +74,8 @@ mod implementation {
use crate::app_interface::{BattleItemCategory, ItemCategory, ItemTrait, StringKey};
use crate::handling::cached_value::CachedValue;
use crate::handling::extern_ref::{ExternRef, ExternalReferenceType};
use crate::handling::Cacheable;
use crate::{cached_value, cached_value_getters};
use crate::handling::{Cacheable, WasmResult};
use crate::{cached_value, cached_value_getters, PkmnResult};
use alloc::rc::Rc;
struct ItemInner {
@ -86,10 +98,12 @@ mod implementation {
Self::from_ref(reference, &|reference| Self {
inner: Rc::new(ItemInner {
reference,
name: cached_value!({ StringKey::new(item_get_name(reference)) }),
category: cached_value!({ item_get_category(reference) }),
battle_category: cached_value!({ item_get_battle_category(reference) }),
price: cached_value!({ item_get_price(reference) }),
name: cached_value!({ StringKey::new(item_get_name(reference).unwrap()) }),
category: cached_value!({ item_get_category(reference).unwrap() }),
battle_category: cached_value!({
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 has_flag(&self, flag: &StringKey) -> bool {
unsafe { item_has_flag(self.inner.reference, flag.ptr()) }
fn has_flag(&self, flag: &StringKey) -> PkmnResult<bool> {
unsafe { item_has_flag(self.inner.reference, flag.ptr()).as_res() }
}
}
@ -131,13 +145,14 @@ mod implementation {
}
extern "wasm" {
fn item_get_name(ptr: ExternRef<ItemImpl>) -> ExternRef<StringKey>;
fn item_get_category(ptr: ExternRef<ItemImpl>) -> ItemCategory;
fn item_get_battle_category(ptr: ExternRef<ItemImpl>) -> BattleItemCategory;
fn item_get_price(ptr: ExternRef<ItemImpl>) -> i32;
fn item_has_flag(ptr: ExternRef<ItemImpl>, flag: ExternRef<StringKey>) -> bool;
fn item_get_name(ptr: ExternRef<ItemImpl>) -> WasmResult<ExternRef<StringKey>>;
fn item_get_category(ptr: ExternRef<ItemImpl>) -> WasmResult<ItemCategory>;
fn item_get_battle_category(ptr: ExternRef<ItemImpl>) -> WasmResult<BattleItemCategory>;
fn item_get_price(ptr: ExternRef<ItemImpl>) -> WasmResult<i32>;
fn item_has_flag(ptr: ExternRef<ItemImpl>, flag: ExternRef<StringKey>) -> WasmResult<bool>;
}
}
use crate::PkmnResult;
#[cfg(not(feature = "mock_data"))]
pub use implementation::*;

View File

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

View File

@ -14,7 +14,7 @@ pub type Nature = Rc<dyn NatureTrait>;
mod implementation {
use super::*;
use crate::handling::extern_ref::{ExternRef, ExternalReferenceType};
use crate::handling::Cacheable;
use crate::handling::{Cacheable, WasmResult};
struct NatureInner {
reference: ExternRef<NatureImpl>,
@ -41,10 +41,10 @@ mod implementation {
Self {
inner: Rc::new(NatureInner {
reference,
increase_stat: nature_get_increase_stat(reference),
decrease_stat: nature_get_decrease_stat(reference),
increase_modifier: nature_get_increase_modifier(reference),
decrease_modifier: nature_get_decrease_modifier(reference),
increase_stat: nature_get_increase_stat(reference).unwrap(),
decrease_stat: nature_get_decrease_stat(reference).unwrap(),
increase_modifier: nature_get_increase_modifier(reference).unwrap(),
decrease_modifier: nature_get_decrease_modifier(reference).unwrap(),
}),
}
})
@ -76,10 +76,10 @@ mod implementation {
}
extern "wasm" {
fn nature_get_increase_stat(r: ExternRef<NatureImpl>) -> Statistic;
fn nature_get_decrease_stat(r: ExternRef<NatureImpl>) -> Statistic;
fn nature_get_increase_modifier(r: ExternRef<NatureImpl>) -> f32;
fn nature_get_decrease_modifier(r: ExternRef<NatureImpl>) -> f32;
fn nature_get_increase_stat(r: ExternRef<NatureImpl>) -> WasmResult<Statistic>;
fn nature_get_decrease_stat(r: ExternRef<NatureImpl>) -> WasmResult<Statistic>;
fn nature_get_increase_modifier(r: ExternRef<NatureImpl>) -> WasmResult<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 alloc::rc::Rc;
use alloc::vec::Vec;
use core::any::Any;
#[repr(u8)]
#[derive(Eq, PartialEq, Debug)]
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub enum Gender {
Male = 0,
Female = 1,
Genderless = 2,
}
impl Default for Gender {
fn default() -> Self {
Self::Genderless
}
}
pub trait FormTrait {
fn name(&self) -> StringKey;
fn height(&self) -> f32;
fn weight(&self) -> f32;
fn base_experience(&self) -> u32;
fn base_stats(&self) -> ImmutableStatisticSet;
fn abilities(&self) -> ImmutableList<Rc<StringKey>>;
fn hidden_abilities(&self) -> ImmutableList<Rc<StringKey>>;
fn abilities(&self) -> Vec<Rc<StringKey>>;
fn hidden_abilities(&self) -> Vec<Rc<StringKey>>;
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;
}
@ -39,7 +44,7 @@ pub trait SpeciesTrait {
/// uncatchable.
fn capture_rate(&self) -> u8;
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;
}
@ -50,13 +55,13 @@ pub type Species = Rc<dyn SpeciesTrait>;
#[cfg(not(feature = "mock_data"))]
mod implementation {
use super::*;
use crate::app_interface::list::ImmutableListWasm;
use crate::app_interface::{get_hash, ImmutableStatisticSetImpl};
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::wasm_result::WasmResult;
use crate::handling::Cacheable;
use crate::{cached_value, cached_value_getters};
use crate::{cached_value, cached_value_getters, PkmnResult};
use spin::RwLock;
struct FormInner {
@ -67,8 +72,8 @@ mod implementation {
types: CachedValue<Vec<u8>>,
base_experience: CachedValue<u32>,
base_stats: CachedValue<ImmutableStatisticSet>,
abilities: CachedValue<ImmutableList<Rc<StringKey>>>,
hidden_abilities: CachedValue<ImmutableList<Rc<StringKey>>>,
abilities: CachedValue<Vec<Rc<StringKey>>>,
hidden_abilities: CachedValue<Vec<Rc<StringKey>>>,
// moves: CachedValue<LearnableMoves>,
}
@ -82,30 +87,38 @@ mod implementation {
Self::from_ref(reference, &|reference| Self {
inner: Rc::new(FormInner {
reference,
name: cached_value!({ form_get_name(reference).get_value().unwrap() }),
height: cached_value!({ form_get_height(reference) }),
weight: cached_value!({ form_get_weight(reference) }),
name: cached_value!({ form_get_name(reference).unwrap().get_value().unwrap() }),
height: cached_value!({ form_get_height(reference).unwrap() }),
weight: cached_value!({ form_get_weight(reference).unwrap() }),
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())
}),
base_experience: cached_value!({ form_get_base_experience(reference) }),
base_experience: cached_value!({
form_get_base_experience(reference).unwrap()
}),
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!({
Rc::new(
crate::app_interface::list::StringKeyImmutableList::from_ref(
form_get_abilities(reference),
),
)
let abilities: FFIArray<ExternRef<StringKey>> =
FFIArray::from_u64(form_get_abilities(reference).unwrap());
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!({
Rc::new(
crate::app_interface::list::StringKeyImmutableList::from_ref(
form_get_hidden_abilities(reference),
),
)
let abilities: FFIArray<ExternRef<StringKey>> =
FFIArray::from_u64(form_get_hidden_abilities(reference).unwrap());
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 base_experience(&self) -> u32;
fn base_stats(&self) -> ImmutableStatisticSet;
fn abilities(&self) -> ImmutableList<Rc<StringKey>>;
fn hidden_abilities(&self) -> ImmutableList<Rc<StringKey>>;
fn abilities(&self) -> Vec<Rc<StringKey>>;
fn hidden_abilities(&self) -> Vec<Rc<StringKey>>;
}
fn types(&self) -> &Vec<u8> {
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);
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 {
@ -160,13 +173,18 @@ mod implementation {
Self {
inner: Rc::new(SpeciesInner {
reference,
id: cached_value!({ species_get_id(reference) }),
name: cached_value!({ species_get_name(reference).get_value().unwrap() }),
gender_rate: cached_value!({ species_get_gender_rate(reference) }),
growth_rate: cached_value!({
species_get_growth_rate(reference).get_value().unwrap()
id: cached_value!({ species_get_id(reference).unwrap() }),
name: cached_value!({
species_get_name(reference).unwrap().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(),
}),
}
@ -198,7 +216,7 @@ mod implementation {
if let Some(v) = self.inner.forms.read().get(&hash) {
v.clone()
} 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: Option<Form> = if let Some(value) = 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);
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 {
@ -237,25 +255,31 @@ mod implementation {
crate::handling::cacheable::cacheable!(SpeciesImpl);
extern "wasm" {
fn form_get_name(r: ExternRef<FormImpl>) -> ExternRef<StringKey>;
fn form_get_height(r: ExternRef<FormImpl>) -> f32;
fn form_get_weight(r: ExternRef<FormImpl>) -> f32;
fn form_get_types(r: ExternRef<FormImpl>) -> FFIArray<u8>;
fn form_get_base_experience(r: ExternRef<FormImpl>) -> u32;
fn form_get_base_stats(r: ExternRef<FormImpl>) -> ExternRef<ImmutableStatisticSetImpl>;
fn form_get_abilities(r: ExternRef<FormImpl>) -> VecExternRef<StringKey>;
fn form_get_hidden_abilities(r: ExternRef<FormImpl>) -> VecExternRef<StringKey>;
fn form_has_flag_by_hash(r: ExternRef<FormImpl>, hash: u32) -> bool;
fn form_get_name(r: ExternRef<FormImpl>) -> WasmResult<ExternRef<StringKey>>;
fn form_get_height(r: ExternRef<FormImpl>) -> WasmResult<f32>;
fn form_get_weight(r: ExternRef<FormImpl>) -> WasmResult<f32>;
fn form_get_types(r: ExternRef<FormImpl>) -> WasmResult<u64>;
fn form_get_base_experience(r: ExternRef<FormImpl>) -> WasmResult<u32>;
fn form_get_base_stats(
r: ExternRef<FormImpl>,
) -> WasmResult<ExternRef<ImmutableStatisticSetImpl>>;
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_name(r: ExternRef<SpeciesImpl>) -> ExternRef<StringKey>;
fn species_get_gender_rate(r: ExternRef<SpeciesImpl>) -> f32;
fn species_get_growth_rate(r: ExternRef<SpeciesImpl>) -> ExternRef<StringKey>;
fn species_get_capture_rate(r: ExternRef<SpeciesImpl>) -> u8;
fn species_get_form_by_hash(r: ExternRef<SpeciesImpl>, hash: u32) -> ExternRef<FormImpl>;
fn species_has_flag_by_hash(r: ExternRef<SpeciesImpl>, flag_hash: u32) -> bool;
fn species_get_id(r: ExternRef<SpeciesImpl>) -> WasmResult<u16>;
fn species_get_name(r: ExternRef<SpeciesImpl>) -> WasmResult<ExternRef<StringKey>>;
fn species_get_gender_rate(r: ExternRef<SpeciesImpl>) -> WasmResult<f32>;
fn species_get_growth_rate(r: ExternRef<SpeciesImpl>) -> WasmResult<ExternRef<StringKey>>;
fn species_get_capture_rate(r: ExternRef<SpeciesImpl>) -> WasmResult<u8>;
fn species_get_form_by_hash(
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"))]
pub use implementation::*;

View File

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

View File

@ -1,7 +1,12 @@
#[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::PkmnResult;
#[cfg(not(feature = "mock_data"))]
use crate::{ExternRef, ExternalReferenceType};
use crate::{pkmn_err, ExternRef, ExternalReferenceType, PkmnErr};
use alloc::rc::Rc;
use core::cell::RefCell;
use core::fmt::{Debug, Display, Formatter};
@ -21,7 +26,10 @@ pub struct StringKey {
impl Debug for StringKey {
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"))]
pub fn str(&self) -> &CString {
pub fn str(&self) -> PkmnResult<&CString> {
if self.data.str.borrow().is_none() {
unsafe {
self.data
.str
.replace(Some(CString::from_raw(string_key_get_str(self.ptr()))));
let ptr = string_key_get_str(self.ptr()).as_res()?;
let ptr = ptr as *mut cstr_core::c_char;
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")]
pub fn str(&self) -> &CString {
unsafe { (*self.data.str.as_ptr()).as_ref().unwrap() }
pub fn str(&self) -> PkmnResult<&CString> {
Ok(unsafe { (*self.data.str.as_ptr()).as_ref().unwrap() })
}
#[cfg(not(feature = "mock_data"))]
pub fn hash(&self) -> u32 {
pub fn hash(&self) -> PkmnResult<u32> {
if self.data.hash.borrow().is_none() {
unsafe {
self.data
.hash
.replace(Some(string_key_get_hash(self.ptr())));
let hash = string_key_get_hash(self.ptr()).as_res()?;
self.data.hash.replace(Some(hash));
}
}
self.data.hash.borrow().unwrap()
Ok(self.data.hash.borrow().unwrap())
}
#[cfg(feature = "mock_data")]
pub fn hash(&self) -> u32 {
self.data.hash.borrow().unwrap()
pub fn hash(&self) -> PkmnResult<u32> {
Ok(self.data.hash.borrow().unwrap())
}
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 {
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())
}
}
#[cfg(not(feature = "mock_data"))]
extern "wasm" {
fn string_key_get_str(ptr: ExternRef<StringKey>) -> *mut cstr_core::c_char;
fn string_key_get_hash(ptr: ExternRef<StringKey>) -> u32;
fn string_key_get_str(ptr: ExternRef<StringKey>) -> WasmResult<u32>;
fn string_key_get_hash(ptr: ExternRef<StringKey>) -> WasmResult<u32>;
}
const CRC_TABLE: &[u32] = &[

View File

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

View File

@ -1,8 +1,6 @@
use alloc::rc::Rc;
use core::cmp::Ordering;
use core::hash::{Hash, Hasher};
#[cfg(not(feature = "mock_data"))]
use core::intrinsics::transmute;
use core::marker::PhantomData;
#[repr(C)]
@ -82,6 +80,15 @@ impl<T> Clone 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> 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 {
fn from_extern_value(reference: ExternRef<Self>) -> Self
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);
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"))]

View File

@ -8,6 +8,7 @@ pub mod ffi_array;
pub mod script;
#[cfg(not(feature = "mock_data"))]
pub(crate) mod temporary;
pub(crate) mod wasm_result;
pub use capabilities::*;
@ -15,6 +16,7 @@ pub use capabilities::*;
pub(crate) use cacheable::Cacheable;
pub use script::Script;
pub use script::ScriptOwner;
pub use wasm_result::*;
#[repr(u8)]
pub enum ScriptCategory {
@ -41,7 +43,7 @@ macro_rules! wasm_reference_getters_extern {
extern "wasm" {
$(
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" {
$(
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" {
$(
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])*
$v fn $name(&self) -> $type {
$v fn $name(&self) -> PkmnResult<$type> {
paste::paste!{
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::{
Battle, BattleSide, DamageSource, DynamicLibrary, EffectParameter, ExecutingMove, Item,
Pokemon, Statistic, TurnChoice, TypeIdentifier,
@ -6,8 +5,10 @@ use crate::app_interface::{
use crate::handling::ScriptCapabilities;
use crate::StringKey;
use alloc::rc::Rc;
use alloc::vec::Vec;
use core::any::Any;
use core::fmt::{Debug, Display, Formatter};
type Result<T> = crate::result::PkmnResult<T>;
pub trait Script {
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
/// 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.
fn on_remove(&self) {}
fn on_remove(&self) -> Result<()> {
Ok(())
}
/// This function is ran when this script starts being in effect.
fn on_initialize(
&self,
_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,
/// 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.
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
/// 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
/// 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.
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
/// 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
/// gets used as the number of hits. If set to 0, this will behave as if the move missed on its
/// 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
/// 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,
/// 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
/// 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.
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
/// 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.
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
/// 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.
fn change_move_type(
&self,
@ -77,7 +117,8 @@ pub trait Script {
_target: Pokemon,
_hit: u8,
_move_type: &mut TypeIdentifier,
) {
) -> Result<()> {
Ok(())
}
/// This function allows the script to change how effective a move is on a target.
fn change_effectiveness(
@ -86,7 +127,8 @@ pub trait Script {
_target: Pokemon,
_hit: u8,
_effectiveness: &mut f32,
) {
) -> Result<()> {
Ok(())
}
/// This function allows a script to block an outgoing move from being critical.
fn block_critical(
@ -95,7 +137,8 @@ pub trait Script {
_target: Pokemon,
_hit: u8,
_block_critical: &mut bool,
) {
) -> Result<()> {
Ok(())
}
/// This function allows a script to block an incoming move from being critical.
fn block_incoming_critical(
@ -104,7 +147,8 @@ pub trait Script {
_target: Pokemon,
_hit: u8,
_block_critical: &mut bool,
) {
) -> Result<()> {
Ok(())
}
/// 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.
@ -114,7 +158,8 @@ pub trait Script {
_target: Pokemon,
_hit: u8,
_accuracy: &mut u8,
) {
) -> Result<()> {
Ok(())
}
/// This function allows a script to change the critical stage of the move used.
@ -124,7 +169,8 @@ pub trait Script {
_target: Pokemon,
_hit: u8,
_stage: &mut u8,
) {
) -> Result<()> {
Ok(())
}
/// This function allows a script to change the damage modifier of a critical hit. This will only
/// run when a hit is critical.
@ -134,7 +180,8 @@ pub trait Script {
_target: Pokemon,
_hit: u8,
_modifier: &mut f32,
) {
) -> Result<()> {
Ok(())
}
/// 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.
@ -144,7 +191,8 @@ pub trait Script {
_target: Pokemon,
_hit: u8,
_modifier: &mut f32,
) {
) -> Result<()> {
Ok(())
}
/// This function allows a script to change the effective base power of a move hit.
@ -154,7 +202,8 @@ pub trait Script {
_target: Pokemon,
_hit: u8,
_base_power: &mut u8,
) {
) -> Result<()> {
Ok(())
}
/// This function allows a script to bypass defensive stat boosts for a move hit.
fn bypass_defensive_stat_boost(
@ -163,7 +212,8 @@ pub trait Script {
_target: Pokemon,
_hit: u8,
_bypass: &mut bool,
) {
) -> Result<()> {
Ok(())
}
/// This function allows a script to bypass offensive stat boosts for a move hit.
fn bypass_offensive_stat_boost(
@ -172,7 +222,8 @@ pub trait Script {
_target: Pokemon,
_hit: u8,
_bypass: &mut bool,
) {
) -> Result<()> {
Ok(())
}
/// This function allows a script to change the actual offensive stat values used when calculating damage
fn change_offensive_stat_value(
@ -181,7 +232,8 @@ pub trait Script {
_target: Pokemon,
_hit: u8,
_amount: &mut u32,
) {
) -> Result<()> {
Ok(())
}
/// This function allows a script to change the actual defensive stat values used when calculating damage.
fn change_defensive_stat_value(
@ -190,7 +242,8 @@ pub trait Script {
_target: Pokemon,
_hit: u8,
_amount: &mut u32,
) {
) -> Result<()> {
Ok(())
}
/// 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,
_hit: u8,
_modifier: &mut f32,
) {
) -> Result<()> {
Ok(())
}
/// This function allows a script to apply a raw multiplier to the damage done by a move.
fn change_damage_modifier(
@ -210,10 +264,19 @@ pub trait Script {
_target: Pokemon,
_hit: u8,
_modifier: &mut f32,
) {
) -> Result<()> {
Ok(())
}
/// 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.
fn change_incoming_damage(
&self,
@ -221,13 +284,18 @@ pub trait Script {
_target: Pokemon,
_hit: u8,
_damage: &mut u32,
) {
) -> Result<()> {
Ok(())
}
/// This function triggers when an incoming hit happens. This triggers after the damage is done,
/// 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.
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
/// changes on that Pokemon.
fn prevent_stat_boost_change(
@ -237,7 +305,8 @@ pub trait Script {
_amount: i8,
_self_inflicted: bool,
_prevent: &mut bool,
) {
) -> Result<()> {
Ok(())
}
/// 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
@ -248,7 +317,8 @@ pub trait Script {
_stat: Statistic,
_self_inflicted: bool,
_amount: &mut i8,
) {
) -> Result<()> {
Ok(())
}
/// 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
@ -259,7 +329,8 @@ pub trait Script {
_target: Pokemon,
_hit: u8,
_prevent: &mut bool,
) {
) -> Result<()> {
Ok(())
}
/// 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
@ -271,7 +342,8 @@ pub trait Script {
_target: Pokemon,
_hit: u8,
_chance: &mut f32,
) {
) -> Result<()> {
Ok(())
}
/// 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,
@ -283,30 +355,49 @@ pub trait Script {
_target: Pokemon,
_hit: u8,
_chance: &mut f32,
) {
) -> Result<()> {
Ok(())
}
/// 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
/// 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.
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.
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.
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.
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.
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
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.
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
/// running. Note that choices are not active anymore here, so their scripts do not call this
/// 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.
fn on_damage(
&self,
@ -314,16 +405,23 @@ pub trait Script {
_source: DamageSource,
_old_health: u32,
_new_health: u32,
) {
) -> Result<()> {
Ok(())
}
/// 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
/// 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
/// 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,
/// and allows for changing this amount of experience.
fn change_experience_gained(
@ -331,18 +429,35 @@ pub trait Script {
_fainted_mon: Pokemon,
_winning_mon: Pokemon,
_amount: &mut u32,
) {
) -> Result<()> {
Ok(())
}
/// 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.
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
/// 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
/// rate of this attempt. Pokeball modifier effects should be implemented here, as well as for
/// 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;

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