Пример #1
0
        static bool TryToDivert(ref IntVec3 destination, PheromoneGrid grid, IntVec3 basePos, List <IntVec3> possibleMoves)
        {
            var forward  = destination - basePos;
            var rotation = Rand.Value > 0.5 ? Rot4.East : Rot4.West;
            var divert   = basePos + forward.RotatedBy(rotation);

            if (possibleMoves.Contains(divert) && grid.GetZombieCount(divert) == 0)
            {
                destination = divert;
                return(true);
            }

            rotation = rotation == Rot4.East ? Rot4.West : Rot4.East;
            divert   = basePos + forward.RotatedBy(rotation);
            if (possibleMoves.Contains(divert) && grid.GetZombieCount(divert) == 0)
            {
                destination = divert;
                return(true);
            }

            var zombieFreePossibleMoves = possibleMoves.Where(cell => grid.GetZombieCount(cell) == 0).ToArray();
            var n = zombieFreePossibleMoves.Length;

            if (n > 0)
            {
                destination = zombieFreePossibleMoves[Constants.random.Next(n)];
                return(true);
            }

            return(false);
        }
Пример #2
0
        // if we have a valid destination, go there =================================================
        //
        public static void ExecuteMove(this JobDriver_Stumble driver, Zombie zombie, PheromoneGrid grid)
        {
            if (driver.destination.IsValid)
            {
                grid.ChangeZombieCount(zombie.lastGotoPosition, -1);
                grid.ChangeZombieCount(driver.destination, 1);
                zombie.lastGotoPosition = driver.destination;

                zombie.pather.StartPath(driver.destination, PathEndMode.OnCell);
            }
        }
Пример #3
0
        public MapInfo(Map map)
        {
            mapSizeX      = map.Size.x;
            mapSizeZ      = map.Size.z;
            mapSize       = mapSizeX * mapSizeZ;
            pathGrid      = map.pathGrid;
            edificeGrid   = map.edificeGrid;
            terrainGrid   = map.terrainGrid;
            pheromoneGrid = map.GetGrid();

            vecGrids    = new byte[][] { new byte[mapSize], new byte[mapSize] };
            openCellSet = new Queue <IntVec3>();
            openDoorSet = new Queue <IntVec3>();
        }
Пример #4
0
        // during night, drift towards colony =======================================================
        //
        public static void Wander(this JobDriver_Stumble driver, Zombie zombie, PheromoneGrid grid, List <IntVec3> possibleMoves)
        {
            if (driver.destination.IsValid)
            {
                return;
            }

            // check for day/night and dust/dawn
            // during night, zombies drift towards the colonies center
            //
            if (zombie.Map.areaManager.Home[zombie.Position] == false)
            {
                var moveTowardsCenter = false;

                var hour = GenLocalDate.HourOfDay(Find.CurrentMap);
                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;
                }

                if (moveTowardsCenter)
                {
                    var center = zombie.wanderDestination.IsValid ? zombie.wanderDestination : zombie.Map.Center;
                    possibleMoves.Sort((p1, p2) => p1.DistanceToSquared(center).CompareTo(p2.DistanceToSquared(center)));
                    possibleMoves      = possibleMoves.Take(Constants.NUMBER_OF_TOP_MOVEMENT_PICKS).ToList();
                    possibleMoves      = possibleMoves.OrderBy(p => grid.GetZombieCount(p)).ToList();
                    driver.destination = possibleMoves.First();
                    return;
                }
            }

            // random wandering
            var n = possibleMoves.Count();

            driver.destination = possibleMoves[Constants.random.Next(n)];
        }
Пример #5
0
        public static PheromoneGrid GetGrid(this Map map)
        {
            if (gridCache.TryGetValue(map, out var grid))
            {
                return(grid);
            }

            grid = map.GetComponent <PheromoneGrid>();
            if (grid == null)
            {
                grid = new PheromoneGrid(map);
                map.components.Add(grid);
            }
            gridCache[map] = grid;
            return(grid);
        }
