use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle}; use crate::ffi::{ffi_handle_arc_dyn_getter, FFIResult, NonOwnedPtrString, OwnedPtrString}; use crate::static_data::{ MoveCategory, MoveData, MoveDataImpl, MoveTarget, Parameter, SecondaryEffect, SecondaryEffectImpl, TypeIdentifier, }; use crate::StringKey; use anyhow::anyhow; use hashbrown::{HashMap, HashSet}; use std::ffi::{c_char, CStr, CString}; use std::sync::Arc; /// Instantiates a new move. #[no_mangle] unsafe extern "C" fn move_data_new( name: *const c_char, move_type: TypeIdentifier, category: MoveCategory, base_power: u8, accuracy: u8, base_usages: u8, target: MoveTarget, priority: i8, secondary_effect: FFIHandle>, flags: *const *const c_char, flags_length: usize, ) -> FFIResult>> { let flags = std::slice::from_raw_parts(flags, flags_length); let name: StringKey = match CStr::from_ptr(name).to_str() { Ok(name) => name.into(), Err(_) => return FFIResult::err_from_str("Unable to convert name to string"), }; let mut flags_set: HashSet = HashSet::with_capacity(flags_length); for flag in flags { let flag = match CStr::from_ptr(*flag).to_str() { Ok(flag) => flag, Err(_) => return FFIResult::err_from_str("Unable to convert flag to string"), }; flags_set.insert(flag.into()); } let secondary_effect = if secondary_effect.is_none() { None } else { Some(secondary_effect.from_ffi_handle()) }; let a: Arc = Arc::new(MoveDataImpl::new( &name, move_type, category, base_power, accuracy, base_usages, target, priority, secondary_effect, flags_set, )); FFIResult::ok(FFIHandle::get_handle(a.into())) } /// The name of the move. #[no_mangle] unsafe extern "C" fn move_data_name(ptr: FFIHandle>) -> FFIResult { let move_data = ptr.from_ffi_handle(); let name = move_data.name(); match CString::new(name.str()) { Ok(name) => FFIResult::ok(OwnedPtrString(name.into_raw())), Err(_) => FFIResult::err_from_str("Unable to convert name to string"), } } ffi_handle_arc_dyn_getter!(MoveData, move_type, TypeIdentifier); ffi_handle_arc_dyn_getter!(MoveData, category, MoveCategory); ffi_handle_arc_dyn_getter!(MoveData, base_power, u8); ffi_handle_arc_dyn_getter!(MoveData, accuracy, u8); ffi_handle_arc_dyn_getter!(MoveData, base_usages, u8); ffi_handle_arc_dyn_getter!(MoveData, target, MoveTarget); ffi_handle_arc_dyn_getter!(MoveData, priority, i8); /// The optional secondary effect the move has. #[no_mangle] unsafe extern "C" fn move_data_secondary_effect( ptr: FFIHandle>, ) -> FFIHandle> { match ptr.from_ffi_handle().secondary_effect() { Some(secondary_effect) => FFIHandle::get_handle(secondary_effect.clone().into()), None => FFIHandle::none(), } } /// Arbitrary flags that can be applied to the move. #[no_mangle] unsafe extern "C" fn move_data_has_flag(ptr: FFIHandle>, flag: *const c_char) -> u8 { let flag = CStr::from_ptr(flag).into(); u8::from(ptr.from_ffi_handle().has_flag(&flag)) } /// Instantiates a new Secondary Effect. #[no_mangle] unsafe extern "C" fn secondary_effect_new( chance: f32, effect_name: NonOwnedPtrString, parameter_keys: *const NonOwnedPtrString, parameters: *mut FFIHandle>, parameters_length: usize, ) -> FFIHandle> { 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 = 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 = Arc::new(SecondaryEffectImpl::new( chance, CStr::from_ptr(effect_name).into(), parameters, )); FFIHandle::get_handle(b.into()) } /// The chance the effect triggers. #[no_mangle] unsafe extern "C" fn secondary_effect_chance(ptr: FFIHandle>) -> f32 { ptr.from_ffi_handle().chance() } /// The name of the effect. #[no_mangle] unsafe extern "C" fn secondary_effect_effect_name( ptr: FFIHandle>, ) -> FFIResult { match CString::new(ptr.from_ffi_handle().effect_name().str()) { Ok(name) => FFIResult::ok(OwnedPtrString(name.into_raw())), Err(_) => FFIResult::err(anyhow!( "Unable to convert effect name '{}' to CString", ptr.from_ffi_handle().effect_name() )), } } /// The length of parameters of the effect. #[no_mangle] unsafe extern "C" fn secondary_effect_parameter_length(ptr: FFIHandle>) -> usize { ptr.from_ffi_handle().parameters().len() } /// Get a parameter of the effect. #[no_mangle] unsafe extern "C" fn secondary_effect_parameter_get( ptr: FFIHandle>, name: NonOwnedPtrString, ) -> FFIHandle> { 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() } }