Basic Ranged Weapon

From RimWorld Wiki
Revision as of 21:28, 10 February 2024 by Aelanna (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Modding Tutorials

This is a basic RimWorld mod tutorial for the purpose of creating a simple ranged weapon using only XML. Be sure to check out the basic melee weapon tutorial as well.

Goals

  • Create a new saw launcher item, a ranged weapon
  • Give it a custom projectile with a custom damage type
  • Give it custom melee and ranged sound effects

Recommended Reading

Sample Repository

ExampleRangedWeapon.png

A working implementation of this mod can be found in this GitHub repository. You can use it to compare against your work or as a basis for modification!

Folder Setup

First, you will want to create the files and folders necessary for this mod:

Mods
└ MyModFolder
  ├ About
  │ ├ About.xml
  │ └ Preview.png
  ├ Defs
  │ ├ DamageDefs
  │ │ └ ExampleDamage_Ranged.xml
  │ ├ SoundDefs
  │ │ └ ExampleSounds_RangedWeapon.xml
  │ └ ThingDefs
  │   └ ExampleWeapons_Ranged.xml
  ├ Sounds
  │ └ ExampleMod
  │   ├ Example_SawLaunch.ogg
  │   └ Example_SawMelee.ogg
  └ Textures
    └ ExampleMod
      ├ Example_SawBlade.png
      └ Example_SawLauncher.png

Please check out the mod folder structure guide for more information about individual folders.

About.xml

Your About.xml is used to identify your mod to RimWorld; please see the About.xml reference page for more information. Be sure to replace "AuthorName" with your own name:

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

  <!-- This is the internal identifier for your mod. -->
  <!-- It is recommended that you make it unique to as to avoid potential collisions with other authors; -->
  <!--     if Rimworld detects multiple mods with the same packageId then it will refuse to load all of them. -->
  <packageId>AuthorName.ExampleRangedWeapon</packageId>

  <!-- This is both the displayed name of your mod as well as the name used for patch targeting. -->
  <name>Example Ranged Weapon</name>

  <!-- Your name goes here. -->
  <author>AuthorName</author>

  <!-- These are the RimWorld game versions that your mod supports. -->
  <!-- It is recommended that you only list versions that you have explicitly tested to ensure they work, -->
  <!-- as even basic XML options can change between major versions of the game. -->
  <supportedVersions>
    <li>1.4</li>
  </supportedVersions>

  <!-- This is the description of your mod shown in both the vanilla mod manager as well as modded managers. -->
  <description>This is an example ranged weapon mod made for the RimWorld Wiki.</description>

</ModMetaData>

Sample Assets

You can use these as the example assets:

Projectile Texture
Example SawBlade.png
Weapon Texture
Example SawLauncher.png

Instructions

1. Create the weapon ThingDef

Our first step is to create the XML that represents our new weapon. Whenever possible, this is best accomplished by first copying a vanilla ThingDef and modifying it; in this case we will use the vanilla pump shotgun as our starting point, as it is the most similar existing weapon to what we want to create. The XML for the pump shotgun can be found in Data/Core/Defs/ThingDefs_Misc/Weapons/RangedIndustrial.xml.

In our own ExampleWeapons_Ranged.xml, we'll add the following content:

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

  <!-- Example weapon: saw launcher -->
  <ThingDef ParentName="BaseHumanMakeableGun">
    <!-- pasted content omitted -->
  </ThingDef>

</Defs>

2. Modify the weapon ThingDef

In order to differentiate our weapon from the vanilla pump shotgun, we'll make the following changes:

XML Description
<defName>ExampleGun_SawLauncher</defName>

The defName of a ThingDef is its identity and must be globally unique across all mods and official content. It is strongly recommended that it is prefixed with a project or mod name, so in this case we will use "ExampleGun_" as our prefix.

<label>saw launcher</label>

A ThingDef's label is its in-game name. Unless it is a proper name, it should be in lowercase so that it can be injected naturally into sentences that use it. RimWorld will automatically capitalize it as necessary if used in titles or as the start of a sentence.

<description>A heavy industrial circular saw used for both construction and demolition.\n\nSome madman has modified this tool to allow its blades to be shot out at high velocity, rendering it a short-ranged but devastating weapon.</description>

A ThingDef's description is used when inspecting the item's details.

<graphicData>
  <texPath>ExampleMod/Example_SawLauncher</texPath>
  <graphicClass>Graphic_Single</graphicClass>
</graphicData>

This is where define the texture of our weapon. Similar to how defNames must be unique across all mods, the texPath of our texture must be unique across all mods if we want to avoid an asset collision. We will use the folder ExampleMod as our "namespace".

For ranged weapons such as our saw launcher, the texture defined in our <graphicData> will be used for both items on the ground as well as the equipped weapon texture. The texture of the fired projectiles will be defined in a separate ThingDef.

<costList>
  <Steel>80</Steel>
  <ComponentIndustrial>4</ComponentIndustrial>
</costList>

Since our saw launcher is a more complex tool than the pump shotgun with more functionality, we will have it cost 80 steel and 4 [[components].

<statBases>
  <WorkToMake>15000</WorkToMake>
  <Mass>9.9</Mass>
  <AccuracyTouch>0.85</AccuracyTouch>
  <AccuracyShort>0.80</AccuracyShort>
  <AccuracyMedium>0.70</AccuracyMedium>
  <AccuracyLong>0.56</AccuracyLong>
  <RangedWeapon_Cooldown>1.8</RangedWeapon_Cooldown>
</statBases>

Our saw launcher requires more time to craft than a pump shotgun, weighs far more, has lower accuracy at range, and has a longer recovery cooldown duration.

<equippedStatOffsets>
  <ConstructionSpeed>0.10</ConstructionSpeed>
</equippedStatOffsets>

While there is no StatDef that specifically affects deconstruction speed, ConstructionSpeed does affect the speed at which colonists deconstruct buildings and is appropriate enough to justify our use of it. Our saw launcher will grant a 10% construction speed bonus to its wielder.

<verbs>
  <li>
    <verbClass>Verb_Shoot</verbClass>
    <hasStandardCommand>true</hasStandardCommand>
    <defaultProjectile>ExampleBullet_SawBlade</defaultProjectile>
    <warmupTime>1.2</warmupTime>
    <range>12.9</range>
    <soundCast>ExampleWeapon_SawLauncher</soundCast>
    <soundCastTail>GunTail_Heavy</soundCastTail>
    <muzzleFlashScale>0</muzzleFlashScale>
  </li>
</verbs>

The verbs list defines the ranged attacks available for a weapon. Here we will specifically modify the defaultProjectile to use a custom projectile that we will define later, increase the warmupTime to represent the awkwardness of its use as a weapon, lower its range to 12.9 to match the chain shotgun, change the soundCast to use a custom SoundDef, and reduce the muzzleFlashScale to 0.

<tools>
  <li>
    <label>handle</label>
    <capacities>
      <li>Blunt</li>
    </capacities>
    <power>9</power>
    <cooldownTime>2</cooldownTime>
  </li>
  <li>
    <label>blade</label>
    <capacities>
      <li>Demolish</li>
    </capacities>
    <power>13</power>
    <cooldownTime>2</cooldownTime>
    <soundMeleeHit>ExampleWeapon_SawLauncherMelee</soundMeleeHit>
    <soundMeleeMiss>ExampleWeapon_SawLauncher</soundMeleeMiss>
  </li>
</tools>

To better model our saw launcher's primary use as a demolition tool, we will change the barrel tool from the pump shotgun into a blade tool that utilizes the Demolish capacity to perform building-destroying attacks similar to a breach axe. Our saw will have a higher power but far slower cooldown, giving it a lower overall damage output that better suits its overall versatility.

Also note that we set custom SoundDef references for soundMeleeHit and soundMeleeMiss. We will create these two SoundDef entries in a later step.

<recipeMaker>
  <skillRequirements>
    <Crafting>5</Crafting>
  </skillRequirements>
  <displayPriority>436</displayPriority>
</recipeMaker>

Our saw launcher will have the same Crafting skill requirement as the pump shotgun, and we will place it just after the chain shotgun in the crafting recipe list.

4. Create and modify the projectile ThingDef

Now we need to create the ThingDef that defines our weapon's projectile. Similarly to the weapon itself, we will copy the pump shotgun's Bullet_Shotgun projectile, which is immediately after the weapon's ThingDef in the same file:

<!-- Example projectile: saw blade -->
<ThingDef ParentName="BaseBullet">
  <!-- pasted content omitted -->
</ThingDef>

Now, we will modify the following:

XML Description
<defName>ExampleBullet_SawBlade</defName>

Since the projectile itself is a ThingDef as well, it must similarly have a globally-unique defName. We must also make sure that we match our defName in the verbs of our weapon.

<label>saw blade</label>

While the label of our projectile is not shown in the weapon's stat card, it is visible if the player hovers over it with their mouse while it is in flight and the game is paused.

<graphicData>
  <texPath>ExampleMod/Example_SawBlade</texPath>
  <graphicClass>Graphic_Single</graphicClass>
</graphicData>

In the graphicData for our projectile, we will specify the texture used for the projectile in flight.

<projectile>
  <damageDef>ExampleDamage_Saw</damageDef>
  <damageAmountBase>25</damageAmountBase>
  <stoppingPower>1.5</stoppingPower>
  <armorPenetrationBase>0.19</armorPenetrationBase>
  <speed>55</speed>
</projectile>

Here we will specify the various values related to the damage dealt by this projectile upon impact. We will be using a custom damageDef, and we want our saw blade to deal higher base damage and slightly higher armor penetration, while having much lower stopping power.

5. Create and modify a DamageDef

Next, we need to create a custom DamageDef for our custom projectile, because none of our vanilla options are entirely accurate or appropriate for our use case. Unlike our previous two ThingDef entries, we will create this one entirely from scratch since it will be relatively simple. We will start by creating the following in our ExampleDamage_Ranged.xml file:

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

  <!-- Example damage type: ranged cut -->
  <DamageDef ParentName="Arrow">

    <!-- further tags will go here -->

  </DamageDef>

</Defs>

The reason we want to use Arrow as our parent is because the vanilla Arrow damage type already does most of what we want: it is a ranged damage type for purposes of shield belt penetration, it inflicts Cut injuries, and it is opposed by Sharp armor. This means we only have to add the following overrides to customize our new damage type:

XML Description
<defName>ExampleDamage_Saw</defName>

As always, we need to ensure our defName is unique amongst all DamageDef entries, so we will prefix it with "ExampleDamage_".

<label>saw</label>

This label will be seen in the damage breakdown for our weapon and projectile stat cards. All the usual recommendations for label fields apply here as well.

<deathMessage>{0} has been sliced to death by a saw blade.</deathMessage>

Our deathMessage is the text that will be shown in the combat log when a pawn is killed by our DamageDef. The {0} is an injection and will be replaced by the name of the pawn by RimWorld's grammar resolver system.

6. Create custom SoundDefs

We're almost done! The last thing we need to do is to create the two custom SoundDef entries so our new weapon can have a unique melee and ranged attack sound effect. We will start by creating two SoundDef entries in our ExampleSounds_RangedWeapon.xml file:

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

  <!-- Example sound: saw launcher firing -->
  <SoundDef>
    <defName>ExampleWeapon_SawLauncher</defName>

    <!-- configuration tags go here -->

  </SoundDef>

  <!-- Example sound: saw launcher melee -->
  <SoundDef>
    <defName>ExampleWeapon_SawLauncherMelee</defName>

    <!-- configuration tags go here -->

  </SoundDef>

</Defs>

ExampleWeapon_SawLauncher

The following tags go into our ExampleWeapon_SawLauncher SoundDef:

XML Description
<context>MapOnly</context>

Setting context to MapOnly specifies that our sound effect should only play while the player's focus is on a regular map such as a settlement or quest map, and will stop playing if the player switches to the world map.

<subSounds>
  <li>
    <grains>
      <li Class="AudioGrain_Clip">
        <clipPath>ExampleMod/Example_SawLaunch</clipPath>
      </li>
    </grains>
    <volumeRange>40~45</volumeRange>
    <pitchRange>0.8940217~1.084783</pitchRange>
  </li>
</subSounds>

This is the meat of our SoundDef:

The grains list in our SoundDef determines the actual sound files that should be associated with it.

volumeRange determines the volume level at which our sound should play, which will be randomly within this range every time it is played. The exact volume range of each sound effect is not always the same, as different sound files may have different baseline volume levels; you may have to adjust this value based on whether it feels too quiet or loud in your testing.

pitchRange is used to randomize the exact pitch of the sound by pitch-shifting within the specified range each time it is played. This can give more perceived variation to your sounds, which helps to ensure that it does not sound repetitive.

ExampleWeapon_SawLauncherMelee

The following tags go into our ExampleWeapon_SawLauncherMelee SoundDef:

XML Description
<context>MapOnly</context>

As with the previous entry, we want this sound to only play on regular maps as well.

<subSounds>
  <li>
    <grains>
      <li Class="AudioGrain_Clip">
        <clipPath>ExampleMod/Example_SawMelee</clipPath>
      </li>
    </grains>
    <volumeRange>45~50</volumeRange>
    <pitchRange>0.8940217~1.084783</pitchRange>
  </li>
</subSounds>

Our melee sound effect will be very similar to our ranged sound effect, but we will use a different grain clip and adjust the volume slightly higher, as the melee sound should be more impactful.

7. Done!

Your first ranged weapon is complete! Boot up RimWorld and you should be able to see and enable the "Example Ranged Weapon" mod in your mod manager. You can then use dev mode tools to spawn the weapon directly, or craft it at a machining table.

If you get any errors, be sure to check out the troubleshooting guide or join us on the #mod-development channel on the RimWorld Discord server.