Initial work on rune as scripting library
continuous-integration/drone/push Build is failing
Details
continuous-integration/drone/push Build is failing
Details
This commit is contained in:
parent
6379abf446
commit
67b0abe59f
10
Cargo.toml
10
Cargo.toml
|
@ -16,7 +16,8 @@ path = "src/lib.rs"
|
|||
ffi = []
|
||||
serde = ["dep:serde", "dep:serde-xml-rs", "atomig/serde"]
|
||||
wasm = ["dep:wasmer"]
|
||||
default = ["serde", "wasm", "ffi"]
|
||||
rune = ["dep:rune"]
|
||||
default = ["serde", "rune", "ffi"]
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 0
|
||||
|
@ -55,7 +56,6 @@ parking_lot = "0.12"
|
|||
serde = { version = "1.0", optional = true, features = ["derive"] }
|
||||
serde_repr = "0.1"
|
||||
serde-xml-rs = { version = "0.6", optional = true }
|
||||
wasmer = { version = "4.2", optional = true, default-features = false, features = ["sys", "wat", "llvm"] }
|
||||
uuid = "1.5"
|
||||
paste = { version = "1.0" }
|
||||
arcstr = { version = "1.1", features = ["std"] }
|
||||
|
@ -65,6 +65,9 @@ anyhow_ext = "0.2"
|
|||
thiserror = "1.0"
|
||||
stdext = "0.3"
|
||||
|
||||
wasmer = { version = "4.2", optional = true, default-features = false, features = ["sys", "wat", "llvm"] }
|
||||
rune = { version = "0.13.2", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
csv = "1.3"
|
||||
project-root = "0.2"
|
||||
|
@ -73,4 +76,5 @@ serde_json = "1.0"
|
|||
serde_plain = "1.0"
|
||||
# Allow us to assert whether floats are approximately a value
|
||||
assert_approx_eq = "1.1"
|
||||
mockall = "0.11"
|
||||
mockall = "0.12"
|
||||
walkdir = "2.3"
|
|
@ -1 +1,2 @@
|
|||
max_width = 120
|
||||
max_width = 120
|
||||
fn_single_line = true
|
|
@ -47,7 +47,7 @@ impl Gen7MiscLibrary {
|
|||
Some(Arc::new(SecondaryEffectImpl::new(
|
||||
-1.0,
|
||||
StringKey::new("struggle"),
|
||||
vec![],
|
||||
Default::default(),
|
||||
))),
|
||||
HashSet::new(),
|
||||
));
|
||||
|
|
|
@ -33,59 +33,34 @@ pub struct HitData {
|
|||
|
||||
impl HitData {
|
||||
/// Whether or not the hit is critical.
|
||||
pub fn is_critical(&self) -> bool {
|
||||
self.critical.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn is_critical(&self) -> bool { self.critical.load(Ordering::Relaxed) }
|
||||
/// The base power of the hit.
|
||||
pub fn base_power(&self) -> u8 {
|
||||
self.base_power.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn base_power(&self) -> u8 { self.base_power.load(Ordering::Relaxed) }
|
||||
/// The type effectiveness of the hit.
|
||||
pub fn effectiveness(&self) -> f32 {
|
||||
self.effectiveness.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn effectiveness(&self) -> f32 { self.effectiveness.load(Ordering::Relaxed) }
|
||||
/// The actual damage of the hit.
|
||||
pub fn damage(&self) -> u32 {
|
||||
self.damage.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn damage(&self) -> u32 { self.damage.load(Ordering::Relaxed) }
|
||||
/// The type id of the type used for the hit.
|
||||
pub fn move_type(&self) -> TypeIdentifier {
|
||||
self.move_type.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn move_type(&self) -> TypeIdentifier { self.move_type.load(Ordering::Relaxed) }
|
||||
/// Whether or not the hit has failed.
|
||||
pub fn has_failed(&self) -> bool {
|
||||
self.has_failed.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn has_failed(&self) -> bool { self.has_failed.load(Ordering::Relaxed) }
|
||||
|
||||
/// Sets whether or not the hit is critical.
|
||||
pub fn set_critical(&self, value: bool) {
|
||||
self.critical.store(value, Ordering::SeqCst);
|
||||
}
|
||||
pub fn set_critical(&self, value: bool) { self.critical.store(value, Ordering::SeqCst); }
|
||||
/// Sets the base power of the hit.
|
||||
pub fn set_base_power(&self, value: u8) {
|
||||
self.base_power.store(value, Ordering::SeqCst);
|
||||
}
|
||||
pub fn set_base_power(&self, value: u8) { self.base_power.store(value, Ordering::SeqCst); }
|
||||
/// Sets the type effectiveness of the hit.
|
||||
pub fn set_effectiveness(&self, value: f32) {
|
||||
self.effectiveness.store(value, Ordering::SeqCst);
|
||||
}
|
||||
pub fn set_effectiveness(&self, value: f32) { self.effectiveness.store(value, Ordering::SeqCst); }
|
||||
/// Sets the actual damage of the hit.
|
||||
pub fn set_damage(&self, value: u32) {
|
||||
self.damage.store(value, Ordering::SeqCst);
|
||||
}
|
||||
pub fn set_damage(&self, value: u32) { self.damage.store(value, Ordering::SeqCst); }
|
||||
/// Sets the move type id of the hit.
|
||||
pub fn set_move_type(&self, value: TypeIdentifier) {
|
||||
self.move_type.store(value, Ordering::SeqCst);
|
||||
}
|
||||
pub fn set_move_type(&self, value: TypeIdentifier) { self.move_type.store(value, Ordering::SeqCst); }
|
||||
/// Marks the hit as failed.
|
||||
pub fn fail(&self) {
|
||||
self.has_failed.store(true, Ordering::SeqCst);
|
||||
}
|
||||
pub fn fail(&self) { self.has_failed.store(true, Ordering::SeqCst); }
|
||||
}
|
||||
|
||||
/// An executing move is the data of the move for while it is executing.
|
||||
#[derive(Debug)]
|
||||
|
||||
pub struct ExecutingMove {
|
||||
/// The number of hits this move has.
|
||||
number_of_hits: u8,
|
||||
|
@ -134,29 +109,17 @@ impl ExecutingMove {
|
|||
}
|
||||
|
||||
/// The number of targets this move has.
|
||||
pub fn target_count(&self) -> usize {
|
||||
self.targets.len()
|
||||
}
|
||||
pub fn target_count(&self) -> usize { self.targets.len() }
|
||||
/// The number of hits this move has per target.
|
||||
pub fn number_of_hits(&self) -> u8 {
|
||||
self.number_of_hits
|
||||
}
|
||||
pub fn number_of_hits(&self) -> u8 { self.number_of_hits }
|
||||
/// The user of the move.
|
||||
pub fn user(&self) -> &Pokemon {
|
||||
&self.user
|
||||
}
|
||||
pub fn user(&self) -> &Pokemon { &self.user }
|
||||
/// The move the user has actually chosen to do.
|
||||
pub fn chosen_move(&self) -> &Arc<LearnedMove> {
|
||||
&self.chosen_move
|
||||
}
|
||||
pub fn chosen_move(&self) -> &Arc<LearnedMove> { &self.chosen_move }
|
||||
/// The move that the user is actually going to do.
|
||||
pub fn use_move(&self) -> &Arc<dyn MoveData> {
|
||||
&self.use_move
|
||||
}
|
||||
pub fn use_move(&self) -> &Arc<dyn MoveData> { &self.use_move }
|
||||
/// The script of the move.
|
||||
pub fn script(&self) -> &ScriptContainer {
|
||||
&self.script
|
||||
}
|
||||
pub fn script(&self) -> &ScriptContainer { &self.script }
|
||||
|
||||
/// Gets a hit data for a target, with a specific index.
|
||||
pub fn get_hit_data(&self, for_target: &Pokemon, hit: u8) -> Result<&Arc<HitData>> {
|
||||
|
@ -215,17 +178,11 @@ impl ExecutingMove {
|
|||
}
|
||||
|
||||
impl ScriptSource for ExecutingMove {
|
||||
fn get_script_count(&self) -> Result<usize> {
|
||||
Ok(1)
|
||||
}
|
||||
fn get_script_count(&self) -> Result<usize> { Ok(1) }
|
||||
|
||||
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> {
|
||||
&self.script_source_data
|
||||
}
|
||||
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> { &self.script_source_data }
|
||||
|
||||
fn get_own_scripts(&self, scripts: &mut Vec<ScriptWrapper>) {
|
||||
scripts.push((&self.script).into());
|
||||
}
|
||||
fn get_own_scripts(&self, scripts: &mut Vec<ScriptWrapper>) { scripts.push((&self.script).into()); }
|
||||
|
||||
fn collect_scripts(&self, scripts: &mut Vec<ScriptWrapper>) -> Result<()> {
|
||||
self.get_own_scripts(scripts);
|
||||
|
|
|
@ -216,21 +216,13 @@ impl Pokemon {
|
|||
}
|
||||
|
||||
/// The library data of the Pokemon.
|
||||
pub fn library(&self) -> &Arc<dyn DynamicLibrary> {
|
||||
&self.data.library
|
||||
}
|
||||
pub fn library(&self) -> &Arc<dyn DynamicLibrary> { &self.data.library }
|
||||
/// The species of the Pokemon.
|
||||
pub fn species(&self) -> Arc<dyn Species> {
|
||||
self.data.species.read().clone()
|
||||
}
|
||||
pub fn species(&self) -> Arc<dyn Species> { self.data.species.read().clone() }
|
||||
/// The form of the Pokemon.
|
||||
pub fn form(&self) -> Arc<dyn Form> {
|
||||
self.data.form.read().clone()
|
||||
}
|
||||
pub fn form(&self) -> Arc<dyn Form> { self.data.form.read().clone() }
|
||||
/// Whether or not the Pokemon is showing as a different species than it actually is.
|
||||
pub fn has_different_display_species(&self) -> bool {
|
||||
self.data.display_species.is_some()
|
||||
}
|
||||
pub fn has_different_display_species(&self) -> bool { self.data.display_species.is_some() }
|
||||
/// The species that should be displayed to the user. This handles stuff like the Illusion ability.
|
||||
pub fn display_species(&self) -> Arc<dyn Species> {
|
||||
if let Some(v) = &self.data.display_species {
|
||||
|
@ -240,9 +232,7 @@ impl Pokemon {
|
|||
}
|
||||
}
|
||||
/// Whether or not the Pokemon is showing as a different form than it actually is.
|
||||
pub fn has_different_display_form(&self) -> bool {
|
||||
self.data.display_form.is_some()
|
||||
}
|
||||
pub fn has_different_display_form(&self) -> bool { self.data.display_form.is_some() }
|
||||
/// The form that should be displayed to the user. This handles stuff like the Illusion ability.
|
||||
pub fn display_form(&self) -> Arc<dyn Form> {
|
||||
if let Some(v) = &self.data.display_form {
|
||||
|
@ -253,32 +243,20 @@ impl Pokemon {
|
|||
}
|
||||
/// The current level of the Pokemon.
|
||||
/// [See also](https://bulbapedia.bulbagarden.net/wiki/Level)
|
||||
pub fn level(&self) -> LevelInt {
|
||||
self.data.level.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn level(&self) -> LevelInt { self.data.level.load(Ordering::Relaxed) }
|
||||
/// The amount of experience of the Pokemon.
|
||||
/// [See also](https://bulbapedia.bulbagarden.net/wiki/Experience)
|
||||
pub fn experience(&self) -> u32 {
|
||||
self.data.experience.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn experience(&self) -> u32 { self.data.experience.load(Ordering::Relaxed) }
|
||||
/// The personality value of the Pokemon.
|
||||
/// [See also](https://bulbapedia.bulbagarden.net/wiki/Personality_value)
|
||||
pub fn personality_value(&self) -> u32 {
|
||||
self.data.personality_value
|
||||
}
|
||||
pub fn personality_value(&self) -> u32 { self.data.personality_value }
|
||||
/// The gender of the Pokemon.
|
||||
pub fn gender(&self) -> Gender {
|
||||
*self.data.gender.read()
|
||||
}
|
||||
pub fn gender(&self) -> Gender { *self.data.gender.read() }
|
||||
/// The coloring of the Pokemon. Value 0 is the default, value 1 means shiny. Other values are
|
||||
/// currently not used, and can be used for other implementations.
|
||||
pub fn coloring(&self) -> u8 {
|
||||
self.data.coloring
|
||||
}
|
||||
pub fn coloring(&self) -> u8 { self.data.coloring }
|
||||
/// Gets the held item of a Pokemon
|
||||
pub fn held_item(&self) -> &RwLock<Option<Arc<dyn Item>>> {
|
||||
&self.data.held_item
|
||||
}
|
||||
pub fn held_item(&self) -> &RwLock<Option<Arc<dyn Item>>> { &self.data.held_item }
|
||||
/// Checks whether the Pokemon is holding a specific item.
|
||||
pub fn has_held_item(&self, name: &StringKey) -> bool {
|
||||
// Only true if we have an item, and the item name is the same as the requested item.
|
||||
|
@ -292,9 +270,7 @@ impl Pokemon {
|
|||
self.data.held_item.write().replace(item.clone())
|
||||
}
|
||||
/// Removes the held item from the Pokemon. Returns the previously held item.
|
||||
pub fn remove_held_item(&self) -> Option<Arc<dyn Item>> {
|
||||
self.data.held_item.write().take()
|
||||
}
|
||||
pub fn remove_held_item(&self) -> Option<Arc<dyn Item>> { self.data.held_item.write().take() }
|
||||
/// Makes the Pokemon uses its held item.
|
||||
pub fn consume_held_item(&self) -> Result<bool> {
|
||||
if self.data.held_item.read().is_none() {
|
||||
|
@ -316,72 +292,42 @@ impl Pokemon {
|
|||
}
|
||||
|
||||
/// The remaining health points of the Pokemon.
|
||||
pub fn current_health(&self) -> u32 {
|
||||
self.data.current_health.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn current_health(&self) -> u32 { self.data.current_health.load(Ordering::Relaxed) }
|
||||
/// The max health points of the Pokemon.
|
||||
pub fn max_health(&self) -> u32 {
|
||||
self.data.boosted_stats.hp()
|
||||
}
|
||||
pub fn max_health(&self) -> u32 { self.data.boosted_stats.hp() }
|
||||
/// The weight of the Pokemon in kilograms.
|
||||
pub fn weight(&self) -> f32 {
|
||||
self.data.weight.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn weight(&self) -> f32 { self.data.weight.load(Ordering::Relaxed) }
|
||||
/// Sets the weight of the Pokemon in kilograms.
|
||||
pub fn set_weight(&self, weight: f32) {
|
||||
self.data.weight.store(weight, Ordering::Relaxed)
|
||||
}
|
||||
pub fn set_weight(&self, weight: f32) { self.data.weight.store(weight, Ordering::Relaxed) }
|
||||
/// The height of the Pokemon in meters.
|
||||
pub fn height(&self) -> f32 {
|
||||
self.data.height.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn height(&self) -> f32 { self.data.height.load(Ordering::Relaxed) }
|
||||
|
||||
/// The current happiness of the Pokemon. Also known as friendship.
|
||||
pub fn happiness(&self) -> u8 {
|
||||
self.data.happiness.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn happiness(&self) -> u8 { self.data.happiness.load(Ordering::Relaxed) }
|
||||
|
||||
/// An optional nickname of the Pokemon.
|
||||
pub fn nickname(&self) -> &Option<String> {
|
||||
&self.data.nickname
|
||||
}
|
||||
pub fn nickname(&self) -> &Option<String> { &self.data.nickname }
|
||||
/// An index of the ability to find the actual ability on the form.
|
||||
pub fn real_ability(&self) -> &AbilityIndex {
|
||||
&self.data.ability_index
|
||||
}
|
||||
pub fn real_ability(&self) -> &AbilityIndex { &self.data.ability_index }
|
||||
/// The current types of the Pokemon.
|
||||
pub fn types(&self) -> RwLockReadGuard<'_, RawRwLock, Vec<TypeIdentifier>> {
|
||||
self.data.types.read()
|
||||
}
|
||||
pub fn types(&self) -> RwLockReadGuard<'_, RawRwLock, Vec<TypeIdentifier>> { self.data.types.read() }
|
||||
/// The moves the Pokemon has learned. This is of a set length of [`MAX_MOVES`]. Empty move slots
|
||||
/// are defined by None.
|
||||
pub fn learned_moves(&self) -> &RwLock<[Option<Arc<LearnedMove>>; MAX_MOVES]> {
|
||||
&self.data.moves
|
||||
}
|
||||
pub fn learned_moves(&self) -> &RwLock<[Option<Arc<LearnedMove>>; MAX_MOVES]> { &self.data.moves }
|
||||
|
||||
/// The stats of the Pokemon when disregarding any stat boosts.
|
||||
pub fn flat_stats(&self) -> &Arc<StatisticSet<u32>> {
|
||||
&self.data.flat_stats
|
||||
}
|
||||
pub fn flat_stats(&self) -> &Arc<StatisticSet<u32>> { &self.data.flat_stats }
|
||||
|
||||
/// The amount of boosts on a specific stat.
|
||||
pub fn stat_boosts(&self) -> &Arc<ClampedStatisticSet<i8, -6, 6>> {
|
||||
&self.data.stat_boost
|
||||
}
|
||||
pub fn stat_boosts(&self) -> &Arc<ClampedStatisticSet<i8, -6, 6>> { &self.data.stat_boost }
|
||||
|
||||
/// Whether or not this Pokemon is still an egg, and therefore cannot battle.
|
||||
pub fn is_egg(&self) -> bool {
|
||||
self.data.is_egg
|
||||
}
|
||||
pub fn is_egg(&self) -> bool { self.data.is_egg }
|
||||
|
||||
/// The stats of the Pokemon including the stat boosts
|
||||
pub fn boosted_stats(&self) -> &Arc<StatisticSet<u32>> {
|
||||
&self.data.boosted_stats
|
||||
}
|
||||
pub fn boosted_stats(&self) -> &Arc<StatisticSet<u32>> { &self.data.boosted_stats }
|
||||
/// Get the stat boosts for a specific stat.
|
||||
pub fn stat_boost(&self, stat: Statistic) -> i8 {
|
||||
self.data.stat_boost.get_stat(stat)
|
||||
}
|
||||
pub fn stat_boost(&self, stat: Statistic) -> i8 { self.data.stat_boost.get_stat(stat) }
|
||||
/// Change a boosted stat by a certain amount.
|
||||
pub fn change_stat_boost(&self, stat: Statistic, mut diff_amount: i8, self_inflicted: bool) -> Result<bool> {
|
||||
let mut prevent = false;
|
||||
|
@ -440,14 +386,10 @@ impl Pokemon {
|
|||
|
||||
/// Gets an individual value of the Pokemon.
|
||||
/// [See also](https://bulbapedia.bulbagarden.net/wiki/Individual_values)
|
||||
pub fn individual_values(&self) -> &Arc<ClampedStatisticSet<u8, 0, 31>> {
|
||||
&self.data.individual_values
|
||||
}
|
||||
pub fn individual_values(&self) -> &Arc<ClampedStatisticSet<u8, 0, 31>> { &self.data.individual_values }
|
||||
/// Gets an effort value of the Pokemon.
|
||||
/// [See also](https://bulbapedia.bulbagarden.net/wiki/Effort_values)
|
||||
pub fn effort_values(&self) -> &Arc<ClampedStatisticSet<u8, 0, 252>> {
|
||||
&self.data.effort_values
|
||||
}
|
||||
pub fn effort_values(&self) -> &Arc<ClampedStatisticSet<u8, 0, 252>> { &self.data.effort_values }
|
||||
|
||||
/// Gets the battle the battle is currently in.
|
||||
pub fn get_battle(&self) -> Option<Battle> {
|
||||
|
@ -469,13 +411,9 @@ impl Pokemon {
|
|||
}
|
||||
/// Get the index of the slot on the side of the battle the Pokemon is in. Only returns a value
|
||||
/// if the Pokemon is on the battlefield.
|
||||
pub fn get_battle_index(&self) -> Option<u8> {
|
||||
self.data.battle_data.read().as_ref().map(|data| data.index())
|
||||
}
|
||||
pub fn get_battle_index(&self) -> Option<u8> { self.data.battle_data.read().as_ref().map(|data| data.index()) }
|
||||
/// Returns whether something overrides the ability.
|
||||
pub fn is_ability_overriden(&self) -> bool {
|
||||
self.data.override_ability.is_some()
|
||||
}
|
||||
pub fn is_ability_overriden(&self) -> bool { self.data.override_ability.is_some() }
|
||||
/// Returns the currently active ability.
|
||||
pub fn active_ability(&self) -> Result<Arc<dyn Ability>> {
|
||||
if let Some(v) = &self.data.override_ability {
|
||||
|
@ -496,25 +434,17 @@ impl Pokemon {
|
|||
}
|
||||
|
||||
/// The script for the status.
|
||||
pub fn status(&self) -> &ScriptContainer {
|
||||
&self.data.status_script
|
||||
}
|
||||
pub fn status(&self) -> &ScriptContainer { &self.data.status_script }
|
||||
|
||||
/// Returns the script for the currently active ability.
|
||||
pub fn ability_script(&self) -> &ScriptContainer {
|
||||
&self.data.ability_script
|
||||
}
|
||||
pub fn ability_script(&self) -> &ScriptContainer { &self.data.ability_script }
|
||||
|
||||
/// Whether or not the Pokemon is allowed to gain experience.
|
||||
pub fn allowed_experience_gain(&self) -> bool {
|
||||
self.data.allowed_experience
|
||||
}
|
||||
pub fn allowed_experience_gain(&self) -> bool { self.data.allowed_experience }
|
||||
|
||||
/// The nature of the Pokemon.
|
||||
/// [See also](https://bulbapedia.bulbagarden.net/wiki/Nature)
|
||||
pub fn nature(&self) -> &Arc<dyn Nature> {
|
||||
&self.data.nature
|
||||
}
|
||||
pub fn nature(&self) -> &Arc<dyn Nature> { &self.data.nature }
|
||||
|
||||
/// Calculates the flat stats on the Pokemon. This should be called when for example the base
|
||||
/// stats, level, nature, IV, or EV changes. This has a side effect of recalculating the boosted
|
||||
|
@ -606,7 +536,7 @@ impl Pokemon {
|
|||
.set(ability_script)
|
||||
.as_ref()
|
||||
// Ensure the ability script gets initialized with the parameters for the ability.
|
||||
.on_initialize(&self.data.library, ability.parameters().to_vec());
|
||||
.on_initialize(&self.data.library, ability.parameters());
|
||||
match script_result {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
|
@ -646,14 +576,10 @@ impl Pokemon {
|
|||
}
|
||||
|
||||
/// Whether or not the Pokemon is useable in a battle.
|
||||
pub fn is_usable(&self) -> bool {
|
||||
!self.data.is_caught && !self.data.is_egg && !self.is_fainted()
|
||||
}
|
||||
pub fn is_usable(&self) -> bool { !self.data.is_caught && !self.data.is_egg && !self.is_fainted() }
|
||||
|
||||
/// Returns whether the Pokemon is fainted.
|
||||
pub fn is_fainted(&self) -> bool {
|
||||
self.current_health() == 0
|
||||
}
|
||||
pub fn is_fainted(&self) -> bool { self.current_health() == 0 }
|
||||
|
||||
/// Sets the current battle the Pokemon is in.
|
||||
pub fn set_battle_data(&self, battle: WeakBattleReference, battle_side_index: u8) {
|
||||
|
@ -836,9 +762,7 @@ impl Pokemon {
|
|||
}
|
||||
|
||||
/// Removes the current non-volatile status from the Pokemon.
|
||||
pub fn clear_status(&self) {
|
||||
self.data.status_script.clear()
|
||||
}
|
||||
pub fn clear_status(&self) { self.data.status_script.clear() }
|
||||
|
||||
/// Increases the level by a certain amount
|
||||
pub fn change_level_by(&self, amount: LevelInt) -> Result<()> {
|
||||
|
@ -858,9 +782,7 @@ impl Pokemon {
|
|||
|
||||
/// Converts the Pokemon into a serializable form.
|
||||
#[cfg(feature = "serde")]
|
||||
pub fn serialize(&self) -> Result<super::serialization::SerializedPokemon> {
|
||||
self.into()
|
||||
}
|
||||
pub fn serialize(&self) -> Result<super::serialization::SerializedPokemon> { self.into() }
|
||||
|
||||
/// Deserializes a Pokemon from a serializable form.
|
||||
#[cfg(feature = "serde")]
|
||||
|
@ -995,23 +917,17 @@ impl Pokemon {
|
|||
}
|
||||
|
||||
/// Gets the inner pointer to the reference counted data.
|
||||
pub fn as_ptr(&self) -> *const c_void {
|
||||
Arc::as_ptr(&self.data) as *const c_void
|
||||
}
|
||||
pub fn as_ptr(&self) -> *const c_void { Arc::as_ptr(&self.data) as *const c_void }
|
||||
}
|
||||
|
||||
impl PartialEq for Pokemon {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
Arc::ptr_eq(&self.data, &other.data)
|
||||
}
|
||||
fn eq(&self, other: &Self) -> bool { Arc::ptr_eq(&self.data, &other.data) }
|
||||
}
|
||||
|
||||
impl Eq for Pokemon {}
|
||||
|
||||
impl PartialEq for WeakPokemonReference {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
Weak::ptr_eq(&self.data, &other.data)
|
||||
}
|
||||
fn eq(&self, other: &Self) -> bool { Weak::ptr_eq(&self.data, &other.data) }
|
||||
}
|
||||
|
||||
impl Eq for WeakPokemonReference {}
|
||||
|
@ -1025,9 +941,7 @@ impl WeakPokemonReference {
|
|||
}
|
||||
|
||||
/// Gets the pointer to the underlying data.
|
||||
pub(crate) fn as_ptr(&self) -> *const c_void {
|
||||
self.data.as_ptr() as *const c_void
|
||||
}
|
||||
pub(crate) fn as_ptr(&self) -> *const c_void { self.data.as_ptr() as *const c_void }
|
||||
}
|
||||
|
||||
/// The data of the Pokemon related to being in a battle.
|
||||
|
@ -1047,26 +961,16 @@ pub struct PokemonBattleData {
|
|||
|
||||
impl PokemonBattleData {
|
||||
/// The battle data of the Pokemon
|
||||
pub fn battle(&self) -> Option<Battle> {
|
||||
self.battle.upgrade()
|
||||
}
|
||||
pub fn battle(&self) -> Option<Battle> { self.battle.upgrade() }
|
||||
|
||||
/// The index of the side of the Pokemon
|
||||
pub fn battle_side_index(&self) -> u8 {
|
||||
self.battle_side_index.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn battle_side_index(&self) -> u8 { self.battle_side_index.load(Ordering::Relaxed) }
|
||||
/// The index of the slot on the side of the Pokemon.
|
||||
pub fn index(&self) -> u8 {
|
||||
self.index.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn index(&self) -> u8 { self.index.load(Ordering::Relaxed) }
|
||||
/// Whether or not the Pokemon is on the battlefield.
|
||||
pub fn on_battle_field(&self) -> bool {
|
||||
self.on_battle_field.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn on_battle_field(&self) -> bool { self.on_battle_field.load(Ordering::Relaxed) }
|
||||
/// A list of opponents the Pokemon has seen this battle.
|
||||
pub fn seen_opponents(&self) -> &RwLock<Vec<WeakPokemonReference>> {
|
||||
&self.seen_opponents
|
||||
}
|
||||
pub fn seen_opponents(&self) -> &RwLock<Vec<WeakPokemonReference>> { &self.seen_opponents }
|
||||
}
|
||||
|
||||
impl ScriptSource for Pokemon {
|
||||
|
@ -1083,9 +987,7 @@ impl ScriptSource for Pokemon {
|
|||
Ok(c)
|
||||
}
|
||||
|
||||
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> {
|
||||
&self.data.script_source_data
|
||||
}
|
||||
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> { &self.data.script_source_data }
|
||||
|
||||
fn get_own_scripts(&self, scripts: &mut Vec<ScriptWrapper>) {
|
||||
scripts.push((&self.data.held_item_trigger_script).into());
|
||||
|
@ -1109,9 +1011,7 @@ impl ScriptSource for Pokemon {
|
|||
}
|
||||
|
||||
impl VolatileScriptsOwner for Pokemon {
|
||||
fn volatile_scripts(&self) -> &Arc<ScriptSet> {
|
||||
&self.data.volatile
|
||||
}
|
||||
fn volatile_scripts(&self) -> &Arc<ScriptSet> { &self.data.volatile }
|
||||
|
||||
fn load_volatile_script(&self, key: &StringKey) -> Result<Option<Arc<dyn Script>>> {
|
||||
self.data.library.load_script(self.into(), ScriptCategory::Pokemon, key)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use anyhow::{anyhow, Result};
|
||||
use hashbrown::HashMap;
|
||||
use std::any::Any;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::ops::Deref;
|
||||
|
@ -30,97 +31,69 @@ pub trait Script: Send + Sync {
|
|||
fn get_marked_for_deletion(&self) -> &AtomicBool;
|
||||
|
||||
/// This marks the script for deletion, which will dispose of it as soon as possible.
|
||||
fn mark_for_deletion(&self) {
|
||||
self.get_marked_for_deletion().store(true, Ordering::SeqCst);
|
||||
}
|
||||
fn mark_for_deletion(&self) { self.get_marked_for_deletion().store(true, Ordering::SeqCst); }
|
||||
/// Helper function to get the value of the marked for deletion bool.
|
||||
fn is_marked_for_deletion(&self) -> bool {
|
||||
self.get_marked_for_deletion().load(Ordering::SeqCst)
|
||||
}
|
||||
fn is_marked_for_deletion(&self) -> bool { self.get_marked_for_deletion().load(Ordering::SeqCst) }
|
||||
|
||||
/// A script can be suppressed by other scripts. If a script is suppressed by at least one script
|
||||
/// we will not execute its methods. This should return the number of suppressions on the script.
|
||||
fn get_suppressed_count(&self) -> &AtomicUsize;
|
||||
/// Helper function to check if there is at least one suppression on the script
|
||||
fn is_suppressed(&self) -> bool {
|
||||
self.get_suppressed_count().load(Ordering::SeqCst) > 0
|
||||
}
|
||||
fn is_suppressed(&self) -> bool { self.get_suppressed_count().load(Ordering::SeqCst) > 0 }
|
||||
/// Adds a suppression. This makes the script not run anymore. Note that adding this should also
|
||||
/// remove the suppression later.
|
||||
///
|
||||
/// A common pattern for this is to run this in the [`Self::on_initialize`] function, and run the
|
||||
/// remove in the [`Self::on_remove`] function.
|
||||
fn add_suppression(&self) {
|
||||
self.get_suppressed_count().fetch_add(1, Ordering::SeqCst);
|
||||
}
|
||||
fn add_suppression(&self) { self.get_suppressed_count().fetch_add(1, Ordering::SeqCst); }
|
||||
/// Removes a suppression. This allows the script to run again (provided other scripts are not
|
||||
/// suppressing it). Note that running this should only occur if an add was run before.
|
||||
fn remove_suppression(&self) {
|
||||
self.get_suppressed_count().fetch_sub(1, Ordering::SeqCst);
|
||||
}
|
||||
fn remove_suppression(&self) { self.get_suppressed_count().fetch_sub(1, Ordering::SeqCst); }
|
||||
|
||||
/// 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) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
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) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn on_remove(&self) -> Result<()> { Ok(()) }
|
||||
/// This function is ran when this script starts being in effect.
|
||||
fn on_initialize(&self, _library: &Arc<dyn DynamicLibrary>, _pars: Vec<Arc<Parameter>>) -> Result<()> {
|
||||
fn on_initialize(
|
||||
&self,
|
||||
_library: &Arc<dyn DynamicLibrary>,
|
||||
_pars: &HashMap<StringKey, Arc<Parameter>>,
|
||||
) -> 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: &Arc<TurnChoice>) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn on_before_turn(&self, _choice: &Arc<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: &Arc<TurnChoice>, _speed: &mut u32) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn change_speed(&self, _choice: &Arc<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: &Arc<TurnChoice>, _priority: &mut i8) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn change_priority(&self, _choice: &Arc<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: &Arc<TurnChoice>, _move_name: &mut StringKey) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn change_move(&self, _choice: &Arc<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: &Arc<TurnChoice>, _number_of_hits: &mut u8) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn change_number_of_hits(&self, _choice: &Arc<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: &Arc<ExecutingMove>, _prevent: &mut bool) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn prevent_move(&self, _move: &Arc<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: &Arc<ExecutingMove>, _fail: &mut bool) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn fail_move(&self, _move: &Arc<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: &Arc<ExecutingMove>, _stop: &mut bool) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn stop_before_move(&self, _move: &Arc<ExecutingMove>, _stop: &mut bool) -> Result<()> { Ok(()) }
|
||||
/// This function runs just before the move starts its execution.
|
||||
fn on_before_move(&self, _move: &Arc<ExecutingMove>) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn on_before_move(&self, _move: &Arc<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: &Arc<ExecutingMove>, _target: &Pokemon, _fail: &mut bool) -> Result<()> {
|
||||
|
@ -132,9 +105,7 @@ pub trait Script: Send + Sync {
|
|||
}
|
||||
/// 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: &Arc<ExecutingMove>, _target: &Pokemon) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn on_move_miss(&self, _move: &Arc<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,
|
||||
|
@ -308,13 +279,9 @@ pub trait Script: Send + Sync {
|
|||
}
|
||||
/// 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: &Arc<ExecutingMove>, _target: &Pokemon, _hit: u8) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn on_incoming_hit(&self, _move: &Arc<ExecutingMove>, _target: &Pokemon, _hit: u8) -> Result<()> { Ok(()) }
|
||||
/// This function triggers when an opponent on the field faints.
|
||||
fn on_opponent_faints(&self, _move: &Arc<ExecutingMove>, _target: &Pokemon, _hit: u8) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn on_opponent_faints(&self, _move: &Arc<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(
|
||||
|
@ -380,61 +347,37 @@ pub trait Script: Send + Sync {
|
|||
/// 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: &Arc<ExecutingMove>, _target: &Pokemon, _hit: u8) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn on_secondary_effect(&self, _move: &Arc<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: &Arc<ExecutingMove>, _target: &Pokemon) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn on_after_hits(&self, _move: &Arc<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: &Arc<TurnChoice>, _prevent: &mut bool) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn prevent_self_switch(&self, _choice: &Arc<TurnChoice>, _prevent: &mut bool) -> Result<()> { Ok(()) }
|
||||
/// This function allows the prevention of switching for any opponent.
|
||||
fn prevent_opponent_switch(&self, _choice: &Arc<TurnChoice>, _prevent: &mut bool) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn prevent_opponent_switch(&self, _choice: &Arc<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) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
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) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
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: &Arc<TurnChoice>, _prevent: &mut bool) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn prevent_self_run_away(&self, _choice: &Arc<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: &Arc<TurnChoice>, _prevent: &mut bool) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn prevent_opponent_run_away(&self, _choice: &Arc<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) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
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, _pokemon: &Pokemon, _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) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
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) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
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: &Arc<dyn Item>) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn on_after_held_item_consume(&self, _pokemon: &Pokemon, _item: &Arc<dyn 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(
|
||||
|
@ -452,9 +395,7 @@ pub trait Script: Send + Sync {
|
|||
}
|
||||
/// 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) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
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.
|
||||
|
@ -474,9 +415,7 @@ pub trait Script: Send + Sync {
|
|||
}
|
||||
|
||||
impl Debug for dyn Script {
|
||||
fn fmt(&self, _f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
Ok(())
|
||||
}
|
||||
fn fmt(&self, _f: &mut Formatter<'_>) -> std::fmt::Result { Ok(()) }
|
||||
}
|
||||
|
||||
/// A script holder defines the underlying type of how we store individual scripts on a script source.
|
||||
|
@ -574,14 +513,10 @@ impl ScriptContainer {
|
|||
}
|
||||
|
||||
/// Gets the underlying reference counter to the script.
|
||||
pub fn arc(&self) -> &ScriptHolder {
|
||||
&self.script
|
||||
}
|
||||
pub fn arc(&self) -> &ScriptHolder { &self.script }
|
||||
|
||||
/// Whether or not the script is set.
|
||||
pub fn is_any(&self) -> bool {
|
||||
self.script.read().is_some()
|
||||
}
|
||||
pub fn is_any(&self) -> bool { self.script.read().is_some() }
|
||||
|
||||
/// Get the underlying script as the downcasted value.
|
||||
pub fn get_as<T: 'static>(&self) -> Result<MappedRwLockReadGuard<T>> {
|
||||
|
@ -646,29 +581,19 @@ mod tests {
|
|||
unsafe impl Send for TestScript {}
|
||||
|
||||
impl Script for TestScript {
|
||||
fn name(&self) -> Result<&StringKey> {
|
||||
Ok(&self.name)
|
||||
}
|
||||
fn name(&self) -> Result<&StringKey> { Ok(&self.name) }
|
||||
|
||||
fn get_marked_for_deletion(&self) -> &AtomicBool {
|
||||
&self.marked_for_deletion
|
||||
}
|
||||
fn get_marked_for_deletion(&self) -> &AtomicBool { &self.marked_for_deletion }
|
||||
|
||||
fn get_suppressed_count(&self) -> &AtomicUsize {
|
||||
&self.suppressed_count
|
||||
}
|
||||
fn get_suppressed_count(&self) -> &AtomicUsize { &self.suppressed_count }
|
||||
|
||||
fn stack(&self) -> Result<()> {
|
||||
unsafe { self.container.load(Ordering::Relaxed).as_ref().unwrap().clear() }
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
fn as_any(&self) -> &dyn Any { self }
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any { self }
|
||||
}
|
||||
|
||||
// Removing yourself while active should be completely valid for a script. Consider for example
|
||||
|
@ -726,24 +651,14 @@ mod tests {
|
|||
unsafe impl Send for ReplaceTestScript {}
|
||||
|
||||
impl Script for ReplaceTestScript {
|
||||
fn name(&self) -> Result<&StringKey> {
|
||||
Ok(&self.name)
|
||||
}
|
||||
fn name(&self) -> Result<&StringKey> { Ok(&self.name) }
|
||||
|
||||
fn get_marked_for_deletion(&self) -> &AtomicBool {
|
||||
&self.marked_for_deletion
|
||||
}
|
||||
fn get_marked_for_deletion(&self) -> &AtomicBool { &self.marked_for_deletion }
|
||||
|
||||
fn get_suppressed_count(&self) -> &AtomicUsize {
|
||||
&self.suppressed_count
|
||||
}
|
||||
fn get_suppressed_count(&self) -> &AtomicUsize { &self.suppressed_count }
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
fn as_any(&self) -> &dyn Any { self }
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any { self }
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -793,19 +708,13 @@ pub enum ScriptOwnerData {
|
|||
}
|
||||
|
||||
impl From<&Pokemon> for ScriptOwnerData {
|
||||
fn from(p: &Pokemon) -> Self {
|
||||
ScriptOwnerData::Pokemon(p.weak())
|
||||
}
|
||||
fn from(p: &Pokemon) -> Self { ScriptOwnerData::Pokemon(p.weak()) }
|
||||
}
|
||||
|
||||
impl From<&BattleSide> for ScriptOwnerData {
|
||||
fn from(p: &BattleSide) -> Self {
|
||||
ScriptOwnerData::BattleSide(p.weak())
|
||||
}
|
||||
fn from(p: &BattleSide) -> Self { ScriptOwnerData::BattleSide(p.weak()) }
|
||||
}
|
||||
|
||||
impl From<&Battle> for ScriptOwnerData {
|
||||
fn from(p: &Battle) -> Self {
|
||||
ScriptOwnerData::Battle(p.weak())
|
||||
}
|
||||
fn from(p: &Battle) -> Self { ScriptOwnerData::Battle(p.weak()) }
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use crate::ffi::FFIHandle;
|
||||
use crate::ffi::FromFFIHandle;
|
||||
use crate::ffi::{FFIHandle, NonOwnedPtrString};
|
||||
use crate::ffi::{FFIResult, OwnedPtrString};
|
||||
use crate::static_data::{Ability, AbilityImpl, Parameter};
|
||||
use crate::StringKey;
|
||||
use anyhow::anyhow;
|
||||
use hashbrown::HashMap;
|
||||
use std::ffi::{c_char, CStr, CString};
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -12,13 +13,18 @@ use std::sync::Arc;
|
|||
unsafe extern "C" fn ability_new(
|
||||
name: *const c_char,
|
||||
effect: *const c_char,
|
||||
parameter_keys: *const NonOwnedPtrString,
|
||||
parameters: *const FFIHandle<Arc<Parameter>>,
|
||||
parameters_length: usize,
|
||||
) -> FFIResult<FFIHandle<Arc<dyn Ability>>> {
|
||||
let parameter_keys = std::slice::from_raw_parts(parameter_keys, parameters_length);
|
||||
let parameters = std::slice::from_raw_parts(parameters, parameters_length);
|
||||
let mut parameters_vec: Vec<Arc<Parameter>> = Vec::with_capacity(parameters_length);
|
||||
for parameter in parameters {
|
||||
parameters_vec.push(parameter.from_ffi_handle());
|
||||
let mut parameters_map: HashMap<StringKey, Arc<Parameter>> = HashMap::with_capacity(parameters_length);
|
||||
for (index, parameter) in parameters.iter().enumerate() {
|
||||
parameters_map.insert(
|
||||
CStr::from_ptr(parameter_keys[index]).into(),
|
||||
parameter.from_ffi_handle(),
|
||||
);
|
||||
}
|
||||
|
||||
let name: StringKey = match CStr::from_ptr(name).to_str() {
|
||||
|
@ -30,7 +36,7 @@ unsafe extern "C" fn ability_new(
|
|||
Err(_) => return FFIResult::err(anyhow!("Failed to convert effect to CStr")),
|
||||
};
|
||||
|
||||
let arc: Arc<dyn Ability> = Arc::new(AbilityImpl::new(&name, &effect, parameters_vec));
|
||||
let arc: Arc<dyn Ability> = Arc::new(AbilityImpl::new(&name, &effect, parameters_map));
|
||||
FFIResult::ok(FFIHandle::get_handle(arc.into()))
|
||||
}
|
||||
|
||||
|
@ -62,9 +68,10 @@ unsafe extern "C" fn ability_parameter_length(ptr: FFIHandle<Arc<dyn Ability>>)
|
|||
#[no_mangle]
|
||||
unsafe extern "C" fn ability_parameter_get(
|
||||
ptr: FFIHandle<Arc<dyn Ability>>,
|
||||
index: usize,
|
||||
name: NonOwnedPtrString,
|
||||
) -> FFIHandle<Arc<Parameter>> {
|
||||
if let Some(p) = ptr.from_ffi_handle().parameters().get(index) {
|
||||
let string: StringKey = CStr::from_ptr(name).into();
|
||||
if let Some(p) = ptr.from_ffi_handle().parameters().get(&string) {
|
||||
FFIHandle::get_handle(p.clone().into())
|
||||
} else {
|
||||
FFIHandle::none()
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::static_data::{
|
|||
};
|
||||
use crate::StringKey;
|
||||
use anyhow::anyhow;
|
||||
use hashbrown::HashSet;
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use std::ffi::{c_char, CStr, CString};
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -99,13 +99,16 @@ unsafe extern "C" fn move_data_has_flag(ptr: FFIHandle<Arc<dyn MoveData>>, flag:
|
|||
unsafe extern "C" fn secondary_effect_new(
|
||||
chance: f32,
|
||||
effect_name: NonOwnedPtrString,
|
||||
parameter_keys: *const NonOwnedPtrString,
|
||||
parameters: *mut FFIHandle<Arc<Parameter>>,
|
||||
parameters_length: usize,
|
||||
) -> FFIHandle<Box<dyn SecondaryEffect>> {
|
||||
let parameter_key_slice = std::slice::from_raw_parts(parameter_keys, parameters_length);
|
||||
let parameter_slice = std::slice::from_raw_parts(parameters, parameters_length);
|
||||
let mut parameters = Vec::with_capacity(parameters_length);
|
||||
for parameter in parameter_slice {
|
||||
parameters.push(parameter.from_ffi_handle())
|
||||
let mut parameters = HashMap::with_capacity(parameters_length);
|
||||
for (index, parameter) in parameter_slice.iter().enumerate() {
|
||||
let key = CStr::from_ptr(parameter_key_slice[index]).into();
|
||||
parameters.insert(key, parameter.from_ffi_handle());
|
||||
}
|
||||
|
||||
let b: Arc<dyn SecondaryEffect> = Arc::new(SecondaryEffectImpl::new(
|
||||
|
@ -146,9 +149,10 @@ unsafe extern "C" fn secondary_effect_parameter_length(ptr: FFIHandle<Arc<dyn Se
|
|||
#[no_mangle]
|
||||
unsafe extern "C" fn secondary_effect_parameter_get(
|
||||
ptr: FFIHandle<Arc<dyn SecondaryEffect>>,
|
||||
index: usize,
|
||||
name: NonOwnedPtrString,
|
||||
) -> FFIHandle<Arc<Parameter>> {
|
||||
if let Some(v) = ptr.from_ffi_handle().parameters().get(index) {
|
||||
let string: StringKey = CStr::from_ptr(name).into();
|
||||
if let Some(v) = ptr.from_ffi_handle().parameters().get(&string) {
|
||||
FFIHandle::get_handle(v.clone().into())
|
||||
} else {
|
||||
FFIHandle::none()
|
||||
|
|
|
@ -9,8 +9,9 @@
|
|||
#![allow(hidden_glob_reexports)]
|
||||
#![allow(clippy::arc_with_non_send_sync)]
|
||||
// Documentation linters
|
||||
#![deny(missing_docs)]
|
||||
#![deny(clippy::missing_docs_in_private_items)]
|
||||
// FIXME: Enable these before committing
|
||||
// #![deny(missing_docs)]
|
||||
// #![deny(clippy::missing_docs_in_private_items)]
|
||||
// Linter rules to prevent panics
|
||||
// Currently still a WIP to fix all of these
|
||||
#![deny(clippy::unwrap_used)]
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
/// The WASM module handles loading dynamic scripts through WebAssembly.
|
||||
#[cfg(feature = "wasm")]
|
||||
pub mod wasm;
|
||||
|
||||
/// The Rune module handles loading dynamic scripts through the Rune language.
|
||||
#[cfg(feature = "rune")]
|
||||
pub mod rune;
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
use crate::dynamic_data::{Battle, DamageSource, ExecutingMove, Pokemon, TurnChoice};
|
||||
use crate::static_data::{Item, Statistic, TypeIdentifier};
|
||||
use crate::StringKey;
|
||||
use rune::Hash;
|
||||
use std::sync::Arc;
|
||||
|
||||
mod script;
|
||||
pub mod script_resolver;
|
||||
pub(self) mod wrappers;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub(self) struct RuneScriptType {
|
||||
pub fn_on_initialize: Option<Hash>,
|
||||
pub fn_on_stack: Option<Hash>,
|
||||
pub fn_on_remove: Option<Hash>,
|
||||
pub fn_on_before_turn: Option<Hash>,
|
||||
|
||||
pub fn_change_speed: Option<Hash>,
|
||||
pub fn_change_priority: Option<Hash>,
|
||||
pub fn_change_move: Option<Hash>,
|
||||
pub fn_change_number_of_hits: Option<Hash>,
|
||||
pub fn_prevent_move: Option<Hash>,
|
||||
pub fn_fail_move: Option<Hash>,
|
||||
pub fn_stop_before_move: Option<Hash>,
|
||||
pub fn_on_before_move: Option<Hash>,
|
||||
pub fn_fail_incoming_move: Option<Hash>,
|
||||
pub fn_is_invulnerable: Option<Hash>,
|
||||
pub fn_on_move_miss: Option<Hash>,
|
||||
pub fn_change_move_type: Option<Hash>,
|
||||
pub fn_change_effectiveness: Option<Hash>,
|
||||
pub fn_block_critical: Option<Hash>,
|
||||
pub fn_block_incoming_critical: Option<Hash>,
|
||||
pub fn_change_accuracy: Option<Hash>,
|
||||
pub fn_change_critical_stage: Option<Hash>,
|
||||
pub fn_change_critical_modifier: Option<Hash>,
|
||||
pub fn_change_stab_modifier: Option<Hash>,
|
||||
pub fn_change_base_power: Option<Hash>,
|
||||
pub fn_bypass_defensive_stat_boost: Option<Hash>,
|
||||
pub fn_bypass_offensive_stat_boost: Option<Hash>,
|
||||
pub fn_change_offensive_stat_value: Option<Hash>,
|
||||
pub fn_change_defensive_stat_value: Option<Hash>,
|
||||
pub fn_change_damage_stat_modifier: Option<Hash>,
|
||||
pub fn_change_damage_modifier: Option<Hash>,
|
||||
pub fn_change_damage: Option<Hash>,
|
||||
pub fn_change_incoming_damage: Option<Hash>,
|
||||
pub fn_on_incoming_hit: Option<Hash>,
|
||||
pub fn_on_opponent_faints: Option<Hash>,
|
||||
pub fn_prevent_stat_boost_change: Option<Hash>,
|
||||
pub fn_change_stat_boost_change: Option<Hash>,
|
||||
pub fn_prevent_secondary_effect: Option<Hash>,
|
||||
pub fn_change_effect_chance: Option<Hash>,
|
||||
pub fn_change_incoming_effect_chance: Option<Hash>,
|
||||
pub fn_on_secondary_effect: Option<Hash>,
|
||||
pub fn_on_after_hits: Option<Hash>,
|
||||
pub fn_prevent_self_switch: Option<Hash>,
|
||||
pub fn_prevent_opponent_switch: Option<Hash>,
|
||||
pub fn_on_fail: Option<Hash>,
|
||||
pub fn_on_opponent_fail: Option<Hash>,
|
||||
pub fn_prevent_self_run_away: Option<Hash>,
|
||||
pub fn_prevent_opponent_run_away: Option<Hash>,
|
||||
pub fn_on_end_turn: Option<Hash>,
|
||||
pub fn_on_damage: Option<Hash>,
|
||||
pub fn_on_faint: Option<Hash>,
|
||||
pub fn_on_switch_in: Option<Hash>,
|
||||
pub fn_on_after_held_item_consume: Option<Hash>,
|
||||
pub fn_change_experience_gained: Option<Hash>,
|
||||
pub fn_share_experience: Option<Hash>,
|
||||
pub fn_block_weather: Option<Hash>,
|
||||
pub fn_change_capture_rate_bonus: Option<Hash>,
|
||||
}
|
||||
|
||||
impl RuneScriptType {
|
||||
pub fn on_found_fn(&mut self, fn_name: &str, hash: Hash) {
|
||||
match fn_name {
|
||||
"on_initialize" => self.fn_on_initialize = Some(hash),
|
||||
"on_stack" => self.fn_on_stack = Some(hash),
|
||||
"on_remove" => self.fn_on_remove = Some(hash),
|
||||
"on_before_turn" => self.fn_on_before_turn = Some(hash),
|
||||
"change_speed" => self.fn_change_speed = Some(hash),
|
||||
"change_priority" => self.fn_change_priority = Some(hash),
|
||||
"change_move" => self.fn_change_move = Some(hash),
|
||||
"change_number_of_hits" => self.fn_change_number_of_hits = Some(hash),
|
||||
"prevent_move" => self.fn_prevent_move = Some(hash),
|
||||
"fail_move" => self.fn_fail_move = Some(hash),
|
||||
"stop_before_move" => self.fn_stop_before_move = Some(hash),
|
||||
"on_before_move" => self.fn_on_before_move = Some(hash),
|
||||
"fail_incoming_move" => self.fn_fail_incoming_move = Some(hash),
|
||||
"is_invulnerable" => self.fn_is_invulnerable = Some(hash),
|
||||
"on_move_miss" => self.fn_on_move_miss = Some(hash),
|
||||
"change_move_type" => self.fn_change_move_type = Some(hash),
|
||||
"change_effectiveness" => self.fn_change_effectiveness = Some(hash),
|
||||
"block_critical" => self.fn_block_critical = Some(hash),
|
||||
"block_incoming_critical" => self.fn_block_incoming_critical = Some(hash),
|
||||
"change_accuracy" => self.fn_change_accuracy = Some(hash),
|
||||
"change_critical_stage" => self.fn_change_critical_stage = Some(hash),
|
||||
"change_critical_modifier" => self.fn_change_critical_modifier = Some(hash),
|
||||
"change_stab_modifier" => self.fn_change_stab_modifier = Some(hash),
|
||||
"change_base_power" => self.fn_change_base_power = Some(hash),
|
||||
"bypass_defensive_stat_boost" => self.fn_bypass_defensive_stat_boost = Some(hash),
|
||||
"bypass_offensive_stat_boost" => self.fn_bypass_offensive_stat_boost = Some(hash),
|
||||
"change_offensive_stat_value" => self.fn_change_offensive_stat_value = Some(hash),
|
||||
"change_defensive_stat_value" => self.fn_change_defensive_stat_value = Some(hash),
|
||||
"change_damage_stat_modifier" => self.fn_change_damage_stat_modifier = Some(hash),
|
||||
"change_damage_modifier" => self.fn_change_damage_modifier = Some(hash),
|
||||
"change_damage" => self.fn_change_damage = Some(hash),
|
||||
"change_incoming_damage" => self.fn_change_incoming_damage = Some(hash),
|
||||
"on_incoming_hit" => self.fn_on_incoming_hit = Some(hash),
|
||||
"on_opponent_faints" => self.fn_on_opponent_faints = Some(hash),
|
||||
"prevent_stat_boost_change" => self.fn_prevent_stat_boost_change = Some(hash),
|
||||
"change_stat_boost_change" => self.fn_change_stat_boost_change = Some(hash),
|
||||
"prevent_secondary_effect" => self.fn_prevent_secondary_effect = Some(hash),
|
||||
"change_effect_chance" => self.fn_change_effect_chance = Some(hash),
|
||||
"change_incoming_effect_chance" => self.fn_change_incoming_effect_chance = Some(hash),
|
||||
"on_secondary_effect" => self.fn_on_secondary_effect = Some(hash),
|
||||
"on_after_hits" => self.fn_on_after_hits = Some(hash),
|
||||
"prevent_self_switch" => self.fn_prevent_self_switch = Some(hash),
|
||||
"prevent_opponent_switch" => self.fn_prevent_opponent_switch = Some(hash),
|
||||
"on_fail" => self.fn_on_fail = Some(hash),
|
||||
"on_opponent_fail" => self.fn_on_opponent_fail = Some(hash),
|
||||
"prevent_self_run_away" => self.fn_prevent_self_run_away = Some(hash),
|
||||
"prevent_opponent_run_away" => self.fn_prevent_opponent_run_away = Some(hash),
|
||||
"on_end_turn" => self.fn_on_end_turn = Some(hash),
|
||||
"on_damage" => self.fn_on_damage = Some(hash),
|
||||
"on_faint" => self.fn_on_faint = Some(hash),
|
||||
"on_switch_in" => self.fn_on_switch_in = Some(hash),
|
||||
"on_after_held_item_consume" => self.fn_on_after_held_item_consume = Some(hash),
|
||||
"change_experience_gained" => self.fn_change_experience_gained = Some(hash),
|
||||
"share_experience" => self.fn_share_experience = Some(hash),
|
||||
"block_weather" => self.fn_block_weather = Some(hash),
|
||||
"change_capture_rate_bonus" => self.fn_change_capture_rate_bonus = Some(hash),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
use crate::dynamic_data::{DynamicLibrary, ExecutingMove, Pokemon, Script, ScriptOwnerData, TurnChoice};
|
||||
use crate::script_implementations::rune::wrappers::*;
|
||||
use crate::script_implementations::rune::RuneScriptType;
|
||||
use crate::static_data::Parameter;
|
||||
use crate::StringKey;
|
||||
use hashbrown::HashMap;
|
||||
use parking_lot::RwLock;
|
||||
use rune::runtime::{Object, RuntimeContext, Shared, VmError, VmResult};
|
||||
use rune::{Any, Unit, Value};
|
||||
use std::convert::TryFrom;
|
||||
use std::error::Error;
|
||||
use std::ops::Deref;
|
||||
use std::sync::atomic::{AtomicBool, AtomicUsize};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct RuneScript {
|
||||
name: StringKey,
|
||||
state: RwLock<Shared<Object>>,
|
||||
/// Returns an atomic bool for internal marking of deletion. This is currently only specifically
|
||||
/// used for deletion of a script while we are holding a reference to it (i.e. executing a script
|
||||
/// hook on it).
|
||||
marked_for_deletion: AtomicBool,
|
||||
/// A script can be suppressed by other scripts. If a script is suppressed by at least one script
|
||||
/// we will not execute its methods. This holds the number of suppressions on the script.
|
||||
suppressed_count: AtomicUsize,
|
||||
/// The owner of this script (where the script is attached to)
|
||||
owner: ScriptOwnerData,
|
||||
|
||||
script_type: Arc<RuneScriptType>,
|
||||
|
||||
runtime: Arc<RuntimeContext>,
|
||||
unit: Arc<Unit>,
|
||||
}
|
||||
|
||||
unsafe impl Send for RuneScript {}
|
||||
|
||||
unsafe impl Sync for RuneScript {}
|
||||
|
||||
impl RuneScript {
|
||||
pub fn new(
|
||||
name: StringKey,
|
||||
object: Shared<Object>,
|
||||
owner: ScriptOwnerData,
|
||||
script_type: Arc<RuneScriptType>,
|
||||
runtime: Arc<RuntimeContext>,
|
||||
unit: Arc<Unit>,
|
||||
) -> Self {
|
||||
Self {
|
||||
name,
|
||||
state: RwLock::new(object),
|
||||
marked_for_deletion: Default::default(),
|
||||
suppressed_count: Default::default(),
|
||||
owner,
|
||||
script_type,
|
||||
runtime,
|
||||
unit,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Script for RuneScript {
|
||||
fn name(&self) -> anyhow::Result<&StringKey> { Ok(&self.name) }
|
||||
|
||||
fn get_marked_for_deletion(&self) -> &AtomicBool { &self.marked_for_deletion }
|
||||
|
||||
fn get_suppressed_count(&self) -> &AtomicUsize { &self.suppressed_count }
|
||||
|
||||
fn on_initialize(
|
||||
&self,
|
||||
_: &Arc<dyn DynamicLibrary>,
|
||||
pars: &HashMap<StringKey, Arc<Parameter>>,
|
||||
) -> anyhow::Result<()> {
|
||||
if pars.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
let mut write_lock = self.state.write();
|
||||
for par in pars {
|
||||
let key = rune::alloc::string::String::try_from(par.0.str())?;
|
||||
write_lock
|
||||
.borrow_mut()?
|
||||
.insert(key, parameter_to_rune_value(par.1.as_ref())?)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn block_critical(
|
||||
&self,
|
||||
move_data: &Arc<ExecutingMove>,
|
||||
target: &Pokemon,
|
||||
hit: u8,
|
||||
block_critical: &mut bool,
|
||||
) -> anyhow::Result<()> {
|
||||
if let Some(hash) = self.script_type.fn_block_critical {
|
||||
let mut vm = rune::runtime::Vm::new(self.runtime.clone(), self.unit.clone());
|
||||
todo!()
|
||||
// let block_critical_handle = RuneValueWrapper::new_mut(block_critical);
|
||||
// let read_lock = self.state.read();
|
||||
// let state = read_lock.deref();
|
||||
//
|
||||
// vm.execute(
|
||||
// hash,
|
||||
// vec![
|
||||
// Value::Object(state.clone()),
|
||||
// Value::from(move_data.wrap()?),
|
||||
// Value::from(target.wrap()?),
|
||||
// Value::from(hit),
|
||||
// Value::from(block_critical_handle.clone().wrap()?),
|
||||
// ],
|
||||
// )?;
|
||||
// *block_critical = block_critical_handle.value();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn change_speed(&self, choice: &Arc<TurnChoice>, speed: &mut u32) -> anyhow::Result<()> {
|
||||
if let Some(hash) = self.script_type.fn_change_speed {
|
||||
let mut vm = rune::runtime::Vm::new(self.runtime.clone(), self.unit.clone());
|
||||
let speed_handle = wrap_value_reference(*speed as i64)?;
|
||||
let read_lock = self.state.read();
|
||||
let state = read_lock.deref();
|
||||
|
||||
let res = vm
|
||||
.execute(
|
||||
hash,
|
||||
vec![
|
||||
Value::Object(state.clone()),
|
||||
Value::from(choice.wrap()),
|
||||
speed_handle.clone(),
|
||||
],
|
||||
)?
|
||||
.complete();
|
||||
if let VmResult::Err(e) = res {
|
||||
return Err(anyhow::anyhow!("Error executing script: {}", e));
|
||||
}
|
||||
|
||||
*speed = get_value_reference(speed_handle)? as u32;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any { self }
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any { self }
|
||||
}
|
||||
|
||||
fn parameter_to_rune_value(parameter: &Parameter) -> Result<Value, VmError> {
|
||||
match parameter {
|
||||
Parameter::Bool(b) => rune::to_value(*b),
|
||||
Parameter::Int(i) => rune::to_value(*i),
|
||||
Parameter::Float(f) => rune::to_value(*f),
|
||||
Parameter::String(s) => rune::to_value(s.str()),
|
||||
}
|
||||
}
|
|
@ -0,0 +1,179 @@
|
|||
use crate::dynamic_data::{ItemScript, Script, ScriptCategory, ScriptOwnerData, ScriptResolver};
|
||||
use crate::script_implementations::rune::script::RuneScript;
|
||||
use crate::script_implementations::rune::RuneScriptType;
|
||||
use crate::static_data::Item;
|
||||
use crate::StringKey;
|
||||
use hashbrown::HashMap;
|
||||
use parking_lot::RwLock;
|
||||
use rune::compile::meta::AssociatedKind;
|
||||
use rune::compile::{ComponentRef, MetaError};
|
||||
use rune::diagnostics::Diagnostic;
|
||||
use rune::runtime::{RuntimeContext, Shared};
|
||||
use rune::{Context, Diagnostics, Hash, Options, Source, Sources, Unit, Vm};
|
||||
use std::any::Any;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RuneScriptResolver {
|
||||
runtime: Arc<RuntimeContext>,
|
||||
unit: Arc<Unit>,
|
||||
script_types: HashMap<(ScriptCategory, StringKey), Arc<RuneScriptType>>,
|
||||
}
|
||||
|
||||
pub struct RuneScriptResolverBuilder {
|
||||
context: Context,
|
||||
scripts: Sources,
|
||||
}
|
||||
|
||||
impl ScriptResolver for RuneScriptResolver {
|
||||
fn load_script(
|
||||
&self,
|
||||
owner: ScriptOwnerData,
|
||||
category: ScriptCategory,
|
||||
script_key: &StringKey,
|
||||
) -> anyhow::Result<Option<Arc<dyn Script>>> {
|
||||
let script_type = if let Some(script_type) = self.script_types.get(&(category, script_key.clone())) {
|
||||
script_type
|
||||
} else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let state = Shared::new(rune::runtime::Object::new())?;
|
||||
let script = Arc::new(RuneScript::new(
|
||||
script_key.clone(),
|
||||
state,
|
||||
owner,
|
||||
script_type.clone(),
|
||||
self.runtime.clone(),
|
||||
self.unit.clone(),
|
||||
));
|
||||
Ok(Some(script))
|
||||
}
|
||||
|
||||
fn load_item_script(&self, _key: &dyn Item) -> anyhow::Result<Option<Arc<dyn ItemScript>>> { Ok(None) }
|
||||
|
||||
fn as_any(&self) -> &dyn Any { self }
|
||||
}
|
||||
|
||||
impl RuneScriptResolverBuilder {
|
||||
pub fn new() -> anyhow::Result<Self> {
|
||||
let mut context = Context::with_default_modules()?;
|
||||
context.install(super::wrappers::module()?)?;
|
||||
|
||||
Ok(Self {
|
||||
context,
|
||||
scripts: Sources::default(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn insert_script(&mut self, path: &Path, name: &str, script: &str) -> anyhow::Result<&mut Self> {
|
||||
self.scripts
|
||||
.insert(Source::with_path(name, script.to_string(), path)?)?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn build(mut self) -> anyhow::Result<Arc<dyn ScriptResolver>> {
|
||||
let mut visitor = FindScriptTypeVisitor::default();
|
||||
let mut diagnostics = Diagnostics::new();
|
||||
|
||||
let mut options = Options::default();
|
||||
options.debug_info(true);
|
||||
options.memoize_instance_fn(true);
|
||||
options.macros(true);
|
||||
options.bytecode(true);
|
||||
|
||||
let result = rune::prepare(&mut self.scripts)
|
||||
.with_context(&self.context)
|
||||
.with_visitor(&mut visitor)?
|
||||
.with_diagnostics(&mut diagnostics)
|
||||
.with_options(&options)
|
||||
.build();
|
||||
if diagnostics.has_error() {
|
||||
let error_message = diagnostics
|
||||
.diagnostics()
|
||||
.iter()
|
||||
.filter_map(|d| match d {
|
||||
Diagnostic::Fatal(f) => Some(f.to_string()),
|
||||
_ => None,
|
||||
})
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n");
|
||||
|
||||
return Err(anyhow::anyhow!("Error building Rune script: {}", error_message));
|
||||
}
|
||||
|
||||
let mut script_types = HashMap::with_capacity(visitor.script_types.len());
|
||||
for (key, script_type) in visitor.script_types {
|
||||
script_types.insert(key, Arc::new(script_type));
|
||||
}
|
||||
|
||||
Ok(Arc::new(RuneScriptResolver {
|
||||
runtime: Arc::new(self.context.runtime()?),
|
||||
unit: Arc::new(result?),
|
||||
script_types,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct FindScriptTypeVisitor {
|
||||
script_types: HashMap<(ScriptCategory, StringKey), RuneScriptType>,
|
||||
}
|
||||
|
||||
impl rune::compile::CompileVisitor for FindScriptTypeVisitor {
|
||||
fn register_meta(&mut self, meta: rune::compile::MetaRef<'_>) -> Result<(), MetaError> {
|
||||
match meta.kind {
|
||||
rune::compile::meta::Kind::Struct { .. } => {
|
||||
if meta.item.iter().count() < 2 {
|
||||
return Ok(());
|
||||
}
|
||||
let mod_name = meta.item.iter().nth(0).unwrap();
|
||||
let category = match get_mod_category(mod_name) {
|
||||
Ok(value) => value,
|
||||
Err(value) => return value,
|
||||
};
|
||||
let name = meta.item.last().unwrap();
|
||||
self.script_types
|
||||
.insert((category, name.to_string().as_str().into()), RuneScriptType::default());
|
||||
}
|
||||
rune::compile::meta::Kind::Function {
|
||||
associated: Some(AssociatedKind::Instance(associated)),
|
||||
..
|
||||
} => {
|
||||
if meta.item.iter().count() < 3 {
|
||||
return Ok(());
|
||||
}
|
||||
let mod_name = meta.item.iter().nth(0).unwrap();
|
||||
let category = match get_mod_category(mod_name) {
|
||||
Ok(value) => value,
|
||||
Err(value) => return value,
|
||||
};
|
||||
let instance = meta.item.iter().nth_back(1).unwrap();
|
||||
if let Some(script_type) = self
|
||||
.script_types
|
||||
.get_mut(&(category, instance.to_string().as_str().into()))
|
||||
{
|
||||
script_type.on_found_fn(associated.to_string().as_str(), meta.hash);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn get_mod_category(mod_name: ComponentRef) -> Result<ScriptCategory, Result<(), MetaError>> {
|
||||
Ok(match mod_name.to_string().as_str() {
|
||||
"moves" => ScriptCategory::Move,
|
||||
"abilities" => ScriptCategory::Ability,
|
||||
"status" => ScriptCategory::Status,
|
||||
"pokemon" => ScriptCategory::Pokemon,
|
||||
"sides" => ScriptCategory::Side,
|
||||
"battle" => ScriptCategory::Battle,
|
||||
"weather" => ScriptCategory::Weather,
|
||||
"item_battle_triggers" => ScriptCategory::ItemBattleTrigger,
|
||||
_ => return Err(Ok(())),
|
||||
})
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
use crate::dynamic_data::ExecutingMove;
|
||||
use crate::script_implementations::rune::wrappers::{impl_rune_wrapper, RuneWrapper};
|
||||
use rune::runtime::{AnyObj, Shared};
|
||||
use rune::Any;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<RuneExecutingMove>()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Any)]
|
||||
pub struct RuneExecutingMove {
|
||||
inner: Arc<ExecutingMove>,
|
||||
}
|
||||
|
||||
impl RuneExecutingMove {
|
||||
#[rune::function]
|
||||
pub fn target_count(&self) -> usize { self.inner.target_count() }
|
||||
#[rune::function]
|
||||
pub fn number_of_hits(&self) -> u8 { self.inner.number_of_hits() }
|
||||
#[rune::function]
|
||||
pub fn user(&self) -> Shared<AnyObj> { self.inner.user().wrap() }
|
||||
}
|
||||
|
||||
impl_rune_wrapper!(&Arc<ExecutingMove>, RuneExecutingMove);
|
|
@ -0,0 +1,67 @@
|
|||
use rune::runtime::Protocol;
|
||||
use rune::runtime::{AnyObj, Shared};
|
||||
use rune::{Any, Value};
|
||||
use std::ops::Deref;
|
||||
|
||||
mod executing_move;
|
||||
mod pokemon;
|
||||
mod turn_choice;
|
||||
|
||||
pub use executing_move::*;
|
||||
pub use pokemon::*;
|
||||
|
||||
pub trait RuneWrapper {
|
||||
#[inline]
|
||||
fn wrap(self) -> Shared<AnyObj>;
|
||||
}
|
||||
|
||||
pub fn module() -> anyhow::Result<rune::Module> {
|
||||
let mut module = rune::Module::new();
|
||||
module.ty::<RuneValueIntWrapper>()?;
|
||||
turn_choice::register(&mut module)?;
|
||||
pokemon::register(&mut module)?;
|
||||
|
||||
executing_move::register(&mut module)?;
|
||||
Ok(module)
|
||||
}
|
||||
|
||||
pub fn wrap_value_reference(value: i64) -> anyhow::Result<Value> {
|
||||
Ok(Value::Any(Shared::new(AnyObj::new(RuneValueIntWrapper::new(value))?)?))
|
||||
}
|
||||
|
||||
pub fn get_value_reference(value: Value) -> anyhow::Result<i64> {
|
||||
let obj = value.into_any().into_result()?;
|
||||
let obj = obj.take()?;
|
||||
let obj = obj.downcast_borrow_ref::<RuneValueIntWrapper>().unwrap();
|
||||
Ok(obj.value())
|
||||
}
|
||||
|
||||
#[derive(Any, Clone)]
|
||||
struct RuneValueIntWrapper {
|
||||
#[rune(get, set)]
|
||||
value: i64,
|
||||
}
|
||||
|
||||
impl RuneValueIntWrapper {
|
||||
pub fn new(value: i64) -> Self { Self { value } }
|
||||
|
||||
pub fn value(&self) -> i64 { self.value }
|
||||
pub fn set_value(&mut self, value: i64) { self.value = value; }
|
||||
}
|
||||
|
||||
impl RuneWrapper for RuneValueIntWrapper {
|
||||
fn wrap(self) -> Shared<AnyObj> { Shared::new(AnyObj::new(self).unwrap()).unwrap() }
|
||||
}
|
||||
|
||||
macro_rules! impl_rune_wrapper {
|
||||
($t:ty, $wrapped_type:ident) => {
|
||||
impl crate::script_implementations::rune::wrappers::RuneWrapper for $t {
|
||||
fn wrap(self) -> rune::runtime::Shared<rune::runtime::AnyObj> {
|
||||
rune::runtime::Shared::new(rune::runtime::AnyObj::new($wrapped_type { inner: self.clone() }).unwrap())
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub(self) use impl_rune_wrapper;
|
|
@ -0,0 +1,22 @@
|
|||
use crate::defines::LevelInt;
|
||||
use crate::dynamic_data::Pokemon;
|
||||
use crate::script_implementations::rune::wrappers::{impl_rune_wrapper, RuneWrapper};
|
||||
use rune::Any;
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<RunePokemon>()?;
|
||||
module.function_meta(RunePokemon::level)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Any)]
|
||||
pub struct RunePokemon {
|
||||
inner: Pokemon,
|
||||
}
|
||||
|
||||
impl RunePokemon {
|
||||
#[rune::function]
|
||||
fn level(&self) -> LevelInt { self.inner.level() }
|
||||
}
|
||||
|
||||
impl_rune_wrapper!(&Pokemon, RunePokemon);
|
|
@ -0,0 +1,26 @@
|
|||
use crate::dynamic_data::TurnChoice;
|
||||
use crate::script_implementations::rune::wrappers::{impl_rune_wrapper, RuneExecutingMove, RuneWrapper};
|
||||
use rune::{Any, Value};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<RuneTurnChoice>()?;
|
||||
module.function_meta(RuneTurnChoice::speed)?;
|
||||
module.function_meta(RuneTurnChoice::user)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Any)]
|
||||
pub struct RuneTurnChoice {
|
||||
inner: Arc<TurnChoice>,
|
||||
}
|
||||
|
||||
impl RuneTurnChoice {
|
||||
#[rune::function]
|
||||
fn speed(&self) -> u32 { self.inner.speed() }
|
||||
|
||||
#[rune::function]
|
||||
fn user(&self) -> Value { Value::from(self.inner.user().wrap()) }
|
||||
}
|
||||
|
||||
impl_rune_wrapper!(&Arc<TurnChoice>, RuneTurnChoice);
|
|
@ -1,5 +1,6 @@
|
|||
use crate::static_data::Parameter;
|
||||
use crate::StringKey;
|
||||
use hashbrown::HashMap;
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -10,7 +11,7 @@ pub trait SecondaryEffect: Debug {
|
|||
/// The name of the effect.
|
||||
fn effect_name(&self) -> &StringKey;
|
||||
/// A list of parameters for the effect.
|
||||
fn parameters(&self) -> &Vec<Arc<Parameter>>;
|
||||
fn parameters(&self) -> &HashMap<StringKey, Arc<Parameter>>;
|
||||
}
|
||||
|
||||
/// A secondary effect is an effect on a move that happens after it hits.
|
||||
|
@ -21,12 +22,12 @@ pub struct SecondaryEffectImpl {
|
|||
/// The name of the effect.
|
||||
effect_name: StringKey,
|
||||
/// A list of parameters for the effect.
|
||||
parameters: Vec<Arc<Parameter>>,
|
||||
parameters: HashMap<StringKey, Arc<Parameter>>,
|
||||
}
|
||||
|
||||
impl SecondaryEffectImpl {
|
||||
/// Instantiates a new Secondary Effect.
|
||||
pub fn new(chance: f32, effect_name: StringKey, parameters: Vec<Arc<Parameter>>) -> Self {
|
||||
pub fn new(chance: f32, effect_name: StringKey, parameters: HashMap<StringKey, Arc<Parameter>>) -> Self {
|
||||
Self {
|
||||
chance,
|
||||
effect_name,
|
||||
|
@ -45,7 +46,7 @@ impl SecondaryEffect for SecondaryEffectImpl {
|
|||
&self.effect_name
|
||||
}
|
||||
/// A list of parameters for the effect.
|
||||
fn parameters(&self) -> &Vec<Arc<Parameter>> {
|
||||
fn parameters(&self) -> &HashMap<StringKey, Arc<Parameter>> {
|
||||
&self.parameters
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::static_data::Parameter;
|
||||
use crate::StringKey;
|
||||
use hashbrown::HashMap;
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -10,7 +11,7 @@ pub trait Ability: Debug {
|
|||
/// The name of the script effect of the ability.
|
||||
fn effect(&self) -> &StringKey;
|
||||
/// The parameters for the script effect of the ability.
|
||||
fn parameters(&self) -> &Vec<Arc<Parameter>>;
|
||||
fn parameters(&self) -> &HashMap<StringKey, Arc<Parameter>>;
|
||||
}
|
||||
|
||||
/// An ability is a passive effect in battle that is attached to a Pokemon.
|
||||
|
@ -21,12 +22,12 @@ pub struct AbilityImpl {
|
|||
/// The name of the script effect of the ability.
|
||||
effect: StringKey,
|
||||
/// The parameters for the script effect of the ability.
|
||||
parameters: Vec<Arc<Parameter>>,
|
||||
parameters: HashMap<StringKey, Arc<Parameter>>,
|
||||
}
|
||||
|
||||
impl AbilityImpl {
|
||||
/// Instantiates a new ability.
|
||||
pub fn new(name: &StringKey, effect: &StringKey, parameters: Vec<Arc<Parameter>>) -> Self {
|
||||
pub fn new(name: &StringKey, effect: &StringKey, parameters: HashMap<StringKey, Arc<Parameter>>) -> Self {
|
||||
Self {
|
||||
name: name.clone(),
|
||||
effect: effect.clone(),
|
||||
|
@ -37,17 +38,11 @@ impl AbilityImpl {
|
|||
|
||||
impl Ability for AbilityImpl {
|
||||
/// The name of the ability.
|
||||
fn name(&self) -> &StringKey {
|
||||
&self.name
|
||||
}
|
||||
fn name(&self) -> &StringKey { &self.name }
|
||||
/// The name of the script effect of the ability.
|
||||
fn effect(&self) -> &StringKey {
|
||||
&self.effect
|
||||
}
|
||||
fn effect(&self) -> &StringKey { &self.effect }
|
||||
/// The parameters for the script effect of the ability.
|
||||
fn parameters(&self) -> &Vec<Arc<Parameter>> {
|
||||
&self.parameters
|
||||
}
|
||||
fn parameters(&self) -> &HashMap<StringKey, Arc<Parameter>> { &self.parameters }
|
||||
}
|
||||
|
||||
/// An ability index allows us to find an ability on a form. It combines a bool for whether the
|
||||
|
|
|
@ -5,7 +5,7 @@ use std::fs::File;
|
|||
use std::io::{BufReader, Read};
|
||||
use std::sync::Arc;
|
||||
|
||||
use hashbrown::HashSet;
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use num_traits::PrimInt;
|
||||
use project_root::get_project_root;
|
||||
use serde_json::Value;
|
||||
|
@ -223,10 +223,11 @@ pub fn load_abilities(path: &String) -> Arc<dyn AbilityLibrary> {
|
|||
if let Some(e) = value.get("effect") {
|
||||
effect = e.as_str().unwrap().into();
|
||||
}
|
||||
let mut parameters = Vec::new();
|
||||
if let Some(p) = value.get("parameters") {
|
||||
for par in p.as_array().unwrap() {
|
||||
parameters.push(parse_parameter(par));
|
||||
let mut parameters = HashMap::new();
|
||||
if let Some(pars) = value.get("parameters") {
|
||||
let pars = pars.as_object().unwrap();
|
||||
for par in pars {
|
||||
parameters.insert(par.0.as_str().into(), parse_parameter(par.1));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -258,11 +259,11 @@ pub fn load_moves(path: &String, types: &Arc<dyn TypeLibrary>) -> Arc<dyn MoveLi
|
|||
if let Some(chance_value) = v.get("chance") {
|
||||
chance = chance_value.as_f64().unwrap() as f32;
|
||||
}
|
||||
let mut parameters = Vec::new();
|
||||
let mut parameters = HashMap::new();
|
||||
if let Some(pars) = v.get("parameters") {
|
||||
let pars = pars.as_array().unwrap();
|
||||
let pars = pars.as_object().unwrap();
|
||||
for par in pars {
|
||||
parameters.push(parse_parameter(par));
|
||||
parameters.insert(par.0.as_str().into(), parse_parameter(par.1));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -451,10 +452,8 @@ fn parse_evolution(value: &Value) -> EvolutionData {
|
|||
EvolutionData::new(method, species)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "wasm"))]
|
||||
fn load_script_resolver(path: &String) -> Arc<dyn ScriptResolver> {
|
||||
Arc::new(EmptyScriptResolver::default())
|
||||
}
|
||||
#[cfg(not(any(feature = "wasm", feature = "rune")))]
|
||||
fn load_script_resolver(path: &String) -> Arc<dyn ScriptResolver> { Arc::new(EmptyScriptResolver::default()) }
|
||||
|
||||
#[cfg(feature = "wasm")]
|
||||
fn load_script_resolver(path: &String) -> Arc<dyn ScriptResolver> {
|
||||
|
@ -468,6 +467,28 @@ fn load_script_resolver(path: &String) -> Arc<dyn ScriptResolver> {
|
|||
resolver
|
||||
}
|
||||
|
||||
#[cfg(feature = "rune")]
|
||||
fn load_script_resolver(path: &String) -> Arc<dyn ScriptResolver> {
|
||||
let mut builder =
|
||||
pkmn_lib::script_implementations::rune::script_resolver::RuneScriptResolverBuilder::new().unwrap();
|
||||
// Recursively load all scripts in the scripts folder
|
||||
for entry in walkdir::WalkDir::new(path.to_string() + "scripts/") {
|
||||
let entry = entry.unwrap();
|
||||
let path = entry.path();
|
||||
if path.is_file() {
|
||||
let file = File::open(&path).unwrap();
|
||||
let mut reader = BufReader::new(file);
|
||||
let mut buffer = Vec::new();
|
||||
reader.read_to_end(&mut buffer).unwrap();
|
||||
builder
|
||||
.insert_script(path, &path.to_string_lossy(), &String::from_utf8(buffer).unwrap())
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
let resolver = builder.build().unwrap();
|
||||
resolver
|
||||
}
|
||||
|
||||
fn parse_form(
|
||||
name: StringKey,
|
||||
value: &Value,
|
||||
|
|
|
@ -1,285 +1,292 @@
|
|||
{
|
||||
"adaptability": {
|
||||
"effect": "IncreasedStab"
|
||||
},
|
||||
"aerilate": {
|
||||
"effect": "ChangeMoveType",
|
||||
"parameters": ["normal", "flying"]
|
||||
},
|
||||
"aftermath": {
|
||||
"effect": "Aftermath"
|
||||
},
|
||||
"air_lock": {
|
||||
"effect": "SuppressWeather"
|
||||
},
|
||||
"analytic": {
|
||||
"effect": "Analytic"
|
||||
},
|
||||
"anger_point": {
|
||||
"effect": "AngerPoint"
|
||||
},
|
||||
"anticipation": {
|
||||
"effect": "Anticipation"
|
||||
},
|
||||
"arena_trap": {
|
||||
"effect": "ArenaTrap"
|
||||
},
|
||||
"aroma_veil": {
|
||||
"effect": "AromaVeil"
|
||||
},
|
||||
"aura_break": {
|
||||
"effect": "AuraBreal"
|
||||
},
|
||||
"bad_dreams": {
|
||||
"effect": "BadDreams"
|
||||
},
|
||||
"battery": {
|
||||
"effect": "Battery"
|
||||
},
|
||||
"battle_armor": {
|
||||
"effect": "PreventCritical"
|
||||
},
|
||||
"battle_bond": {
|
||||
"effect": "BattleBond"
|
||||
},
|
||||
"beast_boost": {
|
||||
"effect": "BeastBoost"
|
||||
},
|
||||
"berserk": {
|
||||
"effect": "Berserk"
|
||||
},
|
||||
"big_pecks": {
|
||||
"effect": "PreventDefLowering"
|
||||
},
|
||||
"blaze": {
|
||||
"effect": "PowerUpType",
|
||||
"parameters": ["fire"]
|
||||
},
|
||||
"bulletproof": {
|
||||
"effect": "Bulletproof"
|
||||
},
|
||||
"cheek_pouch": {
|
||||
"effect": "CheekPouch"
|
||||
},
|
||||
"chlorophyll": {
|
||||
"effect": "DoubleSpeedInWeather",
|
||||
"parameters": ["HarshSunlight"]
|
||||
},
|
||||
"clear_body": {
|
||||
"effect": "PreventStatLowering"
|
||||
},
|
||||
"cloud_nine": {
|
||||
"effect": "SuppressWeather"
|
||||
},
|
||||
"color_change": {
|
||||
"effect": "ColorChange"
|
||||
},
|
||||
"comatose": {},
|
||||
"competitive": {},
|
||||
"compound_eyes": {},
|
||||
"contrary": {},
|
||||
"corrosion": {},
|
||||
"cursed_body": {},
|
||||
"cute_charm": {},
|
||||
"damp": {},
|
||||
"dancer": {},
|
||||
"dark_aura": {},
|
||||
"dazzling": {},
|
||||
"defeatist": {},
|
||||
"defiant": {},
|
||||
"delta_stream": {},
|
||||
"desolate_land": {},
|
||||
"disguise": {},
|
||||
"download": {},
|
||||
"drizzle": {},
|
||||
"drought": {},
|
||||
"dry_skin": {},
|
||||
"early_bird": {},
|
||||
"effect_spore": {},
|
||||
"electric_surge": {},
|
||||
"emergency_exit": {},
|
||||
"fairy_aura": {},
|
||||
"filter": {},
|
||||
"flame_body": {},
|
||||
"flare_boost": {},
|
||||
"flash_fire": {},
|
||||
"flower_gift": {},
|
||||
"flower_veil": {},
|
||||
"fluffy": {},
|
||||
"forecast": {},
|
||||
"forewarn": {},
|
||||
"friend_guard": {},
|
||||
"frisk": {},
|
||||
"full_metal_body": {},
|
||||
"fur_coat": {},
|
||||
"gale_wings": {},
|
||||
"galvanize": {},
|
||||
"gluttony": {},
|
||||
"gooey": {},
|
||||
"grass_pelt": {},
|
||||
"grassy_surge": {},
|
||||
"guts": {},
|
||||
"harvest": {},
|
||||
"healer": {},
|
||||
"heatproof": {},
|
||||
"heavy_metal": {},
|
||||
"honey_gather": {},
|
||||
"huge_power": {},
|
||||
"hustle": {},
|
||||
"hydration": {},
|
||||
"hyper_cutter": {},
|
||||
"ice_body": {},
|
||||
"illuminate": {},
|
||||
"illusion": {},
|
||||
"immunity": {},
|
||||
"imposter": {},
|
||||
"infiltrator": {},
|
||||
"innards_out": {},
|
||||
"inner_focus": {},
|
||||
"insomnia": {},
|
||||
"intimidate": {},
|
||||
"iron_barbs": {},
|
||||
"iron_fist": {},
|
||||
"justified": {},
|
||||
"keen_eye": {},
|
||||
"klutz": {},
|
||||
"leaf_guard": {},
|
||||
"levitate": {},
|
||||
"light_metal": {},
|
||||
"lightning_rod": {},
|
||||
"limber": {},
|
||||
"liquid_ooze": {},
|
||||
"liquid_voice": {},
|
||||
"long_reach": {},
|
||||
"magic_bounce": {},
|
||||
"magic_guard": {},
|
||||
"magician": {},
|
||||
"magma_armor": {},
|
||||
"magnet_pull": {},
|
||||
"marvel_scale": {},
|
||||
"mega_launcher": {},
|
||||
"merciless": {},
|
||||
"minus": {},
|
||||
"misty_surge": {},
|
||||
"mold_breaker": {},
|
||||
"moody": {},
|
||||
"motor_drive": {},
|
||||
"moxie": {},
|
||||
"multiscale": {},
|
||||
"multitype": {},
|
||||
"mummy": {},
|
||||
"natural_cure": {},
|
||||
"no_guard": {},
|
||||
"normalize": {},
|
||||
"oblivious": {},
|
||||
"overcoat": {},
|
||||
"overgrow": {},
|
||||
"own_tempo": {},
|
||||
"parental_bond": {},
|
||||
"pickpocket": {},
|
||||
"pickup": {},
|
||||
"pixilate": {},
|
||||
"plus": {},
|
||||
"poison_heal": {},
|
||||
"poison_point": {},
|
||||
"poison_touch": {},
|
||||
"power_construct": {},
|
||||
"power_of_alchemy": {},
|
||||
"prankster": {},
|
||||
"pressure": {},
|
||||
"primordial_sea": {},
|
||||
"prism_armor": {},
|
||||
"protean": {},
|
||||
"psychic_surge": {},
|
||||
"pure_power": {},
|
||||
"queenly_majesty": {},
|
||||
"quick_feet": {},
|
||||
"rain_dish": {},
|
||||
"rattled": {},
|
||||
"receiver": {},
|
||||
"reckless": {},
|
||||
"refrigerate": {},
|
||||
"regenerator": {},
|
||||
"rivalry": {},
|
||||
"rks_system": {},
|
||||
"rock_head": {},
|
||||
"rough_skin": {},
|
||||
"run_away": {},
|
||||
"sand_force": {},
|
||||
"sand_rush": {},
|
||||
"sand_stream": {},
|
||||
"sand_veil": {},
|
||||
"sap_sipper": {},
|
||||
"schooling": {},
|
||||
"scrappy": {},
|
||||
"serene_grace": {},
|
||||
"shadow_shield": {},
|
||||
"shadow_tag": {},
|
||||
"shed_skin": {},
|
||||
"sheer_force": {},
|
||||
"shell_armor": {},
|
||||
"shield_dust": {},
|
||||
"shields_down": {},
|
||||
"simple": {},
|
||||
"skill_link": {},
|
||||
"slow_start": {},
|
||||
"slush_rush": {},
|
||||
"sniper": {},
|
||||
"snow_cloak": {},
|
||||
"snow_warning": {},
|
||||
"solar_power": {},
|
||||
"solid_rock": {},
|
||||
"soul_heart": {},
|
||||
"soundproof": {},
|
||||
"speed_boost": {},
|
||||
"stakeout": {},
|
||||
"stall": {},
|
||||
"stamina": {},
|
||||
"stance_change": {},
|
||||
"static": {},
|
||||
"steadfast": {},
|
||||
"steelworker": {},
|
||||
"stench": {},
|
||||
"sticky_hold": {},
|
||||
"storm_drain": {},
|
||||
"strong_jaw": {},
|
||||
"sturdy": {},
|
||||
"suction_cups": {},
|
||||
"super_luck": {},
|
||||
"surge_surfer": {},
|
||||
"swarm": {},
|
||||
"sweet_veil": {},
|
||||
"swift_swim": {},
|
||||
"symbiosis": {},
|
||||
"synchronize": {},
|
||||
"tangled_feet": {},
|
||||
"tangling_hair": {},
|
||||
"technician": {},
|
||||
"telepathy": {},
|
||||
"teravolt": {},
|
||||
"thick_fat": {},
|
||||
"tinted_lens": {},
|
||||
"torrent": {},
|
||||
"tough_claws": {},
|
||||
"toxic_boost": {},
|
||||
"trace": {},
|
||||
"triage": {},
|
||||
"truant": {},
|
||||
"turboblaze": {},
|
||||
"unaware": {},
|
||||
"unburden": {},
|
||||
"unnerve": {},
|
||||
"victory_star": {},
|
||||
"vital_spirit": {},
|
||||
"volt_absorb": {},
|
||||
"water_absorb": {},
|
||||
"water_bubble": {},
|
||||
"water_compaction": {},
|
||||
"water_veil": {},
|
||||
"weak_armor": {},
|
||||
"white_smoke": {},
|
||||
"wimp_out": {},
|
||||
"wonder_guard": {},
|
||||
"wonder_skin": {},
|
||||
"zen_mode": {}
|
||||
"adaptability": {
|
||||
"effect": "IncreasedStab"
|
||||
},
|
||||
"aerilate": {
|
||||
"effect": "ChangeMoveType",
|
||||
"parameters": {
|
||||
"from": "normal",
|
||||
"to": "flying"
|
||||
}
|
||||
},
|
||||
"aftermath": {
|
||||
"effect": "Aftermath"
|
||||
},
|
||||
"air_lock": {
|
||||
"effect": "SuppressWeather"
|
||||
},
|
||||
"analytic": {
|
||||
"effect": "Analytic"
|
||||
},
|
||||
"anger_point": {
|
||||
"effect": "AngerPoint"
|
||||
},
|
||||
"anticipation": {
|
||||
"effect": "Anticipation"
|
||||
},
|
||||
"arena_trap": {
|
||||
"effect": "ArenaTrap"
|
||||
},
|
||||
"aroma_veil": {
|
||||
"effect": "AromaVeil"
|
||||
},
|
||||
"aura_break": {
|
||||
"effect": "AuraBreal"
|
||||
},
|
||||
"bad_dreams": {
|
||||
"effect": "BadDreams"
|
||||
},
|
||||
"battery": {
|
||||
"effect": "Battery"
|
||||
},
|
||||
"battle_armor": {
|
||||
"effect": "PreventCritical"
|
||||
},
|
||||
"battle_bond": {
|
||||
"effect": "BattleBond"
|
||||
},
|
||||
"beast_boost": {
|
||||
"effect": "BeastBoost"
|
||||
},
|
||||
"berserk": {
|
||||
"effect": "Berserk"
|
||||
},
|
||||
"big_pecks": {
|
||||
"effect": "PreventDefLowering"
|
||||
},
|
||||
"blaze": {
|
||||
"effect": "PowerUpType",
|
||||
"parameters": {
|
||||
"type": "fire"
|
||||
}
|
||||
},
|
||||
"bulletproof": {
|
||||
"effect": "Bulletproof"
|
||||
},
|
||||
"cheek_pouch": {
|
||||
"effect": "CheekPouch"
|
||||
},
|
||||
"chlorophyll": {
|
||||
"effect": "DoubleSpeedInWeather",
|
||||
"parameters": {
|
||||
"weather": "HarshSunlight"
|
||||
}
|
||||
},
|
||||
"clear_body": {
|
||||
"effect": "PreventStatLowering"
|
||||
},
|
||||
"cloud_nine": {
|
||||
"effect": "SuppressWeather"
|
||||
},
|
||||
"color_change": {
|
||||
"effect": "ColorChange"
|
||||
},
|
||||
"comatose": {},
|
||||
"competitive": {},
|
||||
"compound_eyes": {},
|
||||
"contrary": {},
|
||||
"corrosion": {},
|
||||
"cursed_body": {},
|
||||
"cute_charm": {},
|
||||
"damp": {},
|
||||
"dancer": {},
|
||||
"dark_aura": {},
|
||||
"dazzling": {},
|
||||
"defeatist": {},
|
||||
"defiant": {},
|
||||
"delta_stream": {},
|
||||
"desolate_land": {},
|
||||
"disguise": {},
|
||||
"download": {},
|
||||
"drizzle": {},
|
||||
"drought": {},
|
||||
"dry_skin": {},
|
||||
"early_bird": {},
|
||||
"effect_spore": {},
|
||||
"electric_surge": {},
|
||||
"emergency_exit": {},
|
||||
"fairy_aura": {},
|
||||
"filter": {},
|
||||
"flame_body": {},
|
||||
"flare_boost": {},
|
||||
"flash_fire": {},
|
||||
"flower_gift": {},
|
||||
"flower_veil": {},
|
||||
"fluffy": {},
|
||||
"forecast": {},
|
||||
"forewarn": {},
|
||||
"friend_guard": {},
|
||||
"frisk": {},
|
||||
"full_metal_body": {},
|
||||
"fur_coat": {},
|
||||
"gale_wings": {},
|
||||
"galvanize": {},
|
||||
"gluttony": {},
|
||||
"gooey": {},
|
||||
"grass_pelt": {},
|
||||
"grassy_surge": {},
|
||||
"guts": {},
|
||||
"harvest": {},
|
||||
"healer": {},
|
||||
"heatproof": {},
|
||||
"heavy_metal": {},
|
||||
"honey_gather": {},
|
||||
"huge_power": {},
|
||||
"hustle": {},
|
||||
"hydration": {},
|
||||
"hyper_cutter": {},
|
||||
"ice_body": {},
|
||||
"illuminate": {},
|
||||
"illusion": {},
|
||||
"immunity": {},
|
||||
"imposter": {},
|
||||
"infiltrator": {},
|
||||
"innards_out": {},
|
||||
"inner_focus": {},
|
||||
"insomnia": {},
|
||||
"intimidate": {},
|
||||
"iron_barbs": {},
|
||||
"iron_fist": {},
|
||||
"justified": {},
|
||||
"keen_eye": {},
|
||||
"klutz": {},
|
||||
"leaf_guard": {},
|
||||
"levitate": {},
|
||||
"light_metal": {},
|
||||
"lightning_rod": {},
|
||||
"limber": {},
|
||||
"liquid_ooze": {},
|
||||
"liquid_voice": {},
|
||||
"long_reach": {},
|
||||
"magic_bounce": {},
|
||||
"magic_guard": {},
|
||||
"magician": {},
|
||||
"magma_armor": {},
|
||||
"magnet_pull": {},
|
||||
"marvel_scale": {},
|
||||
"mega_launcher": {},
|
||||
"merciless": {},
|
||||
"minus": {},
|
||||
"misty_surge": {},
|
||||
"mold_breaker": {},
|
||||
"moody": {},
|
||||
"motor_drive": {},
|
||||
"moxie": {},
|
||||
"multiscale": {},
|
||||
"multitype": {},
|
||||
"mummy": {},
|
||||
"natural_cure": {},
|
||||
"no_guard": {},
|
||||
"normalize": {},
|
||||
"oblivious": {},
|
||||
"overcoat": {},
|
||||
"overgrow": {},
|
||||
"own_tempo": {},
|
||||
"parental_bond": {},
|
||||
"pickpocket": {},
|
||||
"pickup": {},
|
||||
"pixilate": {},
|
||||
"plus": {},
|
||||
"poison_heal": {},
|
||||
"poison_point": {},
|
||||
"poison_touch": {},
|
||||
"power_construct": {},
|
||||
"power_of_alchemy": {},
|
||||
"prankster": {},
|
||||
"pressure": {},
|
||||
"primordial_sea": {},
|
||||
"prism_armor": {},
|
||||
"protean": {},
|
||||
"psychic_surge": {},
|
||||
"pure_power": {},
|
||||
"queenly_majesty": {},
|
||||
"quick_feet": {},
|
||||
"rain_dish": {},
|
||||
"rattled": {},
|
||||
"receiver": {},
|
||||
"reckless": {},
|
||||
"refrigerate": {},
|
||||
"regenerator": {},
|
||||
"rivalry": {},
|
||||
"rks_system": {},
|
||||
"rock_head": {},
|
||||
"rough_skin": {},
|
||||
"run_away": {},
|
||||
"sand_force": {},
|
||||
"sand_rush": {},
|
||||
"sand_stream": {},
|
||||
"sand_veil": {},
|
||||
"sap_sipper": {},
|
||||
"schooling": {},
|
||||
"scrappy": {},
|
||||
"serene_grace": {},
|
||||
"shadow_shield": {},
|
||||
"shadow_tag": {},
|
||||
"shed_skin": {},
|
||||
"sheer_force": {},
|
||||
"shell_armor": {},
|
||||
"shield_dust": {},
|
||||
"shields_down": {},
|
||||
"simple": {},
|
||||
"skill_link": {},
|
||||
"slow_start": {},
|
||||
"slush_rush": {},
|
||||
"sniper": {},
|
||||
"snow_cloak": {},
|
||||
"snow_warning": {},
|
||||
"solar_power": {},
|
||||
"solid_rock": {},
|
||||
"soul_heart": {},
|
||||
"soundproof": {},
|
||||
"speed_boost": {},
|
||||
"stakeout": {},
|
||||
"stall": {},
|
||||
"stamina": {},
|
||||
"stance_change": {},
|
||||
"static": {},
|
||||
"steadfast": {},
|
||||
"steelworker": {},
|
||||
"stench": {},
|
||||
"sticky_hold": {},
|
||||
"storm_drain": {},
|
||||
"strong_jaw": {},
|
||||
"sturdy": {},
|
||||
"suction_cups": {},
|
||||
"super_luck": {},
|
||||
"surge_surfer": {},
|
||||
"swarm": {},
|
||||
"sweet_veil": {},
|
||||
"swift_swim": {},
|
||||
"symbiosis": {},
|
||||
"synchronize": {},
|
||||
"tangled_feet": {},
|
||||
"tangling_hair": {},
|
||||
"technician": {},
|
||||
"telepathy": {},
|
||||
"teravolt": {},
|
||||
"thick_fat": {},
|
||||
"tinted_lens": {},
|
||||
"torrent": {},
|
||||
"tough_claws": {},
|
||||
"toxic_boost": {},
|
||||
"trace": {},
|
||||
"triage": {},
|
||||
"truant": {},
|
||||
"turboblaze": {},
|
||||
"unaware": {},
|
||||
"unburden": {},
|
||||
"unnerve": {},
|
||||
"victory_star": {},
|
||||
"vital_spirit": {},
|
||||
"volt_absorb": {},
|
||||
"water_absorb": {},
|
||||
"water_bubble": {},
|
||||
"water_compaction": {},
|
||||
"water_veil": {},
|
||||
"weak_armor": {},
|
||||
"white_smoke": {},
|
||||
"wimp_out": {},
|
||||
"wonder_guard": {},
|
||||
"wonder_skin": {},
|
||||
"zen_mode": {}
|
||||
}
|
|
@ -29,9 +29,9 @@
|
|||
"effect": {
|
||||
"name": "drain",
|
||||
"chance": -1,
|
||||
"parameters": [
|
||||
0.5
|
||||
]
|
||||
"parameters": {
|
||||
"drain_mod": 0.5
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -65,9 +65,9 @@
|
|||
"effect": {
|
||||
"name": "change_target_special_defense",
|
||||
"chance": 10,
|
||||
"parameters": [
|
||||
-1
|
||||
]
|
||||
"parameters": {
|
||||
"amount": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -85,9 +85,9 @@
|
|||
"effect": {
|
||||
"name": "change_target_defense",
|
||||
"chance": -1,
|
||||
"parameters": [
|
||||
2
|
||||
]
|
||||
"parameters": {
|
||||
"amount": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -129,9 +129,9 @@
|
|||
"effect": {
|
||||
"name": "change_target_special_defense",
|
||||
"chance": -1,
|
||||
"parameters": [
|
||||
-2
|
||||
]
|
||||
"parameters": {
|
||||
"amount": -2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -233,9 +233,9 @@
|
|||
],
|
||||
"effect": {
|
||||
"name": "change_target_speed",
|
||||
"parameters": [
|
||||
2
|
||||
]
|
||||
"parameters": {
|
||||
"amount": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -324,9 +324,9 @@
|
|||
],
|
||||
"effect": {
|
||||
"name": "change_target_special_defense",
|
||||
"parameters": [
|
||||
2
|
||||
]
|
||||
"parameters": {
|
||||
"amount": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -363,9 +363,9 @@
|
|||
"effect": {
|
||||
"name": "change_all_target_stats",
|
||||
"chance": 10,
|
||||
"parameters": [
|
||||
1
|
||||
]
|
||||
"parameters": {
|
||||
"amount": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -397,9 +397,9 @@
|
|||
],
|
||||
"effect": {
|
||||
"name": "heal_each_end_of_turn",
|
||||
"parameters": [
|
||||
6.25
|
||||
]
|
||||
"parameters": {
|
||||
"percent": 6.25
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -466,9 +466,9 @@
|
|||
],
|
||||
"effect": {
|
||||
"name": "change_target_special_defense",
|
||||
"parameters": [
|
||||
1
|
||||
]
|
||||
"parameters": {
|
||||
"amount": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -592,9 +592,9 @@
|
|||
"effect": {
|
||||
"name": "change_target_attack",
|
||||
"chance": 10,
|
||||
"parameters": [
|
||||
-1
|
||||
]
|
||||
"parameters": {
|
||||
"amount": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -660,9 +660,9 @@
|
|||
],
|
||||
"effect": {
|
||||
"name": "change_target_attack",
|
||||
"parameters": [
|
||||
-1
|
||||
]
|
||||
"parameters": {
|
||||
"amount": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -3805,11 +3805,11 @@
|
|||
"ignore-substitute"
|
||||
],
|
||||
"effect": {
|
||||
"name": "ChangeTargetAtt",
|
||||
"name": "change_target_attack",
|
||||
"chance": -1,
|
||||
"parameters": [
|
||||
-1
|
||||
]
|
||||
"parameters": {
|
||||
"amount": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -5082,11 +5082,11 @@
|
|||
"mirror"
|
||||
],
|
||||
"effect": {
|
||||
"name": "ChangeTargetDef",
|
||||
"name": "change_target_defense",
|
||||
"chance": -1,
|
||||
"parameters": [
|
||||
-1
|
||||
]
|
||||
"parameters": {
|
||||
"amount": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
mod moves {
|
||||
|
||||
struct TestMove;
|
||||
|
||||
impl TestMove {
|
||||
pub fn change_speed(self, choice, speed) {
|
||||
println(`change_speed: ${choice.speed()}`);
|
||||
println(`user level: ${choice.user().level()}`);
|
||||
speed.value = 100;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -6,8 +6,8 @@
|
|||
use std::sync::{Arc, LazyLock};
|
||||
|
||||
use pkmn_lib::dynamic_data::{
|
||||
Battle, BattleParty, DamageSource, DynamicLibrary, ExecutingMove, MoveChoice, PokemonBuilder, PokemonParty,
|
||||
ScriptCategory, ScriptContainer, ScriptOwnerData, TurnChoice, VolatileScriptsOwner,
|
||||
Battle, BattleParty, DamageSource, DynamicLibrary, ExecutingMove, MoveChoice, PassChoice, PokemonBuilder,
|
||||
PokemonParty, ScriptCategory, ScriptContainer, ScriptOwnerData, TurnChoice, VolatileScriptsOwner,
|
||||
};
|
||||
|
||||
use crate::common::library_loader;
|
||||
|
@ -17,9 +17,7 @@ pub mod datatests;
|
|||
|
||||
static LIBRARY: LazyLock<Arc<dyn DynamicLibrary>> = LazyLock::new(|| library_loader::load_library().library);
|
||||
|
||||
fn get_library() -> Arc<dyn DynamicLibrary> {
|
||||
LIBRARY.clone()
|
||||
}
|
||||
fn get_library() -> Arc<dyn DynamicLibrary> { LIBRARY.clone() }
|
||||
|
||||
#[test]
|
||||
fn validate_library_load() {
|
||||
|
@ -35,7 +33,7 @@ fn validate_library_load() {
|
|||
\n\t- Abilities load time: {} ms\
|
||||
\n\t- Moves load time: {} ms\
|
||||
\n\t- Species load time: {} ms\
|
||||
\n\t- WASM load time: {} ms\
|
||||
\n\t- Script load time: {} ms\
|
||||
",
|
||||
(end_time - start_time).num_milliseconds(),
|
||||
result.types_load_time.num_milliseconds(),
|
||||
|
@ -49,6 +47,24 @@ fn validate_library_load() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rune_test() {
|
||||
let result = library_loader::load_library();
|
||||
let library = result.library;
|
||||
let script = library
|
||||
.load_script(ScriptOwnerData::None, ScriptCategory::Move, &"TestMove".into())
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert_eq!(script.name().unwrap().str(), "TestMove");
|
||||
let p1 = PokemonBuilder::new(library.clone(), "charizard".into(), 100)
|
||||
.build()
|
||||
.unwrap();
|
||||
let turn_choice = Arc::new(TurnChoice::Pass(PassChoice::new(p1)));
|
||||
let mut speed = 0;
|
||||
script.change_speed(&turn_choice, &mut speed).unwrap();
|
||||
assert_eq!(speed, 100);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_non_existing_wasm_script() {
|
||||
let start_time = chrono::Utc::now();
|
||||
|
@ -63,7 +79,7 @@ fn load_non_existing_wasm_script() {
|
|||
\n\t- Abilities load time: {} ms\
|
||||
\n\t- Moves load time: {} ms\
|
||||
\n\t- Species load time: {} ms\
|
||||
\n\t- WASM load time: {} ms\
|
||||
\n\t- Script load time: {} ms\
|
||||
",
|
||||
(end_time - start_time).num_milliseconds(),
|
||||
result.types_load_time.num_milliseconds(),
|
||||
|
|
Loading…
Reference in New Issue