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); }
// 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); } }
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>(); }
// 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)]; }
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); }
// 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); }
// 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; } }
int SortByTimestamp(PheromoneGrid grid, IntVec3 p1, IntVec3 p2) { return(grid.Get(p2, false).timestamp.CompareTo(grid.Get(p1, false).timestamp)); }
static int CountSurroundingZombies(IntVec3 pos, PheromoneGrid grid) { return(GenAdj.AdjacentCellsAndInside.Select(vec => pos + vec) .Select(c => grid.GetZombieCount(c)).Sum()); }
// 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); }
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); }