#library "COOPEXIT"
#include "zcommon.acs"


//Globals 
#define MAXPLAYERS 64
#define SCALEPERPLAYER 0.1

#define TIMER_ID 7892356
#define MESSAGE_ID 235968

bool pressed[MAXPLAYERS];
bool playerAlreadyDied[MAXPLAYERS]; // for survival
bool timeractive = false;
bool pressedonce = false;

int storedTimer = 0;
int finalTimer = 999999;
int players = 6;
int requiredCount = 0;
int smashedExits = 0;
int rate = 5;

//Cvar Variables
int debug = 0;
int finalCountdown = 0;
int playerfinalNum = 0;
int playertimerNum = 0;

//We need to define this globally so other scripts can see it, This is for the timer
int t = 0;

//Initialize
script "InitializeCoopExit" OPEN
{
	smashedExits = 0;
	storedTimer = GetCVAR("ce_timelimit");
	finalCountdown = GetCVAR("ce_finalcountdown");
	playerfinalNum = GetCVAR("ce_playerfinalnum");
}

// A player has joined, raise the requirement
script "PlayerJoinedCoopExit" ENTER
{
	requiredCount++; 
	playerAlreadyDied[PlayerNumber()] = false;
	// don't show "requirement raised" during first second on map, or while timer isn't yet on
	if(requiredCount-smashedExits > 1 && Timer() > 35 && timeractive)
	{
		showHint(strParam(n:0, s:" has joined the game\n", s:howMany(), s:" players have yet to activate the exit."), CR_GREEN);
	}
	else if(requiredCount-smashedExits == 1 && requiredCount > 1)
	{
		// [Ms] Note that "only one more exit" cannot happen on player joining,
		//		because that would mean there were 0 exits required before,
		//		and if there were 0, then map would have already ended.
		showHint("(Impossible! Inform the Developer!)\nOnly one player has yet to activate the exit.\nHurry up!", CR_RED);
	}
}

function void playerLeavePlayState(int gone){
	if(pressed[gone])
	{
		smashedExits--;
		pressed[gone] = false;
		
		if(finalTimer >= finalCountdown)
			finalTimer = finalTimer * (PlayerCount()+1) / PlayerCount();
		//else
			//finalTimer = storedTimer;
		
		if(finalTimer > GetCVar("ce_timelimit")) 
			finalTimer = GetCVar("ce_timelimit");
	}

	if(requiredCount - smashedExits > 1 && smashedExits && timeractive)
	{
		showHint(strParam(s:howMany(),s:" players have yet to activate the exit.\nGo go go!"), CR_GREEN);
	}
	else if(requiredCount - smashedExits == 1 && requiredCount > 1 && timeractive)
	{
		showHint("Only one player has yet to activate the exit.\nHurry up!", CR_YELLOW);
	}
	else if(!smashedExits && timeractive == true) // This can cause an issue possibly in the future with updates if it doesnt check for timeractive. Bug: Timer resets when someone disconnects and timer is not activated.
	{
		showHint("Timer reset. Take your time!", CR_GREEN);
	}

	// Leaver was the last one who hasn't exited
	if(smashedExits >= requiredCount && PlayerCount() != 0)
	{
		Exit_Normal(0);
	}
}

// A player has died in survival, check if they are a dead spectator and if so remove him from exit requirement.
script "PlayerDied" DEATH
{
	if(!GetCvar("survival")) terminate;
	
	if(!GetPlayerLivesLeft(PlayerNumber()))
	{
		playerAlreadyDied[PlayerNumber()] = true;
		playerLeavePlayState(PlayerNumber());
	}
	
}
 
// A player has left, lower the requirement
script "PlayerLeftCoopExit" (int gone) DISCONNECT
{
	if(!playerAlreadyDied[gone]){ 
		requiredCount--; 
	}
	playerAlreadyDied[gone] = false;
	
	playerLeavePlayState(gone);
}
 
Script "CheckForPlayersCoopExit" OPEN
{
	t = GetCVAR("ce_timelimit");
	while(true)
	{
		players = 0;
		for (int l = 0; l < MAXPLAYERS; l++)
		{
			if (!PlayerIsSpectator(1) && PlayerInGame(l))
				players++;
			
			if (PlayerIsSpectator(1) == 2 && GetCvar("survival")){ //This is to handle dead spectators in survival. (Possibly Remove in future versions?)
				players--;
			}
		}
		delay(rate);
	}
}
 
