Custom Gas Types — Modding Guide

Everything you need to build content on top of the Custom Gas Types framework for RimWorld 1.6: new gas types, gas-releasing explosions (IEDs, shells, grenades), weaponisation chains, and protective apparel or bionics. Most of it is pure XML — no C# required.

This page is written in rentry markdown. For the formatting syntax itself, see the companion "rentryco formatting" sheet.


1. Getting started

Your add-on depends on the base mod. It does not need its own DLL for anything on this page — the framework's assembly does all the work.

About/About.xml — declare the dependency and load order:

<ModMetaData>
  <name>My Gas Add-on</name>
  <author>You</author>
  <packageId>You.MyGasAddon</packageId>
  <supportedVersions><li>1.6</li></supportedVersions>
  <modDependencies>
    <li>
      <packageId>brrainz.harmony</packageId>
      <displayName>Harmony</displayName>
      <steamWorkshopUrl>steam://url/CommunityFilePage/2009463077</steamWorkshopUrl>
    </li>
    <li>
      <packageId>Greg.CustomGasTypes</packageId>
      <displayName>Custom Gas Types</displayName>
    </li>
  </modDependencies>
  <loadAfter>
    <li>brrainz.harmony</li>
    <li>Greg.CustomGasTypes</li>
  </loadAfter>
</ModMetaData>

Put your defs in Defs/, textures in Textures/, and (optionally) mod-guarded compatibility patches in Patches/.

All framework types live in the CustomGasTypes namespace. In XML you reference them as CustomGasTypes.GasDef, CustomGasTypes.ApparelGasProtection, etc.


2. Defining a gas (GasDef)

The minimum viable gas:

<CustomGasTypes.GasDef>
  <defName>MyMod_ChlorineGas</defName>
  <label>chlorine gas</label>
  <description>A choking green cloud.</description>
  <color>(0.6, 0.9, 0.3, 0.8)</color>
  <dissipationRate>4</dissipationRate>
  <hediff>MyMod_ChlorineExposure</hediff>
  <severityPerGasTick>0.04</severityPerGasTick>
  <protectedSeverityFactor>0</protectedSeverityFactor>
</CustomGasTypes.GasDef>

Gases are simulated on their own per-map grid that mirrors vanilla gas: they diffuse cell-to-cell, dissipate over time (faster unroofed, much faster in vacuum), pass through open doors, are blocked by walls, and equalise through vents.

GasDef field reference

