This tutorial will show how to create an adrenaline combo and add the combo to all players through a mutator. The specific adrenaline combo that we are making is called the Bullet Time combo. What this adrenaline combo will allow us to do is once the combo is activated, gameplay speed will slowdown allowing all players to enter into "Bullet Time" like in the matrix trilogies.
Getting Started
First off, we will need to create the directory structure in the UT2004 directory. Create a folder named "MutBulletTimeCombo". Then inside this folder, create another folder called "Classes". For more information on the package structure, see Set Up Package Folders.
We will create our script files in the this directory. Next, go into the system directory and locate the ut2004.ini file. Open up the file and do a search for Editor.EditorEngine. In this section, you will see many "EditPackages=X" where X is a package name. Our package is MutBulletTimeCombo, so at the end of that list, add the line "EditPackages=MutBulletTimeCombo".
Creating Combo Class
Create a new file in your preferred text editor and save the file as ComboBulletTime.uc. Inside that file, create a class called ComboBulletTime and have it extend the Combo class. This way, we gain access to the Combo class's functions and member variables. These will help us in creating our own adrenaline combo. Here is the code you will need:
class ComboBulletTime extends Combo; var float fOrigGameSpeed; /* This function will get called when right combination is entered. */ function StartEffect(xPawn P) { fOrigGameSpeed = Level.Game.GameSpeed; Level.Game.SetGameSpeed(0.05); } /* This function gets called when adrenaline is all gone. */ function StopEffect(xPawn P) { Level.Game.SetGameSpeed(fOrigGameSpeed); } defaultproperties { fOrigGameSpeed = 1.0; Duration = 3; ExecMessage = "Bullet Time!" keys[0] = 1; keys[1] = 2; keys[2] = 1; keys[3] = 2; }
The two functions called StartEffect and StopEffect both do exactly what the name implies. The variable Level is an object of the LevelInfo class declared in the Actor class. You have access to this variable because Combo extends from the Info class which then extends from the Actor class. Inside the LevelInfo class, there is a variable called Game which is an object of the GameInfo class. Take a look at these classes to see what these contain. Inside the GameInfo class, there is a function called SetGameSpeed that changes the value of GameSpeed within that same class. Here, we will change the game speed to be 0.05. The game speed is based on a percentage. A game speed of 1.0 means the game speed will be at 100%. We want to slow the game down, so a game speed of 5% will do the job. If you notice, we declared our own variable called fOrigGameSpeed. This is used to get the current game speed setting, which is usually 1.0, to set the speed back to once the adrenaline combo wears off.
The next thing to mention is the keys array in the default properties. These are where the combination of keys are declared that the player must press in order to get the combo activated. If you take a look at the Combo class, there are numbers which go with the direction the player presses. 1 is up, 2 is down, 4 is left, and 8 is right. In this example, the player must press "Up, Down, Up, Down" in that order when the player has full adrenaline to activate the combo.
Also in the default properties, you will notice the duration variable being declared to three. The reason for this is that we have set the game speed to 5%. So, 3 seconds running at 5% game speed will probably take like 60 seconds for the adrenaline to where off.
Mutator
Here, we will be adding a class called MutBulletTimeCombo, so create a new file of the same name and the .uc extension. When declaring the MutBulletTimeCombo class, have it extend Mutator. The code to add the Adrenaline combo to every player is below:
class MutBulletTimeCombo extends Mutator; var xPlayer NotifyPlayer[32]; function Timer() { local int i; for(i = 0; i < 32; i++) { if(NotifyPlayer[i] != None) { NotifyPlayer[i].ClientReceiveCombo("MutBulletTimeCombo.ComboBulletTime"); NotifyPlayer[i] = None; } } } function bool IsRelevant(Actor Other, out byte bSuperRelevant) { local int i; if(xPlayer(Other) != None) { for(i=0; i<16; i++) { if (xPlayer(Other).ComboNameList[i] ~= "MutBulletTimeCombo.ComboBulletTime") break; else if(xPlayer(Other).ComboNameList[i] == "") { xPlayer(Other).ComboNameList[i] = "MutBulletTimeCombo.ComboBulletTime"; break; } } for(i = 0; i < 32; i++) { if(NotifyPlayer[i] == None) { NotifyPlayer[i] = xPlayer(Other); SetTimer(0.5, false); break; } } } if(NextMutator != None) return NextMutator.IsRelevant(Other, bSuperRelevant); else return true; } defaultproperties { FriendlyName = "Bullet Time Combo" Description = "Adds the bullet time combo (UDUD). The combo slows all gameplay down, but allows players aim to be more accurate, as seen in the Matrix trilogies." }
The description and the FriendlyName will be shown in the mutator list. The Timer function above will notify each player in the level about the new combo. To access the combo, you need to put in the package name, followed by the combo class. In this case, we add ComboBulletTime class in the MutBulletTimeCombo package. Now every player is like Neo!
ToDo: Add more description about the IsRelavant Function.
Comments
Mad: I hope this tutorial helps you in understanding how combos work and how it can be activated through a mutator. I recommend grabbing the sniper rifle upon performing this combo and get your headshots in. Feel free to leave any comments or make any suggestions about this tutorial.
Metal_Maniac: I get the way it works, but what if you wanted to make something similar to the berzerk combo, or you wanted to make a mutator that gives you all the default weapons, and they all have infinite ammo, but for a limited time, and at the end of that time limit, your character explodes and dies, I'd call it "KamiKaze Mania combo", so if anyone has a suggestion on how to make that, please reply.
tornWolf: Just from a best practices point of view, it would likely be better to declare an int (const if we could) MAX_PLAYERS so that if the game will allow a different number than 32 players, that can be updated once in the code. I'm a noob so I may be wrong, just thought I'd throw that in.
Lord_Farin: Nice idea from Metal_Maniac (though this was abadoned long ago). I have coded it, fairly easy job. Any interested people, leave a message on my talk page.