diff --git a/Sources/Classes/SmartCTF.uc b/Classes/SmartCTF.UC similarity index 96% rename from Sources/Classes/SmartCTF.uc rename to Classes/SmartCTF.UC index 5977b13..ca48343 100644 --- a/Sources/Classes/SmartCTF.uc +++ b/Classes/SmartCTF.UC @@ -1,3646 +1,3646 @@ -// SmartCTF 4 by {PiN}Kev. Released January 2004. -// SmartCTF 4A Tweaked by {DnF2}SiNiSTeR. Released December 2004. -// SmartCTF 4B/4C Uber Massively tweaked by {DnF2}SiNiSTeR. Released March 2005. -// SmartCTF 4D with IpToCountry by [es]Rush. Released January 2006. -// SmartCTF 4D++ by adminthis. Released October 2008. -// SmartCTF 4E by adminthis & The_Cowboy & Sp0ngeb0b. Released December 2009. -// SmartCTF ChaChaV1 by chacha. 2023: -// - Add bLongRangeSuperShock option to allow bShowLongRangeMsg with SuperShockRifle -// - Fix compilation warnings -// SmartCTF ChaChaV2 by chacha. 2023: -// - Add Denied & AirKill Features -// SmartCTF ChaChaV3 by chacha. 2023: -// - Ajout mémorisation joueur vus par le serveur (couple Name+IP) -// - Messages de welcome et welcomback (reglable) -// - Audio de welcome (desactivable) -// - Correction Kill-In-The-air quand on tombe -// - Fix Access None sur Denied -// SmartCTF ChaChaV4 by chacha. 2023: -// - Fix Access None (TGRPI / PRI) -// - Fix Denied Message -// SmartCTF ChaChaV5 by chacha. 2023: -// - Add LudicrousKill & HolyShit Msg / Sounds -// - Fix accessed none KillInTheAir -// SmartCTF ChaChaV6 by chacha. 2023: -// - Recompile without SmartCTF_4E aside -// -// -// This mod changes the point system and adds features to ultimately promote Teamwork in CTF. -// This is a CTF Mod only. It will not load in any other gametype. -// -// Contact Info: private Message me, {PiN}Hai-Ping, on http://forums.prounreal.com -// {DnF2}SiNiSTeR @ #DutchNet [QuakeNet IRC] -// or if it is about version 4D explicictly -// Rush on unrealadmin.org forums / mail and msn: rush@u.one.pl -// or if it is about version 4D++ explicictly -// adminthis on unrealadmin.org -// -// or if it is about about version 4E -// The_Cowboy on unrealadmin.org -// Sp0ngeb0b on unrealadmin.org , or spongebobut@yahoo.com -// SnowyScoreboard added in 4E. Supported by Sp0ngeb0b. -// -// CHANGELOG: See Readme -// TO DO:Improve algorithm of storing stats -class SmartCTF expands Mutator config( SmartCTF_ChaCha ); - -#exec texture IMPORT NAME=meter FILE=Textures\meter.pcx GROUP=SmartCTF MIPS=OFF -#exec texture IMPORT NAME=shade File=Textures\shade.pcx GROUP=SmartCTF MIPS=OFF -#exec texture IMPORT NAME=powered File=Textures\powered.pcx GROUP=SmartCTF MIPS=OFF - -/* Server Vars */ -var SmartCTFGameReplicationInfo SCTFGame; -var byte RedAstIndex, BlueAstIndex; -var byte TRCount; -var string Version, GameTieMessage; -var Pawn FCs[2], RedAssisters[32], BlueAssisters[32]; -var Pawn RedFlagCarrier[32], BlueFlagCarrier[32]; -var float RedFlagCarrierTime[32], BlueFlagCarrierTime[32]; -var byte RedFCIndex, BlueFCIndex; -var float RedAssistTimes[32], BlueAssistTimes[32], PickupTime[2]; -var FlagBase FlagStands[2]; -var bool bForcedEndGame, bTournamentGameStarted, bTooCloseForSaves, bStartTimeCorrected; -var int MsgPID; -var string GoneName[32]; //list of disconnected players -var string GoneIP[32]; //corresponding IP addy -var float GoneScore[32]; //corresponding scores -var float GoneDeaths[32]; //corresponding deaths -var SmartCTFPlayerReplicationInfo GoneStats[32];//corresponding smartCTF stats -var string StoreName[32]; //list of stored playernames -var float StoreScore[32]; //corresponding scores -var float StoreDeaths[32]; //corresponding deaths -var string StoreIP[32]; //corresponding IP addy -var SmartCTFPlayerReplicationInfo StoreStats[32];//corresponding stored smartCTF stats -// First backup array -var string B1Name[32]; //list of stored playernames -var float B1Score[32]; //corresponding scores -var float B1Deaths[32]; //corresponding deaths -var string B1IP[32]; //corresponding IP addy -var SmartCTFPlayerReplicationInfo B1Stats[32];//corresponding stored smartCTF stats -// Second backup array -var string B2Name[32]; //list of stored playernames -var float B2Score[32]; //corresponding scores -var float B2Deaths[32]; //corresponding deaths -var string B2IP[32]; //corresponding IP addy -var SmartCTFPlayerReplicationInfo B2Stats[32];//corresponding stored smartCTF stats -var string QuitMsg; //the broadcast message when someone leaves the game -var int QuitMsgLen; //length of QuitMsg - -/* Client Vars */ -var bool bClientJoinPlayer, bGameEnded, bInitSb; -var int LogoCounter, DrawLogo, SbCount; -var float SbDelayC; -var PlayerPawn PlayerOwner; -var FontInfo MyFonts; -var TournamentGameReplicationInfo pTGRI; -var PlayerReplicationInfo pPRI; -var ChallengeHUD MyHUD; -var Color RedTeamColor, BlueTeamColor, White, Gray; - -/* Server Vars Configurable */ -var() config bool bEnabled; -var() config bool bExtraStats; -var() config string CountryFlagsPackage; -var(SmartCTFBonuses) config int CapBonus, AssistBonus, FlagKillBonus, CoverBonus, SealBonus, GrabBonus; -var(SmartCTFBonuses) config float BaseReturnBonus, MidReturnBonus, EnemyBaseReturnBonus, CloseSaveReturnBonus; -var(SmartCTFBonuses) config int SpawnKillPenalty, MinimalCapBonus; -var() config bool bFixFlagBug; -var() config bool bEnhancedMultiKill; -var() config byte EnhancedMultiKillBroadcast; -var() config bool bShowFCLocation; -var() config bool bSmartCTFServerInfo; -var() config bool bNewCapAssistScoring; -var() config bool bSpawnkillDetection; -var() config float SpawnKillTimeArena; -var() config float SpawnKillTimeNW; -var() config bool bAfterGodLikeMsg; -var() config bool bStatsDrawFaces; -var() config bool bDrawLogo; -var() config bool bSCTFSbDef; -var() config bool bShowSpecs; -var() config color SpectatorColor; -var() config bool bDoKeybind; -var() config bool bExtraMsg; -var() config float SbDelay; -var() config float MsgDelay; -var() config bool bStoreStats; -var() config bool bSnowyScoreboard; -var() config bool bXmasImages; -var(SmartCTFMessages) config byte CoverMsgType; -var(SmartCTFMessages) config byte CoverSpreeMsgType; -var(SmartCTFMessages) config byte SealMsgType; -var(SmartCTFMessages) config byte SavedMsgType; -var(SmartCTFMessages) config byte DeniedMsgType; -var(SmartCTFMessages) config bool bShowLongRangeMsg; -var(SmartCTFMessages) config bool bLongRangeSuperShock; -var(SmartCTFMessages) config bool bShowSpawnKillerGlobalMsg; -var(SmartCTFMessages) config bool bShowAssistConsoleMsg; -var(SmartCTFMessages) config bool bShowSealRewardConsoleMsg; -var(SmartCTFMessages) config bool bShowCoverRewardConsoleMsg; -var(SmartCTFSounds) config bool bPlayCaptureSound; -var(SmartCTFSounds) config bool bPlayAssistSound; -var(SmartCTFSounds) config bool bPlaySavedSound; -var(SmartCTFSounds) config bool bPlayLeadSound; -var(SmartCTFSounds) config bool bPlayDeniedSound; -var(SmartCTFSounds) config bool bPlay30SecSound; -var(SmartCTFSounds) config bool bPlayAirKillSound; -var(OvertimeControl) config bool bEnableOvertimeControl; -var(OvertimeControl) config bool bOvertime; -var(OvertimeControl) config bool bRememberOvertimeSetting; - -var texture powered; - -/* - * Check if we should spawn a SmartCTF instance. - * This check doesn't seem to work properly in PostBeginPlay, hence here. -*/ -event Spawned() -{ - super.Spawned(); - - SCTFGame = Level.Game.Spawn( class'SmartCTFGameReplicationInfo' ); - - if( !ValidateSmartCTFMutator() ) - { - SCTFGame.Destroy(); - Destroy(); - } -} - -/* - * Get the original Scoreboard and store for SmartCTFScoreboard reference. -*/ -function PreBeginPlay() -{ - local Mutator M; - - super.PreBeginPlay(); - SCTFGame.NormalScoreBoardClass = Level.Game.ScoreBoardType; - if (bSnowyScoreboard) - { - level.game.scoreBoardType = class'SmartCTFSnowyScoreboard'; - } - else - { - Level.Game.ScoreBoardType = class'SmartCTFScoreBoard'; - } - //Level.Game.default.ScoreBoardType = class'SmartCTFScoreBoard'; - // The above line was fatal in version 4B :E - - Log( "Original Scoreboard determined as" @ SCTFGame.NormalScoreBoardClass, 'SmartCTF' ); - - // Change F2 Server Info screen, compatible with UTPure - if( bSmartCTFServerInfo ) - { - class( Level.Game.HUDType ).default.ServerInfoClass = class'SmartCTFServerInfo'; - for( M = Level.Game.BaseMutator; M != None; M = M.NextMutator ) - { - if( M.IsA( 'UTPure' ) ) // Let UTPure rehandle the scoreboard - { - M.PreBeginPlay(); - SCTFGame.bServerInfoSetServerSide = True; // No need for the old fashioned way - it can be set server side. - Log( "Notified UTPure HUD to use SmartCTF ServerInfo.", 'SmartCTF' ); - break; - } - } - if( SCTFGame.bServerInfoSetServerSide && Level.Game.HUDType.Name != 'PureCTFHUD' ) - { - // In this scenario another mod intervered and we still have to do it the old fashion way. - SCTFGame.bServerInfoSetServerSide = False; - Log( "HUD is not the UTPure HUD but" @ Level.Game.HUDType.Name $ ", so SmartCTF ServerInfo will be set clientside.", 'SmartCTF' ); - } - if( !SCTFGame.bServerInfoSetServerSide ) - { - SCTFGame.DefaultHUDType = Level.Game.HUDType; // And in the old fashion way, the client will have to know the current HUD type. - } - } - else - { - SCTFGame.bServerInfoSetServerSide = True; // We didn't change anything, but neither do we want clientside intervention. - } -} - -/* - * Startup and initialize. -*/ -function PostBeginPlay() -{ - local FlagBase fb; - - Level.Game.Spawn( class'SmartCTFSpawnNotifyPRI'); - SCTFGame.WelcomeNewPlayers = Spawn( class'SmartCTFWelcomeNewPlayers'); - SCTFGame.WelcomeNewPlayers.SaveConfig(); - - SaveConfig(); // Create the .ini if its not already there. - - //Register as a message mutator, as we'll be using message monitoring - //to perform some of our code. If not registered, then many message - //events will not be passed to our mutator. - Level.Game.RegisterMessageMutator( self ); - - // Since we have problem replicating config variables... - SCTFGame.bShowFCLocation = bShowFCLocation; - SCTFGame.bPlay30SecSound = bPlay30SecSound; - SCTFGame.bStatsDrawFaces = bStatsDrawFaces; - SCTFGame.bDrawLogo = bDrawLogo; - SCTFGame.bExtraStats = bExtraStats; - SCTFGame.CountryFlagsPackage = CountryFlagsPackage; - SCTFGame.bSCTFSbDef = bSCTFSbDef; - SCTFGame.bShowSpecs = bShowSpecs; - SCTFGame.bDoKeybind = bDoKeybind; - SCTFGame.SbDelayC = SbDelayC; - SCTFGame.SpectatorColor = SpectatorColor; - SCTFGame.bSnowyScoreboard = bSnowyScoreboard; - SCTFGame.bXmasImages = bXmasImages; - - if( !bRememberOvertimeSetting ) - { - bOvertime = True; - } - - // Works serverside! - if( bEnhancedMultiKill ) - { - Level.Game.DeathMessageClass = class'SmartCTFEnhancedDeathMessagePlus'; - } - - // Get the Flag bases - ForEach AllActors( class'FlagBase', fb ) - { - FlagStands[ fb.Team ] = fb; - } - - if( VSize( FlagStands[0].Location - FlagStands[1].Location ) < 1.5 * 900 ) - { - bTooCloseForSaves = True; - } - - SCTFGame.EndStats = Spawn( class'SmartCTFEndStats', self ); - - super.PostBeginPlay(); - - if( Level.NetMode == NM_DedicatedServer ) - { - SetTimer( 1.0 , True); - } - - MsgPID=-1; // First PID is 0, so it wouldn't get messaged if we kept MsgPID at it's default value. - - if(bStoreStats == True) - { - //Register as a damage mutator, as we'll be using damage checks to - //update the stored information (new in v3.2). - Level.Game.RegisterDamageMutator(self); - - //Grab some basic info about the player left message. - QuitMsg=Level.Game.LeftMessage; - QuitMsgLen=Len(QuitMsg); - - } - Log( "SmartCTF" @ Version @ "loaded successfully.", 'SmartCTF' ); -} - -/* - * Returns True or False whether to keep this SmartCTF mutator instance, and sets bInitialized accordingly. -*/ -function bool ValidateSmartCTFMutator() -{ - local Mutator M; - local bool bRunning; - - M = Level.Game.BaseMutator; - while( M != None ) - { - if( M != Self && M.Class == Self.Class ) - { - bRunning = True; - break; - } - M = M.NextMutator; - } - - if( !bEnabled ) - { - Log( "Instance" @ Name @ "not loaded because bEnabled in .ini = False.", 'SmartCTF' ); - } - else if( CTFGame( Level.Game ) == None ) - { - Log( "Instance" @ Name @ "not loaded because gamestyle is not CTF.", 'SmartCTF' ); - } - else if( bRunning ) - { - Log( "Instance" @ Name @ "not loaded because it is already running.", 'SmartCTF' ); - } - else - { - SCTFGame.bInitialized = True; - } - - return SCTFGame.bInitialized; -} - - -/* - * For the flag bug each player gets a FlagChecker inventory on spawn. -*/ -function ModifyPlayer( Pawn Other ) -{ - local Inventory Inv; - local SmartCTFPlayerReplicationInfo OtherStats; - local string IP; - local int j,i; - local bool bIsFirstSpawn; - - - if( Other.bIsPlayer && !Other.IsA('Bot') && !( Other.PlayerReplicationInfo.bIsSpectator && !Other.PlayerReplicationInfo.bWaitingPlayer ) ) - { - // little hacky method to know if its 1st spawn or not - bIsFirstSpawn = Other.PlayerReplicationInfo.Deaths < 1; - SCTFGame.WelcomeNewPlayers.CheckPawn(Other,bIsFirstSpawn); - if( bFixFlagBug) - { - Inv = Spawn( class'SmartCTFFlagCheckerInventory' , Other ); - if( Inv != None ) - { - Inv.GiveTo( Other ); - } - } - } - - SCTFGame.RefreshPRI(); - OtherStats = SCTFGame.GetStats( Other ); - if( OtherStats!=none && - bStoreStats && - !Level.Game.bGameEnded && - Other!=none && - Other.bIsPlayer && - !Other.IsA('Spectator') && - !Other.IsA('Bot') && - Other.PlayerReplicationInfo!=none && - Other.PlayerReplicationInfo.PlayerName!="Player" ) - { - IP=PlayerPawn(Other).GetPlayerNetworkAddress(); - j=InStr(IP,":"); - if( j!=-1 ) - { - IP=Left(IP,j); - } - - for(i=0; i<32 && GoneName[i]!=""; i++) - { - if( Other.PlayerReplicationInfo.PlayerName~=GoneName[i] || (IP==GoneIP[i] && IP!="") ) - { - Log(" ## SmartCTF - Caught player by name or IP "$Other.PlayerReplicationInfo.PlayerName$"@"$IP); - Log(" ## SmartCTF is restoring stats for " $Other.PlayerReplicationInfo.PlayerName$"@"$IP); - if(GoneStats[i]!= none) - { - FirstSpawn( Other ); - OtherStats.Captures=GoneStats[i].Captures; - OtherStats.Frags=GoneStats[i].Frags; - OtherStats.Grabs=GoneStats[i].Grabs; - OtherStats.Covers=GoneStats[i].Covers; - OtherStats.Assists=GoneStats[i].Assists; - OtherStats.Seals=GoneStats[i].Seals; - OtherStats.FlagKills=GoneStats[i].FlagKills; - OtherStats.DefKills=GoneStats[i].DefKills; - OtherStats.HeadShots=GoneStats[i].HeadShots; - OtherStats.ShieldBelts=GoneStats[i].ShieldBelts; - OtherStats.Amps=GoneStats[i].Amps; - OtherStats.LastKillTime=GoneStats[i].LastKillTime; - OtherStats.MultiLevel=GoneStats[i].MultiLevel; - OtherStats.FragSpree=GoneStats[i].FragSpree; - OtherStats.CoverSpree=GoneStats[i].CoverSpree; - OtherStats.SealSpree=GoneStats[i].SealSpree; - OtherStats.SpawnKillSpree=GoneStats[i].SpawnKillSpree; - OtherStats.bHadFirstSpawn =True; - } - Other.PlayerReplicationInfo.Score=GoneScore[i]; - Other.PlayerReplicationInfo.Deaths=GoneDeaths[i]; - CleanGone(i); - Log(" ## Stats are restored"); - break; - } - } - } - - - - if( !OtherStats.bHadFirstSpawn ) - { - OtherStats.bHadFirstSpawn = True; - FirstSpawn( Other ); - } - - OtherStats.SpawnTime = Level.TimeSeconds; - - super.ModifyPlayer( Other ); - if(bStoreStats) - { - UpdateInfo(); - } - -} - -/* - * Gets called when a new player or bot joins the game, that is when they first spawn. -*/ -function FirstSpawn( Pawn Other ) -{ - local byte ID; - local string SkinName, FaceName; - - // Additional logging, useful for player tracking - if( Level.Game.LocalLog != None && PlayerPawn( Other ) != None && Other.bIsPlayer ) - { - ID = PlayerPawn( Other ).PlayerReplicationInfo.PlayerID; - Level.Game.LocalLog.LogSpecialEvent( "IP", ID, PlayerPawn( Other ).GetPlayerNetworkAddress() ); - Level.Game.LocalLog.LogSpecialEvent( "player", "NetSpeed", ID, PlayerPawn( Other ).Player.CurrentNetSpeed ); - Level.Game.LocalLog.LogSpecialEvent( "player", "Fov", ID, PlayerPawn( Other ).FovAngle ); - Level.Game.LocalLog.LogSpecialEvent( "player", "VoiceType", ID, Other.VoiceType ); - if( Other.IsA( 'TournamentPlayer' ) ) - { - if( Other.Skin == None ) - { - Other.static.GetMultiSkin( Other, SkinName, FaceName ); - } - else - { - SkinName = string( Other.Skin ); - FaceName = "None"; - } - Level.Game.LocalLog.LogSpecialEvent( "player", "Skin", ID, SkinName ); - Level.Game.LocalLog.LogSpecialEvent( "player", "Face", ID, FaceName ); - } - } -} - -/* - *Use this function to clean out entries from the gone arrays when a player - *reenters and is caught by SmartCTF -*/ -function CleanGone( int R) -{ - - local int i; - - for(i=R;i<32;i++) - { If(GoneStats[i]!=none) - { - - if(i==31) - { - GoneName[i]=""; - GoneScore[i]=0; - GoneDeaths[i]=0; - GoneIP[i]=""; - GoneStats[i].ClearStats(); - break; - } - - GoneName[i]=GoneName[i+1]; - GoneScore[i]=GoneScore[i+1]; - GoneDeaths[i]=GoneDeaths[i+1]; - GoneIP[i]=GoneIP[i+1]; - GoneStats[i]=GoneStats[i+1]; - } - } - - -} - -function bool MutatorBroadcastMessage( Actor Sender, Pawn Receiver, out coerce string Msg, optional bool bBeep, out optional name Type ) -{ - local string quitter; - local int i,j; - local bool matched; - - if(bStoreStats) - { - //Thanks to the WebChatLog mutator for the Reciever.NextPawn==none check - if(Receiver != none && Receiver.NextPawn == none && !Level.Game.bGameEnded) // prevent duplicate messages - { - if(Right(Msg,QuitMsgLen)==QuitMsg) - { - quitter=left(Msg,Len(Msg)-QuitMsgLen); //strips out the playername - - for(i=0; i<32 && StoreName[i]!=""; i++) - { - if(StoreName[i]~=quitter) - { - matched=true; //found our player match - - for(j=0; j<32; j++) - { - if(GoneName[j]=="") - { - GoneName[j]=StoreName[i]; - GoneScore[j]=StoreScore[i]; - GoneDeaths[j]=StoreDeaths[i]; - GoneIP[j]=StoreIP[i]; - GoneStats[j]=StoreStats[i]; - break; - } - - if(j==31) - { - log(" ## SmartCtf - Gone Array is full"); - break; - } - } - - break; - } - } - - //if the player wasn't caught in the main store array, check backup 1 - if(!matched) - { - for(i=0; i<32 && B1Name[i]!=""; i++) - { - if(B1Name[i]~=quitter) - { - matched=true; //found our player match - - for(j=0; j<32; j++) - { - if(GoneName[j]=="") - { - GoneName[j]=B1Name[i]; - GoneScore[j]=B1Score[i]; - GoneDeaths[j]=B1Deaths[i]; - GoneIP[j]=B1IP[i]; - GoneStats[j]=B1Stats[i]; - break; - } - - if(j==31) - { - log(" ## SmartCtf - Gone Array is full"); - break; - } - } - - break; - } - } - } - - //if the player wasn't caught in the backup 1 array, check backup 2 - if(!matched) - { - for(i=0; i<32 && B2Name[i]!=""; i++) - { - if(B2Name[i]~=quitter) - { - for(j=0; j<32; j++) - { - if(GoneName[j]=="") - { - GoneName[j]=B2Name[i]; - GoneScore[j]=B2Score[i]; - GoneDeaths[j]=B2Deaths[i]; - GoneIP[j]=B2IP[i]; - GoneStats[j]=B2Stats[i]; - break; - } - - if(j==31) - { - log(" ## SmartCtf - Gone Array is full"); - break; - } - } - - break; - } - } - } - } - } - } - - if( NextMessageMutator != none ) - { - //If there are other mutators monitoring messages, make sure we ask them - //whether to allow the message to be broadcast (i.e. return their value). - return NextMessageMutator.MutatorBroadcastMessage( Sender, Receiver, Msg, bBeep, Type ); - } - - //Else, we'll return true (true will allow the message to be broadcast). - return true; -} - -/* - *Just another event to use as an update point for our store array (the more - *update events, the more up to date the store array will be). -*/ -function ScoreKill(pawn Killer, pawn Other) -{ - super.ScoreKill(Killer, Other); - - if(bStoreStats) - { - UpdateInfo(); - } -} - -/* - *Just another event to use as an update point for our store array (the more - *update events, the more up to date the store array will be). -*/ -function MutatorTakeDamage( out int ActualDamage, Pawn Victim, Pawn InstigatedBy, out Vector HitLocation, out Vector Momentum, name DamageType) -{ - super.MutatorTakeDamage(ActualDamage,Victim,InstigatedBy,HitLocation,Momentum,DamageType); - if(bStoreStats) - { - UpdateInfo(); - } - -} - - -function UpdateInfo() -{ - local int i,j,k; - local string IP; - local Pawn P; - local SmartCTFPlayerReplicationInfo PI; - - //clear the previous name values, so we don't double register any players - for(k=0; k<32; k++) - { - StoreName[k]=""; - } - - for(P=Level.PawnList; P!=none; P=P.nextPawn) - { - if( PlayerPawn(P)!=none && - P.bIsPlayer && - !P.IsA('Spectator') && - !P.IsA('Bot') && - P.PlayerReplicationInfo!=none && - P.PlayerReplicationInfo.PlayerName!="Player" && - (P.PlayerReplicationInfo.Score!=0 || P.PlayerReplicationInfo.Deaths!=0) ) - { - IP=PlayerPawn(P).GetPlayerNetworkAddress(); - if( IP!="" ) - { - j=InStr(IP,":"); - if( j!=-1 ) - IP=Left(IP,j); - } - StoreName[i]=P.PlayerReplicationInfo.PlayerName; - StoreScore[i]=P.PlayerReplicationInfo.Score; - StoreDeaths[i]=P.PlayerReplicationInfo.Deaths; - StoreIP[i]=IP; - PI = SCTFGame.GetStats( P ); - If(PI!= none) - StoreStats[i]=PI; - i++; - } - } - -} - -/* - * Gets called once when the Countdown before a Tournament game starts. -*/ -function TournamentGameStarted() -{ - // Fix warmup mode bug + Overtime functionality - ClearStats(); - if( bEnableOvertimeControl ) - { - if( !bOvertime ) - { - BroadcastLocalizedMessage( class'SmartCTFCoolMsg', 4 ); - } - else - { - BroadcastLocalizedMessage( class'SmartCTFCoolMsg', 3 ); - } - } -} - -/* - * Check for covers and seals, and adjust scores. -*/ -function bool PreventDeath( Pawn Victim, Pawn Killer, name DamageType, vector HitLocation ) -{ - local PlayerReplicationInfo VictimPRI, KillerPRI; - local bool bPrevent, bVictimTeamHasFlag, bWarmupSkip; - local Pawn pn; - local float TimeAwake; - local SmartCTFPlayerReplicationInfo KillerStats, VictimStats; - - bPrevent = super.PreventDeath( Victim, Killer, DamageType, HitLocation ); - if( bPrevent ) - { - return bPrevent; // Player didn't die, so return - } - - // If there is no victim, return. - if( Victim == None ) - { - return bPrevent; - } - - VictimPRI = Victim.PlayerReplicationInfo; - if( VictimPRI == None || !Victim.bIsPlayer || ( VictimPRI.bIsSpectator && !VictimPRI.bWaitingPlayer ) ) - { - return bPrevent; - } - - VictimStats = SCTFGame.GetStats( Victim ); - - // airkill handling - if(bPlayAirKillSound && (Victim!=Killer) && (Killer!=None)) - { - if(Victim.Physics == PHYS_Falling && Killer.Physics == PHYS_Falling) - { - if(Victim.bIsPlayer && Victim.IsA('PlayerPawn')) - { - Victim.ReceiveLocalizedMessage( class'SmartCTFAudioMsg', 6); - Victim.ReceiveLocalizedMessage( class'SmartCTFCoolMsg', 7); - } - if(Killer.bIsPlayer && Killer.IsA('PlayerPawn')) - { - Killer.ReceiveLocalizedMessage( class'SmartCTFAudioMsg', 6); - Killer.ReceiveLocalizedMessage( class'SmartCTFCoolMsg', 6); - } - } - } - - if( VictimStats != None ) - { - VictimStats.FragSpree = 0; // Reset FragSpree for Victim - VictimStats.SpawnKillSpree = 0; - } - - // If there is no killer / suicide, return. - if( Killer == None || Killer == Victim ) - { - if( bEnhancedMultiKill && EnhancedMultiKillBroadcast > 0 ) - { - VictimStats.MultiLevel = 0; - } - return bPrevent; - } - - KillerPRI = Killer.PlayerReplicationInfo; - if( KillerPRI == None || !Killer.bIsPlayer || ( KillerPRI.bIsSpectator && !KillerPRI.bWaitingPlayer ) ) - { - return bPrevent; - } - - KillerStats = SCTFGame.GetStats( Killer ); - // Same Team! We don't count those stats like that in SmartCTF. - if( VictimPRI.Team == KillerPRI.Team ) - { - return bPrevent; - } - - // Increase Frags and FragSpree for Killer (Play "Too Easy" at 30) - if( KillerStats != None ) - { - KillerStats.Frags++; - KillerStats.FragSpree++; - } - - if( bEnhancedMultiKill && EnhancedMultiKillBroadcast > 0 ) - { - VictimStats.MultiLevel = 0; - if( Level.TimeSeconds - KillerStats.LastKillTime < 3 ) - { - KillerStats.MultiLevel++; - if( KillerStats.MultiLevel + 1 >= EnhancedMultiKillBroadcast ) - { - Level.Game.BroadcastMessage( KillerPRI.PlayerName @ class'SmartCTFEnhancedMultiKillMessage'.static.GetBroadcastString( KillerStats.MultiLevel ) ); - } - } - else - { - KillerStats.MultiLevel = 0; - } - KillerStats.LastKillTime = Level.TimeSeconds; - } - - bWarmupSkip = DeathMatchPlus( Level.Game ).bTournament && !bTournamentGameStarted; - - if( !bWarmupSkip ) - { - - // For Flag Kill, inc player's FlagKills and total - if( VictimPRI.HasFlag != None ) - { - - if( KillerStats != None ) - { - KillerStats.FlagKills++; - } - KillerPRI.Score += FlagKillBonus; - - // Already logged by UTStats serveractor. Dont want to do it twice. - //if( Level.Game.LocalLog != None ) Level.Game.LocalLog.LogSpecialEvent( "flag_kill", KillerPRI.PlayerID, VictimPRI.PlayerID, VictimPRI.Team ); - - // Handling Denied - if( VSize( Victim.Location - FlagStands[VictimPRI.Team].Location ) < 768 ) - { - if( DeniedMsgType == 1 && PlayerPawn( Killer ) != None ) - { - Killer.ClientMessage( class'SmartCTFMessage'.static.GetString( 11 + 64, KillerPRI, VictimPRI ) ); - } - else if( DeniedMsgType == 2 ) - { - BroadcastMessage( class'SmartCTFMessage'.static.GetString( 11, KillerPRI, VictimPRI ) ); - } - else if( DeniedMsgType == 3 ) - { - BroadcastLocalizedMessage( class'SmartCTFMessage', 11, KillerPRI, VictimPRI ); - } - - for( pn = Level.PawnList; pn != None; pn = pn.NextPawn ) - { - if( PlayerPawn( pn ) != None && pn.bIsPlayer ) - { - if(bPlayDeniedSound) - { - PlayerPawn( pn ).ReceiveLocalizedMessage( class'SmartCTFAudioMsg', 5 ); - } - } - } - } - } - else - { - // If Killer has Flag, no cover or seal for him - if( KillerPRI.HasFlag == None && FCs[KillerPRI.Team] != None && FCs[KillerPRI.Team].PlayerReplicationInfo.HasFlag != None ) - { - // COVER FRAG / SEAL BASE - // If Killer's Team has had an FC - - // If the FC has Flag Right now - // Defend kill - // org: If victim can see the FC or is within 600 unreal units (approx 40 feet) and has a line of sight to fc. - //if( Victim.canSee( FCs[KillerPRI.Team] ) || ( Victim.lineOfSightTo( FCs[KillerPRI.Team] ) && Distance( Victim.Location, FCs[KillerPRI.Team].Location ) < 600 ) ) - // new: victim within 512 uu of FC - // or killer within 512 uu of FC - // or victim can see FC and was Victim within 1536 uu of FC - // or killer can see FC and Victim victim within 1024 uu of FC - // or victim has direct line to FC and was Victim within 768 uu - if( ( VSize( Victim.Location - FCs[KillerPRI.Team].Location ) < 512 ) - || ( VSize( Killer.Location - FCs[KillerPRI.Team].Location ) < 512 ) - || ( VSize( Victim.Location - FCs[KillerPRI.Team].Location ) < 1536 && Victim.canSee( FCs[KillerPRI.Team] ) ) - || ( VSize( Victim.Location - FCs[KillerPRI.Team].Location ) < 1024 && Killer.canSee( FCs[KillerPRI.Team] ) ) - || ( VSize( Victim.Location - FCs[KillerPRI.Team].Location ) < 768 && Victim.lineOfSightTo( FCs[KillerPRI.Team] ) ) ) - { - // Killer DEFENDED THE Flag CARRIER - if( KillerStats != None ) - { - KillerStats.Covers++; - KillerStats.CoverSpree++; // Increment Cover spree - } - KillerPRI.Score += CoverBonus; // Reward points - - // Log cover - if( Level.Game.LocalLog != None ) - { - Level.Game.LocalLog.LogSpecialEvent( "flag_cover", KillerPRI.PlayerID, VictimPRI.PlayerID, KillerPRI.Team ); - } - - // Cover sprees - if( KillerStats != None ) - { - if( KillerStats.CoverSpree == 3 ) // Cover x 3 - { - if( CoverSpreeMsgType == 1 && PlayerPawn( Killer ) != None ) - { - Killer.ClientMessage( class'SmartCTFMessage'.static.GetString( 4 + 64, KillerPRI, VictimPRI ) ); - } - else if( CoverSpreeMsgType == 2 ) - { - BroadcastMessage( class'SmartCTFMessage'.static.GetString( 4, KillerPRI, VictimPRI ) ); - } - else if( CoverSpreeMsgType == 3 ) - { - BroadcastLocalizedMessage( class'SmartCTFMessage', 4, KillerPRI, VictimPRI ); - } - } - else if( KillerStats.CoverSpree == 4 ) // Cover x 4 - { - if( CoverSpreeMsgType == 1 && PlayerPawn( Killer ) != None ) - { - Killer.ClientMessage( class'SmartCTFMessage'.static.GetString( 5 + 64, KillerPRI, VictimPRI ) ); - } - else if( CoverSpreeMsgType == 2 ) - { - BroadcastMessage( class'SmartCTFMessage'.static.GetString( 5, KillerPRI, VictimPRI ) ); - } - else if( CoverSpreeMsgType == 3 ) - { - BroadcastLocalizedMessage( class'SmartCTFMessage', 5, KillerPRI, VictimPRI ); - } - } - else // // Covered FC - { - if( CoverMsgType == 1 && PlayerPawn( Killer ) != None ) - { - Killer.ClientMessage( class'SmartCTFMessage'.static.GetString( 0 + 64, KillerPRI, VictimPRI ) ); - } - else if( CoverMsgType == 2 ) - { - BroadcastMessage( class'SmartCTFMessage'.static.GetString( 0, KillerPRI, VictimPRI ) ); - } - else if( CoverMsgType == 3 ) - { - BroadcastLocalizedMessage( class'SmartCTFMessage', 0, KillerPRI, VictimPRI ); - } - } - } - } - - // Defense kill - // If the map has player zones - bVictimTeamHasFlag = True; - if( FCs[VictimPRI.Team] == None ) - { - bVictimTeamHasFlag = False; - } - - if( FCs[VictimPRI.Team] != None && FCs[VictimPRI.Team].PlayerReplicationInfo.HasFlag == None ) - { - bVictimTeamHasFlag = False; - } - - // If Victim's FC has not been set / If Victim's FC doesn't have our Flag - if( !bVictimTeamHasFlag ) - { - // If Killer is Red & he and his FC's Location has Red - if( IsInZone( VictimPRI, KillerPRI.Team ) && IsInZone( FCs[KillerPRI.Team].PlayerReplicationInfo, KillerPRI.Team ) ) - { - // Killer SEALED THE BASE - if( KillerStats != None ) - { - KillerStats.Seals++; - KillerStats.SealSpree++; - if(CTFReplicationInfo( Level.Game.GameReplicationInfo ).FlagList[KillerPRI.Team].bHome) // only if flag is at home - { - KillerStats.DefKills++; // seal is also a defkill - } - } - KillerPRI.Score += SealBonus; - if( SealMsgType != 0 && KillerStats != None && KillerStats.SealSpree == 2 ) // Sealing base - { - if( SealMsgType == 1 && PlayerPawn( Killer ) != None ) - { - Killer.ClientMessage( class'SmartCTFMessage'.static.GetString( 1 + 64, KillerPRI, VictimPRI ) ); - } - else if( SealMsgType == 2 ) - { - BroadcastMessage( class'SmartCTFMessage'.static.GetString( 1, KillerPRI, VictimPRI ) ); - } - else if( SealMsgType == 3 ) - { - BroadcastLocalizedMessage( class'SmartCTFMessage', 1, KillerPRI, VictimPRI ); - } - } - // Log seal - if( Level.Game.LocalLog != None ) - { - Level.Game.LocalLog.LogSpecialEvent( "flag_seal", KillerPRI.PlayerID, VictimPRI.PlayerID, KillerPRI.Team ); // Log to ngLog; - } - } - } - } - else // our team don't have a flag - { - bVictimTeamHasFlag = True; - if( FCs[VictimPRI.Team] == None ) - { - bVictimTeamHasFlag = False; - } - if( FCs[VictimPRI.Team] != None && FCs[VictimPRI.Team].PlayerReplicationInfo.HasFlag == None ) - { - bVictimTeamHasFlag = False; - } - // Defense kill - // If the map has player zones - if( VictimPRI.PlayerZone != None ) - { - if( IsInZone( VictimPRI, KillerPRI.Team ) && !bVictimTeamHasFlag && CTFReplicationInfo( Level.Game.GameReplicationInfo ).FlagList[KillerPRI.Team].bHome) - { - if( KillerStats != None ) - { - KillerStats.DefKills++; - } - } - } - } - } - } - - if( bAfterGodLikeMsg && KillerStats != None && ( KillerStats.FragSpree == 30 || KillerStats.FragSpree == 35 ) ) - { - for( pn = Level.PawnList; pn != None; pn = pn.NextPawn ) - { - if( pn.IsA( 'TournamentPlayer' ) ) - { - pn.ReceiveLocalizedMessage( class'SmartCTFSpreeMsg', KillerStats.FragSpree / 5 - 1, KillerPRI ); - } - } - } - - // Uber / Long Range kill if not sniper, HeadShot, trans, deemer, instarifle, or vengeance relic. - if( bShowLongRangeMsg && TournamentPlayer( Killer ) != None ) - { - if( DamageType != 'shot' && - DamageType != 'decapitated' && - DamageType != 'Eradicated' && - DamageType != 'Gibbed' && - DamageType != 'RedeemerDeath' && - (SuperShockRifle( Killer.Weapon ) == None || bLongRangeSuperShock)) - { - if( VSize( Killer.Location - Victim.Location ) > 1536 ) - { - if( VSize( Killer.Location - Victim.Location ) > 3072 ) - { - Killer.ReceiveLocalizedMessage( class'SmartCTFCoolMsg', 2, KillerPRI, VictimPRI ); - } - else - { - Killer.ReceiveLocalizedMessage( class'SmartCTFCoolMsg', 1, KillerPRI, VictimPRI ); - } - // Log special kill. - if( Level.Game.LocalLog != None ) - { - Level.Game.LocalLog.LogSpecialEvent( "longrangekill", KillerPRI.PlayerID, VictimPRI.PlayerID ); - } - } - } - } - - // HeadShot tracking - if( DamageType == 'decapitated' && KillerStats != None ) - { - KillerStats.HeadShots++; - } - - // Spawnkill detection - if( bSpawnkillDetection && DamageType != 'Gibbed' && VictimStats != None ) // No telefrags - { - TimeAwake = Level.TimeSeconds - VictimStats.SpawnTime; - if( Level.Game.BaseMutator.MutatedDefaultWeapon() != class'Botpack.ImpactHammer' ) - { // Arena mutator used, spawnkilling must be extreme to count - if( TimeAwake <= SpawnKillTimeArena ) - { - Killer.ReceiveLocalizedMessage( class'SmartCTFCoolMsg', 5, KillerPRI, VictimPRI ); - KillerPRI.Score -= SpawnKillPenalty; - if( KillerStats != None ) - { - KillerStats.SpawnKillSpree++; - } - if( Level.Game.LocalLog != None ) - { - Level.Game.LocalLog.LogSpecialEvent( "spawnkill", KillerPRI.PlayerID, VictimPRI.PlayerID, SpawnKillPenalty ); - } - if( bShowSpawnKillerGlobalMsg && KillerStats != None && KillerStats.SpawnKillSpree > 2 ) - { - BroadcastLocalizedMessage( class'SmartCTFMessage', 10, KillerPRI, VictimPRI ); - } - } - } - else // No arena mutator - { - if( TimeAwake < SpawnKillTimeNW ) - { - Killer.ReceiveLocalizedMessage( class'SmartCTFCoolMsg', 5, KillerPRI, VictimPRI ); - KillerPRI.Score -= SpawnKillPenalty; - if( KillerStats != None ) - { - KillerStats.SpawnKillSpree++; - } - if( Level.Game.LocalLog != None ) - { - Level.Game.LocalLog.LogSpecialEvent( "spawnkill", KillerPRI.PlayerID, VictimPRI.PlayerID, SpawnKillPenalty ); - } - if( bShowSpawnKillerGlobalMsg && KillerStats != None && KillerStats.SpawnKillSpree > 2 ) - { - BroadcastLocalizedMessage( class'SmartCTFMessage', 10, KillerPRI, VictimPRI ); - } - } - } - } - if(bStoreStats) - { - UpdateInfo(); - } - return bPrevent; -} - -/* - * ShieldBelt + Damage Amp tracking, spawnkill detection. -*/ -function bool HandlePickupQuery( Pawn Other, Inventory Item, out byte bAllowPickup ) -{ - local SmartCTFPlayerReplicationInfo OtherStats; - - OtherStats = SCTFGame.GetStats( Other ); - - if( Item.IsA( 'UT_ShieldBelt' ) && OtherStats != None ) - { - OtherStats.ShieldBelts++; - } - if( Item.IsA( 'UDamage' ) && OtherStats != None ) - { - OtherStats.Amps++; - } - - // For spawnkill detection - if( bSpawnkillDetection && OtherStats != None && OtherStats.SpawnTime != 0 ) - { - if( Item.IsA( 'TournamentWeapon' ) || Item.IsA( 'UT_ShieldBelt' ) || Item.IsA( 'UDamage' ) || Item.IsA( 'HealthPack' ) || Item.IsA( 'UT_Invisibility' ) ) - { - // This player has picked up a certain item making a kill on him no longer be qualified as a spawnkill. - OtherStats.SpawnTime = 0; - } - } - - return super.HandlePickupQuery( Other, Item, bAllowPickup ); -} - -/* - * Proper check if a player is in a location with 'red' or 'blue' in the name. -*/ -function bool IsInZone( PlayerReplicationInfo PRI, byte Team ) -{ - local string Loc; - - if( PRI.PlayerLocation != None ) - { - Loc = PRI.PlayerLocation.LocationName; - } - else if( PRI.PlayerZone != None ) - { - Loc = PRI.PlayerZone.ZoneName; - } - else - { - return False; - } - - if( Team == 0 ) - { - return ( Instr( Caps( Loc ), "RED" ) != -1 ); - } - else - { - return ( Instr( Caps( Loc ), "BLUE" ) != -1 ); - } -} - -/* - * Add a player to the Red FC/assister list. -*/ -function AddRedFlagCarrier( Pawn Aster, float Fct ) -{ - local byte i; - - if( Aster == None || !Aster.bIsPlayer || ( Aster.PlayerReplicationInfo.bIsSpectator && !Aster.PlayerReplicationInfo.bWaitingPlayer ) ) - { - return; - } - if( RedFCIndex >= 32 ) - { - RedFCIndex = 0; - } - - // Check if already in list - for( i = 0; i < 32; i++ ) - { - if( Aster == RedFlagCarrier[i] ) - { - RedFlagCarrierTime[i] += Fct; - return; - } - } - - RedFlagCarrier[RedFCIndex] = Aster; - RedFlagCarrierTime[RedFCIndex] = Fct; - RedFCIndex++; -} - -function AddBlueFlagCarrier( Pawn Aster, float Fct ) -{ - local byte i; - - if( Aster == None || !Aster.bIsPlayer || ( Aster.PlayerReplicationInfo.bIsSpectator && !Aster.PlayerReplicationInfo.bWaitingPlayer ) ) - { - return; - } - if( BlueFCIndex >= 32 ) - { - BlueFCIndex = 0; - } - - for( i = 0; i < 32; i++ ) - { - if( Aster == BlueFlagCarrier[i] ) - { - BlueFlagCarrierTime[i] += Fct; - return; - } - } - - BlueFlagCarrier[BlueFCIndex] = Aster; - BlueFlagCarrierTime[BlueFCIndex] = Fct; - BlueFCIndex++; -} - - -/* - * Walk through Red assisters/FC and reward them with points because of a cap. -*/ -function RewardRedFlagCarriers( bool bNotPlayedLead ) -{ - local byte j; - local SmartCTFPlayerReplicationInfo AssisterStats; - local int Bonus; - local float TotalTime, f; - - Bonus = AssistBonus; - - // Calculate the total flag carrying time - for( j = 0; j < 32; j++ ) TotalTime += RedFlagCarrierTime[j]; - - for( j = 0; j < 32; j++ ) - { - // If flagcarrier was not the capper - if( RedFlagCarrier[j] != None && RedFlagCarrier[j] != FCs[0] ) - { - AssisterStats = SCTFGame.GetStats( RedFlagCarrier[j] ); - if( AssisterStats != None ) - { - AssisterStats.Assists++; - } - - if( bNewCapAssistScoring ) - { - if( TotalTime == 0 ) - { - f = 0; - } - else - { - f = ( RedFlagCarrierTime[j] / TotalTime ) * ( 7 + CapBonus ); // proportionally score - } - Bonus = Max( f, 1 ); - } - RedFlagCarrier[j].PlayerReplicationInfo.Score += Bonus; - - if( PlayerPawn( RedFlagCarrier[j] ) != None ) - { - if( bShowAssistConsoleMsg ) - { - PlayerPawn( RedFlagCarrier[j] ).ClientMessage( "You get " $ Bonus $ " bonus pts for the Assist!" @ CarriedString( RedFlagCarrierTime[j], TotalTime ) ); - } - if( bPlayAssistSound && bNotPlayedLead ) - { - PlayerPawn( RedFlagCarrier[j] ).ReceiveLocalizedMessage( class'SmartCTFAudioMsg', 1 ); - } - } - if( Level.Game.LocalLog != None ) - { - Level.Game.LocalLog.LogSpecialEvent( "Flag_assist", RedFlagCarrier[j].PlayerReplicationInfo.PlayerID, 0 ); - } - } - // Award capper propertionally too. Behave like assist - else if( RedFlagCarrier[j] == FCs[0] ) - { - if( bNewCapAssistScoring ) - { - if( TotalTime == 0 ) - { - f = 0; - } - else - { - f = ( RedFlagCarrierTime[j] / TotalTime ) * ( 7 + CapBonus ); - } - Bonus = Max( f, MinimalCapBonus ); - FCs[0].PlayerReplicationInfo.Score += Bonus - 7; // 7 already awarded by UT - if( bShowAssistConsoleMsg && PlayerPawn( FCs[0] ) != None ) - { - PlayerPawn( FCs[0] ).ClientMessage( "You get " $ Bonus $ " pts for the Capture!" @ CarriedString( RedFlagCarrierTime[j], TotalTime ) ); - } - } - else - { - FCs[0].PlayerReplicationInfo.Score += CapBonus; - } - } - } - ResetFlagCarriers( 0 ); -} - -function RewardBlueFlagCarriers( bool bNotPlayedLead ) -{ - local byte j; - local SmartCTFPlayerReplicationInfo AssisterStats; - local int Bonus; - local float TotalTime, f; - - Bonus = AssistBonus; - - for( j = 0; j < 32; j++ ) - { - TotalTime += BlueFlagCarrierTime[j]; - } - - for( j = 0; j < 32; j++ ) - { - if( BlueFlagCarrier[j] != None && BlueFlagCarrier[j] != FCs[1] ) - { - AssisterStats = SCTFGame.GetStats( BlueFlagCarrier[j] ); - if( AssisterStats != None ) - { - AssisterStats.Assists++; - } - - if( bNewCapAssistScoring ) - { - if( TotalTime == 0 ) - { - f = 0; - } - else - { - f = ( BlueFlagCarrierTime[j] / TotalTime ) * ( 7 + CapBonus ); - } - Bonus = Max( f, 1 ); - } - BlueFlagCarrier[j].PlayerReplicationInfo.Score += Bonus; - - if( PlayerPawn( BlueFlagCarrier[j] ) != None ) - { - if( bShowAssistConsoleMsg ) - { - PlayerPawn( BlueFlagCarrier[j] ).ClientMessage( "You get " $ Bonus $ " bonus pts for the Assist!" @ CarriedString( BlueFlagCarrierTime[j], TotalTime ) ); - } - if( bPlayAssistSound && bNotPlayedLead ) - { - PlayerPawn( BlueFlagCarrier[j] ).ReceiveLocalizedMessage( class'SmartCTFAudioMsg', 1 ); - } - } - if( Level.Game.LocalLog != None ) - { - Level.Game.LocalLog.LogSpecialEvent( "Flag_assist", BlueFlagCarrier[j].PlayerReplicationInfo.PlayerID, 0 ); - } - } - else if( BlueFlagCarrier[j] == FCs[1] ) - { - if( bNewCapAssistScoring ) - { - if( TotalTime == 0 ) - { - f = 0; - } - else - { - f = ( BlueFlagCarrierTime[j] / TotalTime ) * ( 7 + CapBonus ); - } - Bonus = Max( f, MinimalCapBonus ); - FCs[1].PlayerReplicationInfo.Score += Bonus - 7; - if( bShowAssistConsoleMsg && PlayerPawn( FCs[1] ) != None ) - { - PlayerPawn( FCs[1] ).ClientMessage( "You get " $ Bonus $ " pts for the Capture!" @ CarriedString( BlueFlagCarrierTime[j], TotalTime ) ); - } - } - else - { - FCs[1].PlayerReplicationInfo.Score += CapBonus; - } - } - } - ResetFlagCarriers( 1 ); -} - -/* - * Clear assisters list of Team, because of flag return. Team = 2: clear both teams. -*/ -function ResetFlagCarriers( byte Team ) -{ - local byte i; - - if( Team != 1 ) - { - RedFCIndex = 0; - for( i = 0; i < 32; i++ ) - { - RedFlagCarrier[i] = None; - RedFlagCarrierTime[i] = 0; - } - } - if( Team != 0 ) - { - BlueFCIndex = 0; - for( i = 0; i < 32; i++ ) - { - BlueFlagCarrier[i] = None; - BlueFlagCarrierTime[i] = 0; - } - } -} - -function string CarriedString( float Time, float TotalTime ) -{ - local int Perc; - local float f; - - if( TotalTime == 0 ) - { - f = 0; - } - else - { - f = ( Time / TotalTime ) * 100; - } - - Perc = Clamp( f, 0, 100 ); - if( Perc == 100 ) - { - return "(Solocap," @ int( Time ) @ "sec.)"; - } - else - { - return "(Carried" @ Perc $ "% of the time:" @ int( Time ) @ "sec.)"; - } -} - -/* - * Intercept CTF messages to set FC states and adjust scores. -*/ -function bool MutatorBroadcastLocalizedMessage( Actor Sender, Pawn Receiver, out class Message, out optional int Switch, out optional PlayerReplicationInfo RelatedPRI_1, out optional PlayerReplicationInfo RelatedPRI_2, out optional Object OptionalObject ) -{ - local CTFFlag Flag; - local byte i, LeadSound; - local Pawn pn, FirstPawn; - local SmartCTFPlayerReplicationInfo ReceiverStats; - - // This function gets called each time someone receives a message. Thus for a broadcast, we need to make sure code only - // gets executed once. We can do that by comparing Receiver with f.e. the FC if applicable, or with the first Pawn - // in the PawnList (FirstPawn, see below). - - if( Message == class'CTFMessage' ) - { - if( Sender.IsA( 'CTFGame' ) ) - { - Flag = CTFFlag( OptionalObject ); - } - else if( Sender.IsA( 'CTFFlag' ) ) - { - Flag = CTFFlag( Sender ); - } - else - { - return super.MutatorBroadcastLocalizedMessage( Sender, Receiver, Message, Switch, RelatedPRI_1, RelatedPRI_2, OptionalObject ); - } - if( Flag == None ) - { - return super.MutatorBroadcastLocalizedMessage( Sender, Receiver, Message, Switch, RelatedPRI_1, RelatedPRI_2, OptionalObject ); - } - - // Warmup - if( DeathMatchPlus( Level.Game ).bTournament && !bTournamentGameStarted ) - { - return super.MutatorBroadcastLocalizedMessage( Sender, Receiver, Message, Switch, RelatedPRI_1, RelatedPRI_2, OptionalObject ); - } - - switch( Switch ) - { - // CAPTURE - // Sender: CTFGame, PRI: Scorer.PlayerReplicationInfo, OptObj: TheFlag - case 0: - if( Receiver == Pawn( RelatedPRI_1.Owner ) ) - { - //Flag = CTFFlag( OptionalObject ); - i = 1 - Flag.Team; - if( i == 1 ) - { - AddBlueFlagCarrier( FCs[i], Level.TimeSeconds - PickupTime[i] ); - } - else - { - AddRedFlagCarrier( FCs[i], Level.TimeSeconds - PickupTime[i] ); - } - - // Increment Caps for the player and the total - ReceiverStats = SCTFGame.GetStats( FCs[i] ); - if( ReceiverStats != None ) - { - ReceiverStats.Captures++; - } - - if( bPlayLeadSound ) - { - if( ( CTFGame( Level.Game ).Teams[i].Score - 1 ) == CTFGame( Level.Game ).Teams[1 - i].Score ) - { - LeadSound = 1; - } - if( CTFGame( Level.Game ).Teams[i].Score == CTFGame( Level.Game ).Teams[1 - i].Score ) - { - LeadSound = 2; - } - - for( pn = Level.PawnList; pn != None; pn = pn.NextPawn ) - { - if( PlayerPawn( pn ) != None && pn.bIsPlayer ) - { - if( LeadSound == 1 && pn.PlayerReplicationInfo.Team == i ) - { - PlayerPawn( pn ).ReceiveLocalizedMessage( class'SmartCTFAudioMsg', 3 ); - } - else if( LeadSound == 2 && pn.PlayerReplicationInfo.Team == ( 1 - i ) ) - { - PlayerPawn( pn ).ReceiveLocalizedMessage( class'SmartCTFAudioMsg', 4 ); - } - } - } - } - - // Don't play Capture sound if "Got The Lead" sound has played - if( bPlayCaptureSound && PlayerPawn( FCs[i] ) != None ) - { - if( !( bPlayLeadSound && ( LeadSound == 1 ) ) ) - { - PlayerPawn( FCs[i] ).ReceiveLocalizedMessage( class'SmartCTFAudioMsg', 0 ); - } - } - - // Reward points To FC and Assisters and increment Assists count and total - if( Flag.Team == 0 ) - { - RewardBlueFlagCarriers( !( bPlayLeadSound && ( LeadSound == 1 ) ) ); - } - else - { - RewardRedFlagCarriers( !( bPlayLeadSound && ( LeadSound == 1 ) ) ); - } - ResetFlagCarriers( 2 ); - GiveCoverSealBonus( Flag.Team ); // Reward pts to Covers And Sealers - - // Reset FCs And Assister num n index And reset sprees - FCs[0] = None; - FCs[1] = None; - ResetSprees( 2 ); // Means reset all since no Team is equal to 2. - } - break; - - // DROP - // Sender: CTFFlag, PRI: Holder.PlayerReplicationInfo, OptObj: CTFGame(Level.Game).Teams[Team] - case 2: - if( Receiver == Pawn( RelatedPRI_1.Owner ) ) - { - i = 1 - Flag.Team; - if( i == 1 ) - { - AddBlueFlagCarrier( FCs[i], Level.TimeSeconds - PickupTime[i] ); - } - else - { - AddRedFlagCarrier( FCs[i], Level.TimeSeconds - PickupTime[i] ); - } - } - break; - - // PICKUP (after the FC dropped it) - // Sender: CTFFlag, PRI: Holder.PlayerReplicationInfo, OptObj: CTFGame(Level.Game).Teams[Team] - case 4: - if( Receiver == Flag.Holder ) - { - i = 1 - Flag.Team; - PickupTime[i] = Level.TimeSeconds; - FCs[i] = Flag.Holder; - } - break; - - // GRAB - // Sender: CTFFlag, PRI: Holder.PlayerReplicationInfo, OptObj: CTFGame(Level.Game).Teams[Team] - case 6: - if( Receiver == Flag.Holder ) - { - i = 1 - Flag.Team; - PickupTime[i] = Level.TimeSeconds; - FCs[i] = Flag.Holder; // Set the FC - RelatedPRI_1.Score += GrabBonus; - // Increment FC's Grabs and total Grabs - ReceiverStats = SCTFGame.GetStats( FCs[i] ); - if( ReceiverStats != None ) - { - ReceiverStats.Grabs++; - } - } - break; - - - // RETURN - case 1: - case 3: - case 5: - // Get a pawn that receives messages, thus triggers this function ( as Receiver ) - for( FirstPawn = Level.PawnList; FirstPawn != None; FirstPawn = FirstPawn.NextPawn ) - { - if( FirstPawn.bIsPlayer || FirstPawn.IsA( 'MessagingSpectator' ) ) - { - break; - } - } - - if( Receiver == FirstPawn ) // Just get the first one. - { - // Switch == 1: it's returned by player, sent by CTFGame. - // Sender: CTFGame, PRI: Scorer.PlayerReplicationInfo, ObtObj: TheFlag - if( Switch == 1 ) - { - // 8 pts for a close save (with msg), Half a pt for base returns, 2 pts for Mid, 4 pts for enemy base - if( !bTooCloseForSaves && VSize( Flag.Location - FlagStands[1 - Flag.Team].Location ) < 900 ) - { // CLOSE SAVE - RelatedPRI_1.Score += CloseSaveReturnBonus; - if( Level.Game.LocalLog != None ) - { - Level.Game.LocalLog.LogSpecialEvent( "flag_return_closesave", RelatedPRI_1.PlayerID, Flag.Team ); - } - - // Only a msg if not a Flag standoff - other flag is home - if( CTFReplicationInfo( Level.Game.GameReplicationInfo ).FlagList[1 - Flag.Team].bHome ) - { - if( SavedMsgType == 1 && PlayerPawn( RelatedPRI_1.Owner ) != None ) - { - PlayerPawn( RelatedPRI_1.Owner ).ClientMessage( class'SmartCTFMessage'.static.GetString( 7 + 64, RelatedPRI_1 ) ); - } - else if( SavedMsgType == 2 ) - { - BroadcastMessage( class'SmartCTFMessage'.static.GetString( 7, RelatedPRI_1 ) ); - } - else if( SavedMsgType == 3 ) - { - BroadcastLocalizedMessage( class'SmartCTFMessage', 7, RelatedPRI_1 ); - } - if( bPlaySavedSound && PlayerPawn( RelatedPRI_1.Owner ) != None ) - { - PlayerPawn( RelatedPRI_1.Owner ).ReceiveLocalizedMessage( class'SmartCTFAudioMsg', 2 ); - } - } - } - else if( IsInZone( RelatedPRI_1, 1 - Flag.Team ) ) - { - RelatedPRI_1.Score += EnemyBaseReturnBonus; // If in enemy base - if( Level.Game.LocalLog != None ) - { - Level.Game.LocalLog.LogSpecialEvent( "flag_return_enemybase", RelatedPRI_1.PlayerID, Flag.Team ); - } - } - else if( !IsInZone( RelatedPRI_1, Flag.Team ) ) // Not in enemy base and not on own side = mid - { - RelatedPRI_1.Score += MidReturnBonus; // If in Mid - if( Level.Game.LocalLog != None ) - { - Level.Game.LocalLog.LogSpecialEvent( "flag_return_mid", RelatedPRI_1.PlayerID, Flag.Team ); - } - } - else - { - RelatedPRI_1.Score += BaseReturnBonus; - if( Level.Game.LocalLog != None ) - { - Level.Game.LocalLog.LogSpecialEvent( "flag_return_base", RelatedPRI_1.PlayerID, Flag.Team ); - } - } - - } // end if switch == 1 - - ResetSprees( Flag.Team ); // Reset cover sprees and seal sprees of Other Team - ResetFlagCarriers( 1 - Flag.Team ); // Reset assist list - } - - break; - } // end switch - if(bStoreStats) - { - UpdateInfo(); - } - } // end if msg is CTF msg. - - return super.MutatorBroadcastLocalizedMessage( Sender, Receiver, Message, Switch, RelatedPRI_1, RelatedPRI_2, OptionalObject ); -} - -/* - * Gives all players of Team that covered their FC extra bonus points after the cap. -*/ -function GiveCoverSealBonus( int Team ) -{ - local PlayerReplicationInfo pnPRI; - local byte i; - local SmartCTFPlayerReplicationInfo PawnStats; - local Pawn pn; - - SCTFGame.RefreshPRI(); - for( i = 0; i < 64; i++ ) - { - PawnStats = SCTFGame.GetStatNr( i ); - if( PawnStats == None ) - { - break; - } - pnPRI = PlayerReplicationInfo( PawnStats.Owner ); - pn = Pawn( pnPRI.Owner ); - - if( pnPRI.Team != Team ) - { - if( PawnStats != None && PawnStats.SealSpree > 0 ) - { - pnPRI.Score += PawnStats.SealSpree * SealBonus; - if( bShowSealRewardConsoleMsg && PlayerPawn( pn ) != None ) - { - PlayerPawn( pn ).ClientMessage("You killed " $ PawnStats.SealSpree $ " people sealing off the base. You get " $ PawnStats.SealSpree * SealBonus $ " bonus pts!" ); - } - if( Level.Game.LocalLog != None ) - { - Level.Game.LocalLog.LogSpecialEvent( "seal_bonus", pnPRI.PlayerID, PawnStats.SealSpree, PawnStats.SealSpree * SealBonus ); - } - } - if( PawnStats != None && PawnStats.CoverSpree > 0 ) - { - pnPRI.Score += PawnStats.CoverSpree * CoverBonus; - if( bShowCoverRewardConsoleMsg && PlayerPawn( pn ) != None ) - { - PlayerPawn( pn ).ClientMessage("You killed " $ PawnStats.CoverSpree $ " people covering your FC. You get " $ PawnStats.CoverSpree * CoverBonus $ " bonus pts!" ); - } - if( Level.Game.LocalLog != None ) - { - Level.Game.LocalLog.LogSpecialEvent( "cover_bonus", pnPRI.PlayerID, PawnStats.CoverSpree, PawnStats.CoverSpree * CoverBonus ); - } - } - } - } - if(bStoreStats) - { - UpdateInfo(); - } -} - -/* - * Reset cover and seal sprees of Team cause of flag return. -*/ -function ResetSprees( int Team ) -{ - local byte i; - local SmartCTFPlayerReplicationInfo PawnStats; - - SCTFGame.RefreshPRI(); - for( i = 0; i < 64; i++ ) - { - PawnStats = SCTFGame.GetStatNr( i ); - if( PawnStats == None ) - { - break; - } - if( PlayerReplicationInfo( PawnStats.Owner ).Team != Team ) - { - PawnStats.CoverSpree = 0; - PawnStats.SealSpree = 0; - } - } -} - -/* - * Clear stats. -*/ -function ClearStats() -{ - SCTFGame.ClearStats(); - ResetFlagCarriers( 2 ); - FCs[0] = None; - FCs[1] = None; -} - -/* - * Give info on 'mutate smartctf' commands. -*/ -function Mutate( string MutateString, PlayerPawn Sender ) -{ - local int ID; - local string SoundsString, MsgsString, CMsgsString; - local SmartCTFPlayerReplicationInfo SenderStats; - - if( Left( MutateString, 8 ) ~= "SmartCTF" ) - { - ID = Sender.PlayerReplicationInfo.PlayerID; - - if( Mid( MutateString, 9, 9 ) ~= "ShowStats" || Mid( MutateString, 9, 5 ) ~= "Stats" ) - { - SenderStats = SCTFGame.GetStats( Sender ); - if( SenderStats != None ) - { - SenderStats.ToggleStats(); - } - } - else if( Mid( MutateString, 9, 10 ) ~= "ForceStats" ) - { - SenderStats = SCTFGame.GetStats( Sender ); - if( SenderStats != None ) - { - SenderStats.ShowStats(); - } - } - else if( Mid( MutateString, 9, 5 ) ~= "Rules" || Mid( MutateString, 9, 6 ) ~= "Points" || Mid( MutateString, 9, 5 ) ~= "Score" || Mid( MutateString, 9, 5 ) ~= "Bonus" ) - { - if( bNewCapAssistScoring ) - { - Sender.ClientMessage( "SmartCTF Score Settings: - Cap/Assist:" @ 7 + CapBonus @ "pts divided over all FC's by time" ); - } - else - { - Sender.ClientMessage( "SmartCTF Score Settings: - Cap:" @ 7 + CapBonus @ "pts, Assist:" @ AssistBonus @ "pts." ); - } - Sender.ClientMessage( "- Cover (Kills while defending FC) Bonus :" @ CoverBonus @ "pts each. And" @ CoverBonus @ "more pts each if FC caps." ); - Sender.ClientMessage( "- Seal Bonus:" @ SealBonus @ "pts each, and" @ SealBonus @ "more pts each if FC caps." ); - Sender.ClientMessage( "- Seals (Kills while sealing off base) are defined by: 1) Your FC is on your team's side of map. 2) Your flag is not taken. 3) You kill someone on your side of the map." ); - if(bExtraStats) - { - Sender.ClientMessage( "- DefKills (Kills while the enemy is in your base area) are defined by: 1) Your flag is not taken. 2) You kill someone on your side of the map." ); - Sender.ClientMessage( "- Flagkills:" @ 5 + FlagKillBonus @ "pts. Flag Returns in base are worth" @ DitchZeros( BaseReturnBonus ) @ "pts, in mid" @ DitchZeros( MidReturnBonus ) @ "pts, enemy base" @ DitchZeros( EnemyBaseReturnBonus ) @ "pts, VERY close to capping" @ DitchZeros( CloseSaveReturnBonus ) @ "pts." ); - Sender.ClientMessage( "- Additional features: See Readme!" ); - } - } - else if( Mid( MutateString, 9, 8 ) ~= "ForceEnd" ) - { - if( !Sender.PlayerReplicationInfo.bAdmin && Level.NetMode != NM_StandAlone ) - { - Sender.ClientMessage( "You need to be logged in as admin to force the game to end." ); - } - else - { - BroadcastMessage( Sender.PlayerReplicationInfo.PlayerName @ "forced the game to end." ); - bForcedEndGame = True; - CTFGame( Level.Game ).EndGame( "forced" ); - } - } - else if( Mid( MutateString, 9, 10 ) ~= "ClearStats" ) - { - if( !Sender.PlayerReplicationInfo.bAdmin && Level.NetMode != NM_StandAlone ) - { - Sender.ClientMessage( "You need to be logged in as admin to be able to clear the stats." ); - } - else - { - ClearStats(); - Sender.ClientMessage( "Stats cleared." ); - } - } - else - { - Sender.ClientMessage( "SmartCTF - ChaCha Fork V6"); - Sender.ClientMessage( "Originally by: {PiN}Kev_HH. 4C by {DnF2}SiNiSTeR. 4D by [es]Rush. 4E by adminthis & The_Cowboy & Sp0ngeb0b.!"); - Sender.ClientMessage( "- To toggle stats, bind a key or type in console: 'Mutate SmartCTF Stats'" ); - Sender.ClientMessage( "- Type 'Mutate CTFInfo' for SmartCTF settings." ); - Sender.ClientMessage( "- Type 'Mutate SmartCTF Rules' for new point system definition." ); - Sender.ClientMessage( "- Type 'Mutate SmartCTF ForceEnd' to end a game." ); - if( bEnableOvertimeControl ) - { - Sender.ClientMessage( "- Type 'Mutate OverTime ' for Overtime Control." ); - } - } - } - else if( Left( MutateString, 7 ) ~= "CTFInfo" ) - { - SoundsString = ""; - if( bPlayCaptureSound ) SoundsString = SoundsString @ "Capture"; - if( bPlayAssistSound ) SoundsString = SoundsString @ "Assist"; - if( bPlaySavedSound ) SoundsString = SoundsString @ "Saved"; - if( bPlayLeadSound ) SoundsString = SoundsString @ "Lead"; - if( bPlay30SecSound ) SoundsString = SoundsString @ "30SecLeft"; - if( SoundsString == "" ) SoundsString = "All off"; - if( Left( SoundsString, 1 ) == " " ) SoundsString = Mid( SoundsString, 1 ); - MsgsString = ""; - if( CoverMsgType == 1 ) MsgsString = MsgsString @ "Covers"; - if( CoverMsgType == 2 ) MsgsString = MsgsString @ "Covers"; - if( CoverMsgType == 3 ) MsgsString = MsgsString @ "Covers"; - if( CoverSpreeMsgType == 1 ) MsgsString = MsgsString @ "Coversprees"; - if( CoverSpreeMsgType == 2 ) MsgsString = MsgsString @ "Coversprees"; - if( CoverSpreeMsgType == 3 ) MsgsString = MsgsString @ "Coversprees"; - if( DeniedMsgType == 1 ) MsgsString = MsgsString @ "Denied"; - if( DeniedMsgType == 2 ) MsgsString = MsgsString @ "Denied"; - if( DeniedMsgType == 3 ) MsgsString = MsgsString @ "Denied"; - if( SealMsgType == 1 ) MsgsString = MsgsString @ "Seals"; - if( SealMsgType == 2 ) MsgsString = MsgsString @ "Seals"; - if( SealMsgType == 3 ) MsgsString = MsgsString @ "Seals"; - if( SavedMsgType == 1 ) MsgsString = MsgsString @ "Saved"; - if( SavedMsgType == 2 ) MsgsString = MsgsString @ "Saved"; - if( SavedMsgType == 3 ) MsgsString = MsgsString @ "Saved"; - if( MsgsString == "" ) MsgsString = "All off"; - if( Left( MsgsString, 1 ) == " " ) MsgsString = Mid( MsgsString, 1 ); - CMsgsString = ""; - if( bShowAssistConsoleMsg ) CMsgsString = CMsgsString @ "AssistBonus"; - if( bShowSealRewardConsoleMsg ) CMsgsString = CMsgsString @ "SealReward"; - if( bShowCoverRewardConsoleMsg ) CMsgsString = CMsgsString @ "CoverReward"; - if( bShowLongRangeMsg ) CMsgsString = CMsgsString @ "LongRangeKill"; - if( CMsgsString == "" ) CMsgsString = "All off"; - if( Left( CMsgsString, 1 ) == " " ) CMsgsString = Mid( CMsgsString, 1 ); - Sender.ClientMessage( "- bExtraStats:" @ bExtraStats); - Sender.ClientMessage( "- Sounds:" @ SoundsString ); - Sender.ClientMessage( "- Msgs:" @ MsgsString ); - Sender.ClientMessage( "- Private Msgs:" @ CMsgsString ); - Sender.ClientMessage( "- bFixFlagBug:" @ bFixFlagBug ); - Sender.ClientMessage( "- bEnhancedMultiKill:" @ bEnhancedMultiKill $ ", Broadcast Level:" @ EnhancedMultiKillBroadcast ); - Sender.ClientMessage( "- bShowFCLocation:" @ bShowFCLocation ); - if( bSpawnKillDetection ) Sender.ClientMessage( "- bSpawnKillDetection: True, Global Msg:" @ bShowSpawnKillerGlobalMsg $ ", Penalty:" @ SpawnKillPenalty @ "pts" ); - else Sender.ClientMessage( "- bSpawnKillDetection: False" ); - Sender.ClientMessage( "- Overtime Control:" @ bEnableOvertimeControl @ "( Type 'Mutate OverTime' )" ); - Sender.ClientMessage( "- Scores: ( Type 'Mutate SmartCTF Rules' )"); - } - else if( Left( MutateString, 8 ) ~= "OverTime" ) - { - if( !DeathMatchPlus( Level.Game ).bTournament ) - { - Sender.ClientMessage( "Not in Tournament Mode: Default Sudden Death Overtime behaviour." ); - } - else if( !bEnableOvertimeControl ) - { - Sender.ClientMessage( "Overtime Control is not enabled: Default UT Sudden Death functionality." ); - Sender.ClientMessage( "Admins can use: admin set SmartCTF bEnableOvertimeControl True" ); - } - else - { - if( Left( MutateString, 11 ) ~= "OverTime On" ) - { - if( !Sender.PlayerReplicationInfo.bAdmin && Level.NetMode != NM_StandAlone ) - { - Sender.ClientMessage( "You need to be logged in as admin to change this setting." ); - } - else - { - bOvertime = True; - SaveConfig(); - BroadcastLocalizedMessage( class'SmartCTFCoolMsg', 3 ); - } - } - else if( Left( MutateString, 12 ) ~= "OverTime Off" ) - { - if( !Sender.PlayerReplicationInfo.bAdmin && Level.NetMode != NM_StandAlone ) - { - Sender.ClientMessage( "You need to be logged in as admin to change this setting." ); - } - else - { - bOvertime = False; - SaveConfig(); - BroadcastLocalizedMessage( class'SmartCTFCoolMsg', 4 ); - } - } - else - { - if( Sender.PlayerReplicationInfo.bAdmin || Level.NetMode == NM_StandAlone ) - { - Sender.ClientMessage( "Usage: Mutate OverTime On|Off" ); - } - if( !bOvertime ) - { - Sender.ClientMessage( "Sudden Death Overtime is DISABLED." ); - } - else - { - Sender.ClientMessage( "Sudden Death Overtime is ENABLED (default)." ); - } - Sender.ClientMessage( "Remember 'Disabled' Setting:" @ bRememberOvertimeSetting ); - } - } - } - - super.Mutate( MutateString, Sender ); -} - -/* - * To stop on a tie if needed. -*/ -function bool HandleEndGame() -{ - local bool bTied; - - if( CTFGame( Level.Game ).Teams[0].Score == CTFGame( Level.Game ).Teams[1].Score ) - { - bTied = True; - } - - if( bForcedEndGame || ( bEnableOvertimeControl && !bOvertime && DeathMatchPlus( Level.Game ).bTournament ) ) - { - bForcedEndGame = False; - if( bTied ) - { - SetEndCamsTiedCTFGame(); - return True; - } - } - - if( !bTied ) - { - CalcSmartCTFEndStats(); - } - if(bStoreStats) - { - UpdateInfo(); - } - if( NextMutator != None ) - { - return NextMutator.HandleEndGame(); - } - return False; -} - - -/* - * Position end cameras for a tied game. -*/ -function SetEndCamsTiedCTFGame() -{ - local Pawn pn, Best; - local PlayerPawn Player; - local CTFGame gg; - - gg = CTFGame( Level.Game ); - - // Find Individual Winner - for( pn = Level.PawnList ; pn != None ; pn = pn.NextPawn ) - { - if( pn.bIsPlayer && ( ( Best == None ) || ( pn.PlayerReplicationInfo.Score > Best.PlayerReplicationInfo.Score ) ) ) - { - Best = pn; - } - } - - gg.GameReplicationInfo.GameEndedComments = GameTieMessage; - gg.EndTime = Level.TimeSeconds + 3.0; - - for( pn = Level.PawnList ; pn != None ; pn = pn.NextPawn ) - { - Player = PlayerPawn( pn ); - if( Player != None ) - { - Player.bBehindView = True; - if( Player == Best ) - { - Player.ViewTarget = None; - } - else - { - Player.ViewTarget = Best; - } - - Player.ClientPlaySound( sound'CaptureSound', , true ); - Player.ClientGameEnded(); - } - pn.GotoState( 'GameEnded' ); - } - - gg.CalcEndStats(); - CalcSmartCTFEndStats(); -} - -function CalcSmartCTFEndStats() -{ - local SmartCTFPlayerReplicationInfo TopScore, TopFrags, TopCaps, TopCovers, TopFlagkills, TopHeadshots; - local string BestRecordDate; - local float PerHour; - local SmartCTFPlayerReplicationInfo PawnStats; - local PlayerReplicationInfo PRI; - local byte i; - local SmartCTFEndStats EndStats; - - EndStats = SCTFGame.EndStats; - - SCTFGame.RefreshPRI(); - for( i = 0; i < 64; i++ ) - { - PawnStats = SCTFGame.GetStatNr( i ); - if( PawnStats == None ) - { - break; - } - - if( TopScore == None || PlayerReplicationInfo( PawnStats.Owner ).Score > PlayerReplicationInfo( TopScore.Owner ).Score ) - { - TopScore = PawnStats; - } - if( TopFrags == None || PawnStats.Frags > TopFrags.Frags ) - { - TopFrags = PawnStats; - } - if( TopCaps == None || PawnStats.Captures > TopCaps.Captures ) - { - TopCaps = PawnStats; - } - if( TopCovers == None || PawnStats.Covers > TopCovers.Covers ) - { - TopCovers = PawnStats; - } - if( TopFlagkills == None || PawnStats.FlagKills > TopFlagkills.FlagKills ) - { - TopFlagkills = PawnStats; - } - if( TopHeadshots == None || PawnStats.HeadShots > TopHeadshots.HeadShots ) - { - TopHeadshots = PawnStats; - } - } - - PRI = PlayerReplicationInfo( TopScore.Owner ); - PerHour = ( Level.TimeSeconds - PRI.StartTime ) / 3600; - if( PRI.Score / PerHour > EndStats.MostPoints.Count && Level.TimeSeconds - PRI.StartTime > 300 ) - { - EndStats.MostPoints.Count = PRI.Score / PerHour; - EndStats.MostPoints.PlayerName = PRI.PlayerName; - EndStats.MostPoints.MapName = Level.Title; - CTFGame( Level.Game ).GetTimeStamp( BestRecordDate ); - EndStats.MostPoints.RecordDate = BestRecordDate; - } - - PRI = PlayerReplicationInfo( TopFrags.Owner ); - PerHour = ( Level.TimeSeconds - PRI.StartTime ) / 3600; - if( TopFrags.Frags / PerHour > EndStats.MostFrags.Count && Level.TimeSeconds - PRI.StartTime > 300 ) - { - EndStats.MostFrags.Count = TopFrags.Frags / PerHour; - EndStats.MostFrags.PlayerName = PRI.PlayerName; - EndStats.MostFrags.MapName = Level.Title; - CTFGame( Level.Game ).GetTimeStamp( BestRecordDate ); - EndStats.MostFrags.RecordDate = BestRecordDate; - } - - PRI = PlayerReplicationInfo( TopCaps.Owner ); - PerHour = ( Level.TimeSeconds - PRI.StartTime ) / 3600; - if( TopCaps.Captures / PerHour > EndStats.MostCaps.Count && Level.TimeSeconds - PRI.StartTime > 300 ) - { - EndStats.MostCaps.Count = TopCaps.Captures / PerHour; - EndStats.MostCaps.PlayerName = PRI.PlayerName; - EndStats.MostCaps.MapName = Level.Title; - CTFGame( Level.Game ).GetTimeStamp( BestRecordDate ); - EndStats.MostCaps.RecordDate = BestRecordDate; - } - - PRI = PlayerReplicationInfo( TopCovers.Owner ); - PerHour = ( Level.TimeSeconds - PRI.StartTime ) / 3600; - if( TopCovers.Covers / PerHour > EndStats.MostCovers.Count && Level.TimeSeconds - PRI.StartTime > 300 ) - { - EndStats.MostCovers.Count = TopCovers.Covers / PerHour; - EndStats.MostCovers.PlayerName = PRI.PlayerName; - EndStats.MostCovers.MapName = Level.Title; - CTFGame( Level.Game ).GetTimeStamp( BestRecordDate ); - EndStats.MostCovers.RecordDate = BestRecordDate; - } - - PRI = PlayerReplicationInfo( TopFlagkills.Owner ); - PerHour = ( Level.TimeSeconds - PRI.StartTime ) / 3600; - if( TopFlagkills.FlagKills / PerHour > EndStats.MostFlagKills.Count && Level.TimeSeconds - PRI.StartTime > 300 ) - { - EndStats.MostFlagKills.Count = TopFlagkills.FlagKills / PerHour; - EndStats.MostFlagKills.PlayerName = PRI.PlayerName; - EndStats.MostFlagKills.MapName = Level.Title; - CTFGame( Level.Game ).GetTimeStamp( BestRecordDate ); - EndStats.MostFlagKills.RecordDate = BestRecordDate; - } - - PRI = PlayerReplicationInfo( TopHeadshots.Owner ); - PerHour = ( Level.TimeSeconds - PRI.StartTime ) / 3600; - if( TopHeadshots.HeadShots / PerHour > EndStats.MostHeadShots.Count && Level.TimeSeconds - PRI.StartTime > 300 ) - { - EndStats.MostHeadShots.Count = TopHeadshots.HeadShots / PerHour; - EndStats.MostHeadShots.PlayerName = PRI.PlayerName; - EndStats.MostHeadShots.MapName = Level.Title; - CTFGame( Level.Game ).GetTimeStamp( BestRecordDate ); - EndStats.MostHeadShots.RecordDate = BestRecordDate; - } - - EndStats.SaveConfig(); -} - -/* - * Convert a float to a readable string. -*/ -function string DitchZeros( float nr ) -{ - local string str; - - str = string( nr ); - while( Right( str, 1 ) == "0" ) - { - str = Left( str , Len( str ) - 1 ); - } - if( Right( str, 1 ) == "." ) - { - str = Left( str , Len( str ) - 1 ); - } - - return str; -} - -//---------------------------------------------------------------------------------------------------------------- -//------------------------------------------------ CLIENT FUNCTIONS ---------------------------------------------- -//---------------------------------------------------------------------------------------------------------------- - -/* - * Render the HUD that is startup logo and FC location. - * ONLY gets executed on clients. -*/ -simulated event PostRender( Canvas C ) -{ - local int i, Y; - local float DummyY, Size, Temp; - local string TempStr; - - if( NextHUDMutator != None ) - { - NextHUDMutator.PostRender( C ); - } - - // Get stuff relating to PlayerOwner, if not gotten. Also spawn Font info. - if( PlayerOwner == None ) - { - PlayerOwner = C.Viewport.Actor; - pPRI = PlayerOwner.PlayerReplicationInfo; - } - - if(MyHUD == None) - { - MyHUD = ChallengeHUD( PlayerOwner.MyHUD ); - MyFonts = MyHUD.MyFonts; - } - - if(pTGRI == None) - { - pTGRI = TournamentGameReplicationInfo (PlayerOwner.GameReplicationInfo); - if(pTGRI==None) - { - return; - } - } - - // Draw the FC Location - if( SCTFGame.bShowFCLocation ) - { - for( i = 0; i < 32; i++ ) - { - if( pTGRI.PRIArray[i] == None ) - { - break; - } - if( pTGRI.PRIArray[i].bIsSpectator && !pTGRI.PRIArray[i].bWaitingPlayer ) - { - continue; - } - if( pTGRI.PRIArray[i].HasFlag != None && pTGRI.PRIArray[i].Team == pPRI.Team && pTGRI.PRIArray[i].PlayerID != pPRI.PlayerID && !pTGRI.PRIArray[i].HasFlag.IsA( 'GreenFlag' ) ) - { - if( pTGRI.PRIArray[i].PlayerLocation != None ) - { - TempStr = pTGRI.PRIArray[i].PlayerLocation.LocationName; - } - else if( pTGRI.PRIArray[i].PlayerZone != None ) - { - TempStr = pTGRI.PRIArray[i].PlayerZone.ZoneName; - } - if( TempStr == "" ) - { - TempStr = "Nameless Area"; - C.Style = ERenderStyle.STY_Translucent; - } - else - { - C.Style = ERenderStyle.STY_Normal; - } - - if( pPRI.Team == 0 ) - { - C.DrawColor = RedTeamColor; - } - else - { - C.DrawColor = BlueTeamColor; - } - - C.Font = MyFonts.GetSmallestFont( C.ClipX ); - C.StrLen( TempStr, Size, DummyY ); - if( MyHUD.bHideAllWeapons ) - { - Y = C.ClipY; - } - else if( MyHUD.HudScale * MyHUD.WeaponScale * C.ClipX <= C.ClipX - 256 * MyHUD.Scale) - { - Y = C.ClipY - 64 * MyHUD.Scale; - } - else - { - Y = C.ClipY - 128 * MyHUD.Scale; - } - - C.SetPos( C.ClipX - Size - 6, Y - 4 - 32 + ( 32 - DummyY ) / 2 ); - C.DrawText( TempStr ); - if( C.Style == ERenderStyle.STY_Translucent ) - { - C.DrawColor = Gray; - } - else - { - C.DrawColor = White; - } - C.SetPos( C.ClipX - Size - 6 - 32 - 4, Y - 4 - 32 ); - if( pPRI.Team == 0 ) - { - C.DrawIcon( texture'blueflag', 1.0 ); - } - else - { - C.DrawIcon( texture'redflag', 1.0 ); - } - - break; - } - } - } - - // Draw "Powered by.." logo when player joins - if( DrawLogo != 0 ) - { - C.Style = ERenderStyle.STY_Translucent; - if( DrawLogo > 1 ) - { - C.DrawColor.R = 255 - DrawLogo/2; - C.DrawColor.G = 255 - DrawLogo/2; - C.DrawColor.B = 255 - DrawLogo/2; - } - else // 1 - { - C.Style = ERenderStyle.STY_Translucent; - C.DrawColor = White; - } - if(powered == None) - { - powered=texture'powered'; - } - C.SetPos( C.ClipX - powered.Usize - 16, 40 ); - C.DrawIcon( powered, 1 ); - C.Font = MyFonts.GetSmallFont( C.ClipX ); - C.StrLen( "SmartCTF "$Version , Size, DummyY ); - C.SetPos( C.ClipX - powered.Usize/2 - Size/2 - 16, 40 + 8 + powered.Vsize ); - Temp = DummyY; - C.DrawText( "SmartCTF "$Version ); - } - - C.Style = ERenderStyle.STY_Normal; -} - - -/* - * Executed on the client when that player joins the server. -*/ -simulated function ClientJoinServer( Pawn Other ) -{ - if( PlayerPawn( Other ) == None || !Other.bIsPlayer ) - { - return; - } - - if(SCTFGame.bDrawLogo) - { - DrawLogo = 1; - } - - SetTimer( 0.05 , True); - - // Since this gets called in the HUD it needs to be changed clientside. - if( SCTFGame.bPlay30SecSound ) - { - class'TimeMessage'.default.TimeSound[5] = sound'Announcer.CD30Sec'; - } -} - -/* - * Clientside settings that need to be set for the first time, checking for welcome message and - * end of game screen. -*/ -simulated function Tick( float delta ) -{ - local SmartCTFPlayerReplicationInfo OwnerStats; - - // Execute on client - if( Level.NetMode != NM_DedicatedServer ) - { - if( SCTFGame == None ) - { - ForEach AllActors( class'SmartCTFGameReplicationInfo', SCTFGame ) - { - break; - } - - if( SCTFGame == None ) - { - return; - } - - if( !SCTFGame.bServerInfoSetServerSide && SCTFGame.DefaultHUDType != None ) // client side required - { - class( SCTFGame.DefaultHUDType ).default.ServerInfoClass = class'SmartCTFServerInfo'; - Log( "Notified HUD (clientside," @ SCTFGame.DefaultHUDType.name $ ") to use SmartCTF ServerInfo.", 'SmartCTF' ); - } - } - if( !SCTFGame.bInitialized ) - { - return; - } - - if( !bHUDMutator ) - { - RegisterHUDMutator(); - } - - if( PlayerOwner != None ) - { - if( !bClientJoinPlayer ) - { - bClientJoinPlayer = True; - ClientJoinServer( PlayerOwner ); - } - - // If Game is over, bring up F3. - if(PlayerOwner.GameReplicationInfo !=None) - { - if( PlayerOwner.GameReplicationInfo.GameEndedComments != "" && !bGameEnded ) - { - bGameEnded = True; - OwnerStats = SCTFGame.GetStatsByPRI( pPRI ); - OwnerStats.bEndStats = True; - PlayerOwner.ConsoleCommand( "mutate SmartCTF ForceStats" ); - } - } - } - } -} - -/* - * For showing the Logo a Timer is used instead of Ticks so its equal for each tickrate. - * On the server it keeps track of some replicated data and whether a Tournament game is starting. -*/ -simulated function Timer() -{ - local bool bReady; - local Pawn pn; - local SmartCTFPlayerReplicationInfo SenderStats; - - super.Timer(); - - // Clients - 0.05 second timer. Stops after logo is displayed. - if( Level.NetMode != NM_DedicatedServer ) - { - if( DrawLogo != 0 && SCTFGame.bDrawLogo ) - { - LogoCounter++; - if( DrawLogo == 510 ) - { - DrawLogo = 0; - if( Role != ROLE_Authority ) - { - SetTimer( 0.0, False ); // client timer off - } - else - { - SetTimer( 1.0, True ); // standalone game? keep timer running for bit below. - } - } - else if( LogoCounter > 60 ) - { - DrawLogo += 8; - if( DrawLogo > 510 ) - { - DrawLogo = 510; - } - } - else if( LogoCounter == 60 ) - { - DrawLogo = 5; - } - } - - if(!bInitSb && SCTFGame.bSCTFSbDef){ // SCTFGame fixes bSCTFSbDef bug. - if(bGameEnded) - { - // Don't interfere with scoreboard showing on game end - bInitSb=true; - return; - } - SbCount++; - if(SbCount>=SCTFGame.SbDelayC){ // Wait SbDelayC second(s) before calling SmartCTF sb - SenderStats = SCTFGame.GetStats( PlayerOwner ); - if( SenderStats != None ) - { - SenderStats.ShowStats(true); - } - bInitSb=true; - if(!SCTFGame.bDrawLogo && Role != ROLE_Authority) - { - SetTimer(0.0,False); - } - } - } - } - - // Server - 1 second timer. infinite. - if( Level.NetMode == NM_DedicatedServer || Role == ROLE_Authority ) - { - if( ++TRCount > 2 ) - { - SCTFGame.TickRate = int( ConsoleCommand( "get IpDrv.TcpNetDriver NetServerMaxTickRate" ) ); - TRCount = 0; - } - - SbDelayC = SbDelay*20; // Timer is called every 0.05s, so * 20 converts the value in seconds to our count compatible value - - // Update config vars to client / manual replication :E - // Allows for runtime changing of settings. - if( SCTFGame.bShowFCLocation != bShowFCLocation ) SCTFGame.bShowFCLocation = bShowFCLocation; - if( SCTFGame.bStatsDrawFaces != bStatsDrawFaces ) SCTFGame.bStatsDrawFaces = bStatsDrawFaces; - if( SCTFGame.bDrawLogo != bDrawLogo ) SCTFGame.bDrawLogo = bDrawLogo; - if( SCTFGame.bSCTFSbDef != bSCTFSbDef ) SCTFGame.bSCTFSbDef = bSCTFSbDef; - if( SCTFGame.bShowSpecs != bShowSpecs ) SCTFGame.bShowSpecs = bShowSpecs; - if( SCTFGame.SpectatorColor != SpectatorColor ) SCTFGame.SpectatorColor = SpectatorColor; - if( SCTFGame.bDoKeybind != bDoKeybind ) SCTFGame.bDoKeybind = bDoKeybind; - if( SCTFGame.SbDelayC != SbDelayC ) SCTFGame.SbDelayC = SbDelayC; - if( SCTFGame.bSnowyScoreboard != bSnowyScoreboard ) SCTFGame.bSnowyScoreboard = bSnowyScoreboard; - if( SCTFGame.bXmasImages != bXmasImages ) SCTFGame.bXmasImages = bXmasImages; - - if( !bTournamentGameStarted && DeathMatchPlus( Level.Game ).bTournament ) - { - if( DeathMatchPlus( Level.Game ).bRequireReady && - DeathMatchPlus( Level.Game ).CountDown > 0 && - ( DeathMatchPlus( Level.Game ).NumPlayers == DeathMatchPlus( Level.Game ).MaxPlayers || Level.NetMode == NM_Standalone ) && - DeathMatchPlus( Level.Game ).RemainingBots <= 0 ) - { - bReady = True; - for( pn = Level.PawnList; pn != None; pn = pn.NextPawn ) - { - if( pn.IsA( 'PlayerPawn' ) && !pn.IsA( 'Spectator' ) && !PlayerPawn( pn ).bReadyToPlay ) - { - bReady = False; - break; - } - } - } - - if( bReady ) - { - bTournamentGameStarted = True; - TournamentGameStarted(); - } - } - - // UT's built-in messaging spectator is excluded from the spectator list based on its starttime. - // We need to make sure this does not include any players as well. - // Update: on slow/exotic servers, the starttime could be delayed (not 0). Let's make sure it is. - if(!bStartTimeCorrected && bShowSpecs) - { - for(pn = Level.PawnList; pn != None; pn = pn.NextPawn){ - if(pn.IsA('PlayerPawn') && pn.PlayerReplicationInfo.StartTime==0) - { - pn.PlayerReplicationInfo.StartTime=1; - } - if(!pn.bIsPlayer && pn.PlayerReplicationInfo.Playername=="Player") - { - pn.PlayerReplicationInfo.StartTime=0; - } - } - if(Level.TimeSeconds>=5) - { - bStartTimeCorrected=true; // After five seconds, the messaging spectator(s) should be loaded, so we are done. - } - } - - // Since PlayerID's are incremented in the order of player joins [and those joined later cannot have an earlier StartTime than preceding players], this can be reliably used to deliver each player the delayed message only once - // without having to resort to a large array of PIDs already messaged; we can simply check against the *last* PID messaged instead. - // Too bad the timer only runs at 1.0. That sorf of defies the purpose of MsgDelay being a float instead of an int. O well... matches nice with SbDelay ;) - for(pn = Level.PawnList; pn != None; pn = pn.NextPawn) - { - if( pn.IsA('PlayerPawn') && - pn.bIsPlayer && - Level.TimeSeconds - pn.PlayerReplicationInfo.StartTime >= MsgDelay && - pn.PlayerReplicationInfo.PlayerID>MsgPID) - { - if(!SCTFGame.bDrawLogo) - { - pn.ClientMessage( "Running SmartCTF " $ Version $ ". Type 'Mutate SmartCTF' in the console for info." ); - } - if(bExtraMsg && bDoKeybind && SCTFGame.bDrawLogo) - { - pn.ClientMessage("Running SmartCTF " $ Version $ ". Press F3 to toggle between scoreboards."); - } - else if(bExtraMsg && bDoKeybind) - { - pn.ClientMessage("Press F3 to toggle between scoreboards."); // Shorter msg, since we already announced we are running SmartCTF. - } - MsgPID = pn.PlayerReplicationInfo.PlayerID; // Increase to keep track of whom still to message - } - } - } -} - -defaultproperties -{ - SCTFGame=None - RedAstIndex=0 - BlueAstIndex=0 - TRCount=0 - version="ChaChaV5" - GameTieMessage="The game ended in a tie!" - FCs(0)=None - FCs(1)=None - RedAssisters(0)=None - RedAssisters(1)=None - RedAssisters(2)=None - RedAssisters(3)=None - RedAssisters(4)=None - RedAssisters(5)=None - RedAssisters(6)=None - RedAssisters(7)=None - RedAssisters(8)=None - RedAssisters(9)=None - RedAssisters(10)=None - RedAssisters(11)=None - RedAssisters(12)=None - RedAssisters(13)=None - RedAssisters(14)=None - RedAssisters(15)=None - RedAssisters(16)=None - RedAssisters(17)=None - RedAssisters(18)=None - RedAssisters(19)=None - RedAssisters(20)=None - RedAssisters(21)=None - RedAssisters(22)=None - RedAssisters(23)=None - RedAssisters(24)=None - RedAssisters(25)=None - RedAssisters(26)=None - RedAssisters(27)=None - RedAssisters(28)=None - RedAssisters(29)=None - RedAssisters(30)=None - RedAssisters(31)=None - BlueAssisters(0)=None - BlueAssisters(1)=None - BlueAssisters(2)=None - BlueAssisters(3)=None - BlueAssisters(4)=None - BlueAssisters(5)=None - BlueAssisters(6)=None - BlueAssisters(7)=None - BlueAssisters(8)=None - BlueAssisters(9)=None - BlueAssisters(10)=None - BlueAssisters(11)=None - BlueAssisters(12)=None - BlueAssisters(13)=None - BlueAssisters(14)=None - BlueAssisters(15)=None - BlueAssisters(16)=None - BlueAssisters(17)=None - BlueAssisters(18)=None - BlueAssisters(19)=None - BlueAssisters(20)=None - BlueAssisters(21)=None - BlueAssisters(22)=None - BlueAssisters(23)=None - BlueAssisters(24)=None - BlueAssisters(25)=None - BlueAssisters(26)=None - BlueAssisters(27)=None - BlueAssisters(28)=None - BlueAssisters(29)=None - BlueAssisters(30)=None - BlueAssisters(31)=None - RedFlagCarrier(0)=None - RedFlagCarrier(1)=None - RedFlagCarrier(2)=None - RedFlagCarrier(3)=None - RedFlagCarrier(4)=None - RedFlagCarrier(5)=None - RedFlagCarrier(6)=None - RedFlagCarrier(7)=None - RedFlagCarrier(8)=None - RedFlagCarrier(9)=None - RedFlagCarrier(10)=None - RedFlagCarrier(11)=None - RedFlagCarrier(12)=None - RedFlagCarrier(13)=None - RedFlagCarrier(14)=None - RedFlagCarrier(15)=None - RedFlagCarrier(16)=None - RedFlagCarrier(17)=None - RedFlagCarrier(18)=None - RedFlagCarrier(19)=None - RedFlagCarrier(20)=None - RedFlagCarrier(21)=None - RedFlagCarrier(22)=None - RedFlagCarrier(23)=None - RedFlagCarrier(24)=None - RedFlagCarrier(25)=None - RedFlagCarrier(26)=None - RedFlagCarrier(27)=None - RedFlagCarrier(28)=None - RedFlagCarrier(29)=None - RedFlagCarrier(30)=None - RedFlagCarrier(31)=None - BlueFlagCarrier(0)=None - BlueFlagCarrier(1)=None - BlueFlagCarrier(2)=None - BlueFlagCarrier(3)=None - BlueFlagCarrier(4)=None - BlueFlagCarrier(5)=None - BlueFlagCarrier(6)=None - BlueFlagCarrier(7)=None - BlueFlagCarrier(8)=None - BlueFlagCarrier(9)=None - BlueFlagCarrier(10)=None - BlueFlagCarrier(11)=None - BlueFlagCarrier(12)=None - BlueFlagCarrier(13)=None - BlueFlagCarrier(14)=None - BlueFlagCarrier(15)=None - BlueFlagCarrier(16)=None - BlueFlagCarrier(17)=None - BlueFlagCarrier(18)=None - BlueFlagCarrier(19)=None - BlueFlagCarrier(20)=None - BlueFlagCarrier(21)=None - BlueFlagCarrier(22)=None - BlueFlagCarrier(23)=None - BlueFlagCarrier(24)=None - BlueFlagCarrier(25)=None - BlueFlagCarrier(26)=None - BlueFlagCarrier(27)=None - BlueFlagCarrier(28)=None - BlueFlagCarrier(29)=None - BlueFlagCarrier(30)=None - BlueFlagCarrier(31)=None - RedFlagCarrierTime(0)=0.000000 - RedFlagCarrierTime(1)=0.000000 - RedFlagCarrierTime(2)=0.000000 - RedFlagCarrierTime(3)=0.000000 - RedFlagCarrierTime(4)=0.000000 - RedFlagCarrierTime(5)=0.000000 - RedFlagCarrierTime(6)=0.000000 - RedFlagCarrierTime(7)=0.000000 - RedFlagCarrierTime(8)=0.000000 - RedFlagCarrierTime(9)=0.000000 - RedFlagCarrierTime(10)=0.000000 - RedFlagCarrierTime(11)=0.000000 - RedFlagCarrierTime(12)=0.000000 - RedFlagCarrierTime(13)=0.000000 - RedFlagCarrierTime(14)=0.000000 - RedFlagCarrierTime(15)=0.000000 - RedFlagCarrierTime(16)=0.000000 - RedFlagCarrierTime(17)=0.000000 - RedFlagCarrierTime(18)=0.000000 - RedFlagCarrierTime(19)=0.000000 - RedFlagCarrierTime(20)=0.000000 - RedFlagCarrierTime(21)=0.000000 - RedFlagCarrierTime(22)=0.000000 - RedFlagCarrierTime(23)=0.000000 - RedFlagCarrierTime(24)=0.000000 - RedFlagCarrierTime(25)=0.000000 - RedFlagCarrierTime(26)=0.000000 - RedFlagCarrierTime(27)=0.000000 - RedFlagCarrierTime(28)=0.000000 - RedFlagCarrierTime(29)=0.000000 - RedFlagCarrierTime(30)=0.000000 - RedFlagCarrierTime(31)=0.000000 - BlueFlagCarrierTime(0)=0.000000 - BlueFlagCarrierTime(1)=0.000000 - BlueFlagCarrierTime(2)=0.000000 - BlueFlagCarrierTime(3)=0.000000 - BlueFlagCarrierTime(4)=0.000000 - BlueFlagCarrierTime(5)=0.000000 - BlueFlagCarrierTime(6)=0.000000 - BlueFlagCarrierTime(7)=0.000000 - BlueFlagCarrierTime(8)=0.000000 - BlueFlagCarrierTime(9)=0.000000 - BlueFlagCarrierTime(10)=0.000000 - BlueFlagCarrierTime(11)=0.000000 - BlueFlagCarrierTime(12)=0.000000 - BlueFlagCarrierTime(13)=0.000000 - BlueFlagCarrierTime(14)=0.000000 - BlueFlagCarrierTime(15)=0.000000 - BlueFlagCarrierTime(16)=0.000000 - BlueFlagCarrierTime(17)=0.000000 - BlueFlagCarrierTime(18)=0.000000 - BlueFlagCarrierTime(19)=0.000000 - BlueFlagCarrierTime(20)=0.000000 - BlueFlagCarrierTime(21)=0.000000 - BlueFlagCarrierTime(22)=0.000000 - BlueFlagCarrierTime(23)=0.000000 - BlueFlagCarrierTime(24)=0.000000 - BlueFlagCarrierTime(25)=0.000000 - BlueFlagCarrierTime(26)=0.000000 - BlueFlagCarrierTime(27)=0.000000 - BlueFlagCarrierTime(28)=0.000000 - BlueFlagCarrierTime(29)=0.000000 - BlueFlagCarrierTime(30)=0.000000 - BlueFlagCarrierTime(31)=0.000000 - RedFCIndex=0 - BlueFCIndex=0 - RedAssistTimes(0)=0.000000 - RedAssistTimes(1)=0.000000 - RedAssistTimes(2)=0.000000 - RedAssistTimes(3)=0.000000 - RedAssistTimes(4)=0.000000 - RedAssistTimes(5)=0.000000 - RedAssistTimes(6)=0.000000 - RedAssistTimes(7)=0.000000 - RedAssistTimes(8)=0.000000 - RedAssistTimes(9)=0.000000 - RedAssistTimes(10)=0.000000 - RedAssistTimes(11)=0.000000 - RedAssistTimes(12)=0.000000 - RedAssistTimes(13)=0.000000 - RedAssistTimes(14)=0.000000 - RedAssistTimes(15)=0.000000 - RedAssistTimes(16)=0.000000 - RedAssistTimes(17)=0.000000 - RedAssistTimes(18)=0.000000 - RedAssistTimes(19)=0.000000 - RedAssistTimes(20)=0.000000 - RedAssistTimes(21)=0.000000 - RedAssistTimes(22)=0.000000 - RedAssistTimes(23)=0.000000 - RedAssistTimes(24)=0.000000 - RedAssistTimes(25)=0.000000 - RedAssistTimes(26)=0.000000 - RedAssistTimes(27)=0.000000 - RedAssistTimes(28)=0.000000 - RedAssistTimes(29)=0.000000 - RedAssistTimes(30)=0.000000 - RedAssistTimes(31)=0.000000 - BlueAssistTimes(0)=0.000000 - BlueAssistTimes(1)=0.000000 - BlueAssistTimes(2)=0.000000 - BlueAssistTimes(3)=0.000000 - BlueAssistTimes(4)=0.000000 - BlueAssistTimes(5)=0.000000 - BlueAssistTimes(6)=0.000000 - BlueAssistTimes(7)=0.000000 - BlueAssistTimes(8)=0.000000 - BlueAssistTimes(9)=0.000000 - BlueAssistTimes(10)=0.000000 - BlueAssistTimes(11)=0.000000 - BlueAssistTimes(12)=0.000000 - BlueAssistTimes(13)=0.000000 - BlueAssistTimes(14)=0.000000 - BlueAssistTimes(15)=0.000000 - BlueAssistTimes(16)=0.000000 - BlueAssistTimes(17)=0.000000 - BlueAssistTimes(18)=0.000000 - BlueAssistTimes(19)=0.000000 - BlueAssistTimes(20)=0.000000 - BlueAssistTimes(21)=0.000000 - BlueAssistTimes(22)=0.000000 - BlueAssistTimes(23)=0.000000 - BlueAssistTimes(24)=0.000000 - BlueAssistTimes(25)=0.000000 - BlueAssistTimes(26)=0.000000 - BlueAssistTimes(27)=0.000000 - BlueAssistTimes(28)=0.000000 - BlueAssistTimes(29)=0.000000 - BlueAssistTimes(30)=0.000000 - BlueAssistTimes(31)=0.000000 - PickupTime(0)=0.000000 - PickupTime(1)=0.000000 - FlagStands(0)=None - FlagStands(1)=None - bForcedEndGame=False - bTournamentGameStarted=False - bTooCloseForSaves=False - bStartTimeCorrected=False - MsgPID=0 - GoneName(0)="" - GoneName(1)="" - GoneName(2)="" - GoneName(3)="" - GoneName(4)="" - GoneName(5)="" - GoneName(6)="" - GoneName(7)="" - GoneName(8)="" - GoneName(9)="" - GoneName(10)="" - GoneName(11)="" - GoneName(12)="" - GoneName(13)="" - GoneName(14)="" - GoneName(15)="" - GoneName(16)="" - GoneName(17)="" - GoneName(18)="" - GoneName(19)="" - GoneName(20)="" - GoneName(21)="" - GoneName(22)="" - GoneName(23)="" - GoneName(24)="" - GoneName(25)="" - GoneName(26)="" - GoneName(27)="" - GoneName(28)="" - GoneName(29)="" - GoneName(30)="" - GoneName(31)="" - GoneIP(0)="" - GoneIP(1)="" - GoneIP(2)="" - GoneIP(3)="" - GoneIP(4)="" - GoneIP(5)="" - GoneIP(6)="" - GoneIP(7)="" - GoneIP(8)="" - GoneIP(9)="" - GoneIP(10)="" - GoneIP(11)="" - GoneIP(12)="" - GoneIP(13)="" - GoneIP(14)="" - GoneIP(15)="" - GoneIP(16)="" - GoneIP(17)="" - GoneIP(18)="" - GoneIP(19)="" - GoneIP(20)="" - GoneIP(21)="" - GoneIP(22)="" - GoneIP(23)="" - GoneIP(24)="" - GoneIP(25)="" - GoneIP(26)="" - GoneIP(27)="" - GoneIP(28)="" - GoneIP(29)="" - GoneIP(30)="" - GoneIP(31)="" - GoneScore(0)=0.000000 - GoneScore(1)=0.000000 - GoneScore(2)=0.000000 - GoneScore(3)=0.000000 - GoneScore(4)=0.000000 - GoneScore(5)=0.000000 - GoneScore(6)=0.000000 - GoneScore(7)=0.000000 - GoneScore(8)=0.000000 - GoneScore(9)=0.000000 - GoneScore(10)=0.000000 - GoneScore(11)=0.000000 - GoneScore(12)=0.000000 - GoneScore(13)=0.000000 - GoneScore(14)=0.000000 - GoneScore(15)=0.000000 - GoneScore(16)=0.000000 - GoneScore(17)=0.000000 - GoneScore(18)=0.000000 - GoneScore(19)=0.000000 - GoneScore(20)=0.000000 - GoneScore(21)=0.000000 - GoneScore(22)=0.000000 - GoneScore(23)=0.000000 - GoneScore(24)=0.000000 - GoneScore(25)=0.000000 - GoneScore(26)=0.000000 - GoneScore(27)=0.000000 - GoneScore(28)=0.000000 - GoneScore(29)=0.000000 - GoneScore(30)=0.000000 - GoneScore(31)=0.000000 - GoneDeaths(0)=0.000000 - GoneDeaths(1)=0.000000 - GoneDeaths(2)=0.000000 - GoneDeaths(3)=0.000000 - GoneDeaths(4)=0.000000 - GoneDeaths(5)=0.000000 - GoneDeaths(6)=0.000000 - GoneDeaths(7)=0.000000 - GoneDeaths(8)=0.000000 - GoneDeaths(9)=0.000000 - GoneDeaths(10)=0.000000 - GoneDeaths(11)=0.000000 - GoneDeaths(12)=0.000000 - GoneDeaths(13)=0.000000 - GoneDeaths(14)=0.000000 - GoneDeaths(15)=0.000000 - GoneDeaths(16)=0.000000 - GoneDeaths(17)=0.000000 - GoneDeaths(18)=0.000000 - GoneDeaths(19)=0.000000 - GoneDeaths(20)=0.000000 - GoneDeaths(21)=0.000000 - GoneDeaths(22)=0.000000 - GoneDeaths(23)=0.000000 - GoneDeaths(24)=0.000000 - GoneDeaths(25)=0.000000 - GoneDeaths(26)=0.000000 - GoneDeaths(27)=0.000000 - GoneDeaths(28)=0.000000 - GoneDeaths(29)=0.000000 - GoneDeaths(30)=0.000000 - GoneDeaths(31)=0.000000 - GoneStats(0)=None - GoneStats(1)=None - GoneStats(2)=None - GoneStats(3)=None - GoneStats(4)=None - GoneStats(5)=None - GoneStats(6)=None - GoneStats(7)=None - GoneStats(8)=None - GoneStats(9)=None - GoneStats(10)=None - GoneStats(11)=None - GoneStats(12)=None - GoneStats(13)=None - GoneStats(14)=None - GoneStats(15)=None - GoneStats(16)=None - GoneStats(17)=None - GoneStats(18)=None - GoneStats(19)=None - GoneStats(20)=None - GoneStats(21)=None - GoneStats(22)=None - GoneStats(23)=None - GoneStats(24)=None - GoneStats(25)=None - GoneStats(26)=None - GoneStats(27)=None - GoneStats(28)=None - GoneStats(29)=None - GoneStats(30)=None - GoneStats(31)=None - StoreName(0)="" - StoreName(1)="" - StoreName(2)="" - StoreName(3)="" - StoreName(4)="" - StoreName(5)="" - StoreName(6)="" - StoreName(7)="" - StoreName(8)="" - StoreName(9)="" - StoreName(10)="" - StoreName(11)="" - StoreName(12)="" - StoreName(13)="" - StoreName(14)="" - StoreName(15)="" - StoreName(16)="" - StoreName(17)="" - StoreName(18)="" - StoreName(19)="" - StoreName(20)="" - StoreName(21)="" - StoreName(22)="" - StoreName(23)="" - StoreName(24)="" - StoreName(25)="" - StoreName(26)="" - StoreName(27)="" - StoreName(28)="" - StoreName(29)="" - StoreName(30)="" - StoreName(31)="" - StoreScore(0)=0.000000 - StoreScore(1)=0.000000 - StoreScore(2)=0.000000 - StoreScore(3)=0.000000 - StoreScore(4)=0.000000 - StoreScore(5)=0.000000 - StoreScore(6)=0.000000 - StoreScore(7)=0.000000 - StoreScore(8)=0.000000 - StoreScore(9)=0.000000 - StoreScore(10)=0.000000 - StoreScore(11)=0.000000 - StoreScore(12)=0.000000 - StoreScore(13)=0.000000 - StoreScore(14)=0.000000 - StoreScore(15)=0.000000 - StoreScore(16)=0.000000 - StoreScore(17)=0.000000 - StoreScore(18)=0.000000 - StoreScore(19)=0.000000 - StoreScore(20)=0.000000 - StoreScore(21)=0.000000 - StoreScore(22)=0.000000 - StoreScore(23)=0.000000 - StoreScore(24)=0.000000 - StoreScore(25)=0.000000 - StoreScore(26)=0.000000 - StoreScore(27)=0.000000 - StoreScore(28)=0.000000 - StoreScore(29)=0.000000 - StoreScore(30)=0.000000 - StoreScore(31)=0.000000 - StoreDeaths(0)=0.000000 - StoreDeaths(1)=0.000000 - StoreDeaths(2)=0.000000 - StoreDeaths(3)=0.000000 - StoreDeaths(4)=0.000000 - StoreDeaths(5)=0.000000 - StoreDeaths(6)=0.000000 - StoreDeaths(7)=0.000000 - StoreDeaths(8)=0.000000 - StoreDeaths(9)=0.000000 - StoreDeaths(10)=0.000000 - StoreDeaths(11)=0.000000 - StoreDeaths(12)=0.000000 - StoreDeaths(13)=0.000000 - StoreDeaths(14)=0.000000 - StoreDeaths(15)=0.000000 - StoreDeaths(16)=0.000000 - StoreDeaths(17)=0.000000 - StoreDeaths(18)=0.000000 - StoreDeaths(19)=0.000000 - StoreDeaths(20)=0.000000 - StoreDeaths(21)=0.000000 - StoreDeaths(22)=0.000000 - StoreDeaths(23)=0.000000 - StoreDeaths(24)=0.000000 - StoreDeaths(25)=0.000000 - StoreDeaths(26)=0.000000 - StoreDeaths(27)=0.000000 - StoreDeaths(28)=0.000000 - StoreDeaths(29)=0.000000 - StoreDeaths(30)=0.000000 - StoreDeaths(31)=0.000000 - StoreIP(0)="" - StoreIP(1)="" - StoreIP(2)="" - StoreIP(3)="" - StoreIP(4)="" - StoreIP(5)="" - StoreIP(6)="" - StoreIP(7)="" - StoreIP(8)="" - StoreIP(9)="" - StoreIP(10)="" - StoreIP(11)="" - StoreIP(12)="" - StoreIP(13)="" - StoreIP(14)="" - StoreIP(15)="" - StoreIP(16)="" - StoreIP(17)="" - StoreIP(18)="" - StoreIP(19)="" - StoreIP(20)="" - StoreIP(21)="" - StoreIP(22)="" - StoreIP(23)="" - StoreIP(24)="" - StoreIP(25)="" - StoreIP(26)="" - StoreIP(27)="" - StoreIP(28)="" - StoreIP(29)="" - StoreIP(30)="" - StoreIP(31)="" - StoreStats(0)=None - StoreStats(1)=None - StoreStats(2)=None - StoreStats(3)=None - StoreStats(4)=None - StoreStats(5)=None - StoreStats(6)=None - StoreStats(7)=None - StoreStats(8)=None - StoreStats(9)=None - StoreStats(10)=None - StoreStats(11)=None - StoreStats(12)=None - StoreStats(13)=None - StoreStats(14)=None - StoreStats(15)=None - StoreStats(16)=None - StoreStats(17)=None - StoreStats(18)=None - StoreStats(19)=None - StoreStats(20)=None - StoreStats(21)=None - StoreStats(22)=None - StoreStats(23)=None - StoreStats(24)=None - StoreStats(25)=None - StoreStats(26)=None - StoreStats(27)=None - StoreStats(28)=None - StoreStats(29)=None - StoreStats(30)=None - StoreStats(31)=None - B1Name(0)="" - B1Name(1)="" - B1Name(2)="" - B1Name(3)="" - B1Name(4)="" - B1Name(5)="" - B1Name(6)="" - B1Name(7)="" - B1Name(8)="" - B1Name(9)="" - B1Name(10)="" - B1Name(11)="" - B1Name(12)="" - B1Name(13)="" - B1Name(14)="" - B1Name(15)="" - B1Name(16)="" - B1Name(17)="" - B1Name(18)="" - B1Name(19)="" - B1Name(20)="" - B1Name(21)="" - B1Name(22)="" - B1Name(23)="" - B1Name(24)="" - B1Name(25)="" - B1Name(26)="" - B1Name(27)="" - B1Name(28)="" - B1Name(29)="" - B1Name(30)="" - B1Name(31)="" - B1Score(0)=0.000000 - B1Score(1)=0.000000 - B1Score(2)=0.000000 - B1Score(3)=0.000000 - B1Score(4)=0.000000 - B1Score(5)=0.000000 - B1Score(6)=0.000000 - B1Score(7)=0.000000 - B1Score(8)=0.000000 - B1Score(9)=0.000000 - B1Score(10)=0.000000 - B1Score(11)=0.000000 - B1Score(12)=0.000000 - B1Score(13)=0.000000 - B1Score(14)=0.000000 - B1Score(15)=0.000000 - B1Score(16)=0.000000 - B1Score(17)=0.000000 - B1Score(18)=0.000000 - B1Score(19)=0.000000 - B1Score(20)=0.000000 - B1Score(21)=0.000000 - B1Score(22)=0.000000 - B1Score(23)=0.000000 - B1Score(24)=0.000000 - B1Score(25)=0.000000 - B1Score(26)=0.000000 - B1Score(27)=0.000000 - B1Score(28)=0.000000 - B1Score(29)=0.000000 - B1Score(30)=0.000000 - B1Score(31)=0.000000 - B1Deaths(0)=0.000000 - B1Deaths(1)=0.000000 - B1Deaths(2)=0.000000 - B1Deaths(3)=0.000000 - B1Deaths(4)=0.000000 - B1Deaths(5)=0.000000 - B1Deaths(6)=0.000000 - B1Deaths(7)=0.000000 - B1Deaths(8)=0.000000 - B1Deaths(9)=0.000000 - B1Deaths(10)=0.000000 - B1Deaths(11)=0.000000 - B1Deaths(12)=0.000000 - B1Deaths(13)=0.000000 - B1Deaths(14)=0.000000 - B1Deaths(15)=0.000000 - B1Deaths(16)=0.000000 - B1Deaths(17)=0.000000 - B1Deaths(18)=0.000000 - B1Deaths(19)=0.000000 - B1Deaths(20)=0.000000 - B1Deaths(21)=0.000000 - B1Deaths(22)=0.000000 - B1Deaths(23)=0.000000 - B1Deaths(24)=0.000000 - B1Deaths(25)=0.000000 - B1Deaths(26)=0.000000 - B1Deaths(27)=0.000000 - B1Deaths(28)=0.000000 - B1Deaths(29)=0.000000 - B1Deaths(30)=0.000000 - B1Deaths(31)=0.000000 - B1IP(0)="" - B1IP(1)="" - B1IP(2)="" - B1IP(3)="" - B1IP(4)="" - B1IP(5)="" - B1IP(6)="" - B1IP(7)="" - B1IP(8)="" - B1IP(9)="" - B1IP(10)="" - B1IP(11)="" - B1IP(12)="" - B1IP(13)="" - B1IP(14)="" - B1IP(15)="" - B1IP(16)="" - B1IP(17)="" - B1IP(18)="" - B1IP(19)="" - B1IP(20)="" - B1IP(21)="" - B1IP(22)="" - B1IP(23)="" - B1IP(24)="" - B1IP(25)="" - B1IP(26)="" - B1IP(27)="" - B1IP(28)="" - B1IP(29)="" - B1IP(30)="" - B1IP(31)="" - B1Stats(0)=None - B1Stats(1)=None - B1Stats(2)=None - B1Stats(3)=None - B1Stats(4)=None - B1Stats(5)=None - B1Stats(6)=None - B1Stats(7)=None - B1Stats(8)=None - B1Stats(9)=None - B1Stats(10)=None - B1Stats(11)=None - B1Stats(12)=None - B1Stats(13)=None - B1Stats(14)=None - B1Stats(15)=None - B1Stats(16)=None - B1Stats(17)=None - B1Stats(18)=None - B1Stats(19)=None - B1Stats(20)=None - B1Stats(21)=None - B1Stats(22)=None - B1Stats(23)=None - B1Stats(24)=None - B1Stats(25)=None - B1Stats(26)=None - B1Stats(27)=None - B1Stats(28)=None - B1Stats(29)=None - B1Stats(30)=None - B1Stats(31)=None - B2Name(0)="" - B2Name(1)="" - B2Name(2)="" - B2Name(3)="" - B2Name(4)="" - B2Name(5)="" - B2Name(6)="" - B2Name(7)="" - B2Name(8)="" - B2Name(9)="" - B2Name(10)="" - B2Name(11)="" - B2Name(12)="" - B2Name(13)="" - B2Name(14)="" - B2Name(15)="" - B2Name(16)="" - B2Name(17)="" - B2Name(18)="" - B2Name(19)="" - B2Name(20)="" - B2Name(21)="" - B2Name(22)="" - B2Name(23)="" - B2Name(24)="" - B2Name(25)="" - B2Name(26)="" - B2Name(27)="" - B2Name(28)="" - B2Name(29)="" - B2Name(30)="" - B2Name(31)="" - B2Score(0)=0.000000 - B2Score(1)=0.000000 - B2Score(2)=0.000000 - B2Score(3)=0.000000 - B2Score(4)=0.000000 - B2Score(5)=0.000000 - B2Score(6)=0.000000 - B2Score(7)=0.000000 - B2Score(8)=0.000000 - B2Score(9)=0.000000 - B2Score(10)=0.000000 - B2Score(11)=0.000000 - B2Score(12)=0.000000 - B2Score(13)=0.000000 - B2Score(14)=0.000000 - B2Score(15)=0.000000 - B2Score(16)=0.000000 - B2Score(17)=0.000000 - B2Score(18)=0.000000 - B2Score(19)=0.000000 - B2Score(20)=0.000000 - B2Score(21)=0.000000 - B2Score(22)=0.000000 - B2Score(23)=0.000000 - B2Score(24)=0.000000 - B2Score(25)=0.000000 - B2Score(26)=0.000000 - B2Score(27)=0.000000 - B2Score(28)=0.000000 - B2Score(29)=0.000000 - B2Score(30)=0.000000 - B2Score(31)=0.000000 - B2Deaths(0)=0.000000 - B2Deaths(1)=0.000000 - B2Deaths(2)=0.000000 - B2Deaths(3)=0.000000 - B2Deaths(4)=0.000000 - B2Deaths(5)=0.000000 - B2Deaths(6)=0.000000 - B2Deaths(7)=0.000000 - B2Deaths(8)=0.000000 - B2Deaths(9)=0.000000 - B2Deaths(10)=0.000000 - B2Deaths(11)=0.000000 - B2Deaths(12)=0.000000 - B2Deaths(13)=0.000000 - B2Deaths(14)=0.000000 - B2Deaths(15)=0.000000 - B2Deaths(16)=0.000000 - B2Deaths(17)=0.000000 - B2Deaths(18)=0.000000 - B2Deaths(19)=0.000000 - B2Deaths(20)=0.000000 - B2Deaths(21)=0.000000 - B2Deaths(22)=0.000000 - B2Deaths(23)=0.000000 - B2Deaths(24)=0.000000 - B2Deaths(25)=0.000000 - B2Deaths(26)=0.000000 - B2Deaths(27)=0.000000 - B2Deaths(28)=0.000000 - B2Deaths(29)=0.000000 - B2Deaths(30)=0.000000 - B2Deaths(31)=0.000000 - B2IP(0)="" - B2IP(1)="" - B2IP(2)="" - B2IP(3)="" - B2IP(4)="" - B2IP(5)="" - B2IP(6)="" - B2IP(7)="" - B2IP(8)="" - B2IP(9)="" - B2IP(10)="" - B2IP(11)="" - B2IP(12)="" - B2IP(13)="" - B2IP(14)="" - B2IP(15)="" - B2IP(16)="" - B2IP(17)="" - B2IP(18)="" - B2IP(19)="" - B2IP(20)="" - B2IP(21)="" - B2IP(22)="" - B2IP(23)="" - B2IP(24)="" - B2IP(25)="" - B2IP(26)="" - B2IP(27)="" - B2IP(28)="" - B2IP(29)="" - B2IP(30)="" - B2IP(31)="" - B2Stats(0)=None - B2Stats(1)=None - B2Stats(2)=None - B2Stats(3)=None - B2Stats(4)=None - B2Stats(5)=None - B2Stats(6)=None - B2Stats(7)=None - B2Stats(8)=None - B2Stats(9)=None - B2Stats(10)=None - B2Stats(11)=None - B2Stats(12)=None - B2Stats(13)=None - B2Stats(14)=None - B2Stats(15)=None - B2Stats(16)=None - B2Stats(17)=None - B2Stats(18)=None - B2Stats(19)=None - B2Stats(20)=None - B2Stats(21)=None - B2Stats(22)=None - B2Stats(23)=None - B2Stats(24)=None - B2Stats(25)=None - B2Stats(26)=None - B2Stats(27)=None - B2Stats(28)=None - B2Stats(29)=None - B2Stats(30)=None - B2Stats(31)=None - QuitMsg="" - QuitMsgLen=0 - bClientJoinPlayer=False - bGameEnded=False - bInitSb=False - LogoCounter=0 - DrawLogo=0 - SbCount=0 - SbDelayC=0.000000 - PlayerOwner=None - MyFonts=None - pTGRI=None - pPRI=None - myHUD=None - RedTeamColor=(R=255,G=0,B=0,A=0) - BlueTeamColor=(R=0,G=128,B=255,A=0) - White=(R=255,G=255,B=255,A=0) - Gray=(R=128,G=128,B=128,A=0) - bEnabled=True - bExtraStats=False - CountryFlagsPackage="CountryFlags32" - CapBonus=15 - AssistBonus=7 - FlagKillBonus=3 - CoverBonus=2 - SealBonus=3 - GrabBonus=0 - BaseReturnBonus=0.500000 - MidReturnBonus=2.000000 - EnemyBaseReturnBonus=5.000000 - CloseSaveReturnBonus=10.000000 - SpawnKillPenalty=0 - MinimalCapBonus=5 - bFixFlagBug=True - bEnhancedMultiKill=True - EnhancedMultiKillBroadcast=3 - bShowFCLocation=True - bSmartCTFServerInfo=True - bNewCapAssistScoring=True - bSpawnkillDetection=True - SpawnKillTimeArena=1.000000 - SpawnKillTimeNW=3.500000 - bAfterGodLikeMsg=True - bStatsDrawFaces=True - bDrawLogo=True - bSCTFSbDef=True - bShowSpecs=True - SpectatorColor=(R=255,G=255,B=255,A=0) - bDoKeybind=True - bExtraMsg=True - SbDelay=5.500000 - MsgDelay=7.000000 - bStoreStats=True - bSnowyScoreboard=False - bXmasImages=True - CoverMsgType=2 - CoverSpreeMsgType=3 - SealMsgType=3 - SavedMsgType=3 - DeniedMsgType=3 - bShowLongRangeMsg=False - bLongRangeSuperShock=True - bShowSpawnKillerGlobalMsg=True - bShowAssistConsoleMsg=True - bShowSealRewardConsoleMsg=True - bShowCoverRewardConsoleMsg=True - bPlayCaptureSound=True - bPlayAssistSound=True - bPlaySavedSound=True - bPlayLeadSound=True - bPlayDeniedSound=True - bPlay30SecSound=True - bPlayAirKillSound=True - bEnableOvertimeControl=False - bOverTime=True - bRememberOvertimeSetting=False - powered=None - bAlwaysRelevant=True - RemoteRole=ROLE_SimulatedProxy -} +// SmartCTF 4 by {PiN}Kev. Released January 2004. +// SmartCTF 4A Tweaked by {DnF2}SiNiSTeR. Released December 2004. +// SmartCTF 4B/4C Uber Massively tweaked by {DnF2}SiNiSTeR. Released March 2005. +// SmartCTF 4D with IpToCountry by [es]Rush. Released January 2006. +// SmartCTF 4D++ by adminthis. Released October 2008. +// SmartCTF 4E by adminthis & The_Cowboy & Sp0ngeb0b. Released December 2009. +// SmartCTF ChaChaV1 by chacha. 2023: +// - Add bLongRangeSuperShock option to allow bShowLongRangeMsg with SuperShockRifle +// - Fix compilation warnings +// SmartCTF ChaChaV2 by chacha. 2023: +// - Add Denied & AirKill Features +// SmartCTF ChaChaV3 by chacha. 2023: +// - Ajout mémorisation joueur vus par le serveur (couple Name+IP) +// - Messages de welcome et welcomback (reglable) +// - Audio de welcome (desactivable) +// - Correction Kill-In-The-air quand on tombe +// - Fix Access None sur Denied +// SmartCTF ChaChaV4 by chacha. 2023: +// - Fix Access None (TGRPI / PRI) +// - Fix Denied Message +// SmartCTF ChaChaV5 by chacha. 2023: +// - Add LudicrousKill & HolyShit Msg / Sounds +// - Fix accessed none KillInTheAir +// SmartCTF ChaChaV6 by chacha. 2023: +// - Recompile without SmartCTF_4E aside +// +// +// This mod changes the point system and adds features to ultimately promote Teamwork in CTF. +// This is a CTF Mod only. It will not load in any other gametype. +// +// Contact Info: private Message me, {PiN}Hai-Ping, on http://forums.prounreal.com +// {DnF2}SiNiSTeR @ #DutchNet [QuakeNet IRC] +// or if it is about version 4D explicictly +// Rush on unrealadmin.org forums / mail and msn: rush@u.one.pl +// or if it is about version 4D++ explicictly +// adminthis on unrealadmin.org +// +// or if it is about about version 4E +// The_Cowboy on unrealadmin.org +// Sp0ngeb0b on unrealadmin.org , or spongebobut@yahoo.com +// SnowyScoreboard added in 4E. Supported by Sp0ngeb0b. +// +// CHANGELOG: See Readme +// TO DO:Improve algorithm of storing stats +class SmartCTF expands Mutator config( SmartCTF_ChaCha ); + +#exec texture IMPORT NAME=meter FILE=Textures\meter.pcx GROUP=SmartCTF MIPS=OFF +#exec texture IMPORT NAME=shade File=Textures\shade.pcx GROUP=SmartCTF MIPS=OFF +#exec texture IMPORT NAME=powered File=Textures\powered.pcx GROUP=SmartCTF MIPS=OFF + +/* Server Vars */ +var SmartCTFGameReplicationInfo SCTFGame; +var byte RedAstIndex, BlueAstIndex; +var byte TRCount; +var string Version, GameTieMessage; +var Pawn FCs[2], RedAssisters[32], BlueAssisters[32]; +var Pawn RedFlagCarrier[32], BlueFlagCarrier[32]; +var float RedFlagCarrierTime[32], BlueFlagCarrierTime[32]; +var byte RedFCIndex, BlueFCIndex; +var float RedAssistTimes[32], BlueAssistTimes[32], PickupTime[2]; +var FlagBase FlagStands[2]; +var bool bForcedEndGame, bTournamentGameStarted, bTooCloseForSaves, bStartTimeCorrected; +var int MsgPID; +var string GoneName[32]; //list of disconnected players +var string GoneIP[32]; //corresponding IP addy +var float GoneScore[32]; //corresponding scores +var float GoneDeaths[32]; //corresponding deaths +var SmartCTFPlayerReplicationInfo GoneStats[32];//corresponding smartCTF stats +var string StoreName[32]; //list of stored playernames +var float StoreScore[32]; //corresponding scores +var float StoreDeaths[32]; //corresponding deaths +var string StoreIP[32]; //corresponding IP addy +var SmartCTFPlayerReplicationInfo StoreStats[32];//corresponding stored smartCTF stats +// First backup array +var string B1Name[32]; //list of stored playernames +var float B1Score[32]; //corresponding scores +var float B1Deaths[32]; //corresponding deaths +var string B1IP[32]; //corresponding IP addy +var SmartCTFPlayerReplicationInfo B1Stats[32];//corresponding stored smartCTF stats +// Second backup array +var string B2Name[32]; //list of stored playernames +var float B2Score[32]; //corresponding scores +var float B2Deaths[32]; //corresponding deaths +var string B2IP[32]; //corresponding IP addy +var SmartCTFPlayerReplicationInfo B2Stats[32];//corresponding stored smartCTF stats +var string QuitMsg; //the broadcast message when someone leaves the game +var int QuitMsgLen; //length of QuitMsg + +/* Client Vars */ +var bool bClientJoinPlayer, bGameEnded, bInitSb; +var int LogoCounter, DrawLogo, SbCount; +var float SbDelayC; +var PlayerPawn PlayerOwner; +var FontInfo MyFonts; +var TournamentGameReplicationInfo pTGRI; +var PlayerReplicationInfo pPRI; +var ChallengeHUD MyHUD; +var Color RedTeamColor, BlueTeamColor, White, Gray; + +/* Server Vars Configurable */ +var() config bool bEnabled; +var() config bool bExtraStats; +var() config string CountryFlagsPackage; +var(SmartCTFBonuses) config int CapBonus, AssistBonus, FlagKillBonus, CoverBonus, SealBonus, GrabBonus; +var(SmartCTFBonuses) config float BaseReturnBonus, MidReturnBonus, EnemyBaseReturnBonus, CloseSaveReturnBonus; +var(SmartCTFBonuses) config int SpawnKillPenalty, MinimalCapBonus; +var() config bool bFixFlagBug; +var() config bool bEnhancedMultiKill; +var() config byte EnhancedMultiKillBroadcast; +var() config bool bShowFCLocation; +var() config bool bSmartCTFServerInfo; +var() config bool bNewCapAssistScoring; +var() config bool bSpawnkillDetection; +var() config float SpawnKillTimeArena; +var() config float SpawnKillTimeNW; +var() config bool bAfterGodLikeMsg; +var() config bool bStatsDrawFaces; +var() config bool bDrawLogo; +var() config bool bSCTFSbDef; +var() config bool bShowSpecs; +var() config color SpectatorColor; +var() config bool bDoKeybind; +var() config bool bExtraMsg; +var() config float SbDelay; +var() config float MsgDelay; +var() config bool bStoreStats; +var() config bool bSnowyScoreboard; +var() config bool bXmasImages; +var(SmartCTFMessages) config byte CoverMsgType; +var(SmartCTFMessages) config byte CoverSpreeMsgType; +var(SmartCTFMessages) config byte SealMsgType; +var(SmartCTFMessages) config byte SavedMsgType; +var(SmartCTFMessages) config byte DeniedMsgType; +var(SmartCTFMessages) config bool bShowLongRangeMsg; +var(SmartCTFMessages) config bool bLongRangeSuperShock; +var(SmartCTFMessages) config bool bShowSpawnKillerGlobalMsg; +var(SmartCTFMessages) config bool bShowAssistConsoleMsg; +var(SmartCTFMessages) config bool bShowSealRewardConsoleMsg; +var(SmartCTFMessages) config bool bShowCoverRewardConsoleMsg; +var(SmartCTFSounds) config bool bPlayCaptureSound; +var(SmartCTFSounds) config bool bPlayAssistSound; +var(SmartCTFSounds) config bool bPlaySavedSound; +var(SmartCTFSounds) config bool bPlayLeadSound; +var(SmartCTFSounds) config bool bPlayDeniedSound; +var(SmartCTFSounds) config bool bPlay30SecSound; +var(SmartCTFSounds) config bool bPlayAirKillSound; +var(OvertimeControl) config bool bEnableOvertimeControl; +var(OvertimeControl) config bool bOvertime; +var(OvertimeControl) config bool bRememberOvertimeSetting; + +var texture powered; + +/* + * Check if we should spawn a SmartCTF instance. + * This check doesn't seem to work properly in PostBeginPlay, hence here. +*/ +event Spawned() +{ + super.Spawned(); + + SCTFGame = Level.Game.Spawn( class'SmartCTFGameReplicationInfo' ); + + if( !ValidateSmartCTFMutator() ) + { + SCTFGame.Destroy(); + Destroy(); + } +} + +/* + * Get the original Scoreboard and store for SmartCTFScoreboard reference. +*/ +function PreBeginPlay() +{ + local Mutator M; + + super.PreBeginPlay(); + SCTFGame.NormalScoreBoardClass = Level.Game.ScoreBoardType; + if (bSnowyScoreboard) + { + level.game.scoreBoardType = class'SmartCTFSnowyScoreboard'; + } + else + { + Level.Game.ScoreBoardType = class'SmartCTFScoreBoard'; + } + //Level.Game.default.ScoreBoardType = class'SmartCTFScoreBoard'; + // The above line was fatal in version 4B :E + + Log( "Original Scoreboard determined as" @ SCTFGame.NormalScoreBoardClass, 'SmartCTF' ); + + // Change F2 Server Info screen, compatible with UTPure + if( bSmartCTFServerInfo ) + { + class( Level.Game.HUDType ).default.ServerInfoClass = class'SmartCTFServerInfo'; + for( M = Level.Game.BaseMutator; M != None; M = M.NextMutator ) + { + if( M.IsA( 'UTPure' ) ) // Let UTPure rehandle the scoreboard + { + M.PreBeginPlay(); + SCTFGame.bServerInfoSetServerSide = True; // No need for the old fashioned way - it can be set server side. + Log( "Notified UTPure HUD to use SmartCTF ServerInfo.", 'SmartCTF' ); + break; + } + } + if( SCTFGame.bServerInfoSetServerSide && Level.Game.HUDType.Name != 'PureCTFHUD' ) + { + // In this scenario another mod intervered and we still have to do it the old fashion way. + SCTFGame.bServerInfoSetServerSide = False; + Log( "HUD is not the UTPure HUD but" @ Level.Game.HUDType.Name $ ", so SmartCTF ServerInfo will be set clientside.", 'SmartCTF' ); + } + if( !SCTFGame.bServerInfoSetServerSide ) + { + SCTFGame.DefaultHUDType = Level.Game.HUDType; // And in the old fashion way, the client will have to know the current HUD type. + } + } + else + { + SCTFGame.bServerInfoSetServerSide = True; // We didn't change anything, but neither do we want clientside intervention. + } +} + +/* + * Startup and initialize. +*/ +function PostBeginPlay() +{ + local FlagBase fb; + + Level.Game.Spawn( class'SmartCTFSpawnNotifyPRI'); + SCTFGame.WelcomeNewPlayers = Spawn( class'SmartCTFWelcomeNewPlayers'); + SCTFGame.WelcomeNewPlayers.SaveConfig(); + + SaveConfig(); // Create the .ini if its not already there. + + //Register as a message mutator, as we'll be using message monitoring + //to perform some of our code. If not registered, then many message + //events will not be passed to our mutator. + Level.Game.RegisterMessageMutator( self ); + + // Since we have problem replicating config variables... + SCTFGame.bShowFCLocation = bShowFCLocation; + SCTFGame.bPlay30SecSound = bPlay30SecSound; + SCTFGame.bStatsDrawFaces = bStatsDrawFaces; + SCTFGame.bDrawLogo = bDrawLogo; + SCTFGame.bExtraStats = bExtraStats; + SCTFGame.CountryFlagsPackage = CountryFlagsPackage; + SCTFGame.bSCTFSbDef = bSCTFSbDef; + SCTFGame.bShowSpecs = bShowSpecs; + SCTFGame.bDoKeybind = bDoKeybind; + SCTFGame.SbDelayC = SbDelayC; + SCTFGame.SpectatorColor = SpectatorColor; + SCTFGame.bSnowyScoreboard = bSnowyScoreboard; + SCTFGame.bXmasImages = bXmasImages; + + if( !bRememberOvertimeSetting ) + { + bOvertime = True; + } + + // Works serverside! + if( bEnhancedMultiKill ) + { + Level.Game.DeathMessageClass = class'SmartCTFEnhancedDeathMessagePlus'; + } + + // Get the Flag bases + ForEach AllActors( class'FlagBase', fb ) + { + FlagStands[ fb.Team ] = fb; + } + + if( VSize( FlagStands[0].Location - FlagStands[1].Location ) < 1.5 * 900 ) + { + bTooCloseForSaves = True; + } + + SCTFGame.EndStats = Spawn( class'SmartCTFEndStats', self ); + + super.PostBeginPlay(); + + if( Level.NetMode == NM_DedicatedServer ) + { + SetTimer( 1.0 , True); + } + + MsgPID=-1; // First PID is 0, so it wouldn't get messaged if we kept MsgPID at it's default value. + + if(bStoreStats == True) + { + //Register as a damage mutator, as we'll be using damage checks to + //update the stored information (new in v3.2). + Level.Game.RegisterDamageMutator(self); + + //Grab some basic info about the player left message. + QuitMsg=Level.Game.LeftMessage; + QuitMsgLen=Len(QuitMsg); + + } + Log( "SmartCTF" @ Version @ "loaded successfully.", 'SmartCTF' ); +} + +/* + * Returns True or False whether to keep this SmartCTF mutator instance, and sets bInitialized accordingly. +*/ +function bool ValidateSmartCTFMutator() +{ + local Mutator M; + local bool bRunning; + + M = Level.Game.BaseMutator; + while( M != None ) + { + if( M != Self && M.Class == Self.Class ) + { + bRunning = True; + break; + } + M = M.NextMutator; + } + + if( !bEnabled ) + { + Log( "Instance" @ Name @ "not loaded because bEnabled in .ini = False.", 'SmartCTF' ); + } + else if( CTFGame( Level.Game ) == None ) + { + Log( "Instance" @ Name @ "not loaded because gamestyle is not CTF.", 'SmartCTF' ); + } + else if( bRunning ) + { + Log( "Instance" @ Name @ "not loaded because it is already running.", 'SmartCTF' ); + } + else + { + SCTFGame.bInitialized = True; + } + + return SCTFGame.bInitialized; +} + + +/* + * For the flag bug each player gets a FlagChecker inventory on spawn. +*/ +function ModifyPlayer( Pawn Other ) +{ + local Inventory Inv; + local SmartCTFPlayerReplicationInfo OtherStats; + local string IP; + local int j,i; + local bool bIsFirstSpawn; + + + if( Other.bIsPlayer && !Other.IsA('Bot') && !( Other.PlayerReplicationInfo.bIsSpectator && !Other.PlayerReplicationInfo.bWaitingPlayer ) ) + { + // little hacky method to know if its 1st spawn or not + bIsFirstSpawn = Other.PlayerReplicationInfo.Deaths < 1; + SCTFGame.WelcomeNewPlayers.CheckPawn(Other,bIsFirstSpawn); + if( bFixFlagBug) + { + Inv = Spawn( class'SmartCTFFlagCheckerInventory' , Other ); + if( Inv != None ) + { + Inv.GiveTo( Other ); + } + } + } + + SCTFGame.RefreshPRI(); + OtherStats = SCTFGame.GetStats( Other ); + if( OtherStats!=none && + bStoreStats && + !Level.Game.bGameEnded && + Other!=none && + Other.bIsPlayer && + !Other.IsA('Spectator') && + !Other.IsA('Bot') && + Other.PlayerReplicationInfo!=none && + Other.PlayerReplicationInfo.PlayerName!="Player" ) + { + IP=PlayerPawn(Other).GetPlayerNetworkAddress(); + j=InStr(IP,":"); + if( j!=-1 ) + { + IP=Left(IP,j); + } + + for(i=0; i<32 && GoneName[i]!=""; i++) + { + if( Other.PlayerReplicationInfo.PlayerName~=GoneName[i] || (IP==GoneIP[i] && IP!="") ) + { + Log(" ## SmartCTF - Caught player by name or IP "$Other.PlayerReplicationInfo.PlayerName$"@"$IP); + Log(" ## SmartCTF is restoring stats for " $Other.PlayerReplicationInfo.PlayerName$"@"$IP); + if(GoneStats[i]!= none) + { + FirstSpawn( Other ); + OtherStats.Captures=GoneStats[i].Captures; + OtherStats.Frags=GoneStats[i].Frags; + OtherStats.Grabs=GoneStats[i].Grabs; + OtherStats.Covers=GoneStats[i].Covers; + OtherStats.Assists=GoneStats[i].Assists; + OtherStats.Seals=GoneStats[i].Seals; + OtherStats.FlagKills=GoneStats[i].FlagKills; + OtherStats.DefKills=GoneStats[i].DefKills; + OtherStats.HeadShots=GoneStats[i].HeadShots; + OtherStats.ShieldBelts=GoneStats[i].ShieldBelts; + OtherStats.Amps=GoneStats[i].Amps; + OtherStats.LastKillTime=GoneStats[i].LastKillTime; + OtherStats.MultiLevel=GoneStats[i].MultiLevel; + OtherStats.FragSpree=GoneStats[i].FragSpree; + OtherStats.CoverSpree=GoneStats[i].CoverSpree; + OtherStats.SealSpree=GoneStats[i].SealSpree; + OtherStats.SpawnKillSpree=GoneStats[i].SpawnKillSpree; + OtherStats.bHadFirstSpawn =True; + } + Other.PlayerReplicationInfo.Score=GoneScore[i]; + Other.PlayerReplicationInfo.Deaths=GoneDeaths[i]; + CleanGone(i); + Log(" ## Stats are restored"); + break; + } + } + } + + + + if( !OtherStats.bHadFirstSpawn ) + { + OtherStats.bHadFirstSpawn = True; + FirstSpawn( Other ); + } + + OtherStats.SpawnTime = Level.TimeSeconds; + + super.ModifyPlayer( Other ); + if(bStoreStats) + { + UpdateInfo(); + } + +} + +/* + * Gets called when a new player or bot joins the game, that is when they first spawn. +*/ +function FirstSpawn( Pawn Other ) +{ + local byte ID; + local string SkinName, FaceName; + + // Additional logging, useful for player tracking + if( Level.Game.LocalLog != None && PlayerPawn( Other ) != None && Other.bIsPlayer ) + { + ID = PlayerPawn( Other ).PlayerReplicationInfo.PlayerID; + Level.Game.LocalLog.LogSpecialEvent( "IP", ID, PlayerPawn( Other ).GetPlayerNetworkAddress() ); + Level.Game.LocalLog.LogSpecialEvent( "player", "NetSpeed", ID, PlayerPawn( Other ).Player.CurrentNetSpeed ); + Level.Game.LocalLog.LogSpecialEvent( "player", "Fov", ID, PlayerPawn( Other ).FovAngle ); + Level.Game.LocalLog.LogSpecialEvent( "player", "VoiceType", ID, Other.VoiceType ); + if( Other.IsA( 'TournamentPlayer' ) ) + { + if( Other.Skin == None ) + { + Other.static.GetMultiSkin( Other, SkinName, FaceName ); + } + else + { + SkinName = string( Other.Skin ); + FaceName = "None"; + } + Level.Game.LocalLog.LogSpecialEvent( "player", "Skin", ID, SkinName ); + Level.Game.LocalLog.LogSpecialEvent( "player", "Face", ID, FaceName ); + } + } +} + +/* + *Use this function to clean out entries from the gone arrays when a player + *reenters and is caught by SmartCTF +*/ +function CleanGone( int R) +{ + + local int i; + + for(i=R;i<32;i++) + { If(GoneStats[i]!=none) + { + + if(i==31) + { + GoneName[i]=""; + GoneScore[i]=0; + GoneDeaths[i]=0; + GoneIP[i]=""; + GoneStats[i].ClearStats(); + break; + } + + GoneName[i]=GoneName[i+1]; + GoneScore[i]=GoneScore[i+1]; + GoneDeaths[i]=GoneDeaths[i+1]; + GoneIP[i]=GoneIP[i+1]; + GoneStats[i]=GoneStats[i+1]; + } + } + + +} + +function bool MutatorBroadcastMessage( Actor Sender, Pawn Receiver, out coerce string Msg, optional bool bBeep, out optional name Type ) +{ + local string quitter; + local int i,j; + local bool matched; + + if(bStoreStats) + { + //Thanks to the WebChatLog mutator for the Reciever.NextPawn==none check + if(Receiver != none && Receiver.NextPawn == none && !Level.Game.bGameEnded) // prevent duplicate messages + { + if(Right(Msg,QuitMsgLen)==QuitMsg) + { + quitter=left(Msg,Len(Msg)-QuitMsgLen); //strips out the playername + + for(i=0; i<32 && StoreName[i]!=""; i++) + { + if(StoreName[i]~=quitter) + { + matched=true; //found our player match + + for(j=0; j<32; j++) + { + if(GoneName[j]=="") + { + GoneName[j]=StoreName[i]; + GoneScore[j]=StoreScore[i]; + GoneDeaths[j]=StoreDeaths[i]; + GoneIP[j]=StoreIP[i]; + GoneStats[j]=StoreStats[i]; + break; + } + + if(j==31) + { + log(" ## SmartCtf - Gone Array is full"); + break; + } + } + + break; + } + } + + //if the player wasn't caught in the main store array, check backup 1 + if(!matched) + { + for(i=0; i<32 && B1Name[i]!=""; i++) + { + if(B1Name[i]~=quitter) + { + matched=true; //found our player match + + for(j=0; j<32; j++) + { + if(GoneName[j]=="") + { + GoneName[j]=B1Name[i]; + GoneScore[j]=B1Score[i]; + GoneDeaths[j]=B1Deaths[i]; + GoneIP[j]=B1IP[i]; + GoneStats[j]=B1Stats[i]; + break; + } + + if(j==31) + { + log(" ## SmartCtf - Gone Array is full"); + break; + } + } + + break; + } + } + } + + //if the player wasn't caught in the backup 1 array, check backup 2 + if(!matched) + { + for(i=0; i<32 && B2Name[i]!=""; i++) + { + if(B2Name[i]~=quitter) + { + for(j=0; j<32; j++) + { + if(GoneName[j]=="") + { + GoneName[j]=B2Name[i]; + GoneScore[j]=B2Score[i]; + GoneDeaths[j]=B2Deaths[i]; + GoneIP[j]=B2IP[i]; + GoneStats[j]=B2Stats[i]; + break; + } + + if(j==31) + { + log(" ## SmartCtf - Gone Array is full"); + break; + } + } + + break; + } + } + } + } + } + } + + if( NextMessageMutator != none ) + { + //If there are other mutators monitoring messages, make sure we ask them + //whether to allow the message to be broadcast (i.e. return their value). + return NextMessageMutator.MutatorBroadcastMessage( Sender, Receiver, Msg, bBeep, Type ); + } + + //Else, we'll return true (true will allow the message to be broadcast). + return true; +} + +/* + *Just another event to use as an update point for our store array (the more + *update events, the more up to date the store array will be). +*/ +function ScoreKill(pawn Killer, pawn Other) +{ + super.ScoreKill(Killer, Other); + + if(bStoreStats) + { + UpdateInfo(); + } +} + +/* + *Just another event to use as an update point for our store array (the more + *update events, the more up to date the store array will be). +*/ +function MutatorTakeDamage( out int ActualDamage, Pawn Victim, Pawn InstigatedBy, out Vector HitLocation, out Vector Momentum, name DamageType) +{ + super.MutatorTakeDamage(ActualDamage,Victim,InstigatedBy,HitLocation,Momentum,DamageType); + if(bStoreStats) + { + UpdateInfo(); + } + +} + + +function UpdateInfo() +{ + local int i,j,k; + local string IP; + local Pawn P; + local SmartCTFPlayerReplicationInfo PI; + + //clear the previous name values, so we don't double register any players + for(k=0; k<32; k++) + { + StoreName[k]=""; + } + + for(P=Level.PawnList; P!=none; P=P.nextPawn) + { + if( PlayerPawn(P)!=none && + P.bIsPlayer && + !P.IsA('Spectator') && + !P.IsA('Bot') && + P.PlayerReplicationInfo!=none && + P.PlayerReplicationInfo.PlayerName!="Player" && + (P.PlayerReplicationInfo.Score!=0 || P.PlayerReplicationInfo.Deaths!=0) ) + { + IP=PlayerPawn(P).GetPlayerNetworkAddress(); + if( IP!="" ) + { + j=InStr(IP,":"); + if( j!=-1 ) + IP=Left(IP,j); + } + StoreName[i]=P.PlayerReplicationInfo.PlayerName; + StoreScore[i]=P.PlayerReplicationInfo.Score; + StoreDeaths[i]=P.PlayerReplicationInfo.Deaths; + StoreIP[i]=IP; + PI = SCTFGame.GetStats( P ); + If(PI!= none) + StoreStats[i]=PI; + i++; + } + } + +} + +/* + * Gets called once when the Countdown before a Tournament game starts. +*/ +function TournamentGameStarted() +{ + // Fix warmup mode bug + Overtime functionality + ClearStats(); + if( bEnableOvertimeControl ) + { + if( !bOvertime ) + { + BroadcastLocalizedMessage( class'SmartCTFCoolMsg', 4 ); + } + else + { + BroadcastLocalizedMessage( class'SmartCTFCoolMsg', 3 ); + } + } +} + +/* + * Check for covers and seals, and adjust scores. +*/ +function bool PreventDeath( Pawn Victim, Pawn Killer, name DamageType, vector HitLocation ) +{ + local PlayerReplicationInfo VictimPRI, KillerPRI; + local bool bPrevent, bVictimTeamHasFlag, bWarmupSkip; + local Pawn pn; + local float TimeAwake; + local SmartCTFPlayerReplicationInfo KillerStats, VictimStats; + + bPrevent = super.PreventDeath( Victim, Killer, DamageType, HitLocation ); + if( bPrevent ) + { + return bPrevent; // Player didn't die, so return + } + + // If there is no victim, return. + if( Victim == None ) + { + return bPrevent; + } + + VictimPRI = Victim.PlayerReplicationInfo; + if( VictimPRI == None || !Victim.bIsPlayer || ( VictimPRI.bIsSpectator && !VictimPRI.bWaitingPlayer ) ) + { + return bPrevent; + } + + VictimStats = SCTFGame.GetStats( Victim ); + + // airkill handling + if(bPlayAirKillSound && (Victim!=Killer) && (Killer!=None)) + { + if(Victim.Physics == PHYS_Falling && Killer.Physics == PHYS_Falling) + { + if(Victim.bIsPlayer && Victim.IsA('PlayerPawn')) + { + Victim.ReceiveLocalizedMessage( class'SmartCTFAudioMsg', 6); + Victim.ReceiveLocalizedMessage( class'SmartCTFCoolMsg', 7); + } + if(Killer.bIsPlayer && Killer.IsA('PlayerPawn')) + { + Killer.ReceiveLocalizedMessage( class'SmartCTFAudioMsg', 6); + Killer.ReceiveLocalizedMessage( class'SmartCTFCoolMsg', 6); + } + } + } + + if( VictimStats != None ) + { + VictimStats.FragSpree = 0; // Reset FragSpree for Victim + VictimStats.SpawnKillSpree = 0; + } + + // If there is no killer / suicide, return. + if( Killer == None || Killer == Victim ) + { + if( bEnhancedMultiKill && EnhancedMultiKillBroadcast > 0 ) + { + VictimStats.MultiLevel = 0; + } + return bPrevent; + } + + KillerPRI = Killer.PlayerReplicationInfo; + if( KillerPRI == None || !Killer.bIsPlayer || ( KillerPRI.bIsSpectator && !KillerPRI.bWaitingPlayer ) ) + { + return bPrevent; + } + + KillerStats = SCTFGame.GetStats( Killer ); + // Same Team! We don't count those stats like that in SmartCTF. + if( VictimPRI.Team == KillerPRI.Team ) + { + return bPrevent; + } + + // Increase Frags and FragSpree for Killer (Play "Too Easy" at 30) + if( KillerStats != None ) + { + KillerStats.Frags++; + KillerStats.FragSpree++; + } + + if( bEnhancedMultiKill && EnhancedMultiKillBroadcast > 0 ) + { + VictimStats.MultiLevel = 0; + if( Level.TimeSeconds - KillerStats.LastKillTime < 3 ) + { + KillerStats.MultiLevel++; + if( KillerStats.MultiLevel + 1 >= EnhancedMultiKillBroadcast ) + { + Level.Game.BroadcastMessage( KillerPRI.PlayerName @ class'SmartCTFEnhancedMultiKillMessage'.static.GetBroadcastString( KillerStats.MultiLevel ) ); + } + } + else + { + KillerStats.MultiLevel = 0; + } + KillerStats.LastKillTime = Level.TimeSeconds; + } + + bWarmupSkip = DeathMatchPlus( Level.Game ).bTournament && !bTournamentGameStarted; + + if( !bWarmupSkip ) + { + + // For Flag Kill, inc player's FlagKills and total + if( VictimPRI.HasFlag != None ) + { + + if( KillerStats != None ) + { + KillerStats.FlagKills++; + } + KillerPRI.Score += FlagKillBonus; + + // Already logged by UTStats serveractor. Dont want to do it twice. + //if( Level.Game.LocalLog != None ) Level.Game.LocalLog.LogSpecialEvent( "flag_kill", KillerPRI.PlayerID, VictimPRI.PlayerID, VictimPRI.Team ); + + // Handling Denied + if( VSize( Victim.Location - FlagStands[VictimPRI.Team].Location ) < 768 ) + { + if( DeniedMsgType == 1 && PlayerPawn( Killer ) != None ) + { + Killer.ClientMessage( class'SmartCTFMessage'.static.GetString( 11 + 64, KillerPRI, VictimPRI ) ); + } + else if( DeniedMsgType == 2 ) + { + BroadcastMessage( class'SmartCTFMessage'.static.GetString( 11, KillerPRI, VictimPRI ) ); + } + else if( DeniedMsgType == 3 ) + { + BroadcastLocalizedMessage( class'SmartCTFMessage', 11, KillerPRI, VictimPRI ); + } + + for( pn = Level.PawnList; pn != None; pn = pn.NextPawn ) + { + if( PlayerPawn( pn ) != None && pn.bIsPlayer ) + { + if(bPlayDeniedSound) + { + PlayerPawn( pn ).ReceiveLocalizedMessage( class'SmartCTFAudioMsg', 5 ); + } + } + } + } + } + else + { + // If Killer has Flag, no cover or seal for him + if( KillerPRI.HasFlag == None && FCs[KillerPRI.Team] != None && FCs[KillerPRI.Team].PlayerReplicationInfo.HasFlag != None ) + { + // COVER FRAG / SEAL BASE + // If Killer's Team has had an FC + + // If the FC has Flag Right now + // Defend kill + // org: If victim can see the FC or is within 600 unreal units (approx 40 feet) and has a line of sight to fc. + //if( Victim.canSee( FCs[KillerPRI.Team] ) || ( Victim.lineOfSightTo( FCs[KillerPRI.Team] ) && Distance( Victim.Location, FCs[KillerPRI.Team].Location ) < 600 ) ) + // new: victim within 512 uu of FC + // or killer within 512 uu of FC + // or victim can see FC and was Victim within 1536 uu of FC + // or killer can see FC and Victim victim within 1024 uu of FC + // or victim has direct line to FC and was Victim within 768 uu + if( ( VSize( Victim.Location - FCs[KillerPRI.Team].Location ) < 512 ) + || ( VSize( Killer.Location - FCs[KillerPRI.Team].Location ) < 512 ) + || ( VSize( Victim.Location - FCs[KillerPRI.Team].Location ) < 1536 && Victim.canSee( FCs[KillerPRI.Team] ) ) + || ( VSize( Victim.Location - FCs[KillerPRI.Team].Location ) < 1024 && Killer.canSee( FCs[KillerPRI.Team] ) ) + || ( VSize( Victim.Location - FCs[KillerPRI.Team].Location ) < 768 && Victim.lineOfSightTo( FCs[KillerPRI.Team] ) ) ) + { + // Killer DEFENDED THE Flag CARRIER + if( KillerStats != None ) + { + KillerStats.Covers++; + KillerStats.CoverSpree++; // Increment Cover spree + } + KillerPRI.Score += CoverBonus; // Reward points + + // Log cover + if( Level.Game.LocalLog != None ) + { + Level.Game.LocalLog.LogSpecialEvent( "flag_cover", KillerPRI.PlayerID, VictimPRI.PlayerID, KillerPRI.Team ); + } + + // Cover sprees + if( KillerStats != None ) + { + if( KillerStats.CoverSpree == 3 ) // Cover x 3 + { + if( CoverSpreeMsgType == 1 && PlayerPawn( Killer ) != None ) + { + Killer.ClientMessage( class'SmartCTFMessage'.static.GetString( 4 + 64, KillerPRI, VictimPRI ) ); + } + else if( CoverSpreeMsgType == 2 ) + { + BroadcastMessage( class'SmartCTFMessage'.static.GetString( 4, KillerPRI, VictimPRI ) ); + } + else if( CoverSpreeMsgType == 3 ) + { + BroadcastLocalizedMessage( class'SmartCTFMessage', 4, KillerPRI, VictimPRI ); + } + } + else if( KillerStats.CoverSpree == 4 ) // Cover x 4 + { + if( CoverSpreeMsgType == 1 && PlayerPawn( Killer ) != None ) + { + Killer.ClientMessage( class'SmartCTFMessage'.static.GetString( 5 + 64, KillerPRI, VictimPRI ) ); + } + else if( CoverSpreeMsgType == 2 ) + { + BroadcastMessage( class'SmartCTFMessage'.static.GetString( 5, KillerPRI, VictimPRI ) ); + } + else if( CoverSpreeMsgType == 3 ) + { + BroadcastLocalizedMessage( class'SmartCTFMessage', 5, KillerPRI, VictimPRI ); + } + } + else // // Covered FC + { + if( CoverMsgType == 1 && PlayerPawn( Killer ) != None ) + { + Killer.ClientMessage( class'SmartCTFMessage'.static.GetString( 0 + 64, KillerPRI, VictimPRI ) ); + } + else if( CoverMsgType == 2 ) + { + BroadcastMessage( class'SmartCTFMessage'.static.GetString( 0, KillerPRI, VictimPRI ) ); + } + else if( CoverMsgType == 3 ) + { + BroadcastLocalizedMessage( class'SmartCTFMessage', 0, KillerPRI, VictimPRI ); + } + } + } + } + + // Defense kill + // If the map has player zones + bVictimTeamHasFlag = True; + if( FCs[VictimPRI.Team] == None ) + { + bVictimTeamHasFlag = False; + } + + if( FCs[VictimPRI.Team] != None && FCs[VictimPRI.Team].PlayerReplicationInfo.HasFlag == None ) + { + bVictimTeamHasFlag = False; + } + + // If Victim's FC has not been set / If Victim's FC doesn't have our Flag + if( !bVictimTeamHasFlag ) + { + // If Killer is Red & he and his FC's Location has Red + if( IsInZone( VictimPRI, KillerPRI.Team ) && IsInZone( FCs[KillerPRI.Team].PlayerReplicationInfo, KillerPRI.Team ) ) + { + // Killer SEALED THE BASE + if( KillerStats != None ) + { + KillerStats.Seals++; + KillerStats.SealSpree++; + if(CTFReplicationInfo( Level.Game.GameReplicationInfo ).FlagList[KillerPRI.Team].bHome) // only if flag is at home + { + KillerStats.DefKills++; // seal is also a defkill + } + } + KillerPRI.Score += SealBonus; + if( SealMsgType != 0 && KillerStats != None && KillerStats.SealSpree == 2 ) // Sealing base + { + if( SealMsgType == 1 && PlayerPawn( Killer ) != None ) + { + Killer.ClientMessage( class'SmartCTFMessage'.static.GetString( 1 + 64, KillerPRI, VictimPRI ) ); + } + else if( SealMsgType == 2 ) + { + BroadcastMessage( class'SmartCTFMessage'.static.GetString( 1, KillerPRI, VictimPRI ) ); + } + else if( SealMsgType == 3 ) + { + BroadcastLocalizedMessage( class'SmartCTFMessage', 1, KillerPRI, VictimPRI ); + } + } + // Log seal + if( Level.Game.LocalLog != None ) + { + Level.Game.LocalLog.LogSpecialEvent( "flag_seal", KillerPRI.PlayerID, VictimPRI.PlayerID, KillerPRI.Team ); // Log to ngLog; + } + } + } + } + else // our team don't have a flag + { + bVictimTeamHasFlag = True; + if( FCs[VictimPRI.Team] == None ) + { + bVictimTeamHasFlag = False; + } + if( FCs[VictimPRI.Team] != None && FCs[VictimPRI.Team].PlayerReplicationInfo.HasFlag == None ) + { + bVictimTeamHasFlag = False; + } + // Defense kill + // If the map has player zones + if( VictimPRI.PlayerZone != None ) + { + if( IsInZone( VictimPRI, KillerPRI.Team ) && !bVictimTeamHasFlag && CTFReplicationInfo( Level.Game.GameReplicationInfo ).FlagList[KillerPRI.Team].bHome) + { + if( KillerStats != None ) + { + KillerStats.DefKills++; + } + } + } + } + } + } + + if( bAfterGodLikeMsg && KillerStats != None && ( KillerStats.FragSpree == 30 || KillerStats.FragSpree == 35 ) ) + { + for( pn = Level.PawnList; pn != None; pn = pn.NextPawn ) + { + if( pn.IsA( 'TournamentPlayer' ) ) + { + pn.ReceiveLocalizedMessage( class'SmartCTFSpreeMsg', KillerStats.FragSpree / 5 - 1, KillerPRI ); + } + } + } + + // Uber / Long Range kill if not sniper, HeadShot, trans, deemer, instarifle, or vengeance relic. + if( bShowLongRangeMsg && TournamentPlayer( Killer ) != None ) + { + if( DamageType != 'shot' && + DamageType != 'decapitated' && + DamageType != 'Eradicated' && + DamageType != 'Gibbed' && + DamageType != 'RedeemerDeath' && + (SuperShockRifle( Killer.Weapon ) == None || bLongRangeSuperShock)) + { + if( VSize( Killer.Location - Victim.Location ) > 1536 ) + { + if( VSize( Killer.Location - Victim.Location ) > 3072 ) + { + Killer.ReceiveLocalizedMessage( class'SmartCTFCoolMsg', 2, KillerPRI, VictimPRI ); + } + else + { + Killer.ReceiveLocalizedMessage( class'SmartCTFCoolMsg', 1, KillerPRI, VictimPRI ); + } + // Log special kill. + if( Level.Game.LocalLog != None ) + { + Level.Game.LocalLog.LogSpecialEvent( "longrangekill", KillerPRI.PlayerID, VictimPRI.PlayerID ); + } + } + } + } + + // HeadShot tracking + if( DamageType == 'decapitated' && KillerStats != None ) + { + KillerStats.HeadShots++; + } + + // Spawnkill detection + if( bSpawnkillDetection && DamageType != 'Gibbed' && VictimStats != None ) // No telefrags + { + TimeAwake = Level.TimeSeconds - VictimStats.SpawnTime; + if( Level.Game.BaseMutator.MutatedDefaultWeapon() != class'Botpack.ImpactHammer' ) + { // Arena mutator used, spawnkilling must be extreme to count + if( TimeAwake <= SpawnKillTimeArena ) + { + Killer.ReceiveLocalizedMessage( class'SmartCTFCoolMsg', 5, KillerPRI, VictimPRI ); + KillerPRI.Score -= SpawnKillPenalty; + if( KillerStats != None ) + { + KillerStats.SpawnKillSpree++; + } + if( Level.Game.LocalLog != None ) + { + Level.Game.LocalLog.LogSpecialEvent( "spawnkill", KillerPRI.PlayerID, VictimPRI.PlayerID, SpawnKillPenalty ); + } + if( bShowSpawnKillerGlobalMsg && KillerStats != None && KillerStats.SpawnKillSpree > 2 ) + { + BroadcastLocalizedMessage( class'SmartCTFMessage', 10, KillerPRI, VictimPRI ); + } + } + } + else // No arena mutator + { + if( TimeAwake < SpawnKillTimeNW ) + { + Killer.ReceiveLocalizedMessage( class'SmartCTFCoolMsg', 5, KillerPRI, VictimPRI ); + KillerPRI.Score -= SpawnKillPenalty; + if( KillerStats != None ) + { + KillerStats.SpawnKillSpree++; + } + if( Level.Game.LocalLog != None ) + { + Level.Game.LocalLog.LogSpecialEvent( "spawnkill", KillerPRI.PlayerID, VictimPRI.PlayerID, SpawnKillPenalty ); + } + if( bShowSpawnKillerGlobalMsg && KillerStats != None && KillerStats.SpawnKillSpree > 2 ) + { + BroadcastLocalizedMessage( class'SmartCTFMessage', 10, KillerPRI, VictimPRI ); + } + } + } + } + if(bStoreStats) + { + UpdateInfo(); + } + return bPrevent; +} + +/* + * ShieldBelt + Damage Amp tracking, spawnkill detection. +*/ +function bool HandlePickupQuery( Pawn Other, Inventory Item, out byte bAllowPickup ) +{ + local SmartCTFPlayerReplicationInfo OtherStats; + + OtherStats = SCTFGame.GetStats( Other ); + + if( Item.IsA( 'UT_ShieldBelt' ) && OtherStats != None ) + { + OtherStats.ShieldBelts++; + } + if( Item.IsA( 'UDamage' ) && OtherStats != None ) + { + OtherStats.Amps++; + } + + // For spawnkill detection + if( bSpawnkillDetection && OtherStats != None && OtherStats.SpawnTime != 0 ) + { + if( Item.IsA( 'TournamentWeapon' ) || Item.IsA( 'UT_ShieldBelt' ) || Item.IsA( 'UDamage' ) || Item.IsA( 'HealthPack' ) || Item.IsA( 'UT_Invisibility' ) ) + { + // This player has picked up a certain item making a kill on him no longer be qualified as a spawnkill. + OtherStats.SpawnTime = 0; + } + } + + return super.HandlePickupQuery( Other, Item, bAllowPickup ); +} + +/* + * Proper check if a player is in a location with 'red' or 'blue' in the name. +*/ +function bool IsInZone( PlayerReplicationInfo PRI, byte Team ) +{ + local string Loc; + + if( PRI.PlayerLocation != None ) + { + Loc = PRI.PlayerLocation.LocationName; + } + else if( PRI.PlayerZone != None ) + { + Loc = PRI.PlayerZone.ZoneName; + } + else + { + return False; + } + + if( Team == 0 ) + { + return ( Instr( Caps( Loc ), "RED" ) != -1 ); + } + else + { + return ( Instr( Caps( Loc ), "BLUE" ) != -1 ); + } +} + +/* + * Add a player to the Red FC/assister list. +*/ +function AddRedFlagCarrier( Pawn Aster, float Fct ) +{ + local byte i; + + if( Aster == None || !Aster.bIsPlayer || ( Aster.PlayerReplicationInfo.bIsSpectator && !Aster.PlayerReplicationInfo.bWaitingPlayer ) ) + { + return; + } + if( RedFCIndex >= 32 ) + { + RedFCIndex = 0; + } + + // Check if already in list + for( i = 0; i < 32; i++ ) + { + if( Aster == RedFlagCarrier[i] ) + { + RedFlagCarrierTime[i] += Fct; + return; + } + } + + RedFlagCarrier[RedFCIndex] = Aster; + RedFlagCarrierTime[RedFCIndex] = Fct; + RedFCIndex++; +} + +function AddBlueFlagCarrier( Pawn Aster, float Fct ) +{ + local byte i; + + if( Aster == None || !Aster.bIsPlayer || ( Aster.PlayerReplicationInfo.bIsSpectator && !Aster.PlayerReplicationInfo.bWaitingPlayer ) ) + { + return; + } + if( BlueFCIndex >= 32 ) + { + BlueFCIndex = 0; + } + + for( i = 0; i < 32; i++ ) + { + if( Aster == BlueFlagCarrier[i] ) + { + BlueFlagCarrierTime[i] += Fct; + return; + } + } + + BlueFlagCarrier[BlueFCIndex] = Aster; + BlueFlagCarrierTime[BlueFCIndex] = Fct; + BlueFCIndex++; +} + + +/* + * Walk through Red assisters/FC and reward them with points because of a cap. +*/ +function RewardRedFlagCarriers( bool bNotPlayedLead ) +{ + local byte j; + local SmartCTFPlayerReplicationInfo AssisterStats; + local int Bonus; + local float TotalTime, f; + + Bonus = AssistBonus; + + // Calculate the total flag carrying time + for( j = 0; j < 32; j++ ) TotalTime += RedFlagCarrierTime[j]; + + for( j = 0; j < 32; j++ ) + { + // If flagcarrier was not the capper + if( RedFlagCarrier[j] != None && RedFlagCarrier[j] != FCs[0] ) + { + AssisterStats = SCTFGame.GetStats( RedFlagCarrier[j] ); + if( AssisterStats != None ) + { + AssisterStats.Assists++; + } + + if( bNewCapAssistScoring ) + { + if( TotalTime == 0 ) + { + f = 0; + } + else + { + f = ( RedFlagCarrierTime[j] / TotalTime ) * ( 7 + CapBonus ); // proportionally score + } + Bonus = Max( f, 1 ); + } + RedFlagCarrier[j].PlayerReplicationInfo.Score += Bonus; + + if( PlayerPawn( RedFlagCarrier[j] ) != None ) + { + if( bShowAssistConsoleMsg ) + { + PlayerPawn( RedFlagCarrier[j] ).ClientMessage( "You get " $ Bonus $ " bonus pts for the Assist!" @ CarriedString( RedFlagCarrierTime[j], TotalTime ) ); + } + if( bPlayAssistSound && bNotPlayedLead ) + { + PlayerPawn( RedFlagCarrier[j] ).ReceiveLocalizedMessage( class'SmartCTFAudioMsg', 1 ); + } + } + if( Level.Game.LocalLog != None ) + { + Level.Game.LocalLog.LogSpecialEvent( "Flag_assist", RedFlagCarrier[j].PlayerReplicationInfo.PlayerID, 0 ); + } + } + // Award capper propertionally too. Behave like assist + else if( RedFlagCarrier[j] == FCs[0] ) + { + if( bNewCapAssistScoring ) + { + if( TotalTime == 0 ) + { + f = 0; + } + else + { + f = ( RedFlagCarrierTime[j] / TotalTime ) * ( 7 + CapBonus ); + } + Bonus = Max( f, MinimalCapBonus ); + FCs[0].PlayerReplicationInfo.Score += Bonus - 7; // 7 already awarded by UT + if( bShowAssistConsoleMsg && PlayerPawn( FCs[0] ) != None ) + { + PlayerPawn( FCs[0] ).ClientMessage( "You get " $ Bonus $ " pts for the Capture!" @ CarriedString( RedFlagCarrierTime[j], TotalTime ) ); + } + } + else + { + FCs[0].PlayerReplicationInfo.Score += CapBonus; + } + } + } + ResetFlagCarriers( 0 ); +} + +function RewardBlueFlagCarriers( bool bNotPlayedLead ) +{ + local byte j; + local SmartCTFPlayerReplicationInfo AssisterStats; + local int Bonus; + local float TotalTime, f; + + Bonus = AssistBonus; + + for( j = 0; j < 32; j++ ) + { + TotalTime += BlueFlagCarrierTime[j]; + } + + for( j = 0; j < 32; j++ ) + { + if( BlueFlagCarrier[j] != None && BlueFlagCarrier[j] != FCs[1] ) + { + AssisterStats = SCTFGame.GetStats( BlueFlagCarrier[j] ); + if( AssisterStats != None ) + { + AssisterStats.Assists++; + } + + if( bNewCapAssistScoring ) + { + if( TotalTime == 0 ) + { + f = 0; + } + else + { + f = ( BlueFlagCarrierTime[j] / TotalTime ) * ( 7 + CapBonus ); + } + Bonus = Max( f, 1 ); + } + BlueFlagCarrier[j].PlayerReplicationInfo.Score += Bonus; + + if( PlayerPawn( BlueFlagCarrier[j] ) != None ) + { + if( bShowAssistConsoleMsg ) + { + PlayerPawn( BlueFlagCarrier[j] ).ClientMessage( "You get " $ Bonus $ " bonus pts for the Assist!" @ CarriedString( BlueFlagCarrierTime[j], TotalTime ) ); + } + if( bPlayAssistSound && bNotPlayedLead ) + { + PlayerPawn( BlueFlagCarrier[j] ).ReceiveLocalizedMessage( class'SmartCTFAudioMsg', 1 ); + } + } + if( Level.Game.LocalLog != None ) + { + Level.Game.LocalLog.LogSpecialEvent( "Flag_assist", BlueFlagCarrier[j].PlayerReplicationInfo.PlayerID, 0 ); + } + } + else if( BlueFlagCarrier[j] == FCs[1] ) + { + if( bNewCapAssistScoring ) + { + if( TotalTime == 0 ) + { + f = 0; + } + else + { + f = ( BlueFlagCarrierTime[j] / TotalTime ) * ( 7 + CapBonus ); + } + Bonus = Max( f, MinimalCapBonus ); + FCs[1].PlayerReplicationInfo.Score += Bonus - 7; + if( bShowAssistConsoleMsg && PlayerPawn( FCs[1] ) != None ) + { + PlayerPawn( FCs[1] ).ClientMessage( "You get " $ Bonus $ " pts for the Capture!" @ CarriedString( BlueFlagCarrierTime[j], TotalTime ) ); + } + } + else + { + FCs[1].PlayerReplicationInfo.Score += CapBonus; + } + } + } + ResetFlagCarriers( 1 ); +} + +/* + * Clear assisters list of Team, because of flag return. Team = 2: clear both teams. +*/ +function ResetFlagCarriers( byte Team ) +{ + local byte i; + + if( Team != 1 ) + { + RedFCIndex = 0; + for( i = 0; i < 32; i++ ) + { + RedFlagCarrier[i] = None; + RedFlagCarrierTime[i] = 0; + } + } + if( Team != 0 ) + { + BlueFCIndex = 0; + for( i = 0; i < 32; i++ ) + { + BlueFlagCarrier[i] = None; + BlueFlagCarrierTime[i] = 0; + } + } +} + +function string CarriedString( float Time, float TotalTime ) +{ + local int Perc; + local float f; + + if( TotalTime == 0 ) + { + f = 0; + } + else + { + f = ( Time / TotalTime ) * 100; + } + + Perc = Clamp( f, 0, 100 ); + if( Perc == 100 ) + { + return "(Solocap," @ int( Time ) @ "sec.)"; + } + else + { + return "(Carried" @ Perc $ "% of the time:" @ int( Time ) @ "sec.)"; + } +} + +/* + * Intercept CTF messages to set FC states and adjust scores. +*/ +function bool MutatorBroadcastLocalizedMessage( Actor Sender, Pawn Receiver, out class Message, out optional int Switch, out optional PlayerReplicationInfo RelatedPRI_1, out optional PlayerReplicationInfo RelatedPRI_2, out optional Object OptionalObject ) +{ + local CTFFlag Flag; + local byte i, LeadSound; + local Pawn pn, FirstPawn; + local SmartCTFPlayerReplicationInfo ReceiverStats; + + // This function gets called each time someone receives a message. Thus for a broadcast, we need to make sure code only + // gets executed once. We can do that by comparing Receiver with f.e. the FC if applicable, or with the first Pawn + // in the PawnList (FirstPawn, see below). + + if( Message == class'CTFMessage' ) + { + if( Sender.IsA( 'CTFGame' ) ) + { + Flag = CTFFlag( OptionalObject ); + } + else if( Sender.IsA( 'CTFFlag' ) ) + { + Flag = CTFFlag( Sender ); + } + else + { + return super.MutatorBroadcastLocalizedMessage( Sender, Receiver, Message, Switch, RelatedPRI_1, RelatedPRI_2, OptionalObject ); + } + if( Flag == None ) + { + return super.MutatorBroadcastLocalizedMessage( Sender, Receiver, Message, Switch, RelatedPRI_1, RelatedPRI_2, OptionalObject ); + } + + // Warmup + if( DeathMatchPlus( Level.Game ).bTournament && !bTournamentGameStarted ) + { + return super.MutatorBroadcastLocalizedMessage( Sender, Receiver, Message, Switch, RelatedPRI_1, RelatedPRI_2, OptionalObject ); + } + + switch( Switch ) + { + // CAPTURE + // Sender: CTFGame, PRI: Scorer.PlayerReplicationInfo, OptObj: TheFlag + case 0: + if( Receiver == Pawn( RelatedPRI_1.Owner ) ) + { + //Flag = CTFFlag( OptionalObject ); + i = 1 - Flag.Team; + if( i == 1 ) + { + AddBlueFlagCarrier( FCs[i], Level.TimeSeconds - PickupTime[i] ); + } + else + { + AddRedFlagCarrier( FCs[i], Level.TimeSeconds - PickupTime[i] ); + } + + // Increment Caps for the player and the total + ReceiverStats = SCTFGame.GetStats( FCs[i] ); + if( ReceiverStats != None ) + { + ReceiverStats.Captures++; + } + + if( bPlayLeadSound ) + { + if( ( CTFGame( Level.Game ).Teams[i].Score - 1 ) == CTFGame( Level.Game ).Teams[1 - i].Score ) + { + LeadSound = 1; + } + if( CTFGame( Level.Game ).Teams[i].Score == CTFGame( Level.Game ).Teams[1 - i].Score ) + { + LeadSound = 2; + } + + for( pn = Level.PawnList; pn != None; pn = pn.NextPawn ) + { + if( PlayerPawn( pn ) != None && pn.bIsPlayer ) + { + if( LeadSound == 1 && pn.PlayerReplicationInfo.Team == i ) + { + PlayerPawn( pn ).ReceiveLocalizedMessage( class'SmartCTFAudioMsg', 3 ); + } + else if( LeadSound == 2 && pn.PlayerReplicationInfo.Team == ( 1 - i ) ) + { + PlayerPawn( pn ).ReceiveLocalizedMessage( class'SmartCTFAudioMsg', 4 ); + } + } + } + } + + // Don't play Capture sound if "Got The Lead" sound has played + if( bPlayCaptureSound && PlayerPawn( FCs[i] ) != None ) + { + if( !( bPlayLeadSound && ( LeadSound == 1 ) ) ) + { + PlayerPawn( FCs[i] ).ReceiveLocalizedMessage( class'SmartCTFAudioMsg', 0 ); + } + } + + // Reward points To FC and Assisters and increment Assists count and total + if( Flag.Team == 0 ) + { + RewardBlueFlagCarriers( !( bPlayLeadSound && ( LeadSound == 1 ) ) ); + } + else + { + RewardRedFlagCarriers( !( bPlayLeadSound && ( LeadSound == 1 ) ) ); + } + ResetFlagCarriers( 2 ); + GiveCoverSealBonus( Flag.Team ); // Reward pts to Covers And Sealers + + // Reset FCs And Assister num n index And reset sprees + FCs[0] = None; + FCs[1] = None; + ResetSprees( 2 ); // Means reset all since no Team is equal to 2. + } + break; + + // DROP + // Sender: CTFFlag, PRI: Holder.PlayerReplicationInfo, OptObj: CTFGame(Level.Game).Teams[Team] + case 2: + if( Receiver == Pawn( RelatedPRI_1.Owner ) ) + { + i = 1 - Flag.Team; + if( i == 1 ) + { + AddBlueFlagCarrier( FCs[i], Level.TimeSeconds - PickupTime[i] ); + } + else + { + AddRedFlagCarrier( FCs[i], Level.TimeSeconds - PickupTime[i] ); + } + } + break; + + // PICKUP (after the FC dropped it) + // Sender: CTFFlag, PRI: Holder.PlayerReplicationInfo, OptObj: CTFGame(Level.Game).Teams[Team] + case 4: + if( Receiver == Flag.Holder ) + { + i = 1 - Flag.Team; + PickupTime[i] = Level.TimeSeconds; + FCs[i] = Flag.Holder; + } + break; + + // GRAB + // Sender: CTFFlag, PRI: Holder.PlayerReplicationInfo, OptObj: CTFGame(Level.Game).Teams[Team] + case 6: + if( Receiver == Flag.Holder ) + { + i = 1 - Flag.Team; + PickupTime[i] = Level.TimeSeconds; + FCs[i] = Flag.Holder; // Set the FC + RelatedPRI_1.Score += GrabBonus; + // Increment FC's Grabs and total Grabs + ReceiverStats = SCTFGame.GetStats( FCs[i] ); + if( ReceiverStats != None ) + { + ReceiverStats.Grabs++; + } + } + break; + + + // RETURN + case 1: + case 3: + case 5: + // Get a pawn that receives messages, thus triggers this function ( as Receiver ) + for( FirstPawn = Level.PawnList; FirstPawn != None; FirstPawn = FirstPawn.NextPawn ) + { + if( FirstPawn.bIsPlayer || FirstPawn.IsA( 'MessagingSpectator' ) ) + { + break; + } + } + + if( Receiver == FirstPawn ) // Just get the first one. + { + // Switch == 1: it's returned by player, sent by CTFGame. + // Sender: CTFGame, PRI: Scorer.PlayerReplicationInfo, ObtObj: TheFlag + if( Switch == 1 ) + { + // 8 pts for a close save (with msg), Half a pt for base returns, 2 pts for Mid, 4 pts for enemy base + if( !bTooCloseForSaves && VSize( Flag.Location - FlagStands[1 - Flag.Team].Location ) < 900 ) + { // CLOSE SAVE + RelatedPRI_1.Score += CloseSaveReturnBonus; + if( Level.Game.LocalLog != None ) + { + Level.Game.LocalLog.LogSpecialEvent( "flag_return_closesave", RelatedPRI_1.PlayerID, Flag.Team ); + } + + // Only a msg if not a Flag standoff - other flag is home + if( CTFReplicationInfo( Level.Game.GameReplicationInfo ).FlagList[1 - Flag.Team].bHome ) + { + if( SavedMsgType == 1 && PlayerPawn( RelatedPRI_1.Owner ) != None ) + { + PlayerPawn( RelatedPRI_1.Owner ).ClientMessage( class'SmartCTFMessage'.static.GetString( 7 + 64, RelatedPRI_1 ) ); + } + else if( SavedMsgType == 2 ) + { + BroadcastMessage( class'SmartCTFMessage'.static.GetString( 7, RelatedPRI_1 ) ); + } + else if( SavedMsgType == 3 ) + { + BroadcastLocalizedMessage( class'SmartCTFMessage', 7, RelatedPRI_1 ); + } + if( bPlaySavedSound && PlayerPawn( RelatedPRI_1.Owner ) != None ) + { + PlayerPawn( RelatedPRI_1.Owner ).ReceiveLocalizedMessage( class'SmartCTFAudioMsg', 2 ); + } + } + } + else if( IsInZone( RelatedPRI_1, 1 - Flag.Team ) ) + { + RelatedPRI_1.Score += EnemyBaseReturnBonus; // If in enemy base + if( Level.Game.LocalLog != None ) + { + Level.Game.LocalLog.LogSpecialEvent( "flag_return_enemybase", RelatedPRI_1.PlayerID, Flag.Team ); + } + } + else if( !IsInZone( RelatedPRI_1, Flag.Team ) ) // Not in enemy base and not on own side = mid + { + RelatedPRI_1.Score += MidReturnBonus; // If in Mid + if( Level.Game.LocalLog != None ) + { + Level.Game.LocalLog.LogSpecialEvent( "flag_return_mid", RelatedPRI_1.PlayerID, Flag.Team ); + } + } + else + { + RelatedPRI_1.Score += BaseReturnBonus; + if( Level.Game.LocalLog != None ) + { + Level.Game.LocalLog.LogSpecialEvent( "flag_return_base", RelatedPRI_1.PlayerID, Flag.Team ); + } + } + + } // end if switch == 1 + + ResetSprees( Flag.Team ); // Reset cover sprees and seal sprees of Other Team + ResetFlagCarriers( 1 - Flag.Team ); // Reset assist list + } + + break; + } // end switch + if(bStoreStats) + { + UpdateInfo(); + } + } // end if msg is CTF msg. + + return super.MutatorBroadcastLocalizedMessage( Sender, Receiver, Message, Switch, RelatedPRI_1, RelatedPRI_2, OptionalObject ); +} + +/* + * Gives all players of Team that covered their FC extra bonus points after the cap. +*/ +function GiveCoverSealBonus( int Team ) +{ + local PlayerReplicationInfo pnPRI; + local byte i; + local SmartCTFPlayerReplicationInfo PawnStats; + local Pawn pn; + + SCTFGame.RefreshPRI(); + for( i = 0; i < 64; i++ ) + { + PawnStats = SCTFGame.GetStatNr( i ); + if( PawnStats == None ) + { + break; + } + pnPRI = PlayerReplicationInfo( PawnStats.Owner ); + pn = Pawn( pnPRI.Owner ); + + if( pnPRI.Team != Team ) + { + if( PawnStats != None && PawnStats.SealSpree > 0 ) + { + pnPRI.Score += PawnStats.SealSpree * SealBonus; + if( bShowSealRewardConsoleMsg && PlayerPawn( pn ) != None ) + { + PlayerPawn( pn ).ClientMessage("You killed " $ PawnStats.SealSpree $ " people sealing off the base. You get " $ PawnStats.SealSpree * SealBonus $ " bonus pts!" ); + } + if( Level.Game.LocalLog != None ) + { + Level.Game.LocalLog.LogSpecialEvent( "seal_bonus", pnPRI.PlayerID, PawnStats.SealSpree, PawnStats.SealSpree * SealBonus ); + } + } + if( PawnStats != None && PawnStats.CoverSpree > 0 ) + { + pnPRI.Score += PawnStats.CoverSpree * CoverBonus; + if( bShowCoverRewardConsoleMsg && PlayerPawn( pn ) != None ) + { + PlayerPawn( pn ).ClientMessage("You killed " $ PawnStats.CoverSpree $ " people covering your FC. You get " $ PawnStats.CoverSpree * CoverBonus $ " bonus pts!" ); + } + if( Level.Game.LocalLog != None ) + { + Level.Game.LocalLog.LogSpecialEvent( "cover_bonus", pnPRI.PlayerID, PawnStats.CoverSpree, PawnStats.CoverSpree * CoverBonus ); + } + } + } + } + if(bStoreStats) + { + UpdateInfo(); + } +} + +/* + * Reset cover and seal sprees of Team cause of flag return. +*/ +function ResetSprees( int Team ) +{ + local byte i; + local SmartCTFPlayerReplicationInfo PawnStats; + + SCTFGame.RefreshPRI(); + for( i = 0; i < 64; i++ ) + { + PawnStats = SCTFGame.GetStatNr( i ); + if( PawnStats == None ) + { + break; + } + if( PlayerReplicationInfo( PawnStats.Owner ).Team != Team ) + { + PawnStats.CoverSpree = 0; + PawnStats.SealSpree = 0; + } + } +} + +/* + * Clear stats. +*/ +function ClearStats() +{ + SCTFGame.ClearStats(); + ResetFlagCarriers( 2 ); + FCs[0] = None; + FCs[1] = None; +} + +/* + * Give info on 'mutate smartctf' commands. +*/ +function Mutate( string MutateString, PlayerPawn Sender ) +{ + local int ID; + local string SoundsString, MsgsString, CMsgsString; + local SmartCTFPlayerReplicationInfo SenderStats; + + if( Left( MutateString, 8 ) ~= "SmartCTF" ) + { + ID = Sender.PlayerReplicationInfo.PlayerID; + + if( Mid( MutateString, 9, 9 ) ~= "ShowStats" || Mid( MutateString, 9, 5 ) ~= "Stats" ) + { + SenderStats = SCTFGame.GetStats( Sender ); + if( SenderStats != None ) + { + SenderStats.ToggleStats(); + } + } + else if( Mid( MutateString, 9, 10 ) ~= "ForceStats" ) + { + SenderStats = SCTFGame.GetStats( Sender ); + if( SenderStats != None ) + { + SenderStats.ShowStats(); + } + } + else if( Mid( MutateString, 9, 5 ) ~= "Rules" || Mid( MutateString, 9, 6 ) ~= "Points" || Mid( MutateString, 9, 5 ) ~= "Score" || Mid( MutateString, 9, 5 ) ~= "Bonus" ) + { + if( bNewCapAssistScoring ) + { + Sender.ClientMessage( "SmartCTF Score Settings: - Cap/Assist:" @ 7 + CapBonus @ "pts divided over all FC's by time" ); + } + else + { + Sender.ClientMessage( "SmartCTF Score Settings: - Cap:" @ 7 + CapBonus @ "pts, Assist:" @ AssistBonus @ "pts." ); + } + Sender.ClientMessage( "- Cover (Kills while defending FC) Bonus :" @ CoverBonus @ "pts each. And" @ CoverBonus @ "more pts each if FC caps." ); + Sender.ClientMessage( "- Seal Bonus:" @ SealBonus @ "pts each, and" @ SealBonus @ "more pts each if FC caps." ); + Sender.ClientMessage( "- Seals (Kills while sealing off base) are defined by: 1) Your FC is on your team's side of map. 2) Your flag is not taken. 3) You kill someone on your side of the map." ); + if(bExtraStats) + { + Sender.ClientMessage( "- DefKills (Kills while the enemy is in your base area) are defined by: 1) Your flag is not taken. 2) You kill someone on your side of the map." ); + Sender.ClientMessage( "- Flagkills:" @ 5 + FlagKillBonus @ "pts. Flag Returns in base are worth" @ DitchZeros( BaseReturnBonus ) @ "pts, in mid" @ DitchZeros( MidReturnBonus ) @ "pts, enemy base" @ DitchZeros( EnemyBaseReturnBonus ) @ "pts, VERY close to capping" @ DitchZeros( CloseSaveReturnBonus ) @ "pts." ); + Sender.ClientMessage( "- Additional features: See Readme!" ); + } + } + else if( Mid( MutateString, 9, 8 ) ~= "ForceEnd" ) + { + if( !Sender.PlayerReplicationInfo.bAdmin && Level.NetMode != NM_StandAlone ) + { + Sender.ClientMessage( "You need to be logged in as admin to force the game to end." ); + } + else + { + BroadcastMessage( Sender.PlayerReplicationInfo.PlayerName @ "forced the game to end." ); + bForcedEndGame = True; + CTFGame( Level.Game ).EndGame( "forced" ); + } + } + else if( Mid( MutateString, 9, 10 ) ~= "ClearStats" ) + { + if( !Sender.PlayerReplicationInfo.bAdmin && Level.NetMode != NM_StandAlone ) + { + Sender.ClientMessage( "You need to be logged in as admin to be able to clear the stats." ); + } + else + { + ClearStats(); + Sender.ClientMessage( "Stats cleared." ); + } + } + else + { + Sender.ClientMessage( "SmartCTF - ChaCha Fork V6"); + Sender.ClientMessage( "Originally by: {PiN}Kev_HH. 4C by {DnF2}SiNiSTeR. 4D by [es]Rush. 4E by adminthis & The_Cowboy & Sp0ngeb0b.!"); + Sender.ClientMessage( "- To toggle stats, bind a key or type in console: 'Mutate SmartCTF Stats'" ); + Sender.ClientMessage( "- Type 'Mutate CTFInfo' for SmartCTF settings." ); + Sender.ClientMessage( "- Type 'Mutate SmartCTF Rules' for new point system definition." ); + Sender.ClientMessage( "- Type 'Mutate SmartCTF ForceEnd' to end a game." ); + if( bEnableOvertimeControl ) + { + Sender.ClientMessage( "- Type 'Mutate OverTime ' for Overtime Control." ); + } + } + } + else if( Left( MutateString, 7 ) ~= "CTFInfo" ) + { + SoundsString = ""; + if( bPlayCaptureSound ) SoundsString = SoundsString @ "Capture"; + if( bPlayAssistSound ) SoundsString = SoundsString @ "Assist"; + if( bPlaySavedSound ) SoundsString = SoundsString @ "Saved"; + if( bPlayLeadSound ) SoundsString = SoundsString @ "Lead"; + if( bPlay30SecSound ) SoundsString = SoundsString @ "30SecLeft"; + if( SoundsString == "" ) SoundsString = "All off"; + if( Left( SoundsString, 1 ) == " " ) SoundsString = Mid( SoundsString, 1 ); + MsgsString = ""; + if( CoverMsgType == 1 ) MsgsString = MsgsString @ "Covers"; + if( CoverMsgType == 2 ) MsgsString = MsgsString @ "Covers"; + if( CoverMsgType == 3 ) MsgsString = MsgsString @ "Covers"; + if( CoverSpreeMsgType == 1 ) MsgsString = MsgsString @ "Coversprees"; + if( CoverSpreeMsgType == 2 ) MsgsString = MsgsString @ "Coversprees"; + if( CoverSpreeMsgType == 3 ) MsgsString = MsgsString @ "Coversprees"; + if( DeniedMsgType == 1 ) MsgsString = MsgsString @ "Denied"; + if( DeniedMsgType == 2 ) MsgsString = MsgsString @ "Denied"; + if( DeniedMsgType == 3 ) MsgsString = MsgsString @ "Denied"; + if( SealMsgType == 1 ) MsgsString = MsgsString @ "Seals"; + if( SealMsgType == 2 ) MsgsString = MsgsString @ "Seals"; + if( SealMsgType == 3 ) MsgsString = MsgsString @ "Seals"; + if( SavedMsgType == 1 ) MsgsString = MsgsString @ "Saved"; + if( SavedMsgType == 2 ) MsgsString = MsgsString @ "Saved"; + if( SavedMsgType == 3 ) MsgsString = MsgsString @ "Saved"; + if( MsgsString == "" ) MsgsString = "All off"; + if( Left( MsgsString, 1 ) == " " ) MsgsString = Mid( MsgsString, 1 ); + CMsgsString = ""; + if( bShowAssistConsoleMsg ) CMsgsString = CMsgsString @ "AssistBonus"; + if( bShowSealRewardConsoleMsg ) CMsgsString = CMsgsString @ "SealReward"; + if( bShowCoverRewardConsoleMsg ) CMsgsString = CMsgsString @ "CoverReward"; + if( bShowLongRangeMsg ) CMsgsString = CMsgsString @ "LongRangeKill"; + if( CMsgsString == "" ) CMsgsString = "All off"; + if( Left( CMsgsString, 1 ) == " " ) CMsgsString = Mid( CMsgsString, 1 ); + Sender.ClientMessage( "- bExtraStats:" @ bExtraStats); + Sender.ClientMessage( "- Sounds:" @ SoundsString ); + Sender.ClientMessage( "- Msgs:" @ MsgsString ); + Sender.ClientMessage( "- Private Msgs:" @ CMsgsString ); + Sender.ClientMessage( "- bFixFlagBug:" @ bFixFlagBug ); + Sender.ClientMessage( "- bEnhancedMultiKill:" @ bEnhancedMultiKill $ ", Broadcast Level:" @ EnhancedMultiKillBroadcast ); + Sender.ClientMessage( "- bShowFCLocation:" @ bShowFCLocation ); + if( bSpawnKillDetection ) Sender.ClientMessage( "- bSpawnKillDetection: True, Global Msg:" @ bShowSpawnKillerGlobalMsg $ ", Penalty:" @ SpawnKillPenalty @ "pts" ); + else Sender.ClientMessage( "- bSpawnKillDetection: False" ); + Sender.ClientMessage( "- Overtime Control:" @ bEnableOvertimeControl @ "( Type 'Mutate OverTime' )" ); + Sender.ClientMessage( "- Scores: ( Type 'Mutate SmartCTF Rules' )"); + } + else if( Left( MutateString, 8 ) ~= "OverTime" ) + { + if( !DeathMatchPlus( Level.Game ).bTournament ) + { + Sender.ClientMessage( "Not in Tournament Mode: Default Sudden Death Overtime behaviour." ); + } + else if( !bEnableOvertimeControl ) + { + Sender.ClientMessage( "Overtime Control is not enabled: Default UT Sudden Death functionality." ); + Sender.ClientMessage( "Admins can use: admin set SmartCTF bEnableOvertimeControl True" ); + } + else + { + if( Left( MutateString, 11 ) ~= "OverTime On" ) + { + if( !Sender.PlayerReplicationInfo.bAdmin && Level.NetMode != NM_StandAlone ) + { + Sender.ClientMessage( "You need to be logged in as admin to change this setting." ); + } + else + { + bOvertime = True; + SaveConfig(); + BroadcastLocalizedMessage( class'SmartCTFCoolMsg', 3 ); + } + } + else if( Left( MutateString, 12 ) ~= "OverTime Off" ) + { + if( !Sender.PlayerReplicationInfo.bAdmin && Level.NetMode != NM_StandAlone ) + { + Sender.ClientMessage( "You need to be logged in as admin to change this setting." ); + } + else + { + bOvertime = False; + SaveConfig(); + BroadcastLocalizedMessage( class'SmartCTFCoolMsg', 4 ); + } + } + else + { + if( Sender.PlayerReplicationInfo.bAdmin || Level.NetMode == NM_StandAlone ) + { + Sender.ClientMessage( "Usage: Mutate OverTime On|Off" ); + } + if( !bOvertime ) + { + Sender.ClientMessage( "Sudden Death Overtime is DISABLED." ); + } + else + { + Sender.ClientMessage( "Sudden Death Overtime is ENABLED (default)." ); + } + Sender.ClientMessage( "Remember 'Disabled' Setting:" @ bRememberOvertimeSetting ); + } + } + } + + super.Mutate( MutateString, Sender ); +} + +/* + * To stop on a tie if needed. +*/ +function bool HandleEndGame() +{ + local bool bTied; + + if( CTFGame( Level.Game ).Teams[0].Score == CTFGame( Level.Game ).Teams[1].Score ) + { + bTied = True; + } + + if( bForcedEndGame || ( bEnableOvertimeControl && !bOvertime && DeathMatchPlus( Level.Game ).bTournament ) ) + { + bForcedEndGame = False; + if( bTied ) + { + SetEndCamsTiedCTFGame(); + return True; + } + } + + if( !bTied ) + { + CalcSmartCTFEndStats(); + } + if(bStoreStats) + { + UpdateInfo(); + } + if( NextMutator != None ) + { + return NextMutator.HandleEndGame(); + } + return False; +} + + +/* + * Position end cameras for a tied game. +*/ +function SetEndCamsTiedCTFGame() +{ + local Pawn pn, Best; + local PlayerPawn Player; + local CTFGame gg; + + gg = CTFGame( Level.Game ); + + // Find Individual Winner + for( pn = Level.PawnList ; pn != None ; pn = pn.NextPawn ) + { + if( pn.bIsPlayer && ( ( Best == None ) || ( pn.PlayerReplicationInfo.Score > Best.PlayerReplicationInfo.Score ) ) ) + { + Best = pn; + } + } + + gg.GameReplicationInfo.GameEndedComments = GameTieMessage; + gg.EndTime = Level.TimeSeconds + 3.0; + + for( pn = Level.PawnList ; pn != None ; pn = pn.NextPawn ) + { + Player = PlayerPawn( pn ); + if( Player != None ) + { + Player.bBehindView = True; + if( Player == Best ) + { + Player.ViewTarget = None; + } + else + { + Player.ViewTarget = Best; + } + + Player.ClientPlaySound( sound'CaptureSound', , true ); + Player.ClientGameEnded(); + } + pn.GotoState( 'GameEnded' ); + } + + gg.CalcEndStats(); + CalcSmartCTFEndStats(); +} + +function CalcSmartCTFEndStats() +{ + local SmartCTFPlayerReplicationInfo TopScore, TopFrags, TopCaps, TopCovers, TopFlagkills, TopHeadshots; + local string BestRecordDate; + local float PerHour; + local SmartCTFPlayerReplicationInfo PawnStats; + local PlayerReplicationInfo PRI; + local byte i; + local SmartCTFEndStats EndStats; + + EndStats = SCTFGame.EndStats; + + SCTFGame.RefreshPRI(); + for( i = 0; i < 64; i++ ) + { + PawnStats = SCTFGame.GetStatNr( i ); + if( PawnStats == None ) + { + break; + } + + if( TopScore == None || PlayerReplicationInfo( PawnStats.Owner ).Score > PlayerReplicationInfo( TopScore.Owner ).Score ) + { + TopScore = PawnStats; + } + if( TopFrags == None || PawnStats.Frags > TopFrags.Frags ) + { + TopFrags = PawnStats; + } + if( TopCaps == None || PawnStats.Captures > TopCaps.Captures ) + { + TopCaps = PawnStats; + } + if( TopCovers == None || PawnStats.Covers > TopCovers.Covers ) + { + TopCovers = PawnStats; + } + if( TopFlagkills == None || PawnStats.FlagKills > TopFlagkills.FlagKills ) + { + TopFlagkills = PawnStats; + } + if( TopHeadshots == None || PawnStats.HeadShots > TopHeadshots.HeadShots ) + { + TopHeadshots = PawnStats; + } + } + + PRI = PlayerReplicationInfo( TopScore.Owner ); + PerHour = ( Level.TimeSeconds - PRI.StartTime ) / 3600; + if( PRI.Score / PerHour > EndStats.MostPoints.Count && Level.TimeSeconds - PRI.StartTime > 300 ) + { + EndStats.MostPoints.Count = PRI.Score / PerHour; + EndStats.MostPoints.PlayerName = PRI.PlayerName; + EndStats.MostPoints.MapName = Level.Title; + CTFGame( Level.Game ).GetTimeStamp( BestRecordDate ); + EndStats.MostPoints.RecordDate = BestRecordDate; + } + + PRI = PlayerReplicationInfo( TopFrags.Owner ); + PerHour = ( Level.TimeSeconds - PRI.StartTime ) / 3600; + if( TopFrags.Frags / PerHour > EndStats.MostFrags.Count && Level.TimeSeconds - PRI.StartTime > 300 ) + { + EndStats.MostFrags.Count = TopFrags.Frags / PerHour; + EndStats.MostFrags.PlayerName = PRI.PlayerName; + EndStats.MostFrags.MapName = Level.Title; + CTFGame( Level.Game ).GetTimeStamp( BestRecordDate ); + EndStats.MostFrags.RecordDate = BestRecordDate; + } + + PRI = PlayerReplicationInfo( TopCaps.Owner ); + PerHour = ( Level.TimeSeconds - PRI.StartTime ) / 3600; + if( TopCaps.Captures / PerHour > EndStats.MostCaps.Count && Level.TimeSeconds - PRI.StartTime > 300 ) + { + EndStats.MostCaps.Count = TopCaps.Captures / PerHour; + EndStats.MostCaps.PlayerName = PRI.PlayerName; + EndStats.MostCaps.MapName = Level.Title; + CTFGame( Level.Game ).GetTimeStamp( BestRecordDate ); + EndStats.MostCaps.RecordDate = BestRecordDate; + } + + PRI = PlayerReplicationInfo( TopCovers.Owner ); + PerHour = ( Level.TimeSeconds - PRI.StartTime ) / 3600; + if( TopCovers.Covers / PerHour > EndStats.MostCovers.Count && Level.TimeSeconds - PRI.StartTime > 300 ) + { + EndStats.MostCovers.Count = TopCovers.Covers / PerHour; + EndStats.MostCovers.PlayerName = PRI.PlayerName; + EndStats.MostCovers.MapName = Level.Title; + CTFGame( Level.Game ).GetTimeStamp( BestRecordDate ); + EndStats.MostCovers.RecordDate = BestRecordDate; + } + + PRI = PlayerReplicationInfo( TopFlagkills.Owner ); + PerHour = ( Level.TimeSeconds - PRI.StartTime ) / 3600; + if( TopFlagkills.FlagKills / PerHour > EndStats.MostFlagKills.Count && Level.TimeSeconds - PRI.StartTime > 300 ) + { + EndStats.MostFlagKills.Count = TopFlagkills.FlagKills / PerHour; + EndStats.MostFlagKills.PlayerName = PRI.PlayerName; + EndStats.MostFlagKills.MapName = Level.Title; + CTFGame( Level.Game ).GetTimeStamp( BestRecordDate ); + EndStats.MostFlagKills.RecordDate = BestRecordDate; + } + + PRI = PlayerReplicationInfo( TopHeadshots.Owner ); + PerHour = ( Level.TimeSeconds - PRI.StartTime ) / 3600; + if( TopHeadshots.HeadShots / PerHour > EndStats.MostHeadShots.Count && Level.TimeSeconds - PRI.StartTime > 300 ) + { + EndStats.MostHeadShots.Count = TopHeadshots.HeadShots / PerHour; + EndStats.MostHeadShots.PlayerName = PRI.PlayerName; + EndStats.MostHeadShots.MapName = Level.Title; + CTFGame( Level.Game ).GetTimeStamp( BestRecordDate ); + EndStats.MostHeadShots.RecordDate = BestRecordDate; + } + + EndStats.SaveConfig(); +} + +/* + * Convert a float to a readable string. +*/ +function string DitchZeros( float nr ) +{ + local string str; + + str = string( nr ); + while( Right( str, 1 ) == "0" ) + { + str = Left( str , Len( str ) - 1 ); + } + if( Right( str, 1 ) == "." ) + { + str = Left( str , Len( str ) - 1 ); + } + + return str; +} + +//---------------------------------------------------------------------------------------------------------------- +//------------------------------------------------ CLIENT FUNCTIONS ---------------------------------------------- +//---------------------------------------------------------------------------------------------------------------- + +/* + * Render the HUD that is startup logo and FC location. + * ONLY gets executed on clients. +*/ +simulated event PostRender( Canvas C ) +{ + local int i, Y; + local float DummyY, Size, Temp; + local string TempStr; + + if( NextHUDMutator != None ) + { + NextHUDMutator.PostRender( C ); + } + + // Get stuff relating to PlayerOwner, if not gotten. Also spawn Font info. + if( PlayerOwner == None ) + { + PlayerOwner = C.Viewport.Actor; + pPRI = PlayerOwner.PlayerReplicationInfo; + } + + if(MyHUD == None) + { + MyHUD = ChallengeHUD( PlayerOwner.MyHUD ); + MyFonts = MyHUD.MyFonts; + } + + if(pTGRI == None) + { + pTGRI = TournamentGameReplicationInfo (PlayerOwner.GameReplicationInfo); + if(pTGRI==None) + { + return; + } + } + + // Draw the FC Location + if( SCTFGame.bShowFCLocation ) + { + for( i = 0; i < 32; i++ ) + { + if( pTGRI.PRIArray[i] == None ) + { + break; + } + if( pTGRI.PRIArray[i].bIsSpectator && !pTGRI.PRIArray[i].bWaitingPlayer ) + { + continue; + } + if( pTGRI.PRIArray[i].HasFlag != None && pTGRI.PRIArray[i].Team == pPRI.Team && pTGRI.PRIArray[i].PlayerID != pPRI.PlayerID && !pTGRI.PRIArray[i].HasFlag.IsA( 'GreenFlag' ) ) + { + if( pTGRI.PRIArray[i].PlayerLocation != None ) + { + TempStr = pTGRI.PRIArray[i].PlayerLocation.LocationName; + } + else if( pTGRI.PRIArray[i].PlayerZone != None ) + { + TempStr = pTGRI.PRIArray[i].PlayerZone.ZoneName; + } + if( TempStr == "" ) + { + TempStr = "Nameless Area"; + C.Style = ERenderStyle.STY_Translucent; + } + else + { + C.Style = ERenderStyle.STY_Normal; + } + + if( pPRI.Team == 0 ) + { + C.DrawColor = RedTeamColor; + } + else + { + C.DrawColor = BlueTeamColor; + } + + C.Font = MyFonts.GetSmallestFont( C.ClipX ); + C.StrLen( TempStr, Size, DummyY ); + if( MyHUD.bHideAllWeapons ) + { + Y = C.ClipY; + } + else if( MyHUD.HudScale * MyHUD.WeaponScale * C.ClipX <= C.ClipX - 256 * MyHUD.Scale) + { + Y = C.ClipY - 64 * MyHUD.Scale; + } + else + { + Y = C.ClipY - 128 * MyHUD.Scale; + } + + C.SetPos( C.ClipX - Size - 6, Y - 4 - 32 + ( 32 - DummyY ) / 2 ); + C.DrawText( TempStr ); + if( C.Style == ERenderStyle.STY_Translucent ) + { + C.DrawColor = Gray; + } + else + { + C.DrawColor = White; + } + C.SetPos( C.ClipX - Size - 6 - 32 - 4, Y - 4 - 32 ); + if( pPRI.Team == 0 ) + { + C.DrawIcon( texture'blueflag', 1.0 ); + } + else + { + C.DrawIcon( texture'redflag', 1.0 ); + } + + break; + } + } + } + + // Draw "Powered by.." logo when player joins + if( DrawLogo != 0 ) + { + C.Style = ERenderStyle.STY_Translucent; + if( DrawLogo > 1 ) + { + C.DrawColor.R = 255 - DrawLogo/2; + C.DrawColor.G = 255 - DrawLogo/2; + C.DrawColor.B = 255 - DrawLogo/2; + } + else // 1 + { + C.Style = ERenderStyle.STY_Translucent; + C.DrawColor = White; + } + if(powered == None) + { + powered=texture'powered'; + } + C.SetPos( C.ClipX - powered.Usize - 16, 40 ); + C.DrawIcon( powered, 1 ); + C.Font = MyFonts.GetSmallFont( C.ClipX ); + C.StrLen( "SmartCTF "$Version , Size, DummyY ); + C.SetPos( C.ClipX - powered.Usize/2 - Size/2 - 16, 40 + 8 + powered.Vsize ); + Temp = DummyY; + C.DrawText( "SmartCTF "$Version ); + } + + C.Style = ERenderStyle.STY_Normal; +} + + +/* + * Executed on the client when that player joins the server. +*/ +simulated function ClientJoinServer( Pawn Other ) +{ + if( PlayerPawn( Other ) == None || !Other.bIsPlayer ) + { + return; + } + + if(SCTFGame.bDrawLogo) + { + DrawLogo = 1; + } + + SetTimer( 0.05 , True); + + // Since this gets called in the HUD it needs to be changed clientside. + if( SCTFGame.bPlay30SecSound ) + { + class'TimeMessage'.default.TimeSound[5] = sound'Announcer.CD30Sec'; + } +} + +/* + * Clientside settings that need to be set for the first time, checking for welcome message and + * end of game screen. +*/ +simulated function Tick( float delta ) +{ + local SmartCTFPlayerReplicationInfo OwnerStats; + + // Execute on client + if( Level.NetMode != NM_DedicatedServer ) + { + if( SCTFGame == None ) + { + ForEach AllActors( class'SmartCTFGameReplicationInfo', SCTFGame ) + { + break; + } + + if( SCTFGame == None ) + { + return; + } + + if( !SCTFGame.bServerInfoSetServerSide && SCTFGame.DefaultHUDType != None ) // client side required + { + class( SCTFGame.DefaultHUDType ).default.ServerInfoClass = class'SmartCTFServerInfo'; + Log( "Notified HUD (clientside," @ SCTFGame.DefaultHUDType.name $ ") to use SmartCTF ServerInfo.", 'SmartCTF' ); + } + } + if( !SCTFGame.bInitialized ) + { + return; + } + + if( !bHUDMutator ) + { + RegisterHUDMutator(); + } + + if( PlayerOwner != None ) + { + if( !bClientJoinPlayer ) + { + bClientJoinPlayer = True; + ClientJoinServer( PlayerOwner ); + } + + // If Game is over, bring up F3. + if(PlayerOwner.GameReplicationInfo !=None) + { + if( PlayerOwner.GameReplicationInfo.GameEndedComments != "" && !bGameEnded ) + { + bGameEnded = True; + OwnerStats = SCTFGame.GetStatsByPRI( pPRI ); + OwnerStats.bEndStats = True; + PlayerOwner.ConsoleCommand( "mutate SmartCTF ForceStats" ); + } + } + } + } +} + +/* + * For showing the Logo a Timer is used instead of Ticks so its equal for each tickrate. + * On the server it keeps track of some replicated data and whether a Tournament game is starting. +*/ +simulated function Timer() +{ + local bool bReady; + local Pawn pn; + local SmartCTFPlayerReplicationInfo SenderStats; + + super.Timer(); + + // Clients - 0.05 second timer. Stops after logo is displayed. + if( Level.NetMode != NM_DedicatedServer ) + { + if( DrawLogo != 0 && SCTFGame.bDrawLogo ) + { + LogoCounter++; + if( DrawLogo == 510 ) + { + DrawLogo = 0; + if( Role != ROLE_Authority ) + { + SetTimer( 0.0, False ); // client timer off + } + else + { + SetTimer( 1.0, True ); // standalone game? keep timer running for bit below. + } + } + else if( LogoCounter > 60 ) + { + DrawLogo += 8; + if( DrawLogo > 510 ) + { + DrawLogo = 510; + } + } + else if( LogoCounter == 60 ) + { + DrawLogo = 5; + } + } + + if(!bInitSb && SCTFGame.bSCTFSbDef){ // SCTFGame fixes bSCTFSbDef bug. + if(bGameEnded) + { + // Don't interfere with scoreboard showing on game end + bInitSb=true; + return; + } + SbCount++; + if(SbCount>=SCTFGame.SbDelayC){ // Wait SbDelayC second(s) before calling SmartCTF sb + SenderStats = SCTFGame.GetStats( PlayerOwner ); + if( SenderStats != None ) + { + SenderStats.ShowStats(true); + } + bInitSb=true; + if(!SCTFGame.bDrawLogo && Role != ROLE_Authority) + { + SetTimer(0.0,False); + } + } + } + } + + // Server - 1 second timer. infinite. + if( Level.NetMode == NM_DedicatedServer || Role == ROLE_Authority ) + { + if( ++TRCount > 2 ) + { + SCTFGame.TickRate = int( ConsoleCommand( "get IpDrv.TcpNetDriver NetServerMaxTickRate" ) ); + TRCount = 0; + } + + SbDelayC = SbDelay*20; // Timer is called every 0.05s, so * 20 converts the value in seconds to our count compatible value + + // Update config vars to client / manual replication :E + // Allows for runtime changing of settings. + if( SCTFGame.bShowFCLocation != bShowFCLocation ) SCTFGame.bShowFCLocation = bShowFCLocation; + if( SCTFGame.bStatsDrawFaces != bStatsDrawFaces ) SCTFGame.bStatsDrawFaces = bStatsDrawFaces; + if( SCTFGame.bDrawLogo != bDrawLogo ) SCTFGame.bDrawLogo = bDrawLogo; + if( SCTFGame.bSCTFSbDef != bSCTFSbDef ) SCTFGame.bSCTFSbDef = bSCTFSbDef; + if( SCTFGame.bShowSpecs != bShowSpecs ) SCTFGame.bShowSpecs = bShowSpecs; + if( SCTFGame.SpectatorColor != SpectatorColor ) SCTFGame.SpectatorColor = SpectatorColor; + if( SCTFGame.bDoKeybind != bDoKeybind ) SCTFGame.bDoKeybind = bDoKeybind; + if( SCTFGame.SbDelayC != SbDelayC ) SCTFGame.SbDelayC = SbDelayC; + if( SCTFGame.bSnowyScoreboard != bSnowyScoreboard ) SCTFGame.bSnowyScoreboard = bSnowyScoreboard; + if( SCTFGame.bXmasImages != bXmasImages ) SCTFGame.bXmasImages = bXmasImages; + + if( !bTournamentGameStarted && DeathMatchPlus( Level.Game ).bTournament ) + { + if( DeathMatchPlus( Level.Game ).bRequireReady && + DeathMatchPlus( Level.Game ).CountDown > 0 && + ( DeathMatchPlus( Level.Game ).NumPlayers == DeathMatchPlus( Level.Game ).MaxPlayers || Level.NetMode == NM_Standalone ) && + DeathMatchPlus( Level.Game ).RemainingBots <= 0 ) + { + bReady = True; + for( pn = Level.PawnList; pn != None; pn = pn.NextPawn ) + { + if( pn.IsA( 'PlayerPawn' ) && !pn.IsA( 'Spectator' ) && !PlayerPawn( pn ).bReadyToPlay ) + { + bReady = False; + break; + } + } + } + + if( bReady ) + { + bTournamentGameStarted = True; + TournamentGameStarted(); + } + } + + // UT's built-in messaging spectator is excluded from the spectator list based on its starttime. + // We need to make sure this does not include any players as well. + // Update: on slow/exotic servers, the starttime could be delayed (not 0). Let's make sure it is. + if(!bStartTimeCorrected && bShowSpecs) + { + for(pn = Level.PawnList; pn != None; pn = pn.NextPawn){ + if(pn.IsA('PlayerPawn') && pn.PlayerReplicationInfo.StartTime==0) + { + pn.PlayerReplicationInfo.StartTime=1; + } + if(!pn.bIsPlayer && pn.PlayerReplicationInfo.Playername=="Player") + { + pn.PlayerReplicationInfo.StartTime=0; + } + } + if(Level.TimeSeconds>=5) + { + bStartTimeCorrected=true; // After five seconds, the messaging spectator(s) should be loaded, so we are done. + } + } + + // Since PlayerID's are incremented in the order of player joins [and those joined later cannot have an earlier StartTime than preceding players], this can be reliably used to deliver each player the delayed message only once + // without having to resort to a large array of PIDs already messaged; we can simply check against the *last* PID messaged instead. + // Too bad the timer only runs at 1.0. That sorf of defies the purpose of MsgDelay being a float instead of an int. O well... matches nice with SbDelay ;) + for(pn = Level.PawnList; pn != None; pn = pn.NextPawn) + { + if( pn.IsA('PlayerPawn') && + pn.bIsPlayer && + Level.TimeSeconds - pn.PlayerReplicationInfo.StartTime >= MsgDelay && + pn.PlayerReplicationInfo.PlayerID>MsgPID) + { + if(!SCTFGame.bDrawLogo) + { + pn.ClientMessage( "Running SmartCTF " $ Version $ ". Type 'Mutate SmartCTF' in the console for info." ); + } + if(bExtraMsg && bDoKeybind && SCTFGame.bDrawLogo) + { + pn.ClientMessage("Running SmartCTF " $ Version $ ". Press F3 to toggle between scoreboards."); + } + else if(bExtraMsg && bDoKeybind) + { + pn.ClientMessage("Press F3 to toggle between scoreboards."); // Shorter msg, since we already announced we are running SmartCTF. + } + MsgPID = pn.PlayerReplicationInfo.PlayerID; // Increase to keep track of whom still to message + } + } + } +} + +defaultproperties +{ + SCTFGame=None + RedAstIndex=0 + BlueAstIndex=0 + TRCount=0 + version="ChaChaV5" + GameTieMessage="The game ended in a tie!" + FCs(0)=None + FCs(1)=None + RedAssisters(0)=None + RedAssisters(1)=None + RedAssisters(2)=None + RedAssisters(3)=None + RedAssisters(4)=None + RedAssisters(5)=None + RedAssisters(6)=None + RedAssisters(7)=None + RedAssisters(8)=None + RedAssisters(9)=None + RedAssisters(10)=None + RedAssisters(11)=None + RedAssisters(12)=None + RedAssisters(13)=None + RedAssisters(14)=None + RedAssisters(15)=None + RedAssisters(16)=None + RedAssisters(17)=None + RedAssisters(18)=None + RedAssisters(19)=None + RedAssisters(20)=None + RedAssisters(21)=None + RedAssisters(22)=None + RedAssisters(23)=None + RedAssisters(24)=None + RedAssisters(25)=None + RedAssisters(26)=None + RedAssisters(27)=None + RedAssisters(28)=None + RedAssisters(29)=None + RedAssisters(30)=None + RedAssisters(31)=None + BlueAssisters(0)=None + BlueAssisters(1)=None + BlueAssisters(2)=None + BlueAssisters(3)=None + BlueAssisters(4)=None + BlueAssisters(5)=None + BlueAssisters(6)=None + BlueAssisters(7)=None + BlueAssisters(8)=None + BlueAssisters(9)=None + BlueAssisters(10)=None + BlueAssisters(11)=None + BlueAssisters(12)=None + BlueAssisters(13)=None + BlueAssisters(14)=None + BlueAssisters(15)=None + BlueAssisters(16)=None + BlueAssisters(17)=None + BlueAssisters(18)=None + BlueAssisters(19)=None + BlueAssisters(20)=None + BlueAssisters(21)=None + BlueAssisters(22)=None + BlueAssisters(23)=None + BlueAssisters(24)=None + BlueAssisters(25)=None + BlueAssisters(26)=None + BlueAssisters(27)=None + BlueAssisters(28)=None + BlueAssisters(29)=None + BlueAssisters(30)=None + BlueAssisters(31)=None + RedFlagCarrier(0)=None + RedFlagCarrier(1)=None + RedFlagCarrier(2)=None + RedFlagCarrier(3)=None + RedFlagCarrier(4)=None + RedFlagCarrier(5)=None + RedFlagCarrier(6)=None + RedFlagCarrier(7)=None + RedFlagCarrier(8)=None + RedFlagCarrier(9)=None + RedFlagCarrier(10)=None + RedFlagCarrier(11)=None + RedFlagCarrier(12)=None + RedFlagCarrier(13)=None + RedFlagCarrier(14)=None + RedFlagCarrier(15)=None + RedFlagCarrier(16)=None + RedFlagCarrier(17)=None + RedFlagCarrier(18)=None + RedFlagCarrier(19)=None + RedFlagCarrier(20)=None + RedFlagCarrier(21)=None + RedFlagCarrier(22)=None + RedFlagCarrier(23)=None + RedFlagCarrier(24)=None + RedFlagCarrier(25)=None + RedFlagCarrier(26)=None + RedFlagCarrier(27)=None + RedFlagCarrier(28)=None + RedFlagCarrier(29)=None + RedFlagCarrier(30)=None + RedFlagCarrier(31)=None + BlueFlagCarrier(0)=None + BlueFlagCarrier(1)=None + BlueFlagCarrier(2)=None + BlueFlagCarrier(3)=None + BlueFlagCarrier(4)=None + BlueFlagCarrier(5)=None + BlueFlagCarrier(6)=None + BlueFlagCarrier(7)=None + BlueFlagCarrier(8)=None + BlueFlagCarrier(9)=None + BlueFlagCarrier(10)=None + BlueFlagCarrier(11)=None + BlueFlagCarrier(12)=None + BlueFlagCarrier(13)=None + BlueFlagCarrier(14)=None + BlueFlagCarrier(15)=None + BlueFlagCarrier(16)=None + BlueFlagCarrier(17)=None + BlueFlagCarrier(18)=None + BlueFlagCarrier(19)=None + BlueFlagCarrier(20)=None + BlueFlagCarrier(21)=None + BlueFlagCarrier(22)=None + BlueFlagCarrier(23)=None + BlueFlagCarrier(24)=None + BlueFlagCarrier(25)=None + BlueFlagCarrier(26)=None + BlueFlagCarrier(27)=None + BlueFlagCarrier(28)=None + BlueFlagCarrier(29)=None + BlueFlagCarrier(30)=None + BlueFlagCarrier(31)=None + RedFlagCarrierTime(0)=0.000000 + RedFlagCarrierTime(1)=0.000000 + RedFlagCarrierTime(2)=0.000000 + RedFlagCarrierTime(3)=0.000000 + RedFlagCarrierTime(4)=0.000000 + RedFlagCarrierTime(5)=0.000000 + RedFlagCarrierTime(6)=0.000000 + RedFlagCarrierTime(7)=0.000000 + RedFlagCarrierTime(8)=0.000000 + RedFlagCarrierTime(9)=0.000000 + RedFlagCarrierTime(10)=0.000000 + RedFlagCarrierTime(11)=0.000000 + RedFlagCarrierTime(12)=0.000000 + RedFlagCarrierTime(13)=0.000000 + RedFlagCarrierTime(14)=0.000000 + RedFlagCarrierTime(15)=0.000000 + RedFlagCarrierTime(16)=0.000000 + RedFlagCarrierTime(17)=0.000000 + RedFlagCarrierTime(18)=0.000000 + RedFlagCarrierTime(19)=0.000000 + RedFlagCarrierTime(20)=0.000000 + RedFlagCarrierTime(21)=0.000000 + RedFlagCarrierTime(22)=0.000000 + RedFlagCarrierTime(23)=0.000000 + RedFlagCarrierTime(24)=0.000000 + RedFlagCarrierTime(25)=0.000000 + RedFlagCarrierTime(26)=0.000000 + RedFlagCarrierTime(27)=0.000000 + RedFlagCarrierTime(28)=0.000000 + RedFlagCarrierTime(29)=0.000000 + RedFlagCarrierTime(30)=0.000000 + RedFlagCarrierTime(31)=0.000000 + BlueFlagCarrierTime(0)=0.000000 + BlueFlagCarrierTime(1)=0.000000 + BlueFlagCarrierTime(2)=0.000000 + BlueFlagCarrierTime(3)=0.000000 + BlueFlagCarrierTime(4)=0.000000 + BlueFlagCarrierTime(5)=0.000000 + BlueFlagCarrierTime(6)=0.000000 + BlueFlagCarrierTime(7)=0.000000 + BlueFlagCarrierTime(8)=0.000000 + BlueFlagCarrierTime(9)=0.000000 + BlueFlagCarrierTime(10)=0.000000 + BlueFlagCarrierTime(11)=0.000000 + BlueFlagCarrierTime(12)=0.000000 + BlueFlagCarrierTime(13)=0.000000 + BlueFlagCarrierTime(14)=0.000000 + BlueFlagCarrierTime(15)=0.000000 + BlueFlagCarrierTime(16)=0.000000 + BlueFlagCarrierTime(17)=0.000000 + BlueFlagCarrierTime(18)=0.000000 + BlueFlagCarrierTime(19)=0.000000 + BlueFlagCarrierTime(20)=0.000000 + BlueFlagCarrierTime(21)=0.000000 + BlueFlagCarrierTime(22)=0.000000 + BlueFlagCarrierTime(23)=0.000000 + BlueFlagCarrierTime(24)=0.000000 + BlueFlagCarrierTime(25)=0.000000 + BlueFlagCarrierTime(26)=0.000000 + BlueFlagCarrierTime(27)=0.000000 + BlueFlagCarrierTime(28)=0.000000 + BlueFlagCarrierTime(29)=0.000000 + BlueFlagCarrierTime(30)=0.000000 + BlueFlagCarrierTime(31)=0.000000 + RedFCIndex=0 + BlueFCIndex=0 + RedAssistTimes(0)=0.000000 + RedAssistTimes(1)=0.000000 + RedAssistTimes(2)=0.000000 + RedAssistTimes(3)=0.000000 + RedAssistTimes(4)=0.000000 + RedAssistTimes(5)=0.000000 + RedAssistTimes(6)=0.000000 + RedAssistTimes(7)=0.000000 + RedAssistTimes(8)=0.000000 + RedAssistTimes(9)=0.000000 + RedAssistTimes(10)=0.000000 + RedAssistTimes(11)=0.000000 + RedAssistTimes(12)=0.000000 + RedAssistTimes(13)=0.000000 + RedAssistTimes(14)=0.000000 + RedAssistTimes(15)=0.000000 + RedAssistTimes(16)=0.000000 + RedAssistTimes(17)=0.000000 + RedAssistTimes(18)=0.000000 + RedAssistTimes(19)=0.000000 + RedAssistTimes(20)=0.000000 + RedAssistTimes(21)=0.000000 + RedAssistTimes(22)=0.000000 + RedAssistTimes(23)=0.000000 + RedAssistTimes(24)=0.000000 + RedAssistTimes(25)=0.000000 + RedAssistTimes(26)=0.000000 + RedAssistTimes(27)=0.000000 + RedAssistTimes(28)=0.000000 + RedAssistTimes(29)=0.000000 + RedAssistTimes(30)=0.000000 + RedAssistTimes(31)=0.000000 + BlueAssistTimes(0)=0.000000 + BlueAssistTimes(1)=0.000000 + BlueAssistTimes(2)=0.000000 + BlueAssistTimes(3)=0.000000 + BlueAssistTimes(4)=0.000000 + BlueAssistTimes(5)=0.000000 + BlueAssistTimes(6)=0.000000 + BlueAssistTimes(7)=0.000000 + BlueAssistTimes(8)=0.000000 + BlueAssistTimes(9)=0.000000 + BlueAssistTimes(10)=0.000000 + BlueAssistTimes(11)=0.000000 + BlueAssistTimes(12)=0.000000 + BlueAssistTimes(13)=0.000000 + BlueAssistTimes(14)=0.000000 + BlueAssistTimes(15)=0.000000 + BlueAssistTimes(16)=0.000000 + BlueAssistTimes(17)=0.000000 + BlueAssistTimes(18)=0.000000 + BlueAssistTimes(19)=0.000000 + BlueAssistTimes(20)=0.000000 + BlueAssistTimes(21)=0.000000 + BlueAssistTimes(22)=0.000000 + BlueAssistTimes(23)=0.000000 + BlueAssistTimes(24)=0.000000 + BlueAssistTimes(25)=0.000000 + BlueAssistTimes(26)=0.000000 + BlueAssistTimes(27)=0.000000 + BlueAssistTimes(28)=0.000000 + BlueAssistTimes(29)=0.000000 + BlueAssistTimes(30)=0.000000 + BlueAssistTimes(31)=0.000000 + PickupTime(0)=0.000000 + PickupTime(1)=0.000000 + FlagStands(0)=None + FlagStands(1)=None + bForcedEndGame=False + bTournamentGameStarted=False + bTooCloseForSaves=False + bStartTimeCorrected=False + MsgPID=0 + GoneName(0)="" + GoneName(1)="" + GoneName(2)="" + GoneName(3)="" + GoneName(4)="" + GoneName(5)="" + GoneName(6)="" + GoneName(7)="" + GoneName(8)="" + GoneName(9)="" + GoneName(10)="" + GoneName(11)="" + GoneName(12)="" + GoneName(13)="" + GoneName(14)="" + GoneName(15)="" + GoneName(16)="" + GoneName(17)="" + GoneName(18)="" + GoneName(19)="" + GoneName(20)="" + GoneName(21)="" + GoneName(22)="" + GoneName(23)="" + GoneName(24)="" + GoneName(25)="" + GoneName(26)="" + GoneName(27)="" + GoneName(28)="" + GoneName(29)="" + GoneName(30)="" + GoneName(31)="" + GoneIP(0)="" + GoneIP(1)="" + GoneIP(2)="" + GoneIP(3)="" + GoneIP(4)="" + GoneIP(5)="" + GoneIP(6)="" + GoneIP(7)="" + GoneIP(8)="" + GoneIP(9)="" + GoneIP(10)="" + GoneIP(11)="" + GoneIP(12)="" + GoneIP(13)="" + GoneIP(14)="" + GoneIP(15)="" + GoneIP(16)="" + GoneIP(17)="" + GoneIP(18)="" + GoneIP(19)="" + GoneIP(20)="" + GoneIP(21)="" + GoneIP(22)="" + GoneIP(23)="" + GoneIP(24)="" + GoneIP(25)="" + GoneIP(26)="" + GoneIP(27)="" + GoneIP(28)="" + GoneIP(29)="" + GoneIP(30)="" + GoneIP(31)="" + GoneScore(0)=0.000000 + GoneScore(1)=0.000000 + GoneScore(2)=0.000000 + GoneScore(3)=0.000000 + GoneScore(4)=0.000000 + GoneScore(5)=0.000000 + GoneScore(6)=0.000000 + GoneScore(7)=0.000000 + GoneScore(8)=0.000000 + GoneScore(9)=0.000000 + GoneScore(10)=0.000000 + GoneScore(11)=0.000000 + GoneScore(12)=0.000000 + GoneScore(13)=0.000000 + GoneScore(14)=0.000000 + GoneScore(15)=0.000000 + GoneScore(16)=0.000000 + GoneScore(17)=0.000000 + GoneScore(18)=0.000000 + GoneScore(19)=0.000000 + GoneScore(20)=0.000000 + GoneScore(21)=0.000000 + GoneScore(22)=0.000000 + GoneScore(23)=0.000000 + GoneScore(24)=0.000000 + GoneScore(25)=0.000000 + GoneScore(26)=0.000000 + GoneScore(27)=0.000000 + GoneScore(28)=0.000000 + GoneScore(29)=0.000000 + GoneScore(30)=0.000000 + GoneScore(31)=0.000000 + GoneDeaths(0)=0.000000 + GoneDeaths(1)=0.000000 + GoneDeaths(2)=0.000000 + GoneDeaths(3)=0.000000 + GoneDeaths(4)=0.000000 + GoneDeaths(5)=0.000000 + GoneDeaths(6)=0.000000 + GoneDeaths(7)=0.000000 + GoneDeaths(8)=0.000000 + GoneDeaths(9)=0.000000 + GoneDeaths(10)=0.000000 + GoneDeaths(11)=0.000000 + GoneDeaths(12)=0.000000 + GoneDeaths(13)=0.000000 + GoneDeaths(14)=0.000000 + GoneDeaths(15)=0.000000 + GoneDeaths(16)=0.000000 + GoneDeaths(17)=0.000000 + GoneDeaths(18)=0.000000 + GoneDeaths(19)=0.000000 + GoneDeaths(20)=0.000000 + GoneDeaths(21)=0.000000 + GoneDeaths(22)=0.000000 + GoneDeaths(23)=0.000000 + GoneDeaths(24)=0.000000 + GoneDeaths(25)=0.000000 + GoneDeaths(26)=0.000000 + GoneDeaths(27)=0.000000 + GoneDeaths(28)=0.000000 + GoneDeaths(29)=0.000000 + GoneDeaths(30)=0.000000 + GoneDeaths(31)=0.000000 + GoneStats(0)=None + GoneStats(1)=None + GoneStats(2)=None + GoneStats(3)=None + GoneStats(4)=None + GoneStats(5)=None + GoneStats(6)=None + GoneStats(7)=None + GoneStats(8)=None + GoneStats(9)=None + GoneStats(10)=None + GoneStats(11)=None + GoneStats(12)=None + GoneStats(13)=None + GoneStats(14)=None + GoneStats(15)=None + GoneStats(16)=None + GoneStats(17)=None + GoneStats(18)=None + GoneStats(19)=None + GoneStats(20)=None + GoneStats(21)=None + GoneStats(22)=None + GoneStats(23)=None + GoneStats(24)=None + GoneStats(25)=None + GoneStats(26)=None + GoneStats(27)=None + GoneStats(28)=None + GoneStats(29)=None + GoneStats(30)=None + GoneStats(31)=None + StoreName(0)="" + StoreName(1)="" + StoreName(2)="" + StoreName(3)="" + StoreName(4)="" + StoreName(5)="" + StoreName(6)="" + StoreName(7)="" + StoreName(8)="" + StoreName(9)="" + StoreName(10)="" + StoreName(11)="" + StoreName(12)="" + StoreName(13)="" + StoreName(14)="" + StoreName(15)="" + StoreName(16)="" + StoreName(17)="" + StoreName(18)="" + StoreName(19)="" + StoreName(20)="" + StoreName(21)="" + StoreName(22)="" + StoreName(23)="" + StoreName(24)="" + StoreName(25)="" + StoreName(26)="" + StoreName(27)="" + StoreName(28)="" + StoreName(29)="" + StoreName(30)="" + StoreName(31)="" + StoreScore(0)=0.000000 + StoreScore(1)=0.000000 + StoreScore(2)=0.000000 + StoreScore(3)=0.000000 + StoreScore(4)=0.000000 + StoreScore(5)=0.000000 + StoreScore(6)=0.000000 + StoreScore(7)=0.000000 + StoreScore(8)=0.000000 + StoreScore(9)=0.000000 + StoreScore(10)=0.000000 + StoreScore(11)=0.000000 + StoreScore(12)=0.000000 + StoreScore(13)=0.000000 + StoreScore(14)=0.000000 + StoreScore(15)=0.000000 + StoreScore(16)=0.000000 + StoreScore(17)=0.000000 + StoreScore(18)=0.000000 + StoreScore(19)=0.000000 + StoreScore(20)=0.000000 + StoreScore(21)=0.000000 + StoreScore(22)=0.000000 + StoreScore(23)=0.000000 + StoreScore(24)=0.000000 + StoreScore(25)=0.000000 + StoreScore(26)=0.000000 + StoreScore(27)=0.000000 + StoreScore(28)=0.000000 + StoreScore(29)=0.000000 + StoreScore(30)=0.000000 + StoreScore(31)=0.000000 + StoreDeaths(0)=0.000000 + StoreDeaths(1)=0.000000 + StoreDeaths(2)=0.000000 + StoreDeaths(3)=0.000000 + StoreDeaths(4)=0.000000 + StoreDeaths(5)=0.000000 + StoreDeaths(6)=0.000000 + StoreDeaths(7)=0.000000 + StoreDeaths(8)=0.000000 + StoreDeaths(9)=0.000000 + StoreDeaths(10)=0.000000 + StoreDeaths(11)=0.000000 + StoreDeaths(12)=0.000000 + StoreDeaths(13)=0.000000 + StoreDeaths(14)=0.000000 + StoreDeaths(15)=0.000000 + StoreDeaths(16)=0.000000 + StoreDeaths(17)=0.000000 + StoreDeaths(18)=0.000000 + StoreDeaths(19)=0.000000 + StoreDeaths(20)=0.000000 + StoreDeaths(21)=0.000000 + StoreDeaths(22)=0.000000 + StoreDeaths(23)=0.000000 + StoreDeaths(24)=0.000000 + StoreDeaths(25)=0.000000 + StoreDeaths(26)=0.000000 + StoreDeaths(27)=0.000000 + StoreDeaths(28)=0.000000 + StoreDeaths(29)=0.000000 + StoreDeaths(30)=0.000000 + StoreDeaths(31)=0.000000 + StoreIP(0)="" + StoreIP(1)="" + StoreIP(2)="" + StoreIP(3)="" + StoreIP(4)="" + StoreIP(5)="" + StoreIP(6)="" + StoreIP(7)="" + StoreIP(8)="" + StoreIP(9)="" + StoreIP(10)="" + StoreIP(11)="" + StoreIP(12)="" + StoreIP(13)="" + StoreIP(14)="" + StoreIP(15)="" + StoreIP(16)="" + StoreIP(17)="" + StoreIP(18)="" + StoreIP(19)="" + StoreIP(20)="" + StoreIP(21)="" + StoreIP(22)="" + StoreIP(23)="" + StoreIP(24)="" + StoreIP(25)="" + StoreIP(26)="" + StoreIP(27)="" + StoreIP(28)="" + StoreIP(29)="" + StoreIP(30)="" + StoreIP(31)="" + StoreStats(0)=None + StoreStats(1)=None + StoreStats(2)=None + StoreStats(3)=None + StoreStats(4)=None + StoreStats(5)=None + StoreStats(6)=None + StoreStats(7)=None + StoreStats(8)=None + StoreStats(9)=None + StoreStats(10)=None + StoreStats(11)=None + StoreStats(12)=None + StoreStats(13)=None + StoreStats(14)=None + StoreStats(15)=None + StoreStats(16)=None + StoreStats(17)=None + StoreStats(18)=None + StoreStats(19)=None + StoreStats(20)=None + StoreStats(21)=None + StoreStats(22)=None + StoreStats(23)=None + StoreStats(24)=None + StoreStats(25)=None + StoreStats(26)=None + StoreStats(27)=None + StoreStats(28)=None + StoreStats(29)=None + StoreStats(30)=None + StoreStats(31)=None + B1Name(0)="" + B1Name(1)="" + B1Name(2)="" + B1Name(3)="" + B1Name(4)="" + B1Name(5)="" + B1Name(6)="" + B1Name(7)="" + B1Name(8)="" + B1Name(9)="" + B1Name(10)="" + B1Name(11)="" + B1Name(12)="" + B1Name(13)="" + B1Name(14)="" + B1Name(15)="" + B1Name(16)="" + B1Name(17)="" + B1Name(18)="" + B1Name(19)="" + B1Name(20)="" + B1Name(21)="" + B1Name(22)="" + B1Name(23)="" + B1Name(24)="" + B1Name(25)="" + B1Name(26)="" + B1Name(27)="" + B1Name(28)="" + B1Name(29)="" + B1Name(30)="" + B1Name(31)="" + B1Score(0)=0.000000 + B1Score(1)=0.000000 + B1Score(2)=0.000000 + B1Score(3)=0.000000 + B1Score(4)=0.000000 + B1Score(5)=0.000000 + B1Score(6)=0.000000 + B1Score(7)=0.000000 + B1Score(8)=0.000000 + B1Score(9)=0.000000 + B1Score(10)=0.000000 + B1Score(11)=0.000000 + B1Score(12)=0.000000 + B1Score(13)=0.000000 + B1Score(14)=0.000000 + B1Score(15)=0.000000 + B1Score(16)=0.000000 + B1Score(17)=0.000000 + B1Score(18)=0.000000 + B1Score(19)=0.000000 + B1Score(20)=0.000000 + B1Score(21)=0.000000 + B1Score(22)=0.000000 + B1Score(23)=0.000000 + B1Score(24)=0.000000 + B1Score(25)=0.000000 + B1Score(26)=0.000000 + B1Score(27)=0.000000 + B1Score(28)=0.000000 + B1Score(29)=0.000000 + B1Score(30)=0.000000 + B1Score(31)=0.000000 + B1Deaths(0)=0.000000 + B1Deaths(1)=0.000000 + B1Deaths(2)=0.000000 + B1Deaths(3)=0.000000 + B1Deaths(4)=0.000000 + B1Deaths(5)=0.000000 + B1Deaths(6)=0.000000 + B1Deaths(7)=0.000000 + B1Deaths(8)=0.000000 + B1Deaths(9)=0.000000 + B1Deaths(10)=0.000000 + B1Deaths(11)=0.000000 + B1Deaths(12)=0.000000 + B1Deaths(13)=0.000000 + B1Deaths(14)=0.000000 + B1Deaths(15)=0.000000 + B1Deaths(16)=0.000000 + B1Deaths(17)=0.000000 + B1Deaths(18)=0.000000 + B1Deaths(19)=0.000000 + B1Deaths(20)=0.000000 + B1Deaths(21)=0.000000 + B1Deaths(22)=0.000000 + B1Deaths(23)=0.000000 + B1Deaths(24)=0.000000 + B1Deaths(25)=0.000000 + B1Deaths(26)=0.000000 + B1Deaths(27)=0.000000 + B1Deaths(28)=0.000000 + B1Deaths(29)=0.000000 + B1Deaths(30)=0.000000 + B1Deaths(31)=0.000000 + B1IP(0)="" + B1IP(1)="" + B1IP(2)="" + B1IP(3)="" + B1IP(4)="" + B1IP(5)="" + B1IP(6)="" + B1IP(7)="" + B1IP(8)="" + B1IP(9)="" + B1IP(10)="" + B1IP(11)="" + B1IP(12)="" + B1IP(13)="" + B1IP(14)="" + B1IP(15)="" + B1IP(16)="" + B1IP(17)="" + B1IP(18)="" + B1IP(19)="" + B1IP(20)="" + B1IP(21)="" + B1IP(22)="" + B1IP(23)="" + B1IP(24)="" + B1IP(25)="" + B1IP(26)="" + B1IP(27)="" + B1IP(28)="" + B1IP(29)="" + B1IP(30)="" + B1IP(31)="" + B1Stats(0)=None + B1Stats(1)=None + B1Stats(2)=None + B1Stats(3)=None + B1Stats(4)=None + B1Stats(5)=None + B1Stats(6)=None + B1Stats(7)=None + B1Stats(8)=None + B1Stats(9)=None + B1Stats(10)=None + B1Stats(11)=None + B1Stats(12)=None + B1Stats(13)=None + B1Stats(14)=None + B1Stats(15)=None + B1Stats(16)=None + B1Stats(17)=None + B1Stats(18)=None + B1Stats(19)=None + B1Stats(20)=None + B1Stats(21)=None + B1Stats(22)=None + B1Stats(23)=None + B1Stats(24)=None + B1Stats(25)=None + B1Stats(26)=None + B1Stats(27)=None + B1Stats(28)=None + B1Stats(29)=None + B1Stats(30)=None + B1Stats(31)=None + B2Name(0)="" + B2Name(1)="" + B2Name(2)="" + B2Name(3)="" + B2Name(4)="" + B2Name(5)="" + B2Name(6)="" + B2Name(7)="" + B2Name(8)="" + B2Name(9)="" + B2Name(10)="" + B2Name(11)="" + B2Name(12)="" + B2Name(13)="" + B2Name(14)="" + B2Name(15)="" + B2Name(16)="" + B2Name(17)="" + B2Name(18)="" + B2Name(19)="" + B2Name(20)="" + B2Name(21)="" + B2Name(22)="" + B2Name(23)="" + B2Name(24)="" + B2Name(25)="" + B2Name(26)="" + B2Name(27)="" + B2Name(28)="" + B2Name(29)="" + B2Name(30)="" + B2Name(31)="" + B2Score(0)=0.000000 + B2Score(1)=0.000000 + B2Score(2)=0.000000 + B2Score(3)=0.000000 + B2Score(4)=0.000000 + B2Score(5)=0.000000 + B2Score(6)=0.000000 + B2Score(7)=0.000000 + B2Score(8)=0.000000 + B2Score(9)=0.000000 + B2Score(10)=0.000000 + B2Score(11)=0.000000 + B2Score(12)=0.000000 + B2Score(13)=0.000000 + B2Score(14)=0.000000 + B2Score(15)=0.000000 + B2Score(16)=0.000000 + B2Score(17)=0.000000 + B2Score(18)=0.000000 + B2Score(19)=0.000000 + B2Score(20)=0.000000 + B2Score(21)=0.000000 + B2Score(22)=0.000000 + B2Score(23)=0.000000 + B2Score(24)=0.000000 + B2Score(25)=0.000000 + B2Score(26)=0.000000 + B2Score(27)=0.000000 + B2Score(28)=0.000000 + B2Score(29)=0.000000 + B2Score(30)=0.000000 + B2Score(31)=0.000000 + B2Deaths(0)=0.000000 + B2Deaths(1)=0.000000 + B2Deaths(2)=0.000000 + B2Deaths(3)=0.000000 + B2Deaths(4)=0.000000 + B2Deaths(5)=0.000000 + B2Deaths(6)=0.000000 + B2Deaths(7)=0.000000 + B2Deaths(8)=0.000000 + B2Deaths(9)=0.000000 + B2Deaths(10)=0.000000 + B2Deaths(11)=0.000000 + B2Deaths(12)=0.000000 + B2Deaths(13)=0.000000 + B2Deaths(14)=0.000000 + B2Deaths(15)=0.000000 + B2Deaths(16)=0.000000 + B2Deaths(17)=0.000000 + B2Deaths(18)=0.000000 + B2Deaths(19)=0.000000 + B2Deaths(20)=0.000000 + B2Deaths(21)=0.000000 + B2Deaths(22)=0.000000 + B2Deaths(23)=0.000000 + B2Deaths(24)=0.000000 + B2Deaths(25)=0.000000 + B2Deaths(26)=0.000000 + B2Deaths(27)=0.000000 + B2Deaths(28)=0.000000 + B2Deaths(29)=0.000000 + B2Deaths(30)=0.000000 + B2Deaths(31)=0.000000 + B2IP(0)="" + B2IP(1)="" + B2IP(2)="" + B2IP(3)="" + B2IP(4)="" + B2IP(5)="" + B2IP(6)="" + B2IP(7)="" + B2IP(8)="" + B2IP(9)="" + B2IP(10)="" + B2IP(11)="" + B2IP(12)="" + B2IP(13)="" + B2IP(14)="" + B2IP(15)="" + B2IP(16)="" + B2IP(17)="" + B2IP(18)="" + B2IP(19)="" + B2IP(20)="" + B2IP(21)="" + B2IP(22)="" + B2IP(23)="" + B2IP(24)="" + B2IP(25)="" + B2IP(26)="" + B2IP(27)="" + B2IP(28)="" + B2IP(29)="" + B2IP(30)="" + B2IP(31)="" + B2Stats(0)=None + B2Stats(1)=None + B2Stats(2)=None + B2Stats(3)=None + B2Stats(4)=None + B2Stats(5)=None + B2Stats(6)=None + B2Stats(7)=None + B2Stats(8)=None + B2Stats(9)=None + B2Stats(10)=None + B2Stats(11)=None + B2Stats(12)=None + B2Stats(13)=None + B2Stats(14)=None + B2Stats(15)=None + B2Stats(16)=None + B2Stats(17)=None + B2Stats(18)=None + B2Stats(19)=None + B2Stats(20)=None + B2Stats(21)=None + B2Stats(22)=None + B2Stats(23)=None + B2Stats(24)=None + B2Stats(25)=None + B2Stats(26)=None + B2Stats(27)=None + B2Stats(28)=None + B2Stats(29)=None + B2Stats(30)=None + B2Stats(31)=None + QuitMsg="" + QuitMsgLen=0 + bClientJoinPlayer=False + bGameEnded=False + bInitSb=False + LogoCounter=0 + DrawLogo=0 + SbCount=0 + SbDelayC=0.000000 + PlayerOwner=None + MyFonts=None + pTGRI=None + pPRI=None + myHUD=None + RedTeamColor=(R=255,G=0,B=0,A=0) + BlueTeamColor=(R=0,G=128,B=255,A=0) + White=(R=255,G=255,B=255,A=0) + Gray=(R=128,G=128,B=128,A=0) + bEnabled=True + bExtraStats=False + CountryFlagsPackage="CountryFlags32" + CapBonus=15 + AssistBonus=7 + FlagKillBonus=3 + CoverBonus=2 + SealBonus=3 + GrabBonus=0 + BaseReturnBonus=0.500000 + MidReturnBonus=2.000000 + EnemyBaseReturnBonus=5.000000 + CloseSaveReturnBonus=10.000000 + SpawnKillPenalty=0 + MinimalCapBonus=5 + bFixFlagBug=True + bEnhancedMultiKill=True + EnhancedMultiKillBroadcast=3 + bShowFCLocation=True + bSmartCTFServerInfo=True + bNewCapAssistScoring=True + bSpawnkillDetection=True + SpawnKillTimeArena=1.000000 + SpawnKillTimeNW=3.500000 + bAfterGodLikeMsg=True + bStatsDrawFaces=True + bDrawLogo=True + bSCTFSbDef=True + bShowSpecs=True + SpectatorColor=(R=255,G=255,B=255,A=0) + bDoKeybind=True + bExtraMsg=True + SbDelay=5.500000 + MsgDelay=7.000000 + bStoreStats=True + bSnowyScoreboard=False + bXmasImages=True + CoverMsgType=2 + CoverSpreeMsgType=3 + SealMsgType=3 + SavedMsgType=3 + DeniedMsgType=3 + bShowLongRangeMsg=False + bLongRangeSuperShock=True + bShowSpawnKillerGlobalMsg=True + bShowAssistConsoleMsg=True + bShowSealRewardConsoleMsg=True + bShowCoverRewardConsoleMsg=True + bPlayCaptureSound=True + bPlayAssistSound=True + bPlaySavedSound=True + bPlayLeadSound=True + bPlayDeniedSound=True + bPlay30SecSound=True + bPlayAirKillSound=True + bEnableOvertimeControl=False + bOverTime=True + bRememberOvertimeSetting=False + powered=None + bAlwaysRelevant=True + RemoteRole=ROLE_SimulatedProxy +} diff --git a/Sources/Classes/SmartCTFAudioMsg.uc b/Classes/SmartCTFAudioMsg.UC similarity index 100% rename from Sources/Classes/SmartCTFAudioMsg.uc rename to Classes/SmartCTFAudioMsg.UC diff --git a/Sources/Classes/SmartCTFBinds.uc b/Classes/SmartCTFBinds.UC similarity index 95% rename from Sources/Classes/SmartCTFBinds.uc rename to Classes/SmartCTFBinds.UC index 4587bdf..856ed08 100644 --- a/Sources/Classes/SmartCTFBinds.uc +++ b/Classes/SmartCTFBinds.UC @@ -1,8 +1,8 @@ -class SmartCTFBinds expands UTExtraKeyBindings; - -defaultproperties -{ - SectionName="SmartCTF" - LabelList(0)="Toggle Stats" - AliasNames(0)="mutate smartctf showstats" -} +class SmartCTFBinds expands UTExtraKeyBindings; + +defaultproperties +{ + SectionName="SmartCTF" + LabelList(0)="Toggle Stats" + AliasNames(0)="mutate smartctf showstats" +} diff --git a/Sources/Classes/SmartCTFCoolMsg.uc b/Classes/SmartCTFCoolMsg.UC similarity index 96% rename from Sources/Classes/SmartCTFCoolMsg.uc rename to Classes/SmartCTFCoolMsg.UC index 1cf3a8c..58013f6 100644 --- a/Sources/Classes/SmartCTFCoolMsg.uc +++ b/Classes/SmartCTFCoolMsg.UC @@ -1,100 +1,100 @@ -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(Messages) string AirKillMsg; -var(Messages) string AirKilledMsg; -var(Messages) string NewPlayerMsg; -var(Messages) string NewPlayerOtherMsg; -var(Messages) string PlayerBackMsg; -var(Messages) string PlayerBackOtherMsg; -var Color EnabledColor, DisabledColor, SpawnLamerColor,AirKillColor,AirKilledColor,NewPlayerColor,PlayerBackColor; - - -static function float GetOffset( int Switch, float YL, float ClipY ) -{ - switch( Switch ) - { - case 8: - case 9: - case 8 + 64: - case 9 + 64: - return ( default.YPos / 768.0 ) * ClipY - 3 * YL; - default: - 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; - case 6: return default.AirKillMsg; - case 7: return default.AirKilledMsg; - case 8: return default.NewPlayerMsg @ RelatedPRI_1.PlayerName @ "!"; - case 9: return default.PlayerBackMsg @ RelatedPRI_1.PlayerName @ "!"; - - case 8 + 64: return default.NewPlayerOtherMsg @ RelatedPRI_1.PlayerName @ "!"; - case 9 + 64: return default.PlayerBackOtherMsg @ RelatedPRI_1.PlayerName @ "!"; - } - 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; - case 6: return default.AirKillColor; - case 7: return default.AirKilledColor; - case 8: return default.NewPlayerColor; - case 9: return default.PlayerBackColor; - - - case 8+64: return default.NewPlayerColor; - case 9+64: return default.PlayerBackColor; - } - return default.DrawColor; -} - -defaultproperties -{ - LongRangeString="Long Range Kill!" - UberLongRangeString="Über Long Range Kill!" - SpawnLamerString="Spawnkill..." - AirKilledMsg="Killed in the air!" - AirKillMsg="Kill in the air!" - OvertimeEnabledString="Sudden Death Overtime = Enabled" - OvertimeDisabledString="Sudden Death Overtime = DISABLED" - NewPlayerMsg="Welcome to you" - NewPlayerOtherMsg="Welcome to" - PlayerBackMsg="Welcome back" - PlayerBackOtherMsg="Welcome back to" - EnabledColor=(R=128,G=255,B=192,A=0) - DisabledColor=(R=255,G=192,B=128,A=0) - SpawnLamerColor=(R=255,G=64,B=0,A=0) - AirKillColor=(R=128,G=255,B=192,A=0) - AirKilledColor=(R=255,G=192,B=128,A=0) - NewPlayerColor=(R=128,G=255,B=192,A=0) - PlayerBackColor=(R=128,G=255,B=192,A=0) - FontSize=1 - bIsSpecial=True - bIsUnique=True - bFadeMessage=True - DrawColor=(G=224,B=224) - YPos=196.000000 - bCenter=True -} +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(Messages) string AirKillMsg; +var(Messages) string AirKilledMsg; +var(Messages) string NewPlayerMsg; +var(Messages) string NewPlayerOtherMsg; +var(Messages) string PlayerBackMsg; +var(Messages) string PlayerBackOtherMsg; +var Color EnabledColor, DisabledColor, SpawnLamerColor,AirKillColor,AirKilledColor,NewPlayerColor,PlayerBackColor; + + +static function float GetOffset( int Switch, float YL, float ClipY ) +{ + switch( Switch ) + { + case 8: + case 9: + case 8 + 64: + case 9 + 64: + return ( default.YPos / 768.0 ) * ClipY - 3 * YL; + default: + 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; + case 6: return default.AirKillMsg; + case 7: return default.AirKilledMsg; + case 8: return default.NewPlayerMsg @ RelatedPRI_1.PlayerName @ "!"; + case 9: return default.PlayerBackMsg @ RelatedPRI_1.PlayerName @ "!"; + + case 8 + 64: return default.NewPlayerOtherMsg @ RelatedPRI_1.PlayerName @ "!"; + case 9 + 64: return default.PlayerBackOtherMsg @ RelatedPRI_1.PlayerName @ "!"; + } + 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; + case 6: return default.AirKillColor; + case 7: return default.AirKilledColor; + case 8: return default.NewPlayerColor; + case 9: return default.PlayerBackColor; + + + case 8+64: return default.NewPlayerColor; + case 9+64: return default.PlayerBackColor; + } + return default.DrawColor; +} + +defaultproperties +{ + LongRangeString="Long Range Kill!" + UberLongRangeString="Über Long Range Kill!" + SpawnLamerString="Spawnkill..." + AirKilledMsg="Killed in the air!" + AirKillMsg="Kill in the air!" + OvertimeEnabledString="Sudden Death Overtime = Enabled" + OvertimeDisabledString="Sudden Death Overtime = DISABLED" + NewPlayerMsg="Welcome to you" + NewPlayerOtherMsg="Welcome to" + PlayerBackMsg="Welcome back" + PlayerBackOtherMsg="Welcome back to" + EnabledColor=(R=128,G=255,B=192,A=0) + DisabledColor=(R=255,G=192,B=128,A=0) + SpawnLamerColor=(R=255,G=64,B=0,A=0) + AirKillColor=(R=128,G=255,B=192,A=0) + AirKilledColor=(R=255,G=192,B=128,A=0) + NewPlayerColor=(R=128,G=255,B=192,A=0) + PlayerBackColor=(R=128,G=255,B=192,A=0) + FontSize=1 + bIsSpecial=True + bIsUnique=True + bFadeMessage=True + DrawColor=(G=224,B=224) + YPos=196.000000 + bCenter=True +} diff --git a/Sources/Classes/SmartCTFEndStats.uc b/Classes/SmartCTFEndStats.UC similarity index 97% rename from Sources/Classes/SmartCTFEndStats.uc rename to Classes/SmartCTFEndStats.UC index da9ddc2..be9a9d2 100644 --- a/Sources/Classes/SmartCTFEndStats.uc +++ b/Classes/SmartCTFEndStats.UC @@ -1,32 +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 -} +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 +} diff --git a/Sources/Classes/SmartCTFEnhancedDeathMessagePlus.uc b/Classes/SmartCTFEnhancedDeathMessagePlus.UC similarity index 97% rename from Sources/Classes/SmartCTFEnhancedDeathMessagePlus.uc rename to Classes/SmartCTFEnhancedDeathMessagePlus.UC index 0f64e9b..f3b2b1f 100644 --- a/Sources/Classes/SmartCTFEnhancedDeathMessagePlus.uc +++ b/Classes/SmartCTFEnhancedDeathMessagePlus.UC @@ -1,54 +1,54 @@ -class SmartCTFEnhancedDeathMessagePlus extends DeathMessagePlus; - -static function ClientReceive( PlayerPawn P, optional int Switch, optional PlayerReplicationInfo RelatedPRI_1, optional PlayerReplicationInfo RelatedPRI_2, optional Object OptionalObject ) -{ - 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 -{ -} +class SmartCTFEnhancedDeathMessagePlus extends DeathMessagePlus; + +static function ClientReceive( PlayerPawn P, optional int Switch, optional PlayerReplicationInfo RelatedPRI_1, optional PlayerReplicationInfo RelatedPRI_2, optional Object OptionalObject ) +{ + 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 +{ +} diff --git a/Sources/Classes/SmartCTFEnhancedMultiKillMessage.uc b/Classes/SmartCTFEnhancedMultiKillMessage.UC similarity index 96% rename from Sources/Classes/SmartCTFEnhancedMultiKillMessage.uc rename to Classes/SmartCTFEnhancedMultiKillMessage.UC index b422eb8..25a6a19 100644 --- a/Sources/Classes/SmartCTFEnhancedMultiKillMessage.uc +++ b/Classes/SmartCTFEnhancedMultiKillMessage.UC @@ -1,108 +1,108 @@ -//============================================================================= -// 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 -#exec AUDIO IMPORT NAME=LudicrousKill FILE=Sounds\LudicrousKill.wav GROUP=SmartCTF -#exec AUDIO IMPORT NAME=HolyShit FILE=Sounds\HolyShit.wav GROUP=SmartCTF - -var(Messages) localized string MegaKillString; -var(Messages) localized string LudicrousKillString; -var(Messages) localized string HolyShitString; - -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; - case 6: return default.MonsterKillString; - break; - case 7: return default.LudicrousKillString; - break; - default: return default.HolyShitString; - 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; - case 6: P.ClientPlaySound( sound'Announcer.MonsterKill', , true ); - break; - case 7: P.ClientPlaySound( sound'LudicrousKill', , true ); - break; - default: P.ClientPlaySound( sound'HolyShit', , 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!" - LudicrousKillString="L U D I C R O U S K I L L !!!" - HolyShitString="H O L Y S H I T!!!" -} +//============================================================================= +// 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 +#exec AUDIO IMPORT NAME=LudicrousKill FILE=Sounds\LudicrousKill.wav GROUP=SmartCTF +#exec AUDIO IMPORT NAME=HolyShit FILE=Sounds\HolyShit.wav GROUP=SmartCTF + +var(Messages) localized string MegaKillString; +var(Messages) localized string LudicrousKillString; +var(Messages) localized string HolyShitString; + +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; + case 6: return default.MonsterKillString; + break; + case 7: return default.LudicrousKillString; + break; + default: return default.HolyShitString; + 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; + case 6: P.ClientPlaySound( sound'Announcer.MonsterKill', , true ); + break; + case 7: P.ClientPlaySound( sound'LudicrousKill', , true ); + break; + default: P.ClientPlaySound( sound'HolyShit', , 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!" + LudicrousKillString="L U D I C R O U S K I L L !!!" + HolyShitString="H O L Y S H I T!!!" +} diff --git a/Sources/Classes/SmartCTFFlagCheckerInventory.uc b/Classes/SmartCTFFlagCheckerInventory.UC similarity index 97% rename from Sources/Classes/SmartCTFFlagCheckerInventory.uc rename to Classes/SmartCTFFlagCheckerInventory.UC index 5b1b367..f4d1944 100644 --- a/Sources/Classes/SmartCTFFlagCheckerInventory.uc +++ b/Classes/SmartCTFFlagCheckerInventory.UC @@ -1,38 +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 -} +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 +} diff --git a/Sources/Classes/SmartCTFGameReplicationInfo.uc b/Classes/SmartCTFGameReplicationInfo.UC similarity index 96% rename from Sources/Classes/SmartCTFGameReplicationInfo.uc rename to Classes/SmartCTFGameReplicationInfo.UC index b9ac453..ec605d5 100644 --- a/Sources/Classes/SmartCTFGameReplicationInfo.uc +++ b/Classes/SmartCTFGameReplicationInfo.UC @@ -1,209 +1,209 @@ -// 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 NormalScoreBoardClass; -var SmartCTFEndStats EndStats; -var SmartCTFWelcomeNewPlayers WelcomeNewPlayers; -var SmartCTFPlayerReplicationInfo PRIArray[64]; -var bool bInitialized, bServerInfoSetServerSide, bDoneBind; -var class 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() -{ - 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 -{ - TickRate=0 - bShowFCLocation=False - bStatsDrawFaces=False - bPlay30SecSound=False - bDrawLogo=False - bExtraStats=False - bShowSpecs=False - bDoKeybind=False - bSCTFSbDef=False - bSnowyScoreboard=False - bXmasImages=False - SbDelayC=0.000000 - SpectatorColor=(R=0,G=0,B=0,A=0) - CountryFlagsPackage="" - NormalScoreBoardClass=None - EndStats=None - PRIArray(0)=None - PRIArray(1)=None - PRIArray(2)=None - PRIArray(3)=None - PRIArray(4)=None - PRIArray(5)=None - PRIArray(6)=None - PRIArray(7)=None - PRIArray(8)=None - PRIArray(9)=None - PRIArray(10)=None - PRIArray(11)=None - PRIArray(12)=None - PRIArray(13)=None - PRIArray(14)=None - PRIArray(15)=None - PRIArray(16)=None - PRIArray(17)=None - PRIArray(18)=None - PRIArray(19)=None - PRIArray(20)=None - PRIArray(21)=None - PRIArray(22)=None - PRIArray(23)=None - PRIArray(24)=None - PRIArray(25)=None - PRIArray(26)=None - PRIArray(27)=None - PRIArray(28)=None - PRIArray(29)=None - PRIArray(30)=None - PRIArray(31)=None - PRIArray(32)=None - PRIArray(33)=None - PRIArray(34)=None - PRIArray(35)=None - PRIArray(36)=None - PRIArray(37)=None - PRIArray(38)=None - PRIArray(39)=None - PRIArray(40)=None - PRIArray(41)=None - PRIArray(42)=None - PRIArray(43)=None - PRIArray(44)=None - PRIArray(45)=None - PRIArray(46)=None - PRIArray(47)=None - PRIArray(48)=None - PRIArray(49)=None - PRIArray(50)=None - PRIArray(51)=None - PRIArray(52)=None - PRIArray(53)=None - PRIArray(54)=None - PRIArray(55)=None - PRIArray(56)=None - PRIArray(57)=None - PRIArray(58)=None - PRIArray(59)=None - PRIArray(60)=None - PRIArray(61)=None - PRIArray(62)=None - PRIArray(63)=None - bInitialized=False - bServerInfoSetServerSide=False - bDoneBind=False - DefaultHUDType=None - RemoteRole=ROLE_SimulatedProxy -} +// 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 NormalScoreBoardClass; +var SmartCTFEndStats EndStats; +var SmartCTFWelcomeNewPlayers WelcomeNewPlayers; +var SmartCTFPlayerReplicationInfo PRIArray[64]; +var bool bInitialized, bServerInfoSetServerSide, bDoneBind; +var class 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() +{ + 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 +{ + TickRate=0 + bShowFCLocation=False + bStatsDrawFaces=False + bPlay30SecSound=False + bDrawLogo=False + bExtraStats=False + bShowSpecs=False + bDoKeybind=False + bSCTFSbDef=False + bSnowyScoreboard=False + bXmasImages=False + SbDelayC=0.000000 + SpectatorColor=(R=0,G=0,B=0,A=0) + CountryFlagsPackage="" + NormalScoreBoardClass=None + EndStats=None + PRIArray(0)=None + PRIArray(1)=None + PRIArray(2)=None + PRIArray(3)=None + PRIArray(4)=None + PRIArray(5)=None + PRIArray(6)=None + PRIArray(7)=None + PRIArray(8)=None + PRIArray(9)=None + PRIArray(10)=None + PRIArray(11)=None + PRIArray(12)=None + PRIArray(13)=None + PRIArray(14)=None + PRIArray(15)=None + PRIArray(16)=None + PRIArray(17)=None + PRIArray(18)=None + PRIArray(19)=None + PRIArray(20)=None + PRIArray(21)=None + PRIArray(22)=None + PRIArray(23)=None + PRIArray(24)=None + PRIArray(25)=None + PRIArray(26)=None + PRIArray(27)=None + PRIArray(28)=None + PRIArray(29)=None + PRIArray(30)=None + PRIArray(31)=None + PRIArray(32)=None + PRIArray(33)=None + PRIArray(34)=None + PRIArray(35)=None + PRIArray(36)=None + PRIArray(37)=None + PRIArray(38)=None + PRIArray(39)=None + PRIArray(40)=None + PRIArray(41)=None + PRIArray(42)=None + PRIArray(43)=None + PRIArray(44)=None + PRIArray(45)=None + PRIArray(46)=None + PRIArray(47)=None + PRIArray(48)=None + PRIArray(49)=None + PRIArray(50)=None + PRIArray(51)=None + PRIArray(52)=None + PRIArray(53)=None + PRIArray(54)=None + PRIArray(55)=None + PRIArray(56)=None + PRIArray(57)=None + PRIArray(58)=None + PRIArray(59)=None + PRIArray(60)=None + PRIArray(61)=None + PRIArray(62)=None + PRIArray(63)=None + bInitialized=False + bServerInfoSetServerSide=False + bDoneBind=False + DefaultHUDType=None + RemoteRole=ROLE_SimulatedProxy +} diff --git a/Sources/Classes/SmartCTFMessage.uc b/Classes/SmartCTFMessage.UC similarity index 96% rename from Sources/Classes/SmartCTFMessage.uc rename to Classes/SmartCTFMessage.UC index 2355660..64af733 100644 --- a/Sources/Classes/SmartCTFMessage.uc +++ b/Classes/SmartCTFMessage.UC @@ -1,97 +1,97 @@ -// 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; -var string DeniedMsg, YouDeniedMsg; - -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 11: // Denied - return default.DeniedMsg @ RelatedPRI_1.PlayerName; - - 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; - case 11 + 64: - return default.YouDeniedMsg; - } - 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!!" - DeniedMsg="Denied By" - YouDeniedMsg="Nide deny!!" - 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 -} +// 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; +var string DeniedMsg, YouDeniedMsg; + +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 11: // Denied + return default.DeniedMsg @ RelatedPRI_1.PlayerName; + + 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; + case 11 + 64: + return default.YouDeniedMsg; + } + 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!!" + DeniedMsg="Denied By" + YouDeniedMsg="Nide deny!!" + 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 +} diff --git a/Sources/Classes/SmartCTFPlayerReplicationInfo.uc b/Classes/SmartCTFPlayerReplicationInfo.UC similarity index 95% rename from Sources/Classes/SmartCTFPlayerReplicationInfo.uc rename to Classes/SmartCTFPlayerReplicationInfo.UC index 1576396..5b58cb1 100644 --- a/Sources/Classes/SmartCTFPlayerReplicationInfo.uc +++ b/Classes/SmartCTFPlayerReplicationInfo.UC @@ -1,192 +1,192 @@ -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() -{ - - 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 -{ - Captures=0 - Assists=0 - Grabs=0 - Covers=0 - Seals=0 - FlagKills=0 - DefKills=0 - Frags=0 - HeadShots=0 - ShieldBelts=0 - Amps=0 - CountryPrefix="" - LastKillTime=0.000000 - MultiLevel=0 - FragSpree=0 - CoverSpree=0 - SealSpree=0 - SpawnKillSpree=0 - SpawnTime=0.000000 - bHadFirstSpawn=False - bViewingStats=False - bEndStats=False - IndicatorStartShow=0.000000 - IndicatorVisibility=0 - ipToCountry=None - bIpToCountry=False -} +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() +{ + + 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 +{ + Captures=0 + Assists=0 + Grabs=0 + Covers=0 + Seals=0 + FlagKills=0 + DefKills=0 + Frags=0 + HeadShots=0 + ShieldBelts=0 + Amps=0 + CountryPrefix="" + LastKillTime=0.000000 + MultiLevel=0 + FragSpree=0 + CoverSpree=0 + SealSpree=0 + SpawnKillSpree=0 + SpawnTime=0.000000 + bHadFirstSpawn=False + bViewingStats=False + bEndStats=False + IndicatorStartShow=0.000000 + IndicatorVisibility=0 + ipToCountry=None + bIpToCountry=False +} diff --git a/Sources/Classes/SmartCTFScoreBoard.uc b/Classes/SmartCTFScoreBoard.UC similarity index 96% rename from Sources/Classes/SmartCTFScoreBoard.uc rename to Classes/SmartCTFScoreBoard.UC index 9398eb6..cc30ae4 100644 --- a/Sources/Classes/SmartCTFScoreBoard.uc +++ b/Classes/SmartCTFScoreBoard.UC @@ -1,1094 +1,1094 @@ -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 */ - local Texture TmpTexture; - - 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, Y + StatIndent - 16); - C.bNoSmooth = False; - C.DrawColor = White; - //C.DrawIcon(FD[GetFlagIndex(PlayerStats.CountryPrefix)].Tex, 1.0); - TmpTexture = FD[GetFlagIndex(PlayerStats.CountryPrefix)].Tex; - C.DrawIcon(TmpTexture, 32 / float(TmpTexture.VSize)); - 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; - local string TextStr; - local string TimeStr; - local int Hours, Minutes, Seconds, i; - local PlayerReplicationInfo PRI; - local color specColor; - - 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 -{ - NormalScoreBoard=None - SCTFGame=None - OwnerStats=None - TryCount=0 - PlayerOwner=None - PtsText="Pts" - FragsText="Frags" - SepText=" / " - MoreText="More..." - HeaderText="" - HeaderText2="[ SmartCTF ChaChaV6 ]" - LastSortTime=0 - MaxMeterWidth=0 - ColorChangeSpeed=0 - RowColState=0 - White=(R=255,G=255,B=255,A=0) - Gray=(R=128,G=128,B=128,A=0) - DarkGray=(R=32,G=32,B=32,A=0) - Yellow=(R=255,G=255,B=0,A=0) - RedTeamColor=(R=255,G=0,B=0,A=0) - BlueTeamColor=(R=0,G=128,B=255,A=0) - RedHeaderColor=(R=64,G=0,B=0,A=0) - BlueHeaderColor=(R=0,G=32,B=64,A=0) - StatsColor=(R=255,G=255,B=255,A=0) - FooterColor=(R=255,G=255,B=255,A=0) - HeaderColor=(R=255,G=255,B=0,A=0) - TinyInfoColor=(R=128,G=128,B=128,A=0) - HeaderTinyInfoColor=(R=192,G=192,B=192,A=0) - StatsTextWidth=0.000000 - StatHeight=0.000000 - MeterHeight=0.000000 - NameHeight=0.000000 - ColumnHeight=0.000000 - StatBlockHeight=0.000000 - RedStartX=0.000000 - BlueStartX=0.000000 - ColumnWidth=0.000000 - StatWidth=0.000000 - StatsHorSpacing=0.000000 - ShadingSpacingX=0.000000 - HeaderShadingSpacingY=0.000000 - ColumnShadingSpacingY=0.000000 - StartY=0.000000 - StatLineHeight=0.000000 - StatBlockSpacing=0.000000 - StatIndent=0.000000 - pTGRI=None - pPRI=None - StatFont=None - CapFont=None - FooterFont=None - GameEndedFont=None - PlayerNameFont=None - FragsFont=None - TinyInfoFont=None - PtsFont22=None - PtsFont20=None - PtsFont18=None - PtsFont16=None - PtsFont14=None - PtsFont12=None - MaxCaps=0 - MaxAssists=0 - MaxGrabs=0 - MaxCovers=0 - MaxSeals=0 - MaxDefKills=0 - MaxFlagKills=0 - MaxFrags=0 - MaxDeaths=0 - TotShieldBelts=0 - TotAmps=0 - bSealsOrDefs=False - bStarted=False - bEndHandled=False - FD(0)=(Prefix="",Tex=None) - FD(1)=(Prefix="",Tex=None) - FD(2)=(Prefix="",Tex=None) - FD(3)=(Prefix="",Tex=None) - FD(4)=(Prefix="",Tex=None) - FD(5)=(Prefix="",Tex=None) - FD(6)=(Prefix="",Tex=None) - FD(7)=(Prefix="",Tex=None) - FD(8)=(Prefix="",Tex=None) - FD(9)=(Prefix="",Tex=None) - FD(10)=(Prefix="",Tex=None) - FD(11)=(Prefix="",Tex=None) - FD(12)=(Prefix="",Tex=None) - FD(13)=(Prefix="",Tex=None) - FD(14)=(Prefix="",Tex=None) - FD(15)=(Prefix="",Tex=None) - FD(16)=(Prefix="",Tex=None) - FD(17)=(Prefix="",Tex=None) - FD(18)=(Prefix="",Tex=None) - FD(19)=(Prefix="",Tex=None) - FD(20)=(Prefix="",Tex=None) - FD(21)=(Prefix="",Tex=None) - FD(22)=(Prefix="",Tex=None) - FD(23)=(Prefix="",Tex=None) - FD(24)=(Prefix="",Tex=None) - FD(25)=(Prefix="",Tex=None) - FD(26)=(Prefix="",Tex=None) - FD(27)=(Prefix="",Tex=None) - FD(28)=(Prefix="",Tex=None) - FD(29)=(Prefix="",Tex=None) - FD(30)=(Prefix="",Tex=None) - FD(31)=(Prefix="",Tex=None) - saveindex=0 - } +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 */ + local Texture TmpTexture; + + 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, Y + StatIndent - 16); + C.bNoSmooth = False; + C.DrawColor = White; + //C.DrawIcon(FD[GetFlagIndex(PlayerStats.CountryPrefix)].Tex, 1.0); + TmpTexture = FD[GetFlagIndex(PlayerStats.CountryPrefix)].Tex; + C.DrawIcon(TmpTexture, 32 / float(TmpTexture.VSize)); + 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; + local string TextStr; + local string TimeStr; + local int Hours, Minutes, Seconds, i; + local PlayerReplicationInfo PRI; + local color specColor; + + 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 +{ + NormalScoreBoard=None + SCTFGame=None + OwnerStats=None + TryCount=0 + PlayerOwner=None + PtsText="Pts" + FragsText="Frags" + SepText=" / " + MoreText="More..." + HeaderText="" + HeaderText2="[ SmartCTF ChaChaV6 ]" + LastSortTime=0 + MaxMeterWidth=0 + ColorChangeSpeed=0 + RowColState=0 + White=(R=255,G=255,B=255,A=0) + Gray=(R=128,G=128,B=128,A=0) + DarkGray=(R=32,G=32,B=32,A=0) + Yellow=(R=255,G=255,B=0,A=0) + RedTeamColor=(R=255,G=0,B=0,A=0) + BlueTeamColor=(R=0,G=128,B=255,A=0) + RedHeaderColor=(R=64,G=0,B=0,A=0) + BlueHeaderColor=(R=0,G=32,B=64,A=0) + StatsColor=(R=255,G=255,B=255,A=0) + FooterColor=(R=255,G=255,B=255,A=0) + HeaderColor=(R=255,G=255,B=0,A=0) + TinyInfoColor=(R=128,G=128,B=128,A=0) + HeaderTinyInfoColor=(R=192,G=192,B=192,A=0) + StatsTextWidth=0.000000 + StatHeight=0.000000 + MeterHeight=0.000000 + NameHeight=0.000000 + ColumnHeight=0.000000 + StatBlockHeight=0.000000 + RedStartX=0.000000 + BlueStartX=0.000000 + ColumnWidth=0.000000 + StatWidth=0.000000 + StatsHorSpacing=0.000000 + ShadingSpacingX=0.000000 + HeaderShadingSpacingY=0.000000 + ColumnShadingSpacingY=0.000000 + StartY=0.000000 + StatLineHeight=0.000000 + StatBlockSpacing=0.000000 + StatIndent=0.000000 + pTGRI=None + pPRI=None + StatFont=None + CapFont=None + FooterFont=None + GameEndedFont=None + PlayerNameFont=None + FragsFont=None + TinyInfoFont=None + PtsFont22=None + PtsFont20=None + PtsFont18=None + PtsFont16=None + PtsFont14=None + PtsFont12=None + MaxCaps=0 + MaxAssists=0 + MaxGrabs=0 + MaxCovers=0 + MaxSeals=0 + MaxDefKills=0 + MaxFlagKills=0 + MaxFrags=0 + MaxDeaths=0 + TotShieldBelts=0 + TotAmps=0 + bSealsOrDefs=False + bStarted=False + bEndHandled=False + FD(0)=(Prefix="",Tex=None) + FD(1)=(Prefix="",Tex=None) + FD(2)=(Prefix="",Tex=None) + FD(3)=(Prefix="",Tex=None) + FD(4)=(Prefix="",Tex=None) + FD(5)=(Prefix="",Tex=None) + FD(6)=(Prefix="",Tex=None) + FD(7)=(Prefix="",Tex=None) + FD(8)=(Prefix="",Tex=None) + FD(9)=(Prefix="",Tex=None) + FD(10)=(Prefix="",Tex=None) + FD(11)=(Prefix="",Tex=None) + FD(12)=(Prefix="",Tex=None) + FD(13)=(Prefix="",Tex=None) + FD(14)=(Prefix="",Tex=None) + FD(15)=(Prefix="",Tex=None) + FD(16)=(Prefix="",Tex=None) + FD(17)=(Prefix="",Tex=None) + FD(18)=(Prefix="",Tex=None) + FD(19)=(Prefix="",Tex=None) + FD(20)=(Prefix="",Tex=None) + FD(21)=(Prefix="",Tex=None) + FD(22)=(Prefix="",Tex=None) + FD(23)=(Prefix="",Tex=None) + FD(24)=(Prefix="",Tex=None) + FD(25)=(Prefix="",Tex=None) + FD(26)=(Prefix="",Tex=None) + FD(27)=(Prefix="",Tex=None) + FD(28)=(Prefix="",Tex=None) + FD(29)=(Prefix="",Tex=None) + FD(30)=(Prefix="",Tex=None) + FD(31)=(Prefix="",Tex=None) + saveindex=0 + } \ No newline at end of file diff --git a/Classes/SmartCTFScoreBoard.UC.bak b/Classes/SmartCTFScoreBoard.UC.bak new file mode 100644 index 0000000..da25003 --- /dev/null +++ b/Classes/SmartCTFScoreBoard.UC.bak @@ -0,0 +1,1094 @@ +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 */ + local Texture TmpTexture; + + 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, Y + StatIndent - 16); + C.bNoSmooth = False; + C.DrawColor = White; + //C.DrawIcon(FD[GetFlagIndex(PlayerStats.CountryPrefix)].Tex, 1.0); + TmpTexture = FD[GetFlagIndex(PlayerStats.CountryPrefix)].Tex; + C.DrawIcon(TmpTexture, 32 / float(TmpTexture.VSize)); + 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; + local string TextStr; + local string TimeStr; + local int Hours, Minutes, Seconds, i; + local PlayerReplicationInfo PRI; + local color specColor; + + 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 +{ + NormalScoreBoard=None + SCTFGame=None + OwnerStats=None + TryCount=0 + PlayerOwner=None + PtsText="Pts" + FragsText="Frags" + SepText=" / " + MoreText="More..." + HeaderText="" + HeaderText2="[ SmartCTF 4E | {PiN}Kev | {DnF2}SiNiSTeR | [es]Rush | adminthis & The_Cowboy & Sp0ngeb0b ]" + LastSortTime=0 + MaxMeterWidth=0 + ColorChangeSpeed=0 + RowColState=0 + White=(R=255,G=255,B=255,A=0) + Gray=(R=128,G=128,B=128,A=0) + DarkGray=(R=32,G=32,B=32,A=0) + Yellow=(R=255,G=255,B=0,A=0) + RedTeamColor=(R=255,G=0,B=0,A=0) + BlueTeamColor=(R=0,G=128,B=255,A=0) + RedHeaderColor=(R=64,G=0,B=0,A=0) + BlueHeaderColor=(R=0,G=32,B=64,A=0) + StatsColor=(R=255,G=255,B=255,A=0) + FooterColor=(R=255,G=255,B=255,A=0) + HeaderColor=(R=255,G=255,B=0,A=0) + TinyInfoColor=(R=128,G=128,B=128,A=0) + HeaderTinyInfoColor=(R=192,G=192,B=192,A=0) + StatsTextWidth=0.000000 + StatHeight=0.000000 + MeterHeight=0.000000 + NameHeight=0.000000 + ColumnHeight=0.000000 + StatBlockHeight=0.000000 + RedStartX=0.000000 + BlueStartX=0.000000 + ColumnWidth=0.000000 + StatWidth=0.000000 + StatsHorSpacing=0.000000 + ShadingSpacingX=0.000000 + HeaderShadingSpacingY=0.000000 + ColumnShadingSpacingY=0.000000 + StartY=0.000000 + StatLineHeight=0.000000 + StatBlockSpacing=0.000000 + StatIndent=0.000000 + pTGRI=None + pPRI=None + StatFont=None + CapFont=None + FooterFont=None + GameEndedFont=None + PlayerNameFont=None + FragsFont=None + TinyInfoFont=None + PtsFont22=None + PtsFont20=None + PtsFont18=None + PtsFont16=None + PtsFont14=None + PtsFont12=None + MaxCaps=0 + MaxAssists=0 + MaxGrabs=0 + MaxCovers=0 + MaxSeals=0 + MaxDefKills=0 + MaxFlagKills=0 + MaxFrags=0 + MaxDeaths=0 + TotShieldBelts=0 + TotAmps=0 + bSealsOrDefs=False + bStarted=False + bEndHandled=False + FD(0)=(Prefix="",Tex=None) + FD(1)=(Prefix="",Tex=None) + FD(2)=(Prefix="",Tex=None) + FD(3)=(Prefix="",Tex=None) + FD(4)=(Prefix="",Tex=None) + FD(5)=(Prefix="",Tex=None) + FD(6)=(Prefix="",Tex=None) + FD(7)=(Prefix="",Tex=None) + FD(8)=(Prefix="",Tex=None) + FD(9)=(Prefix="",Tex=None) + FD(10)=(Prefix="",Tex=None) + FD(11)=(Prefix="",Tex=None) + FD(12)=(Prefix="",Tex=None) + FD(13)=(Prefix="",Tex=None) + FD(14)=(Prefix="",Tex=None) + FD(15)=(Prefix="",Tex=None) + FD(16)=(Prefix="",Tex=None) + FD(17)=(Prefix="",Tex=None) + FD(18)=(Prefix="",Tex=None) + FD(19)=(Prefix="",Tex=None) + FD(20)=(Prefix="",Tex=None) + FD(21)=(Prefix="",Tex=None) + FD(22)=(Prefix="",Tex=None) + FD(23)=(Prefix="",Tex=None) + FD(24)=(Prefix="",Tex=None) + FD(25)=(Prefix="",Tex=None) + FD(26)=(Prefix="",Tex=None) + FD(27)=(Prefix="",Tex=None) + FD(28)=(Prefix="",Tex=None) + FD(29)=(Prefix="",Tex=None) + FD(30)=(Prefix="",Tex=None) + FD(31)=(Prefix="",Tex=None) + saveindex=0 + } + \ No newline at end of file diff --git a/Sources/Classes/SmartCTFServerActor.uc b/Classes/SmartCTFServerActor.UC similarity index 95% rename from Sources/Classes/SmartCTFServerActor.uc rename to Classes/SmartCTFServerActor.UC index 521a38c..dfe60dc 100644 --- a/Sources/Classes/SmartCTFServerActor.uc +++ b/Classes/SmartCTFServerActor.UC @@ -1,16 +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 -} +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 +} diff --git a/Sources/Classes/SmartCTFServerInfo.uc b/Classes/SmartCTFServerInfo.UC similarity index 96% rename from Sources/Classes/SmartCTFServerInfo.uc rename to Classes/SmartCTFServerInfo.UC index eb4c2aa..3c1e1f2 100644 --- a/Sources/Classes/SmartCTFServerInfo.uc +++ b/Classes/SmartCTFServerInfo.UC @@ -1,375 +1,375 @@ -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 -{ - SCTFGame=None - PlayerOwner=None - MapNameText="Where" - bFontUpdated=False - LastUpdateTime=0.000000 - HeaderHeight=0.000000 - CatHeight=0.000000 - textHeight=0.000000 - SmallTextHeight=0.000000 - VSpacing=0.000000 - BorderSpacing=0.000000 - TotalHeight=0.000000 - StartY=0.000000 - Y=0.000000 - SideSpacing=0.000000 - HeaderBlue=(R=9,G=151,B=247,A=0) - TextBlue=(R=0,G=128,B=255,A=0) - InfoWhite=(R=255,G=255,B=255,A=0) - TopPlayersText="SmartCTF Record Holders [Numbers per Hour]" - BestNameText="Who" - BestFPHText="What" - BestRecordSetText="When" -} +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 +{ + SCTFGame=None + PlayerOwner=None + MapNameText="Where" + bFontUpdated=False + LastUpdateTime=0.000000 + HeaderHeight=0.000000 + CatHeight=0.000000 + textHeight=0.000000 + SmallTextHeight=0.000000 + VSpacing=0.000000 + BorderSpacing=0.000000 + TotalHeight=0.000000 + StartY=0.000000 + Y=0.000000 + SideSpacing=0.000000 + HeaderBlue=(R=9,G=151,B=247,A=0) + TextBlue=(R=0,G=128,B=255,A=0) + InfoWhite=(R=255,G=255,B=255,A=0) + TopPlayersText="SmartCTF Record Holders [Numbers per Hour]" + BestNameText="Who" + BestFPHText="What" + BestRecordSetText="When" +} diff --git a/Sources/Classes/SmartCTFSnowyScoreboard.uc b/Classes/SmartCTFSnowyScoreboard.UC similarity index 98% rename from Sources/Classes/SmartCTFSnowyScoreboard.uc rename to Classes/SmartCTFSnowyScoreboard.UC index 335f428..e0372a3 100644 --- a/Sources/Classes/SmartCTFSnowyScoreboard.uc +++ b/Classes/SmartCTFSnowyScoreboard.UC @@ -1,428 +1,428 @@ -// 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\santa.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 constants -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); - } - - 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,A=0) - bSnowInitialized=False - sprites(0)=Texture'SmartCTF_ChaChaV2.snowFlake1' - sprites(1)=Texture'SmartCTF_ChaChaV2.snowFlake2' - sprites(2)=Texture'SmartCTF_ChaChaV2.snowFlake3' - sprites(3)=Texture'SmartCTF_ChaChaV2.snowFlake4' - sprites(4)=Texture'SmartCTF_ChaChaV2.snowFlake5' - sprites(5)=Texture'SmartCTF_ChaChaV2.snowFlake6' - sprites(6)=Texture'SmartCTF_ChaChaV2.snowFlake7' - sprites(7)=Texture'SmartCTF_ChaChaV2.snowFlake8' - sprites(8)=Texture'SmartCTF_ChaChaV2.snowFlake9' - sprites(9)=Texture'SmartCTF_ChaChaV2.snowFlake10' - sprites(10)=Texture'SmartCTF_ChaChaV2.snowFlake11' - sprites(11)=Texture'SmartCTF_ChaChaV2.snowFlake12' - sprites(12)=Texture'SmartCTF_ChaChaV2.snowFlake13' - sprites(13)=Texture'SmartCTF_ChaChaV2.snowFlake14' - sprites(14)=Texture'SmartCTF_ChaChaV2.snowFlake15' - sprites(15)=Texture'SmartCTF_ChaChaV2.snowFlake16' - particles(0)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(1)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(2)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(3)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(4)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(5)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(6)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(7)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(8)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(9)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(10)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(11)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(12)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(13)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(14)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(15)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(16)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(17)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(18)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(19)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(20)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(21)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(22)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(23)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(24)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(25)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(26)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(27)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(28)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(29)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(30)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(31)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(32)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(33)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(34)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(35)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(36)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(37)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(38)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(39)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(40)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(41)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(42)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(43)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(44)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(45)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(46)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(47)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(48)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(49)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(50)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(51)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(52)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(53)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(54)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(55)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(56)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(57)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(58)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(59)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(60)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(61)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(62)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(63)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(64)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(65)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(66)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(67)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(68)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(69)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(70)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(71)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(72)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(73)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(74)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(75)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(76)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(77)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(78)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(79)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(80)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(81)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(82)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(83)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(84)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(85)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(86)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(87)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(88)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(89)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(90)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(91)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(92)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(93)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(94)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(95)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(96)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(97)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(98)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - particles(99)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) - LastUpdateTime=0.000000 - minDX=0.000000 - maxDX=0.000000 - minDY=0.000000 - maxDY=0.000000 - minWaveAmplitude=0.000000 - maxWaveAmplitude=0.000000 -} +// 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\santa.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 constants +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); + } + + 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,A=0) + bSnowInitialized=False + sprites(0)=Texture'SmartCTF_ChaChaV2.snowFlake1' + sprites(1)=Texture'SmartCTF_ChaChaV2.snowFlake2' + sprites(2)=Texture'SmartCTF_ChaChaV2.snowFlake3' + sprites(3)=Texture'SmartCTF_ChaChaV2.snowFlake4' + sprites(4)=Texture'SmartCTF_ChaChaV2.snowFlake5' + sprites(5)=Texture'SmartCTF_ChaChaV2.snowFlake6' + sprites(6)=Texture'SmartCTF_ChaChaV2.snowFlake7' + sprites(7)=Texture'SmartCTF_ChaChaV2.snowFlake8' + sprites(8)=Texture'SmartCTF_ChaChaV2.snowFlake9' + sprites(9)=Texture'SmartCTF_ChaChaV2.snowFlake10' + sprites(10)=Texture'SmartCTF_ChaChaV2.snowFlake11' + sprites(11)=Texture'SmartCTF_ChaChaV2.snowFlake12' + sprites(12)=Texture'SmartCTF_ChaChaV2.snowFlake13' + sprites(13)=Texture'SmartCTF_ChaChaV2.snowFlake14' + sprites(14)=Texture'SmartCTF_ChaChaV2.snowFlake15' + sprites(15)=Texture'SmartCTF_ChaChaV2.snowFlake16' + particles(0)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(1)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(2)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(3)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(4)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(5)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(6)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(7)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(8)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(9)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(10)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(11)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(12)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(13)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(14)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(15)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(16)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(17)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(18)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(19)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(20)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(21)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(22)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(23)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(24)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(25)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(26)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(27)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(28)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(29)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(30)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(31)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(32)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(33)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(34)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(35)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(36)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(37)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(38)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(39)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(40)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(41)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(42)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(43)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(44)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(45)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(46)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(47)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(48)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(49)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(50)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(51)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(52)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(53)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(54)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(55)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(56)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(57)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(58)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(59)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(60)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(61)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(62)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(63)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(64)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(65)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(66)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(67)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(68)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(69)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(70)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(71)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(72)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(73)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(74)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(75)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(76)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(77)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(78)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(79)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(80)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(81)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(82)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(83)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(84)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(85)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(86)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(87)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(88)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(89)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(90)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(91)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(92)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(93)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(94)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(95)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(96)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(97)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(98)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + particles(99)=(spriteNum=0,cx=0.000000,cy=0.000000,ct=0.000000,waveFreq=0.000000,waveAmplitude=0.000000,dy=0.000000,dx=0.000000,col=(R=0,G=0,B=0,A=0)) + LastUpdateTime=0.000000 + minDX=0.000000 + maxDX=0.000000 + minDY=0.000000 + maxDY=0.000000 + minWaveAmplitude=0.000000 + maxWaveAmplitude=0.000000 +} diff --git a/Sources/Classes/SmartCTFSpawnNotifyPRI.uc b/Classes/SmartCTFSpawnNotifyPRI.UC similarity index 95% rename from Sources/Classes/SmartCTFSpawnNotifyPRI.uc rename to Classes/SmartCTFSpawnNotifyPRI.UC index 1abe6bb..7cdd3f6 100644 --- a/Sources/Classes/SmartCTFSpawnNotifyPRI.uc +++ b/Classes/SmartCTFSpawnNotifyPRI.UC @@ -1,39 +1,39 @@ -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 -{ - ipToCountry=None - bChecked=False - ActorClass=Class'Engine.PlayerReplicationInfo' -} +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 +{ + ipToCountry=None + bChecked=False + ActorClass=Class'Engine.PlayerReplicationInfo' +} diff --git a/Sources/Classes/SmartCTFSpreeMsg.uc b/Classes/SmartCTFSpreeMsg.UC similarity index 97% rename from Sources/Classes/SmartCTFSpreeMsg.uc rename to Classes/SmartCTFSpreeMsg.UC index 1abcbae..8d6878e 100644 --- a/Sources/Classes/SmartCTFSpreeMsg.uc +++ b/Classes/SmartCTFSpreeMsg.UC @@ -1,18 +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' -} +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' +} diff --git a/Sources/Classes/SmartCTFWelcomeNewPlayers.UC b/Classes/SmartCTFWelcomeNewPlayers.UC similarity index 96% rename from Sources/Classes/SmartCTFWelcomeNewPlayers.UC rename to Classes/SmartCTFWelcomeNewPlayers.UC index 010c1b2..4e24fcd 100644 --- a/Sources/Classes/SmartCTFWelcomeNewPlayers.UC +++ b/Classes/SmartCTFWelcomeNewPlayers.UC @@ -1,184 +1,184 @@ -class SmartCTFWelcomeNewPlayers expands Actor config(SmartCTF_ChaCha); - - -var config int PawnLastSeenMaxHistory; -var config array PawnIdentHistory; -var config byte WelcomeMsgType; -var config byte WelcomeBackMsgType; -var config bool bPlayWelcomeSound; -var config bool bPlayWelcomeOthersSound; -var config float fDelayWelcome; -var config float fDelayWelcomeBack; - -var Pawn OtherNewpawn; - - -function BumpPawnToTop(int IdxPawn) -{ - PawnIdentHistory.Insert(PawnIdentHistory.Length,1); - PawnIdentHistory[PawnIdentHistory.Length-1]=PawnIdentHistory[IdxPawn]; - PawnIdentHistory.Remove(IdxPawn); -} - -state Welcome -{ - function Timer() - { - local Pawn pn; - local PlayerReplicationInfo OtherNewpawnPRI; - - OtherNewpawnPRI = OtherNewpawn.PlayerReplicationInfo; - if( OtherNewpawnPRI == None || !OtherNewpawn.bIsPlayer || ( OtherNewpawnPRI.bIsSpectator && !OtherNewpawnPRI.bWaitingPlayer ) ) - { - return; - } - - if(bPlayWelcomeSound) - { - //log("a"); - //log(OtherNewpawn); - OtherNewpawn.ReceiveLocalizedMessage( class'SmartCTFAudioMsg', 7 ); - } - if(WelcomeMsgType==1) - { - //log("b"); - //log(OtherNewpawn); - OtherNewpawn.ClientMessage( class'SmartCTFCoolMsg'.static.GetString(8)); - } - else if(WelcomeMsgType==2) - { - //log("c"); - Level.Game.BroadcastMessage( class'SmartCTFCoolMsg'.static.GetString(8 +64,OtherNewpawnPRI)); - } - else if(WelcomeMsgType==3) - { - //log("d"); - //log(class'SmartCTFCoolMsg'.static.GetString(8+64,OtherNewpawnPRI)); - Level.Game.BroadcastLocalizedMessage( class'SmartCTFCoolMsg',8 + 64,OtherNewpawnPRI); - } - - if(bPlayWelcomeOthersSound) - { - //log("e"); - for( pn = Level.PawnList; pn != None; pn = pn.NextPawn ) - { - if( PlayerPawn( pn ) != None && pn.bIsPlayer && pn != OtherNewpawn) - { - //log("f"); - //log(pn); - pn.ReceiveLocalizedMessage( class'SmartCTFAudioMsg', 7 ); - } - } - } - } -} -state WelcomeBack -{ - function Timer() - { - local PlayerReplicationInfo OtherNewpawnPRI; - - OtherNewpawnPRI = OtherNewpawn.PlayerReplicationInfo; - if( OtherNewpawnPRI == None || !OtherNewpawn.bIsPlayer || ( OtherNewpawnPRI.bIsSpectator && !OtherNewpawnPRI.bWaitingPlayer ) ) - { - return; - } - if(WelcomeBackMsgType==1) - { - //log("b"); - //log(OtherNewpawn); - OtherNewpawn.ClientMessage( class'SmartCTFCoolMsg'.static.GetString(9)); - } - else if(WelcomeBackMsgType==2) - { - //log("c"); - Level.Game.BroadcastMessage( class'SmartCTFCoolMsg'.static.GetString(9 +64,OtherNewpawnPRI)); - } - else if(WelcomeBackMsgType==3) - { - //log("d"); - //log(class'SmartCTFCoolMsg'.static.GetString(9+64,OtherNewpawnPRI)); - Level.Game.BroadcastLocalizedMessage( class'SmartCTFCoolMsg',9 + 64,OtherNewpawnPRI); - } - } -} - -function CheckPawn(Pawn Other,bool bIsFirstSpawn) -{ - local int i,iColon; - local string PawnIPPort,PawnIP,PawnName,PawnIdent; - - if( PlayerPawn( Other ) == None) - { - return; - } - - PawnIPPort = PlayerPawn(Other).GetPlayerNetworkAddress(); - iColon = InStr( PawnIPPort, ":" ); - PawnIP = Left( PawnIPPort, iColon ); - if( PawnIP == "") - { - log("[WARNING] Ignored player with empty / incorrect IP address"); - return; - } - PawnName = Other.PlayerReplicationInfo.PlayerName; - - PawnIdent=PawnIP$":"$PawnName; - - //log(Other); - //log(PawnIPPort); - //log(PawnIP); - //log(PawnName); - //log(PawnIdent); - - if( PawnIdentHistory.Length > PawnLastSeenMaxHistory) - { - PawnIdentHistory.Remove(0,PawnIdentHistory.Length - PawnLastSeenMaxHistory); - log("[WARNING] PawnIdentHistory too big, removing old history..."); - } - - for ( i = 0; ( i < PawnIdentHistory.Length ); i++ ) - { - if( PawnIdentHistory[i] == PawnIdent) - { - //log("Pawn FOUND in history :-) !"); - BumpPawnToTop(i); - OtherNewpawn=Other; - if(bIsFirstSpawn) - { - GotoState('WelcomeBack'); - SetTimer(fDelayWelcomeBack,False); - } - SaveConfig(); - return; - } - } - - //log("Pawn NOT found in history :( !"); - PawnIdentHistory.Insert(PawnIdentHistory.Length,1); - PawnIdentHistory[PawnIdentHistory.Length-1]=PawnIdent; - - if( PawnIdentHistory.Length > PawnLastSeenMaxHistory) - { - //log("Need to trim history"); - PawnIdentHistory.Remove(0,1); - } - OtherNewpawn=Other; - GotoState('Welcome'); - SetTimer(fDelayWelcome,False); - - //log("Finish"); - SaveConfig(); -} - -defaultproperties -{ - PawnLastSeenMaxHistory=256 - WelcomeMsgType=3 - WelcomeBackMsgType=3 - bPlayWelcomeSound=True - bPlayWelcomeOthersSound=True - fDelayWelcome=1.0 - fDelayWelcomeBack=1.0 - bHidden=True +class SmartCTFWelcomeNewPlayers expands Actor config(SmartCTF_ChaCha); + + +var config int PawnLastSeenMaxHistory; +var config array PawnIdentHistory; +var config byte WelcomeMsgType; +var config byte WelcomeBackMsgType; +var config bool bPlayWelcomeSound; +var config bool bPlayWelcomeOthersSound; +var config float fDelayWelcome; +var config float fDelayWelcomeBack; + +var Pawn OtherNewpawn; + + +function BumpPawnToTop(int IdxPawn) +{ + PawnIdentHistory.Insert(PawnIdentHistory.Length,1); + PawnIdentHistory[PawnIdentHistory.Length-1]=PawnIdentHistory[IdxPawn]; + PawnIdentHistory.Remove(IdxPawn); +} + +state Welcome +{ + function Timer() + { + local Pawn pn; + local PlayerReplicationInfo OtherNewpawnPRI; + + OtherNewpawnPRI = OtherNewpawn.PlayerReplicationInfo; + if( OtherNewpawnPRI == None || !OtherNewpawn.bIsPlayer || ( OtherNewpawnPRI.bIsSpectator && !OtherNewpawnPRI.bWaitingPlayer ) ) + { + return; + } + + if(bPlayWelcomeSound) + { + //log("a"); + //log(OtherNewpawn); + OtherNewpawn.ReceiveLocalizedMessage( class'SmartCTFAudioMsg', 7 ); + } + if(WelcomeMsgType==1) + { + //log("b"); + //log(OtherNewpawn); + OtherNewpawn.ClientMessage( class'SmartCTFCoolMsg'.static.GetString(8)); + } + else if(WelcomeMsgType==2) + { + //log("c"); + Level.Game.BroadcastMessage( class'SmartCTFCoolMsg'.static.GetString(8 +64,OtherNewpawnPRI)); + } + else if(WelcomeMsgType==3) + { + //log("d"); + //log(class'SmartCTFCoolMsg'.static.GetString(8+64,OtherNewpawnPRI)); + Level.Game.BroadcastLocalizedMessage( class'SmartCTFCoolMsg',8 + 64,OtherNewpawnPRI); + } + + if(bPlayWelcomeOthersSound) + { + //log("e"); + for( pn = Level.PawnList; pn != None; pn = pn.NextPawn ) + { + if( PlayerPawn( pn ) != None && pn.bIsPlayer && pn != OtherNewpawn) + { + //log("f"); + //log(pn); + pn.ReceiveLocalizedMessage( class'SmartCTFAudioMsg', 7 ); + } + } + } + } +} +state WelcomeBack +{ + function Timer() + { + local PlayerReplicationInfo OtherNewpawnPRI; + + OtherNewpawnPRI = OtherNewpawn.PlayerReplicationInfo; + if( OtherNewpawnPRI == None || !OtherNewpawn.bIsPlayer || ( OtherNewpawnPRI.bIsSpectator && !OtherNewpawnPRI.bWaitingPlayer ) ) + { + return; + } + if(WelcomeBackMsgType==1) + { + //log("b"); + //log(OtherNewpawn); + OtherNewpawn.ClientMessage( class'SmartCTFCoolMsg'.static.GetString(9)); + } + else if(WelcomeBackMsgType==2) + { + //log("c"); + Level.Game.BroadcastMessage( class'SmartCTFCoolMsg'.static.GetString(9 +64,OtherNewpawnPRI)); + } + else if(WelcomeBackMsgType==3) + { + //log("d"); + //log(class'SmartCTFCoolMsg'.static.GetString(9+64,OtherNewpawnPRI)); + Level.Game.BroadcastLocalizedMessage( class'SmartCTFCoolMsg',9 + 64,OtherNewpawnPRI); + } + } +} + +function CheckPawn(Pawn Other,bool bIsFirstSpawn) +{ + local int i,iColon; + local string PawnIPPort,PawnIP,PawnName,PawnIdent; + + if( PlayerPawn( Other ) == None) + { + return; + } + + PawnIPPort = PlayerPawn(Other).GetPlayerNetworkAddress(); + iColon = InStr( PawnIPPort, ":" ); + PawnIP = Left( PawnIPPort, iColon ); + if( PawnIP == "") + { + log("[WARNING] Ignored player with empty / incorrect IP address"); + return; + } + PawnName = Other.PlayerReplicationInfo.PlayerName; + + PawnIdent=PawnIP$":"$PawnName; + + //log(Other); + //log(PawnIPPort); + //log(PawnIP); + //log(PawnName); + //log(PawnIdent); + + if( PawnIdentHistory.Length > PawnLastSeenMaxHistory) + { + PawnIdentHistory.Remove(0,PawnIdentHistory.Length - PawnLastSeenMaxHistory); + log("[WARNING] PawnIdentHistory too big, removing old history..."); + } + + for ( i = 0; ( i < PawnIdentHistory.Length ); i++ ) + { + if( PawnIdentHistory[i] == PawnIdent) + { + //log("Pawn FOUND in history :-) !"); + BumpPawnToTop(i); + OtherNewpawn=Other; + if(bIsFirstSpawn) + { + GotoState('WelcomeBack'); + SetTimer(fDelayWelcomeBack,False); + } + SaveConfig(); + return; + } + } + + //log("Pawn NOT found in history :( !"); + PawnIdentHistory.Insert(PawnIdentHistory.Length,1); + PawnIdentHistory[PawnIdentHistory.Length-1]=PawnIdent; + + if( PawnIdentHistory.Length > PawnLastSeenMaxHistory) + { + //log("Need to trim history"); + PawnIdentHistory.Remove(0,1); + } + OtherNewpawn=Other; + GotoState('Welcome'); + SetTimer(fDelayWelcome,False); + + //log("Finish"); + SaveConfig(); +} + +defaultproperties +{ + PawnLastSeenMaxHistory=256 + WelcomeMsgType=3 + WelcomeBackMsgType=3 + bPlayWelcomeSound=True + bPlayWelcomeOthersSound=True + fDelayWelcome=1.0 + fDelayWelcomeBack=1.0 + bHidden=True } \ No newline at end of file diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..e69de29 diff --git a/Sources/Sounds/AirKill.WAV b/Sounds/AirKill.WAV similarity index 100% rename from Sources/Sounds/AirKill.WAV rename to Sounds/AirKill.WAV diff --git a/Sources/Sounds/Denied.WAV b/Sounds/Denied.WAV similarity index 100% rename from Sources/Sounds/Denied.WAV rename to Sounds/Denied.WAV diff --git a/Sources/Sounds/HolyShit.wav b/Sounds/HolyShit.wav similarity index 100% rename from Sources/Sounds/HolyShit.wav rename to Sounds/HolyShit.wav diff --git a/Sources/Sounds/LudicrousKill.wav b/Sounds/LudicrousKill.wav similarity index 100% rename from Sources/Sounds/LudicrousKill.wav rename to Sounds/LudicrousKill.wav diff --git a/Sources/Sounds/welcome.wav b/Sounds/welcome.wav similarity index 100% rename from Sources/Sounds/welcome.wav rename to Sounds/welcome.wav diff --git a/Sources/make.bat b/Sources/make.bat deleted file mode 100644 index 2250228..0000000 --- a/Sources/make.bat +++ /dev/null @@ -1,2 +0,0 @@ -del %~dp0\..\System\SmartCTF_ChaChaV6.u -%~dp0\..\System\ucc.exe make SmartCTF_ChaChaV6 \ No newline at end of file diff --git a/System/SmartCTF_ChaChaV6.u b/System/SmartCTF_ChaChaV6.u new file mode 100644 index 0000000..25a4450 Binary files /dev/null and b/System/SmartCTF_ChaChaV6.u differ diff --git a/Sources/Textures/faceless.pcx b/Textures/faceless.pcx similarity index 100% rename from Sources/Textures/faceless.pcx rename to Textures/faceless.pcx diff --git a/Sources/Textures/meter.pcx b/Textures/meter.pcx similarity index 100% rename from Sources/Textures/meter.pcx rename to Textures/meter.pcx diff --git a/Sources/Textures/powered.pcx b/Textures/powered.pcx similarity index 100% rename from Sources/Textures/powered.pcx rename to Textures/powered.pcx diff --git a/Sources/Textures/presents.pcx b/Textures/presents.pcx similarity index 100% rename from Sources/Textures/presents.pcx rename to Textures/presents.pcx diff --git a/Sources/Textures/santa.pcx b/Textures/santa.pcx similarity index 100% rename from Sources/Textures/santa.pcx rename to Textures/santa.pcx diff --git a/Sources/Textures/shade.pcx b/Textures/shade.pcx similarity index 100% rename from Sources/Textures/shade.pcx rename to Textures/shade.pcx diff --git a/Sources/Textures/SnowFlake1.pcx b/Textures/snowFlake1.pcx similarity index 100% rename from Sources/Textures/SnowFlake1.pcx rename to Textures/snowFlake1.pcx diff --git a/Sources/Textures/SnowFlake10.pcx b/Textures/snowFlake10.pcx similarity index 100% rename from Sources/Textures/SnowFlake10.pcx rename to Textures/snowFlake10.pcx diff --git a/Sources/Textures/SnowFlake11.pcx b/Textures/snowFlake11.pcx similarity index 100% rename from Sources/Textures/SnowFlake11.pcx rename to Textures/snowFlake11.pcx diff --git a/Sources/Textures/SnowFlake12.pcx b/Textures/snowFlake12.pcx similarity index 100% rename from Sources/Textures/SnowFlake12.pcx rename to Textures/snowFlake12.pcx diff --git a/Sources/Textures/SnowFlake13.pcx b/Textures/snowFlake13.pcx similarity index 100% rename from Sources/Textures/SnowFlake13.pcx rename to Textures/snowFlake13.pcx diff --git a/Sources/Textures/SnowFlake14.pcx b/Textures/snowFlake14.pcx similarity index 100% rename from Sources/Textures/SnowFlake14.pcx rename to Textures/snowFlake14.pcx diff --git a/Sources/Textures/SnowFlake15.pcx b/Textures/snowFlake15.pcx similarity index 100% rename from Sources/Textures/SnowFlake15.pcx rename to Textures/snowFlake15.pcx diff --git a/Sources/Textures/SnowFlake16.pcx b/Textures/snowFlake16.pcx similarity index 100% rename from Sources/Textures/SnowFlake16.pcx rename to Textures/snowFlake16.pcx diff --git a/Sources/Textures/SnowFlake2.pcx b/Textures/snowFlake2.pcx similarity index 100% rename from Sources/Textures/SnowFlake2.pcx rename to Textures/snowFlake2.pcx diff --git a/Sources/Textures/SnowFlake3.pcx b/Textures/snowFlake3.pcx similarity index 100% rename from Sources/Textures/SnowFlake3.pcx rename to Textures/snowFlake3.pcx diff --git a/Sources/Textures/SnowFlake4.pcx b/Textures/snowFlake4.pcx similarity index 100% rename from Sources/Textures/SnowFlake4.pcx rename to Textures/snowFlake4.pcx diff --git a/Sources/Textures/SnowFlake5.pcx b/Textures/snowFlake5.pcx similarity index 100% rename from Sources/Textures/SnowFlake5.pcx rename to Textures/snowFlake5.pcx diff --git a/Sources/Textures/SnowFlake6.pcx b/Textures/snowFlake6.pcx similarity index 100% rename from Sources/Textures/SnowFlake6.pcx rename to Textures/snowFlake6.pcx diff --git a/Sources/Textures/SnowFlake7.pcx b/Textures/snowFlake7.pcx similarity index 100% rename from Sources/Textures/SnowFlake7.pcx rename to Textures/snowFlake7.pcx diff --git a/Sources/Textures/SnowFlake8.pcx b/Textures/snowFlake8.pcx similarity index 100% rename from Sources/Textures/SnowFlake8.pcx rename to Textures/snowFlake8.pcx diff --git a/Sources/Textures/SnowFlake9.pcx b/Textures/snowFlake9.pcx similarity index 100% rename from Sources/Textures/SnowFlake9.pcx rename to Textures/snowFlake9.pcx diff --git a/make.bat b/make.bat new file mode 100644 index 0000000..77ac5ec --- /dev/null +++ b/make.bat @@ -0,0 +1,6 @@ +set UArtifactName=SmartCTF_ChaChaV6 +del %~dp0\..\System\%UArtifactName%.u +del %~dp0\System\%UArtifactName%.u +%~dp0\..\System\ucc.exe make ini=%~dp0\make.ini +%~dp0\..\System\ucc.exe stripsource %UArtifactName% +xcopy %~dp0\..\System\%UArtifactName%.u %~dp0\System\ \ No newline at end of file diff --git a/make.ini b/make.ini new file mode 100644 index 0000000..0a93ae4 --- /dev/null +++ b/make.ini @@ -0,0 +1,31 @@ +[Core.System] +Paths=../System/*.u +Paths=../Maps/*.unr +Paths=../Textures/*.utx +Paths=../Sounds/*.uax +Paths=../Music/*.umx + +[Engine.Engine] +EditorEngine=Editor.EditorEngine +Language=int + +[Editor.EditorEngine] +CacheSizeMegs=32 +EditPackages=Core +EditPackages=Engine +EditPackages=Editor +EditPackages=UWindow +EditPackages=Fire +EditPackages=IpDrv +EditPackages=UWeb +EditPackages=UBrowser +EditPackages=UnrealShare +EditPackages=UnrealI +EditPackages=UMenu +EditPackages=IpServer +EditPackages=Botpack +EditPackages=UTServerAdmin +EditPackages=UTMenu +EditPackages=UTBrowser +EditPackages=SmartCTF_ChaChaV6 +