commit 4E version

This commit is contained in:
cclecle
2023-05-06 08:37:14 +01:00
commit 095f277ebd
39 changed files with 4480 additions and 0 deletions

2077
Sources/Classes/SmartCTF.uc Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,35 @@
// This is a fix to be able to get certain sounds to play. Certain sounds like Assist and Capture only
// work on the client. By simply sending this message instead of ClientPlaySound on the server we don't need
// to include the sounds in the pack.
class SmartCTFAudioMsg expands LocalMessagePlus;
static function string GetString( optional int Switch, optional PlayerReplicationInfo RelatedPRI_1, optional PlayerReplicationInfo RelatedPRI_2, optional Object OptionalObject )
{
return "";
}
static simulated function ClientReceive( PlayerPawn P, optional int Switch, optional PlayerReplicationInfo RelatedPRI_1, optional PlayerReplicationInfo RelatedPRI_2, optional Object OptionalObject )
{
super.ClientReceive( P, Switch, RelatedPRI_1, RelatedPRI_2, OptionalObject );
switch( Switch )
{
case 0: P.ClientPlaySound( sound'Announcer.capture', , true );
break;
case 1: P.ClientPlaySound( sound'Announcer.assist', , true );
break;
case 2: P.ClientPlaySound( sound'Announcer.nicecatch', , true );
break;
case 3: P.ClientPlaySound( sound'Announcer.takenlead', , true );
break;
case 4: P.ClientPlaySound( sound'Announcer.lostlead', , true );
break;
}
}
defaultproperties
{
bIsConsoleMessage=False
Lifetime=0
}

View File

@@ -0,0 +1,8 @@
class SmartCTFBinds expands UTExtraKeyBindings;
defaultproperties
{
SectionName="SmartCTF"
LabelList(0)="Toggle Stats"
AliasNames(0)="mutate smartctf showstats"
}

View File

@@ -0,0 +1,58 @@
class SmartCTFCoolMsg expands LocalMessagePlus;
var(Messages) string LongRangeString;
var(Messages) string UberLongRangeString;
var(Messages) string SpawnLamerString;
var(Messages) string OvertimeEnabledString;
var(Messages) string OvertimeDisabledString;
var Color EnabledColor, DisabledColor, SpawnLamerColor;
static function float GetOffset(int Switch, float YL, float ClipY )
{
return ( default.YPos / 768.0 ) * ClipY - 2 * YL;
}
static function string GetString( optional int Switch, optional PlayerReplicationInfo RelatedPRI_1, optional PlayerReplicationInfo RelatedPRI_2, optional Object OptionalObject )
{
switch( Switch )
{
case 1: return default.LongRangeString;
case 2: return default.UberLongRangeString;
case 3: return default.OvertimeEnabledString;
case 4: return default.OvertimeDisabledString;
case 5: return default.SpawnLamerString;
}
return "";
}
static function Color GetColor( optional int Switch, optional PlayerReplicationInfo RelatedPRI_1, optional PlayerReplicationInfo RelatedPRI_2 )
{
switch( Switch )
{
case 1: return default.DrawColor;
case 2: return default.DrawColor;
case 3: return default.EnabledColor;
case 4: return default.DisabledColor;
case 5: return default.SpawnLamerColor;
}
return default.DrawColor;
}
defaultproperties
{
LongRangeString="Long Range Kill!"
UberLongRangeString="Über Long Range Kill!"
SpawnLamerString="Spawnkill..."
OvertimeEnabledString="Sudden Death Overtime = Enabled"
OvertimeDisabledString="Sudden Death Overtime = DISABLED"
EnabledColor=(R=128,G=255,B=192)
DisabledColor=(R=255,G=192,B=128)
SpawnLamerColor=(R=255,G=64)
FontSize=1
bIsSpecial=True
bIsUnique=True
bFadeMessage=True
DrawColor=(G=224,B=224)
YPos=196.000000
bCenter=True
}

View File

@@ -0,0 +1,32 @@
class SmartCTFEndStats expands EndStats config( user );
replication
{
reliable if( Role == ROLE_Authority )
MostPoints, MostFrags, MostCaps, MostFlagKills, MostCovers, MostHeadShots;
}
struct BestSomething {
var int Count;
var string PlayerName;
var string MapName;
var string RecordDate;
};
var globalconfig BestSomething MostPoints;
var globalconfig BestSomething MostFrags;
var globalconfig BestSomething MostCaps;
var globalconfig BestSomething MostFlagKills;
var globalconfig BestSomething MostCovers;
var globalconfig BestSomething MostHeadShots;
defaultproperties
{
MostPoints=(Count=2970,PlayerName="The_Cowboy",MapName="Pure Action",RecordDate="06/03/2009 15:58:14")
MostFrags=(Count=406,PlayerName="Aryss",MapName="Pure Action",RecordDate="06/03/2009 21:31:44")
MostCaps=(Count=105,PlayerName="Archon",MapName="Liandri Docks",RecordDate="05/29/2009 14:09:35")
MostFlagKills=(Count=189,PlayerName="The_Cowboy",MapName="Pure Action",RecordDate="06/03/2009 15:58:14")
MostCovers=(Count=61,PlayerName="Aryss",MapName="Pure Action",RecordDate="06/03/2009 21:31:44")
MostHeadShots=(Count=64,PlayerName="{-_-}",MapName="Facing Worlds",RecordDate="05/14/2009 23:05:14")
bAlwaysRelevant=True
}

View File

@@ -0,0 +1,56 @@
class SmartCTFEnhancedDeathMessagePlus extends DeathMessagePlus;
static function ClientReceive( PlayerPawn P, optional int Switch, optional PlayerReplicationInfo RelatedPRI_1, optional PlayerReplicationInfo RelatedPRI_2, optional Object OptionalObject )
{
local string MultiStr;
if( RelatedPRI_1 == P.PlayerReplicationInfo )
{
// Interdict and send the child message instead.
if( TournamentPlayer( P ).myHUD != None )
{
//if( class'DeathMessagePlus'.default.ChildMessage == class'KillerMessagePlus' ) class'KillerMessagePlus'.default.YouKilled = "You" @ TournamentGameInfo( P.Level.Game ).default.deathmessage[Rand(32)];
TournamentPlayer( P ).myHUD.LocalizedMessage( default.ChildMessage, Switch, RelatedPRI_1, RelatedPRI_2, OptionalObject );
TournamentPlayer( P ).myHUD.LocalizedMessage( default.Class, Switch, RelatedPRI_1, RelatedPRI_2, OptionalObject );
}
if( default.bIsConsoleMessage )
{
TournamentPlayer( P ).Player.Console.AddString( static.GetString( Switch, RelatedPRI_1, RelatedPRI_2, OptionalObject ) );
}
if( ( RelatedPRI_1 != RelatedPRI_2 ) && ( RelatedPRI_2 != None ) )
{
if( ( TournamentPlayer( P ).Level.TimeSeconds - TournamentPlayer( P ).LastKillTime < 3 ) && ( Switch != 1 ) )
{
TournamentPlayer( P ).MultiLevel++;
TournamentPlayer( P ).ReceiveLocalizedMessage( class'SmartCTFEnhancedMultiKillMessage', TournamentPlayer( P ).MultiLevel , RelatedPRI_1 );
}
else
{
TournamentPlayer( P ).MultiLevel = 0;
}
TournamentPlayer( P ).LastKillTime = TournamentPlayer( P ).Level.TimeSeconds;
}
else
{
TournamentPlayer( P ).MultiLevel = 0;
}
if( ChallengeHUD( P.MyHUD ) != None ) ChallengeHUD( P.MyHUD ).ScoreTime = TournamentPlayer( P ).Level.TimeSeconds;
}
else if( RelatedPRI_2 == P.PlayerReplicationInfo )
{
//class'VictimMessage'.default.YouWereKilledBy = "You were" @ TournamentGameInfo( P.Level.Game ).default.deathmessage[Rand(32)] @ "by";
TournamentPlayer( P ).ReceiveLocalizedMessage( class'VictimMessage', 0, RelatedPRI_1 );
super( LocalMessagePlus ).ClientReceive( P, Switch, RelatedPRI_1, RelatedPRI_2, OptionalObject );
}
else
{
super( LocalMessagePlus ).ClientReceive( P, Switch, RelatedPRI_1, RelatedPRI_2, OptionalObject );
}
}
defaultproperties
{
}

View File

@@ -0,0 +1,94 @@
//=============================================================================
// SmartCTFEnhancedMultiKillMessage.
// - v1.0 29-Feb-2004 by {DnF2}SiNiSTeR -
//=============================================================================
class SmartCTFEnhancedMultiKillMessage extends MultiKillMessage;
// Extended Multikills adds 2 more to the list :]
// These Announcer sounds already were included in the orginal game, just not used.
// It also doesn't stop after 9 times ;p
#exec OBJ LOAD FILE=..\Sounds\Announcer.uax
var(Messages) localized string MegaKillString;
static function int GetFontSize( int Switch )
{
if( Switch < 3 ) return default.FontSize;
else return 2;
}
static function string GetString( optional int Switch, optional PlayerReplicationInfo RelatedPRI_1, optional PlayerReplicationInfo RelatedPRI_2, optional Object OptionalObject )
{
switch( Switch )
{
case 0: return "";
break;
case 1: return default.DoubleKillString;
break;
case 2: return default.TripleKillString;
break;
case 3: return default.MultiKillString;
break;
case 4: return default.MegaKillString;
break;
case 5: return default.UltraKillString;
break;
default: return default.MonsterKillString;
break;
}
}
static function string GetBroadcastString( int MultiLevel )
{
if( MultiLevel == 5 ) return "had an" @ static.GetString( MultiLevel );
else return "had a" @ static.GetString( MultiLevel );
}
static simulated function ClientReceive( PlayerPawn P, optional int Switch, optional PlayerReplicationInfo RelatedPRI_1, optional PlayerReplicationInfo RelatedPRI_2, optional Object OptionalObject )
{
super( LocalMessagePlus ).ClientReceive( P, Switch, RelatedPRI_1, RelatedPRI_2, OptionalObject );
switch( Switch )
{
case 0: break;
case 1: P.ClientPlaySound( sound'Announcer.DoubleKill', , true );
break;
case 2: P.ClientPlaySound( sound'Announcer.TripleKill', , true );
break;
case 3: P.ClientPlaySound( sound'Announcer.MultiKill', , true );
break;
case 4: P.ClientPlaySound( sound'Announcer.MegaKill', , true );
break;
case 5: P.ClientPlaySound( sound'Announcer.UltraKill', , true );
break;
default: P.ClientPlaySound( sound'Announcer.MonsterKill', , true );
break;
}
}
static function color GetColor( optional int Switch, optional PlayerReplicationInfo RelatedPRI_1, optional PlayerReplicationInfo RelatedPRI_2 )
{
local Color cres;
cres = Default.DrawColor;
if( Switch >= 1 && Switch <= 5 )
{
cres.G = 48 * ( 5 - Switch );
return cres;
}
else if( Switch > 5 )
{
cres.B = Min( 48 * ( Switch - 5 ), 255 );
return cres;
}
else
{
return cres;
}
}
defaultproperties
{
MegaKillString="MEGA KILL!"
}

View File

