| Home Page | Recent Changes | Preferences

# Useful Mutator Functions

Some useful Mutator (UT) functions. The code on this page probably doesn't work at all in UT2003.

## HUD Mutators

> "How do I register a HUD mutator?"

> "Why doesn't my HUD mutator work in online/LAN games?"

This is a sample HUD mutator which does nothing more that registering itself and showing, how to get a reference to the local PlayerPawn and the HUD (UT).

    class MyHUDMutator extends Mutator;

    var PlayerPawn MyPlayer;
    var HUD MyHUD;

    simulated function Tick(float DeltaTime)
    {
        if ( !bHUDMutator && Level.NetMode != NM_DedicatedServer )
            RegisterHUDMutator();
    }

    simulated function PostRender(Canvas Canvas)
    {
        MyPlayer = Canvas.Viewport.Actor;
        if ( MyPlayer != None )
            MyHUD = MyPlayer.myHUD;

        // This is important! It allows the next HUD mutator to draw on the canvas.
        if ( NextHUDMutator != None )
            NextHUDMutator.PostRender(Canvas);
    }

    defaultproperties
    {
         RemoteRole=ROLE_SimulatedProxy
         bAlwaysRelevant=True
         bNetTemporary=True  // Set to false if you need to replicate data to the clients more than once per level
    }

Note: Don't use the code of the Team Beacon HUD mutator or the Relics. Team Beacon is far to complicated for this simple task and the RelicHUDMutator (apart from being incompatible to regular HUD mutators) calls its Destroy function without properly unregistering itself. (see Destructable Mutators below)

Note: If you want to execute code once client-side, but wish to do it after values have been replicated from the server to the client then used the PostNetBeginPlay() function.

Also see Netcode Idioms.

## Destructable Mutators

Never destroy a Mutator (UT) while it still is in any of the mutator chains. This would effectively disconnect all mutators further down in the list. If you really need to destroy a mutator make sure it was unregistered before destroying it.

The other possible solution is that the mutator unregisters itself:

    // correctly unregister this mutator from all linked mutator chains
    simulated function Destroyed()
    {
        local Mutator M;
        local HUD H;

        if ( Level.Game != None ) {
            if ( Level.Game.BaseMutator == Self )
                Level.Game.BaseMutator = NextMutator;
            if ( Level.Game.DamageMutator == Self )
                Level.Game.DamageMutator = NextDamageMutator;
            if ( Level.Game.MessageMutator == Self )
                Level.Game.MessageMutator = NextMessageMutator;
        }
        ForEach AllActors(Class'Engine.HUD', H)
            if ( H.HUDMutator == Self )
                H.HUDMutator = NextHUDMutator;
        ForEach AllActors(Class'Engine.Mutator', M) {
            if ( M.NextMutator == Self )
                M.NextMutator = NextMutator;
            if ( M.NextHUDMutator == Self )
                M.NextHUDMutator = NextHUDMutator;
            if ( M.NextDamageMutator == Self )
                M.NextDamageMutator = NextDamageMutator;
            if ( M.NextMessageMutator == Self )
                M.NextMessageMutator = NextMessageMutator;
        }
    }

## Replacing Inventory Items

The `ReplaceWith` function does its job in most cases, but not in all maps the items are placed with their default properties. Some have the rotation turned off (either `bRotatingPicklup=False`, which is the recommended way to do it, or `RotationRate.Yaw=0`) or float in mid-air though they normally fall down. (`Physics=PHYS_None` instead of `PHYS_Falling`)

Also mutator sometimes want to further adjust the properties of the item after spawning it.

The `ReplaceWithItem` function takes both into account: It modifies the new item's rotation and physics and returns it, so the mutator can modify its properties.

    // Modified version of the ReplaceWith function
    // Replaces an inventory Other with an inventory of class aClassName and
    // returns a reference to it
    final function Inventory ReplaceWithItem(Inventory Other, coerce string aClassName)
    {
        local Inventory A;
        local class<Inventory> aClass;
        local bool bAllowItemFall, bForceItemFall;
        local bool bAllowItemRotation, bForceItemRotation;

        if ( Other.Location == vect(0,0,0) )
            return None;
        aClass = class<Inventory>(DynamicLoadObject(aClassName, class'Class'));
        if ( aClass != None )
            A = Spawn(aClass, Other.Owner, Other.Tag,
                    Other.Location + (aClass.Default.CollisionHeight - Other.CollisionHeight) * vect(0,0,1),
                    Other.Rotation);

        if ( Other.MyMarker != None ) {
            Other.MyMarker.markedItem = A;
            if ( A != None )
                A.MyMarker = Other.MyMarker;
            Other.MyMarker = None;
        }
        else if ( A != None ) {
            A.bHeldItem = true;
            A.Respawntime = 0.0;
        }

        if ( A != None ) {
            if ( Other.Physics != Other.Class.Default.Physics ) {
                if ( Other.Physics == PHYS_Falling )
                    bForceItemFall = True;
                else if ( Other.Class.Default.Physics == PHYS_Falling )
                    bAllowItemFall = False;
            }
            if ( (!Other.bRotatingPickup || Other.RotationRate == rot(0,0,0))
                    && (Other.Rotation.Pitch != 0 || Other.Rotation.Roll != 0) )
                bAllowItemRotation = False;
            else
                bAllowItemRotation = (Other.RotationRate != rot(0,0,0) && Other.bRotatingPickup)
                        || !Other.default.bRotatingPickup || Other.default.RotationRate == rot(0,0,0);
            bForceItemRotation = Other.RotationRate != rot(0,0,0) && Other.bRotatingPickup
                    && (!Other.default.bRotatingPickup || Other.default.RotationRate == rot(0,0,0));

            if ( A.Physics == PHYS_Falling && !bAllowItemFall )
                A.SetPhysics(PHYS_None);
            else if ( A.Physics != PHYS_Falling && bForceItemFall )
                A.SetPhysics(PHYS_Falling);
            A.bRotatingPickup = bAllowItemRotation && (A.bRotatingPickup || bForceItemRotation);

            A.Event = Other.Event;
            A.Tag = Other.Tag;
            return A;
        }
        return None;
    }

