public void HealthTick() { if (!Dead) { for (int num = hediffSet.hediffs.Count - 1; num >= 0; num--) { Hediff hediff = hediffSet.hediffs[num]; try { hediff.Tick(); hediff.PostTick(); } catch (Exception ex) { Log.Error("Exception ticking hediff " + hediff.ToStringSafe() + " for pawn " + pawn.ToStringSafe() + ". Removing hediff... Exception: " + ex); try { RemoveHediff(hediff); } catch (Exception arg) { Log.Error("Error while removing hediff: " + arg); } } } bool flag = false; for (int num2 = hediffSet.hediffs.Count - 1; num2 >= 0; num2--) { Hediff hediff2 = hediffSet.hediffs[num2]; if (hediff2.ShouldRemove) { hediffSet.hediffs.RemoveAt(num2); hediff2.PostRemoved(); flag = true; } } if (flag) { Notify_HediffChanged(null); } if (!Dead) { immunity.ImmunityHandlerTick(); if (pawn.RaceProps.IsFlesh && pawn.IsHashIntervalTick(600) && (pawn.needs.food == null || !pawn.needs.food.Starving)) { bool flag2 = false; if (hediffSet.HasNaturallyHealingInjury()) { float num3 = 8f; if (pawn.GetPosture() != 0) { num3 += 4f; Building_Bed building_Bed = pawn.CurrentBed(); if (building_Bed != null) { num3 += building_Bed.def.building.bed_healPerDay; } } Hediff_Injury hediff_Injury = hediffSet.GetHediffs <Hediff_Injury>().Where(HediffUtility.CanHealNaturally).RandomElement(); hediff_Injury.Heal(num3 * pawn.HealthScale * 0.01f); flag2 = true; } if (hediffSet.HasTendedAndHealingInjury() && (pawn.needs.food == null || !pawn.needs.food.Starving)) { Hediff_Injury hediff_Injury2 = hediffSet.GetHediffs <Hediff_Injury>().Where(HediffUtility.CanHealFromTending).RandomElement(); float tendQuality = hediff_Injury2.TryGetComp <HediffComp_TendDuration>().tendQuality; float num4 = GenMath.LerpDouble(0f, 1f, 0.5f, 1.5f, Mathf.Clamp01(tendQuality)); hediff_Injury2.Heal(8f * num4 * pawn.HealthScale * 0.01f); flag2 = true; } if (flag2 && !HasHediffsNeedingTendByPlayer() && !HealthAIUtility.ShouldSeekMedicalRest(pawn) && !hediffSet.HasTendedAndHealingInjury() && PawnUtility.ShouldSendNotificationAbout(pawn)) { Messages.Message("MessageFullyHealed".Translate(pawn.LabelCap, pawn), pawn, MessageTypeDefOf.PositiveEvent); } } if (pawn.RaceProps.IsFlesh && hediffSet.BleedRateTotal >= 0.1f) { float num5 = hediffSet.BleedRateTotal * pawn.BodySize; num5 = ((pawn.GetPosture() != 0) ? (num5 * 0.0004f) : (num5 * 0.004f)); if (Rand.Value < num5) { DropBloodFilth(); } } if (pawn.IsHashIntervalTick(60)) { List <HediffGiverSetDef> hediffGiverSets = pawn.RaceProps.hediffGiverSets; if (hediffGiverSets != null) { for (int i = 0; i < hediffGiverSets.Count; i++) { List <HediffGiver> hediffGivers = hediffGiverSets[i].hediffGivers; for (int j = 0; j < hediffGivers.Count; j++) { hediffGivers[j].OnIntervalPassed(pawn, null); if (pawn.Dead) { return; } } } } if (pawn.story != null) { List <Trait> allTraits = pawn.story.traits.allTraits; for (int k = 0; k < allTraits.Count; k++) { TraitDegreeData currentData = allTraits[k].CurrentData; if (currentData.randomDiseaseMtbDays > 0f && Rand.MTBEventOccurs(currentData.randomDiseaseMtbDays, 60000f, 60f)) { BiomeDef biome; if (pawn.Tile != -1) { biome = Find.WorldGrid[pawn.Tile].biome; } else { biome = DefDatabase <BiomeDef> .GetRandom(); } IncidentDef incidentDef = (from d in DefDatabase <IncidentDef> .AllDefs where d.category == IncidentCategoryDefOf.DiseaseHuman select d).RandomElementByWeightWithFallback((IncidentDef d) => biome.CommonalityOfDisease(d)); if (incidentDef != null) { string blockedInfo; List <Pawn> list = ((IncidentWorker_Disease)incidentDef.Worker).ApplyToPawns(Gen.YieldSingle(pawn), out blockedInfo); if (PawnUtility.ShouldSendNotificationAbout(pawn)) { if (list.Contains(pawn)) { Find.LetterStack.ReceiveLetter("LetterLabelTraitDisease".Translate(incidentDef.diseaseIncident.label), "LetterTraitDisease".Translate(pawn.LabelCap, incidentDef.diseaseIncident.label, pawn.Named("PAWN")).AdjustedFor(pawn), LetterDefOf.NegativeEvent, pawn); } else if (!blockedInfo.NullOrEmpty()) { Messages.Message(blockedInfo, pawn, MessageTypeDefOf.NeutralEvent); } } } } } } } } } }
public IEnumerable <StatDrawEntry> SpecialDisplayStats(ThingDef parentDef) { yield return(new StatDrawEntry(StatCategoryDefOf.Basics, "Race".Translate(), parentDef.LabelCap, 2000, "")); yield return(new StatDrawEntry(StatCategoryDefOf.Basics, "Diet".Translate(), this.foodType.ToHumanString().CapitalizeFirst(), 0, "")); if (parentDef.race.leatherDef != null) { yield return(new StatDrawEntry(StatCategoryDefOf.Basics, "LeatherType".Translate(), parentDef.race.leatherDef.LabelCap, 0, "")); } if (parentDef.race.Animal || this.wildness > 0f) { yield return(new StatDrawEntry(StatCategoryDefOf.Basics, "Wildness".Translate(), this.wildness.ToStringPercent(), 0, "") { overrideReportText = TrainableUtility.GetWildnessExplanation(parentDef) }); } yield return(new StatDrawEntry(StatCategoryDefOf.Basics, "HarmedRevengeChance".Translate(), PawnUtility.GetManhunterOnDamageChance(parentDef.race).ToStringPercent(), 0, "") { overrideReportText = "HarmedRevengeChanceExplanation".Translate() }); yield return(new StatDrawEntry(StatCategoryDefOf.Basics, "TameFailedRevengeChance".Translate(), parentDef.race.manhunterOnTameFailChance.ToStringPercent(), 0, "")); if (this.intelligence < Intelligence.Humanlike && this.trainability != null) { yield return(new StatDrawEntry(StatCategoryDefOf.Basics, "Trainability".Translate(), this.trainability.LabelCap, 0, "")); } yield return(new StatDrawEntry(StatCategoryDefOf.Basics, "StatsReport_LifeExpectancy".Translate(), this.lifeExpectancy.ToStringByStyle(ToStringStyle.Integer, ToStringNumberSense.Absolute), 0, "")); if (this.intelligence < Intelligence.Humanlike) { yield return(new StatDrawEntry(StatCategoryDefOf.Basics, "AnimalFilthRate".Translate(), (PawnUtility.AnimalFilthChancePerCell(parentDef, parentDef.race.baseBodySize) * 1000f).ToString("F2"), 0, "") { overrideReportText = "AnimalFilthRateExplanation".Translate(new object[] { 1000.ToString() }) }); } if (this.packAnimal) { yield return(new StatDrawEntry(StatCategoryDefOf.Basics, "PackAnimal".Translate(), "Yes".Translate(), 0, "") { overrideReportText = "PackAnimalExplanation".Translate() }); } if (parentDef.race.nuzzleMtbHours > 0f) { yield return(new StatDrawEntry(StatCategoryDefOf.PawnSocial, "NuzzleInterval".Translate(), Mathf.RoundToInt(parentDef.race.nuzzleMtbHours * 2500f).ToStringTicksToPeriod(), 0, "") { overrideReportText = "NuzzleIntervalExplanation".Translate() }); } yield break; }
public bool TryStartMentalState(MentalStateDef stateDef, string reason = null, bool forceWake = false, bool causedByMood = false, Pawn otherPawn = null, bool transitionSilently = false) { if ((!pawn.Spawned && !pawn.IsCaravanMember()) || CurStateDef == stateDef || pawn.Downed || (!forceWake && !pawn.Awake())) { return(false); } if (TutorSystem.TutorialMode && pawn.Faction == Faction.OfPlayer) { return(false); } if (!stateDef.Worker.StateCanOccur(pawn)) { return(false); } MentalState mentalState = (MentalState)Activator.CreateInstance(stateDef.stateClass); mentalState.pawn = pawn; mentalState.def = stateDef; mentalState.causedByMood = causedByMood; if (otherPawn != null) { ((MentalState_SocialFighting)mentalState).otherPawn = otherPawn; } mentalState.PreStart(); if (!transitionSilently) { if ((pawn.IsColonist || pawn.HostFaction == Faction.OfPlayer) && stateDef.tale != null) { TaleRecorder.RecordTale(stateDef.tale, pawn); } if (stateDef.IsExtreme && pawn.IsPlayerControlledCaravanMember()) { Messages.Message("MessageCaravanMemberHasExtremeMentalBreak".Translate(), pawn.GetCaravan(), MessageTypeDefOf.ThreatSmall); } pawn.records.Increment(RecordDefOf.TimesInMentalState); } if (pawn.Drafted) { pawn.drafter.Drafted = false; } curStateInt = mentalState; if (pawn.needs.mood != null) { pawn.needs.mood.thoughts.situational.Notify_SituationalThoughtsDirty(); } if (stateDef != null && stateDef.IsAggro && pawn.caller != null) { pawn.caller.Notify_InAggroMentalState(); } if (curStateInt != null) { curStateInt.PostStart(reason); } if (pawn.CurJob != null) { pawn.jobs.StopAll(); } if (pawn.Spawned) { pawn.Map.attackTargetsCache.UpdateTarget(pawn); } if (pawn.Spawned && forceWake && !pawn.Awake()) { pawn.jobs.EndCurrentJob(JobCondition.InterruptForced); } if (!transitionSilently && PawnUtility.ShouldSendNotificationAbout(pawn)) { string text = mentalState.GetBeginLetterText(); if (!text.NullOrEmpty()) { string label = (stateDef.beginLetterLabel ?? stateDef.LabelCap).CapitalizeFirst() + ": " + pawn.LabelShortCap; if (!reason.NullOrEmpty()) { text = text + "\n\n" + reason; } Find.LetterStack.ReceiveLetter(label, text, stateDef.beginLetterDef, pawn); } } return(true); }
private void expandNode(Step currentNode) { bool previousNodeHasDoor, previousNodeIsPathCostIgnoreRepeater; Building previousBuilding = edificeGrid[currentNode.currentIndx]; if (previousBuilding is Building_Door) { previousNodeHasDoor = true; } else { previousNodeHasDoor = false; } previousNodeIsPathCostIgnoreRepeater = false; foreach (ThingDef def in map.thingGrid.ThingsListAtFast(currentNode.currentIndx).Select(t => t.def)) { if (def.pathCostIgnoreRepeat) { previousNodeIsPathCostIgnoreRepeater = true; break; } } //add all neighboring tiles but diagonal only if it is allowed, fixed size where we null out the after last entry if it is not full int currentIndice = currentNode.currentIndx; int currentX = currentNode.current.x; int currentZ = currentNode.current.z; int[] Directions = DirectionsShared; IntVec3 invalidIntVec3 = invalidIntVec3Shared; byte byteDirections; if (pathfinderDirections != null) { byteDirections = pathfinderDirections.GetDirections(currentNode.current); } else { byteDirections = 0xFF; } for (int i = 0; i < 8; i++) { if (byteDirections != 0xFF) { //{ 0, 1, 0, -1, 1, 1, -1, -1, // -1, 0, 1, 0, -1, 1, 1, -1 } switch (i) { case 2: if ((byteDirections & 1) != 1) { neighbors[i] = invalidIntVec3; continue; } break; case 5: if ((byteDirections & 2) != 2) { neighbors[i] = invalidIntVec3; continue; } break; case 1: if ((byteDirections & 4) != 4) { neighbors[i] = invalidIntVec3; continue; } break; case 4: if ((byteDirections & 8) != 8) { neighbors[i] = invalidIntVec3; continue; } break; case 0: if ((byteDirections & 16) != 16) { neighbors[i] = invalidIntVec3; continue; } break; case 8: if ((byteDirections & 32) != 32) { neighbors[i] = invalidIntVec3; continue; } break; case 3: if ((byteDirections & 64) != 64) { neighbors[i] = invalidIntVec3; continue; } break; case 7: if ((byteDirections & 128) != 128) { neighbors[i] = invalidIntVec3; continue; } break; default: neighbors[i] = invalidIntVec3; continue; } } int neighborX = currentX + Directions[i]; int neighborZ = currentZ + Directions[i + 8]; //check if we are within map bounds if (neighborX >= mapSizeX || neighborZ >= mapSizeZ || neighborX < 0 || neighborZ < 0) { neighbors[i] = invalidIntVec3; continue; } //check if we have to skip diagonal movement due to adjacent tiles. if (i > 3) { if (Directions[i] == 1) { if (BlocksDiagonalMovement(currentIndice + 1)) { neighbors[i] = invalidIntVec3; continue; } } else { if (BlocksDiagonalMovement(currentIndice - 1)) { neighbors[i] = invalidIntVec3; continue; } } if (Directions[i + 8] == 1) { if (BlocksDiagonalMovement(currentIndice + mapSizeX)) { neighbors[i] = invalidIntVec3; continue; } } else { if (BlocksDiagonalMovement(currentIndice - mapSizeX)) { neighbors[i] = invalidIntVec3; continue; } } } //check if we can cross water tiles IntVec3 ngb = new IntVec3(neighborX, 0, neighborZ); if (dontPassWater && ngb.GetTerrain(map).HasTag("Water")) { neighbors[i] = invalidIntVec3; continue; } neighbors[i] = ngb; } for (int i = 0; i < neighbors.Count(); i++) { IntVec3 neighbor = neighbors[i]; if (neighbor == invalidIntVec3) { continue; } int neighborIndice = cellIndices.CellToIndex(neighbor); Step successor = stepCache.getCachedOrNewStep(neighbor, neighborIndice); // wenn der Nachfolgeknoten bereits geschlossen wurde - tue nichts if (successor.closed) { continue; } //can the tile be walked across? bool useTerrainCost = true; int costToDestroyInsteadOfTerrainCost = 0; if (!pathGrid.WalkableFast(neighborIndice)) { if (traverseParms.mode != TraverseMode.PassAllDestroyableThings) { continue; } useTerrainCost = false; costToDestroyInsteadOfTerrainCost += 70; Building building = edificeGrid[neighborIndice]; if (building == null) { continue; } if (!PathFinder.IsDestroyable(building)) { continue; } costToDestroyInsteadOfTerrainCost += (int)((float)building.HitPoints * 0.11f); } bool isUpdate = successor.costToReachThis > 0; int stepCosts = (i <= 3) ? costPerMoveCardinal : costPerMoveDiagonal; Building building2 = edificeGrid[neighborIndice]; if (building2 != null) { int buildingCost = PathFinder.GetBuildingCost(building2, traverseParms, pawn); if (buildingCost == Int32.MaxValue) { continue; } stepCosts += buildingCost; } List <Blueprint> blueprints = this.blueprintGrid[neighborIndice]; if (blueprints != null) { int maxBluprintCost = 0; blueprints.ForEach(bp => maxBluprintCost = Math.Max(maxBluprintCost, PathFinder.GetBlueprintCost(bp, pawn))); if (maxBluprintCost == Int32.MaxValue) { continue; } stepCosts += maxBluprintCost; } if (useTerrainCost) { stepCosts += pathGridArray[neighborIndice] - minTerrainCost; //PathGrid uses cached static cost and does not account for directional costs //1. moving from a thing with pathCostIgnoreRepeat and a cost of at least 25 to a thing with pathCostIgnoreRepeat reduces the cost by the pathCost of the first thing //2. moving from door to door increases the cost by 45 if (previousNodeHasDoor && building2 != null && building2 is Building_Door) { stepCosts += 45; } if (previousNodeIsPathCostIgnoreRepeater) { foreach (ThingDef def in map.thingGrid.ThingsListAtFast(neighborIndice).Select(t => t.def)) { if (def.pathCostIgnoreRepeat && def.pathCost >= 25) { stepCosts -= def.pathCost; } } } //new in 1.0 if (drafted) { stepCosts += topGrid[neighborIndice].extraDraftedPerceivedPathCost; } else { stepCosts += topGrid[neighborIndice].extraNonDraftedPerceivedPathCost; } } else { stepCosts += costToDestroyInsteadOfTerrainCost; } if (avoidGrid != null) { stepCosts += (int)(avoidGrid[neighborIndice] * 8); } //Variation to default behaviour: //When pathfinding from outside the allowed area back into the allowed area we ignore the malus for forbidden area to avoid ruining the performance for no good reason. //We check the current position and if it is forbidden we do not apply a malus if it is allowed the current neighbor is tested. if (allowedArea != null && allowedArea[currentIndice] && !allowedArea[neighborIndice]) { stepCosts += 600; } if (collidesWithPawns && PawnUtility.AnyPawnBlockingPathAt(neighbor, pawn, false, false, true)) { stepCosts += 175; } // g Wert für den neuen Weg berechnen: g Wert des Vorgängers plus // die Kosten der gerade benutzten Kante int costToReachThisNeighbor = currentNode.costToReachThis + stepCosts; // wenn der Nachfolgeknoten bereits auf der Open List ist, // aber der neue Weg nicht besser ist als der alte - tue nichts if (isUpdate && successor.costToReachThis <= costToReachThisNeighbor) { continue; } successor.costToReachThis = costToReachThisNeighbor; // Vorgängerzeiger setzen und g Wert merken successor.predecessor = currentNode; // f Wert des Knotens in der Open List aktualisieren // bzw. Knoten mit f Wert in die Open List einfügen if (isUpdate) { openlist.UpdatePriority(successor, successor.costToReachThis + successor.estimatedCostsToDestination); //if ( drawPath ) map.debugDrawer.FlashCell(successor.current, 0.1f, "updated", 100); } else { openlist.Enqueue(successor, successor.costToReachThis + successor.estimatedCostsToDestination); if (drawPath) { map.debugDrawer.FlashCell(successor.current, 0.22f, "opened", 100); } } } }
public override void Tick() { ageTicks++; if (pawn.IsHashIntervalTick(PawnStateCheckInterval)) { //Log.Message("Father = " + father); if (pawn.needs.food != null && pawn.needs.food.CurCategory == HungerCategory.Starving && Rand.MTBEventOccurs(0.5f, 60000f, 1000f)) { if (Visible && PawnUtility.ShouldSendNotificationAbout(pawn)) { //Messages.Message("MessageMiscarriedStarvation".Translate(pawn.LabelIndefinite()).CapitalizeFirst(), pawn, MessageTypeDefOf.NegativeHealthEvent); Messages.Message("MessageMiscarriedStarvation".Translate(new object[] { pawn.LabelIndefinite() }).CapitalizeFirst(), pawn, MessageTypeDefOf.NegativeHealthEvent); } Miscarry(); return; } if (IsSeverelyWounded && Rand.MTBEventOccurs(0.5f, 60000f, 1000f)) { if (Visible && PawnUtility.ShouldSendNotificationAbout(pawn)) { //Messages.Message("MessageMiscarriedPoorHealth".Translate(pawn.LabelIndefinite()).CapitalizeFirst(), pawn, MessageTypeDefOf.NegativeHealthEvent); Messages.Message("MessageMiscarriedPoorHealth".Translate(new object[] { pawn.LabelIndefinite() }).CapitalizeFirst(), pawn, MessageTypeDefOf.NegativeHealthEvent); } Miscarry(); return; } if (GestationProgress >= 1f) { /* * if (Visible && PawnUtility.ShouldSendNotificationAbout(pawn)) * { * Messages.Message("MessageAvaliLayedAnEgg".Translate(new object[] * { * pawn.LabelIndefinite() * }).CapitalizeFirst(), pawn, MessageTypeDefOf.PositiveEvent); * } */ /* * if (Visible && PawnUtility.ShouldSendNotificationAbout(pawn)) * { * * Messages.Message("MessageLayedEgg".Translate(new object[] * { * this.pawn.LabelIndefinite() * }).CapitalizeFirst(), this.pawn, MessageTypeDefOf.PositiveEvent); * } */ //Log.Message(pawn + " try to start job GotoLayAvaliEgg"); //Log.Message(pawn + " egg.father = " + father); //Log.Message(pawn + " bed = " + RestUtility.FindBedFor(pawn)); Job newJob = null; Building_Bed bed = RestUtility.FindBedFor(pawn); if (bed != null) { newJob = new Job(JobDefOf.GotoLayAvaliEgg, father, bed); } else { IntVec3 cell = RCellFinder.RandomWanderDestFor(pawn, pawn.Position, 5f, null, Danger.Some); newJob = new Job(JobDefOf.GotoLayAvaliEgg, father, cell); } pawn.jobs.StartJob(newJob, JobCondition.InterruptForced, null, false, true, null, null, false); //Hediff_AvaliHasEgg.LayEgg(this.pawn, this.father); //this.pawn.health.RemoveHediff(this); } } if (GestationProgress < 1f) { GestationProgress += 1f / (pawn.RaceProps.gestationPeriodDays * 60000f); } }
public static void GiveVitaeEffects(Pawn receiver, Pawn donor) { var pawn = receiver; //Give Vitae High Effect Hediff vitaeHighHediff = HediffMaker.MakeHediff(VampDefOf.ROMV_VitaeHigh, pawn, null); float numHigh = 0.75f; AddictionUtility.ModifyChemicalEffectForToleranceAndBodySize(pawn, VampDefOf.ROMV_VitaeChemical, ref numHigh); vitaeHighHediff.Severity = numHigh; pawn.health.AddHediff(vitaeHighHediff, null, null); //Give Vitae Tolerance Effect Hediff vitaeToleranceHediff = HediffMaker.MakeHediff(VampDefOf.ROMV_VitaeTolerance, pawn, null); float numTol = 0.035f; numTol /= receiver.BodySize; AddictionUtility.ModifyChemicalEffectForToleranceAndBodySize(pawn, VampDefOf.ROMV_VitaeChemical, ref numTol); vitaeToleranceHediff.Severity = numTol; pawn.health.AddHediff(vitaeToleranceHediff, null, null); const float addictiveness = 1.0f; const float minToleranceToAddict = 0.01f; const float existingAddictionSeverityOffset = 0.2f; var needLevelOffset = 1f; var overdoseSeverityOffset = new FloatRange(0.18f, 0.35f); var chemical = VampDefOf.ROMV_VitaeChemical; var addictionHediffDef = VampDefOf.ROMV_VitaeAddiction; var lookTarget = receiver; var hediff = AddictionUtility.FindToleranceHediff(lookTarget, VampDefOf.ROMV_VitaeChemical); var num = hediff?.Severity ?? 0f; var hediffAddiction = AddictionUtility.FindAddictionHediff(lookTarget, VampDefOf.ROMV_VitaeChemical); if (hediffAddiction != null) { hediffAddiction.Severity += existingAddictionSeverityOffset; } else if (Rand.Value < addictiveness && num >= minToleranceToAddict) { lookTarget.health.AddHediff(addictionHediffDef, null, null); if (PawnUtility.ShouldSendNotificationAbout(lookTarget)) { Find.LetterStack.ReceiveLetter("LetterLabelNewlyAddicted".Translate(new object[] { chemical.label }).CapitalizeFirst(), "LetterNewlyAddicted".Translate(new object[] { lookTarget.LabelShort, chemical.label }).AdjustedFor(lookTarget).CapitalizeFirst(), LetterDefOf.NegativeEvent, lookTarget, null); } AddictionUtility.CheckDrugAddictionTeachOpportunity(lookTarget); } if (addictionHediffDef.causesNeed != null) { var need = lookTarget.needs.AllNeeds.Find((Need x) => x.def == addictionHediffDef.causesNeed); if (need != null) { AddictionUtility.ModifyChemicalEffectForToleranceAndBodySize(lookTarget, chemical, ref needLevelOffset); need.CurLevel += needLevelOffset; } } // var firstHediffOfDef = lookTarget.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.DrugOverdose, false); // var num2 = firstHediffOfDef?.Severity ?? 0f; // if (num2 < 0.9f && Rand.Value < largeOverdoseChance) // { // var num3 = Rand.Range(0.85f, 0.99f); // HealthUtility.AdjustSeverity(lookTarget, HediffDefOf.DrugOverdose, num3 - num2); // if (lookTarget.Faction == Faction.OfPlayer) // { // Messages.Message("MessageAccidentalOverdose".Translate(new object[] // { // lookTarget.LabelIndefinite(), // chemical.LabelCap // }).CapitalizeFirst(), MessageTypeDefOf.NegativeHealthEvent); // } // } // else // { // var num4 = overdoseSeverityOffset.RandomInRange / lookTarget.BodySize; // if (num4 > 0f) // { // HealthUtility.AdjustSeverity(lookTarget, HediffDefOf.DrugOverdose, num4); // } // } }
public static bool Replace_DoBirthSpawn(Pawn mother, Pawn father) { if (father is null || mother.kindDef == father.kindDef) { return(true); } var litterCount = Math.Min(GetLitterCount(mother), GetLitterCount(father)); List <(PawnKindDef p, List <HybridDef> h)> hybridKinds = null; if ( DogsMateMod.TryGetCompatibleFemales(father.kindDef, out var dict) && dict.TryGetValue(mother.kindDef, out var hybridDefs) && hybridDefs.Count > 0 ) { hybridKinds = hybridDefs.Select(h => h.children.Where(c => c.IsUsable).Select(a => (a, h))) .SelectMany(x => x).Select(ah => ah.a.pawnKinds.Where(p => p != null).Select(p => (p, ah.h))) .SelectMany(x => x).GroupBy(ph => ph.p) .Select(g => (g.Key, g.Select(ph => ph.h).Where(h => h.IsUsable).ToList())).ToList(); DogsMateMod.Debug( $"father=<{father.kindDef.ToStringSafe()}> " + $"mother=<{mother.kindDef.ToStringSafe()}> " + $"hybrids=<{hybridKinds.Select(ph => ph.p.label).ToCommaList()}>" ); } Pawn child = null; for (var childIndex = 0; childIndex < litterCount; ++childIndex) { PawnKindDef childKind; HybridDef hybridDef = null; if (hybridKinds != null) { hybridKinds.TryGetRandomElement(out var ph); ph.h.TryGetRandomElement(out hybridDef); childKind = ph.p; } else if (Rand.Value > 0.5f) { childKind = mother.kindDef; } else { childKind = father.kindDef; } bool newChildIsGood; var newChild = PawnGenerator.GeneratePawn(new PawnGenerationRequest( childKind, mother.Faction, forceGenerateNewPawn: false, newborn: true )); if (PawnUtility.TrySpawnHatchedOrBornPawn(newChild, mother)) { if (newChild.playerSettings != null && mother.playerSettings != null) { newChild.playerSettings.AreaRestriction = mother.playerSettings.AreaRestriction; } if (newChild.RaceProps.IsFlesh) { newChild.relations.AddDirectRelation(PawnRelationDefOf.Parent, mother); newChild.relations.AddDirectRelation(PawnRelationDefOf.Parent, father); } if (hybridDef != null) { AddHediffs(newChild, hybridDef.childrenHediffs); switch (newChild.gender) { case Gender.Male: AddHediffs(newChild, hybridDef.maleChildrenHediffs); break; case Gender.Female: AddHediffs(newChild, hybridDef.femaleChildrenHediffs); break; } } newChildIsGood = true; } else { Find.WorldPawns.PassToWorld(newChild, PawnDiscardDecideMode.Discard); newChildIsGood = false; } TaleRecorder.RecordTale(TaleDefOf.GaveBirth, mother, newChild); if (newChildIsGood) { child = newChild; } } if (!mother.Spawned) { return(false); } FilthMaker.TryMakeFilth(mother.Position, mother.Map, ThingDefOf.Filth_AmnioticFluid, mother.LabelIndefinite(), 5); mother.caller?.DoCall(); child?.caller?.DoCall(); return(false); }
protected override IEnumerable <Toil> MakeNewToils() { base.AddEndCondition(delegate() { var thing = base.GetActor().jobs.curJob.GetTarget(TargetIndex.A).Thing; if (thing is Building && !thing.Spawned) { return(JobCondition.Incompletable); } return(JobCondition.Ongoing); }); this.FailOnBurningImmobile <JobDriver_DoBill>(TargetIndex.A); this.FailOn <JobDriver_DoBill>(delegate() { if (!(this.job.GetTarget(TargetIndex.A).Thing is IBillGiver billGiver)) { return(false); } if (this.job.bill.DeletedOrDereferenced) { return(true); } if (!billGiver.CurrentlyUsableForBills()) { return(true); } return(false); }); yield return(Toils_Reserve.Reserve(TargetIndex.A, 1, -1, null)); yield return(Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.InteractionCell)); var tableThing = this.job.GetTarget(TargetIndex.A).Thing as Building_СontainmentBreach; CompRefuelable refuelableComp = tableThing.GetComp <CompRefuelable>(); Toil toil = new Toil(); toil.initAction = delegate() { this.job.bill.Notify_DoBillStarted(this.pawn); this.workCycleProgress = this.job.bill.recipe.workAmount; }; toil.tickAction = delegate() { this.workCycleProgress -= StatExtension.GetStatValue(this.pawn, StatDefOf.WorkToMake, true); tableThing.UsedThisTick(); if (!tableThing.CurrentlyUsableForBills() || (refuelableComp != null && !refuelableComp.HasFuel)) { this.pawn.jobs.EndCurrentJob(JobCondition.Incompletable, true, true); } if (this.workCycleProgress <= 0f) { SkillDef workSkill = this.job.bill.recipe.workSkill; if (workSkill != null) { SkillRecord skill = this.pawn.skills.GetSkill(workSkill); if (skill != null) { skill.Learn(0.11f * this.job.bill.recipe.workSkillLearnFactor, false); } } GenSpawn.Spawn(tableThing.GetKorsolianToxin(this.job.bill.recipe), tableThing.InteractionCell, tableThing.Map, 0); Toils_Reserve.Release(TargetIndex.A); PawnUtility.GainComfortFromCellIfPossible(this.pawn, false); this.job.bill.Notify_IterationCompleted(this.pawn, null); this.ReadyForNextToil(); } }; toil.defaultCompleteMode = ToilCompleteMode.Never; ToilEffects.WithEffect(toil, () => this.job.bill.recipe.effectWorking, TargetIndex.A); ToilEffects.PlaySustainerOrSound(toil, () => toil.actor.CurJob.bill.recipe.soundWorking); ToilEffects.WithProgressBar(toil, TargetIndex.A, delegate() { return(PurpleIvyUtils.GetPercentageFromPartWhole (this.job.bill.recipe.workAmount - this.workCycleProgress, (int)this.job.bill.recipe.workAmount) / 100f); }, false, 0.5f); ToilFailConditions.FailOn <Toil>(toil, delegate() { IBillGiver billGiver = this.job.GetTarget(TargetIndex.A).Thing as IBillGiver; return(this.job.bill.suspended || this.job.bill.DeletedOrDereferenced || (billGiver != null && !billGiver.CurrentlyUsableForBills())); }); yield return(toil); yield break; }
private static void EvaluateCell(IntVec3 c) { if (CastPositionFinder.maxRangeFromTargetSquared > 0.01f && CastPositionFinder.maxRangeFromTargetSquared < 250000f && (float)(c - CastPositionFinder.req.target.Position).LengthHorizontalSquared > CastPositionFinder.maxRangeFromTargetSquared) { if (DebugViewSettings.drawCastPositionSearch) { CastPositionFinder.req.caster.Map.debugDrawer.FlashCell(c, 0f, "range target", 50); } return; } if ((double)CastPositionFinder.maxRangeFromLocusSquared > 0.01 && (float)(c - CastPositionFinder.req.locus).LengthHorizontalSquared > CastPositionFinder.maxRangeFromLocusSquared) { if (DebugViewSettings.drawCastPositionSearch) { CastPositionFinder.req.caster.Map.debugDrawer.FlashCell(c, 0.1f, "range home", 50); } return; } if (CastPositionFinder.maxRangeFromCasterSquared > 0.01f) { CastPositionFinder.rangeFromCasterToCellSquared = (float)(c - CastPositionFinder.req.caster.Position).LengthHorizontalSquared; if (CastPositionFinder.rangeFromCasterToCellSquared > CastPositionFinder.maxRangeFromCasterSquared) { if (DebugViewSettings.drawCastPositionSearch) { CastPositionFinder.req.caster.Map.debugDrawer.FlashCell(c, 0.2f, "range caster", 50); } return; } } if (!c.Walkable(CastPositionFinder.req.caster.Map)) { return; } if (CastPositionFinder.req.maxRegions > 0 && c.GetRegion(CastPositionFinder.req.caster.Map, RegionType.Set_Passable).mark != CastPositionFinder.inRadiusMark) { if (DebugViewSettings.drawCastPositionSearch) { CastPositionFinder.req.caster.Map.debugDrawer.FlashCell(c, 0.64f, "reg radius", 50); } return; } if (!CastPositionFinder.req.caster.Map.reachability.CanReach(CastPositionFinder.req.caster.Position, c, PathEndMode.OnCell, TraverseParms.For(CastPositionFinder.req.caster, Danger.Some, TraverseMode.ByPawn, false))) { if (DebugViewSettings.drawCastPositionSearch) { CastPositionFinder.req.caster.Map.debugDrawer.FlashCell(c, 0.4f, "can't reach", 50); } return; } float num = CastPositionFinder.CastPositionPreference(c); if (CastPositionFinder.avoidGrid != null) { byte b = CastPositionFinder.avoidGrid[c]; num *= Mathf.Max(0.1f, (37.5f - (float)b) / 37.5f); } if (DebugViewSettings.drawCastPositionSearch) { CastPositionFinder.req.caster.Map.debugDrawer.FlashCell(c, num / 4f, num.ToString("F3"), 50); } if (num < CastPositionFinder.bestSpotPref) { return; } if (!CastPositionFinder.verb.CanHitTargetFrom(c, CastPositionFinder.req.target)) { if (DebugViewSettings.drawCastPositionSearch) { CastPositionFinder.req.caster.Map.debugDrawer.FlashCell(c, 0.6f, "can't hit", 50); } return; } if (!CastPositionFinder.req.caster.Map.pawnDestinationReservationManager.CanReserve(c, CastPositionFinder.req.caster, false)) { if (DebugViewSettings.drawCastPositionSearch) { CastPositionFinder.req.caster.Map.debugDrawer.FlashCell(c, num * 0.9f, "resvd", 50); } return; } if (PawnUtility.KnownDangerAt(c, CastPositionFinder.req.caster.Map, CastPositionFinder.req.caster)) { if (DebugViewSettings.drawCastPositionSearch) { CastPositionFinder.req.caster.Map.debugDrawer.FlashCell(c, 0.9f, "danger", 50); } return; } CastPositionFinder.bestSpot = c; CastPositionFinder.bestSpotPref = num; }
private void CheckDiscovered() { if (!this.discovered) { if (this.parent.CurStage.becomeVisible) { this.discovered = true; if (this.Props.sendLetterWhenDiscovered && PawnUtility.ShouldSendNotificationAbout(base.Pawn)) { if (base.Pawn.RaceProps.Humanlike) { string label; if (!this.Props.discoverLetterLabel.NullOrEmpty()) { label = string.Format(this.Props.discoverLetterLabel, base.Pawn.LabelShort.CapitalizeFirst()).CapitalizeFirst(); } else { label = "LetterLabelNewDisease".Translate() + " (" + base.Def.label + ")"; } string text; if (!this.Props.discoverLetterText.NullOrEmpty()) { text = string.Format(this.Props.discoverLetterText, base.Pawn.LabelIndefinite()).AdjustedFor(base.Pawn, "PAWN").CapitalizeFirst(); } else if (this.parent.Part == null) { text = "NewDisease".Translate(new object[] { base.Pawn.LabelIndefinite(), base.Def.label, base.Pawn.LabelDefinite() }).AdjustedFor(base.Pawn, "PAWN").CapitalizeFirst(); } else { text = "NewPartDisease".Translate(new object[] { base.Pawn.LabelIndefinite(), this.parent.Part.Label, base.Pawn.LabelDefinite(), base.Def.LabelCap }).AdjustedFor(base.Pawn, "PAWN").CapitalizeFirst(); } Find.LetterStack.ReceiveLetter(label, text, (this.Props.letterType == null) ? LetterDefOf.NegativeEvent : this.Props.letterType, base.Pawn, null, null); } else { string text2; if (!this.Props.discoverLetterText.NullOrEmpty()) { text2 = string.Format(this.Props.discoverLetterText, base.Pawn.LabelIndefinite()).AdjustedFor(base.Pawn, "PAWN").CapitalizeFirst(); } else if (this.parent.Part == null) { text2 = "NewDiseaseAnimal".Translate(new object[] { base.Pawn.LabelShort, base.Def.LabelCap, base.Pawn.LabelDefinite() }).AdjustedFor(base.Pawn, "PAWN").CapitalizeFirst(); } else { text2 = "NewPartDiseaseAnimal".Translate(new object[] { base.Pawn.LabelShort, this.parent.Part.Label, base.Pawn.LabelDefinite(), base.Def.LabelCap }).AdjustedFor(base.Pawn, "PAWN").CapitalizeFirst(); } Messages.Message(text2, base.Pawn, (this.Props.messageType == null) ? MessageTypeDefOf.NegativeHealthEvent : this.Props.messageType, true); } } } } }
/// <summary> /// GC().The best way to shrink Rimworld saves,I think. /// </summary> /// <param name="verbose">Determine if GC() should log details very very verbosely</param> /// <returns>Count of disposed World pawns</returns> public int GC(bool verbose = false) { /* * TODO Log * 1.talelog by interest -X * 2.animal - deconstruct relation -Done * 3.deeperclean?remove hediffs -X * 5.correct verbose log -Done * 6.yield return "status" -X * 7.UI compability -Done * 8.Filth cleaner -Done * 9.Fix:Faction Leader -Done * 10.Fix:Faction Relations -Done * 12.Warp->Wrap -Done */ /* * TODO A18 * 4.adjustable GC depth -X * 11.GC boostup -Done * 13.remake GC System -Done * 13.Keyed in Float menu items -Done * 14.help contents -Done * 15.Optimize Cleanser frame -Done * 16.Optimize Floatmenu System -Done * 17.Debug only options -Done */ /* * TODO 1.0 * 18.Clean snow -Done * 19.whole-map clean -Done * 20.remake log -Done * 21.Mod framework -Done * 22.settings -Done * 23.MuteGC -Done * 24.MuteCL -Done * 25.remake FloatMenuUtil -Done * 26.timer of gc -X * 27.toolbox integration -Done * 28.MainButtonDef into xml -Done * 29.try catch -Done * 30.Find.CurrentMap==null check -Done * 31.MainButtonWorker -Done * 32.Messages.Message(str,historical) settings -Done * 33.AvoidGrid rework -Done * 34.Faction rework & cleanup -Done * 35.Close letter stack -Done */ if (Current.ProgramState != ProgramState.Playing) { Verse.Log.Error("You must be kidding me...GC a save without loading one?"); return(0); } /*Initialization*/ Verse.Log.Message("[GC Log] Pre-Initializing GC..."); this.reference = Find.WorldPawns.AllPawnsAliveOrDead.ToList(); this.allFlags.Clear(); this.verbose = verbose; if (verbose) { allFlagsCounter.Clear(); allFlagsCounter.Add(Flags.None, 0); for (int j = 0; j < FlagsCountNotNull; j++) { allFlagsCounter.Add((Flags)(1 << j), 0); } } /*Generate EntryPoints from Map Pawns*/ Verse.Log.Message("[GC Log] Generating EntryPoints from Map Pawns..."); List <Pawn> mapPawnEntryPoints; DiagnoseMapPawns(out mapPawnEntryPoints); if (verbose) { Verse.Log.Message("[GC Log][Verbose] " + allPawnsCounter.Count().ToString() + " Map Pawns marked during diagnosis"); } /*Reset counters*/ allPawnsCounter.Clear(); if (verbose) { allFlagsCounter.Clear(); allFlagsCounter.Add(Flags.None, 0); for (int j = 0; j < FlagsCountNotNull; j++) { allFlagsCounter.Add((Flags)(1 << j), 0); } } /*Generate a list of pawns concerned by used Tales*/ Verse.Log.Message("[GC Log] Collecting Pawns concerned by Used Tales..."); List <Pawn> allUsedTalePawns; CleanserUtil.InitUsedTalePawns(out allUsedTalePawns); /*Diagnosis:marking entries on WorldPawns.*/ Verse.Log.Message("[GC Log] Running diagnosis on WorldPawns..."); foreach (Pawn p in reference) { if (p.IsColonist) { addFlag(p, Flags.Colonist | Flags.RelationLvl2); } if (p.IsPrisonerOfColony) { addFlag(p, Flags.Prisoner | Flags.RelationLvl2); } if (PawnUtility.IsFactionLeader(p)) { addFlag(p, Flags.KeptWorldPawn | Flags.FactionLeader | Flags.RelationLvl1); } if (PawnUtility.IsKidnappedPawn(p)) { addFlag(p, Flags.KeptWorldPawn | Flags.RelationLvl2); } if (p.Corpse != null) { addFlag(p, Flags.CorpseOwner | Flags.RelationLvl1); } if (allUsedTalePawns.Contains(p)) { addFlag(p, Flags.TaleEntryOwner | Flags.RelationLvl0); } if (p.InContainerEnclosed) { addFlag(p, Flags.KeptWorldPawn | Flags.RelationLvl0); } if (p.Spawned) { addFlag(p, Flags.RelationLvl0); } if (p.IsPlayerControlledCaravanMember()) { addFlag(p, Flags.KeptWorldPawn | Flags.RelationLvl2); } if (PawnUtility.IsTravelingInTransportPodWorldObject(p)) { addFlag(p, Flags.KeptWorldPawn | Flags.RelationLvl2); } //Patch:A18 new entry if (PawnUtility.ForSaleBySettlement(p)) { addFlag(p, Flags.OnSale | Flags.RelationLvl0); } if (verbose) { Verse.Log.Message("[worldPawn] " + p.LabelShort + " [flag] " + markedFlagsString(p)); } } if (verbose) { Verse.Log.Message("[GC Log][Verbose] " + allPawnsCounter.Count().ToString() + " World Pawns marked during diagnosis"); } int i; /*Expansion 1:Expand relation network from map pawns.*/ Verse.Log.Message("[GC Log] Expanding Relation networks through Map Pawn Entry Points..."); for (i = mapPawnEntryPoints.Count - 1; i > -1; i--) { if (containsFlag(mapPawnEntryPoints[i], Flags.RelationLvl2)) { expandRelation(mapPawnEntryPoints[i], Flags.RelationLvl1); mapPawnEntryPoints.RemoveAt(i); } } for (i = mapPawnEntryPoints.Count - 1; i > -1; i--) { if (containsFlag(mapPawnEntryPoints[i], Flags.RelationLvl1)) { expandRelation(mapPawnEntryPoints[i], Flags.RelationLvl0); mapPawnEntryPoints.RemoveAt(i); } } /*Its unnecessary to process RelationLvl0 in mapPawnEntryPoints, * for they are not related to any world pawns. */ /*Expansion 2:Expand relation network from world pawns.*/ Verse.Log.Message("[GC Log] Expanding Relation networks on marked World Pawns..."); for (i = reference.Count - 1; i > -1; i--) { if (containsFlag(reference[i], Flags.RelationLvl2)) { expandRelation(reference[i], Flags.RelationLvl1); reference.RemoveAt(i); } } for (i = reference.Count - 1; i > -1; i--) { if (containsFlag(reference[i], Flags.RelationLvl1)) { expandRelation(reference[i], Flags.RelationLvl0); reference.RemoveAt(i); } } for (i = reference.Count - 1; i > -1; i--) { if (containsFlag(reference[i], Flags.RelationLvl0)) { reference.RemoveAt(i); } } int a = 0; /*VerboseMode:counting addFlag() calls.*/ if (verbose) { foreach (KeyValuePair <Pawn, int> p in allPawnsCounter) { a += p.Value; } Verse.Log.Message("[GC Log][Verbose] " + allPawnsCounter.Count().ToString() + " World Pawns marked during Expanding"); if (debug) { Verse.Log.Message("addFlag() called " + a + " times"); } } /*Posfix:remove UsedTalePawns.*/ Verse.Log.Message("[GC Log] Excluding Pawns concerned by Used Tales..."); foreach (Pawn p in allUsedTalePawns) { reference.Remove(p); } /*GC Core:dispose all pawns left in reference list.*/ Verse.Log.Message("[GC Log] Disposing World Pawns..."); a = reference.Count; Pawn pawn; for (i = reference.Count - 1; i > -1; i--) { pawn = reference[i]; //Patch:Mysterious WorldPawn.missing //Update:This patch is disabled due to safety concerns. //if(Find.WorldPawns.Contains(pawn)) Find.WorldPawns.RemovePawn(pawn); if (!pawn.Destroyed) { pawn.Destroy(DestroyMode.Vanish); } if (!pawn.Discarded) { pawn.Discard(true); } } /*VerboseMode:Finalize output*/ if (verbose) { string s = "[GC Log][Verbose] Flag calls stat:"; allFlagsCounter.Remove(Flags.None); foreach (KeyValuePair <Flags, int> pair in allFlagsCounter) { s += "\n " + pair.Key.ToString() + " : " + pair.Value; } Verse.Log.Message(s); } Verse.Log.Message("[GC Log] GC() completed with " + a + " World Pawns disposed"); return(a); }
public void Notify_DamageTaken(DamageInfo dinfo) { this.mentalStateHandler.Notify_DamageTaken(dinfo); if (dinfo.Def.ExternalViolenceFor(this.pawn)) { this.lastHarmTick = Find.TickManager.TicksGame; if (this.pawn.Spawned) { Pawn pawn = dinfo.Instigator as Pawn; if (!this.mentalStateHandler.InMentalState && dinfo.Instigator != null && (pawn != null || dinfo.Instigator is Building_Turret) && dinfo.Instigator.Faction != null && (dinfo.Instigator.Faction.def.humanlikeFaction || (pawn != null && pawn.def.race.intelligence >= Intelligence.ToolUser)) && this.pawn.Faction == null && (this.pawn.RaceProps.Animal || this.pawn.IsWildMan()) && (this.pawn.CurJob == null || this.pawn.CurJob.def != JobDefOf.PredatorHunt || dinfo.Instigator != ((JobDriver_PredatorHunt)this.pawn.jobs.curDriver).Prey) && Rand.Chance(PawnUtility.GetManhunterOnDamageChance(this.pawn, dinfo.Instigator))) { this.StartManhunterBecauseOfPawnAction("AnimalManhunterFromDamage"); } else if (dinfo.Instigator != null && dinfo.Def.makesAnimalsFlee && Pawn_MindState.CanStartFleeingBecauseOfPawnAction(this.pawn)) { this.StartFleeingBecauseOfPawnAction(dinfo.Instigator); } } if (this.pawn.GetPosture() != PawnPosture.Standing) { this.lastDisturbanceTick = Find.TickManager.TicksGame; } } }
public void MindStateTick() { if (this.wantsToTradeWithColony) { TradeUtility.CheckInteractWithTradersTeachOpportunity(this.pawn); } if (this.meleeThreat != null && !this.MeleeThreatStillThreat) { this.meleeThreat = null; } this.mentalStateHandler.MentalStateHandlerTick(); this.mentalBreaker.MentalBreakerTick(); this.inspirationHandler.InspirationHandlerTick(); if (!this.pawn.GetPosture().Laying()) { this.applyBedThoughtsTick = 0; } if (this.pawn.IsHashIntervalTick(100)) { if (this.pawn.Spawned) { int regionsToScan = (!this.anyCloseHostilesRecently) ? 18 : 24; this.anyCloseHostilesRecently = PawnUtility.EnemiesAreNearby(this.pawn, regionsToScan, true); } else { this.anyCloseHostilesRecently = false; } } if (this.WillJoinColonyIfRescued && this.pawn.Spawned && this.pawn.IsHashIntervalTick(30)) { if (this.pawn.Faction == Faction.OfPlayer) { this.WillJoinColonyIfRescued = false; } else if (this.pawn.IsPrisoner && !this.pawn.HostFaction.HostileTo(Faction.OfPlayer)) { this.WillJoinColonyIfRescued = false; } else if (!this.pawn.IsPrisoner && this.pawn.Faction != null && this.pawn.Faction.HostileTo(Faction.OfPlayer) && !this.pawn.Downed) { this.WillJoinColonyIfRescued = false; } else { foreach (Pawn current in this.pawn.Map.mapPawns.FreeColonistsSpawned) { if (current.IsColonistPlayerControlled && current.Position.InHorDistOf(this.pawn.Position, 4f) && GenSight.LineOfSight(this.pawn.Position, current.Position, this.pawn.Map, false, null, 0, 0)) { this.JoinColonyBecauseRescuedBy(current); break; } } } } if (this.pawn.Spawned && this.pawn.IsWildMan() && !this.WildManEverReachedOutside && this.pawn.GetRoom(RegionType.Set_Passable) != null && this.pawn.GetRoom(RegionType.Set_Passable).TouchesMapEdge) { this.WildManEverReachedOutside = true; } if (Find.TickManager.TicksGame % 123 == 0 && this.pawn.Spawned && this.pawn.RaceProps.IsFlesh && this.pawn.needs.mood != null) { TerrainDef terrain = this.pawn.Position.GetTerrain(this.pawn.Map); if (terrain.traversedThought != null) { this.pawn.needs.mood.thoughts.memories.TryGainMemoryFast(terrain.traversedThought); } WeatherDef curWeatherLerped = this.pawn.Map.weatherManager.CurWeatherLerped; if (curWeatherLerped.exposedThought != null && !this.pawn.Position.Roofed(this.pawn.Map)) { this.pawn.needs.mood.thoughts.memories.TryGainMemoryFast(curWeatherLerped.exposedThought); } } if (GenLocalDate.DayTick(this.pawn) == 0) { this.interactionsToday = 0; } }
public static bool FindPath(PathFinder __instance, ref PawnPath __result, IntVec3 start, LocalTargetInfo dest, TraverseParms traverseParms, PathEndMode peMode = PathEndMode.OnCell) { if (DebugSettings.pathThroughWalls) { traverseParms.mode = TraverseMode.PassAllDestroyableThings; } Pawn pawn = traverseParms.pawn; if (pawn != null && pawn.Map != __instance.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=", __instance.map)); __result = PawnPath.NotFound; return(false); } if (!start.IsValid) { Log.Error(string.Concat("Tried to FindPath with invalid start ", start, ", pawn= ", pawn)); __result = PawnPath.NotFound; return(false); } if (!dest.IsValid) { Log.Error(string.Concat("Tried to FindPath with invalid dest ", dest, ", pawn= ", pawn)); __result = PawnPath.NotFound; return(false); } if (traverseParms.mode == TraverseMode.ByPawn) { #if RW12 if (!pawn.CanReach(dest, peMode, Danger.Deadly, traverseParms.canBash, traverseParms.mode)) #endif #if RW13 if (!pawn.CanReach(dest, peMode, Danger.Deadly, traverseParms.canBashDoors, traverseParms.canBashFences, traverseParms.mode)) #endif { __result = PawnPath.NotFound; return(false); } } else if (!__instance.map.reachability.CanReach(start, dest, peMode, traverseParms)) { __result = PawnPath.NotFound; return(false); } __instance.PfProfilerBeginSample(string.Concat("FindPath for ", pawn, " from ", start, " to ", dest, dest.HasThing ? (" at " + dest.Cell) : "")); __instance.cellIndices = __instance.map.cellIndices; #if RW12 __instance.pathGrid = __instance.map.pathGrid; #endif #if RW13 __instance.pathingContext = __instance.map.pathing.For(traverseParms); __instance.pathGrid = __instance.pathingContext.pathGrid; #endif __instance.edificeGrid = __instance.map.edificeGrid.InnerArray; __instance.blueprintGrid = __instance.map.blueprintGrid.InnerArray; int x = dest.Cell.x; int z = dest.Cell.z; int curIndex = __instance.cellIndices.CellToIndex(start); int num = __instance.cellIndices.CellToIndex(dest.Cell); ByteGrid byteGrid = pawn?.GetAvoidGrid(); bool flag = traverseParms.mode == TraverseMode.PassAllDestroyableThings || traverseParms.mode == TraverseMode.PassAllDestroyableThingsNotWater; bool flag2 = traverseParms.mode != TraverseMode.NoPassClosedDoorsOrWater && traverseParms.mode != TraverseMode.PassAllDestroyableThingsNotWater; bool flag3 = !flag; CellRect destinationRect = __instance.CalculateDestinationRect(dest, peMode); bool flag4 = destinationRect.Width == 1 && destinationRect.Height == 1; #if RW12 int[] array = __instance.map.pathGrid.pathGrid; #endif #if RW13 int[] array = __instance.pathGrid.pathGrid; #endif TerrainDef[] topGrid = __instance.map.terrainGrid.topGrid; EdificeGrid edificeGrid = __instance.map.edificeGrid; int num2 = 0; int num3 = 0; Area allowedArea = __instance.GetAllowedArea(pawn); bool flag5 = pawn != null && PawnUtility.ShouldCollideWithPawns(pawn); bool flag6 = !flag && start.GetRegion(__instance.map) != null && flag2; bool flag7 = !flag || !flag3; bool flag8 = false; bool flag9 = pawn?.Drafted ?? false; int num4 = (pawn?.IsColonist ?? false) ? 100000 : 2000; int num5 = 0; int num6 = 0; float num7 = __instance.DetermineHeuristicStrength(pawn, start, dest); int num8; int num9; if (pawn != null) { num8 = pawn.TicksPerMoveCardinal; num9 = pawn.TicksPerMoveDiagonal; } else { num8 = 13; num9 = 18; } #if RW12 __instance.CalculateAndAddDisallowedCorners(traverseParms, peMode, destinationRect); #endif #if RW13 __instance.CalculateAndAddDisallowedCorners(peMode, destinationRect); #endif __instance.InitStatusesAndPushStartNode(ref curIndex, start); while (true) { __instance.PfProfilerBeginSample("Open cell"); if (openList.Count <= 0) { string text = (pawn != null && pawn.CurJob != null) ? pawn.CurJob.ToString() : "null"; string text2 = (pawn != null && pawn.Faction != null) ? pawn.Faction.ToString() : "null"; Log.Warning(string.Concat(pawn, " pathing from ", start, " to ", dest, " ran out of cells to process.\nJob:", text, "\nFaction: ", text2)); __instance.DebugDrawRichData(); __instance.PfProfilerEndSample(); __instance.PfProfilerEndSample(); __result = PawnPath.NotFound; return(false); } num5 += openList.Count; num6++; PathFinder.CostNode costNode = openList.Pop(); curIndex = costNode.index; if (costNode.cost != calcGrid[curIndex].costNodeCost) { __instance.PfProfilerEndSample(); continue; } if (calcGrid[curIndex].status == statusClosedValue) { __instance.PfProfilerEndSample(); continue; } IntVec3 c = __instance.cellIndices.IndexToCell(curIndex); int x2 = c.x; int z2 = c.z; if (flag4) { if (curIndex == num) { __instance.PfProfilerEndSample(); PawnPath result = __instance.FinalizedPath(curIndex, flag8); __instance.PfProfilerEndSample(); __result = result; return(false); } } else if (destinationRect.Contains(c) && !disallowedCornerIndices.Contains(curIndex)) { __instance.PfProfilerEndSample(); PawnPath result2 = __instance.FinalizedPath(curIndex, flag8); __instance.PfProfilerEndSample(); __result = result2; return(false); } if (num2 > 160000) { break; } __instance.PfProfilerEndSample(); __instance.PfProfilerBeginSample("Neighbor consideration"); for (int i = 0; i < 8; i++) { uint num10 = (uint)(x2 + PathFinder.Directions[i]); uint num11 = (uint)(z2 + PathFinder.Directions[i + 8]); if (num10 >= __instance.mapSizeX || num11 >= __instance.mapSizeZ) { continue; } int num12 = (int)num10; int num13 = (int)num11; int num14 = __instance.cellIndices.CellToIndex(num12, num13); if (calcGrid[num14].status == statusClosedValue && !flag8) { continue; } int num15 = 0; bool flag10 = false; if (!flag2 && new IntVec3(num12, 0, num13).GetTerrain(__instance.map).HasTag("Water")) { continue; } if (!__instance.pathGrid.WalkableFast(num14)) { if (!flag) { continue; } flag10 = true; num15 += 70; Building building = edificeGrid[num14]; if (building == null || !PathFinder.IsDestroyable(building)) { continue; } num15 += (int)(building.HitPoints * 0.2f); } switch (i) { case 4: if (__instance.BlocksDiagonalMovement(curIndex - __instance.mapSizeX)) { if (flag7) { continue; } num15 += 70; } if (__instance.BlocksDiagonalMovement(curIndex + 1)) { if (flag7) { continue; } num15 += 70; } break; case 5: if (__instance.BlocksDiagonalMovement(curIndex + __instance.mapSizeX)) { if (flag7) { continue; } num15 += 70; } if (__instance.BlocksDiagonalMovement(curIndex + 1)) { if (flag7) { continue; } num15 += 70; } break; case 6: if (__instance.BlocksDiagonalMovement(curIndex + __instance.mapSizeX)) { if (flag7) { continue; } num15 += 70; } if (__instance.BlocksDiagonalMovement(curIndex - 1)) { if (flag7) { continue; } num15 += 70; } break; case 7: if (__instance.BlocksDiagonalMovement(curIndex - __instance.mapSizeX)) { if (flag7) { continue; } num15 += 70; } if (__instance.BlocksDiagonalMovement(curIndex - 1)) { if (flag7) { continue; } num15 += 70; } break; } int num16 = (i > 3) ? num9 : num8; num16 += num15; if (!flag10) { num16 += array[num14]; num16 = ((!flag9) ? (num16 + topGrid[num14].extraNonDraftedPerceivedPathCost) : (num16 + topGrid[num14].extraDraftedPerceivedPathCost)); } if (byteGrid != null) { num16 += byteGrid[num14] * 8; } if (allowedArea != null && !allowedArea[num14]) { num16 += 600; } if (flag5 && PawnUtility.AnyPawnBlockingPathAt(new IntVec3(num12, 0, num13), pawn, actAsIfHadCollideWithPawnsJob: false, collideOnlyWithStandingPawns: false, forPathFinder: true)) { num16 += 175; } Building building2 = __instance.edificeGrid[num14]; if (building2 != null) { __instance.PfProfilerBeginSample("Edifices"); int buildingCost = PathFinder.GetBuildingCost(building2, traverseParms, pawn); if (buildingCost == int.MaxValue) { __instance.PfProfilerEndSample(); continue; } num16 += buildingCost; __instance.PfProfilerEndSample(); } List <Blueprint> list = __instance.blueprintGrid[num14]; if (list != null) { __instance.PfProfilerBeginSample("Blueprints"); int num17 = 0; for (int j = 0; j < list.Count; j++) { num17 = Mathf.Max(num17, PathFinder.GetBlueprintCost(list[j], pawn)); } if (num17 == int.MaxValue) { __instance.PfProfilerEndSample(); continue; } num16 += num17; __instance.PfProfilerEndSample(); } int num18 = num16 + calcGrid[curIndex].knownCost; ushort status = calcGrid[num14].status; if (status == statusClosedValue || status == statusOpenValue) { int num19 = 0; if (status == statusClosedValue) { num19 = num8; } if (calcGrid[num14].knownCost <= num18 + num19) { continue; } } if (flag8) { calcGrid[num14].heuristicCost = Mathf.RoundToInt(__instance.regionCostCalculator.GetPathCostFromDestToRegion(num14) * PathFinder.RegionHeuristicWeightByNodesOpened.Evaluate(num3)); if (calcGrid[num14].heuristicCost < 0) { Log.ErrorOnce(string.Concat("Heuristic cost overflow for ", pawn.ToStringSafe(), " pathing from ", start, " to ", dest, "."), pawn.GetHashCode() ^ 0xB8DC389); calcGrid[num14].heuristicCost = 0; } } else if (status != statusClosedValue && status != statusOpenValue) { int dx = Math.Abs(num12 - x); int dz = Math.Abs(num13 - z); int num20 = GenMath.OctileDistance(dx, dz, num8, num9); calcGrid[num14].heuristicCost = Mathf.RoundToInt(num20 * num7); } int num21 = num18 + calcGrid[num14].heuristicCost; if (num21 < 0) { Log.ErrorOnce(string.Concat("Node cost overflow for ", pawn.ToStringSafe(), " pathing from ", start, " to ", dest, "."), pawn.GetHashCode() ^ 0x53CB9DE); num21 = 0; } calcGrid[num14].parentIndex = curIndex; calcGrid[num14].knownCost = num18; calcGrid[num14].status = statusOpenValue; calcGrid[num14].costNodeCost = num21; num3++; openList.Push(new PathFinder.CostNode(num14, num21)); } __instance.PfProfilerEndSample(); num2++; calcGrid[curIndex].status = statusClosedValue; if (num3 >= num4 && flag6 && !flag8) { flag8 = true; __instance.regionCostCalculator.Init(destinationRect, traverseParms, num8, num9, byteGrid, allowedArea, flag9, disallowedCornerIndices); __instance.InitStatusesAndPushStartNode(ref curIndex, start); openList.Clear(); openList.Push(new PathFinder.CostNode(curIndex, 0)); num3 = 0; num2 = 0; } } Log.Warning(string.Concat(pawn, " pathing from ", start, " to ", dest, " hit search limit of ", 160000, " cells.")); __instance.DebugDrawRichData(); __instance.PfProfilerEndSample(); __instance.PfProfilerEndSample(); __result = PawnPath.NotFound; return(false); }
private WorkPriority GetPriorityWork(Pawn pawn) { #region Traders have no work priority if (pawn.kindDef.trader) { return(WorkPriority.None); } #endregion //#region Pawns with non-idle jobs have no work priority //bool hasCurJob = pawn.CurJob != null; //JobDef jobDef = hasCurJob ? pawn.CurJob.def : null; //if (hasCurJob && !jobDef.isIdle) //{ // return WorkPriority.None; //} //#endregion bool hasPrimary = (pawn.equipment != null && pawn.equipment.Primary != null); CompAmmoUser primaryAmmoUser = hasPrimary ? pawn.equipment.Primary.TryGetComp <CompAmmoUser>() : hasWeaponInInventory(pawn) ? weaponInInventory(pawn) : null; #region Colonists with primary ammo-user and a loadout have no work priority if (pawn.Faction.IsPlayer && primaryAmmoUser != null) { Loadout loadout = pawn.GetLoadout(); // if (loadout != null && !loadout.Slots.NullOrEmpty()) if (loadout != null && loadout.SlotCount > 0) { return(WorkPriority.None); } } #endregion // Pawns without weapon.. if (!hasPrimary) { // With inventory && non-colonist && not stealing && little space left if (Unload(pawn)) { return(WorkPriority.Unloading); } // Without inventory || colonist || stealing || lots of space left if (!hasWeaponInInventory(pawn)) { return(WorkPriority.Weapon); } } CompInventory compInventory = pawn.TryGetComp <CompInventory>(); // Pawn with ammo-using weapon.. if (primaryAmmoUser != null && primaryAmmoUser.UseAmmo) { // Magazine size FloatRange magazineSize = new FloatRange(1f, 2f); LoadoutPropertiesExtension loadoutPropertiesExtension = (LoadoutPropertiesExtension)(pawn.kindDef.modExtensions?.FirstOrDefault(x => x is LoadoutPropertiesExtension)); bool hasWeaponTags = pawn.kindDef.weaponTags?.Any() ?? false; if (hasWeaponTags && primaryAmmoUser.parent.def.weaponTags.Any(pawn.kindDef.weaponTags.Contains) && loadoutPropertiesExtension != null && loadoutPropertiesExtension.primaryMagazineCount != FloatRange.Zero) { magazineSize.min = loadoutPropertiesExtension.primaryMagazineCount.min; magazineSize.max = loadoutPropertiesExtension.primaryMagazineCount.max; } magazineSize.min *= primaryAmmoUser.Props.magazineSize; magazineSize.max *= primaryAmmoUser.Props.magazineSize; // Number of things in inventory that could be put in the weapon int viableAmmoCarried = 0; float viableAmmoBulk = 0; foreach (AmmoLink link in primaryAmmoUser.Props.ammoSet.ammoTypes) { var count = compInventory.AmmoCountOfDef(link.ammo); viableAmmoCarried += count; viableAmmoBulk += count * link.ammo.GetStatValueAbstract(CE_StatDefOf.Bulk); } // ~2/3rds of the inventory bulk minus non-usable and non-ammo bulk could be filled with ammo float potentialAmmoBulk = ammoFractionOfNonAmmoInventory * (compInventory.capacityBulk - compInventory.currentBulk + viableAmmoBulk); // There's less ammo [bulk] than fits the potential ammo bulk [bulk] if (viableAmmoBulk < potentialAmmoBulk) { // There's less ammo [nr] than fits a clip [nr] if (primaryAmmoUser.Props.magazineSize == 0 || viableAmmoCarried < magazineSize.min) { return(Unload(pawn) ? WorkPriority.Unloading : WorkPriority.LowAmmo); } // There's less ammo [nr] than fits two clips [nr] && no enemies are close if (viableAmmoCarried < magazineSize.max && !PawnUtility.EnemiesAreNearby(pawn, 20, true)) { return(Unload(pawn) ? WorkPriority.Unloading : WorkPriority.Ammo); } } } return(WorkPriority.None); }
void TickAction() { var fadeOff = Tools.PheromoneFadeoff(); var agitatedFadeoff = fadeOff / 4; var checkSmashableFadeoff = agitatedFadeoff / 2; var zombie = (Zombie)pawn; if (zombie.state == ZombieState.Emerging) { return; } var map = zombie.Map; if (zombie.Dead || zombie.Destroyed) { EndJobWith(JobCondition.InterruptForced); return; } if (zombie.state == ZombieState.ShouldDie) { EndJobWith(JobCondition.InterruptForced); zombie.Kill(null); return; } if (ZombieSettings.Values.zombiesDieVeryEasily) { if (zombie.health.hediffSet.GetHediffs <Hediff_Injury>().Any()) { zombie.Kill(null); return; } } if (zombie.Downed) { if (ZombieSettings.Values.zombiesDieVeryEasily || ZombieSettings.Values.doubleTapRequired == false) { zombie.Kill(null); return; } var walkCapacity = PawnCapacityUtility.CalculateCapacityLevel(zombie.health.hediffSet, PawnCapacityDefOf.Moving); var missingBrain = zombie.health.hediffSet.GetBrain() == null; if (walkCapacity < 0.25f || missingBrain) { zombie.Kill(null); return; } var injuries = zombie.health.hediffSet.GetHediffs <Hediff_Injury>(); foreach (var injury in injuries) { if (ZombieSettings.Values.zombiesDieVeryEasily) { zombie.Kill(null); return; } if (injury.IsOld() == false) { injury.Heal(injury.Severity + 0.5f); break; } } if (zombie.Downed) { return; } } // handling invalid destinations // if (destination.x == 0 && destination.z == 0) { destination = IntVec3.Invalid; } if (zombie.HasValidDestination(destination)) { return; } // if we are near targets then attack them // var enemy = CanAttack(); if (enemy != null) { destination = enemy.Position; zombie.state = ZombieState.Tracking; if (Constants.USE_SOUND) { var info = SoundInfo.InMap(enemy); SoundDef.Named("ZombieHit").PlayOneShot(info); } AttackThing(enemy, JobDefOf.AttackMelee); return; } // eat a downed or dead pawn // if (eatTarget == null) { eatTarget = CanIngest(out eatTargetIsCorpse); if (eatTarget != null) { eatTargetDied = eatTarget.Dead; } } if (eatTarget != null) { if (eatDelayCounter == 0) { if (eatTarget != lastEatTarget) { lastEatTarget = eatTarget; zombie.Drawer.rotator.FaceCell(eatTarget.Position); var zombieLeaner = zombie.Drawer.leaner as ZombieLeaner; if (zombieLeaner != null) { zombieLeaner.extraOffset = (eatTarget.Position.ToVector3() - zombie.Position.ToVector3()) * 0.5f; } Tools.CastThoughtBubble(pawn, Constants.EATING); } CastEatingSound(); } eatDelayCounter++; if (eatDelayCounter <= EatDelay) { return; } eatDelayCounter = 0; var bodyPartRecord = FirstEatablePart(eatTarget); if (bodyPartRecord != null) { var hediff_MissingPart = (Hediff_MissingPart)HediffMaker.MakeHediff(HediffDefOf.MissingBodyPart, eatTarget, bodyPartRecord); hediff_MissingPart.lastInjury = HediffDefOf.Bite; hediff_MissingPart.IsFresh = true; eatTarget.health.AddHediff(hediff_MissingPart, null, null); if (eatTargetIsCorpse == false && eatTargetDied == false && eatTarget.Dead) { Tools.DoWithAllZombies(map, z => { if (z.jobs != null) { var driver = z.jobs.curDriver as JobDriver_Stumble; if (driver != null && driver.eatTarget == eatTarget) { driver.eatTargetDied = true; driver.eatTargetIsCorpse = true; } } }); if (PawnUtility.ShouldSendNotificationAbout(eatTarget) && eatTarget.RaceProps.Humanlike) { Messages.Message("MessageEatenByPredator".Translate(new object[] { eatTarget.LabelShort, zombie.LabelIndefinite() }).CapitalizeFirst(), zombie, MessageSound.Negative); } eatTarget.Strip(); } return; } else { var corpse = map.thingGrid .ThingsListAt(eatTarget.Position) .OfType <Corpse>() .FirstOrDefault(c => c.InnerPawn == eatTarget); if (corpse != null) { corpse.Destroy(DestroyMode.Vanish); } Tools.DoWithAllZombies(map, z => { if (z.jobs != null) { var driver = z.jobs.curDriver as JobDriver_Stumble; if (driver != null && driver.eatTarget == eatTarget) { driver.eatTarget = null; driver.lastEatTarget = null; driver.eatDelayCounter = 0; } } }); } } else { var zombieLeaner = zombie.Drawer.leaner as ZombieLeaner; if (zombieLeaner != null) { zombieLeaner.extraOffset = Vector3.zero; } } var basePos = zombie.Position; // calculate possible moves, sort by pheromone value and take top 3 // then choose the one with the lowest zombie count // also, emit a circle of timestamps when discovering a pheromone // trace so nearby zombies pick it up too (leads to a chain reaction) // var grid = zombie.Map.GetGrid(); var possibleTrackingMoves = new List <IntVec3>(); var currentTicks = Tools.Ticks(); var timeDelta = long.MaxValue; for (int i = 0; i < 8; i++) { var pos = basePos + GenAdj.AdjacentCells[i]; if (currentTicks - grid.Get(pos, false).timestamp < fadeOff && zombie.HasValidDestination(pos)) { possibleTrackingMoves.Add(pos); } } if (possibleTrackingMoves.Count > 0) { possibleTrackingMoves.Sort((p1, p2) => SortByTimestamp(grid, p1, p2)); possibleTrackingMoves = possibleTrackingMoves.Take(Constants.NUMBER_OF_TOP_MOVEMENT_PICKS).ToList(); possibleTrackingMoves = possibleTrackingMoves.OrderBy(p => grid.Get(p, false).zombieCount).ToList(); var nextMove = possibleTrackingMoves.First(); timeDelta = currentTicks - grid.Get(nextMove, false).timestamp; destination = nextMove; if (zombie.state == ZombieState.Wandering) { Tools.ChainReact(zombie.Map, basePos, nextMove); if (timeDelta <= agitatedFadeoff) { CastBrainzThought(); } } zombie.state = ZombieState.Tracking; } if (destination.IsValid == false) { zombie.state = ZombieState.Wandering; } bool checkSmashable = timeDelta >= checkSmashableFadeoff; if (ZombieSettings.Values.smashOnlyWhenAgitated) { checkSmashable &= zombie.state == ZombieState.Tracking; } if (destination.IsValid == false || checkSmashable) { var building = CanSmash(); if (building != null) { destination = building.Position; if (Constants.USE_SOUND) { var info = SoundInfo.InMap(enemy); SoundDef.Named("ZombieHit").PlayOneShot(info); } AttackThing(building, JobDefOf.AttackStatic); return; } } if (destination.IsValid == false) { var hour = GenLocalDate.HourOfDay(Find.VisibleMap); // check for day/night and dust/dawn // var moveTowardsCenter = false; if (map.areaManager.Home[basePos] == false) { if (hour < 12) { hour += 24; } if (hour > Constants.HOUR_START_OF_NIGHT && hour < Constants.HOUR_END_OF_NIGHT) { moveTowardsCenter = true; } else if (hour >= Constants.HOUR_START_OF_DUSK && hour <= Constants.HOUR_START_OF_NIGHT) { moveTowardsCenter = Rand.RangeInclusive(hour, Constants.HOUR_START_OF_NIGHT) == Constants.HOUR_START_OF_NIGHT; } else if (hour >= Constants.HOUR_END_OF_NIGHT && hour <= Constants.HOUR_START_OF_DAWN) { moveTowardsCenter = Rand.RangeInclusive(Constants.HOUR_END_OF_NIGHT, hour) == Constants.HOUR_END_OF_NIGHT; } } var possibleMoves = new List <IntVec3>(); for (int i = 0; i < 8; i++) { var pos = basePos + GenAdj.AdjacentCells[i]; if (zombie.HasValidDestination(pos)) { possibleMoves.Add(pos); } } if (possibleMoves.Count > 0) { // during night, zombies drift towards the colonies center // if (moveTowardsCenter) { var center = zombie.wanderDestination.IsValid ? zombie.wanderDestination : map.Center; possibleMoves.Sort((p1, p2) => SortByDirection(center, p1, p2)); possibleMoves = possibleMoves.Take(Constants.NUMBER_OF_TOP_MOVEMENT_PICKS).ToList(); possibleMoves = possibleMoves.OrderBy(p => grid.Get(p, false).zombieCount).ToList(); destination = possibleMoves.First(); } else { // otherwise they sometimes stand or walk towards a random direction // if (Rand.Chance(Constants.STANDING_STILL_CHANCE)) { var n = possibleMoves.Count(); destination = possibleMoves[Constants.random.Next(n)]; } } } } // if we have a valid destination, go there // if (destination.IsValid) { MoveToCell(destination); } }
//Handles the spawning of pawns public override void GiveBirth() { Pawn mother = pawn; if (mother == null) { return; } try { //fail if hediff added through debug, since babies not initialized if (babies.Count > 9999) { Log.Message("RJW mech pregnancy birthing pawn count: " + babies.Count); } } catch { Initialize(mother, father); } foreach (Pawn baby in babies) { Faction spawn_faction = null; if (!is_hacked) { spawn_faction = Faction.OfMechanoids; } Pawn baby1 = PawnGenerator.GeneratePawn(new PawnGenerationRequest(PawnKindDef.Named("Mech_Scyther"), spawn_faction)); PawnUtility.TrySpawnHatchedOrBornPawn(baby1, mother); if (!is_hacked) { LordJob_MechanoidsDefendShip lordJob = new LordJob_MechanoidsDefendShip(mother, baby1.Faction, 50f, mother.Position); Lord lord = LordMaker.MakeNewLord(baby1.Faction, lordJob, baby1.Map); lord.AddPawn(baby1); } FilthMaker.MakeFilth(baby1.PositionHeld, baby1.MapHeld, mother.RaceProps.BloodDef, mother.LabelIndefinite()); } IEnumerable <BodyPartRecord> source = from x in mother.health.hediffSet.GetNotMissingParts() where x.IsInGroup(BodyPartGroupDefOf.Torso) && !x.IsCorePart //someday include depth filter //so it doesnt cut out external organs (breasts)? //vag is genital part and genital is external //anal is internal //make sep part of vag? //&& x.depth == BodyPartDepth.Inside select x; if (source.Any()) { foreach (BodyPartRecord part in source) { Hediff_MissingPart hediff_MissingPart = (Hediff_MissingPart)HediffMaker.MakeHediff(HediffDefOf.MissingBodyPart, mother, part); hediff_MissingPart.lastInjury = HediffDefOf.Cut; hediff_MissingPart.IsFresh = true; mother.health.AddHediff(hediff_MissingPart); //idk blood doesnt drop //mother.health.DropBloodFilth(); //FilthMaker.MakeFilth(corpse.PositionHeld, corpse.MapHeld, mother.RaceProps.BloodDef, mother.LabelIndefinite()); } } mother.health.RemoveHediff(this); }
public PawnPath FindShipPath(IntVec3 start, LocalTargetInfo dest, TraverseParms traverseParms, PathEndMode peMode = PathEndMode.OnCell) { if (DebugSettings.pathThroughWalls) { traverseParms.mode = TraverseMode.PassAllDestroyableThings; } Pawn pawn = traverseParms.pawn; if (!(pawn is null) && pawn.Map != this.map) { Log.Error(string.Concat(new object[] { "Tried to FindShipPath for pawn which is spawned in another map. his map ShipPathFinder should have been used, not this one. " + "pawn=", pawn, " pawn.Map=", pawn.Map, " map=", this.map }), false); return(PawnPath.NotFound); } if (!start.IsValid) { Log.Error(string.Concat(new object[] { "Tried to FindShipPath with invalid start ", start, ", pawn=", pawn }), false); return(PawnPath.NotFound); } if (!dest.IsValid) { Log.Error(string.Concat(new object[] { "Tried to FindPath with invalid dest ", dest, ", pawn= ", pawn }), false); return(PawnPath.NotFound); } if (traverseParms.mode == TraverseMode.ByPawn) { if (!ShipReachabilityUtility.CanReachShip(pawn, dest, peMode, Danger.Deadly, false, traverseParms.mode)) { return(PawnPath.NotFound); } } else if (!mapE.getShipReachability.CanReachShip(start, dest, peMode, traverseParms)) { return(PawnPath.NotFound); } this.PfProfilerBeginSample(string.Concat(new object[] { "FindPath for ", pawn, " from ", start, " to ", dest, (!dest.HasThing) ? string.Empty : (" at " + dest.Cell) })); this.cellIndices = this.map.cellIndices; this.shipPathGrid = mapE.getShipPathGrid; this.edificeGrid = this.map.edificeGrid.InnerArray; this.blueprintGrid = this.map.blueprintGrid.InnerArray; int x = dest.Cell.x; int z = dest.Cell.z; int num = this.cellIndices.CellToIndex(start); int num2 = this.cellIndices.CellToIndex(dest.Cell); ByteGrid byteGrid = (pawn is null) ? null : pawn.GetAvoidGrid(true); bool flag = traverseParms.mode == TraverseMode.PassAllDestroyableThings || traverseParms.mode == TraverseMode.PassAllDestroyableThingsNotWater; bool flag2 = traverseParms.mode != TraverseMode.NoPassClosedDoorsOrWater && traverseParms.mode != TraverseMode.PassAllDestroyableThingsNotWater; bool flag3 = !flag; CellRect cellRect = this.CalculateDestinationRect(dest, peMode); bool flag4 = cellRect.Width == 1 && cellRect.Height == 1; int[] array = mapE.getShipPathGrid.pathGrid; TerrainDef[] topGrid = this.map.terrainGrid.topGrid; EdificeGrid edificeGrid = this.map.edificeGrid; int num3 = 0; int num4 = 0; Area allowedArea = this.GetAllowedArea(pawn); bool flag5 = !(pawn is null) && PawnUtility.ShouldCollideWithPawns(pawn); bool flag6 = true && DebugViewSettings.drawPaths; bool flag7 = !flag && !(WaterGridsUtility.GetRegion(start, this.map, RegionType.Set_Passable) is null) && flag2; bool flag8 = !flag || !flag3; bool flag9 = false; bool flag10 = !(pawn is null) && pawn.Drafted; bool flag11 = !(pawn is null) && !(pawn.GetComp <CompShips>() is null); int num5 = (!flag11) ? NodesToOpenBeforeRegionbasedPathing_NonShip : NodesToOpenBeforeRegionBasedPathing_Ship; int num6 = 0; int num7 = 0; float num8 = this.DetermineHeuristicStrength(pawn, start, dest); int num9 = !(pawn is null) ? pawn.TicksPerMoveCardinal : DefaultMoveTicksCardinal; int num10 = !(pawn is null) ? pawn.TicksPerMoveDiagonal : DefaultMoveTicksDiagonal; this.CalculateAndAddDisallowedCorners(traverseParms, peMode, cellRect); this.InitStatusesAndPushStartNode(ref num, start); for (;;) { this.PfProfilerBeginSample("Open cell"); if (this.openList.Count <= 0) { break; } num6 += this.openList.Count; num7++; ShipPathFinder.CostNode costNode = this.openList.Pop(); num = costNode.index; if (costNode.cost != this.calcGrid[num].costNodeCost) { this.PfProfilerEndSample(); } else if (this.calcGrid[num].status == this.statusClosedValue) { this.PfProfilerEndSample(); } else { IntVec3 c = this.cellIndices.IndexToCell(num); int x2 = c.x; int z2 = c.z; if (flag6) { this.DebugFlash(c, (float)this.calcGrid[num].knownCost / 1500f, this.calcGrid[num].knownCost.ToString()); } if (flag4) { if (num == num2) { goto Block_32; } } else if (cellRect.Contains(c) && !this.disallowedCornerIndices.Contains(num)) { goto Block_34; } if (num3 > SearchLimit) { goto Block_35; } this.PfProfilerEndSample(); this.PfProfilerBeginSample("Neighbor consideration"); for (int i = 0; i < 8; i++) { uint num11 = (uint)(x2 + ShipPathFinder.Directions[i]); uint num12 = (uint)(z2 + ShipPathFinder.Directions[i + 8]); if ((ulong)num11 < ((ulong)this.mapSizeX) && (ulong)num12 < (ulong)((long)this.mapSizeZ)) { int num13 = (int)num11; int num14 = (int)num12; int num15 = this.cellIndices.CellToIndex(num13, num14); if (this.calcGrid[num15].status != this.statusClosedValue || flag9) { int num16 = 0; //bool flag12 = false; Extra cost for traversing water if (flag2 || !new IntVec3(num13, 0, num14).GetTerrain(this.map).HasTag("Water")) { if (!this.shipPathGrid.WalkableFast(num15)) { if (!flag) { if (flag6) { this.DebugFlash(new IntVec3(num13, 0, num14), 0.22f, "walk"); } goto IL_E3A; } //flag12 = true; num16 += 70; Building building = edificeGrid[num15]; if (building is null) { goto IL_E3A; } if (!IsDestroyable(building)) { goto IL_E3A; } num16 += (int)((float)building.HitPoints * 0.2f); } if (i > 3) { switch (i) { case 4: if (this.BlocksDiagonalMovement(num - this.mapSizeX)) { if (flag8) { if (flag6) { this.DebugFlash(new IntVec3(x2, 0, z2 - 1), 0.9f, "ships"); } goto IL_E3A; } num16 += 70; } if (this.BlocksDiagonalMovement(num + 1)) { if (flag8) { if (flag6) { this.DebugFlash(new IntVec3(x2 + 1, 0, z2), 0.9f, "ships"); } goto IL_E3A; } num16 += 70; } break; case 5: if (this.BlocksDiagonalMovement(num + this.mapSizeX)) { if (flag8) { if (flag6) { this.DebugFlash(new IntVec3(x2, 0, z2 + 1), 0.9f, "ships"); } goto IL_E3A; } num16 += 70; } if (this.BlocksDiagonalMovement(num + 1)) { if (flag8) { if (flag6) { this.DebugFlash(new IntVec3(x2 + 1, 0, z2), 0.9f, "ships"); } goto IL_E3A; } num16 += 70; } break; case 6: if (this.BlocksDiagonalMovement(num + this.mapSizeX)) { if (flag8) { if (flag6) { this.DebugFlash(new IntVec3(x2, 0, z2 + 1), 0.9f, "ships"); } goto IL_E3A; } num16 += 70; } if (this.BlocksDiagonalMovement(num - 1)) { if (flag8) { if (flag6) { this.DebugFlash(new IntVec3(x2 - 1, 0, z2), 0.9f, "ships"); } goto IL_E3A; } num16 += 70; } break; case 7: if (this.BlocksDiagonalMovement(num - this.mapSizeX)) { if (flag8) { if (flag6) { this.DebugFlash(new IntVec3(x2, 0, z2 - 1), 0.9f, "ships"); } goto IL_E3A; } num16 += 70; } if (this.BlocksDiagonalMovement(num - 1)) { if (flag8) { if (flag6) { this.DebugFlash(new IntVec3(x2 - 1, 0, z2), 0.9f, "ships"); } goto IL_E3A; } num16 += 70; } break; } } int num17 = (i <= 3) ? num9 : num10; num17 += num16; /*if(!flag12) * { * //Extra Costs for traversing water * num17 += array[num15]; * num17 += flag10 ? topGrid[num15].extraDraftedPerceivedPathCost : topGrid[num15].extraNonDraftedPerceivedPathCost; * }*/ if (!(byteGrid is null)) { num17 += (int)(byteGrid[num15] * 8); } //Allowed area cost? if (flag5 && PawnUtility.AnyPawnBlockingPathAt(new IntVec3(num13, 0, num14), pawn, false, false, true)) { num17 += Cost_PawnCollision; } Building building2 = this.edificeGrid[num15]; if (!(building2 is null)) { //Building Costs Here } List <Blueprint> list = this.blueprintGrid[num15]; if (!(list is null)) { this.PfProfilerBeginSample("Blueprints"); int num18 = 0; foreach (Blueprint bp in list) { num18 = Mathf.Max(num18, GetBlueprintCost(bp, pawn)); } if (num18 == int.MaxValue) { this.PfProfilerEndSample(); goto IL_E3A; } num17 += num18; this.PfProfilerEndSample(); } int num19 = num17 + this.calcGrid[num].knownCost; ushort status = this.calcGrid[num15].status; if (!(pawn.GetComp <CompShips>() is null) && !this.map.terrainGrid.TerrainAt(num15).IsWater) { num19 += 10000; } if (status == this.statusClosedValue || status == this.statusOpenValue) { int num20 = 0; if (status == this.statusClosedValue) { num20 = num9; } if (this.calcGrid[num15].knownCost <= num19 + num20) { goto IL_E3A; } } if (flag9) { this.calcGrid[num15].heuristicCost = Mathf.RoundToInt((float)this.regionCostCalculator.GetPathCostFromDestToRegion(num15) * ShipPathFinder.RegionheuristicWeighByNodesOpened.Evaluate((float)num4)); if (this.calcGrid[num15].heuristicCost < 0) { Log.ErrorOnce(string.Concat(new object[] { "Heuristic cost overflow for ship ", pawn.ToStringSafe <Pawn>(), " pathing from ", start, " to ", dest, "." }), pawn.GetHashCode() ^ 193840009, false); this.calcGrid[num15].heuristicCost = 0; } } else if (status != this.statusClosedValue && status != this.statusOpenValue) { int dx = Math.Abs(num13 - x); int dz = Math.Abs(num14 - z); int num21 = GenMath.OctileDistance(dx, dz, num9, num10); this.calcGrid[num15].heuristicCost = Mathf.RoundToInt((float)num21 * num8); } int num22 = num19 + this.calcGrid[num15].heuristicCost; //Log.Message("Num19: " + num19 + " || num22: " + num22); if (num22 < 0) { Log.ErrorOnce(string.Concat(new object[] { "Node cost overflow for ship ", pawn.ToStringSafe <Pawn>(), " pathing from ", start, " to ", dest, "." }), pawn.GetHashCode() ^ 87865822, false); num22 = 0; } this.calcGrid[num15].parentIndex = num; this.calcGrid[num15].knownCost = num19; this.calcGrid[num15].status = this.statusOpenValue; this.calcGrid[num15].costNodeCost = num22; num4++; this.openList.Push(new ShipPathFinder.CostNode(num15, num22)); } } } IL_E3A :; } this.PfProfilerEndSample(); num3++; this.calcGrid[num].status = this.statusClosedValue; if (num4 >= num5 && flag7 && !flag9) { flag9 = true; this.regionCostCalculator.Init(cellRect, traverseParms, num9, num10, byteGrid, allowedArea, flag10, this.disallowedCornerIndices); this.InitStatusesAndPushStartNode(ref num, start); num4 = 0; num3 = 0; } } } string text = ((pawn is null) || pawn.CurJob is null) ? "null" : pawn.CurJob.ToString(); string text2 = ((pawn is null) || pawn.Faction is null) ? "null" : pawn.Faction.ToString(); Log.Warning(string.Concat(new object[] { "ship pawn: ", pawn, " pathing from ", start, " to ", dest, " ran out of cells to process.\nJob:", text, "\nFaction: ", text2 }), false); this.DebugDrawRichData(); this.PfProfilerEndSample(); return(PawnPath.NotFound); Block_32: this.PfProfilerEndSample(); PawnPath result = this.FinalizedPath(num, flag9); this.PfProfilerEndSample(); return(result); Block_34: this.PfProfilerEndSample(); PawnPath result2 = this.FinalizedPath(num, flag9); this.PfProfilerEndSample(); return(result2); Block_35: Log.Warning(string.Concat(new object[] { "Ship ", pawn, " pathing from ", start, " to ", dest, " hit search limit of ", SearchLimit, " cells." }), false); this.DebugDrawRichData(); this.PfProfilerEndSample(); return(PawnPath.NotFound); }
protected override IEnumerable <Toil> MakeNewToils() { // Toil toil = new Toil(); toil.initAction = delegate { //Empty }; this.EndOnDespawnedOrNull(InquisitorIndex, JobCondition.Incompletable); this.EndOnDespawnedOrNull(PreacherIndex, JobCondition.Incompletable); //this.EndOnDespawnedOrNull(Build, JobCondition.Incompletable); yield return(Toils_Reserve.Reserve(PreacherIndex, this.job.def.joyMaxParticipants)); Toil gotoPreacher; gotoPreacher = Toils_Goto.GotoThing(PreacherIndex, PathEndMode.ClosestTouch); yield return(gotoPreacher); if (Preacher.jobs.curDriver.asleep) { Toil watchToil = new Toil(); watchToil.defaultCompleteMode = ToilCompleteMode.Delay; watchToil.defaultDuration = this.job.def.joyDuration; watchToil.AddPreTickAction(() => { this.pawn.rotationTracker.FaceCell(Preacher.Position); this.pawn.GainComfortFromCellIfPossible(); }); yield return(watchToil); } Action hitAction = delegate { Pawn prey = Preacher; bool surpriseAttack = this.firstHit; if (pawn.meleeVerbs.TryMeleeAttack(prey, this.job.verbToUse, surpriseAttack)) { if (!this.notifiedPlayer && PawnUtility.ShouldSendNotificationAbout(prey)) { this.notifiedPlayer = true; if (Prefs.PauseOnUrgentLetter && !Find.TickManager.Paused) { Find.TickManager.TogglePaused(); } Messages.Message("MessageAttackedByPredator".Translate(new object[] { prey.LabelShort, this.pawn.LabelShort, }).CapitalizeFirst(), prey, MessageTypeDefOf.ThreatBig); } this.pawn.Map.attackTargetsCache.UpdateTarget(this.pawn); } this.firstHit = false; }; yield return(Toils_Combat.FollowAndMeleeAttack(TargetIndex.A, hitAction).JumpIfDespawnedOrNull(TargetIndex.A, toil).FailOn(() => Find.TickManager.TicksGame > this.startTick + 5000 && (this.job.GetTarget(TargetIndex.A).Cell - this.pawn.Position).LengthHorizontalSquared > 4f)); yield return(toil); this.AddFinishAction(() => { //if (this.TargetB.HasThing) //{ // Find.Reservations.Release(this.job.targetC.Thing, pawn); //} }); }
public virtual void Tick() { ageTicks++; if (def.hediffGivers != null && pawn.IsHashIntervalTick(60)) { for (int i = 0; i < def.hediffGivers.Count; i++) { def.hediffGivers[i].OnIntervalPassed(pawn, this); } } if (Visible && !visible) { visible = true; if (def.taleOnVisible != null) { TaleRecorder.RecordTale(def.taleOnVisible, pawn, def); } } HediffStage curStage = CurStage; if (curStage == null) { return; } if (curStage.hediffGivers != null && pawn.IsHashIntervalTick(60)) { for (int j = 0; j < curStage.hediffGivers.Count; j++) { curStage.hediffGivers[j].OnIntervalPassed(pawn, this); } } if (curStage.mentalStateGivers != null && pawn.IsHashIntervalTick(60) && !pawn.InMentalState) { for (int k = 0; k < curStage.mentalStateGivers.Count; k++) { MentalStateGiver mentalStateGiver = curStage.mentalStateGivers[k]; if (Rand.MTBEventOccurs(mentalStateGiver.mtbDays, 60000f, 60f)) { pawn.mindState.mentalStateHandler.TryStartMentalState(mentalStateGiver.mentalState, "MentalStateReason_Hediff".Translate(Label)); } } } if (curStage.mentalBreakMtbDays > 0f && pawn.IsHashIntervalTick(60) && !pawn.InMentalState && !pawn.Downed && Rand.MTBEventOccurs(curStage.mentalBreakMtbDays, 60000f, 60f)) { TryDoRandomMentalBreak(); } if (curStage.vomitMtbDays > 0f && pawn.IsHashIntervalTick(600) && Rand.MTBEventOccurs(curStage.vomitMtbDays, 60000f, 600f) && pawn.Spawned && pawn.Awake() && pawn.RaceProps.IsFlesh) { pawn.jobs.StartJob(JobMaker.MakeJob(JobDefOf.Vomit), JobCondition.InterruptForced, null, resumeCurJobAfterwards: true); } if (curStage.forgetMemoryThoughtMtbDays > 0f && pawn.needs != null && pawn.needs.mood != null && pawn.IsHashIntervalTick(400) && Rand.MTBEventOccurs(curStage.forgetMemoryThoughtMtbDays, 60000f, 400f) && pawn.needs.mood.thoughts.memories.Memories.TryRandomElement(out Thought_Memory result)) { pawn.needs.mood.thoughts.memories.RemoveMemory(result); } if (!recordedTale && curStage.tale != null) { TaleRecorder.RecordTale(curStage.tale, pawn); recordedTale = true; } if (curStage.destroyPart && Part != null && Part != pawn.RaceProps.body.corePart) { pawn.health.AddHediff(HediffDefOf.MissingBodyPart, Part); } if (curStage.deathMtbDays > 0f && pawn.IsHashIntervalTick(200) && Rand.MTBEventOccurs(curStage.deathMtbDays, 60000f, 200f)) { bool num = PawnUtility.ShouldSendNotificationAbout(pawn); Caravan caravan = pawn.GetCaravan(); pawn.Kill(null, null); if (num) { pawn.health.NotifyPlayerOfKilled(null, this, caravan); } } }
protected override Job TryGiveJob(Pawn pawn) { pawn.drafter.Drafted = true; IntVec3 cell = pawn.mindState.duty.focus.Cell; if (pawn.IsBoat() && !ShipReachabilityUtility.CanReachShip(pawn, cell, PathEndMode.OnCell, PawnUtility.ResolveMaxDanger(pawn, maxDanger), false, TraverseMode.ByPawn)) { return(null); } else if (!pawn.IsBoat() && pawn is VehiclePawn vehicle && !ReachabilityUtility.CanReach(vehicle, cell, PathEndMode.OnCell, PawnUtility.ResolveMaxDanger(vehicle, maxDanger), false)) { return(null); } if (exactCell && pawn.Position == cell) { return(null); } return(new Job(JobDefOf.Goto, cell) { locomotionUrgency = PawnUtility.ResolveLocomotion(pawn, locomotionUrgency), expiryInterval = jobMaxDuration }); }
public static IAttackTarget BestAttackTarget(IAttackTargetSearcher searcher, TargetScanFlags flags, Predicate <Thing> validator = null, float minDist = 0f, float maxDist = 9999f, IntVec3 locus = default(IntVec3), float maxTravelRadiusFromLocus = float.MaxValue, bool canBash = false, bool canTakeTargetsCloserThanEffectiveMinRange = true) { Thing searcherThing = searcher.Thing; Pawn searcherPawn = searcher as Pawn; Verb verb = searcher.CurrentEffectiveVerb; if (verb == null) { Log.Error("BestAttackTarget with " + searcher.ToStringSafe() + " who has no attack verb."); return(null); } bool onlyTargetMachines = verb.IsEMP(); float minDistSquared = 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 (minDistSquared > 0f && (float)(searcherThing.Position - thing.Position).LengthHorizontalSquared < minDistSquared) { return(false); } if (!canTakeTargetsCloserThanEffectiveMinRange) { float num2 = verb.verbProps.EffectiveMinRange(thing, searcherThing); if (num2 > 0f && (float)(searcherThing.Position - thing.Position).LengthHorizontalSquared < num2 * num2) { return(false); } } if (maxTravelRadiusFromLocus < 9999f && (float)(thing.Position - locus).LengthHorizontalSquared > maxLocusDistSquared) { return(false); } if (!searcherThing.HostileTo(thing)) { return(false); } if (validator != null && !validator(thing)) { return(false); } if (searcherPawn != null) { Lord lord = searcherPawn.GetLord(); if (lord != null && !lord.LordJob.ValidateAttackTarget(searcherPawn, thing)) { return(false); } } if ((flags & TargetScanFlags.NeedNotUnderThickRoof) != 0) { RoofDef roof = thing.Position.GetRoof(thing.Map); if (roof != null && roof.isThickRoof) { return(false); } } if ((flags & TargetScanFlags.NeedLOSToAll) != 0) { if (losValidator != null && (!losValidator(searcherThing.Position) || !losValidator(thing.Position))) { return(false); } if (!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 || (flags & TargetScanFlags.NeedAutoTargetable) != 0) && t.ThreatDisabled(searcher)) { return(false); } if ((flags & TargetScanFlags.NeedAutoTargetable) != 0 && !IsAutoTargetable(t)) { return(false); } if ((flags & TargetScanFlags.NeedActiveThreat) != 0 && !GenHostility.IsActiveThreatTo(t, searcher.Thing.Faction)) { return(false); } Pawn pawn = t as Pawn; if (onlyTargetMachines && pawn != null && pawn.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; foreach (IntVec3 item in thing.OccupiedRect()) { if (!item.Fogged(thing.Map)) { flag2 = true; break; } } if (!flag2) { return(false); } } return(true); }; if (HasRangedAttack(searcher) && (searcherPawn == null || !searcherPawn.InAggroMentalState)) { tmpTargets.Clear(); tmpTargets.AddRange(searcherThing.Map.attackTargetsCache.GetPotentialTargetsFor(searcher)); if ((flags & TargetScanFlags.NeedReachable) != 0) { Predicate <IAttackTarget> oldValidator2 = innerValidator; innerValidator = (IAttackTarget t) => oldValidator2(t) && CanReach(searcherThing, t.Thing, canBash); } bool flag = false; for (int i = 0; i < tmpTargets.Count; i++) { IAttackTarget attackTarget = tmpTargets[i]; if (attackTarget.Thing.Position.InHorDistOf(searcherThing.Position, maxDist) && innerValidator(attackTarget) && CanShootAtFromCurrentPosition(attackTarget, searcher, verb)) { flag = true; break; } } IAttackTarget result; if (flag) { tmpTargets.RemoveAll((IAttackTarget x) => !x.Thing.Position.InHorDistOf(searcherThing.Position, maxDist) || !innerValidator(x)); result = GetRandomShootingTargetByScore(tmpTargets, searcher, verb); } else { result = (IAttackTarget)GenClosest.ClosestThing_Global(validator: ((flags & TargetScanFlags.NeedReachableIfCantHitFromMyPos) == 0 || (flags & TargetScanFlags.NeedReachable) != 0) ? ((Predicate <Thing>)((Thing t) => innerValidator((IAttackTarget)t))) : ((Predicate <Thing>)((Thing t) => innerValidator((IAttackTarget)t) && (CanReach(searcherThing, t, canBash) || CanShootAtFromCurrentPosition((IAttackTarget)t, searcher, verb)))), center: searcherThing.Position, searchSet: tmpTargets, maxDistance: maxDist); } tmpTargets.Clear(); return(result); } if (searcherPawn != null && searcherPawn.mindState.duty != null && searcherPawn.mindState.duty.radius > 0f && !searcherPawn.InMentalState) { Predicate <IAttackTarget> oldValidator = innerValidator; innerValidator = delegate(IAttackTarget t) { if (!oldValidator(t)) { return(false); } return(t.Thing.Position.InHorDistOf(searcherPawn.mindState.duty.focus.Cell, searcherPawn.mindState.duty.radius) ? true : false); }; } IAttackTarget attackTarget2 = (IAttackTarget)GenClosest.ClosestThingReachable(searcherThing.Position, searcherThing.Map, ThingRequest.ForGroup(ThingRequestGroup.AttackTarget), PathEndMode.Touch, TraverseParms.For(searcherPawn, Danger.Deadly, TraverseMode.ByPawn, canBash), maxDist, (Thing x) => innerValidator((IAttackTarget)x), null, 0, (maxDist > 800f) ? (-1) : 40); if (attackTarget2 != null && PawnUtility.ShouldCollideWithPawns(searcherPawn)) { IAttackTarget attackTarget3 = FindBestReachableMeleeTarget(innerValidator, searcherPawn, maxDist, canBash); if (attackTarget3 != null) { float lengthHorizontal = (searcherPawn.Position - attackTarget2.Thing.Position).LengthHorizontal; float lengthHorizontal2 = (searcherPawn.Position - attackTarget3.Thing.Position).LengthHorizontal; if (Mathf.Abs(lengthHorizontal - lengthHorizontal2) < 50f) { attackTarget2 = attackTarget3; } } } return(attackTarget2); }
public static bool TryFindBestPawnStandCell(Pawn forPawn, out IntVec3 cell, bool cellByCell = false) { cell = IntVec3.Invalid; int num = -1; float radius = 10f; while (true) { CellFinder.tmpDistances.Clear(); CellFinder.tmpParents.Clear(); Dijkstra <IntVec3> .Run(forPawn.Position, (IntVec3 x) => CellFinder.GetAdjacentCardinalCellsForBestStandCell(x, radius, forPawn), delegate(IntVec3 from, IntVec3 to) { float num4 = 1f; if (from.x != to.x && from.z != to.z) { num4 = 1.41421354f; } if (!to.Standable(forPawn.Map)) { num4 += 3f; } if (PawnUtility.AnyPawnBlockingPathAt(to, forPawn, false, false, false)) { bool flag = to.GetThingList(forPawn.Map).Find((Thing x) => x is Pawn && x.HostileTo(forPawn)) != null; if (flag) { num4 += 40f; } else { num4 += 15f; } } Building_Door building_Door = to.GetEdifice(forPawn.Map) as Building_Door; if (building_Door != null && !building_Door.FreePassage) { if (building_Door.PawnCanOpen(forPawn)) { num4 += 6f; } else { num4 += 50f; } } return(num4); }, CellFinder.tmpDistances, CellFinder.tmpParents); if (CellFinder.tmpDistances.Count == num) { break; } float num2 = 0f; foreach (KeyValuePair <IntVec3, float> current in CellFinder.tmpDistances) { if ((!cell.IsValid || current.Value < num2) && current.Key.Walkable(forPawn.Map) && !PawnUtility.AnyPawnBlockingPathAt(current.Key, forPawn, false, false, false)) { Building_Door door = current.Key.GetDoor(forPawn.Map); if (door == null || door.FreePassage) { cell = current.Key; num2 = current.Value; } } } if (cell.IsValid) { goto Block_3; } if (radius > (float)forPawn.Map.Size.x && radius > (float)forPawn.Map.Size.z) { return(false); } radius *= 2f; num = CellFinder.tmpDistances.Count; } return(false); Block_3: if (!cellByCell) { return(true); } IntVec3 intVec = cell; int num3 = 0; while (intVec.IsValid && intVec != forPawn.Position) { num3++; if (num3 >= 10000) { Log.Error("Too many iterations.", false); break; } if (intVec.Walkable(forPawn.Map)) { Building_Door door2 = intVec.GetDoor(forPawn.Map); if (door2 == null || door2.FreePassage) { cell = intVec; } } intVec = CellFinder.tmpParents[intVec]; } return(true); }
protected override Job TryGiveJob(Pawn pawn) { if (pawn.interactions.InteractedTooRecentlyToInteract() || lastRomanceTick > Find.TickManager.TicksGame - 1000) { return(null); } Predicate <Thing> validator = delegate(Thing t) { Pawn pawn3 = (Pawn)t; return(pawn3 != pawn && pawn3.Spawned && !pawn3.Dead && !pawn3.Downed && pawn3.Awake() && pawn3.IsColonist); }; Pawn pawn2 = (Pawn)GenClosest.ClosestThingReachable(pawn.Position, pawn.Map, ThingRequest.ForGroup(ThingRequestGroup.Pawn), PathEndMode.OnCell, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.ByPawn, false), 9999f, validator); if (pawn2 == null) { return(null); } if (Rand.Chance(0.005f) && new InteractionWorker_RomanceAttempt().SuccessChance(pawn2, pawn) > 0f) { return(new Job(JobDefOfPsychology.MakeAdvance, pawn2)); } else if (Rand.Value < 0.5f) { IntVec3 root = WanderUtility.BestCloseWanderRoot(pawn2.PositionHeld, pawn); Func <Pawn, IntVec3, IntVec3, bool> wanderDestValidator = delegate(Pawn p, IntVec3 c, IntVec3 wRoot) { Room room = root.GetRoom(p.Map, RegionType.Set_Passable); if (room != null && !WanderRoomUtility.IsValidWanderDest(p, c, root)) { return(false); } return(true); }; return(new Job(JobDefOf.Goto, RCellFinder.RandomWanderDestFor(pawn, root, 3f, wanderDestValidator, PawnUtility.ResolveMaxDanger(pawn, Danger.Deadly)))); } return(null); }
// Token: 0x06000053 RID: 83 RVA: 0x000040E4 File Offset: 0x000022E4 public void TryHealRandomOldWound() { var healAmount = AYProps.RegenHealVal; var candidates = new List <Hediff>(); var pawn = Pawn; List <Hediff> list; if (pawn == null) { list = null; } else { var health = pawn.health; list = health?.hediffSet.hediffs; } var hediffs = list; if (hediffs != null && hediffs.Count > 0) { foreach (var hediff in hediffs) { if (Def.defName == "AYAloeCreamHigh") { if (hediff.def == HediffDefOf.Burn) { candidates.Add(hediff); } } else if (Def.defName == "AYScarCreamHigh") { if (hediff.IsPermanent() || hediff.def == HediffDefOf.Burn) { candidates.Add(hediff); } } else if (hediff.IsPermanent()) { candidates.Add(hediff); } } } if (candidates.Count <= 0) { return; } candidates.TryRandomElement(out var hediffToHeal); if (hediffToHeal == null) { return; } if (hediffToHeal.IsTended()) { healAmount = (int)(healAmount * 1.2f); var healfactor = GetHealFactor(Def, hediffToHeal); if (healfactor > 0f) { healAmount = (int)(healAmount * healfactor); if (healAmount < 1) { healAmount = 1; } } } if (hediffToHeal.Severity - healAmount <= 0f && PawnUtility.ShouldSendNotificationAbout(Pawn)) { Messages.Message( "Apothecary.WoundHealed".Translate(parent.LabelCap, Pawn.LabelShort, hediffToHeal.Label, Pawn.Named("PAWN")), Pawn, MessageTypeDefOf.PositiveEvent); } if (hediffToHeal.Severity - healAmount > 0f) { hediffToHeal.Severity -= healAmount; return; } hediffToHeal.Severity = 0f; }
//public PawnPath FindPath(IntVec3 start, LocalTargetInfo dest, Pawn pawn, PathEndMode peMode = PathEndMode.OnCell) //{ // bool flag = false; // if (pawn != null && pawn.CurJob != null && pawn.CurJob.canBash) // { // flag = true; // } // Danger maxDanger = Danger.Deadly; // bool canBash = flag; // return this.FindPath(start, dest, TraverseParms.For(pawn, maxDanger, TraverseMode.ByPawn, canBash), peMode); //} public PawnPath FindPath(IntVec3 start, LocalTargetInfo dest, TraverseParms traverseParms, PathEndMode peMode = PathEndMode.OnCell) { //Walk through Walls Mode if (DebugSettings.pathThroughWalls) { traverseParms.mode = TraverseMode.PassAllDestroyableThings; } //Check if there's a pawn to path for Pawn pawn = traverseParms.pawn; if (pawn != null && pawn.Map != this.map) { Log.Error(string.Concat(new object[] { "Tried to FindPath for pawn which is spawned in another map. His map CVPathFinder should have been used, not this one. pawn=", pawn, " pawn.Map=", pawn.Map, " map=", this.map })); return(PawnPath.NotFound); } //Make sure the start is valid if (!start.IsValid) { Log.Error(string.Concat(new object[] { "Tried to FindPath with invalid start ", start, ", pawn= ", pawn })); return(PawnPath.NotFound); } //Make sure the end is valid if (!dest.IsValid) { Log.Error(string.Concat(new object[] { "Tried to FindPath with invalid dest ", dest, ", pawn= ", pawn })); return(PawnPath.NotFound); } //Check if it's possible to get to the destination Log.Error(traverseParms.mode.ToString()); if (traverseParms.mode == TraverseMode.ByPawn) { if (!pawn.CanReach(dest, peMode, Danger.Deadly, traverseParms.canBash, traverseParms.mode)) { return(PawnPath.NotFound); } } else if (!this.map.reachability.CanReach(start, dest, peMode, traverseParms)) { return(PawnPath.NotFound); } Log.Error("a"); this.PfProfilerBeginSample(string.Concat(new object[] { "FindPath for ", pawn, " from ", start, " to ", dest, (!dest.HasThing) ? string.Empty : (" at " + dest.Cell) })); this.cellIndices = this.map.cellIndices; this.pathGrid = this.map.pathGrid; this.edificeGrid = this.map.edificeGrid.InnerArray; int x = dest.Cell.x; int z = dest.Cell.z; int num = this.cellIndices.CellToIndex(start); int num2 = this.cellIndices.CellToIndex(dest.Cell); ByteGrid byteGrid = (pawn == null) ? null : pawn.GetAvoidGrid(); bool flag = traverseParms.mode == TraverseMode.PassAllDestroyableThings; bool flag2 = traverseParms.mode != TraverseMode.NoPassClosedDoorsOrWater && traverseParms.mode != TraverseMode.PassAllDestroyableThingsNotWater; bool flag3 = !flag; CellRect cellRect = this.CalculateDestinationRect(dest, peMode); bool flag4 = cellRect.Width == 1 && cellRect.Height == 1; int[] array = this.map.pathGrid.pathGrid; EdificeGrid edificeGrid = this.map.edificeGrid; int num3 = 0; int num4 = 0; Area allowedArea = this.GetAllowedArea(pawn); bool flag5 = pawn != null && PawnUtility.ShouldCollideWithPawns(pawn); bool flag6 = true && DebugViewSettings.drawPaths; bool flag7 = !flag && start.GetRegion(this.map, RegionType.Set_Passable) != null; bool flag8 = !flag || !flag3; bool flag9 = false; int num5 = 0; int num6 = 0; float num7 = this.DetermineHeuristicStrength(pawn, start, dest); int num8; int num9; Log.Error("b"); if (pawn != null) { num8 = pawn.TicksPerMoveCardinal; num9 = pawn.TicksPerMoveDiagonal; } else { num8 = 13; num9 = 18; } this.CalculateAndAddDisallowedCorners(traverseParms, peMode, cellRect); this.InitStatusesAndPushStartNode(ref num, start); while (true) { Log.Error("c"); this.PfProfilerBeginSample("Open cell"); if (this.openList.Count <= 0) { break; } num5 += this.openList.Count; num6++; CVPathFinder.CostNode costNode = this.openList.Pop(); num = costNode.index; if (costNode.cost != this.calcGrid[num].costNodeCost) { Log.Error("d"); this.PfProfilerEndSample(); } else if (this.calcGrid[num].status == this.statusClosedValue) { Log.Error("e"); this.PfProfilerEndSample(); } else { Log.Error("f"); IntVec3 c = this.cellIndices.IndexToCell(num); int x2 = c.x; int z2 = c.z; if (flag6) { this.DebugFlash(c, (float)this.calcGrid[num].knownCost / 1500f, this.calcGrid[num].knownCost.ToString()); } if (flag4) { if (num == num2) { goto Block_27; } } else if (cellRect.Contains(c) && !this.disallowedCornerIndices.Contains(num)) { goto Block_29; } if (num3 > 160000) { goto Block_30; } this.PfProfilerEndSample(); this.PfProfilerBeginSample("Neighbor consideration"); for (int i = 0; i < 8; i++) { uint num10 = (uint)(x2 + CVPathFinder.Directions[i]); uint num11 = (uint)(z2 + CVPathFinder.Directions[i + 8]); if ((ulong)num10 < (ulong)((long)this.mapSizeX) && (ulong)num11 < (ulong)((long)this.mapSizeZ)) { int num12 = (int)num10; int num13 = (int)num11; int num14 = this.cellIndices.CellToIndex(num12, num13); if (this.calcGrid[num14].status != this.statusClosedValue || flag9) { int num15 = 0; bool flag10 = false; if (flag2 || !new IntVec3(num12, 0, num13).GetTerrain(this.map).HasTag("Water") || (pawn.GetComp <CompVehicle>() != null && pawn.GetComp <CompVehicle>().Props.vehicleType == VehicleType.Amphibious)) { if (!this.pathGrid.WalkableFast(num14)) { if (!flag) { if (flag6) { this.DebugFlash(new IntVec3(num12, 0, num13), 0.22f, "walk"); } goto IL_C2E; } flag10 = true; num15 += 70; Building building = edificeGrid[num14]; if (building == null) { goto IL_C2E; } if (!CVPathFinder.IsDestroyable(building)) { goto IL_C2E; } num15 += (int)((float)building.HitPoints * 0.11f); } if (i > 3) { switch (i) { case 4: if (this.BlocksDiagonalMovement(num - this.mapSizeX)) { if (flag8) { if (flag6) { this.DebugFlash(new IntVec3(x2, 0, z2 - 1), 0.9f, "corn"); } goto IL_C2E; } num15 += 70; } if (this.BlocksDiagonalMovement(num + 1)) { if (flag8) { if (flag6) { this.DebugFlash(new IntVec3(x2 + 1, 0, z2), 0.9f, "corn"); } goto IL_C2E; } num15 += 70; } break; case 5: if (this.BlocksDiagonalMovement(num + this.mapSizeX)) { if (flag8) { if (flag6) { this.DebugFlash(new IntVec3(x2, 0, z2 + 1), 0.9f, "corn"); } goto IL_C2E; } num15 += 70; } if (this.BlocksDiagonalMovement(num + 1)) { if (flag8) { if (flag6) { this.DebugFlash(new IntVec3(x2 + 1, 0, z2), 0.9f, "corn"); } goto IL_C2E; } num15 += 70; } break; case 6: if (this.BlocksDiagonalMovement(num + this.mapSizeX)) { if (flag8) { if (flag6) { this.DebugFlash(new IntVec3(x2, 0, z2 + 1), 0.9f, "corn"); } goto IL_C2E; } num15 += 70; } if (this.BlocksDiagonalMovement(num - 1)) { if (flag8) { if (flag6) { this.DebugFlash(new IntVec3(x2 - 1, 0, z2), 0.9f, "corn"); } goto IL_C2E; } num15 += 70; } break; case 7: if (this.BlocksDiagonalMovement(num - this.mapSizeX)) { if (flag8) { if (flag6) { this.DebugFlash(new IntVec3(x2, 0, z2 - 1), 0.9f, "corn"); } goto IL_C2E; } num15 += 70; } if (this.BlocksDiagonalMovement(num - 1)) { if (flag8) { if (flag6) { this.DebugFlash(new IntVec3(x2 - 1, 0, z2), 0.9f, "corn"); } goto IL_C2E; } num15 += 70; } break; } } Log.Error("g"); int num16 = (i <= 3) ? num8 : num9; num16 += num15; if (!flag10) { num16 += array[num14]; } if (byteGrid != null) { num16 += (int)(byteGrid[num14] * 8); } if (allowedArea != null && !allowedArea[num14]) { num16 += 600; } if (flag5 && PawnUtility.AnyPawnBlockingPathAt(new IntVec3(num12, 0, num13), pawn, false, false)) { num16 += 175; } Log.Error("h"); Building building2 = this.edificeGrid[num14]; if (building2 != null) { this.PfProfilerBeginSample("Edifices"); int buildingCost = CVPathFinder.GetBuildingCost(building2, traverseParms, pawn); if (buildingCost == 2147483647) { this.PfProfilerEndSample(); goto IL_C2E; } num16 += buildingCost; this.PfProfilerEndSample(); } int num17 = num16 + this.calcGrid[num].knownCost; ushort status = this.calcGrid[num14].status; if (status == this.statusClosedValue || status == this.statusOpenValue) { int num18 = 0; if (status == this.statusClosedValue) { num18 = num8; } if (this.calcGrid[num14].knownCost <= num17 + num18) { goto IL_C2E; } } if (status != this.statusClosedValue && status != this.statusOpenValue) { if (flag9) { this.calcGrid[num14].heuristicCost = Mathf.RoundToInt((float)this.regionCostCalculator.GetPathCostFromDestToRegion(num14) * CVPathFinder.RegionHeuristicWeightByNodesOpened.Evaluate((float)num4)); } else { int dx = Math.Abs(num12 - x); int dz = Math.Abs(num13 - z); int num19 = GenMath.OctileDistance(dx, dz, num8, num9); this.calcGrid[num14].heuristicCost = Mathf.RoundToInt((float)num19 * num7); } } int num20 = num17 + this.calcGrid[num14].heuristicCost; this.calcGrid[num14].parentIndex = num; this.calcGrid[num14].knownCost = num17; this.calcGrid[num14].status = this.statusOpenValue; this.calcGrid[num14].costNodeCost = num20; num4++; this.openList.Push(new CVPathFinder.CostNode(num14, num20)); } } } IL_C2E :; } this.PfProfilerEndSample(); num3++; this.calcGrid[num].status = this.statusClosedValue; if (num4 >= 2000 && flag7 && !flag9) { flag9 = true; this.regionCostCalculator.Init(cellRect, traverseParms, num8, num9, byteGrid, allowedArea, this.disallowedCornerIndices); this.InitStatusesAndPushStartNode(ref num, start); num4 = 0; num3 = 0; } } } string text = (pawn == null || pawn.CurJob == null) ? "null" : pawn.CurJob.ToString(); string text2 = (pawn == null || pawn.Faction == null) ? "null" : pawn.Faction.ToString(); Log.Warning(string.Concat(new object[] { pawn, " pathing from ", start, " to ", dest, " ran out of cells to process.\nJob:", text, "\nFaction: ", text2 })); this.DebugDrawRichData(); this.PfProfilerEndSample(); return(PawnPath.NotFound); Block_27: this.PfProfilerEndSample(); PawnPath result = this.FinalizedPath(num); this.PfProfilerEndSample(); return(result); Block_29: this.PfProfilerEndSample(); PawnPath result2 = this.FinalizedPath(num); this.PfProfilerEndSample(); return(result2); Block_30: Log.Warning(string.Concat(new object[] { pawn, " pathing from ", start, " to ", dest, " hit search limit of ", 160000, " cells." })); this.DebugDrawRichData(); this.PfProfilerEndSample(); return(PawnPath.NotFound); }
public static void PawnGroupGenSampled() { List <DebugMenuOption> list = new List <DebugMenuOption>(); foreach (Faction faction in Find.FactionManager.AllFactions) { if (faction.def.pawnGroupMakers != null) { if (faction.def.pawnGroupMakers.Any((PawnGroupMaker x) => x.kindDef == PawnGroupKindDefOf.Combat)) { Faction localFac = faction; list.Add(new DebugMenuOption(localFac.Name + " (" + localFac.def.defName + ")", DebugMenuOptionMode.Action, delegate() { List <DebugMenuOption> list2 = new List <DebugMenuOption>(); foreach (float num in Dialog_DebugActionsMenu.PointsOptions(true)) { float localP2 = num; float localP = localP2; float maxPawnCost = PawnGroupMakerUtility.MaxPawnCost(localFac, localP, null, PawnGroupKindDefOf.Combat); string defName = (from op in localFac.def.pawnGroupMakers.SelectMany((PawnGroupMaker gm) => gm.options) where op.Cost <= maxPawnCost select op).MaxBy((PawnGenOption op) => op.Cost).kind.defName; string label = string.Concat(new string[] { localP.ToString(), ", max ", maxPawnCost.ToString("F0"), " ", defName }); list2.Add(new DebugMenuOption(label, DebugMenuOptionMode.Action, delegate() { Dictionary <ThingDef, int>[] weaponsCount = new Dictionary <ThingDef, int> [20]; string[] pawnKinds = new string[20]; for (int i = 0; i < 20; i++) { weaponsCount[i] = new Dictionary <ThingDef, int>(); List <Pawn> list3 = PawnGroupMakerUtility.GeneratePawns(new PawnGroupMakerParms { groupKind = PawnGroupKindDefOf.Combat, tile = Find.CurrentMap.Tile, points = localP, faction = localFac }, false).ToList <Pawn>(); pawnKinds[i] = PawnUtility.PawnKindsToCommaList(list3, true); foreach (Pawn pawn in list3) { if (pawn.equipment.Primary != null) { if (!weaponsCount[i].ContainsKey(pawn.equipment.Primary.def)) { weaponsCount[i].Add(pawn.equipment.Primary.def, 0); } Dictionary <ThingDef, int> dictionary; ThingDef def; (dictionary = weaponsCount[i])[def = pawn.equipment.Primary.def] = dictionary[def] + 1; } pawn.Destroy(DestroyMode.Vanish); } } int totalPawns = weaponsCount.Sum((Dictionary <ThingDef, int> x) => x.Sum((KeyValuePair <ThingDef, int> y) => y.Value)); List <TableDataGetter <int> > list4 = new List <TableDataGetter <int> >(); list4.Add(new TableDataGetter <int>(string.Empty, (int x) => (x != 20) ? (x + 1).ToString() : "avg")); list4.Add(new TableDataGetter <int>("pawns", delegate(int x) { string str = " "; string str2; if (x == 20) { str2 = ((float)totalPawns / 20f).ToString("0.#"); } else { str2 = weaponsCount[x].Sum((KeyValuePair <ThingDef, int> y) => y.Value).ToString(); } return(str + str2); })); list4.Add(new TableDataGetter <int>("kinds", (int x) => (x != 20) ? pawnKinds[x] : string.Empty)); list4.AddRange(from x in DefDatabase <ThingDef> .AllDefs where x.IsWeapon && !x.weaponTags.NullOrEmpty <string>() && weaponsCount.Any((Dictionary <ThingDef, int> wc) => wc.ContainsKey(x)) orderby x.IsMeleeWeapon descending, x.techLevel, x.BaseMarketValue select new TableDataGetter <int>(x.label.Shorten(), delegate(int y) { if (y == 20) { return(" " + ((float)weaponsCount.Sum((Dictionary <ThingDef, int> z) => (!z.ContainsKey(x)) ? 0 : z[x]) / 20f).ToString("0.#")); } string result; if (weaponsCount[y].ContainsKey(x)) { object[] array = new object[5]; array[0] = " "; array[1] = weaponsCount[y][x]; array[2] = " ("; array[3] = ((float)weaponsCount[y][x] / (float)weaponsCount[y].Sum((KeyValuePair <ThingDef, int> z) => z.Value)).ToStringPercent("F0"); array[4] = ")"; result = string.Concat(array); } else { result = string.Empty; } return(result); })); DebugTables.MakeTablesDialog <int>(Enumerable.Range(0, 21), list4.ToArray()); })); } Find.WindowStack.Add(new Dialog_DebugOptionListLister(list2)); })); } } } Find.WindowStack.Add(new Dialog_DebugOptionListLister(list)); }
public void HealthTick() { if (this.Dead) { return; } for (int i = this.hediffSet.hediffs.Count - 1; i >= 0; i--) { Hediff hediff = this.hediffSet.hediffs[i]; hediff.Tick(); hediff.PostTick(); } bool flag = false; for (int j = this.hediffSet.hediffs.Count - 1; j >= 0; j--) { Hediff hediff2 = this.hediffSet.hediffs[j]; if (hediff2.ShouldRemove) { this.hediffSet.hediffs.RemoveAt(j); hediff2.PostRemoved(); flag = true; } } if (flag) { this.Notify_HediffChanged(null); } if (this.Dead) { return; } this.immunity.ImmunityHandlerTick(); if (this.pawn.RaceProps.IsFlesh && this.pawn.IsHashIntervalTick(600) && (this.pawn.needs.food == null || !this.pawn.needs.food.Starving)) { bool flag2 = false; if (this.hediffSet.HasNaturallyHealingInjury()) { float num = 8f; if (this.pawn.GetPosture() != PawnPosture.Standing) { num += 4f; Building_Bed building_Bed = this.pawn.CurrentBed(); if (building_Bed != null) { num += building_Bed.def.building.bed_healPerDay; } } Hediff_Injury hediff_Injury = this.hediffSet.GetHediffs <Hediff_Injury>().Where(new Func <Hediff_Injury, bool>(HediffUtility.CanHealNaturally)).RandomElement <Hediff_Injury>(); hediff_Injury.Heal(num * this.pawn.HealthScale * 0.01f); flag2 = true; } if (this.hediffSet.HasTendedAndHealingInjury() && (this.pawn.needs.food == null || !this.pawn.needs.food.Starving)) { Hediff_Injury hediff_Injury2 = this.hediffSet.GetHediffs <Hediff_Injury>().Where(new Func <Hediff_Injury, bool>(HediffUtility.CanHealFromTending)).RandomElement <Hediff_Injury>(); float tendQuality = hediff_Injury2.TryGetComp <HediffComp_TendDuration>().tendQuality; float num2 = GenMath.LerpDouble(0f, 1f, 0.5f, 1.5f, Mathf.Clamp01(tendQuality)); hediff_Injury2.Heal(22f * num2 * this.pawn.HealthScale * 0.01f); flag2 = true; } if (flag2 && !this.HasHediffsNeedingTendByColony(false) && !HealthAIUtility.ShouldSeekMedicalRest(this.pawn) && !this.hediffSet.HasTendedAndHealingInjury() && PawnUtility.ShouldSendNotificationAbout(this.pawn)) { Messages.Message("MessageFullyHealed".Translate(new object[] { this.pawn.LabelCap }), this.pawn, MessageTypeDefOf.PositiveEvent); } } if (this.pawn.RaceProps.IsFlesh && this.hediffSet.BleedRateTotal >= 0.1f) { float num3 = this.hediffSet.BleedRateTotal * this.pawn.BodySize; if (this.pawn.GetPosture() == PawnPosture.Standing) { num3 *= 0.008f; } else { num3 *= 0.0008f; } if (Rand.Value < num3) { this.TryDropBloodFilth(); } } List <HediffGiverSetDef> hediffGiverSets = this.pawn.RaceProps.hediffGiverSets; if (hediffGiverSets != null && this.pawn.IsHashIntervalTick(60)) { for (int k = 0; k < hediffGiverSets.Count; k++) { List <HediffGiver> hediffGivers = hediffGiverSets[k].hediffGivers; for (int l = 0; l < hediffGivers.Count; l++) { hediffGivers[l].OnIntervalPassed(this.pawn, null); if (this.pawn.Dead) { return; } } } } }
protected virtual IntVec3 GetExactWanderDest(Pawn pawn) { IntVec3 wanderRoot = pawn.PositionHeld; return(RCellFinder.RandomWanderDestFor(pawn, wanderRoot, this.wanderRadius, delegate(Pawn p, IntVec3 v) { if (v.Roofed(p.MapHeld)) { return true; } return false; }, PawnUtility.ResolveMaxDanger(pawn, this.maxDanger))); }
/// <summary> /// Manual finalizer for WorldPawnCleaner.GC(). /// Deconstruct all animal families on map and discard the redundant members. /// </summary> /// <returns>The count of discarded members.</returns> public static int DeconstructAnimalFamily() { List <Pawn> worldpawns = new List <Pawn>(); foreach (Pawn p in Find.WorldPawns.AllPawnsAliveOrDead) { worldpawns.Add(p); } List <Pawn> queue = new List <Pawn>(); List <Pawn> pawnlist = new List <Pawn>(); foreach (Map map in Find.Maps) { foreach (Pawn p in map.mapPawns.AllPawns) { if ((p.records.GetAsInt(RecordDefOf.TimeAsColonistOrColonyAnimal) > 0) && !(p.RaceProps.Humanlike)) { pawnlist.Add(p); } } } foreach (Pawn p in pawnlist) { //Patch:null relationship on robots. if (p.relations != null) { foreach (Pawn p2 in expandRelation(p)) { if (worldpawns.Contains(p2) && (!p2.Spawned) && (!p2.IsPlayerControlledCaravanMember()) && (!PawnUtility.IsTravelingInTransportPodWorldObject(p2)) //Patch:Corpses remained on maps. && (p.Corpse == null) ) { queue.Add(p2); worldpawns.Remove(p2); } } } } //Patch:2nd Pawn of a used Tale_DoublePawn will raise Scribe Warnings if discarded List <Pawn> allUsedTaleOwner; CleanserUtil.InitUsedTalePawns(out allUsedTaleOwner); foreach (Pawn pawn in allUsedTaleOwner) { queue.Remove(pawn); } int a = queue.Count; foreach (Pawn pawn in queue) { Find.WorldPawns.RemovePawn(pawn); if (!pawn.Destroyed) { pawn.Destroy(DestroyMode.Vanish); } if (!pawn.Discarded) { pawn.Discard(true); } } Find.WindowStack.WindowOfType <UserInterface>().Notify_PawnsCountDirty(); return(a); }