@@ -0,0 +1,38 @@
class SmartCTFFlagCheckerInventory expands TournamentPickup;
// This inventory item gets added to every player by default.
// Now, each time this inventory item gets destroyed it means either the player left the game or died.
// If he simply died, then the original code already made sure the flag is dropped, before we get here,
// and nothing special happens.
// When we're here, we will check if he was actually carrying the flag. If he still has a flag, it means
// the player left the server and we drop the flag manually.
// All this happens before the code that would send the flag home.
// Quite ingenious if I may say so :p (c) {DnF2}SiNiSTeR imo xD
var string DroppedMessage;
function Destroyed()
{
local CTFFlag flag;
// Use Other.Class==Class'ClassName' if you want a specific Actor type
if( Owner != none && Owner.IsA('Pawn') ) {
if( Pawn( Owner ).bIsPlayer ) { // Pawn is a player
flag = CTFFlag( Pawn( Owner ).PlayerReplicationInfo.HasFlag );
if( flag != None ) { // Should handle casting failure
flag.Drop( 0.5 * Pawn( Owner ).Velocity );
BroadcastMessage( Pawn( Owner ).PlayerReplicationInfo.PlayerName @ DroppedMessage );
}
}
}
super.Destroyed(); // Call Destroyed() on super class TournamentPickup
}
defaultproperties
{
DroppedMessage="had the flag but disconnected. Flag is dropped!"
bHeldItem=True
bHidden=True
}

View File

@@ -0,0 +1,125 @@
// This class gets spawned in the mutator, serverside.
// Because of its Role, it will also get copied to clients.
// The replicated variables are accessible there.
class SmartCTFGameReplicationInfo expands ReplicationInfo;
var int TickRate;
var bool bShowFCLocation, bStatsDrawFaces, bPlay30SecSound, bDrawLogo, bExtraStats, bShowSpecs, bDoKeybind, bSCTFSbDef, bSnowyScoreboard, bXmasImages;
var float SbDelayC;
var color SpectatorColor;
var string CountryFlagsPackage;
var class<ScoreBoard> NormalScoreBoardClass;
var SmartCTFEndStats EndStats;
var SmartCTFPlayerReplicationInfo PRIArray[64];
var bool bInitialized, bServerInfoSetServerSide, bDoneBind;
var class<HUD> DefaultHUDType;
replication
{
// Settings
reliable if( Role == ROLE_Authority )
bShowFCLocation, bPlay30SecSound, bStatsDrawFaces, bDrawLogo, bExtraStats, CountryFlagsPackage, bShowSpecs, bSCTFSbDef, bDoKeybind, bSnowyScoreboard, bXmasImages;
reliable if( Role == ROLE_Authority )
bInitialized, TickRate, NormalScoreBoardClass, EndStats, bServerInfoSetServerSide, DefaultHUDType, DoBind, SbDelayC, SpectatorColor;
}
simulated function PostBeginPlay()
{
//default.NormalScoreBoardClass = Level.Game.ScoreBoardType;
SetTimer( 0.5, True );
}
simulated function Timer()
{
local PlayerPawn P;
RefreshPRI();
if (Level.Netmode == NM_DedicatedServer || bDoneBind || !bDoKeybind) return; // Only execute on clients, if bind hasn't been done yet and if bind should be done.
foreach AllActors(class 'PlayerPawn', P)
if (Viewport(P.Player) != None) break;
if(P!=None) DoBind(P);
bDoneBind=true;
}
simulated function SmartCTFPlayerReplicationInfo GetStats( Actor P )
{
local int i;
local PlayerReplicationInfo PRI;
if( !P.IsA( 'Pawn' ) ) return None;
PRI = Pawn( P ).PlayerReplicationInfo;
if( PRI == None ) return None;
for( i = 0; i < 64; i++ )
{
if( PRIArray[i] == None ) break;
if( PRIArray[i].Owner == PRI ) return PRIArray[i];
}
return None;
}
simulated function SmartCTFPlayerReplicationInfo GetStatsByPRI( PlayerReplicationInfo PRI )
{
local int i;
if( PRI == None ) return None;
for( i = 0; i < 64; i++ )
{
if( PRIArray[i] == None ) break;
if( PRIArray[i].Owner == PRI ) return PRIArray[i];
}
return None;
}
simulated function SmartCTFPlayerReplicationInfo GetStatNr( byte i )
{
return PRIArray[i];
}
simulated function ClearStats()
{
local int i;
for( i = 0; i < 64; i++ )
{
if( PRIArray[i] == None ) break;
PRIArray[i].ClearStats();
}
}
simulated function RefreshPRI()
{
local SmartCTFPlayerReplicationInfo PRI;
local int i;
for( i = 0; i < 64; i++ ) PRIArray[i] = None;
i = 0;
ForEach AllActors( class'SmartCTFPlayerReplicationInfo', PRI )
{
if( i < 64 )
{
if( PRI.Owner != None ) PRIArray[i++] = PRI;
}
else break;
}
}
simulated function DoBind(PlayerPawn P)
{
local string keyBinding;
if ((InStr( Caps(P.ConsoleCommand("Keybinding F3")), "MUTATE SMARTCTF SHOWSTATS") == -1))
{
keyBinding = P.ConsoleCommand("Keybinding F3");
P.ConsoleCommand("SET INPUT F3 mutate smartctf showstats|"$keyBinding);
}
}
defaultproperties
{
RemoteRole=ROLE_SimulatedProxy
}

View File

@@ -0,0 +1,82 @@
// Above all other messages.
class SmartCTFMessage extends LocalMessagePlus;
var string CoveredMsg, YouCoveredMsg;
var string CoverSpreeMsg, YouCoverSpreeMsg;
var string UltraCoverMsg, YouUltraCoverMsg;
var string SealMsg, YouSealMsg;
var string SavedMsg, YouSavedMsg;
var string SpawnKillMsg;
static function float GetOffset( int Switch, float YL, float ClipY )
{
return ( default.YPos / 768.0 ) * ClipY - 3 * YL;
}
static function string GetString( optional int Switch, optional PlayerReplicationInfo RelatedPRI_1, optional PlayerReplicationInfo RelatedPRI_2, optional Object OptionalObject )
{
if (RelatedPRI_1 == None) return "";
switch( Switch )
{
case 0: // Cover FC
return RelatedPRI_1.PlayerName @ default.CoveredMsg;
case 1: // Seal base
return RelatedPRI_1.PlayerName @ default.SealMsg;
case 4: // Ultra cover
return RelatedPRI_1.PlayerName @ default.UltraCoverMsg;
case 5: // Cover spree
return RelatedPRI_1.PlayerName @ default.CoverSpreeMsg;
case 7: // Saved by ...
return default.SavedMsg @ RelatedPRI_1.PlayerName $ "!";
case 10: // Spawnkilling
return RelatedPRI_1.PlayerName @ default.SpawnKillMsg;
case 0 + 64:
return default.YouCoveredMsg;
case 1 + 64:
return default.YouSealMsg;
case 4 + 64:
return default.YouUltraCoverMsg;
case 5 + 64:
return default.YouCoverSpreeMsg;
case 7 + 64:
return default.YouSavedMsg;
}
return "";
}
static simulated function ClientReceive( PlayerPawn P, optional int Switch, optional PlayerReplicationInfo RelatedPRI_1, optional PlayerReplicationInfo RelatedPRI_2, optional Object OptionalObject )
{
super.ClientReceive( P, Switch, RelatedPRI_1, RelatedPRI_2, OptionalObject );
switch( Switch )
{
case 5: // Cover spree - guitarsound for player, spreesound for all
if( RelatedPRI_1 == P.PlayerReplicationInfo ) P.ClientPlaySound( sound'CaptureSound', , true );
else P.PlaySound( sound'SpreeSound', , 4.0 );
break;
}
}
defaultproperties
{
CoveredMsg="covered the flagcarrier!"
YouCoveredMsg="You covered the flagcarrier!"
CoverSpreeMsg="is on a cover spree!"
YouCoverSpreeMsg="You are on a cover spree!"
UltraCoverMsg="got a multi cover!"
YouUltraCoverMsg="You got a multi cover!"
SealMsg="is sealing off the base!"
YouSealMsg="You are sealing off the base!"
SavedMsg="Saved By"
YouSavedMsg="Close save!!"
SpawnKillMsg="is a spawnkilling lamer!"
FontSize=1
bIsSpecial=True
bIsUnique=True
bFadeMessage=True
DrawColor=(R=24,G=192,B=24)
YPos=196.000000
bCenter=True
}

View File

@@ -0,0 +1,167 @@
class SmartCTFPlayerReplicationInfo expands ReplicationInfo;
// Replicated
var int Captures, Assists, Grabs, Covers, Seals, FlagKills, DefKills;
var int Frags, HeadShots, ShieldBelts, Amps;
var string CountryPrefix; // for IpToCountry
// Server side
var float LastKillTime;
var int MultiLevel;
var int FragSpree, CoverSpree, SealSpree, SpawnKillSpree;
var float SpawnTime;
var bool bHadFirstSpawn;
// Client side
var bool bViewingStats;
var bool bEndStats;
var float IndicatorStartShow;
var byte IndicatorVisibility;
var Actor IpToCountry;
var bool bIpToCountry;
replication
{
// Stats
reliable if( Role == ROLE_Authority )
Captures, Assists, Grabs, Covers, Seals, FlagKills, DefKills,
Frags, HeadShots, ShieldBelts, Amps, CountryPrefix;
// Toggle stats functions
reliable if( Role == ROLE_Authority )
ToggleStats, ShowStats;
}
function PostBeginPlay()
{
local Actor A;
super.PostBeginPlay();
SetTimer( 0.5, True );
}
function Timer()
{
local string temp;
local PlayerPawn P;
if( Owner == None )
{
SetTimer( 0.0, False );
Destroy();
return;
}
if(bIpToCountry)
{
if(CountryPrefix == "")
{
if(Owner.Owner.IsA('PlayerPawn'))
{
P=PlayerPawn(Owner.Owner);
if(NetConnection(P.Player) != None)
{
temp=P.GetPlayerNetworkAddress();
temp=Left(temp, InStr(temp, ":"));
temp=IpToCountry.GetItemName(temp);
if(temp == "!Disabled") /* after this return, iptocountry won't resolve anything anyway */
bIpToCountry=False;
else if(Left(temp, 1) != "!") /* good response */
{
CountryPrefix=SelElem(temp, 5);
if(CountryPrefix=="") /* the country is probably unknown(maybe LAN), so as the prefix */
bIpToCountry=False;
}
}
else
bIpToCountry=False;
}
else
bIpToCountry=False;
}
else
bIpToCountry=False;
}
}
static final function string SelElem(string Str, int Elem)
{
local int pos;
while(Elem-->1)
Str=Mid(Str, InStr(Str,":")+1);
pos=InStr(Str, ":");
if(pos != -1)
Str=Left(Str, pos);
return Str;
}
// Called on the server, executed on the client
simulated function ToggleStats()
{
local PlayerPawn P;
if( Owner == None ) return;
P = PlayerPawn( Owner.Owner );
if( P == None ) return;
if( P.Scoring != None && !P.Scoring.IsA( 'SmartCTFScoreBoard' ) )
{
P.ClientMessage( "Problem loading the SmartCTF ScoreBoard..." );
}
else
{
bViewingStats = !bViewingStats;
IndicatorStartShow = Level.TimeSeconds;
IndicatorVisibility = 255;
P.bShowScores = True;
}
}
// Called on the client
simulated function ShowStats(optional bool bHide)
{
local PlayerPawn P;
if( Owner == None ) return;
P = PlayerPawn( Owner.Owner );
if( P == None ) return;
if( P.Scoring != None && !P.Scoring.IsA( 'SmartCTFScoreBoard' ) )
{
P.ClientMessage( "Problem loading the SmartCTF ScoreBoard..." );
}
else
{
bViewingStats = True;
if(!bHide) P.bShowScores = True;
}
}
function ClearStats()
{
Captures = 0;
Assists = 0;
Grabs = 0;
Covers = 0;
Seals = 0;
DefKills = 0;
FlagKills = 0;
Frags = 0;
HeadShots = 0;
ShieldBelts = 0;
Amps = 0;
FragSpree = 0;
CoverSpree = 0;
SealSpree = 0;
SpawnKillSpree = 0;
SpawnTime = 0;
LastKillTime = 0;
MultiLevel = 0;
}
defaultproperties
{
}

