use crate::{
self as behaviortree, Control,
behavior::{Behavior, BehaviorData, BehaviorError, BehaviorResult, BehaviorState},
tree::BehaviorTreeElementList,
};
use alloc::boxed::Box;
use tinyscript::SharedRuntime;
#[derive(Control, Debug, Default)]
#[behavior(groot2)]
pub struct IfThenElse {
child_index: usize,
}
#[async_trait::async_trait]
impl Behavior for IfThenElse {
#[inline]
fn on_halt(&mut self) -> Result<(), BehaviorError> {
self.child_index = 0;
Ok(())
}
fn on_start(
&mut self,
behavior: &mut BehaviorData,
children: &mut BehaviorTreeElementList,
_runtime: &SharedRuntime,
) -> Result<(), BehaviorError> {
if !(2..=3).contains(&children.len()) {
return Err(BehaviorError::Composition {
txt: "IfThenElse must have either 2 or 3 children.".into(),
});
}
behavior.set_state(BehaviorState::Running);
Ok(())
}
async fn tick(
&mut self,
behavior: &mut BehaviorData,
children: &mut BehaviorTreeElementList,
runtime: &SharedRuntime,
) -> BehaviorResult {
behavior.set_state(BehaviorState::Running);
let children_count = children.len();
if self.child_index == 0 {
let condition_state = children[0].tick(runtime).await?;
match condition_state {
BehaviorState::Failure => match children_count {
3 => {
self.child_index = 2;
}
2 => {
return Ok(condition_state);
}
_ => {
return Err(BehaviorError::Composition {
txt: "Should not happen in 'IfThenElse'".into(),
});
}
},
BehaviorState::Idle => {
return Err(BehaviorError::State {
behavior: "IfThenElse".into(),
state: condition_state,
});
}
BehaviorState::Running => {
return Ok(BehaviorState::Running);
}
BehaviorState::Skipped => {
return Ok(BehaviorState::Skipped);
}
BehaviorState::Success => {
self.child_index = 1;
}
}
}
if self.child_index > 0 {
let state = children[self.child_index].tick(runtime).await?;
if state != BehaviorState::Running {
children.reset(runtime)?;
self.child_index = 0;
}
Ok(state)
} else {
Err(BehaviorError::Composition {
txt: "Something unexpected happened in IfThenElse".into(),
})
}
}
}