Field Type Default Meaning
color Color RGBA (1,1,1,0.8) Cloud tint. Alpha is the max opacity at full density.
realisticColor Color RGBA (unset) Alternate tint used when the "Realistic gas colours" setting is on. Leave out to reuse color.
texPath string Things/Gas/GasCloudThickA Cloud texture.
dissipationRate int 4 Density removed per dissipation pass (0–255 scale). 1–2 = persistent, 6–7 = clears fast. Always removes at least 1.
diffuses bool true Whether the gas spreads to adjacent open cells.
diffusionThreshold int 17 Minimum density difference before it spreads to a neighbour.
equalizesThroughVents bool true Whether vents/open doors equalise it between rooms.
hediff HediffDef (none) Hediff applied to affected pawns in the cloud.
severityPerGasTick float 0.03 Severity added per gas tick (every 50 ticks) at full density (255). Scales linearly with density.
minDensityForEffect int 5 Minimum density before the gas does anything.
affectsHumanlikes bool true Affects humanlike pawns.
affectsAnimals bool true Affects animals.
affectsInsects bool true Affects insects.
affectsMechanoids bool false Affects mechanoids (they don't breathe by default).
respectsGasProtection bool true Whether masks/suits/genes protect against it. Set false for things that ignore apparel (e.g. nanobots).
protectedSeverityFactor float 0 Residual severity multiplier for a pawn with a perfect respirator. 0 = fully blocked by a mask (pure inhalation agents). >0 = a mask isn't enough because it also hits skin (blister/nerve agents).
accuracyFactor float 1 Obscures shots like vanilla smoke. Any ranged shot whose line of fire passes through the gas has its hit chance multiplied by this. 1 = no effect, 0.7 = vanilla blind smoke, lower = thicker. See §4b.
extraDamageDef DamageDef (none) Optional extra damage dealt in the cloud (e.g. Burn).
extraDamageAmount float 2 Amount of that damage.
extraDamageChancePerGasTick float 0 Chance per gas tick at full density to deal it.
damagesArtificialParts bool false Slowly destroys installed bionics/prosthetics. See §8.
artificialPartDamagePerGasTick float 3.5 Damage per eligible part per gas tick at full density.
minArtificialPartTech TechLevel Industrial Lowest part tech level affected by corrosion.
maxArtificialPartTech TechLevel Spacer Highest part tech level affected by corrosion.

Colours are written (r, g, b, a) with each channel 0–1. Keep alpha around 0.7–0.85 so density-based opacity still reads well. Never use alpha 0 — the cloud would be invisible.


3. The exposure Hediff

Your gas's effects come from the hediff it applies. Use staged capacity modifiers; the framework raises severity while the pawn stands in the gas, and the hediff recovers once they leave.

<HediffDef>
  <defName>MyMod_ChlorineExposure</defName>
  <label>chlorine exposure</label>
  <hediffClass>HediffWithComps</hediffClass>
  <isBad>true</isBad>
  <maxSeverity>1.0</maxSeverity>
  <initialSeverity>0.01</initialSeverity>
  <lethalSeverity>1</lethalSeverity>
  <comps>
    <li Class="HediffCompProperties_SeverityPerDay">
      <severityPerDay>-6</severityPerDay> <!-- recovery once out of the gas -->
    </li>
  </comps>
  <stages>
    <li>
      <label>irritation</label>
      <capMods>
        <li><capacity>Sight</capacity><offset>-0.2</offset></li>
        <li><capacity>Breathing</capacity><offset>-0.15</offset></li>
      </capMods>
    </li>
    <li>
      <minSeverity>0.5</minSeverity>
      <label>choking</label>
      <painOffset>0.3</painOffset>
      <capMods>
        <li><capacity>Breathing</capacity><offset>-0.5</offset></li>
      </capMods>
    </li>
    <li>
      <minSeverity>0.85</minSeverity>
      <label>asphyxiation</label>
      <capMods>
        <li><capacity>Breathing</capacity><setMax>0.1</setMax></li>
      </capMods>
    </li>
  </stages>
</HediffDef>
  • Use severityPerDay (negative) for how fast it wears off in fresh air. Small (−1) = persistent, large (−8 to −12) = clears fast.
  • Add HediffCompProperties_TendDuration and <tendable>true</tendable> for agents that need medical treatment (mustard/VX style).
  • lethalSeverity lets the gas kill at max severity; leave it off for non-lethal agents.

4. Extra contact damage

Blister/incendiary agents can burn on top of the hediff. Add to the GasDef:

1
2
3
<extraDamageDef>Burn</extraDamageDef>
<extraDamageAmount>2</extraDamageAmount>
<extraDamageChancePerGasTick>0.3</extraDamageChancePerGasTick>

Contact damage is blocked when the pawn's skin is sealed (see §7), even if the gas still gets past a mere respirator.


4b. Obscuring vision (acts like smoke)

Set accuracyFactor below 1 to make the cloud reduce ranged accuracy exactly like vanilla blind smoke. Any shot whose line of fire passes through the gas — fired from it, into it, or across it — has its hit chance multiplied by the factor.

<accuracyFactor>0.7</accuracyFactor>   <!-- 0.7 = vanilla smoke; 1 = no effect -->
  • It applies per shot-line, so it protects pawns standing in the cloud and penalises anyone shooting through it.
  • It stacks with vanilla smoke and weather (the game takes the lowest covering-gas factor found along the line).
  • Use it for obscurants (dense smoke) and lacrimators (tear/choke agents that force the eyes shut). Thin, colourless gases shouldn't set it — model their effect through the hediff's Sight penalty instead.

This is separate from the hediff. A Sight penalty on the hediff lowers the shooter's own accuracy while they stand in the gas; accuracyFactor obscures the line of fire for anyone shooting through the cloud. Many real agents warrant both.


5. Releasing the gas from an explosion

Any explosion can drop your gas. Make a harmless "release" DamageDef whose worker is DamageWorker_SpawnsCustomGas, and attach a CustomGasExplosionExtension pointing at the gas:

<DamageDef>
  <defName>MyMod_ChlorineRelease</defName>
  <label>chlorine release</label>
  <workerClass>CustomGasTypes.DamageWorker_SpawnsCustomGas</workerClass>
  <harmsHealth>false</harmsHealth>
  <makesBlood>false</makesBlood>
  <defaultDamage>0</defaultDamage>
  <explosionColorEdge>(0.6, 0.9, 0.3, 0.05)</explosionColorEdge>
  <soundExplosion>Explosion_Smoke</soundExplosion>
  <modExtensions>
    <li Class="CustomGasTypes.CustomGasExplosionExtension">
      <gas>MyMod_ChlorineGas</gas>
    </li>
  </modExtensions>
</DamageDef>

Now use MyMod_ChlorineRelease as the explosiveDamageType of any CompProperties_Explosive — IED, shell, grenade, mortar round, or a projectile's explosion. Every cell the blast touches gets flooded with the gas.

CustomGasExplosionExtension fields

Field Type Default Meaning
gas GasDef (required) The gas to release.
amountPerCell int 255 Density added per affected cell (255 = a cell filled solid).
gasRadiusOverride float -1 If > 0, only fill within this radius instead of the whole blast.

6. Weaponising: canister → recipe → research → IED

The base mod's pattern, which you can copy or extend:

Canister (an inert item that ruptures if shot/burned, releasing the gas):

<ThingDef ParentName="ResourceBase">
  <defName>MyMod_ChlorineCanister</defName>
  <label>chlorine canister</label>
  <description>A pressurised canister of chlorine. Inert until built into a trap.</description>
  <graphicData><texPath>MyMod/Items/ChlorineCanister</texPath><graphicClass>Graphic_Single</graphicClass></graphicData>
  <stackLimit>25</stackLimit>
  <statBases><MaxHitPoints>50</MaxHitPoints><MarketValue>40</MarketValue><Mass>1.2</Mass></statBases>
  <thingCategories><li>Manufactured</li></thingCategories>
  <comps>
    <li Class="CompProperties_Explosive">
      <explosiveRadius>2.4</explosiveRadius>
      <explosiveDamageType>MyMod_ChlorineRelease</explosiveDamageType>
      <startWickOnDamageTaken><li>Bullet</li><li>Flame</li><li>Bomb</li></startWickOnDamageTaken>
      <wickTicks>30~60</wickTicks>
    </li>
  </comps>
</ThingDef>

Recipe at the drug lab (batch of 5):

<RecipeDef>
  <defName>MyMod_MakeChlorineCanister</defName>
  <label>synthesize chlorine canisters x5</label>
  <workAmount>6000</workAmount>
  <workSpeedStat>DrugSynthesisSpeed</workSpeedStat>
  <workSkill>Intellectual</workSkill>
  <recipeUsers><li>DrugLab</li></recipeUsers>
  <researchPrerequisite>MyMod_ChlorineProduction</researchPrerequisite>
  <ingredients>
    <li><filter><thingDefs><li>Chemfuel</li></thingDefs></filter><count>10</count></li>
  </ingredients>
  <fixedIngredientFilter><thingDefs><li>Chemfuel</li></thingDefs></fixedIngredientFilter>
  <products><MyMod_ChlorineCanister>5</MyMod_ChlorineCanister></products>
</RecipeDef>

Research — you can place it in the base mod's existing CGT_GasWarfare tab:

1
2
3
4
5
6
7
8
<ResearchProjectDef>
  <defName>MyMod_ChlorineProduction</defName>
  <label>chlorine production</label>
  <baseCost>800</baseCost>
  <techLevel>Industrial</techLevel>
  <prerequisites><li>DrugProduction</li></prerequisites>
  <tab>CGT_GasWarfare</tab>       <!-- reuse the base mod's Gas Warfare tab -->
</ResearchProjectDef>

IED — parent from vanilla TrapIEDBase so it appears in the Security menu. You can require the base mod's weaponisation node CGT_WeaponizedGasIEDs so it slots into the same progression:

<ThingDef ParentName="TrapIEDBase">
  <defName>MyMod_TrapIED_Chlorine</defName>
  <label>IED chlorine trap</label>
  <description>A chlorine canister rigged to a trigger.</description>
  <graphicData><texPath>MyMod/Buildings/IED_Chlorine</texPath></graphicData>
  <costList><MyMod_ChlorineCanister>1</MyMod_ChlorineCanister><Steel>20</Steel><Chemfuel>15</Chemfuel></costList>
  <researchPrerequisites><li>CGT_WeaponizedGasIEDs</li><li>MyMod_ChlorineProduction</li></researchPrerequisites>
  <comps>
    <li Class="CompProperties_Explosive">
      <explosiveRadius>8.0</explosiveRadius>
      <explosiveDamageType>MyMod_ChlorineRelease</explosiveDamageType>
      <startWickHitPointsPercent>0.2</startWickHitPointsPercent>
      <wickTicks>15</wickTicks>
      <startWickOnDamageTaken><li>Bullet</li><li>Arrow</li><li>ArrowHighVelocity</li></startWickOnDamageTaken>
    </li>
  </comps>
  <specialDisplayRadius>8.0</specialDisplayRadius>
</ThingDef>

Reusing CGT_GasWarfare (research tab) and CGT_WeaponizedGasIEDs (weaponisation node) is optional — you can define your own tab and gate node instead. They only exist to keep everything under one roof.


6b. Mortar shells (vanilla + Combat Extended)

A mortar shell is just another explosion that uses your gas-release DamageDef (§5). The catch is that the shell item is defined very differently under vanilla vs Combat Extended, so you ship two versions and pick between them with LoadFolders.xml.

LoadFolders

Put a LoadFolders.xml in your mod root so vanilla shells load only without CE, and CE ammo only with CE:

1
2
3
4
5
6
7
<loadFolders>
  <v1.6>
    <li>/</li>
    <li IfModActive="CETeam.CombatExtended">CE</li>
    <li IfModNotActive="CETeam.CombatExtended">Vanilla</li>
  </v1.6>
</loadFolders>

Then put the vanilla shell defs under Vanilla/Defs/ and the CE ammo defs under CE/Defs/. Keep textures in the root Textures/ folder (textures inside a conditional load-folder are not always registered by the texture finder — defs are, textures aren't).

Stack-count textures

Both vanilla and CE shells use Graphic_StackCount, which treats texPath as a folder and loads every image inside it. So texPath = MyMod/Shells/MyGas needs the files at Textures/MyMod/Shells/MyGas/MyGas_a.png, ..._b.png, ..._c.png (a/b/c = ascending stack sizes). Two images (a, b) also works.

Vanilla shell

A resource item in the MortarShells category (so the vanilla mortar accepts it) plus a flyOverhead projectile:

<ThingDef ParentName="ShellBase">
  <defName>MyMod_Shell_Chlorine</defName>
  <label>chlorine shell</label>
  <graphicData>
    <texPath>MyMod/Shells/Chlorine</texPath>
    <graphicClass>Graphic_StackCount</graphicClass>
  </graphicData>
  <comps>
    <li Class="CompProperties_Explosive">
      <explosiveRadius>8.0</explosiveRadius>
      <explosiveDamageType>MyMod_ChlorineRelease</explosiveDamageType>
      <wickTicks>30~60</wickTicks>
      <startWickOnDamageTaken><li>Bullet</li><li>Flame</li></startWickOnDamageTaken>
    </li>
  </comps>
  <projectileWhenLoaded>MyMod_Bullet_Chlorine</projectileWhenLoaded>
</ThingDef>

<ThingDef ParentName="BaseBullet">
  <defName>MyMod_Bullet_Chlorine</defName>
  <thingClass>Projectile_Explosive</thingClass>
  <graphicData><texPath>Things/Projectile/ShellSmoke</texPath><graphicClass>Graphic_Single</graphicClass></graphicData>
  <projectile>
    <damageDef>MyMod_ChlorineRelease</damageDef>
    <speed>41</speed>
    <explosionRadius>8.0</explosionRadius>
    <flyOverhead>true</flyOverhead>
    <soundExplode>Explosion_Smoke</soundExplode>
  </projectile>
</ThingDef>

Combat Extended 81mm ammo

Under CE you need a CombatExtended.AmmoDef, a CE projectile, an entry in AmmoSet_81mmMortarShell, and — importantly — your own AmmoCategoryDef. The mortar's ammo-selection menu and the shell's info card both label the shell by its ammoClass, so if you reuse a vanilla class like Smoke every gas collapses into one "Smoke" entry and shows the wrong description. Give each gas its own category:

1
2
3
4
5
6
7
<!-- CE/Defs/AmmoCategoryDefs.xml -->
<CombatExtended.AmmoCategoryDef>
  <defName>MyMod_AmmoCat_Chlorine</defName>
  <label>chlorine</label>
  <description>Bursts into a choking cloud of chlorine gas.</description>
  <advanced>true</advanced>
</CombatExtended.AmmoCategoryDef>
<!-- CE/Defs/ThingDefs_ShellsCE.xml -->
<ThingDef Class="CombatExtended.AmmoDef" ParentName="81mmMortarShellBase">
  <defName>MyMod_Shell_Chlorine</defName>
  <label>81mm mortar shell (Chlorine)</label>
  <graphicData><texPath>MyMod/ShellsCE/Chlorine</texPath><graphicClass>Graphic_StackCount</graphicClass></graphicData>
  <statBases><Mass>4.1</Mass><Bulk>10.01</Bulk></statBases>
  <tradeTags><li>CE_AutoEnableTrade</li></tradeTags>
  <ammoClass>MyMod_AmmoCat_Chlorine</ammoClass>
  <detonateProjectile>MyMod_Bullet_Chlorine</detonateProjectile>
</ThingDef>

<ThingDef ParentName="Base81mmMortarShell">
  <defName>MyMod_Bullet_Chlorine</defName>
  <graphicData><texPath>Things/Projectile/Mortar/Smoke</texPath><graphicClass>Graphic_Single</graphicClass></graphicData>
  <projectile Class="CombatExtended.ProjectilePropertiesCE">
    <damageDef>MyMod_ChlorineRelease</damageDef>
    <armorPenetrationSharp>0</armorPenetrationSharp>
    <armorPenetrationBlunt>0</armorPenetrationBlunt>
    <explosionRadius>8.0</explosionRadius>
    <flyOverhead>true</flyOverhead>
    <soundExplode>Explosion_Smoke</soundExplode>
    <shellingProps><damage>0</damage></shellingProps>
  </projectile>
</ThingDef>
1
2
3
4
5
6
7
8
9
<!-- CE/Patches/AmmoSet.xml — makes it loadable/selectable in CE mortars -->
<Patch>
  <Operation Class="PatchOperationAdd">
    <xpath>Defs/CombatExtended.AmmoSetDef[defName="AmmoSet_81mmMortarShell"]/ammoTypes</xpath>
    <value>
      <MyMod_Shell_Chlorine>MyMod_Bullet_Chlorine</MyMod_Shell_Chlorine>
    </value>
  </Operation>
</Patch>

Then write a normal RecipeDef for each version (vanilla folder uses chemfuel/FSX as the charge, CE folder uses FSX) gated behind your shell research plus the gas's production node.


7. Protection

Protection uses a two-layer model:

  • Respiratory — a mask/respirator that filters what the pawn breathes. A perfect filter fully blocks pure-inhalation agents; a leaky one only cuts the dose.
  • Skin seal — a sealed body suit that stops contact agents from burning exposed skin.

The severity a pawn takes is:

severity x= (1 - protectedSeverityFactor) * respiratoryLeak + (skinSealed ? 0 : protectedSeverityFactor)

So a pure inhalation gas (protectedSeverityFactor 0) is fully stopped by any perfect respirator, while a blister agent (protectedSeverityFactor 0.25) needs a mask and a sealed suit to fully block.

Apparel — ApparelGasProtection

The vanilla apparel flag immuneToToxGasExposure already counts as a perfect respirator (and it protects against vanilla tox gas too), so a basic gas mask needs nothing extra. For finer control add the extension:

1
2
3
4
5
6
7
8
9
<ThingDef ...>            <!-- your apparel -->
  <modExtensions>
    <li Class="CustomGasTypes.ApparelGasProtection">
      <respiratory>true</respiratory>
      <respiratoryLeak>0.5</respiratoryLeak>   <!-- 0 = perfect, ~0.5 = improvised mask -->
      <skinSeal>false</skinSeal>
    </li>
  </modExtensions>
</ThingDef>

Body parts — HediffGasProtection

Put the same extension on an installed part's HediffDef to have the part itself protect the pawn — e.g. bionic lungs as a respirator, bionic skin as a skin seal. A pawn with both is fully immune, exactly like wearing a mask and a sealed suit.

<HediffDef>                <!-- your bionic lung's hediff -->
  <defName>MyMod_BionicLungsExposureBlock</defName>
  ...
  <modExtensions>
    <li Class="CustomGasTypes.HediffGasProtection">
      <respiratory>true</respiratory>
      <respiratoryLeak>0</respiratoryLeak>
    </li>
  </modExtensions>
</HediffDef>

Protection field reference (both extensions)

Field Type Default Meaning
respiratory bool false Provides respiratory (mask) protection.
respiratoryLeak float 0 Fraction of inhaled dose that still gets through. 0 = perfect filter, 1 = useless, ~0.5 = improvised.
skinSeal bool false Seals the skin against contact agents.
fullSeal bool false Shortcut: perfect respirator and skin seal (one-piece hazmat / sealed powered armour).

Protection from apparel, genes and body parts all stack — the best of each is used. To make a gas ignore protection entirely, set respectsGasProtection to false on the GasDef.


8. Artificial-part corrosion (nanobot-style gases)

Set damagesArtificialParts on a GasDef to make it grind down installed bionics/prosthetics on any pawn in the cloud — flesh, animal or mechanoid — independent of the affects* flags and of gas protection.

1
2
3
4
<damagesArtificialParts>true</damagesArtificialParts>
<artificialPartDamagePerGasTick>4</artificialPartDamagePerGasTick>
<minArtificialPartTech>Industrial</minArtificialPartTech>
<maxArtificialPartTech>Spacer</maxArtificialPartTech>

Eligibility: a part is affected only if it is an installed replacement part (Hediff_AddedPart) whose item — read from the hediff's spawnThingOnRemoved — has a tech level within the range. The default Industrial..Spacer hits mechanised prosthetics and bionics while sparing crude prosthetics (peg legs, wood — below Industrial) and archotech implants (above Spacer). This detects parts from other mods (EPOE, A Dog Said, etc.) automatically, with no hard dependency, because they follow the same convention.

Destroying an internal part like a bionic heart or brain can be fatal — intended.


9. Realistic colours

If the player enables the Realistic gas colours setting, every gas that defines a realisticColor switches to it. Set one so your gas plays along:

<realisticColor>(0.55, 0.5, 0.18, 0.85)</realisticColor>  <!-- e.g. mustard-brown -->

If a real gas is colourless, use white (never transparent) so it stays visible. Gases without a realisticColor are simply left on their normal colour when the setting is on.


10. C# API (optional)

For code mods, everything above is reachable directly.

// Add gas at a cell (overflows into surrounding open cells).
CustomGasTypes.CustomGasUtility.AddGas(cell, map, myGasDef, 255);

// Fill a radius solid, like a launcher.
CustomGasTypes.CustomGasUtility.AddGasRadius(cell, map, myGasDef, 4f);

// Read density (0-255) at a cell.
byte d = CustomGasTypes.CustomGasUtility.DensityAt(cell, map, myGasDef);

// The per-map component, if you need it directly.
var comp = CustomGasTypes.GasMapComponent.Get(map);
bool any = comp.AnyGasAt(cell);
float pct = comp.DensityPercentAt(cell, myGasDef);

// Query a pawn's protection.
CustomGasTypes.GasMapComponent.GetGasProtection(pawn, out float leak, out bool skinSealed);
bool hasMask = CustomGasTypes.GasMapComponent.HasGasProtection(pawn);

11. Dev tools

With Development Mode on, the debug menu ("Custom Gas Types" section) has:

  • Add gas x255… / Add gas x5000… — pick any registered gas and paint it onto the map.
  • Clear all custom gas — wipe every custom gas from the current map.

Use these to eyeball colours, spread, dissipation, and protection before shipping.


12. Full worked example

A complete, self-contained chlorine add-on is just the seven defs above dropped into your Defs/ folder:

  • GasDef MyMod_ChlorineGas (§2)
  • HediffDef MyMod_ChlorineExposure (§3)
  • DamageDef MyMod_ChlorineRelease (§5)
  • ThingDef MyMod_ChlorineCanister (§6)
  • RecipeDef MyMod_MakeChlorineCanister (§6)
  • ResearchProjectDef MyMod_ChlorineProduction (§6)
  • ThingDef MyMod_TrapIED_Chlorine (§6)

Plus the About.xml dependency block from §1 and two textures (canister item + IED building). That's a fully playable new gas, weaponised end to end, with correct mask/suit protection — without a single line of C#.


Gotchas

  • protectedSeverityFactor is the mask-on residual, not "how much protection." 0 means a mask fully blocks it; 0.25 means a mask still lets 25% through (skin route).
  • Mechanoids are unaffected unless you set affectsMechanoids. Non-flesh non-mech pawns are always skipped.
  • dissipationRate always removes at least 1 per pass, so a value of 1 still clears indoors (roofed cells dissipate at half rate).
  • Nanobot-style corrosion ignores apparel by design; if you want a suit to stop it, that's not currently modelled — keep such gases as pure area denial against machines.
  • Set a realisticColor if you want to support the realistic-colours setting; otherwise your gas keeps its stylised colour when the setting is on.
  • Graphic_StackCount texPath is a folder, not a file. Put the _a/_b/_c images inside a folder of that name (see §6b), and keep shell textures in your root Textures/ folder even when the defs live in a conditional load-folder.
  • CE mortar ammo needs its own AmmoCategoryDef. Reusing a vanilla ammoClass (like Smoke) makes every shell collapse into one entry in the mortar's ammo menu and inherit that category's description.
Edit

Pub: 03 Jul 2026 23:29 UTC

Edit: 04 Jul 2026 23:04 UTC

Views: 91