2017-10-20 02:00:49 +00:00
Class xVotingHandler extends xVotingHandlerBase
config ( xMapVote ) ;
struct FGameModeOption
{
2021-05-03 19:06:02 +00:00
var config string GameName , GameShortName , GameClass , Mutators , Options , Prefix , ServerName ;
2017-10-20 02:00:49 +00:00
} ;
2021-06-26 21:32:59 +00:00
const CurrentVersion = 1 ;
var config int ConfigVersion ;
2017-10-20 02:00:49 +00:00
var config array < FGameModeOption > GameModes ;
2021-01-08 19:43:09 +00:00
var config int LastVotedGameInfo , VoteTime , MaxMapsOnList , VoteNumForOrgy ;
2017-10-20 02:00:49 +00:00
var config float MidGameVotePct , MapWinPct , MapChangeDelay ;
var config bool bNoWebAdmin ;
2021-01-08 19:43:09 +00:00
var config bool bNoMapVoteOrgy ;
2021-06-26 21:32:59 +00:00
var config bool bEnableAnnouncer ;
2017-10-20 02:00:49 +00:00
var class < Mutator > BaseMutator ;
var array < SoundCue > AnnouncerCues ;
var array < FMapEntry > Maps ;
var array < FVotedMaps > ActiveVotes ;
var array < xVotingReplication > ActiveVoters ;
var int iCurrentHistory , VoteTimeLeft , ShowMenuDelay ;
var string PendingMapURL ;
var KFGameReplicationInfo KF ;
var bool bMapvoteHasEnded , bMapVoteTimer , bHistorySaved ;
function PostBeginPlay ( )
{
local int i , j , z , n , UpV , DownV , Seq , NumPl ;
local string S , MapFile ;
2020-11-28 20:12:58 +00:00
if ( WorldInfo . Game . BaseMutator == None )
2017-10-20 02:00:49 +00:00
WorldInfo . Game . BaseMutator = Self ;
else WorldInfo . Game . BaseMutator . AddMutator ( Self ) ;
2023-05-14 02:49:12 +00:00
2020-11-28 20:12:58 +00:00
if ( bDeleteMe ) // This was a duplicate instance of the mutator.
2017-10-20 02:00:49 +00:00
return ;
2021-06-26 21:32:59 +00:00
InitConfig ( ) ;
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
MapFile = string ( WorldInfo . GetPackageName ( ) ) ;
iCurrentHistory = class 'xMapVoteHistory' . Static . GetMapHistory ( MapFile , WorldInfo . Title ) ;
// Build maplist.
z = 0 ;
2020-11-28 20:12:58 +00:00
for ( i = ( Class 'KFGameInfo' . Default . GameMapCycles . Length - 1 ) ; i >= 0 ; -- i )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
for ( j = ( Class 'KFGameInfo' . Default . GameMapCycles [ i ] . Maps . Length - 1 ) ; j >= 0 ; -- j )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( MaxMapsOnList > 0 && Class 'KFGameInfo' . Default . GameMapCycles [ i ] . Maps [ j ] ~ = MapFile ) // If we limit the maps count, remove current map.
2017-10-20 02:00:49 +00:00
continue ;
Maps . Length = z + 1 ;
Maps [ z ] . MapName = Class 'KFGameInfo' . Default . GameMapCycles [ i ] . Maps [ j ] ;
n = class 'xMapVoteHistory' . Static . GetMapHistory ( Maps [ z ] . MapName , "" ) ;
class 'xMapVoteHistory' . Static . GetHistory ( n , UpV , DownV , Seq , NumPl , S ) ;
Maps [ z ] . UpVotes = UpV ;
Maps [ z ] . DownVotes = DownV ;
Maps [ z ] . Sequence = Seq ;
Maps [ z ] . NumPlays = NumPl ;
Maps [ z ] . History = n ;
Maps [ z ] . MapTitle = S ;
++ z ;
}
}
2023-05-14 02:49:12 +00:00
2020-11-28 20:12:58 +00:00
if ( MaxMapsOnList > 0 )
2017-10-20 02:00:49 +00:00
{
// Remove random maps from list.
2020-11-28 20:12:58 +00:00
while ( Maps . Length > MaxMapsOnList )
2017-10-20 02:00:49 +00:00
Maps . Remove ( Rand ( Maps . Length ) , 1 ) ;
}
SetTimer ( 0.15 , false , 'SetupBroadcast' ) ;
SetTimer ( 1 , true , 'CheckEndGameEnded' ) ;
}
2020-11-28 21:54:57 +00:00
2021-06-26 21:32:59 +00:00
function InitConfig ( )
{
local bool ConfigChanged ;
2023-05-14 02:49:12 +00:00
2021-06-26 21:32:59 +00:00
ConfigChanged = False ;
2023-05-14 02:49:12 +00:00
// Parameters to check each initialization
2021-06-26 21:32:59 +00:00
if ( LastVotedGameInfo < 0 || LastVotedGameInfo >= GameModes . Length )
LastVotedGameInfo = 0 ;
2023-05-14 02:49:12 +00:00
2021-06-26 21:32:59 +00:00
if ( MapChangeDelay == 0 )
MapChangeDelay = 3 ;
2023-05-14 02:49:12 +00:00
2021-06-26 21:32:59 +00:00
if ( GameModes . Length == 0 ) // None specified, so use current settings.
{
GameModes . Length = 1 ;
GameModes [ 0 ] . GameName = "Killing Floor" ;
GameModes [ 0 ] . GameShortName = "KF" ;
GameModes [ 0 ] . GameClass = PathName ( WorldInfo . Game . Class ) ;
GameModes [ 0 ] . Mutators = "" ;
GameModes [ 0 ] . Prefix = "" ;
GameModes [ 0 ] . ServerName = "" ;
MidGameVotePct = 0.51 ;
MapWinPct = 0.75 ;
VoteTime = 35 ;
ConfigChanged = True ;
}
2023-05-14 02:49:12 +00:00
2021-06-26 21:32:59 +00:00
if ( VoteNumForOrgy <= 0 )
{
VoteNumForOrgy = 4 ;
bNoMapVoteOrgy = False ;
ConfigChanged = True ;
}
2023-05-14 02:49:12 +00:00
// Parameters that need to be added once when updating the config
2021-06-26 21:32:59 +00:00
switch ( ConfigVersion )
{
case 0 :
bEnableAnnouncer = True ;
2023-05-14 02:49:12 +00:00
2021-06-26 21:32:59 +00:00
case 2147483647 :
` log("[xVotingHandler] Config updated to version"@CurrentVersion);
break ;
2023-05-14 02:49:12 +00:00
2021-06-26 21:32:59 +00:00
case CurrentVersion :
` log("[xVotingHandler] Config is up-to-date");
break ;
2023-05-14 02:49:12 +00:00
2021-06-26 21:32:59 +00:00
default :
` log("[xVotingHandler] The config version is higher than the current version (are you using an old mutator?)");
` log("[xVotingHandler] Config version is"@ConfigVersion@"but current version is"@CurrentVersion);
` log("[xVotingHandler] The config version will be changed to "@CurrentVersion);
break ;
}
if ( ConfigChanged || ( ConfigVersion != CurrentVersion ) )
{
ConfigVersion = CurrentVersion ;
SaveConfig ( ) ;
}
}
2017-10-20 02:00:49 +00:00
function AddMutator ( Mutator M )
{
2020-11-28 20:12:58 +00:00
if ( M != Self ) // Make sure we don't get added twice.
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( M . Class == Class )
2017-10-20 02:00:49 +00:00
M . Destroy ( ) ;
else Super . AddMutator ( M ) ;
}
}
function SetupBroadcast ( )
{
local xVoteBroadcast B ;
local WebServer W ;
local WebAdmin A ;
local xVoteWebApp xW ;
local byte i ;
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
B = Spawn ( class 'xVoteBroadcast' ) ;
B . Handler = Self ;
B . NextBroadcaster = WorldInfo . Game . BroadcastHandler ;
WorldInfo . Game . BroadcastHandler = B ;
2020-11-28 20:12:58 +00:00
if ( ! bNoWebAdmin )
2017-10-20 02:00:49 +00:00
{
foreach AllActors ( class 'WebServer' , W )
break ;
2020-11-28 20:12:58 +00:00
if ( W != None )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
for ( i = 0 ; ( i < 10 && A == None ) ; ++ i )
2017-10-20 02:00:49 +00:00
A = WebAdmin ( W . ApplicationObjects [ i ] ) ;
2020-11-28 20:12:58 +00:00
if ( A != None )
2017-10-20 02:00:49 +00:00
{
xW = new ( None ) class 'xVoteWebApp' ;
A . addQueryHandler ( xW ) ;
}
else ` Log("X-VoteWebAdmin ERROR: No valid WebAdmin application found!");
}
else ` Log("X-VoteWebAdmin ERROR: No WebServer object found!");
}
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
final function AddVote ( int Count , int MapIndex , int GameIndex )
2017-10-20 02:00:49 +00:00
{
local int i , j ;
2020-11-28 20:12:58 +00:00
if ( bMapvoteHasEnded )
2017-10-20 02:00:49 +00:00
return ;
2020-11-28 20:12:58 +00:00
for ( i = 0 ; i < ActiveVotes . Length ; ++ i )
if ( ActiveVotes [ i ] . GameIndex == GameIndex && ActiveVotes [ i ] . MapIndex == MapIndex )
2017-10-20 02:00:49 +00:00
{
ActiveVotes [ i ] . NumVotes += Count ;
2020-11-28 20:12:58 +00:00
for ( j = ( ActiveVoters . Length - 1 ) ; j >= 0 ; -- j )
2017-10-20 02:00:49 +00:00
ActiveVoters [ j ] . ClientReceiveVote ( GameIndex , MapIndex , ActiveVotes [ i ] . NumVotes ) ;
2020-11-28 20:12:58 +00:00
if ( ActiveVotes [ i ] . NumVotes <= 0 )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
for ( j = ( ActiveVoters . Length - 1 ) ; j >= 0 ; -- j )
if ( ActiveVoters [ j ] . DownloadStage == 2 && ActiveVoters [ j ] . DownloadIndex >= i && ActiveVoters [ j ] . DownloadIndex > 0 ) // Make sure client doesn't skip a download at this point.
2017-10-20 02:00:49 +00:00
-- ActiveVoters [ j ] . DownloadIndex ;
ActiveVotes . Remove ( i , 1 ) ;
}
return ;
}
2020-11-28 20:12:58 +00:00
if ( Count <= 0 )
2017-10-20 02:00:49 +00:00
return ;
ActiveVotes . Length = i + 1 ;
ActiveVotes [ i ] . GameIndex = GameIndex ;
ActiveVotes [ i ] . MapIndex = MapIndex ;
ActiveVotes [ i ] . NumVotes = Count ;
2020-11-28 20:12:58 +00:00
for ( j = ( ActiveVoters . Length - 1 ) ; j >= 0 ; -- j )
2017-10-20 02:00:49 +00:00
ActiveVoters [ j ] . ClientReceiveVote ( GameIndex , MapIndex , Count ) ;
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
final function LogoutPlayer ( PlayerController PC )
2017-10-20 02:00:49 +00:00
{
local int i ;
2023-05-14 02:49:12 +00:00
2020-11-28 20:12:58 +00:00
for ( i = ( ActiveVoters . Length - 1 ) ; i >= 0 ; -- i )
if ( ActiveVoters [ i ] . PlayerOwner == PC )
2017-10-20 02:00:49 +00:00
{
ActiveVoters [ i ] . Destroy ( ) ;
break ;
}
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
final function LoginPlayer ( PlayerController PC )
2017-10-20 02:00:49 +00:00
{
local xVotingReplication R ;
local int i ;
2023-05-14 02:49:12 +00:00
2020-11-28 20:12:58 +00:00
for ( i = ( ActiveVoters . Length - 1 ) ; i >= 0 ; -- i )
if ( ActiveVoters [ i ] . PlayerOwner == PC )
2017-10-20 02:00:49 +00:00
return ;
R = Spawn ( class 'xVotingReplication' , PC ) ;
R . VoteHandler = Self ;
ActiveVoters . AddItem ( R ) ;
}
function NotifyLogout ( Controller Exiting )
{
2020-11-28 20:12:58 +00:00
if ( PlayerController ( Exiting ) != None )
2017-10-20 02:00:49 +00:00
LogoutPlayer ( PlayerController ( Exiting ) ) ;
2020-11-28 20:04:55 +00:00
if ( NextMutator != None )
2017-10-20 02:00:49 +00:00
NextMutator . NotifyLogout ( Exiting ) ;
}
2020-11-28 21:54:57 +00:00
2017-10-20 02:00:49 +00:00
function NotifyLogin ( Controller NewPlayer )
{
2020-11-28 20:12:58 +00:00
if ( PlayerController ( NewPlayer ) != None )
2017-10-20 02:00:49 +00:00
LoginPlayer ( PlayerController ( NewPlayer ) ) ;
2020-11-28 20:04:55 +00:00
if ( NextMutator != None )
2017-10-20 02:00:49 +00:00
NextMutator . NotifyLogin ( NewPlayer ) ;
}
2020-11-28 20:04:55 +00:00
function ClientDownloadInfo ( xVotingReplication V )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( bMapvoteHasEnded )
2017-10-20 02:00:49 +00:00
{
V . DownloadStage = 255 ;
return ;
}
2023-05-14 02:49:12 +00:00
2020-11-28 20:12:58 +00:00
switch ( V . DownloadStage )
2017-10-20 02:00:49 +00:00
{
case 0 : // Game modes.
2020-11-28 20:12:58 +00:00
if ( V . DownloadIndex >= GameModes . Length )
2017-10-20 02:00:49 +00:00
break ;
V . ClientReceiveGame ( V . DownloadIndex , GameModes [ V . DownloadIndex ] . GameName , GameModes [ V . DownloadIndex ] . GameShortName , GameModes [ V . DownloadIndex ] . Prefix ) ;
++ V . DownloadIndex ;
return ;
case 1 : // Maplist.
2020-11-28 20:12:58 +00:00
if ( V . DownloadIndex >= Maps . Length )
2017-10-20 02:00:49 +00:00
break ;
2020-11-28 20:12:58 +00:00
if ( Maps [ V . DownloadIndex ] . MapTitle == "" )
2017-10-20 02:00:49 +00:00
V . ClientReceiveMap ( V . DownloadIndex , Maps [ V . DownloadIndex ] . MapName , Maps [ V . DownloadIndex ] . UpVotes , Maps [ V . DownloadIndex ] . DownVotes , Maps [ V . DownloadIndex ] . Sequence , Maps [ V . DownloadIndex ] . NumPlays ) ;
else V . ClientReceiveMap ( V . DownloadIndex , Maps [ V . DownloadIndex ] . MapName , Maps [ V . DownloadIndex ] . UpVotes , Maps [ V . DownloadIndex ] . DownVotes , Maps [ V . DownloadIndex ] . Sequence , Maps [ V . DownloadIndex ] . NumPlays , Maps [ V . DownloadIndex ] . MapTitle ) ;
++ V . DownloadIndex ;
return ;
case 2 : // Current votes.
2020-11-28 20:12:58 +00:00
if ( V . DownloadIndex >= ActiveVotes . Length )
2017-10-20 02:00:49 +00:00
break ;
V . ClientReceiveVote ( ActiveVotes [ V . DownloadIndex ] . GameIndex , ActiveVotes [ V . DownloadIndex ] . MapIndex , ActiveVotes [ V . DownloadIndex ] . NumVotes ) ;
++ V . DownloadIndex ;
return ;
default :
V . ClientReady ( LastVotedGameInfo ) ;
V . DownloadStage = 255 ;
return ;
}
++ V . DownloadStage ;
V . DownloadIndex = 0 ;
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
function ClientCastVote ( xVotingReplication V , int GameIndex , int MapIndex , bool bAdminForce )
2017-10-20 02:00:49 +00:00
{
local int i ;
2020-11-28 20:12:58 +00:00
if ( bMapvoteHasEnded )
2017-10-20 02:00:49 +00:00
return ;
2020-11-28 20:12:58 +00:00
if ( bAdminForce && V . PlayerOwner . PlayerReplicationInfo . bAdmin )
2017-10-20 02:00:49 +00:00
{
SwitchToLevel ( GameIndex , MapIndex , true ) ;
return ;
}
2020-11-28 20:12:58 +00:00
if ( ! Class 'xUI_MapVote' . Static . BelongsToPrefix ( Maps [ MapIndex ] . MapName , GameModes [ GameIndex ] . Prefix ) )
2017-10-20 02:00:49 +00:00
{
V . PlayerOwner . ClientMessage ( "Error: Can't vote that map (wrong Prefix to that game mode)!" ) ;
return ;
}
2020-11-28 20:12:58 +00:00
if ( V . CurrentVote [ 0 ] >= 0 )
2017-10-20 02:00:49 +00:00
AddVote ( - 1 , V . CurrentVote [ 1 ] , V . CurrentVote [ 0 ] ) ;
V . CurrentVote [ 0 ] = GameIndex ;
V . CurrentVote [ 1 ] = MapIndex ;
AddVote ( 1 , MapIndex , GameIndex ) ;
2020-11-28 20:12:58 +00:00
for ( i = ( ActiveVoters . Length - 1 ) ; i >= 0 ; -- i )
2017-10-20 02:00:49 +00:00
ActiveVoters [ i ] . ClientNotifyVote ( V . PlayerOwner . PlayerReplicationInfo , GameIndex , MapIndex ) ;
TallyVotes ( ) ;
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
function ClientRankMap ( xVotingReplication V , bool bUp )
2017-10-20 02:00:49 +00:00
{
class 'xMapVoteHistory' . Static . AddMapKarma ( iCurrentHistory , bUp ) ;
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
function ClientDisconnect ( xVotingReplication V )
2017-10-20 02:00:49 +00:00
{
ActiveVoters . RemoveItem ( V ) ;
2020-11-28 20:12:58 +00:00
if ( V . CurrentVote [ 0 ] >= 0 )
2017-10-20 02:00:49 +00:00
AddVote ( - 1 , V . CurrentVote [ 1 ] , V . CurrentVote [ 0 ] ) ;
TallyVotes ( ) ;
}
2020-11-28 20:04:55 +00:00
final function float GetPctOf ( int Nom , int Denom )
2017-10-20 02:00:49 +00:00
{
local float R ;
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
R = float ( Nom ) / float ( Denom ) ;
return R ;
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
final function TallyVotes ( optional bool bForce )
2017-10-20 02:00:49 +00:00
{
local int i , NumVotees , c , j ;
local array < int > Candidates ;
2020-11-28 20:12:58 +00:00
if ( bMapvoteHasEnded )
2017-10-20 02:00:49 +00:00
return ;
NumVotees = ActiveVoters . Length ;
c = 0 ;
2020-11-28 20:12:58 +00:00
if ( bForce )
2017-10-20 02:00:49 +00:00
{
// First check for highest result.
2020-11-28 20:12:58 +00:00
for ( i = ( ActiveVotes . Length - 1 ) ; i >= 0 ; -- i )
2017-10-20 02:00:49 +00:00
c = Max ( c , ActiveVotes [ i ] . NumVotes ) ;
2023-05-14 02:49:12 +00:00
2020-11-28 20:12:58 +00:00
if ( c > 0 )
2017-10-20 02:00:49 +00:00
{
// Then check how many votes for the best.
2020-11-28 20:12:58 +00:00
for ( i = ( ActiveVotes . Length - 1 ) ; i >= 0 ; -- i )
if ( ActiveVotes [ i ] . NumVotes == c )
2017-10-20 02:00:49 +00:00
Candidates . AddItem ( i ) ;
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
// Finally pick a random winner from the best.
c = Candidates [ Rand ( Candidates . Length ) ] ;
2023-05-14 02:49:12 +00:00
2021-01-08 19:43:09 +00:00
// If more then "VoteNumForOrgy" voters and everyone voted same map?!!! Give the mapvote some orgy.
2021-06-26 21:32:59 +00:00
if ( bEnableAnnouncer && ! bNoMapVoteOrgy && NumVotees >= VoteNumForOrgy && ActiveVotes . Length == 1 )
2017-10-20 02:00:49 +00:00
{
2021-01-08 19:43:09 +00:00
for ( j = ( ActiveVoters . Length - 1 ) ; j >= 0 ; -- j )
2017-10-20 02:00:49 +00:00
ActiveVoters [ j ] . PlayerOwner . ClientPlaySound ( AnnouncerCues [ 13 ] ) ;
}
SwitchToLevel ( ActiveVotes [ c ] . GameIndex , ActiveVotes [ c ] . MapIndex , false ) ;
}
else
{
// Pick a random map to win.
c = Rand ( Maps . Length ) ;
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
// Pick a random gametype to win along with it.
2020-11-28 20:12:58 +00:00
for ( i = ( GameModes . Length - 1 ) ; i >= 0 ; -- i )
if ( Class 'xUI_MapVote' . Static . BelongsToPrefix ( Maps [ c ] . MapName , GameModes [ i ] . Prefix ) )
2017-10-20 02:00:49 +00:00
Candidates . AddItem ( i ) ;
2023-05-14 02:49:12 +00:00
2020-11-28 20:12:58 +00:00
if ( Candidates . Length == 0 ) // Odd, a map without gametype...
2017-10-20 02:00:49 +00:00
i = Rand ( GameModes . Length ) ;
else i = Candidates [ Rand ( Candidates . Length ) ] ;
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
SwitchToLevel ( i , c , false ) ;
}
return ;
}
// Check for insta-win vote.
2020-11-28 20:12:58 +00:00
for ( i = ( ActiveVotes . Length - 1 ) ; i >= 0 ; -- i )
2017-10-20 02:00:49 +00:00
{
c += ActiveVotes [ i ] . NumVotes ;
2020-11-28 20:12:58 +00:00
if ( GetPctOf ( ActiveVotes [ i ] . NumVotes , NumVotees ) >= MapWinPct )
2017-10-20 02:00:49 +00:00
{
2021-01-09 01:12:46 +00:00
// If more then 4 voters and everyone voted same map?!!! Give the mapvote some orgy.
2021-06-26 21:32:59 +00:00
if ( bEnableAnnouncer && ! bNoMapVoteOrgy && NumVotees >= VoteNumForOrgy && ActiveVotes . Length == 1 )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
for ( j = ( ActiveVoters . Length - 1 ) ; j >= 0 ; -- j )
2017-10-20 02:00:49 +00:00
ActiveVoters [ j ] . PlayerOwner . ClientPlaySound ( AnnouncerCues [ 13 ] ) ;
}
SwitchToLevel ( ActiveVotes [ i ] . GameIndex , ActiveVotes [ i ] . MapIndex , false ) ;
return ;
}
}
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
// Check for mid-game voting timer.
2020-11-28 20:12:58 +00:00
if ( ! bMapVoteTimer && NumVotees > 0 && GetPctOf ( c , NumVotees ) >= MidGameVotePct )
2017-10-20 02:00:49 +00:00
StartMidGameVote ( true ) ;
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
final function StartMidGameVote ( bool bMidGame )
2017-10-20 02:00:49 +00:00
{
local int i ;
2020-11-28 20:12:58 +00:00
if ( bMapVoteTimer || bMapvoteHasEnded )
2017-10-20 02:00:49 +00:00
return ;
bMapVoteTimer = true ;
2020-11-28 20:12:58 +00:00
if ( bMidGame )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
for ( i = ( ActiveVoters . Length - 1 ) ; i >= 0 ; -- i )
2017-10-20 02:00:49 +00:00
ActiveVoters [ i ] . ClientNotifyVoteTime ( 0 ) ;
}
ShowMenuDelay = 5 ;
VoteTimeLeft = Max ( VoteTime , 10 ) ;
SetTimer ( 1 , true ) ;
}
2020-11-28 21:54:57 +00:00
2017-10-20 02:00:49 +00:00
function CheckEndGameEnded ( )
{
2020-11-28 20:12:58 +00:00
if ( KF == None )
2017-10-20 02:00:49 +00:00
{
KF = KFGameReplicationInfo ( WorldInfo . GRI ) ;
2020-11-28 20:12:58 +00:00
if ( KF == None )
2017-10-20 02:00:49 +00:00
return ;
}
2020-11-28 20:12:58 +00:00
if ( KF . bMatchIsOver ) // HACK, since KFGameInfo_Survival doesn't properly notify mutators of this!
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( ! bMapVoteTimer )
2017-10-20 02:00:49 +00:00
StartMidGameVote ( false ) ;
ClearTimer ( 'CheckEndGameEnded' ) ;
WorldInfo . Game . ClearTimer ( 'ShowPostGameMenu' ) ;
}
}
2020-11-28 21:54:57 +00:00
2017-10-20 02:00:49 +00:00
function bool HandleRestartGame ( )
{
2020-11-28 20:12:58 +00:00
if ( ! bMapVoteTimer )
2017-10-20 02:00:49 +00:00
StartMidGameVote ( false ) ;
return true ;
}
2020-11-28 21:54:57 +00:00
2017-10-20 02:00:49 +00:00
function Timer ( )
{
local int i ;
local SoundCue FX ;
2020-11-28 20:12:58 +00:00
if ( bMapvoteHasEnded )
2017-10-20 02:00:49 +00:00
{
2021-01-08 19:43:09 +00:00
// NOTE:
// "WorldInfo.NetMode != NM_Standalone" prevents cyclic unsuccessful map change in single player mode.
// I have not tested how this code will behave if it really fails to change the map.
// Most likely there should be another solution here, but for now it will do.
if ( WorldInfo . NetMode != NM _Standalone && WorldInfo . NextSwitchCountdown <= 0. f ) // Mapswitch failed, force to random other map.
2017-10-20 02:00:49 +00:00
{
ActiveVotes . Length = 0 ;
bMapvoteHasEnded = false ;
TallyVotes ( true ) ;
}
return ;
}
2020-11-28 20:12:58 +00:00
if ( ShowMenuDelay > 0 && -- ShowMenuDelay == 0 )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
for ( i = ( ActiveVoters . Length - 1 ) ; i >= 0 ; -- i )
2017-10-20 02:00:49 +00:00
ActiveVoters [ i ] . ClientOpenMapvote ( true ) ;
}
-- VoteTimeLeft ;
2020-11-28 20:12:58 +00:00
if ( VoteTimeLeft == 0 )
2017-10-20 02:00:49 +00:00
{
TallyVotes ( true ) ;
}
2020-11-28 20:12:58 +00:00
else if ( VoteTimeLeft <= 10 || VoteTimeLeft == 20 || VoteTimeLeft == 30 || VoteTimeLeft == 60 )
2017-10-20 02:00:49 +00:00
{
FX = None ;
2020-11-28 20:12:58 +00:00
if ( VoteTimeLeft <= 10 )
2017-10-20 02:00:49 +00:00
FX = AnnouncerCues [ VoteTimeLeft - 1 ] ;
2020-11-28 20:12:58 +00:00
else if ( VoteTimeLeft == 20 )
2017-10-20 02:00:49 +00:00
FX = AnnouncerCues [ 10 ] ;
2020-11-28 20:12:58 +00:00
else if ( VoteTimeLeft == 30 )
2017-10-20 02:00:49 +00:00
FX = AnnouncerCues [ 11 ] ;
2020-11-28 20:12:58 +00:00
else if ( VoteTimeLeft == 60 )
2017-10-20 02:00:49 +00:00
FX = AnnouncerCues [ 12 ] ;
2020-11-28 20:12:58 +00:00
for ( i = ( ActiveVoters . Length - 1 ) ; i >= 0 ; -- i )
2017-10-20 02:00:49 +00:00
{
ActiveVoters [ i ] . ClientNotifyVoteTime ( VoteTimeLeft ) ;
2021-06-26 21:32:59 +00:00
if ( bEnableAnnouncer && FX != None )
2017-10-20 02:00:49 +00:00
ActiveVoters [ i ] . PlayerOwner . ClientPlaySound ( FX ) ;
}
}
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
final function SwitchToLevel ( int GameIndex , int MapIndex , bool bAdminForce )
2017-10-20 02:00:49 +00:00
{
local int i ;
local string S ;
2020-11-28 20:12:58 +00:00
if ( bMapvoteHasEnded )
2017-10-20 02:00:49 +00:00
return ;
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
Default . LastVotedGameInfo = GameIndex ;
Class . Static . StaticSaveConfig ( ) ;
bMapvoteHasEnded = true ;
2020-11-28 20:12:58 +00:00
if ( ! bAdminForce && ! bHistorySaved )
2017-10-20 02:00:49 +00:00
{
class 'xMapVoteHistory' . Static . UpdateMapHistory ( Maps [ MapIndex ] . History ) ;
class 'xMapVoteHistory' . Static . StaticSaveConfig ( ) ;
bHistorySaved = true ;
}
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
S = Maps [ MapIndex ] . MapName$ " (" $GameModes [ GameIndex ] . GameName$ ")" ;
2020-11-28 20:12:58 +00:00
for ( i = ( ActiveVoters . Length - 1 ) ; i >= 0 ; -- i )
2017-10-20 02:00:49 +00:00
{
KFPlayerController ( ActiveVoters [ i ] . PlayerOwner ) . ShowConnectionProgressPopup ( PMT _AdminMessage , "Switching to level:" , S ) ;
ActiveVoters [ i ] . ClientNotifyVoteWin ( GameIndex , MapIndex , bAdminForce ) ;
}
2023-05-14 02:49:12 +00:00
2017-10-20 02:00:49 +00:00
PendingMapURL = Maps [ MapIndex ] . MapName$ "?Game=" $GameModes [ GameIndex ] . GameClass$ "?Mutator=" $PathName ( BaseMutator ) ;
2020-11-28 20:12:58 +00:00
if ( GameModes [ GameIndex ] . Mutators != "" )
2017-10-20 02:00:49 +00:00
PendingMapURL $ = "," $GameModes [ GameIndex ] . Mutators ;
2020-11-28 20:12:58 +00:00
if ( GameModes [ GameIndex ] . Options != "" )
2017-10-20 02:00:49 +00:00
PendingMapURL $ = "?" $GameModes [ GameIndex ] . Options ;
` Log("MapVote: Switch map to " $ PendingMapURL);
2021-05-03 19:06:02 +00:00
if ( GameModes [ GameIndex ] . ServerName != "" )
{
WorldInfo . GRI . ServerName = GameModes [ GameIndex ] . ServerName ;
WorldInfo . GRI . SaveConfig ( ) ;
` Log("MapVote: Next ServerName: " $ WorldInfo.GRI.ServerName);
}
2017-10-20 02:00:49 +00:00
SetTimer ( FMax ( MapChangeDelay , 0.1 ) , false , 'PendingSwitch' ) ;
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:12:58 +00:00
function Pendingswitch ( )
2017-10-20 02:00:49 +00:00
{
WorldInfo . ServerTravel ( PendingMapURL , false ) ;
SetTimer ( 1 , true ) ;
}
2020-11-28 20:04:55 +00:00
final function ParseCommand ( string Cmd , PlayerController PC )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( Cmd ~ = "Help" )
2017-10-20 02:00:49 +00:00
{
PC . ClientMessage ( "MapVote commands:" ) ;
PC . ClientMessage ( "!MapVote - Show mapvote menu" ) ;
PC . ClientMessage ( "!AddMap <Mapname> - Add map to mapvote" ) ;
PC . ClientMessage ( "!RemoveMap <Mapname> - Remove map from mapvote" ) ;
}
2020-11-28 20:12:58 +00:00
else if ( Cmd ~ = "MapVote" )
2017-10-20 02:00:49 +00:00
ShowMapVote ( PC ) ;
2020-11-28 20:12:58 +00:00
else if ( ! PC . PlayerReplicationInfo . bAdmin && ! PC . IsA ( 'MessagingSpectator' ) )
2017-10-20 02:00:49 +00:00
return ;
2020-11-28 20:12:58 +00:00
else if ( Left ( Cmd , 7 ) ~ = "AddMap " )
2017-10-20 02:00:49 +00:00
{
Cmd = Mid ( Cmd , 7 ) ;
PC . ClientMessage ( "Added map '" $Cmd$ "'!" ) ;
AddMap ( Cmd ) ;
}
2020-11-28 20:12:58 +00:00
else if ( Left ( Cmd , 10 ) ~ = "RemoveMap " )
2017-10-20 02:00:49 +00:00
{
Cmd = Mid ( Cmd , 10 ) ;
2020-11-28 20:12:58 +00:00
if ( RemoveMap ( Cmd ) )
2017-10-20 02:00:49 +00:00
PC . ClientMessage ( "Removed map '" $Cmd$ "'!" ) ;
else PC . ClientMessage ( "Map '" $Cmd$ "' not found!" ) ;
}
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
function ShowMapVote ( PlayerController PC )
2017-10-20 02:00:49 +00:00
{
local int i ;
2020-11-28 20:12:58 +00:00
if ( bMapvoteHasEnded )
2017-10-20 02:00:49 +00:00
return ;
2020-11-28 20:12:58 +00:00
for ( i = ( ActiveVoters . Length - 1 ) ; i >= 0 ; -- i )
if ( ActiveVoters [ i ] . PlayerOwner == PC )
2017-10-20 02:00:49 +00:00
{
ActiveVoters [ i ] . ClientOpenMapvote ( false ) ;
return ;
}
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
final function AddMap ( string M )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( Class 'KFGameInfo' . Default . GameMapCycles . Length == 0 )
2017-10-20 02:00:49 +00:00
Class 'KFGameInfo' . Default . GameMapCycles . Length = 1 ;
Class 'KFGameInfo' . Default . GameMapCycles [ 0 ] . Maps . AddItem ( M ) ;
Class 'KFGameInfo' . Static . StaticSaveConfig ( ) ;
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
final function bool RemoveMap ( string M )
2017-10-20 02:00:49 +00:00
{
local int i , j ;
2020-11-28 20:12:58 +00:00
for ( i = ( Class 'KFGameInfo' . Default . GameMapCycles . Length - 1 ) ; i >= 0 ; -- i )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
for ( j = ( Class 'KFGameInfo' . Default . GameMapCycles [ i ] . Maps . Length - 1 ) ; j >= 0 ; -- j )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( Class 'KFGameInfo' . Default . GameMapCycles [ i ] . Maps [ j ] ~ = M )
2017-10-20 02:00:49 +00:00
{
Class 'KFGameInfo' . Default . GameMapCycles [ i ] . Maps . Remove ( j , 1 ) ;
Class 'KFGameInfo' . Static . StaticSaveConfig ( ) ;
return true ;
}
}
}
return false ;
}
defaultproperties
{
BaseMutator = Class 'xVotingHandler'
AnnouncerCues . Add ( SoundCue 'xVoteAnnouncer.VX_one_Cue' )
AnnouncerCues . Add ( SoundCue 'xVoteAnnouncer.VX_two_Cue' )
AnnouncerCues . Add ( SoundCue 'xVoteAnnouncer.VX_three_Cue' )
AnnouncerCues . Add ( SoundCue 'xVoteAnnouncer.VX_four_Cue' )
AnnouncerCues . Add ( SoundCue 'xVoteAnnouncer.VX_five_Cue' )
AnnouncerCues . Add ( SoundCue 'xVoteAnnouncer.VX_six_Cue' )
AnnouncerCues . Add ( SoundCue 'xVoteAnnouncer.VX_seven_Cue' )
AnnouncerCues . Add ( SoundCue 'xVoteAnnouncer.VX_eight_Cue' )
AnnouncerCues . Add ( SoundCue 'xVoteAnnouncer.VX_nine_Cue' )
AnnouncerCues . Add ( SoundCue 'xVoteAnnouncer.VX_ten_Cue' )
AnnouncerCues . Add ( SoundCue 'xVoteAnnouncer.VX_20_seconds_Cue' )
AnnouncerCues . Add ( SoundCue 'xVoteAnnouncer.VX_30_seconds_Cue' )
AnnouncerCues . Add ( SoundCue 'xVoteAnnouncer.VX_1_minute_Cue' )
AnnouncerCues . Add ( SoundCue 'xVoteAnnouncer.VX_HolyShit_Cue' )
2023-05-14 02:49:12 +00:00
}