Difference between revisions of "Mutator Class"

From Oldunreal-Wiki
Jump to navigation Jump to search
(fixed code wrapping)
Line 84: Line 84:
|}
|}
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(). Let's start with a simple mutator of mine for an example.
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(). Let's start with a simple mutator of mine for an example.
 
<code>
  // Spectre
  // Spectre
  // A modification of GhostBoy example provided online
  // A modification of GhostBoy example provided online
 
  class Spectre extends Mutator;
  class Spectre extends Mutator;
 
  var bool Initialized;
  var bool Initialized;
 
  function PostBeginPlay()
  function PostBeginPlay()
  {
  {
   if (Initialized) return;
   if (Initialized) return;
 
   Initialized = True;
   Initialized = True;
 
   Level.Game.RegisterDamageMutator(Self);
   Level.Game.RegisterDamageMutator(Self);
  }
  }
 
  function ScoreKill(Pawn Killer, Pawn Other)
  function ScoreKill(Pawn Killer, Pawn Other)
  {
  {
Line 109: Line 109:
     Other.ScaleGlow = 1.5;
     Other.ScaleGlow = 1.5;
  }
  }
 
   // we have a kevorkian, give him his dues
   // we have a kevorkian, give him his dues
   if ((Other != None) && ((Killer == None) || (Killer == Other))) Other.ScaleGlow = 1.5;
   if ((Other != None) && ((Killer == None) || (Killer == Other))) Other.ScaleGlow = 1.5;
 
   // set visibility so bots react appropriately
   // set visibility so bots react appropriately
   Other.Visibility = Other.Default.Visibility * Other.ScaleGlow;
   Other.Visibility = Other.Default.Visibility * Other.ScaleGlow;
   Killer.Visibility = Killer.Default.Visibility * Killer.ScaleGlow;
   Killer.Visibility = Killer.Default.Visibility * Killer.ScaleGlow;
 
   // call our parent class counter-part function
   // call our parent class counter-part function
   Super.ScoreKill(Killer, Other);
   Super.ScoreKill(Killer, Other);
  }
  }
 
  function bool CheckReplacement( actor Other, out byte bSuperRelevant)
  function bool CheckReplacement( actor Other, out byte bSuperRelevant)
  {
  {
   // Players, bots and carcasses (including gibs) need to be translucent.
   // Players, bots and carcasses (including gibs) need to be translucent.
   if ( Other.IsA('Pawn') || Other.IsA('Carcass')) Other.Style = STY_Translucent;
   if ( Other.IsA('Pawn') || Other.IsA('Carcass')) Other.Style = STY_Translucent;
 
   // Invisibility pickups mess with our Visibility settings.
   // Invisibility pickups mess with our Visibility settings.
   // We'll just get rid of them completely...
   // We'll just get rid of them completely...
   if (Other.IsA('Invisibility')) return false;
   if (Other.IsA('Invisibility')) return false;
 
   return true;
   return true;
  }
  }
 
  function MutatorTakeDamage(out int ActualDamage, Pawn Victim, Pawn InstigatedBy, out Vector HitLocation, out Vector Momentum, name DamageType)
  function MutatorTakeDamage(out int ActualDamage, Pawn Victim, Pawn InstigatedBy, out Vector HitLocation, out Vector Momentum, name DamageType)
  {
  {
   local float dglow;
   local float dglow;
 
   // reduce victim's glowing
   // reduce victim's glowing
   dglow = float(ActualDamage) / 70.0;
   dglow = float(ActualDamage) / 70.0;
Line 142: Line 142:
   Victim.ScaleGlow -= dglow;
   Victim.ScaleGlow -= dglow;
   if (Victim.ScaleGlow <= 0.1) Victim.ScaleGlow = 0.1;
   if (Victim.ScaleGlow <= 0.1) Victim.ScaleGlow = 0.1;
 
   // raise glow of attacker
   // raise glow of attacker
   if (InstigatedBy != Victim) InstigatedBy.ScaleGlow += dglow;
   if (InstigatedBy != Victim) InstigatedBy.ScaleGlow += dglow;
 
   // set visibility so bots react appropriately
   // set visibility so bots react appropriately
   Victim.Visibility = Victim.Default.Visibility * Victim.ScaleGlow;
   Victim.Visibility = Victim.Default.Visibility * Victim.ScaleGlow;

Revision as of 13:50, 23 February 2014

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).

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(). 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);
} 

The 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.