Implements event batch id to events to display multiple events at the same time
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Deukhoofd 2023-06-30 11:32:00 +02:00
parent 0163c7a105
commit bc9b3ed964
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
11 changed files with 217 additions and 106 deletions

View File

@ -9,7 +9,7 @@ use crate::static_data::Species;
use crate::static_data::{Form, Statistic}; use crate::static_data::{Form, Statistic};
/// A function that will be called when an event occured. /// A function that will be called when an event occured.
type EvtHookFn = Box<dyn Fn(&Box<&Event>)>; type EvtHookFn = Box<dyn Fn(Arc<EventData>, EventBatchId)>;
/// A collection of event hooks. /// A collection of event hooks.
type EvtHookCollection = Vec<EvtHookFn>; type EvtHookCollection = Vec<EvtHookFn>;
@ -35,12 +35,12 @@ impl EventHook {
/// Run a new event. This will send the event to all externally defined event listeners. It will /// Run a new event. This will send the event to all externally defined event listeners. It will
/// dispose of the event afterwards. /// dispose of the event afterwards.
pub fn trigger(&self, evt: Event) { pub fn trigger(&self, evt: EventData, batch_id: EventBatchId) {
let b = Box::new(&evt); let b = Arc::new(evt);
#[allow(clippy::unwrap_used)] // This should never fail. #[allow(clippy::unwrap_used)] // This should never fail.
let read_lock = self.evt_hook_function.read().unwrap(); let read_lock = self.evt_hook_function.read().unwrap();
for f in read_lock.iter() { for f in read_lock.iter() {
f(&b); f(b.clone(), batch_id);
} }
} }
} }
@ -53,7 +53,7 @@ impl Debug for EventHook {
/// The different events that can occur during the battle, for which a GUI should show something. /// The different events that can occur during the battle, for which a GUI should show something.
#[derive(Debug)] #[derive(Debug)]
pub enum Event<'own> { pub enum EventData {
/// A switch event happens when a Pokemon gets switched out for something else. /// A switch event happens when a Pokemon gets switched out for something else.
Switch { Switch {
/// The side the Pokemon got switched from/on /// The side the Pokemon got switched from/on
@ -77,7 +77,7 @@ pub enum Event<'own> {
/// enjoy. /// enjoy.
SpeciesChange { SpeciesChange {
/// The pokemon that changed species. /// The pokemon that changed species.
pokemon: &'own Pokemon, pokemon: Pokemon,
/// The new species of the Pokemon. /// The new species of the Pokemon.
species: Arc<dyn Species>, species: Arc<dyn Species>,
/// The form of the species the Pokemon will have. /// The form of the species the Pokemon will have.
@ -86,14 +86,14 @@ pub enum Event<'own> {
/// This event happens when a Pokemon changes form during battle. This is rather common. /// This event happens when a Pokemon changes form during battle. This is rather common.
FormChange { FormChange {
/// The pokemon that changed forms. /// The pokemon that changed forms.
pokemon: &'own Pokemon, pokemon: Pokemon,
/// The new form of the Pokemon. /// The new form of the Pokemon.
form: Arc<dyn Form>, form: Arc<dyn Form>,
}, },
/// This event happens when a Pokemon takes damage. /// This event happens when a Pokemon takes damage.
Damage { Damage {
/// The Pokemon that takes damage. /// The Pokemon that takes damage.
pokemon: &'own Pokemon, pokemon: Pokemon,
/// The source of damage. /// The source of damage.
source: DamageSource, source: DamageSource,
/// The health of the Pokemon before the damage. /// The health of the Pokemon before the damage.
@ -104,7 +104,7 @@ pub enum Event<'own> {
/// This event happens when a Pokemon gets healed /// This event happens when a Pokemon gets healed
Heal { Heal {
/// The Pokemon that gets healed. /// The Pokemon that gets healed.
pokemon: &'own Pokemon, pokemon: Pokemon,
/// The health of the Pokemon before the heal. /// The health of the Pokemon before the heal.
original_health: u32, original_health: u32,
/// The health of the Pokemon after the heal. /// The health of the Pokemon after the heal.
@ -113,24 +113,24 @@ pub enum Event<'own> {
/// This event happens when a Pokemon faints. /// This event happens when a Pokemon faints.
Faint { Faint {
/// The pokemon that has fainted. /// The pokemon that has fainted.
pokemon: &'own Pokemon, pokemon: Pokemon,
}, },
/// This event happens when a Pokemon uses a move on a target, just before any hits. /// This event happens when a Pokemon uses a move on a target, just before any hits.
MoveUse { MoveUse {
/// The data of the move used. /// The data of the move used.
executing_move: &'own ExecutingMove, executing_move: Arc<ExecutingMove>,
}, },
/// This event happens when a Pokemon missed. /// This event happens when a Pokemon missed.
Miss { Miss {
/// The pokemon that missed. /// The pokemon that missed.
user: &'own Pokemon, user: Pokemon,
}, },
/// The turn is finished running, waiting for new input. /// The turn is finished running, waiting for new input.
EndTurn, EndTurn,
/// A pokemon had its stat boost changed /// A pokemon had its stat boost changed
StatBoostChange { StatBoostChange {
/// The pokemon that had its stat boosts changed. /// The pokemon that had its stat boosts changed.
user: &'own Pokemon, user: Pokemon,
/// The statistic that changed. /// The statistic that changed.
stat: Statistic, stat: Statistic,
/// The value of the stat before the change. /// The value of the stat before the change.
@ -138,4 +138,42 @@ pub enum Event<'own> {
/// The value of the stat after the change. /// The value of the stat after the change.
new_value: i8, new_value: i8,
}, },
/// Triggered when a move hits.
MoveHit {
/// The pokemon that used the move.
user: Pokemon,
/// The pokemon that was hit.
target: Pokemon,
/// The effectiveness of the move.
effectiveness: f32,
},
}
/// Allows for the batching of multiple events that should be shown at the same time.
#[derive(Default, Copy, Clone)]
pub struct EventBatchId {
/// The id of the batch.
batch_id: uuid::Uuid,
}
impl EventBatchId {
/// Gets the batch id as two u64s.
pub fn as_u64_pair(&self) -> (u64, u64) {
self.batch_id.as_u64_pair()
}
/// Creates a new batch id from two u64s.
pub fn from_u64_pair(a: u64, b: u64) -> Self {
Self {
batch_id: uuid::Uuid::from_u64_pair(a, b),
}
}
}
impl From<u128> for EventBatchId {
fn from(value: u128) -> Self {
Self {
batch_id: uuid::Uuid::from_u128(value),
}
}
} }

View File

@ -4,13 +4,13 @@ use std::ops::Deref;
use std::sync::Arc; use std::sync::Arc;
use crate::dynamic_data::choices::TurnChoice; use crate::dynamic_data::choices::TurnChoice;
use crate::dynamic_data::event_hooks::Event; use crate::dynamic_data::event_hooks::EventData;
use crate::dynamic_data::flow::target_resolver::resolve_targets; use crate::dynamic_data::flow::target_resolver::resolve_targets;
use crate::dynamic_data::script_handling::{ScriptSource, ScriptWrapper}; use crate::dynamic_data::script_handling::{ScriptSource, ScriptWrapper};
use crate::dynamic_data::Battle;
use crate::dynamic_data::DamageSource; use crate::dynamic_data::DamageSource;
use crate::dynamic_data::ExecutingMove; use crate::dynamic_data::ExecutingMove;
use crate::dynamic_data::Pokemon; use crate::dynamic_data::Pokemon;
use crate::dynamic_data::{Battle, EventBatchId};
use crate::static_data::MoveCategory; use crate::static_data::MoveCategory;
use crate::{run_scripts, script_hook, PkmnError}; use crate::{run_scripts, script_hook, PkmnError};
@ -145,9 +145,12 @@ impl Battle {
if !executing_move.chosen_move().try_use(1) { if !executing_move.chosen_move().try_use(1) {
return Ok(()); return Ok(());
} }
self.event_hook().trigger(Event::MoveUse { self.event_hook().trigger(
executing_move: &executing_move, EventData::MoveUse {
}); executing_move: executing_move.clone(),
},
Default::default(),
);
let mut fail = false; let mut fail = false;
script_hook!(fail_move, executing_move, &executing_move, &mut fail); script_hook!(fail_move, executing_move, &executing_move, &mut fail);
if fail { if fail {
@ -280,9 +283,12 @@ impl Battle {
// TODO: Deal with accuracy/evasion stats. // TODO: Deal with accuracy/evasion stats.
if accuracy < 100 && self.random().get_max(100)? as u8 >= accuracy { if accuracy < 100 && self.random().get_max(100)? as u8 >= accuracy {
script_hook!(on_move_miss, target, executing_move, target); script_hook!(on_move_miss, target, executing_move, target);
self.event_hook().trigger(Event::Miss { self.event_hook().trigger(
user: executing_move.user().deref(), EventData::Miss {
}); user: executing_move.user().clone(),
},
Default::default(),
);
break; break;
} }
@ -306,7 +312,16 @@ impl Battle {
hit_data.set_damage(damage); hit_data.set_damage(damage);
} }
if damage > 0 { if damage > 0 {
target.damage(damage, DamageSource::MoveDamage)?; let move_hit_event_batch = EventBatchId::default();
self.event_hook().trigger(
EventData::MoveHit {
user: executing_move.user().clone(),
target: target.clone(),
effectiveness,
},
move_hit_event_batch,
);
target.damage(damage, DamageSource::MoveDamage, move_hit_event_batch)?;
if !target.is_fainted() { if !target.is_fainted() {
script_hook!(on_incoming_hit, target, executing_move, target, hit_index); script_hook!(on_incoming_hit, target, executing_move, target, hit_index);
} else { } else {
@ -352,9 +367,12 @@ impl Battle {
if number_of_hits == 0 { if number_of_hits == 0 {
script_hook!(on_move_miss, target, executing_move, target); script_hook!(on_move_miss, target, executing_move, target);
self.event_hook().trigger(Event::Miss { self.event_hook().trigger(
user: executing_move.user().deref(), EventData::Miss {
}); user: executing_move.user().clone(),
},
Default::default(),
);
} }
if !executing_move.user().is_fainted() { if !executing_move.user().is_fainted() {

View File

@ -9,7 +9,7 @@ use atomig::Atomic;
use parking_lot::RwLock; use parking_lot::RwLock;
use crate::dynamic_data::choices::TurnChoice; use crate::dynamic_data::choices::TurnChoice;
use crate::dynamic_data::event_hooks::{Event, EventHook}; use crate::dynamic_data::event_hooks::{EventData, EventHook};
use crate::dynamic_data::models::battle_party::BattleParty; use crate::dynamic_data::models::battle_party::BattleParty;
use crate::dynamic_data::models::battle_random::BattleRandom; use crate::dynamic_data::models::battle_random::BattleRandom;
use crate::dynamic_data::models::battle_side::BattleSide; use crate::dynamic_data::models::battle_side::BattleSide;
@ -333,7 +333,7 @@ impl Battle {
} }
self.data.current_turn_queue.write().take(); self.data.current_turn_queue.write().take();
self.data.event_hook.trigger(Event::EndTurn); self.data.event_hook.trigger(EventData::EndTurn, Default::default());
let end_time = chrono::Utc::now(); let end_time = chrono::Utc::now();
let time = end_time - start_time; let time = end_time - start_time;
match time.num_nanoseconds() { match time.num_nanoseconds() {

View File

@ -8,7 +8,7 @@ use parking_lot::lock_api::RwLockReadGuard;
use parking_lot::{RawRwLock, RwLock}; use parking_lot::{RawRwLock, RwLock};
use crate::dynamic_data::choices::TurnChoice; use crate::dynamic_data::choices::TurnChoice;
use crate::dynamic_data::event_hooks::Event; use crate::dynamic_data::event_hooks::EventData;
use crate::dynamic_data::models::battle::Battle; use crate::dynamic_data::models::battle::Battle;
use crate::dynamic_data::models::pokemon::Pokemon; use crate::dynamic_data::models::pokemon::Pokemon;
use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper}; use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper};
@ -231,18 +231,24 @@ impl BattleSide {
pokemon.mark_opponent_as_seen(opponent.weak()); pokemon.mark_opponent_as_seen(opponent.weak());
} }
} }
battle.event_hook().trigger(Event::Switch { battle.event_hook().trigger(
side_index: self.data.index, EventData::Switch {
index, side_index: self.data.index,
pokemon: Some(pokemon.clone()), index,
}); pokemon: Some(pokemon.clone()),
},
Default::default(),
);
script_hook!(on_switch_in, pokemon, pokemon); script_hook!(on_switch_in, pokemon, pokemon);
} else { } else {
self.battle()?.event_hook().trigger(Event::Switch { self.battle()?.event_hook().trigger(
side_index: self.data.index, EventData::Switch {
index, side_index: self.data.index,
pokemon: None, index,
}); pokemon: None,
},
Default::default(),
);
} }
Ok(()) Ok(())
} }
@ -339,11 +345,14 @@ impl BattleSide {
} }
data.pokemon.write().swap(a as usize, b as usize); data.pokemon.write().swap(a as usize, b as usize);
self.battle()?.event_hook().trigger(Event::Swap { self.battle()?.event_hook().trigger(
side_index: data.index, EventData::Swap {
index_a: a, side_index: data.index,
index_b: b, index_a: a,
}); index_b: b,
},
Default::default(),
);
Ok(true) Ok(true)
} }

View File

@ -9,12 +9,13 @@ use parking_lot::lock_api::RwLockReadGuard;
use parking_lot::{RawRwLock, RwLock}; use parking_lot::{RawRwLock, RwLock};
use crate::defines::{LevelInt, MAX_MOVES}; use crate::defines::{LevelInt, MAX_MOVES};
use crate::dynamic_data::event_hooks::Event; use crate::dynamic_data::event_hooks::EventData;
use crate::dynamic_data::models::battle::Battle; use crate::dynamic_data::models::battle::Battle;
use crate::dynamic_data::models::learned_move::{LearnedMove, MoveLearnMethod}; use crate::dynamic_data::models::learned_move::{LearnedMove, MoveLearnMethod};
use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper}; use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper};
use crate::dynamic_data::{ use crate::dynamic_data::{
DynamicLibrary, Script, ScriptCategory, ScriptContainer, ScriptSet, VolatileScriptsOwner, WeakBattleReference, DynamicLibrary, EventBatchId, Script, ScriptCategory, ScriptContainer, ScriptSet, VolatileScriptsOwner,
WeakBattleReference,
}; };
use crate::static_data::AbilityIndex; use crate::static_data::AbilityIndex;
use crate::static_data::Form; use crate::static_data::Form;
@ -396,12 +397,15 @@ impl Pokemon {
if changed { if changed {
if let Some(battle) = self.get_battle() { if let Some(battle) = self.get_battle() {
let new_value = self.stat_boost(stat); let new_value = self.stat_boost(stat);
battle.event_hook().trigger(Event::StatBoostChange { battle.event_hook().trigger(
user: self, EventData::StatBoostChange {
stat, user: self.clone(),
old_value, stat,
new_value, old_value,
}) new_value,
},
Default::default(),
)
} }
self.recalculate_boosted_stats()?; self.recalculate_boosted_stats()?;
} }
@ -531,11 +535,14 @@ impl Pokemon {
let r = self.data.battle_data.read(); let r = self.data.battle_data.read();
if let Some(battle_data) = &r.deref() { if let Some(battle_data) = &r.deref() {
if let Some(battle) = battle_data.battle() { if let Some(battle) = battle_data.battle() {
battle.event_hook().trigger(Event::SpeciesChange { battle.event_hook().trigger(
pokemon: self, EventData::SpeciesChange {
species, pokemon: self.clone(),
form, species,
}) form,
},
Default::default(),
)
} }
} }
Ok(()) Ok(())
@ -597,10 +604,13 @@ impl Pokemon {
let r = self.data.battle_data.read(); let r = self.data.battle_data.read();
if let Some(battle_data) = r.deref() { if let Some(battle_data) = r.deref() {
if let Some(battle) = battle_data.battle() { if let Some(battle) = battle_data.battle() {
battle.event_hook().trigger(Event::FormChange { battle.event_hook().trigger(
pokemon: self, EventData::FormChange {
form: form.clone(), pokemon: self.clone(),
}) form: form.clone(),
},
Default::default(),
)
} }
}; };
Ok(()) Ok(())
@ -679,7 +689,7 @@ impl Pokemon {
} }
/// Damages the Pokemon by a certain amount of damage, from a damage source. /// Damages the Pokemon by a certain amount of damage, from a damage source.
pub fn damage(&self, mut damage: u32, source: DamageSource) -> Result<()> { pub fn damage(&self, mut damage: u32, source: DamageSource, evt_batch_id: EventBatchId) -> Result<()> {
if damage > self.current_health() { if damage > self.current_health() {
damage = self.current_health(); damage = self.current_health();
} }
@ -689,12 +699,15 @@ impl Pokemon {
let new_health = self.current_health() - damage; let new_health = self.current_health() - damage;
if let Some(battle_data) = &self.data.battle_data.read().deref() { if let Some(battle_data) = &self.data.battle_data.read().deref() {
if let Some(battle) = battle_data.battle() { if let Some(battle) = battle_data.battle() {
battle.event_hook().trigger(Event::Damage { battle.event_hook().trigger(
pokemon: self, EventData::Damage {
source, pokemon: self.clone(),
original_health: self.current_health(), source,
new_health, original_health: self.current_health(),
}); new_health,
},
evt_batch_id,
);
} }
} }
if self if self
@ -719,7 +732,9 @@ impl Pokemon {
let r = self.data.battle_data.read(); let r = self.data.battle_data.read();
if let Some(battle_data) = r.deref() { if let Some(battle_data) = r.deref() {
if let Some(battle) = battle_data.battle() { if let Some(battle) = battle_data.battle() {
battle.event_hook().trigger(Event::Faint { pokemon: self }); battle
.event_hook()
.trigger(EventData::Faint { pokemon: self.clone() }, Default::default());
script_hook!(on_faint, self, self, source); script_hook!(on_faint, self, self, source);
script_hook!(on_remove, self,); script_hook!(on_remove, self,);
@ -752,11 +767,14 @@ impl Pokemon {
let new_health = self.current_health() + max_amount; let new_health = self.current_health() + max_amount;
if let Some(battle_data) = &self.data.battle_data.read().deref() { if let Some(battle_data) = &self.data.battle_data.read().deref() {
if let Some(battle) = battle_data.battle() { if let Some(battle) = battle_data.battle() {
battle.event_hook().trigger(Event::Heal { battle.event_hook().trigger(
pokemon: self, EventData::Heal {
original_health: self.current_health(), pokemon: self.clone(),
new_health, original_health: self.current_health(),
}); new_health,
},
Default::default(),
);
} }
} }
self.data.current_health.store(new_health, Ordering::SeqCst); self.data.current_health.store(new_health, Ordering::SeqCst);

View File

@ -1,22 +1,25 @@
use crate::dynamic_data::{Event, Pokemon}; use crate::dynamic_data::{EventData, Pokemon};
use crate::ffi::ExternPointer; use crate::ffi::ffi_handle::FromFFIHandle;
use crate::ffi::FFIHandle; use crate::ffi::FFIHandle;
use std::ops::Deref;
use std::sync::Arc;
/// The kind of the event. /// The kind of the event.
#[no_mangle] #[no_mangle]
extern "C" fn event_kind(ptr: ExternPointer<Event>) -> u8 { extern "C" fn event_kind(ptr: FFIHandle<Arc<EventData>>) -> u8 {
match ptr.as_ref() { match ptr.from_ffi_handle().deref() {
Event::Switch { .. } => 1, EventData::Switch { .. } => 1,
Event::Swap { .. } => 2, EventData::Swap { .. } => 2,
Event::SpeciesChange { .. } => 3, EventData::SpeciesChange { .. } => 3,
Event::FormChange { .. } => 4, EventData::FormChange { .. } => 4,
Event::Damage { .. } => 5, EventData::Damage { .. } => 5,
Event::Heal { .. } => 6, EventData::Heal { .. } => 6,
Event::Faint { .. } => 7, EventData::Faint { .. } => 7,
Event::MoveUse { .. } => 8, EventData::MoveUse { .. } => 8,
Event::Miss { .. } => 9, EventData::Miss { .. } => 9,
Event::EndTurn => 10, EventData::EndTurn => 10,
Event::StatBoostChange { .. } => 11, EventData::StatBoostChange { .. } => 11,
EventData::MoveHit { .. } => 12,
} }
} }
@ -43,12 +46,12 @@ macro_rules! event_ffi {
} }
/// The getter for the data for the relevant event. /// The getter for the data for the relevant event.
#[no_mangle] #[no_mangle]
extern "C" fn [<event_ $event_name:snake _data>](ptr: ExternPointer<Event>) -> [<$event_name Data>] { extern "C" fn [<event_ $event_name:snake _data>](ptr: FFIHandle<Arc<EventData>>) -> [<$event_name Data>] {
if let Event::$event_name { if let EventData::$event_name {
$( $(
$par_name, $par_name,
)+ )+
} = ptr.as_ref() } = ptr.from_ffi_handle().deref()
{ {
$ctor $ctor
} }

View File

@ -1,25 +1,29 @@
use crate::dynamic_data::Event; use crate::dynamic_data::{EventBatchId, EventData};
use crate::ffi::ffi_handle::FFIHandle;
use std::sync::Arc;
/// Wrapper class for easier use of an external function pointer. /// Wrapper class for easier use of an external function pointer.
#[repr(C)] #[repr(C)]
pub(super) struct NativeEventHook { pub(super) struct NativeEventHook {
/// The actual C function to be called. /// The actual C function to be called. Note that we pass the batch id as a pair of u64s. This
f: extern "C" fn(*const Event<'_>), /// is because u128 does not have a stable ABI yet.
f: extern "C" fn(FFIHandle<Arc<EventData>>, u64, u64),
} }
impl NativeEventHook { impl NativeEventHook {
/// Calls the actual wrapped function in the correct format. /// Calls the actual wrapped function in the correct format.
fn call_self(&self, b: &&Event<'_>) { fn call_self(&self, b: Arc<EventData>, batch_id: EventBatchId) {
(self.f)(*b as *const Event) let batch_id = batch_id.as_u64_pair();
(self.f)(FFIHandle::get_handle(b.into()), batch_id.0, batch_id.1);
} }
} }
/// A tuple with the arguments of the event hook function /// A tuple with the arguments of the event hook function
type EventHookArgs<'a, 'b, 'c> = (&'a Box<&'b Event<'c>>,); type EventHookArgs<'a, 'b, 'c> = (Arc<EventData>, EventBatchId);
impl FnMut<EventHookArgs<'_, '_, '_>> for NativeEventHook { impl FnMut<EventHookArgs<'_, '_, '_>> for NativeEventHook {
extern "rust-call" fn call_mut(&mut self, args: EventHookArgs<'_, '_, '_>) -> Self::Output { extern "rust-call" fn call_mut(&mut self, args: EventHookArgs<'_, '_, '_>) -> Self::Output {
self.call_self(args.0) self.call_self(args.0, args.1)
} }
} }
@ -27,12 +31,12 @@ impl FnOnce<EventHookArgs<'_, '_, '_>> for NativeEventHook {
type Output = (); type Output = ();
extern "rust-call" fn call_once(self, args: EventHookArgs<'_, '_, '_>) -> Self::Output { extern "rust-call" fn call_once(self, args: EventHookArgs<'_, '_, '_>) -> Self::Output {
self.call_self(args.0) self.call_self(args.0, args.1)
} }
} }
impl Fn<EventHookArgs<'_, '_, '_>> for NativeEventHook { impl Fn<EventHookArgs<'_, '_, '_>> for NativeEventHook {
extern "rust-call" fn call(&self, args: EventHookArgs<'_, '_, '_>) -> Self::Output { extern "rust-call" fn call(&self, args: EventHookArgs<'_, '_, '_>) -> Self::Output {
self.call_self(args.0) self.call_self(args.0, args.1)
} }
} }

View File

@ -1,5 +1,5 @@
use crate::defines::LevelInt; use crate::defines::LevelInt;
use crate::dynamic_data::{Battle, DamageSource, DynamicLibrary, LearnedMove, MoveLearnMethod, Pokemon}; use crate::dynamic_data::{Battle, DamageSource, DynamicLibrary, EventBatchId, LearnedMove, MoveLearnMethod, Pokemon};
use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle}; use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::{FFIResult, OwnedPtrString}; use crate::ffi::{FFIResult, OwnedPtrString};
use crate::static_data::{ use crate::static_data::{
@ -397,8 +397,21 @@ extern "C" fn pokemon_is_on_battlefield(handle: FFIHandle<Pokemon>) -> u8 {
/// Damages the Pokemon by a certain amount of damage, from a damage source. /// Damages the Pokemon by a certain amount of damage, from a damage source.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_damage(handle: FFIHandle<Pokemon>, damage: u32, source: DamageSource) -> FFIResult<()> { extern "C" fn pokemon_damage(
handle.from_ffi_handle().damage(damage, source).into() handle: FFIHandle<Pokemon>,
damage: u32,
source: DamageSource,
evt_batch_id_1: u64,
evt_batch_id_2: u64,
) -> FFIResult<()> {
handle
.from_ffi_handle()
.damage(
damage,
source,
EventBatchId::from_u64_pair(evt_batch_id_1, evt_batch_id_2),
)
.into()
} }
/// Heals the Pokemon by a specific amount. Unless allow_revive is set to true, this will not /// Heals the Pokemon by a specific amount. Unless allow_revive is set to true, this will not

View File

@ -100,6 +100,9 @@ pub(super) enum FFIObject {
MiscLibrary(Arc<dyn crate::dynamic_data::MiscLibrary>), MiscLibrary(Arc<dyn crate::dynamic_data::MiscLibrary>),
ScriptResolver(Arc<dyn crate::dynamic_data::ScriptResolver>), ScriptResolver(Arc<dyn crate::dynamic_data::ScriptResolver>),
DynamicLibrary(Arc<dyn crate::dynamic_data::DynamicLibrary>), DynamicLibrary(Arc<dyn crate::dynamic_data::DynamicLibrary>),
// Events
Event(Arc<crate::dynamic_data::EventData>),
} }
unsafe impl Send for FFIObject {} unsafe impl Send for FFIObject {}
@ -218,6 +221,7 @@ impl Hash for FFIObject {
Self::MiscLibrary(a) => Arc::as_ptr(a).hash(state), Self::MiscLibrary(a) => Arc::as_ptr(a).hash(state),
Self::ScriptResolver(a) => Arc::as_ptr(a).hash(state), Self::ScriptResolver(a) => Arc::as_ptr(a).hash(state),
Self::DynamicLibrary(a) => Arc::as_ptr(a).hash(state), Self::DynamicLibrary(a) => Arc::as_ptr(a).hash(state),
FFIObject::Event(a) => Arc::as_ptr(a).hash(state),
} }
} }
} }
@ -265,6 +269,7 @@ impl PartialEq for FFIObject {
(Self::MiscLibrary(a), Self::MiscLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), (Self::MiscLibrary(a), Self::MiscLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::ScriptResolver(a), Self::ScriptResolver(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), (Self::ScriptResolver(a), Self::ScriptResolver(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::DynamicLibrary(a), Self::DynamicLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(), (Self::DynamicLibrary(a), Self::DynamicLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::Event(a), Self::Event(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
_ => false, _ => false,
} }
} }
@ -337,3 +342,4 @@ ffi_obj_conversions!(Arc<dyn crate::dynamic_data::DamageLibrary>, DamageLibrary)
ffi_obj_conversions!(Arc<dyn crate::dynamic_data::MiscLibrary>, MiscLibrary); ffi_obj_conversions!(Arc<dyn crate::dynamic_data::MiscLibrary>, MiscLibrary);
ffi_obj_conversions!(Arc<dyn crate::dynamic_data::ScriptResolver>, ScriptResolver); ffi_obj_conversions!(Arc<dyn crate::dynamic_data::ScriptResolver>, ScriptResolver);
ffi_obj_conversions!(Arc<dyn crate::dynamic_data::DynamicLibrary>, DynamicLibrary); ffi_obj_conversions!(Arc<dyn crate::dynamic_data::DynamicLibrary>, DynamicLibrary);
ffi_obj_conversions!(Arc<crate::dynamic_data::EventData>, Event);

View File

@ -1,7 +1,7 @@
use std::mem::transmute; use std::mem::transmute;
use crate::defines::LevelInt; use crate::defines::LevelInt;
use crate::dynamic_data::{Battle, DynamicLibrary, LearnedMove, Pokemon, VolatileScriptsOwner}; use crate::dynamic_data::{Battle, DynamicLibrary, EventBatchId, LearnedMove, Pokemon, VolatileScriptsOwner};
use crate::script_implementations::wasm::export_registry::{ use crate::script_implementations::wasm::export_registry::{
get_value, get_value_arc, get_value_arc_void, get_value_call_getter, get_value_void, register, try_wasm, wasm_err, get_value, get_value_arc, get_value_arc_void, get_value_call_getter, get_value_void, register, try_wasm, wasm_err,
wasm_ok, WasmResult, WasmVoidResult, WasmVoidResultExtension, wasm_ok, WasmResult, WasmVoidResult, WasmVoidResultExtension,
@ -120,14 +120,16 @@ register! {
env: FunctionEnvMut<WebAssemblyEnv>, env: FunctionEnvMut<WebAssemblyEnv>,
pokemon: ExternRef<Pokemon>, pokemon: ExternRef<Pokemon>,
damage: u32, damage: u32,
source: u8 source: u8,
event_batch_id_1: u64,
event_batch_id_2: u64,
) -> WasmVoidResult { ) -> WasmVoidResult {
unsafe { unsafe {
let pokemon = match pokemon.value_func(&env) { let pokemon = match pokemon.value_func(&env) {
Ok(pokemon) => pokemon, Ok(pokemon) => pokemon,
Err(e) => return WasmVoidResult::err(e, &env), Err(e) => return WasmVoidResult::err(e, &env),
}; };
match pokemon.damage(damage, transmute(source)) { match pokemon.damage(damage, transmute(source), EventBatchId::from_u64_pair(event_batch_id_1, event_batch_id_2)) {
Ok(()) => WasmVoidResult::ok(), Ok(()) => WasmVoidResult::ok(),
Err(e) => WasmVoidResult::err(e, &env), Err(e) => WasmVoidResult::err(e, &env),
} }

Binary file not shown.