Skip to content

Custom Weapons Walkthrough

cxong edited this page Nov 6, 2014 · 10 revisions

This page will walk through the process of creating a custom weapon.

Here's what we'll be making:

A booby trap that is disguised as a health pickup, but once a player gets close it explodes!

Start with a campaign

Let's start with a blank campaign. This one is very basic and will simply let us try the weapon out. There are a few scattered map objects that we can blow up.

The campaign itself will be a folder, inside there are these three files:

Add guns.json and bullets.json

Custom weapons start with guns, defined in a guns.json file. Go ahead and add this, with the following contents:

{
  "Version": 1,
  "Guns": [
    {
      "Name": "My Gun",
      "Bullet": "my_bullet"
    }
  ]
}

And create a bullets.json file too, with the following contents:

{
  "Version": 1,
  "Bullets": [
    {
      "Name": "my_bullet"
    }
  ]
}

You can see what's going on here: the gun we've made will shoot the bullet we've made, by referring to it by the same name. The bullet name doesn't show up anywhere else so it doesn't really matter what we name it, as long as it's unique.

If you open the campaign up in the editor, you should see that this gun already shows up in the "Available weapons" section:

At this point we can actually load this campaign up in game, and try out our new weapon...

... and it does nothing except make a lot of noise. We need to fill out those gun and bullet attributes now.

Add basic attributes

There's a big list of gun and bullet attributes here. No matter what weapon you make however, you'll probably want to change these:

For the guns (guns.json):

  • Cost: how much score each shot costs
  • Lock: how much time between shots, in terms of game ticks. This controls rate of fire.
  • Sound: the sound that this gun makes. Different guns should make different sounds!

For the bullets (bullets.json):

  • Pic: probably the most important, what the bullet will look like. There's actually several different types of structures you can use here, from basic images to animations. The most common types would be "Normal" and "Directional".
  • Speed
  • Range: how much time, in terms of game ticks, this bullet stays alive for.
  • Power: a.k.a. damage

Let's add some of those attributes now:

guns.json

{
  "Version": 1,
  "Guns": [
    {
      "Name": "My Gun",
      "Bullet": "my_bullet",
      "Cost": 6,
      "Lock": 100,
      "Sound": "launch"
    }
  ]
}

bullets.json

{
  "Version": 1,
  "Bullets": [
    {
      "Name": "my_bullet",
      "Pic": {
        "Type": "Normal",
        "Pic": "molotov"
      },
      "Speed": 400,
      "Range": 60,
      "Power": 0
    }
  ]
}

We're getting somewhere now.

More attributes

Let's give the gun some more character. We want to make a gun that shoots a bouncing projectile that deploys into a booby trap. Let's work on the first part: getting the bouncing projectile. Here are the attributes we'll need:

guns.json

  • ReloadLead, ReloadSound: since the gun takes a long time to reload, it'll be nice to add a sound that plays just before the gun is ready to fire again.
  • Recoil: this adds a bit of random inaccuracy to the gun, which makes it feel more like it's launching a heavy, nonaerodynamic projectile.
  • Elevation: this tells the gun to shoot upwards (or downwards).

bullets.json

  • ShadowSize: as the bullet will be falling, it's nice to show this with a shadow. This attribute both enables the shadow and specifies a size, which should match the size of the bullet.
  • Size: this affects the collision size of the bullet.
  • Spark: this is a short-lived sprite that shows whenever the bullet hits something - walls, objects, players - but since this bullet will act like a bouncing grenade, we don't want any sparks.
  • HitSounds: the sounds that will play when this bullet hits something. We'll want sounds that sound like bouncing here.
  • WallBounces: the bullet should bounce off walls
  • HitsObjects: the bullet should ignore objects and simply go through them
  • Falling: this describes whether the bullet will fall with gravity and how. We just want regular gravity so we'll want a GravityFactor of 1, Bounces so that the bullet bounces off the ground instead of getting destroyed.

Let's put those values in and see what we get:

guns.json

{
  "Version": 1,
  "Guns": [
    {
      "Name": "My Gun",
      "Bullet": "my_bullet",
      "Cost": 6,
      "Lock": 100,
      "Sound": "launch",
      "ReloadSound": "package_r",
      "ReloadLead": 15,
      "Recoil": 0.4,
      "Elevation": 20
    }
  ]
}

bullets.json

{
  "Version": 1,
  "Bullets": [
    {
      "Name": "my_bullet",
      "Pic": {
        "Type": "Normal",
        "Pic": "molotov"
      },
      "Speed": 400,
      "Range": 60,
      "Power": 0,
      "ShadowSize": [4, 3],
      "Size": [4, 4],
      "Spark": "",
      "HitSounds": {
        "Object": "",
        "Flesh": "",
        "Wall": "bounce"
      },
      "WallBounces": true,
      "HitsObjects": false,
      "Falling": {
        "GravityFactor": 1,
        "Bounces": true
      }
    }
  ]
}

Custom graphics and sounds

You are not limited to the built-in sounds and graphics; you can provide your own inside custom campaigns. All graphics should go in a graphics/ subfolder, and sounds in sounds/, and they are referred to by file name (without extension). Sprite sheets are also supported but must be named with the frame width and height in the file name, in the form of filename_WxH.ext. Let's go through these by adding some custom graphics/sound attributes.

guns.json

  • Sound: let's give the gun a unique sound, to make it sound more like launching something out of a pipe. We'll use an uncorking sound slowed down.
  • MuzzleFlashParticle: to further reinforce the launcher idea, we'll use a custom muzzle flash that's long and thin. As the name suggests though, this will refer to a particle, which is specified in a particles.json file, described a bit later.

