Update to rune 0.14, more tests
continuous-integration/drone/push Build is failing Details

This commit is contained in:
Deukhoofd 2024-05-19 16:37:19 +02:00
parent 535f6bf79b
commit 92ff5bd0a1
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
29 changed files with 862 additions and 387 deletions

View File

@ -51,14 +51,14 @@ 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 }
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"
@ -66,12 +66,12 @@ thiserror = "1.0"
stdext = "0.3"
wasmer = { version = "4.2", optional = true, default-features = false, features = ["sys", "wat", "llvm"] }
rune = { version = "0.13.2", optional = true }
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

View File

@ -427,7 +427,7 @@ impl Pokemon {
.library
.static_data()
.abilities()
.get(ability)
.get(&ability)
.ok_or(PkmnError::InvalidAbilityName {
ability: ability.clone(),
})?)

View File

@ -4,7 +4,7 @@ use crate::script_implementations::rune::RuneScriptType;
use crate::static_data::Parameter;
use crate::StringKey;
use hashbrown::HashMap;
use rune::runtime::{Object, RuntimeContext, Shared, VmError, VmResult};
use rune::runtime::{RuntimeContext, VmError, VmResult};
use rune::{Unit, Value};
use std::convert::TryFrom;
use std::sync::atomic::{AtomicBool, AtomicUsize};
@ -12,7 +12,7 @@ use std::sync::Arc;
pub struct RuneScript {
name: StringKey,
state: Shared<Object>,
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).
@ -34,7 +34,7 @@ unsafe impl Sync for RuneScript {}
impl RuneScript {
pub fn new(
name: StringKey,
object: Shared<Object>,
object: Value,
script_type: Arc<RuneScriptType>,
runtime: Arc<RuntimeContext>,
unit: Arc<Unit>,
@ -50,7 +50,7 @@ impl RuneScript {
}
}
pub(crate) fn get_state(&self) -> Shared<Object> { self.state.clone() }
pub(crate) fn get_state(&self) -> Value { self.state.clone() }
}
impl Script for RuneScript {
@ -68,12 +68,12 @@ impl Script for RuneScript {
if pars.is_empty() {
return Ok(());
}
let state = self.state.clone();
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
.borrow_mut()?
.insert(key, parameter_to_rune_value(par.1.as_ref())?)?;
state.insert(key, parameter_to_rune_value(par.1.as_ref())?)?;
}
Ok(())
}
@ -87,8 +87,8 @@ impl Script for RuneScript {
.execute(
hash,
vec![
Value::Object(self.state.clone()),
Value::from(choice.wrap()),
rune::to_value(self.state.clone())?,
rune::to_value(choice.wrap())?,
speed_handle.clone(),
],
)?
@ -116,10 +116,10 @@ impl Script for RuneScript {
vm.execute(
hash,
vec![
Value::Object(self.state.clone()),
Value::from(move_data.wrap()),
Value::from(target.wrap()),
Value::from(hit),
self.state.clone(),
move_data.wrap(),
target.wrap(),
rune::to_value(hit)?,
block_critical_handle.clone(),
],
)?;

View File

@ -8,7 +8,7 @@ use hashbrown::HashMap;
use rune::compile::meta::AssociatedKind;
use rune::compile::{ComponentRef, MetaError};
use rune::diagnostics::Diagnostic;
use rune::runtime::{RuntimeContext, Shared};
use rune::runtime::RuntimeContext;
use rune::{Context, Diagnostics, Options, Source, Sources, Unit};
use std::any::Any;
use std::convert::TryFrom;
@ -52,7 +52,7 @@ impl ScriptResolver for RuneScriptResolver {
o.insert(rune::alloc::String::try_from("owner")?, owner_obj.into())?;
}
let state = Shared::new(o)?;
let state = rune::to_value(o)?;
let script = Arc::new(RuneScript::new(
script_key.clone(),
state,

View File

@ -1,7 +1,6 @@
use crate::dynamic_data::Battle;
use crate::script_implementations::rune::wrappers::{impl_rune_wrapper, RuneStringKey, RuneWrapper};
use rune::runtime::{AnyObj, Shared};
use rune::Any;
use rune::{Any, Value};
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
module.ty::<RuneBattle>()?;
@ -27,10 +26,10 @@ impl_rune_wrapper!(&Battle, RuneBattle);
impl RuneBattle {
#[rune::function]
fn library(&self) -> Shared<AnyObj> { self.0.library().wrap() }
fn library(&self) -> Value { self.0.library().wrap() }
#[rune::function]
fn parties(&self) -> Vec<Shared<AnyObj>> { self.0.parties().iter().map(|p| p.wrap()).collect() }
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() }
@ -42,10 +41,10 @@ impl RuneBattle {
fn pokemon_per_side(&self) -> u8 { self.0.pokemon_per_side() }
#[rune::function]
fn sides(&self) -> Vec<Shared<AnyObj>> { self.0.sides().iter().map(|s| s.wrap()).collect() }
fn sides(&self) -> Vec<Value> { self.0.sides().iter().map(|s| s.wrap()).collect() }
#[rune::function]
fn random(&self) -> Shared<AnyObj> { self.0.random().wrap() }
fn random(&self) -> Value { self.0.random().wrap() }
#[rune::function]
fn has_ended(&self) -> bool { self.0.has_ended() }
@ -54,9 +53,7 @@ impl RuneBattle {
fn current_turn(&self) -> u32 { self.0.current_turn() }
#[rune::function]
fn get_pokemon(&self, side: u8, index: u8) -> Option<Shared<AnyObj>> {
self.0.get_pokemon(side, index).map(|v| v.wrap())
}
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<()> {

View File

@ -2,7 +2,7 @@ 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::{AnyObj, Object, Shared};
use rune::runtime::Value;
use rune::Any;
use std::sync::Arc;
@ -29,19 +29,19 @@ impl RuneExecutingMove {
#[rune::function]
fn number_of_hits(&self) -> u8 { self.0.number_of_hits() }
#[rune::function]
fn user(&self) -> Shared<AnyObj> { self.0.user().wrap() }
fn user(&self) -> Value { self.0.user().wrap() }
#[rune::function]
fn chosen_move(&self) -> Shared<AnyObj> { self.0.chosen_move().wrap() }
fn chosen_move(&self) -> Value { self.0.chosen_move().wrap() }
#[rune::function]
fn use_move(&self) -> Shared<AnyObj> { self.0.use_move().wrap() }
fn use_move(&self) -> Value { self.0.use_move().wrap() }
#[rune::function]
fn script(&self) -> Option<Shared<Object>> { resolve_script_data(self.0.script()) }
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<Shared<AnyObj>> {
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())
}
}

View File

@ -1,6 +1,6 @@
use crate::dynamic_data::{LearnedMove, MoveLearnMethod};
use crate::script_implementations::rune::wrappers::{impl_rune_wrapper, RuneWrapper};
use rune::runtime::{AnyObj, Shared};
use rune::runtime::Value;
use rune::Any;
use std::sync::Arc;
@ -24,7 +24,7 @@ impl_rune_wrapper!(&Arc<LearnedMove>, RuneLearnedMove);
impl RuneLearnedMove {
#[rune::function]
fn move_data(&self) -> Shared<AnyObj> { self.0.move_data().wrap() }
fn move_data(&self) -> Value { self.0.move_data().wrap() }
#[rune::function]
fn max_pp(&self) -> u8 { self.0.max_pp() }

View File

@ -1,6 +1,5 @@
use crate::dynamic_data::ScriptContainer;
use crate::script_implementations::rune::script::RuneScript;
use rune::runtime::{Object, Shared};
mod battle;
mod battle_party;
@ -26,7 +25,7 @@ pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
Ok(())
}
fn resolve_script_data(container: &ScriptContainer) -> Option<Shared<Object>> {
fn resolve_script_data(container: &ScriptContainer) -> Option<rune::Value> {
container
.get()
.map(|v| {

View File

@ -5,7 +5,7 @@ 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::{AnyObj, Object, Shared};
use rune::runtime::Value;
use rune::Any;
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
@ -69,25 +69,25 @@ pub struct RunePokemon(pub Pokemon);
impl RunePokemon {
#[rune::function]
fn library(&self) -> Shared<AnyObj> { self.0.library().wrap() }
fn library(&self) -> Value { self.0.library().wrap() }
#[rune::function]
fn species(&self) -> Shared<AnyObj> { self.0.species().wrap() }
fn species(&self) -> Value { self.0.species().wrap() }
#[rune::function]
fn form(&self) -> Shared<AnyObj> { self.0.form().wrap() }
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) -> Shared<AnyObj> { self.0.display_species().wrap() }
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) -> Shared<AnyObj> { self.0.display_form().wrap() }
fn display_form(&self) -> Value { self.0.display_form().wrap() }
#[rune::function]
fn level(&self) -> LevelInt { self.0.level() }
@ -105,18 +105,16 @@ impl RunePokemon {
fn coloring(&self) -> u8 { self.0.coloring() }
#[rune::function]
fn held_item(&self) -> Option<Shared<AnyObj>> { self.0.held_item().map(|v| v.wrap()) }
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<Shared<AnyObj>> {
self.0.set_held_item(&key.0).map(|v| v.wrap())
}
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<Shared<AnyObj>> { self.0.remove_held_item().map(|v| v.wrap()) }
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() }
@ -149,19 +147,19 @@ impl RunePokemon {
fn types(&self) -> Vec<u8> { self.0.types().iter().map(|v| u8::from(*v)).collect() }
#[rune::function]
fn learned_moves(&self) -> Vec<Option<Shared<AnyObj>>> {
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) -> Shared<AnyObj> { self.0.flat_stats().wrap() }
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) -> Shared<AnyObj> { self.0.boosted_stats().wrap() }
fn boosted_stats(&self) -> Value { self.0.boosted_stats().wrap() }
#[rune::function]
fn stat_boost(&self, stat: Statistic) -> i8 { self.0.stat_boost(stat) }
@ -178,7 +176,7 @@ impl RunePokemon {
fn get_effort_value(&self, stat: Statistic) -> u8 { self.0.effort_values().get_stat(stat) }
#[rune::function]
fn get_battle(&self) -> Option<Shared<AnyObj>> { self.0.get_battle().map(|v| v.wrap()) }
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() }
@ -190,13 +188,13 @@ impl RunePokemon {
fn is_ability_overridden(&self) -> bool { self.0.is_ability_overridden() }
#[rune::function]
fn active_ability(&self) -> anyhow::Result<Shared<AnyObj>> { self.0.active_ability().map(|v| v.wrap()) }
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) -> Shared<AnyObj> { self.0.nature().wrap() }
fn nature(&self) -> Value { self.0.nature().wrap() }
#[rune::function]
fn change_form(&self, form: RuneForm) -> anyhow::Result<()> { self.0.change_form(&form.0) }
@ -219,10 +217,10 @@ impl RunePokemon {
fn clear_status(&self) { self.0.clear_status() }
#[rune::function]
fn status_script(&self) -> Option<Shared<Object>> { resolve_script_data(&self.0.status()) }
fn status_script(&self) -> Option<Value> { resolve_script_data(&self.0.status()) }
#[rune::function]
fn ability_script(&self) -> Option<Shared<Object>> { resolve_script_data(&self.0.ability_script()) }
fn ability_script(&self) -> Option<Value> { resolve_script_data(&self.0.ability_script()) }
}
impl_rune_wrapper!(&Pokemon, RunePokemon);

View File

@ -1,6 +1,6 @@
use crate::dynamic_data::TurnChoice;
use crate::script_implementations::rune::wrappers::RuneWrapper;
use rune::runtime::{AnyObj, Shared};
use rune::runtime::Value;
use rune::Any;
use std::sync::Arc;
@ -62,7 +62,7 @@ impl RuneTurnChoice {
}
#[rune::function]
fn user(&self) -> Shared<AnyObj> { self.get_turn_choice().user().wrap() }
fn user(&self) -> Value { self.get_turn_choice().user().wrap() }
#[rune::function]
fn speed(&self) -> u32 { self.get_turn_choice().speed() }
@ -75,7 +75,7 @@ impl RuneTurnChoice {
}
impl RuneWrapper for &Arc<TurnChoice> {
fn wrap(self) -> Shared<AnyObj> {
fn wrap(self) -> Value {
let o = match self.as_ref() {
TurnChoice::Move(_) => RuneTurnChoice::Move(RuneMoveChoice(self.clone())),
TurnChoice::Item(_) => RuneTurnChoice::Item(RuneItemChoice(self.clone())),
@ -83,7 +83,7 @@ impl RuneWrapper for &Arc<TurnChoice> {
TurnChoice::Flee(_) => RuneTurnChoice::Flee(RuneFleeChoice(self.clone())),
TurnChoice::Pass(_) => RuneTurnChoice::Pass(RunePassChoice(self.clone())),
};
Shared::new(AnyObj::new(o).unwrap()).unwrap()
rune::to_value(o).unwrap()
}
}
@ -96,7 +96,7 @@ impl RuneMoveChoice {
}
#[rune::function]
fn used_move(&self) -> Shared<AnyObj> { self.move_choice().used_move().wrap() }
fn used_move(&self) -> Value { self.move_choice().used_move().wrap() }
#[rune::function]
fn target_side(&self) -> u8 { self.move_choice().target_side() }
@ -108,5 +108,5 @@ impl RuneMoveChoice {
fn priority(&self) -> i8 { self.move_choice().priority() }
#[rune::function]
fn user(&self) -> Shared<AnyObj> { self.move_choice().user().wrap() }
fn user(&self) -> Value { self.move_choice().user().wrap() }
}

View File

@ -1,5 +1,5 @@
use rune::alloc::fmt::TryWrite;
use rune::runtime::{AnyObj, Protocol, Shared, VmResult};
use rune::runtime::{Protocol, VmResult};
use rune::{Any, Value};
use std::num::Saturating;
@ -8,7 +8,7 @@ mod parameters;
mod static_data;
pub trait RuneWrapper {
fn wrap(self) -> Shared<AnyObj>;
fn wrap(self) -> Value;
}
pub fn module() -> anyhow::Result<rune::Module> {
@ -33,6 +33,8 @@ pub fn module() -> anyhow::Result<rune::Module> {
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)?;
@ -40,30 +42,24 @@ pub fn module() -> anyhow::Result<rune::Module> {
Ok(module)
}
pub fn wrap_int_reference(value: i64) -> anyhow::Result<Value> {
Ok(Value::Any(Shared::new(AnyObj::new(RuneValueIntWrapper::new(value))?)?))
}
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(Value::Any(Shared::new(AnyObj::new(RuneValueBoolWrapper::new(value))?)?))
Ok(rune::to_value(RuneValueBoolWrapper::new(value))?)
}
pub fn get_int_reference_value(value: Value) -> anyhow::Result<i64> {
let obj = value.into_any().into_result()?;
let obj = obj.take()?;
let obj = match obj.downcast_borrow_ref::<RuneValueIntWrapper>() {
Some(obj) => obj,
None => return Err(anyhow::anyhow!("Value is not a RuneValueIntWrapper")),
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 = value.into_any().into_result()?;
let obj = obj.take()?;
let obj = match obj.downcast_borrow_ref::<RuneValueBoolWrapper>() {
Some(obj) => obj,
None => return Err(anyhow::anyhow!("Value is not a RuneValueBoolWrapper")),
let obj = match value.into_any::<RuneValueBoolWrapper>() {
Ok(obj) => obj,
Err(_) => return Err(anyhow::anyhow!("Value is not a RuneValueBoolWrapper")),
};
Ok(obj.as_bool())
}
@ -71,9 +67,7 @@ pub fn get_bool_reference_value(value: Value) -> anyhow::Result<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::Shared<rune::runtime::AnyObj> {
rune::runtime::Shared::new(rune::runtime::AnyObj::new($wrapped_type(self.clone())).unwrap()).unwrap()
}
fn wrap(self) -> rune::runtime::Value { rune::to_value($wrapped_type(self.clone())).unwrap() }
}
};
}
@ -82,6 +76,7 @@ use crate::StringKey;
use impl_rune_wrapper;
#[derive(Any, Clone)]
#[rune(name = RefInt)]
struct RuneValueIntWrapper {
value: Saturating<i64>,
}
@ -106,10 +101,12 @@ impl RuneValueIntWrapper {
fn sub_assign(&mut self, other: i64) { self.value -= other; }
fn div_assign(&mut self, other: Value) {
match other {
Value::Integer(other) => self.value /= other,
Value::Float(other) => self.div_assign_f64(other),
_ => (),
match other.as_integer() {
Ok(other) => self.value /= other,
Err(_) => match other.as_float() {
Ok(other) => self.div_assign_f64(other),
Err(_) => (),
},
}
}
@ -125,10 +122,12 @@ impl RuneValueIntWrapper {
}
fn mul_assign(&mut self, other: Value) {
match other {
Value::Integer(other) => self.value *= other,
Value::Float(other) => self.mul_assign_f64(other),
_ => (),
match other.as_integer() {
Ok(other) => self.value *= other,
Err(_) => match other.as_float() {
Ok(other) => self.mul_assign_f64(other),
Err(_) => (),
},
}
}
@ -155,6 +154,7 @@ impl RuneValueIntWrapper {
}
#[derive(Any, Clone)]
#[rune(name = RefBool)]
struct RuneValueBoolWrapper(bool);
impl RuneValueBoolWrapper {
@ -178,6 +178,7 @@ impl RuneValueBoolWrapper {
}
#[derive(Any, Clone, Debug)]
#[rune(name = StringKey)]
pub(super) struct RuneStringKey(pub StringKey);
impl RuneStringKey {
@ -188,24 +189,39 @@ impl RuneStringKey {
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) -> Shared<AnyObj> { Shared::new(AnyObj::new(RuneStringKey(self.clone())).unwrap()).unwrap() }
fn wrap(self) -> Value { rune::to_value(RuneStringKey(self.clone())).unwrap() }
}
#[cfg(test)]
mod 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) -> Vm {
let mut context = Context::with_default_modules().unwrap();
context.install(module().unwrap()).unwrap();
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).unwrap()).unwrap();
sources.insert(Source::memory(script)?)?;
let mut diagnostics = Diagnostics::new();
let mut options = Options::default();
@ -218,381 +234,431 @@ mod test {
.with_context(&context)
.with_diagnostics(&mut diagnostics)
.with_options(&options)
.build()
.unwrap();
if !diagnostics.is_empty() {
panic!("Diagnostics: {:?}", diagnostics);
.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));
}
Vm::new(Arc::new(context.runtime().unwrap()), Arc::new(unit))
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).unwrap().complete().into_result().unwrap()
$vm.execute([$func], args)?.complete().into_result()?
}};
}
pub(crate) use execute_vm;
#[test]
fn test_int_wrapper_set_value() {
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).unwrap();
)?;
let val = wrap_int_reference(10)?;
execute_vm!(vm, "test_int", val);
let v = get_int_reference_value(val).unwrap();
let v = get_int_reference_value(val)?;
assert_eq!(v, 5);
Ok(())
}
#[test]
fn test_int_wrapper_as_int() {
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).unwrap();
)?;
let val = wrap_int_reference(10)?;
let res = execute_vm!(vm, "test_int", val);
let res = res.as_integer().unwrap();
let res = res.as_integer()?;
assert_eq!(res, 10);
Ok(())
}
#[test]
fn test_int_wrapper_add() {
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).unwrap();
)?;
let val = wrap_int_reference(10)?;
execute_vm!(vm, "test_int", val);
let v = get_int_reference_value(val).unwrap();
let v = get_int_reference_value(val)?;
assert_eq!(v, 15);
Ok(())
}
#[test]
fn test_int_wrapper_add_overflow() {
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).unwrap();
)?;
let val = wrap_int_reference(i64::MAX)?;
execute_vm!(vm, "test_int", val);
let v = get_int_reference_value(val).unwrap();
let v = get_int_reference_value(val)?;
assert_eq!(v, i64::MAX);
Ok(())
}
#[test]
fn test_int_wrapper_sub() {
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).unwrap();
)?;
let val = wrap_int_reference(10)?;
execute_vm!(vm, "test_int", val);
let v = get_int_reference_value(val).unwrap();
let v = get_int_reference_value(val)?;
assert_eq!(v, 5);
Ok(())
}
#[test]
fn test_int_wrapper_underflow() {
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).unwrap();
)?;
let val = wrap_int_reference(i64::MIN)?;
execute_vm!(vm, "test_int", val);
let v = get_int_reference_value(val).unwrap();
let v = get_int_reference_value(val)?;
assert_eq!(v, i64::MIN);
Ok(())
}
#[test]
fn test_int_wrapper_mul() {
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).unwrap();
)?;
let val = wrap_int_reference(10)?;
execute_vm!(vm, "test_int", val);
let v = get_int_reference_value(val).unwrap();
let v = get_int_reference_value(val)?;
assert_eq!(v, 50);
Ok(())
}
#[test]
fn test_int_wrapper_mul_float() {
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).unwrap();
)?;
let val = wrap_int_reference(10)?;
execute_vm!(vm, "test_int", val);
let v = get_int_reference_value(val).unwrap();
let v = get_int_reference_value(val)?;
assert_eq!(v, 5);
Ok(())
}
#[test]
fn test_int_wrapper_mul_overflow() {
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).unwrap();
)?;
let val = wrap_int_reference(i64::MAX)?;
execute_vm!(vm, "test_int", val);
let v = get_int_reference_value(val).unwrap();
let v = get_int_reference_value(val)?;
assert_eq!(v, i64::MAX);
Ok(())
}
#[test]
fn test_int_wrapper_mul_float_overflow() {
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).unwrap();
)?;
let val = wrap_int_reference(i64::MAX)?;
execute_vm!(vm, "test_int", val);
let v = get_int_reference_value(val).unwrap();
let v = get_int_reference_value(val)?;
assert_eq!(v, i64::MAX);
Ok(())
}
#[test]
fn test_int_wrapper_mul_float_underflow() {
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).unwrap();
)?;
let val = wrap_int_reference(i64::MIN)?;
execute_vm!(vm, "test_int", val);
let v = get_int_reference_value(val).unwrap();
let v = get_int_reference_value(val)?;
assert_eq!(v, i64::MIN);
Ok(())
}
#[test]
fn test_int_wrapper_div() {
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).unwrap();
)?;
let val = wrap_int_reference(10)?;
execute_vm!(vm, "test_int", val);
let v = get_int_reference_value(val).unwrap();
let v = get_int_reference_value(val)?;
assert_eq!(v, 2);
Ok(())
}
#[test]
fn test_int_wrapper_div_float() {
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).unwrap();
)?;
let val = wrap_int_reference(10)?;
execute_vm!(vm, "test_int", val);
let v = get_int_reference_value(val).unwrap();
let v = get_int_reference_value(val)?;
assert_eq!(v, 20);
Ok(())
}
#[test]
fn test_int_wrapper_div_float_overflow() {
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).unwrap();
)?;
let val = wrap_int_reference(i64::MAX)?;
execute_vm!(vm, "test_int", val);
let v = get_int_reference_value(val).unwrap();
let v = get_int_reference_value(val)?;
assert_eq!(v, i64::MAX);
Ok(())
}
#[test]
fn test_int_wrapper_div_float_underflow() {
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).unwrap();
)?;
let val = wrap_int_reference(i64::MIN)?;
execute_vm!(vm, "test_int", val);
let v = get_int_reference_value(val).unwrap();
let v = get_int_reference_value(val)?;
assert_eq!(v, i64::MIN);
Ok(())
}
#[test]
fn test_int_wrapper_eq() {
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).unwrap();
)?;
let val = wrap_int_reference(5)?;
let res = execute_vm!(vm, "test_int", val);
let res = res.as_bool().unwrap();
let res = res.as_bool()?;
assert_eq!(res, true);
Ok(())
}
#[test]
fn test_int_wrapper_ineq() {
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).unwrap();
)?;
let val = wrap_int_reference(6)?;
let res = execute_vm!(vm, "test_int", val);
let res = res.as_bool().unwrap();
let res = res.as_bool()?;
assert_eq!(res, false);
Ok(())
}
#[test]
fn test_int_wrapper_string_display() {
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).unwrap();
)?;
let val = wrap_int_reference(5)?;
let res = execute_vm!(vm, "test_int", val);
let res = res.into_string().unwrap().take().unwrap().into_std();
let res = res.into_string()?.into_std();
assert_eq!(res, "5");
Ok(())
}
#[test]
fn test_bool_wrapper_set_value() {
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).unwrap();
)?;
let val = wrap_bool_reference(false)?;
execute_vm!(vm, "test_bool", val);
let v = get_bool_reference_value(val).unwrap();
let v = get_bool_reference_value(val)?;
assert_eq!(v, true);
Ok(())
}
#[test]
fn test_bool_wrapper_as_bool() {
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).unwrap();
)?;
let val = wrap_bool_reference(true)?;
let res = execute_vm!(vm, "test_bool", val);
let res = res.as_bool().unwrap();
let res = res.as_bool()?;
assert_eq!(res, true);
Ok(())
}
#[test]
fn test_bool_wrapper_eq() {
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).unwrap();
)?;
let val = wrap_bool_reference(true)?;
let res = execute_vm!(vm, "test_bool", val);
let res = res.as_bool().unwrap();
let res = res.as_bool()?;
assert_eq!(res, true);
Ok(())
}
#[test]
fn test_bool_wrapper_ineq() {
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).unwrap();
)?;
let val = wrap_bool_reference(false)?;
let res = execute_vm!(vm, "test_bool", val);
let res = res.as_bool().unwrap();
let res = res.as_bool()?;
assert_eq!(res, false);
Ok(())
}
#[test]
fn test_bool_wrapper_string_display() {
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).unwrap();
)?;
let val = wrap_bool_reference(true)?;
let res = execute_vm!(vm, "test_bool", val);
let res = res.into_string().unwrap().take().unwrap().into_std();
let res = res.into_string()?.into_std();
assert_eq!(res, "true");
Ok(())
}
#[test]
fn test_string_key_wrapper_string_display() {
fn test_string_key_wrapper_string_display() -> Result<()> {
let mut vm = setup_script(
r#"
pub fn test_string_key(a) {
`${a}`
}
"#,
);
let val = RuneStringKey::new(StringKey::from("test"));
let val = Shared::new(AnyObj::new(val).unwrap()).unwrap();
let arg = Value::Any(val);
)?;
let val = StringKey::from("test");
let arg = val.wrap();
let res = execute_vm!(vm, "test_string_key", arg);
let res = res.into_string().unwrap().take().unwrap().into_std();
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(())
}
}

