예제 #1
0
 public static void Postfix(StuffProperties __instance, ref bool __result)
 {
     if (__instance.parent == null)
     {
         return;
     }
     if (__instance.parent == PGIThingDefOf.PerfectlyGenericItem)
     {
         __result = false;
     }
 }
        public StuffPropertiesStats(StuffProperties p)
        {
            this.commonality          = p.commonality;
            this.allowColorGenerators = p.allowColorGenerators;
            this.color = new ColorStats(p.color);

            Util.AssignDefStat(p.constructEffect, out this.constructEffect);
            Util.AssignDefStat(p.appearance, out this.appearance);
            Util.AssignDefStat(p.soundImpactStuff, out this.soundImpactStuff);
            Util.AssignDefStat(p.soundMeleeHitSharp, out this.soundMeleeHitSharp);
            Util.AssignDefStat(p.soundMeleeHitBlunt, out this.soundMeleeHitBlunt);

            Util.Populate(out this.statOffsets, p.statOffsets, (v) => new FloatValueDefStat <StatDef>(v.stat, v.value));
            Util.Populate(out this.statFactors, p.statFactors, (v) => new FloatValueDefStat <StatDef>(v.stat, v.value));
        }
        public void ApplyStats(StuffProperties to)
        {
            to.commonality          = this.commonality;
            to.allowColorGenerators = this.allowColorGenerators;
            to.color = this.color.ToColor();

            Util.AssignDef(this.constructEffect, out to.constructEffect);
            Util.AssignDef(this.appearance, out to.appearance);
            Util.AssignDef(this.soundImpactStuff, out to.soundImpactStuff);
            Util.AssignDef(this.soundMeleeHitSharp, out to.soundMeleeHitSharp);
            Util.AssignDef(this.soundMeleeHitBlunt, out to.soundMeleeHitBlunt);

            to.statOffsets?.Clear();
            Util.Populate(out to.statOffsets, this.statOffsets, (v) => new StatModifier()
            {
                stat = v.Def, value = v.value
            });

            to.statFactors?.Clear();
            Util.Populate(out to.statFactors, this.statFactors, (v) => new StatModifier()
            {
                stat = v.Def, value = v.value
            });
        }
