For direct access use https://forums.oldunreal.com
It's been quite a while since oldunreal had an overhaul, but we are moving to another server which require some updates and changes. The biggest change is the migration of our old reliable YaBB forum to phpBB. This system expects you to login with your username and old password known from YaBB.
If you experience any problems there is also the usual "password forgotten" function. Don't forget to clear your browser cache!
If you have any further concerns feel free to contact me: Smirftsch@oldunreal.com

[WIP] TUTORIAL: How to create a custom SP ladder (UT99)

The section related to UnrealScript and modding. This board is for coders to discuss and exchange experiences or ask questions.
Post Reply
User avatar
Neon_Knight
OldUnreal Member
Posts: 378
Joined: Tue Aug 25, 2009 9:02 pm

[WIP] TUTORIAL: How to create a custom SP ladder (UT99)

Post by Neon_Knight »

I've been faced with this question so many times due to one of my mods. So I thought here's how to build a basic SP ladder.

We're going to tackle how to make a simple ladder without using mutators or changing gametypes. That fancy stuff for show may be discussion material for the comments.
Step #1: Plan the Ladder

This step is VERY important. It saves a LOT of development time to plan things ahead. This is true for everything in life, sure, but it's a must for a SP ladder.

So, what needs to be planned? We aren't going to change the gametypes nor the amount of rungs needed to unlock the next ladder. All that remains are: a) the maps inside of the ladder themselves, b) the rules for each rung, c) the amount of AI bots and d) the properties of said bots.

Every Ladder contains 32 RatedMatches. Every RatedMatch (Botpack.RatedMatchInfo) contains the following properties:

Code: Select all

var() int NumBots;				// Total number of bots.
var() int NumAllies;				// Total allied bots in teamgames. (ONLY used in team-based gametypes like CTF, Assault and Domination)

var() float ModifiedDifficulty;			// Difficulty multiplier (0.000000 a 5.000000)

var() class<RatedTeamInfo> EnemyTeam;		// RatedTeamInfo (Enemy team, see below) (ONLY used in team-based gametypes like CTF, Assault and Domination)

var() localized string BotNames[8];		// Up to 8 bot names, only for non-team based games (such as, you guessed it, Deathmatch).
var() localized string BotClassifications[8];	// Bot classifications (e.g. "Soldier", "Assassin", "Villager", etc), only for non-team based games (such as, you guessed it, Deathmatch).
var() int BotTeams[8];				// Which team skin the bot will use. Valid values: 255, 0, 1, 2, 3 (neutral - red - blue - green - yellow).
var() float BotSkills[8];			// Individual bot base difficulty.
var() float BotAccuracy[8];			// Individual bot accuracy.
var() float CombatStyle[8];			// Negative values: the bot's playstyle is more defensive/careful, positive values: the bot's playstyle is more aggressive/careless.
var() float Camping[8];				// How much the bot loves to camp.
var() string FavoriteWeapon[8];			// Favorite weapon of the bot.
var() string BotClasses[8];			// Bot model. See Appendix A for accepted/official values.
var() string BotSkins[8];			// Bot skin. See Appendix A for accepted/official values.
var() string BotFaces[8];			// Bot face. See Appendix A for accepted/official values.
var() localized string Bio[8];			// Brief bot description. ("Stuart has been found trafficking drugs and is now fighting in the Tournament for his life.")
var() byte BotJumpy[8];				// Binary, specifies if the bot loves to jump (1) or his playstyle is more ground-based (0).
var() float StrafingAbility[8];			// How good the bot is at dodging.
Many of these parameters don't need explanation, really. If you've customized a bot, you know the accepted limits and whatnot. If not, check the file User.ini.

As for the Ladders (Botpack.Ladder), they contain the following data:

Code: Select all

var() int Matches;				 // Ladder match count. (For verification purposes)
var() bool bTeamGame;				 // Specifies if the gametype of the Ladder is team-based or not.
var() localized string Titles[9];		 // Up to 9 rank titles (Defaults being "Untrained", "Contender", "Light Weight", "Heavy Weight", "Warlord", "Battle Master", "Champion")
var() string MapPrefix;				 // If every map in the Ladder uses the same prefix, this specifies it (e.g. "DOM-", "CTF-", "AS-").

// [32] means "up to 32 matches"
var() string Maps[32];				 // Map, without prefix, if the prefix was specified. ("Oblivion", "Stalwart", "Fractal", "Coret", etc.)
var() string MapAuthors[32];			 // Map authors.
var() localized string MapTitle[32];		 // Map titles.
var() localized string MapDescription[32];	 // Map descriptions ("This slum used to be a gang warfare site, but was confiscated for Tournament use.")
var() int RankedGame[32];			 // Specifies the ranking number to give to the player once they beat a rung.
var() int GoalTeamScore[32];			 // Capturelimits/Pointlimits for non-Assault team-based gametypes.
var() int FragLimits[32];			 // Fraglimits for non-team based gametypes.
var() int TimeLimits[32];			 // Timelimit of the rung (I don't recommend setting it because for some reason it bugs the game).
var() string MatchInfo[32];			 // RatedMatchInfo for every rung. (See above)
var() int DemoDisplay[32];			 // If 0, you can play on this rung. Otherwise, you can only spectate it.

var() class<RatedTeamInfo> LadderTeams[32];	 // Up to 32 teams (RatedTeamInfo) can fight in this Ladder. Here's where they're mentioned.

var globalconfig bool HasBeatenGame;		 // If you ever wondered how you can unlock Xan without beating the Ladder, this globalconfig variable is the culprit.
Finally, we have the RatedTeamInfo (Botpack.RatedTeamInfo), whose properties are the following:

Code: Select all

var() localized string TeamName;		 // Name of the team. ("Thunder Crash", "Iron Guard", "Blood Reavers", etc.)
var() texture TeamSymbol;			 // Team symbol. Must be a texture. I recommend using one of the existing teams if you don't want to create a team symbol or want to mess with the game.
var() localized string TeamBio;			 // General team bio ("This team of drug traffickers was doing a prolific business until they got caught and now are fighting in the Tournament as an unit for their lives.")

// Up to 8 bots per team.
var() localized string BotNames[8];		 // Team member name. ("Malcolm", "Aryss", "Ivana", "Nikita", etc.)
var() localized string BotClassifications[8];	 // Team member individual classification ("Tournament champion", "Aviator", "Actress", "Wh*re", etc.)
var() float BotSkills[8];			 // Individual base difficulty of every bot.
var() float BotAccuracy[8];			 // Individual base accuracy of every bot.
var() float CombatStyle[8];			 // Individual playstyle of every bot.
var() float Camping[8];				 // Individual camping preference of every bot.
var() string FavoriteWeapon[8];			 // Individual favorite weapon of every bot.
var() string BotClasses[8];			 // Individual model of every bot.
var() string BotSkins[8];			 // Individual skin of every bot.
var() string BotFaces[8];			 // Individual face of every bot.
var() localized string BotBio[8];		 // Individual description of every bot ("Nikita used to be a cheap prostitute until she was recruited for her team in order to fight in the Tournament.")
var() byte BotJumpy[8];				 // Individual jump preference of the bot..

var() class<TournamentPlayer> MaleClass;	 // Male bot model setting.
var() string MaleSkin;				 // Male bot skin setting.

var() class<TournamentPlayer> FemaleClass;	 // Female bot model setting.
var() string FemaleSkin;			 // Female bot skin setting.
You need to plan the map list first, and then add the bots you want on every match. If you don't want to create teams, you can use the default teams UT already has.

Step #2: (Optional) Export the scripts

From UnrealEd, go to View -> Actor Class Browser, and then to File -> Export All Scripts. This generates a folder for every package you see in the Package list below.

Go to your UT installation. Sort the folders by using date creation/modification criteria. The recently created folders must be at the top. Unless you intend to mod later (in whose case, you can move them to a separate folder or even a folder outside of your UT installation), delete these newly created folders except Botpack and UTMenu.

Step #3: Creating the folder structure

You need to create a new folder in your UT installation, for the purposes of the tutorial, we're going to name it MyLadder. So if your UT base folder is UnrealTournament, your created folder must be UnrealTournament/MyLadder. Inside this folder, create another one called Classes (UnrealTournament/MyLadder/Classes). Here's where we're going to put our .uc scripts.

Step #4: Writing the code

Here's the tedious part: you need to write the code for every single custom RatedMatchInfo, Ladder and RatedTeamInfo. In order to do this, we're going to extend the mother classes with our new classes in this way. Here's an example RatedTeamInfo from my ladder:

Code: Select all

class RatedTeamInfo9 expands RatedTeamInfo;

// The Corrupt
#exec TEXTURE IMPORT NAME=TLPhalanx FILE=textures\teamsymbols\TLPhalanx.PCX GROUP="TeamSymbols" MIPS=OFF

defaultproperties
{
	TeamName="The Corrupt"
	TeamSymbol=Texture'Botpack.TeamSymbols.TLPhalanx'
	TeamBio="The Corrupt is Liandri's sponsored team entry in the Tournament. It is entirely made up of the best advanced AIs that the corporation's wealth can buy, and features the reigning champion, Xan Kriegor, as its leader."
	BotNames(0)="Vector"
	BotNames(1)="Cathode"
	BotNames(2)="Matrix"
	BotNames(3)="Silicon"
	BotNames(4)="Divisor"
	BotNames(5)="Tensor"
	BotNames(6)="Function"
	BotNames(7)="Enigma"
	BotClassifications(0)="Slave Warrior"
	BotClassifications(1)="Slave Warrior"
	BotClassifications(2)="Slave Warrior"
	BotClassifications(3)="Slave Warrior"
	BotClassifications(4)="Slave Warrior"
	BotClassifications(5)="Slave Warrior"
	BotClassifications(6)="Slave Warrior"
	BotClassifications(7)="Slave Warrior"
	BotClasses(0)="BotPack.TMale2Bot"
	BotClasses(1)="BotPack.TFemale2Bot"
	BotClasses(2)="BotPack.TMale2Bot"
	BotClasses(3)="BotPack.TFemale2Bot"
	BotClasses(4)="BotPack.TFemale2Bot"
	BotClasses(5)="BotPack.TMale2Bot"
	BotClasses(6)="BotPack.TFemale2Bot"
	BotClasses(7)="BotPack.TFemale2Bot"
	BotSkins(0)="hkil"
	BotSkins(1)="fwar"
	BotSkins(2)="hkil"
	BotSkins(3)="fwar"
	BotSkins(4)="fwar"
	BotSkins(5)="hkil"
	BotSkins(6)="fwar"
	BotSkins(7)="fwar"
	BotFaces(0)="Vector"
	BotFaces(1)="Cathode"
	BotFaces(2)="Matrix"
	BotFaces(3)="Lilith"
	BotFaces(4)="Fury"
	BotFaces(5)="Tensor"
	BotFaces(6)="Fury"
	BotFaces(7)="Lilith"
	BotBio(0)="A warrior slave. Member of 'The Corrupt,' a group of reprogrammed warriors who fight for the entertainment of Xan Kriegor."
	BotBio(1)="A warrior slave. Member of 'The Corrupt,' a group of reprogrammed warriors who fight for the entertainment of Xan Kriegor."
	BotBio(2)="A warrior slave. Member of 'The Corrupt,' a group of reprogrammed warriors who fight for the entertainment of Xan Kriegor."
	BotBio(3)="A warrior slave. Member of 'The Corrupt,' a group of reprogrammed warriors who fight for the entertainment of Xan Kriegor."
	BotBio(4)="A warrior slave. Member of 'The Corrupt,' a group of reprogrammed warriors who fight for the entertainment of Xan Kriegor."
	BotBio(5)="A warrior slave. Member of 'The Corrupt,' a group of reprogrammed warriors who fight for the entertainment of Xan Kriegor."
	BotBio(6)="A warrior slave. Member of 'The Corrupt,' a group of reprogrammed warriors who fight for the entertainment of Xan Kriegor."
	BotBio(7)="A warrior slave. Member of 'The Corrupt,' a group of reprogrammed warriors who fight for the entertainment of Xan Kriegor."
	MaleClass=class'Botpack.TMale2'
	MaleSkin="SoldierSkins.hkil"
	FemaleClass=class'Botpack.TFemale2'
	FemaleSkin="SGirlSkins.fwar"
}
Here's the explanation for every line:
  • The first line has the new class name (class RatedTeamInfo9) which expands on the functionality of RatedTeamInfo (expands RatedTeamInfo).
  • The next line is a comment. Comments in the code start with // for individual lines or begin and end with /* and */ for huge blocks. The game doesn't render comments, so you can use them to note what does the lines do. It's highly recommended to document your code. (Yeah, yeah, superuberl33tprogrammer, we know you don't comment your code, you can stop your axlrosing)
  • The third line contains the data for a texture to be imported. Every texture indicated on the code. This embeds the texture in the package. In this case, the texture is the team's symbol or logo. I used one of the game's own team symbols. It threw a Warning on compilation, but nothing serious. It can be omitted.
  • The fourth line, defaultproperties, is a section of the code that contains the default values that this class uses whenever it's instantiated in the game proper.
  • The rest of the code speaks for itself, we've already seen it.
