Sniper's Paradise!


Mutator Class

The Mutator class extends the Info class. The following are all the variables (and their purposes that I've discerned) and function members and their purposes (that I've discerned).

Contents
Variable members
var Mutator NextMutator This is the next generic mutator object in the list of generic   mutators
var Mutator NextDamageMutator This is the next damage mutator object in the list of damage mutators
var Mutator NextHUDMutator This is the next HUD mutator object in the list of HUD mutators
var bool bHUDMutator This bool is a flag for whether or not the mutator is a HUDMutator
var class<Weapon> DefaultWeapon Not sure exactly what this is good for, but an educated guess leads me to believe that if set, this var will override any other set default weapon for the level/game (via MutatedDefaultWeapon() and MyDefaultWeapon(), of which I've never used either)
Function members
event PreBeginPlay() This is called before gameplay starts.
simulated event PostRender(canvas Canvas) Called every tick of gameplay *on the machine which starts this mutator* - i.e. this is will not work over network play. See below for further information on HUD mutators.
function ModifyPlayer(Pawn Other) Called whenever a player joins the game. Other references the player's pawn object
function ScoreKill(Pawn Killer, Pawn Other) If a kill is made, this function is called, passing a reference to the Killer (person who scored) and Other (the victim who died). Note - this function is called right on the tick of the kill, before any rendering or other processing has taken place.
function Class<Weapon> MutatedDefaultWeapon() Returns the default weapon taking into account other mutators.
function Class<Weapon> MyDefaultWeapon() Called by MutatedDefaultWeapon() to get what the default weapon for this mutator is.
function AddMutator(Mutator M) Adds the mutator M to the game's mutator list. Normally, this call is not necessary for a generic mutator.
function bool ReplaceWith(Actor Other, string aClassName) Replaces the Actor class object Other with another Actor class object whose name is aClassName. This is not called automatically by the mutator.
function bool AlwaysKeep(Actor Other) Called by UT when an actor is going to be destroyed. By returning true, Other won't be destroyed. Default is false.
function bool IsRelevant(Actor Other, out byte bSuperRelevant) Checks to see if mutators will allow this object to be changed. I'm not certain what purpose bSuperRelevant has yet.
function bool CheckReplacement(Actor Other, out byte bSuperRelevant) Called by IsRelevant to determine whether or not the Actor class object Other should be replaced. I'm not certain what purpose bSuperRelevant has yet.
function Mutate(string MutateString, PlayerPawn Sender) Called when players enter commands. Allows mutator to add commands.
function MutatorTakeDamage(out int ActualDamage, Pawn Victim, Pawn InstigatedBy, out Vector HitLocation, out Vector Momentum, name DamageType) Called whenever a player takes damage. Note - this function is called before any damage processing is done to allow mutators to change (or play with) the damage dealt or hit location.
simulated function RegisterHUDMutator() This registers the mutator as a HUD mutator so that it will receive the PostRender call.

Notice that there are only 5 variable and 14 function members to this class. However, since it extends the Info class (which extends the Actor class), we have access (through class inheritance) to many many MANY more variables and functions. The most important of which would probably be PostBeginPlay().

Example

Let's start with a simple mutator of mine for an example.

// Spectre
// A modification of GhostBoy example provided online

class Spectre extends Mutator;
 
var bool Initialized;
 
function PostBeginPlay()
{
  if (Initialized) return;
 
  Initialized = True;
 
  Level.Game.RegisterDamageMutator(Self);
}
 
function ScoreKill(Pawn Killer, Pawn Other)
{
  // we have a winner, bump up his glowing and reset the victims'
  if ((Killer != Other) && (Other != None) && (Killer != None))
  {
    Killer.ScaleGlow += 0.2;
    Other.ScaleGlow = 1.5;
  }

  // we have a kevorkian, give him his dues
  if ((Other != None) && ((Killer == None) || (Killer == Other))) Other.ScaleGlow = 1.5;
 
  // set visibility so bots react appropriately
  Other.Visibility = Other.Default.Visibility * Other.ScaleGlow;
  Killer.Visibility = Killer.Default.Visibility * Killer.ScaleGlow;
 
  // call our parent class counter-part function
  Super.ScoreKill(Killer, Other);
}
 
function bool CheckReplacement( actor Other, out byte bSuperRelevant)
{
  // Players, bots and carcasses (including gibs) need to be translucent.
  if ( Other.IsA('Pawn') || Other.IsA('Carcass')) Other.Style = STY_Translucent;
 
  // Invisibility pickups mess with our Visibility settings.
  // We'll just get rid of them completely...
  if (Other.IsA('Invisibility')) return false;
 
  return true;
}
 
function MutatorTakeDamage(out int ActualDamage, Pawn Victim, Pawn InstigatedBy, out Vector HitLocation, out Vector Momentum, name DamageType)
{
  local float dglow;
 
  // reduce victim's glowing
  dglow = float(ActualDamage) / 70.0;
  if (dglow <= 0.1) dglow = 0.1;
  Victim.ScaleGlow -= dglow;
  if (Victim.ScaleGlow <= 0.1) Victim.ScaleGlow = 0.1;
 
  // raise glow of attacker
  if (InstigatedBy != Victim) InstigatedBy.ScaleGlow += dglow;
 
  // set visibility so bots react appropriately
  Victim.Visibility = Victim.Default.Visibility * Victim.ScaleGlow;
  InstigatedBy.Visibility = InstigatedBy.Default.Visibility * InstigatedBy.ScaleGlow;
  Super.MutatorTakeDamage(ActualDamage, Victim, InstigatedBy, HitLocation, Momentum, DamageType);
} 
Breakdown

Let's start from the top and work our way down. First is our class declarator. Specifically, we are subclassing (extending) the Mutator class. Then there are the variable declarations. All variables declared outside the functions are global and static to the object from the point of it's creation.

Next is the function PostBeginPlay(). PostBeginPlay() is called right after the game is fully ready to begin (all objects init'd / created / managed) and the game will start right after we return from this (well, as soon as all classes return from this). However, with the mutator class, PostBeginPlay() is called twice. In order to avoid doing our initialization code more than once, we use a global bool to flag our init'd state or not. The only initialization we handle is registering our mutator as a damage mutator, so that the level will call our MutatorTakeDamage() function. As a good practice (albeit necessary one), initialize all your global vars in PostBeginPlay(). Even though objects are initialized by the engine automatically, never assume your vars have a particular value (this is a good lesson to learn - do paranoia checks on variables just as a matter of safegaurding against potential bugs).

Next is the function ScoreKill(). Every mutator type has this function called. This is the best place to do anything you want to two specific player pawns - the killer and the victim. Players do not have their objects deleted when they die, only reset. However, only certain properties (variables) are reset when a player respawns (by the engine). This is where you want to reset/modify/tweak whatever variables in the player's pawns that you're playing with.

Now we have CheckReplacement(). This function is called for every actor in the level. If there is a particular actor class object that you do not want in the level no matter what, this is the convenient place to do it. By returning false, you are telling UT to get rid of the actor. Finally, we have the beef of the mutator, MutatorTakeDamage(). Since we registered the mutator as a damage mutator up in PostBeginPlay(), every time a pawn *is about to take damage* this function is called. This allows you to change the damage dealt to the pawn, where it was hit, or process other things based on the information passed to the function, such as changing the translucency of the pawn based on how much damage was taken.



Spam Killer

Back To Top
2005 Sniper's Paradise
All logos and trademarks are properties of their respective owners.
Unreal™ is a registered trademark of Epic Games Inc.
Privacy Policy
Website by Softly
Powered by RUSH