A lot more work on WASM script execution
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
use crate::dynamic_data::{
|
||||
Battle, BattleParty, BattleRandom, BattleSide, ChoiceQueue, DynamicLibrary, Pokemon, PokemonParty,
|
||||
};
|
||||
use crate::script_implementations::wasm::export_registry::register;
|
||||
use crate::script_implementations::wasm::extern_ref::{ExternRef, VecExternRef};
|
||||
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv;
|
||||
use wasmer::FunctionEnvMut;
|
||||
|
||||
register! {
|
||||
fn battle_get_parties(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
battle: ExternRef<Battle>,
|
||||
) -> VecExternRef<BattleParty> {
|
||||
VecExternRef::new(env.data().data().as_ref(), battle.value_func(&env).unwrap().parties())
|
||||
}
|
||||
|
||||
fn battle_get_choice_queue(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
battle: ExternRef<Battle>,
|
||||
) -> ExternRef<ChoiceQueue> {
|
||||
let queue = battle.value_func(&env).unwrap().current_turn_queue().read();
|
||||
if let Some(queue) = queue.as_ref() {
|
||||
ExternRef::func_new(&env, queue)
|
||||
} else {
|
||||
ExternRef::null()
|
||||
}
|
||||
}
|
||||
|
||||
fn battle_get_library(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
battle: ExternRef<Battle>,
|
||||
) -> ExternRef<DynamicLibrary> {
|
||||
ExternRef::func_new(&env, battle.value_func(&env).unwrap().library().as_ref())
|
||||
}
|
||||
|
||||
fn battle_get_sides(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
battle: ExternRef<Battle>,
|
||||
) -> VecExternRef<BattleSide> {
|
||||
VecExternRef::new(env.data().data().as_ref(), battle.value_func(&env).unwrap().sides())
|
||||
}
|
||||
|
||||
fn battle_get_random(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
battle: ExternRef<Battle>,
|
||||
) -> ExternRef<BattleRandom> {
|
||||
ExternRef::func_new(&env, battle.value_func(&env).unwrap().random())
|
||||
}
|
||||
|
||||
fn battle_find_party_for_pokemon(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
battle: ExternRef<Battle>,
|
||||
pokemon: ExternRef<Pokemon>
|
||||
) -> ExternRef<BattleParty> {
|
||||
let battle = battle.value_func(&env).unwrap();
|
||||
let pokemon = pokemon.value_func(&env).unwrap();
|
||||
for party in battle.parties() {
|
||||
if party.party().has_pokemon(pokemon) {
|
||||
return ExternRef::func_new(&env, party);
|
||||
}
|
||||
}
|
||||
ExternRef::null()
|
||||
}
|
||||
|
||||
fn battle_party_get_party(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
battle_party: ExternRef<BattleParty>,
|
||||
) -> ExternRef<PokemonParty> {
|
||||
ExternRef::func_new(&env, battle_party.value_func(&env).unwrap().party().as_ref())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
use crate::dynamic_data::BattleRandom;
|
||||
use crate::script_implementations::wasm::export_registry::register;
|
||||
use crate::script_implementations::wasm::extern_ref::ExternRef;
|
||||
use wasmer::FunctionEnvMut;
|
||||
|
||||
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv;
|
||||
|
||||
register! {
|
||||
fn battle_random_get(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
battle_random: ExternRef<BattleRandom>,
|
||||
) -> i32 {
|
||||
battle_random.value_func(&env).unwrap().get()
|
||||
}
|
||||
fn battle_random_get_max(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
battle_random: ExternRef<BattleRandom>,
|
||||
max: i32
|
||||
) -> i32 {
|
||||
battle_random.value_func(&env).unwrap().get_max(max)
|
||||
}
|
||||
fn battle_random_get_between(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
battle_random: ExternRef<BattleRandom>,
|
||||
min: i32,
|
||||
max: i32
|
||||
) -> i32 {
|
||||
battle_random.value_func(&env).unwrap().get_between(min, max)
|
||||
}
|
||||
}
|
||||
123
src/script_implementations/wasm/export_registry/dynamic_data/battle_side.rs
Executable file
123
src/script_implementations/wasm/export_registry/dynamic_data/battle_side.rs
Executable file
@@ -0,0 +1,123 @@
|
||||
use crate::dynamic_data::{Battle, BattleSide, Pokemon, VolatileScriptsOwner};
|
||||
use crate::script_implementations::wasm::export_registry::register;
|
||||
use crate::script_implementations::wasm::extern_ref::ExternRef;
|
||||
use crate::script_implementations::wasm::script::WebAssemblyScript;
|
||||
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv;
|
||||
use crate::{ScriptCategory, StringKey};
|
||||
use std::ffi::CString;
|
||||
use wasmer::{FunctionEnvMut, Value};
|
||||
|
||||
register! {
|
||||
fn battleside_has_fled_battle(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
side: ExternRef<BattleSide>,
|
||||
) -> u8 {
|
||||
if side.value_func(&env).unwrap().has_fled_battle() { 1 } else { 0 }
|
||||
}
|
||||
|
||||
fn battleside_is_defeated(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
side: ExternRef<BattleSide>,
|
||||
) -> u8 {
|
||||
if side.value_func(&env).unwrap().is_defeated() { 1 } else { 0 }
|
||||
}
|
||||
|
||||
fn battleside_get_side_index(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
side: ExternRef<BattleSide>,
|
||||
) -> u8 {
|
||||
side.value_func(&env).unwrap().index()
|
||||
}
|
||||
|
||||
fn battleside_get_pokemon_per_side(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
side: ExternRef<BattleSide>,
|
||||
) -> u8 {
|
||||
side.value_func(&env).unwrap().pokemon_per_side()
|
||||
}
|
||||
|
||||
fn battleside_get_battle(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
side: ExternRef<BattleSide>,
|
||||
) -> ExternRef<Battle> {
|
||||
ExternRef::func_new(&env, side.value_func(&env).unwrap().battle())
|
||||
}
|
||||
|
||||
fn battleside_get_pokemon(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
side: ExternRef<BattleSide>,
|
||||
index: u32
|
||||
) -> ExternRef<Pokemon> {
|
||||
if let Some(Some(p)) = side.value_func(&env).unwrap().pokemon().get(index as usize) {
|
||||
ExternRef::func_new(&env, p.as_ref())
|
||||
} else {
|
||||
ExternRef::null()
|
||||
}
|
||||
}
|
||||
|
||||
fn battleside_add_volatile_by_name(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
side: ExternRef<BattleSide>,
|
||||
name_ptr: u32
|
||||
) -> u32 {
|
||||
unsafe {
|
||||
let c_name = CString::from_raw(env.data().data().get_raw_pointer(name_ptr));
|
||||
let script = side.value_func(&env).unwrap().add_volatile_script(&c_name.into()).unwrap();
|
||||
if let Some(script) = script {
|
||||
let script = script.get_as::<WebAssemblyScript>();
|
||||
script.get_wasm_pointer()
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn battleside_add_volatile(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
side: ExternRef<BattleSide>,
|
||||
script_ptr: u32
|
||||
) -> u32 {
|
||||
let side = side.value_func(&env).unwrap();
|
||||
let name_ptr = env.data().data().exported_functions().get(&StringKey::new("script_get_name")).unwrap().call(&mut env.data().data().store_mut(), &[Value::I32(script_ptr as i32)]).unwrap().get(0).unwrap().i32().unwrap() as u32;
|
||||
unsafe{
|
||||
let name_ptr: CString = CString::from_raw(env.data().data().get_raw_pointer(name_ptr));
|
||||
let script = env.data().data().setup_script(script_ptr, ScriptCategory::Side, &name_ptr.into(), side.into()).unwrap();
|
||||
if let Some(script) = script {
|
||||
let script = side.add_volatile_script_with_script(script);
|
||||
script.unwrap().unwrap().get_as::<WebAssemblyScript>().get_wasm_pointer()
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn battleside_get_volatile(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
side: ExternRef<BattleSide>,
|
||||
name_ptr: u32
|
||||
) -> u32 {
|
||||
unsafe {
|
||||
let c_name = CString::from_raw(env.data().data().get_raw_pointer(name_ptr));
|
||||
let script = side.value_func(&env).unwrap().get_volatile_script(&c_name.into());
|
||||
if let Some(script) = script {
|
||||
let script = script.get_as::<WebAssemblyScript>();
|
||||
script.get_wasm_pointer()
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn battleside_remove_volatile(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
side: ExternRef<BattleSide>,
|
||||
name_ptr: u32
|
||||
) {
|
||||
unsafe {
|
||||
let c_name = CString::from_raw(env.data().data().get_raw_pointer(name_ptr));
|
||||
side.value_func(&env).unwrap().remove_volatile_script(&c_name.into());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
use crate::dynamic_data::{ChoiceQueue, Pokemon};
|
||||
use crate::script_implementations::wasm::export_registry::register;
|
||||
use crate::script_implementations::wasm::extern_ref::ExternRef;
|
||||
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv;
|
||||
use wasmer::FunctionEnvMut;
|
||||
|
||||
register! {
|
||||
fn choice_queue_move_pokemon_choice_next(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
battle_random: ExternRef<ChoiceQueue>,
|
||||
pokemon: ExternRef<Pokemon>
|
||||
) -> u8 {
|
||||
if battle_random.value_func(&env).unwrap().move_pokemon_choice_next(pokemon.value_func(&env).unwrap()) {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
use crate::dynamic_data::{ExecutingMove, HitData, LearnedMove, Pokemon};
|
||||
use crate::script_implementations::wasm::export_registry::register;
|
||||
use crate::script_implementations::wasm::extern_ref::ExternRef;
|
||||
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv;
|
||||
use crate::static_data::MoveData;
|
||||
use wasmer::FunctionEnvMut;
|
||||
|
||||
register! {
|
||||
fn executing_move_get_user(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
executing_move: ExternRef<ExecutingMove>,
|
||||
) -> ExternRef<Pokemon> {
|
||||
ExternRef::func_new(&env, executing_move.value_func(&env).unwrap().user().as_ref())
|
||||
}
|
||||
|
||||
fn executing_move_get_use_move(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
executing_move: ExternRef<ExecutingMove>,
|
||||
) -> ExternRef<MoveData> {
|
||||
ExternRef::func_new(&env, executing_move.value_func(&env).unwrap().use_move().as_ref())
|
||||
}
|
||||
|
||||
fn executing_move_get_chosen_move(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
executing_move: ExternRef<ExecutingMove>,
|
||||
) -> ExternRef<LearnedMove> {
|
||||
ExternRef::func_new(&env, executing_move.value_func(&env).unwrap().chosen_move().as_ref())
|
||||
}
|
||||
|
||||
fn executing_move_get_number_of_hits(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
executing_move: ExternRef<ExecutingMove>,
|
||||
) -> u8 {
|
||||
executing_move.value_func(&env).unwrap().number_of_hits()
|
||||
}
|
||||
|
||||
fn executing_move_get_hit_data(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
executing_move: ExternRef<ExecutingMove>,
|
||||
target: ExternRef<Pokemon>,
|
||||
hit: u8
|
||||
) -> ExternRef<HitData> {
|
||||
ExternRef::func_new(&env, executing_move.value_func(&env).unwrap().get_hit_data(target.value_func(&env).unwrap(), hit).unwrap())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
use crate::dynamic_data::HitData;
|
||||
use crate::script_implementations::wasm::export_registry::register;
|
||||
use crate::script_implementations::wasm::extern_ref::ExternRef;
|
||||
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv;
|
||||
use wasmer::FunctionEnvMut;
|
||||
|
||||
register! {
|
||||
fn hit_data_fail(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
hit: ExternRef<HitData>,
|
||||
) {
|
||||
hit.value_func(&env).unwrap().fail()
|
||||
}
|
||||
}
|
||||
0
src/script_implementations/wasm/export_registry/dynamic_data/learned_move.rs
Normal file → Executable file
0
src/script_implementations/wasm/export_registry/dynamic_data/learned_move.rs
Normal file → Executable file
48
src/script_implementations/wasm/export_registry/dynamic_data/mod.rs
Normal file → Executable file
48
src/script_implementations/wasm/export_registry/dynamic_data/mod.rs
Normal file → Executable file
@@ -1,31 +1,67 @@
|
||||
use crate::dynamic_data::DynamicLibrary;
|
||||
use crate::dynamic_data::{DynamicLibrary, ScriptOwnerData};
|
||||
use crate::script_implementations::wasm::export_registry::register;
|
||||
use crate::script_implementations::wasm::extern_ref::ExternRef;
|
||||
use std::sync::atomic::Ordering;
|
||||
use wasmer::{FunctionEnv, FunctionEnvMut, Imports, StoreMut};
|
||||
|
||||
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv;
|
||||
use crate::static_data::StaticData;
|
||||
|
||||
mod battle_random;
|
||||
/// Battle side registration
|
||||
mod battle_side;
|
||||
mod choice_queue;
|
||||
mod executing_move;
|
||||
/// Learned move registration
|
||||
mod learned_move;
|
||||
mod party;
|
||||
/// Pokemon registration
|
||||
mod pokemon;
|
||||
/// Turn choice registration
|
||||
mod turn_choice;
|
||||
mod hit_data;
|
||||
mod battle;
|
||||
|
||||
register! {
|
||||
fn dynamic_library_get_static_data(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
dynamic_lib: ExternRef<DynamicLibrary>,
|
||||
) -> ExternRef<StaticData> {
|
||||
ExternRef::func_new(&env, dynamic_lib.value_func(&env).unwrap().static_data())
|
||||
}
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
dynamic_lib: ExternRef<DynamicLibrary>,
|
||||
) -> ExternRef<StaticData> {
|
||||
ExternRef::func_new(&env, dynamic_lib.value_func(&env).unwrap().static_data())
|
||||
}
|
||||
|
||||
fn script_get_owner(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
script: u32,
|
||||
) -> u32 {
|
||||
unsafe {
|
||||
let script = env.data().data().get_loaded_script(script);
|
||||
if let Some(script) = script {
|
||||
match script.get_owner() {
|
||||
ScriptOwnerData::Pokemon(p) => env.data().data().get_extern_ref_index(p.load(Ordering::Relaxed).as_ref().unwrap()),
|
||||
ScriptOwnerData::BattleSide(p) => env.data().data().get_extern_ref_index(p.load(Ordering::Relaxed).as_ref().unwrap()),
|
||||
ScriptOwnerData::Battle(p) => env.data().data().get_extern_ref_index(p.load(Ordering::Relaxed).as_ref().unwrap()),
|
||||
ScriptOwnerData::None => 0,
|
||||
}
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
manual manual_register
|
||||
}
|
||||
|
||||
/// Additional required manual registration
|
||||
fn manual_register(imports: &mut Imports, store: &mut StoreMut, env: &FunctionEnv<WebAssemblyEnv>) {
|
||||
battle::register(imports, store, env);
|
||||
turn_choice::register(imports, store, env);
|
||||
pokemon::register(imports, store, env);
|
||||
learned_move::register(imports, store, env);
|
||||
battle_side::register(imports, store, env);
|
||||
battle_random::register(imports, store, env);
|
||||
choice_queue::register(imports, store, env);
|
||||
party::register(imports, store, env);
|
||||
executing_move::register(imports, store, env);
|
||||
hit_data::register(imports, store, env);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
use crate::dynamic_data::{Pokemon, PokemonParty};
|
||||
use crate::script_implementations::wasm::export_registry::register;
|
||||
use crate::script_implementations::wasm::extern_ref::ExternRef;
|
||||
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv;
|
||||
use wasmer::FunctionEnvMut;
|
||||
|
||||
register! {
|
||||
fn party_get_pokemon(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
party: ExternRef<PokemonParty>,
|
||||
index: u32
|
||||
) -> ExternRef<Pokemon> {
|
||||
if let Some(v) = &party.value_func(&env).unwrap().pokemon()[index as usize] {
|
||||
ExternRef::func_new(&env, v.as_ref())
|
||||
} else {
|
||||
ExternRef::null()
|
||||
}
|
||||
}
|
||||
|
||||
fn party_get_length(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
party: ExternRef<PokemonParty>,
|
||||
) -> u32 {
|
||||
party.value_func(&env).unwrap().length() as u32
|
||||
}
|
||||
}
|
||||
70
src/script_implementations/wasm/export_registry/dynamic_data/pokemon.rs
Normal file → Executable file
70
src/script_implementations/wasm/export_registry/dynamic_data/pokemon.rs
Normal file → Executable file
@@ -1,11 +1,11 @@
|
||||
use std::mem::transmute;
|
||||
|
||||
use crate::dynamic_data::{DynamicLibrary, Pokemon};
|
||||
use crate::dynamic_data::{Battle, DynamicLibrary, LearnedMove, Pokemon};
|
||||
use crate::script_implementations::wasm::export_registry::register;
|
||||
use crate::script_implementations::wasm::extern_ref::ExternRef;
|
||||
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv;
|
||||
use crate::static_data::StatisticSet;
|
||||
use crate::static_data::{ClampedStatisticSet, Species};
|
||||
use crate::static_data::{Item, StatisticSet};
|
||||
use wasmer::FunctionEnvMut;
|
||||
|
||||
register! {
|
||||
@@ -75,4 +75,70 @@ register! {
|
||||
pokemon.value_func(&env).unwrap().damage(damage, transmute(source));
|
||||
}
|
||||
}
|
||||
|
||||
fn pokemon_get_learned_move(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
pokemon: ExternRef<Pokemon>,
|
||||
index: u32
|
||||
) -> ExternRef<LearnedMove> {
|
||||
let read_lock = pokemon.value_func(&env).unwrap().learned_moves().read();
|
||||
let mv = read_lock.get(index as usize);
|
||||
if let Some(Some(mv)) = mv {
|
||||
ExternRef::func_new(&env, mv)
|
||||
}
|
||||
else{
|
||||
ExternRef::null()
|
||||
}
|
||||
}
|
||||
|
||||
fn pokemon_change_stat_boost(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
pokemon: ExternRef<Pokemon>,
|
||||
stat: u8,
|
||||
amount: i8,
|
||||
self_inflicted: u8
|
||||
) -> u8 {
|
||||
unsafe{
|
||||
if pokemon.value_func(&env).unwrap().change_stat_boost(transmute(stat), amount, self_inflicted == 1) {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn pokemon_get_battle(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
pokemon: ExternRef<Pokemon>,
|
||||
) -> ExternRef<Battle> {
|
||||
if let Some(battle) = pokemon.value_func(&env).unwrap().get_battle() {
|
||||
ExternRef::func_new(&env, battle)
|
||||
} else {
|
||||
ExternRef::null()
|
||||
}
|
||||
}
|
||||
|
||||
fn pokemon_get_battle_side_index(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
pokemon: ExternRef<Pokemon>,
|
||||
) -> u8 {
|
||||
if let Some(i) = pokemon.value_func(&env).unwrap().get_battle_index() {
|
||||
i
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
fn pokemon_get_held_item(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
pokemon: ExternRef<Pokemon>,
|
||||
) -> ExternRef<Item> {
|
||||
let read_lock = pokemon.value_func(&env).unwrap().held_item().read();
|
||||
if let Some(item) = read_lock.as_ref() {
|
||||
ExternRef::func_new(&env, item.as_ref())
|
||||
} else {
|
||||
ExternRef::null()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
7
src/script_implementations/wasm/export_registry/dynamic_data/turn_choice.rs
Normal file → Executable file
7
src/script_implementations/wasm/export_registry/dynamic_data/turn_choice.rs
Normal file → Executable file
@@ -59,4 +59,11 @@ register! {
|
||||
panic!("Invalid turn choice");
|
||||
}
|
||||
|
||||
fn turn_choice_fail(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
turn_choice: ExternRef<TurnChoice>,
|
||||
) {
|
||||
turn_choice.value_func(&env).unwrap().fail();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user