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

This commit is contained in:
2023-06-30 11:32:00 +02:00
parent 0163c7a105
commit bc9b3ed964
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};
/// 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.
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
/// dispose of the event afterwards.
pub fn trigger(&self, evt: Event) {
let b = Box::new(&evt);
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);
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.
#[derive(Debug)]
pub enum Event<'own> {
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
@@ -77,7 +77,7 @@ pub enum Event<'own> {
/// enjoy.
SpeciesChange {
/// The pokemon that changed species.
pokemon: &'own Pokemon,
pokemon: Pokemon,
/// The new species of the Pokemon.
species: Arc<dyn Species>,
/// 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.
FormChange {
/// The pokemon that changed forms.
pokemon: &'own Pokemon,
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: &'own Pokemon,
pokemon: Pokemon,
/// The source of damage.
source: DamageSource,
/// The health of the Pokemon before the damage.
@@ -104,7 +104,7 @@ pub enum Event<'own> {
/// This event happens when a Pokemon gets healed
Heal {
/// The Pokemon that gets healed.
pokemon: &'own Pokemon,
pokemon: Pokemon,
/// The health of the Pokemon before the heal.
original_health: u32,
/// The health of the Pokemon after the heal.
@@ -113,24 +113,24 @@ pub enum Event<'own> {
/// This event happens when a Pokemon faints.
Faint {
/// 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.
MoveUse {
/// The data of the move used.
executing_move: &'own ExecutingMove,
executing_move: Arc<ExecutingMove>,
},
/// This event happens when a Pokemon missed.
Miss {
/// The pokemon that missed.
user: &'own Pokemon,
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: &'own Pokemon,
user: Pokemon,
/// The statistic that changed.
stat: Statistic,
/// The value of the stat before the change.
@@ -138,4 +138,42 @@ pub enum Event<'own> {
/// 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),
}
}
}

View File

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

View File

@@ -9,7 +9,7 @@ use atomig::Atomic;
use parking_lot::RwLock;
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_random::BattleRandom;
use crate::dynamic_data::models::battle_side::BattleSide;
@@ -333,7 +333,7 @@ impl Battle {
}
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 time = end_time - start_time;
match time.num_nanoseconds() {

View File

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

View File

@@ -9,12 +9,13 @@ use parking_lot::lock_api::RwLockReadGuard;
use parking_lot::{RawRwLock, RwLock};
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::learned_move::{LearnedMove, MoveLearnMethod};
use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper};
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::Form;
@@ -396,12 +397,15 @@ impl Pokemon {
if changed {
if let Some(battle) = self.get_battle() {
let new_value = self.stat_boost(stat);
battle.event_hook().trigger(Event::StatBoostChange {
user: self,
stat,
old_value,
new_value,
})
battle.event_hook().trigger(
EventData::StatBoostChange {
user: self.clone(),
stat,
old_value,
new_value,
},
Default::default(),
)
}
self.recalculate_boosted_stats()?;
}
@@ -531,11 +535,14 @@ impl Pokemon {
let r = self.data.battle_data.read();
if let Some(battle_data) = &r.deref() {
if let Some(battle) = battle_data.battle() {
battle.event_hook().trigger(Event::SpeciesChange {
pokemon: self,
species,
form,
})
battle.event_hook().trigger(
EventData::SpeciesChange {
pokemon: self.clone(),
species,
form,
},
Default::default(),
)
}
}
Ok(())
@@ -597,10 +604,13 @@ impl Pokemon {
let r = self.data.battle_data.read();
if let Some(battle_data) = r.deref() {
if let Some(battle) = battle_data.battle() {
battle.event_hook().trigger(Event::FormChange {
pokemon: self,
form: form.clone(),
})
battle.event_hook().trigger(
EventData::FormChange {
pokemon: self.clone(),
form: form.clone(),
},
Default::default(),
)
}
};
Ok(())
@@ -679,7 +689,7 @@ impl Pokemon {
}
/// 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() {
damage = self.current_health();
}
@@ -689,12 +699,15 @@ impl Pokemon {
let new_health = self.current_health() - damage;
if let Some(battle_data) = &self.data.battle_data.read().deref() {
if let Some(battle) = battle_data.battle() {
battle.event_hook().trigger(Event::Damage {
pokemon: self,
source,
original_health: self.current_health(),
new_health,
});
battle.event_hook().trigger(
EventData::Damage {
pokemon: self.clone(),
source,
original_health: self.current_health(),
new_health,
},
evt_batch_id,
);
}
}
if self
@@ -719,7 +732,9 @@ impl Pokemon {
let r = self.data.battle_data.read();
if let Some(battle_data) = r.deref() {
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_remove, self,);
@@ -752,11 +767,14 @@ impl Pokemon {
let new_health = self.current_health() + max_amount;
if let Some(battle_data) = &self.data.battle_data.read().deref() {
if let Some(battle) = battle_data.battle() {
battle.event_hook().trigger(Event::Heal {
pokemon: self,
original_health: self.current_health(),
new_health,
});
battle.event_hook().trigger(
EventData::Heal {
pokemon: self.clone(),
original_health: self.current_health(),
new_health,
},
Default::default(),
);
}
}
self.data.current_health.store(new_health, Ordering::SeqCst);