Пример #6
0
        // lean in and eat bodies made out of flesh =================================================
        //
        public static bool Eat(this JobDriver_Stumble driver, Zombie zombie, PheromoneGrid grid)
        {
            if (zombie.hasTankyShield != -1f || zombie.hasTankyHelmet != -1f || zombie.hasTankySuit != -1f)
            {
                return(false);
            }

            if (driver.eatTarget != null && driver.eatTarget.Spawned == false)
            {
                driver.eatTarget       = null;
                driver.lastEatTarget   = null;
                driver.eatDelayCounter = 0;
            }
            if (driver.eatTarget == null && grid.GetZombieCount(zombie.Position) <= 2)
            {
                driver.eatTarget = CanIngest(zombie);
            }

            var eatTargetPawn = driver.eatTarget as Pawn ?? (driver.eatTarget as Corpse)?.InnerPawn;

            if (eatTargetPawn != null)
            {
                if (driver.LeanAndDelay(zombie, eatTargetPawn))
                {
                    return(true);
                }

                if (driver.EatBodyPart(zombie, eatTargetPawn))
                {
                    return(true);
                }
            }
            else
            {
                if (zombie.Drawer.leaner is ZombieLeaner zombieLeaner)
                {
                    zombieLeaner.extraOffset = Vector3.zero;
                }
            }

            return(false);
        }
Пример #7
0
        // check for tight groups of zombies ========================================================
        //
        public static void BeginRage(Zombie zombie, PheromoneGrid grid)
        {
            if (zombie.IsTanky)
            {
                return;
            }

            if (zombie.raging == 0 && ZombieSettings.Values.ragingZombies)
            {
                var count = CountSurroundingZombies(zombie.Position, grid);
                if (count > Constants.SURROUNDING_ZOMBIES_TO_TRIGGER_RAGE)
                {
                    StartRage(zombie);
                }
                return;
            }

            if (GenTicks.TicksAbs > zombie.raging || ZombieSettings.Values.ragingZombies == false)
            {
                zombie.raging = 0;
            }
        }
Пример #8
0
 int SortByTimestamp(PheromoneGrid grid, IntVec3 p1, IntVec3 p2)
 {
     return(grid.Get(p2, false).timestamp.CompareTo(grid.Get(p1, false).timestamp));
 }
Пример #9
0
 static int CountSurroundingZombies(IntVec3 pos, PheromoneGrid grid)
 {
     return(GenAdj.AdjacentCellsAndInside.Select(vec => pos + vec)
            .Select(c => grid.GetZombieCount(c)).Sum());
 }
Пример #10
0
        // use rage grid to get to colonists ========================================================
        //
        public static bool RageMove(this JobDriver_Stumble driver, Zombie zombie, PheromoneGrid grid, List <IntVec3> possibleMoves, bool checkSmashable)
        {
            var info   = ZombieWanderer.GetMapInfo(zombie.Map);
            var newPos = info.GetParent(zombie.Position, false);

            if (newPos.IsValid == false)
            {
                // tanky can get directly through walls
                if (zombie.IsTanky)
                {
                    newPos = info.GetParent(zombie.Position, true);
                }

                if (newPos.IsValid == false)
                {
                    // no next move available
                    zombie.raging = 0;
                    return(Smash(driver, zombie, checkSmashable, false));
                }
            }

            // next tanky move is on a building
            if (newPos.GetEdifice(zombie.Map) is Building building && (building as Mineable) == null)
            {
                return(Smash(driver, zombie, checkSmashable, false));
            }

            // next move is on a door
            if (newPos.GetEdifice(zombie.Map) is Building_Door door)
            {
                if (door.Open)
                {
                    driver.destination = newPos;
                    return(false);
                }
                return(Smash(driver, zombie, checkSmashable, false));
            }

            // move into places where there is max 0/1 zombie already
            var destZombieCount = grid.GetZombieCount(newPos);

            if (destZombieCount < (zombie.IsTanky ? 1 : 2))
            {
                driver.destination = newPos;
                return(false);
            }

            // cannot move? lets smash things
            if (Smash(driver, zombie, checkSmashable, false))
            {
                return(true);
            }

            // cannot smash? look for alternative ways to move orthogonal
            if (TryToDivert(ref newPos, grid, zombie.Position, possibleMoves))
            {
                driver.destination = newPos;
                return(false);
            }

            // move to least populated place
            var zCount = possibleMoves.Select(p => grid.GetZombieCount(p)).Min();

            driver.destination = possibleMoves.Where(p => grid.GetZombieCount(p) == zCount).RandomElement();
            return(false);
        }
Пример #11
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);
        }