示例#1
0
        void TickAction()
        {
            var fadeOff               = Tools.PheromoneFadeoff();
            var agitatedFadeoff       = fadeOff / 4;
            var checkSmashableFadeoff = agitatedFadeoff / 2;

            var zombie = (Zombie)pawn;

            if (zombie.state == ZombieState.Emerging)
            {
                return;
            }
            var map = zombie.Map;

            if (zombie.Dead || zombie.Destroyed)
            {
                EndJobWith(JobCondition.InterruptForced);
                return;
            }

            if (zombie.state == ZombieState.ShouldDie)
            {
                EndJobWith(JobCondition.InterruptForced);
                zombie.Kill(null);
                return;
            }

            if (ZombieSettings.Values.zombiesDieVeryEasily)
            {
                if (zombie.health.hediffSet.GetHediffs <Hediff_Injury>().Any())
                {
                    zombie.Kill(null);
                    return;
                }
            }

            if (zombie.Downed)
            {
                if (ZombieSettings.Values.zombiesDieVeryEasily || ZombieSettings.Values.doubleTapRequired == false)
                {
                    zombie.Kill(null);
                    return;
                }

                var walkCapacity = PawnCapacityUtility.CalculateCapacityLevel(zombie.health.hediffSet, PawnCapacityDefOf.Moving);
                var missingBrain = zombie.health.hediffSet.GetBrain() == null;
                if (walkCapacity < 0.25f || missingBrain)
                {
                    zombie.Kill(null);
                    return;
                }

                var injuries = zombie.health.hediffSet.GetHediffs <Hediff_Injury>();
                foreach (var injury in injuries)
                {
                    if (ZombieSettings.Values.zombiesDieVeryEasily)
                    {
                        zombie.Kill(null);
                        return;
                    }

                    if (injury.IsOld() == false)
                    {
                        injury.Heal(injury.Severity + 0.5f);
                        break;
                    }
                }

                if (zombie.Downed)
                {
                    return;
                }
            }

            // handling invalid destinations
            //
            if (destination.x == 0 && destination.z == 0)
            {
                destination = IntVec3.Invalid;
            }
            if (zombie.HasValidDestination(destination))
            {
                return;
            }

            // if we are near targets then attack them
            //
            var enemy = CanAttack();

            if (enemy != null)
            {
                destination = enemy.Position;

                zombie.state = ZombieState.Tracking;
                if (Constants.USE_SOUND)
                {
                    var info = SoundInfo.InMap(enemy);
                    SoundDef.Named("ZombieHit").PlayOneShot(info);
                }

                AttackThing(enemy, JobDefOf.AttackMelee);
                return;
            }

            // eat a downed or dead pawn
            //
            if (eatTarget == null)
            {
                eatTarget = CanIngest(out eatTargetIsCorpse);
                if (eatTarget != null)
                {
                    eatTargetDied = eatTarget.Dead;
                }
            }

            if (eatTarget != null)
            {
                if (eatDelayCounter == 0)
                {
                    if (eatTarget != lastEatTarget)
                    {
                        lastEatTarget = eatTarget;
                        zombie.Drawer.rotator.FaceCell(eatTarget.Position);
                        var zombieLeaner = zombie.Drawer.leaner as ZombieLeaner;
                        if (zombieLeaner != null)
                        {
                            zombieLeaner.extraOffset = (eatTarget.Position.ToVector3() - zombie.Position.ToVector3()) * 0.5f;
                        }

                        Tools.CastThoughtBubble(pawn, Constants.EATING);
                    }
                    CastEatingSound();
                }

                eatDelayCounter++;
                if (eatDelayCounter <= EatDelay)
                {
                    return;
                }
                eatDelayCounter = 0;

                var bodyPartRecord = FirstEatablePart(eatTarget);
                if (bodyPartRecord != null)
                {
                    var hediff_MissingPart = (Hediff_MissingPart)HediffMaker.MakeHediff(HediffDefOf.MissingBodyPart, eatTarget, bodyPartRecord);
                    hediff_MissingPart.lastInjury = HediffDefOf.Bite;
                    hediff_MissingPart.IsFresh    = true;
                    eatTarget.health.AddHediff(hediff_MissingPart, null, null);

                    if (eatTargetIsCorpse == false && eatTargetDied == false && eatTarget.Dead)
                    {
                        Tools.DoWithAllZombies(map, z =>
                        {
                            if (z.jobs != null)
                            {
                                var driver = z.jobs.curDriver as JobDriver_Stumble;
                                if (driver != null && driver.eatTarget == eatTarget)
                                {
                                    driver.eatTargetDied     = true;
                                    driver.eatTargetIsCorpse = true;
                                }
                            }
                        });

                        if (PawnUtility.ShouldSendNotificationAbout(eatTarget) && eatTarget.RaceProps.Humanlike)
                        {
                            Messages.Message("MessageEatenByPredator".Translate(new object[]
                            {
                                eatTarget.LabelShort,
                                zombie.LabelIndefinite()
                            }).CapitalizeFirst(), zombie, MessageSound.Negative);
                        }

                        eatTarget.Strip();
                    }

                    return;
                }
                else
                {
                    var corpse = map.thingGrid
                                 .ThingsListAt(eatTarget.Position)
                                 .OfType <Corpse>()
                                 .FirstOrDefault(c => c.InnerPawn == eatTarget);
                    if (corpse != null)
                    {
                        corpse.Destroy(DestroyMode.Vanish);
                    }

                    Tools.DoWithAllZombies(map, z =>
                    {
                        if (z.jobs != null)
                        {
                            var driver = z.jobs.curDriver as JobDriver_Stumble;
                            if (driver != null && driver.eatTarget == eatTarget)
                            {
                                driver.eatTarget       = null;
                                driver.lastEatTarget   = null;
                                driver.eatDelayCounter = 0;
                            }
                        }
                    });
                }
            }
            else
            {
                var zombieLeaner = zombie.Drawer.leaner as ZombieLeaner;
                if (zombieLeaner != null)
                {
                    zombieLeaner.extraOffset = Vector3.zero;
                }
            }

            var basePos = zombie.Position;

            // calculate possible moves, sort by pheromone value and take top 3
            // then choose the one with the lowest zombie count
            // also, emit a circle of timestamps when discovering a pheromone
            // trace so nearby zombies pick it up too (leads to a chain reaction)
            //
            var grid = zombie.Map.GetGrid();
            var possibleTrackingMoves = new List <IntVec3>();
            var currentTicks          = Tools.Ticks();
            var timeDelta             = long.MaxValue;

            for (int i = 0; i < 8; i++)
            {
                var pos = basePos + GenAdj.AdjacentCells[i];
                if (currentTicks - grid.Get(pos, false).timestamp < fadeOff && zombie.HasValidDestination(pos))
                {
                    possibleTrackingMoves.Add(pos);
                }
            }
            if (possibleTrackingMoves.Count > 0)
            {
                possibleTrackingMoves.Sort((p1, p2) => SortByTimestamp(grid, p1, p2));
                possibleTrackingMoves = possibleTrackingMoves.Take(Constants.NUMBER_OF_TOP_MOVEMENT_PICKS).ToList();
                possibleTrackingMoves = possibleTrackingMoves.OrderBy(p => grid.Get(p, false).zombieCount).ToList();
                var nextMove = possibleTrackingMoves.First();
                timeDelta = currentTicks - grid.Get(nextMove, false).timestamp;

                destination = nextMove;
                if (zombie.state == ZombieState.Wandering)
                {
                    Tools.ChainReact(zombie.Map, basePos, nextMove);
                    if (timeDelta <= agitatedFadeoff)
                    {
                        CastBrainzThought();
                    }
                }
                zombie.state = ZombieState.Tracking;
            }
            if (destination.IsValid == false)
            {
                zombie.state = ZombieState.Wandering;
            }

            bool checkSmashable = timeDelta >= checkSmashableFadeoff;

            if (ZombieSettings.Values.smashOnlyWhenAgitated)
            {
                checkSmashable &= zombie.state == ZombieState.Tracking;
            }

            if (destination.IsValid == false || checkSmashable)
            {
                var building = CanSmash();
                if (building != null)
                {
                    destination = building.Position;

                    if (Constants.USE_SOUND)
                    {
                        var info = SoundInfo.InMap(enemy);
                        SoundDef.Named("ZombieHit").PlayOneShot(info);
                    }

                    AttackThing(building, JobDefOf.AttackStatic);
                    return;
                }
            }

            if (destination.IsValid == false)
            {
                var hour = GenLocalDate.HourOfDay(Find.VisibleMap);

                // check for day/night and dust/dawn
                //
                var moveTowardsCenter = false;
                if (map.areaManager.Home[basePos] == false)
                {
                    if (hour < 12)
                    {
                        hour += 24;
                    }
                    if (hour > Constants.HOUR_START_OF_NIGHT && hour < Constants.HOUR_END_OF_NIGHT)
                    {
                        moveTowardsCenter = true;
                    }
                    else if (hour >= Constants.HOUR_START_OF_DUSK && hour <= Constants.HOUR_START_OF_NIGHT)
                    {
                        moveTowardsCenter = Rand.RangeInclusive(hour, Constants.HOUR_START_OF_NIGHT) == Constants.HOUR_START_OF_NIGHT;
                    }
                    else if (hour >= Constants.HOUR_END_OF_NIGHT && hour <= Constants.HOUR_START_OF_DAWN)
                    {
                        moveTowardsCenter = Rand.RangeInclusive(Constants.HOUR_END_OF_NIGHT, hour) == Constants.HOUR_END_OF_NIGHT;
                    }
                }

                var possibleMoves = new List <IntVec3>();
                for (int i = 0; i < 8; i++)
                {
                    var pos = basePos + GenAdj.AdjacentCells[i];
                    if (zombie.HasValidDestination(pos))
                    {
                        possibleMoves.Add(pos);
                    }
                }
                if (possibleMoves.Count > 0)
                {
                    // during night, zombies drift towards the colonies center
                    //
                    if (moveTowardsCenter)
                    {
                        var center = zombie.wanderDestination.IsValid ? zombie.wanderDestination : map.Center;
                        possibleMoves.Sort((p1, p2) => SortByDirection(center, p1, p2));
                        possibleMoves = possibleMoves.Take(Constants.NUMBER_OF_TOP_MOVEMENT_PICKS).ToList();
                        possibleMoves = possibleMoves.OrderBy(p => grid.Get(p, false).zombieCount).ToList();
                        destination   = possibleMoves.First();
                    }
                    else
                    {
                        // otherwise they sometimes stand or walk towards a random direction
                        //
                        if (Rand.Chance(Constants.STANDING_STILL_CHANCE))
                        {
                            var n = possibleMoves.Count();
                            destination = possibleMoves[Constants.random.Next(n)];
                        }
                    }
                }
            }

            // if we have a valid destination, go there
            //
            if (destination.IsValid)
            {
                MoveToCell(destination);
            }
        }
