use bevy::prelude::*;
use bevy_gauge::prelude::*;
use bevy_gearbox::prelude::*;
use bevy_gearbox::SimpleTransition;
#[derive(Component, Default, Debug, Clone)]
#[require(
Attributes,
AttributeRequirements,
AppliedModifiers,
ActivatedModifiers,
UnappliedState,
)]
pub struct PersistentAttributeEffect;
#[derive(Component, Debug, Clone, Default, Deref, DerefMut)]
pub struct AppliedModifiers(pub ModifierSet);
#[derive(Component, Debug, Clone, Default, Deref, DerefMut)]
pub struct ActivatedModifiers(pub ModifierSet);
#[derive(Component, Debug, Clone, Copy)]
pub struct EffectTarget(pub Entity);
#[derive(Component, Default, Debug, PartialEq, Eq, Reflect)]
#[relationship_target(relationship = RequiresStatsOf, linked_spawn)]
#[reflect(Component, FromWorld, Default)]
pub struct RequirementsOf(Vec<Entity>);
impl<'a> IntoIterator for &'a RequirementsOf {
type Item = <Self::IntoIter as Iterator>::Item;
type IntoIter = std::slice::Iter<'a, Entity>;
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl RequirementsOf {
pub fn new() -> Self {
Self(Vec::new())
}
}
#[derive(Component, Clone, PartialEq, Eq, Debug, Reflect)]
#[relationship(relationship_target = RequirementsOf)]
#[reflect(Component, PartialEq, Debug, FromWorld, Clone)]
pub struct RequiresStatsOf(#[entities] pub Entity);
impl FromWorld for RequiresStatsOf {
#[inline(always)]
fn from_world(_world: &mut World) -> Self {
RequiresStatsOf(Entity::PLACEHOLDER)
}
}
#[derive(Component, Reflect, Clone, Default, Debug)]
pub struct UnappliedState;
#[derive(Component, Reflect, Clone, Default, Debug)]
pub struct AppliedState;
#[derive(Component, Reflect, Clone, Default, Debug)]
pub struct ActiveState;
#[derive(SimpleTransition, EntityEvent, Reflect, Clone)]
pub struct PAETryApply {
#[event_target]
pub target: Entity,
}
#[derive(SimpleTransition, EntityEvent, Reflect, Clone)]
pub struct PAESuspend {
#[event_target]
pub target: Entity,
}
#[derive(SimpleTransition, EntityEvent, Reflect, Clone)]
pub struct PAEUnapplyApproved {
#[event_target]
pub target: Entity,
}
pub struct PaeEntities {
pub root: Entity,
pub unapplied: Entity,
pub applied: Entity,
pub active: Entity,
}
pub fn pae_state_machine(
commands: &mut Commands,
entity: Option<Entity>,
) -> PaeEntities {
let machine_entity = entity.unwrap_or_else(|| commands.spawn_empty().id());
let mut unapplied_state = Entity::PLACEHOLDER;
let mut applied_state = Entity::PLACEHOLDER;
let mut active_state = Entity::PLACEHOLDER;
commands.entity(machine_entity).with_children(|parent| {
unapplied_state = parent.spawn(Name::new("Unapplied")).id();
applied_state = parent.spawn(Name::new("Applied")).id();
active_state = parent.spawn(Name::new("Active")).id();
let edge_unapplied_to_applied = parent.spawn(Name::new("Edge Unapplied->Applied")).id();
let edge_applied_to_active = parent.spawn(Name::new("Edge Applied->Active")).id();
let edge_active_to_applied = parent.spawn(Name::new("Edge Active->Applied")).id();
let edge_to_unapplied = parent.spawn(Name::new("Edge Applied->Unapplied")).id();
let edge_active_to_unapplied = parent.spawn(Name::new("Edge Active->Unapplied")).id();
let commands = parent.commands_mut();
commands.entity(unapplied_state).insert((
SubstateOf(machine_entity),
StateComponent(UnappliedState),
));
commands
.entity(unapplied_state)
.observe(super::on_enter_unapplied_state);
commands.entity(applied_state).insert((
SubstateOf(machine_entity),
StateComponent(AppliedState),
));
commands
.entity(applied_state)
.observe(super::on_enter_applied_state);
commands.entity(active_state).insert((
SubstateOf(machine_entity),
StateComponent(ActiveState),
));
commands
.entity(active_state)
.observe(super::on_enter_active_state)
.observe(super::on_exit_active_state);
commands.entity(edge_unapplied_to_applied).insert((
Source(unapplied_state),
Target(applied_state),
EventEdge::<PAETryApply>::default(),
));
commands.entity(edge_applied_to_active).insert((
Source(applied_state),
Target(active_state),
AlwaysEdge,
Guards::new(),
RequiresStatsOf(machine_entity),
));
commands.entity(edge_active_to_applied).insert((
Source(active_state),
Target(applied_state),
EventEdge::<PAESuspend>::default(),
));
commands.entity(edge_to_unapplied).insert((
Source(applied_state),
Target(unapplied_state),
EventEdge::<PAEUnapplyApproved>::default(),
));
commands.entity(edge_active_to_unapplied).insert((
Source(active_state),
Target(unapplied_state),
EventEdge::<PAEUnapplyApproved>::default(),
));
commands.entity(machine_entity).insert((
Name::new("PAE Machine"),
PersistentAttributeEffect,
StateMachine::new(),
InitialState(unapplied_state),
));
});
PaeEntities {
root: machine_entity,
unapplied: unapplied_state,
applied: applied_state,
active: active_state,
}
}