Sega 500 Creating a New Game Jeff “Ezeikeil” Giles [email protected] jgiles.
Sega 500 Mutators Jeff “Ezeikeil” Giles [email protected] jgiles.
-
Upload
jasper-williams -
Category
Documents
-
view
213 -
download
0
Transcript of Sega 500 Mutators Jeff “Ezeikeil” Giles [email protected] jgiles.
![Page 2: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/2.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/3.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/4.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/5.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/6.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/7.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/8.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/9.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/10.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/11.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/12.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/13.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/14.jpg)
But first…
What is this DependsOn operation?
![Page 15: Sega 500 Mutators Jeff “Ezeikeil” Giles jgiles@artschool.com jgiles.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/15.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/16.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/17.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/18.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/19.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/20.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/21.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/22.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/23.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/24.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/25.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/26.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/27.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/28.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/29.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/30.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/31.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/32.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/33.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/34.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/35.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/36.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/37.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/38.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/39.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/40.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/41.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/42.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/43.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/44.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/45.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/46.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/47.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/48.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/49.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/50.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/51.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/52.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/53.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/54.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/55.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/56.jpg)
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.](https://reader036.fdocuments.in/reader036/viewer/2022070403/56649f2e5503460f94c481f0/html5/thumbnails/57.jpg)
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.