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 = []
|
ffi = []
|
||||||
serde = ["dep:serde", "dep:serde-xml-rs", "atomig/serde"]
|
serde = ["dep:serde", "dep:serde-xml-rs", "atomig/serde"]
|
||||||
wasm = ["dep:wasmer"]
|
wasm = ["dep:wasmer"]
|
||||||
default = ["serde", "wasm", "ffi"]
|
rune = ["dep:rune"]
|
||||||
|
default = ["serde", "rune", "ffi"]
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
opt-level = 0
|
opt-level = 0
|
||||||
|
@ -55,7 +56,6 @@ parking_lot = "0.12"
|
||||||
serde = { version = "1.0", optional = true, features = ["derive"] }
|
serde = { version = "1.0", optional = true, features = ["derive"] }
|
||||||
serde_repr = "0.1"
|
serde_repr = "0.1"
|
||||||
serde-xml-rs = { version = "0.6", optional = true }
|
serde-xml-rs = { version = "0.6", optional = true }
|
||||||
wasmer = { version = "4.2", optional = true, default-features = false, features = ["sys", "wat", "llvm"] }
|
|
||||||
uuid = "1.5"
|
uuid = "1.5"
|
||||||
paste = { version = "1.0" }
|
paste = { version = "1.0" }
|
||||||
arcstr = { version = "1.1", features = ["std"] }
|
arcstr = { version = "1.1", features = ["std"] }
|
||||||
|
@ -65,6 +65,9 @@ anyhow_ext = "0.2"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
stdext = "0.3"
|
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]
|
[dev-dependencies]
|
||||||
csv = "1.3"
|
csv = "1.3"
|
||||||
project-root = "0.2"
|
project-root = "0.2"
|
||||||
|
@ -73,4 +76,5 @@ serde_json = "1.0"
|
||||||
serde_plain = "1.0"
|
serde_plain = "1.0"
|
||||||
# Allow us to assert whether floats are approximately a value
|
# Allow us to assert whether floats are approximately a value
|
||||||
assert_approx_eq = "1.1"
|
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(
|
Some(Arc::new(SecondaryEffectImpl::new(
|
||||||
-1.0,
|
-1.0,
|
||||||
StringKey::new("struggle"),
|
StringKey::new("struggle"),
|
||||||
vec![],
|
Default::default(),
|
||||||
))),
|
))),
|
||||||
HashSet::new(),
|
HashSet::new(),
|
||||||
));
|
));
|
||||||
|
|
|
@ -33,59 +33,34 @@ pub struct HitData {
|
||||||
|
|
||||||
impl HitData {
|
impl HitData {
|
||||||
/// Whether or not the hit is critical.
|
/// Whether or not the hit is critical.
|
||||||
pub fn is_critical(&self) -> bool {
|
pub fn is_critical(&self) -> bool { self.critical.load(Ordering::Relaxed) }
|
||||||
self.critical.load(Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
/// The base power of the hit.
|
/// The base power of the hit.
|
||||||
pub fn base_power(&self) -> u8 {
|
pub fn base_power(&self) -> u8 { self.base_power.load(Ordering::Relaxed) }
|
||||||
self.base_power.load(Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
/// The type effectiveness of the hit.
|
/// The type effectiveness of the hit.
|
||||||
pub fn effectiveness(&self) -> f32 {
|
pub fn effectiveness(&self) -> f32 { self.effectiveness.load(Ordering::Relaxed) }
|
||||||
self.effectiveness.load(Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
/// The actual damage of the hit.
|
/// The actual damage of the hit.
|
||||||
pub fn damage(&self) -> u32 {
|
pub fn damage(&self) -> u32 { self.damage.load(Ordering::Relaxed) }
|
||||||
self.damage.load(Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
/// The type id of the type used for the hit.
|
/// The type id of the type used for the hit.
|
||||||
pub fn move_type(&self) -> TypeIdentifier {
|
pub fn move_type(&self) -> TypeIdentifier { self.move_type.load(Ordering::Relaxed) }
|
||||||
self.move_type.load(Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
/// Whether or not the hit has failed.
|
/// Whether or not the hit has failed.
|
||||||
pub fn has_failed(&self) -> bool {
|
pub fn has_failed(&self) -> bool { self.has_failed.load(Ordering::Relaxed) }
|
||||||
self.has_failed.load(Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets whether or not the hit is critical.
|
/// Sets whether or not the hit is critical.
|
||||||
pub fn set_critical(&self, value: bool) {
|
pub fn set_critical(&self, value: bool) { self.critical.store(value, Ordering::SeqCst); }
|
||||||
self.critical.store(value, Ordering::SeqCst);
|
|
||||||
}
|
|
||||||
/// Sets the base power of the hit.
|
/// Sets the base power of the hit.
|
||||||
pub fn set_base_power(&self, value: u8) {
|
pub fn set_base_power(&self, value: u8) { self.base_power.store(value, Ordering::SeqCst); }
|
||||||
self.base_power.store(value, Ordering::SeqCst);
|
|
||||||
}
|
|
||||||
/// Sets the type effectiveness of the hit.
|
/// Sets the type effectiveness of the hit.
|
||||||
pub fn set_effectiveness(&self, value: f32) {
|
pub fn set_effectiveness(&self, value: f32) { self.effectiveness.store(value, Ordering::SeqCst); }
|
||||||
self.effectiveness.store(value, Ordering::SeqCst);
|
|
||||||
}
|
|
||||||
/// Sets the actual damage of the hit.
|
/// Sets the actual damage of the hit.
|
||||||
pub fn set_damage(&self, value: u32) {
|
pub fn set_damage(&self, value: u32) { self.damage.store(value, Ordering::SeqCst); }
|
||||||
self.damage.store(value, Ordering::SeqCst);
|
|
||||||
}
|
|
||||||
/// Sets the move type id of the hit.
|
/// Sets the move type id of the hit.
|
||||||
pub fn set_move_type(&self, value: TypeIdentifier) {
|
pub fn set_move_type(&self, value: TypeIdentifier) { self.move_type.store(value, Ordering::SeqCst); }
|
||||||
self.move_type.store(value, Ordering::SeqCst);
|
|
||||||
}
|
|
||||||
/// Marks the hit as failed.
|
/// Marks the hit as failed.
|
||||||
pub fn fail(&self) {
|
pub fn fail(&self) { self.has_failed.store(true, Ordering::SeqCst); }
|
||||||
self.has_failed.store(true, Ordering::SeqCst);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An executing move is the data of the move for while it is executing.
|
/// An executing move is the data of the move for while it is executing.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
||||||
pub struct ExecutingMove {
|
pub struct ExecutingMove {
|
||||||
/// The number of hits this move has.
|
/// The number of hits this move has.
|
||||||
number_of_hits: u8,
|
number_of_hits: u8,
|
||||||
|
@ -134,29 +109,17 @@ impl ExecutingMove {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The number of targets this move has.
|
/// The number of targets this move has.
|
||||||
pub fn target_count(&self) -> usize {
|
pub fn target_count(&self) -> usize { self.targets.len() }
|
||||||
self.targets.len()
|
|
||||||
}
|
|
||||||
/// The number of hits this move has per target.
|
/// The number of hits this move has per target.
|
||||||
pub fn number_of_hits(&self) -> u8 {
|
pub fn number_of_hits(&self) -> u8 { self.number_of_hits }
|
||||||
self.number_of_hits
|
|
||||||
}
|
|
||||||
/// The user of the move.
|
/// The user of the move.
|
||||||
pub fn user(&self) -> &Pokemon {
|
pub fn user(&self) -> &Pokemon { &self.user }
|
||||||
&self.user
|
|
||||||
}
|
|
||||||
/// The move the user has actually chosen to do.
|
/// The move the user has actually chosen to do.
|
||||||
pub fn chosen_move(&self) -> &Arc<LearnedMove> {
|
pub fn chosen_move(&self) -> &Arc<LearnedMove> { &self.chosen_move }
|
||||||
&self.chosen_move
|
|
||||||
}
|
|
||||||
/// The move that the user is actually going to do.
|
/// The move that the user is actually going to do.
|
||||||
pub fn use_move(&self) -> &Arc<dyn MoveData> {
|
pub fn use_move(&self) -> &Arc<dyn MoveData> { &self.use_move }
|
||||||
&self.use_move
|
|
||||||
}
|
|
||||||
/// The script of the move.
|
/// The script of the move.
|
||||||
pub fn script(&self) -> &ScriptContainer {
|
pub fn script(&self) -> &ScriptContainer { &self.script }
|
||||||
&self.script
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets a hit data for a target, with a specific index.
|
/// 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>> {
|
pub fn get_hit_data(&self, for_target: &Pokemon, hit: u8) -> Result<&Arc<HitData>> {
|
||||||
|
@ -215,17 +178,11 @@ impl ExecutingMove {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScriptSource for ExecutingMove {
|
impl ScriptSource for ExecutingMove {
|
||||||
fn get_script_count(&self) -> Result<usize> {
|
fn get_script_count(&self) -> Result<usize> { Ok(1) }
|
||||||
Ok(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> {
|
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> { &self.script_source_data }
|
||||||
&self.script_source_data
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_own_scripts(&self, scripts: &mut Vec<ScriptWrapper>) {
|
fn get_own_scripts(&self, scripts: &mut Vec<ScriptWrapper>) { scripts.push((&self.script).into()); }
|
||||||
scripts.push((&self.script).into());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn collect_scripts(&self, scripts: &mut Vec<ScriptWrapper>) -> Result<()> {
|
fn collect_scripts(&self, scripts: &mut Vec<ScriptWrapper>) -> Result<()> {
|
||||||
self.get_own_scripts(scripts);
|
self.get_own_scripts(scripts);
|
||||||
|
|
|
@ -216,21 +216,13 @@ impl Pokemon {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The library data of the Pokemon.
|
/// The library data of the Pokemon.
|
||||||
pub fn library(&self) -> &Arc<dyn DynamicLibrary> {
|
pub fn library(&self) -> &Arc<dyn DynamicLibrary> { &self.data.library }
|
||||||
&self.data.library
|
|
||||||
}
|
|
||||||
/// The species of the Pokemon.
|
/// The species of the Pokemon.
|
||||||
pub fn species(&self) -> Arc<dyn Species> {
|
pub fn species(&self) -> Arc<dyn Species> { self.data.species.read().clone() }
|
||||||
self.data.species.read().clone()
|
|
||||||
}
|
|
||||||
/// The form of the Pokemon.
|
/// The form of the Pokemon.
|
||||||
pub fn form(&self) -> Arc<dyn Form> {
|
pub fn form(&self) -> Arc<dyn Form> { self.data.form.read().clone() }
|
||||||
self.data.form.read().clone()
|
|
||||||
}
|
|
||||||
/// Whether or not the Pokemon is showing as a different species than it actually is.
|
/// Whether or not the Pokemon is showing as a different species than it actually is.
|
||||||
pub fn has_different_display_species(&self) -> bool {
|
pub fn has_different_display_species(&self) -> bool { self.data.display_species.is_some() }
|
||||||
self.data.display_species.is_some()
|
|
||||||
}
|
|
||||||
/// The species that should be displayed to the user. This handles stuff like the Illusion ability.
|
/// The species that should be displayed to the user. This handles stuff like the Illusion ability.
|
||||||
pub fn display_species(&self) -> Arc<dyn Species> {
|
pub fn display_species(&self) -> Arc<dyn Species> {
|
||||||
if let Some(v) = &self.data.display_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.
|
/// Whether or not the Pokemon is showing as a different form than it actually is.
|
||||||
pub fn has_different_display_form(&self) -> bool {
|
pub fn has_different_display_form(&self) -> bool { self.data.display_form.is_some() }
|
||||||
self.data.display_form.is_some()
|
|
||||||
}
|
|
||||||
/// The form that should be displayed to the user. This handles stuff like the Illusion ability.
|
/// The form that should be displayed to the user. This handles stuff like the Illusion ability.
|
||||||
pub fn display_form(&self) -> Arc<dyn Form> {
|
pub fn display_form(&self) -> Arc<dyn Form> {
|
||||||
if let Some(v) = &self.data.display_form {
|
if let Some(v) = &self.data.display_form {
|
||||||
|
@ -253,32 +243,20 @@ impl Pokemon {
|
||||||
}
|
}
|
||||||
/// The current level of the Pokemon.
|
/// The current level of the Pokemon.
|
||||||
/// [See also](https://bulbapedia.bulbagarden.net/wiki/Level)
|
/// [See also](https://bulbapedia.bulbagarden.net/wiki/Level)
|
||||||
pub fn level(&self) -> LevelInt {
|
pub fn level(&self) -> LevelInt { self.data.level.load(Ordering::Relaxed) }
|
||||||
self.data.level.load(Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
/// The amount of experience of the Pokemon.
|
/// The amount of experience of the Pokemon.
|
||||||
/// [See also](https://bulbapedia.bulbagarden.net/wiki/Experience)
|
/// [See also](https://bulbapedia.bulbagarden.net/wiki/Experience)
|
||||||
pub fn experience(&self) -> u32 {
|
pub fn experience(&self) -> u32 { self.data.experience.load(Ordering::Relaxed) }
|
||||||
self.data.experience.load(Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
/// The personality value of the Pokemon.
|
/// The personality value of the Pokemon.
|
||||||
/// [See also](https://bulbapedia.bulbagarden.net/wiki/Personality_value)
|
/// [See also](https://bulbapedia.bulbagarden.net/wiki/Personality_value)
|
||||||
pub fn personality_value(&self) -> u32 {
|
pub fn personality_value(&self) -> u32 { self.data.personality_value }
|
||||||
self.data.personality_value
|
|
||||||
}
|
|
||||||
/// The gender of the Pokemon.
|
/// The gender of the Pokemon.
|
||||||
pub fn gender(&self) -> Gender {
|
pub fn gender(&self) -> Gender { *self.data.gender.read() }
|
||||||
*self.data.gender.read()
|
|
||||||
}
|
|
||||||
/// The coloring of the Pokemon. Value 0 is the default, value 1 means shiny. Other values are
|
/// 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.
|
/// currently not used, and can be used for other implementations.
|
||||||
pub fn coloring(&self) -> u8 {
|
pub fn coloring(&self) -> u8 { self.data.coloring }
|
||||||
self.data.coloring
|
|
||||||
}
|
|
||||||
/// Gets the held item of a Pokemon
|
/// Gets the held item of a Pokemon
|
||||||
pub fn held_item(&self) -> &RwLock<Option<Arc<dyn Item>>> {
|
pub fn held_item(&self) -> &RwLock<Option<Arc<dyn Item>>> { &self.data.held_item }
|
||||||
&self.data.held_item
|
|
||||||
}
|
|
||||||
/// Checks whether the Pokemon is holding a specific item.
|
/// Checks whether the Pokemon is holding a specific item.
|
||||||
pub fn has_held_item(&self, name: &StringKey) -> bool {
|
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.
|
// 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())
|
self.data.held_item.write().replace(item.clone())
|
||||||
}
|
}
|
||||||
/// Removes the held item from the Pokemon. Returns the previously held item.
|
/// Removes the held item from the Pokemon. Returns the previously held item.
|
||||||
pub fn remove_held_item(&self) -> Option<Arc<dyn Item>> {
|
pub fn remove_held_item(&self) -> Option<Arc<dyn Item>> { self.data.held_item.write().take() }
|
||||||
self.data.held_item.write().take()
|
|
||||||
}
|
|
||||||
/// Makes the Pokemon uses its held item.
|
/// Makes the Pokemon uses its held item.
|
||||||
pub fn consume_held_item(&self) -> Result<bool> {
|
pub fn consume_held_item(&self) -> Result<bool> {
|
||||||
if self.data.held_item.read().is_none() {
|
if self.data.held_item.read().is_none() {
|
||||||
|
@ -316,72 +292,42 @@ impl Pokemon {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The remaining health points of the Pokemon.
|
/// The remaining health points of the Pokemon.
|
||||||
pub fn current_health(&self) -> u32 {
|
pub fn current_health(&self) -> u32 { self.data.current_health.load(Ordering::Relaxed) }
|
||||||
self.data.current_health.load(Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
/// The max health points of the Pokemon.
|
/// The max health points of the Pokemon.
|
||||||
pub fn max_health(&self) -> u32 {
|
pub fn max_health(&self) -> u32 { self.data.boosted_stats.hp() }
|
||||||
self.data.boosted_stats.hp()
|
|
||||||
}
|
|
||||||
/// The weight of the Pokemon in kilograms.
|
/// The weight of the Pokemon in kilograms.
|
||||||
pub fn weight(&self) -> f32 {
|
pub fn weight(&self) -> f32 { self.data.weight.load(Ordering::Relaxed) }
|
||||||
self.data.weight.load(Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
/// Sets the weight of the Pokemon in kilograms.
|
/// Sets the weight of the Pokemon in kilograms.
|
||||||
pub fn set_weight(&self, weight: f32) {
|
pub fn set_weight(&self, weight: f32) { self.data.weight.store(weight, Ordering::Relaxed) }
|
||||||
self.data.weight.store(weight, Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
/// The height of the Pokemon in meters.
|
/// The height of the Pokemon in meters.
|
||||||
pub fn height(&self) -> f32 {
|
pub fn height(&self) -> f32 { self.data.height.load(Ordering::Relaxed) }
|
||||||
self.data.height.load(Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The current happiness of the Pokemon. Also known as friendship.
|
/// The current happiness of the Pokemon. Also known as friendship.
|
||||||
pub fn happiness(&self) -> u8 {
|
pub fn happiness(&self) -> u8 { self.data.happiness.load(Ordering::Relaxed) }
|
||||||
self.data.happiness.load(Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An optional nickname of the Pokemon.
|
/// An optional nickname of the Pokemon.
|
||||||
pub fn nickname(&self) -> &Option<String> {
|
pub fn nickname(&self) -> &Option<String> { &self.data.nickname }
|
||||||
&self.data.nickname
|
|
||||||
}
|
|
||||||
/// An index of the ability to find the actual ability on the form.
|
/// An index of the ability to find the actual ability on the form.
|
||||||
pub fn real_ability(&self) -> &AbilityIndex {
|
pub fn real_ability(&self) -> &AbilityIndex { &self.data.ability_index }
|
||||||
&self.data.ability_index
|
|
||||||
}
|
|
||||||
/// The current types of the Pokemon.
|
/// The current types of the Pokemon.
|
||||||
pub fn types(&self) -> RwLockReadGuard<'_, RawRwLock, Vec<TypeIdentifier>> {
|
pub fn types(&self) -> RwLockReadGuard<'_, RawRwLock, Vec<TypeIdentifier>> { self.data.types.read() }
|
||||||
self.data.types.read()
|
|
||||||
}
|
|
||||||
/// The moves the Pokemon has learned. This is of a set length of [`MAX_MOVES`]. Empty move slots
|
/// The moves the Pokemon has learned. This is of a set length of [`MAX_MOVES`]. Empty move slots
|
||||||
/// are defined by None.
|
/// are defined by None.
|
||||||
pub fn learned_moves(&self) -> &RwLock<[Option<Arc<LearnedMove>>; MAX_MOVES]> {
|
pub fn learned_moves(&self) -> &RwLock<[Option<Arc<LearnedMove>>; MAX_MOVES]> { &self.data.moves }
|
||||||
&self.data.moves
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The stats of the Pokemon when disregarding any stat boosts.
|
/// The stats of the Pokemon when disregarding any stat boosts.
|
||||||
pub fn flat_stats(&self) -> &Arc<StatisticSet<u32>> {
|
pub fn flat_stats(&self) -> &Arc<StatisticSet<u32>> { &self.data.flat_stats }
|
||||||
&self.data.flat_stats
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The amount of boosts on a specific stat.
|
/// The amount of boosts on a specific stat.
|
||||||
pub fn stat_boosts(&self) -> &Arc<ClampedStatisticSet<i8, -6, 6>> {
|
pub fn stat_boosts(&self) -> &Arc<ClampedStatisticSet<i8, -6, 6>> { &self.data.stat_boost }
|
||||||
&self.data.stat_boost
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Whether or not this Pokemon is still an egg, and therefore cannot battle.
|
/// Whether or not this Pokemon is still an egg, and therefore cannot battle.
|
||||||
pub fn is_egg(&self) -> bool {
|
pub fn is_egg(&self) -> bool { self.data.is_egg }
|
||||||
self.data.is_egg
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The stats of the Pokemon including the stat boosts
|
/// The stats of the Pokemon including the stat boosts
|
||||||
pub fn boosted_stats(&self) -> &Arc<StatisticSet<u32>> {
|
pub fn boosted_stats(&self) -> &Arc<StatisticSet<u32>> { &self.data.boosted_stats }
|
||||||
&self.data.boosted_stats
|
|
||||||
}
|
|
||||||
/// Get the stat boosts for a specific stat.
|
/// Get the stat boosts for a specific stat.
|
||||||
pub fn stat_boost(&self, stat: Statistic) -> i8 {
|
pub fn stat_boost(&self, stat: Statistic) -> i8 { self.data.stat_boost.get_stat(stat) }
|
||||||
self.data.stat_boost.get_stat(stat)
|
|
||||||
}
|
|
||||||
/// Change a boosted stat by a certain amount.
|
/// 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> {
|
pub fn change_stat_boost(&self, stat: Statistic, mut diff_amount: i8, self_inflicted: bool) -> Result<bool> {
|
||||||
let mut prevent = false;
|
let mut prevent = false;
|
||||||
|
@ -440,14 +386,10 @@ impl Pokemon {
|
||||||
|
|
||||||
/// Gets an individual value of the Pokemon.
|
/// Gets an individual value of the Pokemon.
|
||||||
/// [See also](https://bulbapedia.bulbagarden.net/wiki/Individual_values)
|
/// [See also](https://bulbapedia.bulbagarden.net/wiki/Individual_values)
|
||||||
pub fn individual_values(&self) -> &Arc<ClampedStatisticSet<u8, 0, 31>> {
|
pub fn individual_values(&self) -> &Arc<ClampedStatisticSet<u8, 0, 31>> { &self.data.individual_values }
|
||||||
&self.data.individual_values
|
|
||||||
}
|
|
||||||
/// Gets an effort value of the Pokemon.
|
/// Gets an effort value of the Pokemon.
|
||||||
/// [See also](https://bulbapedia.bulbagarden.net/wiki/Effort_values)
|
/// [See also](https://bulbapedia.bulbagarden.net/wiki/Effort_values)
|
||||||
pub fn effort_values(&self) -> &Arc<ClampedStatisticSet<u8, 0, 252>> {
|
pub fn effort_values(&self) -> &Arc<ClampedStatisticSet<u8, 0, 252>> { &self.data.effort_values }
|
||||||
&self.data.effort_values
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the battle the battle is currently in.
|
/// Gets the battle the battle is currently in.
|
||||||
pub fn get_battle(&self) -> Option<Battle> {
|
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
|
/// 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.
|
/// if the Pokemon is on the battlefield.
|
||||||
pub fn get_battle_index(&self) -> Option<u8> {
|
pub fn get_battle_index(&self) -> Option<u8> { self.data.battle_data.read().as_ref().map(|data| data.index()) }
|
||||||
self.data.battle_data.read().as_ref().map(|data| data.index())
|
|
||||||
}
|
|
||||||
/// Returns whether something overrides the ability.
|
/// Returns whether something overrides the ability.
|
||||||
pub fn is_ability_overriden(&self) -> bool {
|
pub fn is_ability_overriden(&self) -> bool { self.data.override_ability.is_some() }
|
||||||
self.data.override_ability.is_some()
|
|
||||||
}
|
|
||||||
/// Returns the currently active ability.
|
/// Returns the currently active ability.
|
||||||
pub fn active_ability(&self) -> Result<Arc<dyn Ability>> {
|
pub fn active_ability(&self) -> Result<Arc<dyn Ability>> {
|
||||||
if let Some(v) = &self.data.override_ability {
|
if let Some(v) = &self.data.override_ability {
|
||||||
|
@ -496,25 +434,17 @@ impl Pokemon {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The script for the status.
|
/// The script for the status.
|
||||||
pub fn status(&self) -> &ScriptContainer {
|
pub fn status(&self) -> &ScriptContainer { &self.data.status_script }
|
||||||
&self.data.status_script
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the script for the currently active ability.
|
/// Returns the script for the currently active ability.
|
||||||
pub fn ability_script(&self) -> &ScriptContainer {
|
pub fn ability_script(&self) -> &ScriptContainer { &self.data.ability_script }
|
||||||
&self.data.ability_script
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Whether or not the Pokemon is allowed to gain experience.
|
/// Whether or not the Pokemon is allowed to gain experience.
|
||||||
pub fn allowed_experience_gain(&self) -> bool {
|
pub fn allowed_experience_gain(&self) -> bool { self.data.allowed_experience }
|
||||||
self.data.allowed_experience
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The nature of the Pokemon.
|
/// The nature of the Pokemon.
|
||||||
/// [See also](https://bulbapedia.bulbagarden.net/wiki/Nature)
|
/// [See also](https://bulbapedia.bulbagarden.net/wiki/Nature)
|
||||||
pub fn nature(&self) -> &Arc<dyn Nature> {
|
pub fn nature(&self) -> &Arc<dyn Nature> { &self.data.nature }
|
||||||
&self.data.nature
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculates the flat stats on the Pokemon. This should be called when for example the base
|
/// Calculates the flat stats on the Pokemon. This should be called when for example the base
|
||||||
/// stats, level, nature, IV, or EV changes. This has a side effect of recalculating the boosted
|
/// stats, level, nature, IV, or EV changes. This has a side effect of recalculating the boosted
|
||||||
|
@ -606,7 +536,7 @@ impl Pokemon {
|
||||||
.set(ability_script)
|
.set(ability_script)
|
||||||
.as_ref()
|
.as_ref()
|
||||||
// Ensure the ability script gets initialized with the parameters for the ability.
|
// 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 {
|
match script_result {
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -646,14 +576,10 @@ impl Pokemon {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether or not the Pokemon is useable in a battle.
|
/// Whether or not the Pokemon is useable in a battle.
|
||||||
pub fn is_usable(&self) -> bool {
|
pub fn is_usable(&self) -> bool { !self.data.is_caught && !self.data.is_egg && !self.is_fainted() }
|
||||||
!self.data.is_caught && !self.data.is_egg && !self.is_fainted()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns whether the Pokemon is fainted.
|
/// Returns whether the Pokemon is fainted.
|
||||||
pub fn is_fainted(&self) -> bool {
|
pub fn is_fainted(&self) -> bool { self.current_health() == 0 }
|
||||||
self.current_health() == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the current battle the Pokemon is in.
|
/// Sets the current battle the Pokemon is in.
|
||||||
pub fn set_battle_data(&self, battle: WeakBattleReference, battle_side_index: u8) {
|
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.
|
/// Removes the current non-volatile status from the Pokemon.
|
||||||
pub fn clear_status(&self) {
|
pub fn clear_status(&self) { self.data.status_script.clear() }
|
||||||
self.data.status_script.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Increases the level by a certain amount
|
/// Increases the level by a certain amount
|
||||||
pub fn change_level_by(&self, amount: LevelInt) -> Result<()> {
|
pub fn change_level_by(&self, amount: LevelInt) -> Result<()> {
|
||||||
|
@ -858,9 +782,7 @@ impl Pokemon {
|
||||||
|
|
||||||
/// Converts the Pokemon into a serializable form.
|
/// Converts the Pokemon into a serializable form.
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
pub fn serialize(&self) -> Result<super::serialization::SerializedPokemon> {
|
pub fn serialize(&self) -> Result<super::serialization::SerializedPokemon> { self.into() }
|
||||||
self.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deserializes a Pokemon from a serializable form.
|
/// Deserializes a Pokemon from a serializable form.
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
|
@ -995,23 +917,17 @@ impl Pokemon {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the inner pointer to the reference counted data.
|
/// Gets the inner pointer to the reference counted data.
|
||||||
pub fn as_ptr(&self) -> *const c_void {
|
pub fn as_ptr(&self) -> *const c_void { Arc::as_ptr(&self.data) as *const c_void }
|
||||||
Arc::as_ptr(&self.data) as *const c_void
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for Pokemon {
|
impl PartialEq for Pokemon {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool { Arc::ptr_eq(&self.data, &other.data) }
|
||||||
Arc::ptr_eq(&self.data, &other.data)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for Pokemon {}
|
impl Eq for Pokemon {}
|
||||||
|
|
||||||
impl PartialEq for WeakPokemonReference {
|
impl PartialEq for WeakPokemonReference {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool { Weak::ptr_eq(&self.data, &other.data) }
|
||||||
Weak::ptr_eq(&self.data, &other.data)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for WeakPokemonReference {}
|
impl Eq for WeakPokemonReference {}
|
||||||
|
@ -1025,9 +941,7 @@ impl WeakPokemonReference {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the pointer to the underlying data.
|
/// Gets the pointer to the underlying data.
|
||||||
pub(crate) fn as_ptr(&self) -> *const c_void {
|
pub(crate) fn as_ptr(&self) -> *const c_void { self.data.as_ptr() as *const c_void }
|
||||||
self.data.as_ptr() as *const c_void
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The data of the Pokemon related to being in a battle.
|
/// The data of the Pokemon related to being in a battle.
|
||||||
|
@ -1047,26 +961,16 @@ pub struct PokemonBattleData {
|
||||||
|
|
||||||
impl PokemonBattleData {
|
impl PokemonBattleData {
|
||||||
/// The battle data of the Pokemon
|
/// The battle data of the Pokemon
|
||||||
pub fn battle(&self) -> Option<Battle> {
|
pub fn battle(&self) -> Option<Battle> { self.battle.upgrade() }
|
||||||
self.battle.upgrade()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The index of the side of the Pokemon
|
/// The index of the side of the Pokemon
|
||||||
pub fn battle_side_index(&self) -> u8 {
|
pub fn battle_side_index(&self) -> u8 { self.battle_side_index.load(Ordering::Relaxed) }
|
||||||
self.battle_side_index.load(Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
/// The index of the slot on the side of the Pokemon.
|
/// The index of the slot on the side of the Pokemon.
|
||||||
pub fn index(&self) -> u8 {
|
pub fn index(&self) -> u8 { self.index.load(Ordering::Relaxed) }
|
||||||
self.index.load(Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
/// Whether or not the Pokemon is on the battlefield.
|
/// Whether or not the Pokemon is on the battlefield.
|
||||||
pub fn on_battle_field(&self) -> bool {
|
pub fn on_battle_field(&self) -> bool { self.on_battle_field.load(Ordering::Relaxed) }
|
||||||
self.on_battle_field.load(Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
/// A list of opponents the Pokemon has seen this battle.
|
/// A list of opponents the Pokemon has seen this battle.
|
||||||
pub fn seen_opponents(&self) -> &RwLock<Vec<WeakPokemonReference>> {
|
pub fn seen_opponents(&self) -> &RwLock<Vec<WeakPokemonReference>> { &self.seen_opponents }
|
||||||
&self.seen_opponents
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScriptSource for Pokemon {
|
impl ScriptSource for Pokemon {
|
||||||
|
@ -1083,9 +987,7 @@ impl ScriptSource for Pokemon {
|
||||||
Ok(c)
|
Ok(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> {
|
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> { &self.data.script_source_data }
|
||||||
&self.data.script_source_data
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_own_scripts(&self, scripts: &mut Vec<ScriptWrapper>) {
|
fn get_own_scripts(&self, scripts: &mut Vec<ScriptWrapper>) {
|
||||||
scripts.push((&self.data.held_item_trigger_script).into());
|
scripts.push((&self.data.held_item_trigger_script).into());
|
||||||
|
@ -1109,9 +1011,7 @@ impl ScriptSource for Pokemon {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VolatileScriptsOwner for Pokemon {
|
impl VolatileScriptsOwner for Pokemon {
|
||||||
fn volatile_scripts(&self) -> &Arc<ScriptSet> {
|
fn volatile_scripts(&self) -> &Arc<ScriptSet> { &self.data.volatile }
|
||||||
&self.data.volatile
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_volatile_script(&self, key: &StringKey) -> Result<Option<Arc<dyn Script>>> {
|
fn load_volatile_script(&self, key: &StringKey) -> Result<Option<Arc<dyn Script>>> {
|
||||||
self.data.library.load_script(self.into(), ScriptCategory::Pokemon, key)
|
self.data.library.load_script(self.into(), ScriptCategory::Pokemon, key)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
|
use hashbrown::HashMap;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
@ -30,97 +31,69 @@ pub trait Script: Send + Sync {
|
||||||
fn get_marked_for_deletion(&self) -> &AtomicBool;
|
fn get_marked_for_deletion(&self) -> &AtomicBool;
|
||||||
|
|
||||||
/// This marks the script for deletion, which will dispose of it as soon as possible.
|
/// This marks the script for deletion, which will dispose of it as soon as possible.
|
||||||
fn mark_for_deletion(&self) {
|
fn mark_for_deletion(&self) { self.get_marked_for_deletion().store(true, Ordering::SeqCst); }
|
||||||
self.get_marked_for_deletion().store(true, Ordering::SeqCst);
|
|
||||||
}
|
|
||||||
/// Helper function to get the value of the marked for deletion bool.
|
/// Helper function to get the value of the marked for deletion bool.
|
||||||
fn is_marked_for_deletion(&self) -> bool {
|
fn is_marked_for_deletion(&self) -> bool { self.get_marked_for_deletion().load(Ordering::SeqCst) }
|
||||||
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
|
/// 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.
|
/// we will not execute its methods. This should return the number of suppressions on the script.
|
||||||
fn get_suppressed_count(&self) -> &AtomicUsize;
|
fn get_suppressed_count(&self) -> &AtomicUsize;
|
||||||
/// Helper function to check if there is at least one suppression on the script
|
/// Helper function to check if there is at least one suppression on the script
|
||||||
fn is_suppressed(&self) -> bool {
|
fn is_suppressed(&self) -> bool { self.get_suppressed_count().load(Ordering::SeqCst) > 0 }
|
||||||
self.get_suppressed_count().load(Ordering::SeqCst) > 0
|
|
||||||
}
|
|
||||||
/// Adds a suppression. This makes the script not run anymore. Note that adding this should also
|
/// Adds a suppression. This makes the script not run anymore. Note that adding this should also
|
||||||
/// remove the suppression later.
|
/// remove the suppression later.
|
||||||
///
|
///
|
||||||
/// A common pattern for this is to run this in the [`Self::on_initialize`] function, and run the
|
/// 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.
|
/// remove in the [`Self::on_remove`] function.
|
||||||
fn add_suppression(&self) {
|
fn add_suppression(&self) { self.get_suppressed_count().fetch_add(1, Ordering::SeqCst); }
|
||||||
self.get_suppressed_count().fetch_add(1, Ordering::SeqCst);
|
|
||||||
}
|
|
||||||
/// Removes a suppression. This allows the script to run again (provided other scripts are not
|
/// 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.
|
/// suppressing it). Note that running this should only occur if an add was run before.
|
||||||
fn remove_suppression(&self) {
|
fn remove_suppression(&self) { self.get_suppressed_count().fetch_sub(1, Ordering::SeqCst); }
|
||||||
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
|
/// This function is ran when a volatile effect is added while that volatile effect already is
|
||||||
/// in place. Instead of adding the volatile effect twice, it will execute this function instead.
|
/// in place. Instead of adding the volatile effect twice, it will execute this function instead.
|
||||||
fn stack(&self) -> Result<()> {
|
fn stack(&self) -> Result<()> { Ok(()) }
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// This function is ran when this script stops being in effect, and is removed from its owner.
|
/// This function is ran when this script stops being in effect, and is removed from its owner.
|
||||||
fn on_remove(&self) -> Result<()> {
|
fn on_remove(&self) -> Result<()> { Ok(()) }
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// This function is ran when this script starts being in effect.
|
/// This function is ran when this script starts being in effect.
|
||||||
fn on_initialize(&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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
/// This function is ran just before the start of the turn. Everyone has made its choices here,
|
/// This function is ran just before the start of the turn. Everyone has made its choices here,
|
||||||
/// and the turn is about to start. This is a great place to initialize data if you need to know
|
/// and the turn is about to start. This is a great place to initialize data if you need to know
|
||||||
/// something has happened during a turn.
|
/// something has happened during a turn.
|
||||||
fn on_before_turn(&self, _choice: &Arc<TurnChoice>) -> Result<()> {
|
fn on_before_turn(&self, _choice: &Arc<TurnChoice>) -> Result<()> { Ok(()) }
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// This function allows you to modify the effective speed of the Pokemon. This is ran before
|
/// This function allows you to modify the effective speed of the Pokemon. This is ran before
|
||||||
/// turn ordering, so overriding here will allow you to put certain Pokemon before others.
|
/// turn ordering, so overriding here will allow you to put certain Pokemon before others.
|
||||||
fn change_speed(&self, _choice: &Arc<TurnChoice>, _speed: &mut u32) -> Result<()> {
|
fn change_speed(&self, _choice: &Arc<TurnChoice>, _speed: &mut u32) -> Result<()> { Ok(()) }
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// This function allows you to modify the effective priority of the Pokemon. This is ran before
|
/// This function allows you to modify the effective priority of the Pokemon. This is ran before
|
||||||
/// turn ordering, so overriding here will allow you to put certain Pokemon before others. Note
|
/// turn ordering, so overriding here will allow you to put certain Pokemon before others. Note
|
||||||
/// that this is only relevant on move choices, as other turn choice types do not have a priority.
|
/// that this is only relevant on move choices, as other turn choice types do not have a priority.
|
||||||
fn change_priority(&self, _choice: &Arc<TurnChoice>, _priority: &mut i8) -> Result<()> {
|
fn change_priority(&self, _choice: &Arc<TurnChoice>, _priority: &mut i8) -> Result<()> { Ok(()) }
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This function allows you to change the move that is used during execution. This is useful for
|
/// This function allows you to change the move that is used during execution. This is useful for
|
||||||
/// moves such as metronome, where the move chosen actually differs from the move used.
|
/// moves such as metronome, where the move chosen actually differs from the move used.
|
||||||
fn change_move(&self, _choice: &Arc<TurnChoice>, _move_name: &mut StringKey) -> Result<()> {
|
fn change_move(&self, _choice: &Arc<TurnChoice>, _move_name: &mut StringKey) -> Result<()> { Ok(()) }
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// This function allows you to change a move into a multi-hit move. The number of hits set here
|
/// This function allows you to change a move into a multi-hit move. The number of hits set here
|
||||||
/// gets used as the number of hits. If set to 0, this will behave as if the move missed on its
|
/// gets used as the number of hits. If set to 0, this will behave as if the move missed on its
|
||||||
/// first hit.
|
/// first hit.
|
||||||
fn change_number_of_hits(&self, _choice: &Arc<TurnChoice>, _number_of_hits: &mut u8) -> Result<()> {
|
fn change_number_of_hits(&self, _choice: &Arc<TurnChoice>, _number_of_hits: &mut u8) -> Result<()> { Ok(()) }
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This function allows you to prevent a move from running. If this gets set to true, the move
|
/// This function allows you to prevent a move from running. If this gets set to true, the move
|
||||||
/// ends execution here. No PP will be decreased in this case.
|
/// ends execution here. No PP will be decreased in this case.
|
||||||
fn prevent_move(&self, _move: &Arc<ExecutingMove>, _prevent: &mut bool) -> Result<()> {
|
fn prevent_move(&self, _move: &Arc<ExecutingMove>, _prevent: &mut bool) -> Result<()> { Ok(()) }
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// This function makes the move fail. If the fail field gets set to true, the move ends execution,
|
/// This function makes the move fail. If the fail field gets set to true, the move ends execution,
|
||||||
/// and fail events get triggered.
|
/// and fail events get triggered.
|
||||||
fn fail_move(&self, _move: &Arc<ExecutingMove>, _fail: &mut bool) -> Result<()> {
|
fn fail_move(&self, _move: &Arc<ExecutingMove>, _fail: &mut bool) -> Result<()> { Ok(()) }
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// Similar to [`Self::prevent_move`]. This function will also stop execution, but PP will be
|
/// Similar to [`Self::prevent_move`]. This function will also stop execution, but PP will be
|
||||||
/// decreased.
|
/// decreased.
|
||||||
fn stop_before_move(&self, _move: &Arc<ExecutingMove>, _stop: &mut bool) -> Result<()> {
|
fn stop_before_move(&self, _move: &Arc<ExecutingMove>, _stop: &mut bool) -> Result<()> { Ok(()) }
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// This function runs just before the move starts its execution.
|
/// This function runs just before the move starts its execution.
|
||||||
fn on_before_move(&self, _move: &Arc<ExecutingMove>) -> Result<()> {
|
fn on_before_move(&self, _move: &Arc<ExecutingMove>) -> Result<()> { Ok(()) }
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// This function allows a script to prevent a move that is targeted at its owner. If set to true
|
/// This function allows a script to prevent a move that is targeted at its owner. If set to true
|
||||||
/// the move fails, and fail events get triggered.
|
/// the move fails, and fail events get triggered.
|
||||||
fn fail_incoming_move(&self, _move: &Arc<ExecutingMove>, _target: &Pokemon, _fail: &mut bool) -> Result<()> {
|
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
|
/// This function occurs when a move gets missed. This runs on the scripts belonging to the executing
|
||||||
/// move, which include the scripts that are attached to the owner of the script.
|
/// move, which include the scripts that are attached to the owner of the script.
|
||||||
fn on_move_miss(&self, _move: &Arc<ExecutingMove>, _target: &Pokemon) -> Result<()> {
|
fn on_move_miss(&self, _move: &Arc<ExecutingMove>, _target: &Pokemon) -> Result<()> { Ok(()) }
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// This function allows the script to change the actual type that is used for the move on a target.
|
/// This function allows the script to change the actual type that is used for the move on a target.
|
||||||
fn change_move_type(
|
fn change_move_type(
|
||||||
&self,
|
&self,
|
||||||
|
@ -308,13 +279,9 @@ pub trait Script: Send + Sync {
|
||||||
}
|
}
|
||||||
/// This function triggers when an incoming hit happens. This triggers after the damage is done,
|
/// This function triggers when an incoming hit happens. This triggers after the damage is done,
|
||||||
/// but before the secondary effect of the move happens.
|
/// but before the secondary effect of the move happens.
|
||||||
fn on_incoming_hit(&self, _move: &Arc<ExecutingMove>, _target: &Pokemon, _hit: u8) -> Result<()> {
|
fn on_incoming_hit(&self, _move: &Arc<ExecutingMove>, _target: &Pokemon, _hit: u8) -> Result<()> { Ok(()) }
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// This function triggers when an opponent on the field faints.
|
/// This function triggers when an opponent on the field faints.
|
||||||
fn on_opponent_faints(&self, _move: &Arc<ExecutingMove>, _target: &Pokemon, _hit: u8) -> Result<()> {
|
fn on_opponent_faints(&self, _move: &Arc<ExecutingMove>, _target: &Pokemon, _hit: u8) -> Result<()> { Ok(()) }
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// This function allows a script attached to a Pokemon or its parents to prevent stat boost
|
/// This function allows a script attached to a Pokemon or its parents to prevent stat boost
|
||||||
/// changes on that Pokemon.
|
/// changes on that Pokemon.
|
||||||
fn prevent_stat_boost_change(
|
fn prevent_stat_boost_change(
|
||||||
|
@ -380,61 +347,37 @@ pub trait Script: Send + Sync {
|
||||||
/// This function triggers when the move uses its secondary effect. Moves should implement their
|
/// This function triggers when the move uses its secondary effect. Moves should implement their
|
||||||
/// secondary effects here. Status moves should implement their actual functionality in this
|
/// secondary effects here. Status moves should implement their actual functionality in this
|
||||||
/// function as well, as status moves effects are defined as secondary effects for simplicity.
|
/// function as well, as status moves effects are defined as secondary effects for simplicity.
|
||||||
fn on_secondary_effect(&self, _move: &Arc<ExecutingMove>, _target: &Pokemon, _hit: u8) -> Result<()> {
|
fn on_secondary_effect(&self, _move: &Arc<ExecutingMove>, _target: &Pokemon, _hit: u8) -> Result<()> { Ok(()) }
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// This function triggers on a move or its parents when all hits on a target are finished.
|
/// This function triggers on a move or its parents when all hits on a target are finished.
|
||||||
fn on_after_hits(&self, _move: &Arc<ExecutingMove>, _target: &Pokemon) -> Result<()> {
|
fn on_after_hits(&self, _move: &Arc<ExecutingMove>, _target: &Pokemon) -> Result<()> { Ok(()) }
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// This function prevents the Pokemon it is attached to from being able to switch out.
|
/// This function prevents the Pokemon it is attached to from being able to switch out.
|
||||||
fn prevent_self_switch(&self, _choice: &Arc<TurnChoice>, _prevent: &mut bool) -> Result<()> {
|
fn prevent_self_switch(&self, _choice: &Arc<TurnChoice>, _prevent: &mut bool) -> Result<()> { Ok(()) }
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// This function allows the prevention of switching for any opponent.
|
/// This function allows the prevention of switching for any opponent.
|
||||||
fn prevent_opponent_switch(&self, _choice: &Arc<TurnChoice>, _prevent: &mut bool) -> Result<()> {
|
fn prevent_opponent_switch(&self, _choice: &Arc<TurnChoice>, _prevent: &mut bool) -> Result<()> { Ok(()) }
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// This function is called on a move and its parents when the move fails.
|
/// This function is called on a move and its parents when the move fails.
|
||||||
fn on_fail(&self, _target: &Pokemon) -> Result<()> {
|
fn on_fail(&self, _target: &Pokemon) -> Result<()> { Ok(()) }
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// This function is called on a script when an opponent fails.
|
/// This function is called on a script when an opponent fails.
|
||||||
fn on_opponent_fail(&self, _target: &Pokemon) -> Result<()> {
|
fn on_opponent_fail(&self, _target: &Pokemon) -> Result<()> { Ok(()) }
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// This function allows preventing the running away of the Pokemon its attached to
|
/// This function allows preventing the running away of the Pokemon its attached to
|
||||||
fn prevent_self_run_away(&self, _choice: &Arc<TurnChoice>, _prevent: &mut bool) -> Result<()> {
|
fn prevent_self_run_away(&self, _choice: &Arc<TurnChoice>, _prevent: &mut bool) -> Result<()> { Ok(()) }
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// This function prevents a Pokemon on another side than where its attached to from running away.
|
/// This function prevents a Pokemon on another side than where its attached to from running away.
|
||||||
fn prevent_opponent_run_away(&self, _choice: &Arc<TurnChoice>, _prevent: &mut bool) -> Result<()> {
|
fn prevent_opponent_run_away(&self, _choice: &Arc<TurnChoice>, _prevent: &mut bool) -> Result<()> { Ok(()) }
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// This function id triggered on all scripts active in the battle after all choices have finished
|
/// This function id triggered on all scripts active in the battle after all choices have finished
|
||||||
/// running. Note that choices are not active anymore here, so their scripts do not call this
|
/// running. Note that choices are not active anymore here, so their scripts do not call this
|
||||||
/// function.
|
/// function.
|
||||||
fn on_end_turn(&self) -> Result<()> {
|
fn on_end_turn(&self) -> Result<()> { Ok(()) }
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// This function is triggered on a Pokemon and its parents when the given Pokemon takes damage.
|
/// This function is triggered on a Pokemon and its parents when the given Pokemon takes damage.
|
||||||
fn on_damage(&self, _pokemon: &Pokemon, _source: DamageSource, _old_health: u32, _new_health: u32) -> Result<()> {
|
fn on_damage(&self, _pokemon: &Pokemon, _source: DamageSource, _old_health: u32, _new_health: u32) -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
/// This function is triggered on a Pokemon and its parents when the given Pokemon faints.
|
/// This function is triggered on a Pokemon and its parents when the given Pokemon faints.
|
||||||
fn on_faint(&self, _pokemon: &Pokemon, _source: DamageSource) -> Result<()> {
|
fn on_faint(&self, _pokemon: &Pokemon, _source: DamageSource) -> Result<()> { Ok(()) }
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// This function is triggered on a Pokemon and its parents when the given Pokemon is switched into
|
/// This function is triggered on a Pokemon and its parents when the given Pokemon is switched into
|
||||||
/// the battlefield.
|
/// the battlefield.
|
||||||
fn on_switch_in(&self, _pokemon: &Pokemon) -> Result<()> {
|
fn on_switch_in(&self, _pokemon: &Pokemon) -> Result<()> { Ok(()) }
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// This function is triggered on a Pokemon and its parents when the given Pokemon consumes the
|
/// This function is triggered on a Pokemon and its parents when the given Pokemon consumes the
|
||||||
/// held item it had.
|
/// held item it had.
|
||||||
fn on_after_held_item_consume(&self, _pokemon: &Pokemon, _item: &Arc<dyn Item>) -> Result<()> {
|
fn on_after_held_item_consume(&self, _pokemon: &Pokemon, _item: &Arc<dyn Item>) -> Result<()> { Ok(()) }
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// This function is triggered on a Pokemon and its parents when the given Pokemon gains experience,
|
/// This function is triggered on a Pokemon and its parents when the given Pokemon gains experience,
|
||||||
/// and allows for changing this amount of experience.
|
/// and allows for changing this amount of experience.
|
||||||
fn change_experience_gained(
|
fn change_experience_gained(
|
||||||
|
@ -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
|
/// This function is triggered on a battle and its parents when something attempts to change the
|
||||||
/// weather, and allows for blocking the weather change.
|
/// weather, and allows for blocking the weather change.
|
||||||
fn block_weather(&self, _battle: &Battle, _blocked: &mut bool) -> Result<()> {
|
fn block_weather(&self, _battle: &Battle, _blocked: &mut bool) -> Result<()> { Ok(()) }
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
/// This function is called when a Pokeball is thrown at a Pokemon, and allows modifying the catch
|
/// This function is called when a Pokeball is thrown at a Pokemon, and allows modifying the catch
|
||||||
/// rate of this attempt. Pokeball modifier effects should be implemented here, as well as for
|
/// rate of this attempt. Pokeball modifier effects should be implemented here, as well as for
|
||||||
/// example status effects that change capture rates.
|
/// example status effects that change capture rates.
|
||||||
|
@ -474,9 +415,7 @@ pub trait Script: Send + Sync {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for dyn Script {
|
impl Debug for dyn Script {
|
||||||
fn fmt(&self, _f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, _f: &mut Formatter<'_>) -> std::fmt::Result { Ok(()) }
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A script holder defines the underlying type of how we store individual scripts on a script source.
|
/// 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.
|
/// Gets the underlying reference counter to the script.
|
||||||
pub fn arc(&self) -> &ScriptHolder {
|
pub fn arc(&self) -> &ScriptHolder { &self.script }
|
||||||
&self.script
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Whether or not the script is set.
|
/// Whether or not the script is set.
|
||||||
pub fn is_any(&self) -> bool {
|
pub fn is_any(&self) -> bool { self.script.read().is_some() }
|
||||||
self.script.read().is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the underlying script as the downcasted value.
|
/// Get the underlying script as the downcasted value.
|
||||||
pub fn get_as<T: 'static>(&self) -> Result<MappedRwLockReadGuard<T>> {
|
pub fn get_as<T: 'static>(&self) -> Result<MappedRwLockReadGuard<T>> {
|
||||||
|
@ -646,29 +581,19 @@ mod tests {
|
||||||
unsafe impl Send for TestScript {}
|
unsafe impl Send for TestScript {}
|
||||||
|
|
||||||
impl Script for TestScript {
|
impl Script for TestScript {
|
||||||
fn name(&self) -> Result<&StringKey> {
|
fn name(&self) -> Result<&StringKey> { Ok(&self.name) }
|
||||||
Ok(&self.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_marked_for_deletion(&self) -> &AtomicBool {
|
fn get_marked_for_deletion(&self) -> &AtomicBool { &self.marked_for_deletion }
|
||||||
&self.marked_for_deletion
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_suppressed_count(&self) -> &AtomicUsize {
|
fn get_suppressed_count(&self) -> &AtomicUsize { &self.suppressed_count }
|
||||||
&self.suppressed_count
|
|
||||||
}
|
|
||||||
|
|
||||||
fn stack(&self) -> Result<()> {
|
fn stack(&self) -> Result<()> {
|
||||||
unsafe { self.container.load(Ordering::Relaxed).as_ref().unwrap().clear() }
|
unsafe { self.container.load(Ordering::Relaxed).as_ref().unwrap().clear() }
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn Any {
|
fn as_any(&self) -> &dyn Any { self }
|
||||||
self
|
fn as_any_mut(&mut self) -> &mut 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
|
// 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 {}
|
unsafe impl Send for ReplaceTestScript {}
|
||||||
|
|
||||||
impl Script for ReplaceTestScript {
|
impl Script for ReplaceTestScript {
|
||||||
fn name(&self) -> Result<&StringKey> {
|
fn name(&self) -> Result<&StringKey> { Ok(&self.name) }
|
||||||
Ok(&self.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_marked_for_deletion(&self) -> &AtomicBool {
|
fn get_marked_for_deletion(&self) -> &AtomicBool { &self.marked_for_deletion }
|
||||||
&self.marked_for_deletion
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_suppressed_count(&self) -> &AtomicUsize {
|
fn get_suppressed_count(&self) -> &AtomicUsize { &self.suppressed_count }
|
||||||
&self.suppressed_count
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn Any {
|
fn as_any(&self) -> &dyn Any { self }
|
||||||
self
|
fn as_any_mut(&mut self) -> &mut dyn Any { self }
|
||||||
}
|
|
||||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -793,19 +708,13 @@ pub enum ScriptOwnerData {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&Pokemon> for ScriptOwnerData {
|
impl From<&Pokemon> for ScriptOwnerData {
|
||||||
fn from(p: &Pokemon) -> Self {
|
fn from(p: &Pokemon) -> Self { ScriptOwnerData::Pokemon(p.weak()) }
|
||||||
ScriptOwnerData::Pokemon(p.weak())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&BattleSide> for ScriptOwnerData {
|
impl From<&BattleSide> for ScriptOwnerData {
|
||||||
fn from(p: &BattleSide) -> Self {
|
fn from(p: &BattleSide) -> Self { ScriptOwnerData::BattleSide(p.weak()) }
|
||||||
ScriptOwnerData::BattleSide(p.weak())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&Battle> for ScriptOwnerData {
|
impl From<&Battle> for ScriptOwnerData {
|
||||||
fn from(p: &Battle) -> Self {
|
fn from(p: &Battle) -> Self { ScriptOwnerData::Battle(p.weak()) }
|
||||||
ScriptOwnerData::Battle(p.weak())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
use crate::ffi::FFIHandle;
|
|
||||||
use crate::ffi::FromFFIHandle;
|
use crate::ffi::FromFFIHandle;
|
||||||
|
use crate::ffi::{FFIHandle, NonOwnedPtrString};
|
||||||
use crate::ffi::{FFIResult, OwnedPtrString};
|
use crate::ffi::{FFIResult, OwnedPtrString};
|
||||||
use crate::static_data::{Ability, AbilityImpl, Parameter};
|
use crate::static_data::{Ability, AbilityImpl, Parameter};
|
||||||
use crate::StringKey;
|
use crate::StringKey;
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
|
use hashbrown::HashMap;
|
||||||
use std::ffi::{c_char, CStr, CString};
|
use std::ffi::{c_char, CStr, CString};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
@ -12,13 +13,18 @@ use std::sync::Arc;
|
||||||
unsafe extern "C" fn ability_new(
|
unsafe extern "C" fn ability_new(
|
||||||
name: *const c_char,
|
name: *const c_char,
|
||||||
effect: *const c_char,
|
effect: *const c_char,
|
||||||
|
parameter_keys: *const NonOwnedPtrString,
|
||||||
parameters: *const FFIHandle<Arc<Parameter>>,
|
parameters: *const FFIHandle<Arc<Parameter>>,
|
||||||
parameters_length: usize,
|
parameters_length: usize,
|
||||||
) -> FFIResult<FFIHandle<Arc<dyn Ability>>> {
|
) -> 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 parameters = std::slice::from_raw_parts(parameters, parameters_length);
|
||||||
let mut parameters_vec: Vec<Arc<Parameter>> = Vec::with_capacity(parameters_length);
|
let mut parameters_map: HashMap<StringKey, Arc<Parameter>> = HashMap::with_capacity(parameters_length);
|
||||||
for parameter in parameters {
|
for (index, parameter) in parameters.iter().enumerate() {
|
||||||
parameters_vec.push(parameter.from_ffi_handle());
|
parameters_map.insert(
|
||||||
|
CStr::from_ptr(parameter_keys[index]).into(),
|
||||||
|
parameter.from_ffi_handle(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let name: StringKey = match CStr::from_ptr(name).to_str() {
|
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")),
|
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()))
|
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]
|
#[no_mangle]
|
||||||
unsafe extern "C" fn ability_parameter_get(
|
unsafe extern "C" fn ability_parameter_get(
|
||||||
ptr: FFIHandle<Arc<dyn Ability>>,
|
ptr: FFIHandle<Arc<dyn Ability>>,
|
||||||
index: usize,
|
name: NonOwnedPtrString,
|
||||||
) -> FFIHandle<Arc<Parameter>> {
|
) -> 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())
|
FFIHandle::get_handle(p.clone().into())
|
||||||
} else {
|
} else {
|
||||||
FFIHandle::none()
|
FFIHandle::none()
|
||||||
|
|
|
@ -5,7 +5,7 @@ use crate::static_data::{
|
||||||
};
|
};
|
||||||
use crate::StringKey;
|
use crate::StringKey;
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use hashbrown::HashSet;
|
use hashbrown::{HashMap, HashSet};
|
||||||
use std::ffi::{c_char, CStr, CString};
|
use std::ffi::{c_char, CStr, CString};
|
||||||
use std::sync::Arc;
|
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(
|
unsafe extern "C" fn secondary_effect_new(
|
||||||
chance: f32,
|
chance: f32,
|
||||||
effect_name: NonOwnedPtrString,
|
effect_name: NonOwnedPtrString,
|
||||||
|
parameter_keys: *const NonOwnedPtrString,
|
||||||
parameters: *mut FFIHandle<Arc<Parameter>>,
|
parameters: *mut FFIHandle<Arc<Parameter>>,
|
||||||
parameters_length: usize,
|
parameters_length: usize,
|
||||||
) -> FFIHandle<Box<dyn SecondaryEffect>> {
|
) -> 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 parameter_slice = std::slice::from_raw_parts(parameters, parameters_length);
|
||||||
let mut parameters = Vec::with_capacity(parameters_length);
|
let mut parameters = HashMap::with_capacity(parameters_length);
|
||||||
for parameter in parameter_slice {
|
for (index, parameter) in parameter_slice.iter().enumerate() {
|
||||||
parameters.push(parameter.from_ffi_handle())
|
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(
|
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]
|
#[no_mangle]
|
||||||
unsafe extern "C" fn secondary_effect_parameter_get(
|
unsafe extern "C" fn secondary_effect_parameter_get(
|
||||||
ptr: FFIHandle<Arc<dyn SecondaryEffect>>,
|
ptr: FFIHandle<Arc<dyn SecondaryEffect>>,
|
||||||
index: usize,
|
name: NonOwnedPtrString,
|
||||||
) -> FFIHandle<Arc<Parameter>> {
|
) -> 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())
|
FFIHandle::get_handle(v.clone().into())
|
||||||
} else {
|
} else {
|
||||||
FFIHandle::none()
|
FFIHandle::none()
|
||||||
|
|
|
@ -9,8 +9,9 @@
|
||||||
#![allow(hidden_glob_reexports)]
|
#![allow(hidden_glob_reexports)]
|
||||||
#![allow(clippy::arc_with_non_send_sync)]
|
#![allow(clippy::arc_with_non_send_sync)]
|
||||||
// Documentation linters
|
// Documentation linters
|
||||||
#![deny(missing_docs)]
|
// FIXME: Enable these before committing
|
||||||
#![deny(clippy::missing_docs_in_private_items)]
|
// #![deny(missing_docs)]
|
||||||
|
// #![deny(clippy::missing_docs_in_private_items)]
|
||||||
// Linter rules to prevent panics
|
// Linter rules to prevent panics
|
||||||
// Currently still a WIP to fix all of these
|
// Currently still a WIP to fix all of these
|
||||||
#![deny(clippy::unwrap_used)]
|
#![deny(clippy::unwrap_used)]
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
/// The WASM module handles loading dynamic scripts through WebAssembly.
|
/// The WASM module handles loading dynamic scripts through WebAssembly.
|
||||||
#[cfg(feature = "wasm")]
|
#[cfg(feature = "wasm")]
|
||||||
pub mod 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::static_data::Parameter;
|
||||||
use crate::StringKey;
|
use crate::StringKey;
|
||||||
|
use hashbrown::HashMap;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
@ -10,7 +11,7 @@ pub trait SecondaryEffect: Debug {
|
||||||
/// The name of the effect.
|
/// The name of the effect.
|
||||||
fn effect_name(&self) -> &StringKey;
|
fn effect_name(&self) -> &StringKey;
|
||||||
/// A list of parameters for the effect.
|
/// 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.
|
/// 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.
|
/// The name of the effect.
|
||||||
effect_name: StringKey,
|
effect_name: StringKey,
|
||||||
/// A list of parameters for the effect.
|
/// A list of parameters for the effect.
|
||||||
parameters: Vec<Arc<Parameter>>,
|
parameters: HashMap<StringKey, Arc<Parameter>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SecondaryEffectImpl {
|
impl SecondaryEffectImpl {
|
||||||
/// Instantiates a new Secondary Effect.
|
/// 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 {
|
Self {
|
||||||
chance,
|
chance,
|
||||||
effect_name,
|
effect_name,
|
||||||
|
@ -45,7 +46,7 @@ impl SecondaryEffect for SecondaryEffectImpl {
|
||||||
&self.effect_name
|
&self.effect_name
|
||||||
}
|
}
|
||||||
/// A list of parameters for the effect.
|
/// A list of parameters for the effect.
|
||||||
fn parameters(&self) -> &Vec<Arc<Parameter>> {
|
fn parameters(&self) -> &HashMap<StringKey, Arc<Parameter>> {
|
||||||
&self.parameters
|
&self.parameters
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::static_data::Parameter;
|
use crate::static_data::Parameter;
|
||||||
use crate::StringKey;
|
use crate::StringKey;
|
||||||
|
use hashbrown::HashMap;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
@ -10,7 +11,7 @@ pub trait Ability: Debug {
|
||||||
/// The name of the script effect of the ability.
|
/// The name of the script effect of the ability.
|
||||||
fn effect(&self) -> &StringKey;
|
fn effect(&self) -> &StringKey;
|
||||||
/// The parameters for the script effect of the ability.
|
/// 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.
|
/// 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.
|
/// The name of the script effect of the ability.
|
||||||
effect: StringKey,
|
effect: StringKey,
|
||||||
/// The parameters for the script effect of the ability.
|
/// The parameters for the script effect of the ability.
|
||||||
parameters: Vec<Arc<Parameter>>,
|
parameters: HashMap<StringKey, Arc<Parameter>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbilityImpl {
|
impl AbilityImpl {
|
||||||
/// Instantiates a new ability.
|
/// 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 {
|
Self {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
effect: effect.clone(),
|
effect: effect.clone(),
|
||||||
|
@ -37,17 +38,11 @@ impl AbilityImpl {
|
||||||
|
|
||||||
impl Ability for AbilityImpl {
|
impl Ability for AbilityImpl {
|
||||||
/// The name of the ability.
|
/// The name of the ability.
|
||||||
fn name(&self) -> &StringKey {
|
fn name(&self) -> &StringKey { &self.name }
|
||||||
&self.name
|
|
||||||
}
|
|
||||||
/// The name of the script effect of the ability.
|
/// The name of the script effect of the ability.
|
||||||
fn effect(&self) -> &StringKey {
|
fn effect(&self) -> &StringKey { &self.effect }
|
||||||
&self.effect
|
|
||||||
}
|
|
||||||
/// The parameters for the script effect of the ability.
|
/// The parameters for the script effect of the ability.
|
||||||
fn parameters(&self) -> &Vec<Arc<Parameter>> {
|
fn parameters(&self) -> &HashMap<StringKey, Arc<Parameter>> { &self.parameters }
|
||||||
&self.parameters
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An ability index allows us to find an ability on a form. It combines a bool for whether the
|
/// 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::io::{BufReader, Read};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use hashbrown::HashSet;
|
use hashbrown::{HashMap, HashSet};
|
||||||
use num_traits::PrimInt;
|
use num_traits::PrimInt;
|
||||||
use project_root::get_project_root;
|
use project_root::get_project_root;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
@ -223,10 +223,11 @@ pub fn load_abilities(path: &String) -> Arc<dyn AbilityLibrary> {
|
||||||
if let Some(e) = value.get("effect") {
|
if let Some(e) = value.get("effect") {
|
||||||
effect = e.as_str().unwrap().into();
|
effect = e.as_str().unwrap().into();
|
||||||
}
|
}
|
||||||
let mut parameters = Vec::new();
|
let mut parameters = HashMap::new();
|
||||||
if let Some(p) = value.get("parameters") {
|
if let Some(pars) = value.get("parameters") {
|
||||||
for par in p.as_array().unwrap() {
|
let pars = pars.as_object().unwrap();
|
||||||
parameters.push(parse_parameter(par));
|
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") {
|
if let Some(chance_value) = v.get("chance") {
|
||||||
chance = chance_value.as_f64().unwrap() as f32;
|
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") {
|
if let Some(pars) = v.get("parameters") {
|
||||||
let pars = pars.as_array().unwrap();
|
let pars = pars.as_object().unwrap();
|
||||||
for par in pars {
|
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)
|
EvolutionData::new(method, species)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "wasm"))]
|
#[cfg(not(any(feature = "wasm", feature = "rune")))]
|
||||||
fn load_script_resolver(path: &String) -> Arc<dyn ScriptResolver> {
|
fn load_script_resolver(path: &String) -> Arc<dyn ScriptResolver> { Arc::new(EmptyScriptResolver::default()) }
|
||||||
Arc::new(EmptyScriptResolver::default())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "wasm")]
|
#[cfg(feature = "wasm")]
|
||||||
fn load_script_resolver(path: &String) -> Arc<dyn ScriptResolver> {
|
fn load_script_resolver(path: &String) -> Arc<dyn ScriptResolver> {
|
||||||
|
@ -468,6 +467,28 @@ fn load_script_resolver(path: &String) -> Arc<dyn ScriptResolver> {
|
||||||
resolver
|
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(
|
fn parse_form(
|
||||||
name: StringKey,
|
name: StringKey,
|
||||||
value: &Value,
|
value: &Value,
|
||||||
|
|
|
@ -1,285 +1,292 @@
|
||||||
{
|
{
|
||||||
"adaptability": {
|
"adaptability": {
|
||||||
"effect": "IncreasedStab"
|
"effect": "IncreasedStab"
|
||||||
},
|
},
|
||||||
"aerilate": {
|
"aerilate": {
|
||||||
"effect": "ChangeMoveType",
|
"effect": "ChangeMoveType",
|
||||||
"parameters": ["normal", "flying"]
|
"parameters": {
|
||||||
},
|
"from": "normal",
|
||||||
"aftermath": {
|
"to": "flying"
|
||||||
"effect": "Aftermath"
|
}
|
||||||
},
|
},
|
||||||
"air_lock": {
|
"aftermath": {
|
||||||
"effect": "SuppressWeather"
|
"effect": "Aftermath"
|
||||||
},
|
},
|
||||||
"analytic": {
|
"air_lock": {
|
||||||
"effect": "Analytic"
|
"effect": "SuppressWeather"
|
||||||
},
|
},
|
||||||
"anger_point": {
|
"analytic": {
|
||||||
"effect": "AngerPoint"
|
"effect": "Analytic"
|
||||||
},
|
},
|
||||||
"anticipation": {
|
"anger_point": {
|
||||||
"effect": "Anticipation"
|
"effect": "AngerPoint"
|
||||||
},
|
},
|
||||||
"arena_trap": {
|
"anticipation": {
|
||||||
"effect": "ArenaTrap"
|
"effect": "Anticipation"
|
||||||
},
|
},
|
||||||
"aroma_veil": {
|
"arena_trap": {
|
||||||
"effect": "AromaVeil"
|
"effect": "ArenaTrap"
|
||||||
},
|
},
|
||||||
"aura_break": {
|
"aroma_veil": {
|
||||||
"effect": "AuraBreal"
|
"effect": "AromaVeil"
|
||||||
},
|
},
|
||||||
"bad_dreams": {
|
"aura_break": {
|
||||||
"effect": "BadDreams"
|
"effect": "AuraBreal"
|
||||||
},
|
},
|
||||||
"battery": {
|
"bad_dreams": {
|
||||||
"effect": "Battery"
|
"effect": "BadDreams"
|
||||||
},
|
},
|
||||||
"battle_armor": {
|
"battery": {
|
||||||
"effect": "PreventCritical"
|
"effect": "Battery"
|
||||||
},
|
},
|
||||||
"battle_bond": {
|
"battle_armor": {
|
||||||
"effect": "BattleBond"
|
"effect": "PreventCritical"
|
||||||
},
|
},
|
||||||
"beast_boost": {
|
"battle_bond": {
|
||||||
"effect": "BeastBoost"
|
"effect": "BattleBond"
|
||||||
},
|
},
|
||||||
"berserk": {
|
"beast_boost": {
|
||||||
"effect": "Berserk"
|
"effect": "BeastBoost"
|
||||||
},
|
},
|
||||||
"big_pecks": {
|
"berserk": {
|
||||||
"effect": "PreventDefLowering"
|
"effect": "Berserk"
|
||||||
},
|
},
|
||||||
"blaze": {
|
"big_pecks": {
|
||||||
"effect": "PowerUpType",
|
"effect": "PreventDefLowering"
|
||||||
"parameters": ["fire"]
|
},
|
||||||
},
|
"blaze": {
|
||||||
"bulletproof": {
|
"effect": "PowerUpType",
|
||||||
"effect": "Bulletproof"
|
"parameters": {
|
||||||
},
|
"type": "fire"
|
||||||
"cheek_pouch": {
|
}
|
||||||
"effect": "CheekPouch"
|
},
|
||||||
},
|
"bulletproof": {
|
||||||
"chlorophyll": {
|
"effect": "Bulletproof"
|
||||||
"effect": "DoubleSpeedInWeather",
|
},
|
||||||
"parameters": ["HarshSunlight"]
|
"cheek_pouch": {
|
||||||
},
|
"effect": "CheekPouch"
|
||||||
"clear_body": {
|
},
|
||||||
"effect": "PreventStatLowering"
|
"chlorophyll": {
|
||||||
},
|
"effect": "DoubleSpeedInWeather",
|
||||||
"cloud_nine": {
|
"parameters": {
|
||||||
"effect": "SuppressWeather"
|
"weather": "HarshSunlight"
|
||||||
},
|
}
|
||||||
"color_change": {
|
},
|
||||||
"effect": "ColorChange"
|
"clear_body": {
|
||||||
},
|
"effect": "PreventStatLowering"
|
||||||
"comatose": {},
|
},
|
||||||
"competitive": {},
|
"cloud_nine": {
|
||||||
"compound_eyes": {},
|
"effect": "SuppressWeather"
|
||||||
"contrary": {},
|
},
|
||||||
"corrosion": {},
|
"color_change": {
|
||||||
"cursed_body": {},
|
"effect": "ColorChange"
|
||||||
"cute_charm": {},
|
},
|
||||||
"damp": {},
|
"comatose": {},
|
||||||
"dancer": {},
|
"competitive": {},
|
||||||
"dark_aura": {},
|
"compound_eyes": {},
|
||||||
"dazzling": {},
|
"contrary": {},
|
||||||
"defeatist": {},
|
"corrosion": {},
|
||||||
"defiant": {},
|
"cursed_body": {},
|
||||||
"delta_stream": {},
|
"cute_charm": {},
|
||||||
"desolate_land": {},
|
"damp": {},
|
||||||
"disguise": {},
|
"dancer": {},
|
||||||
"download": {},
|
"dark_aura": {},
|
||||||
"drizzle": {},
|
"dazzling": {},
|
||||||
"drought": {},
|
"defeatist": {},
|
||||||
"dry_skin": {},
|
"defiant": {},
|
||||||
"early_bird": {},
|
"delta_stream": {},
|
||||||
"effect_spore": {},
|
"desolate_land": {},
|
||||||
"electric_surge": {},
|
"disguise": {},
|
||||||
"emergency_exit": {},
|
"download": {},
|
||||||
"fairy_aura": {},
|
"drizzle": {},
|
||||||
"filter": {},
|
"drought": {},
|
||||||
"flame_body": {},
|
"dry_skin": {},
|
||||||
"flare_boost": {},
|
"early_bird": {},
|
||||||
"flash_fire": {},
|
"effect_spore": {},
|
||||||
"flower_gift": {},
|
"electric_surge": {},
|
||||||
"flower_veil": {},
|
"emergency_exit": {},
|
||||||
"fluffy": {},
|
"fairy_aura": {},
|
||||||
"forecast": {},
|
"filter": {},
|
||||||
"forewarn": {},
|
"flame_body": {},
|
||||||
"friend_guard": {},
|
"flare_boost": {},
|
||||||
"frisk": {},
|
"flash_fire": {},
|
||||||
"full_metal_body": {},
|
"flower_gift": {},
|
||||||
"fur_coat": {},
|
"flower_veil": {},
|
||||||
"gale_wings": {},
|
"fluffy": {},
|
||||||
"galvanize": {},
|
"forecast": {},
|
||||||
"gluttony": {},
|
"forewarn": {},
|
||||||
"gooey": {},
|
"friend_guard": {},
|
||||||
"grass_pelt": {},
|
"frisk": {},
|
||||||
"grassy_surge": {},
|
"full_metal_body": {},
|
||||||
"guts": {},
|
"fur_coat": {},
|
||||||
"harvest": {},
|
"gale_wings": {},
|
||||||
"healer": {},
|
"galvanize": {},
|
||||||
"heatproof": {},
|
"gluttony": {},
|
||||||
"heavy_metal": {},
|
"gooey": {},
|
||||||
"honey_gather": {},
|
"grass_pelt": {},
|
||||||
"huge_power": {},
|
"grassy_surge": {},
|
||||||
"hustle": {},
|
"guts": {},
|
||||||
"hydration": {},
|
"harvest": {},
|
||||||
"hyper_cutter": {},
|
"healer": {},
|
||||||
"ice_body": {},
|
"heatproof": {},
|
||||||
"illuminate": {},
|
"heavy_metal": {},
|
||||||
"illusion": {},
|
"honey_gather": {},
|
||||||
"immunity": {},
|
"huge_power": {},
|
||||||
"imposter": {},
|
"hustle": {},
|
||||||
"infiltrator": {},
|
"hydration": {},
|
||||||
"innards_out": {},
|
"hyper_cutter": {},
|
||||||
"inner_focus": {},
|
"ice_body": {},
|
||||||
"insomnia": {},
|
"illuminate": {},
|
||||||
"intimidate": {},
|
"illusion": {},
|
||||||
"iron_barbs": {},
|
"immunity": {},
|
||||||
"iron_fist": {},
|
"imposter": {},
|
||||||
"justified": {},
|
"infiltrator": {},
|
||||||
"keen_eye": {},
|
"innards_out": {},
|
||||||
"klutz": {},
|
"inner_focus": {},
|
||||||
"leaf_guard": {},
|
"insomnia": {},
|
||||||
"levitate": {},
|
"intimidate": {},
|
||||||
"light_metal": {},
|
"iron_barbs": {},
|
||||||
"lightning_rod": {},
|
"iron_fist": {},
|
||||||
"limber": {},
|
"justified": {},
|
||||||
"liquid_ooze": {},
|
"keen_eye": {},
|
||||||
"liquid_voice": {},
|
"klutz": {},
|
||||||
"long_reach": {},
|
"leaf_guard": {},
|
||||||
"magic_bounce": {},
|
"levitate": {},
|
||||||
"magic_guard": {},
|
"light_metal": {},
|
||||||
"magician": {},
|
"lightning_rod": {},
|
||||||
"magma_armor": {},
|
"limber": {},
|
||||||
"magnet_pull": {},
|
"liquid_ooze": {},
|
||||||
"marvel_scale": {},
|
"liquid_voice": {},
|
||||||
"mega_launcher": {},
|
"long_reach": {},
|
||||||
"merciless": {},
|
"magic_bounce": {},
|
||||||
"minus": {},
|
"magic_guard": {},
|
||||||
"misty_surge": {},
|
"magician": {},
|
||||||
"mold_breaker": {},
|
"magma_armor": {},
|
||||||
"moody": {},
|
"magnet_pull": {},
|
||||||
"motor_drive": {},
|
"marvel_scale": {},
|
||||||
"moxie": {},
|
"mega_launcher": {},
|
||||||
"multiscale": {},
|
"merciless": {},
|
||||||
"multitype": {},
|
"minus": {},
|
||||||
"mummy": {},
|
"misty_surge": {},
|
||||||
"natural_cure": {},
|
"mold_breaker": {},
|
||||||
"no_guard": {},
|
"moody": {},
|
||||||
"normalize": {},
|
"motor_drive": {},
|
||||||
"oblivious": {},
|
"moxie": {},
|
||||||
"overcoat": {},
|
"multiscale": {},
|
||||||
"overgrow": {},
|
"multitype": {},
|
||||||
"own_tempo": {},
|
"mummy": {},
|
||||||
"parental_bond": {},
|
"natural_cure": {},
|
||||||
"pickpocket": {},
|
"no_guard": {},
|
||||||
"pickup": {},
|
"normalize": {},
|
||||||
"pixilate": {},
|
"oblivious": {},
|
||||||
"plus": {},
|
"overcoat": {},
|
||||||
"poison_heal": {},
|
"overgrow": {},
|
||||||
"poison_point": {},
|
"own_tempo": {},
|
||||||
"poison_touch": {},
|
"parental_bond": {},
|
||||||
"power_construct": {},
|
"pickpocket": {},
|
||||||
"power_of_alchemy": {},
|
"pickup": {},
|
||||||
"prankster": {},
|
"pixilate": {},
|
||||||
"pressure": {},
|
"plus": {},
|
||||||
"primordial_sea": {},
|
"poison_heal": {},
|
||||||
"prism_armor": {},
|
"poison_point": {},
|
||||||
"protean": {},
|
"poison_touch": {},
|
||||||
"psychic_surge": {},
|
"power_construct": {},
|
||||||
"pure_power": {},
|
"power_of_alchemy": {},
|
||||||
"queenly_majesty": {},
|
"prankster": {},
|
||||||
"quick_feet": {},
|
"pressure": {},
|
||||||
"rain_dish": {},
|
"primordial_sea": {},
|
||||||
"rattled": {},
|
"prism_armor": {},
|
||||||
"receiver": {},
|
"protean": {},
|
||||||
"reckless": {},
|
"psychic_surge": {},
|
||||||
"refrigerate": {},
|
"pure_power": {},
|
||||||
"regenerator": {},
|
"queenly_majesty": {},
|
||||||
"rivalry": {},
|
"quick_feet": {},
|
||||||
"rks_system": {},
|
"rain_dish": {},
|
||||||
"rock_head": {},
|
"rattled": {},
|
||||||
"rough_skin": {},
|
"receiver": {},
|
||||||
"run_away": {},
|
"reckless": {},
|
||||||
"sand_force": {},
|
"refrigerate": {},
|
||||||
"sand_rush": {},
|
"regenerator": {},
|
||||||
"sand_stream": {},
|
"rivalry": {},
|
||||||
"sand_veil": {},
|
"rks_system": {},
|
||||||
"sap_sipper": {},
|
"rock_head": {},
|
||||||
"schooling": {},
|
"rough_skin": {},
|
||||||
"scrappy": {},
|
"run_away": {},
|
||||||
"serene_grace": {},
|
"sand_force": {},
|
||||||
"shadow_shield": {},
|
"sand_rush": {},
|
||||||
"shadow_tag": {},
|
"sand_stream": {},
|
||||||
"shed_skin": {},
|
"sand_veil": {},
|
||||||
"sheer_force": {},
|
"sap_sipper": {},
|
||||||
"shell_armor": {},
|
"schooling": {},
|
||||||
"shield_dust": {},
|
"scrappy": {},
|
||||||
"shields_down": {},
|
"serene_grace": {},
|
||||||
"simple": {},
|
"shadow_shield": {},
|
||||||
"skill_link": {},
|
"shadow_tag": {},
|
||||||
"slow_start": {},
|
"shed_skin": {},
|
||||||
"slush_rush": {},
|
"sheer_force": {},
|
||||||
"sniper": {},
|
"shell_armor": {},
|
||||||
"snow_cloak": {},
|
"shield_dust": {},
|
||||||
"snow_warning": {},
|
"shields_down": {},
|
||||||
"solar_power": {},
|
"simple": {},
|
||||||
"solid_rock": {},
|
"skill_link": {},
|
||||||
"soul_heart": {},
|
"slow_start": {},
|
||||||
"soundproof": {},
|
"slush_rush": {},
|
||||||
"speed_boost": {},
|
"sniper": {},
|
||||||
"stakeout": {},
|
"snow_cloak": {},
|
||||||
"stall": {},
|
"snow_warning": {},
|
||||||
"stamina": {},
|
"solar_power": {},
|
||||||
"stance_change": {},
|
"solid_rock": {},
|
||||||
"static": {},
|
"soul_heart": {},
|
||||||
"steadfast": {},
|
"soundproof": {},
|
||||||
"steelworker": {},
|
"speed_boost": {},
|
||||||
"stench": {},
|
"stakeout": {},
|
||||||
"sticky_hold": {},
|
"stall": {},
|
||||||
"storm_drain": {},
|
"stamina": {},
|
||||||
"strong_jaw": {},
|
"stance_change": {},
|
||||||
"sturdy": {},
|
"static": {},
|
||||||
"suction_cups": {},
|
"steadfast": {},
|
||||||
"super_luck": {},
|
"steelworker": {},
|
||||||
"surge_surfer": {},
|
"stench": {},
|
||||||
"swarm": {},
|
"sticky_hold": {},
|
||||||
"sweet_veil": {},
|
"storm_drain": {},
|
||||||
"swift_swim": {},
|
"strong_jaw": {},
|
||||||
"symbiosis": {},
|
"sturdy": {},
|
||||||
"synchronize": {},
|
"suction_cups": {},
|
||||||
"tangled_feet": {},
|
"super_luck": {},
|
||||||
"tangling_hair": {},
|
"surge_surfer": {},
|
||||||
"technician": {},
|
"swarm": {},
|
||||||
"telepathy": {},
|
"sweet_veil": {},
|
||||||
"teravolt": {},
|
"swift_swim": {},
|
||||||
"thick_fat": {},
|
"symbiosis": {},
|
||||||
"tinted_lens": {},
|
"synchronize": {},
|
||||||
"torrent": {},
|
"tangled_feet": {},
|
||||||
"tough_claws": {},
|
"tangling_hair": {},
|
||||||
"toxic_boost": {},
|
"technician": {},
|
||||||
"trace": {},
|
"telepathy": {},
|
||||||
"triage": {},
|
"teravolt": {},
|
||||||
"truant": {},
|
"thick_fat": {},
|
||||||
"turboblaze": {},
|
"tinted_lens": {},
|
||||||
"unaware": {},
|
"torrent": {},
|
||||||
"unburden": {},
|
"tough_claws": {},
|
||||||
"unnerve": {},
|
"toxic_boost": {},
|
||||||
"victory_star": {},
|
"trace": {},
|
||||||
"vital_spirit": {},
|
"triage": {},
|
||||||
"volt_absorb": {},
|
"truant": {},
|
||||||
"water_absorb": {},
|
"turboblaze": {},
|
||||||
"water_bubble": {},
|
"unaware": {},
|
||||||
"water_compaction": {},
|
"unburden": {},
|
||||||
"water_veil": {},
|
"unnerve": {},
|
||||||
"weak_armor": {},
|
"victory_star": {},
|
||||||
"white_smoke": {},
|
"vital_spirit": {},
|
||||||
"wimp_out": {},
|
"volt_absorb": {},
|
||||||
"wonder_guard": {},
|
"water_absorb": {},
|
||||||
"wonder_skin": {},
|
"water_bubble": {},
|
||||||
"zen_mode": {}
|
"water_compaction": {},
|
||||||
|
"water_veil": {},
|
||||||
|
"weak_armor": {},
|
||||||
|
"white_smoke": {},
|
||||||
|
"wimp_out": {},
|
||||||
|
"wonder_guard": {},
|
||||||
|
"wonder_skin": {},
|
||||||
|
"zen_mode": {}
|
||||||
}
|
}
|
|
@ -29,9 +29,9 @@
|
||||||
"effect": {
|
"effect": {
|
||||||
"name": "drain",
|
"name": "drain",
|
||||||
"chance": -1,
|
"chance": -1,
|
||||||
"parameters": [
|
"parameters": {
|
||||||
0.5
|
"drain_mod": 0.5
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -65,9 +65,9 @@
|
||||||
"effect": {
|
"effect": {
|
||||||
"name": "change_target_special_defense",
|
"name": "change_target_special_defense",
|
||||||
"chance": 10,
|
"chance": 10,
|
||||||
"parameters": [
|
"parameters": {
|
||||||
-1
|
"amount": -1
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -85,9 +85,9 @@
|
||||||
"effect": {
|
"effect": {
|
||||||
"name": "change_target_defense",
|
"name": "change_target_defense",
|
||||||
"chance": -1,
|
"chance": -1,
|
||||||
"parameters": [
|
"parameters": {
|
||||||
2
|
"amount": 2
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -129,9 +129,9 @@
|
||||||
"effect": {
|
"effect": {
|
||||||
"name": "change_target_special_defense",
|
"name": "change_target_special_defense",
|
||||||
"chance": -1,
|
"chance": -1,
|
||||||
"parameters": [
|
"parameters": {
|
||||||
-2
|
"amount": -2
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -233,9 +233,9 @@
|
||||||
],
|
],
|
||||||
"effect": {
|
"effect": {
|
||||||
"name": "change_target_speed",
|
"name": "change_target_speed",
|
||||||
"parameters": [
|
"parameters": {
|
||||||
2
|
"amount": 2
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -324,9 +324,9 @@
|
||||||
],
|
],
|
||||||
"effect": {
|
"effect": {
|
||||||
"name": "change_target_special_defense",
|
"name": "change_target_special_defense",
|
||||||
"parameters": [
|
"parameters": {
|
||||||
2
|
"amount": 2
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -363,9 +363,9 @@
|
||||||
"effect": {
|
"effect": {
|
||||||
"name": "change_all_target_stats",
|
"name": "change_all_target_stats",
|
||||||
"chance": 10,
|
"chance": 10,
|
||||||
"parameters": [
|
"parameters": {
|
||||||
1
|
"amount": 1
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -397,9 +397,9 @@
|
||||||
],
|
],
|
||||||
"effect": {
|
"effect": {
|
||||||
"name": "heal_each_end_of_turn",
|
"name": "heal_each_end_of_turn",
|
||||||
"parameters": [
|
"parameters": {
|
||||||
6.25
|
"percent": 6.25
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -466,9 +466,9 @@
|
||||||
],
|
],
|
||||||
"effect": {
|
"effect": {
|
||||||
"name": "change_target_special_defense",
|
"name": "change_target_special_defense",
|
||||||
"parameters": [
|
"parameters": {
|
||||||
1
|
"amount": 1
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -592,9 +592,9 @@
|
||||||
"effect": {
|
"effect": {
|
||||||
"name": "change_target_attack",
|
"name": "change_target_attack",
|
||||||
"chance": 10,
|
"chance": 10,
|
||||||
"parameters": [
|
"parameters": {
|
||||||
-1
|
"amount": -1
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -660,9 +660,9 @@
|
||||||
],
|
],
|
||||||
"effect": {
|
"effect": {
|
||||||
"name": "change_target_attack",
|
"name": "change_target_attack",
|
||||||
"parameters": [
|
"parameters": {
|
||||||
-1
|
"amount": -1
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -3805,11 +3805,11 @@
|
||||||
"ignore-substitute"
|
"ignore-substitute"
|
||||||
],
|
],
|
||||||
"effect": {
|
"effect": {
|
||||||
"name": "ChangeTargetAtt",
|
"name": "change_target_attack",
|
||||||
"chance": -1,
|
"chance": -1,
|
||||||
"parameters": [
|
"parameters": {
|
||||||
-1
|
"amount": -1
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -5082,11 +5082,11 @@
|
||||||
"mirror"
|
"mirror"
|
||||||
],
|
],
|
||||||
"effect": {
|
"effect": {
|
||||||
"name": "ChangeTargetDef",
|
"name": "change_target_defense",
|
||||||
"chance": -1,
|
"chance": -1,
|
||||||
"parameters": [
|
"parameters": {
|
||||||
-1
|
"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 std::sync::{Arc, LazyLock};
|
||||||
|
|
||||||
use pkmn_lib::dynamic_data::{
|
use pkmn_lib::dynamic_data::{
|
||||||
Battle, BattleParty, DamageSource, DynamicLibrary, ExecutingMove, MoveChoice, PokemonBuilder, PokemonParty,
|
Battle, BattleParty, DamageSource, DynamicLibrary, ExecutingMove, MoveChoice, PassChoice, PokemonBuilder,
|
||||||
ScriptCategory, ScriptContainer, ScriptOwnerData, TurnChoice, VolatileScriptsOwner,
|
PokemonParty, ScriptCategory, ScriptContainer, ScriptOwnerData, TurnChoice, VolatileScriptsOwner,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::common::library_loader;
|
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);
|
static LIBRARY: LazyLock<Arc<dyn DynamicLibrary>> = LazyLock::new(|| library_loader::load_library().library);
|
||||||
|
|
||||||
fn get_library() -> Arc<dyn DynamicLibrary> {
|
fn get_library() -> Arc<dyn DynamicLibrary> { LIBRARY.clone() }
|
||||||
LIBRARY.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn validate_library_load() {
|
fn validate_library_load() {
|
||||||
|
@ -35,7 +33,7 @@ fn validate_library_load() {
|
||||||
\n\t- Abilities load time: {} ms\
|
\n\t- Abilities load time: {} ms\
|
||||||
\n\t- Moves load time: {} ms\
|
\n\t- Moves load time: {} ms\
|
||||||
\n\t- Species 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(),
|
(end_time - start_time).num_milliseconds(),
|
||||||
result.types_load_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]
|
#[test]
|
||||||
fn load_non_existing_wasm_script() {
|
fn load_non_existing_wasm_script() {
|
||||||
let start_time = chrono::Utc::now();
|
let start_time = chrono::Utc::now();
|
||||||
|
@ -63,7 +79,7 @@ fn load_non_existing_wasm_script() {
|
||||||
\n\t- Abilities load time: {} ms\
|
\n\t- Abilities load time: {} ms\
|
||||||
\n\t- Moves load time: {} ms\
|
\n\t- Moves load time: {} ms\
|
||||||
\n\t- Species 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(),
|
(end_time - start_time).num_milliseconds(),
|
||||||
result.types_load_time.num_milliseconds(),
|
result.types_load_time.num_milliseconds(),
|
||||||
|
|
Loading…
Reference in New Issue