use bevy::prelude::*;
use bevy_gearbox::transitions::EventValidator;
pub trait ProvidesRolePositions {
fn attacker_pos(&self) -> Option<Vec3>;
fn defender_pos(&self) -> Option<Vec3>;
}
pub trait ProvidesDamageInfo {
fn damage_amount(&self) -> f32;
fn damage_element(&self) -> &str;
}
#[derive(Component, Clone, Reflect)]
pub struct DistanceWithin {
pub max: f32,
}
impl<E: Event + ProvidesRolePositions> EventValidator<E> for DistanceWithin {
fn matches(&self, event: &E) -> bool {
let (Some(a), Some(d)) = (event.attacker_pos(), event.defender_pos()) else {
return false;
};
a.distance(d) <= self.max
}
}
#[derive(Component, Clone, Reflect)]
pub struct DamageElementAnyOf {
pub elements: Vec<String>,
}
impl<E: Event + ProvidesDamageInfo> EventValidator<E> for DamageElementAnyOf {
fn matches(&self, event: &E) -> bool {
self.elements.iter().any(|e| e == event.damage_element())
}
}
#[derive(Component, Clone, Reflect)]
pub struct DamageAmountAtLeast {
pub minimum: f32,
}
impl<E: Event + ProvidesDamageInfo> EventValidator<E> for DamageAmountAtLeast {
fn matches(&self, event: &E) -> bool {
event.damage_amount() >= self.minimum
}
}
#[derive(Component, Clone, Reflect)]
pub struct ConditionSet {
#[reflect(ignore)]
pub conditions: Vec<Condition>,
}
#[derive(Clone)]
pub enum Condition {
DistanceWithin { max: f32 },
DamageElementAnyOf { elements: Vec<String> },
DamageAmountAtLeast { minimum: f32 },
}
impl<E: Event + ProvidesRolePositions + ProvidesDamageInfo> EventValidator<E> for ConditionSet {
fn matches(&self, event: &E) -> bool {
self.conditions.iter().all(|cond| match cond {
Condition::DistanceWithin { max } => {
let (Some(a), Some(d)) = (event.attacker_pos(), event.defender_pos()) else {
return false;
};
a.distance(d) <= *max
}
Condition::DamageElementAnyOf { elements } => {
elements.iter().any(|e| e == event.damage_element())
}
Condition::DamageAmountAtLeast { minimum } => event.damage_amount() >= *minimum,
})
}
}
#[derive(Event, Clone)]
pub struct DamageEvent {
pub attacker: Entity,
pub defender: Entity,
pub attacker_position: Vec3,
pub defender_position: Vec3,
pub amount: f32,
pub element: String,
}
impl ProvidesRolePositions for DamageEvent {
fn attacker_pos(&self) -> Option<Vec3> {
Some(self.attacker_position)
}
fn defender_pos(&self) -> Option<Vec3> {
Some(self.defender_position)
}
}
impl ProvidesDamageInfo for DamageEvent {
fn damage_amount(&self) -> f32 {
self.amount
}
fn damage_element(&self) -> &str {
&self.element
}
}
fn main() {
println!("Validators example - see source code for patterns");
}