sega 500 mutators jeff “ezeikeil” giles [email protected] jgiles

57
Sega 500 Mutators Jeff “Ezeikeil” Giles [email protected]

Upload: jasper-williams

Post on 05-Jan-2016

213 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

Sega 500

Mutators

Jeff “Ezeikeil” [email protected]://gamestudies.cdis.org/~jgiles

Page 2: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

So far

We’ve created changes to the UT game play by modifying & creating our own content. HUD Weapons Game play / timing

However all our changes have been restricted to game types.

Page 3: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

Today

We’re going to look at an alternate method of changing how UT runs / plays, known as mutators.

The goal of the week is to cover how to build a mutator & wrap it up into an installer package for distribution.

Page 4: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

Mutators…What are they?

Mutators are special classes which modify the game being played in some way. Normally, mutators are single minded in their goals, such as just making the players fat, or reducing the gravity.

As they’re name suggests, they are pretty good at modifying and replacing stuff. Although this can be accomplished by creating new game types, one of the main advantages of the Mutators is that you don't need a new game type.

Page 5: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

Mutators…What are they?

In fact, you can combine Mutators with any game type, including 3rd party mods.

Provided they are properly written, they can be linked together, thus allowing you to more fully customize your gaming experience.

For instance, it allows you to be fat AND have low gravity.

Page 6: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

Mutators…What are they?

Another reason to use Mutators is that during network play, the clients will not need to download anything to join, unless of course, they don’t have that mutator or it makes use of actors not shipped with Unreal.

Page 7: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

Mutators…What are they?

So running one for an example…

Big head, instagib.

Page 8: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

Mutators…What are they?

In game we get

And Instagibbers for all

Changing head sizes…As you can see, Mandible here is not doing all that well

Page 9: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

Mutators…What are they?

After a bit of kick’n ass & take’n names…

“Look a-his grrreat- huuge- crainium! It’s got It’s own weathar sistem!!!”

Page 10: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

Mutators…What are they?

This is really cool functionality to have at our fingertips. Radically changing the game WITH OUT changing the game type.

In effect, Mutators are basically replacement classes. They are launched whenever an actor is spawned and by overriding some of the classes found in the standard Mutator class, we can control what items are to be spawned and which ones to scrap.

Page 11: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

Mutators…What are they?

You’ll find the mutator base class here:Object Actor Info Mutator

Page 12: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

Mutators…What are they?

With the following header: Mutators allow modifications to gameplay while keeping the

game rules intact. Mutators are given the opportunity to modify player login

parameters with ModifyLogin(), To modify player pawn properties with ModifyPlayer() To change the default weapon for players with

GetDefaultWeapon() To modify, remove, or replace all other actors when they are

spawned with CheckRelevance(), which is called from the PreBeginPlay() function of all actors except those (Decals, Effects and Projectiles for performance reasons) which have bGameRelevant==true.

Page 13: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

About the base class

The first thing to note about it is that the mutator class not only has functionality to change the game dynamics, but is also a linked list.

Look at the declaration:

class Mutator extends Info DependsOn(GameInfo) native;

var Mutator NextMutator;

Page 14: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

But first…

What is this DependsOn operation?

Page 15: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

What the Wiki says…

DependsOn Takes a class name as parameter. It allows you to

automatically import the structs, constants, and enums of a class. You don't need to specify a package name. You can then refer to the structs, enums, and constants using the syntax ClassName.TypeName. The dependsOn modifier takes exactly one parameter. If your class depends on more classes you have to use the modifier several times,

Page 16: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

Well, hang on a sec

We’re in the mutator class, so why are we declaring a mutator first thing?

class Mutator extends Info DependsOn(GameInfo) native;

var Mutator NextMutator;

Page 17: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

About the base class

Doing so allows the mutators to be chained together and iterated over.

This is very important to remember otherwise, you may not be able to compound you mutators together.

Page 18: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

About the base class

