Rework in line with PkmnLib for moving towards Result
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 => {}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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) }
|
||||
|
||||
Reference in New Issue
Block a user