rott/kf_sources/Engine/Classes/GameProfile.uc
2026-07-14 20:27:09 +07:00

426 lines
11 KiB
Ucode

class GameProfile extends Object
native;
var() string PackageName;
var() int ManifestIndex;
enum EPlayerPos
{
POS_Auto,
POS_Defense,
POS_Offense,
POS_Roam,
/*POS_Captain, Not handy for dropdown display */
POS_Supporting
};
const NUM_POSITIONS = 5;
var localized string PositionName[5]; // text names of these positions
var EPlayerPos PlayerPositions[7]; // only need positions for AI team, so 7 max
const TEAM_SIZE = 7;
var() array<string> PlayerTeam; // Player team members
var int PlayerLineup[4]; // Lineup for current match. Stores index into PlayerTeam array.
const LINEUP_SIZE = 4;
var string EnemyTeam; // Opponent team name for pending/current match
var string TeamName; // Player team name
var string TeamSymbolName; // name of team symbol
var() float BaseDifficulty; // configured at start of single player
var() float Difficulty;
var int SalaryCap; // allowable salary cap for team roster
// stored here, but also passed separately on URL
var string PlayerName;
var string PlayerCharacter;
// player's stats - individual experience
var() int Kills;
var() int Goals;
var() int Deaths;
var() int Wins;
var() int Matches;
// Ladders: -1 = Locked
var int LadderRung[6];
const NUM_LADDERS = 6;
var string SpecialEvent;
var string GameLadderName;
var class<LadderInfo> GameLadder;
// current match
var int CurrentLadder;
var transient int CurrentMenuRung; // set by menu system, used for starting a match, in LadderInfo. if -1, use next match in order
var transient Object NextMatchObject; // Used by GUI SP Pages for holding the Button for Next Match
var transient Object ChampBorderObject; // Used by GUI SP Pages for holding the border for Championship.
// Sad hack, but easiest way to communicate GUI objects between Ladder and Qual tabs
var bool bInLadderGame; // Used to see if we should return to the SP menu after the match has finished,
// also used to check if we should use the LoadingClass vignette
var bool bWonMatch;
// constructor: set up the GameLadder
function Initialize(GameInfo currentGame, string pn)
{
local Controller C;
if (GameLadder == none)
{
GameLadder = class<LadderInfo>(DynamicLoadObject(GameLadderName, class'Class'));
}
PackageName=pn;
PlayerName=pn;
// set character, player in current game
for ( C=currentGame.Level.ControllerList; C!=None; C=C.NextController )
{
if ( PlayerController(C) != None )
{
currentGame.ChangeName (PlayerController(C), PlayerName, false);
break;
}
}
NextMatchObject=None;
ChampBorderObject=None;
}
// skip this rung of the ladder without saving
function CheatSkipMatch(GameInfo CurrentGame)
{
SpecialEvent = GameLadder.static.UpdateLadders(self,CurrentLadder); // updates LadderRungs appropriately
ContinueSinglePlayerGame(CurrentGame.Level);
}
// skip directly to a certain ladder/rung
// takes a single number (54) and splits into ladder 5, match 4
function CheatJumpMatch(GameInfo currentGame, int param) {
local Controller C;
local int newladder, newrung;
newladder = param/10;
newrung = param-(newladder*10);
if (newladder < 0 || newladder >= NUM_LADDERS || newrung < 0)
return;
bInLadderGame=true;
CurrentLadder = newladder;
LadderRung[CurrentLadder] = newrung;
CurrentMenuRung=newrung;
// open game
for ( C=currentGame.Level.ControllerList; C!=None; C=C.NextController )
{
if ( PlayerController(C) != None )
{
PlayerController(C).ConsoleCommand("START"@GameLadder.static.MakeURLFor(self));
break;
}
}
}
// robust checks are in LadderInfo, returns none if not found
function MatchInfo GetMatchInfo(int ladder, int rung) {
if ( GameLadder != none )
{
return GameLadder.static.GetMatchInfo(ladder,rung);
}
else
{
return none;
}
}
// After a game is completed, this function should be called to
// record the player's statistics and update the ladder.
// Currently called from Deathmatch 'MatchOver' state
function RegisterGame(GameInfo currentGame, PlayerReplicationInfo PRI)
{
Log("SINGLEPLAYER GameProfile::RegisterGame for profile"@self.packagename);
Kills += PRI.Kills;
Goals += PRI.GoalsScored;
Deaths += PRI.Deaths;
Matches++;
if ( bWonMatch ) {
//Log("SINGLEPLAYER GameProfile::RegisterGame player won the match.");
SpecialEvent = GameLadder.static.UpdateLadders(self,CurrentLadder); // updates LadderRungs appropriately
Wins++;
}
bWonMatch = false;
}
// Send the player to the next match in the given ladder
function StartNewMatch(int PickedLadder, LevelInfo CurrentLevel)
{
local Controller C;
bWonMatch = false;
bInLadderGame=true;
CurrentLadder = PickedLadder;
CurrentLevel.Game.SavePackage(PackageName);
// open game
for ( C=currentLevel.ControllerList; C!=None; C=C.NextController )
{
if ( PlayerController(C) != None )
{
PlayerController(C).ConsoleCommand("START"@GameLadder.static.MakeURLFor(self));
break;
}
}
}
// Handy helper function to find the player's first unfinished ladder
// If no ladders are unfinished, return 0 for DM ladder
function int FindFirstUnfinishedLadder() {
local int i;
for (i=0; i<6; i++)
{
// 6 is magic from number of ladders, declared above
if (LadderRung[i] < GameLadder.static.LengthOfLadder(i)) {
return i;
}
}
return 0;
}
// override in subclasses!
function ContinueSinglePlayerGame(LevelInfo level, optional bool bReplace)
{
Level.Game.SavePackage(PackageName);
// the direct call to startnewmatch is to avoid using a game-specific menu system
StartNewMatch(FindFirstUnfinishedLadder(), level);
}
// Used in menus: this is the gametype info for the next match
function string GetMatchDescription()
{
return GameLadder.static.GetMatchDescription(self);
}
// accessor
function static int GetNumPositions()
{
return NUM_POSITIONS;
}
// return number of teammates needed for currently selected match
// assumes player team always gets an odd player
function int GetNumTeammatesForMatch()
{
local MatchInfo M;
M = GameLadder.static.GetCurrentMatchInfo(self);
if ( M.GameType ~= "xGame.xDeathmatch" || M.GameType ~= "xGame.BossDM" )
return 0;
else
return M.NumBots / 2;
}
function static string TextPositionDescription(int posnval)
{
local string retval;
if (posnval < 0 || posnval > NUM_POSITIONS) // magic number based on team size of 7
return "Error";
switch (posnval) {
case EPlayerPos.POS_Auto:
retval = default.PositionName[0];
break;
case EPlayerPos.POS_Defense:
retval = default.PositionName[1];
break;
case EPlayerPos.POS_Offense:
retval = default.PositionName[2];
break;
case EPlayerPos.POS_Roam:
retval = default.PositionName[3];
break;
/* case EPlayerPos.POS_Captain:
retval = "CAPTAIN";
break;*/
case EPlayerPos.POS_Supporting:
retval = default.PositionName[4];
break;
}
return retval;
}
function static EPlayerPos EnumPositionDescription(string posnval)
{
local EPlayerPos retval;
if (posnval == default.PositionName[0]) {
retval = EPlayerPos.POS_Auto;
} else if (posnval == default.PositionName[1]) {
retval = EPlayerPos.POS_Defense;
} else if (posnval == default.PositionName[2]) {
retval = EPlayerPos.POS_Offense;
} else if (posnval == default.PositionName[3]) {
retval = EPlayerPos.POS_Roam;
} else if (posnval == default.PositionName[4]) {
retval = EPlayerPos.POS_Supporting;
} else
retval = EPlayerPos.POS_Auto;
return retval;
}
function string GetPositionDescription(int playernum)
{
if (playernum < 0 || playernum >= TEAM_SIZE)
return "Error";
return TextPositionDescription(PlayerPositions[playernum]);
}
// takes a lineup position (1-4) and sets that player's game position
function SetPosition (int lineupnum, string posn)
{
if ((lineupnum >= 0) && (lineupnum < 4))
PlayerPositions[PlayerLineup[lineupnum]] = EnumPositionDescription(posn);
}
// called when adjusting the lineup
// takes lineup position (1-4) and team position (1-7) and makes it all work
function SetLineup (int lineuppos, int teampos)
{
local int oldlineuppos, oldteammate, i;
// check bounds
if ( lineuppos < 0 || lineuppos > LINEUP_SIZE )
return;
if ( teampos < 0 || teampos >= TEAM_SIZE )
return;
if ( PlayerLineup[lineuppos] == teampos ) // no-op
return;
// check to see if player 'teampos' was already in the lineup
oldlineuppos=-1;
for ( i=0; i<LINEUP_SIZE; i++ )
{
if ( PlayerLineup[i] == teampos )
{
oldlineuppos = i;
break;
}
}
if ( oldlineuppos >= 0 ) {
oldteammate = PlayerLineup[lineuppos];
}
PlayerLineup[lineuppos] = teampos;
if ( oldlineuppos >= 0 ) {
PlayerLineup[oldlineuppos] = oldteammate;
}
}
// add teammate to the next available position on the team
// return false if not added because already on team or no room
// assumes it's a legal player record
function bool AddTeammate(string botname)
{
local int i;
if ( botname == "" )
{
return false;
}
for ( i=0; i<TEAM_SIZE; i++ )
{
if ( i >= PlayerTeam.Length || PlayerTeam[i] == "" )
{
Playerteam[i] = botname;
return true;
}
if ( PlayerTeam[i] ~= botname )
{
// already on team
return false;
}
}
return false; // never found space
}
// remove teammate from the team
// return false if not removed because not on team
function bool ReleaseTeammate(string botname)
{
local int i, j;
if ( botname == "" )
{
return false;
}
for ( i=0; i<PlayerTeam.Length; i++ )
{
if ( PlayerTeam[i] ~= botname )
{
// player is on team, shuffle list
for ( j=i; j<PlayerTeam.Length-1; j++ )
{
PlayerTeam[j] = PlayerTeam[j+1];
}
PlayerTeam[PlayerTeam.Length-1] = "";
return true;
}
}
return false; // never found botname
}
function ClearTeammates()
{
local int i;
for ( i=0; i<PlayerTeam.Length; i++ )
{
PlayerTeam[i] = "";
}
}
function ReportCheat(PlayerController Cheater, string cheat);
function bool CanChangeTeam(Controller Other, int NewTeam)
{
return true;
}
defaultproperties
{
GameLadderName="Engine.LadderInfo"
LadderRung(0)=0
LadderRung(1)=-1
LadderRung(2)=-1
LadderRung(3)=-1
LadderRung(4)=-1
LadderRung(5)=-1
PositionName(0)="AUTO-ASSIGN"
PositionName(1)="DEFENSE"
PositionName(2)="OFFENSE"
PositionName(3)="ROAM"
PositionName(4)="SUPPORT"
PlayerLineup(0)=0
PlayerLineup(1)=1
PlayerLineup(2)=2
PlayerLineup(3)=3
BaseDifficulty=1
PlayerName="Name"
PlayerCharacter="Roc"
PlayerTeam="TeamName"
PackageName="Default"
Kills=0
Goals=0
Deaths=0
bInLadderGame=false
}