use crate::context::ResourceContext;
use async_trait::async_trait;
use super::events::BattleId;
use super::types::{CombatResult, Combatant};
#[async_trait]
pub trait CombatHook: Send + Sync {
async fn before_turn(
&self,
_battle_id: &BattleId,
_turn: u32,
_resources: &ResourceContext,
) -> Result<(), String> {
Ok(())
}
async fn calculate_damage_modifier(
&self,
_battle_id: &BattleId,
_attacker: &dyn Combatant,
_defender: &dyn Combatant,
base_multiplier: f32,
_resources: &ResourceContext,
) -> f32 {
base_multiplier
}
async fn process_turn(
&self,
_battle_id: &BattleId,
_turn: u32,
_resources: &mut ResourceContext,
) -> Vec<String> {
Vec::new()
}
async fn after_turn(
&self,
_battle_id: &BattleId,
_turn: u32,
_log_entries: &[String],
_resources: &mut ResourceContext,
) {
}
async fn on_combat_ended(
&self,
_battle_id: &BattleId,
_result: &CombatResult,
_total_turns: u32,
_score: u32,
_resources: &mut ResourceContext,
) {
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct DefaultCombatHook;
#[async_trait]
impl CombatHook for DefaultCombatHook {
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_default_hook_does_nothing() {
let hook = DefaultCombatHook;
let battle_id = "test_battle".to_string();
let resources = ResourceContext::new();
let result = hook.before_turn(&battle_id, 1, &resources).await;
assert!(result.is_ok());
let multiplier = hook
.calculate_damage_modifier(&battle_id, &MockCombatant, &MockCombatant, 1.5, &resources)
.await;
assert_eq!(multiplier, 1.5);
let mut resources = ResourceContext::new();
hook.after_turn(&battle_id, 1, &[], &mut resources).await;
hook.on_combat_ended(&battle_id, &CombatResult::Victory, 5, 100, &mut resources)
.await;
}
struct MockCombatant;
impl Combatant for MockCombatant {
fn name(&self) -> &str {
"Mock"
}
fn hp(&self) -> i32 {
100
}
fn max_hp(&self) -> i32 {
100
}
fn attack(&self) -> i32 {
10
}
fn take_damage(&mut self, _damage: i32) {}
}
}