aboutsummaryrefslogtreecommitdiff
path: root/src/conditionals.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/conditionals.rs')
-rw-r--r--src/conditionals.rs202
1 files changed, 202 insertions, 0 deletions
diff --git a/src/conditionals.rs b/src/conditionals.rs
new file mode 100644
index 0000000..266379a
--- /dev/null
+++ b/src/conditionals.rs
@@ -0,0 +1,202 @@
+use bevy::{
+ ecs::system::SystemState,
+ prelude::{AncestorIter, Entity, Parent, Query, World},
+};
+use serde::{Deserialize, Serialize};
+use strum::{AsRefStr, EnumString};
+use uuid::Uuid;
+
+use crate::{components::DirworldEntity, resources::DirworldCurrentDir};
+
+// I Store Conditions as Enum Data
+#[derive(Serialize, Deserialize, AsRefStr, Debug, Default, Clone, PartialEq, Eq)]
+pub enum Condition {
+ #[default]
+ #[strum(serialize = "Always True")]
+ True,
+ #[strum(serialize = "Child Of")]
+ ChildOf {
+ child: Uuid,
+ parent: Uuid,
+ },
+ #[strum(serialize = "Parent Of")]
+ ParentOf {
+ parent: Uuid,
+ child: Uuid,
+ },
+ #[strum(serialize = "Descendant Of")]
+ DescendantOf {
+ descendant: Uuid,
+ ancestor: Uuid,
+ },
+ #[strum(serialize = "Ancestor Of")]
+ AncestorOf {
+ ancestor: Uuid,
+ descendant: Uuid,
+ },
+ #[strum(serialize = "In Room")]
+ InRoom(Uuid),
+ #[strum(serialize = "Object In Room")]
+ ObjectInRoom(Uuid),
+}
+
+impl Condition {
+ pub fn evaluate(&self, world: &mut World) -> bool {
+ match self {
+ Condition::True => true,
+ Condition::ChildOf { child, parent } => parent_of(world, *parent, *child),
+ Condition::ParentOf { parent, child } => parent_of(world, *parent, *child),
+ Condition::DescendantOf {
+ descendant,
+ ancestor,
+ } => ancestor_of(world, *ancestor, *descendant),
+ Condition::AncestorOf {
+ ancestor,
+ descendant,
+ } => ancestor_of(world, *ancestor, *descendant),
+ Condition::InRoom(uuid) => in_room(world, *uuid),
+ Condition::ObjectInRoom(uuid) => object_in_room(world, *uuid),
+ }
+ }
+
+ pub fn get_api_function_name(&self) -> &'static str {
+ match self {
+ Condition::True => "conditional_true",
+ Condition::ChildOf { .. } => "conditional_child_of",
+ Condition::ParentOf { .. } => "conditional_parent_of",
+ Condition::DescendantOf { .. } => "conditional_descendant_of",
+ Condition::AncestorOf { .. } =>"conditional_ancestor_of",
+ Condition::InRoom(_) => "conditional_in_room",
+ Condition::ObjectInRoom(_) => "conditional_object_in_room",
+ }
+ }
+
+ pub fn from_api_function_name_and_args(name: &str, args: &[&str]) -> Option<Self> {
+ match name {
+ "conditional_true" => Some(Condition::True),
+ "conditional_child_of" => {
+ let Some(child) = args.get(0).and_then(|arg| Uuid::parse_str(arg).ok()) else {
+ return None;
+ };
+ let Some(parent) = args.get(1).and_then(|arg| Uuid::parse_str(arg).ok()) else {
+ return None;
+ };
+ Some(Condition::ChildOf { child, parent })
+ }
+ "conditional_parent_of" => {
+ let Some(child) = args.get(1).and_then(|arg| Uuid::parse_str(arg).ok()) else {
+ return None;
+ };
+ let Some(parent) = args.get(0).and_then(|arg| Uuid::parse_str(arg).ok()) else {
+ return None;
+ };
+ Some(Condition::ParentOf { child, parent })
+ }
+ "conditional_descendant_of" => {
+ let Some(descendant) = args.get(0).and_then(|arg| Uuid::parse_str(arg).ok()) else {
+ return None;
+ };
+ let Some(ancestor) = args.get(1).and_then(|arg| Uuid::parse_str(arg).ok()) else {
+ return None;
+ };
+ Some(Condition::DescendantOf { descendant, ancestor })
+ }
+ "conditional_ancestor_of" => {
+ let Some(descendant) = args.get(1).and_then(|arg| Uuid::parse_str(arg).ok()) else {
+ return None;
+ };
+ let Some(ancestor) = args.get(0).and_then(|arg| Uuid::parse_str(arg).ok()) else {
+ return None;
+ };
+ Some(Condition::AncestorOf { descendant, ancestor })
+ }
+ "condtitional_in_room" => {
+ let Some(room_id) = args.get(0).and_then(|arg| Uuid::parse_str(arg).ok()) else {
+ return None;
+ };
+ Some(Condition::InRoom(room_id))
+ }
+ "condtitional_object_in_room" => {
+ let Some(object_id) = args.get(0).and_then(|arg| Uuid::parse_str(arg).ok()) else {
+ return None;
+ };
+ Some(Condition::ObjectInRoom(object_id))
+ }
+ _ => None,
+ }
+ }
+}
+
+// Condition Checkers beyond this point
+
+fn ancestor_of(world: &mut World, ancestor: Uuid, descendant: Uuid) -> bool {
+ let mut system_state =
+ SystemState::<(Query<(Entity, &DirworldEntity)>, Query<&Parent>)>::new(world);
+ let (dirworld_entities, parents) = system_state.get(world);
+ let Some((ancestor_entity, _)) = dirworld_entities.iter().find(|(_, entity)| {
+ entity
+ .payload
+ .as_ref()
+ .is_some_and(|payload| payload.id == ancestor)
+ }) else {
+ return false;
+ };
+
+ let Some((descendant_entity, _)) = dirworld_entities.iter().find(|(_, entity)| {
+ entity
+ .payload
+ .as_ref()
+ .is_some_and(|payload| payload.id == descendant)
+ }) else {
+ return false;
+ };
+
+ AncestorIter::new(&parents, descendant_entity)
+ .find(|descendant| *descendant == ancestor_entity)
+ .is_some()
+}
+
+fn parent_of(world: &mut World, parent: Uuid, child: Uuid) -> bool {
+ let mut system_state =
+ SystemState::<(Query<(Entity, &DirworldEntity)>, Query<&Parent>)>::new(world);
+ let (dirworld_entities, parents) = system_state.get(world);
+ let Some((parent_entity, _)) = dirworld_entities.iter().find(|(_, entity)| {
+ entity
+ .payload
+ .as_ref()
+ .is_some_and(|payload| payload.id == parent)
+ }) else {
+ return false;
+ };
+
+ let Some((child_entity, _)) = dirworld_entities.iter().find(|(_, entity)| {
+ entity
+ .payload
+ .as_ref()
+ .is_some_and(|payload| payload.id == child)
+ }) else {
+ return false;
+ };
+
+ parents
+ .get(child_entity)
+ .is_ok_and(|parent| parent.get() == parent_entity)
+}
+
+fn in_room(world: &mut World, room: Uuid) -> bool {
+ let current_dir = world.resource::<DirworldCurrentDir>();
+ current_dir.payload.as_ref().is_some_and(|payload| payload.id == room)
+}
+
+fn object_in_room(world: &mut World, object: Uuid) -> bool {
+ let mut dirworld_entities = world.query::<&DirworldEntity>();
+ dirworld_entities
+ .iter(world)
+ .find(|entity| {
+ entity
+ .payload
+ .as_ref()
+ .is_some_and(|payload| payload.id == object)
+ })
+ .is_some()
+}