1502 lines
44 KiB
Plaintext
1502 lines
44 KiB
Plaintext
根据向量相似度分析,与 '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<ResearchProjectDef> requiredResearch;
|
|
|
|
public List<ThingDefCountClass> extraRequiredIngredients;
|
|
|
|
private Texture2D icon;
|
|
|
|
public Texture2D Icon
|
|
{
|
|
get
|
|
{
|
|
if (icon == null)
|
|
{
|
|
icon = ContentFinder<Texture2D>.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<Texture2D>.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<ThingCount> chosenExtraItems = new List<ThingCount>();
|
|
|
|
private List<FloatMenuOption> cycleEligiblePawnOptions = new List<FloatMenuOption>();
|
|
|
|
private Pawn pawnEnteringBiosculpter;
|
|
|
|
private Dictionary<CompBiosculpterPod_Cycle, List<IngredientCount>> cachedExtraIngredients = new Dictionary<CompBiosculpterPod_Cycle, List<IngredientCount>>();
|
|
|
|
private Dictionary<CompBiosculpterPod_Cycle, CacheAnyPawnEligibleCycle> cachedAnyPawnEligible = new Dictionary<CompBiosculpterPod_Cycle, CacheAnyPawnEligibleCycle>();
|
|
|
|
private static Dictionary<Pawn, List<CompBiosculpterPod>> cachedBiotunedPods = new Dictionary<Pawn, List<CompBiosculpterPod>>();
|
|
|
|
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<CompBiosculpterPod_Cycle> cachedAvailableCycles;
|
|
|
|
private Dictionary<string, CompBiosculpterPod_Cycle> cycleLookup;
|
|
|
|
private static string cachedAgeReversalCycleKey = null;
|
|
|
|
private List<string> tmpIngredientsStrings = new List<string>();
|
|
|
|
private static readonly List<Thing> tmpItems = new List<Thing>();
|
|
|
|
private CompPowerTrader powerTraderComp;
|
|
|
|
private CompPower powerComp;
|
|
|
|
private static List<ThingDef> 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<Texture2D>.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<CompBiosculpterPod_Cycle> 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<CompPowerTrader>().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<Thing>(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<CompBiosculpterPod_Cycle>();
|
|
cachedAvailableCycles.AddRange(parent.AllComps.OfType<CompBiosculpterPod_Cycle>());
|
|
cycleLookup = new Dictionary<string, CompBiosculpterPod_Cycle>();
|
|
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<CompBiosculpterPod>();
|
|
}
|
|
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<Gizmo> 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<FloatMenuOption> 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<FloatMenuOption> 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<CompBiosculpterPod> BiotunedPods(Pawn pawn)
|
|
{
|
|
return cachedBiotunedPods.TryGetValue(pawn);
|
|
}
|
|
|
|
public static bool HasBiotunedAutoAgeReversePod(Pawn pawn)
|
|
{
|
|
List<CompBiosculpterPod> 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<string> 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<IngredientCount> RequiredIngredients(CompBiosculpterPod_Cycle cycle)
|
|
{
|
|
List<ThingDefCountClass> 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<FloatMenuOption> 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<ThingCount> extraIngredients)
|
|
{
|
|
if (!extraIngredients.NullOrEmpty())
|
|
{
|
|
job.targetQueueB = new List<LocalTargetInfo>(extraIngredients.Count);
|
|
job.countQueue = new List<int>(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<CompPowerTrader>();
|
|
}
|
|
if (powerComp == null)
|
|
{
|
|
powerComp = parent.TryGetComp<CompPower>();
|
|
}
|
|
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<IThingHolder> 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<ThingDef>.AllDefs.Where((ThingDef def) => def.GetCompProperties<CompProperties_BiosculpterPod>() != 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<CompBiosculpterPod>();
|
|
if (biotuned && compBiosculpterPod.biotunedTo != traveller)
|
|
{
|
|
return false;
|
|
}
|
|
return compBiosculpterPod.CanAcceptOnceCycleChosen(traveller);
|
|
}
|
|
}
|
|
|
|
public static bool WasLoadingCanceled(Thing thing)
|
|
{
|
|
CompBiosculpterPod compBiosculpterPod = thing.TryGetComp<CompBiosculpterPod>();
|
|
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<string> tmpMissingResearchLabels = new List<string>();
|
|
|
|
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<string> 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<CompBiosculpterPod>();
|
|
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<CompBiosculpterPod>();
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
``` |