| Home Page | Recent Changes

Weapon Modification (UT)

This page is one of a series of UnrealScript Lessons.

Introduction

This is my first UnrealScript Tutorial.

This tutorial assume that you have basic UnrealScript knowledge.

Weapon Modification: Faster Sniper Rifle

You will learn how to modify a standard Weapon, in this case the Sniper Rifle, for the original Unreal Tournament. Here, we will try to enhance the Sniper Rifle to make it shoot faster. Some modifications will be made on the new weapon's ammo for conveniance.

Two classes will be created:

SniperRifle >> FastRifle
The sniper rifle modification class
Mutator >> FastRifleMutator
The mutator class to replace stuff

FastRifle.uc

class FastRifle extends SniperRifle; // We are modifying the Sniper Rifle


var float fRifleAnimRate; // Custom rifle animation rate multiplier


// Play firing sound and animation (override PlayFiring() in SniperRifle)
simulated function PlayFiring() {
    PlayOwnedSound( FireSound, SLOT_None, Pawn(Owner).SoundDampening * 3.0 );
    PlayAnim( FireAnims[Rand(5)], fRifleAnimRate, 0.05 );

    if ( ( PlayerPawn(Owner) != None ) && ( PlayerPawn(Owner).DesiredFOV == PlayerPawn(Owner).DefaultFOV ) )
        bMuzzleFlash++;
}


defaultproperties
{
    fRifleAnimRate=6.0   // Custom rifle animation rate multiplier
    PickupAmmoCount=40   // Defined in SniperRifle class Default = 8
}

class FastRifle extends SniperRifle;

To get access to its functions and properties, we must subclass the SniperRifle class. Our new weapon is now the same as the SniperRifle.

var float fRifleAnimRate;

This is a new variable we create here to store animation rate multiplier. I will talk about it in details in the following sections.

PlayFiring()

This function is declared in TournamentWeapon, the parent class of the SniperRifle.

It is overriden in the SniperRifle class of the Botpack package:

simulated function PlayFiring() {
    PlayOwnedSound(FireSound, SLOT_None, Pawn(Owner).SoundDampening*3.0);
    PlayAnim(FireAnims[Rand(5)], 0.5 + 0.5 * FireAdjust, 0.05);

    if ( (PlayerPawn(Owner) != None) && (PlayerPawn(Owner).DesiredFOV == PlayerPawn(Owner).DefaultFOV) )
        bMuzzleFlash++;
}

Basically, PlayFiring() is called when you press the Fire button and it is called again and again as long as you hold the fire button and the current weapon still contains some ammos.

The interesting part here is the PlayAnim() function. It is defined in the Actor class:

PlayAnim (name Sequence, optional float Rate, optional float TweenTime)
Plays an Animation.

Sequence: Anim sequence Name.
Rate: Animation Rate multiplier.
TweenTime: Amount of Time to "tween" into the first frame of this animation sequence if in a different sequence.

This function plays the given Sequence. The Rate parameter is a multiplier. That means the animation will be played Rate times faster than normal. The faster the animation is played, the sooner PlayFiring() will be called again. :)

The FireAdjust variable is defined in TournamentWeapon and will always be 1.0 if Pawn is not a Bot. Since we don't want the bots to shoot at a different Rate than us, we will get rid of this variable in the animation rate and replace it with 1.0. Then now, 0.5 + 0.5 * 1.0 = 1.0, the default firing rate is 1.0.

So, we need to overrides PlayFiring() in order to modify this animation Rate multiplier. The new function will be:

simulated function PlayFiring() {
    PlayOwnedSound( FireSound, SLOT_None, Pawn(Owner).SoundDampening * 3.0 );
    PlayAnim( FireAnims[Rand(5)], fRifleAnimRate, 0.05 );
    if ( ( PlayerPawn(Owner) != None ) && ( PlayerPawn(Owner).DesiredFOV == PlayerPawn(Owner).DefaultFOV ) )
        bMuzzleFlash++;
}

The only difference with our new function is the Rate of the PlayAnim() function. This was a fixed value of 1.0, and now it is set to our new fRifleAnimRate variable.

defaultproperties

Here we define a new property and we override an existing one.

