Modular Hediffs - KonradHeinser/EBSGFramework GitHub Wiki

Core Hediff

This hediff comp (and optional classes) allow you to make hediffs that can be installed and uninstalled with an item, the most common example being implant hediffs like limb replacements that can be swapped at will. This module nature is all centered around one core hediff that uses the HediffCompProperties_Modular comp:

        <comps>
            <li Class="EBSGFramework.HediffCompProperties_Modular">
                <slots>
                    <li>
                        <slotID>UniqueishID</slotID>
                        <slotName>Name</slotName>
                        <capacity>-1</capacity>
                    </li>
                </slots>
            </li>
        </comps>

When any of the ThingDefs that install parts looks for a slot, it checks the hediffs the pawn has for this modular hediff comp to install into. These are the options available within the comp:

  • dropModulesOnRemoval : Default (True) : When the hediff is removed, anything currently slotted in will try to drop. If any individual module has ejectable set to False, they will be destroyed instead
  • slots : A special list of items that specifies what the hediff makes available for the pawn
    • slotID : This is akin to a defName for a slot. The ThingDefs we will discuss later have a list of slotIDs that they look for, and if any of them match with this one, then the ThingDef will view this as a valid hediff
      • While these would normally need to be unique, there may be some instances where you want other mods to interact with this without making compatibility patches constantly. If the modular hediff replaces a part, make your slotID have the name of the part it's replacing followed by the word Socket. For example, if it's installed in the shoulder to replace the arm, use armSocket. For hands use handSocket, legs use legSocket, etc.
    • slotName : This is the label associated with the slot. It's generally only seen when parts are being installed or removed
    • capacity : Default (-1) : How many parts can be installed there. If left at -1, then there is no limit

The Modules

Once you have the core hediff set up, you'll need some stuff to install and eject. This occurs within certain usable ThingDefs that you designate with some comps:

        <comps>
            <li Class="CompProperties_Usable">
                <compClass>EBSGFramework.CompUsable_HediffModule</compClass>
                <useJob>EBSG_InstallItem</useJob>
                <useDuration>50</useDuration>
            </li>
        </comps>
        <comps>
            <li Class="EBSGFramework.CompProperties_UseEffectHediffModule">
                <slotIDs>
                    <li>UniqueishID</li>
                </slotIDs>
                <requiredCapacity>1</requiredCapacity>
            </li>
        </comps>

The first comp (CompProperties_Usable) needs to use the EBSGFramework.CompUsable_HediffModule compClass, but the useJob can technically be any job that uses the driverClass JobDriver_UseItem. This is what EBSG_InstallItem looks like:

    <JobDef>
        <defName>EBSG_InstallItem</defName>
        <driverClass>JobDriver_UseItem</driverClass>
        <reportString>installing TargetA.</reportString>
        <allowOpportunisticPrefix>true</allowOpportunisticPrefix>
    </JobDef>

The second comp (EBSGFramework.CompProperties_UseEffectHediffModule) is what tells the modular hediff what is being installed

  • slotIDs : A list of potential slots that the module can be put in. Only one will be used even if multiple are available
  • requiredCapacity : Default (0) : How much capacity this takes up (or adds if negative)
  • excludeIDs : A list of strings that act similar to exclusionTags for genes, memes, and traits. If there is an exclusion, then only one of these can be installed at any time, and nothing else with the same excludeID can be installed on the specific modular hediff
  • ejectable : Default (True) : Allows the thing to be taken out. This will return the item
  • installSound : The SoundDef played when the item is installed
  • ejectSound : The SoundDef played when the item is successfully ejected
  • stageOverlays : This special list of items adds to (or in the case of True/False stuff, replaces) the stuff that exists in the modular hediff's current stage. If the main hediff only has 1 stage, then this should only have one item. If the modular hediff has multiple stages, then the number of items here should be equal to the number of stages (stages where nothing should happen just need a <li />). Most of the options in the li are the same as standard hediff stage stuff, including labels, painOffset/painFactor, totalBleedFactor, etc. For the sake of brevity, this page will only provide details on the stat factor/offset stuff since that's the most likely stuff to be used, and most likely to cause difficulties:
    • statOffsets : A list of statOffsets that add/subtract to the statOffsets in the parent hediff, or add entirely new ones if certain ones don't exist
    • statOffsetFactors : A list stat stuff set up similar to statOffsets and statFactors that multiply existing offsets. This is applied before statOffsets. This will not add any new offsets if they don't exist
    • statFactors : A list of statFactors that multiply the statFactors in the parent hediff. This won't add any new statFactors, only multiply existing ones
    • statFactorOffsets : A list stat stuff set up similar to statOffsets and statFactors that add/subtract to the statFactors in the parent hediff, or add entirely new ones if certain ones don't exist. This occurs after statFactors.
  • comps : HediffComps that are added to the modular hediff when this item is installed
  • hediffs : A list of HediffDefs to give to the pawn when the thing is installed. This is generally only needed if you have very specific circumstances, which is usually just render node stuff or very specialized hediff related things like render nodes
  • prerequisites : A special item that limits who can install the module
    • hasAnyOfHediffs : List of HediffDefs that the pawn must have any one of
    • hasAllOfHediffs : List of HediffDefs that the pawn must have all of
    • hasNoneOfHediffs : List of HediffDefs that the pawn must have none of
    • samePartPrerequisites : Default (False) : Causes the hediff checks to only try to look at the same part that the modular hediff is on
    • hasAnyOfGenes : List of GeneDefs that the pawn must have any one of
    • hasAllOfGenes : List of GeneDefs that the pawn must have all of
    • hasNoneOfGenes : List of GeneDefs that the pawn must have none of
    • isAnyOfXenotype : List of XenotypeDefs that the pawn must be one of
    • isNoneOfXenotype : List of XenotypeDefs that the pawn must not be one of

