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...