//! PoisonCoating — an on-hit weapon mod that applies a poison DoT. Doesn't deal instant
//! damage itself (that's `Impact`'s job); it just pushes a status onto `HitContext.status`
//! the same way `Impact` pushes onto `HitContext.damage` — same event, same accumulate-then-
//! finalize shape, just a different accumulator.
//!
//! Deliberately builds `PeriodDamage` directly instead of going through `StatusRegistry` at
//! hit-time: `PoisonCoating` already knows exactly what it wants, the same way
//! `TowerBaseWeapon` never calls back into `DamageRegistry` from `on_hit_enemy` either. The
//! registry is for generic/data-driven construction (UI, "apply a random status" behaviors);
//! a hardcoded weapon mod that always applies the same status doesn't need that indirection.
use crate::{
behavior::{
projectile::{BehaviorPriority, HitResponse, ProjectileBehavior},
status::PeriodDamage,
},
context::HitContext,
enemy::Enemy,
registry::DamageID,
world::Projectile,
};
#[derive(Clone)]
pub struct PoisonCoating {
damage_type: DamageID,
amount: f32,
interval: f32,
duration: f32,
}
impl PoisonCoating {
/// The registry supplies `damage_type` (resolved once from the live `DamageRegistry`,
/// see `WeaponRegistry::new`) — same pattern as `TowerBaseWeapon::create`.
pub fn create(tier: u32, damage_type: DamageID) -> Box<dyn ProjectileBehavior> {
Box::new(Self {
damage_type,
amount: 3.0 + (1.5 * tier as f32),
interval: 1.0,
duration: 5.0,
})
}
}
impl ProjectileBehavior for PoisonCoating {
fn priority(&self) -> i32 {
BehaviorPriority::DEFAULT
}
fn on_hit_enemy(
&mut self,
p: &mut Projectile,
_e: &mut Enemy,
c: &mut HitContext,
) -> HitResponse {
c.status.push(PeriodDamage::make(
self.damage_type,
self.amount,
self.interval,
self.duration,
p.source,
));
HitResponse::PASS
}
}