class AMC extends Mutator
	config(AdjustingMapcycle);
	
struct MapConfig
{
	var string mapname;
	var int minAvgPlayers;
	var int maxAvgPlayers;
	var int skipCount;
};	

var config MapConfig mapcycle[32];
var config int currentIndex;
var bool bPostInit;
var bool bMsgShown;
//////////////////////
var Pawn skipVotes[16];
var config float skipPercentage;
//////////////////////
var config float avgPopulation;
//////////////////////
var bool bNotEnded;

var string Reason;

function PostBeginPlay() 
{
	local int i;
	if(bPostInit)
		return;
	
	bNotEnded = True;
	bPostInit = True;
	//Level.Game.RegisterMessageMutator(Self); -> ELS bug... somewhere
	SetTimer(60 * Level.TimeDilation, True);
	
	for(i = 0;i<32;i++)//@debug
	{
		if(mapcycle[i].mapname != "")
			Log(mapcycle[i].mapname $
				" ||| " $ mapcycle[i].minAvgPlayers $
				" - " $ mapcycle[i].maxAvgPlayers);
	}
}

function Timer()
{
	if(!bMsgShown)
	{
		Self.BroadcastMessage("If you want to see this map skipped say !skip.");
		Self.BroadcastMessage(int(100 * skipPercentage) $ "% !skip-votes needed.");
		Self.BroadcastMessage(mapcycle[currentIndex].mapName $ " used for " $ 
			mapcycle[currentIndex].minAvgPlayers $ " - " $ mapcycle[currentIndex].maxAvgPlayers $
			" players.");
			
		bMsgShown = True;
	}

	if(bNotEnded)
	{
		avgPopulation += (Level.Game.NumPlayers - avgPopulation) / 4;
		Log(Level.Game.NumPlayers $ " -> " $ avgPopulation);
	}
	else //delay after we ended game
	{
		Level.ServerTravel(mapcycle[currentIndex].mapname, False);
		//Level.Game.ProcessServerTravel(mapcycle[currentIndex].mapname, False);
	}
}

function bool MutatorTeamMessage(Actor Sender, Pawn Receiver, PlayerReplicationInfo PRI, coerce string Msg, name Type, optional bool bBeep) 
{
	if(Sender == Receiver) 
	{ 
		if (Left(Msg, 5) == "!skip") 
		{ 
			if(Level.TimeSeconds < 35)
			{
				Receiver.ClientMessage("Wait for " $ int(1 + (35 - Level.TimeSeconds)/Level.TimeDilation) $ " seconds then say it again.");
			}
			else
				ProcessSkipVote(Receiver);
		}
	}
  
	if(NextMessageMutator != None)
		return NextMessageMutator.MutatorTeamMessage( Sender, Receiver, PRI, Msg, Type, bBeep );
	else
		return true;
}

function ProcessSkipVote(Pawn p)
{
	local int i, k;
	local bool bDone;
	local Actor A;
		
	//clean
	for(i = 0; i < 16; i++)
	{
		if(skipVotes[i] == None)
		{
			if(!bDone)
			{
				skipVotes[i] = p;
				k++;
				bDone = True;
			}
		}
		else //count
			k++;
	}
	
	if(k >= skipPercentage * Level.Game.NumPlayers)
	{
		if(!NextMap(True))
		{
			BroadcastMessage("No other map matching current population", True, 'CriticalEvent');
		}
		else
		{
			BroadcastMessage("skip this map", True, 'CriticalEvent');
			mapCycle[currentIndex].skipCount ++;
			
			Level.Game.bGameEnded = true;
			foreach AllActors(class'Actor', A, 'EndGame')
				A.trigger(Level.Game, none);

			if (Level.Game.LocalLog != None)
			{
				Level.Game.LocalLog.LogGameEnd(Reason);
				Level.Game.LocalLog.StopLog();
				if (Level.Game.bBatchLocal)
					Level.Game.LocalLog.ExecuteSilentLogBatcher();
				Level.Game.LocalLog.Destroy();
				Level.Game.LocalLog = None;
			}
			if (Level.Game.WorldLog != None)
			{
				Level.Game.WorldLog.LogGameEnd(Reason);
				Level.Game.WorldLog.StopLog();
				Level.Game.WorldLog.ExecuteWorldLogBatcher();
				Level.Game.WorldLog.Destroy();
				Level.Game.WorldLog = None;
			}
		}
	}
}

function bool Nextmap(bool skipMap)
{
	local int oldIndex;
	
	oldIndex = currentIndex;

	Log(currentIndex $ " old");
	//find a matching map -> maybe little offset due to slow convergence in the end
	while(mapcycle[++currentIndex].mapname == "" || 
		mapcycle[currentIndex].minAvgPlayers > avgPopulation + 0.2 ||
		mapcycle[currentIndex].maxAvgPlayers < avgPopulation - 0.2)
		{
			if(currentIndex == oldIndex)//no els
				break;
				
			if(currentIndex == 31)//wrap
				currentIndex = -1;
		}
	Log(currentIndex $ " new");
	
	if(currentIndex == oldIndex)//ending on the same map!
		return False;

	SaveConfig();
	
	//prepare
	DeathMatchPlus(Level.Game).bDontRestart = True;
	
	//last calculation
	avgPopulation += (Level.Game.NumPlayers - avgPopulation) / 4;
	SaveConfig();//save now
	Log(Level.Game.NumPlayers $ " ->NM " $ avgPopulation);
	
	//delay
	bNotEnded = False;//delay mode in timer()
	if(skipMap)
		SetTimer(10, False);
	else
		SetTimer(15, False);
		
	return True;
}


function bool HandleEndGame()
{
	Super.HandleEndGame();
	
	
	if(True)//tgp.teams[0].Score != tgp.teams[1].Score)@todo -> determine ?TDM only
	{
		//find next suitable map - and start end-game timer
		NextMap(False);
		//show winner
		Level.Game.SetEndCams("teamscorelimit");
		
		return True;
	}
	else
		return False;
}


defaultproperties
{
	skipPercentage=0.6
	Reason="Players want to skip this map."
}