// Someone hits the switch
Script 17293 (int secret)
{
    if(pressed[PlayerNumber()] == false)
    {
        storedTimer = finalTimer;
        smashedExits++;
        pressed[PlayerNumber()] = true;
        
        // First things first -- ready to actually exit?
        if (smashedExits >= requiredCount && PlayerCount() != 0 && PlayerIsSpectator(PlayerNumber()) != 2)
        {
            if(!secret)
                Exit_Normal(0);
            else
                Exit_Secret(0);
        }
        
        // Timer activation
        if(!timeractive && smashedExits == playertimerNum)
            timeractive = true;
        
        // Not first leaver(s) -- reduce time remaining
        if(smashedExits > playertimerNum)
        {
            finalTimer = finalTimer * (PlayerCount()-1) / PlayerCount();
        }
        
        // Last player(s) -- final countdown activation
        if(smashedExits >= requiredCount - playerfinalNum)
        {
            if(finalTimer > finalCountdown) finalTimer = finalCountdown;
            
            if(requiredCount - smashedExits == 1) // The very last one player
                showHint("Only one player has yet to activate the exit!", CR_RED);
            else // Just one of the last few
                showHint(strParam(s:"Hurry up!\nEveryone but one player has activated the exit\nand time is running out!\n", s:howMany(), s:" players still have hit the exit button!"), CR_YELLOW);
        }
        // Normal flow -- updating players on exiting progress
        else
        {
            showHint(strParam(s:howMany(), s:" players have yet to activate the exit. Go go go!"), CR_GREEN);
        }
        
    }
    else
    {
        showHint(strParam(s:"Slow down buddy!\nYou've already activated the exit!\n ", s:howMany(), s:" players still have to activate the exit!"), CR_RED);
    }
}
 
script "TimerControl" OPEN
{
	while (true)
	{
		if (timeractive != true)
		finalTimer = GetCVar("ce_timelimit");
		
		if (timeractive && smashedExits != 0)
		{
			finalTimer--;
			
			if (finalTimer <= 0)
			{
				delay(35);
				timeractive = false;
				Exit_Normal(0);
			}
			
			if(finalTimer > finalCountdown) // Non-agitated timer
			{
				SetFont("BIGFONT");
				SetHudSize(320, 200, 0);
				HudMessageBold(d:finalTimer/60, s:":", d:(finalTimer%60)/10, d:finalTimer%10;
					HUDMSG_FADEOUT, TIMER_ID, CR_GREEN, 160.0, 0.1, 0.3, 3.0);
			}
			else // _Livid_ timer
			{
				SetFont("BIGFONT");
				SetHudSize(260, 160, 0);
				HudMessageBold(d:finalTimer/60, s:":", d:(finalTimer%60)/10, d:finalTimer%10;
					HUDMSG_FADEOUT, TIMER_ID, CR_RED, 130.0, 0.1, 0.1, 1.5);
			}
			
			delay(35);
		}
		else
		
		if (smashedExits == 0 && timeractive == true)
		{
			finalTimer = GetCVar("ce_timelimit");
			timeractive = false;
			log(s:"Anyone who has pressed the exit is no longer in game. Timer has been reset.");
		}
		
		if (PlayerCount() <= 0 && timeractive == true)
		{
			timeractive = false;
			finalTimer = GetCVar("ce_timelimit");
			log(s:"Nobody is in the server. Disabling timer and resetting.");
		}
		
		delay(1);
	}
}

function int howMany(void)
{
	return strparam(d:requiredCount-smashedExits, s:" / ", d:requiredCount);
}

function void showHint(int text, int color)
{
	SetHudSize(640, 480, 0);
	SetFont("SMALLFONT");
	HudMessage(s:text; HUDMSG_FADEOUT, 0, color, 320.0, 50.1, 2.0 + strlen(text) * 0.03, 1.0);
}

script "CheckForCvarsCoopExit" OPEN
{
	while(true)
	{
		requiredCount = PlayerCount();
		debug = GetCVAR("ce_debug");
		playertimerNum = GetCVAR("ce_playertimernum");
		delay(rate);
	}
}


script "ResetScript" UNLOADING
{
	timeractive = false;
	finalTimer = GetCVar("ce_timelimit");
	storedTimer = GetCVar("ce_timelimit");
}