View File

@@ -0,0 +1,962 @@
class SmartCTFScoreBoard extends UnrealCTFScoreBoard;
#exec texture IMPORT NAME=faceless File=Textures\faceless.pcx GROUP=SmartCTF
var ScoreBoard NormalScoreBoard;
var SmartCTFGameReplicationInfo SCTFGame;
var SmartCTFPlayerReplicationInfo OwnerStats;
var int TryCount;
var PlayerPawn PlayerOwner;
var string PtsText, FragsText, SepText, MoreText, HeaderText, HeaderText2;
var int LastSortTime, MaxMeterWidth;
var byte ColorChangeSpeed, RowColState;
var Color White, Gray, DarkGray, Yellow, RedTeamColor, BlueTeamColor, RedHeaderColor, BlueHeaderColor, StatsColor, FooterColor, HeaderColor, TinyInfoColor, HeaderTinyInfoColor;
var float StatsTextWidth, StatHeight, MeterHeight, NameHeight, ColumnHeight, StatBlockHeight;
var float RedStartX, BlueStartX, ColumnWidth, StatWidth, StatsHorSpacing, ShadingSpacingX, HeaderShadingSpacingY, ColumnShadingSpacingY;
var float StartY, StatLineHeight, StatBlockSpacing, StatIndent;
var TournamentGameReplicationInfo pTGRI;
var PlayerReplicationInfo pPRI;
var Font StatFont, CapFont, FooterFont, GameEndedFont, PlayerNameFont, FragsFont, TinyInfoFont;
var Font PtsFont22, PtsFont20, PtsFont18, PtsFont16, PtsFont14, PtsFont12;
var int MaxCaps, MaxAssists, MaxGrabs, MaxCovers, MaxSeals, MaxDefKills, MaxFlagKills, MaxFrags, MaxDeaths;
var int TotShieldBelts, TotAmps;
var bool bSealsOrDefs;
var bool bStarted;
var bool bEndHandled;
struct FlagData {
var string Prefix;
var texture Tex;
};
var FlagData FD[32]; // there can be max 32 so max 32 different flags
var int saveindex; // new loaded flags will be saved in FD[index]
function int GetFlagIndex(string Prefix)
{
local int i;
for(i=0;i<32;i++)
if(FD[i].Prefix == Prefix)
return i;
FD[saveindex].Prefix=Prefix;
FD[saveindex].Tex=texture(DynamicLoadObject(SCTFGame.CountryFlagsPackage$"."$Prefix, class'Texture'));
i=saveindex;
saveindex = (saveindex+1) % 256;
return i;
}
function PostBeginPlay()
{
super.PostBeginPlay();
PlayerOwner = PlayerPawn( Owner );
pTGRI = TournamentGameReplicationInfo( PlayerOwner.GameReplicationInfo );
pPRI = PlayerOwner.PlayerReplicationInfo;
LastSortTime = -100;
// Preload
PtsFont22 = Font( DynamicLoadObject( "LadderFonts.UTLadder22", class'Font' ) );
PtsFont20 = Font( DynamicLoadObject( "LadderFonts.UTLadder20", class'Font' ) );
PtsFont18 = Font( DynamicLoadObject( "LadderFonts.UTLadder18", class'Font' ) );
PtsFont16 = Font( DynamicLoadObject( "LadderFonts.UTLadder16", class'Font' ) );
PtsFont14 = Font( DynamicLoadObject( "LadderFonts.UTLadder14", class'Font' ) );
PtsFont12 = Font( DynamicLoadObject( "LadderFonts.UTLadder12", class'Font' ) );
SpawnNormalScoreBoard();
if( NormalScoreBoard == None ) SetTimer( 1.0 , True );
else
{
bStarted = True;
SetTimer( 3.0, true);
}
}
// Try to spawn a local instance of the original scoreboard class if it doesn't exist already.
function SpawnNormalScoreBoard()
{
if( SCTFGame == None )
{
ForEach AllActors( class'SmartCTFGameReplicationInfo', SCTFGame ) break;
}
if( SCTFGame != None ) OwnerStats = SCTFGame.GetStats( PlayerOwner );
if( SCTFGame != None && SCTFGame.NormalScoreBoardClass == None )
{
Log( "Unable to identify original ScoreBoard type. Retrying in 1 second." , 'SmartCTF' );
return;
}
if( SCTFGame != None && SCTFGame.NormalScoreBoardClass == self.Class )
{
NormalScoreBoard = Spawn( class'UnrealCTFScoreBoard', PlayerOwner );
Log( "Cannot use itself. Using the default CTF ScoreBoard instead." , 'SmartCTF' );
return;
}
if( SCTFGame != None && SCTFGame.NormalScoreBoardClass != None )
{
NormalScoreBoard = Spawn( SCTFGame.NormalScoreBoardClass, PlayerOwner );
Log( "Determined and spawned original scoreboard as" @ NormalScoreBoard, 'SmartCTF' );
}
}
// In the case of the 'normal scoreboard' not being replicated properly, try every second to see if it has.
function Timer()
{
if(!bStarted)
{
if( NormalScoreBoard == None )
{
TryCount++;
SpawnNormalScoreBoard();
}
if( NormalScoreBoard != None )
{
bStarted = True;
SetTimer( 3.0, True );
}
else if( TryCount > 3 )
{
Log( "Given up. Using the default CTF ScoreBoard instead." , 'SmartCTF' );
if( NormalScoreBoard == None )
{
NormalScoreBoard = Spawn( class'UnrealCTFScoreBoard', PlayerOwner );
Log( "Spawned as" @ NormalScoreBoard, 'SmartCTF' );
}
bStarted = True;
SetTimer( 3.0, True );
}
}
else
{
bSealsOrDefs = !bSealsOrDefs;
}
}
function ShowScores( Canvas C )
{
if( SCTFGame == None || OwnerStats == None )
{
if( NormalScoreBoard != None ) NormalScoreBoard.ShowScores( C );
else PlayerOwner.bShowScores = False;
return;
}
if(OwnerStats.bEndStats && !bEndHandled)
{
bEndHandled = True;
bSealsOrDefs = True;
SetTimer(10, true);
}
if( OwnerStats.bViewingStats )
SmartCTFShowScores( C );
else
{
if( NormalScoreBoard == None ) SmartCTFShowScores( C );
else NormalScoreBoard.ShowScores( C );
}
if( OwnerStats.IndicatorVisibility > 0 ) ShowIndicator( C );
}
function ShowIndicator( Canvas C )
{
local float BlockLen, LineHeight;
C.DrawColor.R = OwnerStats.IndicatorVisibility;
C.DrawColor.G = OwnerStats.IndicatorVisibility;
C.DrawColor.B = OwnerStats.IndicatorVisibility;
C.Style = ERenderStyle.STY_Translucent;
C.Font = C.SmallFont;
C.StrLen( "Scoreboard:", BlockLen, LineHeight );
C.SetPos( C.ClipX - BlockLen - 16, 16 );
C.DrawText( "Scoreboard:" );
C.SetPos( C.ClipX - BlockLen, 16 + LineHeight );
C.DrawText( "Default" );
C.SetPos( C.ClipX - BlockLen, 16 + 2 * LineHeight );
C.DrawText( "SmartCTF" );
if( OwnerStats.bViewingStats ) C.SetPos( C.ClipX - BlockLen - 16, 16 + 2 * LineHeight );
else C.SetPos( C.ClipX - BlockLen - 16, 16 + LineHeight );
C.DrawIcon( texture'UWindow.MenuTick', 1 );
C.Style = ERenderStyle.STY_Normal;
if( Level.TimeSeconds - OwnerStats.IndicatorStartShow > 2 ) OwnerStats.IndicatorVisibility = 0;
}
function SmartCTFShowScores( Canvas C )
{
local int ID, i, j, Time, AvgPing, AvgPL, TotSB, TotAmp;
local float Eff;
local int RedY, BlueY, X, Y;
local float Nil, DummyX, DummyY, SizeX, SizeY, Buffer, Size;
local byte LabelDrawn[2], Rendered[2];
local Color TeamColor, TempColor;
local string TempStr;
local SmartCTFPlayerReplicationInfo PlayerStats, PlayerStats2;
local int FlagShift; /* shifting elements to fit a flag */
if( Level.TimeSeconds - LastSortTime > 0.5 )
{
SortScores( 32 );
RecountNumbers();
InitStatBoardConstPos( C );
CompressStatBoard( C );
LastSortTime = Level.TimeSeconds;
}
Y = int( StartY );
RedY = Y;
BlueY = Y;
C.Style = ERenderStyle.STY_Normal;
// FOR EACH PLAYER DRAW INFO
for( i = 0; i < 32; i++ )
{
if( Ordered[i] == None ) break;
PlayerStats = SCTFGame.GetStatsByPRI( Ordered[i] );
if( PlayerStats == None ) continue;
// Get the ID of the ith player
ID = Ordered[i].PlayerID;
// set the pos depending on Team
if( Ordered[i].Team == 0 )
{
X = RedStartX;
Y = RedY;
TeamColor = RedTeamColor;
}
else
{
X = BlueStartX;
Y = BlueY;
TeamColor = BlueTeamColor;
}
C.DrawColor = TeamColor;
if( LabelDrawn[Ordered[i].Team] == 0 )
{
// DRAW THE Team SCORES with the cool Flag icons (masked because of black borders)
C.bNoSmooth = False;
C.Font = PlayerNameFont;
C.Style = ERenderStyle.STY_Translucent;
if( Ordered[i].Team == 0 ) C.DrawColor = RedHeaderColor;
else C.DrawColor = BlueHeaderColor;
C.StrLen( PtsText, SizeX, SizeY );
C.Style = ERenderStyle.STY_Modulated;
C.SetPos( X - ShadingSpacingX, Y - HeaderShadingSpacingY );
C.DrawRect( texture'shade', ColumnWidth + ( ShadingSpacingX * 2 ) , SizeY + ( HeaderShadingSpacingY * 2 ) );
C.Style = ERenderStyle.STY_Translucent;
C.SetPos( X - ShadingSpacingX, Y - HeaderShadingSpacingY );
if( Ordered[i].Team == 0 ) C.DrawPattern( texture'redskin2', ColumnWidth + ( ShadingSpacingX * 2 ) , SizeY + ( HeaderShadingSpacingY * 2 ) , 1 );
else C.DrawPattern( texture'blueskin2', ColumnWidth + ( ShadingSpacingX * 2 ) , SizeY + ( HeaderShadingSpacingY * 2 ) , 1 );
C.Style = ERenderStyle.STY_Modulated;
C.SetPos( X - ShadingSpacingX, Y + SizeY + HeaderShadingSpacingY );
C.DrawRect( texture'shade', ColumnWidth + ( ShadingSpacingX * 2 ) , ColumnHeight + ( ColumnShadingSpacingY * 2 ) );
C.Style = ERenderStyle.STY_Translucent;
C.DrawColor = TeamColor;
C.SetPos( X, Y - ( ( 32 - SizeY ) / 2 ) ); // Y - 4
if( Ordered[i].Team == 0 ) C.DrawIcon( texture'I_TeamR', 0.5 );
else C.DrawIcon( texture'I_TeamB', 0.5 );
C.Font = CapFont;
C.StrLen( int( pTGRI.Teams[Ordered[i].Team].Score ), DummyX, DummyY );
C.Style = ERenderStyle.STY_Normal;
C.SetPos( X + StatIndent, Y - ( ( DummyY - SizeY ) / 2 ) );
C.DrawText( int( pTGRI.Teams[Ordered[i].Team].Score ) );
//Draw the Frags/Pts text
C.Font = PlayerNameFont;
C.SetPos( X + ColumnWidth - SizeX, Y );
C.DrawText( PtsText );
C.Font = FragsFont;
C.StrLen( FragsText $ SepText, Buffer, Nil );
C.SetPos( X + ColumnWidth - SizeX - Buffer, Y );
C.DrawText( FragsText $ SepText );
C.DrawColor = HeaderTinyInfoColor;
C.Font = TinyInfoFont;
C.StrLen( "TEST", Nil, DummyY );
C.SetPos( X + StatIndent + DummyX + 2 * StatsHorSpacing, Y + ( SizeY - DummyY * 2 ) / 2 );
Time = Max( 1, Level.TimeSeconds / 60 );
AvgPing = 0;
AvgPL = 0;
TotSB = 0;
TotAmp = 0;
for( j = 0; j < 32; j++ )
{
if( Ordered[j] == None ) break;
if( Ordered[j].Team == Ordered[i].Team )
{
PlayerStats2 = SCTFGame.GetStatsByPRI( Ordered[j] );
if( PlayerStats2 == None ) continue;
AvgPing += Ordered[j].Ping;
AvgPL += Ordered[j].PacketLoss;
TotSB += PlayerStats2.ShieldBelts;
TotAmp += PlayerStats2.Amps;
}
}
if( pTGRI.Teams[Ordered[i].Team].Size != 0 )
{
AvgPing = AvgPing / pTGRI.Teams[Ordered[i].Team].Size;
AvgPL = AvgPL / pTGRI.Teams[Ordered[i].Team].Size;
}
if( TotShieldBelts == 0 ) TotSB = 0;
else TotSB = Clamp( float( TotSB ) / float( TotShieldBelts ) * 100, 0, 100 );
if( TotAmps == 0 ) TotAmp = 0;
else TotAmp = Clamp( float( TotAmp ) / float( TotAmps ) * 100, 0, 100 );
TempStr = "PING:" $ AvgPing $ " PL:" $ AvgPL $ "%";
C.DrawText( TempStr );
C.SetPos( X + StatIndent + DummyX + 2 * StatsHorSpacing, Y + ( SizeY - DummyY * 2 ) / 2 + DummyY );
TempStr = "TM:" $ Time;
if( TotSB != 0 ) TempStr = TempStr @ "SB:" $ TotSB $ "%";
if( TotAmp != 0 ) TempStr = TempStr @ "AM:" $ TotAmp $ "%";
C.DrawText( TempStr );
C.bNoSmooth = True;
Y += SizeY + HeaderShadingSpacingY + ColumnShadingSpacingY;
LabelDrawn[Ordered[i].Team] = 1;
}
C.Font = FooterFont;
C.StrLen( "Test", Nil, DummyY );
if( LabelDrawn[Ordered[i].Team] != 2 && ( Y + NameHeight + StatBlockHeight + StatBlockSpacing > C.ClipY - DummyY * 5 ) )
{
C.DrawColor = TeamColor;
C.StrLen( MoreText , Size, DummyY );
if( Ordered[i].Team == 1 ) C.SetPos( X + ColumnWidth - Size, C.ClipY - DummyY * 5 );
else C.SetPos( X, C.ClipY - DummyY * 5 );
C.DrawText( "[" @ pTGRI.Teams[Ordered[i].Team].Size - Rendered[Ordered[i].Team] @ MoreText @ "]" );
LabelDrawn[Ordered[i].Team] = 2; // "More" label also drawn
}
else if( LabelDrawn[Ordered[i].Team] != 2 )
{
// Draw the face
if( Ordered[i].HasFlag == None )
{
C.bNoSmooth = False;
C.DrawColor = White;
C.Style = ERenderStyle.STY_Translucent;
C.SetPos( X, Y );
if( SCTFGame.bStatsDrawFaces && Ordered[i].TalkTexture != None ) C.DrawIcon( Ordered[i].TalkTexture, 0.5 );
else C.DrawIcon( texture'faceless', 0.5 );
C.SetPos( X, Y );
C.DrawColor = DarkGray;
C.DrawIcon( texture'IconSelection', 1 );
C.Style = ERenderStyle.STY_Normal;
C.bNoSmooth = True;
}
// Draw the player name
C.SetPos( X + StatIndent, Y );
C.Font = PlayerNameFont;
if( Ordered[i].bAdmin ) C.DrawColor = White;
else if( Ordered[i].PlayerID == pPRI.PlayerID ) C.DrawColor = Yellow;
else C.DrawColor = TeamColor;
TempColor = C.DrawColor;
C.DrawText( Ordered[i].PlayerName );
C.StrLen( Ordered[i].PlayerName, Size, Buffer );
C.DrawColor = TinyInfoColor;
C.Font = TinyInfoFont;
C.StrLen( "TEST", Buffer, DummyY );
// Draw Time, Eff, HS, SB, Amp
C.SetPos( X + StatIndent + Size + StatsHorSpacing, Y + ( NameHeight - DummyY * 2 ) / 2 );
TempStr = "";
if( PlayerStats.HeadShots != 0 ) TempStr = TempStr $ "HS:" $ PlayerStats.HeadShots;
if( PlayerStats.ShieldBelts != 0 ) TempStr = TempStr @ "SB:" $ PlayerStats.ShieldBelts;
if( PlayerStats.Amps != 0 ) TempStr = TempStr @ "AM:" $ PlayerStats.Amps;
if( Left( TempStr, 1 ) == " " ) TempStr = Mid( TempStr, 1 );
C.DrawText( TempStr );
Time = Max( 1, ( Level.TimeSeconds + pPRI.StartTime - Ordered[i].StartTime ) / 60 );
if( PlayerStats.Frags + Ordered[i].Deaths == 0 ) Eff = 0;
else Eff = ( PlayerStats.Frags / ( PlayerStats.Frags + Ordered[i].Deaths ) ) * 100;
C.SetPos( X + StatIndent + Size + StatsHorSpacing, Y + ( NameHeight - DummyY * 2 ) / 2 + DummyY );
C.DrawText( "TM:" $ Time $ " EFF:" $ Clamp( int( Eff ), 0, 100 ) $ "%" );
// Draw the country flag
if(PlayerStats.CountryPrefix != "")
{
C.SetPos( X+8, Y + StatIndent);
C.bNoSmooth = False;
C.DrawColor = White;
C.DrawIcon(FD[GetFlagIndex(PlayerStats.CountryPrefix)].Tex, 1.0);
FlagShift=12;
C.bNoSmooth = True;
}
else
FlagShift=0;
// Draw Bot or Ping/PL
C.SetPos( X, Y + StatIndent + FlagShift);
if( Ordered[i].bIsABot )
{
C.DrawText( "BOT" );
if( Ordered[i].Team == pPRI.Team )
{
C.SetPos( X, Y + StatIndent + DummyY);
C.DrawText( Left( string( BotReplicationInfo( Ordered[i] ).RealOrders ) , 3 ) );
}
}
else
{
C.DrawColor = HeaderTinyInfoColor;
TempStr = "PI:" $ Ordered[i].Ping;
if( Len( TempStr ) > 5 ) TempStr = "P:" $ Ordered[i].Ping;
if( Len( TempStr ) > 5 ) TempStr = string( Ordered[i].Ping );
C.DrawText( TempStr );
C.SetPos( X, Y + StatIndent + DummyY + FlagShift);
TempStr = "PL:" $ Ordered[i].PacketLoss $ "%";
if( Len( TempStr ) > 5 ) TempStr = "L:" $ Ordered[i].PacketLoss $ "%";
if( Len( TempStr ) > 5 ) TempStr = "L:" $ Ordered[i].PacketLoss;
if( Len( TempStr ) > 5 ) TempStr = Ordered[i].PacketLoss $ "%";
C.DrawText( TempStr );
}
// Draw the Flag if he has Flag
if( Ordered[i].HasFlag != None )
{
C.DrawColor = White;
C.SetPos( X, Y );
if( Ordered[i].HasFlag.IsA( 'GreenFlag' ) ) C.DrawIcon( texture'GreenFlag', 1 );
else if( Ordered[i].HasFlag.IsA( 'YellowFlag' ) ) C.DrawIcon( texture'YellowFlag', 1 );
else if( Ordered[i].Team == 0 ) C.DrawIcon( texture'BlueFlag', 1 );
else C.DrawIcon( texture'RedFlag', 1 );
} // End if he has Flag
C.Font = PlayerNameFont;
C.DrawColor = TempColor;
// Draw Frag/Score
C.StrLen( int( Ordered[i].Score ), Size, DummyY );
C.SetPos( X + ColumnWidth - Size, Y );
C.DrawText( int( Ordered[i].Score ) );
C.Font = FragsFont;
C.StrLen( PlayerStats.Frags $ SepText, Buffer, SizeY );
C.SetPos( X + ColumnWidth - Size - Buffer, Y );
C.DrawText( PlayerStats.Frags $ SepText );
Y += NameHeight;
// Set the Font for the stat drawing
C.Font = StatFont;
if( RowColState == 1 )
{
DrawStatType( C, X, Y, 1, 1, "Caps: ", PlayerStats.Captures, MaxCaps );
DrawStatType( C, X, Y, 1, 2, "Assists: ", PlayerStats.Assists, MaxAssists );
DrawStatType( C, X, Y, 1, 3, "Grabs: ", PlayerStats.Grabs, MaxGrabs );
if(SCTFGame.bExtraStats)
{
if( bSealsOrDefs) {
DrawStatType( C, X, Y, 2, 2, "DefKills: ", PlayerStats.DefKills, MaxDefKills );
DrawStatType( C, X, Y, 2, 1, "Covers: ", PlayerStats.Covers, MaxCovers );
}
else {
DrawStatType( C, X, Y, 2, 2, "Seals: ", PlayerStats.Seals, MaxSeals );
DrawStatType( C, X, Y, 2, 1, "Deaths: ", Ordered[i].Deaths, MaxDeaths );
}
}
else
{
DrawStatType( C, X, Y, 2, 1, "Covers: ", PlayerStats.Covers, MaxCovers );
if( MaxSeals > 0 ) DrawStatType( C, X, Y, 2, 2, "Seals: ", PlayerStats.Seals, MaxSeals );
else DrawStatType( C, X, Y, 2, 2, "Deaths: ", Ordered[i].Deaths, MaxDeaths );
}
DrawStatType( C, X, Y, 2, 3, "FlagKls: ", PlayerStats.FlagKills, MaxFlagKills );
}
else
{
DrawStatType( C, X, Y, 1, 1, "Caps: ", PlayerStats.Captures, MaxCaps );
DrawStatType( C, X, Y, 2, 1, "Grabs: ", PlayerStats.Grabs, MaxGrabs );
if(SCTFGame.bExtraStats)
{
if( bSealsOrDefs) {
DrawStatType( C, X, Y, 2, 2, "DefKills: ", PlayerStats.DefKills, MaxDefKills );
DrawStatType( C, X, Y, 1, 2, "Covers: ", PlayerStats.Covers, MaxCovers );
}
else {
DrawStatType( C, X, Y, 2, 2, "Seals: ", PlayerStats.Seals, MaxSeals );
DrawStatType( C, X, Y, 1, 2, "Deaths: ", Ordered[i].Deaths, MaxDeaths );
}
}
else
{
DrawStatType( C, X, Y, 1, 2, "Covers: ", PlayerStats.Covers, MaxCovers );
if( MaxSeals > 0 ) DrawStatType( C, X, Y, 2, 2, "Seals: ", PlayerStats.Seals, MaxSeals );
else DrawStatType( C, X, Y, 2, 2, "Deaths: ", Ordered[i].Deaths, MaxDeaths );
}
DrawStatType( C, X, Y, 3, 1, "Assists: ", PlayerStats.Assists, MaxAssists );
DrawStatType( C, X, Y, 3, 2, "FlagKls: ", PlayerStats.FlagKills, MaxFlagKills );
}
Y += StatBlockHeight + StatBlockSpacing;
}
// Alter the RedY or BlueY and do next player
if( Ordered[i].Team == 0 ) RedY = Y;
else BlueY = Y;
Rendered[Ordered[i].Team]++;
} //End of PRI for loop
DrawHeader( C );
DrawFooters( C );
}
function InitStatBoardConstPos( Canvas C )
{
local float Nil, LeftSpacingPercent, MidSpacingPercent, RightSpacingPercent;
CapFont = Font'LEDFont2'; //Font( DynamicLoadObject( "UWindowFonts.UTFont40", class'Font' ) );
FooterFont = MyFonts.GetSmallestFont( C.ClipX );
GameEndedFont = MyFonts.GetHugeFont( C.ClipX );
PlayerNameFont = MyFonts.GetBigFont( C.ClipX );
TinyInfoFont = C.SmallFont;
if( PlayerNameFont == PtsFont22 ) FragsFont = PtsFont18;
else if( PlayerNameFont == PtsFont20 ) FragsFont = PtsFont18;
else if( PlayerNameFont == PtsFont18 ) FragsFont = PtsFont14;
else if( PlayerNameFont == PtsFont16 ) FragsFont = PtsFont12;
else FragsFont = font'SmallFont';
C.Font = PlayerNameFont;
C.StrLen( "Player", Nil, NameHeight );
StartY = ( 120.0 / 1024.0 ) * C.ClipY;
ColorChangeSpeed = 100; // Influences how 'fast' the color changes from white to green. Higher = faster.
LeftSpacingPercent = 0.075;
MidSpacingPercent = 0.15;
RightSpacingPercent = 0.075;
RedStartX = LeftSpacingPercent * C.ClipX;
ColumnWidth = ( ( 1 - LeftSpacingPercent - MidSpacingPercent - RightSpacingPercent ) / 2 * C.ClipX );
BlueStartX = RedStartX + ColumnWidth + ( MidSpacingPercent * C.ClipX );
ShadingSpacingX = ( 10.0 / 1024.0 ) * C.ClipX;
HeaderShadingSpacingY = ( 32 - NameHeight ) / 2 + ( ( 4.0 / 1024.0 ) * C.ClipX );
ColumnShadingSpacingY = ( 10.0 / 1024.0 ) * C.ClipX;
StatsHorSpacing = ( 5.0 / 1024.0 ) * C.ClipX;
StatIndent = ( 32 + StatsHorSpacing ); // For face + flag icons
InitStatBoardDynamicPos( C );
}
function InitStatBoardDynamicPos( Canvas C , optional int Rows , optional int Cols , optional Font NewStatFont , optional float LineSpacing , optional float BlockSpacing )
{
if( Rows == 0 ) Rows = 3;
if( Cols == 0 ) Cols = 2;
if( LineSpacing == 0 ) LineSpacing = 0.9;
if( BlockSpacing == 0 ) BlockSpacing = 1;
if( Rows == 2 && Cols == 3 ) RowColState = 1;
else RowColState = 0;
StatWidth = ( ( ColumnWidth - StatIndent ) / Cols ) - ( StatsHorSpacing * ( Cols - 1 ) );
if( NewStatFont == None ) StatFont = MyFonts.GetSmallestFont( C.ClipX );
else StatFont = NewStatFont;
C.Font = StatFont;
C.StrLen( "FlagKls: 00", StatsTextWidth, StatHeight );
MaxMeterWidth = StatWidth - StatsTextWidth - StatsHorSpacing;
StatLineHeight = StatHeight * LineSpacing;
MeterHeight = Max( 1, StatLineHeight * 0.3 );
StatBlockSpacing = StatLineHeight * BlockSpacing;
StatBlockHeight = Rows * StatLineHeight;
if( pTGRI.Teams[0].Size > pTGRI.Teams[1].Size )
ColumnHeight = pTGRI.Teams[0].Size * ( NameHeight + StatBlockHeight + StatBlockSpacing ) - StatBlockSpacing;
else
ColumnHeight = pTGRI.Teams[1].Size * ( NameHeight + StatBlockHeight + StatBlockSpacing ) - StatBlockSpacing;
}
function CompressStatBoard( Canvas C , optional int Level )
{
local float EndY, Nil, DummyY;
C.Font = FooterFont;
C.StrLen( "Test", Nil, DummyY );
EndY = StartY + ColumnHeight + ( ColumnShadingSpacingY * 2 ) + NameHeight + HeaderShadingSpacingY;
if( EndY > C.ClipY - DummyY * 5 )
{
if( Level == 0 )
{
InitStatBoardDynamicPos( C, , , , 0.8 );
}
else if( Level == 1 )
{
InitStatBoardDynamicPos( C, 2, 3 );
}
else if( Level == 2 )
{
InitStatBoardDynamicPos( C, 2, 3, Font( DynamicLoadObject( "UWindowFonts.Tahoma10", class'Font' ) ) , 1.0 , 1.0 );
}
else
{
// We did all the compression we can do. Draw 'More' labels later.
// First find the columnheight for the amount of players that fit on it.
ColumnHeight = int( ( C.ClipY - ( EndY - ColumnHeight ) - DummyY * 5 + StatBlockSpacing ) / ( NameHeight + StatBlockHeight + StatBlockSpacing ) )
* ( NameHeight + StatBlockHeight + StatBlockSpacing ) - StatBlockSpacing;
return;
}
// Did some compression, see if we need more.
CompressStatBoard( C , Level + 1 );
}
// No compression at all or no more compression needed.
return;
}
/*
* Draw a specific stat
* X, Y = Upper left corner of stats ( row,col: 1,1)
*/
function DrawStatType( Canvas C, int X, int Y, int Row, int Col, string Label, int Count, int Total )
{
local float Size, DummyY;
local int ColorChange, M;
X += StatIndent + ( ( StatWidth + StatsHorSpacing ) * ( Col - 1 ) );
Y += ( StatLineHeight * ( Row - 1 ) );
C.DrawColor = StatsColor;
C.SetPos( X, Y );
C.DrawText( Label );
C.StrLen( Count, Size, DummyY );
C.SetPos( X + StatsTextWidth - Size, Y );
C.DrawText( Count ); //text
if( Count > 0 )
{
ColorChange = ColorChangeSpeed * loge( Count );
if( ColorChange > 255 ) ColorChange = 255;
C.DrawColor.R = StatsColor.R - ColorChange;
C.DrawColor.B = StatsColor.B - ColorChange;
}
M = GetMeterLength( Count, Total );
C.SetPos( X + StatsTextWidth + StatsHorSpacing, Y + ( ( StatHeight - MeterHeight ) / 2 ) );
C.DrawRect( texture'meter', M, MeterHeight ); //meter
}
function DrawFooters( Canvas C )
{
local float DummyX, DummyY, Nil, X1, Y1;
local string TextStr;
local string TimeStr;
local int Hours, Minutes, Seconds, i;
local PlayerReplicationInfo PRI;
local color specColor;
local int baseX, baseY;
C.bCenter = True;
C.Font = FooterFont;
// Display server info in bottom center
C.DrawColor = FooterColor;
C.StrLen( "Test", DummyX, DummyY );
C.SetPos( 0, C.ClipY - DummyY );
TextStr = "Playing" @ Level.Title @ "on" @ pTGRI.ServerName;
if( SCTFGame.TickRate > 0 ) TextStr = TextStr @ "(TR:" @ SCTFGame.TickRate $ ")";
C.DrawText( TextStr );
// Draw Time
if( bTimeDown || ( PlayerOwner.GameReplicationInfo.RemainingTime > 0 ) )
{
bTimeDown = True;
if( PlayerOwner.GameReplicationInfo.RemainingTime <= 0 )
{
TimeStr = RemainingTime $ "00:00";
}
else
{
Minutes = PlayerOwner.GameReplicationInfo.RemainingTime / 60;
Seconds = PlayerOwner.GameReplicationInfo.RemainingTime % 60;
TimeStr = RemainingTime $ TwoDigitString( Minutes ) $ ":" $ TwoDigitString( Seconds );
}
}
else
{
Seconds = PlayerOwner.GameReplicationInfo.ElapsedTime;
Minutes = Seconds / 60;
Hours = Minutes / 60;
Seconds = Seconds - ( Minutes * 60 );
Minutes = Minutes - ( Hours * 60 );
TimeStr = ElapsedTime $ TwoDigitString( Hours ) $ ":" $ TwoDigitString( Minutes ) $ ":" $ TwoDigitString( Seconds );
}
if(SCTFGame.bShowSpecs){
for ( i=0; i<32; i++ )
{
if (PlayerPawn(Owner).GameReplicationInfo.PRIArray[i] != None)
{
PRI = PlayerPawn(Owner).GameReplicationInfo.PRIArray[i];
if (PRI.bIsSpectator && !PRI.bWaitingPlayer && PRI.StartTime > 0)
{
if(HeaderText=="") HeaderText = pri.Playername; else HeaderText = HeaderText$", "$pri.Playername;
}
}
}
if (HeaderText=="") HeaderText = "there is currently no one spectating this match."; else HeaderText = HeaderText$"."; // I'm sorry about this, it's really stupid
} // but I'm to lazy rewrite it :P
// Atleast it's working..
C.SetPos( 0, C.ClipY - 2 * DummyY );
C.DrawText( "Current Time:" @ GetTimeStr() @ "|" @ TimeStr );
// Draw Spectators
C.StrLen( HeaderText, DummyX, Nil );
C.Style = ERenderStyle.STY_Normal;
C.SetPos( 0, C.ClipY - 5 * DummyY );
if(SCTFGame.bShowSpecs){
specColor = SCTFGame.SpectatorColor;
C.Font = MyFonts.GetSmallestFont(C.ClipX);
C.DrawColor = specColor; // Added in 4E
C.DrawText("Spectators:"@HeaderText);
HeaderText=""; // This is declared as a global var, so we reset it to start with a clean slate.
}else{
C.DrawText( "" ); // Don't draw credits 2 times
}
// Draw new-credits
C.StrLen( HeaderText2, DummyX, DummyY );
C.Style = ERenderStyle.STY_Normal;
C.SetPos( 0, C.ClipY - 3 * DummyY );
C.Font = MyFonts.GetSmallestFont(C.ClipX);
C.DrawColor = Yellow;
C.DrawText( HeaderText2 );
C.bCenter = False;
}
function DrawHeader( Canvas C )
{
local float DummyX, DummyY;
if( pTGRI.GameEndedComments == "" ) return;
C.Font = GameEndedFont;
C.StrLen( pTGRI.GameEndedComments, DummyX, DummyY );
C.DrawColor = DarkGray;
C.Style = ERenderStyle.STY_Translucent;
C.SetPos( C.ClipX / 2 - DummyX / 2 + 2, DummyY + 2 );
C.DrawText( pTGRI.GameEndedComments );
C.DrawColor = HeaderColor;
C.Style = ERenderStyle.STY_Normal;
C.SetPos( C.ClipX / 2 - DummyX / 2, DummyY );
C.DrawText( pTGRI.GameEndedComments );
}
/*
* Returns time and date in a string.
*/
function string GetTimeStr()
{
local string Mon, Day, Min;
Min = string( PlayerOwner.Level.Minute );
if( int( Min ) < 10 ) Min = "0" $ Min;
switch( PlayerOwner.Level.month )
{
case 1: Mon = "Jan"; break;
case 2: Mon = "Feb"; break;
case 3: Mon = "Mar"; break;
case 4: Mon = "Apr"; break;
case 5: Mon = "May"; break;
case 6: Mon = "Jun"; break;
case 7: Mon = "Jul"; break;
case 8: Mon = "Aug"; break;
case 9: Mon = "Sep"; break;
case 10: Mon = "Oct"; break;
case 11: Mon = "Nov"; break;
case 12: Mon = "Dec"; break;
}
switch( PlayerOwner.Level.dayOfWeek )
{
case 0: Day = "Sunday"; break;
case 1: Day = "Monday"; break;
case 2: Day = "Tuesday"; break;
case 3: Day = "Wednesday"; break;
case 4: Day = "Thursday"; break;
case 5: Day = "Friday"; break;
case 6: Day = "Saturday"; break;
}
return Day @ PlayerOwner.Level.Day @ Mon @ PlayerOwner.Level.Year $ "," @ PlayerOwner.Level.Hour $ ":" $ Min;
}
/*
* Length of a meter drawing for a given number A out of B total.
*/
function int GetMeterLength( int A, int B )
{
local int Result;
if( B == 0 ) return 0;
Result = ( A * MaxMeterWidth ) / B;
if( Result > MaxMeterWidth ) return MaxMeterWidth;
else return Result;
}
/*
* Sort PlayerReplicationInfo's on score.
*/
function SortScores( int N )
{
local byte i, j;
local bool bSorted;
local SmartCTFPlayerReplicationInfo PlayerStats1, PlayerStats2;
// Copy PRI array except for spectators.
j = 0;
for( i = 0; i < N; i++ )
{
if( pTGRI.priArray[i] == None ) break;
if( pTGRI.priArray[i].bIsSpectator && !pTGRI.priArray[i].bWaitingPlayer ) continue;
Ordered[j] = pTGRI.priArray[i];
j++;
}
// Clear the remaining entries.
for( i = j; i < N; i++ )
{
Ordered[i] = None;
}
for( i = 0; i < N; i++)
{
bSorted = True;
for( j = 0; j < N - 1; j++)
{
if( Ordered[j] == None || Ordered[j+1] == None ) break;
if( Ordered[j].Score < Ordered[j+1].Score )
{
SwapOrdered( j, j + 1 );
bSorted = False;
}
else if( Ordered[j].Score == Ordered[j+1].Score )
{
PlayerStats1 = SCTFGame.GetStatsByPRI( Ordered[j] );
PlayerStats2 = SCTFGame.GetStatsByPRI( Ordered[j+1] );
if( PlayerStats1 != None && PlayerStats2 != None )
{
if( PlayerStats1.Frags < PlayerStats2.Frags )
{
SwapOrdered( j, j + 1 );
bSorted = False;
}
else if( PlayerStats1.Frags == PlayerStats2.Frags )
{
if( Ordered[j].Deaths > Ordered[j+1].Deaths )
{
SwapOrdered( j, j + 1 );
bSorted = False;
}
}
}
}
}
if( bSorted ) break;
}
}
/*
* Used for sorting.
*/
function SwapOrdered( byte A, byte B )
{
local PlayerReplicationInfo Temp;
Temp = Ordered[A];
Ordered[A] = Ordered[B];
Ordered[B] = Temp;
}
/*
* Recalculate the totals for displaying meters on the scoreboards.
* This way it doesn't get calculated every tick.
*/
function RecountNumbers()
{
local byte ID, i;
local SmartCTFPlayerReplicationInfo PlayerStats;
MaxCaps = 0;
MaxAssists = 0;
MaxGrabs = 0;
MaxCovers = 0;
MaxSeals = 0;
MaxDefKills = 0;
MaxFlagKills = 0;
MaxFrags = 0;
MaxDeaths = 0;
TotShieldBelts = 0;
TotAmps = 0;
for( i = 0; i < 32; i++ )
{
if( Ordered[i] == None ) break;
if( Ordered[i].bIsSpectator && !Ordered[i].bWaitingPlayer ) continue;
ID = Ordered[i].PlayerID;
PlayerStats = SCTFGame.GetStatsByPRI( Ordered[i] );
if( PlayerStats != None )
{
if( PlayerStats.Captures > MaxCaps ) MaxCaps = PlayerStats.Captures;
if( PlayerStats.Assists > MaxAssists ) MaxAssists = PlayerStats.Assists;
if( PlayerStats.Grabs > MaxGrabs ) MaxGrabs = PlayerStats.Grabs;
if( PlayerStats.Covers > MaxCovers ) MaxCovers = PlayerStats.Covers;
if( PlayerStats.Seals > MaxSeals ) MaxSeals = PlayerStats.Seals;
if( PlayerStats.DefKills > MaxDefKills ) MaxDefKills = PlayerStats.DefKills;
if( PlayerStats.FlagKills > MaxFlagKills ) MaxFlagKills = PlayerStats.FlagKills;
if( PlayerStats.Frags > MaxFrags ) MaxFrags = PlayerStats.Frags;
TotShieldBelts += PlayerStats.ShieldBelts;
TotAmps += PlayerStats.Amps;
}
if( Ordered[i].Deaths > MaxDeaths ) MaxDeaths = Ordered[i].Deaths;
}
}
defaultproperties
{
PtsText="Pts"
FragsText="Frags"
SepText=" / "
MoreText="More..."
HeaderText2="[ SmartCTF 4E | {PiN}Kev | {DnF2}SiNiSTeR | [es]Rush | adminthis & The_Cowboy & Sp0ngeb0b ]"
White=(R=255,G=255,B=255)
Gray=(R=128,G=128,B=128)
DarkGray=(R=32,G=32,B=32)
Yellow=(R=255,G=255)
RedTeamColor=(R=255)
BlueTeamColor=(G=128,B=255)
RedHeaderColor=(R=64)
BlueHeaderColor=(G=32,B=64)
StatsColor=(R=255,G=255,B=255)
FooterColor=(R=255,G=255,B=255)
HeaderColor=(R=255,G=255)
TinyInfoColor=(R=128,G=128,B=128)
HeaderTinyInfoColor=(R=192,G=192,B=192)
}