View File

@ -1,6 +1,6 @@
use crate::script_implementations::rune::wrappers::{RuneStringKey, RuneWrapper};
use crate::static_data::Parameter;
use rune::runtime::{AnyObj, Shared};
use rune::runtime::Value;
use rune::Any;
use std::ops::Deref;
use std::sync::Arc;
@ -11,6 +11,7 @@ pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
}
#[derive(Debug, Any)]
#[rune(name = Parameter)]
pub(super) enum RuneParameter {
Int(#[rune(get)] i32),
Float(#[rune(get)] f32),
@ -19,13 +20,13 @@ pub(super) enum RuneParameter {
}
impl RuneWrapper for &Arc<Parameter> {
fn wrap(self) -> Shared<AnyObj> {
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())),
};
Shared::new(AnyObj::new(p).unwrap()).unwrap()
rune::to_value(p).unwrap()
}
}

View File

@ -1,6 +1,7 @@
use crate::script_implementations::rune::wrappers::{impl_rune_wrapper, RuneStringKey, RuneWrapper};
use crate::static_data::Ability;
use rune::runtime::{AnyObj, Shared};
use crate::StringKey;
use rune::runtime::Value;
use rune::Any;
use std::sync::Arc;
@ -19,16 +20,101 @@ impl_rune_wrapper!(&Arc<dyn Ability>, RuneAbility);
impl RuneAbility {
#[rune::function]
fn name(&self) -> Shared<AnyObj> { self.0.name().wrap() }
fn name(&self) -> Value { self.0.name().wrap() }
#[rune::function]
fn effect(&self) -> Shared<AnyObj> { self.0.effect().wrap() }
fn effect(&self) -> Value { self.0.effect().wrap() }
#[rune::function(vm_result)]
fn get_parameter(&self, key: RuneStringKey) -> Option<Shared<AnyObj>> {
match self.0.parameters().get(&key.0) {
None => None,
Some(p) => Some(p.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(())
}
}

View File

@ -1,6 +1,7 @@
use crate::script_implementations::rune::wrappers::{impl_rune_wrapper, RuneStringKey, RuneWrapper};
use crate::static_data::{AbilityIndex, Form, Statistic};
use rune::runtime::{AnyObj, Shared};
use crate::StringKey;
use rune::runtime::Value;
use rune::Any;
use std::sync::Arc;
@ -22,13 +23,14 @@ pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
}
#[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) -> Shared<AnyObj> { self.0.name().wrap() }
fn name(&self) -> Value { self.0.name().wrap() }
#[rune::function]
fn height(&self) -> f32 { self.0.height() }
@ -40,28 +42,286 @@ impl RuneForm {
fn base_experience(&self) -> u32 { self.0.base_experience() }
#[rune::function]
fn types(&self) -> Vec<u8> { self.0.types().iter().map(|t| u8::from(*t)).collect() }
fn types(&self) -> Vec<i64> { self.0.types().iter().map(|t| u8::from(*t) as i64).collect() }
#[rune::function]
fn base_stats(&self) -> Shared<AnyObj> { self.0.base_stats().wrap() }
fn base_stats(&self) -> Value { self.0.base_stats().wrap() }
#[rune::function]
fn abilities(&self) -> Vec<Shared<AnyObj>> { self.0.abilities().iter().map(|a| a.wrap()).collect() }
fn abilities(&self) -> Vec<Value> { self.0.abilities().iter().map(|a| a.wrap()).collect() }
#[rune::function]
fn hidden_abilities(&self) -> Vec<Shared<AnyObj>> { self.0.hidden_abilities().iter().map(|a| a.wrap()).collect() }
fn hidden_abilities(&self) -> Vec<Value> { self.0.hidden_abilities().iter().map(|a| a.wrap()).collect() }
#[rune::function]
fn has_flag(&self, key: &RuneStringKey) -> bool { self.0.has_flag(&key.0) }
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<u8> { self.0.get_type(index).map(|t| u8::from(t)) }
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: u8) -> anyhow::Result<Shared<AnyObj>> {
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(())
}
}