script "DebugCoopExit" OPEN
{
	while(debug>0)
	{
		SetFont("SMALLFONT");
		HudMessage(s:"requiredCount: ",d:requiredCount,s:"\n",s:"smashedExits: ",d:smashedExits,s:"\n",s:"PlayerCount(): ",d:PlayerCount(),s:"\n",s:"Timer Active?: ",b:timeractive,s:"\n",s:"finalTimer (Seconds): ",d:finalTimer,s:"\n",s:"finalTimer (Display): ",d:finalTimer/60, s:":", d:(finalTimer%60)/10, d:finalTimer%10,s:"\n",s:"playertimerNum: ",d:playertimerNum,s:"\n",s:"storedTimer (Seconds): ",d:storedTimer,s:"\n",s:"storedTimer (Display): ",d:storedTimer/60, s:":", d:(storedTimer%60)/10, d:storedTimer%10;
			HUDMSG_PLAIN, 0, CR_RED, 0.3, 0.2, 0.18);
		HudMessage(s:"Pressed [0]: ",d:pressed[0],s:"\n",s:"Pressed [1]: ",d:pressed[1],s:"\n",s:"Pressed [2]: ",d:pressed[2],s:"\n",s:"Pressed [3]: ",d:pressed[3],s:"\n",s:"Pressed [4]: ",d:pressed[4],s:"\n",s:"Pressed [5]: ",d:pressed[5],s:"\n",s:"Pressed [6]: ",d:pressed[6],s:"\n",s:"Pressed [7]: ",d:pressed[7],s:"\n",s:"Pressed [8]: ",d:pressed[8],s:"\n",s:"Pressed [9]: ",d:pressed[9],s:"\n",s:"Pressed [10]: ",d:pressed[10],s:"\n",s:"Pressed [11]: ",d:pressed[11],s:"\n",s:"Pressed [12]: ",d:pressed[12],s:"\n",s:"Pressed [13]: ",d:pressed[13],s:"\n",s:"Pressed [14]: ",d:pressed[14],s:"\n",s:"Pressed [15]: ",d:pressed[15],s:"\n",s:"Pressed [16]: ",d:pressed[16];
			HUDMSG_PLAIN, 0, CR_RED, 0.7, 0.2, 0.18);
		HudMessage(s:"Pressed [17] ",d:pressed[17],s:"\n",s:"Pressed [18]: ",d:pressed[18],s:"\n",s:"Pressed [19]: ",d:pressed[19],s:"\n",s:"Pressed [20]: ",d:pressed[20],s:"\n",s:"Pressed [21]: ",d:pressed[21],s:"\n",s:"Pressed [22]: ",d:pressed[22],s:"\n",s:"Pressed [23]: ",d:pressed[23],s:"\n",s:"Pressed [24]: ",d:pressed[24],s:"\n",s:"Pressed [25]: ",d:pressed[25],s:"\n",s:"Pressed [26]: ",d:pressed[26],s:"\n",s:"Pressed [27]: ",d:pressed[27],s:"\n",s:"Pressed [28]: ",d:pressed[28],s:"\n",s:"Pressed [29]: ",d:pressed[29],s:"\n",s:"Pressed [30]: ",d:pressed[30],s:"\n",s:"Pressed [31]: ",d:pressed[31],s:"\n",s:"Pressed [32]: ",d:pressed[32];
			HUDMSG_PLAIN, 0, CR_RED, 0.85, 0.2, 0.18);
		HudMessage(s:"Pressed [33]: ",d:pressed[33],s:"\n",s:"Pressed [34]: ",d:pressed[34],s:"\n",s:"Pressed [35]: ",d:pressed[35],s:"\n",s:"Pressed [36]: ",d:pressed[36],s:"\n",s:"Pressed [37]: ",d:pressed[37],s:"\n",s:"Pressed [38]: ",d:pressed[38],s:"\n",s:"Pressed [39]: ",d:pressed[39],s:"\n",s:"Pressed [40]: ",d:pressed[40],s:"\n",s:"Pressed [41]: ",d:pressed[41],s:"\n",s:"Pressed [42]: ",d:pressed[42],s:"\n",s:"Pressed [43]: ",d:pressed[43],s:"\n",s:"Pressed [44]: ",d:pressed[44],s:"\n",s:"Pressed [45]: ",d:pressed[45],s:"\n",s:"Pressed [46]: ",d:pressed[46],s:"\n",s:"Pressed [47]: ",d:pressed[47],s:"\n",s:"Pressed [48]: ",d:pressed[48];
			HUDMSG_PLAIN, 0, CR_RED, 1.0, 0.2, 0.18);
		HudMessage(s:"Pressed [49]: ",d:pressed[40],s:"\n",s:"Pressed [50]: ",d:pressed[50],s:"\n",s:"Pressed [51]: ",d:pressed[51],s:"\n",s:"Pressed [52]: ",d:pressed[52],s:"\n",s:"Pressed [53]: ",d:pressed[53],s:"\n",s:"Pressed [54]: ",d:pressed[54],s:"\n",s:"Pressed [55]: ",d:pressed[55],s:"\n",s:"Pressed [56]: ",d:pressed[56],s:"\n",s:"Pressed [57]: ",d:pressed[57],s:"\n",s:"Pressed [58]: ",d:pressed[58],s:"\n",s:"Pressed [59]: ",d:pressed[59],s:"\n",s:"Pressed [60]: ",d:pressed[60],s:"\n",s:"Pressed [61]: ",d:pressed[61],s:"\n",s:"Pressed [62]: ",d:pressed[62],s:"\n",s:"Pressed [63]: ",d:pressed[63],s:"\n",s:"Pressed [64]: ",d:pressed[64];
			HUDMSG_PLAIN, 0, CR_RED, 1.0, 0.6, 0.18);
		Delay(rate);
	}
	delay(1);
	restart;
}