Skip to content

Compatibility Patch Guide

N7Huntsman edited this page Mar 30, 2024 · 16 revisions

Introduction

This guide serves as an introduction to xml compatibility patches for Combat Extended and provides a walkthrough for creating patches for several different types of content commonly found in mods—patches that require C# work are outside the scope of this guide and are generally handled on an individual basis.

The entire process of creating an xml patch is relatively straightforward. In most cases, much of what you need already exists elsewhere in another patch, and you can copy-paste to save yourself a lot of effort formatting files and xpath operations. So, the next time you see an unsupported mod, instead of asking “ce patch when?”, consider taking a crack at making a patch yourself!

Why Does Combat Extended Need Patches?

Combat Extended completely and dramatically overhauls Rimworld’s combat mechanics, replacing a largely percentage and random number-driven system with a physics-based model. We overhaul everything from projectile flight modeling and interception to the basic functionality of the armor system and, in brief, this requires a lot of custom code and a lot of changes.

While the team has created a few built-in autopatchers to (roughly) handle some common items, handling such a wide array of changes isn’t easy to automate. To that end, compatibility patches serve two chief functions; firstly, to allow basic functionality of the mod’s contents with Combat Extended and, secondly, to balance vanilla values.

What Needs Patched?

The compatibility requirements of every mod should be evaluated on an individual basis, and there are a few hard and fast rules regarding what does and doesn’t require a compatibility patch. Moreover, there are different degrees of functionality for unpatched mods—some may not work at all without a patch, while others may work fine but still get patched for balance considerations.

If in doubt, remember this; if it attacks or gets attacked, it likely needs a patch. Beyond that, playtesting the mod content will generally show you what does and doesn’t work.

The following is a non-exhaustive list of mod content that usually requires a compatibility patch to be fully functional and balanced with Combat Extended:

  • Weapons, ranged or melee.
  • Pawns (animals, humanoids, mechanoids, etc.)
  • Custom pawnKinds, such as those from faction mods.
  • Turrets, manned and automated.
  • Vehicles with weaponry or meaningful amounts of armor.
  • Custom artillery/mortar shells.
  • Apparel, especially armor
  • Implants, body parts, xenotypes, etc. that add new attack abilities.
  • Materials that can be used to make armor or weapons.

Other types of mod usually do not require patching for Combat Extended, such as:

  • Custom biomes that don’t add new animals or weapon/armor crafting materials.
  • Custom xenotypes and genes that don’t have armor values or new attacks.
  • Purely cosmetic mods (lighting, hair styles, retextures, etc.)
  • Furniture and workbenches.
  • Custom ideologies.
  • Custom map generation mods.
  • Interface and Quality-of-Life Mods.

Additionally, some content deserves special mention:

  • Apparel that doesn’t provide much protection—like basic clothing—is patched for balance, but the difference in armor values if often quite small, and it may work as-is.
  • pawnKinds that use already supported weapons will be functional, but they may not spawn with appropriate amounts of ammo for the weapon and purpose.
  • Scenarios that start with patched ranged weapons are patched to provide the player with an appropriate amount of ammo to start with, but don’t strictly require a patch.
  • Similarly, traders are patched to let them stock CE ammo and crafting resources.
  • For some workbenches, it may be sensible to patch in recipes from Combat Extended but, again, this isn’t strictly required for them to work.
  • Psycasts need to be evaluated on a case-by-case basis, as some combat-related ones may need patched to work.

Finally, while the Combat Extended team puts in a lot of work to provide support for as many different types of mods as possible, there are a few out there that are simply incompatible with Combat Extended.

Fortunately, there are relatively few hard compatibilities, and they mostly consist of mods that either add features already within Combat Extended—like stabilization or an ammo system—or touch vanilla features that Combat Extended does away with, like changing the accuracy of vanilla mortars. The Combat Extended About.xml file contains a list in the <incompatibleWith> section, but this isn’t exhaustive.

Getting Started

For brevity’s sake, this guide will assume you have a basic familiarity with xml and the xpath patching system. If you’re brand new to the subject, then I would strongly recommend looking over the Rimworld wiki. It can offer useful resources for learning both xml and xpath, and for the particulars of Rimworld mod folder formatting and the like.

To get started, what you’ll need is:

  • A copy of Rimworld, legally owned and of the latest stable build.
  • A local copy of the latest release of Combat Extended and its dependencies.
  • A copy of the mod you want to patch, along with any dependencies.
  • A text editor of your choice, such as Notepad++ or Visual Studio Code.

For ease of editing, you’ll want a local copy of Combat Extended. If you haven’t used your local mods folder already, check out the wiki for an overview.

Before setting out to write a patch for a mod, it’s important that you confirm that the mod needs a patch and that one doesn’t already exist elsewhere.

For the first part, refer to the What Needs Patched? section of this guide. For the second part, you’ll have to review the mod in question and the Combat Extended patches. You can find a complete list of compatibility patches integrated into Combat Extended here.

Note, this list does not include any mods patched externally—such as those with a standalone patch or a patch integrated into a third-party mod. To find those, you’ll have to do some looking around; check the mod files, search the Steam Workshop, etc.

Patching Guidelines

The following are some general rules on patch making:

Keep Your Patch Compact.

You should—within reason — do what you can to minimize the size of your patch without sacrificing functionality or readability. That may mean consolidating small files together, combining patch operations (such as folding a PatchOperationAdd into a PatchOperationReplace that touches the same xml elements), and avoiding unnecessary patching.

Reuse, Repurpose, Recycle.

