private int CheckForHunger; // Random 180 to 600 #endregion Fields #region Methods public static Thing FindMeat(Pawn pawn, TraverseParms traverseParams) { ThingRequest meatRequest = ThingRequest.ForGroup(ThingRequestGroup.FoodNotPlant); Predicate<Thing> availMeatPredicate = food => { return (isMeaty(pawn, food) && (Find.Reservations.CanReserve(pawn, food, 1) == true)); }; Thing thing = GenClosest.ClosestThingReachable(pawn.Position, meatRequest, PathEndMode.Touch, traverseParams, 100f, availMeatPredicate); return thing; }
public static Corpse FindMeatyCorpse(Pawn pawn, TraverseParms traverseParams) { ThingRequest corpseRequest = ThingRequest.ForGroup(ThingRequestGroup.Corpse); Predicate<Thing> availCorpsePredicate = corpse => { return (isMeaty(pawn, corpse) && (Find.Reservations.CanReserve(pawn, corpse, 1) == true)); }; Corpse closestCorpse = GenClosest.ClosestThingReachable(pawn.Position, corpseRequest, PathEndMode.Touch, traverseParams, 100f, availCorpsePredicate) as Corpse; return closestCorpse; }
public static Pawn FindThreat(Pawn pawn, TraverseParms traverseParams) { ThingRequest agressorRequest = ThingRequest.ForGroup(ThingRequestGroup.Pawn); Predicate<Thing> availAgressorPredicate = p => { Pawn agressor = p as Pawn; return isPossibleThreat(agressor, pawn); }; Pawn closestThreat = GenClosest.ClosestThingReachable(pawn.Position, agressorRequest, PathEndMode.Touch, traverseParams, 100f, availAgressorPredicate) as Pawn; return closestThreat; }
public static Pawn FindBloodyPrey(Pawn pawn, TraverseParms traverseParams) { ThingRequest preyRequest = ThingRequest.ForGroup(ThingRequestGroup.Pawn); Predicate<Thing> availPreyPredicate = p => { Pawn prey = p as Pawn; return isPossibleBloodyPrey(prey, pawn); }; Pawn closestBloodyPrey = GenClosest.ClosestThingReachable(pawn.Position, preyRequest, PathEndMode.Touch, traverseParams, 100f, availPreyPredicate) as Pawn; return closestBloodyPrey; }
public IntVec3? NearestTerrainOfType(IntVec3 root, Func<TerrainDef, bool> terrainPred, TraverseParms traverseParams, int minRegions=9, int maxRegions=0, float maxDistance=9999f) { IntVec3? nearest = null; Region validRegionAt = Find.RegionGrid.GetValidRegionAt(root); if (validRegionAt == null) { return nearest; } maxRegions = (maxRegions == 0 ? 50 : maxRegions); float maxDistSquared = maxDistance * maxDistance; float closestDistSquared = 99999f; int regionsSeen = 0; RegionEntryPredicate entryCondition = r => r.Allows(traverseParams, false) && (maxDistance > 5000f || r.extentsClose.ClosestDistSquaredTo(root) < maxDistSquared); RegionProcessor regionProc = delegate(Region r) { if (!r.Allows(traverseParams, true)) { return false; } // If a region definitely doesn't have the correct terrain, skip it. if (!RegionMayContain(r, terrainPred)) { return false; } var tg = Find.TerrainGrid; foreach (var cellVec in r.Cells) { float cellDistSquared = (cellVec - root).LengthHorizontalSquared; var cellTerrain = tg.TerrainAt(cellVec); if ((cellDistSquared < closestDistSquared && cellDistSquared < maxDistSquared) && (terrainPred == null || terrainPred(cellTerrain))) { nearest = cellVec; closestDistSquared = cellDistSquared; } } regionsSeen++; return regionsSeen > minRegions && nearest != null; }; RegionTraverser.BreadthFirstTraverse(validRegionAt, entryCondition, regionProc, maxRegions); return nearest; }
public static Thing ClosestThing_Global_Reachable(IntVec3 center, IEnumerable<Thing> searchSet, PathEndMode pathMode, TraverseParms traverseParams, float maxDistance, Pawn pawn) { if (searchSet == null) { return null; } int num = 0; int num2 = 0; Thing result = null; int num3 = -2147483648; int num4 = 0; float num5 = maxDistance * maxDistance; float num6 = 2.14748365E+09f; foreach (Thing current in searchSet) { num2++; float lengthHorizontalSquared = (center - current.Position).LengthHorizontalSquared; if (lengthHorizontalSquared <= num5) { if (num4 > num3 || lengthHorizontalSquared < num6) { if (center.CanReach(current, pathMode, traverseParams)) { if (current.SpawnedInWorld) { if(((Building_DroidChargePad)current).IsAvailable(pawn)) { result = current; num6 = lengthHorizontalSquared; num3 = num4; num++; } } } } } } return result; }
// Token: 0x06000063 RID: 99 RVA: 0x00004318 File Offset: 0x00002518 protected override IEnumerable <Toil> MakeNewToils() { this.FailOnDespawnedOrNull(TargetIndex.A); var toilInv = new Toil(); var toilEquipGoto = new Toil(); var toilEquip = new Toil(); var toilGoto = new Toil(); var toilCast = new Toil(); var toilTouch = new Toil(); var toilBeat = new Toil(); var toilBash = new Toil(); var HasPrimFE = false; var HasPrimFB = false; if (pawn.equipment.Primary != null) { if (pawn.equipment.Primary.def.defName == FEDefName && FWFoamUtility.HasFEFoam(pawn.equipment.Primary)) { HasPrimFE = true; } else if (pawn.equipment.Primary.def.defName == FBDefName) { HasPrimFB = true; } } if (!HasPrimFE) { var fb = HasPrimFB; toilInv.initAction = delegate { var Swap = false; ThingWithComps invGearToEquip2 = null; ThingWithComps primToSwap2 = null; Thing RemoveThing = null; Thing BackupThing2 = null; if (pawn.equipment.Primary != null) { primToSwap2 = pawn.equipment.Primary; } foreach (var invThing2 in pawn.inventory.innerContainer) { if (invThing2.def.defName != FEDefName || !FWFoamUtility.HasFEFoam(invThing2)) { if (invThing2.def.defName == FBDefName) { BackupThing2 = invThing2; } } else { RemoveThing = invThing2; invGearToEquip2 = (ThingWithComps)invThing2; if (primToSwap2 != null) { Swap = true; } break; } } if (invGearToEquip2 == null && !fb && BackupThing2 != null) { RemoveThing = BackupThing2; invGearToEquip2 = (ThingWithComps)BackupThing2; if (primToSwap2 != null) { Swap = true; } } if (invGearToEquip2 == null) { return; } var primDef = ""; if (Swap) { primDef = pawn.equipment.Primary.def.defName; pawn.equipment.Remove(pawn.equipment.Primary); } pawn.inventory.innerContainer.Remove(RemoveThing); pawn.equipment.MakeRoomFor(invGearToEquip2); pawn.equipment.AddEquipment(invGearToEquip2); if (Swap) { pawn.inventory.innerContainer.TryAdd(primToSwap2); } if (!Swap) { return; } var returnType = "SI"; if (pawn.equipment.Primary.def.defName != FEDefName && pawn.equipment.Primary.def.defName != FBDefName) { return; } var primary = pawn.equipment.Primary; ((FireWardenData)primary).FWSwapType = returnType; ((FireWardenData)primary).FWPawnID = pawn.thingIDNumber; ((FireWardenData)primary).FWPrimDef = primDef; if (!DebugFWData) { return; } var Test = pawn.equipment.Primary; var debugTest = pawn.Label + " : "; debugTest = debugTest + Test.Label + " : "; debugTest = debugTest + pawn.equipment.Primary.GetType() + " : "; if (((FireWardenData)Test).FWSwapType != null) { debugTest = debugTest + ((FireWardenData)Test).FWSwapType + " : "; } else { debugTest += "null : "; } debugTest = debugTest + ((FireWardenData)Test).FWPawnID + " : "; if (((FireWardenData)Test).FWPrimDef != null) { debugTest += ((FireWardenData)Test).FWPrimDef; } else { debugTest += "null"; } Messages.Message(debugTest, pawn, MessageTypeDefOf.NeutralEvent, false); }; toilInv.defaultCompleteMode = ToilCompleteMode.FinishedBusy; yield return(toilInv); } var FWEquipping = Controller.Settings.EquippingDone; var FWSearchRange = (float)Controller.Settings.SearchRange; if (FWSearchRange < 25f) { FWSearchRange = 25f; } if (FWSearchRange > 75f) { FWSearchRange = 75f; } HasPrimFE = false; HasPrimFB = false; if (pawn.equipment.Primary != null) { if (pawn.equipment.Primary.def.defName == FEDefName && FWFoamUtility.HasFEFoam(pawn.equipment.Primary)) { HasPrimFE = true; } else if (pawn.equipment.Primary.def.defName == FBDefName) { HasPrimFB = true; } } if (!HasPrimFE && !HasPrimFB && FWEquipping) { ThingWithComps invGearToEquip = null; ThingWithComps primToSwap = null; Thing BackupThing = null; if (pawn.equipment.Primary != null) { primToSwap = pawn.equipment.Primary; } foreach (var invThing in pawn.inventory.innerContainer) { if (invThing.def.defName == FEDefName && FWFoamUtility.HasFEFoam(invThing)) { invGearToEquip = (ThingWithComps)invThing; if (primToSwap != null) { } break; } if (invThing.def.defName == FBDefName) { BackupThing = invThing; } } if (invGearToEquip == null && BackupThing != null) { invGearToEquip = (ThingWithComps)BackupThing; } if (invGearToEquip == null) { Thing ThingToGrab = null; var skip = Controller.Settings.BrawlerNotOK && pawn.story.traits.HasTrait(TraitDefOf.Brawler); var traverseParams = TraverseParms.For(pawn); bool validatorFE(Thing t) { return(!t.IsForbidden(pawn) && pawn.CanReserve(t) && FWFoamUtility.HasFEFoam(t) && !FWFoamUtility.ReplaceFEFoam(t)); } bool validatorFB(Thing t) { return(!t.IsForbidden(pawn) && pawn.CanReserve(t)); } if (!skip) { var FElist = pawn.Map.listerThings.ThingsOfDef(DefDatabase <ThingDef> .GetNamed(FEDefName)); var FEGrab = GenClosest.ClosestThing_Global_Reachable(pawn.Position, pawn.Map, FElist, PathEndMode.OnCell, traverseParams, FWSearchRange, validatorFE); if (FEGrab != null) { ThingToGrab = FEGrab; } else { var FBlist = pawn.Map.listerThings.ThingsOfDef(DefDatabase <ThingDef> .GetNamed(FBDefName)); var FBGrab = GenClosest.ClosestThing_Global_Reachable(pawn.Position, pawn.Map, FBlist, PathEndMode.OnCell, traverseParams, FWSearchRange, validatorFB); if (FBGrab != null) { ThingToGrab = FBGrab; } } } else { var FBlist2 = pawn.Map.listerThings.ThingsOfDef(DefDatabase <ThingDef> .GetNamed(FBDefName)); var FBGrab2 = GenClosest.ClosestThing_Global_Reachable(pawn.Position, pawn.Map, FBlist2, PathEndMode.OnCell, traverseParams, FWSearchRange, validatorFB); if (FBGrab2 != null) { ThingToGrab = FBGrab2; } } if (ThingToGrab != null) { toilEquipGoto.initAction = delegate { if (Map.reservationManager.CanReserve(pawn, ThingToGrab)) { pawn.Reserve(ThingToGrab, job); } pawn.pather.StartPath(ThingToGrab, PathEndMode.OnCell); }; toilEquipGoto.FailOn(ThingToGrab.DestroyedOrNull); toilEquipGoto.AddFailCondition(() => FWHasFE(pawn) && ThingToGrab.def.defName == FEDefName); toilEquipGoto.AddFailCondition(() => FWHasFB(pawn) && ThingToGrab.def.defName == FBDefName); toilEquipGoto.defaultCompleteMode = ToilCompleteMode.PatherArrival; yield return(toilEquipGoto); toilEquip.initAction = delegate { var primDeEquip = pawn.equipment.Primary; var primDef = "N"; if (primDeEquip != null) { primDef = pawn.equipment.Primary.def.defName; pawn.equipment.Remove(pawn.equipment.Primary); pawn.inventory.innerContainer.TryAdd(primDeEquip); } var FWGrabWithComps = (ThingWithComps)ThingToGrab; ThingWithComps FWGrabbed; if (FWGrabWithComps.def.stackLimit > 1 && FWGrabWithComps.stackCount > 1) { FWGrabbed = (ThingWithComps)FWGrabWithComps.SplitOff(1); } else { FWGrabbed = FWGrabWithComps; FWGrabbed.DeSpawn(); } pawn.equipment.MakeRoomFor(FWGrabbed); pawn.equipment.AddEquipment(FWGrabbed); var returnType = "EN"; if (pawn.equipment.Primary.def.defName != FEDefName && pawn.equipment.Primary.def.defName != FBDefName) { return; } var primary = pawn.equipment.Primary; ((FireWardenData)primary).FWSwapType = returnType; ((FireWardenData)primary).FWPawnID = pawn.thingIDNumber; ((FireWardenData)primary).FWPrimDef = primDef; if (!DebugFWData) { return; } var Test = pawn.equipment.Primary; var debugTest = pawn.Label + " : "; debugTest = debugTest + Test.Label + " : "; debugTest = debugTest + pawn.equipment.Primary.GetType() + " : "; if ((Test as FireWardenData)?.FWSwapType != null) { debugTest = debugTest + ((FireWardenData)Test).FWSwapType + " : "; } else { debugTest += "null : "; } debugTest = debugTest + ((FireWardenData)Test).FWPawnID + " : "; if (((FireWardenData)Test).FWPrimDef != null) { debugTest += ((FireWardenData)Test).FWPrimDef; } else { debugTest += "null"; } Messages.Message(debugTest, pawn, MessageTypeDefOf.NeutralEvent, false); }; toilEquip.AddFailCondition(() => FWHasFE(pawn) && ThingToGrab.def.defName == FEDefName); toilEquip.AddFailCondition(() => FWHasFB(pawn) && ThingToGrab.def.defName == FBDefName); toilEquip.defaultCompleteMode = ToilCompleteMode.FinishedBusy; yield return(toilEquip); } } } var HasPrimFEEq = pawn.equipment.Primary != null && pawn.equipment.Primary.def.defName == FEDefName && FWFoamUtility.HasFEFoam(pawn.equipment.Primary); if (HasPrimFEEq) { var FEVerbToUse = pawn.TryGetAttackVerb(TargetFire); var RangeFireExt = 10f; if (FEVerbToUse != null) { pawn.jobs.curJob.verbToUse = FEVerbToUse; RangeFireExt = pawn.jobs.curJob.verbToUse.verbProps.range; RangeFireExt *= (float)(Controller.Settings.HowClose / 100.0); if (RangeFireExt < 3f) { RangeFireExt = 3f; } if (RangeFireExt > pawn.jobs.curJob.verbToUse.verbProps.range) { RangeFireExt = pawn.jobs.curJob.verbToUse.verbProps.range; } } toilGoto.initAction = delegate { if (Map.reservationManager.CanReserve(pawn, TargetFire)) { pawn.Reserve(TargetFire, job); } if (!CastPositionFinder.TryFindCastPosition(new CastPositionRequest { caster = pawn, target = TargetFire, verb = pawn.jobs.curJob.verbToUse, maxRangeFromTarget = RangeFireExt, wantCoverFromTarget = false }, out var dest)) { toilGoto.actor.jobs.EndCurrentJob(JobCondition.Incompletable); return; } toilGoto.actor.pather.StartPath(dest, PathEndMode.OnCell); pawn.Map.pawnDestinationReservationManager.Reserve(pawn, pawn.jobs.curJob, dest); }; toilGoto.tickAction = delegate { if (Controller.Settings.TooBrave) { return; } if (pawn.pather.Moving && pawn.pather.nextCell != TargetFire.Position) { StartTacklingFireIfAnyAt(pawn.pather.nextCell, toilCast); } if (pawn.Position != TargetFire.Position) { StartTacklingFireIfAnyAt(pawn.Position, toilCast); } }; toilGoto.FailOnDespawnedOrNull(TargetIndex.A); toilGoto.defaultCompleteMode = ToilCompleteMode.PatherArrival; toilGoto.atomicWithPrevious = true; yield return(toilGoto); toilCast.initAction = delegate { pawn.jobs.curJob.verbToUse.TryStartCastOn(TargetFire); if (!TargetFire.Destroyed) { return; } pawn.records.Increment(RecordDefOf.FiresExtinguished); pawn.jobs.EndCurrentJob(JobCondition.Succeeded); }; toilCast.FailOnDespawnedOrNull(TargetIndex.A); toilCast.defaultCompleteMode = ToilCompleteMode.FinishedBusy; yield return(toilCast); } else { toilTouch.initAction = delegate { if (Map.reservationManager.CanReserve(pawn, TargetFire)) { pawn.Reserve(TargetFire, job); } pawn.pather.StartPath(TargetFire, PathEndMode.Touch); }; toilTouch.tickAction = delegate { if (Controller.Settings.TooBrave) { return; } if (pawn.pather.Moving && pawn.pather.nextCell != TargetFire.Position) { StartTacklingFireIfAnyAt(pawn.pather.nextCell, toilBeat); } if (pawn.Position != TargetFire.Position) { StartTacklingFireIfAnyAt(pawn.Position, toilBeat); } }; toilTouch.FailOnDespawnedOrNull(TargetIndex.A); toilTouch.defaultCompleteMode = ToilCompleteMode.PatherArrival; toilTouch.atomicWithPrevious = true; yield return(toilTouch); toilBeat.tickAction = delegate { if (!pawn.CanReachImmediate(TargetFire, PathEndMode.Touch)) { JumpToToil(toilTouch); return; } if (pawn.Position != TargetFire.Position && StartTacklingFireIfAnyAt(pawn.Position, toilBeat)) { return; } if (pawn.equipment.Primary != null) { if (pawn.equipment.Primary.def.defName == FBDefName) { JumpToToil(toilBash); } else { pawn.natives.TryBeatFire(TargetFire); } } else { pawn.natives.TryBeatFire(TargetFire); } if (!TargetFire.Destroyed) { return; } pawn.records.Increment(RecordDefOf.FiresExtinguished); pawn.jobs.EndCurrentJob(JobCondition.Succeeded); }; toilBeat.FailOnDespawnedOrNull(TargetIndex.A); toilBeat.defaultCompleteMode = ToilCompleteMode.Never; yield return(toilBeat); if (pawn.equipment.Primary == null || pawn.equipment.Primary.def.defName != FBDefName) { yield break; } toilBash.initAction = delegate { if (TargetFire != null && Map.reservationManager.CanReserve(pawn, TargetFire)) { pawn.Reserve(TargetFire, job); } pawn.pather.StopDead(); }; toilBash.handlingFacing = true; toilBash.tickAction = delegate { pawn.rotationTracker.FaceTarget(pawn.CurJob.GetTarget(TargetIndex.A)); if (TargetFire != null) { pawn.Drawer.Notify_MeleeAttackOn(TargetFire); } }; toilBash.PlaySoundAtStart(SoundDefOf.Interact_BeatFire); toilBash.WithProgressBarToilDelay(TargetIndex.A); toilBash.AddFinishAction(delegate { if (TargetFire != null && !TargetFire.Destroyed) { TargetFire.Destroy(); } }); toilBash.FailOnDespawnedOrNull(TargetIndex.A); toilBash.defaultCompleteMode = ToilCompleteMode.Delay; var ticks = 50; var WorkSpeed = pawn.GetStatValue(StatDefOf.WorkSpeedGlobal); if (WorkSpeed <= 0f) { WorkSpeed = 1f; } ticks = (int)(ticks * (1f / WorkSpeed)); if (ticks < 25) { ticks = 25; } if (ticks > 200) { ticks = 200; } toilBash.defaultDuration = ticks; yield return(toilBash); } }
private static Pawn FindPawnTargetNearPlants(Pawn pawn) { Pawn victim = null; bool Predicate(Thing p) => p != null && p != pawn && p.Faction != pawn.Faction && ((Pawn)p).health.hediffSet.GetFirstHediffOfDef(PurpleIvyDefOf.PI_MaskingSprayHigh) == null; const float distance = 9999f; var plants = pawn.Map.listerThings.ThingsOfDef(PurpleIvyDefOf.PI_Nest); if (plants.Count == 0) { plants = pawn.Map.listerThings.ThingsOfDef(PurpleIvyDefOf.PurpleIvy); } if (plants.Count > 0) { victim = (Pawn)GenClosest.ClosestThingReachable(plants.RandomElement().Position, pawn.Map, ThingRequest.ForGroup(ThingRequestGroup.Pawn), PathEndMode.Touch, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.PassDoors, false) , distance, Predicate); } return(victim); }
//The standard A* search algorithm has been modified to implement the bidirectional pathmax algorithm //("Inconsistent heuristics in theory and practice" Felner et al.) http://web.cs.du.edu/~sturtevant/papers/incnew.pdf internal PawnPath FindPathInner(IntVec3 start, LocalTargetInfo dest, TraverseParms traverseParms, PathEndMode peMode, HeuristicMode mode = HeuristicMode.Better) { //The initialization is largely unchanged from Core, aside from coding style in some spots #region initialization if (DebugSettings.pathThroughWalls) { traverseParms.mode = TraverseMode.PassAnything; } Pawn pawn = traverseParms.pawn; bool canPassAnything = traverseParms.mode == TraverseMode.PassAnything; if (!ValidateFindPathParameters(pawn, start, dest, traverseParms, peMode, canPassAnything)) { return(PawnPath.NotFound); } PfProfilerBeginSample(string.Concat("FindPath for ", pawn, " from ", start, " to ", dest, (!dest.HasThing) ? string.Empty : (" at " + dest.Cell))); destinationX = dest.Cell.x; destinationZ = dest.Cell.z; var cellIndices = this.map.cellIndices; curIndex = cellIndices.CellToIndex(start); destinationIndex = cellIndices.CellToIndex(dest.Cell); if (!dest.HasThing || peMode == PathEndMode.OnCell) { destinationRect = CellRect.SingleCell(dest.Cell); } else { destinationRect = dest.Thing.OccupiedRect(); } if (peMode == PathEndMode.Touch) { destinationRect = destinationRect.ExpandedBy(1); } destinationRect = destinationRect.ClipInsideMap(map); var regions = destinationRect.Cells.Select(c => this.map.regionGrid.GetValidRegionAt_NoRebuild(c)).Where(r => r != null); //Pretty sure this shouldn't be able to happen... if (mode == HeuristicMode.Better && !canPassAnything && !regions.Any()) { mode = HeuristicMode.Vanilla; Log.Warning("Pathfinding destination not in region, must fall back to vanilla!"); } destinationIsOneCell = (destinationRect.Width == 1 && destinationRect.Height == 1); this.pathGridDirect = this.map.pathGrid.pathGrid; this.edificeGrid = this.map.edificeGrid.InnerArray; statusOpenValue += 2; statusClosedValue += 2; if (statusClosedValue >= 65435) { ResetStatuses(); } if (pawn?.RaceProps.Animal == true) { heuristicStrength = 30; } else { float lengthHorizontal = (start - dest.Cell).LengthHorizontal; heuristicStrength = (int)Math.Round(HeuristicStrengthHuman_DistanceCurve.Evaluate(lengthHorizontal)); } closedCellCount = 0; openList.Clear(); debug_pathFailMessaged = false; debug_totalOpenListCount = 0; debug_openCellsPopped = 0; PawnPathCostSettings pawnPathCosts = GetPawnPathCostSettings(traverseParms.pawn); moveTicksCardinal = pawnPathCosts.moveTicksCardinal; moveTicksDiagonal = pawnPathCosts.moveTicksDiagonal; //Where the magic happens RegionPathCostHeuristic regionCost = new RegionPathCostHeuristic(map, start, destinationRect, regions, traverseParms, pawnPathCosts); if (mode == HeuristicMode.Better) { if (canPassAnything) { //Roughly preserves the Vanilla behavior of increasing path accuracy for shorter paths and slower pawns, though not as smoothly. Only applies to sappers. heuristicStrength = Math.Max(1, (int)Math.Round(heuristicStrength / (float)moveTicksCardinal)); } else { var totalCostEst = (debug_totalHeuristicCostEstimate = regionCost.GetPathCostToRegion(curIndex)) + (moveTicksCardinal * 50); //Add constant cost so it tries harder on short paths regionHeuristicWeightReal[1].x = totalCostEst / 2; regionHeuristicWeightReal[2].x = totalCostEst; } regionHeuristicWeight = weightEnabled ? regionHeuristicWeightReal : regionHeuristicWeightNone; } else { regionHeuristicWeight = regionHeuristicWeightNone; } calcGrid[curIndex].knownCost = 0; calcGrid[curIndex].heuristicCost = 0; calcGrid[curIndex].parentIndex = curIndex; calcGrid[curIndex].status = statusOpenValue; openList.Push(new CostNode(curIndex, 0)); bool shouldCollideWithPawns = false; if (pawn != null) { shouldCollideWithPawns = PawnUtility.ShouldCollideWithPawns(pawn); } #endregion while (true) { PfProfilerBeginSample("Open cell pop"); if (openList.Count <= 0) { break; } debug_openCellsPopped++; var thisNode = openList.Pop(); curIndex = thisNode.gridIndex; PfProfilerEndSample(); PfProfilerBeginSample("Open cell"); if (calcGrid[curIndex].status == statusClosedValue) { PfProfilerEndSample(); } else { #if DEBUG calcGrid[curIndex].timesPopped++; #endif curIntVec3 = cellIndices.IndexToCell(curIndex); if (DebugViewSettings.drawPaths && !disableDebugFlash && debug_openCellsPopped < 20000) { //draw backpointer var arrow = GetBackPointerArrow(cellIndices.IndexToCell(calcGrid[curIndex].parentIndex), curIntVec3); string leading = ""; string trailing = ""; #if DEBUG switch (calcGrid[curIndex].timesPopped) { case 1: trailing = "\n\n"; // $"\n\n\n{thisNode.totalCostEstimate}({calcGrid[curIndex].knownCost + calcGrid[curIndex].originalHeuristicCost})"; break; case 2: trailing = "\n"; break; case 3: break; case 4: leading = "\n"; break; default: leading = "\n\n"; break; } #endif DebugFlash(curIntVec3, calcGrid[curIndex].knownCost / 1500f, leading + calcGrid[curIndex].knownCost + " " + arrow + " " + debug_openCellsPopped + trailing); } if (curIndex == destinationIndex || (!destinationIsOneCell && destinationRect.Contains(curIntVec3))) { PfProfilerEndSample(); PfProfilerBeginSample("Finalize Path"); var ret = FinalizedPath(curIndex); PfProfilerEndSample(); return(ret); } //With reopening closed nodes, this limit can be reached a lot more easily. I've left it as is because it gets users to report bad paths. if (closedCellCount > 160000) { Log.Warning(string.Concat(pawn, " pathing from ", start, " to ", dest, " hit search limit of ", 160000, " cells.")); PfProfilerEndSample(); return(PawnPath.NotFound); } PfProfilerEndSample(); PfProfilerBeginSample("Neighbor consideration"); for (int i = 0; i < 8; i++) { neighIndexes[i] = -1; neighX = (ushort)(curIntVec3.x + Directions[i]); neighZ = (ushort)(curIntVec3.z + Directions[i + 8]); if (neighX >= mapSizeX || neighZ >= mapSizeZ) { continue; } switch (i) { case 4: //Northeast if (!pathGridDirect.WalkableExtraFast(curIndex - mapSizeX) || !pathGridDirect.WalkableExtraFast(curIndex + 1)) { continue; } break; case 5: //Southeast if (!pathGridDirect.WalkableExtraFast(curIndex + mapSizeX) || !pathGridDirect.WalkableExtraFast(curIndex + 1)) { continue; } break; case 6: //Southwest if (!pathGridDirect.WalkableExtraFast(curIndex + mapSizeX) || !pathGridDirect.WalkableExtraFast(curIndex - 1)) { continue; } break; case 7: //Northwest if (!pathGridDirect.WalkableExtraFast(curIndex - mapSizeX) || !pathGridDirect.WalkableExtraFast(curIndex - 1)) { continue; } break; } neighIndex = cellIndices.CellToIndex(neighX, neighZ); if ((calcGrid[neighIndex].status != statusClosedValue) && (calcGrid[neighIndex].status != statusOpenValue)) { if (10000 <= (calcGrid[neighIndex].perceivedPathCost = GetTotalPerceivedPathCost(traverseParms, canPassAnything, shouldCollideWithPawns, pawn, pawnPathCosts))) { continue; } #if DEBUG calcGrid[neighIndex].timesPopped = 0; #endif #region heuristic PfProfilerBeginSample("Heuristic"); switch (mode) { case HeuristicMode.Vanilla: h = heuristicStrength * (Math.Abs(neighX - destinationX) + Math.Abs(neighZ - destinationZ)); break; case HeuristicMode.AdmissableOctile: { var dx = Math.Abs(neighX - destinationX); var dy = Math.Abs(neighZ - destinationZ); h = moveTicksCardinal * (dx + dy) + (moveTicksDiagonal - 2 * moveTicksCardinal) * Math.Min(dx, dy); } break; case HeuristicMode.Better: if (canPassAnything) { var dx = Math.Abs(neighX - destinationX); var dy = Math.Abs(neighZ - destinationZ); h = heuristicStrength * (moveTicksCardinal * (dx + dy) + (moveTicksDiagonal - 2 * moveTicksCardinal) * Math.Min(dx, dy)); } else { h = regionCost.GetPathCostToRegion(neighIndex); } break; } calcGrid[neighIndex].heuristicCost = h; #if PATHMAX calcGrid[neighIndex].originalHeuristicCost = h; #endif PfProfilerEndSample(); #endregion } if (calcGrid[neighIndex].perceivedPathCost < 10000) { neighIndexes[i] = neighIndex; } if (mode == HeuristicMode.Better && (calcGrid[neighIndex].status == statusOpenValue && Math.Max(i > 3 ? (int)(calcGrid[curIndex].perceivedPathCost * diagonalPerceivedCostWeight) + moveTicksDiagonal : calcGrid[curIndex].perceivedPathCost + moveTicksCardinal, 1) + calcGrid[neighIndex].knownCost < calcGrid[curIndex].knownCost)) { calcGrid[curIndex].parentIndex = neighIndex; calcGrid[curIndex].knownCost = Math.Max(i > 3 ? (int)(calcGrid[curIndex].perceivedPathCost * diagonalPerceivedCostWeight) + moveTicksDiagonal : calcGrid[curIndex].perceivedPathCost + moveTicksCardinal, 1) + calcGrid[neighIndex].knownCost; } } #region BPMX Best H #if PATHMAX PfProfilerBeginSample("BPMX Best H"); int bestH = calcGrid[curIndex].heuristicCost; if (mode == HeuristicMode.Better && pathmaxEnabled) { for (int i = 0; i < 8; i++) { neighIndex = neighIndexes[i]; if (neighIndex < 0) { continue; } bestH = Math.Max(bestH, calcGrid[neighIndex].heuristicCost - (calcGrid[curIndex].perceivedPathCost + (i > 3 ? moveTicksDiagonal : moveTicksCardinal))); } } //Pathmax Rule 3: set the current node heuristic to the best value of all connected nodes calcGrid[curIndex].heuristicCost = bestH; PfProfilerEndSample(); #endif #endregion #region Updating open list for (int i = 0; i < 8; i++) { neighIndex = neighIndexes[i]; if (neighIndex < 0) { continue; } if (calcGrid[neighIndex].status == statusClosedValue && (canPassAnything || mode != HeuristicMode.Better)) { continue; } //When path costs are significantly higher than move costs (e.g. snowy ice, or outside of allowed areas), //small differences in the weighted heuristic overwhelm the added cost of diagonal movement, so nodes //can often be visited in unnecessary zig-zags, causing lots of nodes to be reopened later, and weird looking //paths if they are not revisited. Weighting the diagonal path cost slightly counteracts this behavior, and //should result in natural looking paths when it does cause suboptimal behavior var thisDirEdgeCost = (i > 3 ? (int)(calcGrid[neighIndex].perceivedPathCost * diagonalPerceivedCostWeight) + moveTicksDiagonal : calcGrid[neighIndex].perceivedPathCost + moveTicksCardinal); //var thisDirEdgeCost = calcGrid[neighIndex].perceivedPathCost + (i > 3 ? moveTicksDiagonal : moveTicksCardinal); //Some mods can result in negative path costs. That works well enough with Vanilla, since it won't revisit closed nodes, but when we do, it's an infinite loop. thisDirEdgeCost = (ushort)Math.Max(thisDirEdgeCost, 1); neighCostThroughCur = thisDirEdgeCost + calcGrid[curIndex].knownCost; #if PATHMAX //Pathmax Rule 1 int nodeH = (mode == HeuristicMode.Better && pathmaxEnabled) ? Math.Max(calcGrid[neighIndex].heuristicCost, bestH - thisDirEdgeCost) : calcGrid[neighIndex].heuristicCost; #endif if (calcGrid[neighIndex].status == statusClosedValue || calcGrid[neighIndex].status == statusOpenValue) { #if PATHMAX bool needsUpdate = false; #endif int minReopenGain = 0; if (calcGrid[neighIndex].status == statusOpenValue) { #if PATHMAX needsUpdate = nodeH > calcGrid[neighIndex].heuristicCost; #endif } else { //Don't reopen closed nodes if the path cost difference isn't large enough to justify it; otherwise there can be cascades of revisiting the same nodes over and over for tiny path improvements each time //Increasing the threshold as more cells get reopened further helps prevent cascades minReopenGain = moveTicksCardinal + closedCellsReopened / 5; if (pawnPathCosts.area?[neighIndex] == false) { minReopenGain *= 10; } } #if PATHMAX calcGrid[neighIndex].heuristicCost = nodeH; #endif if (!(neighCostThroughCur + minReopenGain < calcGrid[neighIndex].knownCost)) { #if PATHMAX if (needsUpdate) //if the heuristic cost was increased for an open node, we need to adjust its spot in the queue { var neighCell = cellIndices.IndexToCell(neighIndex); var edgeCost = Math.Max(calcGrid[neighIndex].parentX != neighCell.x && calcGrid[neighIndex].parentZ != neighCell.z ? (int)(calcGrid[neighIndex].perceivedPathCost * diagonalPercievedCostWeight) + moveTicksDiagonal : calcGrid[neighIndex].perceivedPathCost + moveTicksCardinal, 1); openList.PushOrUpdate(new CostNode(neighIndex, calcGrid[neighIndex].knownCost - edgeCost + (int)Math.Ceiling((edgeCost + nodeH) * regionHeuristicWeight.Evaluate(calcGrid[neighIndex].knownCost)))); } #endif continue; } if (calcGrid[neighIndex].status == statusClosedValue) { closedCellsReopened++; } } //else //{ // DebugFlash(cellIndices.IndexToCell(neighIndex), 0.2f, $"\n\n{neighCostThroughCur} | {nodeH}\n{calcGrid[curIndex].knownCost + (int)Math.Ceiling((nodeH + thisDirEdgeCost) * regionHeuristicWeight.Evaluate(calcGrid[curIndex].knownCost))}"); //} calcGrid[neighIndex].parentIndex = curIndex; calcGrid[neighIndex].knownCost = neighCostThroughCur; calcGrid[neighIndex].status = statusOpenValue; #if PATHMAX calcGrid[neighIndex].heuristicCost = nodeH; #endif PfProfilerBeginSample("Push Open"); openList.PushOrUpdate(new CostNode(neighIndex, calcGrid[curIndex].knownCost + (int)Math.Ceiling((calcGrid[neighIndex].heuristicCost + thisDirEdgeCost) * regionHeuristicWeight.Evaluate(calcGrid[curIndex].knownCost)))); debug_totalOpenListCount++; PfProfilerEndSample(); } #endregion PfProfilerEndSample(); closedCellCount++; calcGrid[curIndex].status = statusClosedValue; } } if (!debug_pathFailMessaged) { string text = pawn?.CurJob?.ToString() ?? "null"; string text2 = pawn?.Faction?.ToString() ?? "null"; Log.Warning(string.Concat(pawn, " pathing from ", start, " to ", dest, " ran out of cells to process.\nJob:", text, "\nFaction: ", text2)); debug_pathFailMessaged = true; } PfProfilerEndSample(); return(PawnPath.NotFound); }
private static bool CanReach(Thing searcher, Thing target, bool canBash) { Pawn pawn = searcher as Pawn; if (pawn != null) { if (!pawn.CanReach(target, PathEndMode.Touch, Danger.Some, canBash, TraverseMode.ByPawn)) { return(false); } } else { TraverseMode mode = (TraverseMode)(canBash ? 1 : 2); if (!searcher.Map.reachability.CanReach(searcher.Position, target, PathEndMode.Touch, TraverseParms.For(mode, Danger.Deadly, false))) { return(false); } } return(true); }
private static Thing FindClosestReachable(Pawn p, Predicate <Thing> validator) { return(GenClosest.ClosestThingReachable(p.Position, p.Map, ThingRequest.ForGroup(ThingRequestGroup.HaulableEver), PathEndMode.Touch, TraverseParms.For(p, Danger.Deadly, TraverseMode.ByPawn, false), 9999f, validator, null, 0, -1, false, RegionType.Set_Passable, false)); }
public static Building_BioReactor FindBioReactorFor(Pawn p, Pawn traveler, bool ignoreOtherReservations = false) { IEnumerable <ThingDef> enumerable = from def in DefDatabase <ThingDef> .AllDefs where typeof(Building_BioReactor).IsAssignableFrom(def.thingClass) select def; foreach (ThingDef singleDef in enumerable) { Building_BioReactor building_BioReactor = (Building_BioReactor)GenClosest.ClosestThingReachable(p.Position, p.Map, ThingRequest.ForDef(singleDef), PathEndMode.InteractionCell, TraverseParms.For(traveler, Danger.Deadly, TraverseMode.ByPawn, false), 9999f, delegate(Thing x) { bool result; if (!((Building_BioReactor)x).HasAnyContents) { Pawn traveler2 = traveler; LocalTargetInfo target = x; bool ignoreOtherReservations2 = ignoreOtherReservations; result = traveler2.CanReserve(target, 1, -1, null, ignoreOtherReservations2); } else { result = false; } return(result); }, null, 0, -1, false, RegionType.Set_Passable, false); if (building_BioReactor != null && !building_BioReactor.forbiddable.Forbidden) { if ((p.BodySize <= ((BioReactorDef)(building_BioReactor.def)).bodySizeMax) && (p.BodySize >= ((BioReactorDef)(building_BioReactor.def)).bodySizeMin)) { return(building_BioReactor); } } } return(null); }
public override void CompTick() { base.CompTick(); if (AlphaAnimalsEvents_Settings.flagHelixienCorpseEffect) { tickCounter++; if (tickCounter > Props.tickInterval) { Pawn pawn = this.parent as Pawn; if (pawn.Map != null) { CellRect rect = GenAdj.OccupiedRect(pawn.Position, pawn.Rotation, IntVec2.One); rect = rect.ExpandedBy(Props.radius); foreach (IntVec3 current in rect.Cells) { if (current.InBounds(pawn.Map)) { HashSet <Thing> hashSet = new HashSet <Thing>(current.GetThingList(pawn.Map)); if (hashSet != null) { foreach (Thing thingInCell in hashSet) { Corpse corpse = thingInCell as Corpse; if (corpse != null) { if (corpse.InnerPawn.def.race.IsFlesh) { corpse.HitPoints -= 5; pawn.needs.food.CurLevel += Props.nutritionGained; if ((pawn.Faction == Faction.OfPlayer) && (corpse.InnerPawn.def.race.Humanlike)) { pawn.health.AddHediff(HediffDef.Named("AA_CorpseFeast")); } CompRottable compRottable = corpse.TryGetComp <CompRottable>(); if (compRottable.Stage == RotStage.Fresh) { compRottable.RotProgress += 100000; } if (corpse.HitPoints < 0) { corpse.Destroy(DestroyMode.Vanish); for (int i = 0; i < 20; i++) { IntVec3 c; CellFinder.TryFindRandomReachableCellNear(pawn.Position, pawn.Map, 2, TraverseParms.For(TraverseMode.NoPassClosedDoors, Danger.Deadly, false), null, null, out c); FilthMaker.TryMakeFilth(c, pawn.Map, ThingDefOf.Filth_CorpseBile, pawn.LabelIndefinite(), 1, FilthSourceFlags.None); SoundDef.Named(Props.corpseSound).PlayOneShot(new TargetInfo(pawn.Position, pawn.Map, false)); } } FilthMaker.TryMakeFilth(current, pawn.Map, ThingDefOf.Filth_CorpseBile, pawn.LabelIndefinite(), 1, FilthSourceFlags.None); flagOnce = true; } } } } } if (flagOnce) { flagOnce = false; break; } } } tickCounter = 0; } } }
private static bool TryFindBestBillIngredients(Pawn pawn, Building_CokeFurnace billGiver, List <ThingCount> chosen) { chosen.Clear(); newRelevantThings.Clear(); if (billGiver.SelectedRecipe.ingredients.Count == 0) { return(true); } IntVec3 rootCell = GetBillGiverRootCell(billGiver, pawn); Region rootReg = rootCell.GetRegion(pawn.Map); if (rootReg == null) { return(false); } MakeIngredientsListInProcessingOrder(ingredientsOrdered, billGiver); relevantThings.Clear(); processedThings.Clear(); bool foundAll = false; Predicate <Thing> baseValidator = (Thing t) => t.Spawned && !t.IsForbidden(pawn) && (float)(t.Position - billGiver.Position).LengthHorizontalSquared < 9999f && pawn.CanReserve(t); TraverseParms traverseParams = TraverseParms.For(pawn); RegionEntryPredicate entryCondition = (Region from, Region r) => r.Allows(traverseParams, isDestination: false); int adjacentRegionsAvailable = rootReg.Neighbors.Count((Region region) => entryCondition(rootReg, region)); int regionsProcessed = 0; processedThings.AddRange(relevantThings); RegionProcessor regionProcessor = delegate(Region r) { List <Thing> list = r.ListerThings.ThingsMatching(ThingRequest.ForGroup(ThingRequestGroup.HaulableEver)); for (int i = 0; i < list.Count; i++) { Thing thing = list[i]; if (!processedThings.Contains(thing) && ReachabilityWithinRegion.ThingFromRegionListerReachable(thing, r, PathEndMode.ClosestTouch, pawn) && baseValidator(thing) && !thing.def.IsMedicine) { newRelevantThings.Add(thing); processedThings.Add(thing); } } regionsProcessed++; if (newRelevantThings.Count > 0 && regionsProcessed > adjacentRegionsAvailable) { Comparison <Thing> comparison = delegate(Thing t1, Thing t2) { float num = (t1.Position - rootCell).LengthHorizontalSquared; float value = (t2.Position - rootCell).LengthHorizontalSquared; return(num.CompareTo(value)); }; newRelevantThings.Sort(comparison); relevantThings.AddRange(newRelevantThings); newRelevantThings.Clear(); if (TryFindBestBillIngredientsInSet(relevantThings, billGiver, chosen)) { foundAll = true; return(true); } } return(false); }; RegionTraverser.BreadthFirstTraverse(rootReg, entryCondition, regionProcessor, 99999); relevantThings.Clear(); newRelevantThings.Clear(); processedThings.Clear(); ingredientsOrdered.Clear(); return(foundAll); }
private static bool TryRandomNonOccupiedClosewalkCellNear(IntVec3 root, Map map, int radius, out IntVec3 result) { return(CellFinder.TryFindRandomReachableCellNear(root, map, (float)radius, TraverseParms.For(TraverseMode.NoPassClosedDoors, Danger.Deadly, false), (Predicate <IntVec3>)((IntVec3 c) => c.Standable(map) && c.GetFirstPawn(map) == null), (Predicate <Region>)null, out result, 999999)); }
private List <IntVec3> RefineEndcap(List <IntVec3> input, Map map) { float[] array = new float[endcapSamples.Length]; for (int i = 0; i < endcapSamples.Length; i++) { int index = Mathf.RoundToInt((float)input.Count * endcapSamples[i]); PawnPath pawnPath = map.pathFinder.FindPath(input[index], input[input.Count - 1], TraverseParms.For(TraverseMode.NoPassClosedDoorsOrWater)); if (pawnPath == PawnPath.NotFound) { pawnPath = map.pathFinder.FindPath(input[index], input[input.Count - 1], TraverseParms.For(TraverseMode.NoPassClosedDoors)); } if (pawnPath == PawnPath.NotFound) { pawnPath = map.pathFinder.FindPath(input[index], input[input.Count - 1], TraverseParms.For(TraverseMode.PassAllDestroyableThingsNotWater)); } if (pawnPath == PawnPath.NotFound) { pawnPath = map.pathFinder.FindPath(input[index], input[input.Count - 1], TraverseParms.For(TraverseMode.PassAllDestroyableThings)); } if (pawnPath != null && pawnPath != PawnPath.NotFound) { array[i] = pawnPath.TotalCost; } pawnPath.ReleaseToPool(); } float num = 0f; int num2 = 0; IntVec3 start = IntVec3.Invalid; for (int j = 0; j < 2; j++) { IntVec3 facingCell = new Rot4(j).FacingCell; IntVec3 intVec = input[input.Count - 1]; bool flag = true; if (Mathf.Abs(intVec.x * facingCell.x) > 5 && Mathf.Abs(intVec.x * facingCell.x - map.Size.x) > 5) { flag = false; } if (Mathf.Abs(intVec.z * facingCell.z) > 5 && Mathf.Abs(intVec.z * facingCell.z - map.Size.z) > 5) { flag = false; } if (!flag) { continue; } for (int k = 0; k < endcapSamples.Length; k++) { if (array[k] == 0f) { continue; } int num3 = Mathf.RoundToInt((float)input.Count * endcapSamples[k]); IntVec3 intVec2 = input[num3]; if (facingCell.x != 0) { intVec2.x = intVec.x; } else if (facingCell.z != 0) { intVec2.z = intVec.z; } PawnPath pawnPath2 = map.pathFinder.FindPath(input[num3], input[input.Count - 1], TraverseParms.For(TraverseMode.NoPassClosedDoors)); if (pawnPath2 == PawnPath.NotFound) { pawnPath2 = map.pathFinder.FindPath(input[num3], input[input.Count - 1], TraverseParms.For(TraverseMode.PassAllDestroyableThings)); } if (pawnPath2 != PawnPath.NotFound) { float num4 = array[k] / pawnPath2.TotalCost; if (num4 > num) { num = num4; num2 = num3; start = intVec2; } pawnPath2.ReleaseToPool(); } } } input = new List <IntVec3>(input); if ((double)num > 1.75) { using (PawnPath pawnPath3 = map.pathFinder.FindPath(start, input[num2], TraverseParms.For(TraverseMode.NoPassClosedDoors))) { input.RemoveRange(num2, input.Count - num2); input.AddRange(pawnPath3.NodesReversed); return(input); } } return(input); }
protected override Job TryGiveJob(Pawn pawn) { if (lastTickTantrumed > Find.TickManager.TicksGame - 2000 || Rand.Value < 0.5f) { return(null); } Predicate <Thing> validator = delegate(Thing t) { return(!t.IsBurning() && t.def.useHitPoints); }; Building building = (Building)GenClosest.ClosestThingReachable(pawn.Position, pawn.Map, ThingRequest.ForGroup(ThingRequestGroup.BuildingArtificial), PathEndMode.Touch, TraverseParms.For(TraverseMode.ByPawn, Danger.Deadly, true), 9999f, validator, null, -1, false); if (building != null) { lastTickTantrumed = Find.TickManager.TicksGame; int maxNumMeleeAttacks = Rand.RangeInclusive(10, 30) + (Rand.Value < 0.1f ? Rand.RangeInclusive(10, 30) : 0); pawn.guilt.Notify_Guilty(); return(new Job(JobDefOf.AttackMelee, building) { maxNumMeleeAttacks = maxNumMeleeAttacks, expiryInterval = 50000, canBash = true }); } return(null); }
private IntVec3 FindRoadExitCell(Map map, float angle, IntVec3 crossroads, ref RoadPathingDef pathingDef) { Predicate <IntVec3> tileValidator = delegate(IntVec3 pos) { foreach (IntVec3 item in GenRadial.RadialCellsAround(pos, 8f, useCenter: true)) { if (item.InBounds(map) && item.GetTerrain(map).IsWater) { return(false); } } return(true); }; IntVec3 result; for (float validAngleSpan2 = 10f; validAngleSpan2 < 90f; validAngleSpan2 += 10f) { Predicate <IntVec3> angleValidator2 = (IntVec3 pos) => GenGeo.AngleDifferenceBetween((pos - map.Center).AngleFlat, angle) < validAngleSpan2; if (CellFinder.TryFindRandomEdgeCellWith((IntVec3 x) => angleValidator2(x) && tileValidator(x) && map.reachability.CanReach(crossroads, x, PathEndMode.OnCell, TraverseParms.For(TraverseMode.NoPassClosedDoors)), map, 0f, out result)) { return(result); } } if (pathingDef == RoadPathingDefOf.Avoid) { pathingDef = RoadPathingDefOf.Bulldoze; } for (float validAngleSpan = 10f; validAngleSpan < 90f; validAngleSpan += 10f) { Predicate <IntVec3> angleValidator = (IntVec3 pos) => GenGeo.AngleDifferenceBetween((pos - map.Center).AngleFlat, angle) < validAngleSpan; if (CellFinder.TryFindRandomEdgeCellWith((IntVec3 x) => angleValidator(x) && tileValidator(x) && map.reachability.CanReach(crossroads, x, PathEndMode.OnCell, TraverseParms.For(TraverseMode.PassAllDestroyableThings)), map, 0f, out result)) { return(result); } } Log.Error($"Can't find exit from map from {crossroads} to angle {angle}"); return(IntVec3.Invalid); }
protected override bool CanScatterAt(IntVec3 c, Map map) { return(map.reachability.CanReachMapEdge(c, TraverseParms.For(TraverseMode.PassDoors, Danger.Deadly, false))); }
private Thing FindDrugFor(Pawn pawn, Need_Chemical need) { Hediff_Addiction addictionHediff = need.AddictionHediff; Thing result; if (addictionHediff == null) { result = null; } else { ThingOwner <Thing> innerContainer = pawn.inventory.innerContainer; for (int i = 0; i < innerContainer.Count; i++) { if (this.DrugValidator(pawn, addictionHediff, innerContainer[i])) { return(innerContainer[i]); } } result = GenClosest.ClosestThingReachable(pawn.Position, pawn.Map, ThingRequest.ForGroup(ThingRequestGroup.Drug), PathEndMode.ClosestTouch, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.ByPawn, false), 9999f, (Thing x) => this.DrugValidator(pawn, addictionHediff, x), null, 0, -1, false, RegionType.Set_Passable, false); } return(result); }
public static Thing FindThingToHaul(Pawn p, Lord lord) { neededItems.Clear(); List <TransferableOneWay> transferables = ((LordJob_FormAndSendCaravan)lord.LordJob).transferables; for (int i = 0; i < transferables.Count; i++) { TransferableOneWay transferableOneWay = transferables[i]; if (CountLeftToTransfer(p, transferableOneWay, lord) > 0) { for (int j = 0; j < transferableOneWay.things.Count; j++) { neededItems.Add(transferableOneWay.things[j]); } } } if (!neededItems.Any()) { return(null); } Thing result = GenClosest.ClosestThingReachable(p.Position, p.Map, ThingRequest.ForGroup(ThingRequestGroup.HaulableEver), PathEndMode.Touch, TraverseParms.For(p), 9999f, (Thing x) => neededItems.Contains(x) && p.CanReserve(x)); neededItems.Clear(); return(result); }
public static Toil CarryIngestibleToChewSpot(Pawn pawn, TargetIndex ingestibleInd) { Toil toil = new Toil(); toil.initAction = delegate { Pawn actor = toil.actor; IntVec3 intVec = IntVec3.Invalid; Thing thing = null; Thing thing2 = actor.CurJob.GetTarget(ingestibleInd).Thing; Predicate <Thing> baseChairValidator = delegate(Thing t) { if (t.def.building == null || !t.def.building.isSittable) { return(false); } if (t.IsForbidden(pawn)) { return(false); } if (!actor.CanReserve(t)) { return(false); } if (!t.IsSociallyProper(actor)) { return(false); } if (t.IsBurning()) { return(false); } if (t.HostileTo(pawn)) { return(false); } bool flag = false; for (int i = 0; i < 4; i++) { IntVec3 c = t.Position + GenAdj.CardinalDirections[i]; Building edifice = c.GetEdifice(t.Map); if (edifice != null && edifice.def.surfaceType == SurfaceType.Eat) { flag = true; break; } } if (!flag) { return(false); } return(true); }; if (thing2.def.ingestible.chairSearchRadius > 0f) { thing = GenClosest.ClosestThingReachable(actor.Position, actor.Map, ThingRequest.ForGroup(ThingRequestGroup.BuildingArtificial), PathEndMode.OnCell, TraverseParms.For(actor), thing2.def.ingestible.chairSearchRadius, (Thing t) => baseChairValidator(t) && t.Position.GetDangerFor(pawn, t.Map) == Danger.None); } if (thing == null) { intVec = RCellFinder.SpotToChewStandingNear(actor, actor.CurJob.GetTarget(ingestibleInd).Thing); Danger chewSpotDanger = intVec.GetDangerFor(pawn, actor.Map); if (chewSpotDanger != Danger.None) { thing = GenClosest.ClosestThingReachable(actor.Position, actor.Map, ThingRequest.ForGroup(ThingRequestGroup.BuildingArtificial), PathEndMode.OnCell, TraverseParms.For(actor), thing2.def.ingestible.chairSearchRadius, (Thing t) => baseChairValidator(t) && (int)t.Position.GetDangerFor(pawn, t.Map) <= (int)chewSpotDanger); } } if (thing != null) { intVec = thing.Position; actor.Reserve(thing, actor.CurJob); } actor.Map.pawnDestinationReservationManager.Reserve(actor, actor.CurJob, intVec); actor.pather.StartPath(intVec, PathEndMode.OnCell); }; toil.defaultCompleteMode = ToilCompleteMode.PatherArrival; return(toil); }
/// <summary> /// Figures out the best location to use this Ability at. Default implementation returns the enemy target, closest ally or the caster. /// </summary> /// <param name="abilityDef">Ability Def for the AI.</param> /// <param name="pawn">Pawn to take in account.</param> /// <returns>Targeting location or Pawn.</returns> public virtual LocalTargetInfo TargetAbilityFor(AbilityAIDef abilityDef, Pawn pawn) { if (abilityDef.usedOnCaster) { return(pawn); } else if (abilityDef.canTargetAlly) { return(GenClosest.ClosestThingReachable(pawn.Position, pawn.Map, ThingRequest.ForGroup(ThingRequestGroup.Pawn), Verse.AI.PathEndMode.OnCell, TraverseParms.For(TraverseMode.NoPassClosedDoors), abilityDef.maxRange, thing => AbilityUtility.AreAllies(pawn, thing))); } else if (pawn.mindState.enemyTarget != null && pawn.mindState.enemyTarget is Pawn targetPawn) { if (!targetPawn.Dead) { return(pawn.mindState.enemyTarget); } } else { if (pawn.mindState.enemyTarget != null && !(pawn.mindState.enemyTarget is Corpse)) { return(pawn.mindState.enemyTarget); } } return(null); }
public static Thing findAmmo(Pawn pawn, AERIALSYSTEM aeriel) { StorageSettings allowed = pawn.IsColonist ? aeriel.gun.TryGetComp <AERIALChangeableProjectile>().allowedShellsSettings : null; Predicate <Thing> validator = (Thing t) => !t.IsForbidden(pawn) && pawn.CanReserve(t, 10, 1, null, false) && (allowed == null || allowed.AllowedToAccept(t)); return(GenClosest.ClosestThingReachable(pawn.Position, pawn.Map, ThingRequest.ForGroup(ThingRequestGroup.Shell), PathEndMode.OnCell, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.ByPawn, false), 40f, validator, null, 0, -1, false, RegionType.Set_Passable, false)); }
public static Toil CarryIngestibleToChewSpot(Pawn pawn, TargetIndex ingestibleInd) { Toil toil = new Toil(); toil.initAction = delegate { Pawn actor = toil.actor; IntVec3 cell2 = IntVec3.Invalid; Thing thing = null; Thing thing2 = actor.CurJob.GetTarget(ingestibleInd).Thing; Predicate <Thing> baseChairValidator = delegate(Thing t) { if (t.def.building == null || !t.def.building.isSittable) { return(false); } if (!TryFindFreeSittingSpotOnThing(t, out var _)) { return(false); } if (t.IsForbidden(pawn)) { return(false); } if (!actor.CanReserve(t)) { return(false); } if (!t.IsSociallyProper(actor)) { return(false); } if (t.IsBurning()) { return(false); } if (t.HostileTo(pawn)) { return(false); } bool flag = false; for (int i = 0; i < 4; i++) { Building edifice = (t.Position + GenAdj.CardinalDirections[i]).GetEdifice(t.Map); if (edifice != null && edifice.def.surfaceType == SurfaceType.Eat) { flag = true; break; } } return(flag ? true : false); }; if (thing2.GetIngestibleProperties().chairSearchRadius > 0f) { thing = GenClosest.ClosestThingReachable(actor.Position, actor.Map, ThingRequest.ForGroup(ThingRequestGroup.BuildingArtificial), PathEndMode.OnCell, TraverseParms.For(actor), thing2.GetIngestibleProperties().chairSearchRadius, (Thing t) => baseChairValidator(t) && t.Position.GetDangerFor(pawn, t.Map) == Danger.None); } if (thing == null) { cell2 = RCellFinder.SpotToChewStandingNear(actor, actor.CurJob.GetTarget(ingestibleInd).Thing, (IntVec3 c) => actor.CanReserveSittableOrSpot(c)); Danger chewSpotDanger = cell2.GetDangerFor(pawn, actor.Map); if (chewSpotDanger != Danger.None) { thing = GenClosest.ClosestThingReachable(actor.Position, actor.Map, ThingRequest.ForGroup(ThingRequestGroup.BuildingArtificial), PathEndMode.OnCell, TraverseParms.For(actor), thing2.GetIngestibleProperties().chairSearchRadius, (Thing t) => baseChairValidator(t) && (int)t.Position.GetDangerFor(pawn, t.Map) <= (int)chewSpotDanger); } } if (thing != null && !TryFindFreeSittingSpotOnThing(thing, out cell2)) { Log.Error("Could not find sitting spot on chewing chair! This is not supposed to happen - we looked for a free spot in a previous check!"); } actor.ReserveSittableOrSpot(cell2, actor.CurJob); actor.Map.pawnDestinationReservationManager.Reserve(actor, actor.CurJob, cell2); actor.pather.StartPath(cell2, PathEndMode.OnCell); bool TryFindFreeSittingSpotOnThing(Thing t, out IntVec3 cell) { foreach (IntVec3 item in t.OccupiedRect()) { if (actor.CanReserveSittableOrSpot(item)) { cell = item; return(true); } } cell = default(IntVec3); return(false); } }; toil.defaultCompleteMode = ToilCompleteMode.PatherArrival; return(toil); }
//Wrapper function to run extra testing/logging code. public PawnPath FindPath(IntVec3 start, LocalTargetInfo dest, TraverseParms traverseParms, PathEndMode peMode = PathEndMode.OnCell) { #if DEBUG if (traverseParms.pawn != null) { Log.Message($"Pathfinding times for pawn {traverseParms.pawn}, mode: {traverseParms.mode}\n Move speed: {traverseParms.pawn.TicksPerMoveCardinal}, {traverseParms.pawn.TicksPerMoveDiagonal}"); } disableDebugFlash = true; //disable debug flash during timing tests var sw = new Stopwatch(); PawnPath temp = null; var vanillaCost = float.MaxValue - 1000; diagonalPerceivedCostWeight = 1.0f; sw.Start(); temp = FindPathInner(start, dest, traverseParms, peMode, HeuristicMode.Vanilla); sw.Stop(); Log.Message("~~ Vanilla ~~ " + sw.ElapsedTicks + " ticks, " + debug_openCellsPopped + " open cells popped, " + temp.TotalCost + " path cost!"); vanillaCost = temp.TotalCost; temp.Dispose(); //sw.Reset(); //sw.Start(); //temp = FindPathInner(start, dest, traverseParms, peMode, HeuristicMode.AdmissableOctile); //sw.Stop(); //Log.Message("~~ Admissable Octile ~~ " + sw.ElapsedTicks + " ticks, " + debug_openCellsPopped + " open cells popped, " + temp.TotalCost + " path cost!"); //var optimal = temp.TotalCost; //temp.Dispose(); try { diagonalPerceivedCostWeight = diagonalCostWeightSetting; sw.Reset(); sw.Start(); temp = FindPathInner(start, dest, traverseParms, peMode, HeuristicMode.Better); sw.Stop(); Log.Message("~~ Better ~~ " + sw.ElapsedTicks + " ticks, " + debug_openCellsPopped + " open cells popped, " + temp.TotalCost + " path cost! (" /*+ sw.ElapsedMilliseconds*/ + "ms)"); } catch { if (Current.ProgramState == ProgramState.Playing) { PathDataLog.SaveFromPathCall(this.map, start, dest, traverseParms, peMode); } } //var sb = new StringBuilder(); //foreach (var pathmax in new [] {false, true}) //{ // pathmaxEnabled = pathmax; // foreach (var weight in new[] {false, true}) // { // weightEnabled = weight; // sw.Reset(); // sw.Start(); // temp = FindPathInner(start, dest, traverseParms, peMode); // sw.Stop(); // sb.AppendLine($"pathmax: {pathmax}, weight: {weight}, pops: {debug_openCellsPopped}, pathcost: {temp.TotalCost}, elapsed: {sw.ElapsedTicks}"); // temp.Dispose(); // } //} //Log.Message(sb.ToString()); //Log.Message("\t Distance Map Pops: " + RegionLinkDijkstra.nodes_popped); //Log.Message("\t Total open cells added: " + debug_totalOpenListCount); //Log.Message("\t Closed cells reopened: " + closedCellsReopened); //Log.Message($"\t Total Heuristic Estimate {debug_totalHeuristicCostEstimate}, off by {((temp.TotalCost / debug_totalHeuristicCostEstimate) - 1.0f).ToStringPercent()}"); temp?.Dispose(); disableDebugFlash = false; #endif #if PFPROFILE if (!hasRunOnce) { disableDebugFlash = true; var jitRun = FindPathInner(start, dest, traverseParms, peMode, HeuristicMode.Better); jitRun.Dispose(); hasRunOnce = true; disableDebugFlash = false; } sws.Clear(); #endif var result = FindPathInner(start, dest, traverseParms, peMode, HeuristicMode.Better); #if PFPROFILE var profsb = new StringBuilder(); foreach (var pfsw in sws) { profsb.AppendLine("SW " + pfsw.Key + ": " + pfsw.Value.ElapsedTicks.ToString("##,#") + " ticks."); } Log.Message(profsb.ToString()); #endif #if DEBUG if (Current.ProgramState == ProgramState.Playing) { if (debug_openCellsPopped > 2500 || (vanillaCost + 100) < result.TotalCost || result == PawnPath.NotFound) { PathDataLog.SaveFromPathCall(this.map, start, dest, traverseParms, peMode); } } #endif return(result); }
public static IAttackTarget BestAttackTarget(IAttackTargetSearcher searcher, TargetScanFlags flags, Predicate <Thing> validator = null, float minDist = 0f, float maxDist = 9999f, IntVec3 locus = default(IntVec3), float maxTravelRadiusFromLocus = 3.40282347E+38f, bool canBash = false) { Thing searcherThing = searcher.Thing; Pawn searcherPawn = searcher as Pawn; Verb verb = searcher.CurrentEffectiveVerb; if (verb == null) { Log.Error("BestAttackTarget with " + searcher + " who has no attack verb."); return(null); } bool onlyTargetMachines = verb != null && verb.IsEMP(); float minDistanceSquared = minDist * minDist; float num = maxTravelRadiusFromLocus + verb.verbProps.range; float maxLocusDistSquared = num * num; Func <IntVec3, bool> losValidator = null; if ((flags & TargetScanFlags.LOSBlockableByGas) != 0) { losValidator = delegate(IntVec3 vec3) { Gas gas = vec3.GetGas(searcherThing.Map); return(gas == null || !gas.def.gas.blockTurretTracking); }; } Predicate <IAttackTarget> innerValidator = delegate(IAttackTarget t) { Thing thing = t.Thing; if (t == searcher) { return(false); } if (minDistanceSquared > 0.0 && (float)(searcherThing.Position - thing.Position).LengthHorizontalSquared < minDistanceSquared) { return(false); } if (maxTravelRadiusFromLocus < 9999.0 && (float)(thing.Position - locus).LengthHorizontalSquared > maxLocusDistSquared) { return(false); } if (!searcherThing.HostileTo(thing)) { return(false); } if (validator != null && !validator(thing)) { return(false); } if ((flags & TargetScanFlags.NeedLOSToAll) != 0 && !searcherThing.CanSee(thing, losValidator)) { if (t is Pawn) { if ((flags & TargetScanFlags.NeedLOSToPawns) != 0) { return(false); } } else if ((flags & TargetScanFlags.NeedLOSToNonPawns) != 0) { return(false); } } if ((flags & TargetScanFlags.NeedThreat) != 0 && t.ThreatDisabled()) { return(false); } Pawn pawn2 = t as Pawn; if (onlyTargetMachines && pawn2 != null && pawn2.RaceProps.IsFlesh) { return(false); } if ((flags & TargetScanFlags.NeedNonBurning) != 0 && thing.IsBurning()) { return(false); } if (searcherThing.def.race != null && (int)searcherThing.def.race.intelligence >= 2) { CompExplosive compExplosive = thing.TryGetComp <CompExplosive>(); if (compExplosive != null && compExplosive.wickStarted) { return(false); } } if (thing.def.size.x == 1 && thing.def.size.z == 1) { if (thing.Position.Fogged(thing.Map)) { return(false); } } else { bool flag2 = false; CellRect.CellRectIterator iterator = thing.OccupiedRect().GetIterator(); while (!iterator.Done()) { if (iterator.Current.Fogged(thing.Map)) { iterator.MoveNext(); continue; } flag2 = true; break; } if (!flag2) { return(false); } } return(true); }; if (AttackTargetFinder.HasRangedAttack(searcher)) { AttackTargetFinder.tmpTargets.Clear(); AttackTargetFinder.tmpTargets.AddRange(searcherThing.Map.attackTargetsCache.GetPotentialTargetsFor(searcher)); if ((flags & TargetScanFlags.NeedReachable) != 0) { Predicate <IAttackTarget> oldValidator = innerValidator; innerValidator = ((IAttackTarget t) => oldValidator(t) && AttackTargetFinder.CanReach(searcherThing, t.Thing, canBash)); } bool flag = false; if (searcherThing.Faction != Faction.OfPlayer) { for (int i = 0; i < AttackTargetFinder.tmpTargets.Count; i++) { IAttackTarget attackTarget = AttackTargetFinder.tmpTargets[i]; if (attackTarget.Thing.Position.InHorDistOf(searcherThing.Position, maxDist) && innerValidator(attackTarget) && AttackTargetFinder.CanShootAtFromCurrentPosition(attackTarget, searcher, verb)) { flag = true; break; } } } IAttackTarget result; if (flag) { AttackTargetFinder.tmpTargets.RemoveAll((IAttackTarget x) => !x.Thing.Position.InHorDistOf(searcherThing.Position, maxDist) || !innerValidator(x)); result = AttackTargetFinder.GetRandomShootingTargetByScore(AttackTargetFinder.tmpTargets, searcher, verb); } else { Predicate <Thing> validator2 = ((flags & TargetScanFlags.NeedReachableIfCantHitFromMyPos) == TargetScanFlags.None || (flags & TargetScanFlags.NeedReachable) != 0) ? ((Predicate <Thing>)((Thing t) => innerValidator((IAttackTarget)t))) : ((Predicate <Thing>)((Thing t) => innerValidator((IAttackTarget)t) && (AttackTargetFinder.CanReach(searcherThing, t, canBash) || AttackTargetFinder.CanShootAtFromCurrentPosition((IAttackTarget)t, searcher, verb)))); result = (IAttackTarget)GenClosest.ClosestThing_Global(searcherThing.Position, AttackTargetFinder.tmpTargets, maxDist, validator2, null); } AttackTargetFinder.tmpTargets.Clear(); return(result); } if (searcherPawn != null && searcherPawn.mindState.duty != null && searcherPawn.mindState.duty.radius > 0.0 && !searcherPawn.InMentalState) { Predicate <IAttackTarget> oldValidator2 = innerValidator; innerValidator = delegate(IAttackTarget t) { if (!oldValidator2(t)) { return(false); } if (!t.Thing.Position.InHorDistOf(searcherPawn.mindState.duty.focus.Cell, searcherPawn.mindState.duty.radius)) { return(false); } return(true); }; } IntVec3 root = searcherThing.Position; Map map = searcherThing.Map; ThingRequest thingReq = ThingRequest.ForGroup(ThingRequestGroup.AttackTarget); PathEndMode peMode = PathEndMode.Touch; Pawn pawn = searcherPawn; Danger maxDanger = Danger.Deadly; bool canBash2 = canBash; TraverseParms traverseParams = TraverseParms.For(pawn, maxDanger, TraverseMode.ByPawn, canBash2); float maxDistance = maxDist; Predicate <Thing> validator3 = (Thing x) => innerValidator((IAttackTarget)x); int searchRegionsMax = (!(maxDist > 800.0)) ? 40 : (-1); IAttackTarget attackTarget2 = (IAttackTarget)GenClosest.ClosestThingReachable(root, map, thingReq, peMode, traverseParams, maxDistance, validator3, null, 0, searchRegionsMax, false, RegionType.Set_Passable, false); if (attackTarget2 != null && PawnUtility.ShouldCollideWithPawns(searcherPawn)) { IAttackTarget attackTarget3 = AttackTargetFinder.FindBestReachableMeleeTarget(innerValidator, searcherPawn, maxDist, canBash); if (attackTarget3 != null) { root = searcherPawn.Position - attackTarget2.Thing.Position; float lengthHorizontal = root.LengthHorizontal; float lengthHorizontal2 = (searcherPawn.Position - attackTarget3.Thing.Position).LengthHorizontal; if (Mathf.Abs(lengthHorizontal - lengthHorizontal2) < 50.0) { attackTarget2 = attackTarget3; } } } return(attackTarget2); }
private static Pawn FindPawnTarget(Pawn pawn) { Pawn victim = null; bool Predicate(Thing p) => p != null && p != pawn && p.Faction != pawn.Faction && ((Pawn)p).health.hediffSet.GetFirstHediffOfDef(PurpleIvyDefOf.PI_MaskingSprayHigh) == null; const float distance = 25f; victim = (Pawn)GenClosest.ClosestThingReachable(pawn.Position, pawn.Map, ThingRequest.ForGroup(ThingRequestGroup.Pawn), PathEndMode.Touch, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.PassDoors, false) , distance, Predicate); return(victim); }
private Job GetProductionBillJob(Pawn meeseeks, CompMeeseeksMemory memory, SavedJob savedJob, SavedTargetInfo jobTarget, ref JobAvailability jobAvailabilty) { Bill_Production bill = jobTarget.bill as Bill_Production; Job job = null; Logger.MessageFormat(this, "Checking for production bill job..."); if (bill.repeatMode == BillRepeatModeDefOf.RepeatCount && bill.repeatCount < 1) { bill.deleted = true; jobAvailabilty = JobAvailability.Complete; return(null); } else if (bill.repeatMode == BillRepeatModeDefOf.TargetCount) { // Might be here without a billgiver (after a save?) so try to set the current target if (jobTarget.Thing != null) { bill.billStack.billGiver = jobTarget.Thing as IBillGiver; } // Otherwise count them later I guess :P if (bill.Map != null) { int productCount = bill.recipe.WorkerCounter.CountProducts(bill); if (productCount >= bill.targetCount) { bill.deleted = true; jobAvailabilty = JobAvailability.Complete; return(null); } } } Logger.MessageFormat(this, "Checking workstations..."); bool workStationValid = (jobTarget.HasThing && !jobTarget.ThingDestroyed && meeseeks.CanReserve(jobTarget.Thing, 1, -1, null, false) && ((jobTarget.Thing as IBillGiver).CurrentlyUsableForBills() || (jobTarget.Thing as IBillGiver).UsableForBillsAfterFueling())); if (!workStationValid) { Logger.MessageFormat(this, "We think the workstation is invalid looking for new one"); List <Building> buildings = meeseeks.MapHeld.listerBuildings.allBuildingsColonist.Where(building => building is IBillGiver && savedJob.workGiverDef.fixedBillGiverDefs.Contains(building.def) && meeseeks.CanReserve(building, 1, -1, null, false) && ((building as IBillGiver).CurrentlyUsableForBills() || (building as IBillGiver).UsableForBillsAfterFueling())).ToList(); if (buildings.Count > 0) { Logger.MessageFormat(this, "Found new one"); buildings.Sort((a, b) => (int)(meeseeks.PositionHeld.DistanceTo(a.Position) - meeseeks.PositionHeld.DistanceTo(b.Position))); jobTarget.target = buildings[0]; workStationValid = true; } else { Logger.MessageFormat(this, "Found no alternate workstations..."); } } else { Logger.MessageFormat(this, "We think the workstation is valid..."); } if (workStationValid) { IBillGiver billGiver = jobTarget.Thing as IBillGiver; bill.billStack.billGiver = billGiver; Bill_ProductionWithUft bill_ProductionWithUft = bill as Bill_ProductionWithUft; if (bill_ProductionWithUft != null) { if (bill_ProductionWithUft.BoundUft != null) { if (bill_ProductionWithUft.BoundUft.Creator.kindDef == MeeseeksDefOf.MeeseeksKind && meeseeks.CanReserveAndReach(bill_ProductionWithUft.BoundUft, PathEndMode.Touch, Danger.Deadly)) { job = FinishUftJob(meeseeks, bill_ProductionWithUft.BoundUft, bill_ProductionWithUft, billGiver); } } else { Predicate <Thing> validator = (Thing t) => ((UnfinishedThing)t).Recipe == bill.recipe && ((UnfinishedThing)t).Creator.kindDef == MeeseeksDefOf.MeeseeksKind && ((UnfinishedThing)t).ingredients.TrueForAll((Thing x) => bill.IsFixedOrAllowedIngredient(x.def)) && meeseeks.CanReserve(t); UnfinishedThing unfinishedThing = (UnfinishedThing)GenClosest.ClosestThingReachable(meeseeks.Position, meeseeks.Map, ThingRequest.ForDef(bill.recipe.unfinishedThingDef), PathEndMode.InteractionCell, TraverseParms.For(meeseeks), 9999f, validator); if (unfinishedThing != null) { job = FinishUftJob(meeseeks, unfinishedThing, bill_ProductionWithUft, billGiver); } } } if (job == null) { List <ThingCount> chosenIngredients = new List <ThingCount>(); // Screw you I need this function bool result = (bool)typeof(WorkGiver_DoBill).GetMethod("TryFindBestBillIngredients", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, new object[] { bill, meeseeks, jobTarget.Thing, chosenIngredients }); if (result) { Job haulOffJob = null; job = WorkGiver_DoBill.TryStartNewDoBillJob(meeseeks, bill, billGiver, chosenIngredients, out haulOffJob); } } } if (job == null) { jobAvailabilty = JobAvailability.Delayed; } else { jobAvailabilty = JobAvailability.Available; } return(job); }
private static bool setup(IntVec3 s, LocalTargetInfo dest, TraverseParms traverseParms, PathEndMode peMode, Map map) { sMap = map; sMapW = map.Size.x; sMapH = map.Size.z; if (s.x < 0 || s.y < 0 || s.z < 0 || s.x >= sMapW || s.z >= sMapH) { #if DEBUG_LOG_ERROR Log.Error("Start point is out side of map:" + s); #endif return(true); } IntVec3 e = dest.Cell; if (e.x < 0 || e.y < 0 || e.z < 0 || e.x >= sMapW || e.z >= sMapH) { #if DEBUG_LOG_ERROR Log.Error("End point is out side of map:" + e); #endif return(true); } if (dest.HasThing && dest.Thing.Map != map) { #if DEBUG_LOG_ERROR Log.Error("Tartget thing is not this map:" + dest.Thing.ThingID); #endif return(true); } int w = (sMapW + NodeSetBitMask) >> NodeSetBitShift; sMapW4 = w; int h = (sMapH + NodeSetBitMask) >> NodeSetBitShift; int wh_size = w * h; if (sNodeSet == null || sNodeSet.Length < wh_size) { sNodeSet = new NodeSet[wh_size]; } sEndX = dest.Cell.x; sEndY = dest.Cell.z; sPathGrid = sMap.pathGrid; sPathGridArray = sMap.pathGrid.pathGrid; sEdifice = sMap.edificeGrid.InnerArray; sTopGrid = sMap.terrainGrid.topGrid; sBlueprint = sMap.blueprintGrid.InnerArray; sTraverseParms = traverseParms; Pawn pawn = traverseParms.pawn; if (pawn != null) { if (!pawn.Spawned || pawn.Map != map) { #if DEBUG_LOG_ERROR Log.Error("Pawn is not spawned or diff map"); #endif return(true); } sCardinal = pawn.TicksPerMoveCardinal; sDiagonal = pawn.TicksPerMoveDiagonal; sAvoidGrid = pawn.GetAvoidGrid(true); sAllowedArea = allowedArea(pawn); sDrafted = pawn.Drafted; sShouldCollideWithPawns = PawnUtility.ShouldCollideWithPawns(pawn); } else { sCardinal = DefaultMoveTicksCardinal; sDiagonal = DefaultMoveTicksDiagonal; sAvoidGrid = null; sAllowedArea = null; sDrafted = false; sShouldCollideWithPawns = false; } sD2C = sDiagonal - (2 * sCardinal); sAllowWater = traverseParms.mode != TraverseMode.NoPassClosedDoorsOrWater && traverseParms.mode != TraverseMode.PassAllDestroyableThingsNotWater; sPassAllDestroyableThings = traverseParms.mode == TraverseMode.PassAllDestroyableThings || traverseParms.mode == TraverseMode.PassAllDestroyableThingsNotWater; setupDestRect(dest, traverseParms, peMode, sMap); return(false); }
public static bool TryFindGoodKidnapVictim(Pawn kidnapper, float maxDist, out Pawn victim, List <Thing> disallowed = null) { if (kidnapper.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation) && kidnapper.Map.reachability.CanReachMapEdge(kidnapper.Position, TraverseParms.For(kidnapper, Danger.Some, TraverseMode.ByPawn, false))) { Predicate <Thing> validator = delegate(Thing t) { Pawn pawn = t as Pawn; if (!pawn.RaceProps.Humanlike) { return(false); } if (!pawn.Downed) { return(false); } if (pawn.Faction != Faction.OfPlayer) { return(false); } if (!pawn.Faction.HostileTo(kidnapper.Faction)) { return(false); } if (!kidnapper.CanReserve(pawn, 1, -1, null, false)) { return(false); } if (disallowed != null && disallowed.Contains(pawn)) { return(false); } return(true); }; victim = (Pawn)GenClosest.ClosestThingReachable(kidnapper.Position, kidnapper.Map, ThingRequest.ForGroup(ThingRequestGroup.Pawn), PathEndMode.OnCell, TraverseParms.For(TraverseMode.NoPassClosedDoors, Danger.Some, false), maxDist, validator, null, 0, -1, false, RegionType.Set_Passable, false); return(victim != null); } victim = null; return(false); }
public static bool TryIssueJobPackage(JobGiver_Work __instance, ref ThinkResult __result, Pawn pawn, JobIssueParams jobParams) { #if DEBUG DateTime startTime = DateTime.Now; #endif if (__instance.emergency && pawn.mindState.priorityWork.IsPrioritized) { List <WorkGiverDef> workGiversByPriority = pawn.mindState.priorityWork.WorkGiver.workType.workGiversByPriority; for (int i = 0; i < workGiversByPriority.Count; i++) { WorkGiver worker = workGiversByPriority[i].Worker; if (__instance.WorkGiversRelated(pawn.mindState.priorityWork.WorkGiver, worker.def)) { Job job = GiverTryGiveJobPrioritized(__instance, pawn, worker, pawn.mindState.priorityWork.Cell); if (job != null) { job.playerForced = true; __result = new ThinkResult(job, __instance, workGiversByPriority[i].tagToGive); return(false); } } } pawn.mindState.priorityWork.Clear(); } List <WorkGiver> list = (!__instance.emergency) ? pawn.workSettings.WorkGiversInOrderNormal : pawn.workSettings.WorkGiversInOrderEmergency; int num = -999; TargetInfo bestTargetOfLastPriority = TargetInfo.Invalid; WorkGiver_Scanner scannerWhoProvidedTarget = null; WorkGiver_Scanner scanner; IntVec3 pawnPosition; float closestDistSquared; float bestPriority; bool prioritized; bool allowUnreachable; Danger maxPathDanger; for (int j = 0; j < list.Count; j++) { WorkGiver workGiver = list[j]; if (workGiver.def.priorityInType != num && bestTargetOfLastPriority.IsValid) { break; } if (!__instance.PawnCanUseWorkGiver(pawn, workGiver)) { continue; } try { Job job2 = workGiver.NonScanJob(pawn); if (job2 != null) { __result = new ThinkResult(job2, __instance, workGiver.def.tagToGive); return(false); } scanner = (workGiver as WorkGiver_Scanner); if (scanner != null) { if (scanner.def.scanThings) { //----------------------THERE HAVE BEEN NO CHANGES ABOVE THIS--------------------------------- Predicate <Thing> validator; if (scanner is WorkGiver_DoBill workGiver_DoBill) { validator = (Thing t) => !t.IsForbidden(pawn) && WorkGiver_Scanner_Patch.HasJobOnThing(workGiver_DoBill, pawn, t); } else { validator = (Thing t) => !t.IsForbidden(pawn) && scanner.HasJobOnThing(pawn, t); } IEnumerable <Thing> enumerable = scanner.PotentialWorkThingsGlobal(pawn); Thing thing; if (scanner.Prioritized) { IEnumerable <Thing> enumerable2 = enumerable; if (enumerable2 == null) { enumerable2 = pawn.Map.listerThings.ThingsMatching(scanner.PotentialWorkThingRequest); } thing = ((!scanner.AllowUnreachable) ? GenClosest.ClosestThing_Global_Reachable(pawn.Position, pawn.Map, enumerable2, scanner.PathEndMode, TraverseParms.For(pawn, scanner.MaxPathDanger(pawn)), 9999f, validator, (Thing x) => scanner.GetPriority(pawn, x)) : GenClosest.ClosestThing_Global(pawn.Position, enumerable2, 99999f, validator, (Thing x) => scanner.GetPriority(pawn, x))); } else if (scanner.AllowUnreachable) { IEnumerable <Thing> enumerable3 = enumerable; if (enumerable3 == null) { enumerable3 = pawn.Map.listerThings.ThingsMatching(scanner.PotentialWorkThingRequest); } thing = GenClosest.ClosestThing_Global(pawn.Position, enumerable3, 99999f, validator); } else { //TODO: use better ThingRequest groups if ( workGiver.def.defName.Equals("DoctorFeedAnimals") || workGiver.def.defName.Equals("DoctorFeedHumanlikes") || workGiver.def.defName.Equals("DoctorTendToAnimals") || workGiver.def.defName.Equals("DoctorTendToHumanlikes") || workGiver.def.defName.Equals("DoBillsUseCraftingSpot") || workGiver.def.defName.Equals("DoctorTendEmergency") || workGiver.def.defName.Equals("HaulCorpses") || workGiver.def.defName.Equals("FillFermentingBarrel") || workGiver.def.defName.Equals("HandlingFeedPatientAnimals") || workGiver.def.defName.Equals("Train") || workGiver.def.defName.Equals("VisitSickPawn") || workGiver.def.defName.Equals("DoBillsButcherFlesh") || workGiver.def.defName.Equals("DoBillsCook") || workGiver.def.defName.Equals("DoBillsMakeApparel") ) { //long thing = GenClosest_Patch.ClosestThingReachable2(pawn.Position, pawn.Map, scanner.PotentialWorkThingRequest, scanner.PathEndMode, TraverseParms.For(pawn, scanner.MaxPathDanger(pawn)), 9999f, validator, enumerable, 0, scanner.MaxRegionsToScanBeforeGlobalSearch, enumerable != null); } else if ( workGiver.def.defName.Equals("HaulGeneral") ) { //long thing = HaulingCache.ClosestThingReachable(pawn, scanner, pawn.Map, scanner.PotentialWorkThingRequest, scanner.PathEndMode, TraverseParms.For(pawn, scanner.MaxPathDanger(pawn)), 9999f, validator, enumerable, 0, scanner.MaxRegionsToScanBeforeGlobalSearch, enumerable != null); } /* * else if( * workGiver.def.defName.Equals("DoBillsButcherFlesh") || * workGiver.def.defName.Equals("DoBillsCook") || * workGiver.def.defName.Equals("DoBillsMakeApparel")) * { * * thing = null; * //ThingGrid_Patch * int mapSizeX = pawn.Map.Size.x; * int mapSizeZ = pawn.Map.Size.z; * int index = pawn.Map.cellIndices.CellToIndex(pawn.Position); * //Dictionary<Bill, float> billPointsDict = ThingGrid_Patch.thingBillPoints[t.def]; * Dictionary<WorkGiver_Scanner, Dictionary<float, List<HashSet<Thing>[]>>> ingredientDict = ThingGrid_Patch.mapIngredientDict[pawn.Map]; * ThingRequest thingReq = scanner.PotentialWorkThingRequest; * if(!ingredientDict.TryGetValue(scanner, out Dictionary<float, List<HashSet<Thing>[]>> scoreToJumboCellsList)) { * scoreToJumboCellsList = new Dictionary<float, List<HashSet<Thing>[]>>(); * List<Thing> thingsMatchingRequest = pawn.Map.listerThings.ThingsMatching(thingReq); * } * * } */ else { //long thing = GenClosest.ClosestThingReachable(pawn.Position, pawn.Map, scanner.PotentialWorkThingRequest, scanner.PathEndMode, TraverseParms.For(pawn, scanner.MaxPathDanger(pawn)), 9999f, validator, enumerable, 0, scanner.MaxRegionsToScanBeforeGlobalSearch, enumerable != null); } } if (thing != null) { bestTargetOfLastPriority = thing; scannerWhoProvidedTarget = scanner; } } if (scanner.def.scanCells) { pawnPosition = pawn.Position; closestDistSquared = 99999f; bestPriority = float.MinValue; prioritized = scanner.Prioritized; allowUnreachable = scanner.AllowUnreachable; maxPathDanger = scanner.MaxPathDanger(pawn); IEnumerable <IntVec3> enumerable4; if (scanner is WorkGiver_GrowerSow workGiver_Grower) { //RimThreaded.WorkGiver_GrowerSow_Patch_JobOnCell = 0; //thing = HaulingCache.ClosestThingReachable(pawn, scanner, pawn.Map, scanner.PotentialWorkThingRequest, scanner.PathEndMode, TraverseParms.For(pawn, scanner.MaxPathDanger(pawn)), 9999f, validator, enumerable, 0, scanner.MaxRegionsToScanBeforeGlobalSearch, enumerable != null); IntVec3 bestCell = WorkGiver_Grower_Patch.ClosestLocationReachable(workGiver_Grower, pawn); //Log.Message(bestCell.ToString()); if (bestCell.IsValid) { bestTargetOfLastPriority = new TargetInfo(bestCell, pawn.Map); scannerWhoProvidedTarget = scanner; } //Log.Message(RimThreaded.WorkGiver_GrowerSow_Patch_JobOnCell.ToString()); } else if (scanner is WorkGiver_GrowerHarvest workGiver_GrowerHarvest) { IntVec3 bestCell = WorkGiver_GrowerHarvest_Patch.ClosestLocationReachable(workGiver_GrowerHarvest, pawn); if (bestCell.IsValid) { bestTargetOfLastPriority = new TargetInfo(bestCell, pawn.Map); scannerWhoProvidedTarget = scanner; } /* * enumerable4 = workGiver_GrowerHarvest.PotentialWorkCellsGlobal(pawn); * IList<IntVec3> list2; * if ((list2 = (enumerable4 as IList<IntVec3>)) != null) * { * for (int k = 0; k < list2.Count; k++) * { * ProcessCell(list2[k]); * } * } * else * { * foreach (IntVec3 item in enumerable4) * { * ProcessCell(item); * } * } */ } else { enumerable4 = scanner.PotentialWorkCellsGlobal(pawn); IList <IntVec3> list2; if ((list2 = (enumerable4 as IList <IntVec3>)) != null) { for (int k = 0; k < list2.Count; k++) { ProcessCell(list2[k]); } } else { foreach (IntVec3 item in enumerable4) { ProcessCell(item); } } } } } void ProcessCell(IntVec3 c) { float newDistanceSquared = (c - pawnPosition).LengthHorizontalSquared; float newPriority = 0f; if (prioritized) { newPriority = scanner.GetPriority(pawn, c); if (newPriority < bestPriority) { return; } } if (newDistanceSquared < closestDistSquared && !c.IsForbidden(pawn) && scanner.HasJobOnCell(pawn, c)) { if (!allowUnreachable && !pawn.CanReach(c, scanner.PathEndMode, maxPathDanger)) { return; } bestTargetOfLastPriority = new TargetInfo(c, pawn.Map); scannerWhoProvidedTarget = scanner; closestDistSquared = newDistanceSquared; bestPriority = newPriority; } } } catch (Exception ex) { Log.Error(string.Concat(pawn, " threw exception in WorkGiver ", workGiver.def.defName, ": ", ex.ToString())); } finally { } if (bestTargetOfLastPriority.IsValid) { Job job3 = (!bestTargetOfLastPriority.HasThing) ? scannerWhoProvidedTarget.JobOnCell(pawn, bestTargetOfLastPriority.Cell) : scannerWhoProvidedTarget.JobOnThing(pawn, bestTargetOfLastPriority.Thing); if (job3 != null) { job3.workGiverDef = scannerWhoProvidedTarget.def; __result = new ThinkResult(job3, __instance, list[j].def.tagToGive); return(false); } //If this was a cached plant job, deregister it if (scannerWhoProvidedTarget is WorkGiver_GrowerSow) { Map map = pawn.Map; IntVec3 cell = bestTargetOfLastPriority.Cell; List <Thing> thingList = cell.GetThingList(map); foreach (Thing thing in thingList) { if (thing is Building_PlantGrower buildingPlantGrower) { PlantSowing_Cache.ReregisterObject(map, cell, WorkGiver_Grower_Patch.awaitingPlantCellsMapDict); } } PlantSowing_Cache.ReregisterObject(map, cell, WorkGiver_Grower_Patch.awaitingPlantCellsMapDict); } //HACK - I know. I'm awful. //Log.ErrorOnce(string.Concat(scannerWhoProvidedTarget, " provided target ", bestTargetOfLastPriority, " but yielded no actual job for pawn ", pawn, ". The CanGiveJob and JobOnX methods may not be synchronized."), 6112651); Log.Warning(string.Concat(scannerWhoProvidedTarget, " provided target ", bestTargetOfLastPriority, " but yielded no actual job for pawn ", pawn, ". The CanGiveJob and JobOnX methods may not be synchronized.")); } num = workGiver.def.priorityInType; #if DEBUG int milli99 = (int)DateTime.Now.Subtract(startTime).TotalMilliseconds; if (milli99 > 300) { Log.Warning("99 JobGiver_Work.TryIssueJobPackage Took over " + milli99.ToString() + "ms for workGiver: " + workGiver.def.defName); //Log.Warning(scanner.PotentialWorkThingRequest.ToString()); //Log.Warning(validator.ToString()); } #endif } __result = ThinkResult.NoJob; return(false); }
public override void ProcessInput(Event ev) { base.ProcessInput(ev); if (this.transporters == null) { this.transporters = new List <CompTransporter>(); } if (!this.transporters.Contains(this.transComp)) { this.transporters.Add(this.transComp); } CompLaunchable launchable = this.transComp.Launchable; if (launchable != null) { Building fuelingPortSource = launchable.FuelingPortSource; if (fuelingPortSource != null) { Map map = this.transComp.Map; Command_LoadToTransporter.tmpFuelingPortGivers.Clear(); map.floodFiller.FloodFill(fuelingPortSource.Position, (IntVec3 x) => FuelingPortUtility.AnyFuelingPortGiverAt(x, map), delegate(IntVec3 x) { Command_LoadToTransporter.tmpFuelingPortGivers.Add(FuelingPortUtility.FuelingPortGiverAt(x, map)); }, 2147483647, false, null); for (int i = 0; i < this.transporters.Count; i++) { Building fuelingPortSource2 = this.transporters[i].Launchable.FuelingPortSource; if (fuelingPortSource2 != null && !Command_LoadToTransporter.tmpFuelingPortGivers.Contains(fuelingPortSource2)) { Messages.Message("MessageTransportersNotAdjacent".Translate(), fuelingPortSource2, MessageTypeDefOf.RejectInput); return; } } } } for (int j = 0; j < this.transporters.Count; j++) { if (this.transporters[j] != this.transComp && !this.transComp.Map.reachability.CanReach(this.transComp.parent.Position, this.transporters[j].parent, PathEndMode.Touch, TraverseParms.For(TraverseMode.PassDoors, Danger.Deadly, false))) { Messages.Message("MessageTransporterUnreachable".Translate(), this.transporters[j].parent, MessageTypeDefOf.RejectInput); return; } } Find.WindowStack.Add(new Dialog_LoadTransporters(this.transComp.Map, this.transporters)); }
//FindPath parameter validation private bool ValidateFindPathParameters(Pawn pawn, IntVec3 start, LocalTargetInfo dest, TraverseParms traverseParms, PathEndMode peMode, bool canPassAnything) { if (pawn != null && pawn.Map != this.map) { Log.Error(string.Concat("Tried to FindPath for pawn which is spawned in another map. His map PathFinder should have been used, not this one. pawn=", pawn, " pawn.Map=", pawn.Map, " map=", this.map)); return(false); } if (!start.IsValid) { Log.Error(string.Concat("Tried to FindPath with invalid start ", start, ", pawn= ", pawn)); return(false); } if (!dest.IsValid) { Log.Error(string.Concat("Tried to FindPath with invalid dest ", dest, ", pawn= ", pawn)); return(false); } if (!canPassAnything) { //For offline testing, reachability check can crash with null pawn if (Current.ProgramState == ProgramState.Playing) { if (!this.map.reachability.CanReach(start, dest, peMode, traverseParms)) { return(false); } } map.regionAndRoomUpdater.RebuildDirtyRegionsAndRooms(); } else if (dest.HasThing && dest.Thing.Map != this.map) { return(false); } return(true); }
public void TryRevive(bool ForcedRevive = false) { string str = "sucessful"; reviveIntervalTicks = -1; reviveTried = true; Rand.PushState(); if (Rand.Chance(reanimateChance) || ForcedRevive) { List <Hediff> hediffs = unhealableHediffs; ResurrectionUtility.Resurrect(pawn); if (originalWeapon == null && pawn.kindDef.weaponTags.Count > 0) { ThingDef thingDef = ThingDef.Named(pawn.kindDef.weaponTags[0]); Thing thing2 = GenClosest.ClosestThingReachable(pawn.Position, pawn.Map, ThingRequest.ForDef(thingDef), PathEndMode.InteractionCell, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.ByPawn, false)); this.originalWeapon = (ThingWithComps)thing2; } if (originalWeapon != null) { ThingWithComps thing = originalWeapon; if (thing.Spawned) { thing.DeSpawn(); } if (pawn.inventory.innerContainer.Contains(thing)) { pawn.inventory.innerContainer.Remove(thing); } pawn.equipment.AddEquipment(thing); } if (secondryWeapon != null) { ThingWithComps thing = secondryWeapon; if (thing.Spawned) { thing.DeSpawn(); } if (pawn.inventory.innerContainer.Contains(thing)) { pawn.inventory.innerContainer.Remove(thing); } // pawn.equipment.AdMechAddOffHandEquipment(thing); } if (!ForcedRevive) { bool revives = true; foreach (Hediff item in hediffs) { if (!pawn.health.hediffSet.PartIsMissing(item.Part)) { if (pawn.health.WouldDieAfterAddingHediff(item)) { revives = false; str = "failiure"; } if (pawn.health.WouldBeDownedAfterAddingHediff(item)) { revives = false; str = "failiure: still downed"; } pawn.health.AddHediff(item); } } } ThrowNecronGlow(pos.ToVector3(), map, 5f); MoteMaker.MakeStaticMote(pos, map, ThingDefOf.Mote_ExplosionFlash, 3f); // log.message(string.Format("{0} revive {1}",pawn, str)); } else { str = "failiure: roll"; // log.message(string.Format("{0} revive {1}", pawn, str)); } Rand.PopState(); }
protected override Job TryGiveJob(Pawn pawn) { if (Find.TickManager.TicksGame < PrevTick + 10) { return(null); } PrevTick = Find.TickManager.TicksGame; if (GridsUtility.Fogged(pawn.Position, pawn.Map)) { return(JobMaker.MakeJob(JobDefOf.LayDown)); } Alien alien = pawn as Alien; // Some optimizations here... //if (pawn.TryGetAttackVerb(null, false) == null) //{ // return null; //} if (pawn.CurJob != null) { Log.Message(pawn + " - " + pawn.CurJob.def.defName); } Pawn pawn2 = null; if ((Find.TickManager.TicksGame - alien.lastAttacked) < 1000) { pawn2 = alien.lastInstigator; } else if ((Find.TickManager.TicksGame - pawn.Map.GetComponent <MapComponent_MapEvents>().LastAttacked) < 1000) { pawn2 = FindPawnTargetNearPlants(pawn); } else { pawn2 = FindPawnTarget(pawn); } if (pawn2 == null) { if (pawn.GetRoom() != null && !pawn.GetRoom().PsychologicallyOutdoors) { Predicate <Thing> validator = delegate(Thing t) { return(t.def.defName.ToLower().Contains("door")); }; var door = GenClosest.ClosestThingReachable(pawn.Position, pawn.Map, ThingRequest.ForGroup(ThingRequestGroup.BuildingArtificial), PathEndMode.Touch, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.ByPawn, false) , 5f, validator); if (door != null) { return(PurpleIvyUtils.MeleeAttackJob(pawn, door)); } else { Predicate <Thing> validator2 = delegate(Thing t) { return(t.def.defName.ToLower().Contains("wall")); }; var wall = GenClosest.ClosestThingReachable(pawn.Position, pawn.Map, ThingRequest.ForGroup(ThingRequestGroup.BuildingArtificial), PathEndMode.Touch, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.ByPawn, false) , 5f, validator2); if (wall != null) { return(PurpleIvyUtils.MeleeAttackJob(pawn, wall)); } } } } else if (!pawn2.Downed) { var verb = pawn.VerbTracker.AllVerbs.Where(x => x.IsMeleeAttack != true).FirstOrDefault(); if (pawn.def == PurpleIvyDefOf.Genny_ParasiteOmega && pawn.Position.InHorDistOf(pawn2.Position, 15) && Rand.Chance(0.7f)) { //Log.Message(Find.TickManager.TicksGame.ToString() + " - " + pawn + " - " + pawn.jobs?.curJob?.def?.defName + " - JUMP"); return(PurpleIvyUtils.JumpOnTargetJob(pawn, pawn2)); } else if (pawn.def == PurpleIvyDefOf.Genny_ParasiteBeta && pawn.Position.InHorDistOf(pawn2.Position, 2) && Rand.Chance(0.1f)) { //Log.Message(Find.TickManager.TicksGame.ToString() + " - " + pawn + " - " + pawn.jobs?.curJob?.def?.defName + " - SMOKE"); return(PurpleIvyUtils.SmokeAttackJob(pawn, pawn2)); } else if (verb != null && Rand.Chance(0.8f) && pawn.Position.InHorDistOf(pawn2.Position, verb.verbProps.range)) { //Log.Message(Find.TickManager.TicksGame.ToString() + " - " + pawn + " - " + pawn.jobs?.curJob?.def?.defName + " - SHOOT"); return(PurpleIvyUtils.RangeAttackJob(pawn, pawn2)); } else { //Log.Message(Find.TickManager.TicksGame.ToString() + " - " + pawn + " - " + pawn.jobs?.curJob?.def?.defName + " - MELEE"); return(PurpleIvyUtils.MeleeAttackJob(pawn, pawn2)); } } else if (pawn2.Downed) { if (pawn2.BodySize >= 0.5f && pawn.def != PurpleIvyDefOf.Genny_ParasiteOmega && pawn.def != PurpleIvyDefOf.Genny_ParasiteGamma && pawn.kindDef != PurpleIvyDefOf.Genny_Queen && pawn.needs.food.CurCategory < HungerCategory.Hungry) { //Log.Message(Find.TickManager.TicksGame.ToString() + " - " + pawn + " - " + pawn.jobs?.curJob?.def?.defName + " - Goo"); return(PurpleIvyUtils.EntagleWithGooJob(pawn, pawn2)); } else { //Log.Message(Find.TickManager.TicksGame.ToString() + " - " + pawn + " - " + pawn.jobs?.curJob?.def?.defName + " - KILL"); return(PurpleIvyUtils.KillAttackJob(pawn, pawn2)); } } if (alien.canGuard) { if (alien.mindState?.duty?.focus == null || !PurpleIvyUtils.AlienPlantInCell (alien.Map, alien.mindState.duty.focus.Cell)) { alien.SetFocus(); } } if (alien.canHaul) { Predicate <Thing> validator = delegate(Thing t) { List <Thing> list = pawn.Map.thingGrid.ThingsListAt(t.Position); return(!(list.Count > 0 && list.OfType <Plant>().Any(x => x.def == PurpleIvyDefOf.PurpleIvy || x.def == PurpleIvyDefOf.PI_Nest || x.def == PurpleIvyDefOf.PlantVenomousToothwort))); }; Thing thing = GenClosest.ClosestThingReachable(pawn.Position, pawn.Map, ThingRequest.ForDef(PurpleIvyDefOf.PI_StickyGoo), PathEndMode.ClosestTouch, TraverseParms.For(pawn, Danger.None, TraverseMode.NoPassClosedDoors, false), 9999f, validator, null); if (thing == null) { thing = GenClosest.ClosestThingReachable(pawn.Position, pawn.Map, ThingRequest.ForGroup(ThingRequestGroup.Corpse), PathEndMode.ClosestTouch, TraverseParms.For(pawn, Danger.None, TraverseMode.NoPassClosedDoors, false), 50f, validator, null); } if (thing != null && ReservationUtility.CanReserveAndReach(pawn, thing, PathEndMode.ClosestTouch, Danger.None)) { var plants = pawn.Map.listerThings.ThingsOfDef(PurpleIvyDefOf.PurpleIvy); if (plants == null || plants.Count <= 0) { return(null); } var plantToHaul = plants.RandomElement(); if (ReachabilityUtility.CanReach(pawn, plantToHaul, PathEndMode.ClosestTouch, Danger.None, true, TraverseMode.NoPassClosedDoors)) { Job job = JobMaker.MakeJob(PurpleIvyDefOf.PI_HaulToCell, thing, plantToHaul.Position); job.attackDoorIfTargetLost = true; if (job != null && job.TryMakePreToilReservations(pawn, false)) { ReservationUtility.Reserve(pawn, thing, job); return(job); } } } } //Log.Message(Find.TickManager.TicksGame.ToString() + " - " + pawn + " - " + pawn.jobs?.curJob?.def?.defName + " - NULL 1"); //Building building = this.FindTurretTarget(pawn); //if (building != null) //{ // return MeleeAttackJob(pawn, building); //} //if (pawn2 != null) //{ // using (PawnPath pawnPath = pawn.Map.pathFinder.FindPath(pawn.Position, pawn2.Position, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.PassDoors, false), PathEndMode.OnCell)) // { // if (!pawnPath.Found) // { // return null; // } // IntVec3 loc; // if (!pawnPath.TryFindLastCellBeforeBlockingDoor(pawn, out loc)) // { // Log.Error(pawn + " did TryFindLastCellBeforeDoor but found none when it should have been one. Target: " + pawn2.LabelCap, false); // return null; // } // IntVec3 randomCell = CellFinder.RandomRegionNear(loc.GetRegion(pawn.Map, RegionType.Set_Passable), 9, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.ByPawn, false), null, null, RegionType.Set_Passable).RandomCell; // if (randomCell == pawn.Position) // { // return JobMaker.MakeJob(JobDefOf.Wait, 30, false); // } // return JobMaker.MakeJob(JobDefOf.Goto, randomCell); // } //} return(null); }