Example #1
0
        public static IEnumerator <BTStatus> Hunt(Animal agent, Func <Animal, BTStatus> noNearbyFoodBehavior)
        {
            while (agent.Hunger > Brain.HungerSatiated)
            {
                var agentRegion = RouteRegions.GetRegion(agent.Position.WorldPosition3i);
                var nearPrey    = NetObjectManager.GetObjectsWithin(agent.Position.XZ, agent.DetectionRange).OfType <Animal>()
                                  .Where(x => agent.ShouldFleeUs(x) && RouteRegions.GetRegion(x.Position.WorldPosition3i) == agentRegion)
                                  .OrderBy(x => Vector3.WrappedDistanceSq(x.Position, agent.Position) + (x.AnimationState == AnimalAnimationState.Sleeping ? -200 : 0));
                foreach (var prey in nearPrey)
                {
                    var i = 0;
                    while (prey.Active)
                    {
                        Eco.Simulation.ExternalInputs.PredatorTracker.AddPredator(agent);
                        var route = AIUtilities.GetRoute(agent.Position, prey.Position, prey.Alertness < 50 ? agent.Species.WanderingSpeed : agent.Species.Speed);
                        agent.Target.SetPath(route);
                        agent.Target.Set(prey);
                        agent.NextTick = Math.Min(agent.Target.TargetTime, WorldTime.Seconds + 3);
                        i++;
                        yield return(BTStatus.Running);

                        if (Vector3.WrappedDistance(agent.Position, prey.Position) < 2f || i > 4)
                        {
                            // making this look good will require a lot of work, for now just let it go
                            agent.Hunger = 0;
                            Eco.Simulation.ExternalInputs.PredatorTracker.RemovePredator(agent);
                            yield break;
                        }
                    }
                }
                yield return(noNearbyFoodBehavior(agent));
            }
        }
Example #2
0
        private IEnumerable <Vector3> GetFoodSources(Animal agent)
        {
            var agentRegion = RouteRegions.GetRegion(agent.GroundPosition.WorldPosition3i);

            return(EcoSim.PlantSim.PlantsWithinRange(agent.Position, 10,
                                                     plant => agent.Species.Eats(plant.Species) &&
                                                     RouteRegions.GetRegion(plant.Position.WorldPosition3i.Down()) == agentRegion)
                   .Shuffle().Select(plant => plant.Position + Vector3.Down));
        }
        public static IEnumerator <BTStatus> FoodFinder(Animal agent, Func <Animal, BTStatus> noNearbyFoodBehavior, float hungerRestored)
        {
            var             lastPos     = Vector3.Zero;
            Queue <Vector3> foodSources = new Queue <Vector3>();

            while (agent.Hunger > Brain.HungerSatiated)
            {
                foodSources.Clear();
                while (foodSources.Count == 0)
                {
                    if (Vector3.WrappedDistanceSq(lastPos, agent.Position) > 100)
                    {
                        var agentRegion = RouteRegions.GetRegion(agent.Position.WorldPosition3i);
                        foodSources.AddRange(EcoSim.PlantSim.PlantsWithinRange(agent.Position, 10, plant => agent.Species.Eats(plant.Species) &&
                                                                               RouteRegions.GetRegion(plant.Position.WorldPosition3i.Down()) == agentRegion).Shuffle().Select(plant => plant.Position + Vector3.Down));
                        lastPos = agent.Position;
                    }
                    else
                    {
                        yield return(noNearbyFoodBehavior(agent));
                    }
                }

                while (foodSources.Count > 0 && agent.Hunger > Brain.HungerSatiated && Vector3.WrappedDistanceSq(lastPos, agent.Position) < 100)
                {
                    // low-effort search for the first option or any other option visited while trying to hit the first
                    Vector3 targetPlantPosition;
                    PiecewiseLinearFunction route = AIUtilities.GetRouteToAny(agent.Position, foodSources, agent.Species.WanderingSpeed, out targetPlantPosition, 100, 20, agent.Species.HeadDistance);
                    if (route == null)
                    {
                        break;
                    }
                    agent.Target.SetPath(route);
                    agent.Target.LookPos = targetPlantPosition;
                    agent.AnimationState = AnimalAnimationState.LookingForFood;
                    var target = route.EndPosition;

                    // just in case something interrupts the path
                    while (agent.Target.TargetTime > WorldTime.Seconds && agent.Target.TargetPosition == target)
                    {
                        agent.NextTick = agent.Target.TargetTime;
                        yield return(BTStatus.Running);
                    }

                    if (Vector3.WrappedDistanceSq(target, agent.Position) < 4)
                    {
                        agent.AnimationState = AnimalAnimationState.Eating;
                        agent.NextTick       = WorldTime.Seconds + 10;
                        agent.Hunger        -= hungerRestored;
                        agent.Target.LookPos = targetPlantPosition;
                        yield return(BTStatus.Running);
                    }

                    // something interrupted eating, probably need to find new food
                    if (agent.Target.TargetPosition != target)
                    {
                        break;
                    }
                }
            }
        }
