use async_trait::async_trait;
use crate::agent::AgentContext;
use crate::oxyde_game::intent::{Intent, IntentType};
use crate::Result;
use super::base::{Behavior, BehaviorResult, BaseBehavior};
#[derive(Debug)]
pub struct GreetingBehavior {
base: BaseBehavior,
distance_threshold: f32,
greetings: Vec<String>,
}
impl GreetingBehavior {
pub fn new_with_options(distance_threshold: f32, greetings: Vec<String>) -> Self {
Self {
base: BaseBehavior::new(
"greeting",
"Greets the player when they get close",
10,
vec!["proximity".to_string()],
60, ),
distance_threshold,
greetings,
}
}
pub fn new_default() -> Self {
Self::new_with_options(
3.0,
vec![
"Hello there!".to_string(),
"Greetings, traveler!".to_string(),
"Welcome!".to_string(),
"Good day to you!".to_string(),
"Well met!".to_string(),
],
)
}
pub fn new(greeting: &str) -> Self {
Self::new_with_options(
3.0,
vec![greeting.to_string()],
)
}
}
#[async_trait]
impl Behavior for GreetingBehavior {
async fn matches_intent(&self, intent: &Intent) -> bool {
if self.base.is_on_cooldown().await {
return false;
}
intent.intent_type == IntentType::Proximity || intent.intent_type == IntentType::Greeting
}
async fn execute(&self, _intent: &Intent, context: &AgentContext) -> Result<BehaviorResult> {
let player_distance = context.get("player_distance")
.and_then(|v| v.as_f64())
.unwrap_or(f64::INFINITY) as f32;
if player_distance <= self.distance_threshold {
self.base.mark_executed().await;
let greeting_idx = rand::random::<usize>() % self.greetings.len();
let greeting = &self.greetings[greeting_idx];
Ok(BehaviorResult::Response(greeting.clone()))
} else {
Ok(BehaviorResult::None)
}
}
}