根据向量相似度分析,与 'BiosculpterPod, ThingDef' 最相关的代码定义如下: --- **文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\CompProperties_BiosculpterPod_BaseCycle.txt` **相似度:** 0.7659 ```csharp public abstract class CompProperties_BiosculpterPod_BaseCycle : CompProperties { [NoTranslate] public string key; [MustTranslate] public string label; [MustTranslate] public string description; [NoTranslate] public string iconPath; public float durationDays; public Color operatingColor = new Color(0.5f, 0.7f, 0.5f); public ThoughtDef gainThoughtOnCompletion; public List requiredResearch; public List extraRequiredIngredients; private Texture2D icon; public Texture2D Icon { get { if (icon == null) { icon = ContentFinder.Get(iconPath); } return icon; } } public string LabelCap => label.CapitalizeFirst(); } ``` --- **文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\CompBiosculpterPod.txt` **相似度:** 0.7294 ```csharp public class CompBiosculpterPod : ThingComp, ISuspendableThingHolder, IThingHolder, IThingHolderWithDrawnPawn, IStoreSettingsParent, INotifyHauledTo, ISearchableContents { private const int NoPowerEjectCumulativeTicks = 60000; private const int BiotunedDuration = 4800000; private const float NutritionRequired = 5f; private const float CacheForSecs = 2f; private static readonly Texture2D InterruptCycleIcon = ContentFinder.Get("UI/Designators/Cancel"); private static readonly Material BackgroundMat = SolidColorMaterials.NewSolidColorMaterial(new Color(0.082f, 0.078f, 0.063f), ShaderDatabase.SolidColorBehind); private const float BackgroundRect_YOff = 0.07317074f; private const float Pawn_YOff = 0.03658537f; private string currentCycleKey; private float currentCycleTicksRemaining; private int currentCyclePowerCutTicks; private ThingOwner innerContainer; private Pawn biotunedTo; private int biotunedCountdownTicks; private StorageSettings allowedNutritionSettings; private float liquifiedNutrition; public bool autoLoadNutrition = true; public bool devFillPodLatch; private bool autoAgeReversal; private int tickEntered = -99999; public Job queuedEnterJob; public Pawn queuedPawn; private List chosenExtraItems = new List(); private List cycleEligiblePawnOptions = new List(); private Pawn pawnEnteringBiosculpter; private Dictionary> cachedExtraIngredients = new Dictionary>(); private Dictionary cachedAnyPawnEligible = new Dictionary(); private static Dictionary> cachedBiotunedPods = new Dictionary>(); private Pawn cacheReachIngredientsPawn; private CompBiosculpterPod_Cycle cacheReachIngredientsCycle; private float cacheReachIngredientsTime = float.MinValue; private bool cacheReachIngredientsResult; private Effecter progressBarEffecter; private Effecter operatingEffecter; private Effecter readyEffecter; private Texture2D cachedAutoAgeReverseIcon; private List cachedAvailableCycles; private Dictionary cycleLookup; private static string cachedAgeReversalCycleKey = null; private List tmpIngredientsStrings = new List(); private static readonly List tmpItems = new List(); private CompPowerTrader powerTraderComp; private CompPower powerComp; private static List cachedPodDefs; public CompProperties_BiosculpterPod Props => props as CompProperties_BiosculpterPod; public ThingOwner SearchableContents => innerContainer; public bool IsContentsSuspended => true; public float RequiredNutritionRemaining => Mathf.Max(5f - liquifiedNutrition, 0f); public bool NutritionLoaded => RequiredNutritionRemaining <= 0f; public bool AutoAgeReversal => autoAgeReversal; private Texture2D AutoAgeReversalIcon { get { if (cachedAutoAgeReverseIcon == null) { cachedAutoAgeReverseIcon = ContentFinder.Get("UI/Gizmos/BiosculpterAutoAgeReversal"); } return cachedAutoAgeReverseIcon; } } public BiosculpterPodState State { get { if (Occupant != null) { return BiosculpterPodState.Occupied; } if (NutritionLoaded) { return BiosculpterPodState.SelectingCycle; } return BiosculpterPodState.LoadingNutrition; } } public Pawn Occupant { get { if (pawnEnteringBiosculpter != null) { return pawnEnteringBiosculpter; } if (currentCycleKey == null) { return null; } if (innerContainer.Count != 1) { return null; } return innerContainer[0] as Pawn; } } public CompBiosculpterPod_Cycle CurrentCycle { get { if (currentCycleKey == null) { return null; } foreach (CompBiosculpterPod_Cycle availableCycle in AvailableCycles) { if (availableCycle.Props.key == currentCycleKey) { return availableCycle; } } return null; } } public List AvailableCycles { get { if (cachedAvailableCycles == null) { SetupCycleCaches(); } return cachedAvailableCycles; } } public string AgeReversalCycleKey { get { if (cachedAgeReversalCycleKey == null) { SetupCycleCaches(); } return cachedAgeReversalCycleKey; } } private float CycleSpeedFactorNoPawn => CleanlinessSpeedFactor * BiotunedSpeedFactor; public float CycleSpeedFactor { get { if (Occupant == null) { return Mathf.Max(0.1f, CycleSpeedFactorNoPawn); } return GetCycleSpeedFactorForPawn(Occupant); } } private float CleanlinessSpeedFactor => parent.GetStatValue(StatDefOf.BiosculpterPodSpeedFactor); private float BiotunedSpeedFactor { get { if (biotunedTo == null) { return 1f; } return Props.biotunedCycleSpeedFactor; } } public bool PowerOn => parent.TryGetComp().PowerOn; public float HeldPawnDrawPos_Y => parent.DrawPos.y - 0.03658537f; public float HeldPawnBodyAngle => parent.Rotation.Opposite.AsAngle; public PawnPosture HeldPawnPosture => PawnPosture.LayingOnGroundFaceUp; public bool StorageTabVisible => true; public CompBiosculpterPod() { innerContainer = new ThingOwner(this); } public override void Initialize(CompProperties props) { base.Initialize(props); allowedNutritionSettings = new StorageSettings(this); if (parent.def.building.defaultStorageSettings != null) { allowedNutritionSettings.CopyFrom(parent.def.building.defaultStorageSettings); } } public override void PostSpawnSetup(bool respawningAfterLoad) { if (ModLister.CheckIdeology("Biosculpter pod comp")) { base.PostSpawnSetup(respawningAfterLoad); } } public override void PostExposeData() { base.PostExposeData(); Scribe_Deep.Look(ref innerContainer, "innerContainer", this); Scribe_Values.Look(ref currentCycleKey, "currentCycleKey"); Scribe_Values.Look(ref currentCycleTicksRemaining, "currentCycleTicksRemaining", 0f); Scribe_Values.Look(ref currentCyclePowerCutTicks, "currentCyclePowerCutTicks", 0); Scribe_References.Look(ref biotunedTo, "biotunedTo"); Scribe_Values.Look(ref biotunedCountdownTicks, "biotunedCountdownTicks", 0); Scribe_Deep.Look(ref allowedNutritionSettings, "allowedNutritionSettings"); Scribe_Values.Look(ref liquifiedNutrition, "liquifiedNutrition", 0f); Scribe_Values.Look(ref autoLoadNutrition, "autoLoadNutrition", defaultValue: false); Scribe_Values.Look(ref devFillPodLatch, "devFillPodLatch", defaultValue: false); Scribe_Values.Look(ref autoAgeReversal, "autoAgeReversal", defaultValue: false); Scribe_Values.Look(ref tickEntered, "tickEntered", 0); Scribe_References.Look(ref queuedEnterJob, "queuedEnterJob"); Scribe_References.Look(ref queuedPawn, "queuedPawn"); if (allowedNutritionSettings == null) { allowedNutritionSettings = new StorageSettings(this); if (parent.def.building.defaultStorageSettings != null) { allowedNutritionSettings.CopyFrom(parent.def.building.defaultStorageSettings); } } if (Scribe.mode == LoadSaveMode.PostLoadInit) { if (currentCycleKey == "healing") { currentCycleKey = "medic"; } if (biotunedTo != null) { SetBiotuned(biotunedTo); } LiquifyNutrition(); } } public CompBiosculpterPod_Cycle GetCycle(string key) { if (cycleLookup == null) { SetupCycleCaches(); } return cycleLookup[key]; } public float GetCycleSpeedFactorForPawn(Pawn p) { return Mathf.Max(0.1f, CycleSpeedFactorNoPawn * p.GetStatValue(StatDefOf.BiosculpterOccupantSpeed)); } private void SetupCycleCaches() { cachedAvailableCycles = new List(); cachedAvailableCycles.AddRange(parent.AllComps.OfType()); cycleLookup = new Dictionary(); foreach (CompBiosculpterPod_Cycle cachedAvailableCycle in cachedAvailableCycles) { if (cachedAvailableCycle is CompBiosculpterPod_AgeReversalCycle compBiosculpterPod_AgeReversalCycle) { cachedAgeReversalCycleKey = compBiosculpterPod_AgeReversalCycle.Props.key; } cycleLookup[cachedAvailableCycle.Props.key] = cachedAvailableCycle; } } public void SetBiotuned(Pawn newBiotunedTo) { if (newBiotunedTo != biotunedTo) { autoAgeReversal = false; } if (biotunedTo != null && cachedBiotunedPods.ContainsKey(biotunedTo)) { cachedBiotunedPods[biotunedTo].Remove(this); } if (newBiotunedTo != null && !cachedBiotunedPods.ContainsKey(newBiotunedTo)) { cachedBiotunedPods[newBiotunedTo] = new List(); } if (newBiotunedTo != null && !cachedBiotunedPods[newBiotunedTo].Contains(this)) { cachedBiotunedPods[newBiotunedTo].Add(this); } if (newBiotunedTo != null && newBiotunedTo != biotunedTo) { biotunedCountdownTicks = 4800000; } biotunedTo = newBiotunedTo; } public override void PostDestroy(DestroyMode mode, Map previousMap) { SetBiotuned(null); if (mode == DestroyMode.Deconstruct || mode == DestroyMode.KillFinalize) { EjectContents(interrupted: true, playSounds: false, previousMap); } innerContainer.ClearAndDestroyContents(); base.PostDestroy(mode, previousMap); } public override void PostDeSpawn(Map map, DestroyMode mode = DestroyMode.Vanish) { if (mode != DestroyMode.WillReplace) { EjectContents(interrupted: true, playSounds: false, map); currentCycleKey = null; } progressBarEffecter?.Cleanup(); progressBarEffecter = null; operatingEffecter?.Cleanup(); operatingEffecter = null; readyEffecter?.Cleanup(); readyEffecter = null; } public override void DrawGUIOverlay() { base.DrawGUIOverlay(); if (!Find.ScreenshotModeHandler.Active && (biotunedTo != null || Occupant != null)) { GenMapUI.DrawThingLabel(parent, biotunedTo?.LabelShort ?? Occupant.LabelShort, GenMapUI.DefaultThingLabelColor); } } public override string CompInspectStringExtra() { StringBuilder stringBuilder = new StringBuilder(); BiosculpterPodState state = State; if (parent.Spawned) { CompBiosculpterPod_Cycle currentCycle = CurrentCycle; if (currentCycle != null) { stringBuilder.AppendLineIfNotEmpty().Append("BiosculpterPodCycleLabel".Translate()).Append(": ") .Append(currentCycle.Props.LabelCap); if (biotunedTo == null) { stringBuilder.Append(" " + "BiosculpterPodCycleWillBiotune".Translate()); } } else if (state == BiosculpterPodState.SelectingCycle) { if (PowerOn) { if (queuedEnterJob != null && !queuedEnterJob.biosculpterCycleKey.NullOrEmpty()) { stringBuilder.Append("BiosculpterPodCycleStandby".Translate(GetCycle(queuedEnterJob.biosculpterCycleKey).Props.label.Named("CYCLE"), queuedPawn.Named("PAWN"))); } else { stringBuilder.Append("BiosculpterPodCycleSelection".Translate().CapitalizeFirst()); } } else { stringBuilder.Append("BiosculpterPodCycleSelectionNoPower".Translate().CapitalizeFirst()); } } if (state == BiosculpterPodState.LoadingNutrition) { stringBuilder.Append("BiosculpterPodCycleLabelLoading".Translate().CapitalizeFirst()); stringBuilder.AppendLineIfNotEmpty().Append("Nutrition".Translate()).Append(": ") .Append(liquifiedNutrition.ToStringByStyle(ToStringStyle.FloatMaxOne)) .Append(" / ") .Append(5f); } if (state == BiosculpterPodState.Occupied) { float num = currentCycleTicksRemaining / CycleSpeedFactor; stringBuilder.AppendLineIfNotEmpty().Append("Contains".Translate()).Append(": ") .Append(Occupant.NameShortColored.Resolve()); if (!PowerOn) { stringBuilder.AppendLine().Append("BiosculpterCycleNoPowerInterrupt".Translate((60000 - currentCyclePowerCutTicks).ToStringTicksToPeriod().Named("TIME")).Colorize(ColorLibrary.RedReadable)); } stringBuilder.AppendLine().Append("BiosculpterCycleTimeRemaining".Translate()).Append(": ") .Append(((int)num).ToStringTicksToPeriod().Colorize(ColoredText.DateTimeColor)); Ideo ideo = Occupant.Ideo; if (ideo != null && ideo.HasPrecept(PreceptDefOf.Biosculpting_Accelerated)) { stringBuilder.Append(" (" + "BiosculpterCycleAccelerated".Translate() + ")"); } if (biotunedTo != null) { stringBuilder.AppendLine().Append("BiosculpterBiotunedSpeedFactor".Translate()).Append(": ") .Append(BiotunedSpeedFactor.ToStringPercent()); } stringBuilder.AppendLine().Append("BiosculpterCleanlinessSpeedFactor".Translate()).Append(": ") .Append(CleanlinessSpeedFactor.ToStringPercent()); } } if (biotunedTo != null && state != BiosculpterPodState.Occupied) { stringBuilder.AppendLineIfNotEmpty().Append("BiosculpterBiotunedTo".Translate()).Append(": ") .Append(biotunedTo.LabelShort) .Append(" (") .Append(biotunedCountdownTicks.ToStringTicksToPeriod()) .Append(")"); } if (stringBuilder.Length <= 0) { return null; } return stringBuilder.ToString(); } public override IEnumerable CompGetGizmosExtra() { BiosculpterPodState state = State; string cycleIndependentCannotUseReason = CannotUseNowReason(); foreach (CompBiosculpterPod_Cycle cycle in AvailableCycles) { string text = cycleIndependentCannotUseReason ?? CannotUseNowCycleReason(cycle); Command_Action command_Action = new Command_Action(); command_Action.defaultLabel = "BiosculpterPodCycleCommand".Translate(cycle.Props.label) + ((biotunedTo != null) ? (" (" + biotunedTo.LabelShort + ")") : ""); command_Action.defaultDesc = CycleDescription(cycle); command_Action.icon = cycle.Props.Icon; command_Action.action = delegate { SelectPawnsForCycleOptions(cycle, out var options2); if (biotunedTo != null && options2.Count > 0) { options2[0].action(); if (!(cycle is CompBiosculpterPod_HealingCycle)) { Messages.Message("BiosculpterEnteringMessage".Translate(biotunedTo.Named("PAWN"), cycle.Props.label.Named("CYCLE")).CapitalizeFirst(), parent, MessageTypeDefOf.SilentInput, historical: false); } } else { Find.WindowStack.Add(new FloatMenu(options2)); } }; command_Action.activateSound = SoundDefOf.Tick_Tiny; command_Action.Disabled = text != null; List options; if (text != null) { command_Action.Disable(text); } else if (!SelectPawnsForCycleOptions(cycle, out options, shortCircuit: true)) { command_Action.Disable((biotunedTo != null) ? "BiosculpterNoEligiblePawnsBiotuned".Translate(biotunedTo.Named("PAWN")) : "BiosculpterNoEligiblePawns".Translate()); } yield return command_Action; } if (state == BiosculpterPodState.Occupied) { Command_Action command_Action2 = new Command_Action(); command_Action2.defaultLabel = "BiosculpterInteruptCycle".Translate(); command_Action2.defaultDesc = "BiosculpterInteruptCycleDesc".Translate(); command_Action2.icon = InterruptCycleIcon; command_Action2.action = delegate { EjectContents(interrupted: true, playSounds: true); }; command_Action2.activateSound = SoundDefOf.Designate_Cancel; yield return command_Action2; } Command_Toggle command_Toggle = new Command_Toggle(); command_Toggle.defaultLabel = "BiosculpterAutoLoadNutritionLabel".Translate(); command_Toggle.defaultDesc = "BiosculpterAutoLoadNutritionDescription".Translate(); command_Toggle.icon = (autoLoadNutrition ? TexCommand.ForbidOff : TexCommand.ForbidOn); command_Toggle.isActive = () => autoLoadNutrition; command_Toggle.toggleAction = delegate { autoLoadNutrition = !autoLoadNutrition; }; yield return command_Toggle; if ((biotunedTo?.Ideo?.HasPrecept(PreceptDefOf.AgeReversal_Demanded)).GetValueOrDefault()) { Command_Toggle command_Toggle2 = new Command_Toggle(); command_Toggle2.defaultLabel = "BiosculpterAutoAgeReversalLabel".Translate(biotunedTo.Named("PAWN")); TaggedString taggedString = ((biotunedTo.ageTracker.AgeReversalDemandedDeadlineTicks > 0) ? "BiosculpterAutoAgeReversalDescriptionFuture".Translate(biotunedTo.Named("PAWN"), ((int)biotunedTo.ageTracker.AgeReversalDemandedDeadlineTicks).ToStringTicksToPeriodVague().Named("TIME")) : "BiosculpterAutoAgeReversalDescriptionNow".Translate(biotunedTo.Named("PAWN"))); command_Toggle2.defaultDesc = "BiosculpterAutoAgeReversalDescription".Translate(biotunedTo.Named("PAWN"), taggedString.Named("NEXTTREATMENT")); command_Toggle2.icon = AutoAgeReversalIcon; command_Toggle2.isActive = () => AutoAgeReversal; command_Toggle2.toggleAction = delegate { autoAgeReversal = !autoAgeReversal; }; if (!CanAgeReverse(biotunedTo)) { command_Toggle2.Disable("UnderMinBiosculpterAgeReversalAge".Translate(biotunedTo.ageTracker.AdultMinAge.Named("ADULTAGE")).CapitalizeFirst()); autoAgeReversal = false; } yield return command_Toggle2; } foreach (Gizmo item in StorageSettingsClipboard.CopyPasteGizmosFor(allowedNutritionSettings)) { yield return item; } Gizmo gizmo = Building.SelectContainedItemGizmo(parent, Occupant); if (gizmo != null) { yield return gizmo; } if (DebugSettings.ShowDevGizmos) { yield return new Command_Action { defaultLabel = "DEV: complete cycle", action = delegate { currentCycleTicksRemaining = 10f; }, Disabled = (State != BiosculpterPodState.Occupied) }; yield return new Command_Action { defaultLabel = "DEV: advance cycle +1 day", action = delegate { currentCycleTicksRemaining -= 60000f; }, Disabled = (State != BiosculpterPodState.Occupied) }; yield return new Command_Action { defaultLabel = "DEV: complete biotune timer", action = delegate { biotunedCountdownTicks = 10; }, Disabled = (biotunedCountdownTicks <= 0) }; yield return new Command_Action { defaultLabel = "DEV: fill nutrition and cycle ingredients", action = delegate { liquifiedNutrition = 5f; devFillPodLatch = true; }, Disabled = (State == BiosculpterPodState.Occupied || (devFillPodLatch && liquifiedNutrition == 5f)) }; } } private string IngredientsDescription(CompBiosculpterPod_Cycle cycle) { tmpIngredientsStrings.Clear(); if (!cycle.Props.extraRequiredIngredients.NullOrEmpty() && !devFillPodLatch) { for (int i = 0; i < cycle.Props.extraRequiredIngredients.Count; i++) { tmpIngredientsStrings.Add(cycle.Props.extraRequiredIngredients[i].Summary); } } return tmpIngredientsStrings.ToCommaList(useAnd: true); } private string CycleDescription(CompBiosculpterPod_Cycle cycle) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(cycle.Description(biotunedTo)); float num = cycle.Props.durationDays / CycleSpeedFactor; float num2 = num / PreceptDefOf.Biosculpting_Accelerated.biosculpterPodCycleSpeedFactor; stringBuilder.AppendLine("\n\n" + "BiosculpterPodCycleDuration".Translate() + ": " + ((int)(num * 60000f)).ToStringTicksToDays()); if (!Find.IdeoManager.classicMode) { stringBuilder.Append("BiosculpterPodCycleDurationTranshumanists".Translate() + ": " + ((int)(num2 * 60000f)).ToStringTicksToDays()); } return stringBuilder.ToString(); } public bool PawnCanUseNow(Pawn pawn, CompBiosculpterPod_Cycle cycle) { return (CannotUseNowReason() ?? CannotUseNowPawnReason(pawn) ?? CannotUseNowCycleReason(cycle) ?? CannotUseNowPawnCycleReason(pawn, cycle)) == null; } public override IEnumerable CompFloatMenuOptions(Pawn selPawn) { if (selPawn.IsQuestLodger()) { yield return new FloatMenuOption("CannotEnter".Translate() + ": " + "CryptosleepCasketGuestsNotAllowed".Translate().CapitalizeFirst(), null); yield break; } string cycleIndependentfailureReason = CannotUseNowReason() ?? CannotUseNowPawnReason(selPawn); foreach (CompBiosculpterPod_Cycle cycle in AvailableCycles) { string text = cycleIndependentfailureReason ?? CannotUseNowCycleReason(cycle) ?? CannotUseNowPawnCycleReason(selPawn, cycle); if (text != null) { yield return new FloatMenuOption(CannotStartText(cycle, text), null); continue; } string label = "EnterBiosculpterPod".Translate(cycle.Props.label, ((int)(cycle.Props.durationDays / GetCycleSpeedFactorForPawn(selPawn) * 60000f)).ToStringTicksToDays()); yield return FloatMenuUtility.DecoratePrioritizedTask(new FloatMenuOption(label, delegate { PrepareCycleJob(selPawn, selPawn, cycle, EnterBiosculpterJob()); }), selPawn, parent); } } public static bool CanAgeReverse(Pawn biosculptee) { return biosculptee.ageTracker.Adult; } public static List BiotunedPods(Pawn pawn) { return cachedBiotunedPods.TryGetValue(pawn); } public static bool HasBiotunedAutoAgeReversePod(Pawn pawn) { List list = cachedBiotunedPods.TryGetValue(pawn); if (list == null) { return false; } foreach (CompBiosculpterPod item in list) { if (item.AutoAgeReversal) { return true; } } return false; } public static string CannotStartText(CompBiosculpterPod_Cycle cycle, string translatedReason) { return "BiosculpterCannotStartCycle".Translate(cycle.Props.label) + ": " + translatedReason.CapitalizeFirst(); } public string CannotUseNowCycleReason(CompBiosculpterPod_Cycle cycle) { List list = cycle.MissingResearchLabels(); if (list.Any()) { return "MissingRequiredResearch".Translate() + " " + list.ToCommaList(); } return null; } public string CannotUseNowPawnCycleReason(Pawn p, CompBiosculpterPod_Cycle cycle, bool checkIngredients = true) { return CannotUseNowPawnCycleReason(p, p, cycle, checkIngredients); } private bool CanReachOrHasIngredients(Pawn hauler, Pawn biosculptee, CompBiosculpterPod_Cycle cycle, bool useCache = false) { if (!PawnCarryingExtraCycleIngredients(biosculptee, cycle) && (biosculptee == hauler || !PawnCarryingExtraCycleIngredients(hauler, cycle))) { return CanReachRequiredIngredients(hauler, cycle, useCache); } return true; } public string CannotUseNowPawnCycleReason(Pawn hauler, Pawn biosculptee, CompBiosculpterPod_Cycle cycle, bool checkIngredients = true) { if (AgeReversalCycleKey != null && cycle.Props.key == AgeReversalCycleKey && !CanAgeReverse(biosculptee)) { return "UnderMinBiosculpterAgeReversalAge".Translate(biosculptee.ageTracker.AdultMinAge.Named("ADULTAGE")).CapitalizeFirst(); } if (checkIngredients && !CanReachOrHasIngredients(hauler, biosculptee, cycle, useCache: true)) { return "BiosculpterMissingIngredients".Translate(IngredientsDescription(cycle).Named("INGREDIENTS")).CapitalizeFirst(); } return null; } public string CannotUseNowPawnReason(Pawn p) { if (biotunedTo != null && biotunedTo != p) { return "BiosculpterBiotunedToAnother".Translate().CapitalizeFirst(); } if (!p.CanReach(parent, PathEndMode.InteractionCell, Danger.Deadly)) { return "NoPath".Translate().CapitalizeFirst(); } return null; } public string CannotUseNowReason() { if (!PowerOn) { return "NoPower".Translate().CapitalizeFirst(); } if (State == BiosculpterPodState.LoadingNutrition) { return "BiosculpterNutritionNotLoaded".Translate().CapitalizeFirst(); } if (State == BiosculpterPodState.Occupied) { return "BiosculpterOccupied".Translate().CapitalizeFirst(); } return null; } private List RequiredIngredients(CompBiosculpterPod_Cycle cycle) { List extraRequiredIngredients = cycle.Props.extraRequiredIngredients; if (extraRequiredIngredients == null || devFillPodLatch) { return null; } if (!cachedExtraIngredients.ContainsKey(cycle)) { cachedExtraIngredients[cycle] = extraRequiredIngredients.Select((ThingDefCountClass tc) => tc.ToIngredientCount()).ToList(); } return cachedExtraIngredients[cycle]; } private bool CanReachRequiredIngredients(Pawn pawn, CompBiosculpterPod_Cycle cycle, bool useCache = false) { chosenExtraItems.Clear(); if (cycle.Props.extraRequiredIngredients == null || devFillPodLatch) { return true; } float realtimeSinceStartup = Time.realtimeSinceStartup; if (useCache && cacheReachIngredientsPawn == pawn && cacheReachIngredientsCycle == cycle && realtimeSinceStartup < cacheReachIngredientsTime + 2f) { return cacheReachIngredientsResult; } cacheReachIngredientsPawn = pawn; cacheReachIngredientsCycle = cycle; cacheReachIngredientsTime = realtimeSinceStartup; cacheReachIngredientsResult = WorkGiver_DoBill.TryFindBestFixedIngredients(RequiredIngredients(cycle), pawn, parent, chosenExtraItems); return cacheReachIngredientsResult; } private bool SelectPawnCycleOption(Pawn pawn, CompBiosculpterPod_Cycle cycle, out FloatMenuOption option) { string text = CannotUseNowPawnReason(pawn) ?? CannotUseNowPawnCycleReason(pawn, cycle, checkIngredients: false); string label = pawn.Label + ((text == null) ? "" : (": " + text)); Action action = null; if (text == null) { action = delegate { PrepareCycleJob(pawn, pawn, cycle, EnterBiosculpterJob()); }; } option = new FloatMenuOption(label, action); return text == null; } private bool SelectPawnsForCycleOptions(CompBiosculpterPod_Cycle cycle, out List options, bool shortCircuit = false) { cycleEligiblePawnOptions.Clear(); options = cycleEligiblePawnOptions; if (!cachedAnyPawnEligible.ContainsKey(cycle)) { cachedAnyPawnEligible[cycle] = new CacheAnyPawnEligibleCycle { gameTime = float.MinValue }; } int ticksGame = Find.TickManager.TicksGame; if (shortCircuit && (float)ticksGame < cachedAnyPawnEligible[cycle].gameTime + 2f) { return cachedAnyPawnEligible[cycle].anyEligible; } cachedAnyPawnEligible[cycle].gameTime = ticksGame; if (biotunedTo != null) { if (biotunedTo.Dead || !biotunedTo.Spawned || biotunedTo.Map != parent.Map) { cachedAnyPawnEligible[cycle].anyEligible = false; return cachedAnyPawnEligible[cycle].anyEligible; } if (SelectPawnCycleOption(biotunedTo, cycle, out var option) && shortCircuit) { cachedAnyPawnEligible[cycle].anyEligible = true; return cachedAnyPawnEligible[cycle].anyEligible; } cycleEligiblePawnOptions.Add(option); } else { foreach (Pawn item in parent.Map.mapPawns.FreeColonistsSpawned) { if (SelectPawnCycleOption(item, cycle, out var option2) && shortCircuit) { cachedAnyPawnEligible[cycle].anyEligible = true; return cachedAnyPawnEligible[cycle].anyEligible; } cycleEligiblePawnOptions.Add(option2); } } cachedAnyPawnEligible[cycle].anyEligible = cycleEligiblePawnOptions.Count > 0; return cachedAnyPawnEligible[cycle].anyEligible; } public Job EnterBiosculpterJob() { return JobMaker.MakeJob(JobDefOf.EnterBiosculpterPod, parent); } public Job MakeCarryToBiosculpterJob(Pawn willBeCarried) { return JobMaker.MakeJob(JobDefOf.CarryToBiosculpterPod, willBeCarried, LocalTargetInfo.Invalid, parent); } public void ConfigureJobForCycle(Job job, CompBiosculpterPod_Cycle cycle, List extraIngredients) { if (!extraIngredients.NullOrEmpty()) { job.targetQueueB = new List(extraIngredients.Count); job.countQueue = new List(extraIngredients.Count); foreach (ThingCount extraIngredient in extraIngredients) { job.targetQueueB.Add(extraIngredient.Thing); job.countQueue.Add(extraIngredient.Count); } } job.haulMode = HaulMode.ToCellNonStorage; job.biosculpterCycleKey = cycle.Props.key; } public void PrepareCycleJob(Pawn hauler, Pawn biosculptee, CompBiosculpterPod_Cycle cycle, Job job) { OrderToPod(cycle, biosculptee, delegate { chosenExtraItems.Clear(); if (!CanReachOrHasIngredients(hauler, biosculptee, cycle)) { Messages.Message("BiosculpterMissingIngredients".Translate(IngredientsDescription(cycle).Named("INGREDIENTS")).CapitalizeFirst(), parent, MessageTypeDefOf.NegativeEvent, historical: false); } else { ConfigureJobForCycle(job, cycle, chosenExtraItems); if (cycle.Props.extraRequiredIngredients != null && !devFillPodLatch) { if (job.def == JobDefOf.CarryToBiosculpterPod) { Messages.Message("BiosculpterCarryStartedMessage".Translate(hauler.Named("PAWN"), IngredientsDescription(cycle).Named("INGREDIENTS"), biosculptee.Named("DOWNED"), cycle.Props.label.Named("CYCLE")), parent, MessageTypeDefOf.SilentInput, historical: false); } else { Messages.Message("BiosculpterLoadingStartedMessage".Translate(hauler.Named("PAWN"), IngredientsDescription(cycle).Named("INGREDIENTS"), cycle.Props.label.Named("CYCLE")), parent, MessageTypeDefOf.SilentInput, historical: false); } } if (hauler.jobs.TryTakeOrderedJob(job, JobTag.Misc)) { SetQueuedInformation(job, biosculptee); } } }); } public void ClearQueuedInformation() { SetQueuedInformation(null, null); } public void SetQueuedInformation(Job job, Pawn biosculptee) { queuedEnterJob = job; queuedPawn = biosculptee; } public bool CanAcceptNutrition(Thing thing) { return allowedNutritionSettings.AllowedToAccept(thing); } public bool CanAcceptOnceCycleChosen(Pawn pawn) { if (State != BiosculpterPodState.SelectingCycle || !PowerOn) { return false; } if (biotunedTo != null && biotunedTo != pawn) { return false; } return true; } public bool PawnCarryingExtraCycleIngredients(Pawn pawn, string cycleKey, bool remove = false) { return PawnCarryingExtraCycleIngredients(pawn, GetCycle(cycleKey), remove); } public bool PawnCarryingExtraCycleIngredients(Pawn pawn, CompBiosculpterPod_Cycle cycle, bool remove = false) { if (cycle.Props.extraRequiredIngredients.NullOrEmpty() || devFillPodLatch) { return true; } foreach (ThingDefCountClass extraRequiredIngredient in cycle.Props.extraRequiredIngredients) { if (pawn.inventory.Count(extraRequiredIngredient.thingDef) < extraRequiredIngredient.count) { return false; } } if (remove) { foreach (ThingDefCountClass extraRequiredIngredient2 in cycle.Props.extraRequiredIngredients) { pawn.inventory.RemoveCount(extraRequiredIngredient2.thingDef, extraRequiredIngredient2.count); } } return true; } public bool TryAcceptPawn(Pawn pawn, string cycleKey) { return TryAcceptPawn(pawn, GetCycle(cycleKey)); } public bool TryAcceptPawn(Pawn pawn, CompBiosculpterPod_Cycle cycle) { if (!CanAcceptOnceCycleChosen(pawn)) { return false; } if (!PawnCarryingExtraCycleIngredients(pawn, cycle, remove: true)) { return false; } currentCycleKey = cycle.Props.key; innerContainer.ClearAndDestroyContents(); pawnEnteringBiosculpter = pawn; bool num = pawn.DeSpawnOrDeselect(); if (pawn.holdingOwner != null) { pawn.holdingOwner.TryTransferToContainer(pawn, innerContainer); } else { innerContainer.TryAdd(pawn); } if (num) { Find.Selector.Select(pawn, playSound: false, forceDesignatorDeselect: false); } pawnEnteringBiosculpter = null; currentCycleTicksRemaining = cycle.Props.durationDays * 60000f; liquifiedNutrition = 0f; devFillPodLatch = false; ClearQueuedInformation(); tickEntered = Find.TickManager.TicksGame; return true; } public void EjectContents(bool interrupted, bool playSounds, Map destMap = null) { if (destMap == null) { destMap = parent.Map; } Pawn occupant = Occupant; currentCycleKey = null; currentCycleTicksRemaining = 0f; currentCyclePowerCutTicks = 0; liquifiedNutrition = 0f; devFillPodLatch = false; innerContainer.TryDropAll(parent.InteractionCell, destMap, ThingPlaceMode.Near); if (occupant != null) { FilthMaker.TryMakeFilth(parent.InteractionCell, destMap, ThingDefOf.Filth_PodSlime, new IntRange(3, 6).RandomInRange); if (interrupted) { occupant.needs?.mood.thoughts.memories.TryGainMemory(ThoughtDefOf.SoakingWet); occupant.health?.AddHediff(HediffDefOf.BiosculptingSickness); } } if (playSounds) { Props.exitSound?.PlayOneShot(SoundInfo.InMap(new TargetInfo(parent.Position, parent.Map))); } } private void CycleCompleted() { Pawn occupant = Occupant; CompBiosculpterPod_Cycle currentCycle = CurrentCycle; SetBiotuned(occupant); currentCycle.CycleCompleted(occupant); EjectContents(interrupted: false, playSounds: true); if (occupant != null) { Need_Food need_Food = occupant.needs?.food; if (need_Food != null) { need_Food.CurLevelPercentage = 1f; } Need_Rest need_Rest = occupant.needs?.rest; if (need_Rest != null) { need_Rest.CurLevelPercentage = 1f; } if (currentCycle.Props.gainThoughtOnCompletion != null) { occupant.needs?.mood?.thoughts.memories.TryGainMemory(ThoughtDefOf.AgeReversalReceived); } Find.HistoryEventsManager.RecordEvent(new HistoryEvent(HistoryEventDefOf.UsedBiosculpterPod, occupant.Named(HistoryEventArgsNames.Doer))); } if (tickEntered > 0) { occupant.drugs.Notify_LeftSuspension(Find.TickManager.TicksGame - tickEntered); } } private void LiquifyNutrition() { tmpItems.AddRange(innerContainer); foreach (Thing tmpItem in tmpItems) { float num = tmpItem.GetStatValue(StatDefOf.Nutrition) * (float)tmpItem.stackCount; if (!(num <= 0f) && !(tmpItem is Pawn)) { liquifiedNutrition = Mathf.Min(5f, liquifiedNutrition + num); tmpItem.Destroy(); } } tmpItems.Clear(); } public override void CompTick() { if (!ModLister.CheckIdeology("Biosculpting")) { return; } base.CompTick(); if (State != BiosculpterPodState.SelectingCycle || !PowerOn) { readyEffecter?.Cleanup(); readyEffecter = null; } else if (Props.readyEffecter != null) { if (readyEffecter == null) { readyEffecter = Props.readyEffecter.Spawn(); ColorizeEffecter(readyEffecter, Props.selectCycleColor); readyEffecter.Trigger(parent, new TargetInfo(parent.InteractionCell, parent.Map)); } readyEffecter.EffectTick(parent, new TargetInfo(parent.InteractionCell, parent.Map)); } if (State != BiosculpterPodState.Occupied) { progressBarEffecter?.Cleanup(); progressBarEffecter = null; operatingEffecter?.Cleanup(); operatingEffecter = null; } else { Pawn occupant = Occupant; biotunedCountdownTicks = 4800000; if (PowerOn) { int num = 1; currentCycleTicksRemaining -= (float)num * CycleSpeedFactor; if (currentCycleTicksRemaining <= 0f) { CycleCompleted(); } } else { currentCyclePowerCutTicks++; if (currentCyclePowerCutTicks >= 60000) { EjectContents(interrupted: true, playSounds: true); Messages.Message("BiosculpterNoPowerEjectedMessage".Translate(occupant.Named("PAWN")), occupant, MessageTypeDefOf.NegativeEvent, historical: false); } } if (currentCycleTicksRemaining > 0f) { if (progressBarEffecter == null) { progressBarEffecter = EffecterDefOf.ProgressBar.Spawn(); } progressBarEffecter.EffectTick(parent, TargetInfo.Invalid); MoteProgressBar moteProgressBar = (progressBarEffecter.children[0] as SubEffecter_ProgressBar)?.mote; if (moteProgressBar != null) { float num2 = CurrentCycle.Props.durationDays * 60000f; moteProgressBar.progress = 1f - Mathf.Clamp01(currentCycleTicksRemaining / num2); int num3 = (parent.RotatedSize.z - 1) / 2; moteProgressBar.offsetZ = 0f - ((float)num3 + 0.5f); } if (Props.operatingEffecter != null) { if (!PowerOn) { operatingEffecter?.Cleanup(); operatingEffecter = null; } else { if (operatingEffecter == null) { operatingEffecter = Props.operatingEffecter.Spawn(); ColorizeEffecter(operatingEffecter, CurrentCycle.Props.operatingColor); operatingEffecter.Trigger(parent, new TargetInfo(parent.InteractionCell, parent.Map)); } operatingEffecter.EffectTick(parent, new TargetInfo(parent.InteractionCell, parent.Map)); } } } } if (PowerOn && biotunedCountdownTicks > 0) { biotunedCountdownTicks--; } if (biotunedCountdownTicks <= 0) { SetBiotuned(null); } SetPower(); if (biotunedTo?.Ideo != null && !biotunedTo.Ideo.HasPrecept(PreceptDefOf.AgeReversal_Demanded)) { autoAgeReversal = false; } } private void SetPower() { if (powerTraderComp == null) { powerTraderComp = parent.TryGetComp(); } if (powerComp == null) { powerComp = parent.TryGetComp(); } if (State == BiosculpterPodState.Occupied) { powerTraderComp.PowerOutput = 0f - powerComp.Props.PowerConsumption; } else { powerTraderComp.PowerOutput = 0f - powerComp.Props.idlePowerDraw; } } private void ColorizeEffecter(Effecter effecter, Color color) { foreach (SubEffecter child in effecter.children) { if (child is SubEffecter_Sprayer subEffecter_Sprayer) { subEffecter_Sprayer.colorOverride = color * child.def.color; } } } public override void PostDraw() { base.PostDraw(); Rot4 rotation = parent.Rotation; Vector3 s = new Vector3(parent.def.graphicData.drawSize.x * 0.8f, 1f, parent.def.graphicData.drawSize.y * 0.8f); Vector3 drawPos = parent.DrawPos; drawPos.y -= 0.07317074f; Graphics.DrawMesh(MeshPool.plane10, Matrix4x4.TRS(drawPos, rotation.AsQuat, s), BackgroundMat, 0); if (State == BiosculpterPodState.Occupied) { Pawn occupant = Occupant; Vector3 drawLoc = parent.DrawPos + FloatingOffset(currentCycleTicksRemaining + (float)currentCyclePowerCutTicks); Rot4 rotation2 = parent.Rotation; if (rotation2 == Rot4.East || rotation2 == Rot4.West) { drawLoc.z += 0.2f; } occupant.Drawer.renderer.RenderPawnAt(drawLoc, null, neverAimWeapon: true); } } public static Vector3 FloatingOffset(float tickOffset) { float num = tickOffset % 500f / 500f; float num2 = Mathf.Sin(MathF.PI * num); float z = num2 * num2 * 0.04f; return new Vector3(0f, 0f, z); } public void GetChildHolders(List outChildren) { ThingOwnerUtility.AppendThingHoldersFromThings(outChildren, GetDirectlyHeldThings()); } public ThingOwner GetDirectlyHeldThings() { return innerContainer; } public StorageSettings GetStoreSettings() { return allowedNutritionSettings; } public StorageSettings GetParentStoreSettings() { return parent.def.building.fixedStorageSettings; } public void Notify_SettingsChanged() { } private static void OrderToPod(CompBiosculpterPod_Cycle cycle, Pawn pawn, Action giveJobAct) { if (cycle is CompBiosculpterPod_HealingCycle compBiosculpterPod_HealingCycle) { string healingDescriptionForPawn = compBiosculpterPod_HealingCycle.GetHealingDescriptionForPawn(pawn); string text = (healingDescriptionForPawn.NullOrEmpty() ? "BiosculpterNoCoditionsToHeal".Translate(pawn.Named("PAWN"), compBiosculpterPod_HealingCycle.Props.label.Named("CYCLE")).Resolve() : ("OnCompletionOfCycle".Translate(compBiosculpterPod_HealingCycle.Props.label.Named("CYCLE")).Resolve() + ":\n\n" + healingDescriptionForPawn)); Find.WindowStack.Add(Dialog_MessageBox.CreateConfirmation(text, giveJobAct, healingDescriptionForPawn.NullOrEmpty())); } else { giveJobAct(); } } public static Thing FindPodFor(Pawn pawn, Pawn traveller, bool biotuned) { if (cachedPodDefs.NullOrEmpty()) { cachedPodDefs = DefDatabase.AllDefs.Where((ThingDef def) => def.GetCompProperties() != null).ToList(); } foreach (ThingDef cachedPodDef in cachedPodDefs) { Thing thing = GenClosest.ClosestThingReachable(traveller.Position, pawn.Map, ThingRequest.ForDef(cachedPodDef), PathEndMode.InteractionCell, TraverseParms.For(pawn), 9999f, Validator); if (thing != null) { return thing; } } return null; bool Validator(Thing t) { CompBiosculpterPod compBiosculpterPod = t.TryGetComp(); if (biotuned && compBiosculpterPod.biotunedTo != traveller) { return false; } return compBiosculpterPod.CanAcceptOnceCycleChosen(traveller); } } public static bool WasLoadingCanceled(Thing thing) { CompBiosculpterPod compBiosculpterPod = thing.TryGetComp(); if (compBiosculpterPod != null && compBiosculpterPod.State != 0) { return true; } return false; } public void ClearCycle() { currentCycleKey = null; } public void Notify_HauledTo(Pawn hauler, Thing thing, int count) { LiquifyNutrition(); SoundDefOf.Standard_Drop.PlayOneShot(parent); } } ``` --- **文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\CompBiosculpterPod_Cycle.txt` **相似度:** 0.7210 ```csharp public abstract class CompBiosculpterPod_Cycle : ThingComp { private List tmpMissingResearchLabels = new List(); public CompProperties_BiosculpterPod_BaseCycle Props => (CompProperties_BiosculpterPod_BaseCycle)props; public abstract void CycleCompleted(Pawn occupant); public virtual string Description(Pawn tunedFor) { return Props.description; } public List MissingResearchLabels() { tmpMissingResearchLabels.Clear(); if (Props.requiredResearch.NullOrEmpty()) { return tmpMissingResearchLabels; } foreach (ResearchProjectDef item in Props.requiredResearch) { if (!item.IsFinished) { tmpMissingResearchLabels.Add(item.LabelCap); } } return tmpMissingResearchLabels; } } ``` --- **文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\WorkGiver_HaulToBiosculpterPod.txt` **相似度:** 0.7198 ```csharp public class WorkGiver_HaulToBiosculpterPod : WorkGiver_Scanner { public override ThingRequest PotentialWorkThingRequest => ThingRequest.ForDef(ThingDefOf.BiosculpterPod); public override PathEndMode PathEndMode => PathEndMode.Touch; public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false) { if (!ModLister.CheckIdeology("Biosculpting")) { return false; } if (!pawn.CanReserve(t, 1, -1, null, forced)) { return false; } if (pawn.Map.designationManager.DesignationOn(t, DesignationDefOf.Deconstruct) != null) { return false; } CompBiosculpterPod compBiosculpterPod = t.TryGetComp(); if (compBiosculpterPod == null || !compBiosculpterPod.PowerOn || compBiosculpterPod.State != 0 || (!forced && !compBiosculpterPod.autoLoadNutrition)) { return false; } if (t.IsBurning()) { return false; } if (compBiosculpterPod.RequiredNutritionRemaining > 0f) { if (FindNutrition(pawn, compBiosculpterPod).Thing == null) { JobFailReason.Is("NoFood".Translate()); return false; } return true; } return false; } public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false) { CompBiosculpterPod compBiosculpterPod = t.TryGetComp(); if (compBiosculpterPod == null) { return null; } if (compBiosculpterPod.RequiredNutritionRemaining > 0f) { ThingCount thingCount = FindNutrition(pawn, compBiosculpterPod); if (thingCount.Thing != null) { Job job = HaulAIUtility.HaulToContainerJob(pawn, thingCount.Thing, t); job.count = Mathf.Min(job.count, thingCount.Count); return job; } } return null; } private ThingCount FindNutrition(Pawn pawn, CompBiosculpterPod pod) { Thing thing = GenClosest.ClosestThingReachable(pawn.Position, pawn.Map, ThingRequest.ForGroup(ThingRequestGroup.FoodSourceNotPlantOrTree), PathEndMode.ClosestTouch, TraverseParms.For(pawn), 9999f, Validator); if (thing == null) { return default(ThingCount); } int b = Mathf.CeilToInt(pod.RequiredNutritionRemaining / thing.GetStatValue(StatDefOf.Nutrition)); return new ThingCount(thing, Mathf.Min(thing.stackCount, b)); bool Validator(Thing x) { if (x.IsForbidden(pawn) || !pawn.CanReserve(x)) { return false; } if (!pod.CanAcceptNutrition(x)) { return false; } return true; } } } ```