View File

@@ -0,0 +1,16 @@
class SmartCTFServerActor expands Actor;
function PostBeginPlay()
{
if( CTFGame( Level.Game ) != None )
{
Log( "ServerActor, Spawning and adding Mutator...", 'SmartCTF' );
Level.Game.BaseMutator.AddMutator( Level.Game.Spawn( class'SmartCTF' ) );
}
Destroy();
}
defaultproperties
{
bHidden=True
}

View File

@@ -0,0 +1,361 @@
class SmartCTFServerInfo expands ServerInfoCTF;
var SmartCTFGameReplicationInfo SCTFGame;
var PlayerPawn PlayerOwner;
var string MapNameText;
var bool bFontUpdated;
var float LastUpdateTime;
var float HeaderHeight, CatHeight, TextHeight, SmallTextHeight, VSpacing, BorderSpacing, TotalHeight;
var float StartY, Y, SideSpacing;
var Color HeaderBlue, TextBlue, InfoWhite;
function PostBeginPlay()
{
if( SCTFGame == None )
{
ForEach AllActors( class'SmartCTFGameReplicationInfo', SCTFGame ) break;
}
super.PostBeginPlay();
}
function RenderInfo( Canvas C )
{
local float XL;
local GameReplicationInfo GRI;
if( Level.TimeSeconds - LastUpdateTime > 0.5 ) bFontUpdated = False;
if( !bFontUpdated )
{
C.Font = MyFonts.GetHugeFont( C.ClipX );
C.StrLen( "Test", XL, HeaderHeight );
C.Font = MyFonts.GetBigFont( C.ClipX );
C.StrLen( "Test", XL, CatHeight );
C.Font = MyFonts.GetSmallFont( C.ClipX );
C.StrLen( "Test", XL, TextHeight );
C.Font = MyFonts.GetSmallFont( C.ClipX );
C.StrLen( "Test", XL, SmallTextHeight );
CatHeight = CatHeight * 1.2;
TextHeight = TextHeight * 1.2;
SmallTextHeight = SmallTextHeight * 1.1;
VSpacing = HeaderHeight * 0.8;
BorderSpacing = VSpacing;
TotalHeight = 1.5 * HeaderHeight + 2 * BorderSpacing + CatHeight * 3 + TextHeight * 6 + SmallTextHeight * 7 + VSpacing * 3;
StartY = C.ClipY / 2 - TotalHeight / 2;
SideSpacing = C.ClipX / 10;
bFontUpdated = True;
LastUpdateTime = Level.TimeSeconds;
}
GRI = PlayerPawn(Owner).GameReplicationInfo;
DrawTitle( C );
DrawContactInfo( C, GRI );
DrawMOTD( C, GRI );
DrawGameStats( C, GRI );
DrawServerStats( C, GRI );
DrawLeaderBoard( C, GRI );
}
function DrawTitle( Canvas C )
{
Y = StartY;
C.Style = ERenderStyle.STY_Modulated;
C.SetPos( SideSpacing - BorderSpacing, Y );
C.DrawRect( texture'shade', C.ClipX - 2 * SideSpacing + 2 * BorderSpacing , TotalHeight );
C.Style = ERenderStyle.STY_Translucent;
C.DrawColor.R = 32;
C.DrawColor.G = 32;
C.DrawColor.B = 32;
C.SetPos( SideSpacing - BorderSpacing, Y );
C.DrawPattern( texture'newblue', C.ClipX - 2 * SideSpacing + 2 * BorderSpacing , 1.5 * HeaderHeight, 1.0 );
C.Style = ERenderStyle.STY_Normal;
C.Font = MyFonts.GetHugeFont( C.ClipX );
C.DrawColor = HeaderBlue;
C.bCenter = True;
C.SetPos( 0, Y + 0.25 * HeaderHeight );
C.DrawText( ServerInfoText, True );
C.bCenter = False;
Y += 1.5 * HeaderHeight + BorderSpacing;
}
function DrawContactInfo( Canvas C, GameReplicationInfo GRI )
{
local float XL, YL, XL2, YL2;
C.DrawColor = HeaderBlue;
C.Font = MyFonts.GetBigFont( C.ClipX );
C.StrLen( "TEMP", XL, YL );
C.SetPos( SideSpacing, Y );
C.DrawText( ContactInfoText, True);
C.DrawColor = TextBlue;
C.Font = MyFonts.GetSmallFont( C.ClipX );
C.StrLen( "TEMP", XL2, YL2 );
C.SetPos( SideSpacing, Y + CatHeight );
C.DrawText( NameText, True);
C.SetPos( SideSpacing, Y + CatHeight + TextHeight );
C.DrawText( AdminText, True);
C.SetPos( SideSpacing, Y + CatHeight + 2 * TextHeight);
C.DrawText( EMailText, True);
C.DrawColor = InfoWhite;
C.SetPos( SideSpacing + XL2 * 2, Y + CatHeight );
C.DrawText( GRI.ServerName, True);
C.SetPos( SideSpacing + XL2 * 2, Y + CatHeight + TextHeight );
if( GRI.AdminName != "" )
C.DrawText( GRI.AdminName, True );
else
C.DrawText( UnknownText, True );
C.SetPos( SideSpacing + XL2 * 2, Y + CatHeight + 2 * TextHeight );
if( GRI.AdminEmail != "" )
C.DrawText( GRI.AdminEmail, True );
else
C.DrawText( UnknownText, True );
}
function DrawMOTD( Canvas C, GameReplicationInfo GRI )
{
local float XL, YL, XL2, YL2;
C.DrawColor = HeaderBlue;
C.Font = MyFonts.GetBigFont( C.ClipX );
C.StrLen( "TEMP", XL, YL );
C.SetPos( SideSpacing * 6, Y );
C.DrawText( MOTD, True );
C.DrawColor = InfoWhite;
C.Font = MyFonts.GetSmallFont( C.ClipX );
C.StrLen( "TEMP", XL2, YL2 );
C.StrLen( GRI.MOTDLine1, XL2, YL2 );
C.SetPos( SideSpacing * 6, Y + CatHeight );
C.DrawText( GRI.MOTDLine1, True );
C.StrLen( GRI.MOTDLine2, XL2, YL2 );
C.SetPos( SideSpacing * 6, Y + CatHeight + TextHeight );
C.DrawText( GRI.MOTDLine2, True );
C.StrLen( GRI.MOTDLine3, XL2, YL2 );
C.SetPos( SideSpacing * 6, Y + CatHeight + 2 * TextHeight );
C.DrawText( GRI.MOTDLine3, True );
C.StrLen( GRI.MOTDLine4, XL2, YL2 );
C.SetPos( SideSpacing * 6, Y + CatHeight + 3 * TextHeight );
C.DrawText( GRI.MOTDLine4, True );
Y += CatHeight + 4 * TextHeight + VSpacing;
}
function DrawGameStats( Canvas C, GameReplicationInfo GRI )
{
local float XL, YL, XL2, YL2;
local int i, NumBots;
C.DrawColor = HeaderBlue;
C.Font = MyFonts.GetBigFont( C.ClipX );
C.StrLen( "TEMP", XL, YL );
C.SetPos( SideSpacing, Y );
C.DrawText( GameStatsText, True );
C.DrawColor = TextBlue;
C.Font = MyFonts.GetSmallFont( C.ClipX );
C.StrLen( "TEMP", XL2, YL2 );
C.SetPos( SideSpacing, Y + CatHeight );
C.DrawText( GameTypeText, True );
C.SetPos( SideSpacing, Y + CatHeight + TextHeight );
C.DrawText( PlayersText, True );
C.DrawColor = InfoWhite;
C.SetPos( SideSpacing * 2, Y + CatHeight );
C.DrawText( "Smart Capture The Flag", True); // GRI.GameName
for( i = 0; i < 32; i++ )
{
if( ( GRI.PRIArray[i] != None ) && ( GRI.PRIArray[i].bIsABot ) ) NumBots++;
}
C.SetPos( SideSpacing * 2, Y + CatHeight + TextHeight );
C.DrawText( GRI.NumPlayers $ " [" $ NumBots @ BotText $ "]", True );
}
function DrawServerStats( canvas C, GameReplicationInfo GRI )
{
local float XL, YL, XL2, YL2;
local TournamentGameReplicationInfo TGRI;
C.DrawColor = HeaderBlue;
C.Font = MyFonts.GetBigFont( C.ClipX );
C.StrLen( "TEMP", XL, YL );
C.SetPos( SideSpacing * 6, Y );
C.DrawText( ServerStatsText, True );
C.DrawColor = TextBlue;
C.Font = MyFonts.GetSmallFont( C.ClipX );
C.StrLen( "TEMP", XL2, YL2 );
C.SetPos( SideSpacing * 6, Y + CatHeight );
C.DrawText( GamesHostedText, True);
C.SetPos( SideSpacing * 6, Y + CatHeight + TextHeight );
C.DrawText( FlagsCapturedText, True);
C.DrawColor = InfoWhite;
TGRI = TournamentGameReplicationInfo( GRI );
C.SetPos( SideSpacing * 7.25, Y + CatHeight );
C.DrawText( TGRI.TotalGames, True );
C.SetPos( SideSpacing * 7.25, Y + CatHeight + TextHeight );
C.DrawText( TGRI.TotalFlags, True );
Y += CatHeight + 2 * TextHeight + VSpacing;
}
function DrawLeaderBoard( Canvas C, GameReplicationInfo GRI )
{
local float YL;
local int i;
local SmartCTFEndStats EndStats;
local string Title, What, Who, Where, When;
C.DrawColor = HeaderBlue;
YL = ( CatHeight + SmallTextHeight - 4 ) / 64;
C.Font = MyFonts.GetBigFont( C.ClipX );
C.SetPos( SideSpacing + 68 * YL, Y );
C.DrawText( TopPlayersText, True );
C.DrawColor = InfoWhite;
C.Style = ERenderStyle.STY_Translucent;
C.bNoSmooth = False;
C.SetPos( SideSpacing, Y );
C.DrawIcon( texture'UTMenu.TrophyCTF', YL );
C.SetPos( SideSpacing, Y );
C.bNoSmooth = True;
C.Style = ERenderStyle.STY_Normal;
C.Font = MyFonts.GetSmallestFont( C.ClipX );
C.DrawColor = TextBlue;
C.SetPos( SideSpacing * 2.5, Y + CatHeight );
C.DrawText( BestFPHText, True );
C.SetPos( SideSpacing * 3.75, Y + CatHeight );
C.DrawText( BestNameText, True );
C.SetPos( SideSpacing * 5.75, Y + CatHeight );
C.DrawText( MapNameText, True );
C.SetPos( SideSpacing * 7.5, Y + CatHeight );
C.DrawText( BestRecordSetText, True );
C.DrawColor = InfoWhite;
if( SCTFGame != None ) EndStats = SCTFGame.EndStats;
if( EndStats != None )
{
for( i = 0; i < 6; i++ )
{
switch( i )
{
case 0:
Title = "Greatest Point 'Ho";
What = EndStats.MostPoints.Count @ "points/h";
Who = EndStats.MostPoints.PlayerName;
Where = EndStats.MostPoints.MapName;
When = EndStats.MostPoints.RecordDate;
break;
case 1:
Title = "Biggest DM'er";
What = EndStats.MostFrags.Count @ "frags/h";
Who = EndStats.MostFrags.PlayerName;
Where = EndStats.MostFrags.MapName;
When = EndStats.MostFrags.RecordDate;
break;
case 2:
Title = "Best Flagcapper";
What = EndStats.MostCaps.Count @ "caps/h";
Who = EndStats.MostCaps.PlayerName;
Where = EndStats.MostCaps.MapName;
When = EndStats.MostCaps.RecordDate;
break;
case 3:
Title = "Best Flagkiller";
What = EndStats.MostFlagkills.Count @ "flagk./h";
Who = EndStats.MostFlagkills.PlayerName;
Where = EndStats.MostFlagkills.MapName;
When = EndStats.MostFlagkills.RecordDate;
break;
case 4:
Title = "Most Cover";
What = EndStats.MostCovers.Count @ "covers/h";
Who = EndStats.MostCovers.PlayerName;
Where = EndStats.MostCovers.MapName;
When = EndStats.MostCovers.RecordDate;
break;
case 5:
Title = "Hardcore Sniper";
What = EndStats.MostHeadShots.Count @ "HS/h";
Who = EndStats.MostHeadShots.PlayerName;
Where = EndStats.MostHeadShots.MapName;
When = EndStats.MostHeadShots.RecordDate;
break;
}
if( What == "" ) What = "--";
if( Who == "" ) Who = "--";
if( Where == "" ) Where = "--";
if( When == "" ) When = "--";
if( Len( Where ) > 20 ) Where = Left( Where, 20 ) $ "..";
if( Len( Who ) > 25 ) Who = Left( Who, 25 ) $ "..";
C.DrawColor = TextBlue;
C.SetPos( SideSpacing, Y + CatHeight + ( ( i + 1 ) * SmallTextHeight ) );
C.DrawText( Title, True );
C.DrawColor = InfoWhite;
C.SetPos( SideSpacing * 2.5, Y + CatHeight + ( ( i + 1 ) * SmallTextHeight ) );
C.DrawText( What, True );
C.SetPos( SideSpacing * 3.75, Y + CatHeight + ( ( i + 1 ) * SmallTextHeight ) );
C.DrawText( Who, True );
C.SetPos( SideSpacing * 5.75, Y + CatHeight + ( ( i + 1 ) * SmallTextHeight ) );
C.DrawText( Where, True );
C.SetPos( SideSpacing * 7.5, Y + CatHeight + ( ( i + 1 ) * SmallTextHeight ) );
C.DrawText( When, True );
}
}
}
defaultproperties
{
MapNameText="Where"
HeaderBlue=(R=9,G=151,B=247)
TextBlue=(G=128,B=255)
InfoWhite=(R=255,G=255,B=255)
TopPlayersText="SmartCTF Record Holders [Numbers per Hour]"
BestNameText="Who"
BestFPHText="What"
BestRecordSetText="When"
}