It’s a lot faster to copy-paste and modify that to make from scratch. Writing a patch? Look around for an outdated one you might be able to fix up in less time. Patching a modern firearm? Look through the patch files to see if it’s already been patched for another mod and work from that.

Preserve Balance and Function.

Obviously, Combat Extended radically upends the balance of Rimworld combat—weapon ranges are greater, weapons are more lethal and fill more niche roles, and numerous other changes all make it a far different game. Even so, when patching mod content, we aim to preserve the relative vanilla balance of items against each other wherever possible.

Useful Resources

In addition to this guide, there are many other useful resources and references that can help you make your compatibility patch. Keeping them handy can be the difference between quick and straightforward success and drawn-out frustration and confusion.

The single most useful resource will be the hundreds of integrated patches already contained within Combat Extended. Most types of Rimworld mod content have already been patched by someone, and you are strongly encouraged to reference them and copy-paste from existing patches wherever possible. Not only is it a massive time-saver, but it can also be useful for keeping balance consistent across the various mods.

Another set of useful resources are the spreadsheets used to calculate the stats of various weapons and projectiles. While these are generally best suited for conventional weapons and projectiles, they can still be a useful resource for more exotic content. Remember, these sheets are guidelines and tools, and they’re only as good as the numbers you enter.

If you’re still left with questions, the next place to turn is the Combat Extended discord server. The community includes a sizable group of contributors and mod authors with experience making and troubleshooting patches.

Patch File Formatting

