Beispiel #1
0
        /// <summary>
        ///     Figures out the best location to use this Ability at. Default implementation returns the enemy target, closest ally
        ///     or the caster.
        /// </summary>
        /// <param name="abilityDef">Ability Def for the AI.</param>
        /// <param name="pawn">Pawn to take in account.</param>
        /// <returns>Targeting location or Pawn.</returns>
        public virtual LocalTargetInfo TargetAbilityFor(AbilityAIDef abilityDef, Pawn pawn)
        {
            if (abilityDef.usedOnCaster)
            {
                return(pawn);
            }
            if (abilityDef.canTargetAlly)
            {
                return(GenClosest.ClosestThingReachable(pawn.Position, pawn.Map,
                                                        ThingRequest.ForGroup(ThingRequestGroup.Pawn), PathEndMode.OnCell,
                                                        TraverseParms.For(TraverseMode.NoPassClosedDoors), abilityDef.maxRange,
                                                        thing => AbilityUtility.AreAllies(pawn, thing)));
            }
            if (pawn.mindState.enemyTarget != null && pawn.mindState.enemyTarget is Pawn targetPawn)
            {
                if (!targetPawn.Dead)
                {
                    return(pawn.mindState.enemyTarget);
                }
            }
            else
            {
                if (pawn.mindState.enemyTarget != null && !(pawn.mindState.enemyTarget is Corpse))
                {
                    return(pawn.mindState.enemyTarget);
                }
            }

            return(null);
        }
Beispiel #2
0
        public override float PowerScoreFor(AbilityAIDef abilityDef, Pawn pawn)
        {
            var baseScore = abilityDef.power;

            //Grab enemies \ allies
            var potentionalTargets = new List <Thing>(GrabTargets(abilityDef, pawn,
                                                                  CustomGrabTargetsPredicate(abilityDef, pawn), MaxTargetsToCheck));

            //Add self if can target allies.
            if (abilityDef.canTargetAlly)
            {
                potentionalTargets.Add(pawn);
            }

            //Get the highest intersecting target.
            var targetInfos = new List <LocalTargetInfo>();

            foreach (var target in potentionalTargets)
            {
                targetInfos.Add(new LocalTargetInfo(target));
            }

            var bestTarget = AbilityMaths.PickMostRadialIntersectingTarget(targetInfos, abilityDef.abilityRadius);

            //If we found no valid target, return negative power.
            if (bestTarget == LocalTargetInfo.Invalid)
            {
                return(-abilityDef.power);
            }

            //Calculate final score from best target.
            var finalScore = baseScore;

            foreach (var targetPawn in AbilityUtility.GetPawnsInsideRadius(bestTarget, pawn.Map,
                                                                           abilityDef.abilityRadius,
                                                                           predPawn => abilityDef.abilityRadiusNeedSight &&
                                                                           GenSight.LineOfSight(pawn.Position, predPawn.Position, pawn.Map, true) ||
                                                                           abilityDef.abilityRadiusNeedSight == false))
            {
                if (targetPawn.HostileTo(pawn) || targetPawn.AnimalOrWildMan()
                    ) //Hostile pawns or animals increase score.
                {
                    finalScore += abilityDef.power;
                }
                else //Friendly pawns decrease score.
                {
                    finalScore -= abilityDef.power;
                }
            }

            //Log.Message("AbilityWorker_AreaOfEffect, finalScore=" + finalScore);
            return(finalScore);
        }
Beispiel #3
0
        /// <summary>
        ///     Can the caster use this ability at all?
        /// </summary>
        /// <param name="caster">Caster wanting to use ability.</param>
        /// <param name="target">Target if any to use ability on.</param>
        /// <returns>True if they can, false if not.</returns>
        public bool CanPawnUseThisAbility(Pawn caster, LocalTargetInfo target)
        {
            //if (!appliedHediffs.NullOrEmpty())
            //    return false;

            if (appliedHediffs.Count > 0 &&
                !appliedHediffs.Any(hediffDef => caster.health.hediffSet.HasHediff(hediffDef)))
            {
                return(false);
            }

            if (!Worker.CanPawnUseThisAbility(this, caster, target))
            {
                return(false);
            }

            if (!needEnemyTarget)
            {
                return(true);
            }

            if (!usedOnCaster && target.IsValid)
            {
                var distance = Math.Abs(caster.Position.DistanceTo(target.Cell));
                //Log.Message("CanPawnUseThisAbility.distance=" + distance);

                if (distance < minRange || distance > maxRange)
                {
                    return(false);
                }

                //if (needSeeingTarget && !GenSight.LineOfSight(caster.Position, target.Cell, caster.Map))
                if (needSeeingTarget && !AbilityUtility.LineOfSightLocalTarget(caster, target, true))
                {
                    return(false);
                }
            }

            //Valid ability to use.
            return(true);
        }