View File

@ -21,7 +21,59 @@ impl RuneGrowthRate {
fn calculate_level(&self, experience: u32) -> i32 { self.0.calculate_level(experience) as i32 }
#[rune::function]
fn calculate_experience(&self, level: LevelInt) -> Result<u32, String> {
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(())
}
}

View File

@ -1,6 +1,6 @@
use std::sync::Arc;
use rune::runtime::{AnyObj, Shared};
use rune::runtime::Value;
use rune::Any;
use crate::script_implementations::rune::wrappers::{impl_rune_wrapper, RuneStringKey, RuneWrapper};
@ -28,7 +28,7 @@ impl_rune_wrapper!(&Arc<dyn Item>, RuneItem);
impl RuneItem {
#[rune::function]
fn name(&self) -> Shared<AnyObj> { self.0.name().clone().wrap() }
fn name(&self) -> Value { self.0.name().clone().wrap() }
#[rune::function]
fn category(&self) -> ItemCategory { self.0.category() }
@ -40,8 +40,34 @@ impl RuneItem {
fn price(&self) -> i32 { self.0.price() }
#[rune::function]
fn flags(&self) -> Vec<Shared<AnyObj>> { self.0.flags().iter().map(|s| s.clone().wrap()).collect() }
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(())
}
}

View File