Going forward from the initial 1.5 release, Combat Extended has switched from using PatchOperationFindMod for integrated xml compatibility patches (that is, patches contained within CE's files) to the LoadFolders method. Due to a quirk of the LoadFolders system that means files with the same relative path with overwrite each other.

To avoid this, patch folders are structured as follows:

ModPatches
  ├ ModName1
  │ ├ Patches
  │ │ └ ModName1
  │ │   └ PatchFile.xml
  │ └ Defs
  │   └ ModName1
  │     └ DefFile.xml 
  └ ModName2
    ├ Patches
    │ └ ModName2
    │   └ PatchFile.xml
    └ Defs
      └ ModName2
        └ DefFile.xml 

While this may seem a bit redundant, it provides a unique relative path across all mod patches. Since many files share names across the hundreds of integrated patches, this redundancy prevents files accidentally being overwritten.

Making a Patch

Below are a series of overviews for different types of patches in order of complexity, starting from least complex to most. The overview will consist of an example patch for the content, followed by a summary of the components. For brevity's sake, these guides will focus chiefly upon stats and considerations unique to Combat Extended.

Material

<?xml version="1.0" encoding="utf-8"?>
<Patch>

	<Operation Class="PatchOperationAdd">
		<xpath>Defs/ThingDef[defName="Steel"]/statBases</xpath>
		<value>
			<Bulk>0.03</Bulk>
		</value>
	</Operation>

	<Operation Class="PatchOperationAdd">
		<xpath>Defs/ThingDef[defName="Steel"]/stuffProps/categories</xpath>
		<value>
			<li>Metallic_Weapon</li>
			<li>Steeled</li>
		</value>
	</Operation>

	<Operation Class="PatchOperationReplace">
		<xpath>Defs/ThingDef[defName="Steel"]/statBases/StuffPower_Armor_Sharp</xpath>
		<value>
			<StuffPower_Armor_Sharp>1</StuffPower_Armor_Sharp>
		</value>
	</Operation>

	<Operation Class="PatchOperationReplace">
		<xpath>Defs/ThingDef[defName="Steel"]/statBases/StuffPower_Armor_Blunt</xpath>
		<value>
			<StuffPower_Armor_Blunt>1.5</StuffPower_Armor_Blunt>
		</value>
	</Operation>

	<Operation Class="PatchOperationReplace">
		<xpath>Defs/ThingDef[defName="Steel"]/statBases/StuffPower_Armor_Heat</xpath>
		<value>
			<StuffPower_Armor_Heat>0</StuffPower_Armor_Heat>
		</value>
	</Operation>

</Patch>

<Bulk> - A measure of how much space an item takes up when carried. Small, compact items have low Bulk, while larger and more cumbersome items have high bulk.

<li>Metallic_Weapon</li> - A stuff category applied to materials, such as steel and plasteel, that are suitable to being used to make weapons. In base Combat Extended, this excludes materials like silver and gold, which don't provide much Sharp penetration.

<li>Steeled</li> - A stuff category applied to materials, such as steel and plasteel, that are suitable to being used to make metallic armor. In base Combat Extended, this consists of Steel and Plasteel.

<li>SoftArmor</li> - Though not shown here, this category is applied to materials suitable for making soft, flexible armor similar to modern Kevlar. This includes Devilstrand and Thrumbo leather. Notably, apparel made of a soft armor material always takes at least some damage from Sharp attacks, while hard armor may or may not be damaged depending upon various factors.

<StuffPower_Armor_Sharp> - For apparel made of this material, this value is multiplied by the thickness of the material (StuffEffectMultiplierArmor) to find the base amount of Sharp protection it provides, as measured in millimeters (mm) of steel Rolled Homogenous Armor (RHA).

<StuffPower_Armor_Blunt> - For apparel made of this material, this value is multiplied by the thickness of the material (StuffEffectMultiplierArmor) to find the base amount of Blunt protection it provides, as measured in Megapascals (MPa). For most metals, this is 1.5x greater than the Sharp value.

<StuffPower_Armor_Heat> - For apparel made of this material, this value is multiplied by the thickness of the apparel (StuffEffectMultiplierArmor) to find the base amount of Heat protection it provides. Unlike Sharp and Blunt armor types, Combat Extended does not change function of Heat armor--however, it does make changes to the thickness of stuffable apparel that means it may be necessary to adjust the value.

Apparel

<?xml version="1.0" encoding="utf-8"?>
<Patch>

 	<!-- Stuffable Armor -->
	<Operation Class="PatchOperationReplace">
		<xpath>Defs/ThingDef[defName="Apparel_TribalHeaddress"]/statBases/StuffEffectMultiplierArmor</xpath>
		<value>
			<StuffEffectMultiplierArmor>5</StuffEffectMultiplierArmor>
		</value>
	</Operation>

 	<!-- Non-Stuffable Armor -->
	<Operation Class="PatchOperationAdd">
		<xpath>Defs/ThingDef[@Name="ApparelArmorReconBase"]/statBases</xpath>
		<value>
			<Bulk>80</Bulk>
			<WornBulk>12</WornBulk>
		</value>
	</Operation>

	<Operation Class="PatchOperationReplace">
		<xpath>Defs/ThingDef[@Name="ApparelArmorReconBase"]/statBases/MaxHitPoints</xpath>
		<value>
			<MaxHitPoints>400</MaxHitPoints> <!-- Weapons do more damage in Combat Extended, so it may be sensible to increase armor HP. -->
		</value>
	</Operation>

	<Operation Class="PatchOperationReplace">
		<xpath>Defs/ThingDef[@Name="ApparelArmorReconBase"]/statBases/ArmorRating_Sharp</xpath>
		<value>
			<ArmorRating_Sharp>16</ArmorRating_Sharp>
		</value>
	</Operation>

	<Operation Class="PatchOperationReplace">
		<xpath>Defs/ThingDef[@Name="ApparelArmorReconBase"]/statBases/ArmorRating_Blunt</xpath>
		<value>
			<ArmorRating_Blunt>34</ArmorRating_Blunt>
		</value>
	</Operation>

	<Operation Class="PatchOperationAdd">
		<xpath>Defs/ThingDef[@Name="ApparelArmorReconBase"]</xpath>
		<value>
			<equippedStatOffsets>
				<CarryWeight>50</CarryWeight>
				<CarryBulk>8</CarryBulk>
				<ToxicEnvironmentResistance>0.50</ToxicEnvironmentResistance>
				<MoveSpeed>0.4</MoveSpeed>
			</equippedStatOffsets>
		</value>
	</Operation>

	<Operation Class="PatchOperationAdd">
		<xpath>Defs/ThingDef[@Name="ApparelArmorReconBase"]/apparel/bodyPartGroups</xpath>
		<value>
			<li>Hands</li> <!-- In Combat Extended, most power armor protects the hands and feet. -->
			<li>Feet</li>
		</value>
	</Operation>

	<Operation Class="PatchOperationAddModExtension">
		<xpath>Defs/ThingDef[@Name="ApparelArmorReconBase"]</xpath>
		<value>
			<li Class="CombatExtended.PartialArmorExt">
				<stats>
					<li>
						<ArmorRating_Sharp>0.60</ArmorRating_Sharp>
						<parts>
							<li>Neck</li>
							<li>Hand</li>
						</parts>
					</li>
					<li>
						<ArmorRating_Blunt>0.60</ArmorRating_Blunt>
						<parts>
							<li>Neck</li>
							<li>Hand</li>
						</parts>
					</li>
					<li>
						<ArmorRating_Sharp>0.90</ArmorRating_Sharp>
						<parts>
							<li>Leg</li>
						</parts>
					</li>
					<li>
						<ArmorRating_Blunt>0.90</ArmorRating_Blunt>
						<parts>
							<li>Leg</li>
						</parts>
					</li>
					<li>
						<ArmorRating_Sharp>0.80</ArmorRating_Sharp>
						<parts>
							<li>Arm</li>
						</parts>
					</li>
					<li>
						<ArmorRating_Blunt>0.80</ArmorRating_Blunt>
						<parts>
							<li>Arm</li>
						</parts>
					</li>
				</stats>
			</li>
		</value>
	</Operation>

</Patch>

<Bulk> - A measure of how much space an item takes up when carried. Small, compact items have low Bulk, while larger and more cumbersome items have high bulk.

<wornBulk> - A measure of how encumbering a piece of apparel is to the wearer. For most types of apparel, this is significantly lower than the <Bulk>, since it's usually less cumbersome to be wearing something compared to carrying it. For many pieces of common clothing (e.g t-shirt, pants, hats, etc.) that offer little protection or insulation, this value may be 0, because the encumbrance of wearing them is trivial. For most combat helmets, the standard <wornBulk> value is 1.

<StuffEffectMultiplierArmor> - The thickness of the piece apparel, as measured in milimeters. for stuffed apparel, this is multiplied with the values of the material's StuffPower_Armor_Sharp and StuffPower_Armor_Blunt stats to find the Sharp and Blunt armor values, respectively.

<ArmorRating_Sharp> - The amount of protection this apparel provides against Sharp attacks like bullets and blades, as measured in millimeters (mm) of steel Rolled Homogenous Armor (RHA).

<ArmorRating_Blunt> - The amount of protection this apparel provides against Blunt attacks like punches and explosive shockwaves, as measured in Megapascals (MPa).

<CarryWeight> - The amount of additional Mass the wearer of this apparel can carry. Usually found on powered armor, exo-suits, and similar gear.

<CarryBulk> - The amount of additional Bulk the wearer of this apparel can carry. Usually found on backpacks, chest rigs, and other pieces of apparel with significant storage volume.

<li Class="CombatExtended.PartialArmorExt"> - This ModExtension allows the amount of protection across different body parts covered by a piece of apparel, allowing for the simulation of variable armor thickness. The value under each part and armor type is a multiplier applied to base armor value.

Melee Weapon

<?xml version="1.0" encoding="utf-8"?>
<Patch>
	<Operation Class="PatchOperationReplace">
		<xpath>Defs/ThingDef[defName="MeleeWeapon_Gladius"]/tools</xpath>
		<value>
			<tools>
				<li Class="CombatExtended.ToolCE">
					<label>handle</label>
					<capacities>
						<li>Poke</li>
					</capacities>
					<power>2</power>
					<chanceFactor>0.33</chanceFactor>
					<cooldownTime>1.44</cooldownTime>
					<armorPenetrationBlunt>0.425</armorPenetrationBlunt>
					<linkedBodyPartsGroup>Handle</linkedBodyPartsGroup>
				</li>
				<li Class="CombatExtended.ToolCE">
					<label>point</label>
					<capacities>
						<li>Stab</li>
					</capacities>
					<power>27</power>
					<cooldownTime>1.44</cooldownTime>
					<armorPenetrationBlunt>0.425</armorPenetrationBlunt>
					<armorPenetrationSharp>0.48</armorPenetrationSharp>
					<linkedBodyPartsGroup>Point</linkedBodyPartsGroup>
				</li>
				<li Class="CombatExtended.ToolCE">
					<label>edge</label>
					<capacities>
						<li>Cut</li>
					</capacities>
					<power>20</power>
					<cooldownTime>1.34</cooldownTime>
					<armorPenetrationBlunt>0.956</armorPenetrationBlunt>
					<armorPenetrationSharp>0.43</armorPenetrationSharp>
					<linkedBodyPartsGroup>Edge</linkedBodyPartsGroup>
				</li>
			</tools>
		</value>
	</Operation>

	<Operation Class="PatchOperationAdd">
		<xpath>Defs/ThingDef[defName="MeleeWeapon_Gladius"]/statBases</xpath>
		<value>
			<Bulk>3.5</Bulk>
			<MeleeCounterParryBonus>0.35</MeleeCounterParryBonus>
		</value>
	</Operation>

	<Operation Class="PatchOperationAdd">
		<xpath>Defs/ThingDef[defName="MeleeWeapon_Gladius"]</xpath>
		<value>
			<equippedStatOffsets>
				<MeleeCritChance>0.2</MeleeCritChance>
				<MeleeParryChance>0.35</MeleeParryChance>
				<MeleeDodgeChance>0.2</MeleeDodgeChance>
			</equippedStatOffsets>
		</value>
	</Operation>

	<Operation Class="PatchOperationAdd">
		<xpath>Defs/ThingDef[defName="MeleeWeapon_Gladius"]/weaponTags</xpath>
		<value>
			<li>CE_OneHandedWeapon</li>
		</value>
	</Operation>

</Patch>

Important: A spreadsheet for roughly calculating blunt and sharp melee penetration values can be found here, but you're encouraged to use other patched weapons for reference.

<armorPenetrationSharp> - The amount of Blunt armor protection this weapon can overcome, measured in millimeters (mm) of steel Rolled Homogenous Armor (RHA).

<armorPenetrationBlunt> - The amount of Blunt armor protection this weapon can overcome, measured in Megapascals (MPa). If a sharp attack--whether a melee blow or projectile--fails to penetrate a target's sharp armor, a reduced portion of the damage (relative sharp penetration / sharp armor value) will be converted to Blunt damage and continue. In other words, a target may still be injured by the force of attacks that failed to penetrate their armor.

<MeleeCritChance> - The chance the wielder will land a critical blow against a target. On a critical hit, the attack will deal additional damage and the target will be stunned (blunt attack) or the attack will do double the amount of armor penetration (sharp attack). This tends to be higher for larger, harder-hitting and blunt weapons.

<MeleeDodgeChance> - The chance the wielder will avoid a melee attack that would've otherwise hit. This tends to be higher for quick weapons that provide a lot of reach, like spears or longswords.

<MeleeParryChance> - The chance the wielder will block a melee attack that would've otherwise hit them, using their weapon to absorb the incoming damage. This tends to be higher for weapons that are two-handed and have long hafts or blades for the wielder to block with. If the wielder critically succeeds on their parry, they will automatically riposte.

<MeleeCounterParryBonus> - The ability of a melee weapon to crush through or otherwise circumvent a target's attacks to parry the blow. This tends to be higher for weapons with a lot of reach or with the weight concentrated at the striking end (like a mace or sledgehammer).

<li>CE_OneHandedWeapon</li> - Weapons, ranged or melee, with this weaponTag can be wielded while wearing a shield. If a pawn has a melee shield equipped alongside a weapon without this tag, they will be unable to attack.

Ranged Weapon

Note: Some additional fields and nodes have been added to this patch, as denoted by the comments. It is not necessary to include these items in most cases, but they've been inclued for demonstration purposes.

<?xml version="1.0" encoding="utf-8"?>
<Patch>

	<Operation Class="PatchOperationReplace">
		<xpath>
			Defs/ThingDef[defName="Gun_LMG"]/tools <!-- This works the same as patching a melee weapon. -->
		</xpath>
		<value>
			<tools>
				<li Class="CombatExtended.ToolCE">
					<label>stock</label>
					<capacities>
						<li>Blunt</li>
					</capacities>
					<power>8</power>
					<cooldownTime>1.55</cooldownTime>
					<chanceFactor>1.5</chanceFactor>
					<armorPenetrationBlunt>2.755</armorPenetrationBlunt>
					<linkedBodyPartsGroup>Stock</linkedBodyPartsGroup>
				</li>
				<li Class="CombatExtended.ToolCE">
					<label>barrel</label>
					<capacities>
						<li>Blunt</li>
					</capacities>
					<power>5</power>
					<cooldownTime>2.02</cooldownTime>
					<armorPenetrationBlunt>1.630</armorPenetrationBlunt>
					<linkedBodyPartsGroup>Barrel</linkedBodyPartsGroup>
				</li>
				<li Class="CombatExtended.ToolCE">
					<label>muzzle</label>
					<capacities>
						<li>Poke</li>
					</capacities>
					<power>8</power>
					<cooldownTime>1.55</cooldownTime>
					<armorPenetrationBlunt>2.755</armorPenetrationBlunt>
					<linkedBodyPartsGroup>Muzzle</linkedBodyPartsGroup>
				</li>
			</tools>
		</value>
	</Operation>

	<Operation Class="CombatExtended.PatchOperationMakeGunCECompatible">
		<defName>Gun_LMG</defName>
		<statBases>
			<Mass>8.7</Mass>
			<RangedWeapon_Cooldown>0.56</RangedWeapon_Cooldown>
			<SightsEfficiency>1</SightsEfficiency>
			<NightVisionEfficiency_Weapon>0.4</NightVisionEfficiency_Weapon> <!-- Some weapons have have advanced optics that reduce the penalty for shooting in the dark. -->
			<ShotSpread>0.05</ShotSpread>
			<SwayFactor>1.37</SwayFactor>
			<Bulk>12.9</Bulk>
			<WorkToMake>31500</WorkToMake>
		</statBases>
		<costList>
			<Steel>80</Steel>
			<WoodLog>10</WoodLog>
			<ComponentIndustrial>5</ComponentIndustrial>
		</costList>
		<Properties>
			<recoilAmount>1.38</recoilAmount>
			<verbClass>CombatExtended.Verb_ShootCE</verbClass>
			<hasStandardCommand>true</hasStandardCommand>
			<defaultProjectile>Bullet_303British_FMJ</defaultProjectile>
			<warmupTime>1.3</warmupTime>
			<range>62</range>
			<ticksBetweenBurstShots>7</ticksBetweenBurstShots>
			<burstShotCount>10</burstShotCount> <!-- Deleting this field will make the weapon fire single shots. -->
			<soundCast>Shot_CE_BattleRifle</soundCast>
			<soundCastTail>GunTail_Medium</soundCastTail>
			<muzzleFlashScale>9</muzzleFlashScale> <!-- The higher this value, the more visible the shooter is when firing in the dark. -->
			<targetParams>
				<canTargetLocations>true</canTargetLocations>
			</targetParams>
		</Properties>
		<AmmoUser>
			<magazineSize>50</magazineSize>
			<reloadTime>4.9</reloadTime>
			<ammoSet>AmmoSet_303British</ammoSet>
			<reloadOneAtATime>True</reloadOneAtATime> <-- Does the shooter reload the weapon one round at a time? -->
		</AmmoUser>
		<FireModes>
			<aimedBurstShotCount>5</aimedBurstShotCount>
			<aiUseBurstMode>FALSE</aiUseBurstMode>
			<aiAimMode>SuppressFire</aiAimMode>
			<noSingleShot>true</noSingleShot> <!-- If true, prevents automatic weapons from firing single shots, useful for forcing burst fire.-->
			<noSnapshot>true</noSnapshot> <!-- If true, prevents the weapon using the `Snapshot` aiming mode. -->
		</FireModes>
		<weaponTags>
			<li>CE_MachineGun</li>
			<li>CE_AI_LMG</li>
			<li>Bipod_LMG</li>
		</weaponTags>
		<researchPrerequisite>GasOperation</researchPrerequisite>
		<AllowWithRunAndGun>false</AllowWithRunAndGun> <!-- When the Run And Gun mod is enabled, can this weapon be fired on the move? -->
	</Operation>

</Patch>

Important: Stats for most conventional weapons can be calculated using this spreadsheet.

<Operation Class="CombatExtended.PatchOperationMakeGunCECompatible"> - This is a custom Patch Operation used by Combat Extended which is specifically intended to patch ranged weapons and effectively combines several PatchOperationAdd and PatchOperationReplace operations into one. It will add or replace fields specified in the operation, but will leave omitted fields in place on the patched gun. For example; you can include a new <Mass> in the operation to overwrite the weapon's mass, but deleting that field from the operation will leave the gun's base mass. Note: This operation may not work if the weapon ThingDef being targeted does not have a <verbs> field.

<SightsEfficiency> - The effectiveness of the weapon's sights. This has a base value of 1 for basic iron sights.

<ShotSpread> - How much inherent dispersion a weapon's shots have. This is not reduced by shooting skill.

<SwayFactor> - How much the weapon sways while being aimed. Usually higher for heavier or one-handed weapons, this is can be reduced by things like shooting in 'Aimed Shot' mode and by higher shooting skill.

<recoilAmount> - The amount of recoil felt by the shooter from each shot, impacting the accuracy of the next shot. Skilled shooters and firing with a deployed bipod can reduce the effects of recoil.

<AmmoUser> - Contains all the info for the weapon's ammo usage. Deleting this field will allow the gun to fire without consuming ammo or needing to reload, but will restrict it to firing the defaultProjectile.

<magazineSize> - How many times the weapon can fire until it needs to reload.

<reloadTime> - How long it takes to reload the weapon, in seconds (s).

<ammoSet> - What <CombatExtended.AmmoSetDef> the weapon uses. Deleting this field will allow the gun to fire without consuming ammo while still stopping to 'reload' the magazine. This will restrict the weapon to using the defaultProjectile.

<reloadOneAtATime> - Dictates whether the shooter reloads the weapon one round at a time. The default is false and so the field can be omitted for most weapons, but this might be true for weapons like tube-fed shotguns and gate-loading revolvers.

<FireModes> - Controls the weapon's available firing modes. Without this field, the weapon will fire using its burstShotCount.

<aimedBurstShotCount> - How many rounds are fired when in Burst Fire mode. Value should not be less than burstShotCount. Deleting this field will prevent the weapon from firing in 'Burst' mode.

<aiUseBurstMode> - For automatic weapons, do the AI fire in 'Burst' (true) or 'Auto' (false) mode? Default is False.

<aiAimMode> - What fire mode does the AI use for this weapon? Valid choices are AimedShot, SuppressFire, or Snapshot.

<li>Bipod_LMG</li> - This weaponTag gives the weapon a bipod that uses the Bipod_LMG stats. Weapons with bipods get bonuses or penalties to recoil, warmup, and sway depending on whether or not the bipod is deployed.

Turret

<?xml version="1.0" encoding="utf-8"?>
<Patch>

	<Operation Class="PatchOperationReplace">
		<xpath>Defs/ThingDef[defName="Turret_MiniTurret"]/thingClass</xpath>
		<value>
			<thingClass>CombatExtended.Building_TurretGunCE</thingClass> <!-- Makes the turret a CE turret. -->
		</value>
	</Operation>

	<Operation Class="PatchOperationAdd">
		<xpath>Defs/ThingDef[defName="Turret_MiniTurret"]/statBases</xpath>
		<value>
			<AimingAccuracy>0.25</AimingAccuracy>
		</value>
	</Operation>

	<Operation Class="PatchOperationReplace">
		<xpath>Defs/ThingDef[defName="Turret_MiniTurret"]/statBases/ShootingAccuracyTurret</xpath>
		<value>
			<ShootingAccuracyTurret>0.5</ShootingAccuracyTurret>
		</value>
	</Operation>

	<Operation Class="PatchOperationReplace">
		<xpath>Defs/ThingDef[defName="Turret_MiniTurret"]/statBases/Mass</xpath>
		<value>
			<Mass>25</Mass> <!-- Since this turret is portable, we need appropriate Mass and Bulk stats. -->
			<Bulk>15</Bulk>
		</value>
	</Operation>

	<Operation Class="PatchOperationRemove">
		<xpath>Defs/ThingDef[defName="Turret_MiniTurret"]/comps/li[@Class="CompProperties_Explosive"]</xpath>
	</Operation>

	<Operation Class="PatchOperationRemove">
		<xpath>Defs/ThingDef[defName="Turret_MiniTurret"]/comps/li[@Class="CompProperties_Refuelable"]</xpath> <!-- Since we reload from CE's ammo systems, we don't need vanilla's fueling system. -->
	</Operation>

	<Operation Class="PatchOperationReplace">
		<xpath>Defs/ThingDef[defName="Turret_MiniTurret"]/fillPercent</xpath>
		<value>
			<fillPercent>0.85</fillPercent> <!-- In CE, this controls how tall the building is. Turrets shorter than 0.7 won't be able to fire out through embrasures. -->
		</value>
	</Operation>

	<Operation Class="PatchOperationReplace">
		<xpath>Defs/ThingDef[defName="Turret_MiniTurret"]/building/turretBurstCooldownTime</xpath>
		<value>
			<turretBurstCooldownTime>1.0</turretBurstCooldownTime>
		</value>
	</Operation>

</Patch>

Patching automated turrets is pretty straightforward, you simply need to swap out a few vanilla elements for their Combat Extended version. The turret's gun is patched just like you would any other ranged weapon.

Humanoid/Animal

<?xml version="1.0" encoding="utf-8"?>
<Patch>

	<Operation Class="PatchOperationReplace">
		<xpath>Defs/ThingDef[@Name="BasePawn"]/inspectorTabs/li[.="ITab_Pawn_Gear"]</xpath>
		<value>
			<li>CombatExtended.ITab_Inventory</li>
		</value>
	</Operation>

	<Operation Class="PatchOperationAdd">
		<xpath>Defs/ThingDef[@Name="BasePawn"]/comps</xpath>
		<value>
			<li Class="CombatExtended.CompProperties_Inventory" />
			<li Class="CombatExtended.CompProperties_TacticalManager" />
		</value>
	</Operation>

	<Operation Class="PatchOperationAddModExtension">
		<xpath>Defs/ThingDef[defName="Human"]</xpath>
		<value>
			<li Class="CombatExtended.RacePropertiesExtensionCE">
				<bodyShape>Humanoid</bodyShape>
			</li>
		</value>
	</Operation>

	<Operation Class="PatchOperationAdd">
		<xpath>Defs/ThingDef[defName="Human"]/statBases</xpath>
		<value>
			<MeleeDodgeChance>1</MeleeDodgeChance>
			<MeleeCritChance>1</MeleeCritChance>
			<MeleeParryChance>1</MeleeParryChance>
		</value>
	</Operation>

	<Operation Class="PatchOperationReplace">
		<xpath>Defs/ThingDef[defName="Human"]/tools</xpath>
		<value>
			<tools>
				<li Class="CombatExtended.ToolCE">
					<label>left fist</label>
					<capacities>
						<li>Blunt</li>
					</capacities>
					<power>1</power>
					<cooldownTime>1.26</cooldownTime>
					<linkedBodyPartsGroup>LeftHand</linkedBodyPartsGroup>
					<armorPenetrationBlunt>0.5</armorPenetrationBlunt>
				</li>
				<li Class="CombatExtended.ToolCE">
					<label>right fist</label>
					<capacities>
						<li>Blunt</li>
					</capacities>
					<power>1</power>
					<cooldownTime>1.26</cooldownTime>
					<linkedBodyPartsGroup>RightHand</linkedBodyPartsGroup>
					<armorPenetrationBlunt>0.5</armorPenetrationBlunt>
				</li>
				<li Class="CombatExtended.ToolCE">
					<label>teeth</label>
					<capacities>
						<li>Bite</li>
					</capacities>
					<power>1</power>
					<cooldownTime>2</cooldownTime>
					<linkedBodyPartsGroup>Teeth</linkedBodyPartsGroup>
					<chanceFactor>0.07</chanceFactor>
					<soundMeleeHit>Pawn_Melee_HumanBite_Hit</soundMeleeHit>
					<soundMeleeMiss>Pawn_Melee_HumanBite_Miss</soundMeleeMiss>
					<armorPenetrationSharp>0.15</armorPenetrationSharp>
					<armorPenetrationBlunt>1.0</armorPenetrationBlunt>
				</li>
				<li Class="CombatExtended.ToolCE">
					<label>head</label>
					<capacities>
						<li>Blunt</li>
					</capacities>
					<power>2</power>
					<cooldownTime>4.49</cooldownTime>
					<linkedBodyPartsGroup>HeadAttackTool</linkedBodyPartsGroup>
					<chanceFactor>0.2</chanceFactor>
					<armorPenetrationBlunt>0.625</armorPenetrationBlunt>
				</li>
			</tools>
		</value>
	</Operation>

	<Operation Class="PatchOperationAdd">
		<xpath>Defs/ThingDef[defName="Human"]/comps</xpath>
		<value>
			<li>
				<compClass>CombatExtended.CompPawnGizmo</compClass>
			</li>
			<li Class="CombatExtended.CompProperties_Suppressable" />
			<li>
				<compClass>CombatExtended.CompAmmoGiver</compClass>
			</li>
			<li Class="CombatExtended.CompProperties_ArmorDurability">
				<Durability>500</Durability>
				<Regenerates>true</Regenerates> <!-- Does the armor repair itself over time? -->
				<RegenInterval>600</RegenInterval> <!-- How long between each regeneration cycle -->
				<RegenValue>5</RegenValue> <!-- How many points does it regenerate each cycle? -->
				<<Repairable>true</Repairable> <!-- Can another pawn repair this creature's damaged armor? -->
				<RepairIngredients> <!-- Does this repair require materials? Without this field, the repair is free.  -->
					<Steel>5</Steel>
					<Plasteel>5</Plasteel>
				</RepairIngredients>
				<RepairTime>240</RepairTime> <!-- How long does it take to repair the armor? -->
				<RepairValue>200</RepairValue> <!-- How much armor is restored per repair? -->
				<CanOverHeal>true</CanOverHeal> <!-- Can the creature's armor have bonus HP added to it by repairing it? -->
				<MaxOverHeal>500</MaxOverHeal> <!-- If so, how much? -->
				<MinArmorPct>0.75</MinArmorPct> <!-- What is the minimum percentage all types of the creature's armor can be reduced by? 
				<MinArmorValueSharp>14</MinArmorValueSharp> <!-- What is the absolute minimum the creature's armor can be reduced to? -->
				<MinArmorValueBlunt>30</MinArmorValueBlunt>
				<MinArmorValueHeat>0.2</MinArmorValueHeat>
				<MinArmorValueElectric>0.1</MinArmorValueElectric>
			</li>
		</value>
	</Operation>

</Patch>

<li>CombatExtended.ITab_Inventory</li> and <li Class="CombatExtended.CompProperties_Inventory" /> - These two fields swap the vanilla inventory system out for CE's. If your creature inherits from BasePawn, they already have it.

<bodyShape> - Defines the proportions of the creature's hitbox as set by the corresponding CombatExtended.BodyShapeDef.

<li Class="CombatExtended.CompProperties_Suppressable" /> - Causes the creature to automatically seek cover when under fire. Animals and creatures lacking a self-preservation instinct don't need this.

<compClass>CombatExtended.CompAmmoGiver</compClass> - Allows the creature to pass ammo directly from its inventory into the inventory of another creature equipped with a weapon that uses that ammo.

<li Class="CombatExtended.CompProperties_ArmorDurability"> - If the creature has inherent armor values (either naturally or from implants), this section allows that armor to be reduced by incoming damage. Without this field, their natural armor cannot be damaged.

AmmoSet

Note: Due to the length of the file, it was necessary to remove redundant elements. You can find the full file in here. Important: This spreadsheet can be used to find the ammo item and projectile stats for most types of ammo.

<?xml version="1.0" encoding="utf-8"?>
<Defs>

	<ThingCategoryDef>
		<defName>Ammo303British</defName> <!-- This is just for stockpile purposes. -->
		<label>.303 British</label>
		<parent>AmmoRifles</parent>
		<iconPath>UI/Icons/ThingCategories/CaliberRifle</iconPath>
	</ThingCategoryDef>

	<!-- ==================== AmmoSet ========================== -->

	<CombatExtended.AmmoSetDef> 
		<defName>AmmoSet_303British</defName>
		<label>.303 British</label>
		<ammoTypes> <!-- This list ties ammo items together to corresponding projectile. -->
			<Ammo_303British_FMJ>Bullet_303British_FMJ</Ammo_303British_FMJ>
			<Ammo_303British_AP>Bullet_303British_AP</Ammo_303British_AP>
			<Ammo_303British_HP>Bullet_303British_HP</Ammo_303British_HP>
			<Ammo_303British_Incendiary>Bullet_303British_Incendiary</Ammo_303British_Incendiary>
			<Ammo_303British_HE>Bullet_303British_HE</Ammo_303British_HE>
			<Ammo_303British_Sabot>Bullet_303British_Sabot</Ammo_303British_Sabot>
		</ammoTypes>
		<similarTo>AmmoSet_Rifle</similarTo> <!-- In 'Generic Ammo' mode, this ammo set is replaced by the `similarTo` ammo set. -->
	</CombatExtended.AmmoSetDef>


	<!-- ==================== Ammo ========================== -->

	<ThingDef Class="CombatExtended.AmmoDef" Name="303BritishBase" ParentName="SmallAmmoBase" Abstract="True">
		<description>Large rifle bullet found mostly in outdated bolt-action firearms.</description>
		<statBases>
			<Mass>0.026</Mass>
			<Bulk>0.03</Bulk>
		</statBases>
		<tradeTags>
			<li>CE_AutoEnableTrade</li> <!-- This lets traders stock this kind of ammo. -->
			<li>CE_AutoEnableCrafting</li> <!-- This adds the ammo recipes to the Loading Bench when the ammo set is in-use. -->
		</tradeTags>
		<thingCategories>
			<li>Ammo303British</li>
		</thingCategories>
	</ThingDef>

	<ThingDef Class="CombatExtended.AmmoDef" ParentName="303BritishBase">
		<defName>Ammo_303British_FMJ</defName>
		<label>.303 British (FMJ)</label>
		<graphicData>
			<texPath>Things/Ammo/Rifle/Clip/FMJ</texPath>
			<graphicClass>Graphic_StackCount</graphicClass>
		</graphicData>
		<statBases>
			<MarketValue>0.12</MarketValue>
		</statBases>
		<ammoClass>FullMetalJacket</ammoClass> <!-- What ammo type appears on the ammo selector when loading it? Note: AmmoClass must be unique within the ammo set, or the system cannot distinguish between the two items. -->
		<cookOffProjectile>Bullet_303British_FMJ</cookOffProjectile> <!-- If this round cooks off without `Realistic Cookoff` enabled, what projectile spawns? -->
	</ThingDef>

	<!-- ================== Projectiles ================== -->

	<ThingDef Name="Base303BritishBullet" ParentName="BaseBulletCE" Abstract="true">
		<graphicData>
			<texPath>Things/Projectile/Bullet_Small</texPath>
			<graphicClass>Graphic_Single</graphicClass>
		</graphicData>
		<projectile Class="CombatExtended.ProjectilePropertiesCE">
			<damageDef>Bullet</damageDef>
			<speed>147</speed>
			<dropsCasings>true</dropsCasings> <!-- Does the weapon spit out empty casing when it fires? -->
		</projectile>
	</ThingDef>

	<ThingDef ParentName="Base303BritishBullet">
		<defName>Bullet_303British_FMJ</defName>
		<label>.303 British bullet (FMJ)</label>
		<projectile Class="CombatExtended.ProjectilePropertiesCE">
			<damageAmountBase>20</damageAmountBase>
			<armorPenetrationSharp>6.5</armorPenetrationSharp>
			<armorPenetrationBlunt>67</armorPenetrationBlunt>
		</projectile>
	</ThingDef>

	<!-- ==================== Recipes ========================== -->

	<RecipeDef ParentName="AmmoRecipeBase">
		<defName>MakeAmmo_303British_FMJ</defName> <!-- This defName must be in the format of `MakeAmmo_[Ammo Item Name]. -->
		<label>make .303 British (FMJ) cartridge x500</label>
		<description>Craft 500 .303 British (FMJ) cartridges.</description>
		<jobString>Making .303 British (FMJ) cartridges.</jobString>
		<ingredients>
			<li>
				<filter>
					<thingDefs>
						<li>Steel</li>
					</thingDefs>
				</filter>
				<count>28</count>
			</li>
		</ingredients>
		<fixedIngredientFilter>
			<thingDefs>
				<li>Steel</li>
			</thingDefs>
		</fixedIngredientFilter>
		<products>
			<Ammo_303British_FMJ>500</Ammo_303British_FMJ>
		</products>
		<workAmount>2800</workAmount>
	</RecipeDef>

</Defs>

Combat Extended's ammo system works off of a system called the AmmoInjector, various elements of which parts of each AmmoSetDef keys off of. When the game is launched, the injector finds all of the ammo sets that are in use and loads those, leaving unused sets unloaded. This way, only ammunition actively in use appears in-game, preventing clutter and improving load times.

The AmmoSetDef is also what marries the projectile to the ammo item, ensuring that the type of bullet loaded is the same type of bullet that comes out of the barrel. While the details of the ammo system are fairly complicated, you generally don't have to worry about it. In most cases, you can just use an existing ammo set as a template and adjust the stats to your liking.

Conclusion

While writing a compatibility patch might seem like a daunting task, most of the work is straightforward copy-pasting and I encourage you to give it a try--it's a great way to give back to the mod! And remember, if you're ever stuck, there are plenty of places you can find help and resources.