The Sub-Hediffs

The hediffs that you may attach to Modules are actually the least involved portion of the process as they are just standard hediffs, and are technically optional if you're using the stageOverlays and comps on the Module itself, and don't need any special hediff stuff added with the module. The main examples of when they will be needed are when you need special render stuff and when special comps are being used (i.e. Using Tiered Regeneration on a sub-hediff to make it so the pawn only has the regeneration when that specific module is installed and has a tier based on that sub-hediff's severity instead of the modular hediff's).

The hediff itself never needs to reference anything specifically involving the modular hediffs unless you create a modular hediff inside a modular hediff, which isn't recommended due to the complexity of it unless you are VERY sure of what you're doing, and test it a lot.


This example is a slight variation of the one used by DetVisor for the stoneborn series. It has two separate arms that can be installed into the multi-arm socket. Both of them could (and usually should) use the same method as the other when it comes to adding stage effects and comps, but I decided to make both versions for the purpose of this example:

    <HediffDef ParentName="AddedBodyPartBase">
        <defName>DV_SocketJoint_Shoulder</defName>
        <label>multi-arm socket</label>
        <labelNoun>a multi-arm socket</labelNoun>
        <description>A shoulder replacement multi-arm socket.</description>
        <defaultInstallPart>Shoulder</defaultInstallPart>
        <hediffClass>EBSGFramework.Hediff_ModularAddedPart</hediffClass>
        <comps>
            <li Class="EBSGFramework.HediffCompProperties_Modular">
                <slots>
                    <li>
                        <slotID>armSocket</slotID>
                        <slotName>Arm Socket</slotName>
                        <capacity>1</capacity>
                    </li>
                </slots>
            </li>
        </comps>
        <addedPartProps>
            <solid>true</solid>
            <partEfficiency>1</partEfficiency>
        </addedPartProps>
    </HediffDef>

    <ThingDef Name="MultiArmBionicDwarven" ParentName="BodyPartBase" Abstract="True">
        <techLevel>Spacer</techLevel>
        <thingSetMakerTags><li>RewardStandardMidFreq</li></thingSetMakerTags>
        <comps>
            <li Class="CompProperties_Usable">
                <compClass>EBSGFramework.CompUsable_HediffModule</compClass>
                <useJob>EBSG_InstallItem</useJob>
                <useDuration>50</useDuration>
            </li>
        </comps>
        <thingCategories>
            <li>BodyPartsBionic</li>
        </thingCategories>
        <graphicData>
            <texPath>Things/Item/Health/HealthItem</texPath>
            <shaderType>CutoutComplex</shaderType>
            <graphicClass>Graphic_Single</graphicClass>
            <drawSize>0.90</drawSize>
        </graphicData>
        <tradeTags>
            <li>Bionic</li>
        </tradeTags>
        <techHediffsTags>
            <li>Advanced</li>
        </techHediffsTags>
        <statBases>
            <WorkToMake>32000</WorkToMake>
        </statBases>
        <recipeMaker>
            <displayPriority>600</displayPriority>
            <workSpeedStat>GeneralLaborSpeed</workSpeedStat>
            <workSkill>Crafting</workSkill>
            <effectWorking>Smith</effectWorking>
            <soundWorking>Recipe_Smith</soundWorking>
            <recipeUsers>
                <li>TableMachining</li>
            </recipeUsers>
            <skillRequirements>
                <Crafting>9</Crafting>
            </skillRequirements>
            <unfinishedThingDef>UnfinishedHealthItemProsthetic</unfinishedThingDef>
        </recipeMaker>
    </ThingDef>

    <ThingDef ParentName="MultiArmBionicDwarven">
        <defName>DV_CarrierArmThing</defName>
        <label>carrier multi-arm</label>
        <description>A heavy bionic multi-arm designed to be mounted on the shoulder blades to aid in various tasks, with neural conduits passing through the arm's body that let the user control its actions. This arm is designed for carrying heavy things, its hydraulic muscles and tough joints make lifting anything a piece of cake, The metal fists also make them great emergency weapons.</description>
        <comps>
            <li Class="EBSGFramework.CompProperties_UseEffectHediffModule">
                <slotIDs>
                    <li>armSocket</li>
                </slotIDs>
                <requiredCapacity>1</requiredCapacity>
                <ejectable>true</ejectable>
                <ejectSound>Metal_Drop</ejectSound>
                <stageOverlays>
                    <li>
                        <partEfficiencyOffset>0.1</partEfficiencyOffset>
                        <statOffsets>
                            <CarryingCapacity>1.3</CarryingCapacity>
                        </statOffsets>
                        <capMods>
                            <li>
                                <capacity>Moving</capacity>
                                <offset>-0.1</offset>
                            </li>
                        </capMods>
                    </li>
                </stageOverlays>
                <comps>
                    <li Class="HediffCompProperties_VerbGiver">
                        <tools>
                            <li>
                                <label>carrier arm</label>
                                <capacities>
                                    <li>Blunt</li>
                                </capacities>
                                <power>16</power>
                                <cooldownTime>2.5</cooldownTime>
                                <alwaysTreatAsWeapon>true</alwaysTreatAsWeapon>
                                <soundMeleeHit>MeleeHit_BionicPunch</soundMeleeHit>
                                <soundMeleeMiss>MeleeMiss_BionicPunch</soundMeleeMiss>
                            </li>
                        </tools>
                    </li>
                </comps>
            </li>
        </comps>
        <costList>
            <Plasteel>35</Plasteel>
            <Steel>50</Steel>
            <ComponentSpacer>6</ComponentSpacer>
        </costList>
    </ThingDef>

    <ThingDef ParentName="MultiArmBionicDwarven">
        <defName>DV_AssistantArmThing</defName>
        <label>assistant multi-arm</label>
        <description>A heavy bionic multi-arm designed to be mounted on the shoulder blades to aid in various tasks, with neural conduits passing through the arm's body that let the user control its actions. This arm is designed for aiding in general labor, from crafting weapons to brewing drinks, it is versatile and quite articulated.</description>
        <comps>
        <li Class="EBSGFramework.CompProperties_UseEffectHediffModule">
            <slotIDs>
                <li>armSocket</li>
            </slotIDs>
            <requiredCapacity>1</requiredCapacity>
            <ejectable>true</ejectable>
            <installSound></installSound>
            <ejectSound>Metal_Drop</ejectSound>
            <hediffs>
                <li>DV_AssistantMultiarm</li>
            </hediffs>
        </li>
        </comps>
        <costList>
            <Plasteel>30</Plasteel>
            <Steel>30</Steel>
            <ComponentSpacer>5</ComponentSpacer>
        </costList>
    </ThingDef>

    <HediffDef ParentName="ImplantHediffBase">
        <defName>DV_AssistantMultiarm</defName>
        <label>assistant multi-arm</label>
        <labelNoun>an assistant arm</labelNoun>
        <description>A heavy bionic multi-arm designed to aid in general labor.</description>
        <defaultInstallPart>Shoulder</defaultInstallPart>
        <stages>
        <li>
            <capMods>
                <li>
                    <capacity>Moving</capacity>
                    <offset>-0.08</offset>
                </li>
                <li>
                    <capacity>Manipulation</capacity>
                    <postFactor>1.12</postFactor>
                </li>
            </capMods>
        </li>
        </stages>
        <comps>
            <li Class="HediffCompProperties_VerbGiver">
                <tools>
                    <li>
                        <label>assistant arm</label>
                        <capacities>
                        <li>Blunt</li>
                        </capacities>
                        <power>11</power>
                        <cooldownTime>2.8</cooldownTime>
                        <alwaysTreatAsWeapon>true</alwaysTreatAsWeapon>
                        <soundMeleeHit>MeleeHit_BionicPunch</soundMeleeHit>
                        <soundMeleeMiss>MeleeMiss_BionicPunch</soundMeleeMiss>
                    </li>
                </tools>
            </li>
        </comps>
        <addedPartProps>
            <solid>true</solid>
            <partEfficiency>1.10</partEfficiency>
        </addedPartProps>
    </HediffDef>
⚠️ **GitHub.com Fallback** ⚠️