Beispiel #4
0
        /// <summary>
        ///     Grab all viable target candidates.
        /// </summary>
        /// <param name="abilityDef">Ability Def to take in account.</param>
        /// <param name="pawn">Caster Pawn.</param>
        /// <param name="customPredicate">If set it overrides the default predicate.</param>
        /// <param name="pawnsToTest">How many pawns to test at max before stopping. Default is 30.</param>
        /// <returns>Things that are viable.</returns>
        public virtual IEnumerable <Thing> GrabTargets(AbilityAIDef abilityDef, Pawn pawn,
                                                       Predicate <Thing> customPredicate = null, int pawnsToTest = 30)
        {
            //Make a list of candidates.
            var potentionalTargets          = new List <Thing>();
            Predicate <Thing> pawnPredicate = null;

            if (customPredicate != null)
            {
                pawnPredicate = customPredicate;
            }
            else if (abilityDef.canTargetAlly)
            {
                pawnPredicate = delegate(Thing thing)
                {
                    //Count own faction and faction whose goodwill they got above 50% as allies.
                    if (AbilityUtility.AreAllies(pawn, thing))
                    {
                        return(true);
                    }
                    return(false);
                }
            }
            ;
            else
            {
                pawnPredicate = delegate(Thing thing)
                {
                    var thingPawn = thing as Pawn;

                    //Count anything hostile as a target.
                    if (thingPawn != null)
                    {
                        if (!thingPawn.Downed && thing.HostileTo(pawn))
                        {
                            return(true);
                        }
                        else if (thing.HostileTo(pawn))
                        {
                            return(true);
                        }
                    }

                    return(false);
                }
            };

            //Max 'pawnsToTest' shall we grab.
            for (var i = 0; i < pawnsToTest; i++)
            {
                var grabResult = GenClosest.ClosestThingReachable(pawn.Position, pawn.Map,
                                                                  ThingRequest.ForGroup(ThingRequestGroup.Pawn), PathEndMode.OnCell,
                                                                  TraverseParms.For(TraverseMode.NoPassClosedDoors),
                                                                  abilityDef.maxRange,
                                                                  thing => pawn != thing && !potentionalTargets.Contains(thing) &&
                                                                  (thing.Position - pawn.Position).LengthHorizontal >= abilityDef.minRange &&
                                                                  pawnPredicate(thing));

                //If found nothing, then break.
                if (grabResult == null)
                {
                    break;
                }

                potentionalTargets.Add(grabResult);

                yield return(grabResult);
            }
        }
    }
Beispiel #5
0
        /// <summary>
        ///     Picks the best candidate Pawn out of up to 10 other.
        /// </summary>
        /// <param name="abilityDef">Ability Def to optionally take in account.</param>
        /// <param name="pawn">Pawn using the Ability.</param>
        /// <returns>Candidate Pawn if found, null if not.</returns>
        public virtual Pawn PickBestClosestPawn(AbilityAIDef abilityDef, Pawn pawn)
        {
            Pawn bestPawn   = null;
            var  bestHealth = 1f;

            var checkedThings = new List <Thing>();

            //Check 10 closest for optimal target.
            for (var i = 0; i < 10; i++)
            {
                var foundThing = GenClosest.ClosestThingReachable(pawn.Position, pawn.Map,
                                                                  ThingRequest.ForGroup(ThingRequestGroup.Pawn), PathEndMode.OnCell,
                                                                  TraverseParms.For(TraverseMode.NoPassClosedDoors), abilityDef.maxRange,
                                                                  thing => pawn != thing && !checkedThings.Contains(thing) && AbilityUtility.AreAllies(pawn, thing));

                //Found no valid candidate.
                if (foundThing == null)
                {
                    break;
                }

                checkedThings.Add(foundThing);

                var foundPawn = foundThing as Pawn;

                if (foundPawn != null)
                {
                    if (foundPawn.health.summaryHealth.SummaryHealthPercent < bestHealth)
                    {
                        bestPawn   = foundPawn;
                        bestHealth = foundPawn.health.summaryHealth.SummaryHealthPercent;
                    }
                }
            }

            return(bestPawn);
        }