static Building CanSmash(Zombie zombie) { var map = zombie.Map; var basePos = zombie.Position; var attackColonistsOnly = (ZombieSettings.Values.attackMode == AttackMode.OnlyColonists); var playerFaction = Faction.OfPlayer; if (zombie.IsTanky) { var info = ZombieWanderer.GetMapInfo(map); var pos = info.GetParent(basePos, false); if (pos.IsValid == false) { pos = info.GetParent(basePos, true); } if (pos.IsValid && pos.GetEdifice(zombie.Map) is Building building && (building as Mineable) == null && (attackColonistsOnly == false || building.Faction == playerFaction)) { return(building); } return(null); } if (zombie.IsSuicideBomber == false && zombie.IsTanky == false && zombie.wasMapPawnBefore == false) { if (ZombieSettings.Values.smashMode == SmashMode.Nothing) { return(null); } if (ZombieSettings.Values.smashOnlyWhenAgitated && zombie.state != ZombieState.Tracking && zombie.raging == 0) { return(null); } } var nextIndex = Constants.random.Next(4); var c = adjIndex4[prevIndex4]; adjIndex4[prevIndex4] = adjIndex4[nextIndex]; adjIndex4[nextIndex] = c; prevIndex4 = nextIndex; if (ZombieSettings.Values.smashMode == SmashMode.DoorsOnly && zombie.IsSuicideBomber == false) { for (var i = 0; i < 4; i++) { var pos = basePos + GenAdj.CardinalDirections[adjIndex4[i]]; if (pos.InBounds(map) == false) { continue; } if (pos.GetEdifice(map) is Building_Door door && door.Open == false && (attackColonistsOnly == false || door.Faction == playerFaction)) { return(door); } } } if (ZombieSettings.Values.smashMode == SmashMode.AnyBuilding || zombie.IsSuicideBomber || zombie.IsTanky) { var grid = map.thingGrid; for (var i = 0; i < 4; i++) { var pos = basePos + GenAdj.CardinalDirections[adjIndex4[i]]; if (pos.InBounds(map) == false) { continue; } foreach (var thing in grid.ThingsListAtFast(pos)) { var building = thing as Building; if (building == null || (building as Mineable) != null) { continue; } var buildingDef = building.def; var factionCondition = (attackColonistsOnly == false || building.Faction == playerFaction); if (buildingDef.useHitPoints && buildingDef.building.isNaturalRock == false && factionCondition) { if (zombie.IsSuicideBomber) { zombie.bombWillGoOff = true; return(null); } return(building); } } } } return(null); }
// 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); }