PkmnLib_rs/src/dynamic_data/event_hooks.rs

180 lines
5.9 KiB
Rust
Executable File

use std::fmt::{Debug, Formatter};
use std::sync::Arc;
use std::sync::RwLock;
use crate::dynamic_data::DamageSource;
use crate::dynamic_data::ExecutingMove;
use crate::dynamic_data::Pokemon;
use crate::static_data::Species;
use crate::static_data::{Form, Statistic};
/// A function that will be called when an event occured.
type EvtHookFn = Box<dyn Fn(Arc<EventData>, EventBatchId)>;
/// A collection of event hooks.
type EvtHookCollection = Vec<EvtHookFn>;
/// The event hook is used to store external functions that listen to events.
///
/// Events happen in many
/// different places in the battle, and can be used for GUI applications to show that these events
/// are happening.
#[derive(Default)]
pub struct EventHook {
/// All the registered event listeners on the hook.
evt_hook_function: RwLock<EvtHookCollection>,
}
impl EventHook {
/// Register a new listener. This will start receiving all events in the battle. Multiple event
/// listeners can exist at the same time. Note that for these functions the event will be disposed
/// of after the event is finished being sent.
pub fn register_listener(&self, func: EvtHookFn) {
#[allow(clippy::unwrap_used)] // This should never fail.
self.evt_hook_function.write().unwrap().push(func);
}
/// Run a new event. This will send the event to all externally defined event listeners. It will
/// dispose of the event afterwards.
pub fn trigger(&self, evt: EventData, batch_id: EventBatchId) {
let b = Arc::new(evt);
#[allow(clippy::unwrap_used)] // This should never fail.
let read_lock = self.evt_hook_function.read().unwrap();
for f in read_lock.iter() {
f(b.clone(), batch_id);
}
}
}
impl Debug for EventHook {
fn fmt(&self, _f: &mut Formatter<'_>) -> std::fmt::Result {
Ok(())
}
}
/// The different events that can occur during the battle, for which a GUI should show something.
#[derive(Debug)]
pub enum EventData {
/// A switch event happens when a Pokemon gets switched out for something else.
Switch {
/// The side the Pokemon got switched from/on
side_index: u8,
/// The index of the Pokemon that got switched in/out on its side
index: u8,
/// The new Pokemon that will be on the spot. If none, the spot will now be empty.
pokemon: Option<Pokemon>,
},
/// A swap event happens when two Pokemon on a side swap positions. Note that this is rare.
Swap {
/// The side the Pokemon swapped on.
side_index: u8,
/// The index on the side of the first Pokemon that was swapped.
index_a: u8,
/// The index on the side of the second pokemon that was swapped.
index_b: u8,
},
/// This event happens when a Pokemon changes species during battle. While not normally occuring
/// this can be useful for things such as mid-battle evolutions, which some fanmade implementations
/// enjoy.
SpeciesChange {
/// The pokemon that changed species.
pokemon: Pokemon,
/// The new species of the Pokemon.
species: Arc<dyn Species>,
/// The form of the species the Pokemon will have.
form: Arc<dyn Form>,
},
/// This event happens when a Pokemon changes form during battle. This is rather common.
FormChange {
/// The pokemon that changed forms.
pokemon: Pokemon,
/// The new form of the Pokemon.
form: Arc<dyn Form>,
},
/// This event happens when a Pokemon takes damage.
Damage {
/// The Pokemon that takes damage.
pokemon: Pokemon,
/// The source of damage.
source: DamageSource,
/// The health of the Pokemon before the damage.
original_health: u32,
/// The health of the Pokemon after the damage.
new_health: u32,
},
/// This event happens when a Pokemon gets healed
Heal {
/// The Pokemon that gets healed.
pokemon: Pokemon,
/// The health of the Pokemon before the heal.
original_health: u32,
/// The health of the Pokemon after the heal.
new_health: u32,
},
/// This event happens when a Pokemon faints.
Faint {
/// The pokemon that has fainted.
pokemon: Pokemon,
},
/// This event happens when a Pokemon uses a move on a target, just before any hits.
MoveUse {
/// The data of the move used.
executing_move: Arc<ExecutingMove>,
},
/// This event happens when a Pokemon missed.
Miss {
/// The pokemon that missed.
user: Pokemon,
},
/// The turn is finished running, waiting for new input.
EndTurn,
/// A pokemon had its stat boost changed
StatBoostChange {
/// The pokemon that had its stat boosts changed.
user: Pokemon,
/// The statistic that changed.
stat: Statistic,
/// The value of the stat before the change.
old_value: i8,
/// The value of the stat after the change.
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),
}
}
}