View File

@@ -0,0 +1,314 @@
// SnowyScoreboard original from CTT. Thanks to Defrost!
// Brought to SmartCTF by Sp0ngeb0b
// spongebobut@yahoo.com
class SmartCTFSnowyScoreboard extends SmartCTFScoreBoard;
#exec texture import name=snowFlake1 file="Textures\SnowFlake1.pcx" mips=off flags=2
#exec texture import name=snowFlake2 file="Textures\SnowFlake2.pcx" mips=off flags=2
#exec texture import name=snowFlake3 file="Textures\SnowFlake3.pcx" mips=off flags=2
#exec texture import name=snowFlake4 file="Textures\SnowFlake4.pcx" mips=off flags=2
#exec texture import name=snowFlake5 file="Textures\SnowFlake5.pcx" mips=off flags=2
#exec texture import name=snowFlake6 file="Textures\SnowFlake6.pcx" mips=off flags=2
#exec texture import name=snowFlake7 file="Textures\SnowFlake7.pcx" mips=off flags=2
#exec texture import name=snowFlake8 file="Textures\SnowFlake8.pcx" mips=off flags=2
#exec texture import name=snowFlake9 file="Textures\SnowFlake9.pcx" mips=off flags=2
#exec texture import name=snowFlake10 file="Textures\SnowFlake10.pcx" mips=off flags=2
#exec texture import name=snowFlake11 file="Textures\SnowFlake11.pcx" mips=off flags=2
#exec texture import name=snowFlake12 file="Textures\SnowFlake12.pcx" mips=off flags=2
#exec texture import name=snowFlake13 file="Textures\SnowFlake13.pcx" mips=off flags=2
#exec texture import name=snowFlake14 file="Textures\SnowFlake14.pcx" mips=off flags=2
#exec texture import name=snowFlake15 file="Textures\SnowFlake15.pcx" mips=off flags=2
#exec texture import name=snowFlake16 file="Textures\SnowFlake16.pcx" mips=off flags=2
//#exec texture import name=lights file="Textures\Lights2.pcx" mips=off flags=2
#exec texture import name=santa file="Textures\santa2.pcx" mips=off flags=2
#exec texture import name=present file="Textures\presents.pcx" mips=off flags=2
struct ParticleInfo { // Snow particle description struct.
var int spriteNum; // The snow flake sprite to use.
var float cx; // Horizontal offset.
var float cy; // Vertical offset.
var float ct; // Time offset.
var float waveFreq; // Particle wave frequency.
var float waveAmplitude; // Amplitude of the wave.
var float dy; // Vertical base velocity.
var float dx; // Horizontal base velocity.
var color col; // Color of the particle.
};
var color baseColor; // Base color of the snow flakes.
var bool bSnowInitialized; // Whether the particles have been initialized.
var Texture sprites[16]; // Snow flake sprites.
var ParticleInfo particles[100]; // Current particles displayed.
var float lastUpdateTime; // Last time the particles were rendered.
var float minDX; // Minimum horizontal base velocity.
var float maxDX; // Maximum horizontal base velocity.
var float minDY; // Minimum vertical base velocity.
var float maxDY; // Maximum vertical base velocity.
var float minWaveAmplitude; // Minimum wave amplitude.
var float maxWaveAmplitude; // Maximum wave amplitude.
// Non scaled constants.
const minWaveFreq = 0.25; // Minimum wave frequency.
const maxWaveFreq = 1.0; // Maximum wave frequency.
const minGlow = 0.40; // Minimum snow flake sprite glow.
const maxGlow = 1.00; // Maximum snow flake sprite glow.
// Scaled constants (set for a resolution of 1280x1024 px).
const scaleMinDX = -20.0;
const scaleMaxDX = 20.0;
const scaleMinDY = 100.0;
const scaleMaxDY = 300.0;
const scaleMinWaveAmplitude = 8;
const scaleMaxWaveAmplitude = 22;
const scaleWidth = 1280;
const scaleHeight = 1024;
// Texture constante
// const lightsTextureWidth = 32; // Width of the lights texture.
// const lightsTextureHeight = 256; // Height of the lights texture.
const santaTextureWidth = 128; // Width of the santa texture.
const santaTextureHeight = 128; // Height of the santa texture.
const presentTextureWidth = 128; // Width of the present texture.
const presentTextureHeight = 128; // Height of the present texture.
/***************************************************************************************************
*
* $DESCRIPTION Renders the scoreboard.
* $PARAM c The canvas on which the rendering should be performed.
* $REQUIRE c != none
* $OVERRIDE
*
**************************************************************************************************/
function showScores(Canvas c) {
super.showScores(c);
renderSnow(c);
}
/***************************************************************************************************
*
* $DESCRIPTION Renders the scoreboard in small scale?
* $PARAM c The canvas on which the rendering should be performed.
* $REQUIRE c != none
* $OVERRIDE
*
**************************************************************************************************/
function showMiniScores(Canvas c) {
super.showMiniScores(c);
renderSnow(c);
}
/***************************************************************************************************
*
* $DESCRIPTION Renders the snow particles. Also adds the XmasImages.
* $PARAM c The canvas on which the rendering should be performed.
* $REQUIRE c != none
* $OVERRIDE
*
**************************************************************************************************/
simulated function renderSnow(Canvas c) {
local int baseX, baseY;
local int index;
local Texture sprite;
local float cx, cy;
// Update position of each particle.
updateSnow(c);
// Draw each particle.
c.style = ERenderStyle.STY_Translucent;
for (index = 0; index < arrayCount(particles); index++) {
// Set position.
cx = particles[index].cx;
cy = particles[index].cy;
cx += sin(particles[index].ct * particles[index].waveFreq * 2 * pi) * particles[index].waveAmplitude;
c.setPos(cx, cy);
// Draw particle sprite.
c.drawColor = particles[index].col;
sprite = sprites[particles[index].spriteNum];
c.drawTile(sprite, sprite.uSize, sprite.vSize, 0, 0, sprite.uSize, sprite.vSize);
}
/* Draw Lights (Looked stupid, removed)
baseX = 0;
baseY = c.clipY / 2;
c.style = ERenderStyle.STY_Normal;
c.drawColor = BaseColor;
c.setPos(baseX, baseY);
c.drawTile(Texture'lights', lightsTextureWidth, lightsTextureHeight, 0.0, 0.0, lightsTextureWidth, lightsTextureHeight);*/
if (SCTFGame.bXmasImages) // whether to display the Sexy Xmas images! :D
{
// Draw Santa
baseX = c.clipX - santaTextureWidth - 16;
baseY = c.clipY - santaTextureHeight - 16;
c.style = ERenderStyle.STY_Normal;
c.drawColor = BaseColor;
c.setPos(baseX, baseY);
c.drawTile(Texture'santa', santaTextureWidth, santaTextureHeight, 0.0, 0.0, santaTextureWidth, santaTextureHeight);
// Draw presents
baseX = 16;
baseY = c.clipY - presentTextureHeight - 16;
c.style = ERenderStyle.STY_Normal;
c.drawColor = BaseColor;
c.setPos(baseX, baseY);
c.drawTile(Texture'present', presentTextureWidth, presentTextureHeight, 0.0, 0.0, presentTextureWidth, presentTextureHeight);
}
}
/***************************************************************************************************
*
* $DESCRIPTION Updates the positions of the snow particles.
* $PARAM c The canvas on which the rendering should be performed.
* $REQUIRE c != none
* $OVERRIDE
*
**************************************************************************************************/
simulated function updateSnow(Canvas c) {
local float deltaTime;
local int index;
// Prepare for update.
setupScalars(c);
if (!bSnowInitialized) {
initializeSnow(c);
}
deltaTime = fMin(0.5, level.timeSeconds - lastUpdateTime);
// Move each particle.
for (index = 0; index < arrayCount(particles); index++) {
particles[index].cx += particles[index].dx * deltaTime;
particles[index].cy += particles[index].dy * deltaTime;
particles[index].ct += deltaTime / level.timeDilation;
// Check if particle has left the screen.
if (particles[index].cy > c.clipY) {
// It has, reset particle.
initializeParticle(index, c, true);
}
}
lastUpdateTime = level.timeSeconds;
}
/***************************************************************************************************
*
* $DESCRIPTION Initializes all snow particles.
* $PARAM c The canvas on which the rendering should be performed.
* $REQUIRE c != none
* $ENSURE bSnowInitialized
* $OVERRIDE
*
**************************************************************************************************/
simulated function initializeSnow(Canvas c) {
local int index;
bSnowInitialized = true;
// Initialize each particle.
for (index = 0; index < arrayCount(particles); index++) {
initializeParticle(index, c);
}
lastUpdateTime = level.timeSeconds;
}
/***************************************************************************************************
*
* $DESCRIPTION Initializes the specified particle.
* $PARAM index The particle that is to be initialized.
* $PARAM c The canvas on which the rendering should be performed.
* $PARAM bReset Reset particle to the top of the screen.
* $REQUIRE 0 <= index && index <= arrayCount(particles) && c != none
* $OVERRIDE
*
**************************************************************************************************/
simulated function initializeParticle(int index, Canvas c, optional bool bReset) {
particles[index].spriteNum = rand(arrayCount(sprites));
particles[index].cx = fRand() * c.clipX;
if (bReset) {
particles[index].cy = -sprites[particles[index].spriteNum].vSize;
} else {
particles[index].cy = fRand() * c.clipY;
}
particles[index].ct = 0.0;
particles[index].dx = fRand() * (maxDX - minDX) + minDX;
particles[index].dy = fRand() * (maxDY - minDY) + minDY;
particles[index].waveFreq = fRand() * (maxWaveFreq - minWaveFreq) + minWaveFreq;
particles[index].waveAmplitude = fRand() * (maxWaveAmplitude - minWaveAmplitude) + minWaveAmplitude;
particles[index].waveFreq *= particles[index].dy / maxDY;
particles[index].waveAmplitude *= particles[index].dy / maxDY;
if (level.month == 12 && level.day == 24 || level.month == 12 && level.day == 25 || level.month == 12 && level.day == 31 || level.month == 1 && level.day == 1) {
particles[index].col.r = rand(256);
particles[index].col.g = rand(256);
particles[index].col.b = rand(256);
} else {
particles[index].col = baseColor * (fRand() * (maxGlow - minGlow) + minGlow);
}
}
/***************************************************************************************************
*
* $DESCRIPTION Computes the absolute values of the scaled settings.
* $PARAM c The canvas on which the rendering should be performed.
* $REQUIRE c != none
* $OVERRIDE
*
**************************************************************************************************/
simulated function setupScalars(Canvas c) {
minDX = scaleMinDX / scaleWidth * c.clipX;
maxDX = scaleMaxDX / scaleWidth * c.clipX;
minDY = scaleMinDY / scaleHeight * c.clipY;
maxDY = scaleMaxDY / scaleHeight * c.clipY;
minWaveAmplitude = scaleMinWaveAmplitude / scaleWidth * c.clipX;
maxWaveAmplitude = scaleMaxWaveAmplitude / scaleWidth * c.clipX;
}
/***************************************************************************************************
*
* $DESCRIPTION Default properties block.
*
**************************************************************************************************/
defaultproperties
{
BaseColor=(R=255,G=255,B=255)
sprites(0)=Texture'SmartCTF_4E.snowFlake1'
sprites(1)=Texture'SmartCTF_4E.snowFlake2'
sprites(2)=Texture'SmartCTF_4E.snowFlake3'
sprites(3)=Texture'SmartCTF_4E.snowFlake4'
sprites(4)=Texture'SmartCTF_4E.snowFlake5'
sprites(5)=Texture'SmartCTF_4E.snowFlake6'
sprites(6)=Texture'SmartCTF_4E.snowFlake7'
sprites(7)=Texture'SmartCTF_4E.snowFlake8'
sprites(8)=Texture'SmartCTF_4E.snowFlake9'
sprites(9)=Texture'SmartCTF_4E.snowFlake10'
sprites(10)=Texture'SmartCTF_4E.snowFlake11'
sprites(11)=Texture'SmartCTF_4E.snowFlake12'
sprites(12)=Texture'SmartCTF_4E.snowFlake13'
sprites(13)=Texture'SmartCTF_4E.snowFlake14'
sprites(14)=Texture'SmartCTF_4E.snowFlake15'
sprites(15)=Texture'SmartCTF_4E.snowFlake16'
}

