根据向量相似度分析,与 'Human, ThingDef' 最相关的代码定义如下: --- **文件路径 (精确匹配):** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\Verse\ThingDef.txt` ```csharp public class ThingDef : BuildableDef { public Type thingClass; public ThingCategory category; public TickerType tickerType; public int stackLimit = 1; public IntVec2 size = IntVec2.One; public bool destroyable = true; public bool rotatable = true; public bool smallVolume; public bool useHitPoints = true; public bool receivesSignals; public List comps = new List(); public List virtualDefs = new List(); public ThingDef virtualDefParent; [NoTranslate] public string devNote; public List killedLeavingsRanges; public List killedLeavings; public List killedLeavingsPlayerHostile; public float killedLeavingsChance = 1f; public bool forceLeavingsAllowed; public List butcherProducts; public List smeltProducts; public bool smeltable; public bool burnableByRecipe; public bool randomizeRotationOnSpawn; public List damageMultipliers; public bool isTechHediff; public RecipeMakerProperties recipeMaker; public ThingDef minifiedDef; public bool isUnfinishedThing; public bool leaveResourcesWhenKilled; public ThingDef slagDef; public bool isFrameInt; public List multipleInteractionCellOffsets; public IntVec3 interactionCellOffset = IntVec3.Zero; public bool hasInteractionCell; public ThingDef interactionCellIcon; public bool interactionCellIconReverse; public ThingDef filthLeaving; public bool forceDebugSpawnable; public bool intricate; public bool scatterableOnMapGen = true; public float deepCommonality; public int deepCountPerCell = 300; public int deepCountPerPortion = -1; public IntRange deepLumpSizeRange = IntRange.Zero; public float generateCommonality = 1f; public float generateAllowChance = 1f; private bool canOverlapZones = true; public FloatRange startingHpRange = FloatRange.One; [NoTranslate] public List thingSetMakerTags; public bool alwaysFlee; public List recipes; public bool messageOnDeteriorateInStorage = true; public bool deteriorateFromEnvironmentalEffects = true; public bool canDeteriorateUnspawned; public bool canLoadIntoCaravan = true; public bool isMechClusterThreat; public FloatRange displayNumbersBetweenSameDefDistRange = FloatRange.Zero; public int minRewardCount = 1; public bool preventSkyfallersLandingOn; public FactionDef requiresFactionToAcquire; public float relicChance; public OrderedTakeGroupDef orderedTakeGroup; public int allowedArchonexusCount; public int possessionCount; public bool notifyMapRemoved; public bool canScatterOver = true; public bool genericMarketSellable = true; public bool drawHighlight; public Color? highlightColor; public bool drawHighlightOnlyForHostile; public bool autoTargetNearbyIdenticalThings; public bool preventDroppingThingsOn; public bool hiddenWhileUndiscovered; public bool disableImpassableShotOverConfigError; public bool showInSearch = true; public bool bringAlongOnGravship = true; public ThingDef dropPodFaller; public bool preventSpawningInResourcePod; public bool pathfinderDangerous; public bool noRightClickDraftAttack; public int gravshipSpawnPriority = 1; public List replaceTags; public GraphicData graphicData; public DrawerType drawerType = DrawerType.RealtimeOnly; public bool drawOffscreen; public ColorGenerator colorGenerator; public float hideAtSnowOrSandDepth = 99999f; public bool drawDamagedOverlay = true; public bool castEdgeShadows; public float staticSunShadowHeight; public bool useSameGraphicForGhost; public bool useBlueprintGraphicAsGhost; public List randomStyle; public float randomStyleChance; public bool canEditAnyStyle; public bool dontPrint; public ThingDef defaultStuff; public int killedLeavingsExpandRect; public bool minifiedManualDraw; public float minifiedDrawScale = 1f; public Rot4 overrideMinifiedRot = Rot4.Invalid; public Vector3 minifiedDrawOffset = Vector3.zero; public float deselectedSelectionBracketFactor = 1f; public bool selectable; public bool containedPawnsSelectable; public bool containedItemsSelectable; public bool neverMultiSelect; public bool isAutoAttackableMapObject; public bool hasTooltip; public List inspectorTabs; [Unsaved(false)] public List inspectorTabsResolved; public bool seeThroughFog; public bool drawGUIOverlay; public bool drawGUIOverlayQuality = true; public ResourceCountPriority resourceReadoutPriority; public bool resourceReadoutAlwaysShow; public bool drawPlaceWorkersWhileSelected; public bool drawPlaceWorkersWhileInstallBlueprintSelected; public ConceptDef storedConceptLearnOpportunity; public float uiIconScale = 1f; public bool hasCustomRectForSelector; public bool hideStats; public bool hideInspect; public bool onlyShowInspectString; public bool hideMainDesc; public bool alwaysHaulable; public bool designateHaulable; public List thingCategories; public bool mineable; public bool socialPropernessMatters; public bool stealable = true; public SoundDef soundSpawned; public SoundDef soundDrop; public SoundDef soundPickup; public SoundDef soundInteract; public SoundDef soundImpactDefault; public SoundDef soundPlayInstrument; public SoundDef soundOpen; public bool saveCompressible; public bool isSaveable = true; public bool holdsRoof; public float fillPercent; public bool coversFloor; public bool neverOverlapFloors; public SurfaceType surfaceType; public bool wipesPlants; public bool blockPlants; public bool blockLight; public bool blockWind; public bool blockWeather; public Tradeability tradeability = Tradeability.All; [NoTranslate] public List tradeTags; public bool tradeNeverStack; public bool tradeNeverGenerateStacked; public bool healthAffectsPrice = true; public ColorGenerator colorGeneratorInTraderStock; private List verbs; public List tools; public float equippedAngleOffset; public float equippedDistanceOffset; public EquipmentType equipmentType; public TechLevel techLevel; public List weaponClasses; [NoTranslate] public List weaponTags; [NoTranslate] public List techHediffsTags; public bool violentTechHediff; public bool destroyOnDrop; public List equippedStatOffsets; public SoundDef meleeHitSound; public float recoilPower = 1f; public float recoilRelaxation = 10f; public bool rotateInShelves = true; public bool mergeVerbGizmos = true; public BuildableDef entityDefToBuild; public ThingDef projectileWhenLoaded; public RulePackDef ideoBuildingNamerBase; public EntityCodexEntryDef entityCodexEntry; public IngestibleProperties ingestible; public FilthProperties filth; public GasProperties gas; public BuildingProperties building; public RaceProperties race; public ApparelProperties apparel; public MoteProperties mote; public PlantProperties plant; public ProjectileProperties projectile; public StuffProperties stuffProps; public SkyfallerProperties skyfaller; public PawnFlyerProperties pawnFlyer; public RitualFocusProperties ritualFocus; public IngredientProperties ingredient; public MapPortalProperties portal; public bool canBeUsedUnderRoof = true; [Unsaved(false)] private string descriptionDetailedCached; [Unsaved(false)] public Graphic interactionCellGraphic; [Unsaved(false)] private bool? isNaturalOrganCached; [Unsaved(false)] private bool? hasSunShadowsCached; [Unsaved(false)] private List cachedRelevantStyleCategories; public const int SmallUnitPerVolume = 10; public const float SmallVolumePerUnit = 0.1f; public const float ArchonexusMaxItemStackMass = 5f; public const int ArchonexusMaxItemStackCount = 25; public const float ArchonexusMaxItemStackValue = 2000f; public const int ArchonexusAutoCalculateValue = -1; private List allRecipesCached; private static List EmptyVerbPropertiesList = new List(); private Dictionary concreteExamplesInt; public bool EverHaulable { get { if (!alwaysHaulable) { return designateHaulable; } return true; } } public bool EverPollutable => !building.isNaturalRock; public float VolumePerUnit { get { if (smallVolume) { return 0.1f; } return 1f; } } public override IntVec2 Size => size; public bool DiscardOnDestroyed => race == null; public int BaseMaxHitPoints => Mathf.RoundToInt(this.GetStatValueAbstract(StatDefOf.MaxHitPoints)); public float BaseFlammability => this.GetStatValueAbstract(StatDefOf.Flammability); public float BaseMarketValue { get { return this.GetStatValueAbstract(StatDefOf.MarketValue); } set { this.SetStatBaseValue(StatDefOf.MarketValue, value); } } public float BaseMass => this.GetStatValueAbstract(StatDefOf.Mass); public int ArchonexusMaxAllowedCount { get { if (allowedArchonexusCount == -1) { return Mathf.Min(stackLimit, 25, (BaseMass > 0f) ? ((int)(5f / BaseMass)) : 0, (BaseMarketValue > 0f) ? ((int)(2000f / BaseMarketValue)) : 0); } return allowedArchonexusCount; } } public bool PlayerAcquirable { get { if (destroyOnDrop) { return false; } if (this == ThingDefOf.ReinforcedBarrel && Find.Storyteller != null && Find.Storyteller.difficulty.classicMortars) { return false; } if (requiresFactionToAcquire != null && Find.World != null && Find.World.factionManager != null) { return Find.FactionManager.FirstFactionOfDef(requiresFactionToAcquire) != null; } return true; } } public bool EverTransmitsPower { get { for (int i = 0; i < comps.Count; i++) { if (comps[i] is CompProperties_Power { transmitsPower: not false }) { return true; } } return false; } } public bool Minifiable => minifiedDef != null; public bool HasThingIDNumber => category != ThingCategory.Mote; public List AllRecipes { get { if (allRecipesCached == null) { allRecipesCached = new List(); if (recipes != null) { for (int i = 0; i < recipes.Count; i++) { allRecipesCached.Add(recipes[i]); } } List allDefsListForReading = DefDatabase.AllDefsListForReading; for (int j = 0; j < allDefsListForReading.Count; j++) { if (allDefsListForReading[j].recipeUsers != null && allDefsListForReading[j].recipeUsers.Contains(this)) { allRecipesCached.Add(allDefsListForReading[j]); } } } return allRecipesCached; } } public bool ConnectToPower { get { if (EverTransmitsPower) { return false; } for (int i = 0; i < comps.Count; i++) { if (comps[i].compClass == typeof(CompPowerBattery)) { return true; } if (comps[i].compClass == typeof(CompPowerTrader)) { return true; } } return false; } } public bool CoexistsWithFloors { get { if (!neverOverlapFloors) { return !coversFloor; } return false; } } public FillCategory Fillage { get { if (fillPercent < 0.01f) { return FillCategory.None; } if (fillPercent > 0.99f) { return FillCategory.Full; } return FillCategory.Partial; } } public bool MakeFog => Fillage == FillCategory.Full; public bool CanOverlapZones { get { if (building != null && building.SupportsPlants) { return false; } if (passability == Traversability.Impassable && category != ThingCategory.Plant && !HasComp(typeof(CompTransporter))) { return false; } if ((int)surfaceType >= 1) { return false; } if (typeof(ISlotGroupParent).IsAssignableFrom(thingClass)) { return false; } if (!canOverlapZones) { return false; } if ((IsBlueprint || IsFrame) && entityDefToBuild is ThingDef thingDef) { return thingDef.CanOverlapZones; } return true; } } public bool CountAsResource => resourceReadoutPriority != ResourceCountPriority.Uncounted; public List Verbs { get { if (verbs != null) { return verbs; } return EmptyVerbPropertiesList; } } public bool CanHaveFaction { get { if (IsBlueprint || IsFrame) { return true; } return category switch { ThingCategory.Pawn => true, ThingCategory.Building => true, _ => false, }; } } public bool Claimable { get { if (building != null && building.claimable) { return !building.isNaturalRock; } return false; } } public ThingCategoryDef FirstThingCategory { get { if (thingCategories.NullOrEmpty()) { return null; } return thingCategories[0]; } } public float MedicineTendXpGainFactor => Mathf.Clamp(this.GetStatValueAbstract(StatDefOf.MedicalPotency) * 0.7f, 0.5f, 1f); public bool CanEverDeteriorate { get { if (!useHitPoints) { return false; } if (category != ThingCategory.Item) { if (plant != null) { return plant.canDeteriorate; } return false; } return true; } } public bool CanInteractThroughCorners { get { if (category != ThingCategory.Building) { return false; } if (!holdsRoof) { return false; } if (building != null && building.isNaturalRock && !IsSmoothed) { return false; } return true; } } public bool AffectsRegions { get { if (passability != Traversability.Impassable && !IsDoor) { return IsFence; } return true; } } public bool AffectsReachability { get { if (AffectsRegions) { return true; } if (passability == Traversability.Impassable || IsDoor) { return true; } if (TouchPathEndModeUtility.MakesOccupiedCellsAlwaysReachableDiagonally(this)) { return true; } return false; } } public string DescriptionDetailed { get { if (descriptionDetailedCached == null) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(description); if (IsApparel) { stringBuilder.AppendLine(); stringBuilder.AppendLine(); stringBuilder.AppendLine(string.Format("{0}: {1}", "Layer".Translate(), apparel.GetLayersString())); stringBuilder.Append(string.Format("{0}: {1}", "Covers".Translate(), apparel.GetCoveredOuterPartsString(BodyDefOf.Human))); if (equippedStatOffsets != null && equippedStatOffsets.Count > 0) { stringBuilder.AppendLine(); stringBuilder.AppendLine(); for (int i = 0; i < equippedStatOffsets.Count; i++) { if (i > 0) { stringBuilder.AppendLine(); } StatModifier statModifier = equippedStatOffsets[i]; stringBuilder.Append($"{statModifier.stat.LabelCap}: {statModifier.ValueToStringAsOffset}"); } } } descriptionDetailedCached = stringBuilder.ToString(); } return descriptionDetailedCached; } } public bool CanBenefitFromCover { get { if (category == ThingCategory.Pawn) { return true; } if (building != null && building.IsTurret) { return true; } return false; } } public bool PotentiallySmeltable { get { if (!smeltable) { return false; } if (base.MadeFromStuff) { foreach (ThingDef item in GenStuff.AllowedStuffsFor(this)) { if (item.smeltable) { return true; } } return false; } return true; } } public bool HasSingleOrMultipleInteractionCells { get { if (!hasInteractionCell) { return !multipleInteractionCellOffsets.NullOrEmpty(); } return true; } } public bool IsApparel => apparel != null; public bool IsBed => typeof(Building_Bed).IsAssignableFrom(thingClass); public bool IsWall { get { if (building != null) { return building.isWall; } return false; } } public bool IsCorpse => typeof(Corpse).IsAssignableFrom(thingClass); public bool IsFrame => isFrameInt; public bool IsBlueprint { get { if (entityDefToBuild != null) { return category == ThingCategory.Ethereal; } return false; } } public bool IsStuff => stuffProps != null; public bool IsMedicine => statBases.StatListContains(StatDefOf.MedicalPotency); public bool IsDoor => typeof(Building_Door).IsAssignableFrom(thingClass); public bool IsFence { get { if (building != null) { return building.isFence; } return false; } } public bool IsFilth => filth != null; public bool IsIngestible => ingestible != null; public bool IsNutritionGivingIngestible { get { if (IsIngestible) { return ingestible.CachedNutrition > 0f; } return false; } } public bool IsNutritionGivingIngestibleForHumanlikeBabies { get { if (IsNutritionGivingIngestible && ingestible.HumanEdible) { return ingestible.babiesCanIngest; } return false; } } public bool IsWeapon { get { if (category == ThingCategory.Item && (!verbs.NullOrEmpty() || !tools.NullOrEmpty())) { return !IsApparel; } return false; } } public bool IsCommsConsole => typeof(Building_CommsConsole).IsAssignableFrom(thingClass); public bool IsOrbitalTradeBeacon => typeof(Building_OrbitalTradeBeacon).IsAssignableFrom(thingClass); public bool IsFoodDispenser => typeof(Building_NutrientPasteDispenser).IsAssignableFrom(thingClass); public bool IsDrug { get { if (ingestible != null) { return ingestible.drugCategory != DrugCategory.None; } return false; } } public bool IsPleasureDrug { get { if (IsDrug) { return ingestible.joy > 0f; } return false; } } public bool IsNonMedicalDrug { get { if (IsDrug) { return ingestible.drugCategory != DrugCategory.Medical; } return false; } } public bool IsTable { get { if (surfaceType == SurfaceType.Eat) { return HasComp(typeof(CompGatherSpot)); } return false; } } public bool IsWorkTable => typeof(Building_WorkTable).IsAssignableFrom(thingClass); public bool IsShell => projectileWhenLoaded != null; public bool IsArt => IsWithinCategory(ThingCategoryDefOf.BuildingsArt); public bool IsSmoothable => building?.smoothedThing != null; public bool IsSmoothed => building?.unsmoothedThing != null; public bool IsMetal { get { if (stuffProps != null) { return stuffProps.categories.Contains(StuffCategoryDefOf.Metallic); } return false; } } public bool IsCryptosleepCasket => typeof(Building_CryptosleepCasket).IsAssignableFrom(thingClass); public bool IsGibbetCage => typeof(Building_GibbetCage).IsAssignableFrom(thingClass); public bool IsMechGestator => typeof(Building_MechGestator).IsAssignableFrom(thingClass); public bool IsMechRecharger => typeof(Building_MechCharger).IsAssignableFrom(thingClass); public bool IsAddictiveDrug { get { CompProperties_Drug compProperties = GetCompProperties(); if (compProperties != null) { return compProperties.addictiveness > 0f; } return false; } } public bool IsMeat { get { if (category == ThingCategory.Item && thingCategories != null) { return thingCategories.Contains(ThingCategoryDefOf.MeatRaw); } return false; } } public bool IsEgg { get { if (category == ThingCategory.Item && thingCategories != null) { if (!thingCategories.Contains(ThingCategoryDefOf.EggsFertilized)) { return thingCategories.Contains(ThingCategoryDefOf.EggsUnfertilized); } return true; } return false; } } public bool IsLeather { get { if (category == ThingCategory.Item && thingCategories != null) { return thingCategories.Contains(ThingCategoryDefOf.Leathers); } return false; } } public bool IsWool { get { if (category == ThingCategory.Item && thingCategories != null) { return thingCategories.Contains(ThingCategoryDefOf.Wools); } return false; } } public bool IsRangedWeapon { get { if (!IsWeapon) { return false; } if (!verbs.NullOrEmpty()) { for (int i = 0; i < verbs.Count; i++) { if (!verbs[i].IsMeleeAttack) { return true; } } } return false; } } public bool IsMeleeWeapon { get { if (IsWeapon) { return !IsRangedWeapon; } return false; } } public bool IsWeaponUsingProjectiles { get { if (!IsWeapon) { return false; } if (!verbs.NullOrEmpty()) { for (int i = 0; i < verbs.Count; i++) { if (verbs[i].LaunchesProjectile) { return true; } } } return false; } } public bool IsShieldThatBlocksRanged { get { if (HasComp(typeof(CompShield))) { return GetCompProperties().blocksRangedWeapons; } return false; } } public bool IsBuildingArtificial { get { if (category == ThingCategory.Building || IsFrame) { if (building != null) { if (!building.isNaturalRock) { return !building.isResourceRock; } return false; } return true; } return false; } } public bool IsNonResourceNaturalRock { get { if (category == ThingCategory.Building && building.isNaturalRock && !building.isResourceRock && !building.mineablePreventNaturalRockOnSurface) { return !IsSmoothed; } return false; } } public bool HasSunShadows { get { if (!hasSunShadowsCached.HasValue) { hasSunShadowsCached = typeof(Pawn).IsAssignableFrom(thingClass); } return hasSunShadowsCached.Value; } } public bool IsNaturalOrgan { get { if (!isNaturalOrganCached.HasValue) { if (category != ThingCategory.Item) { isNaturalOrganCached = false; } else { List allDefsListForReading = DefDatabase.AllDefsListForReading; isNaturalOrganCached = false; for (int i = 0; i < allDefsListForReading.Count; i++) { if (allDefsListForReading[i].spawnThingOnRemoved == this) { isNaturalOrganCached = true; break; } } } } return isNaturalOrganCached.Value; } } public bool IsFungus { get { if (ingestible != null) { return ingestible.foodType.HasFlag(FoodTypeFlags.Fungus); } return false; } } public bool IsAnimalProduct { get { if (ingestible != null) { return ingestible.foodType.HasFlag(FoodTypeFlags.AnimalProduct); } return false; } } public bool IsProcessedFood { get { if (ingestible != null) { return ingestible.foodType.HasFlag(FoodTypeFlags.Processed); } return false; } } public bool CanAffectLinker { get { if (graphicData == null || !graphicData.Linked) { return IsDoor; } return true; } } public bool IsNonDeconstructibleAttackableBuilding { get { if (IsBuildingArtificial && !building.IsDeconstructible && destroyable && !mineable && building.isTargetable) { return building.draftAttackNonDeconstructable; } return false; } } public bool IsPlant => typeof(Plant).IsAssignableFrom(thingClass); public bool IsDeadPlant => typeof(DeadPlant).IsAssignableFrom(thingClass); public bool IsStudiable => HasAssignableCompFrom(typeof(CompStudiable)); public List RelevantStyleCategories { get { if (cachedRelevantStyleCategories == null) { cachedRelevantStyleCategories = new List(); foreach (StyleCategoryDef allDef in DefDatabase.AllDefs) { if (allDef.thingDefStyles.NullOrEmpty()) { continue; } foreach (ThingDefStyle thingDefStyle in allDef.thingDefStyles) { if (thingDefStyle.ThingDef == this) { cachedRelevantStyleCategories.Add(allDef); break; } } } } return cachedRelevantStyleCategories; } } public string LabelAsStuff { get { if (!stuffProps.stuffAdjective.NullOrEmpty()) { return stuffProps.stuffAdjective; } return label; } } public bool BlocksPlanting(bool canWipePlants = false) { if (building != null && building.SupportsPlants) { return false; } if (building != null && building.isAttachment) { return false; } if (blockPlants) { return true; } if (!canWipePlants && category == ThingCategory.Plant) { return true; } if ((int)Fillage > 0) { return true; } if (this.IsEdifice()) { return true; } return false; } public virtual bool CanSpawnAt(IntVec3 pos, Rot4 rot, Map map) { return true; } public bool EverStorable(bool willMinifyIfPossible) { if (typeof(MinifiedThing).IsAssignableFrom(thingClass)) { return true; } if (!thingCategories.NullOrEmpty()) { if (category == ThingCategory.Item) { return true; } if (willMinifyIfPossible && Minifiable) { return true; } } return false; } public Thing GetConcreteExample(ThingDef stuff = null) { if (concreteExamplesInt == null) { concreteExamplesInt = new Dictionary(); } if (stuff == null) { stuff = ThingDefOf.Steel; } if (!concreteExamplesInt.ContainsKey(stuff)) { if (race == null) { concreteExamplesInt[stuff] = ThingMaker.MakeThing(this, base.MadeFromStuff ? stuff : null); } else { concreteExamplesInt[stuff] = PawnGenerator.GeneratePawn(DefDatabase.AllDefsListForReading.FirstOrDefault((PawnKindDef pkd) => pkd.race == this)); } } return concreteExamplesInt[stuff]; } public CompProperties CompDefFor() where T : ThingComp { for (int i = 0; i < comps.Count; i++) { if (comps[i].compClass == typeof(T)) { return comps[i]; } } return null; } public CompProperties CompDefForAssignableFrom() where T : ThingComp { for (int i = 0; i < comps.Count; i++) { if (typeof(T).IsAssignableFrom(comps[i].compClass)) { return comps[i]; } } return null; } public bool HasComp(Type compType) { for (int i = 0; i < comps.Count; i++) { if (comps[i].compClass == compType) { return true; } } return false; } public bool HasComp() where T : ThingComp { for (int i = 0; i < comps.Count; i++) { if (comps[i].compClass == typeof(T) || typeof(T).IsAssignableFrom(comps[i].compClass)) { return true; } } return false; } public bool HasAssignableCompFrom(Type compType) { for (int i = 0; i < comps.Count; i++) { if (compType.IsAssignableFrom(comps[i].compClass)) { return true; } } return false; } public T GetCompProperties() where T : CompProperties { for (int i = 0; i < comps.Count; i++) { if (comps[i] is T result) { return result; } } return null; } public override void PostLoad() { if (graphicData != null) { LongEventHandler.ExecuteWhenFinished(delegate { GraphicData graphicData = this.graphicData; if (graphicData.shaderType == null) { graphicData.shaderType = ShaderTypeDefOf.Cutout; } ContentFinderRequester.requester = this; try { graphic = this.graphicData.Graphic; if (drawerType != DrawerType.RealtimeOnly) { TextureAtlasGroup textureAtlasGroup = category.ToAtlasGroup(); graphic.TryInsertIntoAtlas(textureAtlasGroup); if (textureAtlasGroup == TextureAtlasGroup.Building && Minifiable) { graphic.TryInsertIntoAtlas(TextureAtlasGroup.Item); } } } finally { ContentFinderRequester.requester = null; } }); } if (tools != null) { for (int i = 0; i < tools.Count; i++) { tools[i].id = i.ToString(); } } if (verbs != null && verbs.Count == 1 && verbs[0].label.NullOrEmpty()) { verbs[0].label = label; } base.PostLoad(); if (category == ThingCategory.Building && building == null) { building = new BuildingProperties(); } building?.PostLoadSpecial(this); apparel?.PostLoadSpecial(this); plant?.PostLoadSpecial(this); if (comps == null) { return; } foreach (CompProperties comp in comps) { comp.PostLoadSpecial(this); } } protected override void ResolveIcon() { base.ResolveIcon(); if (category == ThingCategory.Pawn) { if (!uiIconPath.NullOrEmpty()) { uiIcon = ContentFinder.Get(uiIconPath); } else { if (race.Humanlike) { return; } PawnKindDef anyPawnKind = race.AnyPawnKind; if (anyPawnKind != null) { Material material = ((ModsConfig.BiotechActive && anyPawnKind.RaceProps.IsMechanoid) ? anyPawnKind.lifeStages.First() : anyPawnKind.lifeStages.Last()).bodyGraphicData.Graphic.MatAt(Rot4.East); uiIcon = (Texture2D)material.mainTexture; uiIconColor = material.color; if (ShaderDatabase.TryGetUIShader(material.shader, out var uiShader) && MaterialPool.TryGetRequestForMat(material, out var request)) { request.shader = uiShader; uiIconMaterial = MaterialPool.MatFrom(request); } } } } else { ThingDef thingDef = GenStuff.DefaultStuffFor(this); if (colorGenerator != null && (thingDef == null || thingDef.stuffProps.allowColorGenerators)) { uiIconColor = colorGenerator.ExemplaryColor; } else if (thingDef != null) { uiIconColor = GetColorForStuff(thingDef); } else if (graphicData != null) { uiIconColor = graphicData.color; } if (rotatable && graphic != null && graphic != BaseContent.BadGraphic && graphic.ShouldDrawRotated && defaultPlacingRot == Rot4.South) { uiIconAngle = 180f + graphic.DrawRotatedExtraAngleOffset; } } } public override void ResolveReferences() { base.ResolveReferences(); if (ingestible != null) { ingestible.parent = this; } if (stuffProps != null) { stuffProps.parent = this; } building?.ResolveReferencesSpecial(); graphicData?.ResolveReferencesSpecial(); race?.ResolveReferencesSpecial(); stuffProps?.ResolveReferencesSpecial(); apparel?.ResolveReferencesSpecial(); if (soundImpactDefault == null) { soundImpactDefault = SoundDefOf.BulletImpact_Ground; } if (soundDrop == null) { soundDrop = SoundDefOf.Standard_Drop; } if (soundPickup == null) { soundPickup = SoundDefOf.Standard_Pickup; } if (soundInteract == null) { soundInteract = SoundDefOf.Standard_Pickup; } if (inspectorTabs != null && inspectorTabs.Any()) { inspectorTabsResolved = new List(); for (int i = 0; i < inspectorTabs.Count; i++) { try { inspectorTabsResolved.Add(InspectTabManager.GetSharedInstance(inspectorTabs[i])); } catch (Exception ex) { Log.Error("Could not instantiate inspector tab of type " + inspectorTabs[i]?.ToString() + ": " + ex); } } } if (comps != null) { for (int j = 0; j < comps.Count; j++) { comps[j].ResolveReferences(this); } } } public override IEnumerable ConfigErrors() { foreach (string item in base.ConfigErrors()) { yield return item; } if (category != ThingCategory.Ethereal && label.NullOrEmpty()) { yield return "no label"; } if (category == ThingCategory.Building && !IsFrame && building.IsDeconstructible && thingClass != null && typeof(Building).IsSubclassOf(thingClass)) { yield return "has building category and is marked as deconstructible, but thing class is not a subclass of building (" + thingClass.Name + ")"; } if (graphicData != null) { foreach (string item2 in graphicData.ConfigErrors(this)) { yield return item2; } } if (projectile != null) { foreach (string item3 in projectile.ConfigErrors(this)) { yield return item3; } } if (statBases != null) { foreach (StatModifier statBase in statBases) { if (statBases.Count((StatModifier st) => st.stat == statBase.stat) > 1) { yield return "defines the stat base " + statBase.stat?.ToString() + " more than once."; } } } if (!BeautyUtility.BeautyRelevant(category) && this.StatBaseDefined(StatDefOf.Beauty)) { yield return "Beauty stat base is defined, but Things of category " + category.ToString() + " cannot have beauty."; } if (!BeautyUtility.BeautyRelevant(category) && this.StatBaseDefined(StatDefOf.BeautyOutdoors)) { yield return "BeautyOutdoors stat base is defined, but Things of category " + category.ToString() + " cannot have beauty."; } if (char.IsNumber(defName[defName.Length - 1])) { yield return "ends with a numerical digit, which is not allowed on ThingDefs."; } if (thingClass == null) { yield return "has null thingClass."; } if (comps.Count > 0 && !typeof(ThingWithComps).IsAssignableFrom(thingClass)) { yield return "has components but it's thingClass is not a ThingWithComps"; } if (ConnectToPower && drawerType == DrawerType.RealtimeOnly && IsFrame) { yield return "connects to power but does not add to map mesh. Will not create wire meshes."; } if (costList != null) { foreach (ThingDefCountClass cost in costList) { if (cost.count == 0) { yield return "cost in " + cost.thingDef?.ToString() + " is zero."; } } } ThingCategoryDef thingCategoryDef = thingCategories?.FirstOrDefault((ThingCategoryDef cat) => thingCategories.Count((ThingCategoryDef c) => c == cat) > 1); if (thingCategoryDef != null) { yield return "has duplicate thingCategory " + thingCategoryDef?.ToString() + "."; } if (Fillage == FillCategory.Full && category != ThingCategory.Building) { yield return "gives full cover but is not a building."; } if (equipmentType != 0) { if (techLevel == TechLevel.Undefined && !destroyOnDrop) { yield return "is equipment but has no tech level."; } if (!comps.Any((CompProperties c) => typeof(CompEquippable).IsAssignableFrom(c.compClass))) { yield return "is equipment but has no CompEquippable"; } } if (thingClass == typeof(Bullet) && projectile.damageDef == null) { yield return " is a bullet but has no damageDef."; } if (destroyOnDrop && tradeability != 0) { yield return "destroyOnDrop but tradeability is " + tradeability; } if (stackLimit > 1 && !drawGUIOverlay) { yield return "has stackLimit > 1 but also has drawGUIOverlay = false."; } if (damageMultipliers != null) { foreach (DamageMultiplier mult in damageMultipliers) { if (damageMultipliers.Count((DamageMultiplier m) => m.damageDef == mult.damageDef) > 1) { yield return "has multiple damage multipliers for damageDef " + mult.damageDef; break; } } } if (Fillage == FillCategory.Full && !this.IsEdifice()) { yield return "fillPercent is 1.00 but is not edifice"; } if (base.MadeFromStuff && constructEffect != null) { yield return "madeFromStuff but has a defined constructEffect (which will always be overridden by stuff's construct animation)."; } if (base.MadeFromStuff && stuffCategories.NullOrEmpty()) { yield return "madeFromStuff but has no stuffCategories."; } if (costList.NullOrEmpty() && costStuffCount <= 0 && recipeMaker != null) { yield return "has a recipeMaker but no costList or costStuffCount."; } if (costStuffCount > 0 && stuffCategories.NullOrEmpty()) { yield return "has costStuffCount but no stuffCategories."; } if (this.GetStatValueAbstract(StatDefOf.DeteriorationRate) > 1E-05f && !CanEverDeteriorate && !destroyOnDrop) { yield return "has >0 DeteriorationRate but can't deteriorate."; } if (smeltProducts != null && !smeltable) { yield return "has smeltProducts but has smeltable=false"; } if (smeltable && smeltProducts.NullOrEmpty() && base.CostList.NullOrEmpty() && !IsStuff && !base.MadeFromStuff && !destroyOnDrop) { yield return "is smeltable but does not give anything for smelting."; } if (equipmentType != 0 && verbs.NullOrEmpty() && tools.NullOrEmpty()) { yield return "is equipment but has no verbs or tools"; } if (Minifiable && thingCategories.NullOrEmpty()) { yield return "is minifiable but not in any thing category"; } if (category == ThingCategory.Building && !Minifiable && !thingCategories.NullOrEmpty()) { yield return "is not minifiable yet has thing categories (could be confusing in thing filters because it can't be moved/stored anyway)"; } if (!destroyOnDrop && !typeof(MinifiedThing).IsAssignableFrom(thingClass) && (EverHaulable || Minifiable) && (statBases.NullOrEmpty() || !statBases.Any((StatModifier s) => s.stat == StatDefOf.Mass))) { yield return "is haulable, but does not have an authored mass value"; } if (ingestible == null && this.GetStatValueAbstract(StatDefOf.Nutrition) != 0f) { yield return "has nutrition but ingestible properties are null"; } if (BaseFlammability != 0f && !useHitPoints && category != ThingCategory.Pawn && !destroyOnDrop) { yield return "flammable but has no hitpoints (will burn indefinitely)"; } if (graphicData?.shadowData != null && staticSunShadowHeight > 0f) { yield return "graphicData defines a shadowInfo but staticSunShadowHeight > 0"; } if (saveCompressible && Claimable) { yield return "claimable item is compressible; faction will be unset after load"; } if (deepCommonality > 0f != deepLumpSizeRange.TrueMax > 0) { yield return "if deepCommonality or deepLumpSizeRange is set, the other also must be set"; } if (deepCommonality > 0f && deepCountPerPortion <= 0) { yield return "deepCommonality > 0 but deepCountPerPortion is not set"; } if (verbs != null) { for (int i = 0; i < verbs.Count; i++) { foreach (string item4 in verbs[i].ConfigErrors(this)) { yield return $"verb {i}: {item4}"; } } } if (building != null) { foreach (string item5 in building.ConfigErrors(this)) { yield return item5; } if ((building.isAirtight || building.isStuffableAirtight) && Fillage != FillCategory.Full) { yield return "is airtight but Fillage is not Full"; } } if (apparel != null) { foreach (string item6 in apparel.ConfigErrors(this)) { yield return item6; } } if (comps != null) { for (int i = 0; i < comps.Count; i++) { foreach (string item7 in comps[i].ConfigErrors(this)) { yield return item7; } } } if (race != null) { foreach (string item8 in race.ConfigErrors(this)) { yield return item8; } if (race.body != null && race != null && tools != null) { int i; for (i = 0; i < tools.Count; i++) { if (tools[i].linkedBodyPartsGroup != null && !race.body.AllParts.Any((BodyPartRecord part) => part.groups.Contains(tools[i].linkedBodyPartsGroup))) { yield return "has tool with linkedBodyPartsGroup " + tools[i].linkedBodyPartsGroup?.ToString() + " but body " + race.body?.ToString() + " has no parts with that group."; } } } if (race.Animal && this.GetStatValueAbstract(StatDefOf.Wildness) < 0f) { yield return "is animal but wildness is not defined"; } } if (ingestible != null) { foreach (string item9 in ingestible.ConfigErrors()) { yield return item9; } } if (plant != null) { foreach (string item10 in plant.ConfigErrors()) { yield return item10; } } if (tools != null) { Tool tool = tools.SelectMany((Tool lhs) => tools.Where((Tool rhs) => lhs != rhs && lhs.id == rhs.id)).FirstOrDefault(); if (tool != null) { yield return "duplicate thingdef tool id " + tool.id; } foreach (Tool tool2 in tools) { foreach (string item11 in tool2.ConfigErrors()) { yield return item11; } } } if (!randomStyle.NullOrEmpty()) { foreach (ThingStyleChance item12 in randomStyle) { if (item12.Chance <= 0f) { yield return "style chance <= 0."; } } if (!comps.Any((CompProperties c) => c.compClass == typeof(CompStyleable))) { yield return "random style assigned, but missing CompStyleable!"; } } if (relicChance > 0f && category != ThingCategory.Item) { yield return "relic chance > 0 but category != item"; } if (hasInteractionCell && !multipleInteractionCellOffsets.NullOrEmpty()) { yield return "both single and multiple interaction cells are defined, it should be one or the other"; } if (Fillage != FillCategory.Full && passability == Traversability.Impassable && !IsDoor && base.BuildableByPlayer && !disableImpassableShotOverConfigError) { yield return "impassable, player-buildable building that can be shot/seen over."; } } public static ThingDef Named(string defName) { return DefDatabase.GetNamed(defName); } public bool IsWithinCategory(ThingCategoryDef category) { if (thingCategories == null) { return false; } for (int i = 0; i < thingCategories.Count; i++) { for (ThingCategoryDef thingCategoryDef = thingCategories[i]; thingCategoryDef != null; thingCategoryDef = thingCategoryDef.parent) { if (thingCategoryDef == category) { return true; } } } return false; } public void Notify_UnlockedByResearch() { if (comps != null) { for (int i = 0; i < comps.Count; i++) { comps[i].Notify_PostUnlockedByResearch(this); } } } public override IEnumerable SpecialDisplayStats(StatRequest req) { foreach (StatDrawEntry item in base.SpecialDisplayStats(req)) { yield return item; } if (apparel != null) { string coveredOuterPartsString = apparel.GetCoveredOuterPartsString(BodyDefOf.Human); yield return new StatDrawEntry(StatCategoryDefOf.Apparel, "Covers".Translate(), coveredOuterPartsString, "Stat_Thing_Apparel_Covers_Desc".Translate(), 2750); yield return new StatDrawEntry(StatCategoryDefOf.Apparel, "Layer".Translate(), apparel.GetLayersString(), "Stat_Thing_Apparel_Layer_Desc".Translate(), 2751); yield return new StatDrawEntry(StatCategoryDefOf.Apparel, "Stat_Thing_Apparel_CountsAsClothingNudity_Name".Translate(), apparel.countsAsClothingForNudity ? "Yes".Translate() : "No".Translate(), "Stat_Thing_Apparel_CountsAsClothingNudity_Desc".Translate(), 2753); if (ModsConfig.BiotechActive) { yield return new StatDrawEntry(StatCategoryDefOf.Apparel, "Stat_Thing_Apparel_ValidLifestage".Translate(), apparel.developmentalStageFilter.ToCommaList().CapitalizeFirst(), "Stat_Thing_Apparel_ValidLifestage_Desc".Translate(), 2748); } if (apparel.gender != 0) { yield return new StatDrawEntry(StatCategoryDefOf.Apparel, "Stat_Thing_Apparel_Gender".Translate(), apparel.gender.GetLabel().CapitalizeFirst(), "Stat_Thing_Apparel_Gender_Desc".Translate(), 2749); } } if (IsMedicine && MedicineTendXpGainFactor != 1f) { yield return new StatDrawEntry(StatCategoryDefOf.Basics, "MedicineXpGainFactor".Translate(), MedicineTendXpGainFactor.ToStringPercent(), "Stat_Thing_Drug_MedicineXpGainFactor_Desc".Translate(), 1000); } if (fillPercent > 0f && (category == ThingCategory.Item || category == ThingCategory.Building || category == ThingCategory.Plant)) { yield return new StatDrawEntry(StatCategoryDefOf.Basics, "CoverEffectiveness".Translate(), this.BaseBlockChance().ToStringPercent(), "CoverEffectivenessExplanation".Translate(), 2000); } if (constructionSkillPrerequisite > 0) { yield return new StatDrawEntry(StatCategoryDefOf.Basics, "SkillRequiredToBuild".Translate(SkillDefOf.Construction.LabelCap), constructionSkillPrerequisite.ToString(), "SkillRequiredToBuildExplanation".Translate(SkillDefOf.Construction.LabelCap), 1100); } if (artisticSkillPrerequisite > 0) { yield return new StatDrawEntry(StatCategoryDefOf.Basics, "SkillRequiredToBuild".Translate(SkillDefOf.Artistic.LabelCap), artisticSkillPrerequisite.ToString(), "SkillRequiredToBuildExplanation".Translate(SkillDefOf.Artistic.LabelCap), 1100); } IEnumerable recipes = DefDatabase.AllDefsListForReading.Where((RecipeDef r) => r.products.Count == 1 && r.products.Any((ThingDefCountClass p) => p.thingDef == this) && !r.IsSurgery); if (recipes.Any()) { IEnumerable enumerable = (from u in recipes.Where((RecipeDef x) => x.recipeUsers != null).SelectMany((RecipeDef r) => r.recipeUsers) select u.label).Concat(from x in DefDatabase.AllDefsListForReading where x.recipes != null && x.recipes.Any((RecipeDef y) => y.products.Any((ThingDefCountClass z) => z.thingDef == this)) select x.label).Distinct(); if (enumerable.Any()) { yield return new StatDrawEntry(StatCategoryDefOf.Basics, "CreatedAt".Translate(), enumerable.ToCommaList().CapitalizeFirst(), "Stat_Thing_CreatedAt_Desc".Translate(), 1103); } RecipeDef recipeDef = recipes.FirstOrDefault(); if (recipeDef != null && !recipeDef.ingredients.NullOrEmpty()) { BuildableDef.tmpCostList.Clear(); BuildableDef.tmpHyperlinks.Clear(); for (int j = 0; j < recipeDef.ingredients.Count; j++) { IngredientCount ingredientCount = recipeDef.ingredients[j]; if (ingredientCount.filter.Summary.NullOrEmpty()) { continue; } IEnumerable allowedThingDefs = ingredientCount.filter.AllowedThingDefs; if (allowedThingDefs.Any()) { foreach (ThingDef p in allowedThingDefs) { if (!BuildableDef.tmpHyperlinks.Any((Dialog_InfoCard.Hyperlink x) => x.def == p)) { BuildableDef.tmpHyperlinks.Add(new Dialog_InfoCard.Hyperlink(p)); } } } BuildableDef.tmpCostList.Add(recipeDef.IngredientValueGetter.BillRequirementsDescription(recipeDef, ingredientCount)); } } if (BuildableDef.tmpCostList.Any()) { yield return new StatDrawEntry(StatCategoryDefOf.Basics, "Ingredients".Translate(), BuildableDef.tmpCostList.ToCommaList(), "Stat_Thing_Ingredients".Translate(), 1102, null, BuildableDef.tmpHyperlinks); } } if (thingClass != null && typeof(Building_Bed).IsAssignableFrom(thingClass) && !statBases.StatListContains(StatDefOf.BedRestEffectiveness)) { yield return new StatDrawEntry(StatCategoryDefOf.Building, StatDefOf.BedRestEffectiveness, StatDefOf.BedRestEffectiveness.valueIfMissing, StatRequest.ForEmpty()); } if (!verbs.NullOrEmpty()) { VerbProperties verb = verbs.First((VerbProperties x) => x.isPrimary); StatCategoryDef verbStatCategory = ((category == ThingCategory.Pawn) ? StatCategoryDefOf.PawnCombat : null); float num = verb.warmupTime; StringBuilder stringBuilder = new StringBuilder("Stat_Thing_Weapon_RangedWarmupTime_Desc".Translate()); stringBuilder.AppendLine(); stringBuilder.AppendLine(); stringBuilder.AppendLine("StatsReport_BaseValue".Translate() + ": " + num.ToString("0.##") + " " + "LetterSecond".Translate()); if (num > 0f) { if (req.HasThing) { float statValue = req.Thing.GetStatValue(StatDefOf.RangedWeapon_WarmupMultiplier); num *= statValue; if (!Mathf.Approximately(statValue, 1f)) { stringBuilder.AppendLine(); stringBuilder.AppendLine("Stat_Thing_Weapon_WarmupTime_Multiplier".Translate() + ": x" + statValue.ToStringPercent()); stringBuilder.Append(StatUtility.GetOffsetsAndFactorsFor(StatDefOf.RangedWeapon_WarmupMultiplier, req.Thing)); } } stringBuilder.AppendLine(); stringBuilder.AppendLine("StatsReport_FinalValue".Translate() + ": " + num.ToString("0.##") + " " + "LetterSecond".Translate()); yield return new StatDrawEntry(verbStatCategory ?? StatCategoryDefOf.Weapon_Ranged, "RangedWarmupTime".Translate(), num.ToString("0.##") + " " + "LetterSecond".Translate(), stringBuilder.ToString(), 3555); } if (verb.defaultProjectile?.projectile.damageDef != null && verb.defaultProjectile.projectile.damageDef.harmsHealth) { StatCategoryDef statCat = verbStatCategory ?? StatCategoryDefOf.Weapon_Ranged; StringBuilder stringBuilder2 = new StringBuilder(); stringBuilder2.AppendLine("Stat_Thing_Damage_Desc".Translate()); stringBuilder2.AppendLine(); float num2 = verb.defaultProjectile.projectile.GetDamageAmount(req.Thing, stringBuilder2); yield return new StatDrawEntry(statCat, "Damage".Translate(), num2.ToString(), stringBuilder2.ToString(), 5500); if (verb.defaultProjectile.projectile.damageDef.armorCategory != null) { StringBuilder stringBuilder3 = new StringBuilder(); float armorPenetration = verb.defaultProjectile.projectile.GetArmorPenetration(req.Thing, stringBuilder3); TaggedString taggedString = "ArmorPenetrationExplanation".Translate(); if (stringBuilder3.Length != 0) { taggedString += "\n\n" + stringBuilder3; } yield return new StatDrawEntry(statCat, "ArmorPenetration".Translate(), armorPenetration.ToStringPercent(), taggedString, 5400); } float buildingDamageFactor = verb.defaultProjectile.projectile.damageDef.buildingDamageFactor; float dmgBuildingsImpassable = verb.defaultProjectile.projectile.damageDef.buildingDamageFactorImpassable; float dmgBuildingsPassable = verb.defaultProjectile.projectile.damageDef.buildingDamageFactorPassable; if (buildingDamageFactor != 1f) { yield return new StatDrawEntry(statCat, "BuildingDamageFactor".Translate(), buildingDamageFactor.ToStringPercent(), "BuildingDamageFactorExplanation".Translate(), 5410); } if (dmgBuildingsImpassable != 1f) { yield return new StatDrawEntry(statCat, "BuildingDamageFactorImpassable".Translate(), dmgBuildingsImpassable.ToStringPercent(), "BuildingDamageFactorImpassableExplanation".Translate(), 5420); } if (dmgBuildingsPassable != 1f) { yield return new StatDrawEntry(statCat, "BuildingDamageFactorPassable".Translate(), dmgBuildingsPassable.ToStringPercent(), "BuildingDamageFactorPassableExplanation".Translate(), 5430); } } if (verb.defaultProjectile == null && verb.beamDamageDef != null) { yield return new StatDrawEntry(verbStatCategory ?? StatCategoryDefOf.Weapon_Ranged, "ArmorPenetration".Translate(), verb.beamDamageDef.defaultArmorPenetration.ToStringPercent(), "ArmorPenetrationExplanation".Translate(), 5400); } if (verb.Ranged) { float num3 = verb.burstShotCount; float num4 = verb.ticksBetweenBurstShots; float dmgBuildingsPassable = (verb?.defaultProjectile?.projectile?.stoppingPower).GetValueOrDefault(); StringBuilder stringBuilder4 = new StringBuilder("Stat_Thing_Weapon_BurstShotFireRate_Desc".Translate()); stringBuilder4.AppendLine(); stringBuilder4.AppendLine(); stringBuilder4.AppendLine("StatsReport_BaseValue".Translate() + ": " + verb.burstShotCount.ToString()); stringBuilder4.AppendLine(); StringBuilder ticksBetweenBurstShotsExplanation = new StringBuilder("Stat_Thing_Weapon_BurstShotFireRate_Desc".Translate()); ticksBetweenBurstShotsExplanation.AppendLine(); ticksBetweenBurstShotsExplanation.AppendLine(); ticksBetweenBurstShotsExplanation.AppendLine("StatsReport_BaseValue".Translate() + ": " + (60f / verb.ticksBetweenBurstShots.TicksToSeconds()).ToString("0.##") + " rpm"); ticksBetweenBurstShotsExplanation.AppendLine(); StringBuilder stoppingPowerExplanation = new StringBuilder("StoppingPowerExplanation".Translate()); stoppingPowerExplanation.AppendLine(); stoppingPowerExplanation.AppendLine(); stoppingPowerExplanation.AppendLine("StatsReport_BaseValue".Translate() + ": " + dmgBuildingsPassable.ToString("F1")); stoppingPowerExplanation.AppendLine(); if (req.HasThing && req.Thing.TryGetComp(out CompUniqueWeapon comp)) { bool flag = false; bool flag2 = false; bool flag3 = false; foreach (WeaponTraitDef item2 in comp.TraitsListForReading) { if (!Mathf.Approximately(item2.burstShotCountMultiplier, 1f)) { if (!flag) { stringBuilder4.AppendLine("StatsReport_WeaponTraits".Translate() + ":"); flag = true; } num3 *= item2.burstShotCountMultiplier; stringBuilder4.AppendLine(" " + item2.LabelCap + ": " + item2.burstShotCountMultiplier.ToStringByStyle(ToStringStyle.PercentOne, ToStringNumberSense.Factor)); } if (!Mathf.Approximately(item2.burstShotSpeedMultiplier, 1f)) { if (!flag2) { ticksBetweenBurstShotsExplanation.AppendLine("StatsReport_WeaponTraits".Translate() + ":"); flag2 = true; } num4 /= item2.burstShotSpeedMultiplier; ticksBetweenBurstShotsExplanation.AppendLine(" " + item2.LabelCap + ": " + item2.burstShotSpeedMultiplier.ToStringByStyle(ToStringStyle.PercentOne, ToStringNumberSense.Factor)); } if (!Mathf.Approximately(item2.additionalStoppingPower, 0f)) { if (!flag3) { stoppingPowerExplanation.AppendLine("StatsReport_WeaponTraits".Translate() + ":"); flag3 = true; } dmgBuildingsPassable += item2.additionalStoppingPower; stoppingPowerExplanation.AppendLine(" " + item2.LabelCap + ": " + item2.additionalStoppingPower.ToStringByStyle(ToStringStyle.FloatOne, ToStringNumberSense.Offset)); } } } stringBuilder4.AppendLine(); stringBuilder4.AppendLine("StatsReport_FinalValue".Translate() + ": " + Mathf.CeilToInt(num3).ToString()); float dmgBuildingsImpassable = 60f / ((int)num4).TicksToSeconds(); ticksBetweenBurstShotsExplanation.AppendLine(); ticksBetweenBurstShotsExplanation.AppendLine("StatsReport_FinalValue".Translate() + ": " + dmgBuildingsImpassable.ToString("0.##") + " rpm"); stoppingPowerExplanation.AppendLine(); stoppingPowerExplanation.AppendLine("StatsReport_FinalValue".Translate() + ": " + dmgBuildingsPassable.ToString("F1")); StatCategoryDef statCat = verbStatCategory ?? StatCategoryDefOf.Weapon_Ranged; if (verb.showBurstShotStats && verb.burstShotCount > 1) { yield return new StatDrawEntry(statCat, "BurstShotCount".Translate(), Mathf.CeilToInt(num3).ToString(), stringBuilder4.ToString(), 5391); yield return new StatDrawEntry(statCat, "BurstShotFireRate".Translate(), dmgBuildingsImpassable.ToString("0.##") + " rpm", ticksBetweenBurstShotsExplanation.ToString(), 5395); } if (dmgBuildingsPassable > 0f) { yield return new StatDrawEntry(statCat, "StoppingPower".Translate(), dmgBuildingsPassable.ToString("F1"), stoppingPowerExplanation.ToString(), 5402); } float num5 = verb.range; StringBuilder stringBuilder5 = new StringBuilder("Stat_Thing_Weapon_Range_Desc".Translate()); stringBuilder5.AppendLine(); stringBuilder5.AppendLine(); stringBuilder5.AppendLine("StatsReport_BaseValue".Translate() + ": " + num5.ToString("F0")); if (req.HasThing) { float statValue2 = req.Thing.GetStatValue(StatDefOf.RangedWeapon_RangeMultiplier); num5 *= statValue2; if (!Mathf.Approximately(statValue2, 1f)) { stringBuilder5.AppendLine(); stringBuilder5.AppendLine("Stat_Thing_Weapon_Range_Multiplier".Translate() + ": x" + statValue2.ToStringPercent()); stringBuilder5.Append(StatUtility.GetOffsetsAndFactorsFor(StatDefOf.RangedWeapon_RangeMultiplier, req.Thing)); } Map obj = req.Thing.Map ?? req.Thing.MapHeld; if (obj != null && obj.weatherManager.CurWeatherMaxRangeCap >= 0f) { WeatherManager weatherManager = (req.Thing.Map ?? req.Thing.MapHeld).weatherManager; bool num6 = num5 > weatherManager.CurWeatherMaxRangeCap; float num7 = num5; num5 = Mathf.Min(num5, weatherManager.CurWeatherMaxRangeCap); if (num6) { stringBuilder5.AppendLine(); stringBuilder5.AppendLine(" " + "Stat_Thing_Weapon_Range_Clamped".Translate(num5.ToString("F0").Named("CAP"), num7.ToString("F0").Named("ORIGINAL"))); } } } stringBuilder5.AppendLine(); stringBuilder5.AppendLine("StatsReport_FinalValue".Translate() + ": " + num5.ToString("F0")); yield return new StatDrawEntry(statCat, "Range".Translate(), num5.ToString("F0"), stringBuilder5.ToString(), 5390); } if (verb.ForcedMissRadius > 0f) { StatCategoryDef statCat = verbStatCategory ?? StatCategoryDefOf.Weapon_Ranged; yield return new StatDrawEntry(statCat, "MissRadius".Translate(), verb.ForcedMissRadius.ToString("0.#"), "Stat_Thing_Weapon_MissRadius_Desc".Translate(), 3557); yield return new StatDrawEntry(statCat, "DirectHitChance".Translate(), (1f / (float)GenRadial.NumCellsInRadius(verb.ForcedMissRadius)).ToStringPercent(), "Stat_Thing_Weapon_DirectHitChance_Desc".Translate(), 3560); } } if (plant != null) { foreach (StatDrawEntry item3 in plant.SpecialDisplayStats()) { yield return item3; } } if (ingestible != null) { foreach (StatDrawEntry item4 in ingestible.SpecialDisplayStats()) { yield return item4; } } if (race != null) { foreach (StatDrawEntry item5 in race.SpecialDisplayStats(this, req)) { yield return item5; } } if (building != null) { foreach (StatDrawEntry item6 in building.SpecialDisplayStats(this, req)) { yield return item6; } } if (isTechHediff) { IEnumerable enumerable2 = DefDatabase.AllDefs.Where((RecipeDef x) => x.addsHediff != null && x.IsIngredient(this)); foreach (StatDrawEntry medicalStatsFromRecipeDef in MedicalRecipesUtility.GetMedicalStatsFromRecipeDefs(enumerable2)) { yield return medicalStatsFromRecipeDef; } } for (int i = 0; i < comps.Count; i++) { foreach (StatDrawEntry item7 in comps[i].SpecialDisplayStats(req)) { yield return item7; } } if (building != null) { if (building.mineableThing != null) { Dialog_InfoCard.Hyperlink[] hyperlinks = new Dialog_InfoCard.Hyperlink[1] { new Dialog_InfoCard.Hyperlink(building.mineableThing) }; yield return new StatDrawEntry(StatCategoryDefOf.BasicsImportant, "Stat_MineableThing_Name".Translate(), building.mineableThing.LabelCap, "Stat_MineableThing_Desc".Translate(), 2200, null, hyperlinks); StringBuilder stringBuilder6 = new StringBuilder(); stringBuilder6.AppendLine("Stat_MiningYield_Desc".Translate()); stringBuilder6.AppendLine(); stringBuilder6.AppendLine("StatsReport_DifficultyMultiplier".Translate(Find.Storyteller.difficultyDef.label) + ": " + Find.Storyteller.difficulty.mineYieldFactor.ToStringByStyle(ToStringStyle.PercentZero, ToStringNumberSense.Factor)); yield return new StatDrawEntry(StatCategoryDefOf.Basics, "Stat_MiningYield_Name".Translate(), Mathf.CeilToInt(building.EffectiveMineableYield).ToString("F0"), stringBuilder6.ToString(), 2200, null, hyperlinks); } if (building.IsTurret) { ThingDef turret = building.turretGunDef; yield return new StatDrawEntry(StatCategoryDefOf.BasicsImportant, "Stat_Weapon_Name".Translate(), turret.LabelCap, "Stat_Weapon_Desc".Translate(), 5389, null, new Dialog_InfoCard.Hyperlink[1] { new Dialog_InfoCard.Hyperlink(turret) }); StatRequest request = StatRequest.For(turret, null); foreach (StatDrawEntry item8 in turret.SpecialDisplayStats(request)) { if (item8.category == StatCategoryDefOf.Weapon_Ranged) { yield return item8; } } for (int i = 0; i < turret.statBases.Count; i++) { StatModifier statModifier = turret.statBases[i]; if (statModifier.stat.category == StatCategoryDefOf.Weapon_Ranged) { yield return new StatDrawEntry(StatCategoryDefOf.Weapon_Ranged, statModifier.stat, statModifier.value, request); } } } if (ModsConfig.OdysseyActive && Fillage == FillCategory.Full) { bool b = building.isAirtight || (building.isStuffableAirtight && req.StuffDef.stuffProps.isAirtight); yield return new StatDrawEntry(StatCategoryDefOf.Building, "Stat_Airtight".Translate(), b.ToStringYesNo(), "Stat_Airtight_Desc".Translate(), 6100); } } if (IsMeat) { List list = new List(); bool flag4 = false; foreach (ThingDef allDef in DefDatabase.AllDefs) { if (allDef.race != null && allDef.race.meatDef == this && !allDef.IsCorpse) { if (!Find.HiddenItemsManager.Hidden(allDef)) { flag4 = true; } list.Add(allDef); } } yield return new StatDrawEntry(valueString: (!flag4) ? string.Format("({0})", "NotYetDiscovered".Translate()) : string.Join(", ", (from x in list where !Find.HiddenItemsManager.Hidden(x) select x into p select p.label).ToArray()).CapitalizeFirst(), category: StatCategoryDefOf.BasicsPawn, label: "Stat_SourceSpecies_Name".Translate(), reportText: "Stat_SourceSpecies_Desc".Translate(), displayPriorityWithinCategory: 1200, overrideReportTitle: null, hyperlinks: Dialog_InfoCard.DefsToHyperlinks(list)); } if (IsLeather) { List list2 = new List(); bool flag5 = false; foreach (ThingDef allDef2 in DefDatabase.AllDefs) { if (allDef2.race != null && allDef2.race.leatherDef == this && !allDef2.IsCorpse) { if (!Find.HiddenItemsManager.Hidden(allDef2)) { flag5 = true; } list2.Add(allDef2); } } yield return new StatDrawEntry(valueString: (!flag5) ? string.Format("({0})", "NotYetDiscovered".Translate()) : string.Join(", ", (from x in list2 where !Find.HiddenItemsManager.Hidden(x) select x into p select p.label).ToArray()).CapitalizeFirst(), category: StatCategoryDefOf.BasicsPawn, label: "Stat_SourceSpecies_Name".Translate(), reportText: "Stat_SourceSpecies_Desc".Translate(), displayPriorityWithinCategory: 1200, overrideReportTitle: null, hyperlinks: Dialog_InfoCard.DefsToHyperlinks(list2)); } if (!equippedStatOffsets.NullOrEmpty()) { for (int i = 0; i < equippedStatOffsets.Count; i++) { StatDef stat = equippedStatOffsets[i].stat; float num8 = equippedStatOffsets[i].value; StringBuilder stringBuilder7 = new StringBuilder(stat.description); if (req.HasThing && stat.Worker != null) { stringBuilder7.AppendLine(); stringBuilder7.AppendLine(); stringBuilder7.AppendLine("StatsReport_BaseValue".Translate() + ": " + stat.ValueToString(num8, ToStringNumberSense.Offset, stat.finalizeEquippedStatOffset)); num8 = StatWorker.StatOffsetFromGear(req.Thing, stat); if (!stat.parts.NullOrEmpty()) { stringBuilder7.AppendLine(); for (int k = 0; k < stat.parts.Count; k++) { string text = stat.parts[k].ExplanationPart(req); if (!text.NullOrEmpty()) { stringBuilder7.AppendLine(text); } } } stringBuilder7.AppendLine(); stringBuilder7.AppendLine("StatsReport_FinalValue".Translate() + ": " + stat.ValueToString(num8, ToStringNumberSense.Offset, !stat.formatString.NullOrEmpty())); } yield return new StatDrawEntry(StatCategoryDefOf.EquippedStatOffsets, equippedStatOffsets[i].stat, num8, StatRequest.ForEmpty(), ToStringNumberSense.Offset, null, forceUnfinalizedMode: true).SetReportText(stringBuilder7.ToString()); } } if (!IsDrug) { yield break; } foreach (StatDrawEntry item9 in DrugStatsUtility.SpecialDisplayStats(this)) { yield return item9; } } } ``` --- **文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\Core\Defs\ThingDefs_Races\Races_Animal_Insect.xml` **相似度:** 0.5880 ```xml insect 1 1 60 0.8 Insect InsectConstant Insectoid Filth_BloodInsect (160,168,139) 0.5 OmnivoreAnimal, AnimalProduct 0.50 Insectoid_Eat false
  • InsectMeat
  • true
  • Food
  • true false
  • ``` --- **文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\Core\Defs\ThingDefs_Items\Items_Luxury.xml` **相似度:** 0.5741 ```xml Chocolate A delicious preparation of cocoa seeds ground together with sugar and vanilla. It fulfills the need for recreation, but it is not very nutritious. Things/Item/Resource/Chocolate Graphic_StackCount 0.88 Standard_Drop Standard_Drop true 60 3 0.075 1.0 8 0.1
  • Foods
  • DesperateOnly Processed 0.10 Gluttonous 4 4 Meal_Eat 80 10
    ``` --- **文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\CompMechGestatorTank.txt` **相似度:** 0.5175 ```csharp public class CompMechGestatorTank : ThingComp, IThingGlower { public enum TankState { Empty, Dormant, Proximity } private TankState state; private float triggerRadius; private const int StunTicks = 180; private static readonly IntRange GestationFluidFilthRange = new IntRange(2, 4); private CompProperties_MechGestatorTank Props => (CompProperties_MechGestatorTank)props; public TankState State { get { return state; } set { state = value; if (parent.Spawned) { parent.DirtyMapMesh(parent.Map); parent.TryGetComp()?.UpdateLit(parent.Map); } } } public override string CompInspectStringExtra() { return string.Format("{0}: {1}", "Contains".Translate(), ((state == TankState.Empty) ? "Nothing" : "Unknown").Translate().CapitalizeFirst()); } public bool ShouldBeLitNow() { return state != TankState.Empty; } public override bool DontDrawParent() { return true; } public override void PostPostMake() { triggerRadius = Props.triggerRadiusRange.RandomInRange; } public override void CompTick() { if (state == TankState.Proximity && parent.IsHashIntervalTick(250)) { CheckTrigger(); } } private void CheckTrigger() { if (!parent.Spawned) { return; } foreach (IntVec3 item in GenRadial.RadialCellsAround(parent.Position, triggerRadius, useCenter: false)) { if (!item.InBounds(parent.Map) || !GenSight.LineOfSight(parent.Position, item, parent.Map)) { continue; } foreach (Thing thing in item.GetThingList(parent.Map)) { if (thing is Pawn { IsColonist: not false }) { Trigger(parent.Map); return; } } } } public override void PostDestroy(DestroyMode mode, Map previousMap) { if (mode != DestroyMode.WillReplace && state != 0) { Trigger(previousMap); } } private void Trigger(Map map) { if (state == TankState.Empty) { return; } State = TankState.Empty; IntVec3 loc = parent.OccupiedRect().ExpandedBy(1).EdgeCells.Where(Standable).RandomElementWithFallback(IntVec3.Invalid); ScatterDebrisUtility.ScatterFilthAroundThing(parent, map, ThingDefOf.Filth_GestationFluid, GestationFluidFilthRange); if (loc.IsValid) { Pawn pawn = PawnGenerator.GeneratePawn(Props.mechKindOptions.RandomElementByWeight((PawnKindDefWeight x) => x.weight).kindDef, Faction.OfMechanoids); GenSpawn.Spawn(pawn, loc, map); pawn.stances?.stunner?.StunFor(180, null, addBattleLog: false); if (!map.lordManager.TryGetLordByJob(Faction.OfMechanoids, out var lord)) { LordMaker.MakeNewLord(Faction.OfMechanoids, new LordJob_AssaultColony(Faction.OfMechanoids, canKidnap: false, canTimeoutOrFlee: false, sappers: false, useAvoidGridSmart: false, canSteal: false), map, new List { pawn }); } else { lord.lord.AddPawn(pawn); } Messages.Message(Props.triggeredMessage.Formatted(pawn), pawn, MessageTypeDefOf.NegativeEvent); Props.triggerSound.PlayOneShot(parent); } bool Standable(IntVec3 c) { return c.Standable(map); } } public override IEnumerable CompGetGizmosExtra() { if (!DebugSettings.ShowDevGizmos) { yield break; } if (State == TankState.Empty) { Command_Action command_Action = new Command_Action(); command_Action.defaultLabel = "DEV: Add mech"; command_Action.action = delegate { State = TankState.Proximity; }; yield return command_Action; } else { Command_Action command_Action2 = new Command_Action(); command_Action2.defaultLabel = "DEV: Remove mech"; command_Action2.action = delegate { State = TankState.Empty; }; yield return command_Action2; } } public override void PostPrintOnto(SectionLayer layer) { ((state == TankState.Empty) ? Props.emptyGraphic.Graphic : Props.dormantGraphic.Graphic).Print(layer, parent, 0f); } public override void PostExposeData() { Scribe_Values.Look(ref state, "state", TankState.Empty); Scribe_Values.Look(ref triggerRadius, "triggerRadius", 0f); } } ```