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 aMaxAmmo
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
- UnrealScript Lessons – UnrealScript tutorials
- UnrealScript – UnrealScript reference pages
- Mutator Topics – Topics on mutators
- Creating A New Weapontype – more on weapon creation/modification
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'