## Giving Weapons To Players

This function is a modified version of the `DeathMatchPlus.GiveWeapon` function. It adds the weapon to the player's inventory and optionally brings it up as the players selected weapon. The function returns the weapon.

    // Give a weapon to a player and optionally bring it up as current weapon.
    function Weapon GiveWeapon(Pawn PlayerPawn, string aClassName, optional bool bBringUp)
    {
        local class<Weapon> WeaponClass;
        local Weapon NewWeapon;

        WeaponClass = class<Weapon>(DynamicLoadObject(aClassName, class'Class'));

        if ( PlayerPawn.FindInventoryType(WeaponClass) != None )
            return None;
        newWeapon = Spawn(WeaponClass);
        if ( newWeapon != None ) {
            newWeapon.RespawnTime = 0.0;
            newWeapon.GiveTo(PlayerPawn);
            newWeapon.bHeldItem = true;
            newWeapon.GiveAmmo(PlayerPawn);
            newWeapon.SetSwitchPriority(PlayerPawn);
            newWeapon.WeaponSet(PlayerPawn);
            newWeapon.AmbientGlow = 0;
            if ( PlayerPawn.IsA('PlayerPawn') )
                newWeapon.SetHand(PlayerPawn(PlayerPawn).Handedness);
            else
                newWeapon.GotoState('Idle');
            if ( bBringUp ) {
                PlayerPawn.Weapon.GotoState('DownWeapon');
                PlayerPawn.PendingWeapon = None;
                PlayerPawn.Weapon = newWeapon;
                PlayerPawn.Weapon.BringUp();
            }
        }
        return newWeapon;
    }

## Related Topics

- Open Source

Kuhal: I have a developed a way to allow a mutator to "appear" to handle Damage to players BEFORE Inventory.ReduceDamage is called. Shall I create a page for this and link to it from OpenSource or would it be better to create the page and link form my homepage until one of the guru's can comment on the content? I investigated this while helping someone on the forums who wanted it specifically for his SpawnProtection code.

Mychaeel: Would you describe that method in a few words? – By the way, I believe the sections on this page would be well worth individual pages; maybe subpages of this one.

Kuhal: Synopsis: Create an Inventory Item with Charge=0; ArmorAbsorption=0; AbsorptionPriority=1000; bIsAnArmor=true;. Override ArmorAbsorbDamage in new class to update member variables for use by the mutator. Make sure that the mutator deals out the damage accordingly because the REAL armor was not damaged in the hit. Has limited usefulness - Why oh why didn't EPIC give Inventory.ReduceDamage the Victim and InstigatedBy vars too? I'm interested in other ideas in this area so by all means hook me up. I have full working source for the SpawnProtection use if needed.

Csimbi: Could someone add an example of adding another mutator from a mutator that is already added? I want to have only one entry in the .int file for practical reasons (the one Mutator would add all the others), and I cannot figure out how to do it. I tried a couple of things, but none of those worked so far. Thank You in advance.

Foxpaw: Depending on what exactly you had in mind, that may be quite easy. Or it may be next to impossible. Do you mean, you only want the one entry in the mutator list and when play begins all the other mutators are added? Or do you mean you want all of them to show up in the mutator list, but only want one listed in the INT file?

Wormbo: Just Level.Game.BaseMutator.AddMutator(Spawn(theMutatorClass)) should do the trick, but why don't you just combine the mutators into a single class?

Csimbi:

Foxpaw, the idea is that one mutator adds all the others.

Wormbo, in which function do You call this? Prebeginplay, PostBeginPlay, or ?

Wormbo: Yes, call it from one of the *BeginPlay functions.

Csimbi: I do this in the Mutator's PostBeginplay: Level.Game.BaseMutator.AddMutator(Spawn(class'CustomTranslocator'));

The error message I get is: "Error, Call to 'AddMutator': type mismatch in parameter 1"

What am I doing wrong?

Wormbo: 'Type mismatch' compiler errors tell you that the function expects a different variable type than you used. This CustomTranslocator class of yours, it's a mutator subclass, isn't it?

Csimbi: My mistake. It's a TournamentWeapon. Changed class name to the mutator's class, and it works like a charm. Thank You.

The Unreal Engine Documentation Site

Wiki Community

Topic Categories

Image Uploads

Random Page

Recent Changes

Offline Wiki

Unreal Engine

Console Commands

Terminology

Mapping Topics

Mapping Lessons

UnrealEd Interface

Questions&Answers

Scripting Topics

Scripting Lessons

Making Mods

Class Tree

Questions&Answers

Modeling Topics

Questions&Answers

Log In