diff --git a/assets/behaviors/common/attackFollowedEntity.behavior b/assets/behaviors/common/attackFollowedEntity.behavior index 8dd32317..cf21f3bf 100644 --- a/assets/behaviors/common/attackFollowedEntity.behavior +++ b/assets/behaviors/common/attackFollowedEntity.behavior @@ -23,7 +23,7 @@ } } }, - move_to + {lookup: { tree: "Behaviors:naiveMoveTo" }} ] } ] diff --git a/assets/behaviors/creatures/combinedCritter.behavior b/assets/behaviors/creatures/combinedCritter.behavior new file mode 100644 index 00000000..e90533ec --- /dev/null +++ b/assets/behaviors/creatures/combinedCritter.behavior @@ -0,0 +1,134 @@ +{ +selector: [ + { + guard: { // Implementation of territorial Critter + + // For DistanceSquared is A System Needed + // Orientation in "LocationChangedSystem" + + // Looks for a Territory Existing + componentPresent: "Behaviors:Territory", // Needs Component + values: [ + "N location exists" + ], + + child: { + selector: [ + { + + //Is the Territory still in Range? + guard: { + componentPresent: "Behaviors:Territory", + values: [ + "F distanceSquared < maxDistance" + ], + + child: { + selector: [ + { + // Checks for an Player in Range + guard: { + componentPresent: "Behaviors:FindNearbyPlayers", // Only for Players or for Nemesis aswell? + values: [ + "N charactersWithinRange nonEmpty" + ], + + // If there is a Player in Range we get hostile -> Has to be changed for Nemesis? + child: { + sequence: [ + set_target_nearby_player, // Could be for Nemesis aswell? + { + "lookup": { + tree: "Behaviors:hostile" + } + } + ] + } + } + + } + ] + } + } + }, + // + { // Back up sequence for when out of territory + sequence: [ + set_target_territory, + move_to + ] + } + ] + } + } + }, + // First Guard fo Selector for Territory End. + { + guard: { // Implementation of scared Critter + + componentPresent: "Behaviors:FindNearbyEntity", + values: ["N nemesisWithinRange nonEmpty"], + + child: { + sequence: [ + + { sleep: {time: 0.1f }}, + "flee_from_nemesis", + { lookup: {tree: "Behaviors:flee" }} + + ] + } + } + }, + + /** + Here would be Implementation for Base Needs + + ToDO + For now not implemented + Hungry, Thirsty, Sleep -> Metal Renegade (Citizens) + Got hurt -> Deer behaviour + */ + + //Implementation Start for Aggressive Critter + { + guard: { + + //Checking if Critter is Hungry and Prey is around + componentPresent: "Behaviors:FindNearbyEntity", // Implementation ??? // Could Be Nemesis aswell? Else another Component? + values: ["H hungerEntity < 25"], + + child: { + lookup: {tree: "Behaviors: aggressiveCritter"} + } + } + }, + + // Implementation for Friendly Critter + { + guard: { + + //Checks if Nearby Player has Item in Hand + componentPresent: "Behaviors:FindNearbyPlayers", + values: [ + "N characterWithinRange nonEmpty" + ], + + child: { + sequence: [ + check_luring_item_in_use, + { sleep: {time: 0.1f}}, + followCharacter, + {lookup: {tree: "Behaviors:follow"}} + ] + } + } + }, // Furthest Outside Selector + + { + lookup: { + tree: "Behaviors:stray" + } + } + ] +} diff --git a/docs/AI_Tree_Concepts/Chaser.drawIo b/docs/AI_Tree_Concepts/Chaser.drawIo new file mode 100644 index 00000000..b2919e14 --- /dev/null +++ b/docs/AI_Tree_Concepts/Chaser.drawIo @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/AI_Tree_Concepts/Guard.drawIO b/docs/AI_Tree_Concepts/Guard.drawIO new file mode 100644 index 00000000..321b71bf --- /dev/null +++ b/docs/AI_Tree_Concepts/Guard.drawIO @@ -0,0 +1,177 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/AI_Tree_Concepts/Intelligent Sheep.drawIo b/docs/AI_Tree_Concepts/Intelligent Sheep.drawIo new file mode 100644 index 00000000..3663bb47 --- /dev/null +++ b/docs/AI_Tree_Concepts/Intelligent Sheep.drawIo @@ -0,0 +1,661 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/AI_Tree_Concepts/SubtreePriority.DrawIo b/docs/AI_Tree_Concepts/SubtreePriority.DrawIo new file mode 100644 index 00000000..10a74b17 --- /dev/null +++ b/docs/AI_Tree_Concepts/SubtreePriority.DrawIo @@ -0,0 +1,608 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/AI_Tree_Concepts/Timid.drawIo b/docs/AI_Tree_Concepts/Timid.drawIo new file mode 100644 index 00000000..0dff2cef --- /dev/null +++ b/docs/AI_Tree_Concepts/Timid.drawIo @@ -0,0 +1,174 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/java/org/terasology/module/behaviors/actions/FleeFromNemesisAction.java b/src/main/java/org/terasology/module/behaviors/actions/FleeFromNemesisAction.java new file mode 100644 index 00000000..aaabe06a --- /dev/null +++ b/src/main/java/org/terasology/module/behaviors/actions/FleeFromNemesisAction.java @@ -0,0 +1,34 @@ +// Copyright 2023 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.module.behaviors.actions; + +import org.terasology.engine.logic.behavior.BehaviorAction; +import org.terasology.engine.logic.behavior.core.BaseAction; +import org.terasology.engine.logic.behavior.core.Actor; +import org.terasology.engine.logic.behavior.core.BehaviorState; +import org.terasology.module.behaviors.components.FindNearbyNemesisComponent; +import org.terasology.module.behaviors.components.FleeingComponent; + +@BehaviorAction(name = "flee_from_nemesis") + +/** + * This Action is used for the combinedCritter behaviour + * It's used for finding an Entity of a configurable Nemesis-Group and fleeing from them. + */ + +public class FleeFromNemesisAction extends BaseAction { + @Override + public void construct(Actor actor) { + FleeingComponent fleeingComponent = new FleeingComponent(); + FindNearbyNemesisComponent component = actor.getComponent(FindNearbyNemesisComponent.class); + fleeingComponent.instigator = component.closestNemesis; + actor.save(fleeingComponent); + + } + + @Override + public BehaviorState modify(Actor actor, BehaviorState result) { + return BehaviorState.SUCCESS; + } +} diff --git a/src/main/java/org/terasology/module/behaviors/actions/SetTargetToTerritory.java b/src/main/java/org/terasology/module/behaviors/actions/SetTargetToTerritory.java index 292b917e..959c2656 100644 --- a/src/main/java/org/terasology/module/behaviors/actions/SetTargetToTerritory.java +++ b/src/main/java/org/terasology/module/behaviors/actions/SetTargetToTerritory.java @@ -9,18 +9,18 @@ import org.terasology.engine.logic.behavior.core.BehaviorState; import org.terasology.engine.world.block.Blocks; import org.terasology.module.behaviors.components.MinionMoveComponent; -import org.terasology.module.behaviors.components.TerritoryDistance; +import org.terasology.module.behaviors.components.TerritoryComponent; @BehaviorAction(name = "set_target_territory") public class SetTargetToTerritory extends BaseAction { @Override public BehaviorState modify(Actor actor, BehaviorState result) { - if (!actor.hasComponent(TerritoryDistance.class) || !actor.hasComponent(MinionMoveComponent.class)) { + if (!actor.hasComponent(TerritoryComponent.class) || !actor.hasComponent(MinionMoveComponent.class)) { return BehaviorState.FAILURE; } - Vector3f territory = actor.getComponent(TerritoryDistance.class).location; + Vector3f territory = actor.getComponent(TerritoryComponent.class).location; MinionMoveComponent moveComponent = actor.getComponent(MinionMoveComponent.class); if (moveComponent.target.equals(territory)) { diff --git a/src/main/java/org/terasology/module/behaviors/components/FindNearbyNemesisComponent.java b/src/main/java/org/terasology/module/behaviors/components/FindNearbyNemesisComponent.java new file mode 100644 index 00000000..b896dabe --- /dev/null +++ b/src/main/java/org/terasology/module/behaviors/components/FindNearbyNemesisComponent.java @@ -0,0 +1,31 @@ +// Copyright 2023 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.module.behaviors.components; + +import com.google.common.collect.Lists; +import org.terasology.engine.entitySystem.entity.EntityRef; +import org.terasology.gestalt.entitysystem.component.Component; + +import java.util.List; + +/** + * If this components is attached to an NPC entity it will constantly look + * around for nearby Nemesis that enter a given radius. + */ + +public class FindNearbyNemesisComponent implements Component { + /* Search radius for finding nearby Nemesis */ + public float searchRadius = 10f; + /* List of Nemesis entities nearby */ + public List nemesisWithinRange; + /* The Nemesis entity closest to the actor */ + public EntityRef closestNemesis; + + @Override + public void copyFrom(FindNearbyNemesisComponent other) { + this.searchRadius = other.searchRadius; + this.nemesisWithinRange = Lists.newArrayList(other.nemesisWithinRange); + this.closestNemesis = other.closestNemesis; + } +} diff --git a/src/main/java/org/terasology/module/behaviors/components/LuringComponent.java b/src/main/java/org/terasology/module/behaviors/components/LuringComponent.java new file mode 100644 index 00000000..32dba829 --- /dev/null +++ b/src/main/java/org/terasology/module/behaviors/components/LuringComponent.java @@ -0,0 +1,26 @@ +// Copyright 2023 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.module.behaviors.components; + +import com.google.common.collect.Lists; +import org.terasology.gestalt.entitysystem.component.Component; + +import java.util.List; + +/** + * This components shall be used by the combinedCritter module to allow an NPC to exhibit the lure behavior + */ + +public class LuringComponent implements Component { + + //List of Items for a Luring Stat + // Configurable for e.g. + //"CoreAssets:TallGrass1" + public List luringItems = Lists.newArrayList(); + + @Override + public void copyFrom(LuringComponent other) { + this.luringItems = Lists.newArrayList(other.luringItems); + } +} diff --git a/src/main/java/org/terasology/module/behaviors/components/TerritoryComponent.java b/src/main/java/org/terasology/module/behaviors/components/TerritoryComponent.java new file mode 100644 index 00000000..c1863ecb --- /dev/null +++ b/src/main/java/org/terasology/module/behaviors/components/TerritoryComponent.java @@ -0,0 +1,23 @@ +// Copyright 2022 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 +package org.terasology.module.behaviors.components; + +import org.joml.Vector3f; +import org.terasology.engine.registry.In; +import org.terasology.gestalt.entitysystem.component.Component; + +public class TerritoryComponent implements Component { + public float maxDistance; //Distance for Chasing + public float distanceSquared; //Current Distance from Territory Mid Point + public float radius; //Radius of the Territory + public Vector3f location; //MidPoint of the Territory + + @Override + public void copyFrom(TerritoryComponent other) { + this.distanceSquared = other.distanceSquared; + this.location = new Vector3f(other.location); + // Should this be done in a logic or can this be done in initialisation? + this.maxDistance = other.maxDistance * other.maxDistance; + this.radius = other.radius * other.radius; + } +} diff --git a/src/main/java/org/terasology/module/behaviors/components/TerritoryDistance.java b/src/main/java/org/terasology/module/behaviors/components/TerritoryDistance.java deleted file mode 100644 index e8795580..00000000 --- a/src/main/java/org/terasology/module/behaviors/components/TerritoryDistance.java +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2022 The Terasology Foundation -// SPDX-License-Identifier: Apache-2.0 -package org.terasology.module.behaviors.components; - -import org.joml.Vector3f; -import org.terasology.gestalt.entitysystem.component.Component; - -public class TerritoryDistance implements Component { - public float distanceSquared; - public Vector3f location; - - @Override - public void copyFrom(TerritoryDistance other) { - this.distanceSquared = other.distanceSquared; - this.location = new Vector3f(other.location); - } -} diff --git a/src/main/java/org/terasology/module/behaviors/systems/TerritorialBehaviourSystem.java b/src/main/java/org/terasology/module/behaviors/systems/TerritorialBehaviourSystem.java index 56d1c2ca..5b16e971 100644 --- a/src/main/java/org/terasology/module/behaviors/systems/TerritorialBehaviourSystem.java +++ b/src/main/java/org/terasology/module/behaviors/systems/TerritorialBehaviourSystem.java @@ -5,7 +5,8 @@ import org.joml.Vector3f; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.terasology.module.behaviors.components.TerritoryDistance; +import org.terasology.engine.core.Time; +import org.terasology.module.behaviors.components.TerritoryComponent; import org.terasology.engine.entitySystem.entity.EntityManager; import org.terasology.engine.entitySystem.entity.EntityRef; import org.terasology.engine.entitySystem.entity.lifecycleEvents.OnActivatedComponent; @@ -30,10 +31,16 @@ public class TerritorialBehaviourSystem extends BaseComponentSystem implements U public EntityManager entityManager; private List territories = new ArrayList(); private Random random = new Random(); - + // Unnecessary if delta is enough for the intervall. + private static float CHECK_INTERVALL = 200; + private float lastCheckTime = 0; + + @In + private Time timer; @Override public void initialise() { + territories.clear(); } @@ -45,18 +52,30 @@ public void initialise() { */ @Override public void update(float delta) { - for (EntityRef entity : entityManager.getEntitiesWith(TerritoryDistance.class, LocationComponent.class)) { - TerritoryDistance territoryDistance = entity.getComponent(TerritoryDistance.class); - territoryDistance.distanceSquared = territoryDistance.location.distanceSquared( - entity.getComponent(LocationComponent.class).getWorldPosition(new Vector3f())); - entity.saveComponent(territoryDistance); + + long gameTimeInMS = timer.getGameTimeInMs(); + + if(lastCheckTime + CHECK_INTERVALL < gameTimeInMS) { + + for (EntityRef entity : entityManager.getEntitiesWith(TerritoryComponent.class, LocationComponent.class)) { + + TerritoryComponent territoryComponent = entity.getComponent(TerritoryComponent.class); + // This is basically distance squared? And continuously updated + territoryComponent.distanceSquared = territoryComponent.location.distanceSquared( + entity.getComponent(LocationComponent.class).getWorldPosition(new Vector3f())); + + lastCheckTime = gameTimeInMS; + entity.saveComponent(territoryComponent); + } + } } - } - @ReceiveEvent(components = TerritoryDistance.class) + @ReceiveEvent(components = TerritoryComponent.class) public void onCreatureSpawned(OnActivatedComponent event, EntityRef creature) { - TerritoryDistance territoryDistance = creature.getComponent(TerritoryDistance.class); - territoryDistance.location = creature.getComponent(LocationComponent.class).getWorldPosition(new Vector3f()); - creature.saveComponent(territoryDistance); + + TerritoryComponent territoryComponent = creature.getComponent(TerritoryComponent.class); + territoryComponent.location = creature.getComponent(LocationComponent.class).getWorldPosition(new Vector3f()); + territoryComponent.distanceSquared = 0; + creature.saveComponent(territoryComponent); } }