예제 #4
0
        public TerrainDef GetStuffedTerrainDef(ThingDef stuffThingDef)
        {
            if (!stuffThingDef.IsStuff)
            {
                throw new ArgumentException(stuffThingDef.defName + " is not a stuff!");
            }

            // create new terrain
            TerrainDef terrain = new TerrainDef();

            terrain.acceptFilth = acceptFilth;
            terrain.acceptTerrainSourceFilth = acceptTerrainSourceFilth;
            terrain.affordances = affordances.NullOrEmpty()
                                      ? new List <TerrainAffordance>()
                                      : new List <TerrainAffordance>(affordances);
            terrain.avoidWander           = avoidWander;
            terrain.altitudeLayer         = altitudeLayer;
            terrain.buildingPrerequisites = buildingPrerequisites.NullOrEmpty()
                                                ? new List <ThingDef>()
                                                : new List <ThingDef>(buildingPrerequisites);
            terrain.burnedDef           = burnedDef;
            terrain.changeable          = changeable;
            terrain.driesTo             = driesTo;
            terrain.designationCategory = DefDatabase <DesignationCategoryDef> .GetNamed("Floors");

            terrain.edgeType             = edgeType;
            terrain.fertility            = fertility;
            terrain.holdSnow             = holdSnow;
            terrain.layerable            = layerable;
            terrain.menuHidden           = menuHidden;
            terrain.passability          = passability;
            terrain.pathCost             = pathCost;
            terrain.pathCostIgnoreRepeat = pathCostIgnoreRepeat;
            terrain.placeWorkers         = placeWorkers.NullOrEmpty()
                                       ? new List <Type>()
                                       : new List <Type>(placeWorkers);
            terrain.placingDraggableDimensions = placingDraggableDimensions;
            terrain.renderPrecedence           = renderPrecedence;
            terrain.researchPrerequisites      = researchPrerequisites.NullOrEmpty()
                                                ? new List <ResearchProjectDef>()
                                                : new List <ResearchProjectDef>(researchPrerequisites);
            terrain.resourcesFractionWhenDeconstructed = resourcesFractionWhenDeconstructed;
            terrain.scatterType          = scatterType;
            terrain.smoothedTerrain      = smoothedTerrain;
            terrain.specialDisplayRadius = specialDisplayRadius;
            terrain.statBases            = statBases.NullOrEmpty() ? new List <StatModifier>() : new List <StatModifier>(statBases);
            terrain.tags                    = tags.NullOrEmpty() ? new List <string>() : new List <string>(tags);
            terrain.takeFootprints          = takeFootprints;
            terrain.takeSplashes            = takeSplashes;
            terrain.terrainFilthDef         = terrainFilthDef;
            terrain.terrainAffordanceNeeded = terrainAffordanceNeeded;
            terrain.texturePath             = texturePath;

            // apply stuff elements
            StuffProperties stuff = stuffThingDef.stuffProps;

            terrain.color           = stuff.color;
            terrain.constructEffect = stuff.constructEffect;
            terrain.repairEffect    = stuff.constructEffect;
            terrain.label           = "ThingMadeOfStuffLabel".Translate(stuffThingDef.LabelAsStuff, label);
            terrain.description     = description;
            terrain.defName         = stuffThingDef.defName + "_" + defName;
            terrain.costList        = new List <ThingCountClass>();
            if (!costList.NullOrEmpty())
            {
                foreach (ThingCountClass cost in costList)
                {
                    terrain.costList.Add(new ThingCountClass(cost.thingDef, cost.count));
                }
            }
            if (stuffCost > 0)
            {
                terrain.costList.Add(new ThingCountClass(stuffThingDef, Mathf.CeilToInt(stuffCost / stuffThingDef.VolumePerUnit)));
            }


            // apply stuff offsets and factors, but apply them to a new list of statmodifiers, re-using the same list
            // keeps the actual statmodifier entries around as references, and leads to exponentially increasing stats
            // for terrains of the same base def and different stuffs
            if (!statsAffectedByStuff.NullOrEmpty())
            {
                // prepare variables
                var           stats = new List <StatModifier>();
                StringBuilder text  = new StringBuilder();

                foreach (StatDef stat in statsAffectedByStuff)
                {
                    // get base/default value
                    float value = terrain.statBases.GetStatValueFromList(stat, stat.defaultBaseValue);
                    text.AppendLine($"Base {stat.label} for {terrain.label}: {value}");

                    // apply offset
                    float offset = stuff.statOffsets.GetStatOffsetFromList(stat);

                    // apply factor
                    float factor = (value >= 0 || stat.applyFactorsIfNegative)
                                       ? stuff.statFactors.GetStatFactorFromList(stat)
                                       : 1f;

                    // lower impact of stuff beauty on floors
                    if (stat == StatDefOf.Beauty)
                    {
                        offset *= 1 / 3f;
                        factor  = Mathf.Sqrt(factor);
                    }

                    // calculate new value
                    float final = (value + offset) * factor;
                    text.AppendLine($"\tstuffed: ({value} + {offset}) x {factor} = {final}");

                    StatUtility.SetStatValueInList(ref stats, stat, final);
                }

#if DEBUG_IMPLIED_DEFS
                Log.Message($"Created {terrain.defName} from {stuffThingDef.defName}");
#if DEBUG_COSTLIST
                foreach (ThingCountClass count in terrain.costList)
                {
                    Log.Message($"\t{count.thingDef.defName}: {count.count}");
                }
#endif
#if DEBUG_STUFFING
                Log.Message(text.ToString());
#endif
#endif

                // asign the stats, overwriting the statBases list
                terrain.statBases = stats;
            }

            return(terrain);
        }
        static MyStaticConstructor()
        {
            List <ThingDef> impliedDefs   = new List <ThingDef>();
            StringBuilder   stringBuilder = new StringBuilder("[LuluChunkWalls] Dynamic patched the following defs: ");
            bool            first         = true;
            float           wallWork      = ThingDefOf.Wall.statBases.GetStatValueFromList(StatDefOf.WorkToBuild, 135);
            float           floorWork     = TerrainDefOf.Concrete.statBases.GetStatValueFromList(StatDefOf.WorkToBuild, 100);

            MethodInfo newThingBlueprintDef   = typeof(ThingDefGenerator_Buildings).GetMethod("NewBlueprintDef_Thing", BindingFlags.NonPublic | BindingFlags.Static);
            MethodInfo newThingFrameDef       = typeof(ThingDefGenerator_Buildings).GetMethod("NewFrameDef_Thing", BindingFlags.NonPublic | BindingFlags.Static);
            MethodInfo newTerrainBlueprintDef = typeof(ThingDefGenerator_Buildings).GetMethod("NewBlueprintDef_Terrain", BindingFlags.NonPublic | BindingFlags.Static);
            MethodInfo newTerrainFrameDef     = typeof(ThingDefGenerator_Buildings).GetMethod("NewFrameDef_Terrain", BindingFlags.NonPublic | BindingFlags.Static);
            MethodInfo giveShortHash          = typeof(ShortHashGiver).GetMethod("GiveShortHash", BindingFlags.NonPublic | BindingFlags.Static);

            foreach (ThingDef thingDef in DefDatabase <ThingDef> .AllDefs)
            {
                if (thingDef.building?.isNaturalRock ?? false)
                {
                    ThingDef chunkDef = thingDef.building.mineableThing;

                    if (chunkDef?.thingCategories?.Contains(ThingCategoryDefOf.StoneChunks) ?? false)
                    {
                        // Ensure lists are initialized.
                        if (thingDef.building.blueprintGraphicData == null)
                        {
                            thingDef.building.blueprintGraphicData = new GraphicData();
                        }
                        if (thingDef.costList == null)
                        {
                            thingDef.costList = new List <ThingDefCountClass>();
                        }
                        if (thingDef.researchPrerequisites == null)
                        {
                            thingDef.researchPrerequisites = new List <ResearchProjectDef>();
                        }
                        if (thingDef.statBases == null)
                        {
                            thingDef.statBases = new List <StatModifier>();
                        }

                        StuffProperties productProps = (chunkDef.butcherProducts?.Where(p => p.thingDef.IsStuff).FirstOrDefault()?.thingDef ?? ThingDefOf.BlocksGranite).stuffProps;
                        float           stuffWork    = productProps.statOffsets.GetStatOffsetFromList(StatDefOf.WorkToBuild);
                        float           stuffFactor  = productProps.statFactors.GetStatFactorFromList(StatDefOf.WorkToBuild);

                        // Patch the def.
                        thingDef.building.blueprintGraphicData.texPath = "Lulu/ChunkWalls/ChunkWalls_Blueprint_Atlas";
                        thingDef.constructionSkillPrerequisite         = 6;
                        thingDef.costList.Add(new ThingDefCountClass(chunkDef, 2));
                        thingDef.designationCategory        = DesignationCategoryDefOf.Structure;
                        thingDef.designatorDropdown         = MyDefOf.LuluChunkWalls_NaturalWall;
                        thingDef.placingDraggableDimensions = 1;
                        thingDef.researchPrerequisites.Add(MyDefOf.Stonecutting);
                        thingDef.statBases.Add(new StatModifier {
                            stat = StatDefOf.WorkToBuild, value = (wallWork + stuffWork) * (stuffFactor + 3)
                        });                                                                                                                                              // was 2430
                        thingDef.terrainAffordanceNeeded = TerrainAffordanceDefOf.Heavy;
                        thingDef.uiIconPath = "Lulu/ChunkWalls/ChunkWalls_MenuIcon";

                        // Manually create implied defs (we're past the point where they'd be generated automatically).
                        impliedDefs.Add((ThingDef)newThingBlueprintDef.Invoke(null, new object[] { thingDef, false, null }));
                        impliedDefs.Add((ThingDef)newThingFrameDef.Invoke(null, new object[] { thingDef }));

                        // Finalize graphic data.
                        thingDef.ResolveReferences();
                        thingDef.PostLoad();

                        // Build the log string.
                        if (first)
                        {
                            stringBuilder.Append(thingDef.defName);
                            first = false;
                        }
                        else
                        {
                            stringBuilder.AppendWithComma(thingDef.defName);
                        }

                        TerrainDef terrainDef = thingDef.building.leaveTerrain;

                        if (terrainDef != null)
                        {
                            if (terrainDef.costList == null)
                            {
                                terrainDef.costList = new List <ThingDefCountClass>();
                            }
                            if (terrainDef.researchPrerequisites == null)
                            {
                                terrainDef.researchPrerequisites = new List <ResearchProjectDef>();
                            }
                            if (terrainDef.statBases == null)
                            {
                                terrainDef.statBases = new List <StatModifier>();
                            }
                            terrainDef.constructionSkillPrerequisite = 6;
                            terrainDef.costList.Add(new ThingDefCountClass(chunkDef, 1));
                            terrainDef.designationCategory = MyDefOf.Floors;
                            terrainDef.designatorDropdown  = MyDefOf.LuluChunkWalls_NaturalFloor;
                            terrainDef.researchPrerequisites.Add(MyDefOf.Stonecutting);
                            terrainDef.statBases.Add(new StatModifier {
                                stat = StatDefOf.WorkToBuild, value = (floorWork + stuffWork) * (stuffFactor + 3)
                            });                                                                                                                                                     // was 1500
                            terrainDef.terrainAffordanceNeeded = TerrainAffordanceDefOf.Heavy;
                            impliedDefs.Add((ThingDef)newTerrainBlueprintDef.Invoke(null, new object[] { terrainDef }));
                            impliedDefs.Add((ThingDef)newTerrainFrameDef.Invoke(null, new object[] { terrainDef }));
                            stringBuilder.AppendWithComma(terrainDef.defName);
                        }
                    }
                }
            }

            // Add the created implied defs to the def database.
            foreach (ThingDef impliedDef in impliedDefs)
            {
                DefGenerator.AddImpliedDef(impliedDef);
                impliedDef.ResolveReferences();
                giveShortHash.Invoke(null, new object[] { impliedDef, typeof(ThingDef) });
            }

            // Regenerate the references in designation categories to make sure everything shows up to the player.
            DesignationCategoryDefOf.Structure.ResolveReferences();
            MyDefOf.Floors.ResolveReferences();

            // Report on what we've done.
            Log.Message(stringBuilder.ToString());
        }
            private static TerrainDef CopyAndStuffTerrainDef(TerrainDef terrainToCopy, ThingDef stuffThingDef)
            {
                TerrainDef terrain = new TerrainDef();

                terrain.modContentPack = PocketDimensionMod.Instance.Content;

                // Copy properties, everything we can think of, so that the xml can still be the main source for properties
                terrain.affordances = terrainToCopy.affordances.NullOrEmpty()
                                          ? new List <TerrainAffordanceDef>()
                                          : new List <TerrainAffordanceDef>(terrainToCopy.affordances);
                terrain.avoidWander               = terrainToCopy.avoidWander;
                terrain.altitudeLayer             = terrainToCopy.altitudeLayer;
                terrain.artisticSkillPrerequisite = terrainToCopy.artisticSkillPrerequisite;
                terrain.blueprintDef              = terrainToCopy.blueprintDef;
                terrain.buildingPrerequisites     = terrainToCopy.buildingPrerequisites.NullOrEmpty()
                                                    ? new List <ThingDef>()
                                                    : new List <ThingDef>(terrainToCopy.buildingPrerequisites);
                terrain.burnedDef                     = terrainToCopy.burnedDef;
                terrain.changeable                    = terrainToCopy.changeable;
                terrain.clearBuildingArea             = terrainToCopy.clearBuildingArea;
                terrain.constructionSkillPrerequisite = terrainToCopy.constructionSkillPrerequisite;
                terrain.driesTo = terrainToCopy.driesTo;
                terrain.destroyBuildingsOnDestroyed = terrainToCopy.destroyBuildingsOnDestroyed;
                terrain.destroyEffect                = terrainToCopy.destroyEffect;
                terrain.destroyEffectWater           = terrainToCopy.destroyEffectWater;
                terrain.destroyOnBombDamageThreshold = terrainToCopy.destroyOnBombDamageThreshold;
                terrain.defaultPlacingRot            = terrainToCopy.defaultPlacingRot;
                //terrain.designationCategory = DefDatabase<DesignationCategoryDef>.GetNamed("Floors");
                terrain.edgeType                         = terrainToCopy.edgeType;
                terrain.extinguishesFire                 = terrainToCopy.extinguishesFire;
                terrain.extraDeteriorationFactor         = terrainToCopy.extraDeteriorationFactor;
                terrain.extraDraftedPerceivedPathCost    = terrainToCopy.extraDraftedPerceivedPathCost;
                terrain.extraNonDraftedPerceivedPathCost = terrainToCopy.extraNonDraftedPerceivedPathCost;
                terrain.fertility                        = terrainToCopy.fertility;
                terrain.filthAcceptanceMask              = terrainToCopy.filthAcceptanceMask;
                terrain.frameDef                         = terrainToCopy.frameDef;
                terrain.generatedFilth                   = terrainToCopy.generatedFilth;
                terrain.holdSnow                         = terrainToCopy.holdSnow;
                terrain.layerable                        = terrainToCopy.layerable;
                terrain.maxTechLevelToBuild              = terrainToCopy.maxTechLevelToBuild;
                terrain.minTechLevelToBuild              = terrainToCopy.minTechLevelToBuild;
                terrain.menuHidden                       = terrainToCopy.menuHidden;
                terrain.passability                      = terrainToCopy.passability;
                terrain.pathCost                         = terrainToCopy.pathCost;
                terrain.pathCostIgnoreRepeat             = terrainToCopy.pathCostIgnoreRepeat;
                terrain.placeWorkers                     = terrainToCopy.placeWorkers.NullOrEmpty()
                                           ? new List <Type>()
                                           : new List <Type>(terrainToCopy.placeWorkers);
                terrain.placingDraggableDimensions = terrainToCopy.placingDraggableDimensions;
                terrain.renderPrecedence           = terrainToCopy.renderPrecedence;
                terrain.researchPrerequisites      = terrainToCopy.researchPrerequisites.NullOrEmpty()
                                                    ? new List <ResearchProjectDef>()
                                                    : new List <ResearchProjectDef>(terrainToCopy.researchPrerequisites);
                terrain.resourcesFractionWhenDeconstructed = terrainToCopy.resourcesFractionWhenDeconstructed;
                terrain.scatterType          = terrainToCopy.scatterType;
                terrain.smoothedTerrain      = terrainToCopy.smoothedTerrain;
                terrain.specialDisplayRadius = terrainToCopy.specialDisplayRadius;
                terrain.statBases            = terrainToCopy.statBases.NullOrEmpty() ? new List <StatModifier>() : new List <StatModifier>(terrainToCopy.statBases);
                terrain.tags                       = terrainToCopy.tags.NullOrEmpty() ? new List <string>() : new List <string>(terrainToCopy.tags);
                terrain.takeFootprints             = terrainToCopy.takeFootprints;
                terrain.takeSplashes               = terrainToCopy.takeSplashes;
                terrain.terrainAffordanceNeeded    = terrainToCopy.terrainAffordanceNeeded;
                terrain.texturePath                = terrainToCopy.texturePath;
                terrain.tools                      = terrainToCopy.tools.NullOrEmpty() ? new List <Tool>() : new List <Tool>(terrainToCopy.tools);
                terrain.traversedThought           = terrainToCopy.traversedThought;
                terrain.waterDepthMaterial         = terrainToCopy.waterDepthMaterial;
                terrain.waterDepthShader           = terrainToCopy.waterDepthShader;
                terrain.waterDepthShaderParameters = terrainToCopy.waterDepthShaderParameters.NullOrEmpty()
                    ? new List <ShaderParameter>()
                    : new List <ShaderParameter>(terrainToCopy.waterDepthShaderParameters);

                // apply stuff elements
                StuffProperties stuff = stuffThingDef.stuffProps;

                terrain.color           = stuff.color;
                terrain.constructEffect = stuff.constructEffect;
                terrain.repairEffect    = stuff.constructEffect;
                terrain.label           = "ThingMadeOfStuffLabel".Translate(stuffThingDef.LabelAsStuff, terrainToCopy.label);
                terrain.description     = terrainToCopy.description;
                terrain.defName         = terrainToCopy.defName + "_" + stuffThingDef.defName;
                terrain.costList        = new List <ThingDefCountClass>();

                //Log.Message(String.Format("Created {0} from {1}", terrain.defName, stuffThingDef.defName));

                return(terrain);
            }