@ -1,7 +1,7 @@
use crate::defines::LevelInt;
use crate::script_implementations::rune::wrappers::{impl_rune_wrapper, RuneStringKey, RuneWrapper};
use crate::static_data::LearnableMoves;
use rune::runtime::{AnyObj, Shared};
use rune::runtime::Value;
use rune::Any;
use std::sync::Arc;
@ -20,14 +20,14 @@ impl_rune_wrapper!(&Arc<dyn LearnableMoves>, RuneLearnableMoves);
impl RuneLearnableMoves {
#[rune::function]
fn get_learned_by_level(&self, level: LevelInt) -> Option<Vec<Shared<AnyObj>>> {
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<Shared<AnyObj>> {
fn get_distinct_level_moves(&self) -> Vec<Value> {
self.0
.get_distinct_level_moves()
.into_iter()

View File

@ -6,7 +6,7 @@ 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::{AnyObj, Shared};
use rune::runtime::Value;
use std::sync::Arc;
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
@ -49,13 +49,13 @@ macro_rules! impl_rune_data_library_wrapper {
impl $t {
#[rune::function]
fn get(&self, key: &RuneStringKey) -> Option<Shared<AnyObj>> { self.0.get(&key.0).map(|v| v.wrap()) }
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<Shared<AnyObj>> {
fn get_key_by_index(&self, index: usize) -> Option<Value> {
self.0.get_key_by_index(index).map(|v| v.wrap())
}
}

View File

@ -1,7 +1,7 @@
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::{AnyObj, Shared};
use rune::runtime::Value;
use std::sync::Arc;
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
@ -18,7 +18,7 @@ impl_rune_wrapper!(&Arc<dyn NatureLibrary>, RuneNatureLibrary);
impl RuneNatureLibrary {
#[rune::function]
fn get_nature(&self, key: RuneStringKey) -> Option<Shared<AnyObj>> { self.0.get_nature(&key.0).map(|v| v.wrap()) }
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 {

View File

@ -1,6 +1,6 @@
use crate::script_implementations::rune::wrappers::{impl_rune_wrapper, RuneWrapper};
use crate::static_data::StaticData;
use rune::runtime::{AnyObj, Shared};
use rune::runtime::Value;
use std::sync::Arc;
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
@ -23,26 +23,26 @@ impl_rune_wrapper!(&Arc<dyn StaticData>, RuneStaticData);
impl RuneStaticData {
#[rune::function]
fn settings(&self) -> Shared<AnyObj> { self.0.settings().wrap() }
fn settings(&self) -> Value { self.0.settings().wrap() }
#[rune::function]
fn species(&self) -> Shared<AnyObj> { self.0.species().wrap() }
fn species(&self) -> Value { self.0.species().wrap() }
#[rune::function]
fn moves(&self) -> Shared<AnyObj> { self.0.moves().wrap() }
fn moves(&self) -> Value { self.0.moves().wrap() }
#[rune::function]
fn items(&self) -> Shared<AnyObj> { self.0.items().wrap() }
fn items(&self) -> Value { self.0.items().wrap() }
#[rune::function]
fn growth_rates(&self) -> Shared<AnyObj> { self.0.growth_rates().wrap() }
fn growth_rates(&self) -> Value { self.0.growth_rates().wrap() }
#[rune::function]
fn types(&self) -> Shared<AnyObj> { self.0.types().wrap() }
fn types(&self) -> Value { self.0.types().wrap() }
#[rune::function]
fn natures(&self) -> Shared<AnyObj> { self.0.natures().wrap() }
fn natures(&self) -> Value { self.0.natures().wrap() }
#[rune::function]
fn abilities(&self) -> Shared<AnyObj> { self.0.abilities().wrap() }
fn abilities(&self) -> Value { self.0.abilities().wrap() }
}

View File

@ -1,6 +1,6 @@
use crate::script_implementations::rune::wrappers::{impl_rune_wrapper, RuneStringKey, RuneWrapper};
use crate::static_data::TypeLibrary;
use rune::runtime::{AnyObj, Shared};
use rune::runtime::Value;
use std::sync::Arc;
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
@ -22,7 +22,7 @@ impl RuneTypeLibrary {
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<Shared<AnyObj>> { self.0.get_type_name(t.into()).map(|v| v.wrap()) }
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> {

View File

@ -1,7 +1,7 @@
use crate::script_implementations::rune::wrappers::{impl_rune_wrapper, RuneStringKey, RuneWrapper};
use crate::static_data::{MoveCategory, MoveData, MoveTarget, SecondaryEffect};
use rune::runtime::{AnyObj, Object, Shared};
use rune::{Any, Value};
use rune::runtime::{Object, Value};
use rune::Any;
use std::convert::TryFrom;
use std::sync::Arc;
@ -35,7 +35,7 @@ impl_rune_wrapper!(&Arc<dyn MoveData>, RuneMoveData);
impl RuneMoveData {
#[rune::function]
fn name(&self) -> Shared<AnyObj> { self.0.name().wrap() }
fn name(&self) -> Value { self.0.name().wrap() }
#[rune::function]
fn move_type(&self) -> u8 { u8::from(self.0.move_type()) }
@ -59,7 +59,7 @@ impl RuneMoveData {
fn priority(&self) -> i8 { self.0.priority() }
#[rune::function]
fn secondary_effect(&self) -> Option<Shared<AnyObj>> { self.0.secondary_effect().as_ref().map(|x| x.wrap()) }
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) }
@ -75,7 +75,7 @@ impl RuneSecondaryEffect {
fn chance(&self) -> f32 { self.0.chance() }
#[rune::function]
fn effect_name(&self) -> Shared<AnyObj> { self.0.effect_name().wrap() }
fn effect_name(&self) -> Value { self.0.effect_name().wrap() }
#[rune::function]
fn parameters(&self) -> anyhow::Result<Object> {

View File

@ -1,6 +1,6 @@
use crate::script_implementations::rune::wrappers::{impl_rune_wrapper, RuneStringKey, RuneWrapper};
use crate::static_data::Species;
use rune::runtime::{AnyObj, Shared};
use rune::runtime::Value;
use rune::Any;
use std::sync::Arc;
@ -29,13 +29,13 @@ impl RuneSpecies {
fn id(&self) -> u16 { self.0.id() }
#[rune::function]
fn name(&self) -> Shared<AnyObj> { self.0.name().wrap() }
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) -> Shared<AnyObj> { self.0.growth_rate().wrap() }
fn growth_rate(&self) -> Value { self.0.growth_rate().wrap() }
#[rune::function]
fn capture_rate(&self) -> u8 { self.0.capture_rate() }
@ -44,12 +44,10 @@ impl RuneSpecies {
fn base_happiness(&self) -> u8 { self.0.base_happiness() }
#[rune::function]
fn get_form(&self, name: &RuneStringKey) -> Option<Shared<AnyObj>> {
self.0.get_form(&name.0).map(|form| form.wrap())
}
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<Shared<AnyObj>> { self.0.get_default_form().map(|v| v.wrap()) }
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) }

View File

@ -12,20 +12,28 @@ use crate::StringKey;
#[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,
}
@ -36,14 +44,19 @@ pub enum ItemCategory {
#[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,
}

View File

@ -14,6 +14,8 @@ 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 moves::tests::*;
#[doc(inline)] pub use natures::tests::*;
#[doc(inline)] pub use species_data::tests::*;

View File

@ -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;

View File

@ -9,6 +9,7 @@
pub(crate) mod tests {
pub use super::form::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.

View File

@ -7,15 +7,21 @@
#[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,
}

View File

@ -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")); }