示例#2
0
        public static bool Track(this JobDriver_Stumble driver, Zombie zombie, PheromoneGrid grid)
        {
            if (zombie.EveryNTick(NthTick.Every60) || fadeOff == -1)
            {
                fadeOff                = Tools.PheromoneFadeoff();
                wasColonistFadeoff     = fadeOff / 6;
                agitatedFadeoff        = fadeOff / 4;
                checkSmashableFadeoff1 = agitatedFadeoff / 4;
                checkSmashableFadeoff2 = agitatedFadeoff * 3 / 4;
            }

            var trackingMoves = new List <IntVec3>(8);
            var currentTicks  = Tools.Ticks();
            var timeDelta     = long.MaxValue;

            var fmin = long.MaxValue;

            if (zombie.raging == 0)
            {
                for (var i = 0; i < 8; i++)
                {
                    var pos = zombie.Position + GenAdj.AdjacentCells[i];
                    if (zombie.HasValidDestination(pos))
                    {
                        var f     = zombie.wasMapPawnBefore ? wasColonistFadeoff : fadeOff;
                        var tdiff = currentTicks - grid.GetTimestamp(pos);
                        fmin = Math.Min(fmin, tdiff);
                        if (tdiff < f)
                        {
                            trackingMoves.Add(pos);
                        }
                    }
                }
            }

            if (trackingMoves.Count > 0)
            {
                trackingMoves.Sort((p1, p2) => grid.GetTimestamp(p2).CompareTo(grid.GetTimestamp(p1)));
                trackingMoves = trackingMoves.Take(Constants.NUMBER_OF_TOP_MOVEMENT_PICKS).ToList();
                trackingMoves = trackingMoves.OrderBy(p => grid.GetZombieCount(p)).ToList();
                var nextMove = trackingMoves.First();
                timeDelta = currentTicks - (grid.GetTimestamp(nextMove));

                driver.destination = nextMove;
                if (zombie.state == ZombieState.Wandering)
                {
                    Tools.ChainReact(zombie.Map, zombie.Position, nextMove);
                    if (timeDelta <= agitatedFadeoff)
                    {
                        CastBrainzThought(zombie);
                    }
                }
                zombie.state = ZombieState.Tracking;
            }

            if (driver.destination.IsValid == false)
            {
                zombie.state = ZombieState.Wandering;
            }

            if (zombie.wasMapPawnBefore)
            {
                return(true);
            }

            var checkSmashable = timeDelta >= checkSmashableFadeoff1 && timeDelta < checkSmashableFadeoff2;

            if (ZombieSettings.Values.smashOnlyWhenAgitated)
            {
                checkSmashable &= (zombie.state == ZombieState.Tracking || zombie.raging > 0);
            }

            return(checkSmashable);
        }