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); }
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); }
public static IEnumerator AssignNewGraphics(Zombie zombie) { zombie.Drawer.renderer.graphics.ResolveAllGraphics(); yield return(null); var headPath = FixGlowingEyeOffset(zombie); if (zombie.IsSuicideBomber) { zombie.lastBombTick = Find.TickManager.TicksAbs + Rand.Range(0, (int)zombie.bombTickingInterval); } if (ZombieSettings.Values.useCustomTextures) { var renderPrecedence = 0; var bodyPath = "Zombie/Naked_" + zombie.story.bodyType.ToString(); var color = zombie.isToxicSplasher ? "toxic" : (zombie.isMiner ? "miner" : GraphicToolbox.RandomSkinColorString()); yield return(null); var bodyRequest = new GraphicRequest(typeof(VariableGraphic), bodyPath, ShaderDatabase.CutoutSkin, Vector2.one, Color.white, Color.white, null, renderPrecedence, new List <ShaderParameter>()); yield return(null); var maxStainPoints = ZombieStains.maxStainPoints; if (zombie.isMiner) { maxStainPoints *= 2; } var customBodyGraphic = new VariableGraphic { bodyColor = color }; yield return(null); customBodyGraphic.Init(VariableGraphic.minimal); yield return(null); for (var i = 0; i < 4; i++) { var j = 0; var it = customBodyGraphic.InitIterativ(bodyRequest, i, maxStainPoints); while (it.MoveNext()) { yield return(null); j++; } } zombie.Drawer.renderer.graphics.nakedGraphic = customBodyGraphic; var headRequest = new GraphicRequest(typeof(VariableGraphic), headPath, ShaderDatabase.CutoutSkin, Vector2.one, Color.white, Color.white, null, renderPrecedence, new List <ShaderParameter>()); yield return(null); var customHeadGraphic = new VariableGraphic { bodyColor = color }; yield return(null); customHeadGraphic.Init(VariableGraphic.minimal); yield return(null); for (var i = 0; i < 4; i++) { var j = 0; var it = customHeadGraphic.InitIterativ(headRequest, i, maxStainPoints); while (it.MoveNext()) { yield return(null); j++; } } zombie.Drawer.renderer.graphics.headGraphic = customHeadGraphic; } yield return(null); }
private static BodyTypeDef PrepareZombieType(Zombie zombie, ZombieType overwriteType) { var zombieTypeInitializers = new Pair <float, Func <BodyTypeDef> >[] { // suicide bomber new Pair <float, Func <BodyTypeDef> >( ZombieSettings.Values.suicideBomberChance / 2f, delegate { zombie.bombTickingInterval = 60f; zombie.lastBombTick = Find.TickManager.TicksAbs + Rand.Range(0, (int)zombie.bombTickingInterval); // zombie.gender = Gender.Male; return(BodyTypeDefOf.Hulk); } ), // toxic splasher new Pair <float, Func <BodyTypeDef> >( ZombieSettings.Values.toxicSplasherChance / 2f, delegate { zombie.isToxicSplasher = true; // switch (Rand.RangeInclusive(1, 3)) { case 1: zombie.gender = Gender.Male; return(BodyTypeDefOf.Male); case 2: zombie.gender = Gender.Female; return(BodyTypeDefOf.Female); case 3: zombie.gender = Gender.Male; return(BodyTypeDefOf.Thin); } return(null); } ), // tanky operator new Pair <float, Func <BodyTypeDef> >( ZombieSettings.Values.tankyOperatorChance / 3f, delegate { zombie.hasTankyShield = 1f; zombie.hasTankyHelmet = 1f; zombie.hasTankySuit = 1f; // zombie.gender = Gender.Male; return(BodyTypeDefOf.Fat); } ), // miner new Pair <float, Func <BodyTypeDef> >( ZombieSettings.Values.minerChance / 2f, delegate { zombie.isMiner = true; return(SetRandomBody(zombie)); } ), // default ordinary zombie new Pair <float, Func <BodyTypeDef> >( float.MaxValue, delegate { return(SetRandomBody(zombie)); } ) }; if (overwriteType != ZombieType.Random) { var initializer = zombieTypeInitializers[(int)overwriteType]; return(initializer.Second()); } var typeChance = Rand.Value; BodyTypeDef bodyType = null; foreach (var initializer in zombieTypeInitializers) { typeChance -= initializer.First; if (typeChance < 0f) { bodyType = initializer.Second(); break; } } return(bodyType); }
public ZombieLeaner(Pawn pawn) : base(pawn) { zombie = pawn as Zombie; }