Unreal Tournament 2004 Explosive Ammo Mutator

Download for the impatient.

Introduction

Back in the day, someone wrote an Explosive Ammo mutator which made all of the ammo clips sitting on the ground blow up and shoot rockets or bullets or goo or schrapnel all over the place when you shot them. We found that mutator very amusing and it is sadly missed in the latest in the UT series: UT2004.

Since we're reasonably intelligent hackers, Brian Vargas and I decided that we couldn't live without this mutator and set out to develop our own. Having not done any Unreal scripting since the original Unreal Tournament, we were a little rusty. This page describes our journey and presents the Explosive Ammo Mutator to the world.

First of all, our knowledge of mutators and, honestly, the whole scripting engine is minimal, so if something we're doing seems really stupid, please let us know. We'd like to do this the "right way", but we'll get it done any way that works for now.

The Plan

Our basic plan was to replace all of the ammo clips in the game with our own, which would simply 'wrap' existing ammo types with our exploding ones. The exploding ammo class would be sensitive to taking damage, and pretty much just generate a lot of flying death of the proper type when shot.

There are a few problems with our master plan. First, although Unreal Script is very object-oriented, there are still these 'properties' that classes can have, and we don't get to intercept get/set operations on those peoperties, so we can't actually wrap any existing ammo class with a generic exploding one: we have to create a new exploding ammo clip for each known type of clip. This sucks, because it won't extend to new ammo types without a code change. Perhaps if we're smart enough to read a config file, we could do these on the fly and so we'd only have to change a config file instead of the actual code. We'll see.

The second problem is that not all ammo works the same. There are some types of ammo which act like we thought they would: you can create an object of, say, the Rocket type, and send it off in any direction at any speed. No problem: just send off a bunch of them and let 'em go. Well, that works fine for things like rockets, link goo, and flak balls. However, ammunition for the assult rifle, lightning gun, minigun, etc. have different types of ammo that don't work that way.

The Implementation

Since ammo types are not generic, we decided to replace each ammo pickup with a subclass of the original. We would just override the appropriate behaviors and go with it. While this minimizes our opportunities for code-reuse, we figured it wasn't a big deal because the standard types of ammo are well-defined and aren't likely to change. Also, using this technique will not interfere with other mutators or even if new ammo types are added. (It will, however, totally crap itself if some ammo type is removed from the game. The liklihood of this happening, though, is ... low).

Projectiles

As I mentioned, projectiles (rockets, flak clunks, grenades, mines, etc.) are all very easy to do : you simple spawn a projectile pointing in a particular direction with a speed vector, etc. and off it goes. Here's the actual code for doing this:

local Projectile projectile;

projectile = ammo.Spawn(class'BioGlob', ammo, , ammo.Location, ammo.RotRand());

The Spawn method is defined in the Actor class, and takes the following arguments:

  1. The class to instantiate. The example here is for bio-gun goo.
  2. The 'owner' of the projectile. For projectiles that do damage, this ends up being the Actor who gets credit for the damage that may be caused by the projectile.
  3. The 'spawn tag' (left out in this example). I have no idea what this is.
  4. The location where the projectile should be spawned. For most ammo, we want the origin of the projectiles to be the same as the ammo pickup itself, so we use the ammo's location.
  5. The rotator that indicates the direction vector of the projectile. We use the RotRand function (defined in Object) to pick a random direction for the new projectile.

Hit-Scan Weapons

After projectiles, all other weapons do their own dirty-work. That means that when you fire the weapon, the damage is done instantaneously to any targets that are found. The weapon (the minigun, for example) actually follows lines outward, looking for hits. When it finds a hit, it will either damage the target (like a person or vehicle) or produce some effect (like a bullet ricochet or burn mark on a wall).

For these types of ammo, we have performed our own hit-scans in multiple, random directions. Here's the code that fires the weapon once:

local Actor other;
local Vector hitLocation, hitNormal, endLocation, direction, momentum;
local Rotator fireRotation;
local int damage;

fireRotation = RotRand();
direction = Vector(fireRotation);

other = self.Trace(hitLocation, hitNormal, endLocation, self.Location, true);
      
if (other == none)
{
   // Missed everything == hit the sky
   hitLocation = endLocation;
   hitNormal   = Normal(self.Location - endLocation);
}
else if (!other.bWorldGeometry && other != self)
{
   // We've hit something other than the "world" or the ammo pickup itself
   damage = class'UTClassic.ClassicSniperFire'.default.DamageMin
             + Rand(class'UTClassic.ClassicSniperFire'.default.DamageMax
               - class'UTClassic.ClassicSniperFire'.default.DamageMin);

   momentum = hitNormal * class'UTClassic.ClassicSniperFire'.default.Momentum;

   // Inflict damage on the player
   other.TakeDamage(damage, self.Instigator, hitLocation, momentum, class'DamTypeClassicSniper');
}

To make things feel "better", we have added a few other features to these ammo pickups:

Downloads

Download

Here's the mutator as it stands right now. It currently handles all ammo types that have pickups (that's pretty much everything except for the Redeemer, tank shells, etc.).

To install, put the files ExplosiveAmmo.u and ExplosiveAmmo.int in the System directory of your UT2004 installation.

Installation on a server is somewhat more involved, and I'll put some instructions here shortly.

The source code is also available.

Screenshots

Early in the development of this mutator, I was testing out a feature that I found amusing: generating perverse quantities of flying ammo when explosing an ammo pickup.

I tried this with the bio-rifle ammo and things ended poorly for me.

Bio-Goop explosion, frame 1 Bio-Goop explosion, frame 2 Bio-Goop explosion, frame 3 Bio-Goop explosion, frame 4 Bio-Goop explosion, frame 5

I got a horrible frame-rate, even on my P4 3GHz(ht). We're talking 0.5 fps or so. Maybe it was worse. I can't remember. It was too funny.

Code Samples

(coming soon)

Valid HTML 4.01! Valid CSS!