bullets.json

  • Pic: let's change our bullet picture, to an animation to give it more interest. We'll use a rotating crystal animation, resized to suit.

particles.json

This will be the perfect time to introduce particles. Particles are temporary images or animations that appear in the game, which mostly has no effect on gameplay. It is used for many things - brass, blood splatter, sparks - but in this exercise, it will be used for the muzzle flash. The muzzle flash special in that it requires a directional particle - one with 8 frames, one for each direction in the game, starting from up and continuing clockwise.

Create a particles.json file, alongside the other json files, and fill it with the following contents:

{
  "Version": 1,
  "Particles": [
    {
      "Name": "muzzle_flash_my_gun",
      "Sprites": "muzzle_flash_thin",
      "Mask": "ccccff",
      "Range": 5
    }
  ]
}

Sprites is what the image file will be named, minus the width/height and extension parts. Mask is a hexadecimal number representing RGB - here we're using a slight blue tint. Range is how many game ticks this particle will live for.

Here's what the muzzle flash image itself looks like:

Let's look at the files we should have now:

Note that the .txt files are not necessary - they contain license information.

guns.json

{
  "Version": 1,
  "Guns": [
    {
      "Name": "My Gun",
      "Bullet": "my_bullet",
      "Cost": 6,
      "Lock": 100,
      "Sound": "bottle_pop",
      "ReloadSound": "package_r",
      "ReloadLead": 15,
      "Recoil": 0.4,
      "Elevation": 20,
      "MuzzleFlashParticle": "muzzle_flash_my_gun"
    }
  ]
}

bullets.json

{
  "Version": 1,
  "Bullets": [
    {
      "Name": "my_bullet",
      "Pic": {
        "Type": "Animated",
        "Sprites": "crystal",
        "TicksPerFrame": 8
      },
      "Speed": 400,
      "Range": 60,
      "Power": 0,
      "ShadowSize": [4, 3],
      "Size": [4, 4],
      "Spark": "",
      "HitSounds": {
        "Object": "",
        "Flesh": "",
        "Wall": "bounce"
      },
      "WallBounces": true,
      "HitsObjects": false,
      "Falling": {
        "GravityFactor": 1,
        "Bounces": true
      }
    }
  ]
}

Bullets that shoot more bullets

Now for the interesting part: we want the bullet to deploy a booby trap at the end. To facilitate this, we can have the bullets fire pseudo-guns, which in turn fire bullets themselves. This way we can get complex guns like grenades and explosions. The way this ties together is this:

  • Our main gun fires a grenade
  • The grenade, at end of its range, fires a gun that deploys a single booby trap
  • The booby trap (which is a special bullet) has a proximity trigger, that when triggered fires an explosion gun
  • The explosion gun in turn fires a bunch of explosion fireballs

To make things easier, we'll just reuse the fire explosion built in the game, as used by weapons like the molotov. Of course you can provide your own custom weapons if you want to. This means we need to add two things: the booby trap gun, and the booby trap bullet.

For our bullet, we'll need this new attribute:

  • OutOfRangeGuns: these are the guns that will fire when the bullet goes out of range. We'll want it to fire the booby trap gun.

For the booby trap gun, we'll need the following new attributes:

  • MuzzleHeight: this determines the height above ground that the bullet will shoot out from. Normally this is the height of the player's barrel, which is 10. 0 is on the ground, and is what we'll use.

Also note that we'll need to add this gun in a different section in JSON: "PseudoGuns" instead of "Guns". This way it won't show up in weapon menus.

For the booby trap itself, these attributes:

  • Range: set this to -1, which means this bullet never goes out of range.
  • Persists: so this bullet stays alive even if touched by players or objects.
  • ProximityGuns: these are the guns that will fire when a player comes within 1 tile distance away from this bullet. We want the booby trap to set off a fire explosion.

This would also be a good time to use better names for all our guns and bullets! (Note that if you rename the weapon after it's already being used in missions, you'll need to add them again in the editor.)

Here's our final files:

guns.json

{
  "Version": 1,
  "Guns": [
    {
      "Name": "Booby Trap",
      "Bullet": "booby_trap_pod",
      "Cost": 6,
      "Lock": 100,
      "Sound": "bottle_pop",
      "ReloadSound": "package_r",
      "ReloadLead": 15,
      "Recoil": 0.4,
      "Elevation": 20,
      "MuzzleFlashParticle": "muzzle_flash_thin"
    }
  ],
  "PseudoGuns": [
    {
      "Name": "booby_trap_deployer",
      "Bullet": "booby_trap",
      "Sound": "puff",
      "MuzzleHeight": 0
    }
  ]
}

bullets.json

{
  "Version": 1,
  "Bullets": [
    {
      "Name": "booby_trap_pod",
      "Pic": {
        "Type": "Animated",
        "Sprites": "crystal",
        "TicksPerFrame": 8
      },
      "Speed": 400,
      "Range": 60,
      "Power": 0,
      "ShadowSize": [4, 3],
      "Size": [4, 4],
      "Spark": "",
      "HitSounds": {
        "Object": "",
        "Flesh": "",
        "Wall": "bounce"
      },
      "WallBounces": true,
      "HitsObjects": false,
      "Falling": {
        "GravityFactor": 1,
        "Bounces": true
      },
      "OutOfRangeGuns": [
        "booby_trap_deployer"
      ]
    },
    {
      "Name": "booby_trap",
      "Pic": {
        "Type": "Normal",
        "Pic": "health"
      },
      "Range": -1,
      "Persists": true,
      "ProximityGuns": [
        "fire_explosion"
      ]
    }
  ]
}

Et voila! Good luck in making your own custom weapons!

The booby trap weapon is available in the mission techdemo/funwithguns.cdogscpn.