For example, from the mutator’s destroyed function:function Destroyed(){

local Mutator M;

// remove from mutator listif ( Level.Game.BaseMutator == self )

Level.Game.BaseMutator = NextMutator;else{

for ( M=Level.Game.BaseMutator; M!=None; M=M.NextMutator )

if ( M.NextMutator == self ){

M.NextMutator = NextMutator;

Page 19: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

Base class Defaults

Default properties: IconMaterialName:

allows mutators to have a symbol/graphic associated with them in the form TexturePack.Texture.

ConfigMenuClassName: This is used if the mutator needs an extra config

menu for special settings.

Page 20: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

Base class Defaults

GroupName: If there are two mutators in the same group, only

one is allowed to be used at a time, e.g. Arena and No Superweapons.

FriendlyName: This is the name seen in the mutator

screen when starting a game.

Page 21: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

Base class Defaults

Description: A longer description/help text to tell players

what the mutator does.

Note: the real description is stored in the int file and over rides the one listed here.

Page 22: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

About the base class

This class also comes with a core set of basic functions

And, unlike some of the other Script, has some useful comments.

Page 23: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

About the base class

event PreBeginPlay() and function bool MutatorIsAllowed() if the mutator isn't allowed, get rid of it. Mutators are

allowed if this isn't the demo, or if the class is a basic Mutator.

function Destroyed() The Destroyed() function for mutators must perform

the added task of removing it from the linked list.

Page 24: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

About the base class

function ModifyLogin(out string Portal, out string Options) ModifyLogin could be used to create some special

effect when a player logs in, or make an announcement

function ModifyPlayer(Pawn Other) called by GameInfo.RestartPlayer() change the

players jumpz, etc. here ModifyPlayer is commonly used to change speed,

gravity, jump height, health and such.

Page 25: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

About the base class

function Class<Weapon> GetDefaultWeapon() return what should replace the default weapon

mutators further down the list override earlier mutators.

function Class<Inventory> GetInventoryClass(string InventoryClassName) return an inventory class - either the class specified

by InventoryClassName, or a replacement. Called when spawning initial

inventory for player.

Page 26: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

About the base class

function string GetInventoryClassOverride(string InventoryClassName) return the string passed in, or a replacement class

name string.

function string GetInventoryClassOverride(string InventoryClassName) return the string passed in, or a replacement class

name string.

Page 27: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

About the base class

function class<Weapon> MyDefaultWeapon() return the default weapon used by the mutator.

function AddMutator(Mutator M) adds a mutator onto the end of the linked list.

function string RecommendCombo(string ComboName) used to modify the Combo Adrenalin moves used by

players.

Page 28: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

About the base class

function bool ReplaceWith(actor Other, string aClassName) Call this function to replace an actor Other with an

actor of aClass. scans the whole map replacing Other with aClass. It

is better to call this than to modify it.

function bool AlwaysKeep(Actor Other) Force game to always keep this actor, even if other

mutators want to get rid of it Important because mutators are supposed to be

pretty compatible with each other.

Page 29: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

About the base class

function bool IsRelevant(Actor Other, out byte bSuperRelevant)

function bool CheckRelevance(Actor Other) function bool CheckReplacement(Actor Other,

out byte bSuperRelevant) These functions check whether an actor is required

by the game or not. It is required if a mutator has called AlwaysKeep() on it. CheckReplacement is used, for example, by NoSuperWeapons mutator to replace the Ion Painter with the Sniper Rifle

Page 30: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

About the base class

function PlayerChangedClass(Controller aPlayer) Called when a player sucessfully changes to a new

class

Page 31: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

About the base class

function GetServerDetails( out GameInfo.ServerResponseLine ServerState )

function GetServerPlayers( out GameInfo.ServerResponseLine ServerState ) Server stuff. GetServerDetails returns the usual

details of the server, plus something telling everyone that our mutator is active on it. GetServerPlayer does nothing (obviously) and ParseChatPercVar could be used for silencing players etc.

Page 32: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

About the base class

And that concludes a very high level walk through of the mutator base class.

Now lets do something with it…

Page 33: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

Building a mutator

As always, starting simple.

I’m going to implement a real basic mutator that simply doubles the players jump height.

Page 34: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

Building a mutator

Getting the set up stuff out of the way first, we derive our class off the mutator base class and set up our defaults.

DefaultProperties{

IconMaterialName="MutatorArt.nosym"ConfigMenuClassName=""GroupName="SuperBounce"FriendlyName="Super Bounce"Description="Doubles jump height “

}

Page 35: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

Building a mutator

And now add to the int file:

So that we can call it from the menu.

[Public]Object=(Class=Class,MetaClass=Engine.Mutator,Name=Eze.Bounce ,

Description="Doubles jump height.")

Page 36: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

Building a mutator

Our mutator

But right now, it doesn’t do a thing.

Page 37: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

Building a mutator

Right, now we want to modify the players jump height…but how…err…

Oh yeah, we have a function for that…Modify player…Sounds logical.

Page 38: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

Building a mutator

Our function:

function ModifyPlayer(Pawn Other){ local Controller C; for (C = Level.ControllerList; C != None; C = C.NextController) {

if (C.Pawn != none ) { C.Pawn.jumpz *=2; } } super.ModifyPlayer(other);}

Page 39: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

Building a mutator

Remember the Level has a list of all the controllers in existence in the game, so well just iterate over all of these with the for loop.

And then double the jumpz value withC.Pawn.jumpz*=2;

Build & give it a shot…

Page 40: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

Building a mutator

Looks like it runs fine…

But what’s that stuff falling from the sky?

Hrmm…Weird.

Page 41: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

Building a mutator

Look what happens when I jump.

<KA-PWING!!!>

I nearly go into orbit! What the heck is going on?

Page 42: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

Building a mutator

Here’s the mistake I made, I placed the following log in the for loop in my home build

Log(c.PlayerReplicationInfo.PlayerName$"------------"$C.Pawn.jumpz);

…look at what it spat out…

Page 43: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

Building a mutator

Some insanely huge float values…in the tens of thousands!

Heh? The jumpZ default is only defined as JumpZ=+00420.000000 in the pawn class.

Look again at the log…

Page 44: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

Building a mutator

The player names repeat and get doubled with every pass…even before the match starts.

So what’s going on? The mutator is getting called with every access to any pawn. Doubling all of the jumpZ’s.

Causing an exponential increase in our jump height.

Page 45: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

Building a mutator

The solution, after much head scratching, was surprisingly simple. I was just how I was accessing my values.

It’s a one line fix.C.Pawn.jumpz = C.Pawn.default.jumpz*2;

Double my default jump height and then assign it to my pawns jump height. This will allow for dynamic changes specific to the pawn type

Page 46: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

Congrat’s

You’ve just completed you first mutator, ready for release to the world.

Page 47: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

A bit of polish.

On a second look at this modify player function, I had a bit of an epiphany.

Or some might say that I grew a brain.

Page 48: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

A bit of polish.

Looking back at what a mutator fundamentally is….a node in a linked list, it occurred to me that using the loop in the modify player function is a bad idea…

…real bad.

Page 49: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

A bit of polish.

Think about this for a moment, I’ve a list of objects that I’m using to modify my players in turn…in effect, each node has a turn at processing a player.

Thus, each pawn that gets processed in ModifyPlayer, modifies all other players in the game.

Page 50: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

A bit of polish.

Gah! That’s bad!

But just for a chuckle, lets say there are 6 players in the game, using the controller loop:

(C.Pawn.default.jumpz*2) * 6 * 6 * 6 * 6 * 6 * 6(C.Pawn.default.jumpz*2;)*6^6(C.Pawn.default.jumpz*2;)*46656

Page 51: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

A bit of polish.

*46656 !?!?

My god!

No wonder we go into orbit!

Page 52: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

The solution:

We’ll, not that we know why we were launching our pawns,

How do we fix it.

Page 53: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

The solution:

First off, now that we’ve realized that we don’t want to loop over all the controllers here.

It’s apparent that the modify player does it for us, we just need to set the new value.

Page 54: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

The solution:

Yup one function.

function ModifyPlayer(Pawn Other){

Other.jumpz = Other.default.jumpz*2; super.ModifyPlayer(other);}

Page 55: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

The Lesson?

In many places in the code, objects can be link together in this manner, and it’s frequently not documented all that clearly.

Page 56: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

The Lesson?

Also, UT doesn’t really have any build in data structures (like linked lists and hash tables) to conveniently store stuff. Hence we often have to make our own.

And a linked list in this fashion is the most common.

Page 57: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles

Tomorrow

We’re going to expand on this to create a mutator that had the jump doubler as part of an adrenalin combo where, when the combo is active, the player can jump twice as high…along with combo effects.