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.
- Custom Gas Types — Modding Guide
- 1. Getting started
- 2. Defining a gas (GasDef)
- 3. The exposure Hediff
- 4. Extra contact damage
- 4b. Obscuring vision (acts like smoke)
- 5. Releasing the gas from an explosion
- 6. Weaponising: canister → recipe → research → IED
- 6b. Mortar shells (vanilla + Combat Extended)
- 7. Protection
- 8. Artificial-part corrosion (nanobot-style gases)
- 9. Realistic colours
- 10. C# API (optional)
- 11. Dev tools
- 12. Full worked example
- Gotchas
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:
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:
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.
- Use
severityPerDay(negative) for how fast it wears off in fresh air. Small (−1) = persistent, large (−8 to −12) = clears fast. - Add
HediffCompProperties_TendDurationand<tendable>true</tendable>for agents that need medical treatment (mustard/VX style). lethalSeveritylets 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:
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.
- 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:
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):
Recipe at the drug lab (batch of 5):
Research — you can place it in the base mod's existing CGT_GasWarfare tab:
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:
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:
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:
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:
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:
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:
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.
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.
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:
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.
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
protectedSeverityFactoris the mask-on residual, not "how much protection."0means a mask fully blocks it;0.25means a mask still lets 25% through (skin route).- Mechanoids are unaffected unless you set
affectsMechanoids. Non-flesh non-mech pawns are always skipped. dissipationRatealways removes at least 1 per pass, so a value of1still 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
realisticColorif you want to support the realistic-colours setting; otherwise your gas keeps its stylised colour when the setting is on. Graphic_StackCounttexPath is a folder, not a file. Put the_a/_b/_cimages inside a folder of that name (see §6b), and keep shell textures in your rootTextures/folder even when the defs live in a conditional load-folder.- CE mortar ammo needs its own
AmmoCategoryDef. Reusing a vanillaammoClass(likeSmoke) makes every shell collapse into one entry in the mortar's ammo menu and inherit that category's description.