Compare commits
6 Commits
Author | SHA1 | Date |
---|---|---|
Deukhoofd | 92ff5bd0a1 | |
Deukhoofd | 535f6bf79b | |
Deukhoofd | 42bee5e37c | |
Deukhoofd | 4ec07ca049 | |
Deukhoofd | 4bc76b0ee4 | |
Deukhoofd | 67b0abe59f |
18
Cargo.toml
18
Cargo.toml
|
@ -16,7 +16,8 @@ path = "src/lib.rs"
|
|||
ffi = []
|
||||
serde = ["dep:serde", "dep:serde-xml-rs", "atomig/serde"]
|
||||
wasm = ["dep:wasmer"]
|
||||
default = ["serde", "wasm", "ffi"]
|
||||
rune = ["dep:rune"]
|
||||
default = ["serde", "rune", "ffi"]
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 0
|
||||
|
@ -50,27 +51,30 @@ chrono = "0.4"
|
|||
rand = "0.8"
|
||||
rand_pcg = "0.3"
|
||||
hashbrown = "0.14"
|
||||
indexmap = "2.0"
|
||||
indexmap = "2.2"
|
||||
parking_lot = "0.12"
|
||||
serde = { version = "1.0", optional = true, features = ["derive"] }
|
||||
serde_repr = "0.1"
|
||||
serde-xml-rs = { version = "0.6", optional = true }
|
||||
wasmer = { version = "4.2", optional = true, default-features = false, features = ["sys", "wat", "llvm"] }
|
||||
uuid = "1.5"
|
||||
uuid = "1.8"
|
||||
paste = { version = "1.0" }
|
||||
arcstr = { version = "1.1", features = ["std"] }
|
||||
arcstr = { version = "1.2", features = ["std"] }
|
||||
enum-display-derive = "0.1"
|
||||
anyhow = "1.0"
|
||||
anyhow_ext = "0.2"
|
||||
thiserror = "1.0"
|
||||
stdext = "0.3"
|
||||
|
||||
wasmer = { version = "4.2", optional = true, default-features = false, features = ["sys", "wat", "llvm"] }
|
||||
rune = { version = "0.14.0", optional = true, git = "https://github.com/rune-rs/rune" }
|
||||
|
||||
[dev-dependencies]
|
||||
csv = "1.3"
|
||||
project-root = "0.2"
|
||||
serde_yaml = "0.9"
|
||||
serde_yml = "0.0.7"
|
||||
serde_json = "1.0"
|
||||
serde_plain = "1.0"
|
||||
# Allow us to assert whether floats are approximately a value
|
||||
assert_approx_eq = "1.1"
|
||||
mockall = "0.11"
|
||||
mockall = "0.12"
|
||||
walkdir = "2.3"
|
|
@ -1 +1,4 @@
|
|||
max_width = 120
|
||||
fn_single_line = true
|
||||
inline_attribute_width = 120
|
||||
unstable_features = true
|
|
@ -56,47 +56,33 @@ impl TurnChoice {
|
|||
}
|
||||
|
||||
/// Get the user of the given choice.
|
||||
pub fn user(&self) -> &Pokemon {
|
||||
&self.choice_data().user
|
||||
}
|
||||
pub fn user(&self) -> &Pokemon { &self.choice_data().user }
|
||||
|
||||
/// Get the speed of the user for the choice. Note that this speed is the speed of the Pokemon
|
||||
/// at the start of the turn!
|
||||
pub fn speed(&self) -> u32 {
|
||||
self.choice_data().speed.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn speed(&self) -> u32 { self.choice_data().speed.load(Ordering::Relaxed) }
|
||||
|
||||
/// Sets the speed of user for the choice. Note that this speed is the speed of the Pokemon at
|
||||
/// the start of the turn!
|
||||
pub fn set_speed(&self, value: u32) {
|
||||
self.choice_data().speed.store(value, Ordering::Relaxed);
|
||||
}
|
||||
pub fn set_speed(&self, value: u32) { self.choice_data().speed.store(value, Ordering::Relaxed); }
|
||||
|
||||
/// Gets whether or not the choice has failed. If we notice this when we execute the choice, we
|
||||
/// will not execute it.
|
||||
pub fn has_failed(&self) -> bool {
|
||||
self.choice_data().has_failed.load(Ordering::SeqCst)
|
||||
}
|
||||
pub fn has_failed(&self) -> bool { self.choice_data().has_failed.load(Ordering::SeqCst) }
|
||||
|
||||
/// Fails the choice. This will prevent it from executing and run a specific fail handling during
|
||||
/// execution. Note that this can not be undone.
|
||||
pub fn fail(&self) {
|
||||
self.choice_data().has_failed.store(true, Ordering::SeqCst)
|
||||
}
|
||||
pub fn fail(&self) { self.choice_data().has_failed.store(true, Ordering::SeqCst) }
|
||||
|
||||
/// The random value of a turn choice gets set during the start of a choice, and is used for tie
|
||||
/// breaking of turn executions. This means that choices get executed with a predictable order,
|
||||
/// regardless of implementation details.
|
||||
pub(crate) fn random_value(&self) -> u32 {
|
||||
self.choice_data().random_value.load(Ordering::Relaxed)
|
||||
}
|
||||
pub(crate) fn random_value(&self) -> u32 { self.choice_data().random_value.load(Ordering::Relaxed) }
|
||||
|
||||
/// This sets the above random value.
|
||||
pub(crate) fn set_random_value(&self, val: u32) {
|
||||
self.choice_data().random_value.store(val, Ordering::Relaxed)
|
||||
}
|
||||
pub(crate) fn set_random_value(&self, val: u32) { self.choice_data().random_value.store(val, Ordering::Relaxed) }
|
||||
|
||||
/// Helper function to get the move choice data from a turn. Note that this will panic if not
|
||||
/// Helper function to get the move choice data from a turn. Note that this will error if not
|
||||
/// used on a move choice.
|
||||
pub(crate) fn get_move_turn_data(&self) -> Result<&MoveChoice> {
|
||||
if let TurnChoice::Move(data) = self {
|
||||
|
@ -187,48 +173,28 @@ impl MoveChoice {
|
|||
}
|
||||
|
||||
/// The actual learned move on the Pokemon we use for this choice.
|
||||
pub fn used_move(&self) -> &Arc<LearnedMove> {
|
||||
&self.used_move
|
||||
}
|
||||
pub fn used_move(&self) -> &Arc<LearnedMove> { &self.used_move }
|
||||
|
||||
/// The target side the move is aimed at.
|
||||
pub fn target_side(&self) -> u8 {
|
||||
self.target_side
|
||||
}
|
||||
pub fn target_side(&self) -> u8 { self.target_side }
|
||||
/// The Pokemon index on the side we're aiming at.
|
||||
pub fn target_index(&self) -> u8 {
|
||||
self.target_index
|
||||
}
|
||||
pub fn target_index(&self) -> u8 { self.target_index }
|
||||
/// The priority of the move choice at the beginning of the turn.
|
||||
pub fn priority(&self) -> i8 {
|
||||
self.priority.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn priority(&self) -> i8 { self.priority.load(Ordering::Relaxed) }
|
||||
/// The priority of the move choice at the beginning of the turn.
|
||||
pub fn set_priority(&self, value: i8) {
|
||||
self.priority.store(value, Ordering::Relaxed)
|
||||
}
|
||||
pub fn set_priority(&self, value: i8) { self.priority.store(value, Ordering::Relaxed) }
|
||||
/// The user of the choice.
|
||||
pub fn user(&self) -> &Pokemon {
|
||||
&self.choice_data.user
|
||||
}
|
||||
pub fn user(&self) -> &Pokemon { &self.choice_data.user }
|
||||
/// The move script of the choice.
|
||||
pub fn script(&self) -> &ScriptContainer {
|
||||
&self.script
|
||||
}
|
||||
pub fn script(&self) -> &ScriptContainer { &self.script }
|
||||
}
|
||||
|
||||
impl ScriptSource for MoveChoice {
|
||||
fn get_script_count(&self) -> Result<usize> {
|
||||
Ok(self.choice_data.user.get_script_count()? + 1)
|
||||
}
|
||||
fn get_script_count(&self) -> Result<usize> { Ok(self.choice_data.user.get_script_count()? + 1) }
|
||||
|
||||
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> {
|
||||
&self.choice_data.script_source_data
|
||||
}
|
||||
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> { &self.choice_data.script_source_data }
|
||||
|
||||
fn get_own_scripts(&self, scripts: &mut Vec<ScriptWrapper>) {
|
||||
scripts.push((&self.script).into());
|
||||
}
|
||||
fn get_own_scripts(&self, scripts: &mut Vec<ScriptWrapper>) { scripts.push((&self.script).into()); }
|
||||
|
||||
fn collect_scripts(&self, scripts: &mut Vec<ScriptWrapper>) -> Result<()> {
|
||||
self.get_own_scripts(scripts);
|
||||
|
@ -260,13 +226,9 @@ impl ItemChoice {
|
|||
}
|
||||
|
||||
impl ScriptSource for ItemChoice {
|
||||
fn get_script_count(&self) -> Result<usize> {
|
||||
Ok(0)
|
||||
}
|
||||
fn get_script_count(&self) -> Result<usize> { Ok(0) }
|
||||
|
||||
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> {
|
||||
&self.choice_data.script_source_data
|
||||
}
|
||||
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> { &self.choice_data.script_source_data }
|
||||
|
||||
fn get_own_scripts(&self, _scripts: &mut Vec<ScriptWrapper>) {}
|
||||
|
||||
|
@ -299,13 +261,9 @@ impl SwitchChoice {
|
|||
}
|
||||
|
||||
impl ScriptSource for SwitchChoice {
|
||||
fn get_script_count(&self) -> Result<usize> {
|
||||
Ok(0)
|
||||
}
|
||||
fn get_script_count(&self) -> Result<usize> { Ok(0) }
|
||||
|
||||
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> {
|
||||
&self.choice_data.script_source_data
|
||||
}
|
||||
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> { &self.choice_data.script_source_data }
|
||||
|
||||
fn get_own_scripts(&self, _scripts: &mut Vec<ScriptWrapper>) {}
|
||||
|
||||
|
@ -337,13 +295,9 @@ impl FleeChoice {
|
|||
}
|
||||
|
||||
impl ScriptSource for FleeChoice {
|
||||
fn get_script_count(&self) -> Result<usize> {
|
||||
Ok(0)
|
||||
}
|
||||
fn get_script_count(&self) -> Result<usize> { Ok(0) }
|
||||
|
||||
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> {
|
||||
&self.choice_data.script_source_data
|
||||
}
|
||||
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> { &self.choice_data.script_source_data }
|
||||
|
||||
fn get_own_scripts(&self, _scripts: &mut Vec<ScriptWrapper>) {}
|
||||
|
||||
|
@ -376,13 +330,9 @@ impl PassChoice {
|
|||
}
|
||||
|
||||
impl ScriptSource for PassChoice {
|
||||
fn get_script_count(&self) -> Result<usize> {
|
||||
Ok(0)
|
||||
}
|
||||
fn get_script_count(&self) -> Result<usize> { Ok(0) }
|
||||
|
||||
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> {
|
||||
&self.choice_data.script_source_data
|
||||
}
|
||||
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> { &self.choice_data.script_source_data }
|
||||
|
||||
fn get_own_scripts(&self, _scripts: &mut Vec<ScriptWrapper>) {}
|
||||
|
||||
|
@ -392,17 +342,13 @@ impl ScriptSource for PassChoice {
|
|||
}
|
||||
|
||||
impl PartialEq<Self> for TurnChoice {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
std::ptr::eq(self, other)
|
||||
}
|
||||
fn eq(&self, other: &Self) -> bool { std::ptr::eq(self, other) }
|
||||
}
|
||||
|
||||
impl Eq for TurnChoice {}
|
||||
|
||||
impl PartialOrd for TurnChoice {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { Some(self.cmp(other)) }
|
||||
}
|
||||
|
||||
impl Ord for TurnChoice {
|
||||
|
|
|
@ -68,9 +68,7 @@ impl ChoiceQueue {
|
|||
}
|
||||
|
||||
/// Check if we have any choices remaining.
|
||||
pub fn has_next(&self) -> bool {
|
||||
self.current.load(Ordering::Relaxed) < self.queue.read().len()
|
||||
}
|
||||
pub fn has_next(&self) -> bool { self.current.load(Ordering::Relaxed) < self.queue.read().len() }
|
||||
|
||||
/// This resorts the yet to be executed choices. This can be useful for dealing with situations
|
||||
/// such as Pokemon changing forms just after the very start of a turn, when turn order has
|
||||
|
@ -163,7 +161,6 @@ mod tests {
|
|||
use crate::defines::LevelInt;
|
||||
use crate::dynamic_data::{DynamicLibrary, PassChoice};
|
||||
use crate::static_data::{AbilityIndex, Gender};
|
||||
use std::sync::Arc;
|
||||
#[test]
|
||||
fn create_empty_queue() {
|
||||
let queue = ChoiceQueue::new(Vec::new());
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
#[doc(inline)]
|
||||
pub use choice_queue::*;
|
||||
#[doc(inline)]
|
||||
pub use target_resolver::*;
|
||||
#[doc(inline)]
|
||||
pub use turn_runner::*;
|
||||
#[doc(inline)] pub use choice_queue::*;
|
||||
#[doc(inline)] pub use target_resolver::*;
|
||||
|
||||
/// Data for enqueueing and retrieving choices.
|
||||
mod choice_queue;
|
||||
|
|
|
@ -4,6 +4,7 @@ use crate::static_data::{EvolutionMethod, TimeOfDay};
|
|||
/// A library for handling the checking of evolution requirements.
|
||||
pub trait EvolutionLibrary {
|
||||
/// Checks if the given Pokemon fulfills the given evolution conditions.
|
||||
#[allow(dead_code)]
|
||||
fn pokemon_fulfills_evolution_conditions(&self, pokemon: &Pokemon, method: &EvolutionMethod) -> bool;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ impl Gen7MiscLibrary {
|
|||
Some(Arc::new(SecondaryEffectImpl::new(
|
||||
-1.0,
|
||||
StringKey::new("struggle"),
|
||||
vec![],
|
||||
Default::default(),
|
||||
))),
|
||||
HashSet::new(),
|
||||
));
|
||||
|
|
|
@ -125,57 +125,31 @@ impl Battle {
|
|||
}
|
||||
|
||||
/// The library the battle uses for handling.
|
||||
pub fn library(&self) -> &Arc<dyn DynamicLibrary> {
|
||||
&self.data.library
|
||||
}
|
||||
pub fn library(&self) -> &Arc<dyn DynamicLibrary> { &self.data.library }
|
||||
/// A list of all different parties in the battle.
|
||||
pub fn parties(&self) -> &Vec<Arc<BattleParty>> {
|
||||
&self.data.parties
|
||||
}
|
||||
pub fn parties(&self) -> &Vec<Arc<BattleParty>> { &self.data.parties }
|
||||
/// Whether or not Pokemon can flee from the battle.
|
||||
pub fn can_flee(&self) -> bool {
|
||||
self.data.can_flee
|
||||
}
|
||||
pub fn can_flee(&self) -> bool { self.data.can_flee }
|
||||
/// The number of sides in the battle. Typically 2.
|
||||
pub fn number_of_sides(&self) -> u8 {
|
||||
self.data.number_of_sides
|
||||
}
|
||||
pub fn number_of_sides(&self) -> u8 { self.data.number_of_sides }
|
||||
/// The number of Pokemon that can be on each side.
|
||||
pub fn pokemon_per_side(&self) -> u8 {
|
||||
self.data.pokemon_per_side
|
||||
}
|
||||
pub fn pokemon_per_side(&self) -> u8 { self.data.pokemon_per_side }
|
||||
/// A list of all sides in the battle.
|
||||
pub fn sides(&self) -> &Vec<BattleSide> {
|
||||
&self.data.sides
|
||||
}
|
||||
pub fn sides(&self) -> &Vec<BattleSide> { &self.data.sides }
|
||||
/// The RNG used for the battle.
|
||||
pub fn random(&self) -> &Arc<BattleRandom> {
|
||||
&self.data.random
|
||||
}
|
||||
pub fn random(&self) -> &Arc<BattleRandom> { &self.data.random }
|
||||
/// Whether or not the battle has ended.
|
||||
pub fn has_ended(&self) -> bool {
|
||||
self.data.has_ended.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn has_ended(&self) -> bool { self.data.has_ended.load(Ordering::Relaxed) }
|
||||
/// The eventual result of the battle. Inconclusive until the battle is ended.
|
||||
pub fn result(&self) -> BattleResult {
|
||||
*self.data.result.read()
|
||||
}
|
||||
pub fn result(&self) -> BattleResult { *self.data.result.read() }
|
||||
/// The handler to send all events to.
|
||||
pub fn event_hook(&self) -> &EventHook {
|
||||
&self.data.event_hook
|
||||
}
|
||||
pub fn event_hook(&self) -> &EventHook { &self.data.event_hook }
|
||||
/// The index of the current turn. 0 until all choices
|
||||
pub fn current_turn(&self) -> u32 {
|
||||
self.data.current_turn.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn current_turn(&self) -> u32 { self.data.current_turn.load(Ordering::Relaxed) }
|
||||
/// The time in nanoseconds the last turn took to run. Defaults to 0.
|
||||
pub fn last_turn_time(&self) -> u64 {
|
||||
self.data.last_turn_time.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn last_turn_time(&self) -> u64 { self.data.last_turn_time.load(Ordering::Relaxed) }
|
||||
/// A queue of the yet to be executed choices in a turn.
|
||||
pub fn current_turn_queue(&self) -> &RwLock<Option<Arc<ChoiceQueue>>> {
|
||||
&self.data.current_turn_queue
|
||||
}
|
||||
pub fn current_turn_queue(&self) -> &RwLock<Option<Arc<ChoiceQueue>>> { &self.data.current_turn_queue }
|
||||
|
||||
/// Get a Pokemon on the battlefield, on a specific side and an index on that side.
|
||||
pub fn get_pokemon(&self, side: u8, index: u8) -> Option<Pokemon> {
|
||||
|
@ -379,28 +353,21 @@ impl Battle {
|
|||
}
|
||||
|
||||
/// Gets the inner pointer to the reference counted data.
|
||||
pub fn as_ptr(&self) -> *const c_void {
|
||||
Arc::as_ptr(&self.data) as *const c_void
|
||||
}
|
||||
pub fn as_ptr(&self) -> *const c_void { Arc::as_ptr(&self.data) as *const c_void }
|
||||
}
|
||||
|
||||
impl PartialEq for Battle {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
Arc::ptr_eq(&self.data, &other.data)
|
||||
}
|
||||
fn eq(&self, other: &Self) -> bool { Arc::ptr_eq(&self.data, &other.data) }
|
||||
}
|
||||
|
||||
impl WeakBattleReference {
|
||||
/// Attempts to upgrade the weak reference to a strong reference. If the strong reference has
|
||||
/// been dropped, this returns None.
|
||||
pub fn upgrade(&self) -> Option<Battle> {
|
||||
self.data.upgrade().map(|battle| Battle { data: battle })
|
||||
}
|
||||
pub fn upgrade(&self) -> Option<Battle> { self.data.upgrade().map(|battle| Battle { data: battle }) }
|
||||
|
||||
/// Gets the inner pointer to the reference counted data.
|
||||
pub(crate) fn as_ptr(&self) -> *const c_void {
|
||||
self.data.as_ptr() as *const c_void
|
||||
}
|
||||
#[cfg(feature = "wasm")]
|
||||
pub(crate) fn as_ptr(&self) -> *const c_void { self.data.as_ptr() as *const c_void }
|
||||
}
|
||||
|
||||
unsafe impl Send for WeakBattleReference {}
|
||||
|
@ -408,17 +375,13 @@ unsafe impl Send for WeakBattleReference {}
|
|||
unsafe impl Sync for WeakBattleReference {}
|
||||
|
||||
impl PartialEq for WeakBattleReference {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.data.ptr_eq(&other.data)
|
||||
}
|
||||
fn eq(&self, other: &Self) -> bool { self.data.ptr_eq(&other.data) }
|
||||
}
|
||||
|
||||
impl Eq for WeakBattleReference {}
|
||||
|
||||
impl VolatileScriptsOwner for Battle {
|
||||
fn volatile_scripts(&self) -> &Arc<ScriptSet> {
|
||||
&self.data.volatile_scripts
|
||||
}
|
||||
fn volatile_scripts(&self) -> &Arc<ScriptSet> { &self.data.volatile_scripts }
|
||||
|
||||
fn load_volatile_script(&self, key: &StringKey) -> Result<Option<Arc<dyn Script>>> {
|
||||
self.data.library.load_script(self.into(), ScriptCategory::Battle, key)
|
||||
|
@ -426,13 +389,9 @@ impl VolatileScriptsOwner for Battle {
|
|||
}
|
||||
|
||||
impl ScriptSource for Battle {
|
||||
fn get_script_count(&self) -> Result<usize> {
|
||||
Ok(1)
|
||||
}
|
||||
fn get_script_count(&self) -> Result<usize> { Ok(1) }
|
||||
|
||||
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> {
|
||||
&self.data.script_source_data
|
||||
}
|
||||
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> { &self.data.script_source_data }
|
||||
|
||||
fn get_own_scripts(&self, scripts: &mut Vec<ScriptWrapper>) {
|
||||
scripts.push((&self.data.weather).into());
|
||||
|
@ -457,7 +416,5 @@ pub enum BattleResult {
|
|||
|
||||
impl BattleResult {
|
||||
/// Whether or not the battle has a winner.
|
||||
pub fn is_conclusive(&self) -> bool {
|
||||
matches!(self, Self::Conclusive(_))
|
||||
}
|
||||
pub fn is_conclusive(&self) -> bool { matches!(self, Self::Conclusive(_)) }
|
||||
}
|
||||
|
|
|
@ -101,30 +101,18 @@ impl BattleSide {
|
|||
}
|
||||
|
||||
/// The index of the side on the battle.
|
||||
pub fn index(&self) -> u8 {
|
||||
self.data.index
|
||||
}
|
||||
pub fn index(&self) -> u8 { self.data.index }
|
||||
/// The number of Pokemon that can be on the side.
|
||||
pub fn pokemon_per_side(&self) -> u8 {
|
||||
self.data.pokemon_per_side
|
||||
}
|
||||
pub fn pokemon_per_side(&self) -> u8 { self.data.pokemon_per_side }
|
||||
/// A list of pokemon currently on the battlefield.
|
||||
pub fn pokemon(&self) -> RwLockReadGuard<'_, RawRwLock, Vec<Option<Pokemon>>> {
|
||||
self.data.pokemon.read()
|
||||
}
|
||||
pub fn pokemon(&self) -> RwLockReadGuard<'_, RawRwLock, Vec<Option<Pokemon>>> { self.data.pokemon.read() }
|
||||
/// The currently set choices for all Pokemon on the battlefield. Cleared when the turn starts.
|
||||
pub fn choices(&self) -> &RwLock<Vec<Option<Arc<TurnChoice>>>> {
|
||||
&self.data.choices
|
||||
}
|
||||
pub fn choices(&self) -> &RwLock<Vec<Option<Arc<TurnChoice>>>> { &self.data.choices }
|
||||
/// The slots on the side that can still be filled. Once all slots are set to false, this side
|
||||
/// has lost the battle.
|
||||
pub fn fillable_slots(&self) -> &Vec<AtomicBool> {
|
||||
&self.data.fillable_slots
|
||||
}
|
||||
pub fn fillable_slots(&self) -> &Vec<AtomicBool> { &self.data.fillable_slots }
|
||||
/// The number of choices that are set.
|
||||
pub fn choices_set(&self) -> u8 {
|
||||
self.data.choices_set.load(Ordering::SeqCst)
|
||||
}
|
||||
pub fn choices_set(&self) -> u8 { self.data.choices_set.load(Ordering::SeqCst) }
|
||||
/// A reference to the battle we're part of.
|
||||
pub fn battle(&self) -> Result<Battle> {
|
||||
self.data
|
||||
|
@ -133,18 +121,12 @@ impl BattleSide {
|
|||
.ok_or(anyhow!("Battle was not set, but requested"))
|
||||
}
|
||||
/// Whether or not this side has fled.
|
||||
pub fn has_fled_battle(&self) -> bool {
|
||||
self.data.has_fled_battle.load(Ordering::SeqCst)
|
||||
}
|
||||
pub fn has_fled_battle(&self) -> bool { self.data.has_fled_battle.load(Ordering::SeqCst) }
|
||||
/// The volatile scripts that are attached to the side.
|
||||
pub fn volatile_scripts(&self) -> &Arc<ScriptSet> {
|
||||
&self.data.volatile_scripts
|
||||
}
|
||||
pub fn volatile_scripts(&self) -> &Arc<ScriptSet> { &self.data.volatile_scripts }
|
||||
|
||||
/// Whether every Pokemon on this side has its choices
|
||||
pub fn all_choices_set(&self) -> bool {
|
||||
self.choices_set() == self.data.pokemon_per_side
|
||||
}
|
||||
pub fn all_choices_set(&self) -> bool { self.choices_set() == self.data.pokemon_per_side }
|
||||
|
||||
/// Returns true if there are slots that need to be filled with a new pokemon, that have parties
|
||||
/// responsible for them. Returns false if all slots are filled with usable pokemon, or slots are
|
||||
|
@ -190,9 +172,7 @@ impl BattleSide {
|
|||
}
|
||||
|
||||
/// Forcibly removes a Pokemon from the field.
|
||||
pub fn force_clear_pokemon(&mut self, index: u8) {
|
||||
self.data.pokemon.write().get_mut(index as usize).take();
|
||||
}
|
||||
pub fn force_clear_pokemon(&mut self, index: u8) { self.data.pokemon.write().get_mut(index as usize).take(); }
|
||||
|
||||
/// Switches out a spot on the field for a different Pokemon.
|
||||
pub fn set_pokemon(&self, index: u8, pokemon: Option<Pokemon>) -> Result<()> {
|
||||
|
@ -296,9 +276,7 @@ impl BattleSide {
|
|||
}
|
||||
|
||||
/// Mark the side as fled.
|
||||
pub fn mark_as_fled(&mut self) {
|
||||
self.data.has_fled_battle.store(true, Ordering::SeqCst);
|
||||
}
|
||||
pub fn mark_as_fled(&mut self) { self.data.has_fled_battle.store(true, Ordering::SeqCst); }
|
||||
|
||||
/// Gets a random Pokemon on the given side.
|
||||
pub fn get_random_creature_index(&self) -> Result<u8> {
|
||||
|
@ -364,28 +342,21 @@ impl BattleSide {
|
|||
}
|
||||
|
||||
/// Gets the inner pointer to the reference counted data.
|
||||
pub fn as_ptr(&self) -> *const c_void {
|
||||
Arc::as_ptr(&self.data) as *const c_void
|
||||
}
|
||||
pub fn as_ptr(&self) -> *const c_void { Arc::as_ptr(&self.data) as *const c_void }
|
||||
}
|
||||
|
||||
impl PartialEq for BattleSide {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
Arc::ptr_eq(&self.data, &other.data)
|
||||
}
|
||||
fn eq(&self, other: &Self) -> bool { Arc::ptr_eq(&self.data, &other.data) }
|
||||
}
|
||||
|
||||
impl WeakBattleSideReference {
|
||||
/// Upgrades the weak reference to a strong reference, returning `None` if the side has been
|
||||
/// dropped.
|
||||
pub fn upgrade(&self) -> Option<BattleSide> {
|
||||
self.data.upgrade().map(|data| BattleSide { data })
|
||||
}
|
||||
pub fn upgrade(&self) -> Option<BattleSide> { self.data.upgrade().map(|data| BattleSide { data }) }
|
||||
|
||||
/// Gets the underlying pointer to the data of the side.
|
||||
pub(crate) fn as_ptr(&self) -> *const c_void {
|
||||
self.data.as_ptr() as *const c_void
|
||||
}
|
||||
#[cfg(feature = "wasm")]
|
||||
pub(crate) fn as_ptr(&self) -> *const c_void { self.data.as_ptr() as *const c_void }
|
||||
}
|
||||
|
||||
unsafe impl Send for WeakBattleSideReference {}
|
||||
|
@ -393,15 +364,11 @@ unsafe impl Send for WeakBattleSideReference {}
|
|||
unsafe impl Sync for WeakBattleSideReference {}
|
||||
|
||||
impl PartialEq for WeakBattleSideReference {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.data.ptr_eq(&other.data)
|
||||
}
|
||||
fn eq(&self, other: &Self) -> bool { self.data.ptr_eq(&other.data) }
|
||||
}
|
||||
|
||||
impl VolatileScriptsOwner for BattleSide {
|
||||
fn volatile_scripts(&self) -> &Arc<ScriptSet> {
|
||||
&self.data.volatile_scripts
|
||||
}
|
||||
fn volatile_scripts(&self) -> &Arc<ScriptSet> { &self.data.volatile_scripts }
|
||||
|
||||
fn load_volatile_script(&self, key: &StringKey) -> Result<Option<Arc<dyn Script>>> {
|
||||
self.battle()?
|
||||
|
@ -411,17 +378,11 @@ impl VolatileScriptsOwner for BattleSide {
|
|||
}
|
||||
|
||||
impl ScriptSource for BattleSide {
|
||||
fn get_script_count(&self) -> Result<usize> {
|
||||
Ok(self.battle()?.get_script_count()? + 1)
|
||||
}
|
||||
fn get_script_count(&self) -> Result<usize> { Ok(self.battle()?.get_script_count()? + 1) }
|
||||
|
||||
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> {
|
||||
&self.data.script_source_data
|
||||
}
|
||||
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> { &self.data.script_source_data }
|
||||
|
||||
fn get_own_scripts(&self, scripts: &mut Vec<ScriptWrapper>) {
|
||||
scripts.push((&self.data.volatile_scripts).into());
|
||||
}
|
||||
fn get_own_scripts(&self, scripts: &mut Vec<ScriptWrapper>) { scripts.push((&self.data.volatile_scripts).into()); }
|
||||
|
||||
fn collect_scripts(&self, scripts: &mut Vec<ScriptWrapper>) -> Result<()> {
|
||||
self.get_own_scripts(scripts);
|
||||
|
|
|
@ -33,59 +33,34 @@ pub struct HitData {
|
|||
|
||||
impl HitData {
|
||||
/// Whether or not the hit is critical.
|
||||
pub fn is_critical(&self) -> bool {
|
||||
self.critical.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn is_critical(&self) -> bool { self.critical.load(Ordering::Relaxed) }
|
||||
/// The base power of the hit.
|
||||
pub fn base_power(&self) -> u8 {
|
||||
self.base_power.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn base_power(&self) -> u8 { self.base_power.load(Ordering::Relaxed) }
|
||||
/// The type effectiveness of the hit.
|
||||
pub fn effectiveness(&self) -> f32 {
|
||||
self.effectiveness.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn effectiveness(&self) -> f32 { self.effectiveness.load(Ordering::Relaxed) }
|
||||
/// The actual damage of the hit.
|
||||
pub fn damage(&self) -> u32 {
|
||||
self.damage.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn damage(&self) -> u32 { self.damage.load(Ordering::Relaxed) }
|
||||
/// The type id of the type used for the hit.
|
||||
pub fn move_type(&self) -> TypeIdentifier {
|
||||
self.move_type.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn move_type(&self) -> TypeIdentifier { self.move_type.load(Ordering::Relaxed) }
|
||||
/// Whether or not the hit has failed.
|
||||
pub fn has_failed(&self) -> bool {
|
||||
self.has_failed.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn has_failed(&self) -> bool { self.has_failed.load(Ordering::Relaxed) }
|
||||
|
||||
/// Sets whether or not the hit is critical.
|
||||
pub fn set_critical(&self, value: bool) {
|
||||
self.critical.store(value, Ordering::SeqCst);
|
||||
}
|
||||
pub fn set_critical(&self, value: bool) { self.critical.store(value, Ordering::SeqCst); }
|
||||
/// Sets the base power of the hit.
|
||||
pub fn set_base_power(&self, value: u8) {
|
||||
self.base_power.store(value, Ordering::SeqCst);
|
||||
}
|
||||
pub fn set_base_power(&self, value: u8) { self.base_power.store(value, Ordering::SeqCst); }
|
||||
/// Sets the type effectiveness of the hit.
|
||||
pub fn set_effectiveness(&self, value: f32) {
|
||||
self.effectiveness.store(value, Ordering::SeqCst);
|
||||
}
|
||||
pub fn set_effectiveness(&self, value: f32) { self.effectiveness.store(value, Ordering::SeqCst); }
|
||||
/// Sets the actual damage of the hit.
|
||||
pub fn set_damage(&self, value: u32) {
|
||||
self.damage.store(value, Ordering::SeqCst);
|
||||
}
|
||||
pub fn set_damage(&self, value: u32) { self.damage.store(value, Ordering::SeqCst); }
|
||||
/// Sets the move type id of the hit.
|
||||
pub fn set_move_type(&self, value: TypeIdentifier) {
|
||||
self.move_type.store(value, Ordering::SeqCst);
|
||||
}
|
||||
pub fn set_move_type(&self, value: TypeIdentifier) { self.move_type.store(value, Ordering::SeqCst); }
|
||||
/// Marks the hit as failed.
|
||||
pub fn fail(&self) {
|
||||
self.has_failed.store(true, Ordering::SeqCst);
|
||||
}
|
||||
pub fn fail(&self) { self.has_failed.store(true, Ordering::SeqCst); }
|
||||
}
|
||||
|
||||
/// An executing move is the data of the move for while it is executing.
|
||||
#[derive(Debug)]
|
||||
|
||||
pub struct ExecutingMove {
|
||||
/// The number of hits this move has.
|
||||
number_of_hits: u8,
|
||||
|
@ -134,29 +109,17 @@ impl ExecutingMove {
|
|||
}
|
||||
|
||||
/// The number of targets this move has.
|
||||
pub fn target_count(&self) -> usize {
|
||||
self.targets.len()
|
||||
}
|
||||
pub fn target_count(&self) -> usize { self.targets.len() }
|
||||
/// The number of hits this move has per target.
|
||||
pub fn number_of_hits(&self) -> u8 {
|
||||
self.number_of_hits
|
||||
}
|
||||
pub fn number_of_hits(&self) -> u8 { self.number_of_hits }
|
||||
/// The user of the move.
|
||||
pub fn user(&self) -> &Pokemon {
|
||||
&self.user
|
||||
}
|
||||
pub fn user(&self) -> &Pokemon { &self.user }
|
||||
/// The move the user has actually chosen to do.
|
||||
pub fn chosen_move(&self) -> &Arc<LearnedMove> {
|
||||
&self.chosen_move
|
||||
}
|
||||
pub fn chosen_move(&self) -> &Arc<LearnedMove> { &self.chosen_move }
|
||||
/// The move that the user is actually going to do.
|
||||
pub fn use_move(&self) -> &Arc<dyn MoveData> {
|
||||
&self.use_move
|
||||
}
|
||||
pub fn use_move(&self) -> &Arc<dyn MoveData> { &self.use_move }
|
||||
/// The script of the move.
|
||||
pub fn script(&self) -> &ScriptContainer {
|
||||
&self.script
|
||||
}
|
||||
pub fn script(&self) -> &ScriptContainer { &self.script }
|
||||
|
||||
/// Gets a hit data for a target, with a specific index.
|
||||
pub fn get_hit_data(&self, for_target: &Pokemon, hit: u8) -> Result<&Arc<HitData>> {
|
||||
|
@ -215,17 +178,11 @@ impl ExecutingMove {
|
|||
}
|
||||
|
||||
impl ScriptSource for ExecutingMove {
|
||||
fn get_script_count(&self) -> Result<usize> {
|
||||
Ok(1)
|
||||
}
|
||||
fn get_script_count(&self) -> Result<usize> { Ok(1) }
|
||||
|
||||
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> {
|
||||
&self.script_source_data
|
||||
}
|
||||
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> { &self.script_source_data }
|
||||
|
||||
fn get_own_scripts(&self, scripts: &mut Vec<ScriptWrapper>) {
|
||||
scripts.push((&self.script).into());
|
||||
}
|
||||
fn get_own_scripts(&self, scripts: &mut Vec<ScriptWrapper>) { scripts.push((&self.script).into()); }
|
||||
|
||||
fn collect_scripts(&self, scripts: &mut Vec<ScriptWrapper>) -> Result<()> {
|
||||
self.get_own_scripts(scripts);
|
||||
|
|
|
@ -23,6 +23,7 @@ pub struct LearnedMove {
|
|||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[repr(u8)]
|
||||
#[cfg_attr(feature = "serde", derive(serde_repr::Serialize_repr, serde_repr::Deserialize_repr))]
|
||||
#[cfg_attr(feature = "rune", derive(rune::Any))]
|
||||
pub enum MoveLearnMethod {
|
||||
/// We do not know the learn method.
|
||||
#[default]
|
||||
|
@ -44,28 +45,18 @@ impl LearnedMove {
|
|||
}
|
||||
|
||||
/// The immutable move information of the move.
|
||||
pub fn move_data(&self) -> &Arc<dyn MoveData> {
|
||||
&self.move_data
|
||||
}
|
||||
pub fn move_data(&self) -> &Arc<dyn MoveData> { &self.move_data }
|
||||
/// The maximal power points for this move.
|
||||
pub fn max_pp(&self) -> u8 {
|
||||
self.move_data.base_usages() + self.max_pp_modification
|
||||
}
|
||||
pub fn max_pp(&self) -> u8 { self.move_data.base_usages() + self.max_pp_modification }
|
||||
|
||||
/// The amount by which the maximal power points have been modified for this move.
|
||||
/// This could for example be due to PP Ups.
|
||||
pub fn max_pp_modification(&self) -> u8 {
|
||||
self.max_pp_modification
|
||||
}
|
||||
pub fn max_pp_modification(&self) -> u8 { self.max_pp_modification }
|
||||
|
||||
/// The amount of remaining power points. If this is 0, we can not use the move anymore.
|
||||
pub fn remaining_pp(&self) -> u8 {
|
||||
self.remaining_pp.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn remaining_pp(&self) -> u8 { self.remaining_pp.load(Ordering::Relaxed) }
|
||||
/// The way the move was learned.
|
||||
pub fn learn_method(&self) -> MoveLearnMethod {
|
||||
self.learn_method
|
||||
}
|
||||
pub fn learn_method(&self) -> MoveLearnMethod { self.learn_method }
|
||||
|
||||
/// Try and reduce the PP by a certain amount. If the amount is higher than the current uses,
|
||||
/// return false. Otherwise, reduce the PP, and return true.
|
||||
|
@ -81,9 +72,7 @@ impl LearnedMove {
|
|||
}
|
||||
|
||||
/// Set the remaining PP to the max amount of PP.
|
||||
pub fn restore_all_uses(&self) {
|
||||
self.remaining_pp.store(self.max_pp(), Ordering::SeqCst);
|
||||
}
|
||||
pub fn restore_all_uses(&self) { self.remaining_pp.store(self.max_pp(), Ordering::SeqCst); }
|
||||
|
||||
/// Restore the remaining PP by a certain amount. Will prevent it from going above max PP.
|
||||
pub fn restore_uses(&self, mut uses: u8) {
|
||||
|
|
|
@ -216,21 +216,13 @@ impl Pokemon {
|
|||
}
|
||||
|
||||
/// The library data of the Pokemon.
|
||||
pub fn library(&self) -> &Arc<dyn DynamicLibrary> {
|
||||
&self.data.library
|
||||
}
|
||||
pub fn library(&self) -> &Arc<dyn DynamicLibrary> { &self.data.library }
|
||||
/// The species of the Pokemon.
|
||||
pub fn species(&self) -> Arc<dyn Species> {
|
||||
self.data.species.read().clone()
|
||||
}
|
||||
pub fn species(&self) -> Arc<dyn Species> { self.data.species.read().clone() }
|
||||
/// The form of the Pokemon.
|
||||
pub fn form(&self) -> Arc<dyn Form> {
|
||||
self.data.form.read().clone()
|
||||
}
|
||||
pub fn form(&self) -> Arc<dyn Form> { self.data.form.read().clone() }
|
||||
/// Whether or not the Pokemon is showing as a different species than it actually is.
|
||||
pub fn has_different_display_species(&self) -> bool {
|
||||
self.data.display_species.is_some()
|
||||
}
|
||||
pub fn has_different_display_species(&self) -> bool { self.data.display_species.is_some() }
|
||||
/// The species that should be displayed to the user. This handles stuff like the Illusion ability.
|
||||
pub fn display_species(&self) -> Arc<dyn Species> {
|
||||
if let Some(v) = &self.data.display_species {
|
||||
|
@ -240,9 +232,7 @@ impl Pokemon {
|
|||
}
|
||||
}
|
||||
/// Whether or not the Pokemon is showing as a different form than it actually is.
|
||||
pub fn has_different_display_form(&self) -> bool {
|
||||
self.data.display_form.is_some()
|
||||
}
|
||||
pub fn has_different_display_form(&self) -> bool { self.data.display_form.is_some() }
|
||||
/// The form that should be displayed to the user. This handles stuff like the Illusion ability.
|
||||
pub fn display_form(&self) -> Arc<dyn Form> {
|
||||
if let Some(v) = &self.data.display_form {
|
||||
|
@ -253,32 +243,20 @@ impl Pokemon {
|
|||
}
|
||||
/// The current level of the Pokemon.
|
||||
/// [See also](https://bulbapedia.bulbagarden.net/wiki/Level)
|
||||
pub fn level(&self) -> LevelInt {
|
||||
self.data.level.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn level(&self) -> LevelInt { self.data.level.load(Ordering::Relaxed) }
|
||||
/// The amount of experience of the Pokemon.
|
||||
/// [See also](https://bulbapedia.bulbagarden.net/wiki/Experience)
|
||||
pub fn experience(&self) -> u32 {
|
||||
self.data.experience.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn experience(&self) -> u32 { self.data.experience.load(Ordering::Relaxed) }
|
||||
/// The personality value of the Pokemon.
|
||||
/// [See also](https://bulbapedia.bulbagarden.net/wiki/Personality_value)
|
||||
pub fn personality_value(&self) -> u32 {
|
||||
self.data.personality_value
|
||||
}
|
||||
pub fn personality_value(&self) -> u32 { self.data.personality_value }
|
||||
/// The gender of the Pokemon.
|
||||
pub fn gender(&self) -> Gender {
|
||||
*self.data.gender.read()
|
||||
}
|
||||
pub fn gender(&self) -> Gender { *self.data.gender.read() }
|
||||
/// The coloring of the Pokemon. Value 0 is the default, value 1 means shiny. Other values are
|
||||
/// currently not used, and can be used for other implementations.
|
||||
pub fn coloring(&self) -> u8 {
|
||||
self.data.coloring
|
||||
}
|
||||
pub fn coloring(&self) -> u8 { self.data.coloring }
|
||||
/// Gets the held item of a Pokemon
|
||||
pub fn held_item(&self) -> &RwLock<Option<Arc<dyn Item>>> {
|
||||
&self.data.held_item
|
||||
}
|
||||
pub fn held_item(&self) -> Option<Arc<dyn Item>> { self.data.held_item.read().clone().map(|v| v) }
|
||||
/// Checks whether the Pokemon is holding a specific item.
|
||||
pub fn has_held_item(&self, name: &StringKey) -> bool {
|
||||
// Only true if we have an item, and the item name is the same as the requested item.
|
||||
|
@ -292,9 +270,7 @@ impl Pokemon {
|
|||
self.data.held_item.write().replace(item.clone())
|
||||
}
|
||||
/// Removes the held item from the Pokemon. Returns the previously held item.
|
||||
pub fn remove_held_item(&self) -> Option<Arc<dyn Item>> {
|
||||
self.data.held_item.write().take()
|
||||
}
|
||||
pub fn remove_held_item(&self) -> Option<Arc<dyn Item>> { self.data.held_item.write().take() }
|
||||
/// Makes the Pokemon uses its held item.
|
||||
pub fn consume_held_item(&self) -> Result<bool> {
|
||||
if self.data.held_item.read().is_none() {
|
||||
|
@ -316,72 +292,42 @@ impl Pokemon {
|
|||
}
|
||||
|
||||
/// The remaining health points of the Pokemon.
|
||||
pub fn current_health(&self) -> u32 {
|
||||
self.data.current_health.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn current_health(&self) -> u32 { self.data.current_health.load(Ordering::Relaxed) }
|
||||
/// The max health points of the Pokemon.
|
||||
pub fn max_health(&self) -> u32 {
|
||||
self.data.boosted_stats.hp()
|
||||
}
|
||||
pub fn max_health(&self) -> u32 { self.data.boosted_stats.hp() }
|
||||
/// The weight of the Pokemon in kilograms.
|
||||
pub fn weight(&self) -> f32 {
|
||||
self.data.weight.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn weight(&self) -> f32 { self.data.weight.load(Ordering::Relaxed) }
|
||||
/// Sets the weight of the Pokemon in kilograms.
|
||||
pub fn set_weight(&self, weight: f32) {
|
||||
self.data.weight.store(weight, Ordering::Relaxed)
|
||||
}
|
||||
pub fn set_weight(&self, weight: f32) { self.data.weight.store(weight, Ordering::Relaxed) }
|
||||
/// The height of the Pokemon in meters.
|
||||
pub fn height(&self) -> f32 {
|
||||
self.data.height.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn height(&self) -> f32 { self.data.height.load(Ordering::Relaxed) }
|
||||
|
||||
/// The current happiness of the Pokemon. Also known as friendship.
|
||||
pub fn happiness(&self) -> u8 {
|
||||
self.data.happiness.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn happiness(&self) -> u8 { self.data.happiness.load(Ordering::Relaxed) }
|
||||
|
||||
/// An optional nickname of the Pokemon.
|
||||
pub fn nickname(&self) -> &Option<String> {
|
||||
&self.data.nickname
|
||||
}
|
||||
pub fn nickname(&self) -> &Option<String> { &self.data.nickname }
|
||||
/// An index of the ability to find the actual ability on the form.
|
||||
pub fn real_ability(&self) -> &AbilityIndex {
|
||||
&self.data.ability_index
|
||||
}
|
||||
pub fn real_ability(&self) -> &AbilityIndex { &self.data.ability_index }
|
||||
/// The current types of the Pokemon.
|
||||
pub fn types(&self) -> RwLockReadGuard<'_, RawRwLock, Vec<TypeIdentifier>> {
|
||||
self.data.types.read()
|
||||
}
|
||||
pub fn types(&self) -> RwLockReadGuard<'_, RawRwLock, Vec<TypeIdentifier>> { self.data.types.read() }
|
||||
/// The moves the Pokemon has learned. This is of a set length of [`MAX_MOVES`]. Empty move slots
|
||||
/// are defined by None.
|
||||
pub fn learned_moves(&self) -> &RwLock<[Option<Arc<LearnedMove>>; MAX_MOVES]> {
|
||||
&self.data.moves
|
||||
}
|
||||
pub fn learned_moves(&self) -> &RwLock<[Option<Arc<LearnedMove>>; MAX_MOVES]> { &self.data.moves }
|
||||
|
||||
/// The stats of the Pokemon when disregarding any stat boosts.
|
||||
pub fn flat_stats(&self) -> &Arc<StatisticSet<u32>> {
|
||||
&self.data.flat_stats
|
||||
}
|
||||
pub fn flat_stats(&self) -> &Arc<StatisticSet<u32>> { &self.data.flat_stats }
|
||||
|
||||
/// The amount of boosts on a specific stat.
|
||||
pub fn stat_boosts(&self) -> &Arc<ClampedStatisticSet<i8, -6, 6>> {
|
||||
&self.data.stat_boost
|
||||
}
|
||||
pub fn stat_boosts(&self) -> &Arc<ClampedStatisticSet<i8, -6, 6>> { &self.data.stat_boost }
|
||||
|
||||
/// Whether or not this Pokemon is still an egg, and therefore cannot battle.
|
||||
pub fn is_egg(&self) -> bool {
|
||||
self.data.is_egg
|
||||
}
|
||||
pub fn is_egg(&self) -> bool { self.data.is_egg }
|
||||
|
||||
/// The stats of the Pokemon including the stat boosts
|
||||
pub fn boosted_stats(&self) -> &Arc<StatisticSet<u32>> {
|
||||
&self.data.boosted_stats
|
||||
}
|
||||
pub fn boosted_stats(&self) -> &Arc<StatisticSet<u32>> { &self.data.boosted_stats }
|
||||
/// Get the stat boosts for a specific stat.
|
||||
pub fn stat_boost(&self, stat: Statistic) -> i8 {
|
||||
self.data.stat_boost.get_stat(stat)
|
||||
}
|
||||
pub fn stat_boost(&self, stat: Statistic) -> i8 { self.data.stat_boost.get_stat(stat) }
|
||||
/// Change a boosted stat by a certain amount.
|
||||
pub fn change_stat_boost(&self, stat: Statistic, mut diff_amount: i8, self_inflicted: bool) -> Result<bool> {
|
||||
let mut prevent = false;
|
||||
|
@ -440,14 +386,10 @@ impl Pokemon {
|
|||
|
||||
/// Gets an individual value of the Pokemon.
|
||||
/// [See also](https://bulbapedia.bulbagarden.net/wiki/Individual_values)
|
||||
pub fn individual_values(&self) -> &Arc<ClampedStatisticSet<u8, 0, 31>> {
|
||||
&self.data.individual_values
|
||||
}
|
||||
pub fn individual_values(&self) -> &Arc<ClampedStatisticSet<u8, 0, 31>> { &self.data.individual_values }
|
||||
/// Gets an effort value of the Pokemon.
|
||||
/// [See also](https://bulbapedia.bulbagarden.net/wiki/Effort_values)
|
||||
pub fn effort_values(&self) -> &Arc<ClampedStatisticSet<u8, 0, 252>> {
|
||||
&self.data.effort_values
|
||||
}
|
||||
pub fn effort_values(&self) -> &Arc<ClampedStatisticSet<u8, 0, 252>> { &self.data.effort_values }
|
||||
|
||||
/// Gets the battle the battle is currently in.
|
||||
pub fn get_battle(&self) -> Option<Battle> {
|
||||
|
@ -469,13 +411,9 @@ impl Pokemon {
|
|||
}
|
||||
/// Get the index of the slot on the side of the battle the Pokemon is in. Only returns a value
|
||||
/// if the Pokemon is on the battlefield.
|
||||
pub fn get_battle_index(&self) -> Option<u8> {
|
||||
self.data.battle_data.read().as_ref().map(|data| data.index())
|
||||
}
|
||||
pub fn get_battle_index(&self) -> Option<u8> { self.data.battle_data.read().as_ref().map(|data| data.index()) }
|
||||
/// Returns whether something overrides the ability.
|
||||
pub fn is_ability_overriden(&self) -> bool {
|
||||
self.data.override_ability.is_some()
|
||||
}
|
||||
pub fn is_ability_overridden(&self) -> bool { self.data.override_ability.is_some() }
|
||||
/// Returns the currently active ability.
|
||||
pub fn active_ability(&self) -> Result<Arc<dyn Ability>> {
|
||||
if let Some(v) = &self.data.override_ability {
|
||||
|
@ -489,32 +427,24 @@ impl Pokemon {
|
|||
.library
|
||||
.static_data()
|
||||
.abilities()
|
||||
.get(ability)
|
||||
.get(&ability)
|
||||
.ok_or(PkmnError::InvalidAbilityName {
|
||||
ability: ability.clone(),
|
||||
})?)
|
||||
}
|
||||
|
||||
/// The script for the status.
|
||||
pub fn status(&self) -> &ScriptContainer {
|
||||
&self.data.status_script
|
||||
}
|
||||
pub fn status(&self) -> &ScriptContainer { &self.data.status_script }
|
||||
|
||||
/// Returns the script for the currently active ability.
|
||||
pub fn ability_script(&self) -> &ScriptContainer {
|
||||
&self.data.ability_script
|
||||
}
|
||||
pub fn ability_script(&self) -> &ScriptContainer { &self.data.ability_script }
|
||||
|
||||
/// Whether or not the Pokemon is allowed to gain experience.
|
||||
pub fn allowed_experience_gain(&self) -> bool {
|
||||
self.data.allowed_experience
|
||||
}
|
||||
pub fn allowed_experience_gain(&self) -> bool { self.data.allowed_experience }
|
||||
|
||||
/// The nature of the Pokemon.
|
||||
/// [See also](https://bulbapedia.bulbagarden.net/wiki/Nature)
|
||||
pub fn nature(&self) -> &Arc<dyn Nature> {
|
||||
&self.data.nature
|
||||
}
|
||||
pub fn nature(&self) -> &Arc<dyn Nature> { &self.data.nature }
|
||||
|
||||
/// Calculates the flat stats on the Pokemon. This should be called when for example the base
|
||||
/// stats, level, nature, IV, or EV changes. This has a side effect of recalculating the boosted
|
||||
|
@ -606,7 +536,7 @@ impl Pokemon {
|
|||
.set(ability_script)
|
||||
.as_ref()
|
||||
// Ensure the ability script gets initialized with the parameters for the ability.
|
||||
.on_initialize(&self.data.library, ability.parameters().to_vec());
|
||||
.on_initialize(&self.data.library, ability.parameters());
|
||||
match script_result {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
|
@ -646,14 +576,10 @@ impl Pokemon {
|
|||
}
|
||||
|
||||
/// Whether or not the Pokemon is useable in a battle.
|
||||
pub fn is_usable(&self) -> bool {
|
||||
!self.data.is_caught && !self.data.is_egg && !self.is_fainted()
|
||||
}
|
||||
pub fn is_usable(&self) -> bool { !self.data.is_caught && !self.data.is_egg && !self.is_fainted() }
|
||||
|
||||
/// Returns whether the Pokemon is fainted.
|
||||
pub fn is_fainted(&self) -> bool {
|
||||
self.current_health() == 0
|
||||
}
|
||||
pub fn is_fainted(&self) -> bool { self.current_health() == 0 }
|
||||
|
||||
/// Sets the current battle the Pokemon is in.
|
||||
pub fn set_battle_data(&self, battle: WeakBattleReference, battle_side_index: u8) {
|
||||
|
@ -836,9 +762,7 @@ impl Pokemon {
|
|||
}
|
||||
|
||||
/// Removes the current non-volatile status from the Pokemon.
|
||||
pub fn clear_status(&self) {
|
||||
self.data.status_script.clear()
|
||||
}
|
||||
pub fn clear_status(&self) { self.data.status_script.clear() }
|
||||
|
||||
/// Increases the level by a certain amount
|
||||
pub fn change_level_by(&self, amount: LevelInt) -> Result<()> {
|
||||
|
@ -858,9 +782,7 @@ impl Pokemon {
|
|||
|
||||
/// Converts the Pokemon into a serializable form.
|
||||
#[cfg(feature = "serde")]
|
||||
pub fn serialize(&self) -> Result<super::serialization::SerializedPokemon> {
|
||||
self.into()
|
||||
}
|
||||
pub fn serialize(&self) -> Result<super::serialization::SerializedPokemon> { self.into() }
|
||||
|
||||
/// Deserializes a Pokemon from a serializable form.
|
||||
#[cfg(feature = "serde")]
|
||||
|
@ -995,23 +917,17 @@ impl Pokemon {
|
|||
}
|
||||
|
||||
/// Gets the inner pointer to the reference counted data.
|
||||
pub fn as_ptr(&self) -> *const c_void {
|
||||
Arc::as_ptr(&self.data) as *const c_void
|
||||
}
|
||||
pub fn as_ptr(&self) -> *const c_void { Arc::as_ptr(&self.data) as *const c_void }
|
||||
}
|
||||
|
||||
impl PartialEq for Pokemon {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
Arc::ptr_eq(&self.data, &other.data)
|
||||
}
|
||||
fn eq(&self, other: &Self) -> bool { Arc::ptr_eq(&self.data, &other.data) }
|
||||
}
|
||||
|
||||
impl Eq for Pokemon {}
|
||||
|
||||
impl PartialEq for WeakPokemonReference {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
Weak::ptr_eq(&self.data, &other.data)
|
||||
}
|
||||
fn eq(&self, other: &Self) -> bool { Weak::ptr_eq(&self.data, &other.data) }
|
||||
}
|
||||
|
||||
impl Eq for WeakPokemonReference {}
|
||||
|
@ -1025,9 +941,8 @@ impl WeakPokemonReference {
|
|||
}
|
||||
|
||||
/// Gets the pointer to the underlying data.
|
||||
pub(crate) fn as_ptr(&self) -> *const c_void {
|
||||
self.data.as_ptr() as *const c_void
|
||||
}
|
||||
#[cfg(feature = "wasm")]
|
||||
pub(crate) fn as_ptr(&self) -> *const c_void { self.data.as_ptr() as *const c_void }
|
||||
}
|
||||
|
||||
/// The data of the Pokemon related to being in a battle.
|
||||
|
@ -1047,26 +962,16 @@ pub struct PokemonBattleData {
|
|||
|
||||
impl PokemonBattleData {
|
||||
/// The battle data of the Pokemon
|
||||
pub fn battle(&self) -> Option<Battle> {
|
||||
self.battle.upgrade()
|
||||
}
|
||||
pub fn battle(&self) -> Option<Battle> { self.battle.upgrade() }
|
||||
|
||||
/// The index of the side of the Pokemon
|
||||
pub fn battle_side_index(&self) -> u8 {
|
||||
self.battle_side_index.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn battle_side_index(&self) -> u8 { self.battle_side_index.load(Ordering::Relaxed) }
|
||||
/// The index of the slot on the side of the Pokemon.
|
||||
pub fn index(&self) -> u8 {
|
||||
self.index.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn index(&self) -> u8 { self.index.load(Ordering::Relaxed) }
|
||||
/// Whether or not the Pokemon is on the battlefield.
|
||||
pub fn on_battle_field(&self) -> bool {
|
||||
self.on_battle_field.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn on_battle_field(&self) -> bool { self.on_battle_field.load(Ordering::Relaxed) }
|
||||
/// A list of opponents the Pokemon has seen this battle.
|
||||
pub fn seen_opponents(&self) -> &RwLock<Vec<WeakPokemonReference>> {
|
||||
&self.seen_opponents
|
||||
}
|
||||
pub fn seen_opponents(&self) -> &RwLock<Vec<WeakPokemonReference>> { &self.seen_opponents }
|
||||
}
|
||||
|
||||
impl ScriptSource for Pokemon {
|
||||
|
@ -1083,9 +988,7 @@ impl ScriptSource for Pokemon {
|
|||
Ok(c)
|
||||
}
|
||||
|
||||
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> {
|
||||
&self.data.script_source_data
|
||||
}
|
||||
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> { &self.data.script_source_data }
|
||||
|
||||
fn get_own_scripts(&self, scripts: &mut Vec<ScriptWrapper>) {
|
||||
scripts.push((&self.data.held_item_trigger_script).into());
|
||||
|
@ -1109,9 +1012,7 @@ impl ScriptSource for Pokemon {
|
|||
}
|
||||
|
||||
impl VolatileScriptsOwner for Pokemon {
|
||||
fn volatile_scripts(&self) -> &Arc<ScriptSet> {
|
||||
&self.data.volatile
|
||||
}
|
||||
fn volatile_scripts(&self) -> &Arc<ScriptSet> { &self.data.volatile }
|
||||
|
||||
fn load_volatile_script(&self, key: &StringKey) -> Result<Option<Arc<dyn Script>>> {
|
||||
self.data.library.load_script(self.into(), ScriptCategory::Pokemon, key)
|
||||
|
@ -1120,6 +1021,7 @@ impl VolatileScriptsOwner for Pokemon {
|
|||
|
||||
/// A source of damage.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[cfg_attr(feature = "rune", derive(rune::Any))]
|
||||
#[repr(u8)]
|
||||
pub enum DamageSource {
|
||||
/// The damage is done by a move.
|
||||
|
|
|
@ -96,10 +96,7 @@ impl Into<anyhow_ext::Result<SerializedPokemon>> for &Pokemon {
|
|||
personality_value: self.personality_value(),
|
||||
gender: self.gender(),
|
||||
coloring: self.coloring(),
|
||||
held_item: {
|
||||
let held_item = self.held_item().read();
|
||||
held_item.as_ref().map(|held_item| held_item.name().clone())
|
||||
},
|
||||
held_item: self.held_item().map(|held_item| held_item.name().clone()),
|
||||
current_health: self.current_health(),
|
||||
weight: self.weight(),
|
||||
height: self.height(),
|
||||
|
@ -111,7 +108,7 @@ impl Into<anyhow_ext::Result<SerializedPokemon>> for &Pokemon {
|
|||
nickname: self.nickname().clone(),
|
||||
ability_index: *self.real_ability(),
|
||||
override_ability: {
|
||||
if self.is_ability_overriden() {
|
||||
if self.is_ability_overridden() {
|
||||
Some(self.active_ability()?.name().clone())
|
||||
} else {
|
||||
None
|
||||
|
|
|
@ -4,14 +4,10 @@ use std::sync::{Arc, LazyLock, Weak};
|
|||
use parking_lot::RwLock;
|
||||
|
||||
use crate::VecExt;
|
||||
#[doc(inline)]
|
||||
pub use item_script::*;
|
||||
#[doc(inline)]
|
||||
pub use script::*;
|
||||
#[doc(inline)]
|
||||
pub use script_set::*;
|
||||
#[doc(inline)]
|
||||
pub use volatile_scripts_owner::*;
|
||||
#[doc(inline)] pub use item_script::*;
|
||||
#[doc(inline)] pub use script::*;
|
||||
#[doc(inline)] pub use script_set::*;
|
||||
#[doc(inline)] pub use volatile_scripts_owner::*;
|
||||
|
||||
/// Scripts that are used for item usage
|
||||
mod item_script;
|
||||
|
@ -169,15 +165,11 @@ pub enum ScriptWrapper {
|
|||
}
|
||||
|
||||
impl From<&ScriptContainer> for ScriptWrapper {
|
||||
fn from(c: &ScriptContainer) -> Self {
|
||||
ScriptWrapper::Script(Arc::downgrade(c.arc()))
|
||||
}
|
||||
fn from(c: &ScriptContainer) -> Self { ScriptWrapper::Script(Arc::downgrade(c.arc())) }
|
||||
}
|
||||
|
||||
impl From<&Arc<ScriptSet>> for ScriptWrapper {
|
||||
fn from(c: &Arc<ScriptSet>) -> Self {
|
||||
ScriptWrapper::Set(Arc::downgrade(c))
|
||||
}
|
||||
fn from(c: &Arc<ScriptSet>) -> Self { ScriptWrapper::Set(Arc::downgrade(c)) }
|
||||
}
|
||||
|
||||
/// This struct allows for the iteration over scripts.
|
||||
|
@ -291,7 +283,6 @@ mod tests {
|
|||
use std::any::Any;
|
||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||
|
||||
use crate::dynamic_data::script_handling::script::ScriptContainer;
|
||||
use crate::StringKey;
|
||||
|
||||
use super::*;
|
||||
|
@ -323,17 +314,11 @@ mod tests {
|
|||
}
|
||||
|
||||
impl Script for TestScript {
|
||||
fn name(&self) -> Result<&StringKey> {
|
||||
Ok(&self.name)
|
||||
}
|
||||
fn name(&self) -> Result<&StringKey> { Ok(&self.name) }
|
||||
|
||||
fn get_marked_for_deletion(&self) -> &AtomicBool {
|
||||
&self.is_marked_for_deletion
|
||||
}
|
||||
fn get_marked_for_deletion(&self) -> &AtomicBool { &self.is_marked_for_deletion }
|
||||
|
||||
fn get_suppressed_count(&self) -> &AtomicUsize {
|
||||
&self.suppressed_count
|
||||
}
|
||||
fn get_suppressed_count(&self) -> &AtomicUsize { &self.suppressed_count }
|
||||
|
||||
fn add_suppression(&self) {}
|
||||
|
||||
|
@ -344,13 +329,9 @@ mod tests {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
fn as_any(&self) -> &dyn Any { self }
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any { self }
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -551,17 +532,11 @@ mod tests {
|
|||
}
|
||||
|
||||
impl ScriptSource for TestScriptSource {
|
||||
fn get_script_count(&self) -> Result<usize> {
|
||||
Ok(1)
|
||||
}
|
||||
fn get_script_count(&self) -> Result<usize> { Ok(1) }
|
||||
|
||||
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> {
|
||||
&self.data
|
||||
}
|
||||
fn get_script_source_data(&self) -> &RwLock<ScriptSourceData> { &self.data }
|
||||
|
||||
fn get_own_scripts(&self, scripts: &mut Vec<ScriptWrapper>) {
|
||||
scripts.push((&self.script).into());
|
||||
}
|
||||
fn get_own_scripts(&self, scripts: &mut Vec<ScriptWrapper>) { scripts.push((&self.script).into()); }
|
||||
|
||||
fn collect_scripts(&self, scripts: &mut Vec<ScriptWrapper>) -> Result<()> {
|
||||
self.get_own_scripts(scripts);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use anyhow::{anyhow, Result};
|
||||
use hashbrown::HashMap;
|
||||
use std::any::Any;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::ops::Deref;
|
||||
|
@ -30,97 +31,69 @@ pub trait Script: Send + Sync {
|
|||
fn get_marked_for_deletion(&self) -> &AtomicBool;
|
||||
|
||||
/// This marks the script for deletion, which will dispose of it as soon as possible.
|
||||
fn mark_for_deletion(&self) {
|
||||
self.get_marked_for_deletion().store(true, Ordering::SeqCst);
|
||||
}
|
||||
fn mark_for_deletion(&self) { self.get_marked_for_deletion().store(true, Ordering::SeqCst); }
|
||||
/// Helper function to get the value of the marked for deletion bool.
|
||||
fn is_marked_for_deletion(&self) -> bool {
|
||||
self.get_marked_for_deletion().load(Ordering::SeqCst)
|
||||
}
|
||||
fn is_marked_for_deletion(&self) -> bool { self.get_marked_for_deletion().load(Ordering::SeqCst) }
|
||||
|
||||
/// A script can be suppressed by other scripts. If a script is suppressed by at least one script
|
||||
/// we will not execute its methods. This should return the number of suppressions on the script.
|
||||
fn get_suppressed_count(&self) -> &AtomicUsize;
|
||||
/// Helper function to check if there is at least one suppression on the script
|
||||
fn is_suppressed(&self) -> bool {
|
||||
self.get_suppressed_count().load(Ordering::SeqCst) > 0
|
||||
}
|
||||
fn is_suppressed(&self) -> bool { self.get_suppressed_count().load(Ordering::SeqCst) > 0 }
|
||||
/// Adds a suppression. This makes the script not run anymore. Note that adding this should also
|
||||
/// remove the suppression later.
|
||||
///
|
||||
/// A common pattern for this is to run this in the [`Self::on_initialize`] function, and run the
|
||||
/// remove in the [`Self::on_remove`] function.
|
||||
fn add_suppression(&self) {
|
||||
self.get_suppressed_count().fetch_add(1, Ordering::SeqCst);
|
||||
}
|
||||
fn add_suppression(&self) { self.get_suppressed_count().fetch_add(1, Ordering::SeqCst); }
|
||||
/// Removes a suppression. This allows the script to run again (provided other scripts are not
|
||||
/// suppressing it). Note that running this should only occur if an add was run before.
|
||||
fn remove_suppression(&self) {
|
||||
self.get_suppressed_count().fetch_sub(1, Ordering::SeqCst);
|
||||
}
|
||||
fn remove_suppression(&self) { self.get_suppressed_count().fetch_sub(1, Ordering::SeqCst); }
|
||||
|
||||
/// This function is ran when a volatile effect is added while that volatile effect already is
|
||||
/// in place. Instead of adding the volatile effect twice, it will execute this function instead.
|
||||
fn stack(&self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn stack(&self) -> Result<()> { Ok(()) }
|
||||
/// This function is ran when this script stops being in effect, and is removed from its owner.
|
||||
fn on_remove(&self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn on_remove(&self) -> Result<()> { Ok(()) }
|
||||
/// This function is ran when this script starts being in effect.
|
||||
fn on_initialize(&self, _library: &Arc<dyn DynamicLibrary>, _pars: Vec<Arc<Parameter>>) -> Result<()> {
|
||||
fn on_initialize(
|
||||
&self,
|
||||
_library: &Arc<dyn DynamicLibrary>,
|
||||
_pars: &HashMap<StringKey, Arc<Parameter>>,
|
||||
) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
/// This function is ran just before the start of the turn. Everyone has made its choices here,
|
||||
/// and the turn is about to start. This is a great place to initialize data if you need to know
|
||||
/// something has happened during a turn.
|
||||
fn on_before_turn(&self, _choice: &Arc<TurnChoice>) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn on_before_turn(&self, _choice: &Arc<TurnChoice>) -> Result<()> { Ok(()) }
|
||||
/// This function allows you to modify the effective speed of the Pokemon. This is ran before
|
||||
/// turn ordering, so overriding here will allow you to put certain Pokemon before others.
|
||||
fn change_speed(&self, _choice: &Arc<TurnChoice>, _speed: &mut u32) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn change_speed(&self, _choice: &Arc<TurnChoice>, _speed: &mut u32) -> Result<()> { Ok(()) }
|
||||
/// This function allows you to modify the effective priority of the Pokemon. This is ran before
|
||||
/// turn ordering, so overriding here will allow you to put certain Pokemon before others. Note
|
||||
/// that this is only relevant on move choices, as other turn choice types do not have a priority.
|
||||
fn change_priority(&self, _choice: &Arc<TurnChoice>, _priority: &mut i8) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn change_priority(&self, _choice: &Arc<TurnChoice>, _priority: &mut i8) -> Result<()> { Ok(()) }
|
||||
|
||||
/// This function allows you to change the move that is used during execution. This is useful for
|
||||
/// moves such as metronome, where the move chosen actually differs from the move used.
|
||||
fn change_move(&self, _choice: &Arc<TurnChoice>, _move_name: &mut StringKey) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn change_move(&self, _choice: &Arc<TurnChoice>, _move_name: &mut StringKey) -> Result<()> { Ok(()) }
|
||||
/// This function allows you to change a move into a multi-hit move. The number of hits set here
|
||||
/// gets used as the number of hits. If set to 0, this will behave as if the move missed on its
|
||||
/// first hit.
|
||||
fn change_number_of_hits(&self, _choice: &Arc<TurnChoice>, _number_of_hits: &mut u8) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn change_number_of_hits(&self, _choice: &Arc<TurnChoice>, _number_of_hits: &mut u8) -> Result<()> { Ok(()) }
|
||||
|
||||
/// This function allows you to prevent a move from running. If this gets set to true, the move
|
||||
/// ends execution here. No PP will be decreased in this case.
|
||||
fn prevent_move(&self, _move: &Arc<ExecutingMove>, _prevent: &mut bool) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn prevent_move(&self, _move: &Arc<ExecutingMove>, _prevent: &mut bool) -> Result<()> { Ok(()) }
|
||||
/// This function makes the move fail. If the fail field gets set to true, the move ends execution,
|
||||
/// and fail events get triggered.
|
||||
fn fail_move(&self, _move: &Arc<ExecutingMove>, _fail: &mut bool) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn fail_move(&self, _move: &Arc<ExecutingMove>, _fail: &mut bool) -> Result<()> { Ok(()) }
|
||||
/// Similar to [`Self::prevent_move`]. This function will also stop execution, but PP will be
|
||||
/// decreased.
|
||||
fn stop_before_move(&self, _move: &Arc<ExecutingMove>, _stop: &mut bool) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn stop_before_move(&self, _move: &Arc<ExecutingMove>, _stop: &mut bool) -> Result<()> { Ok(()) }
|
||||
/// This function runs just before the move starts its execution.
|
||||
fn on_before_move(&self, _move: &Arc<ExecutingMove>) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn on_before_move(&self, _move: &Arc<ExecutingMove>) -> Result<()> { Ok(()) }
|
||||
/// This function allows a script to prevent a move that is targeted at its owner. If set to true
|
||||
/// the move fails, and fail events get triggered.
|
||||
fn fail_incoming_move(&self, _move: &Arc<ExecutingMove>, _target: &Pokemon, _fail: &mut bool) -> Result<()> {
|
||||
|
@ -132,9 +105,7 @@ pub trait Script: Send + Sync {
|
|||
}
|
||||
/// This function occurs when a move gets missed. This runs on the scripts belonging to the executing
|
||||
/// move, which include the scripts that are attached to the owner of the script.
|
||||
fn on_move_miss(&self, _move: &Arc<ExecutingMove>, _target: &Pokemon) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn on_move_miss(&self, _move: &Arc<ExecutingMove>, _target: &Pokemon) -> Result<()> { Ok(()) }
|
||||
/// This function allows the script to change the actual type that is used for the move on a target.
|
||||
fn change_move_type(
|
||||
&self,
|
||||
|
@ -308,13 +279,9 @@ pub trait Script: Send + Sync {
|
|||
}
|
||||
/// This function triggers when an incoming hit happens. This triggers after the damage is done,
|
||||
/// but before the secondary effect of the move happens.
|
||||
fn on_incoming_hit(&self, _move: &Arc<ExecutingMove>, _target: &Pokemon, _hit: u8) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn on_incoming_hit(&self, _move: &Arc<ExecutingMove>, _target: &Pokemon, _hit: u8) -> Result<()> { Ok(()) }
|
||||
/// This function triggers when an opponent on the field faints.
|
||||
fn on_opponent_faints(&self, _move: &Arc<ExecutingMove>, _target: &Pokemon, _hit: u8) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn on_opponent_faints(&self, _move: &Arc<ExecutingMove>, _target: &Pokemon, _hit: u8) -> Result<()> { Ok(()) }
|
||||
/// This function allows a script attached to a Pokemon or its parents to prevent stat boost
|
||||
/// changes on that Pokemon.
|
||||
fn prevent_stat_boost_change(
|
||||
|
@ -380,61 +347,37 @@ pub trait Script: Send + Sync {
|
|||
/// This function triggers when the move uses its secondary effect. Moves should implement their
|
||||
/// secondary effects here. Status moves should implement their actual functionality in this
|
||||
/// function as well, as status moves effects are defined as secondary effects for simplicity.
|
||||
fn on_secondary_effect(&self, _move: &Arc<ExecutingMove>, _target: &Pokemon, _hit: u8) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn on_secondary_effect(&self, _move: &Arc<ExecutingMove>, _target: &Pokemon, _hit: u8) -> Result<()> { Ok(()) }
|
||||
/// This function triggers on a move or its parents when all hits on a target are finished.
|
||||
fn on_after_hits(&self, _move: &Arc<ExecutingMove>, _target: &Pokemon) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn on_after_hits(&self, _move: &Arc<ExecutingMove>, _target: &Pokemon) -> Result<()> { Ok(()) }
|
||||
/// This function prevents the Pokemon it is attached to from being able to switch out.
|
||||
fn prevent_self_switch(&self, _choice: &Arc<TurnChoice>, _prevent: &mut bool) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn prevent_self_switch(&self, _choice: &Arc<TurnChoice>, _prevent: &mut bool) -> Result<()> { Ok(()) }
|
||||
/// This function allows the prevention of switching for any opponent.
|
||||
fn prevent_opponent_switch(&self, _choice: &Arc<TurnChoice>, _prevent: &mut bool) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn prevent_opponent_switch(&self, _choice: &Arc<TurnChoice>, _prevent: &mut bool) -> Result<()> { Ok(()) }
|
||||
/// This function is called on a move and its parents when the move fails.
|
||||
fn on_fail(&self, _target: &Pokemon) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn on_fail(&self, _target: &Pokemon) -> Result<()> { Ok(()) }
|
||||
/// This function is called on a script when an opponent fails.
|
||||
fn on_opponent_fail(&self, _target: &Pokemon) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn on_opponent_fail(&self, _target: &Pokemon) -> Result<()> { Ok(()) }
|
||||
/// This function allows preventing the running away of the Pokemon its attached to
|
||||
fn prevent_self_run_away(&self, _choice: &Arc<TurnChoice>, _prevent: &mut bool) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn prevent_self_run_away(&self, _choice: &Arc<TurnChoice>, _prevent: &mut bool) -> Result<()> { Ok(()) }
|
||||
/// This function prevents a Pokemon on another side than where its attached to from running away.
|
||||
fn prevent_opponent_run_away(&self, _choice: &Arc<TurnChoice>, _prevent: &mut bool) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn prevent_opponent_run_away(&self, _choice: &Arc<TurnChoice>, _prevent: &mut bool) -> Result<()> { Ok(()) }
|
||||
/// This function id triggered on all scripts active in the battle after all choices have finished
|
||||
/// running. Note that choices are not active anymore here, so their scripts do not call this
|
||||
/// function.
|
||||
fn on_end_turn(&self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn on_end_turn(&self) -> Result<()> { Ok(()) }
|
||||
/// This function is triggered on a Pokemon and its parents when the given Pokemon takes damage.
|
||||
fn on_damage(&self, _pokemon: &Pokemon, _source: DamageSource, _old_health: u32, _new_health: u32) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
/// This function is triggered on a Pokemon and its parents when the given Pokemon faints.
|
||||
fn on_faint(&self, _pokemon: &Pokemon, _source: DamageSource) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn on_faint(&self, _pokemon: &Pokemon, _source: DamageSource) -> Result<()> { Ok(()) }
|
||||
/// This function is triggered on a Pokemon and its parents when the given Pokemon is switched into
|
||||
/// the battlefield.
|
||||
fn on_switch_in(&self, _pokemon: &Pokemon) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn on_switch_in(&self, _pokemon: &Pokemon) -> Result<()> { Ok(()) }
|
||||
/// This function is triggered on a Pokemon and its parents when the given Pokemon consumes the
|
||||
/// held item it had.
|
||||
fn on_after_held_item_consume(&self, _pokemon: &Pokemon, _item: &Arc<dyn Item>) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn on_after_held_item_consume(&self, _pokemon: &Pokemon, _item: &Arc<dyn Item>) -> Result<()> { Ok(()) }
|
||||
/// This function is triggered on a Pokemon and its parents when the given Pokemon gains experience,
|
||||
/// and allows for changing this amount of experience.
|
||||
fn change_experience_gained(
|
||||
|
@ -452,9 +395,7 @@ pub trait Script: Send + Sync {
|
|||
}
|
||||
/// This function is triggered on a battle and its parents when something attempts to change the
|
||||
/// weather, and allows for blocking the weather change.
|
||||
fn block_weather(&self, _battle: &Battle, _blocked: &mut bool) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn block_weather(&self, _battle: &Battle, _blocked: &mut bool) -> Result<()> { Ok(()) }
|
||||
/// This function is called when a Pokeball is thrown at a Pokemon, and allows modifying the catch
|
||||
/// rate of this attempt. Pokeball modifier effects should be implemented here, as well as for
|
||||
/// example status effects that change capture rates.
|
||||
|
@ -474,9 +415,7 @@ pub trait Script: Send + Sync {
|
|||
}
|
||||
|
||||
impl Debug for dyn Script {
|
||||
fn fmt(&self, _f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
Ok(())
|
||||
}
|
||||
fn fmt(&self, _f: &mut Formatter<'_>) -> std::fmt::Result { Ok(()) }
|
||||
}
|
||||
|
||||
/// A script holder defines the underlying type of how we store individual scripts on a script source.
|
||||
|
@ -574,14 +513,10 @@ impl ScriptContainer {
|
|||
}
|
||||
|
||||
/// Gets the underlying reference counter to the script.
|
||||
pub fn arc(&self) -> &ScriptHolder {
|
||||
&self.script
|
||||
}
|
||||
pub fn arc(&self) -> &ScriptHolder { &self.script }
|
||||
|
||||
/// Whether or not the script is set.
|
||||
pub fn is_any(&self) -> bool {
|
||||
self.script.read().is_some()
|
||||
}
|
||||
pub fn is_any(&self) -> bool { self.script.read().is_some() }
|
||||
|
||||
/// Get the underlying script as the downcasted value.
|
||||
pub fn get_as<T: 'static>(&self) -> Result<MappedRwLockReadGuard<T>> {
|
||||
|
@ -619,7 +554,7 @@ impl Clone for ScriptContainer {
|
|||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
use std::sync::atomic::{AtomicBool, AtomicPtr};
|
||||
use std::sync::atomic::AtomicPtr;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
@ -646,29 +581,19 @@ mod tests {
|
|||
unsafe impl Send for TestScript {}
|
||||
|
||||
impl Script for TestScript {
|
||||
fn name(&self) -> Result<&StringKey> {
|
||||
Ok(&self.name)
|
||||
}
|
||||
fn name(&self) -> Result<&StringKey> { Ok(&self.name) }
|
||||
|
||||
fn get_marked_for_deletion(&self) -> &AtomicBool {
|
||||
&self.marked_for_deletion
|
||||
}
|
||||
fn get_marked_for_deletion(&self) -> &AtomicBool { &self.marked_for_deletion }
|
||||
|
||||
fn get_suppressed_count(&self) -> &AtomicUsize {
|
||||
&self.suppressed_count
|
||||
}
|
||||
fn get_suppressed_count(&self) -> &AtomicUsize { &self.suppressed_count }
|
||||
|
||||
fn stack(&self) -> Result<()> {
|
||||
unsafe { self.container.load(Ordering::Relaxed).as_ref().unwrap().clear() }
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
fn as_any(&self) -> &dyn Any { self }
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any { self }
|
||||
}
|
||||
|
||||
// Removing yourself while active should be completely valid for a script. Consider for example
|
||||
|
@ -726,24 +651,14 @@ mod tests {
|
|||
unsafe impl Send for ReplaceTestScript {}
|
||||
|
||||
impl Script for ReplaceTestScript {
|
||||
fn name(&self) -> Result<&StringKey> {
|
||||
Ok(&self.name)
|
||||
}
|
||||
fn name(&self) -> Result<&StringKey> { Ok(&self.name) }
|
||||
|
||||
fn get_marked_for_deletion(&self) -> &AtomicBool {
|
||||
&self.marked_for_deletion
|
||||
}
|
||||
fn get_marked_for_deletion(&self) -> &AtomicBool { &self.marked_for_deletion }
|
||||
|
||||
fn get_suppressed_count(&self) -> &AtomicUsize {
|
||||
&self.suppressed_count
|
||||
}
|
||||
fn get_suppressed_count(&self) -> &AtomicUsize { &self.suppressed_count }
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
fn as_any(&self) -> &dyn Any { self }
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any { self }
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -793,19 +708,13 @@ pub enum ScriptOwnerData {
|
|||
}
|
||||
|
||||
impl From<&Pokemon> for ScriptOwnerData {
|
||||
fn from(p: &Pokemon) -> Self {
|
||||
ScriptOwnerData::Pokemon(p.weak())
|
||||
}
|
||||
fn from(p: &Pokemon) -> Self { ScriptOwnerData::Pokemon(p.weak()) }
|
||||
}
|
||||
|
||||
impl From<&BattleSide> for ScriptOwnerData {
|
||||
fn from(p: &BattleSide) -> Self {
|
||||
ScriptOwnerData::BattleSide(p.weak())
|
||||
}
|
||||
fn from(p: &BattleSide) -> Self { ScriptOwnerData::BattleSide(p.weak()) }
|
||||
}
|
||||
|
||||
impl From<&Battle> for ScriptOwnerData {
|
||||
fn from(p: &Battle) -> Self {
|
||||
ScriptOwnerData::Battle(p.weak())
|
||||
}
|
||||
fn from(p: &Battle) -> Self { ScriptOwnerData::Battle(p.weak()) }
|
||||
}
|
||||
|
|
|
@ -78,16 +78,12 @@ extern "C" fn pokemon_display_form(handle: FFIHandle<Pokemon>) -> FFIHandle<Arc<
|
|||
/// The level of the Pokemon.
|
||||
/// [See also](https://bulbapedia.bulbagarden.net/wiki/Level)
|
||||
#[no_mangle]
|
||||
extern "C" fn pokemon_level(handle: FFIHandle<Pokemon>) -> LevelInt {
|
||||
handle.from_ffi_handle().level()
|
||||
}
|
||||
extern "C" fn pokemon_level(handle: FFIHandle<Pokemon>) -> LevelInt { handle.from_ffi_handle().level() }
|
||||
|
||||
/// The experience of the Pokemon.
|
||||
/// [See also](https://bulbapedia.bulbagarden.net/wiki/Experience)
|
||||
#[no_mangle]
|
||||
extern "C" fn pokemon_experience(handle: FFIHandle<Pokemon>) -> u32 {
|
||||
handle.from_ffi_handle().experience()
|
||||
}
|
||||
extern "C" fn pokemon_experience(handle: FFIHandle<Pokemon>) -> u32 { handle.from_ffi_handle().experience() }
|
||||
|
||||
/// The personality value of the Pokemon.
|
||||
/// [See also](https://bulbapedia.bulbagarden.net/wiki/Personality_value)
|
||||
|
@ -98,21 +94,17 @@ extern "C" fn pokemon_personality_value(handle: FFIHandle<Pokemon>) -> u32 {
|
|||
|
||||
/// The gender of the Pokemon.
|
||||
#[no_mangle]
|
||||
extern "C" fn pokemon_gender(handle: FFIHandle<Pokemon>) -> Gender {
|
||||
handle.from_ffi_handle().gender()
|
||||
}
|
||||
extern "C" fn pokemon_gender(handle: FFIHandle<Pokemon>) -> Gender { handle.from_ffi_handle().gender() }
|
||||
|
||||
/// The coloring of the Pokemon. If this is 1, the Pokemon is shiny, otherwise it is not. This can
|
||||
/// also be used for other custom coloring schemes.
|
||||
#[no_mangle]
|
||||
extern "C" fn pokemon_coloring(handle: FFIHandle<Pokemon>) -> u8 {
|
||||
handle.from_ffi_handle().coloring()
|
||||
}
|
||||
extern "C" fn pokemon_coloring(handle: FFIHandle<Pokemon>) -> u8 { handle.from_ffi_handle().coloring() }
|
||||
|
||||
/// Gets the held item of a Pokemon
|
||||
#[no_mangle]
|
||||
extern "C" fn pokemon_held_item(handle: FFIHandle<Pokemon>) -> FFIHandle<Arc<dyn Item>> {
|
||||
if let Some(v) = handle.from_ffi_handle().held_item().read().as_ref() {
|
||||
if let Some(v) = handle.from_ffi_handle().held_item() {
|
||||
FFIHandle::get_handle(v.clone().into())
|
||||
} else {
|
||||
FFIHandle::none()
|
||||
|
@ -160,27 +152,19 @@ extern "C" fn pokemon_consume_held_item(handle: FFIHandle<Pokemon>) -> FFIResult
|
|||
|
||||
/// The current health of the Pokemon.
|
||||
#[no_mangle]
|
||||
extern "C" fn pokemon_current_health(handle: FFIHandle<Pokemon>) -> u32 {
|
||||
handle.from_ffi_handle().current_health()
|
||||
}
|
||||
extern "C" fn pokemon_current_health(handle: FFIHandle<Pokemon>) -> u32 { handle.from_ffi_handle().current_health() }
|
||||
|
||||
/// The max health of the Pokemon.
|
||||
#[no_mangle]
|
||||
extern "C" fn pokemon_max_health(handle: FFIHandle<Pokemon>) -> u32 {
|
||||
handle.from_ffi_handle().max_health()
|
||||
}
|
||||
extern "C" fn pokemon_max_health(handle: FFIHandle<Pokemon>) -> u32 { handle.from_ffi_handle().max_health() }
|
||||
|
||||
/// The current weight of the Pokemon.
|
||||
#[no_mangle]
|
||||
extern "C" fn pokemon_weight(handle: FFIHandle<Pokemon>) -> f32 {
|
||||
handle.from_ffi_handle().weight()
|
||||
}
|
||||
extern "C" fn pokemon_weight(handle: FFIHandle<Pokemon>) -> f32 { handle.from_ffi_handle().weight() }
|
||||
|
||||
/// The current height of the Pokemon.
|
||||
#[no_mangle]
|
||||
extern "C" fn pokemon_height(handle: FFIHandle<Pokemon>) -> f32 {
|
||||
handle.from_ffi_handle().height()
|
||||
}
|
||||
extern "C" fn pokemon_height(handle: FFIHandle<Pokemon>) -> f32 { handle.from_ffi_handle().height() }
|
||||
|
||||
/// An optional nickname of the Pokemon.
|
||||
#[no_mangle]
|
||||
|
@ -211,9 +195,7 @@ extern "C" fn pokemon_real_ability_index(handle: FFIHandle<Pokemon>) -> u8 {
|
|||
|
||||
/// The amount of types the Pokemon has.
|
||||
#[no_mangle]
|
||||
extern "C" fn pokemon_types_length(ptr: FFIHandle<Pokemon>) -> usize {
|
||||
ptr.from_ffi_handle().types().len()
|
||||
}
|
||||
extern "C" fn pokemon_types_length(ptr: FFIHandle<Pokemon>) -> usize { ptr.from_ffi_handle().types().len() }
|
||||
|
||||
/// Gets a type of the Pokemon.
|
||||
#[no_mangle]
|
||||
|
@ -328,7 +310,7 @@ extern "C" fn pokemon_get_battle_index(handle: FFIHandle<Pokemon>) -> u8 {
|
|||
/// Returns whether something overrides the ability.
|
||||
#[no_mangle]
|
||||
extern "C" fn pokemon_is_ability_overriden(handle: FFIHandle<Pokemon>) -> u8 {
|
||||
u8::from(handle.from_ffi_handle().is_ability_overriden())
|
||||
u8::from(handle.from_ffi_handle().is_ability_overridden())
|
||||
}
|
||||
|
||||
/// Returns the currently active ability.
|
||||
|
@ -388,15 +370,11 @@ extern "C" fn pokemon_change_form(handle: FFIHandle<Pokemon>, form: FFIHandle<Ar
|
|||
|
||||
/// Whether or not the Pokemon is useable in a battle.
|
||||
#[no_mangle]
|
||||
extern "C" fn pokemon_is_usable(handle: FFIHandle<Pokemon>) -> u8 {
|
||||
u8::from(handle.from_ffi_handle().is_usable())
|
||||
}
|
||||
extern "C" fn pokemon_is_usable(handle: FFIHandle<Pokemon>) -> u8 { u8::from(handle.from_ffi_handle().is_usable()) }
|
||||
|
||||
/// Returns whether the Pokemon is fainted.
|
||||
#[no_mangle]
|
||||
extern "C" fn pokemon_is_fainted(handle: FFIHandle<Pokemon>) -> u8 {
|
||||
u8::from(handle.from_ffi_handle().is_fainted())
|
||||
}
|
||||
extern "C" fn pokemon_is_fainted(handle: FFIHandle<Pokemon>) -> u8 { u8::from(handle.from_ffi_handle().is_fainted()) }
|
||||
|
||||
/// Whether or not the Pokemon is on the battlefield.
|
||||
#[no_mangle]
|
||||
|
@ -447,9 +425,7 @@ extern "C" fn pokemon_learn_move(
|
|||
|
||||
/// Removes the current non-volatile status from the Pokemon.
|
||||
#[no_mangle]
|
||||
extern "C" fn pokemon_clear_status(handle: FFIHandle<Pokemon>) {
|
||||
handle.from_ffi_handle().clear_status()
|
||||
}
|
||||
extern "C" fn pokemon_clear_status(handle: FFIHandle<Pokemon>) { handle.from_ffi_handle().clear_status() }
|
||||
|
||||
/// Returns a serialized version of the Pokemon as xml.
|
||||
#[cfg(feature = "serde")]
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use crate::ffi::FFIHandle;
|
||||
use crate::ffi::FromFFIHandle;
|
||||
use crate::ffi::{FFIHandle, NonOwnedPtrString};
|
||||
use crate::ffi::{FFIResult, OwnedPtrString};
|
||||
use crate::static_data::{Ability, AbilityImpl, Parameter};
|
||||
use crate::StringKey;
|
||||
use anyhow::anyhow;
|
||||
use hashbrown::HashMap;
|
||||
use std::ffi::{c_char, CStr, CString};
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -12,13 +13,18 @@ use std::sync::Arc;
|
|||
unsafe extern "C" fn ability_new(
|
||||
name: *const c_char,
|
||||
effect: *const c_char,
|
||||
parameter_keys: *const NonOwnedPtrString,
|
||||
parameters: *const FFIHandle<Arc<Parameter>>,
|
||||
parameters_length: usize,
|
||||
) -> FFIResult<FFIHandle<Arc<dyn Ability>>> {
|
||||
let parameter_keys = std::slice::from_raw_parts(parameter_keys, parameters_length);
|
||||
let parameters = std::slice::from_raw_parts(parameters, parameters_length);
|
||||
let mut parameters_vec: Vec<Arc<Parameter>> = Vec::with_capacity(parameters_length);
|
||||
for parameter in parameters {
|
||||
parameters_vec.push(parameter.from_ffi_handle());
|
||||
let mut parameters_map: HashMap<StringKey, Arc<Parameter>> = HashMap::with_capacity(parameters_length);
|
||||
for (index, parameter) in parameters.iter().enumerate() {
|
||||
parameters_map.insert(
|
||||
CStr::from_ptr(parameter_keys[index]).into(),
|
||||
parameter.from_ffi_handle(),
|
||||
);
|
||||
}
|
||||
|
||||
let name: StringKey = match CStr::from_ptr(name).to_str() {
|
||||
|
@ -30,7 +36,7 @@ unsafe extern "C" fn ability_new(
|
|||
Err(_) => return FFIResult::err(anyhow!("Failed to convert effect to CStr")),
|
||||
};
|
||||
|
||||
let arc: Arc<dyn Ability> = Arc::new(AbilityImpl::new(&name, &effect, parameters_vec));
|
||||
let arc: Arc<dyn Ability> = Arc::new(AbilityImpl::new(&name, &effect, parameters_map));
|
||||
FFIResult::ok(FFIHandle::get_handle(arc.into()))
|
||||
}
|
||||
|
||||
|
@ -62,9 +68,10 @@ unsafe extern "C" fn ability_parameter_length(ptr: FFIHandle<Arc<dyn Ability>>)
|
|||
#[no_mangle]
|
||||
unsafe extern "C" fn ability_parameter_get(
|
||||
ptr: FFIHandle<Arc<dyn Ability>>,
|
||||
index: usize,
|
||||
name: NonOwnedPtrString,
|
||||
) -> FFIHandle<Arc<Parameter>> {
|
||||
if let Some(p) = ptr.from_ffi_handle().parameters().get(index) {
|
||||
let string: StringKey = CStr::from_ptr(name).into();
|
||||
if let Some(p) = ptr.from_ffi_handle().parameters().get(&string) {
|
||||
FFIHandle::get_handle(p.clone().into())
|
||||
} else {
|
||||
FFIHandle::none()
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::static_data::{
|
|||
};
|
||||
use crate::StringKey;
|
||||
use anyhow::anyhow;
|
||||
use hashbrown::HashSet;
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use std::ffi::{c_char, CStr, CString};
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -99,13 +99,16 @@ unsafe extern "C" fn move_data_has_flag(ptr: FFIHandle<Arc<dyn MoveData>>, flag:
|
|||
unsafe extern "C" fn secondary_effect_new(
|
||||
chance: f32,
|
||||
effect_name: NonOwnedPtrString,
|
||||
parameter_keys: *const NonOwnedPtrString,
|
||||
parameters: *mut FFIHandle<Arc<Parameter>>,
|
||||
parameters_length: usize,
|
||||
) -> FFIHandle<Box<dyn SecondaryEffect>> {
|
||||
let parameter_key_slice = std::slice::from_raw_parts(parameter_keys, parameters_length);
|
||||
let parameter_slice = std::slice::from_raw_parts(parameters, parameters_length);
|
||||
let mut parameters = Vec::with_capacity(parameters_length);
|
||||
for parameter in parameter_slice {
|
||||
parameters.push(parameter.from_ffi_handle())
|
||||
let mut parameters = HashMap::with_capacity(parameters_length);
|
||||
for (index, parameter) in parameter_slice.iter().enumerate() {
|
||||
let key = CStr::from_ptr(parameter_key_slice[index]).into();
|
||||
parameters.insert(key, parameter.from_ffi_handle());
|
||||
}
|
||||
|
||||
let b: Arc<dyn SecondaryEffect> = Arc::new(SecondaryEffectImpl::new(
|
||||
|
@ -146,9 +149,10 @@ unsafe extern "C" fn secondary_effect_parameter_length(ptr: FFIHandle<Arc<dyn Se
|
|||
#[no_mangle]
|
||||
unsafe extern "C" fn secondary_effect_parameter_get(
|
||||
ptr: FFIHandle<Arc<dyn SecondaryEffect>>,
|
||||
index: usize,
|
||||
name: NonOwnedPtrString,
|
||||
) -> FFIHandle<Arc<Parameter>> {
|
||||
if let Some(v) = ptr.from_ffi_handle().parameters().get(index) {
|
||||
let string: StringKey = CStr::from_ptr(name).into();
|
||||
if let Some(v) = ptr.from_ffi_handle().parameters().get(&string) {
|
||||
FFIHandle::get_handle(v.clone().into())
|
||||
} else {
|
||||
FFIHandle::none()
|
||||
|
|
|
@ -9,8 +9,9 @@
|
|||
#![allow(hidden_glob_reexports)]
|
||||
#![allow(clippy::arc_with_non_send_sync)]
|
||||
// Documentation linters
|
||||
#![deny(missing_docs)]
|
||||
#![deny(clippy::missing_docs_in_private_items)]
|
||||
// FIXME: Enable these before committing
|
||||
// #![deny(missing_docs)]
|
||||
// #![deny(clippy::missing_docs_in_private_items)]
|
||||
// Linter rules to prevent panics
|
||||
// Currently still a WIP to fix all of these
|
||||
#![deny(clippy::unwrap_used)]
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
/// The WASM module handles loading dynamic scripts through WebAssembly.
|
||||
#[cfg(feature = "wasm")]
|
||||
pub mod wasm;
|
||||
|
||||
/// The Rune module handles loading dynamic scripts through the Rune language.
|
||||
#[cfg(feature = "rune")]
|
||||
pub mod rune;
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
use rune::Hash;
|
||||
|
||||
mod script;
|
||||
pub mod script_resolver;
|
||||
mod wrappers;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
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,143 @@
|
|||
use crate::dynamic_data::{DynamicLibrary, ExecutingMove, Pokemon, Script, 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 rune::runtime::{RuntimeContext, VmError, VmResult};
|
||||
use rune::{Unit, Value};
|
||||
use std::convert::TryFrom;
|
||||
use std::sync::atomic::{AtomicBool, AtomicUsize};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct RuneScript {
|
||||
name: StringKey,
|
||||
state: Value,
|
||||
/// 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,
|
||||
|
||||
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: Value,
|
||||
script_type: Arc<RuneScriptType>,
|
||||
runtime: Arc<RuntimeContext>,
|
||||
unit: Arc<Unit>,
|
||||
) -> Self {
|
||||
Self {
|
||||
name,
|
||||
state: object,
|
||||
marked_for_deletion: Default::default(),
|
||||
suppressed_count: Default::default(),
|
||||
script_type,
|
||||
runtime,
|
||||
unit,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_state(&self) -> Value { self.state.clone() }
|
||||
}
|
||||
|
||||
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 binding = self.state.clone().into_struct()?;
|
||||
let state = binding.data_mut();
|
||||
for par in pars {
|
||||
let key = rune::alloc::string::String::try_from(par.0.str())?;
|
||||
state.insert(key, parameter_to_rune_value(par.1.as_ref())?)?;
|
||||
}
|
||||
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_int_reference(*speed as i64)?;
|
||||
|
||||
let res = vm
|
||||
.execute(
|
||||
hash,
|
||||
vec![
|
||||
rune::to_value(self.state.clone())?,
|
||||
rune::to_value(choice.wrap())?,
|
||||
speed_handle.clone(),
|
||||
],
|
||||
)?
|
||||
.complete();
|
||||
if let VmResult::Err(e) = res {
|
||||
return Err(anyhow::anyhow!("Error executing script: {}", e));
|
||||
}
|
||||
|
||||
*speed = get_int_reference_value(speed_handle)? as u32;
|
||||
}
|
||||
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());
|
||||
let block_critical_handle = wrap_bool_reference(*block_critical)?;
|
||||
|
||||
vm.execute(
|
||||
hash,
|
||||
vec![
|
||||
self.state.clone(),
|
||||
move_data.wrap(),
|
||||
target.wrap(),
|
||||
rune::to_value(hit)?,
|
||||
block_critical_handle.clone(),
|
||||
],
|
||||
)?;
|
||||
*block_critical = get_bool_reference_value(block_critical_handle)?;
|
||||
}
|
||||
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,193 @@
|
|||
use crate::dynamic_data::{ItemScript, Script, ScriptCategory, ScriptOwnerData, ScriptResolver};
|
||||
use crate::script_implementations::rune::script::RuneScript;
|
||||
use crate::script_implementations::rune::wrappers::RuneWrapper;
|
||||
use crate::script_implementations::rune::RuneScriptType;
|
||||
use crate::static_data::Item;
|
||||
use crate::StringKey;
|
||||
use hashbrown::HashMap;
|
||||
use rune::compile::meta::AssociatedKind;
|
||||
use rune::compile::{ComponentRef, MetaError};
|
||||
use rune::diagnostics::Diagnostic;
|
||||
use rune::runtime::RuntimeContext;
|
||||
use rune::{Context, Diagnostics, Options, Source, Sources, Unit};
|
||||
use std::any::Any;
|
||||
use std::convert::TryFrom;
|
||||
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 mut o = rune::runtime::Object::new();
|
||||
|
||||
let owner_obj = match owner {
|
||||
ScriptOwnerData::Pokemon(p) => Some(p.upgrade().unwrap().wrap()),
|
||||
ScriptOwnerData::BattleSide(_) => None, //FIXME
|
||||
ScriptOwnerData::Battle(_) => None, //FIXME
|
||||
ScriptOwnerData::None => None,
|
||||
};
|
||||
if let Some(owner_obj) = owner_obj {
|
||||
o.insert(rune::alloc::String::try_from("owner")?, owner_obj.into())?;
|
||||
}
|
||||
|
||||
let state = rune::to_value(o)?;
|
||||
let script = Arc::new(RuneScript::new(
|
||||
script_key.clone(),
|
||||
state,
|
||||
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(());
|
||||
}
|
||||
#[allow(clippy::unwrap_used)] // We know that the first element exists
|
||||
let mod_name = meta.item.iter().nth(0).unwrap();
|
||||
let category = match get_mod_category(mod_name) {
|
||||
Ok(value) => value,
|
||||
Err(value) => return value,
|
||||
};
|
||||
#[allow(clippy::unwrap_used)] // We know that the last element exists
|
||||
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,62 @@
|
|||
use crate::dynamic_data::Battle;
|
||||
use crate::script_implementations::rune::wrappers::{impl_rune_wrapper, RuneStringKey, RuneWrapper};
|
||||
use rune::{Any, Value};
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<RuneBattle>()?;
|
||||
module.function_meta(RuneBattle::library)?;
|
||||
module.function_meta(RuneBattle::parties)?;
|
||||
module.function_meta(RuneBattle::can_flee)?;
|
||||
module.function_meta(RuneBattle::number_of_sides)?;
|
||||
module.function_meta(RuneBattle::pokemon_per_side)?;
|
||||
module.function_meta(RuneBattle::sides)?;
|
||||
module.function_meta(RuneBattle::random)?;
|
||||
module.function_meta(RuneBattle::has_ended)?;
|
||||
module.function_meta(RuneBattle::current_turn)?;
|
||||
module.function_meta(RuneBattle::get_pokemon)?;
|
||||
module.function_meta(RuneBattle::set_weather)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Any)]
|
||||
pub struct RuneBattle(Battle);
|
||||
|
||||
impl_rune_wrapper!(&Battle, RuneBattle);
|
||||
|
||||
impl RuneBattle {
|
||||
#[rune::function]
|
||||
fn library(&self) -> Value { self.0.library().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn parties(&self) -> Vec<Value> { self.0.parties().iter().map(|p| p.wrap()).collect() }
|
||||
|
||||
#[rune::function]
|
||||
fn can_flee(&self) -> bool { self.0.can_flee() }
|
||||
|
||||
#[rune::function]
|
||||
fn number_of_sides(&self) -> u8 { self.0.number_of_sides() }
|
||||
|
||||
#[rune::function]
|
||||
fn pokemon_per_side(&self) -> u8 { self.0.pokemon_per_side() }
|
||||
|
||||
#[rune::function]
|
||||
fn sides(&self) -> Vec<Value> { self.0.sides().iter().map(|s| s.wrap()).collect() }
|
||||
|
||||
#[rune::function]
|
||||
fn random(&self) -> Value { self.0.random().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn has_ended(&self) -> bool { self.0.has_ended() }
|
||||
|
||||
#[rune::function]
|
||||
fn current_turn(&self) -> u32 { self.0.current_turn() }
|
||||
|
||||
#[rune::function]
|
||||
fn get_pokemon(&self, side: u8, index: u8) -> Option<Value> { self.0.get_pokemon(side, index).map(|v| v.wrap()) }
|
||||
|
||||
#[rune::function]
|
||||
fn set_weather(&self, weather: Option<RuneStringKey>) -> anyhow::Result<()> {
|
||||
self.0.set_weather(weather.map(|w| w.0))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
use crate::dynamic_data::BattleParty;
|
||||
use crate::script_implementations::rune::wrappers::impl_rune_wrapper;
|
||||
use rune::Any;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<RuneBattleParty>()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Any)]
|
||||
pub struct RuneBattleParty(pub Arc<BattleParty>);
|
||||
|
||||
impl_rune_wrapper!(&Arc<BattleParty>, RuneBattleParty);
|
|
@ -0,0 +1,43 @@
|
|||
use crate::dynamic_data::BattleRandom;
|
||||
use crate::script_implementations::rune::wrappers::dynamic_data::executing_move::RuneExecutingMove;
|
||||
use crate::script_implementations::rune::wrappers::dynamic_data::pokemon::RunePokemon;
|
||||
use crate::script_implementations::rune::wrappers::impl_rune_wrapper;
|
||||
use rune::Any;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<RuneBattleRandom>()?;
|
||||
module.function_meta(RuneBattleRandom::get)?;
|
||||
module.function_meta(RuneBattleRandom::get_max)?;
|
||||
module.function_meta(RuneBattleRandom::get_between)?;
|
||||
module.function_meta(RuneBattleRandom::effect_chance)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Any)]
|
||||
pub struct RuneBattleRandom(pub(crate) Arc<BattleRandom>);
|
||||
|
||||
impl_rune_wrapper!(&Arc<BattleRandom>, RuneBattleRandom);
|
||||
|
||||
impl RuneBattleRandom {
|
||||
#[rune::function]
|
||||
fn get(&self) -> i32 { self.0.get().unwrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn get_max(&self, max: i32) -> i32 { self.0.get_max(max).unwrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn get_between(&self, min: i32, max: i32) -> i32 { self.0.get_between(min, max).unwrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn effect_chance(
|
||||
&self,
|
||||
chance: f32,
|
||||
executing_move: &RuneExecutingMove,
|
||||
target: RunePokemon,
|
||||
hit_number: u8,
|
||||
) -> anyhow::Result<bool> {
|
||||
self.0.effect_chance(chance, &executing_move.0, &target.0, hit_number)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
use crate::dynamic_data::BattleSide;
|
||||
use crate::script_implementations::rune::wrappers::impl_rune_wrapper;
|
||||
use rune::Any;
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<RuneBattleSide>()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Any)]
|
||||
pub struct RuneBattleSide(pub BattleSide);
|
||||
|
||||
impl_rune_wrapper!(&BattleSide, RuneBattleSide);
|
||||
|
||||
impl RuneBattleSide {}
|
|
@ -0,0 +1,72 @@
|
|||
use crate::dynamic_data::{ExecutingMove, HitData};
|
||||
use crate::script_implementations::rune::wrappers::dynamic_data::pokemon::RunePokemon;
|
||||
use crate::script_implementations::rune::wrappers::dynamic_data::resolve_script_data;
|
||||
use crate::script_implementations::rune::wrappers::{impl_rune_wrapper, RuneWrapper};
|
||||
use rune::runtime::Value;
|
||||
use rune::Any;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<RuneExecutingMove>()?;
|
||||
module.function_meta(RuneExecutingMove::target_count)?;
|
||||
module.function_meta(RuneExecutingMove::number_of_hits)?;
|
||||
module.function_meta(RuneExecutingMove::user)?;
|
||||
module.function_meta(RuneExecutingMove::chosen_move)?;
|
||||
module.function_meta(RuneExecutingMove::use_move)?;
|
||||
module.function_meta(RuneExecutingMove::script)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Any)]
|
||||
pub struct RuneExecutingMove(pub Arc<ExecutingMove>);
|
||||
|
||||
impl_rune_wrapper!(&Arc<ExecutingMove>, RuneExecutingMove);
|
||||
|
||||
impl RuneExecutingMove {
|
||||
#[rune::function]
|
||||
fn target_count(&self) -> usize { self.0.target_count() }
|
||||
#[rune::function]
|
||||
fn number_of_hits(&self) -> u8 { self.0.number_of_hits() }
|
||||
#[rune::function]
|
||||
fn user(&self) -> Value { self.0.user().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn chosen_move(&self) -> Value { self.0.chosen_move().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn use_move(&self) -> Value { self.0.use_move().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn script(&self) -> Option<Value> { resolve_script_data(self.0.script()) }
|
||||
|
||||
#[rune::function]
|
||||
fn get_hit_data(&self, for_target: RunePokemon, hit: u8) -> anyhow::Result<Value> {
|
||||
self.0.get_hit_data(&for_target.0, hit).map(|hit_data| hit_data.wrap())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Any)]
|
||||
pub struct RuneHitData(pub Arc<HitData>);
|
||||
|
||||
impl_rune_wrapper!(&Arc<HitData>, RuneHitData);
|
||||
|
||||
impl RuneHitData {
|
||||
#[rune::function]
|
||||
fn is_critical(&self) -> bool { self.0.is_critical() }
|
||||
|
||||
#[rune::function]
|
||||
fn base_power(&self) -> u8 { self.0.base_power() }
|
||||
|
||||
#[rune::function]
|
||||
fn effectiveness(&self) -> f32 { self.0.effectiveness() }
|
||||
|
||||
#[rune::function]
|
||||
fn damage(&self) -> u32 { self.0.damage() }
|
||||
|
||||
#[rune::function]
|
||||
fn move_type(&self) -> u8 { u8::from(self.0.move_type()) }
|
||||
|
||||
#[rune::function]
|
||||
fn fail(&self) { self.0.fail() }
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
use crate::dynamic_data::{LearnedMove, MoveLearnMethod};
|
||||
use crate::script_implementations::rune::wrappers::{impl_rune_wrapper, RuneWrapper};
|
||||
use rune::runtime::Value;
|
||||
use rune::Any;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<RuneLearnedMove>()?;
|
||||
module.function_meta(RuneLearnedMove::move_data)?;
|
||||
module.function_meta(RuneLearnedMove::max_pp)?;
|
||||
module.function_meta(RuneLearnedMove::max_pp_modification)?;
|
||||
module.function_meta(RuneLearnedMove::remaining_pp)?;
|
||||
module.function_meta(RuneLearnedMove::learn_method)?;
|
||||
module.function_meta(RuneLearnedMove::try_use)?;
|
||||
module.function_meta(RuneLearnedMove::restore_all_uses)?;
|
||||
module.function_meta(RuneLearnedMove::restore_uses)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Any)]
|
||||
struct RuneLearnedMove(Arc<LearnedMove>);
|
||||
|
||||
impl_rune_wrapper!(&Arc<LearnedMove>, RuneLearnedMove);
|
||||
|
||||
impl RuneLearnedMove {
|
||||
#[rune::function]
|
||||
fn move_data(&self) -> Value { self.0.move_data().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn max_pp(&self) -> u8 { self.0.max_pp() }
|
||||
|
||||
#[rune::function]
|
||||
fn max_pp_modification(&self) -> u8 { self.0.max_pp_modification() }
|
||||
|
||||
#[rune::function]
|
||||
fn remaining_pp(&self) -> u8 { self.0.remaining_pp() }
|
||||
|
||||
#[rune::function]
|
||||
fn learn_method(&self) -> MoveLearnMethod { self.0.learn_method() }
|
||||
|
||||
#[rune::function]
|
||||
fn try_use(&self, amount: u8) -> bool { self.0.try_use(amount) }
|
||||
|
||||
#[rune::function]
|
||||
fn restore_all_uses(&self) { self.0.restore_all_uses() }
|
||||
|
||||
#[rune::function]
|
||||
fn restore_uses(&self, amount: u8) { self.0.restore_uses(amount) }
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
use crate::dynamic_data::{BattleStatCalculator, DynamicLibrary, MiscLibrary};
|
||||
use crate::script_implementations::rune::wrappers::dynamic_data::pokemon::RunePokemon;
|
||||
use crate::script_implementations::rune::wrappers::dynamic_data::turn_choice::RuneTurnChoice;
|
||||
use crate::script_implementations::rune::wrappers::impl_rune_wrapper;
|
||||
use crate::script_implementations::rune::wrappers::static_data::libraries::static_data::RuneStaticData;
|
||||
use crate::static_data::{Statistic, TimeOfDay};
|
||||
use rune::Any;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<RuneBattleStatCalculator>()?;
|
||||
module.function_meta(RuneBattleStatCalculator::calculate_flat_stat)?;
|
||||
module.function_meta(RuneBattleStatCalculator::calculate_boosted_stat)?;
|
||||
|
||||
module.ty::<RuneMiscLibrary>()?;
|
||||
module.function_meta(RuneMiscLibrary::can_flee)?;
|
||||
module.function_meta(RuneMiscLibrary::time_of_day)?;
|
||||
|
||||
module.ty::<RuneDynamicLibrary>()?;
|
||||
module.function_meta(RuneDynamicLibrary::battle_stat_calculator)?;
|
||||
module.function_meta(RuneDynamicLibrary::misc_library)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Any)]
|
||||
pub struct RuneBattleStatCalculator(Arc<dyn BattleStatCalculator>);
|
||||
|
||||
impl_rune_wrapper!(&Arc<dyn BattleStatCalculator>, RuneBattleStatCalculator);
|
||||
|
||||
impl RuneBattleStatCalculator {
|
||||
#[rune::function]
|
||||
fn calculate_flat_stat(&self, pokemon: RunePokemon, stat: Statistic) -> anyhow::Result<u32> {
|
||||
self.0.calculate_flat_stat(&pokemon.0, stat)
|
||||
}
|
||||
|
||||
#[rune::function]
|
||||
fn calculate_boosted_stat(&self, pokemon: RunePokemon, stat: Statistic) -> anyhow::Result<u32> {
|
||||
self.0.calculate_boosted_stat(&pokemon.0, stat)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Any)]
|
||||
pub struct RuneMiscLibrary(Arc<dyn MiscLibrary>);
|
||||
impl_rune_wrapper!(&Arc<dyn MiscLibrary>, RuneMiscLibrary);
|
||||
|
||||
impl RuneMiscLibrary {
|
||||
#[rune::function]
|
||||
fn can_flee(&self, choice: RuneTurnChoice) -> bool { self.0.can_flee(choice.get_turn_choice()) }
|
||||
|
||||
#[rune::function]
|
||||
fn time_of_day(&self) -> TimeOfDay { self.0.time_of_day() }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Any)]
|
||||
pub struct RuneDynamicLibrary(Arc<dyn DynamicLibrary>);
|
||||
impl_rune_wrapper!(&Arc<dyn DynamicLibrary>, RuneDynamicLibrary);
|
||||
|
||||
impl RuneDynamicLibrary {
|
||||
#[rune::function]
|
||||
fn battle_stat_calculator(&self) -> RuneBattleStatCalculator {
|
||||
RuneBattleStatCalculator(self.0.stat_calculator().clone())
|
||||
}
|
||||
|
||||
#[rune::function]
|
||||
fn misc_library(&self) -> RuneMiscLibrary { RuneMiscLibrary(self.0.misc_library().clone()) }
|
||||
|
||||
#[rune::function]
|
||||
fn static_data(&self) -> RuneStaticData { RuneStaticData(self.0.static_data().clone()) }
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
use crate::dynamic_data::ScriptContainer;
|
||||
use crate::script_implementations::rune::script::RuneScript;
|
||||
|
||||
mod battle;
|
||||
mod battle_party;
|
||||
mod battle_random;
|
||||
mod battle_side;
|
||||
mod executing_move;
|
||||
mod learned_move;
|
||||
mod libraries;
|
||||
mod pokemon;
|
||||
mod turn_choice;
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
executing_move::register(module)?;
|
||||
pokemon::register(module)?;
|
||||
turn_choice::register(module)?;
|
||||
learned_move::register(module)?;
|
||||
battle::register(module)?;
|
||||
battle_random::register(module)?;
|
||||
battle_party::register(module)?;
|
||||
battle_side::register(module)?;
|
||||
|
||||
libraries::register(module)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn resolve_script_data(container: &ScriptContainer) -> Option<rune::Value> {
|
||||
container
|
||||
.get()
|
||||
.map(|v| {
|
||||
v.read()
|
||||
.as_ref()
|
||||
.map(|v| v.clone().as_any().downcast_ref::<RuneScript>().map(|s| s.get_state()))
|
||||
})
|
||||
.flatten()
|
||||
.flatten()
|
||||
}
|
|
@ -0,0 +1,226 @@
|
|||
use crate::defines::LevelInt;
|
||||
use crate::dynamic_data::{DamageSource, EventBatchId, Pokemon};
|
||||
use crate::script_implementations::rune::wrappers::dynamic_data::resolve_script_data;
|
||||
use crate::script_implementations::rune::wrappers::static_data::form::RuneForm;
|
||||
use crate::script_implementations::rune::wrappers::static_data::item::RuneItem;
|
||||
use crate::script_implementations::rune::wrappers::{impl_rune_wrapper, RuneStringKey, RuneWrapper};
|
||||
use crate::static_data::{Gender, Statistic};
|
||||
use rune::runtime::Value;
|
||||
use rune::Any;
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<DamageSource>()?;
|
||||
|
||||
module.ty::<RunePokemon>()?;
|
||||
module.function_meta(RunePokemon::library)?;
|
||||
module.function_meta(RunePokemon::species)?;
|
||||
module.function_meta(RunePokemon::form)?;
|
||||
module.function_meta(RunePokemon::has_different_display_species)?;
|
||||
module.function_meta(RunePokemon::display_species)?;
|
||||
module.function_meta(RunePokemon::has_different_display_form)?;
|
||||
module.function_meta(RunePokemon::display_form)?;
|
||||
module.function_meta(RunePokemon::level)?;
|
||||
module.function_meta(RunePokemon::experience)?;
|
||||
module.function_meta(RunePokemon::personality_value)?;
|
||||
module.function_meta(RunePokemon::gender)?;
|
||||
module.function_meta(RunePokemon::coloring)?;
|
||||
module.function_meta(RunePokemon::held_item)?;
|
||||
module.function_meta(RunePokemon::has_held_item)?;
|
||||
module.function_meta(RunePokemon::set_held_item)?;
|
||||
module.function_meta(RunePokemon::remove_held_item)?;
|
||||
module.function_meta(RunePokemon::consume_held_item)?;
|
||||
module.function_meta(RunePokemon::current_health)?;
|
||||
module.function_meta(RunePokemon::max_health)?;
|
||||
module.function_meta(RunePokemon::weight)?;
|
||||
module.function_meta(RunePokemon::set_weight)?;
|
||||
module.function_meta(RunePokemon::height)?;
|
||||
module.function_meta(RunePokemon::happiness)?;
|
||||
module.function_meta(RunePokemon::nickname)?;
|
||||
module.function_meta(RunePokemon::real_ability)?;
|
||||
module.function_meta(RunePokemon::types)?;
|
||||
module.function_meta(RunePokemon::learned_moves)?;
|
||||
module.function_meta(RunePokemon::flat_stats)?;
|
||||
module.function_meta(RunePokemon::is_egg)?;
|
||||
module.function_meta(RunePokemon::boosted_stats)?;
|
||||
module.function_meta(RunePokemon::stat_boost)?;
|
||||
module.function_meta(RunePokemon::change_stat_boost)?;
|
||||
module.function_meta(RunePokemon::get_individual_value)?;
|
||||
module.function_meta(RunePokemon::get_effort_value)?;
|
||||
module.function_meta(RunePokemon::get_battle)?;
|
||||
module.function_meta(RunePokemon::get_battle_side_index)?;
|
||||
module.function_meta(RunePokemon::get_battle_index)?;
|
||||
module.function_meta(RunePokemon::is_ability_overridden)?;
|
||||
module.function_meta(RunePokemon::active_ability)?;
|
||||
module.function_meta(RunePokemon::allowed_experience_gain)?;
|
||||
module.function_meta(RunePokemon::nature)?;
|
||||
module.function_meta(RunePokemon::change_form)?;
|
||||
module.function_meta(RunePokemon::is_usable)?;
|
||||
module.function_meta(RunePokemon::is_fainted)?;
|
||||
module.function_meta(RunePokemon::damage)?;
|
||||
module.function_meta(RunePokemon::heal)?;
|
||||
module.function_meta(RunePokemon::status_script)?;
|
||||
module.function_meta(RunePokemon::clear_status)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Any, Clone, Debug)]
|
||||
pub struct RunePokemon(pub Pokemon);
|
||||
|
||||
impl RunePokemon {
|
||||
#[rune::function]
|
||||
fn library(&self) -> Value { self.0.library().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn species(&self) -> Value { self.0.species().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn form(&self) -> Value { self.0.form().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn has_different_display_species(&self) -> bool { self.0.has_different_display_species() }
|
||||
|
||||
#[rune::function]
|
||||
fn display_species(&self) -> Value { self.0.display_species().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn has_different_display_form(&self) -> bool { self.0.has_different_display_form() }
|
||||
|
||||
#[rune::function]
|
||||
fn display_form(&self) -> Value { self.0.display_form().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn level(&self) -> LevelInt { self.0.level() }
|
||||
|
||||
#[rune::function]
|
||||
fn experience(&self) -> u32 { self.0.experience() }
|
||||
|
||||
#[rune::function]
|
||||
fn personality_value(&self) -> u32 { self.0.personality_value() }
|
||||
|
||||
#[rune::function]
|
||||
fn gender(&self) -> Gender { self.0.gender() }
|
||||
|
||||
#[rune::function]
|
||||
fn coloring(&self) -> u8 { self.0.coloring() }
|
||||
|
||||
#[rune::function]
|
||||
fn held_item(&self) -> Option<Value> { self.0.held_item().map(|v| v.wrap()) }
|
||||
|
||||
#[rune::function]
|
||||
fn has_held_item(&self, key: RuneStringKey) -> bool { self.0.has_held_item(&key.0) }
|
||||
|
||||
#[rune::function]
|
||||
fn set_held_item(&mut self, key: RuneItem) -> Option<Value> { self.0.set_held_item(&key.0).map(|v| v.wrap()) }
|
||||
|
||||
#[rune::function]
|
||||
fn remove_held_item(&mut self) -> Option<Value> { self.0.remove_held_item().map(|v| v.wrap()) }
|
||||
|
||||
#[rune::function]
|
||||
fn consume_held_item(&mut self) -> anyhow::Result<bool> { self.0.consume_held_item() }
|
||||
|
||||
#[rune::function]
|
||||
fn current_health(&self) -> u32 { self.0.current_health() }
|
||||
|
||||
#[rune::function]
|
||||
fn max_health(&self) -> u32 { self.0.max_health() }
|
||||
|
||||
#[rune::function]
|
||||
fn weight(&self) -> f32 { self.0.weight() }
|
||||
|
||||
#[rune::function]
|
||||
fn set_weight(&mut self, value: f32) { self.0.set_weight(value); }
|
||||
|
||||
#[rune::function]
|
||||
fn height(&self) -> f32 { self.0.height() }
|
||||
|
||||
#[rune::function]
|
||||
fn happiness(&self) -> u8 { self.0.happiness() }
|
||||
|
||||
#[rune::function]
|
||||
fn nickname(&self) -> Option<String> { self.0.nickname().clone() }
|
||||
|
||||
#[rune::function]
|
||||
fn real_ability(&self) -> (bool, u8) { (self.0.real_ability().hidden, self.0.real_ability().index) }
|
||||
|
||||
#[rune::function]
|
||||
fn types(&self) -> Vec<u8> { self.0.types().iter().map(|v| u8::from(*v)).collect() }
|
||||
|
||||
#[rune::function]
|
||||
fn learned_moves(&self) -> Vec<Option<Value>> {
|
||||
let l = self.0.learned_moves().read();
|
||||
l.iter().map(|v| v.as_ref().map(|l| l.wrap())).collect()
|
||||
}
|
||||
|
||||
#[rune::function]
|
||||
fn flat_stats(&self) -> Value { self.0.flat_stats().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn is_egg(&self) -> bool { self.0.is_egg() }
|
||||
|
||||
#[rune::function]
|
||||
fn boosted_stats(&self) -> Value { self.0.boosted_stats().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn stat_boost(&self, stat: Statistic) -> i8 { self.0.stat_boost(stat) }
|
||||
|
||||
#[rune::function]
|
||||
fn change_stat_boost(&mut self, stat: Statistic, diff_amount: i8, self_inflicted: bool) -> anyhow::Result<bool> {
|
||||
self.0.change_stat_boost(stat, diff_amount, self_inflicted)
|
||||
}
|
||||
|
||||
#[rune::function]
|
||||
fn get_individual_value(&self, stat: Statistic) -> u8 { self.0.individual_values().get_stat(stat) }
|
||||
|
||||
#[rune::function]
|
||||
fn get_effort_value(&self, stat: Statistic) -> u8 { self.0.effort_values().get_stat(stat) }
|
||||
|
||||
#[rune::function]
|
||||
fn get_battle(&self) -> Option<Value> { self.0.get_battle().map(|v| v.wrap()) }
|
||||
|
||||
#[rune::function]
|
||||
fn get_battle_side_index(&self) -> Option<u8> { self.0.get_battle_side_index() }
|
||||
|
||||
#[rune::function]
|
||||
fn get_battle_index(&self) -> Option<u8> { self.0.get_battle_index() }
|
||||
|
||||
#[rune::function]
|
||||
fn is_ability_overridden(&self) -> bool { self.0.is_ability_overridden() }
|
||||
|
||||
#[rune::function]
|
||||
fn active_ability(&self) -> anyhow::Result<Value> { self.0.active_ability().map(|v| v.wrap()) }
|
||||
|
||||
#[rune::function]
|
||||
fn allowed_experience_gain(&self) -> bool { self.0.allowed_experience_gain() }
|
||||
|
||||
#[rune::function]
|
||||
fn nature(&self) -> Value { self.0.nature().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn change_form(&self, form: RuneForm) -> anyhow::Result<()> { self.0.change_form(&form.0) }
|
||||
|
||||
#[rune::function]
|
||||
fn is_usable(&self) -> bool { self.0.is_usable() }
|
||||
|
||||
#[rune::function]
|
||||
fn is_fainted(&self) -> bool { self.0.is_fainted() }
|
||||
|
||||
#[rune::function]
|
||||
fn damage(&self, amount: u32, source: DamageSource) -> anyhow::Result<()> {
|
||||
self.0.damage(amount, source, EventBatchId::default())
|
||||
}
|
||||
|
||||
#[rune::function]
|
||||
fn heal(&self, amount: u32, allow_revive: bool) -> bool { self.0.heal(amount, allow_revive) }
|
||||
|
||||
#[rune::function]
|
||||
fn clear_status(&self) { self.0.clear_status() }
|
||||
|
||||
#[rune::function]
|
||||
fn status_script(&self) -> Option<Value> { resolve_script_data(&self.0.status()) }
|
||||
|
||||
#[rune::function]
|
||||
fn ability_script(&self) -> Option<Value> { resolve_script_data(&self.0.ability_script()) }
|
||||
}
|
||||
|
||||
impl_rune_wrapper!(&Pokemon, RunePokemon);
|
|
@ -0,0 +1,112 @@
|
|||
use crate::dynamic_data::TurnChoice;
|
||||
use crate::script_implementations::rune::wrappers::RuneWrapper;
|
||||
use rune::runtime::Value;
|
||||
use rune::Any;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<RuneTurnChoice>()?;
|
||||
module.function_meta(RuneTurnChoice::user)?;
|
||||
module.function_meta(RuneTurnChoice::speed)?;
|
||||
module.function_meta(RuneTurnChoice::has_failed)?;
|
||||
module.function_meta(RuneTurnChoice::fail)?;
|
||||
|
||||
module.ty::<RuneMoveChoice>()?;
|
||||
module.function_meta(RuneMoveChoice::used_move)?;
|
||||
module.function_meta(RuneMoveChoice::target_side)?;
|
||||
module.function_meta(RuneMoveChoice::target_index)?;
|
||||
module.function_meta(RuneMoveChoice::priority)?;
|
||||
module.function_meta(RuneMoveChoice::user)?;
|
||||
|
||||
module.ty::<RuneItemChoice>()?;
|
||||
module.ty::<RuneSwitchChoice>()?;
|
||||
module.ty::<RuneFleeChoice>()?;
|
||||
module.ty::<RunePassChoice>()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Any)]
|
||||
pub enum RuneTurnChoice {
|
||||
Move(#[rune(get)] RuneMoveChoice),
|
||||
Item(#[rune(get)] RuneItemChoice),
|
||||
Switch(#[rune(get)] RuneSwitchChoice),
|
||||
Flee(#[rune(get)] RuneFleeChoice),
|
||||
Pass(#[rune(get)] RunePassChoice),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Any)]
|
||||
pub struct RuneMoveChoice(Arc<TurnChoice>);
|
||||
|
||||
#[derive(Debug, Clone, Any)]
|
||||
pub struct RuneItemChoice(Arc<TurnChoice>);
|
||||
|
||||
#[derive(Debug, Clone, Any)]
|
||||
pub struct RuneSwitchChoice(Arc<TurnChoice>);
|
||||
|
||||
#[derive(Debug, Clone, Any)]
|
||||
pub struct RuneFleeChoice(Arc<TurnChoice>);
|
||||
|
||||
#[derive(Debug, Clone, Any)]
|
||||
pub struct RunePassChoice(Arc<TurnChoice>);
|
||||
|
||||
impl RuneTurnChoice {
|
||||
pub fn get_turn_choice(&self) -> &Arc<TurnChoice> {
|
||||
match self {
|
||||
RuneTurnChoice::Move(m) => &m.0,
|
||||
RuneTurnChoice::Item(i) => &i.0,
|
||||
RuneTurnChoice::Switch(s) => &s.0,
|
||||
RuneTurnChoice::Flee(f) => &f.0,
|
||||
RuneTurnChoice::Pass(p) => &p.0,
|
||||
}
|
||||
}
|
||||
|
||||
#[rune::function]
|
||||
fn user(&self) -> Value { self.get_turn_choice().user().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn speed(&self) -> u32 { self.get_turn_choice().speed() }
|
||||
|
||||
#[rune::function]
|
||||
fn has_failed(&self) -> bool { self.get_turn_choice().has_failed() }
|
||||
|
||||
#[rune::function]
|
||||
fn fail(&self) { self.get_turn_choice().fail() }
|
||||
}
|
||||
|
||||
impl RuneWrapper for &Arc<TurnChoice> {
|
||||
fn wrap(self) -> Value {
|
||||
let o = match self.as_ref() {
|
||||
TurnChoice::Move(_) => RuneTurnChoice::Move(RuneMoveChoice(self.clone())),
|
||||
TurnChoice::Item(_) => RuneTurnChoice::Item(RuneItemChoice(self.clone())),
|
||||
TurnChoice::Switch(_) => RuneTurnChoice::Switch(RuneSwitchChoice(self.clone())),
|
||||
TurnChoice::Flee(_) => RuneTurnChoice::Flee(RuneFleeChoice(self.clone())),
|
||||
TurnChoice::Pass(_) => RuneTurnChoice::Pass(RunePassChoice(self.clone())),
|
||||
};
|
||||
rune::to_value(o).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl RuneMoveChoice {
|
||||
fn move_choice(&self) -> &crate::dynamic_data::MoveChoice {
|
||||
match self.0.as_ref() {
|
||||
TurnChoice::Move(m) => m,
|
||||
_ => unreachable!("RuneMoveChoice should only be created with a MoveChoice"),
|
||||
}
|
||||
}
|
||||
|
||||
#[rune::function]
|
||||
fn used_move(&self) -> Value { self.move_choice().used_move().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn target_side(&self) -> u8 { self.move_choice().target_side() }
|
||||
|
||||
#[rune::function]
|
||||
fn target_index(&self) -> u8 { self.move_choice().target_index() }
|
||||
|
||||
#[rune::function]
|
||||
fn priority(&self) -> i8 { self.move_choice().priority() }
|
||||
|
||||
#[rune::function]
|
||||
fn user(&self) -> Value { self.move_choice().user().wrap() }
|
||||
}
|
|
@ -0,0 +1,664 @@
|
|||
use rune::alloc::fmt::TryWrite;
|
||||
use rune::runtime::{Protocol, VmResult};
|
||||
use rune::{Any, Value};
|
||||
use std::num::Saturating;
|
||||
|
||||
mod dynamic_data;
|
||||
mod parameters;
|
||||
mod static_data;
|
||||
|
||||
pub trait RuneWrapper {
|
||||
fn wrap(self) -> Value;
|
||||
}
|
||||
|
||||
pub fn module() -> anyhow::Result<rune::Module> {
|
||||
let mut module = rune::Module::new();
|
||||
module.ty::<RuneValueIntWrapper>()?;
|
||||
module.function_meta(RuneValueIntWrapper::rn_as_int)?;
|
||||
module.function_meta(RuneValueIntWrapper::set_value)?;
|
||||
module.associated_function(Protocol::ADD_ASSIGN, RuneValueIntWrapper::add_assign)?;
|
||||
module.associated_function(Protocol::SUB_ASSIGN, RuneValueIntWrapper::sub_assign)?;
|
||||
module.associated_function(Protocol::DIV_ASSIGN, RuneValueIntWrapper::div_assign)?;
|
||||
module.associated_function(Protocol::MUL_ASSIGN, RuneValueIntWrapper::mul_assign)?;
|
||||
module.associated_function(Protocol::PARTIAL_EQ, RuneValueIntWrapper::partial_eq)?;
|
||||
module.associated_function(Protocol::EQ, RuneValueIntWrapper::eq)?;
|
||||
module.function_meta(RuneValueIntWrapper::string_display)?;
|
||||
|
||||
module.ty::<RuneValueBoolWrapper>()?;
|
||||
module.function_meta(RuneValueBoolWrapper::rn_as_bool)?;
|
||||
module.function_meta(RuneValueBoolWrapper::set_value)?;
|
||||
module.associated_function(Protocol::PARTIAL_EQ, RuneValueBoolWrapper::eq)?;
|
||||
module.associated_function(Protocol::EQ, RuneValueBoolWrapper::eq)?;
|
||||
module.function_meta(RuneValueBoolWrapper::string_display)?;
|
||||
|
||||
module.ty::<RuneStringKey>()?;
|
||||
module.function_meta(RuneStringKey::string_display)?;
|
||||
module.associated_function(Protocol::PARTIAL_EQ, RuneStringKey::eq)?;
|
||||
module.associated_function(Protocol::EQ, RuneStringKey::eq)?;
|
||||
|
||||
parameters::register(&mut module)?;
|
||||
dynamic_data::register(&mut module)?;
|
||||
static_data::register(&mut module)?;
|
||||
Ok(module)
|
||||
}
|
||||
|
||||
pub fn wrap_int_reference(value: i64) -> anyhow::Result<Value> { Ok(rune::to_value(RuneValueIntWrapper::new(value))?) }
|
||||
|
||||
pub fn wrap_bool_reference(value: bool) -> anyhow::Result<Value> {
|
||||
Ok(rune::to_value(RuneValueBoolWrapper::new(value))?)
|
||||
}
|
||||
|
||||
pub fn get_int_reference_value(value: Value) -> anyhow::Result<i64> {
|
||||
let obj = match value.into_any::<RuneValueIntWrapper>() {
|
||||
Ok(obj) => obj,
|
||||
Err(_) => return Err(anyhow::anyhow!("Value is not a RuneValueIntWrapper")),
|
||||
};
|
||||
Ok(obj.as_int())
|
||||
}
|
||||
|
||||
pub fn get_bool_reference_value(value: Value) -> anyhow::Result<bool> {
|
||||
let obj = match value.into_any::<RuneValueBoolWrapper>() {
|
||||
Ok(obj) => obj,
|
||||
Err(_) => return Err(anyhow::anyhow!("Value is not a RuneValueBoolWrapper")),
|
||||
};
|
||||
Ok(obj.as_bool())
|
||||
}
|
||||
|
||||
macro_rules! impl_rune_wrapper {
|
||||
($t:ty, $wrapped_type:ident) => {
|
||||
impl crate::script_implementations::rune::wrappers::RuneWrapper for $t {
|
||||
fn wrap(self) -> rune::runtime::Value { rune::to_value($wrapped_type(self.clone())).unwrap() }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
use crate::StringKey;
|
||||
use impl_rune_wrapper;
|
||||
|
||||
#[derive(Any, Clone)]
|
||||
#[rune(name = RefInt)]
|
||||
struct RuneValueIntWrapper {
|
||||
value: Saturating<i64>,
|
||||
}
|
||||
|
||||
impl RuneValueIntWrapper {
|
||||
pub fn new(value: i64) -> Self {
|
||||
Self {
|
||||
value: Saturating(value),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_int(&self) -> i64 { self.value.0 }
|
||||
|
||||
#[rune::function(path = RuneValueIntWrapper::as_int)]
|
||||
fn rn_as_int(&self) -> i64 { self.value.0 }
|
||||
|
||||
#[rune::function]
|
||||
fn set_value(&mut self, value: i64) { self.value.0 = value; }
|
||||
|
||||
fn add_assign(&mut self, other: i64) { self.value += other; }
|
||||
|
||||
fn sub_assign(&mut self, other: i64) { self.value -= other; }
|
||||
|
||||
fn div_assign(&mut self, other: Value) {
|
||||
match other.as_integer() {
|
||||
Ok(other) => self.value /= other,
|
||||
Err(_) => match other.as_float() {
|
||||
Ok(other) => self.div_assign_f64(other),
|
||||
Err(_) => (),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn div_assign_f64(&mut self, other: f64) {
|
||||
let v = (self.value.0 as f64 / other).floor();
|
||||
if v > i64::MAX as f64 {
|
||||
self.value = Saturating(i64::MAX);
|
||||
} else if v < i64::MIN as f64 {
|
||||
self.value = Saturating(i64::MIN);
|
||||
} else {
|
||||
self.value = Saturating(v as i64);
|
||||
}
|
||||
}
|
||||
|
||||
fn mul_assign(&mut self, other: Value) {
|
||||
match other.as_integer() {
|
||||
Ok(other) => self.value *= other,
|
||||
Err(_) => match other.as_float() {
|
||||
Ok(other) => self.mul_assign_f64(other),
|
||||
Err(_) => (),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn mul_assign_f64(&mut self, other: f64) {
|
||||
let v = (self.value.0 as f64 * other).floor();
|
||||
if v > i64::MAX as f64 {
|
||||
self.value = Saturating(i64::MAX);
|
||||
} else if v < i64::MIN as f64 {
|
||||
self.value = Saturating(i64::MIN);
|
||||
} else {
|
||||
self.value = Saturating(v as i64);
|
||||
}
|
||||
}
|
||||
|
||||
fn partial_eq(&self, b: i64) -> VmResult<bool> { VmResult::Ok(self.value.0 == b) }
|
||||
|
||||
fn eq(&self, b: i64) -> VmResult<bool> { VmResult::Ok(self.value.0 == b) }
|
||||
|
||||
#[rune::function(instance, protocol = STRING_DISPLAY)]
|
||||
fn string_display(&self, f: &mut rune::runtime::Formatter) -> VmResult<()> {
|
||||
rune::vm_write!(f, "{}", self.value.0);
|
||||
VmResult::Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Any, Clone)]
|
||||
#[rune(name = RefBool)]
|
||||
struct RuneValueBoolWrapper(bool);
|
||||
|
||||
impl RuneValueBoolWrapper {
|
||||
pub fn new(value: bool) -> Self { Self(value) }
|
||||
|
||||
pub fn as_bool(&self) -> bool { self.0 }
|
||||
|
||||
#[rune::function(path = RuneValueIntWrapper::as_bool)]
|
||||
fn rn_as_bool(&self) -> bool { self.0 }
|
||||
|
||||
#[rune::function]
|
||||
fn set_value(&mut self, value: bool) { self.0 = value; }
|
||||
|
||||
#[rune::function(instance, protocol = STRING_DISPLAY)]
|
||||
fn string_display(&self, f: &mut rune::runtime::Formatter) -> VmResult<()> {
|
||||
rune::vm_write!(f, "{}", self.0);
|
||||
VmResult::Ok(())
|
||||
}
|
||||
|
||||
fn eq(&self, b: bool) -> VmResult<bool> { VmResult::Ok(self.0 == b) }
|
||||
}
|
||||
|
||||
#[derive(Any, Clone, Debug)]
|
||||
#[rune(name = StringKey)]
|
||||
pub(super) struct RuneStringKey(pub StringKey);
|
||||
|
||||
impl RuneStringKey {
|
||||
pub fn new(value: StringKey) -> Self { Self(value) }
|
||||
|
||||
#[rune::function(instance, protocol = STRING_DISPLAY)]
|
||||
fn string_display(&self, f: &mut rune::runtime::Formatter) -> VmResult<()> {
|
||||
rune::vm_write!(f, "{}", self.0);
|
||||
VmResult::Ok(())
|
||||
}
|
||||
|
||||
fn eq(&self, b: Value) -> VmResult<bool> {
|
||||
match b.borrow_string_ref() {
|
||||
Ok(s) => VmResult::Ok(self.0 == StringKey::new(&s)),
|
||||
Err(_) => {
|
||||
let b = b.borrow_any_ref::<RuneStringKey>();
|
||||
match b {
|
||||
Ok(b) => VmResult::Ok(self.0 == b.0),
|
||||
_ => VmResult::Ok(false),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RuneWrapper for &StringKey {
|
||||
fn wrap(self) -> Value { rune::to_value(RuneStringKey(self.clone())).unwrap() }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use anyhow::Result;
|
||||
use rune::diagnostics::Diagnostic;
|
||||
use rune::{Context, Diagnostics, Options, Source, Vm};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn setup_script(script: &str) -> Result<Vm> {
|
||||
let mut context = Context::with_default_modules()?;
|
||||
context.install(module()?)?;
|
||||
|
||||
let mut sources = rune::Sources::new();
|
||||
sources.insert(Source::memory(script)?)?;
|
||||
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 unit = rune::prepare(&mut sources)
|
||||
.with_context(&context)
|
||||
.with_diagnostics(&mut diagnostics)
|
||||
.with_options(&options)
|
||||
.build();
|
||||
if !diagnostics.is_empty() && 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));
|
||||
}
|
||||
|
||||
Ok(Vm::new(Arc::new(context.runtime()?), Arc::new(unit?)))
|
||||
}
|
||||
|
||||
macro_rules! execute_vm {
|
||||
($vm:expr, $func:expr, $val:expr) => {{
|
||||
let args = vec![$val.clone()];
|
||||
$vm.execute([$func], args)?.complete().into_result()?
|
||||
}};
|
||||
}
|
||||
|
||||
pub(crate) use execute_vm;
|
||||
|
||||
#[test]
|
||||
fn test_int_wrapper_set_value() -> Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_int(a) {
|
||||
a.set_value(5);
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let val = wrap_int_reference(10)?;
|
||||
execute_vm!(vm, "test_int", val);
|
||||
let v = get_int_reference_value(val)?;
|
||||
assert_eq!(v, 5);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_int_wrapper_as_int() -> Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_int(a) {
|
||||
a.as_int()
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let val = wrap_int_reference(10)?;
|
||||
let res = execute_vm!(vm, "test_int", val);
|
||||
let res = res.as_integer()?;
|
||||
assert_eq!(res, 10);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_int_wrapper_add() -> Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_int(a) {
|
||||
a += 5;
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let val = wrap_int_reference(10)?;
|
||||
execute_vm!(vm, "test_int", val);
|
||||
let v = get_int_reference_value(val)?;
|
||||
assert_eq!(v, 15);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_int_wrapper_add_overflow() -> Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_int(a) {
|
||||
a += 5;
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let val = wrap_int_reference(i64::MAX)?;
|
||||
execute_vm!(vm, "test_int", val);
|
||||
let v = get_int_reference_value(val)?;
|
||||
assert_eq!(v, i64::MAX);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_int_wrapper_sub() -> Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_int(a) {
|
||||
a -= 5;
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let val = wrap_int_reference(10)?;
|
||||
execute_vm!(vm, "test_int", val);
|
||||
let v = get_int_reference_value(val)?;
|
||||
assert_eq!(v, 5);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_int_wrapper_underflow() -> Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_int(a) {
|
||||
a -= 5;
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let val = wrap_int_reference(i64::MIN)?;
|
||||
execute_vm!(vm, "test_int", val);
|
||||
let v = get_int_reference_value(val)?;
|
||||
assert_eq!(v, i64::MIN);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_int_wrapper_mul() -> Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_int(a) {
|
||||
a *= 5;
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let val = wrap_int_reference(10)?;
|
||||
execute_vm!(vm, "test_int", val);
|
||||
let v = get_int_reference_value(val)?;
|
||||
assert_eq!(v, 50);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_int_wrapper_mul_float() -> Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_int(a) {
|
||||
a *= 0.5;
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let val = wrap_int_reference(10)?;
|
||||
execute_vm!(vm, "test_int", val);
|
||||
let v = get_int_reference_value(val)?;
|
||||
assert_eq!(v, 5);
|
||||
Ok(())
|
||||
}
|
||||
#[test]
|
||||
fn test_int_wrapper_mul_overflow() -> Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_int(a) {
|
||||
a *= 5;
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let val = wrap_int_reference(i64::MAX)?;
|
||||
execute_vm!(vm, "test_int", val);
|
||||
let v = get_int_reference_value(val)?;
|
||||
assert_eq!(v, i64::MAX);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_int_wrapper_mul_float_overflow() -> Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_int(a) {
|
||||
a *= 10.0;
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let val = wrap_int_reference(i64::MAX)?;
|
||||
execute_vm!(vm, "test_int", val);
|
||||
let v = get_int_reference_value(val)?;
|
||||
assert_eq!(v, i64::MAX);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_int_wrapper_mul_float_underflow() -> Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_int(a) {
|
||||
a *= 10.0;
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let val = wrap_int_reference(i64::MIN)?;
|
||||
execute_vm!(vm, "test_int", val);
|
||||
let v = get_int_reference_value(val)?;
|
||||
assert_eq!(v, i64::MIN);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_int_wrapper_div() -> Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_int(a) {
|
||||
a /= 5;
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let val = wrap_int_reference(10)?;
|
||||
execute_vm!(vm, "test_int", val);
|
||||
let v = get_int_reference_value(val)?;
|
||||
assert_eq!(v, 2);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_int_wrapper_div_float() -> Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_int(a) {
|
||||
a /= 0.5;
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let val = wrap_int_reference(10)?;
|
||||
execute_vm!(vm, "test_int", val);
|
||||
let v = get_int_reference_value(val)?;
|
||||
assert_eq!(v, 20);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_int_wrapper_div_float_overflow() -> Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_int(a) {
|
||||
a /= 0.0001;
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let val = wrap_int_reference(i64::MAX)?;
|
||||
execute_vm!(vm, "test_int", val);
|
||||
let v = get_int_reference_value(val)?;
|
||||
assert_eq!(v, i64::MAX);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_int_wrapper_div_float_underflow() -> Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_int(a) {
|
||||
a /= 0.0001;
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let val = wrap_int_reference(i64::MIN)?;
|
||||
execute_vm!(vm, "test_int", val);
|
||||
let v = get_int_reference_value(val)?;
|
||||
assert_eq!(v, i64::MIN);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_int_wrapper_eq() -> Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_int(a) {
|
||||
a == 5
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let val = wrap_int_reference(5)?;
|
||||
let res = execute_vm!(vm, "test_int", val);
|
||||
let res = res.as_bool()?;
|
||||
assert_eq!(res, true);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_int_wrapper_ineq() -> Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_int(a) {
|
||||
a == 5
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let val = wrap_int_reference(6)?;
|
||||
let res = execute_vm!(vm, "test_int", val);
|
||||
let res = res.as_bool()?;
|
||||
assert_eq!(res, false);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_int_wrapper_string_display() -> Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_int(a) {
|
||||
`${a}`
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let val = wrap_int_reference(5)?;
|
||||
let res = execute_vm!(vm, "test_int", val);
|
||||
let res = res.into_string()?.into_std();
|
||||
assert_eq!(res, "5");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bool_wrapper_set_value() -> Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_bool(a) {
|
||||
a.set_value(true);
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let val = wrap_bool_reference(false)?;
|
||||
execute_vm!(vm, "test_bool", val);
|
||||
let v = get_bool_reference_value(val)?;
|
||||
assert_eq!(v, true);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bool_wrapper_as_bool() -> Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_bool(a) {
|
||||
a.as_bool()
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let val = wrap_bool_reference(true)?;
|
||||
let res = execute_vm!(vm, "test_bool", val);
|
||||
let res = res.as_bool()?;
|
||||
assert_eq!(res, true);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bool_wrapper_eq() -> Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_bool(a) {
|
||||
a == true
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let val = wrap_bool_reference(true)?;
|
||||
let res = execute_vm!(vm, "test_bool", val);
|
||||
let res = res.as_bool()?;
|
||||
assert_eq!(res, true);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bool_wrapper_ineq() -> Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_bool(a) {
|
||||
a == true
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let val = wrap_bool_reference(false)?;
|
||||
let res = execute_vm!(vm, "test_bool", val);
|
||||
let res = res.as_bool()?;
|
||||
assert_eq!(res, false);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bool_wrapper_string_display() -> Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_bool(a) {
|
||||
`${a}`
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let val = wrap_bool_reference(true)?;
|
||||
let res = execute_vm!(vm, "test_bool", val);
|
||||
let res = res.into_string()?.into_std();
|
||||
assert_eq!(res, "true");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_string_key_wrapper_string_display() -> Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_string_key(a) {
|
||||
`${a}`
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let val = StringKey::from("test");
|
||||
let arg = val.wrap();
|
||||
let res = execute_vm!(vm, "test_string_key", arg);
|
||||
let res = res.into_string()?.into_std();
|
||||
assert_eq!(res, "test");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_string_key_wrapper_eq() -> Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_string_key(a) {
|
||||
a == "test"
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let val = StringKey::from("test");
|
||||
let arg = val.wrap();
|
||||
let res = execute_vm!(vm, "test_string_key", arg);
|
||||
let res = res.as_bool()?;
|
||||
assert_eq!(res, true);
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
use crate::script_implementations::rune::wrappers::{RuneStringKey, RuneWrapper};
|
||||
use crate::static_data::Parameter;
|
||||
use rune::runtime::Value;
|
||||
use rune::Any;
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<RuneParameter>()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Any)]
|
||||
#[rune(name = Parameter)]
|
||||
pub(super) enum RuneParameter {
|
||||
Int(#[rune(get)] i32),
|
||||
Float(#[rune(get)] f32),
|
||||
String(#[rune(get)] RuneStringKey),
|
||||
Bool(#[rune(get)] bool),
|
||||
}
|
||||
|
||||
impl RuneWrapper for &Arc<Parameter> {
|
||||
fn wrap(self) -> Value {
|
||||
let p = match self.deref() {
|
||||
Parameter::Bool(b) => RuneParameter::Bool(*b),
|
||||
Parameter::Int(i) => RuneParameter::Int(*i as i32),
|
||||
Parameter::Float(f) => RuneParameter::Float(*f),
|
||||
Parameter::String(s) => RuneParameter::String(RuneStringKey::new(s.clone())),
|
||||
};
|
||||
rune::to_value(p).unwrap()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
use crate::script_implementations::rune::wrappers::{impl_rune_wrapper, RuneStringKey, RuneWrapper};
|
||||
use crate::static_data::Ability;
|
||||
use crate::StringKey;
|
||||
use rune::runtime::Value;
|
||||
use rune::Any;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<RuneAbility>()?;
|
||||
module.function_meta(RuneAbility::name)?;
|
||||
module.function_meta(RuneAbility::effect)?;
|
||||
module.function_meta(RuneAbility::get_parameter)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Any)]
|
||||
pub struct RuneAbility(Arc<dyn Ability>);
|
||||
|
||||
impl_rune_wrapper!(&Arc<dyn Ability>, RuneAbility);
|
||||
|
||||
impl RuneAbility {
|
||||
#[rune::function]
|
||||
fn name(&self) -> Value { self.0.name().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn effect(&self) -> Value { self.0.effect().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn get_parameter(&self, key: Value) -> Option<Value> {
|
||||
if let Ok(s) = key.borrow_string_ref() {
|
||||
return self.0.parameters().get(&StringKey::new(&s)).map(|v| v.wrap());
|
||||
}
|
||||
if let Ok(v) = key.into_any::<RuneStringKey>() {
|
||||
self.0.parameters().get(&v.0).map(|v| v.wrap())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::super::super::tests::{execute_vm, setup_script};
|
||||
use super::*;
|
||||
use crate::static_data::tests::MockAbility;
|
||||
use crate::static_data::Parameter;
|
||||
use hashbrown::HashMap;
|
||||
|
||||
#[test]
|
||||
fn test_ability_name() -> anyhow::Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_ability(ability) {
|
||||
let name = ability.name();
|
||||
assert_eq!(name, "TestAbility");
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let mut ability = MockAbility::new();
|
||||
ability.expect_name().once().return_const(StringKey::new("TestAbility"));
|
||||
let ability: Arc<dyn Ability> = Arc::new(ability);
|
||||
let wrapped = ability.wrap();
|
||||
execute_vm!(&mut vm, "test_ability", wrapped);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ability_effect() -> anyhow::Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_ability(ability) {
|
||||
let effect = ability.effect();
|
||||
assert_eq!(effect, "TestEffect");
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let mut ability = MockAbility::new();
|
||||
ability
|
||||
.expect_effect()
|
||||
.once()
|
||||
.return_const(StringKey::new("TestEffect"));
|
||||
let ability: Arc<dyn Ability> = Arc::new(ability);
|
||||
let wrapped = ability.wrap();
|
||||
execute_vm!(&mut vm, "test_ability", wrapped);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ability_get_parameter() -> anyhow::Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_ability(ability) {
|
||||
let value = ability.get_parameter("test_key");
|
||||
match value {
|
||||
Some(v) => {
|
||||
match v {
|
||||
Parameter::String(s) => assert_eq!(s, "TestValue"),
|
||||
_ => panic!("Invalid value type"),
|
||||
}
|
||||
}
|
||||
None => panic!("Value not found"),
|
||||
}
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let mut ability = MockAbility::new();
|
||||
ability.expect_parameters().once().return_const({
|
||||
let mut map = HashMap::new();
|
||||
map.insert(
|
||||
StringKey::new("test_key"),
|
||||
Arc::new(Parameter::String(StringKey::new("TestValue"))),
|
||||
);
|
||||
map
|
||||
});
|
||||
let a: Arc<dyn Ability> = Arc::new(ability);
|
||||
let wrapped = a.wrap();
|
||||
execute_vm!(&mut vm, "test_ability", wrapped);
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,327 @@
|
|||
use crate::script_implementations::rune::wrappers::{impl_rune_wrapper, RuneStringKey, RuneWrapper};
|
||||
use crate::static_data::{AbilityIndex, Form, Statistic};
|
||||
use crate::StringKey;
|
||||
use rune::runtime::Value;
|
||||
use rune::Any;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<RuneForm>()?;
|
||||
module.function_meta(RuneForm::name)?;
|
||||
module.function_meta(RuneForm::height)?;
|
||||
module.function_meta(RuneForm::weight)?;
|
||||
module.function_meta(RuneForm::base_experience)?;
|
||||
module.function_meta(RuneForm::types)?;
|
||||
module.function_meta(RuneForm::base_stats)?;
|
||||
module.function_meta(RuneForm::abilities)?;
|
||||
module.function_meta(RuneForm::hidden_abilities)?;
|
||||
module.function_meta(RuneForm::has_flag)?;
|
||||
module.function_meta(RuneForm::get_type)?;
|
||||
module.function_meta(RuneForm::get_base_stat)?;
|
||||
module.function_meta(RuneForm::get_ability)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Any)]
|
||||
#[rune(name = Form)]
|
||||
pub struct RuneForm(pub Arc<dyn Form>);
|
||||
|
||||
impl_rune_wrapper!(&Arc<dyn Form>, RuneForm);
|
||||
|
||||
impl RuneForm {
|
||||
#[rune::function]
|
||||
fn name(&self) -> Value { self.0.name().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn height(&self) -> f32 { self.0.height() }
|
||||
|
||||
#[rune::function]
|
||||
fn weight(&self) -> f32 { self.0.weight() }
|
||||
|
||||
#[rune::function]
|
||||
fn base_experience(&self) -> u32 { self.0.base_experience() }
|
||||
|
||||
#[rune::function]
|
||||
fn types(&self) -> Vec<i64> { self.0.types().iter().map(|t| u8::from(*t) as i64).collect() }
|
||||
|
||||
#[rune::function]
|
||||
fn base_stats(&self) -> Value { self.0.base_stats().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn abilities(&self) -> Vec<Value> { self.0.abilities().iter().map(|a| a.wrap()).collect() }
|
||||
|
||||
#[rune::function]
|
||||
fn hidden_abilities(&self) -> Vec<Value> { self.0.hidden_abilities().iter().map(|a| a.wrap()).collect() }
|
||||
|
||||
#[rune::function]
|
||||
fn has_flag(&self, key: Value) -> bool {
|
||||
if let Ok(s) = key.borrow_string_ref() {
|
||||
return self.0.has_flag(&StringKey::new(&s));
|
||||
}
|
||||
if let Ok(v) = key.into_any::<RuneStringKey>() {
|
||||
return self.0.has_flag(&v.0);
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
#[rune::function]
|
||||
fn get_type(&self, index: usize) -> anyhow::Result<i64> { self.0.get_type(index).map(|t| u8::from(t) as i64) }
|
||||
|
||||
#[rune::function]
|
||||
fn get_base_stat(&self, statistic: Statistic) -> u16 { self.0.get_base_stat(statistic) }
|
||||
|
||||
#[rune::function]
|
||||
fn get_ability(&self, hidden: bool, index: i64) -> anyhow::Result<Value> {
|
||||
if index > u8::MAX as i64 || index < 0 {
|
||||
return Err(anyhow::anyhow!("Index out of bounds"));
|
||||
}
|
||||
let index = index as u8;
|
||||
self.0.get_ability(AbilityIndex { hidden, index }).map(|a| a.wrap())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::super::super::tests::{execute_vm, setup_script};
|
||||
use super::*;
|
||||
use crate::static_data::tests::MockForm;
|
||||
use crate::static_data::{StaticStatisticSet, TypeIdentifier};
|
||||
|
||||
#[test]
|
||||
fn test_form_name() -> anyhow::Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_form(form) {
|
||||
let name = form.name();
|
||||
assert_eq!(name, "TestForm");
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let mut form = MockForm::new();
|
||||
form.expect_name().once().return_const(StringKey::new("TestForm"));
|
||||
let form: Arc<dyn Form> = Arc::new(form);
|
||||
let wrapped = form.wrap();
|
||||
execute_vm!(&mut vm, "test_form", wrapped);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_form_height() -> anyhow::Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_form(form) {
|
||||
let height = form.height();
|
||||
assert_eq!(height, 1.0);
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let mut form = MockForm::new();
|
||||
form.expect_height().once().return_const(1.0);
|
||||
let form: Arc<dyn Form> = Arc::new(form);
|
||||
let wrapped = form.wrap();
|
||||
execute_vm!(&mut vm, "test_form", wrapped);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_form_weight() -> anyhow::Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_form(form) {
|
||||
let weight = form.weight();
|
||||
assert_eq!(weight, 1.0);
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let mut form = MockForm::new();
|
||||
form.expect_weight().once().return_const(1.0);
|
||||
let form: Arc<dyn Form> = Arc::new(form);
|
||||
let wrapped = form.wrap();
|
||||
execute_vm!(&mut vm, "test_form", wrapped);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_form_base_experience() -> anyhow::Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_form(form) {
|
||||
let base_experience = form.base_experience();
|
||||
assert_eq!(base_experience, 1);
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let mut form = MockForm::new();
|
||||
form.expect_base_experience().once().return_const(1u32);
|
||||
let form: Arc<dyn Form> = Arc::new(form);
|
||||
let wrapped = form.wrap();
|
||||
execute_vm!(&mut vm, "test_form", wrapped);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_form_types() -> anyhow::Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_form(form) {
|
||||
let types = form.types();
|
||||
assert_eq!(types[0], 1);
|
||||
assert_eq!(types[1], 2);
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let mut form = MockForm::new();
|
||||
form.expect_types()
|
||||
.once()
|
||||
.return_const(vec![TypeIdentifier::from(1u8), TypeIdentifier::from(2u8)]);
|
||||
let form: Arc<dyn Form> = Arc::new(form);
|
||||
let wrapped = form.wrap();
|
||||
execute_vm!(&mut vm, "test_form", wrapped);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_form_base_stats() -> anyhow::Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_form(form) {
|
||||
let base_stats = form.base_stats();
|
||||
assert_eq!(base_stats.hp(), 1);
|
||||
assert_eq!(base_stats.attack(), 2);
|
||||
assert_eq!(base_stats.defense(), 3);
|
||||
assert_eq!(base_stats.special_attack(), 4);
|
||||
assert_eq!(base_stats.special_defense(), 5);
|
||||
assert_eq!(base_stats.speed(), 6);
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let mut form = MockForm::new();
|
||||
form.expect_base_stats()
|
||||
.once()
|
||||
.return_const(Arc::new(StaticStatisticSet::<u16>::new(1, 2, 3, 4, 5, 6)));
|
||||
let form: Arc<dyn Form> = Arc::new(form);
|
||||
let wrapped = form.wrap();
|
||||
execute_vm!(&mut vm, "test_form", wrapped);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_form_abilities() -> anyhow::Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_form(form) {
|
||||
let abilities = form.abilities();
|
||||
assert_eq!(abilities.len(), 1);
|
||||
assert_eq!(abilities[0], "TestAbility");
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let mut form = MockForm::new();
|
||||
form.expect_abilities()
|
||||
.once()
|
||||
.return_const(vec![StringKey::new("TestAbility")]);
|
||||
let form: Arc<dyn Form> = Arc::new(form);
|
||||
let wrapped = form.wrap();
|
||||
execute_vm!(&mut vm, "test_form", wrapped);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_form_hidden_abilities() -> anyhow::Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_form(form) {
|
||||
let abilities = form.hidden_abilities();
|
||||
assert_eq!(abilities.len(), 1);
|
||||
assert_eq!(abilities[0], "TestAbility");
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let mut form = MockForm::new();
|
||||
form.expect_hidden_abilities()
|
||||
.once()
|
||||
.return_const(vec![StringKey::new("TestAbility")]);
|
||||
let form: Arc<dyn Form> = Arc::new(form);
|
||||
let wrapped = form.wrap();
|
||||
execute_vm!(&mut vm, "test_form", wrapped);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_form_has_flag() -> anyhow::Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_form(form) {
|
||||
let has_flag = form.has_flag("test_key");
|
||||
assert_eq!(has_flag, true);
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let mut form = MockForm::new();
|
||||
form.expect_has_flag().once().return_const(true);
|
||||
let form: Arc<dyn Form> = Arc::new(form);
|
||||
let wrapped = form.wrap();
|
||||
execute_vm!(&mut vm, "test_form", wrapped);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_form_get_type() -> anyhow::Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_form(form) {
|
||||
let type_id = form.get_type(0)?;
|
||||
assert_eq!(type_id, 1);
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let mut form = MockForm::new();
|
||||
form.expect_get_type()
|
||||
.once()
|
||||
.returning(|_| Ok(TypeIdentifier::from(1u8)));
|
||||
let form: Arc<dyn Form> = Arc::new(form);
|
||||
let wrapped = form.wrap();
|
||||
execute_vm!(&mut vm, "test_form", wrapped);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_form_get_base_stat() -> anyhow::Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_form(form) {
|
||||
let base_stat = form.get_base_stat(Statistic::HP);
|
||||
assert_eq!(base_stat, 1);
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let mut form = MockForm::new();
|
||||
form.expect_get_base_stat()
|
||||
.once()
|
||||
.return_const(StaticStatisticSet::<u16>::new(1, 2, 3, 4, 5, 6).hp());
|
||||
let form: Arc<dyn Form> = Arc::new(form);
|
||||
let wrapped = form.wrap();
|
||||
execute_vm!(&mut vm, "test_form", wrapped);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_form_get_ability() -> anyhow::Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_form(form) {
|
||||
let ability = form.get_ability(false, 0)?;
|
||||
assert_eq!(ability, "TestAbility");
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let mut form = MockForm::new();
|
||||
form.expect_get_ability()
|
||||
.once()
|
||||
.returning(move |_| Ok(StringKey::new("TestAbility")));
|
||||
let form: Arc<dyn Form> = Arc::new(form);
|
||||
let wrapped = form.wrap();
|
||||
execute_vm!(&mut vm, "test_form", wrapped);
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
use crate::defines::LevelInt;
|
||||
use crate::script_implementations::rune::wrappers::impl_rune_wrapper;
|
||||
use crate::static_data::GrowthRate;
|
||||
use rune::Any;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<RuneGrowthRate>()?;
|
||||
module.function_meta(RuneGrowthRate::calculate_level)?;
|
||||
module.function_meta(RuneGrowthRate::calculate_experience)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Any)]
|
||||
pub struct RuneGrowthRate(Arc<dyn GrowthRate>);
|
||||
|
||||
impl_rune_wrapper!(&Arc<dyn GrowthRate>, RuneGrowthRate);
|
||||
|
||||
impl RuneGrowthRate {
|
||||
#[rune::function]
|
||||
fn calculate_level(&self, experience: u32) -> i32 { self.0.calculate_level(experience) as i32 }
|
||||
|
||||
#[rune::function]
|
||||
fn calculate_experience(&self, level: i64) -> Result<u32, String> {
|
||||
if level < 0 {
|
||||
return Err("Level cannot be negative".to_string());
|
||||
}
|
||||
if level > LevelInt::MAX as i64 {
|
||||
return Err(format!("Level cannot be greater than {}", LevelInt::MAX));
|
||||
}
|
||||
let level = level as LevelInt;
|
||||
|
||||
self.0.calculate_experience(level).map_err(|e| e.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::super::super::tests::{execute_vm, setup_script};
|
||||
use super::*;
|
||||
use crate::script_implementations::rune::wrappers::RuneWrapper;
|
||||
use crate::static_data::tests::MockGrowthRate;
|
||||
|
||||
#[test]
|
||||
fn test_calculate_level() -> anyhow::Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_growth_rate(growth_rate) {
|
||||
let level = growth_rate.calculate_level(10);
|
||||
assert_eq!(level, 10);
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let mut growth_rate = MockGrowthRate::new();
|
||||
growth_rate.expect_calculate_level().returning(|_| 10);
|
||||
let growth_rate: Arc<dyn GrowthRate> = Arc::new(growth_rate);
|
||||
let wrapped = growth_rate.wrap();
|
||||
execute_vm!(&mut vm, "test_growth_rate", wrapped);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_calculate_experience() -> anyhow::Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_growth_rate(growth_rate) {
|
||||
let experience = growth_rate.calculate_experience(10)?;
|
||||
assert_eq!(experience, 10);
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let mut growth_rate = MockGrowthRate::new();
|
||||
growth_rate.expect_calculate_experience().returning(|_| Ok(10));
|
||||
let growth_rate: Arc<dyn GrowthRate> = Arc::new(growth_rate);
|
||||
let wrapped = growth_rate.wrap();
|
||||
execute_vm!(&mut vm, "test_growth_rate", wrapped);
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use rune::runtime::Value;
|
||||
use rune::Any;
|
||||
|
||||
use crate::script_implementations::rune::wrappers::{impl_rune_wrapper, RuneStringKey, RuneWrapper};
|
||||
use crate::static_data::{BattleItemCategory, Item, ItemCategory};
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<ItemCategory>()?;
|
||||
module.ty::<BattleItemCategory>()?;
|
||||
|
||||
module.ty::<RuneItem>()?;
|
||||
module.function_meta(RuneItem::name)?;
|
||||
module.function_meta(RuneItem::category)?;
|
||||
module.function_meta(RuneItem::battle_category)?;
|
||||
module.function_meta(RuneItem::price)?;
|
||||
module.function_meta(RuneItem::flags)?;
|
||||
module.function_meta(RuneItem::has_flag)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Any)]
|
||||
pub struct RuneItem(pub Arc<dyn Item>);
|
||||
|
||||
impl_rune_wrapper!(&Arc<dyn Item>, RuneItem);
|
||||
|
||||
impl RuneItem {
|
||||
#[rune::function]
|
||||
fn name(&self) -> Value { self.0.name().clone().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn category(&self) -> ItemCategory { self.0.category() }
|
||||
|
||||
#[rune::function]
|
||||
fn battle_category(&self) -> BattleItemCategory { self.0.battle_category() }
|
||||
|
||||
#[rune::function]
|
||||
fn price(&self) -> i32 { self.0.price() }
|
||||
|
||||
#[rune::function]
|
||||
fn flags(&self) -> Vec<Value> { self.0.flags().iter().map(|s| s.clone().wrap()).collect() }
|
||||
|
||||
#[rune::function]
|
||||
fn has_flag(&self, key: &RuneStringKey) -> bool { self.0.has_flag(&key.0) }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::super::super::tests::{execute_vm, setup_script};
|
||||
use super::*;
|
||||
use crate::static_data::tests::MockItem;
|
||||
use crate::StringKey;
|
||||
|
||||
#[test]
|
||||
fn test_get_name() -> anyhow::Result<()> {
|
||||
let mut vm = setup_script(
|
||||
r#"
|
||||
pub fn test_item(item) {
|
||||
let name = item.name();
|
||||
assert_eq!(name, "Test Item");
|
||||
}
|
||||
"#,
|
||||
)?;
|
||||
let mut item = MockItem::new();
|
||||
item.expect_name().once().return_const(StringKey::new("Test Item"));
|
||||
let item: Arc<dyn Item> = Arc::new(item);
|
||||
let wrapped = item.wrap();
|
||||
execute_vm!(&mut vm, "test_item", wrapped);
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
use crate::defines::LevelInt;
|
||||
use crate::script_implementations::rune::wrappers::{impl_rune_wrapper, RuneStringKey, RuneWrapper};
|
||||
use crate::static_data::LearnableMoves;
|
||||
use rune::runtime::Value;
|
||||
use rune::Any;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<RuneLearnableMoves>()?;
|
||||
module.function_meta(RuneLearnableMoves::get_learned_by_level)?;
|
||||
module.function_meta(RuneLearnableMoves::get_distinct_level_moves)?;
|
||||
module.function_meta(RuneLearnableMoves::learns_move)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Any)]
|
||||
pub struct RuneLearnableMoves(Arc<dyn LearnableMoves>);
|
||||
|
||||
impl_rune_wrapper!(&Arc<dyn LearnableMoves>, RuneLearnableMoves);
|
||||
|
||||
impl RuneLearnableMoves {
|
||||
#[rune::function]
|
||||
fn get_learned_by_level(&self, level: LevelInt) -> Option<Vec<Value>> {
|
||||
self.0
|
||||
.get_learned_by_level(level)
|
||||
.map(|v| v.into_iter().map(|s| s.wrap()).collect())
|
||||
}
|
||||
|
||||
#[rune::function]
|
||||
fn get_distinct_level_moves(&self) -> Vec<Value> {
|
||||
self.0
|
||||
.get_distinct_level_moves()
|
||||
.into_iter()
|
||||
.map(|s| s.wrap())
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[rune::function]
|
||||
fn learns_move(&self, moveName: &RuneStringKey) -> bool { self.0.get_distinct_level_moves().contains(&moveName.0) }
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
use crate::defines::LevelInt;
|
||||
use crate::script_implementations::rune::wrappers::{impl_rune_wrapper, RuneStringKey};
|
||||
use crate::static_data::GrowthRateLibrary;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<RuneGrowthRateLibrary>()?;
|
||||
module.function_meta(RuneGrowthRateLibrary::calculate_level)?;
|
||||
module.function_meta(RuneGrowthRateLibrary::calculate_experience)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, rune::Any)]
|
||||
struct RuneGrowthRateLibrary(Arc<dyn GrowthRateLibrary>);
|
||||
|
||||
impl_rune_wrapper!(&Arc<dyn GrowthRateLibrary>, RuneGrowthRateLibrary);
|
||||
|
||||
impl RuneGrowthRateLibrary {
|
||||
#[rune::function]
|
||||
fn calculate_level(&self, growth_rate: &RuneStringKey, experience: u32) -> anyhow::Result<LevelInt> {
|
||||
self.0.calculate_level(&growth_rate.0, experience)
|
||||
}
|
||||
|
||||
#[rune::function]
|
||||
fn calculate_experience(&self, growth_rate: &RuneStringKey, level: LevelInt) -> anyhow::Result<u32> {
|
||||
self.0.calculate_experience(&growth_rate.0, level)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
use crate::script_implementations::rune::wrappers::impl_rune_wrapper;
|
||||
use crate::static_data::LibrarySettings;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<RuneLibrarySettings>()?;
|
||||
module.function_meta(RuneLibrarySettings::maximum_level)?;
|
||||
module.function_meta(RuneLibrarySettings::shiny_rate)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, rune::Any)]
|
||||
struct RuneLibrarySettings(Arc<dyn LibrarySettings>);
|
||||
|
||||
impl_rune_wrapper!(&Arc<dyn LibrarySettings>, RuneLibrarySettings);
|
||||
|
||||
impl RuneLibrarySettings {
|
||||
#[rune::function]
|
||||
fn maximum_level(&self) -> i64 { self.0.maximum_level() as i64 }
|
||||
|
||||
#[rune::function]
|
||||
fn shiny_rate(&self) -> i64 { self.0.shiny_rate() as i64 }
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
mod growth_rate_library;
|
||||
mod library_settings;
|
||||
mod nature_library;
|
||||
pub mod static_data;
|
||||
mod type_library;
|
||||
|
||||
use crate::script_implementations::rune::wrappers::{impl_rune_wrapper, RuneStringKey, RuneWrapper};
|
||||
use crate::static_data::{AbilityLibrary, ItemLibrary, MoveLibrary, SpeciesLibrary};
|
||||
use rune::runtime::Value;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<RuneAbilityLibrary>()?;
|
||||
module.function_meta(RuneAbilityLibrary::get)?;
|
||||
module.function_meta(RuneAbilityLibrary::len)?;
|
||||
module.function_meta(RuneAbilityLibrary::get_key_by_index)?;
|
||||
|
||||
module.ty::<RuneItemLibrary>()?;
|
||||
module.function_meta(RuneItemLibrary::get)?;
|
||||
module.function_meta(RuneItemLibrary::len)?;
|
||||
module.function_meta(RuneItemLibrary::get_key_by_index)?;
|
||||
|
||||
module.ty::<RuneMoveLibrary>()?;
|
||||
module.function_meta(RuneMoveLibrary::get)?;
|
||||
module.function_meta(RuneMoveLibrary::len)?;
|
||||
module.function_meta(RuneMoveLibrary::get_key_by_index)?;
|
||||
|
||||
module.ty::<RuneSpeciesLibrary>()?;
|
||||
module.function_meta(RuneSpeciesLibrary::get)?;
|
||||
module.function_meta(RuneSpeciesLibrary::len)?;
|
||||
module.function_meta(RuneSpeciesLibrary::get_key_by_index)?;
|
||||
|
||||
growth_rate_library::register(module)?;
|
||||
library_settings::register(module)?;
|
||||
nature_library::register(module)?;
|
||||
type_library::register(module)?;
|
||||
|
||||
static_data::register(module)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
macro_rules! impl_rune_data_library_wrapper {
|
||||
($t:ident, $wrapped_type:ty) => {
|
||||
#[derive(Debug, rune::Any)]
|
||||
struct $t($wrapped_type);
|
||||
|
||||
impl_rune_wrapper!(&$wrapped_type, $t);
|
||||
|
||||
impl $t {
|
||||
#[rune::function]
|
||||
fn get(&self, key: &RuneStringKey) -> Option<Value> { self.0.get(&key.0).map(|v| v.wrap()) }
|
||||
|
||||
#[rune::function]
|
||||
fn len(&self) -> usize { self.0.len() }
|
||||
|
||||
#[rune::function]
|
||||
fn get_key_by_index(&self, index: usize) -> Option<Value> {
|
||||
self.0.get_key_by_index(index).map(|v| v.wrap())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_rune_data_library_wrapper!(RuneAbilityLibrary, Arc<dyn AbilityLibrary>);
|
||||
impl_rune_data_library_wrapper!(RuneItemLibrary, Arc<dyn ItemLibrary>);
|
||||
impl_rune_data_library_wrapper!(RuneMoveLibrary, Arc<dyn MoveLibrary>);
|
||||
impl_rune_data_library_wrapper!(RuneSpeciesLibrary, Arc<dyn SpeciesLibrary>);
|
|
@ -0,0 +1,27 @@
|
|||
use crate::script_implementations::rune::wrappers::static_data::nature::RuneNature;
|
||||
use crate::script_implementations::rune::wrappers::{impl_rune_wrapper, RuneStringKey, RuneWrapper};
|
||||
use crate::static_data::NatureLibrary;
|
||||
use rune::runtime::Value;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<RuneNatureLibrary>()?;
|
||||
module.function_meta(RuneNatureLibrary::get_nature)?;
|
||||
module.function_meta(RuneNatureLibrary::get_nature_name)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, rune::Any)]
|
||||
struct RuneNatureLibrary(Arc<dyn NatureLibrary>);
|
||||
|
||||
impl_rune_wrapper!(&Arc<dyn NatureLibrary>, RuneNatureLibrary);
|
||||
|
||||
impl RuneNatureLibrary {
|
||||
#[rune::function]
|
||||
fn get_nature(&self, key: RuneStringKey) -> Option<Value> { self.0.get_nature(&key.0).map(|v| v.wrap()) }
|
||||
|
||||
#[rune::function]
|
||||
fn get_nature_name(&self, nature: &RuneNature) -> RuneStringKey {
|
||||
RuneStringKey(self.0.get_nature_name(&nature.0).unwrap())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
use crate::script_implementations::rune::wrappers::{impl_rune_wrapper, RuneWrapper};
|
||||
use crate::static_data::StaticData;
|
||||
use rune::runtime::Value;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<RuneStaticData>()?;
|
||||
module.function_meta(RuneStaticData::settings)?;
|
||||
module.function_meta(RuneStaticData::species)?;
|
||||
module.function_meta(RuneStaticData::moves)?;
|
||||
module.function_meta(RuneStaticData::items)?;
|
||||
module.function_meta(RuneStaticData::growth_rates)?;
|
||||
module.function_meta(RuneStaticData::types)?;
|
||||
module.function_meta(RuneStaticData::natures)?;
|
||||
module.function_meta(RuneStaticData::abilities)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, rune::Any)]
|
||||
pub struct RuneStaticData(pub Arc<dyn StaticData>);
|
||||
|
||||
impl_rune_wrapper!(&Arc<dyn StaticData>, RuneStaticData);
|
||||
|
||||
impl RuneStaticData {
|
||||
#[rune::function]
|
||||
fn settings(&self) -> Value { self.0.settings().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn species(&self) -> Value { self.0.species().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn moves(&self) -> Value { self.0.moves().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn items(&self) -> Value { self.0.items().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn growth_rates(&self) -> Value { self.0.growth_rates().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn types(&self) -> Value { self.0.types().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn natures(&self) -> Value { self.0.natures().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn abilities(&self) -> Value { self.0.abilities().wrap() }
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
use crate::script_implementations::rune::wrappers::{impl_rune_wrapper, RuneStringKey, RuneWrapper};
|
||||
use crate::static_data::TypeLibrary;
|
||||
use rune::runtime::Value;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<RuneTypeLibrary>()?;
|
||||
module.function_meta(RuneTypeLibrary::get_type_id)?;
|
||||
module.function_meta(RuneTypeLibrary::get_type_name)?;
|
||||
module.function_meta(RuneTypeLibrary::get_single_effectiveness)?;
|
||||
module.function_meta(RuneTypeLibrary::get_effectiveness)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, rune::Any)]
|
||||
struct RuneTypeLibrary(Arc<dyn TypeLibrary>);
|
||||
|
||||
impl_rune_wrapper!(&Arc<dyn TypeLibrary>, RuneTypeLibrary);
|
||||
|
||||
impl RuneTypeLibrary {
|
||||
#[rune::function]
|
||||
fn get_type_id(&self, key: &RuneStringKey) -> Option<u8> { self.0.get_type_id(&key.0).map(|v| v.into()) }
|
||||
|
||||
#[rune::function]
|
||||
fn get_type_name(&self, t: u8) -> Option<Value> { self.0.get_type_name(t.into()).map(|v| v.wrap()) }
|
||||
|
||||
#[rune::function]
|
||||
fn get_single_effectiveness(&self, attacking: u8, defending: u8) -> anyhow::Result<f32> {
|
||||
self.0.get_single_effectiveness(attacking.into(), defending.into())
|
||||
}
|
||||
|
||||
#[rune::function]
|
||||
fn get_effectiveness(&self, attacking: u8, defending: &[u8]) -> anyhow::Result<f32> {
|
||||
self.0.get_effectiveness(
|
||||
attacking.into(),
|
||||
&defending.iter().map(|v| (*v).into()).collect::<Vec<_>>(),
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
mod ability;
|
||||
pub mod form;
|
||||
mod growth_rate;
|
||||
pub mod item;
|
||||
mod learnable_moves;
|
||||
pub mod libraries;
|
||||
mod move_data;
|
||||
mod nature;
|
||||
mod species;
|
||||
mod statistic_set;
|
||||
|
||||
use crate::static_data::{Gender, Statistic, TimeOfDay};
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<TimeOfDay>()?;
|
||||
module.ty::<Statistic>()?;
|
||||
module.ty::<Gender>()?;
|
||||
statistic_set::register(module)?;
|
||||
nature::register(module)?;
|
||||
item::register(module)?;
|
||||
growth_rate::register(module)?;
|
||||
form::register(module)?;
|
||||
ability::register(module)?;
|
||||
learnable_moves::register(module)?;
|
||||
species::register(module)?;
|
||||
move_data::register(module)?;
|
||||
|
||||
libraries::register(module)?;
|
||||
Ok(())
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
use crate::script_implementations::rune::wrappers::{impl_rune_wrapper, RuneStringKey, RuneWrapper};
|
||||
use crate::static_data::{MoveCategory, MoveData, MoveTarget, SecondaryEffect};
|
||||
use rune::runtime::{Object, Value};
|
||||
use rune::Any;
|
||||
use std::convert::TryFrom;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<MoveCategory>()?;
|
||||
module.ty::<MoveTarget>()?;
|
||||
module.ty::<RuneMoveData>()?;
|
||||
module.function_meta(RuneMoveData::name)?;
|
||||
module.function_meta(RuneMoveData::move_type)?;
|
||||
module.function_meta(RuneMoveData::category)?;
|
||||
module.function_meta(RuneMoveData::base_power)?;
|
||||
module.function_meta(RuneMoveData::accuracy)?;
|
||||
module.function_meta(RuneMoveData::base_usages)?;
|
||||
module.function_meta(RuneMoveData::target)?;
|
||||
module.function_meta(RuneMoveData::priority)?;
|
||||
module.function_meta(RuneMoveData::secondary_effect)?;
|
||||
module.function_meta(RuneMoveData::has_flag)?;
|
||||
|
||||
module.ty::<RuneSecondaryEffect>()?;
|
||||
module.function_meta(RuneSecondaryEffect::chance)?;
|
||||
module.function_meta(RuneSecondaryEffect::effect_name)?;
|
||||
module.function_meta(RuneSecondaryEffect::parameters)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Any)]
|
||||
pub struct RuneMoveData(Arc<dyn MoveData>);
|
||||
|
||||
impl_rune_wrapper!(&Arc<dyn MoveData>, RuneMoveData);
|
||||
|
||||
impl RuneMoveData {
|
||||
#[rune::function]
|
||||
fn name(&self) -> Value { self.0.name().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn move_type(&self) -> u8 { u8::from(self.0.move_type()) }
|
||||
|
||||
#[rune::function]
|
||||
fn category(&self) -> MoveCategory { self.0.category() }
|
||||
|
||||
#[rune::function]
|
||||
fn base_power(&self) -> u8 { self.0.base_power() }
|
||||
|
||||
#[rune::function]
|
||||
fn accuracy(&self) -> u8 { self.0.accuracy() }
|
||||
|
||||
#[rune::function]
|
||||
fn base_usages(&self) -> u8 { self.0.base_usages() }
|
||||
|
||||
#[rune::function]
|
||||
fn target(&self) -> MoveTarget { self.0.target() }
|
||||
|
||||
#[rune::function]
|
||||
fn priority(&self) -> i8 { self.0.priority() }
|
||||
|
||||
#[rune::function]
|
||||
fn secondary_effect(&self) -> Option<Value> { self.0.secondary_effect().as_ref().map(|x| x.wrap()) }
|
||||
|
||||
#[rune::function]
|
||||
fn has_flag(&self, flag: RuneStringKey) -> bool { self.0.has_flag(&flag.0) }
|
||||
}
|
||||
|
||||
#[derive(Debug, Any)]
|
||||
pub struct RuneSecondaryEffect(Arc<dyn SecondaryEffect>);
|
||||
|
||||
impl_rune_wrapper!(&Arc<dyn SecondaryEffect>, RuneSecondaryEffect);
|
||||
|
||||
impl RuneSecondaryEffect {
|
||||
#[rune::function]
|
||||
fn chance(&self) -> f32 { self.0.chance() }
|
||||
|
||||
#[rune::function]
|
||||
fn effect_name(&self) -> Value { self.0.effect_name().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn parameters(&self) -> anyhow::Result<Object> {
|
||||
let pars = self.0.parameters();
|
||||
let mut o = Object::with_capacity(pars.len())?;
|
||||
for (key, value) in pars.iter() {
|
||||
o.insert(rune::alloc::String::try_from(key.str())?, Value::from(value.wrap()))?;
|
||||
}
|
||||
Ok(o)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
use crate::script_implementations::rune::wrappers::impl_rune_wrapper;
|
||||
use crate::static_data::{Nature, Statistic};
|
||||
use rune::Any;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<RuneNature>()?;
|
||||
module.function_meta(RuneNature::increased_stat)?;
|
||||
module.function_meta(RuneNature::decreased_stat)?;
|
||||
module.function_meta(RuneNature::increased_modifier)?;
|
||||
module.function_meta(RuneNature::decreased_modifier)?;
|
||||
module.function_meta(RuneNature::get_stat_modifier)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Any)]
|
||||
pub struct RuneNature(pub Arc<dyn Nature>);
|
||||
|
||||
impl_rune_wrapper!(&Arc<dyn Nature>, RuneNature);
|
||||
|
||||
impl RuneNature {
|
||||
#[rune::function]
|
||||
fn increased_stat(&self) -> Statistic { self.0.increased_stat() }
|
||||
|
||||
#[rune::function]
|
||||
fn decreased_stat(&self) -> Statistic { self.0.decreased_stat() }
|
||||
|
||||
#[rune::function]
|
||||
fn increased_modifier(&self) -> f32 { self.0.increased_modifier() }
|
||||
|
||||
#[rune::function]
|
||||
fn decreased_modifier(&self) -> f32 { self.0.decreased_modifier() }
|
||||
|
||||
#[rune::function]
|
||||
fn get_stat_modifier(&self, stat: Statistic) -> f32 { self.0.get_stat_modifier(stat) }
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
use crate::script_implementations::rune::wrappers::{impl_rune_wrapper, RuneStringKey, RuneWrapper};
|
||||
use crate::static_data::Species;
|
||||
use rune::runtime::Value;
|
||||
use rune::Any;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<RuneSpecies>()?;
|
||||
module.function_meta(RuneSpecies::id)?;
|
||||
module.function_meta(RuneSpecies::name)?;
|
||||
module.function_meta(RuneSpecies::gender_rate)?;
|
||||
module.function_meta(RuneSpecies::growth_rate)?;
|
||||
module.function_meta(RuneSpecies::capture_rate)?;
|
||||
module.function_meta(RuneSpecies::base_happiness)?;
|
||||
module.function_meta(RuneSpecies::get_form)?;
|
||||
module.function_meta(RuneSpecies::get_default_form)?;
|
||||
module.function_meta(RuneSpecies::has_flag)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Any)]
|
||||
pub struct RuneSpecies(Arc<dyn Species>);
|
||||
|
||||
impl_rune_wrapper!(&Arc<dyn Species>, RuneSpecies);
|
||||
|
||||
impl RuneSpecies {
|
||||
#[rune::function]
|
||||
fn id(&self) -> u16 { self.0.id() }
|
||||
|
||||
#[rune::function]
|
||||
fn name(&self) -> Value { self.0.name().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn gender_rate(&self) -> f32 { self.0.gender_rate() }
|
||||
|
||||
#[rune::function]
|
||||
fn growth_rate(&self) -> Value { self.0.growth_rate().wrap() }
|
||||
|
||||
#[rune::function]
|
||||
fn capture_rate(&self) -> u8 { self.0.capture_rate() }
|
||||
|
||||
#[rune::function]
|
||||
fn base_happiness(&self) -> u8 { self.0.base_happiness() }
|
||||
|
||||
#[rune::function]
|
||||
fn get_form(&self, name: &RuneStringKey) -> Option<Value> { self.0.get_form(&name.0).map(|form| form.wrap()) }
|
||||
|
||||
#[rune::function]
|
||||
fn get_default_form(&self) -> anyhow::Result<Value> { self.0.get_default_form().map(|v| v.wrap()) }
|
||||
|
||||
#[rune::function]
|
||||
fn has_flag(&self, key: &RuneStringKey) -> bool { self.0.has_flag(&key.0) }
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
use crate::script_implementations::rune::wrappers::impl_rune_wrapper;
|
||||
use crate::static_data::{StaticStatisticSet, Statistic, StatisticSet};
|
||||
use rune::Any;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<RuneU32StatisticSet>()?;
|
||||
module.function_meta(RuneU32StatisticSet::get)?;
|
||||
module.function_meta(RuneU32StatisticSet::set)?;
|
||||
module.function_meta(RuneU32StatisticSet::hp)?;
|
||||
module.function_meta(RuneU32StatisticSet::attack)?;
|
||||
module.function_meta(RuneU32StatisticSet::defense)?;
|
||||
module.function_meta(RuneU32StatisticSet::special_attack)?;
|
||||
module.function_meta(RuneU32StatisticSet::special_defense)?;
|
||||
module.function_meta(RuneU32StatisticSet::speed)?;
|
||||
|
||||
module.ty::<RuneStaticStatisticSet>()?;
|
||||
module.function_meta(RuneStaticStatisticSet::get)?;
|
||||
module.function_meta(RuneStaticStatisticSet::hp)?;
|
||||
module.function_meta(RuneStaticStatisticSet::attack)?;
|
||||
module.function_meta(RuneStaticStatisticSet::defense)?;
|
||||
module.function_meta(RuneStaticStatisticSet::special_attack)?;
|
||||
module.function_meta(RuneStaticStatisticSet::special_defense)?;
|
||||
module.function_meta(RuneStaticStatisticSet::speed)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Any)]
|
||||
pub struct RuneU32StatisticSet(Arc<StatisticSet<u32>>);
|
||||
|
||||
impl_rune_wrapper!(&Arc<StatisticSet<u32>>, RuneU32StatisticSet);
|
||||
impl RuneU32StatisticSet {
|
||||
#[rune::function]
|
||||
fn get(&self, stat: Statistic) -> u32 { self.0.get_stat(stat) }
|
||||
|
||||
#[rune::function]
|
||||
fn set(&mut self, stat: Statistic, value: u32) { self.0.set_stat(stat, value) }
|
||||
|
||||
#[rune::function]
|
||||
fn hp(&self) -> u32 { self.0.hp() }
|
||||
|
||||
#[rune::function]
|
||||
fn attack(&self) -> u32 { self.0.attack() }
|
||||
|
||||
#[rune::function]
|
||||
fn defense(&self) -> u32 { self.0.defense() }
|
||||
|
||||
#[rune::function]
|
||||
fn special_attack(&self) -> u32 { self.0.special_attack() }
|
||||
|
||||
#[rune::function]
|
||||
fn special_defense(&self) -> u32 { self.0.special_defense() }
|
||||
|
||||
#[rune::function]
|
||||
fn speed(&self) -> u32 { self.0.speed() }
|
||||
}
|
||||
|
||||
#[derive(Debug, Any)]
|
||||
pub struct RuneStaticStatisticSet(Arc<StaticStatisticSet<u16>>);
|
||||
|
||||
impl_rune_wrapper!(&Arc<StaticStatisticSet<u16>>, RuneStaticStatisticSet);
|
||||
|
||||
impl RuneStaticStatisticSet {
|
||||
#[rune::function]
|
||||
fn get(&self, stat: Statistic) -> u16 { self.0.get_stat(stat) }
|
||||
|
||||
#[rune::function]
|
||||
fn hp(&self) -> u16 { self.0.hp() }
|
||||
|
||||
#[rune::function]
|
||||
fn attack(&self) -> u16 { self.0.attack() }
|
||||
|
||||
#[rune::function]
|
||||
fn defense(&self) -> u16 { self.0.defense() }
|
||||
|
||||
#[rune::function]
|
||||
fn special_attack(&self) -> u16 { self.0.special_attack() }
|
||||
|
||||
#[rune::function]
|
||||
fn special_defense(&self) -> u16 { self.0.special_defense() }
|
||||
|
||||
#[rune::function]
|
||||
pub fn speed(&self) -> u16 { self.0.speed() }
|
||||
}
|
|
@ -2,9 +2,10 @@ use crate::defines::LevelInt;
|
|||
use crate::VecExt;
|
||||
use anyhow::Result;
|
||||
use anyhow_ext::ensure;
|
||||
use std::fmt::Debug;
|
||||
|
||||
/// A growth rate defines how much experience is required per level.
|
||||
pub trait GrowthRate {
|
||||
pub trait GrowthRate: Debug {
|
||||
/// Calculate the level something with this growth rate would have at a certain experience.
|
||||
fn calculate_level(&self, experience: u32) -> LevelInt;
|
||||
/// Calculate the experience something with this growth rate would have at a certain level.
|
||||
|
@ -12,6 +13,7 @@ pub trait GrowthRate {
|
|||
}
|
||||
|
||||
/// An implementation of the growth rate that uses a lookup table for experience.
|
||||
#[derive(Debug)]
|
||||
pub struct LookupGrowthRate {
|
||||
/// The lookup Vec.
|
||||
experience: Vec<u32>,
|
||||
|
@ -20,9 +22,7 @@ pub struct LookupGrowthRate {
|
|||
impl LookupGrowthRate {
|
||||
/// Instantiates a new lookup growth rate. The experience vec should be the amount of experience
|
||||
/// required per level, with the first element being the experience required for level 1 (generally 0).
|
||||
pub fn new(experience: Vec<u32>) -> LookupGrowthRate {
|
||||
LookupGrowthRate { experience }
|
||||
}
|
||||
pub fn new(experience: Vec<u32>) -> LookupGrowthRate { LookupGrowthRate { experience } }
|
||||
}
|
||||
|
||||
impl GrowthRate for LookupGrowthRate {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use hashbrown::HashSet;
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[cfg(feature = "serde")] use serde::{Deserialize, Serialize};
|
||||
use std::any::Any;
|
||||
use std::fmt::Debug;
|
||||
|
||||
|
@ -9,40 +8,55 @@ use crate::StringKey;
|
|||
/// An item category defines which bag slot items are stored in.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "rune", derive(rune::Any))]
|
||||
#[repr(u8)]
|
||||
pub enum ItemCategory {
|
||||
/// This is where most items should go.
|
||||
#[cfg_attr(feature = "rune", rune(constructor))]
|
||||
MiscItem,
|
||||
/// Pokeballs are used for capturing Pokemons.
|
||||
#[cfg_attr(feature = "rune", rune(constructor))]
|
||||
Pokeball,
|
||||
/// Medicine is used for healing HP, PP, and status effects
|
||||
#[cfg_attr(feature = "rune", rune(constructor))]
|
||||
Medicine,
|
||||
/// Berry is used for all berries.
|
||||
#[cfg_attr(feature = "rune", rune(constructor))]
|
||||
Berry,
|
||||
/// TMHM is used for Technical and Hidden Machines.
|
||||
#[cfg_attr(feature = "rune", rune(constructor))]
|
||||
TMHM,
|
||||
/// Form Changer is used for items that change forms, such as mega stones.
|
||||
#[cfg_attr(feature = "rune", rune(constructor))]
|
||||
FormChanger,
|
||||
/// Key Items are single stored items, generally used for story progression.
|
||||
#[cfg_attr(feature = "rune", rune(constructor))]
|
||||
KeyItem,
|
||||
/// Mail is used for mail items.
|
||||
#[cfg_attr(feature = "rune", rune(constructor))]
|
||||
Mail,
|
||||
}
|
||||
|
||||
/// A battle item category defines how the item is categorized when in battle.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "rune", derive(rune::Any))]
|
||||
#[repr(u8)]
|
||||
pub enum BattleItemCategory {
|
||||
/// This item can't be used in battle.
|
||||
#[cfg_attr(feature = "rune", rune(constructor))]
|
||||
None,
|
||||
/// This item is used for healing Pokemon.
|
||||
#[cfg_attr(feature = "rune", rune(constructor))]
|
||||
Healing,
|
||||
/// This item is used for healing Pokemon from a status.
|
||||
#[cfg_attr(feature = "rune", rune(constructor))]
|
||||
StatusHealing,
|
||||
/// This item is used for capturing Pokemon.
|
||||
#[cfg_attr(feature = "rune", rune(constructor))]
|
||||
Pokeball,
|
||||
/// This item does not belong in above categories, but is still a battle item.
|
||||
#[cfg_attr(feature = "rune", rune(constructor))]
|
||||
MiscBattleItem,
|
||||
}
|
||||
|
||||
|
@ -99,30 +113,18 @@ impl ItemImpl {
|
|||
|
||||
impl Item for ItemImpl {
|
||||
/// The name of the item.
|
||||
fn name(&self) -> &StringKey {
|
||||
&self.name
|
||||
}
|
||||
fn name(&self) -> &StringKey { &self.name }
|
||||
/// Which bag slot items are stored in.
|
||||
fn category(&self) -> ItemCategory {
|
||||
self.category
|
||||
}
|
||||
fn category(&self) -> ItemCategory { self.category }
|
||||
/// How the item is categorized when in battle.
|
||||
fn battle_category(&self) -> BattleItemCategory {
|
||||
self.battle_category
|
||||
}
|
||||
fn battle_category(&self) -> BattleItemCategory { self.battle_category }
|
||||
/// The buying value of the item.
|
||||
fn price(&self) -> i32 {
|
||||
self.price
|
||||
}
|
||||
fn price(&self) -> i32 { self.price }
|
||||
/// A set of arbitrary flags that can be set on the item.
|
||||
fn flags(&self) -> &HashSet<StringKey> {
|
||||
&self.flags
|
||||
}
|
||||
fn flags(&self) -> &HashSet<StringKey> { &self.flags }
|
||||
|
||||
/// Checks whether the item has a specific flag.
|
||||
fn has_flag(&self, key: &StringKey) -> bool {
|
||||
self.flags.contains(key)
|
||||
}
|
||||
fn has_flag(&self, key: &StringKey) -> bool { self.flags.contains(key) }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -29,12 +29,8 @@ impl AbilityLibraryImpl {
|
|||
impl AbilityLibrary for AbilityLibraryImpl {}
|
||||
|
||||
impl DataLibrary<dyn Ability> for AbilityLibraryImpl {
|
||||
fn map(&self) -> &IndexMap<StringKey, Arc<dyn Ability>> {
|
||||
&self.map
|
||||
}
|
||||
fn get_modify(&mut self) -> &mut IndexMap<StringKey, Arc<dyn Ability>> {
|
||||
&mut self.map
|
||||
}
|
||||
fn map(&self) -> &IndexMap<StringKey, Arc<dyn Ability>> { &self.map }
|
||||
fn get_modify(&mut self) -> &mut IndexMap<StringKey, Arc<dyn Ability>> { &mut self.map }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -45,6 +41,7 @@ pub mod tests {
|
|||
use crate::static_data::AbilityImpl;
|
||||
use crate::static_data::DataLibrary;
|
||||
use crate::StringKey;
|
||||
use hashbrown::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn build() -> AbilityLibraryImpl {
|
||||
|
@ -54,7 +51,7 @@ pub mod tests {
|
|||
Arc::new(AbilityImpl::new(
|
||||
&"test_ability".into(),
|
||||
&"test_ability".into(),
|
||||
Vec::new(),
|
||||
HashMap::new(),
|
||||
)),
|
||||
);
|
||||
lib
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use anyhow_ext::Result;
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
use indexmap::IndexMap;
|
||||
|
@ -8,7 +9,7 @@ use crate::StringKey;
|
|||
|
||||
/// A data library is a collection of methods to set up a default library, where values are stored
|
||||
/// by both key, while keeping their insertion order.
|
||||
pub trait DataLibrary<T: ?Sized> {
|
||||
pub trait DataLibrary<T: ?Sized>: Debug {
|
||||
/// Returns the underlying map.
|
||||
fn map(&self) -> &IndexMap<StringKey, Arc<T>>;
|
||||
/// Returns the underlying map in mutable manner.
|
||||
|
@ -25,32 +26,22 @@ pub trait DataLibrary<T: ?Sized> {
|
|||
fn remove(&self, key: &StringKey) {
|
||||
#[allow(clippy::unwrap_used)] // We know this cant fail.
|
||||
let self_mut = unsafe { (self as *const Self as *mut Self).as_mut() }.unwrap();
|
||||
self_mut.get_modify().remove(key);
|
||||
self_mut.get_modify().swap_remove(key);
|
||||
}
|
||||
|
||||
/// Gets a value from the library.
|
||||
fn get(&self, key: &StringKey) -> Option<Arc<T>> {
|
||||
self.map().get::<StringKey>(key).cloned()
|
||||
}
|
||||
fn get(&self, key: &StringKey) -> Option<Arc<T>> { self.map().get::<StringKey>(key).cloned() }
|
||||
|
||||
/// Gets a value from the library.
|
||||
fn get_by_hash(&self, key: u32) -> Option<Arc<T>> {
|
||||
self.map().get::<u32>(&key).cloned()
|
||||
}
|
||||
fn get_by_hash(&self, key: u32) -> Option<Arc<T>> { self.map().get::<u32>(&key).cloned() }
|
||||
|
||||
/// Gets a value from the library by the index where it is stored.
|
||||
fn get_key_by_index(&self, index: usize) -> Option<StringKey> {
|
||||
self.map().get_index(index).map(|a| a.0.clone())
|
||||
}
|
||||
fn get_key_by_index(&self, index: usize) -> Option<StringKey> { self.map().get_index(index).map(|a| a.0.clone()) }
|
||||
|
||||
/// Gets the amount of values in the library.
|
||||
fn len(&self) -> usize {
|
||||
self.map().len()
|
||||
}
|
||||
fn len(&self) -> usize { self.map().len() }
|
||||
/// Returns whether the library has no values.
|
||||
fn is_empty(&self) -> bool {
|
||||
self.map().is_empty()
|
||||
}
|
||||
fn is_empty(&self) -> bool { self.map().is_empty() }
|
||||
|
||||
/// Gets a random value from the library.
|
||||
fn random_value(&self, rand: &mut Random) -> Result<&Arc<T>> {
|
||||
|
|
|
@ -61,9 +61,7 @@ impl GrowthRateLibrary for GrowthRateLibraryImpl {
|
|||
}
|
||||
|
||||
impl Debug for GrowthRateLibraryImpl {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("GrowthRateLibrary").finish()
|
||||
}
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("GrowthRateLibrary").finish() }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -72,8 +70,6 @@ impl Debug for GrowthRateLibraryImpl {
|
|||
pub mod tests {
|
||||
use super::*;
|
||||
use crate::static_data::growth_rates::LookupGrowthRate;
|
||||
use crate::static_data::libraries::growth_rate_library::GrowthRateLibrary;
|
||||
use crate::static_data::GrowthRateLibraryImpl;
|
||||
|
||||
pub fn build() -> GrowthRateLibraryImpl {
|
||||
let mut lib = GrowthRateLibraryImpl::new(1);
|
||||
|
|
|
@ -38,14 +38,10 @@ impl NatureLibraryImpl {
|
|||
|
||||
impl NatureLibrary for NatureLibraryImpl {
|
||||
/// Adds a new nature with name to the library.
|
||||
fn load_nature(&self, name: StringKey, nature: Arc<dyn Nature>) {
|
||||
self.map.write().insert(name, nature);
|
||||
}
|
||||
fn load_nature(&self, name: StringKey, nature: Arc<dyn Nature>) { self.map.write().insert(name, nature); }
|
||||
|
||||
/// Gets a nature by name.
|
||||
fn get_nature(&self, key: &StringKey) -> Option<Arc<dyn Nature>> {
|
||||
self.map.read().get(key).cloned()
|
||||
}
|
||||
fn get_nature(&self, key: &StringKey) -> Option<Arc<dyn Nature>> { self.map.read().get(key).cloned() }
|
||||
|
||||
fn get_random_nature(&self, rand: &mut Random) -> Result<Arc<dyn Nature>> {
|
||||
let map = self.map.read();
|
||||
|
@ -80,7 +76,7 @@ impl NatureLibrary for NatureLibraryImpl {
|
|||
pub mod tests {
|
||||
use super::*;
|
||||
use crate::static_data::statistics::Statistic;
|
||||
use crate::static_data::{NatureImpl, NatureLibrary, NatureLibraryImpl};
|
||||
use crate::static_data::NatureImpl;
|
||||
|
||||
pub fn build() -> NatureLibraryImpl {
|
||||
let lib = NatureLibraryImpl::new(2);
|
||||
|
|
|
@ -11,27 +11,18 @@ use crate::{PkmnError, StringKey};
|
|||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash, Atom)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[repr(transparent)]
|
||||
pub struct TypeIdentifier {
|
||||
/// The unique internal value.
|
||||
val: u8,
|
||||
}
|
||||
pub struct TypeIdentifier(u8);
|
||||
|
||||
impl From<u8> for TypeIdentifier {
|
||||
fn from(val: u8) -> Self {
|
||||
Self { val }
|
||||
}
|
||||
fn from(val: u8) -> Self { Self(val) }
|
||||
}
|
||||
|
||||
impl From<TypeIdentifier> for u8 {
|
||||
fn from(id: TypeIdentifier) -> Self {
|
||||
id.val
|
||||
}
|
||||
fn from(id: TypeIdentifier) -> Self { id.0 }
|
||||
}
|
||||
|
||||
impl Display for TypeIdentifier {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "TypeId({})", self.val)
|
||||
}
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "TypeId({})", self.0) }
|
||||
}
|
||||
|
||||
/// All data related to types and effectiveness.
|
||||
|
@ -87,18 +78,16 @@ impl TypeLibraryImpl {
|
|||
defending: TypeIdentifier,
|
||||
) -> Result<f32> {
|
||||
Ok(*lock
|
||||
.get((attacking.val - 1) as usize)
|
||||
.get((attacking.0 - 1) as usize)
|
||||
.ok_or(PkmnError::InvalidTypeIdentifier { type_id: attacking })?
|
||||
.get((defending.val - 1) as usize)
|
||||
.get((defending.0 - 1) as usize)
|
||||
.ok_or(PkmnError::InvalidTypeIdentifier { type_id: defending })?)
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeLibrary for TypeLibraryImpl {
|
||||
/// Gets the type identifier for a type with a name.
|
||||
fn get_type_id(&self, key: &StringKey) -> Option<TypeIdentifier> {
|
||||
self.types.read().get(key).cloned()
|
||||
}
|
||||
fn get_type_id(&self, key: &StringKey) -> Option<TypeIdentifier> { self.types.read().get(key).cloned() }
|
||||
|
||||
/// Gets the type name from the type identifier.
|
||||
fn get_type_name(&self, t: TypeIdentifier) -> Option<StringKey> {
|
||||
|
@ -133,13 +122,11 @@ impl TypeLibrary for TypeLibraryImpl {
|
|||
let mut types_write_lock = self.types.write();
|
||||
let mut effectiveness_write_lock = self.effectiveness.write();
|
||||
|
||||
let id = TypeIdentifier {
|
||||
val: (types_write_lock.len() + 1) as u8,
|
||||
};
|
||||
let id = TypeIdentifier((types_write_lock.len() + 1) as u8);
|
||||
types_write_lock.insert(name.clone(), id);
|
||||
effectiveness_write_lock.resize((id.val) as usize, vec![]);
|
||||
effectiveness_write_lock.resize((id.0) as usize, vec![]);
|
||||
for effectiveness in &mut effectiveness_write_lock.iter_mut() {
|
||||
effectiveness.resize((id.val) as usize, 1.0)
|
||||
effectiveness.resize((id.0) as usize, 1.0)
|
||||
}
|
||||
id
|
||||
}
|
||||
|
@ -154,9 +141,9 @@ impl TypeLibrary for TypeLibraryImpl {
|
|||
*self
|
||||
.effectiveness
|
||||
.write()
|
||||
.get_mut((attacking.val - 1) as usize)
|
||||
.get_mut((attacking.0 - 1) as usize)
|
||||
.ok_or(PkmnError::InvalidTypeIdentifier { type_id: attacking })?
|
||||
.get_mut((defending.val - 1) as usize)
|
||||
.get_mut((defending.0 - 1) as usize)
|
||||
.ok_or(PkmnError::InvalidTypeIdentifier { type_id: defending })? = effectiveness;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -169,7 +156,6 @@ pub mod tests {
|
|||
use assert_approx_eq::assert_approx_eq;
|
||||
|
||||
use super::*;
|
||||
use crate::static_data::libraries::type_library::TypeLibrary;
|
||||
|
||||
pub fn build() -> TypeLibraryImpl {
|
||||
let mut lib = TypeLibraryImpl::new(2);
|
||||
|
|
|
@ -1,40 +1,24 @@
|
|||
use crate::StringKey;
|
||||
#[doc(inline)]
|
||||
pub use growth_rates::*;
|
||||
#[doc(inline)]
|
||||
pub use items::*;
|
||||
#[doc(inline)]
|
||||
pub use libraries::*;
|
||||
#[doc(inline)]
|
||||
pub use moves::*;
|
||||
#[doc(inline)]
|
||||
pub use natures::*;
|
||||
#[doc(inline)]
|
||||
pub use species_data::*;
|
||||
#[doc(inline)]
|
||||
pub use statistic_set::*;
|
||||
#[doc(inline)]
|
||||
pub use statistics::*;
|
||||
#[doc(inline)]
|
||||
pub use time_of_day::*;
|
||||
#[doc(inline)] pub use growth_rates::*;
|
||||
#[doc(inline)] pub use items::*;
|
||||
#[doc(inline)] pub use libraries::*;
|
||||
#[doc(inline)] pub use moves::*;
|
||||
#[doc(inline)] pub use natures::*;
|
||||
#[doc(inline)] pub use species_data::*;
|
||||
#[doc(inline)] pub use statistic_set::*;
|
||||
#[doc(inline)] pub use statistics::*;
|
||||
#[doc(inline)] pub use time_of_day::*;
|
||||
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
use super::*;
|
||||
#[doc(inline)]
|
||||
pub use growth_rates::tests::*;
|
||||
#[doc(inline)]
|
||||
pub use items::tests::*;
|
||||
#[doc(inline)]
|
||||
pub use libraries::tests::*;
|
||||
#[doc(inline)]
|
||||
pub use moves::tests::*;
|
||||
#[doc(inline)]
|
||||
pub use natures::tests::*;
|
||||
#[doc(inline)]
|
||||
pub use species_data::tests::*;
|
||||
#[doc(inline)] pub use growth_rates::tests::*;
|
||||
#[doc(inline)] pub use items::tests::*;
|
||||
#[doc(inline)] pub use moves::tests::*;
|
||||
#[doc(inline)] pub use natures::tests::*;
|
||||
#[doc(inline)] pub use species_data::tests::*;
|
||||
}
|
||||
|
||||
/// Growth rates define how fast a Pokemon can level up.
|
||||
|
@ -71,27 +55,19 @@ pub enum Parameter {
|
|||
}
|
||||
|
||||
impl From<bool> for Parameter {
|
||||
fn from(b: bool) -> Self {
|
||||
Parameter::Bool(b)
|
||||
}
|
||||
fn from(b: bool) -> Self { Parameter::Bool(b) }
|
||||
}
|
||||
|
||||
impl From<i64> for Parameter {
|
||||
fn from(i: i64) -> Self {
|
||||
Parameter::Int(i)
|
||||
}
|
||||
fn from(i: i64) -> Self { Parameter::Int(i) }
|
||||
}
|
||||
|
||||
impl From<f32> for Parameter {
|
||||
fn from(f: f32) -> Self {
|
||||
Parameter::Float(f)
|
||||
}
|
||||
fn from(f: f32) -> Self { Parameter::Float(f) }
|
||||
}
|
||||
|
||||
impl From<StringKey> for Parameter {
|
||||
fn from(s: StringKey) -> Self {
|
||||
Parameter::String(s)
|
||||
}
|
||||
fn from(s: StringKey) -> Self { Parameter::String(s) }
|
||||
}
|
||||
|
||||
impl Display for Parameter {
|
||||
|
|
|
@ -1,16 +1,11 @@
|
|||
#[doc(inline)]
|
||||
pub use move_data::*;
|
||||
#[doc(inline)]
|
||||
pub use secondary_effect::*;
|
||||
#[doc(inline)] pub use move_data::*;
|
||||
#[doc(inline)] pub use secondary_effect::*;
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
use super::*;
|
||||
|
||||
#[doc(inline)]
|
||||
pub use move_data::tests::*;
|
||||
#[doc(inline)]
|
||||
pub use secondary_effect::tests::*;
|
||||
#[doc(inline)] pub use move_data::tests::*;
|
||||
}
|
||||
|
||||
/// The data belonging to a certain move.
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use hashbrown::HashSet;
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[cfg(feature = "serde")] use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -11,6 +10,7 @@ use crate::StringKey;
|
|||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
|
||||
#[cfg_attr(feature = "rune", derive(rune::Any))]
|
||||
#[repr(u8)]
|
||||
pub enum MoveCategory {
|
||||
/// A physical move uses the physical attack stats and physical defense stats to calculate damage.
|
||||
|
@ -24,6 +24,7 @@ pub enum MoveCategory {
|
|||
/// The move target defines what kind of targets the move can touch.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "rune", derive(rune::Any))]
|
||||
#[repr(u8)]
|
||||
pub enum MoveTarget {
|
||||
/// Adjacent allows a move to target any Pokemon that is either directly to the left or right of
|
||||
|
@ -149,54 +150,32 @@ impl MoveDataImpl {
|
|||
|
||||
impl MoveData for MoveDataImpl {
|
||||
/// The name of the move.
|
||||
fn name(&self) -> &StringKey {
|
||||
&self.name
|
||||
}
|
||||
fn name(&self) -> &StringKey { &self.name }
|
||||
/// The attacking type of the move.
|
||||
fn move_type(&self) -> TypeIdentifier {
|
||||
self.move_type
|
||||
}
|
||||
fn move_type(&self) -> TypeIdentifier { self.move_type }
|
||||
/// The category of the move.
|
||||
fn category(&self) -> MoveCategory {
|
||||
self.category
|
||||
}
|
||||
fn category(&self) -> MoveCategory { self.category }
|
||||
/// The base power, not considering any modifiers, the move has.
|
||||
fn base_power(&self) -> u8 {
|
||||
self.base_power
|
||||
}
|
||||
fn base_power(&self) -> u8 { self.base_power }
|
||||
/// The accuracy of the move in percentage. Should be 255 for moves that always hit.
|
||||
fn accuracy(&self) -> u8 {
|
||||
self.accuracy
|
||||
}
|
||||
fn accuracy(&self) -> u8 { self.accuracy }
|
||||
/// The number of times the move can be used. This can be modified on actually learned moves using
|
||||
/// PP-Ups
|
||||
fn base_usages(&self) -> u8 {
|
||||
self.base_usages
|
||||
}
|
||||
fn base_usages(&self) -> u8 { self.base_usages }
|
||||
/// How the move handles targets.
|
||||
fn target(&self) -> MoveTarget {
|
||||
self.target
|
||||
}
|
||||
fn target(&self) -> MoveTarget { self.target }
|
||||
|
||||
/// The priority of the move. A higher priority means the move should go before other moves.
|
||||
fn priority(&self) -> i8 {
|
||||
self.priority
|
||||
}
|
||||
fn priority(&self) -> i8 { self.priority }
|
||||
|
||||
/// The optional secondary effect the move has.
|
||||
fn secondary_effect(&self) -> &Option<Arc<dyn SecondaryEffect>> {
|
||||
&self.secondary_effect
|
||||
}
|
||||
fn secondary_effect(&self) -> &Option<Arc<dyn SecondaryEffect>> { &self.secondary_effect }
|
||||
|
||||
/// Checks if the move has a specific flag.
|
||||
fn has_flag(&self, key: &StringKey) -> bool {
|
||||
self.flags.contains::<StringKey>(key)
|
||||
}
|
||||
fn has_flag(&self, key: &StringKey) -> bool { self.flags.contains::<StringKey>(key) }
|
||||
|
||||
/// Checks if the move has a specific flag.
|
||||
fn has_flag_by_hash(&self, key_hash: u32) -> bool {
|
||||
self.flags.contains::<u32>(&key_hash)
|
||||
}
|
||||
fn has_flag_by_hash(&self, key_hash: u32) -> bool { self.flags.contains::<u32>(&key_hash) }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::static_data::Parameter;
|
||||
use crate::StringKey;
|
||||
use hashbrown::HashMap;
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -10,7 +11,7 @@ pub trait SecondaryEffect: Debug {
|
|||
/// The name of the effect.
|
||||
fn effect_name(&self) -> &StringKey;
|
||||
/// A list of parameters for the effect.
|
||||
fn parameters(&self) -> &Vec<Arc<Parameter>>;
|
||||
fn parameters(&self) -> &HashMap<StringKey, Arc<Parameter>>;
|
||||
}
|
||||
|
||||
/// A secondary effect is an effect on a move that happens after it hits.
|
||||
|
@ -21,12 +22,12 @@ pub struct SecondaryEffectImpl {
|
|||
/// The name of the effect.
|
||||
effect_name: StringKey,
|
||||
/// A list of parameters for the effect.
|
||||
parameters: Vec<Arc<Parameter>>,
|
||||
parameters: HashMap<StringKey, Arc<Parameter>>,
|
||||
}
|
||||
|
||||
impl SecondaryEffectImpl {
|
||||
/// Instantiates a new Secondary Effect.
|
||||
pub fn new(chance: f32, effect_name: StringKey, parameters: Vec<Arc<Parameter>>) -> Self {
|
||||
pub fn new(chance: f32, effect_name: StringKey, parameters: HashMap<StringKey, Arc<Parameter>>) -> Self {
|
||||
Self {
|
||||
chance,
|
||||
effect_name,
|
||||
|
@ -37,17 +38,11 @@ impl SecondaryEffectImpl {
|
|||
|
||||
impl SecondaryEffect for SecondaryEffectImpl {
|
||||
/// The chance in percentages that the effect triggers. -1 to make it always trigger.
|
||||
fn chance(&self) -> f32 {
|
||||
self.chance
|
||||
}
|
||||
fn chance(&self) -> f32 { self.chance }
|
||||
/// The name of the effect.
|
||||
fn effect_name(&self) -> &StringKey {
|
||||
&self.effect_name
|
||||
}
|
||||
fn effect_name(&self) -> &StringKey { &self.effect_name }
|
||||
/// A list of parameters for the effect.
|
||||
fn parameters(&self) -> &Vec<Arc<Parameter>> {
|
||||
&self.parameters
|
||||
}
|
||||
fn parameters(&self) -> &HashMap<StringKey, Arc<Parameter>> { &self.parameters }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -57,26 +52,23 @@ pub(crate) mod tests {
|
|||
use super::*;
|
||||
use assert_approx_eq::assert_approx_eq;
|
||||
|
||||
use crate::static_data::moves::secondary_effect::SecondaryEffect;
|
||||
use crate::static_data::SecondaryEffectImpl;
|
||||
|
||||
mockall::mock! {
|
||||
#[derive(Debug)]
|
||||
pub SecondaryEffect{}
|
||||
impl SecondaryEffect for SecondaryEffect {
|
||||
fn chance(&self) -> f32;
|
||||
fn effect_name(&self) -> &StringKey;
|
||||
fn parameters(&self) -> &Vec<Arc<Parameter >>;
|
||||
fn parameters(&self) -> &HashMap<StringKey, Arc<Parameter >>;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_secondary_effect() {
|
||||
let empty = SecondaryEffectImpl::new(0.0, "".into(), vec![]);
|
||||
let empty = SecondaryEffectImpl::new(0.0, "".into(), HashMap::new());
|
||||
assert_approx_eq!(empty.chance(), 0.0);
|
||||
assert_eq!(empty.effect_name(), &"".into());
|
||||
assert_eq!(empty.parameters().len(), 0);
|
||||
let set = SecondaryEffectImpl::new(50.0, "foo".into(), Vec::new());
|
||||
let set = SecondaryEffectImpl::new(50.0, "foo".into(), HashMap::new());
|
||||
assert_approx_eq!(set.chance(), 50.0);
|
||||
assert_eq!(set.effect_name(), &"foo".into());
|
||||
assert_eq!(set.parameters().len(), 0);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::static_data::Parameter;
|
||||
use crate::StringKey;
|
||||
use hashbrown::HashMap;
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -10,7 +11,7 @@ pub trait Ability: Debug {
|
|||
/// The name of the script effect of the ability.
|
||||
fn effect(&self) -> &StringKey;
|
||||
/// The parameters for the script effect of the ability.
|
||||
fn parameters(&self) -> &Vec<Arc<Parameter>>;
|
||||
fn parameters(&self) -> &HashMap<StringKey, Arc<Parameter>>;
|
||||
}
|
||||
|
||||
/// An ability is a passive effect in battle that is attached to a Pokemon.
|
||||
|
@ -21,12 +22,12 @@ pub struct AbilityImpl {
|
|||
/// The name of the script effect of the ability.
|
||||
effect: StringKey,
|
||||
/// The parameters for the script effect of the ability.
|
||||
parameters: Vec<Arc<Parameter>>,
|
||||
parameters: HashMap<StringKey, Arc<Parameter>>,
|
||||
}
|
||||
|
||||
impl AbilityImpl {
|
||||
/// Instantiates a new ability.
|
||||
pub fn new(name: &StringKey, effect: &StringKey, parameters: Vec<Arc<Parameter>>) -> Self {
|
||||
pub fn new(name: &StringKey, effect: &StringKey, parameters: HashMap<StringKey, Arc<Parameter>>) -> Self {
|
||||
Self {
|
||||
name: name.clone(),
|
||||
effect: effect.clone(),
|
||||
|
@ -37,17 +38,11 @@ impl AbilityImpl {
|
|||
|
||||
impl Ability for AbilityImpl {
|
||||
/// The name of the ability.
|
||||
fn name(&self) -> &StringKey {
|
||||
&self.name
|
||||
}
|
||||
fn name(&self) -> &StringKey { &self.name }
|
||||
/// The name of the script effect of the ability.
|
||||
fn effect(&self) -> &StringKey {
|
||||
&self.effect
|
||||
}
|
||||
fn effect(&self) -> &StringKey { &self.effect }
|
||||
/// The parameters for the script effect of the ability.
|
||||
fn parameters(&self) -> &Vec<Arc<Parameter>> {
|
||||
&self.parameters
|
||||
}
|
||||
fn parameters(&self) -> &HashMap<StringKey, Arc<Parameter>> { &self.parameters }
|
||||
}
|
||||
|
||||
/// An ability index allows us to find an ability on a form. It combines a bool for whether the
|
||||
|
@ -74,7 +69,7 @@ pub(crate) mod tests {
|
|||
impl Ability for Ability {
|
||||
fn name(&self) -> &StringKey;
|
||||
fn effect(&self) -> &StringKey;
|
||||
fn parameters(&self) -> &Vec<Arc<Parameter >>;
|
||||
fn parameters(&self) -> &HashMap<StringKey, Arc<Parameter >>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,12 +44,12 @@ pub trait Form: Debug {
|
|||
fn find_ability_index(&self, ability: &dyn Ability) -> Option<AbilityIndex>;
|
||||
|
||||
/// Gets an ability from the form.
|
||||
fn get_ability(&self, index: AbilityIndex) -> Result<&StringKey>;
|
||||
fn get_ability(&self, index: AbilityIndex) -> Result<StringKey>;
|
||||
|
||||
/// Gets a random ability from the form.
|
||||
fn get_random_ability(&self, rand: &mut Random) -> Result<&StringKey>;
|
||||
fn get_random_ability(&self, rand: &mut Random) -> Result<StringKey>;
|
||||
/// Gets a random hidden ability from the form.
|
||||
fn get_random_hidden_ability(&self, rand: &mut Random) -> Result<&StringKey>;
|
||||
fn get_random_hidden_ability(&self, rand: &mut Random) -> Result<StringKey>;
|
||||
|
||||
/// Check if the form has a specific flag set.
|
||||
fn has_flag(&self, key: &StringKey) -> bool;
|
||||
|
@ -118,56 +118,32 @@ impl FormImpl {
|
|||
|
||||
impl Form for FormImpl {
|
||||
/// The name of the form.
|
||||
fn name(&self) -> &StringKey {
|
||||
&self.name
|
||||
}
|
||||
fn name(&self) -> &StringKey { &self.name }
|
||||
/// The height of the form in meters.
|
||||
fn height(&self) -> f32 {
|
||||
self.height
|
||||
}
|
||||
fn height(&self) -> f32 { self.height }
|
||||
/// The weight of the form in kilograms.
|
||||
fn weight(&self) -> f32 {
|
||||
self.weight
|
||||
}
|
||||
fn weight(&self) -> f32 { self.weight }
|
||||
/// The base amount of experience that is gained when beating a Pokemon with this form.
|
||||
fn base_experience(&self) -> u32 {
|
||||
self.base_experience
|
||||
}
|
||||
fn base_experience(&self) -> u32 { self.base_experience }
|
||||
/// The normal types a Pokemon with this form has.
|
||||
fn types(&self) -> &Vec<TypeIdentifier> {
|
||||
&self.types
|
||||
}
|
||||
fn types(&self) -> &Vec<TypeIdentifier> { &self.types }
|
||||
/// The inherent values of a form of species that are used for the stats of a Pokemon.
|
||||
fn base_stats(&self) -> &Arc<StaticStatisticSet<u16>> {
|
||||
&self.base_stats
|
||||
}
|
||||
fn base_stats(&self) -> &Arc<StaticStatisticSet<u16>> { &self.base_stats }
|
||||
/// The possible abilities a Pokemon with this form can have.
|
||||
fn abilities(&self) -> &Vec<StringKey> {
|
||||
&self.abilities
|
||||
}
|
||||
fn abilities(&self) -> &Vec<StringKey> { &self.abilities }
|
||||
/// The possible hidden abilities a Pokemon with this form can have.
|
||||
fn hidden_abilities(&self) -> &Vec<StringKey> {
|
||||
&self.hidden_abilities
|
||||
}
|
||||
fn hidden_abilities(&self) -> &Vec<StringKey> { &self.hidden_abilities }
|
||||
|
||||
/// The moves a Pokemon with this form can learn.
|
||||
fn moves(&self) -> &Arc<dyn LearnableMoves> {
|
||||
&self.moves
|
||||
}
|
||||
fn moves(&self) -> &Arc<dyn LearnableMoves> { &self.moves }
|
||||
/// Arbitrary flags can be set on a form for scripting use.
|
||||
fn flags(&self) -> &HashSet<StringKey> {
|
||||
&self.flags
|
||||
}
|
||||
fn flags(&self) -> &HashSet<StringKey> { &self.flags }
|
||||
|
||||
/// Get a type of the move at a certain index.
|
||||
fn get_type(&self, index: usize) -> Result<TypeIdentifier> {
|
||||
Ok(*self.types.get_res(index)?)
|
||||
}
|
||||
fn get_type(&self, index: usize) -> Result<TypeIdentifier> { Ok(*self.types.get_res(index)?) }
|
||||
|
||||
/// Gets a single base stat value.
|
||||
fn get_base_stat(&self, stat: Statistic) -> u16 {
|
||||
self.base_stats.get_stat(stat)
|
||||
}
|
||||
fn get_base_stat(&self, stat: Statistic) -> u16 { self.base_stats.get_stat(stat) }
|
||||
|
||||
/// Find the index of an ability that can be on this form.
|
||||
fn find_ability_index(&self, ability: &dyn Ability) -> Option<AbilityIndex> {
|
||||
|
@ -191,39 +167,35 @@ impl Form for FormImpl {
|
|||
}
|
||||
|
||||
/// Gets an ability from the form.
|
||||
fn get_ability(&self, index: AbilityIndex) -> Result<&StringKey> {
|
||||
fn get_ability(&self, index: AbilityIndex) -> Result<StringKey> {
|
||||
if index.hidden {
|
||||
Ok(self.hidden_abilities.get_res(index.index as usize)?)
|
||||
self.hidden_abilities.get_res(index.index as usize).map(|s| s.clone())
|
||||
} else {
|
||||
Ok(self.abilities.get_res(index.index as usize)?)
|
||||
self.abilities.get_res(index.index as usize).map(|s| s.clone())
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a random ability from the form.
|
||||
fn get_random_ability(&self, rand: &mut Random) -> Result<&StringKey> {
|
||||
fn get_random_ability(&self, rand: &mut Random) -> Result<StringKey> {
|
||||
ensure!(!self.abilities.is_empty(), "No abilities on form");
|
||||
self.abilities
|
||||
.get_res(rand.get_between_unsigned(0, self.abilities.len() as u32) as usize)
|
||||
.map(|s| s.clone())
|
||||
}
|
||||
/// Gets a random hidden ability from the form.
|
||||
fn get_random_hidden_ability(&self, rand: &mut Random) -> Result<&StringKey> {
|
||||
fn get_random_hidden_ability(&self, rand: &mut Random) -> Result<StringKey> {
|
||||
ensure!(!self.hidden_abilities.is_empty(), "No hidden abilities on form");
|
||||
self.hidden_abilities
|
||||
.get_res(rand.get_between_unsigned(0, self.hidden_abilities.len() as u32) as usize)
|
||||
.map(|s| s.clone())
|
||||
}
|
||||
|
||||
/// Check if the form has a specific flag set.
|
||||
fn has_flag(&self, key: &StringKey) -> bool {
|
||||
self.flags.contains(key)
|
||||
}
|
||||
fn has_flag(&self, key: &StringKey) -> bool { self.flags.contains(key) }
|
||||
|
||||
fn has_flag_by_hash(&self, key_hash: u32) -> bool {
|
||||
self.flags.contains::<u32>(&key_hash)
|
||||
}
|
||||
fn has_flag_by_hash(&self, key_hash: u32) -> bool { self.flags.contains::<u32>(&key_hash) }
|
||||
|
||||
fn eq(&self, other: &dyn Form) -> bool {
|
||||
std::ptr::eq(self, other as *const dyn Form as *const Self)
|
||||
}
|
||||
fn eq(&self, other: &dyn Form) -> bool { std::ptr::eq(self, other as *const dyn Form as *const Self) }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -249,9 +221,9 @@ pub(crate) mod tests {
|
|||
fn get_type(&self, index: usize) -> Result<TypeIdentifier>;
|
||||
fn get_base_stat(&self, stat: Statistic) -> u16;
|
||||
fn find_ability_index(&self, ability: &dyn Ability) -> Option<AbilityIndex>;
|
||||
fn get_ability<'a>(&'a self, index: AbilityIndex) -> Result<&'a StringKey>;
|
||||
fn get_random_ability<'a>(&'a self, rand: &mut Random) -> Result<&'a StringKey>;
|
||||
fn get_random_hidden_ability<'a>(&'a self, rand: &mut Random) -> Result<&'a StringKey>;
|
||||
fn get_ability(&self, index: AbilityIndex) -> Result<StringKey>;
|
||||
fn get_random_ability(&self, rand: &mut Random) -> Result<StringKey>;
|
||||
fn get_random_hidden_ability(&self, rand: &mut Random) -> Result<StringKey>;
|
||||
fn has_flag(&self, key: &StringKey) -> bool;
|
||||
fn has_flag_by_hash(&self, key_hash: u32) -> bool;
|
||||
fn eq(&self, other: &dyn Form) -> bool;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
/// that allows for a more progressive gender system for those that want it?
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
||||
#[cfg_attr(feature = "serde", derive(serde_repr::Serialize_repr, serde_repr::Deserialize_repr))]
|
||||
#[cfg_attr(feature = "rune", derive(rune::Any))]
|
||||
#[repr(u8)]
|
||||
pub enum Gender {
|
||||
/// The Pokemon has no gender.
|
||||
|
|
|
@ -1,22 +1,15 @@
|
|||
#[doc(inline)]
|
||||
pub use ability::*;
|
||||
#[doc(inline)]
|
||||
pub use evolution_data::*;
|
||||
#[doc(inline)]
|
||||
pub use form::*;
|
||||
#[doc(inline)]
|
||||
pub use gender::*;
|
||||
#[doc(inline)]
|
||||
pub use learnable_moves::*;
|
||||
#[doc(inline)]
|
||||
pub use species::*;
|
||||
#[doc(inline)] pub use ability::*;
|
||||
#[doc(inline)] pub use evolution_data::*;
|
||||
#[doc(inline)] pub use form::*;
|
||||
#[doc(inline)] pub use gender::*;
|
||||
#[doc(inline)] pub use learnable_moves::*;
|
||||
#[doc(inline)] pub use species::*;
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
pub use super::ability::tests::*;
|
||||
pub use super::form::tests::*;
|
||||
pub use super::learnable_moves::tests::*;
|
||||
pub use super::species::tests::*;
|
||||
pub use super::ability::tests::*;
|
||||
}
|
||||
|
||||
/// An ability is a passive effect in battle that is attached to a Pokemon.
|
||||
|
|
|
@ -54,29 +54,17 @@ where
|
|||
}
|
||||
|
||||
/// The health point stat value.
|
||||
pub fn hp(&self) -> T {
|
||||
self.hp.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn hp(&self) -> T { self.hp.load(Ordering::Relaxed) }
|
||||
/// The physical attack stat value.
|
||||
pub fn attack(&self) -> T {
|
||||
self.attack.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn attack(&self) -> T { self.attack.load(Ordering::Relaxed) }
|
||||
/// The physical defense stat value.
|
||||
pub fn defense(&self) -> T {
|
||||
self.defense.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn defense(&self) -> T { self.defense.load(Ordering::Relaxed) }
|
||||
/// The special attack stat value.
|
||||
pub fn special_attack(&self) -> T {
|
||||
self.special_attack.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn special_attack(&self) -> T { self.special_attack.load(Ordering::Relaxed) }
|
||||
/// The special defense stat value.
|
||||
pub fn special_defense(&self) -> T {
|
||||
self.special_defense.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn special_defense(&self) -> T { self.special_defense.load(Ordering::Relaxed) }
|
||||
/// The speed stat value.
|
||||
pub fn speed(&self) -> T {
|
||||
self.speed.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn speed(&self) -> T { self.speed.load(Ordering::Relaxed) }
|
||||
|
||||
/// Get the value of a specific stat
|
||||
pub fn get_stat(&self, stat: Statistic) -> T {
|
||||
|
@ -165,29 +153,17 @@ where
|
|||
}
|
||||
|
||||
/// The health point stat value.
|
||||
pub const fn hp(&self) -> T {
|
||||
self.hp
|
||||
}
|
||||
pub const fn hp(&self) -> T { self.hp }
|
||||
/// The physical attack stat value.
|
||||
pub const fn attack(&self) -> T {
|
||||
self.attack
|
||||
}
|
||||
pub const fn attack(&self) -> T { self.attack }
|
||||
/// The physical defense stat value.
|
||||
pub const fn defense(&self) -> T {
|
||||
self.defense
|
||||
}
|
||||
pub const fn defense(&self) -> T { self.defense }
|
||||
/// The special attack stat value.
|
||||
pub const fn special_attack(&self) -> T {
|
||||
self.special_attack
|
||||
}
|
||||
pub const fn special_attack(&self) -> T { self.special_attack }
|
||||
/// The special defense stat value.
|
||||
pub const fn special_defense(&self) -> T {
|
||||
self.special_defense
|
||||
}
|
||||
pub const fn special_defense(&self) -> T { self.special_defense }
|
||||
/// The speed stat value.
|
||||
pub const fn speed(&self) -> T {
|
||||
self.speed
|
||||
}
|
||||
pub const fn speed(&self) -> T { self.speed }
|
||||
|
||||
/// Get the value of a specific stat
|
||||
pub const fn get_stat(&self, stat: Statistic) -> T {
|
||||
|
@ -245,14 +221,10 @@ where
|
|||
{
|
||||
/// The lowest value a value on the set can have.
|
||||
#[allow(clippy::unwrap_used)] // Should never fail
|
||||
pub fn min() -> T {
|
||||
<T as NumCast>::from(MIN).unwrap()
|
||||
}
|
||||
pub fn min() -> T { <T as NumCast>::from(MIN).unwrap() }
|
||||
/// The highest value a value on the set can have.
|
||||
#[allow(clippy::unwrap_used)] // Should never fail
|
||||
pub fn max() -> T {
|
||||
<T as NumCast>::from(MAX).unwrap()
|
||||
}
|
||||
pub fn max() -> T { <T as NumCast>::from(MAX).unwrap() }
|
||||
|
||||
/// Takes the underlying primary value, clamp it between the two values, and give it back as
|
||||
/// atomic.
|
||||
|
@ -274,29 +246,17 @@ where
|
|||
}
|
||||
|
||||
/// The health point stat value.
|
||||
pub fn hp(&self) -> T {
|
||||
self.hp.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn hp(&self) -> T { self.hp.load(Ordering::Relaxed) }
|
||||
/// The physical attack stat value.
|
||||
pub fn attack(&self) -> T {
|
||||
self.attack.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn attack(&self) -> T { self.attack.load(Ordering::Relaxed) }
|
||||
/// The physical defense stat value.
|
||||
pub fn defense(&self) -> T {
|
||||
self.defense.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn defense(&self) -> T { self.defense.load(Ordering::Relaxed) }
|
||||
/// The special attack stat value.
|
||||
pub fn special_attack(&self) -> T {
|
||||
self.special_attack.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn special_attack(&self) -> T { self.special_attack.load(Ordering::Relaxed) }
|
||||
/// The special defense stat value.
|
||||
pub fn special_defense(&self) -> T {
|
||||
self.special_defense.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn special_defense(&self) -> T { self.special_defense.load(Ordering::Relaxed) }
|
||||
/// The speed stat value.
|
||||
pub fn speed(&self) -> T {
|
||||
self.speed.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn speed(&self) -> T { self.speed.load(Ordering::Relaxed) }
|
||||
|
||||
/// Gets a specific stat.
|
||||
pub fn get_stat(&self, stat: Statistic) -> T {
|
||||
|
@ -399,6 +359,28 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, const MIN: i64, const MAX: i64> From<&ClampedStatisticSet<T, MIN, MAX>> for StatisticSet<T>
|
||||
where
|
||||
T: PrimitiveAtom,
|
||||
T: Atom,
|
||||
T: PrimitiveAtomInteger,
|
||||
<T as Atom>::Repr: PrimitiveAtomInteger,
|
||||
T: AtomInteger,
|
||||
T: NumCast,
|
||||
T: PrimInt,
|
||||
{
|
||||
fn from(value: &ClampedStatisticSet<T, MIN, MAX>) -> Self {
|
||||
Self {
|
||||
hp: Atomic::<T>::new(value.hp()),
|
||||
attack: Atomic::<T>::new(value.attack()),
|
||||
defense: Atomic::<T>::new(value.defense()),
|
||||
special_attack: Atomic::<T>::new(value.special_attack()),
|
||||
special_defense: Atomic::<T>::new(value.special_defense()),
|
||||
speed: Atomic::<T>::new(value.speed()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
@ -1,21 +1,27 @@
|
|||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[cfg(feature = "serde")] use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Stats are numerical values on Pokemon that are used in battle.
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "rune", derive(rune::Any))]
|
||||
#[repr(u8)]
|
||||
pub enum Statistic {
|
||||
/// Health Points determine how much damage a Pokemon can receive before fainting.
|
||||
#[cfg_attr(feature = "rune", rune(constructor))]
|
||||
HP,
|
||||
/// Attack determines how much damage a Pokemon deals when using a physical attack.
|
||||
#[cfg_attr(feature = "rune", rune(constructor))]
|
||||
Attack,
|
||||
/// Defense determines how much damage a Pokemon receives when it is hit by a physical attack.
|
||||
#[cfg_attr(feature = "rune", rune(constructor))]
|
||||
Defense,
|
||||
/// Special Attack determines how much damage a Pokemon deals when using a special attack.
|
||||
#[cfg_attr(feature = "rune", rune(constructor))]
|
||||
SpecialAttack,
|
||||
/// Special Defense determines how much damage a Pokemon receives when it is hit by a special attack.
|
||||
#[cfg_attr(feature = "rune", rune(constructor))]
|
||||
SpecialDefense,
|
||||
/// Speed determines the order that a Pokemon can act in battle.
|
||||
#[cfg_attr(feature = "rune", rune(constructor))]
|
||||
Speed,
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/// The time of day. These values are the 4 different groups of time of day in Pokemon games since
|
||||
/// gen 5. The exact times these correspond to differ between games.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "rune", derive(rune::Any))]
|
||||
#[repr(u8)]
|
||||
pub enum TimeOfDay {
|
||||
/// The morning.
|
||||
|
|
|
@ -5,7 +5,7 @@ use std::fs::File;
|
|||
use std::io::{BufReader, Read};
|
||||
use std::sync::Arc;
|
||||
|
||||
use hashbrown::HashSet;
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use num_traits::PrimInt;
|
||||
use project_root::get_project_root;
|
||||
use serde_json::Value;
|
||||
|
@ -223,10 +223,11 @@ pub fn load_abilities(path: &String) -> Arc<dyn AbilityLibrary> {
|
|||
if let Some(e) = value.get("effect") {
|
||||
effect = e.as_str().unwrap().into();
|
||||
}
|
||||
let mut parameters = Vec::new();
|
||||
if let Some(p) = value.get("parameters") {
|
||||
for par in p.as_array().unwrap() {
|
||||
parameters.push(parse_parameter(par));
|
||||
let mut parameters = HashMap::new();
|
||||
if let Some(pars) = value.get("parameters") {
|
||||
let pars = pars.as_object().unwrap();
|
||||
for par in pars {
|
||||
parameters.insert(par.0.as_str().into(), parse_parameter(par.1));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -258,11 +259,11 @@ pub fn load_moves(path: &String, types: &Arc<dyn TypeLibrary>) -> Arc<dyn MoveLi
|
|||
if let Some(chance_value) = v.get("chance") {
|
||||
chance = chance_value.as_f64().unwrap() as f32;
|
||||
}
|
||||
let mut parameters = Vec::new();
|
||||
let mut parameters = HashMap::new();
|
||||
if let Some(pars) = v.get("parameters") {
|
||||
let pars = pars.as_array().unwrap();
|
||||
let pars = pars.as_object().unwrap();
|
||||
for par in pars {
|
||||
parameters.push(parse_parameter(par));
|
||||
parameters.insert(par.0.as_str().into(), parse_parameter(par.1));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -451,10 +452,8 @@ fn parse_evolution(value: &Value) -> EvolutionData {
|
|||
EvolutionData::new(method, species)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "wasm"))]
|
||||
fn load_script_resolver(path: &String) -> Arc<dyn ScriptResolver> {
|
||||
Arc::new(EmptyScriptResolver::default())
|
||||
}
|
||||
#[cfg(not(any(feature = "wasm", feature = "rune")))]
|
||||
fn load_script_resolver(path: &String) -> Arc<dyn ScriptResolver> { Arc::new(EmptyScriptResolver::default()) }
|
||||
|
||||
#[cfg(feature = "wasm")]
|
||||
fn load_script_resolver(path: &String) -> Arc<dyn ScriptResolver> {
|
||||
|
@ -468,6 +467,28 @@ fn load_script_resolver(path: &String) -> Arc<dyn ScriptResolver> {
|
|||
resolver
|
||||
}
|
||||
|
||||
#[cfg(feature = "rune")]
|
||||
fn load_script_resolver(path: &String) -> Arc<dyn ScriptResolver> {
|
||||
let mut builder =
|
||||
pkmn_lib::script_implementations::rune::script_resolver::RuneScriptResolverBuilder::new().unwrap();
|
||||
// Recursively load all scripts in the scripts folder
|
||||
for entry in walkdir::WalkDir::new(path.to_string() + "scripts/") {
|
||||
let entry = entry.unwrap();
|
||||
let path = entry.path();
|
||||
if path.is_file() {
|
||||
let file = File::open(&path).unwrap();
|
||||
let mut reader = BufReader::new(file);
|
||||
let mut buffer = Vec::new();
|
||||
reader.read_to_end(&mut buffer).unwrap();
|
||||
builder
|
||||
.insert_script(path, &path.to_string_lossy(), &String::from_utf8(buffer).unwrap())
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
let resolver = builder.build().unwrap();
|
||||
resolver
|
||||
}
|
||||
|
||||
fn parse_form(
|
||||
name: StringKey,
|
||||
value: &Value,
|
||||
|
|
|
@ -4,7 +4,10 @@
|
|||
},
|
||||
"aerilate": {
|
||||
"effect": "ChangeMoveType",
|
||||
"parameters": ["normal", "flying"]
|
||||
"parameters": {
|
||||
"from": "normal",
|
||||
"to": "flying"
|
||||
}
|
||||
},
|
||||
"aftermath": {
|
||||
"effect": "Aftermath"
|
||||
|
@ -53,7 +56,9 @@
|
|||
},
|
||||
"blaze": {
|
||||
"effect": "PowerUpType",
|
||||
"parameters": ["fire"]
|
||||
"parameters": {
|
||||
"type": "fire"
|
||||
}
|
||||
},
|
||||
"bulletproof": {
|
||||
"effect": "Bulletproof"
|
||||
|
@ -63,7 +68,9 @@
|
|||
},
|
||||
"chlorophyll": {
|
||||
"effect": "DoubleSpeedInWeather",
|
||||
"parameters": ["HarshSunlight"]
|
||||
"parameters": {
|
||||
"weather": "HarshSunlight"
|
||||
}
|
||||
},
|
||||
"clear_body": {
|
||||
"effect": "PreventStatLowering"
|
||||
|
|
|
@ -29,9 +29,9 @@
|
|||
"effect": {
|
||||
"name": "drain",
|
||||
"chance": -1,
|
||||
"parameters": [
|
||||
0.5
|
||||
]
|
||||
"parameters": {
|
||||
"drain_mod": 0.5
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -65,9 +65,9 @@
|
|||
"effect": {
|
||||
"name": "change_target_special_defense",
|
||||
"chance": 10,
|
||||
"parameters": [
|
||||
-1
|
||||
]
|
||||
"parameters": {
|
||||
"amount": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -85,9 +85,9 @@
|
|||
"effect": {
|
||||
"name": "change_target_defense",
|
||||
"chance": -1,
|
||||
"parameters": [
|
||||
2
|
||||
]
|
||||
"parameters": {
|
||||
"amount": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -129,9 +129,9 @@
|
|||
"effect": {
|
||||
"name": "change_target_special_defense",
|
||||
"chance": -1,
|
||||
"parameters": [
|
||||
-2
|
||||
]
|
||||
"parameters": {
|
||||
"amount": -2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -233,9 +233,9 @@
|
|||
],
|
||||
"effect": {
|
||||
"name": "change_target_speed",
|
||||
"parameters": [
|
||||
2
|
||||
]
|
||||
"parameters": {
|
||||
"amount": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -324,9 +324,9 @@
|
|||
],
|
||||
"effect": {
|
||||
"name": "change_target_special_defense",
|
||||
"parameters": [
|
||||
2
|
||||
]
|
||||
"parameters": {
|
||||
"amount": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -363,9 +363,9 @@
|
|||
"effect": {
|
||||
"name": "change_all_target_stats",
|
||||
"chance": 10,
|
||||
"parameters": [
|
||||
1
|
||||
]
|
||||
"parameters": {
|
||||
"amount": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -397,9 +397,9 @@
|
|||
],
|
||||
"effect": {
|
||||
"name": "heal_each_end_of_turn",
|
||||
"parameters": [
|
||||
6.25
|
||||
]
|
||||
"parameters": {
|
||||
"percent": 6.25
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -466,9 +466,9 @@
|
|||
],
|
||||
"effect": {
|
||||
"name": "change_target_special_defense",
|
||||
"parameters": [
|
||||
1
|
||||
]
|
||||
"parameters": {
|
||||
"amount": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -592,9 +592,9 @@
|
|||
"effect": {
|
||||
"name": "change_target_attack",
|
||||
"chance": 10,
|
||||
"parameters": [
|
||||
-1
|
||||
]
|
||||
"parameters": {
|
||||
"amount": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -660,9 +660,9 @@
|
|||
],
|
||||
"effect": {
|
||||
"name": "change_target_attack",
|
||||
"parameters": [
|
||||
-1
|
||||
]
|
||||
"parameters": {
|
||||
"amount": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -3805,11 +3805,11 @@
|
|||
"ignore-substitute"
|
||||
],
|
||||
"effect": {
|
||||
"name": "ChangeTargetAtt",
|
||||
"name": "change_target_attack",
|
||||
"chance": -1,
|
||||
"parameters": [
|
||||
-1
|
||||
]
|
||||
"parameters": {
|
||||
"amount": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -5082,11 +5082,11 @@
|
|||
"mirror"
|
||||
],
|
||||
"effect": {
|
||||
"name": "ChangeTargetDef",
|
||||
"name": "change_target_defense",
|
||||
"chance": -1,
|
||||
"parameters": [
|
||||
-1
|
||||
]
|
||||
"parameters": {
|
||||
"amount": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
mod moves {
|
||||
|
||||
struct TestMove;
|
||||
|
||||
impl TestMove {
|
||||
pub fn change_speed(self, choice, speed) {
|
||||
println(`change_speed: ${choice.speed()}`);
|
||||
println(`user level: ${choice.user().level()}`);
|
||||
println(`owner: ${self.owner.level()}`);
|
||||
speed += 100;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -10,12 +10,10 @@ fn integration_tests(input: &Path) {
|
|||
let mut str: String = "".to_string();
|
||||
let mut file = File::open(input).unwrap();
|
||||
file.read_to_string(&mut str).unwrap();
|
||||
let test_case = serde_yaml::from_str::<TestCase>(&str).unwrap();
|
||||
let test_case = serde_yml::from_str::<TestCase>(&str).unwrap();
|
||||
println!(" Running integration test {}", test_case.name);
|
||||
test_case.run_test(get_library());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic_single_turn() {
|
||||
integration_tests(Path::new("tests/test_cases/basic_single_turn.yaml"));
|
||||
}
|
||||
fn basic_single_turn() { integration_tests(Path::new("tests/test_cases/basic_single_turn.yaml")); }
|
||||
|
|
|
@ -5,10 +5,7 @@
|
|||
|
||||
use std::sync::{Arc, LazyLock};
|
||||
|
||||
use pkmn_lib::dynamic_data::{
|
||||
Battle, BattleParty, DamageSource, DynamicLibrary, ExecutingMove, MoveChoice, PokemonBuilder, PokemonParty,
|
||||
ScriptCategory, ScriptContainer, ScriptOwnerData, TurnChoice, VolatileScriptsOwner,
|
||||
};
|
||||
use pkmn_lib::dynamic_data::{DynamicLibrary, PassChoice, PokemonBuilder, ScriptCategory, ScriptOwnerData, TurnChoice};
|
||||
|
||||
use crate::common::library_loader;
|
||||
|
||||
|
@ -17,9 +14,7 @@ pub mod datatests;
|
|||
|
||||
static LIBRARY: LazyLock<Arc<dyn DynamicLibrary>> = LazyLock::new(|| library_loader::load_library().library);
|
||||
|
||||
fn get_library() -> Arc<dyn DynamicLibrary> {
|
||||
LIBRARY.clone()
|
||||
}
|
||||
fn get_library() -> Arc<dyn DynamicLibrary> { LIBRARY.clone() }
|
||||
|
||||
#[test]
|
||||
fn validate_library_load() {
|
||||
|
@ -35,7 +30,7 @@ fn validate_library_load() {
|
|||
\n\t- Abilities load time: {} ms\
|
||||
\n\t- Moves load time: {} ms\
|
||||
\n\t- Species load time: {} ms\
|
||||
\n\t- WASM load time: {} ms\
|
||||
\n\t- Script load time: {} ms\
|
||||
",
|
||||
(end_time - start_time).num_milliseconds(),
|
||||
result.types_load_time.num_milliseconds(),
|
||||
|
@ -49,6 +44,32 @@ fn validate_library_load() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rune_test() {
|
||||
let result = library_loader::load_library();
|
||||
let library = result.library;
|
||||
let p1 = PokemonBuilder::new(library.clone(), "charizard".into(), 100)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let script = library
|
||||
.load_script(
|
||||
ScriptOwnerData::Pokemon(p1.weak()),
|
||||
ScriptCategory::Move,
|
||||
&"TestMove".into(),
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert_eq!(script.name().unwrap().str(), "TestMove");
|
||||
let p1 = PokemonBuilder::new(library.clone(), "charizard".into(), 100)
|
||||
.build()
|
||||
.unwrap();
|
||||
let turn_choice = Arc::new(TurnChoice::Pass(PassChoice::new(p1)));
|
||||
let mut speed = 0;
|
||||
script.change_speed(&turn_choice, &mut speed).unwrap();
|
||||
assert_eq!(speed, 100);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_non_existing_wasm_script() {
|
||||
let start_time = chrono::Utc::now();
|
||||
|
@ -63,7 +84,7 @@ fn load_non_existing_wasm_script() {
|
|||
\n\t- Abilities load time: {} ms\
|
||||
\n\t- Moves load time: {} ms\
|
||||
\n\t- Species load time: {} ms\
|
||||
\n\t- WASM load time: {} ms\
|
||||
\n\t- Script load time: {} ms\
|
||||
",
|
||||
(end_time - start_time).num_milliseconds(),
|
||||
result.types_load_time.num_milliseconds(),
|
||||
|
@ -82,75 +103,3 @@ fn load_non_existing_wasm_script() {
|
|||
|
||||
assert!(script.is_none());
|
||||
}
|
||||
|
||||
/// Assurance has the interesting properties that it creates a special data script internally, and
|
||||
/// deletes that data script through the get_owner functionality.
|
||||
#[test]
|
||||
fn validate_assurance() {
|
||||
let lib = get_library();
|
||||
let p1 = PokemonBuilder::new(lib.clone(), "charizard".into(), 100)
|
||||
.learn_move("assurance".into())
|
||||
.build()
|
||||
.unwrap();
|
||||
let p2 = PokemonBuilder::new(lib.clone(), "venusaur".into(), 100)
|
||||
.build()
|
||||
.unwrap();
|
||||
let party1 = Arc::new(
|
||||
BattleParty::new(
|
||||
Arc::new(PokemonParty::new_from_vec(vec![Some(p1.clone())])),
|
||||
vec![(0, 0)],
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
let party2 = Arc::new(
|
||||
BattleParty::new(
|
||||
Arc::new(PokemonParty::new_from_vec(vec![Some(p2.clone())])),
|
||||
vec![(1, 0)],
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let battle = Battle::new(lib.clone(), vec![party1, party2], false, 2, 1, None);
|
||||
|
||||
battle.sides()[0].set_pokemon(0, Some(p1.clone())).unwrap();
|
||||
battle.sides()[1].set_pokemon(0, Some(p2.clone())).unwrap();
|
||||
|
||||
let script = lib
|
||||
.load_script(
|
||||
ScriptOwnerData::None,
|
||||
ScriptCategory::Move,
|
||||
&"double_power_if_target_damaged_in_turn".into(),
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
let mv = p1.learned_moves().read()[0].as_ref().unwrap().clone();
|
||||
let choice = Arc::new(TurnChoice::Move(MoveChoice::new(p1.clone(), mv.clone(), 1, 0)));
|
||||
script.on_before_turn(&choice).unwrap();
|
||||
assert!(battle.sides()[1].has_volatile_script(&"double_power_if_target_damaged_in_turn_data".into()));
|
||||
|
||||
let executing_move = Arc::new(ExecutingMove::new(
|
||||
vec![],
|
||||
1,
|
||||
p1,
|
||||
mv.clone(),
|
||||
mv.move_data().clone(),
|
||||
ScriptContainer::default(),
|
||||
));
|
||||
let mut v = 20_u8;
|
||||
script.change_base_power(&executing_move, &p2, 0, &mut v).unwrap();
|
||||
assert_eq!(v, 20_u8);
|
||||
|
||||
let s = battle.sides()[1].get_volatile_script(&"double_power_if_target_damaged_in_turn_data".into());
|
||||
let binding = s.as_ref().unwrap().get().unwrap().read();
|
||||
let data_script = binding.as_ref().unwrap();
|
||||
|
||||
data_script.on_damage(&p2, DamageSource::Misc, 100, 50).unwrap();
|
||||
|
||||
let mut v = 20_u8;
|
||||
script.change_base_power(&executing_move, &p2, 0, &mut v).unwrap();
|
||||
assert_eq!(v, 40_u8);
|
||||
|
||||
data_script.on_end_turn().unwrap();
|
||||
assert!(!battle.sides()[1].has_volatile_script(&"double_power_if_target_damaged_in_turn_data".into()));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue