Beispiel #1
0
        public ActionUtility(EntityAction action, Tuple <Need, double>[] values)
        {
            Action        = action;
            UtilityDeltas = values;

            action.SetUtilityDeltas(UtilityDeltas);
        }
Beispiel #2
0
        public override void Do(Entity entity)
        {
            double squaredDistance = Utilities.SquaredDistance(entity.Position, fleeObject.Position);

            if (squaredDistance < entity.VisionRange * entity.VisionRange)
            {
                double x = entity.Position.X + entity.Position.X - fleeObject.Position.X;
                double y = entity.Position.Y + entity.Position.Y - fleeObject.Position.Y;

                activeAction = new GotoAction(x, y, entity.Size);
                activeAction.Do(entity);
            }
            else
            {
                entity.ApplyNeedDeltas(UtilityDeltas);
                End();
            }


            if (activeAction != null && activeAction.State == ActionState.Failure) // If the entity has hit a wall while running away, head to a random point.
            {
                OrderedPair <int> randomPoint = Utilities.GetDirectionalPoint(entity.CollisionDirection, entity.Position);
                activeAction = new GotoAction(randomPoint.X, randomPoint.Y, entity.Size);
            }
        }
Beispiel #3
0
        public virtual bool TrySetAction(EntityAction newAction, bool locked = false)
        {
            if (Utilities.AreSameBaseType(Action, newAction)) // Don't assign an action of the same type.
            {
                return(false);
            }
            else
            {
                if (Action != null && !Action.IsActive)
                {
                    Action.End();
                }

                Action       = newAction;
                ActionLocked = locked;
                return(true);
            }
        }
Beispiel #4
0
        public void DecideAction(Animal animal, List <GameObject> nearbyObjects)
        {
            List <ActionUtility> actionAds = nearbyObjects.
                                             Where(o => o != animal)
                                             .SelectMany(o => o.GetAdvertisedActions(animal, 0.0)).ToList();

            actionAds.Add(new ActionUtility(animal.IdleAction, new Tuple <Need, double>[]
            {
                ActionUtility.NewPair(Need.JobFullfilment, 0.002)
            }));

            EntityAction attackerResponseAction;

            // Add actions to respond to the attacker being nearby.
            // Bears will always attack nearby entities, but wolves might not, and goats and hogs will not.
            if (animal.Attacker != null && nearbyObjects.Contains(animal.Attacker))
            {
                if (animal.Type == AnimalType.Bear)
                {
                    attackerResponseAction = new AttackAction(animal.Attacker);
                }
                // Wolves will fight back if it can win. I.e. it will take less ticks for the wolf to kill the attacker than for the
                //  attacker to kill the wolf.
                else if (animal.Type == AnimalType.Wolf && animal.GetHealth() / animal.Attacker.Strength > animal.GetHealth() / animal.Strength)
                {
                    attackerResponseAction = new AttackAction(animal.Attacker);
                }
                else
                {
                    attackerResponseAction = new FleeAction(animal.Attacker);
                }
                actionAds.Add(new ActionUtility(attackerResponseAction, new Tuple <Need, double>[]
                {
                    ActionUtility.NewPair(Need.JobFullfilment, DDeltaConfig.attackerResponseDelta)
                }));
            }

            EntityAction bestAction = utilityDecider.GetBestAction(animal, actionAds);

            if (!Utilities.AreSameBaseType(animal.Action, bestAction))
            {
                animal.TrySetAction(bestAction);
            }
        }
Beispiel #5
0
        // Need to select action that gives the highest change to the lowest need values. 0.0 is max, 1.0 is min need.
        // Returns best action for now...
        public EntityAction GetBestAction(Entity entity, List <ActionUtility> actionAds)
        {
            double attenuator(double input)
            {
                return(5.0 / (input == 0.0 ? 0.000001 : input));
            }

            double attenuatorDelta(Tuple <Need, double> deltaPair)
            {
                double currentValue = entity.GetNeedValue(deltaPair.Item1);
                double futureValue  = currentValue + deltaPair.Item2;

                return(attenuator(currentValue) - attenuator(futureValue));
            }

            Tuple <ActionUtility, double> createWeightPairs(ActionUtility actionUtility)
            {
                double weight = actionUtility.UtilityDeltas.Sum(deltaPair => attenuatorDelta(deltaPair));
                Tuple <ActionUtility, double> weightedActionUtility = new Tuple <ActionUtility, double>(actionUtility, weight);

                return(weightedActionUtility);
            }

            // Pair each ActionUtility from actionAds with its score from sumFunction. This applies the attenuation function f(x) = 10.0 / x
            //  to prioritize needs that are more important and favor actions that will reduce that need the most.
            List <Tuple <ActionUtility, double> > weightedActionAds = actionAds
                                                                      .Select(actionAd => createWeightPairs(actionAd))
                                                                      .OrderByDescending(weightPair => weightPair.Item2) // Sort action advertisements by their weight value. Highest first.
                                                                      .Take(3)                                           // Take the top 3 from the list.
                                                                      .ToList();

            EntityAction action = WeightedRandomChoice(weightedActionAds).Action;

            return(action);

            // Assign a value to each action based on the increase in utility. Weight values nonlinearly based on the urgency of the need
            // List.Sum(attenuator(currentNeed) - attenuator(futureNeed))
        }
Beispiel #6
0
 public void DoActionOnce(EntityAction action)
 {
     action.Do(this);
 }
Beispiel #7
0
 public override bool TrySetAction(EntityAction newAction, bool locked = false)
 {
     OnUpdateElement(ChangeType.UpdateElement, "Action", Action != null ? Action.GetName() : "None");
     return(base.TrySetAction(newAction, locked));
 }
Beispiel #8
0
        // Uses the person's needs and the list of GameObjects that are nearby
        public void DecideAction(Person person, List <GameObject> nearbyObjects, int personCount, int food, int mouseX, int mouseY)
        {
            //person.SetAction(new FollowMouseAction(mouseX, mouseY, housePosition, houseRectangle));

            double personCountMod = (personCount == 0 ? 1.0 : food / (2 * personCount));

            List <ActionUtility> actionAds = nearbyObjects
                                             .Where(o => o != person)
                                             // Kinda clunky but this will allow extra data to control action advertisements.
                                             .SelectMany(o => o is Person ? o.GetAdvertisedActions(person, personCountMod) : o.GetAdvertisedActions(person, 0.0))
                                             .ToList();

            //if (personCount >= personLimit)
            //    actionAds = actionAds.Where(ad => !(ad.Action is MateAction)).ToList();


            // Limit the number of people that can be present at one time. This would be more efficient as a check inside Person to prevent
            //  people from advertising a mate action if their are too many people.
            if (personCount >= personLimit)
            {
                actionAds = actionAds.Where(au => !(au.Action is MateAction)).ToList();
            }

            double deliverFoodDelta = person.GetItemCount(ItemType.Apple) / 2;

            // Return food to house.
            actionAds.Add(new ActionUtility(new DeliverFoodAction(houseRectangle), new Tuple <Need, double>[]
            {
                ActionUtility.NewPair(Need.JobFullfilment, deliverFoodDelta)
            }));
            // Wander around.
            actionAds.Add(new ActionUtility(person.IdleAction, new Tuple <Need, double>[]
            {
                ActionUtility.NewPair(Need.JobFullfilment, DDeltaConfig.idleActionAdvertisement)
            }));

            // Hunger need.
            if ((person.GetItemCount(ItemType.Apple) > 0 || food > 0) && person.Hunger <= 0.5)
            {
                actionAds.Add(new ActionUtility(new EatAction(), new Tuple <Need, double>[]
                {
                    ActionUtility.NewPair(Need.Hunger, 1.0 - person.Hunger)
                }));
            }

            // Tiredness need.
            if ((person.Tiredness < 0.6 || person.Health < 50) && !person.AttackerInRange()) // Sleep required. ** Add check to see if attacker is nearby **.
            {
                actionAds.Add(new ActionUtility(new SleepAction(Person.sleepSeconds, true), new Tuple <Need, double>[]
                {
                    ActionUtility.NewPair(Need.Tiredness, DDeltaConfig.sleepActionAdvertisement),
                    ActionUtility.NewPair(Need.Health, DDeltaConfig.sleepHealthAdvertisement)
                }));
            }
            else // Napping optional. This should be picked more often unless there are a lot of other actions to pick.
            {
                actionAds.Add(new ActionUtility(new SleepAction(Person.napSeconds, false), new Tuple <Need, double>[]
                {
                    ActionUtility.NewPair(Need.Tiredness, DDeltaConfig.napActionDelta)
                }));
            }

            if (person.GetRectangleF().IntersectsWith(houseRectangle))
            {
                actionAds.Add(dropUtility);
            }

            EntityAction attackerResponseAction;

            if (person.Attacker != null && nearbyObjects.Contains(person.Attacker))
            {
                if (person.Sex == Sex.Male && person.GetHealth() / person.Attacker.Strength > person.GetHealth() / person.Strength)
                {
                    attackerResponseAction = new AttackAction(person.Attacker);
                }
                else
                {
                    attackerResponseAction = new FleeAction(person.Attacker);
                }

                actionAds.Add(new ActionUtility(attackerResponseAction, new Tuple <Need, double>[]
                {
                    ActionUtility.NewPair(Need.JobFullfilment, DDeltaConfig.attackerResponseDelta)
                }));
            }

            // *** Apply action ad filters here from EntitController's tasks ***
            ApplyTaskFilters(actionAds);

            // NOTE: Doesn't filter actions that give 0.0 delta or a negative!
            EntityAction bestAction = utilityDecider.GetBestAction(person, actionAds);

            if (!Utilities.AreSameBaseType(person.Action, bestAction))
            {
                if (!(bestAction is WanderAction)) // Remove leftover velocity from a WanderAction.
                {
                    person.Stop();
                }
                person.TrySetAction(bestAction);
            }
        }
Beispiel #9
0
 public void AddTask(EntityAction taskAction, double mod)
 {
     Tasks.Add(new Task(taskAction, mod));
 }
Beispiel #10
0
 public void ForceAction(Entity entity, EntityAction action)
 {
     action.Do(entity);
 }
Beispiel #11
0
 public Task(EntityAction action, double mod)
 {
     Action    = action;
     ActionMod = mod;
 }
Beispiel #12
0
 public FleeAction(GameObject entity) : base(true)
 {
     fleeObject = entity;
     idleAction = new WanderAction();
 }
Beispiel #13
0
 // Cause the entity to wait and schedule when it can move again with an additional action.
 public WaitAction(int seconds, EntityAction action, bool interruptible = true) : base(seconds, interruptible)
 {
     IsInterruptible = interruptible;
     finalAction     = action;
 }
Beispiel #14
0
 // Cause the entity to wait and schedule when it can move again.
 public WaitAction(int seconds, bool interruptible = true) : base(seconds, interruptible)
 {
     IsInterruptible = interruptible;
     finalAction     = null;
 }