예제 #7
0
        private static void ResolveImpliedStoneChunkStuffProperties(ThingDef stoneChunk, StuffProperties referenceProps)
        {
            // For compatibility with other mods that make stone chunks a material
            var stuffCategories = new List <StuffCategoryDef>()
            {
                StuffCategoryDefOf.DZ_StoneChunks
            };

            if (stoneChunk.stuffProps?.categories is List <StuffCategoryDef> oldCats)
            {
                for (int i = 0; i < oldCats.Count; i++)
                {
                    var cat = oldCats[i];
                    if (!stuffCategories.Contains(cat))
                    {
                        stuffCategories.Add(cat);
                    }
                }
            }

            stoneChunk.resourceReadoutPriority = ResourceCountPriority.Middle;
            stoneChunk.smeltable  = false;
            stoneChunk.stuffProps = new StuffProperties()
            {
                stuffAdjective     = referenceProps.stuffAdjective,
                commonality        = referenceProps.commonality,
                categories         = stuffCategories,
                statOffsets        = new List <StatModifier>(),
                statFactors        = new List <StatModifier>(),
                color              = referenceProps.color,
                constructEffect    = referenceProps.constructEffect,
                appearance         = referenceProps.appearance,
                soundImpactStuff   = referenceProps.soundImpactStuff,
                soundMeleeHitSharp = referenceProps.soundMeleeHitSharp,
                soundMeleeHitBlunt = referenceProps.soundMeleeHitBlunt
            };

            var chunkProps = stoneChunk.stuffProps;

            if (referenceProps.statOffsets != null)
            {
                for (int i = 0; i < referenceProps.statOffsets.Count; i++)
                {
                    var statOffset = referenceProps.statOffsets[i];
                    chunkProps.statOffsets.Add(new StatModifier()
                    {
                        stat = statOffset.stat, value = statOffset.value
                    });
                }
            }

            if (referenceProps.statFactors != null)
            {
                for (int i = 0; i < referenceProps.statFactors.Count; i++)
                {
                    var statFactor = referenceProps.statFactors[i];
                    chunkProps.statFactors.Add(new StatModifier()
                    {
                        stat = statFactor.stat, value = statFactor.value
                    });
                }
            }

            ModifyStatModifier(ref chunkProps.statFactors, StatDefOf.WorkToMake, ToStringNumberSense.Factor, factor: 1.5f);
            ModifyStatModifier(ref chunkProps.statFactors, StatDefOf.WorkToBuild, ToStringNumberSense.Factor, factor: 1.5f);
        }
        public StuffPropertiesWidget(StuffProperties sp)
        {
            this.stuffProperties = sp;

            this.inputWidgets = new List <IInputWidget>()
            {
                new FloatInputWidget <StuffProperties>(this.stuffProperties, "Commonality", d => d.commonality, (d, v) => d.commonality = v),
                new ColorWidget <StuffProperties>(this.stuffProperties, "Color", d => d.color, (d, v) => d.color = v),
                new BoolInputWidget <StuffProperties>(this.stuffProperties, "Allow Color Generators", d => d.allowColorGenerators, (d, v) => d.allowColorGenerators          = v),
                new DefInputWidget <StuffProperties, EffecterDef>(this.stuffProperties, "Construct Effect", 200, d => d.constructEffect, (d, v) => d.constructEffect         = v, true),
                new DefInputWidget <StuffProperties, StuffAppearanceDef>(this.stuffProperties, "Appearance", 200, d => d.appearance, (d, v) => d.appearance                  = v, true),
                new DefInputWidget <StuffProperties, SoundDef>(this.stuffProperties, "Sound Impact", 200, d => d.soundImpactStuff, (d, v) => d.soundImpactStuff              = v, true),
                new DefInputWidget <StuffProperties, SoundDef>(this.stuffProperties, "Sound Melee Hit Sharp", 200, d => d.soundMeleeHitSharp, (d, v) => d.soundMeleeHitSharp = v, true),
                new DefInputWidget <StuffProperties, SoundDef>(this.stuffProperties, "Sound Melee Hit Blunt", 200, d => d.soundMeleeHitBlunt, (d, v) => d.soundMeleeHitBlunt = v, true),
            };

            this.statOffsetsArgs = new WindowUtil.PlusMinusArgs <StatDef>()
            {
                getDisplayName = v => v.label,
                allItems       = DefDatabase <StatDef> .AllDefs,
                beingUsed      = () =>
                {
                    List <StatDef> l = new List <StatDef>();
                    if (this.stuffProperties.statOffsets != null)
                    {
                        foreach (var v in this.stuffProperties.statOffsets)
                        {
                            l.Add(v.stat);
                        }
                    }
                    return(l);
                },
                onAdd = def =>
                {
                    StatModifier sm = new StatModifier()
                    {
                        stat = def, value = 0
                    };
                    this.stuffProperties.statOffsets = Util.AddTo(this.stuffProperties.statOffsets, sm);
                    this.statOffsets = Util.AddTo(this.statOffsets, this.CreateStatModifierInput(sm));
                },
                onRemove = def =>
                {
                    this.statOffsets?.RemoveAll(v => v.Parent.stat == def);
                    this.stuffProperties.statOffsets?.RemoveAll(v => v.stat == def);
                }
            };

            this.statFactorsArgs = new WindowUtil.PlusMinusArgs <StatDef>()
            {
                getDisplayName = v => v.label,
                allItems       = DefDatabase <StatDef> .AllDefs,
                beingUsed      = () =>
                {
                    List <StatDef> l = new List <StatDef>();
                    if (this.stuffProperties.statFactors != null)
                    {
                        foreach (var v in this.stuffProperties.statFactors)
                        {
                            l.Add(v.stat);
                        }
                    }
                    return(l);
                },
                onAdd = def =>
                {
                    StatModifier sm = new StatModifier()
                    {
                        stat = def, value = 0
                    };
                    this.stuffProperties.statFactors = Util.AddTo(this.stuffProperties.statFactors, sm);
                    this.statFactors = Util.AddTo(this.statFactors, this.CreateStatModifierInput(sm));
                },
                onRemove = def =>
                {
                    this.statFactors?.RemoveAll(v => v.Parent.stat == def);
                    this.stuffProperties.statFactors?.RemoveAll(v => v.stat == def);
                }
            };

            this.ResetBuffers();
        }