Before we continue, a note: the game has problems recognizing double quotes ("). A workaround to solve this is to use two single quotes (''). The game uses this in order to emulate double quotes whenever it's necessary. You can also use other Unicode-based characters, these won't affect the code as well. That said, it's a good practice to enclose every string between double quotes.
Also, and this is REALLY important: RESPECT THE SYNTAX OF THE CODE. The compiler can throw errors and/or the game may behave in an unintended form just because you missed a quote. Basic rules of programming.
Last, but not least, even though I don't recommend doing so, if you didn't use some of the properties, you can delete them. In fact, two teams of the game (Iron Skull y Red Claw) only have 6 team members, unlike the other teams, which have 8. However, bear in mind that the game may behave weirdly if you put a 6-member team in an 8-on-8 match.

Once we created the custom teams, let's see the individual matches. Every match filling is different for team games and non-team games, so we're going to see both cases:

Non-team-based game:

Code: Select all

class RatedMatchDM10AM extends RatedMatchInfo;

defaultproperties
{
	NumBots=2
	ModifiedDifficulty=1.000000

	BotNames(0)="Vanessa"
	BotNames(1)="Xoleras"
	BotClassifications(0)="Psychotic"
	BotClassifications(1)="Executioner"
	BotTeams(0)=255
	BotTeams(1)=1
	CombatStyle(0)=1.000000
	CombatStyle(1)=0.500000
	FavoriteWeapon(0)="Botpack.UT_FlakCannon"
	FavoriteWeapon(1)="Botpack.PulseGun"
	BotClasses(0)="Botpack.TFemale1Bot"
	BotClasses(1)="Botpack.TMale2Bot"
	BotSkins(0)="FCommandoSkins.cmdo"
	BotSkins(1)="SoldierSkins.sldr"
	BotFaces(0)="FCommandoSkins.Gromida"
	BotFaces(1)="SoldierSkins.Harlin"
	Bio(0)="Vanessa was committed at a psychiatric institution at the age of twelve for murdering her parents and brother. This one is a real nut case. She likes to blow her opponents open with a well aimed rocket."
	Bio(1)="A former Greek mob executioner on 'extended leave' from his 'family business', Xoleras has a reputation of completely and utterly dominating his opponents. A master of thin ledges and with vision of an eagle, he rarely misses an opportunity to blank an unskilled opponent."
}
Team-based game:

Code: Select all

class RatedMatchCTF10AM extends RatedMatchInfo;

defaultproperties
{
	NumBots=7
	NumAllies=3
	ModifiedDifficulty=1.500000

	EnemyTeam=class'Botpack.RatedTeamInfo2'
}
Every individual match extends RatedMatchInfo. In non-team-based games, it's non necessary to put all properties. You can also split them, in whose case it'll look like this:

Code: Select all

class RatedMatchDM10AM extends RatedMatchInfo;

defaultproperties
{
	NumBots=2
	ModifiedDifficulty=1.000000

	BotNames(0)="Vanessa"
	BotClassifications(0)="Psychotic"
	BotTeams(0)=255
	CombatStyle(0)=1.000000
	FavoriteWeapon(0)="Botpack.UT_FlakCannon"
	BotClasses(0)="Botpack.TFemale1Bot"
	BotSkins(0)="FCommandoSkins.cmdo"
	BotFaces(0)="FCommandoSkins.Gromida"
	Bio(0)="Vanessa was committed at a psychiatric institution at the age of twelve for murdering her parents and brother. This one is a real nut case. She likes to blow her opponents open with a well aimed rocket."

	BotNames(1)="Xoleras"
	BotClassifications(1)="Executioner"
	BotTeams(1)=1
	CombatStyle(1)=0.500000
	FavoriteWeapon(1)="Botpack.PulseGun"
	BotClasses(1)="Botpack.TMale2Bot"
	BotSkins(1)="SoldierSkins.sldr"
	BotFaces(1)="SoldierSkins.Harlin"
	Bio(1)="A former Greek mob executioner on 'extended leave' from his 'family business', Xoleras has a reputation of completely and utterly dominating his opponents. A master of thin ledges and with vision of an eagle, he rarely misses an opportunity to blank an unskilled opponent."
}
The clear advantage this method has over the other is that it makes code clearer to read.

Finally, we're going to take a look at the Ladders. Here, the thing is... a bit more complicated. But I'm too tired to continue today.

To be continued...
Localization project coordinator/spanish maintainer

Only the people that do nothing but criticize don't make mistakes. Do things. Make mistakes. Learn from them. And screw those who do nothing but throw poison and criticize.
User avatar
Neon_Knight
OldUnreal Member
Posts: 378
Joined: Tue Aug 25, 2009 9:02 pm

[WIP] TUTORIAL: How to create a custom SP ladder (UT99)

Post by Neon_Knight »

Step #4: (Cont) Writing the Code

For the Ladders we just can't extend Ladder itself. We also need to extend every single component out of it. Why? (slaps head multiple times) Here's why: the UT ladder wasn't coded to be extendable, it's highly hard-coded, to the point lots of unnecessary duplication must be made. That's why you don't see many ladder mods.

We have to extend every single UT default Ladder, as well as Botpack.Ladder and UTMenu.UTLadder. But before that, we have to prepare the individual ladders:

Code: Select all

class MyLadderDM extends LadderDM config(MyLadder);

defaultproperties
{
	Matches=16
	MapPrefix="DM-"

	Maps(0)="Tutorial.unr"
	MapAuthors(0)="Cliff Bleszinski"
	MapTitle(0)="DM Tutorial"
	MapDescription(0)="Learn the basic rules of Deathmatch in this special training environment. Test your skills against an untrained enemy before entering the tournament proper."
	RankedGame(0)=1
	FragLimits(0)=3
	MatchInfo(0)="Botpack.RatedMatchDMTUT"

	Maps(1)="Oblivion.unr"
	MapAuthors(1)="Juan Pancho Eekels"
	MapTitle(1)="Oblivion"
	MapDescription(1)="The ITV Oblivion is one of Liandri's armored transport ships. It transports new contestants via hyperspace jump from the Initiation Chambers to their first events on Earth. Little do most fighters know, however, that the ship itself is a battle arena."
	RankedGame(1)=1
	FragLimits(1)=10
	MatchInfo(1)="MyLadder.MyRatedMatchDM1"

//(...)

	Maps(14)="StalwartXL.unr"
	MapAuthors(14)="Alan Willard"
	MapTitle(14)="Stalwart Rematch"
	MapDescription(14)="It didn't take long for Jerl Liandri to realize that there was a hidden, but large, room behind closed garage doors. Amazed, he named his discovery as part of the battle arena and added some more powerful weapons, including Jerl's own personal favorite, the 'hellraising' Warhead Launcher."
	RankedGame(14)=3
	FragLimits(14)=20
	MatchInfo(14)="MyLadder.MyRatedMatchDM14"

	Maps(15)="Turbine.unr"
	MapAuthors(15)="Cliff Bleszinski"
	MapTitle(15)="Turbine"
	MapDescription(15)="A decaying water-treatment facility that has been purchased for use in the Tourney, the Turbine Facility offers an extremely tight and fast arena for combatants which ensures that there is no running, and no hiding from certain death."
	RankedGame(15)=3
	FragLimits(15)=20
	MatchInfo(15)="MyLadder.MyRatedMatchDM15"
}
Here we see lots of familiar coding which we've seen in the first post. However there's one key difference: the first line now contains config(MyLadder). This allows the ladder to be saved in the file MyLadder.ini in the System folder. This is necessary to save the progress of the match.

Now we have to subclass every window and game component. We're also going to create a mod window so we can start our custom Ladder. We need to subclass the following classes:
  • UTMenu.EnemyBrowser
  • UTMenu.KillGameQueryClient
  • UTMenu.KillGameQueryWindow
  • Botpack.Ladder
  • UTMenu.ManagerWindow
  • UTMenu.NewCharacterWindow
  • UTMenu.NewGameInterimObject
  • UTMenu.ObjectiveBrowser
  • UTMenu.SlotWindow
  • UTMenu.TeamBrowser
  • UTMenu.UTLadder
  • UTMenu.UTLadderAS
  • UTMenu.UTLadderChal
  • UTMenu.UTLadderCTF
  • UTMenu.UTLadderDM
  • UTMenu.UTLadderDOM
We can either create the new classes from scratch or copy the respective files from their folders onto our new folder which we created in steps #2 and #3. We're going to see the first method, since we only need to duplicate the functionality which we need to modify. We can later extend the functionality in order to incorporate mutators, change the gametype (and even create multi-gametype ladders) and the like. But for now let's focus on the important stuff.

We're going to begin with Botpack.Ladder and the UTLadder classes. UTLadder is an Abstract Class. This class cannot be instantiated, but you can generate new subclasses from this one. These classes have an Abstract Method, which must be implemented in the subclasses generated from this one. UTLadder has UTLadderAS, UTLadderChal, UTLadderCTF, UTLadderDM and UTLadderDOM as subclasses. So we need to subclass Botpack.Ladder first, by creating a new class called MyLadderLadder, with the following code:

Code: Select all

class MyLadderLadder extends Ladder Config(MyLadder);

defaultproperties
{
	Titles(0)="Untrained"
	Titles(1)="Contender"
	Titles(2)="Light Weight"
	Titles(3)="Heavy Weight"
	Titles(4)="Warlord"
	Titles(5)="Battle Master"
	Titles(6)="Champion"
	LadderTeams(0)=Class'Botpack.RatedTeamInfo1'
	LadderTeams(1)=Class'Botpack.RatedTeamInfo2'
	LadderTeams(2)=Class'Botpack.RatedTeamInfo3'
	LadderTeams(3)=Class'Botpack.RatedTeamInfo4'
	LadderTeams(4)=Class'Botpack.RatedTeamInfo5'
	LadderTeams(5)=Class'Botpack.RatedTeamInfo6'
	LadderTeams(6)=Class'Botpack.RatedTeamInfoS'
	LadderTeams(7)=Class'Botpack.RatedTeamInfoDemo1'
	LadderTeams(8)=Class'Botpack.RatedTeamInfoDemo2'
	LadderTeams(9)=Class'MyLadder.RatedTeamInfo9'
	NumTeams=7
}
Titles and LadderTeams can be customized as seen in the first post. The reason why this class has been subclassed is to bypass a limitation of the game, as it's easy to mess up the references and revert the Ladder back to UT's original ladder. And the results aren't pretty. So, from now on, every time we see class'Ladder' we're going to replace it with class'MyLadderLadder'. For some reason this isn't the case with the individual gametype Ladders, so these can be subclassed without problems.

Next, we'll subclass UTMenu.KillGameQueryClient and UTMenu.KillGameQueryWindow as MyKillGameQueryClient and MyKillGameQueryWindow. These are the dialogues that ask the player if they really want to delete a previously saved progress and free a save slot. Contains calls to MySlotWindow (UTMenu.SlotWindow) and MyManagerWindow (UTMenu.ManagerWindow), which we're going to subclass further:

Code: Select all

class MyKillGameQueryClient extends KillGameQueryClient;

var SlotWindow SlotWindow;

function YesPressed ()
{
	if ( SlotWindow != None )
	{
		SlotWindow.Saves[SlotIndex] = "";
		SlotWindow.SaveConfig();
		SlotWindow.SlotButton[SlotIndex].Text = class'MySlotWindow'.Default.EmptyText;
		class'MyManagerWindow'.Default.DOMDoorOpen[SlotIndex] = 0;
		class'MyManagerWindow'.Default.CTFDoorOpen[SlotIndex] = 0;
		class'MyManagerWindow'.Default.ASDoorOpen[SlotIndex] = 0;
		class'MyManagerWindow'.Default.ChalDoorOpen[SlotIndex] = 0;
		class'MyManagerWindow'.Default.TrophyDoorOpen[SlotIndex] = 0;
		class'MyManagerWindow'.StaticSaveConfig();
	}
	Close();
}

defaultproperties
{
	QueryText="Are you sure you want to delete this saved game?"
	YesText="Yes"
	NoText="No"
}

Code: Select all

class MyKillGameQueryWindow extends KillGameQueryWindow;

function BeginPlay ()
{
	ClientClass = Class'MyKillGameQueryClient';
}

defaultproperties
{
	WindowTitle="Delete saved progress?"
}
Now we're going to subclass the browsers. These are MyTeamBrowser (UTMenu.TeamBrowser) and MyEnemyBrowser (UTMenu.EnemyBrowser). These display our teammates and enemies. We can extend these in order to support extra teams for the gametypes that support more than two teams, but we won't do that now:

Code: Select all

class MyEnemyBrowser extends EnemyBrowser Config(MyLadder);

Code: Select all

class MyTeamBrowser extends TeamBrowser;

function NextPressed()
{
	local EnemyBrowser EB;

	HideWindow();
	EB = EnemyBrowser(Root.CreateWindow(class'MyEnemyBrowser', 100, 100, 200, 200, Root, True));
	EB.LadderWindow = LadderWindow;
	EB.TeamWindow = Self;
	EB.Ladder = Ladder;
	EB.Match = Match;
	EB.GameType = GameType;
	EB.Initialize();
}
UTMenu.NewGameInterimObject is the first object created after clicking on "Start Unreal Tournament". So we'll subclass it as MyNewGameInterimObject.

Code: Select all

class MyNewGameInterimObject expands NewGameInterimObject;

var string GameWindowType;

function PostBeginPlay()
{
	local LadderInventory LadderObj;
	local int EmptySlot, j;
	
	EmptySlot = -1;
	for (j=0; j<5; j++)
	{
		if (class'MySlotWindow'.Default.Saves[j] == "") {
			EmptySlot = j;
			break;
		}
	}

	if (EmptySlot < 0)
	{
		// Create "You must first free a slot..." dialog.
		TournamentConsole(PlayerPawn(Owner).Player.Console).Root.CreateWindow(class'FreeSlotsWindow', 100, 100, 200, 200);
		return;
	}

	// Create new game dialog.
	TournamentConsole(PlayerPawn(Owner).Player.Console).bNoDrawWorld = True;
	TournamentConsole(PlayerPawn(Owner).Player.Console).bLocked = True;
	UMenuRootWindow(TournamentConsole(PlayerPawn(Owner).Player.Console).Root).MenuBar.HideWindow();

	// Make them a ladder object.
	LadderObj = LadderInventory(PlayerPawn(Owner).FindInventoryType(class'LadderInventory'));
	if (LadderObj == None)
	{
		// Make them a ladder object.
		LadderObj = Spawn(class'LadderInventory');
		Log("Created a new LadderInventory.");
		LadderObj.GiveTo(PlayerPawn(Owner));
	}
	LadderObj.Reset();
	LadderObj.Slot = EmptySlot; // Find a free slot.
	class'MyManagerWindow'.Default.DOMDoorOpen[EmptySlot] = 0;
	class'MyManagerWindow'.Default.CTFDoorOpen[EmptySlot] = 0;
	class'MyManagerWindow'.Default.ASDoorOpen[EmptySlot] = 0;
	class'MyManagerWindow'.Default.ChalDoorOpen[EmptySlot] = 0;
	class'MyManagerWindow'.Static.StaticSaveConfig();
	Log("Assigned player a LadderInventory.");

	// Clear all slots.
	Owner.PlaySound(sound'LadderSounds.ladvance', SLOT_None, 0.1);
	Owner.PlaySound(sound'LadderSounds.ladvance', SLOT_Misc, 0.1);
	Owner.PlaySound(sound'LadderSounds.ladvance', SLOT_Pain, 0.1);
	Owner.PlaySound(sound'LadderSounds.ladvance', SLOT_Interact, 0.1);
	Owner.PlaySound(sound'LadderSounds.ladvance', SLOT_Talk, 0.1);
	Owner.PlaySound(sound'LadderSounds.ladvance', SLOT_Interface, 0.1);

	// Go to the character creation screen.
	TournamentConsole(PlayerPawn(Owner).Player.Console).Root.CreateWindow(Class<UWindowWindow>(DynamicLoadObject(GameWindowType, Class'Class')), 100, 100, 200, 200, TournamentConsole(PlayerPawn(Owner).Player.Console).Root, True);
}

defaultproperties
{
	GameWindowType="MyLadder.MyNewCharacterWindow"
}
Now we subclass UTMenu.SlotWindow, and we're going to call it MySlotWindow.

Code: Select all

class MySlotWindow extends SlotWindow config(MyLadder);

function KillGame(int i)
{
	local KillGameQueryWindow KGQWindow;

	if (SlotButton[i].Text != EmptyText)
	{
		// Are you sure?
		KGQWindow = KillGameQueryWindow(Root.CreateWindow(class'MyKillGameQueryWindow', 100, 100, 100, 100));
		MyKillGameQueryClient(KGQWindow.ClientArea).SlotWindow = Self;
		MyKillGameQueryClient(KGQWindow.ClientArea).SlotIndex = i;
		ShowModal(KGQWindow);
	}
}

function RestoreGame(int i)
{
	local LadderInventory LadderObj;
	local string Temp, Name, PlayerSkin;
	local Class<TournamentPlayer> PlayerClass;
	local int Pos, Team, j, Face;

	if (Saves[i] == "")
		return;

	// Check ladder object.
	LadderObj = LadderInventory(GetPlayerOwner().FindInventoryType(class'LadderInventory'));
	if (LadderObj == None)
	{
		// Make them a ladder object.
		LadderObj = GetPlayerOwner().Spawn(class'LadderInventory');
		LadderObj.GiveTo(GetPlayerOwner());
	}

	// Fill the ladder object.

	// Slot...
	LadderObj.Slot = i;

	// Difficulty...
	LadderObj.TournamentDifficulty = int(Left(Saves[i], 1));
	LadderObj.SkillText = class'MyNewCharacterWindow'.Default.SkillText[LadderObj.TournamentDifficulty];

	// Team
	Temp = Right(Saves[i], Len(Saves[i]) - 2);
	Pos = InStr(Temp, "\\");
	Team = int(Left(Temp, Pos));
	LadderObj.Team = class'MyLadderLadder'.Default.LadderTeams[Team];

	// DMRank
	Temp = Right(Saves[i], Len(Temp) - Pos - 1);
	Pos = InStr(Temp, "\\");
	LadderObj.DMRank = int(Left(Temp, Pos));

	// DMPosition
	Temp = Right(Temp, Len(Temp) - Pos - 1);
	Pos = InStr(Temp, "\\");
	LadderObj.DMPosition = int(Left(Temp, Pos));

	// DOMRank
	Temp = Right(Temp, Len(Temp) - Pos - 1);
	Pos = InStr(Temp, "\\");
	LadderObj.DOMRank = int(Left(Temp, Pos));

	// DOMPosition
	Temp = Right(Temp, Len(Temp) - Pos - 1);
	Pos = InStr(Temp, "\\");
	LadderObj.DOMPosition = int(Left(Temp, Pos));

	// CTFRank
	Temp = Right(Temp, Len(Temp) - Pos - 1);
	Pos = InStr(Temp, "\\");
	LadderObj.CTFRank = int(Left(Temp, Pos));

	// CTFPosition
	Temp = Right(Temp, Len(Temp) - Pos - 1);
	Pos = InStr(Temp, "\\");
	LadderObj.CTFPosition = int(Left(Temp, Pos));

	// ASRank
	Temp = Right(Temp, Len(Temp) - Pos - 1);
	Pos = InStr(Temp, "\\");
	LadderObj.ASRank = int(Left(Temp, Pos));

	// ASPosition
	Temp = Right(Temp, Len(Temp) - Pos - 1);
	Pos = InStr(Temp, "\\");
	LadderObj.ASPosition = int(Left(Temp, Pos));

	// ChalRank
	Temp = Right(Temp, Len(Temp) - Pos - 1);
	Pos = InStr(Temp, "\\");
	LadderObj.ChalRank = int(Left(Temp, Pos));

	// ChalPosition
	Temp = Right(Temp, Len(Temp) - Pos - 1);
	Pos = InStr(Temp, "\\");
	LadderObj.ChalPosition = int(Left(Temp, Pos));

	// Sex
	Temp = Right(Temp, Len(Temp) - Pos - 1);
	Pos = InStr(Temp, "\\");
	LadderObj.Sex = Left(Temp, Pos);

	// Face
	Temp = Right(Temp, Len(Temp) - Pos - 1);
	Pos = InStr(Temp, "\\");
	Face = int(Left(Temp, Pos));
	LadderObj.Face = Face;

	// Name
	Temp = Right(Temp, Len(Temp) - 2);
	Name = Temp;
	GetPlayerOwner().ChangeName(Name);
	GetPlayerOwner().UpdateURL("Name", Name, True);

	if (LadderObj.Sex ~= "M")
	{
		PlayerClass = LadderObj.Team.Default.MaleClass;
		PlayerSkin = LadderObj.Team.Default.MaleSkin;
	} else {
		PlayerClass = LadderObj.Team.Default.FemaleClass;
		PlayerSkin = LadderObj.Team.Default.FemaleSkin;
	}

	IterateFaces(PlayerSkin, GetPlayerOwner().GetItemName(string(PlayerClass.Default.Mesh)));
	GetPlayerOwner().UpdateURL("Class", string(PlayerClass), True);
	GetPlayerOwner().UpdateURL("Skin", PlayerSkin, True);
	GetPlayerOwner().UpdateURL("Face", Faces[Face], True);
	GetPlayerOwner().UpdateURL("Voice", PlayerClass.Default.VoiceType, True);
	GetPlayerOwner().UpdateURL("Team", "255", True);

	// Goto Manager
	HideWindow();
	Root.CreateWindow(class'MyManagerWindow', 100, 100, 200, 200, Root, True);
}

defaultproperties
{
	BGName1(0)="UTMenu.Save11"
	BGName1(1)="UTMenu.Save12"
	BGName1(2)="UTMenu.Save13"
	BGName1(3)="UTMenu.Save14"
	BGName2(0)="UTMenu.Save21"
	BGName2(1)="UTMenu.Save22"
	BGName2(2)="UTMenu.Save23"
	BGName2(3)="UTMenu.Save24"
	BGName3(0)="UTMenu.Save31"
	BGName3(1)="UTMenu.Save32"
	BGName3(2)="UTMenu.Save33"
	BGName3(3)="UTMenu.Save34"
	EmptyText="UNUSED"
	AvgRankStr="Average Rank:"
	CompletedStr="Matches Won:"
}
And now we subclass UTMenu.UTLadder. And we're going to name it MyLadder:

Code: Select all

class MyLadder extends UTLadder;

function EvaluateMatch(optional bool bTrophyVictory)
{
	local string SaveString;
	local int Team, i;

	if (LadderObj != None)
	{
		SaveString = string(LadderObj.TournamentDifficulty);
		for (i=0; i<class'MyLadderLadder'.Default.NumTeams; i++)
		{
			if (class'MyLadderLadder'.Default.LadderTeams[i] == LadderObj.Team)
				Team = i;
		}
		SaveString = SaveString$"\\"$Team;
		SaveString = SaveString$"\\"$LadderObj.DMRank;
		SaveString = SaveString$"\\"$LadderObj.DMPosition;
		SaveString = SaveString$"\\"$LadderObj.DOMRank;
		SaveString = SaveString$"\\"$LadderObj.DOMPosition;
		SaveString = SaveString$"\\"$LadderObj.CTFRank;
		SaveString = SaveString$"\\"$LadderObj.CTFPosition;
		SaveString = SaveString$"\\"$LadderObj.ASRank;
		SaveString = SaveString$"\\"$LadderObj.ASPosition;
		SaveString = SaveString$"\\"$LadderObj.ChalRank;
		SaveString = SaveString$"\\"$LadderObj.ChalPosition;
		SaveString = SaveString$"\\"$LadderObj.Sex;
		SaveString = SaveString$"\\"$LadderObj.Face;
		SaveString = SaveString$"\\"$GetPlayerOwner().PlayerReplicationInfo.PlayerName;
		class'MySlotWindow'.Default.Saves[LadderObj.Slot] = SaveString;
		class'MySlotWindow'.Static.StaticSaveConfig();

		if (LadderObj.PendingPosition > 7)
		{
			SelectedMatch = LadderObj.PendingPosition;
			BaseMatch = LadderObj.PendingPosition - 7;
			ArrowPos = LadderObj.PendingPosition - 1;
			PendingPos = LadderObj.PendingPosition;
		}
		LadderObj.PendingPosition = 0;
		if (bTrophyVictory)
			bTrophyTravelPending = True;

		SelectedMatch = LadderPos;
		SetMapShot(LadderPos);
		FillInfoArea(LadderPos);
	}
}

function EscClose()
{
	BackPressed();
}

function BackPressed()
{
	Root.CreateWindow(class'MyManagerWindow', 100, 100, 200, 200, Root, True);
	Close();
}

function ShowWindow()
{
	LadderObj.CurrentLadder = Ladder;
	Super.ShowWindow();
}
For Assault, we're going to subclass UTMenu.ObjectiveBrowser, the browser Assault uses in order to show the objectives. We're going to call it MyObjectiveBrowser.

Code: Select all

class MyObjectiveBrowser extends ObjectiveBrowser;

function NextPressed ()
{
	local TeamBrowser TB;

	HideWindow();
	TB = TeamBrowser(Root.CreateWindow(Class'MyTeamBrowser',100.0,100.0,200.0,200.0,Root,True));
	TB.LadderWindow = LadderWindow;
	TB.ObjectiveWindow = self;
	TB.LadderWindow = LadderWindow;
	TB.Ladder = Ladder;
	TB.Match = Match;
	TB.GameType = GameType;
	TB.Initialize();
}

function Initialize()
{
	local class<Bot> InitialMate;
	local int i;
	local int W, H;
	local float XWidth, YHeight, XMod, YMod, XPos, YPos, YOffset;
	local color TextColor;
	local AssaultInfo AI;

	GetPlayerOwner().ViewRotation.Pitch = 0;
	GetPlayerOwner().ViewRotation.Roll = 0;

	/*
	 * Setup window parameters.
	 */

	bLeaveOnScreen = True;
	bAlwaysOnTop = True;
	class'UTLadderStub'.Static.GetStubClass().Static.SetupWinParams(Self, Root, W, H);

	XMod = 4*W;
	YMod = 3*H;

	/*
	 * Load the background.
	 */

	BG1[0] = Texture(DynamicLoadObject(BGName1[0], Class'Texture'));
	BG1[1] = Texture(DynamicLoadObject(BGName1[1], Class'Texture'));
	BG1[2] = Texture(DynamicLoadObject(BGName1[2], Class'Texture'));
	BG1[3] = Texture(DynamicLoadObject(BGName1[3], Class'Texture'));
	BG2[0] = Texture(DynamicLoadObject(BGName2[0], Class'Texture'));
	BG2[1] = Texture(DynamicLoadObject(BGName2[1], Class'Texture'));
	BG2[2] = Texture(DynamicLoadObject(BGName2[2], Class'Texture'));
	BG2[3] = Texture(DynamicLoadObject(BGName2[3], Class'Texture'));
	BG3[0] = Texture(DynamicLoadObject(BGName3[0], Class'Texture'));
	BG3[1] = Texture(DynamicLoadObject(BGName3[1], Class'Texture'));
	BG3[2] = Texture(DynamicLoadObject(BGName3[2], Class'Texture'));
	BG3[3] = Texture(DynamicLoadObject(BGName3[3], Class'Texture'));

	/*
	 * Create components.
	 */

	// Title
	XPos = 74.0/1024 * XMod;
	YPos = 69.0/768 * YMod;
	XWidth = 352.0/1024 * XMod;
	YHeight = 41.0/768 * YMod;
	Title1 = NotifyButton(CreateWindow(class'NotifyButton', XPos, YPos, XWidth, YHeight));
	Title1.Text = BrowserName;
	TextColor.R = 255;
	TextColor.G = 255;
	TextColor.B = 0;
	Title1.NotifyWindow = Self;
	Title1.SetTextColor(TextColor);
	Title1.MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetHugeFont(Root);
	Title1.bStretched = True;
	Title1.bDisabled = True;
	if (!Ladder.Default.bTeamGame)
		Title1.bDisabled = True;

	// Names
	TextColor.R = 0;
	TextColor.G = 128;
	TextColor.B = 255;
	XPos = 168.0/1024 * XMod;
	YPos = 255.0/768 * YMod;
	XWidth = 256.0/1024 * XMod;
	YHeight = 64.0/768 * YMod;
	YOffset = 48.0/768 * YMod;
	NumNames = class'MyLadderAS'.Static.GetObjectiveCount(Match, AI);
	for (i=0; i<NumNames; i++)
	{
		Names[i] = LadderButton(CreateWindow(class'LadderButton', XPos, YPos + i*YOffset, XWidth, YHeight));
		Names[i].MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetBigFont(Root);
		Names[i].NotifyWindow = Self;
		Names[i].SetTextColor(TextColor);
		Names[i].bStretched = True;
		Names[i].bDontSetLabel = True;
		Names[i].LabelWidth = 178.0/1024 * XMod;
		Names[i].LabelHeight = 49.0/768 * YMod;
		Names[i].OverSound = sound'LadderSounds.lcursorMove';
		Names[i].DownSound = sound'SpeechWindowClick';
		Names[i].Text = ObjectiveString@i+1;
	}
	Names[0].bBottom = True;
	Names[NumNames-1].bTop = True;

	// Back Button
	XPos = 192.0/1024 * XMod;
	YPos = 701.0/768 * YMod;
	XWidth = 64.0/1024 * XMod;
	YHeight = 64.0/768 * YMod;
	BackButton = NotifyButton(CreateWindow(class'NotifyButton', XPos, YPos, XWidth, YHeight));
	BackButton.DisabledTexture = Texture(DynamicLoadObject("UTMenu.LeftUp", Class'Texture'));
	BackButton.UpTexture = Texture(DynamicLoadObject("UTMenu.LeftUp", Class'Texture'));
	BackButton.DownTexture = Texture(DynamicLoadObject("UTMenu.LeftDown", Class'Texture'));
	BackButton.OverTexture = Texture(DynamicLoadObject("UTMenu.LeftOver", Class'Texture'));
	BackButton.NotifyWindow = Self;
	BackButton.Text = "";
	TextColor.R = 255;
	TextColor.G = 255;
	TextColor.B = 0;
	BackButton.SetTextColor(TextColor);
	BackButton.MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetBigFont(Root);
	BackButton.bStretched = True;
	BackButton.OverSound = sound'LadderSounds.lcursorMove';
	BackButton.DownSound = sound'LadderSounds.ladvance';

	// Next Button
	XPos = 256.0/1024 * XMod;
	YPos = 701.0/768 * YMod;
	XWidth = 64.0/1024 * XMod;
	YHeight = 64.0/768 * YMod;
	NextButton = NotifyButton(CreateWindow(class'NotifyButton', XPos, YPos, XWidth, YHeight));
	NextButton.DisabledTexture = Texture(DynamicLoadObject("UTMenu.RightUp", Class'Texture'));
	NextButton.UpTexture = Texture(DynamicLoadObject("UTMenu.RightUp", Class'Texture'));
	NextButton.DownTexture = Texture(DynamicLoadObject("UTMenu.RightDown", Class'Texture'));
	NextButton.OverTexture = Texture(DynamicLoadObject("UTMenu.RightOver", Class'Texture'));
	NextButton.NotifyWindow = Self;
	NextButton.Text = "";
	TextColor.R = 255;
	TextColor.G = 255;
	TextColor.B = 0;
	NextButton.SetTextColor(TextColor);
	NextButton.MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetBigFont(Root);
	NextButton.bStretched = True;
	NextButton.OverSound = sound'LadderSounds.lcursorMove';
	NextButton.DownSound = sound'LadderSounds.ladvance';

	// Obj Desc
	XPos = 529.0/1024 * XMod;
	YPos = 586.0/768 * YMod;
	XWidth = 385.0/1024 * XMod;
	YHeight = 113.0/768 * YMod;
	ObjDescArea = UTFadeTextArea(CreateWindow(Class<UWindowWindow>(DynamicLoadObject("UTMenu.UTFadeTextArea", Class'Class')), XPos, YPos, XWidth, YHeight));
	ObjDescArea.TextColor.R = 255;
	ObjDescArea.TextColor.G = 255;
	ObjDescArea.TextColor.B = 0;
	ObjDescArea.MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetSmallFont(Root);
	ObjDescArea.bAlwaysOnTop = True;
	ObjDescArea.bAutoScrolling = True;

	// DescScrollup
	XPos = 923.0/1024 * XMod;
	YPos = 590.0/768 * YMod;
	XWidth = 32.0/1024 * XMod;
	YHeight = 16.0/768 * YMod;
	DescScrollup = NotifyButton(CreateWindow(class'NotifyButton', XPos, YPos, XWidth, YHeight));
	DescScrollup.NotifyWindow = Self;
	DescScrollup.Text = "";
	DescScrollup.bStretched = True;
	DescScrollup.UpTexture = Texture(DynamicLoadObject("UTMenu.AroUup", Class'Texture'));
	DescScrollup.OverTexture = Texture(DynamicLoadObject("UTMenu.AroUovr", Class'Texture'));
	DescScrollup.DownTexture = Texture(DynamicLoadObject("UTMenu.AroUdwn", Class'Texture'));
	DescScrollup.MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetSmallFont(Root);
	DescScrollup.bAlwaysOnTop = True;

	// DescScrolldown
	XPos = 923.0/1024 * XMod;
	YPos = 683.0/768 * YMod;
	XWidth = 32.0/1024 * XMod;
	YHeight = 16.0/768 * YMod;
	DescScrolldown = NotifyButton(CreateWindow(class'NotifyButton', XPos, YPos, XWidth, YHeight));
	DescScrolldown.NotifyWindow = Self;
	DescScrolldown.Text = "";
	DescScrolldown.bStretched = True;
	DescScrolldown.UpTexture = Texture(DynamicLoadObject("UTMenu.AroDup", Class'Texture'));
	DescScrolldown.OverTexture = Texture(DynamicLoadObject("UTMenu.AroDovr", Class'Texture'));
	DescScrolldown.DownTexture = Texture(DynamicLoadObject("UTMenu.AroDdwn", Class'Texture'));
	DescScrolldown.MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetSmallFont(Root);
	DescScrolldown.bAlwaysOnTop = True;

	// StaticArea
	XPos = 608.0/1024 * XMod;
	YPos = 90.0/768 * YMod;
	XWidth = 320.0/1024 * XMod;
	YHeight = 319.0/768 * YMod;
	MapStatic = StaticArea(CreateWindow(class'StaticArea', XPos, YPos, XWidth, YHeight));
	MapStatic.VStaticScale = 300.0;

	Initialized = True;
	Root.Console.bBlackout = True;

	SelectedO = 0;
	SetMapShot(class'MyLadderAS'.Static.GetObjectiveShot(Match, 0, AI));
	AddObjDesc();
	StaticScale = 1.0;
}

function NameSelected(int i)
{
	local AssaultInfo AI;

	SelectedO = i;
	SetMapShot(class'MyLadderAS'.Static.GetObjectiveShot(Match, i, AI));
	AddObjDesc();
}

function AddObjDesc()
{
	local AssaultInfo AI;

	ObjDescArea.Clear();
	ObjDescArea.AddText(OrdersTransmissionText);
	ObjDescArea.AddText("---");
	ObjDescArea.AddText(class'MyLadderAS'.Static.GetObjectiveString(Match, SelectedO, AI));
}
Then, we subclass every one of the UTLadders: UTMenu.UTLadderAS (MyLadderASMenu) - UTMenu.UTLadderChal (MyLadderChalMenu) - UTMenu.UTLadderCTF (MyLadderCTFMenu) - UTMenu.UTLadderDM (MyLadderDMMenu) - UTMenu.UTLadderDOM (MyLadderDOMMenu). These differ between each other due to functionality (DM is a non-team-based ladder, DOM is a regular team-based ladder, CTF has a short name functionality and AS has the ObjectiveBrowser we've previously subclassed). Also, all of them extend the functionality of MyLadder and NOT UTLadder, since they're classes of that abstract class.

Code: Select all

class MyLadderASMenu extends MyLadder;

function Created()
{
	Super.Created();

	if (LadderObj.ASPosition == -1) {
		LadderObj.ASPosition = 1;
		SelectedMatch = 0;
	} else {
		SelectedMatch = LadderObj.ASPosition;
	}
	SetupLadder(LadderObj.ASPosition, LadderObj.ASRank);
}

function FillInfoArea(int i)
{
	MapInfoArea.Clear();
	MapInfoArea.AddText(MapText$" "$Ladder.Static.GetMapTitle(i));
	MapInfoArea.AddText(Ladder.Static.GetDesc(i));
}

function NextPressed()
{
	local ObjectiveBrowser OB;

	if (PendingPos > ArrowPos)
		return;

	HideWindow();
	OB = ObjectiveBrowser(Root.CreateWindow(class'MyObjectiveBrowser', 100, 100, 200, 200, Root, True));
	OB.LadderWindow = Self;
	OB.Ladder = Ladder;
	OB.Match = SelectedMatch;
	OB.GameType = GameType;
	OB.Initialize();
}

function EvaluateMatch(optional bool bTrophyVictory)
{
	if (LadderObj.PendingPosition > LadderObj.ASPosition)
	{
		PendingPos = LadderObj.PendingPosition;
		LadderObj.ASPosition = LadderObj.PendingPosition;
	}
	if (LadderObj.PendingRank > LadderObj.ASRank)
	{
		LadderObj.ASRank = LadderObj.PendingRank;
		LadderObj.PendingRank = 0;
	}
	LadderPos = LadderObj.ASPosition;
	LadderRank = LadderObj.ASRank;
	if (LadderObj.ASRank == 6)
		Super.EvaluateMatch(True);
	else
		Super.EvaluateMatch();
}

defaultproperties
{
	GameType="Botpack.Assault"
	TrophyMap="EOL_Assault.unr"
	LadderName="Assault"
	Ladder=Class'MyLadder.MyLadderAS'
	LadderTrophy=Texture'UTMenu.Skins.TrophyAS'
}

Code: Select all

class MyLadderCTFMenu extends MyLadder;

function Created()
{
	Super.Created();

	if (LadderObj.CTFPosition == -1) {
		LadderObj.CTFPosition = 1;
		SelectedMatch = 0;
	} else {
		SelectedMatch = LadderObj.CTFPosition;
	}
	SetupLadder(LadderObj.CTFPosition, LadderObj.CTFRank);
}

function FillInfoArea(int i)
{
	MapInfoArea.Clear();
	MapInfoArea.AddText(MapText$" "$LadderObj.CurrentLadder.Static.GetMapTitle(i));
	MapInfoArea.AddText(TeamScoreText$" "$LadderObj.CurrentLadder.Static.GetGoalTeamScore(i));
	MapInfoArea.AddText(LadderObj.CurrentLadder.Static.GetDesc(i));
}

function NextPressed()
{
	local TeamBrowser TB;
	local string MapName;

	if (PendingPos > ArrowPos)
		return;

	if (SelectedMatch == 0)
	{
		MapName = LadderObj.CurrentLadder.Default.MapPrefix$Ladder.Static.GetMap(0);
		CloseUp();
		StartMap(MapName, 0, "Botpack.TrainingCTF");
	} else {
		if (LadderObj.CurrentLadder.Default.DemoDisplay[SelectedMatch] == 1)
			return;

		HideWindow();
		TB = TeamBrowser(Root.CreateWindow(class'MyTeamBrowser', 100, 100, 200, 200, Root, True));
		TB.LadderWindow = Self;
		TB.Ladder = LadderObj.CurrentLadder;
		TB.Match = SelectedMatch;
		TB.GameType = GameType;
		TB.Initialize();
	}
}

function EvaluateMatch(optional bool bTrophyVictory)
{
	if (LadderObj.PendingPosition > LadderObj.CTFPosition)
	{
		if (class'UTLadderStub'.Static.IsDemo() && LadderObj.PendingPosition > 1)
		{
			PendingPos = 1;
		} else {
			PendingPos = LadderObj.PendingPosition;
			LadderObj.CTFPosition = LadderObj.PendingPosition;
		}
	}
	if (LadderObj.PendingRank > LadderObj.CTFRank)
	{
		LadderObj.CTFRank = LadderObj.PendingRank;
		LadderObj.PendingRank = 0;
	}
	LadderPos = LadderObj.CTFPosition;
	LadderRank = LadderObj.CTFRank;
	if (LadderObj.CTFRank == 6)
		Super.EvaluateMatch(True);
	else
		Super.EvaluateMatch();
}

function CheckOpenCondition()
{
	Super.CheckOpenCondition();
}

defaultproperties
{
	GameType="Botpack.CTFGame"
	TrophyMap="EOL_CTF.unr"
	LadderName="Capture The Flag"
	Ladder=Class'MyLadder.MyLadderCTF'
	LadderTrophy=Texture'UTMenu.Skins.TrophyCTF'
}

Code: Select all

class MyLadderDMMenu extends MyLadder;

function Created()
{
	Super.Created();

	if (LadderObj.DMPosition == -1) {
		LadderObj.DMPosition = 1;
		SelectedMatch = 0;
	} else {
		SelectedMatch = LadderObj.DMPosition;
	}
	SetupLadder(LadderObj.DMPosition, LadderObj.DMRank);
}

function FillInfoArea(int i)
{
	MapInfoArea.Clear();
	MapInfoArea.AddText(MapText$" "$LadderObj.CurrentLadder.Static.GetMapTitle(i));
	MapInfoArea.AddText(FragText$" "$LadderObj.CurrentLadder.Static.GetFragLimit(i));
	MapInfoArea.AddText(LadderObj.CurrentLadder.Static.GetDesc(i));
}

function NextPressed()
{
	local EnemyBrowser EB;
	local string MapName;

	if (PendingPos > ArrowPos)
		return;

	if (SelectedMatch == 0)
	{
		MapName = LadderObj.CurrentLadder.Default.MapPrefix$Ladder.Static.GetMap(0);
		CloseUp();
		StartMap(MapName, 0, "Botpack.TrainingDM");
	} else {
		HideWindow();
		EB = EnemyBrowser(Root.CreateWindow(class'MyEnemyBrowser', 100, 100, 200, 200, Root, True));
		EB.LadderWindow = Self;
		EB.Ladder = LadderObj.CurrentLadder;
		EB.Match = SelectedMatch;
		EB.GameType = GameType;
		EB.Initialize();
	}
}

function StartMap(string StartMap, int Rung, string GameType)
{
	local Class<GameInfo> GameClass;

	GameClass = Class<GameInfo>(DynamicLoadObject(GameType, Class'Class'));
	GameClass.Static.ResetGame();

	StartMap = StartMap
				$"?Game="$GameType
				$"?Mutator="
				$"?Tournament="$Rung
				$"?Name="$GetPlayerOwner().PlayerReplicationInfo.PlayerName
				$"?Team=255";

	Root.Console.CloseUWindow();
	GetPlayerOwner().ClientTravel(StartMap, TRAVEL_Absolute, True);
}

function EvaluateMatch(optional bool bTrophyVictory)
{
	local int Pos;
	local string MapName;

	if (LadderObj.PendingPosition > LadderObj.DMPosition)
	{
		PendingPos = LadderObj.PendingPosition;
		LadderObj.DMPosition = LadderObj.PendingPosition;
	}
	if (LadderObj.PendingRank > LadderObj.DMRank)
	{
		LadderObj.DMRank = LadderObj.PendingRank;
		LadderObj.PendingRank = 0;
	}
	LadderPos = LadderObj.DMPosition;
	LadderRank = LadderObj.DMRank;
	if (LadderObj.DMRank == 6)
		Super.EvaluateMatch(True);
	else
		Super.EvaluateMatch();
}

function CheckOpenCondition()
{
	Super.CheckOpenCondition();
}

defaultproperties
{
	GameType="Botpack.TeamGamePlus"
	TrophyMap="EOL_DeathMatch.unr"
	LadderName="Deathmatch"
	Ladder=Class'MyLadder.MyLadderDM'
	LadderTrophy=Texture'UTMenu.Skins.TrophyDM'
}

Code: Select all

class MyLadderDOMMenu extends MyLadder;

function Created()
{
	Super.Created();

	if (LadderObj.DOMPosition == -1) {
		LadderObj.DOMPosition = 1;
		SelectedMatch = 0;
	} else {
		SelectedMatch = LadderObj.DOMPosition;
	}
	SetupLadder(LadderObj.DOMPosition, LadderObj.DOMRank);
}

function FillInfoArea(int i)
{
	MapInfoArea.Clear();
	MapInfoArea.AddText(MapText$" "$LadderObj.CurrentLadder.Static.GetMapTitle(i));
	MapInfoArea.AddText(TeamScoreText$" "$LadderObj.CurrentLadder.Static.GetGoalTeamScore(i));
	MapInfoArea.AddText(LadderObj.CurrentLadder.Static.GetDesc(i));
}

function NextPressed()
{
	local TeamBrowser TB;
	local string MapName;

	if (PendingPos > ArrowPos)
		return;

	if (SelectedMatch == 0)
	{
		MapName = LadderObj.CurrentLadder.Default.MapPrefix$Ladder.Static.GetMap(0);
		CloseUp();
		StartMap(MapName, 0, "Botpack.TrainingDOM");
	} else {
		if (LadderObj.CurrentLadder.Default.DemoDisplay[SelectedMatch] == 1)
			return;

		HideWindow();
		TB = TeamBrowser(Root.CreateWindow(class'MyTeamBrowser', 100, 100, 200, 200, Root, True));
		TB.LadderWindow = Self;
		TB.Ladder = LadderObj.CurrentLadder;
		TB.Match = SelectedMatch;
		TB.GameType = GameType;
		TB.Initialize();
	}
}

function EvaluateMatch(optional bool bTrophyVictory)
{
	local int Pos;
	local string MapName;

	if (LadderObj.PendingPosition > LadderObj.DOMPosition)
	{
		PendingPos = LadderObj.PendingPosition;
		LadderObj.DOMPosition = LadderObj.PendingPosition;
	}
	if (LadderObj.PendingRank > LadderObj.DOMRank)
	{
		LadderObj.DOMRank = LadderObj.PendingRank;
		LadderObj.PendingRank = 0;
	}
	LadderPos = LadderObj.DOMPosition;
	LadderRank = LadderObj.DOMRank;
	if (LadderObj.DOMRank == 6)
		Super.EvaluateMatch(True);
	else
		Super.EvaluateMatch();
}

function CheckOpenCondition()
{
	Super.CheckOpenCondition();
}

defaultproperties
{
	GameType="Botpack.Domination"
	TrophyMap="EOL_Domination.unr"
	LadderName="Domination"
	Ladder=Class'MyLadder.MyLadderDOM'
	LadderTrophy=Texture'UTMenu.Skins.TrophyDOM'
}

Code: Select all

class MyLadderChalMenu extends MyLadder;

function Created()
{
	Super.Created();

	SelectedMatch = LadderObj.ChalPosition;
	SetupLadder(LadderObj.ChalPosition, LadderObj.ChalRank);
}

function FillInfoArea(int i)
{
	MapInfoArea.Clear();
	MapInfoArea.AddText(MapText$" "$Ladder.Static.GetMapTitle(i));
	MapInfoArea.AddText(FragText$" "$Ladder.Static.GetFragLimit(i));
	MapInfoArea.AddText(Ladder.Static.GetDesc(i));
}

function NextPressed()
{
	local EnemyBrowser EB;

	if (PendingPos > ArrowPos)
		return;

	HideWindow();
	EB = EnemyBrowser(Root.CreateWindow(class'MyEnemyBrowser', 100, 100, 200, 200, Root, True));
	EB.LadderWindow = Self;
	EB.Ladder = Ladder;
	EB.Match = SelectedMatch;
	if (SelectedMatch == 3)
		EB.GameType = "Botpack.ChallengeDMP";
	else
		EB.GameType = GameType;
	EB.Initialize();
}

function EvaluateMatch(optional bool bTrophyVictory)
{
	if (LadderObj.PendingPosition > LadderObj.ChalPosition)
	{
		PendingPos = LadderObj.PendingPosition;
		LadderObj.ChalPosition = LadderObj.PendingPosition;
	}
	if (LadderObj.PendingRank > LadderObj.ChalRank)
	{
		LadderObj.ChalRank = LadderObj.PendingRank;
		LadderObj.PendingRank = 0;
	}
	LadderPos = LadderObj.ChalPosition;
	LadderRank = LadderObj.ChalRank;
	if (LadderObj.ChalRank == 6)
		Super.EvaluateMatch(True);
	else
		Super.EvaluateMatch();

	Super.EvaluateMatch();
}

defaultproperties
{
	GameType="Botpack.ChallengeDMP"
	TrophyMap="EOL_Challenge.unr"
	LadderName="Final Challenge"
	Ladder=Class'MyLadder.MyLadderChal'
	LadderTrophy=Texture'UTMenu.Skins.TrophyChal'
}
To be continued...
Localization project coordinator/spanish maintainer

Only the people that do nothing but criticize don't make mistakes. Do things. Make mistakes. Learn from them. And screw those who do nothing but throw poison and criticize.
User avatar
Neon_Knight
OldUnreal Member
Posts: 378
Joined: Tue Aug 25, 2009 9:02 pm

Re: [WIP] TUTORIAL: How to create a custom SP ladder (UT99)

Post by Neon_Knight »

Step #4: (Cont) Writing the Code

Next we subclass UTMenu.NewCharacterWindow, we're naming it MyNewCharacterWindow. This is the character customization screen we're shown before entering the Ladder proper.

Code: Select all

class MyNewCharacterWindow extends NewCharacterWindow config(MyLadder);

function BackPressed ()
{
	SwitchBack();
	Close();
}

function EscClose ()
{
	SwitchBack();
	Close();
}

function SwitchBack ()
{
	UTConsole(GetPlayerOwner().Player.Console).ManagerWindowClass = "UTMenu.ManagerWindow";
	UTConsole(GetPlayerOwner().Player.Console).UTLadderDMClass = "UTMenu.UTLadderDM";
	UTConsole(GetPlayerOwner().Player.Console).UTLadderDOMClass = "UTMenu.UTLadderDOM";
	UTConsole(GetPlayerOwner().Player.Console).UTLadderCTFClass = "UTMenu.UTLadderCTF";
	UTConsole(GetPlayerOwner().Player.Console).UTLadderASClass = "UTMenu.UTLadderAS";
	UTConsole(GetPlayerOwner().Player.Console).UTLadderChalClass = "UTMenu.UTLadderChal";
	UTConsole(GetPlayerOwner().Player.Console).InterimObjectType = "UTMenu.NewGameInterimObject";
	UTConsole(GetPlayerOwner().Player.Console).SlotWindowType = "UTMenu.SlotWindow";
	Log("Now playing the original Unreal Tournament ladder.");
}

function StartLadder ()
{
	UTConsole(GetPlayerOwner().Player.Console).ManagerWindowClass = "MyLadder.MyManagerWindow";
	UTConsole(GetPlayerOwner().Player.Console).UTLadderDMClass = "MyLadder.MyLadderDMMenu";
	UTConsole(GetPlayerOwner().Player.Console).UTLadderDOMClass = "MyLadder.MyLadderDOMMenu";
	UTConsole(GetPlayerOwner().Player.Console).UTLadderCTFClass = "MyLadder.MyLadderCTFMenu";
	UTConsole(GetPlayerOwner().Player.Console).UTLadderASClass = "MyLadder.MyLadderASMenu";
	UTConsole(GetPlayerOwner().Player.Console).UTLadderChalClass = "MyLadder.MyLadderChalMenu";
	UTConsole(GetPlayerOwner().Player.Console).InterimObjectType = "MyLadder.MyNewGameInterimObject";
	UTConsole(GetPlayerOwner().Player.Console).SlotWindowType = "MyLadder.MySlotWindow";
	Log("Now playing my awesome ladder :3.");
}

function TeamPressed ()
{
	local string MeshName;

	PreferredTeam++;
	if (PreferredTeam == class'MyLadderLadder'.Default.NumTeams)
		PreferredTeam = 0;
	TeamButton.Text = Class'MyLadderLadder'.Default.LadderTeams[PreferredTeam].Default.TeamName;
	LadderObj.Team = Class'MyLadderLadder'.Default.LadderTeams[PreferredTeam];
	MaleClass = Class'MyLadderLadder'.Default.LadderTeams[PreferredTeam].Default.MaleClass;
	MaleSkin = Class'MyLadderLadder'.Default.LadderTeams[PreferredTeam].Default.MaleSkin;
	FemaleClass = Class'MyLadderLadder'.Default.LadderTeams[PreferredTeam].Default.FemaleClass;
	FemaleSkin = Class'MyLadderLadder'.Default.LadderTeams[PreferredTeam].Default.FemaleSkin;
	if ( (MaleClass == None) && (SexButton.Text ~= MaleText) )
	{
		TeamPressed();
	}
	if ( (FemaleClass == None) && (SexButton.Text ~= FemaleText) )
	{
		TeamPressed();
	}
	if ( SexButton.Text ~= MaleText )
	{
		IterateFaces(MaleSkin,GetPlayerOwner().GetItemName(string(MaleClass.Default.Mesh)));
		PreferredFace = 0;
		MeshName = MaleClass.Default.SelectionMesh;
		MeshWindow.SetMeshString(MeshName);
		MaleClass.static.SetMultiSkin(MeshWindow.MeshActor, MaleSkin, Faces[PreferredFace], 255);
		GetPlayerOwner().UpdateURL("Class",string(MaleClass),True);
		GetPlayerOwner().UpdateURL("Voice",MaleClass.Default.VoiceType,True);
		GetPlayerOwner().UpdateURL("Skin",MaleSkin,True);
		GetPlayerOwner().UpdateURL("Face",Faces[PreferredFace],True);
		FaceButton.Text = FaceDescs[PreferredFace];
		SexButton.Text = MaleText;
		PreferredSex = 0;
		LadderObj.Sex = "M";
	} else {
		IterateFaces(FemaleSkin,GetPlayerOwner().GetItemName(string(FemaleClass.Default.Mesh)));
		PreferredFace = 0;
		MeshName = FemaleClass.Default.SelectionMesh;
		MeshWindow.SetMeshString(MeshName);
		FemaleClass.static.SetMultiSkin(MeshWindow.MeshActor,FemaleSkin,Faces[PreferredFace],255);
		GetPlayerOwner().UpdateURL("Class",string(FemaleClass),True);
		GetPlayerOwner().UpdateURL("Voice",FemaleClass.Default.VoiceType,True);
		GetPlayerOwner().UpdateURL("Skin",FemaleSkin,True);
		GetPlayerOwner().UpdateURL("Face",Faces[PreferredFace],True);
		FaceButton.Text = FaceDescs[PreferredFace];
		SexButton.Text = FemaleText;
		PreferredSex = 1;
		LadderObj.Sex = "F";
	}
	TeamDescArea.Clear();
	TeamDescArea.AddText(TeamNameString @ LadderObj.Team.static.GetTeamName());
	TeamDescArea.AddText(" ");
	TeamDescArea.AddText(LadderObj.Team.static.GetTeamBio());
	SaveConfig();
}

function Created ()
{
	local string MeshName, SkinDesc, Temp;
	local int i;
	local int W, H;
	local float XWidth, YHeight, XMod, YMod, XPos, YPos;
	local color TextColor;

	Super.Created();

	/*
	 * Window parameters.
	 */

	bLeaveOnScreen = True;
	bAlwaysOnTop = True;

	class'UTLadderStub'.Static.GetStubClass().Static.SetupWinParams(Self, Root, W, H);

	XMod = 4*W;
	YMod = 3*H;

	/*
	 * Background.
	 */

	BG1[0] = Texture(DynamicLoadObject(BGName1[0], Class'Texture'));
	BG1[1] = Texture(DynamicLoadObject(BGName1[1], Class'Texture'));
	BG1[2] = Texture(DynamicLoadObject(BGName1[2], Class'Texture'));
	BG1[3] = Texture(DynamicLoadObject(BGName1[3], Class'Texture'));
	BG2[0] = Texture(DynamicLoadObject(BGName2[0], Class'Texture'));
	BG2[1] = Texture(DynamicLoadObject(BGName2[1], Class'Texture'));
	BG2[2] = Texture(DynamicLoadObject(BGName2[2], Class'Texture'));
	BG2[3] = Texture(DynamicLoadObject(BGName2[3], Class'Texture'));
	BG3[0] = Texture(DynamicLoadObject(BGName3[0], Class'Texture'));
	BG3[1] = Texture(DynamicLoadObject(BGName3[1], Class'Texture'));
	BG3[2] = Texture(DynamicLoadObject(BGName3[2], Class'Texture'));
	BG3[3] = Texture(DynamicLoadObject(BGName3[3], Class'Texture'));

	// Verify object state.
	LadderObj = LadderInventory(GetPlayerOwner().FindInventoryType(class'LadderInventory'));
	if (LadderObj == None)
	{
		Log("MyNewCharacterWindow: Player has no LadderInventory!!");
	}

	/*
	 * Create components.
	 */

	MaleClass = class'MyLadderLadder'.Default.LadderTeams[PreferredTeam].Default.MaleClass;
	MaleSkin = class'MyLadderLadder'.Default.LadderTeams[PreferredTeam].Default.MaleSkin;

	FemaleClass = class'MyLadderLadder'.Default.LadderTeams[PreferredTeam].Default.FemaleClass;
	FemaleSkin = class'MyLadderLadder'.Default.LadderTeams[PreferredTeam].Default.FemaleSkin;

	IterateFaces(MaleSkin, GetPlayerOwner().GetItemName(string(MaleClass.Default.Mesh)));

	LadderObj.Face = PreferredFace;

	// MeshView
	XPos = 608.0/1024 * XMod;
	YPos = 88.0/768 * YMod;
	XWidth = 323.0/1024 * XMod;
	YHeight = 466.0/768 * YMod;
	MeshWindow = UMenuPlayerMeshClient(CreateWindow(class'UMenuPlayerMeshClient', XPos, YPos, XWidth, YHeight));
	MeshWindow.SetMeshString(MaleClass.Default.SelectionMesh);
	MeshWindow.ClearSkins();
	MaleClass.static.SetMultiSkin(MeshWindow.MeshActor, MaleSkin, MaleFace, 255);
	GetPlayerOwner().UpdateURL("Class", "Botpack."$string(MaleClass.Name), True);
	GetPlayerOwner().UpdateURL("Skin", MaleSkin, True);
	GetPlayerOwner().UpdateURL("Face", Faces[PreferredFace], True);
	GetPlayerOwner().UpdateURL("Team", "255", True);
	GetPlayerOwner().UpdateURL("Voice", MaleClass.Default.VoiceType, True);

	// Name Label
	XPos = 164.0/1024 * XMod;
	YPos = 263.0/768 * YMod;
	XWidth = 256.0/1024 * XMod;
	YHeight = 64.0/768 * YMod;
	NameLabel = NotifyButton(CreateWindow(class'NotifyButton', XPos, YPos, XWidth, YHeight));
	NameLabel.NotifyWindow = Self;
	NameLabel.Text = NameText;
	TextColor.R = 255;
	TextColor.G = 255;
	TextColor.B = 0;
	NameLabel.SetTextColor(TextColor);
	NameLabel.MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetBigFont(Root);
	NameLabel.bStretched = True;
	NameLabel.bDisabled = True;
	NameLabel.bDontSetLabel = True;
	NameLabel.LabelWidth = 178.0/1024 * XMod;
	NameLabel.LabelHeight = 49.0/768 * YMod;

	// Name Button
	XPos = 164.0/1024 * XMod;
	YPos = 295.0/768 * YMod;
	XWidth = 256.0/1024 * XMod;
	YHeight = 64.0/768 * YMod;
	NameButton = NotifyButton(CreateWindow(class'NotifyButton', XPos, YPos, XWidth, YHeight));
	NameButton.NotifyWindow = Self;
	TextColor.R = 255;
	TextColor.G = 255;
	TextColor.B = 0;
	NameButton.SetTextColor(TextColor);
	NameButton.MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetBigFont(Root);
	NameButton.bStretched = True;
	NameButton.bDisabled = True;
	NameButton.DisabledTexture = Texture(DynamicLoadObject("UTMenu.Plate3Plain", Class'Texture'));
	NameButton.bDontSetLabel = True;
	NameButton.LabelWidth = 178.0/1024 * XMod;
	NameButton.LabelHeight = 49.0/768 * YMod;
	NameButton.OverSound = sound'LadderSounds.lcursorMove';
	NameButton.DownSound = sound'SpeechWindowClick';

	// Name Edit
	XPos = 164.0/1024 * XMod;
	YPos = 295.0/768 * YMod;
	XWidth = 178.0/1024 * XMod;
	YHeight = 49.0/768 * YMod;
	NameEdit = NameEditBox(CreateWindow(class'NameEditBox', XPos, YPos, XWidth, YHeight));
	NameEdit.bDelayedNotify = True;
	NameEdit.SetValue(GetPlayerOwner().PlayerReplicationInfo.PlayerName);
	NameEdit.CharacterWindow = Self;
	NameEdit.bCanEdit = True;
	NameEdit.bShowCaret = True;
	NameEdit.bAlwaysOnTop = True;
	NameEdit.bSelectOnFocus = True;
	NameEdit.MaxLength = 20;
	NameEdit.TextColor.R = 255;
	NameEdit.TextColor.G = 255;
	NameEdit.TextColor.B = 0;

	// Sex Label
	XPos = 164.0/1024 * XMod;
	YPos = 338.0/768 * YMod;
	XWidth = 256.0/1024 * XMod;
	YHeight = 64.0/768 * YMod;
	SexLabel = NotifyButton(CreateWindow(class'NotifyButton', XPos, YPos, XWidth, YHeight));
	SexLabel.NotifyWindow = Self;
	SexLabel.Text = SexText;
	TextColor.R = 255;
	TextColor.G = 255;
	TextColor.B = 0;
	SexLabel.SetTextColor(TextColor);
	SexLabel.MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetBigFont(Root);
	SexLabel.bStretched = True;
	SexLabel.bDisabled = True;
	SexLabel.bDontSetLabel = True;
	SexLabel.LabelWidth = 178.0/1024 * XMod;
	SexLabel.LabelHeight = 49.0/768 * YMod;

	// Sex Button
	XPos = 164.0/1024 * XMod;
	YPos = 370.0/768 * YMod;
	XWidth = 256.0/1024 * XMod;
	YHeight = 64.0/768 * YMod;
	SexButton = NotifyButton(CreateWindow(class'NotifyButton', XPos, YPos, XWidth, YHeight));
	SexButton.NotifyWindow = Self;
	SexButton.Text = MaleText;
	TextColor.R = 255;
	TextColor.G = 255;
	TextColor.B = 0;
	SexButton.SetTextColor(TextColor);
	SexButton.MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetBigFont(Root);
	SexButton.bStretched = True;
	SexButton.UpTexture = Texture(DynamicLoadObject("UTMenu.Plate3Plain", Class'Texture'));
	SexButton.DownTexture = Texture(DynamicLoadObject("UTMenu.PlateYellow2", Class'Texture'));
	SexButton.OverTexture = Texture(DynamicLoadObject("UTMenu.Plate2", Class'Texture'));
	SexButton.bDontSetLabel = True;
	SexButton.LabelWidth = 178.0/1024 * XMod;
	SexButton.LabelHeight = 49.0/768 * YMod;
	SexButton.bIgnoreLDoubleclick = True;
	SexButton.OverSound = sound'LadderSounds.lcursorMove';
	SexButton.DownSound = sound'SpeechWindowClick';

	// Team Label
	XPos = 164.0/1024 * XMod;
	YPos = 413.0/768 * YMod;
	XWidth = 256.0/1024 * XMod;
	YHeight = 64.0/768 * YMod;
	TeamLabel = NotifyButton(CreateWindow(class'NotifyButton', XPos, YPos, XWidth, YHeight));
	TeamLabel.NotifyWindow = Self;
	TeamLabel.Text = TeamText;
	TextColor.R = 255;
	TextColor.G = 255;
	TextColor.B = 0;
	TeamLabel.SetTextColor(TextColor);
	TeamLabel.MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetBigFont(Root);
	TeamLabel.bStretched = True;
	TeamLabel.bDisabled = True;
	TeamLabel.bDontSetLabel = True;
	TeamLabel.LabelWidth = 178.0/1024 * XMod;
	TeamLabel.LabelHeight = 49.0/768 * YMod;

	// Team Button
	XPos = 164.0/1024 * XMod;
	YPos = 445.0/768 * YMod;
	XWidth = 256.0/1024 * XMod;
	YHeight = 64.0/768 * YMod;
	TeamButton = NotifyButton(CreateWindow(class'NotifyButton', XPos, YPos, XWidth, YHeight));
	TeamButton.NotifyWindow = Self;
	TextColor.R = 255;
	TextColor.G = 255;
	TextColor.B = 0;
	TeamButton.SetTextColor(TextColor);
	TeamButton.MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetBigFont(Root);
	TeamButton.bStretched = True;
	TeamButton.UpTexture = Texture(DynamicLoadObject("UTMenu.Plate3Plain", Class'Texture'));
	TeamButton.DownTexture = Texture(DynamicLoadObject("UTMenu.PlateYellow2", Class'Texture'));
	TeamButton.OverTexture = Texture(DynamicLoadObject("UTMenu.Plate2", Class'Texture'));
	TeamButton.bDontSetLabel = True;
	TeamButton.LabelWidth = 178.0/1024 * XMod;
	TeamButton.LabelHeight = 49.0/768 * YMod;
	TeamButton.bIgnoreLDoubleclick = True;
	if (PreferredTeam == class'MyLadderLadder'.Default.NumTeams)
		PreferredTeam = 0;
	TeamButton.Text = class'MyLadderLadder'.Default.LadderTeams[PreferredTeam].Default.TeamName;
	LadderObj.Team = class'MyLadderLadder'.Default.LadderTeams[PreferredTeam];
	TeamButton.OverSound = sound'LadderSounds.lcursorMove';
	TeamButton.DownSound = sound'SpeechWindowClick';

	// Face Label
	XPos = 164.0/1024 * XMod;
	YPos = 488.0/768 * YMod;
	XWidth = 256.0/1024 * XMod;
	YHeight = 64.0/768 * YMod;
	FaceLabel = NotifyButton(CreateWindow(class'NotifyButton', XPos, YPos, XWidth, YHeight));
	FaceLabel.NotifyWindow = Self;
	FaceLabel.Text = FaceText;
	TextColor.R = 255;
	TextColor.G = 255;
	TextColor.B = 0;
	FaceLabel.SetTextColor(TextColor);
	FaceLabel.MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetBigFont(Root);
	FaceLabel.bStretched = True;
	FaceLabel.bDisabled = True;
	FaceLabel.bDontSetLabel = True;
	FaceLabel.LabelWidth = 178.0/1024 * XMod;
	FaceLabel.LabelHeight = 49.0/768 * YMod;

	// Face Button
	XPos = 164.0/1024 * XMod;
	YPos = 520.0/768 * YMod;
	XWidth = 256.0/1024 * XMod;
	YHeight = 64.0/768 * YMod;
	FaceButton = NotifyButton(CreateWindow(class'NotifyButton', XPos, YPos, XWidth, YHeight));
	FaceButton.NotifyWindow = Self;
	FaceButton.Text = FaceDescs[PreferredFace];
	TextColor.R = 255;
	TextColor.G = 255;
	TextColor.B = 0;
	FaceButton.SetTextColor(TextColor);
	FaceButton.MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetBigFont(Root);
	FaceButton.bStretched = True;
	FaceButton.UpTexture = Texture(DynamicLoadObject("UTMenu.Plate3Plain", Class'Texture'));
	FaceButton.DownTexture = Texture(DynamicLoadObject("UTMenu.PlateYellow2", Class'Texture'));
	FaceButton.OverTexture = Texture(DynamicLoadObject("UTMenu.Plate2", Class'Texture'));
	FaceButton.bDontSetLabel = True;
	FaceButton.LabelWidth = 178.0/1024 * XMod;
	FaceButton.LabelHeight = 49.0/768 * YMod;
	FaceButton.bIgnoreLDoubleclick = True;
	FaceButton.OverSound = sound'LadderSounds.lcursorMove';
	FaceButton.DownSound = sound'SpeechWindowClick';

	// Skill Label
	XPos = 164.0/1024 * XMod;
	YPos = 563.0/768 * YMod;
	XWidth = 256.0/1024 * XMod;
	YHeight = 64.0/768 * YMod;
	SkillLabel = NotifyButton(CreateWindow(class'NotifyButton', XPos, YPos, XWidth, YHeight));
	SkillLabel.NotifyWindow = Self;
	SkillLabel.Text = SkillsText;
	TextColor.R = 255;
	TextColor.G = 255;
	TextColor.B = 0;
	SkillLabel.SetTextColor(TextColor);
	SkillLabel.MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetBigFont(Root);
	SkillLabel.bStretched = True;
	SkillLabel.bDisabled = True;
	SkillLabel.bDontSetLabel = True;
	SkillLabel.LabelWidth = 178.0/1024 * XMod;
	SkillLabel.LabelHeight = 49.0/768 * YMod;

	// Skill Button
	XPos = 164.0/1024 * XMod;
	YPos = 595.0/768 * YMod;
	XWidth = 256.0/1024 * XMod;
	YHeight = 64.0/768 * YMod;
	SkillButton = NotifyButton(CreateWindow(class'NotifyButton', XPos, YPos, XWidth, YHeight));
	SkillButton.NotifyWindow = Self;
	SkillButton.Text = SkillText[1];
	CurrentSkill = 1;
	TextColor.R = 255;
	TextColor.G = 255;
	TextColor.B = 0;
	SkillButton.SetTextColor(TextColor);
	SkillButton.MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetBigFont(Root);
	SkillButton.bStretched = True;
	SkillButton.UpTexture = Texture(DynamicLoadObject("UTMenu.Plate3Plain", Class'Texture'));
	SkillButton.DownTexture = Texture(DynamicLoadObject("UTMenu.PlateYellow2", Class'Texture'));
	SkillButton.OverTexture = Texture(DynamicLoadObject("UTMenu.Plate2", Class'Texture'));
	SkillButton.bDontSetLabel = True;
	SkillButton.LabelWidth = 178.0/1024 * XMod;
	SkillButton.LabelHeight = 49.0/768 * YMod;
	SkillButton.bIgnoreLDoubleclick = True;
	CurrentSkill = PreferredSkill;
	SkillButton.Text = SkillText[CurrentSkill];
	LadderObj.TournamentDifficulty = CurrentSkill;
	LadderObj.SkillText = SkillText[LadderObj.TournamentDifficulty];
	SkillButton.OverSound = sound'LadderSounds.lcursorMove';
	SkillButton.DownSound = sound'SpeechWindowClick';

	// Title Button
	XPos = 84.0/1024 * XMod;
	YPos = 69.0/768 * YMod;
	XWidth = 342.0/1024 * XMod;
	YHeight = 41.0/768 * YMod;
	TitleButton = NotifyButton(CreateWindow(class'NotifyButton', XPos, YPos, XWidth, YHeight));
	TitleButton.NotifyWindow = Self;
	TitleButton.Text = CCText;
	TextColor.R = 255;
	TextColor.G = 255;
	TextColor.B = 0;
	TitleButton.SetTextColor(TextColor);
	TitleButton.MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetHugeFont(Root);
	TitleButton.bStretched = True;

	// Back Button
	XPos = 192.0/1024 * XMod;
	YPos = 701.0/768 * YMod;
	XWidth = 64.0/1024 * XMod;
	YHeight = 64.0/768 * YMod;
	BackButton = NotifyButton(CreateWindow(class'NotifyButton', XPos, YPos, XWidth, YHeight));
	BackButton.DisabledTexture = Texture(DynamicLoadObject("UTMenu.LeftUp", Class'Texture'));
	BackButton.UpTexture = Texture(DynamicLoadObject("UTMenu.LeftUp", Class'Texture'));
	BackButton.DownTexture = Texture(DynamicLoadObject("UTMenu.LeftDown", Class'Texture'));
	BackButton.OverTexture = Texture(DynamicLoadObject("UTMenu.LeftOver", Class'Texture'));
	BackButton.NotifyWindow = Self;
	BackButton.Text = "";
	TextColor.R = 255;
	TextColor.G = 255;
	TextColor.B = 0;
	BackButton.SetTextColor(TextColor);
	BackButton.MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetBigFont(Root);
	BackButton.bStretched = True;
	BackButton.OverSound = sound'LadderSounds.lcursorMove';
	BackButton.DownSound = sound'LadderSounds.ladvance';

	// Next Button
	XPos = 256.0/1024 * XMod;
	YPos = 701.0/768 * YMod;
	XWidth = 64.0/1024 * XMod;
	YHeight = 64.0/768 * YMod;
	NextButton = NotifyButton(CreateWindow(class'NotifyButton', XPos, YPos, XWidth, YHeight));
	NextButton.DisabledTexture = Texture(DynamicLoadObject("UTMenu.RightUp", Class'Texture'));
	NextButton.UpTexture = Texture(DynamicLoadObject("UTMenu.RightUp", Class'Texture'));
	NextButton.DownTexture = Texture(DynamicLoadObject("UTMenu.RightDown", Class'Texture'));
	NextButton.OverTexture = Texture(DynamicLoadObject("UTMenu.RightOver", Class'Texture'));
	NextButton.NotifyWindow = Self;
	NextButton.Text = "";
	TextColor.R = 255;
	TextColor.G = 255;
	TextColor.B = 0;
	NextButton.SetTextColor(TextColor);
	NextButton.MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetBigFont(Root);
	NextButton.bStretched = True;
	NextButton.OverSound = sound'LadderSounds.lcursorMove';
	NextButton.DownSound = sound'LadderSounds.ladvance';

	// Team Desc
	XPos = 609.0/1024 * XMod;
	YPos = 388.0/768 * YMod;
	XWidth = 321.0/1024 * XMod;
	YHeight = 113.0/768 * YMod;
	TeamDescArea = UTFadeTextArea(CreateWindow(Class<UWindowWindow>(DynamicLoadObject("UTMenu.UTFadeTextArea", Class'Class')), XPos, YPos, XWidth, YHeight));
	TeamDescArea.TextColor.R = 255;
	TeamDescArea.TextColor.G = 255;
	TeamDescArea.TextColor.B = 0;
	TeamDescArea.MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetSmallFont(Root);
	TeamDescArea.bAlwaysOnTop = True;
	TeamDescArea.bMousePassThrough = True;
	TeamDescArea.bAutoScrolling = True;
	TeamDescArea.Clear();
	TeamDescArea.AddText(TeamNameString@LadderObj.Team.Static.GetTeamName());
	TeamDescArea.AddText(" ");
	TeamDescArea.AddText(LadderObj.Team.Static.GetTeamBio());

	// DescScrollup
	XPos = 715.0/1024 * XMod;
	YPos = 538.0/768 * YMod;
	XWidth = 32.0/1024 * XMod;
	YHeight = 16.0/768 * YMod;
	DescScrollup = NotifyButton(CreateWindow(class'NotifyButton', XPos, YPos, XWidth, YHeight));
	DescScrollup.NotifyWindow = Self;
	DescScrollup.Text = "";
	DescScrollup.bStretched = True;
	DescScrollup.UpTexture = Texture(DynamicLoadObject("UTMenu.AroUup", Class'Texture'));
	DescScrollup.OverTexture = Texture(DynamicLoadObject("UTMenu.AroUovr", Class'Texture'));
	DescScrollup.DownTexture = Texture(DynamicLoadObject("UTMenu.AroUdwn", Class'Texture'));
	DescScrollup.MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetSmallFont(Root);
	DescScrollup.bAlwaysOnTop = True;

	// DescScrolldown
	XPos = 799.0/1024 * XMod;
	YPos = 538.0/768 * YMod;
	XWidth = 32.0/1024 * XMod;
	YHeight = 16.0/768 * YMod;
	DescScrolldown = NotifyButton(CreateWindow(class'NotifyButton', XPos, YPos, XWidth, YHeight));
	DescScrolldown.NotifyWindow = Self;
	DescScrolldown.Text = "";
	DescScrolldown.bStretched = True;
	DescScrolldown.UpTexture = Texture(DynamicLoadObject("UTMenu.AroDup", Class'Texture'));
	DescScrolldown.OverTexture = Texture(DynamicLoadObject("UTMenu.AroDovr", Class'Texture'));
	DescScrolldown.DownTexture = Texture(DynamicLoadObject("UTMenu.AroDdwn", Class'Texture'));
	DescScrolldown.MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetSmallFont(Root);
	DescScrolldown.bAlwaysOnTop = True;

	if (PreferredSex == 1)
	{
		LadderObj.Sex = "F";
		SexButton.Text = MaleText;
	} else {
		LadderObj.Sex = "M";
		SexButton.Text = FemaleText;
	}
	SexPressed();

	Initialized = True;
	Root.Console.bBlackout = True;
}

function NextPressed ()
{
	local int i;
	local ManagerWindow ManagerWindow;

	StartLadder();
	if ( LadderObj.Sex ~= "F" )
	{
		SexButton.Text = MaleText;
	} else {
		SexButton.Text = FemaleText;
	}
	SexPressed();
	LadderObj.DMRank = 0;
	LadderObj.DMPosition = -1;
	LadderObj.CTFRank = 0;
	LadderObj.CTFPosition = -1;
	LadderObj.DOMRank = 0;
	LadderObj.DOMPosition = -1;
	LadderObj.ASRank = 0;
	LadderObj.ASPosition = -1;
	LadderObj.ChalRank = 0;
	LadderObj.ChalPosition = 0;
	LadderObj = None;
	Close();
	ManagerWindow = ManagerWindow(Root.CreateWindow(Class'MyManagerWindow',100.0,100.0,200.0,200.0,Root,True));
}
All that remains is to subclass UTMenu.ManagerWindow, as MyManagerWindow.

Code: Select all

class MyManagerWindow extends ManagerWindow Config(MyLadder);

function StartLadder ()
{
	UTConsole(GetPlayerOwner().Player.Console).ManagerWindowClass = "MyLadder.MyManagerWindow";
	UTConsole(GetPlayerOwner().Player.Console).UTLadderDMClass = "MyLadder.MyLadderDMMenu";
	UTConsole(GetPlayerOwner().Player.Console).UTLadderDOMClass = "MyLadder.MyLadderDOMMenu";
	UTConsole(GetPlayerOwner().Player.Console).UTLadderCTFClass = "MyLadder.MyLadderCTFMenu";
	UTConsole(GetPlayerOwner().Player.Console).UTLadderASClass = "MyLadder.MyLadderASMenu";
	UTConsole(GetPlayerOwner().Player.Console).UTLadderChalClass = "MyLadder.MyLadderChalMenu";
	UTConsole(GetPlayerOwner().Player.Console).InterimObjectType = "MyLadder.MyNewGameInterimObject";
	UTConsole(GetPlayerOwner().Player.Console).SlotWindowType = "MyLadder.MySlotWindow";
	Log("Now playing my awesome ladder :3.");
}

function SwitchBack ()
{
	UTConsole(GetPlayerOwner().Player.Console).ManagerWindowClass = "UTMenu.ManagerWindow";
	UTConsole(GetPlayerOwner().Player.Console).UTLadderDMClass = "UTMenu.UTLadderDM";
	UTConsole(GetPlayerOwner().Player.Console).UTLadderDOMClass = "UTMenu.UTLadderDOM";
	UTConsole(GetPlayerOwner().Player.Console).UTLadderCTFClass = "UTMenu.UTLadderCTF";
	UTConsole(GetPlayerOwner().Player.Console).UTLadderASClass = "UTMenu.UTLadderAS";
	UTConsole(GetPlayerOwner().Player.Console).UTLadderChalClass = "UTMenu.UTLadderChal";
	UTConsole(GetPlayerOwner().Player.Console).InterimObjectType = "UTMenu.NewGameInterimObject";
	UTConsole(GetPlayerOwner().Player.Console).SlotWindowType = "UTMenu.SlotWindow";
	Log("Now playing the original Unreal Tournament ladder.");
}

function Created()
{
	local float Xs, Ys;
	local int i;
	local int W, H;
	local float XWidth, YHeight, XMod, YMod, XPos, YPos;
	local color TextColor;

	Super.Created();

	/*
	 * Window parameters.
	 */

	bLeaveOnScreen = True;
	bAlwaysOnTop = True;
	class'UTLadderStub'.Static.GetStubClass().Static.SetupWinParams(Self, Root, W, H);

	XMod = 4*W;
	YMod = 3*H;

	/*
	 * Fondo.
	 */

	BG1[0] = Texture(DynamicLoadObject(BGName1[0], Class'Texture'));
	BG1[1] = Texture(DynamicLoadObject(BGName1[1], Class'Texture'));
	BG1[2] = Texture(DynamicLoadObject(BGName1[2], Class'Texture'));
	BG1[3] = Texture(DynamicLoadObject(BGName1[3], Class'Texture'));
	BG2[0] = Texture(DynamicLoadObject(BGName2[0], Class'Texture'));
	BG2[1] = Texture(DynamicLoadObject(BGName2[1], Class'Texture'));
	BG2[2] = Texture(DynamicLoadObject(BGName2[2], Class'Texture'));
	BG2[3] = Texture(DynamicLoadObject(BGName2[3], Class'Texture'));
	BG3[0] = Texture(DynamicLoadObject(BGName3[0], Class'Texture'));
	BG3[1] = Texture(DynamicLoadObject(BGName3[1], Class'Texture'));
	BG3[2] = Texture(DynamicLoadObject(BGName3[2], Class'Texture'));
	BG3[3] = Texture(DynamicLoadObject(BGName3[3], Class'Texture'));

	/*
	 * Window components.
	 */

	// Check ladder object.
	LadderObj = LadderInventory(GetPlayerOwner().FindInventoryType(class'LadderInventory'));
	if (LadderObj == None)
	{
		Log("MyManagerWindow: Player has no LadderInventory!!");
	}
	LadderObj.LastMatchType = 0;

	// Deathmatch door.
	XPos = 95.0/1024 * XMod;
	YPos = 102.0/768 * YMod;
	XWidth = 307.0/1024 * XMod;
	YHeight = 44.0/768 * YMod;
	DMLadderButton = NotifyButton(CreateWindow(class'NotifyButton', XPos, YPos, XWidth, YHeight));
	DMLadderButton.NotifyWindow = Self;
	DMLadderButton.bStretched = True;
	DMLadderButton.Text = DMText;
	TextColor.R = 255;
	TextColor.G = 255;
	TextColor.B = 0;
	DMLadderButton.SetTextColor(TextColor);
	DMLadderButton.MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetHugeFont(Root);

	// Domination ladder.
	XPos = 95.0/1024 * XMod;
	YPos = 231.0/768 * YMod;
	XWidth = 307.0/1024 * XMod;
	YHeight = 44.0/768 * YMod;
	DOMLadderButton = NotifyButton(CreateWindow(class'NotifyButton', XPos, YPos, XWidth, YHeight));
	DOMLadderButton.NotifyWindow = Self;
	DOMLadderButton.bStretched = True;
	DOMLadderButton.Text = DOMText;
	TextColor.R = 255;
	TextColor.G = 0;
	TextColor.B = 0;
	DOMLadderButton.SetTextColor(TextColor);
	DOMLadderButton.MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetHugeFont(Root);

	// Domination door.
	if (DOMDoorOpen[LadderObj.Slot] == 0)
	{
		XPos = 83.0/1024 * XMod;
		YPos = 222.0/768 * YMod;
		XWidth = 332.0/1024 * XMod;
		YHeight = 63.0/768 * YMod;
		DOMDoor = DoorArea(CreateWindow(class'DoorArea', XPos, YPos, XWidth, YHeight));
		DOMDoor.bClosed = True;
	}

	// CTF ladder.
	XPos = 95.0/1024 * XMod;
	YPos = 363.0/768 * YMod;
	XWidth = 307.0/1024 * XMod;
	YHeight = 44.0/768 * YMod;
	CTFLadderButton = NotifyButton(CreateWindow(class'NotifyButton', XPos, YPos, XWidth, YHeight));
	CTFLadderButton.NotifyWindow = Self;
	CTFLadderButton.bStretched = True;
	if (LadderObj.CTFRank == 6)
		CTFLadderButton.Text = "    "$CTFText;
	else
		CTFLadderButton.Text = CTFText;
	TextColor.R = 255;
	TextColor.G = 0;
	TextColor.B = 0;
	CTFLadderButton.SetTextColor(TextColor);
	CTFLadderButton.MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetHugeFont(Root);

	// CTF door.
	if (CTFDoorOpen[LadderObj.Slot] == 0)
	{
		XPos = 83.0/1024 * XMod;
		YPos = 356.0/768 * YMod;
		XWidth = 332.0/1024 * XMod;
		YHeight = 63.0/768 * YMod;
		CTFDoor = DoorArea(CreateWindow(class'DoorArea', XPos, YPos, XWidth, YHeight));
		CTFDoor.bClosed = True;
	}

	// Assault Ladder.
	XPos = 95.0/1024 * XMod;
	YPos = 497.0/768 * YMod;
	XWidth = 307.0/1024 * XMod;
	YHeight = 44.0/768 * YMod;
	ASLadderButton = NotifyButton(CreateWindow(class'NotifyButton', XPos, YPos, XWidth, YHeight));
	ASLadderButton.NotifyWindow = Self;
	ASLadderButton.bStretched = True;
	ASLadderButton.Text = ASText;
	TextColor.R = 255;
	TextColor.G = 0;
	TextColor.B = 0;
	ASLadderButton.SetTextColor(TextColor);
	ASLadderButton.MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetHugeFont(Root);

	// Assault door.
	if (ASDoorOpen[LadderObj.Slot] == 0)
	{
		XPos = 83.0/1024 * XMod;
		YPos = 488.0/768 * YMod;
		XWidth = 332.0/1024 * XMod;
		YHeight = 63.0/768 * YMod;
		ASDoor = DoorArea(CreateWindow(class'DoorArea', XPos, YPos, XWidth, YHeight));
		ASDoor.bClosed = True;
	}

	// Challenge ladder.
	XPos = 95.0/1024 * XMod;
	YPos = 627.0/768 * YMod;
	XWidth = 307.0/1024 * XMod;
	YHeight = 44.0/768 * YMod;
	ChallengeLadderButton = NotifyButton(CreateWindow(class'NotifyButton', XPos, YPos, XWidth, YHeight));
	ChallengeLadderButton.NotifyWindow = Self;
	ChallengeLadderButton.bStretched = True;
	ChallengeLadderButton.Text = ChallengeText;
	TextColor.R = 255;
	TextColor.G = 0;
	TextColor.B = 0;
	ChallengeLadderButton.SetTextColor(TextColor);
	ChallengeLadderButton.MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetHugeFont(Root);

	// Challenge door.
	if (ChalDoorOpen[LadderObj.Slot] == 0)
	{
		XPos = 83.0/1024 * XMod;
		YPos = 618.0/768 * YMod;
		XWidth = 332.0/1024 * XMod;
		YHeight = 63.0/768 * YMod;
		ChalDoor = DoorArea(CreateWindow(class'DoorArea', XPos, YPos, XWidth, YHeight));
		ChalDoor.bClosed = True;
	}

	// Trophy room.
	XPos = 656.0/1024 * XMod;
	YPos = 63.0/768 * YMod;
	XWidth = 222.0/1024 * XMod;
	YHeight = 50.0/768 * YMod;
	TrophyButton = NotifyButton(CreateWindow(class'NotifyButton', XPos, YPos, XWidth, YHeight));
	TrophyButton.NotifyWindow = Self;
	TrophyButton.bStretched = True;
	TrophyButton.Text = TrophyText;
	TextColor.R = 255;
	TextColor.G = 0;
	TextColor.B = 0;
	TrophyButton.SetTextColor(TextColor);
	TrophyButton.MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetHugeFont(Root);

	// Trophy door.
	if (TrophyDoorOpen[LadderObj.Slot] == 0)
	{
		XPos = 649.0/1024 * XMod;
		YPos = 57.0/768 * YMod;
		XWidth = 236.0/1024 * XMod;
		YHeight = 62.0/768 * YMod;
		TrophyDoor = DoorArea(CreateWindow(class'DoorArea', XPos, YPos, XWidth, YHeight));
		TrophyDoor.bClosed = True;
	}

	// Back button.
	XPos = 192.0/1024 * XMod;
	YPos = 701.0/768 * YMod;
	XWidth = 64.0/1024 * XMod;
	YHeight = 64.0/768 * YMod;
	BackButton = NotifyButton(CreateWindow(class'NotifyButton', XPos, YPos, XWidth, YHeight));
	BackButton.DisabledTexture = Texture(DynamicLoadObject("UTMenu.LeftUp", Class'Texture'));
	BackButton.UpTexture = Texture(DynamicLoadObject("UTMenu.LeftUp", Class'Texture'));
	BackButton.DownTexture = Texture(DynamicLoadObject("UTMenu.LeftDown", Class'Texture'));
	BackButton.OverTexture = Texture(DynamicLoadObject("UTMenu.LeftOver", Class'Texture'));
	BackButton.NotifyWindow = Self;
	BackButton.Text = "";
	TextColor.R = 255;
	TextColor.G = 255;
	TextColor.B = 0;
	BackButton.SetTextColor(TextColor);
	BackButton.MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetHugeFont(Root);
	BackButton.bStretched = True;
	BackButton.OverSound = sound'LadderSounds.lcursorMove';
	BackButton.DownSound = sound'LadderSounds.ladvance';

	// Next button.
	XPos = 256.0/1024 * XMod;
	YPos = 701.0/768 * YMod;
	XWidth = 64.0/1024 * XMod;
	YHeight = 64.0/768 * YMod;
	NextButton = NotifyButton(CreateWindow(class'NotifyButton', XPos, YPos, XWidth, YHeight));
	NextButton.DisabledTexture = Texture(DynamicLoadObject("UTMenu.RightUp", Class'Texture'));
	NextButton.UpTexture = Texture(DynamicLoadObject("UTMenu.RightUp", Class'Texture'));
	NextButton.DownTexture = Texture(DynamicLoadObject("UTMenu.RightDown", Class'Texture'));
	NextButton.OverTexture = Texture(DynamicLoadObject("UTMenu.RightOver", Class'Texture'));
	NextButton.NotifyWindow = Self;
	NextButton.Text = "";
	TextColor.R = 255;
	TextColor.G = 255;
	TextColor.B = 0;
	NextButton.SetTextColor(TextColor);
	NextButton.MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetHugeFont(Root);
	NextButton.bStretched = True;
	NextButton.OverSound = sound'LadderSounds.lcursorMove';
	NextButton.DownSound = sound'LadderSounds.ladvance';

	// Info
	XPos = 617.0/1024 * XMod;
	YPos = 233.0/768 * YMod;
	XWidth = 303.0/1024 * XMod;
	YHeight = 440.0/768 * YMod;
	InfoArea = UTFadeTextArea(CreateWindow(Class<UWindowWindow>(DynamicLoadObject("UTMenu.UTFadeTextArea", Class'Class')), XPos, YPos, XWidth, YHeight));
	InfoArea.TextColor.R = 255;
	InfoArea.TextColor.G = 255;
	InfoArea.TextColor.B = 0;
	InfoArea.MyFont = class'UTLadderStub'.Static.GetStubClass().Static.GetSmallFont(Root);
	InfoArea.FadeFactor = 8;
	InfoArea.Clear();
	if (Root.WinWidth < 512)
		return;
	if (LadderObj.DMPosition == -1)
		InfoArea.AddText(MatchesString@"0");
	else {
		if (LadderObj.DMRank == 6)
			InfoArea.AddText(MatchesString@LadderObj.DMPosition);
		else
			InfoArea.AddText(MatchesString@(LadderObj.DMPosition-1));
	}
	if (LadderObj.DMPosition >= 4) {
		InfoArea.AddText(" ");
		InfoArea.AddText(RankString[1]@class'MyLadderLadder'.Static.GetRank(LadderObj.DOMRank));
		if (LadderObj.DOMPosition == -1)
			InfoArea.AddText(MatchesString@"0");
		else {
			if (LadderObj.DOMRank == 6)
				InfoArea.AddText(MatchesString@LadderObj.DOMPosition);
			else
				InfoArea.AddText(MatchesString@(LadderObj.DOMPosition-1));
		}
	}
	if (LadderObj.DOMPosition >= 4) {
		InfoArea.AddText(" ");
		InfoArea.AddText(RankString[2]@class'MyLadderLadder'.Static.GetRank(LadderObj.CTFRank));
		if (LadderObj.CTFPosition == -1)
			InfoArea.AddText(MatchesString@"0");
		else {
			if (LadderObj.CTFRank == 6)
				InfoArea.AddText(MatchesString@LadderObj.CTFPosition);
			else
				InfoArea.AddText(MatchesString@(LadderObj.CTFPosition-1));
		}
	}
	if (LadderObj.CTFPosition >= 4) {
		InfoArea.AddText(" ");
		InfoArea.AddText(RankString[3]@class'MyLadderLadder'.Static.GetRank(LadderObj.ASRank));
		if (LadderObj.ASPosition == -1)
			InfoArea.AddText(MatchesString@"0");
		else {
			if (LadderObj.ASRank == 6)
				InfoArea.AddText(MatchesString@LadderObj.ASPosition);
			else
				InfoArea.AddText(MatchesString@(LadderObj.ASPosition-1));
		}
	}
	if ( (LadderObj.DMRank == 6) && (LadderObj.DOMRank == 6) &&
		(LadderObj.CTFRank == 6) && (LadderObj.ASRank == 6) ) {
		InfoArea.AddText(" ");
		InfoArea.AddText(ChallengeString);
		InfoArea.AddText(ChalPosString@class'MyLadderLadder'.Static.GetRank(LadderObj.ChalRank));
	}
	Root.Console.bBlackOut = True;
}

function BeforePaint (Canvas C, float X, float Y)
{
	local LadderInventory LadderObj;
	local float Xs,Ys;
	local int i, W, H;
	local float XWidth, YHeight, XMod, YMod, XPos, YPos;

	Super.BeforePaint(C,X,Y);
	Class'UTLadderStub'.Static.GetStubClass().Static.SetupWinParams(self,Root,W,H);
	XMod = 4.0 * W;
	YMod = 3.0 * H;
	XPos = 95.0 / 1024 * XMod;
	YPos = 102.0 / 768 * YMod;
	XWidth = 307.0 / 1024 * XMod;
	YHeight = 44.0 / 768 * YMod;
	DMLadderButton.WinLeft = XPos;
	DMLadderButton.WinTop = YPos;
	DMLadderButton.SetSize(XWidth,YHeight);
	DMLadderButton.MyFont = Class'UTLadderStub'.Static.GetStubClass().Static.GetHugeFont(Root);
	XPos = 95.0 / 1024 * XMod;
	YPos = 231.0 / 768 * YMod;
	XWidth = 307.0 / 1024 * XMod;
	YHeight = 44.0 / 768 * YMod;
	DOMLadderButton.WinLeft = XPos;
	DOMLadderButton.WinTop = YPos;
	DOMLadderButton.SetSize(XWidth,YHeight);
	DOMLadderButton.MyFont = Class'UTLadderStub'.Static.GetStubClass().Static.GetHugeFont(Root);
	if ( DOMDoor != None )
	{
		XPos = 83.0 / 1024 * XMod;
		YPos = 222.0 / 768 * YMod;
		XWidth = 332.0 / 1024 * XMod;
		YHeight = 63.0 / 768 * YMod;
		DOMDoor.WinLeft = XPos;
		DOMDoor.WinTop = YPos;
		DOMDoor.SetSize(XWidth,YHeight);
	}
	XPos = 95.0 / 1024 * XMod;
	YPos = 363.0 / 768 * YMod;
	XWidth = 307.0 / 1024 * XMod;
	YHeight = 44.0 / 768 * YMod;
	CTFLadderButton.WinLeft = XPos;
	CTFLadderButton.WinTop = YPos;
	CTFLadderButton.SetSize(XWidth,YHeight);
	CTFLadderButton.MyFont = Class'UTLadderStub'.Static.GetStubClass().Static.GetHugeFont(Root);
	if ( CTFDoor != None )
	{
		XPos = 83.0 / 1024 * XMod;
		YPos = 356.0 / 768 * YMod;
		XWidth = 332.0 / 1024 * XMod;
		YHeight = 63.0 / 768 * YMod;
		CTFDoor.WinLeft = XPos;
		CTFDoor.WinTop = YPos;
		CTFDoor.SetSize(XWidth,YHeight);
	}
	XPos = 95.0 / 1024 * XMod;
	YPos = 497.0 / 768 * YMod;
	XWidth = 307.0 / 1024 * XMod;
	YHeight = 44.0 / 768 * YMod;
	ASLadderButton.WinLeft = XPos;
	ASLadderButton.WinTop = YPos;
	ASLadderButton.SetSize(XWidth,YHeight);
	ASLadderButton.MyFont = Class'UTLadderStub'.Static.GetStubClass().Static.GetHugeFont(Root);
	if ( ASDoor != None )
	{
		XPos = 83.0 / 1024 * XMod;
		YPos = 488.0 / 768 * YMod;
		XWidth = 332.0 / 1024 * XMod;
		YHeight = 63.0 / 768 * YMod;
		ASDoor.WinLeft = XPos;
		ASDoor.WinTop = YPos;
		ASDoor.SetSize(XWidth,YHeight);
	}
	XPos = 95.0 / 1024 * XMod;
	YPos = 627.0 / 768 * YMod;
	XWidth = 307.0 / 1024 * XMod;
	YHeight = 44.0 / 768 * YMod;
	ChallengeLadderButton.WinLeft = XPos;
	ChallengeLadderButton.WinTop = YPos;
	ChallengeLadderButton.SetSize(XWidth,YHeight);
	ChallengeLadderButton.MyFont = Class'UTLadderStub'.Static.GetStubClass().Static.GetHugeFont(Root);
	if ( ChalDoor != None )
	{
		XPos = 83.0 / 1024 * XMod;
		YPos = 618.0 / 768 * YMod;
		XWidth = 332.0 / 1024 * XMod;
		YHeight = 63.0 / 768 * YMod;
		ChalDoor.WinLeft = XPos;
		ChalDoor.WinTop = YPos;
		ChalDoor.SetSize(XWidth,YHeight);
	}
	XPos = 656.0 / 1024 * XMod;
	YPos = 63.0 / 768 * YMod;
	XWidth = 222.0 / 1024 * XMod;
	YHeight = 50.0 / 768 * YMod;
	TrophyButton.WinLeft = XPos;
	TrophyButton.WinTop = YPos;
	TrophyButton.SetSize(XWidth,YHeight);
	TrophyButton.MyFont = Class'UTLadderStub'.Static.GetStubClass().Static.GetHugeFont(Root);
	if ( TrophyDoor != None )
	{
		XPos = 650.0 / 1024 * XMod;
		YPos = 58.0 / 768 * YMod;
		XWidth = 236.0 / 1024 * XMod;
		YHeight = 62.0 / 768 * YMod;
		TrophyDoor.WinLeft = XPos;
		TrophyDoor.WinTop = YPos;
		TrophyDoor.SetSize(XWidth,YHeight);
	}
	XPos = 192.0 / 1024 * XMod;
	YPos = 701.0 / 768 * YMod;
	XWidth = 64.0 / 1024 * XMod;
	YHeight = 64.0 / 768 * YMod;
	BackButton.SetSize(XWidth,YHeight);
	BackButton.WinLeft = XPos;
	BackButton.WinTop = YPos;
	XPos = 256.0 / 1024 * XMod;
	YPos = 701.0 / 768 * YMod;
	XWidth = 64.0 / 1024 * XMod;
	YHeight = 64.0 / 768 * YMod;
	NextButton.SetSize(XWidth,YHeight);
	NextButton.WinLeft = XPos;
	NextButton.WinTop = YPos;
	XPos = 617.0 / 1024 * XMod;
	YPos = 233.0 / 768 * YMod;
	XWidth = 303.0 / 1024 * XMod;
	YHeight = 440.0 / 768 * YMod;
	InfoArea.SetSize(XWidth,YHeight);
	InfoArea.WinLeft = XPos;
	InfoArea.WinTop = YPos;
	InfoArea.MyFont = Class'UTLadderStub'.Static.GetStubClass().Static.GetSmallFont(Root);
}

function OpenDoors ()
{
	local bool bOneOpened;

	if ( LadderObj.DMPosition >= 3 )
	{
		if ( (DOMDoorOpen[LadderObj.Slot] == 0) && (DOMDoor != None) )
		{
			DOMDoorOpen[LadderObj.Slot] = 1;
			DOMDoor.Open();
			SaveConfig();
			bOneOpened = True;
		}
	}
	if ( LadderObj.DOMPosition >= 2 )
	{
		if ( (CTFDoorOpen[LadderObj.Slot] == 0) && (CTFDoor != None) )
		{
			CTFDoorOpen[LadderObj.Slot] = 1;
			CTFDoor.Open();
			SaveConfig();
			bOneOpened = True;
		}
	}
	if ( LadderObj.CTFPosition >= 3 )
	{
		if ( (ASDoorOpen[LadderObj.Slot] == 0) && (ASDoor != None) )
		{
			ASDoorOpen[LadderObj.Slot] = 1;
			ASDoor.Open();
			SaveConfig();
			bOneOpened = True;
		}
	}
	if ( (LadderObj.DMRank == 6) && (LadderObj.DOMRank == 6) && (LadderObj.CTFRank == 6) && (LadderObj.ASRank == 6) )
	{
		if ( (ChalDoorOpen[LadderObj.Slot] == 0) && (ChalDoor != None) )
		{
			ChalDoorOpen[LadderObj.Slot] = 1;
			ChalDoor.Open();
			SaveConfig();
			bOneOpened = True;
		}
	}
	if ( (LadderObj.DMRank == 6) || (LadderObj.DOMRank == 6) || (LadderObj.CTFRank == 6) || (LadderObj.ASRank == 6) )
	{
		if ( (TrophyDoorOpen[LadderObj.Slot] == 0) && (TrophyDoor != None) )
		{
			TrophyDoorOpen[LadderObj.Slot] = 1;
			TrophyDoor.Open();
			SaveConfig();
			bOneOpened = True;
		}
	}
	if ( bOneOpened )
	{
		GetPlayerOwner().PlaySound(Sound'LadderSounds.ldoorsopen1b',SLOT_Interface);
	}
	bOpened = True;
}

function ShowWindow ()
{
	Super(UWindowWindow).ShowWindow();
	if ( (DOMDoorOpen[LadderObj.Slot] == 0) && (DOMDoor != None) )
	{
		DOMDoor.bClosed = True;
	}
	if ( (CTFDoorOpen[LadderObj.Slot] == 0) && (CTFDoor != None) )
	{
		CTFDoor.bClosed = True;
	}
	if ( (ASDoorOpen[LadderObj.Slot] == 0) && (ASDoor != None) )
	{
		ASDoor.bClosed = True;
	}
	if ( (ChalDoorOpen[LadderObj.Slot] == 0) && (ChalDoor != None) )
	{
		ChalDoor.bClosed = True;
	}
	if ( (TrophyDoorOpen[LadderObj.Slot] == 0) && (TrophyDoor != None) )
	{
		TrophyDoor.bClosed = True;
	}
	OpenTime = 0.0;
	InfoArea.Clear();
	if ( Root.WinWidth < 512 )
	{
		return;
	}
	InfoArea.AddText(RankString[0] @ Class'MyLadderLadder'.Static.GetRank(LadderObj.DMRank));
	InfoArea.AddText(MatchesString @ string(LadderObj.DMPosition - 1));
	if ( LadderObj.DMPosition >= 3 )
	{
		InfoArea.AddText("");
		InfoArea.AddText(RankString[1] @ Class'MyLadderLadder'.Static.GetRank(LadderObj.DOMRank));
		InfoArea.AddText(MatchesString @ string(LadderObj.DOMPosition - 1));
	}
	if ( LadderObj.DOMPosition >= 2 )
	{
		InfoArea.AddText("");
		InfoArea.AddText(RankString[2] @ Class'MyLadderLadder'.Static.GetRank(LadderObj.CTFRank));
		InfoArea.AddText(MatchesString @ string(LadderObj.CTFPosition - 1));
	}
	if ( LadderObj.CTFPosition >= 3 )
	{
		InfoArea.AddText("");
		InfoArea.AddText(RankString[3] @ Class'MyLadderLadder'.Static.GetRank(LadderObj.ASRank));
		InfoArea.AddText(MatchesString @ string(LadderObj.ASPosition - 1));
	}
	if ( (LadderObj.DMRank == 6) && (LadderObj.DOMRank == 6) && (LadderObj.CTFRank == 6) && (LadderObj.ASRank == 6) )
	{
		InfoArea.AddText(" ");
		InfoArea.AddText(ChallengeString);
		InfoArea.AddText(ChalPosString @ Class'MyLadderLadder'.Static.GetRank(LadderObj.ChalRank));
	}
}

defaultproperties
{
	LadderTypes(0)="MyLadder.MyLadderDMMenu"
	LadderTypes(1)="MyLadder.MyLadderDOMMenu"
	LadderTypes(2)="MyLadder.MyLadderCTFMenu"
	LadderTypes(3)="MyLadder.MyLadderASMenu"
	LadderTypes(4)="MyLadder.MyLadderChalMenu"
}
Some things to bear in mind:
* As mentioned before, every class'Ladder' was replaced by class'MyLadderLadder'. This change is necessary, since otherwise the game will revert to the default Ladder.
* There are many minor things we can do in this code such as deciding how many matches must be won in order to proceed to the next Ladder, we can give different names to the Ladders and configure them so they can be played on other game modes. That's an exercise to the reader, as well as how to create the interface on which the Ladder will be run. I'll leave a hint, though: UMenu.UMenuPageWindow (MyMenuClientWindow), UMenu.UMenuModMenuItem (MyMenuMyItem) and UMenu.UMenuFramedWindow (MyMenuMyWindow).

Why I don't explain this? Because I'm too tired to continue, so I'm going to sleep. Good night!

That's all for today.
Localization project coordinator/spanish maintainer

Only the people that do nothing but criticize don't make mistakes. Do things. Make mistakes. Learn from them. And screw those who do nothing but throw poison and criticize.
Post Reply

Return to “UScript Board”