View File

@@ -0,0 +1,37 @@
class SmartCTFSpawnNotifyPRI expands SpawnNotify;
var Actor IpToCountry;
var bool bChecked;
simulated event Actor SpawnNotification( Actor A )
{
local Actor Search;
local SmartCTFPlayerReplicationInfo RI;
if( A.Owner == None ) return A;
if( !A.Owner.IsA( 'PlayerPawn' ) && !A.Owner.IsA( 'Bot' ) ) return A;
if( !Pawn( A.Owner ).bIsPlayer ) return A;
if(!bChecked)
{
foreach Level.Game.AllActors(class'Actor', Search, 'IpToCountry')
{
IpToCountry=Search;
break;
}
bChecked=True;
}
// Spawn SmartCTF PRI for this pawn on the server
RI=Spawn( class'SmartCTFPlayerReplicationInfo', A );
if(IpToCountry != None)
{
RI.IpToCountry=IpToCountry;
RI.bIpToCountry=True;
}
return A;
}
defaultproperties
{
ActorClass=Class'Engine.PlayerReplicationInfo'
}

View File

@@ -0,0 +1,18 @@
class SmartCTFSpreeMsg expands KillingSpreeMessage;
static function string GetString( optional int Switch, optional PlayerReplicationInfo RelatedPRI_1, optional PlayerReplicationInfo RelatedPRI_2, optional Object OptionalObject )
{
if( RelatedPRI_1 != None )
{
if( Switch == 5 ) return default.SpreeNote[Switch] @ RelatedPRI_1.PlayerName $ "!";
if( Switch == 6 ) return RelatedPRI_1.PlayerName @ class'TournamentPlayer'.default.SpreeNote[3];
}
return "";
}
defaultproperties
{
spreenote(5)="This is just TOO EASY for"
SpreeSound(5)=Sound'Botpack.ChatSound.SpreeSound'
SpreeSound(6)=Sound'Botpack.ChatSound.SpreeSound'
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Sources/Textures/meter.pcx Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Sources/Textures/santa2.pcx Normal file

Binary file not shown.

BIN
Sources/Textures/shade.pcx Normal file

Binary file not shown.