Example #4
0
        // Groups form and dissolve along with animal visibility
        public static Animal GetLeader(Animal agent)
        {
            float checkTime;

            if (agent.TryGetMemory <float>(IsAlone, out checkTime))
            {
                if (TimeUtil.Seconds < checkTime)
                {
                    return(agent);
                }

                agent.RemoveMemory(IsAlone);
            }

            List <Animal> followers;

            if (agent.TryGetMemory <List <Animal> >(IsLeader, out followers))
            {
                followers.RemoveAll(x => x == null || x.Dead);

                // this animal is a leader as long as it has followers
                if (followers.Count > 0)
                {
                    return(agent);
                }
                else
                {
                    agent.RemoveMemory(IsLeader);
                }
            }

            Animal leader;

            if (!agent.TryGetMemory <Animal>(IsFollower, out leader))
            {
                var agentRegion = RouteRegions.GetRegion(agent.Position.WorldPosition3i);
                var nearAnimals = NetObjectManager.GetObjectsWithin(agent.Position.XZ, agent.Species.VoxelsPerEntry).OfType <Animal>()
                                  .Where(x => !x.Dead && x.Visible && x.Species == agent.Species && x != agent &&
                                         HaveAdjacentHomePositions(agent, x) && // don't join a herd far from home
                                         RouteRegions.GetRegion(x.Position.WorldPosition3i) == agentRegion);

                if (!nearAnimals.Any())
                {
                    agent.SetMemory(IsAlone, TimeUtil.Seconds + TimeBetweenHerdChecks);
                    return(agent);
                }

                List <Animal> stragglers = new List <Animal>();
                foreach (var nearAnimal in nearAnimals)
                {
                    Animal tmpLeader;
                    if (nearAnimal.TryGetMemory <Animal>(IsFollower, out tmpLeader))
                    {
                        if (leader == null && tmpLeader.Visible && !tmpLeader.Dead && HaveAdjacentHomePositions(tmpLeader, agent))
                        {
                            leader = tmpLeader;
                        }
                    }
                    else if (nearAnimal.HasMemory(IsLeader))
                    {
                        if (leader == null)
                        {
                            leader = nearAnimal;
                        }
                    }
                    else
                    {
                        stragglers.Add(nearAnimal);
                    }
                }

                if (leader == null)
                {
                    // become the leader
                    leader = agent;
                    agent.SetMemory(IsLeader, stragglers);
                }
                else
                {
                    // join the pack along w/ any other stragglers
                    stragglers.Add(agent);

                    if (!leader.TryGetMemory <List <Animal> >(IsLeader, out followers))
                    {
                        followers = new List <Animal>();
                        leader.SetMemory(IsLeader, followers);
                    }

                    foreach (var newMember in stragglers)
                    {
                        followers.Add(newMember);
                    }
                }

                foreach (var newMember in stragglers)
                {
                    newMember.SetMemory(IsFollower, leader);
                }
            }
            else
            {
                if (leader == null || !leader.Visible || leader.Dead)
                {
                    agent.RemoveMemory(IsFollower);
                    return(agent);
                }
            }
            return(leader);
        }