fRifleAnimRate
Modify fRifleAnimRate value to change firing speed.
I do not recommend setting higher than 30.0. Anyway, number of ammo will be largely insufficient for the firing speed.

SniperRifle: 1.0, Epic Original SniperRifle
AssaultRifle: 5.0, Zark AssaultRifle
CyberRifle: 9.0, Ramx CyberRifle

PickupAmmoCount
Modify the initial number of ammo.
Since our new weapon is faster than the standard SniperRifle, it would be wise to raise the initial number of ammos the weapon contains when picked up.
Our weapon uses BulletBox ammo type, that support a MaxAmmo count of 50, so setting an initial ammo count higher than 50 would cause some illogical behaviors... excepts if you subclass BulletBox to modify his defaultproperties.

For more weapon properties, see Default Properties For Weapons.

FastRifleMutator.uc

class FastRifleMutator extends Mutator;


// Only allow one instance of this mutator.
function AddMutator(Mutator M) {
    if ( M != Self )
        Super.AddMutator(M);
}


// Do not allow FastRifle to be replaced or removed.
function bool AlwaysKeep(Actor Other) {
    if( Other.IsA('FastRifle') )
        return true;
    return Super.AlwaysKeep(Other);
}


// Replace the default weapon with FastRifle when a player spawn.
function ModifyPlayer(Pawn Other) {
    DeathMatchPlus(Level.Game).GiveWeapon( Other, "FastRifle.FastRifle" );
    Super.ModifyPlayer(Other);
}


// Replace SniperRifle with the FastRifle.
function bool CheckReplacement(Actor Other, out byte bSuperRelevant) {
    if ( Other.IsA('Weapon') ) {
        if ( Other.IsA('SniperRifle') ) {
            ReplaceWith( Other, "FastRifle.FastRifle" );
            return false;
        }
    }
    return true;
}

class FastRifleMutator extends Mutator;

This is added to the mutator list and will be used to replace any SniperRifle in the game with our new FastRifle.

AddMutator()

This will prevent this mutator to try adding himself recursively.

AlwaysKeep()

This will prevent your new weapon to be replaced or removed by another mutator or mod and also avoid to get an endless recursive loop in CheckReplacement(), because our new weapon IsA SniperRifle.

ModifyPlayer()

This function allow to init some stuff when the player spawn. We might want to give the FastRifle as main weapon when spawning.

This is not recommended behavior, but you can add some way to disable this, like configuration files or such.

CheckReplacement()

This will Check for the presence of any Actor and allow replacement with ReplaceWith(). This is where we will actually replace all original SniperRifle in the current game with our new customized FastRifle.

Conclusion

Now compile the package that contains those 2 classes and start a game with this mutator. I'm not sure about network compatibility, i'm new to UnrealScript and need to learn more on replication.

Related Topics

Comments

Ramx: OK, so it should be complete. Please correct me if I am wrong. :)

Newbie notes (by cla):

The needed .int must be called FastRifle.int, and have only two lines:

   [Public]
   Object=(Name=FastRifle.FastRifleMutator,Class=Class,MetaClass=Engine.Mutator,Description="Fast Rifle Replacement.")
 

To see this mutator you must be starting a DM or TDM game. By example,It wont be visible starting a CTF game.Thats because the line DeathMatchPlus(Level.Game).GiveWeapon( Other, "FastRifle.FastRifle" );

For the code to work the package must be called FastRifle, thats the same as say 'the .uc files must be under $UTdir\FastRifle\Classes'

If you want to change the package name, say to 'FARifle', then

   put the .uc files under $UTdir\FARifle\Classes 
   change all ocurrences of 'FastRifle.FastRifle' to 'FARifle.FastRifle' in the .uc files
   change 'FastRifle.FastRifleMutator' to 'FARifle.FastRifleMutator' in the .int file
   rename the .int file to 'FARifle.int'

Category Tutorial

The Unreal Engine Documentation Site

Wiki Community

Topic Categories

Recent Changes

Offline Wiki

Unreal Engine

Console Commands

Terminology

FAQs

Help Desk

Mapping Topics

Mapping Lessons

UnrealEd Interface

UnrealScript Topics

UnrealScript Lessons

Making Mods

Class Tree

Modeling Topics

Chongqing Page

Log In