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, EventBatchId)>; /// A collection of event hooks. type EvtHookCollection = Vec; /// 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, } 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, }, /// 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, /// The form of the species the Pokemon will have. form: Arc, }, /// 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, }, /// 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, }, /// 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 for EventBatchId { fn from(value: u128) -> Self { Self { batch_id: uuid::Uuid::from_u128(value), } } }