from GamePlay import PYBaseGamePlay

import GEEntity, GEPlayer, GEUtil, GEWeapon, GEMPGameRules, GEGlobal
import math

class CTKToken:
	MAX_CAPTURETIME = 5
	CAPTURETIMER_IDX = 0
	
	def __init__(self):
		self.picked = False
		self.owner = None
		self.ResetCaptureState()
		
	def SetPicked(self, state, owner):
		self.owner = owner
		self.picked = state
		
	def OnDropped(self):
		GEUtil.RemoveHudProgressBarPlayer( self.owner, self.CAPTURETIMER_IDX )
		self.owner = None
		self.ResetCaptureState()
		
	def IsPicked(self):
		return self.picked
	
	def IsCapturable(self):
		return self.capTimer > self.MAX_CAPTURETIME
		
	def CalcCaptureTime(self, onCapPoint = False):
		if self.owner == None:
			return
			
		currtime = GEUtil.GetTime()
		
		if onCapPoint:
			if not self.isCapturing or self.isInCooldown:
				# We have just entered a capture region or timed out and re-entered
				self.isCapturing = True
				
				# Reset the capture timer if we are not in cooldown
				if not self.isInCooldown:
					self.capTimer = 0
					GEUtil.InitHudProgressBarPlayer( self.owner, self.CAPTURETIMER_IDX, "Capture Override: ", 1, float(self.MAX_CAPTURETIME), -1, 0.75, 120, 15, GEUtil.CColor(220,220,220,240) )
					
				# Set the capture time to be the currtime less remaining capture time
				self.startCaptureTime = currtime - self.capTimer
				self.isInCooldown = False
				
			else:
				# We were already capturing so adjust the timer
				self.capTimer = currtime - self.startCaptureTime
			
			# Adjust our capture timeout
			self.capTimeOut = currtime + 0.5
				
		elif self.capTimer > 0:
			# We are officially in cooldown
			self.isInCooldown = True
			
			if currtime > self.capTimeOut:
				# Our timeout expired start decreasing our time
				self.capTimer = self.capTimer - 0.1
			
				if self.capTimer <= 0:
					self.capTimer = 0
					self.isInCooldown = False
					self.isCapturing = False
					GEUtil.RemoveHudProgressBarPlayer( self.owner, self.CAPTURETIMER_IDX )
					return
			
		GEUtil.UpdateHudProgressBarPlayer( self.owner, self.CAPTURETIMER_IDX, self.capTimer )
		
	def SetOverrideTimeout(self,time):
		self.MAX_CAPTURETIME = time

	def ResetCaptureState(self):
		self.capTimer = 0
		self.capTimeOut = 0
		self.startCapTime = 0
		self.isCapturing = False
		self.isInCooldown = False
		
class TurboCTK(PYBaseGamePlay):

	tokenlist = [CTKToken() for j in range(3)]
	
	def __init__(self):
		super(TurboCTK, self).__init__()

		self.InTeamplay = False
		self.TeamplayLimit = 5
		self.InWaitTime = True
		
		# Double checks for forcing DM mode if team spawns not present
		self.ForceDMMode = False
		self.NextForceDMCheck = 0
		self.CPSpawnCount = 0
		
		self.TokenClassDM = 'token_deathmatch'
		self.TokenClassMI6 = 'token_mi6'
		self.TokenClassJanus = 'token_janus'
		
		self.TokenDMGlow = GEUtil.CColor(244,192,11,200)
		self.TokenMI6Glow = GEUtil.CColor(14,139,237,200)
		self.TokenJanusGlow = GEUtil.CColor(224,18,18,200)
		
		self.PlayerDMRadar = GEUtil.CColor(247,253,2,255)
		
		self.TokenDMRadar = GEUtil.CColor(244,192,11,255)
		self.TokenMI6Radar = GEUtil.CColor(94,171,231,255)
		self.TokenJanusRadar = GEUtil.CColor(206,43,43,255)

	def GetPrintName(self):
		return "TurboCTK"

	def GetHelpString(self):
		return "#GES_GP_CAPTUREKEY_HELP"

	def GetGameDescription(self):
		return "TurboCTK"

	def GetTeamPlay(self):
		if self.InTeamplay:
			return GEGlobal.TEAMPLAY_ALWAYS
		else:
			return GEGlobal.TEAMPLAY_NONE

	def OnLoadGamePlay(self):
		tokenmgr = GEMPGameRules.GetTokenMgr()
		
		tokenmgr.AddTokenType( self.TokenClassDM, 1, GEGlobal.SPAWN_TOKEN )
		tokenmgr.SetTokenGlow( self.TokenClassDM, True, self.TokenDMGlow, 450 )
		tokenmgr.SetTokenCapturable( self.TokenClassDM, True )
		tokenmgr.SetTokenRespawnDelay( self.TokenClassDM, 20 )
		tokenmgr.SetCustomTokenSettings( self.TokenClassDM, "", "", "GoldenEye Key" )
		
		tokenmgr.AddTokenType( self.TokenClassMI6, 0, GEGlobal.SPAWN_TOKEN | GEGlobal.SPAWN_TEAMSPECIFIC )
		tokenmgr.SetTokenTeam( self.TokenClassMI6, GEGlobal.TEAM_JANUS )
		tokenmgr.SetTokenGlow( self.TokenClassMI6, True, self.TokenJanusGlow, 450 )
		tokenmgr.SetTokenCapturable( self.TokenClassMI6, True )
		tokenmgr.SetTokenAllowSwitch( self.TokenClassMI6, False )
		tokenmgr.SetTokenRespawnDelay( self.TokenClassMI6, 20 )
		tokenmgr.SetCustomTokenSettings( self.TokenClassMI6, "", "", "GoldenEye Key" )
		
		tokenmgr.AddTokenType( self.TokenClassJanus, 0, GEGlobal.SPAWN_TOKEN | GEGlobal.SPAWN_TEAMSPECIFIC )
		tokenmgr.SetTokenTeam( self.TokenClassJanus, GEGlobal.TEAM_MI6 )
		tokenmgr.SetTokenGlow( self.TokenClassJanus, True, self.TokenMI6Glow, 450 )
		tokenmgr.SetTokenCapturable( self.TokenClassJanus, True )
		tokenmgr.SetTokenAllowSwitch( self.TokenClassJanus, False )
		tokenmgr.SetTokenRespawnDelay( self.TokenClassJanus, 20 )
		tokenmgr.SetCustomTokenSettings( self.TokenClassJanus, "models/weapons/tokens/v_briefcasetoken.mdl", "models/weapons/tokens/w_briefcasetoken.mdl", "Briefcase" )
		
		GEUtil.PrecacheSound( "GEGamePlay.Token_Grab" )
		GEUtil.PrecacheSound( "GEGamePlay.Token_Grab_Enemy" )
		GEUtil.PrecacheSound( "GEGamePlay.Token_Capture_Friend" )
		GEUtil.PrecacheSound( "GEGamePlay.Token_Capture_Enemy" )
		GEUtil.PrecacheSound( "GEGamePlay.Token_Drop_Friend" )
		GEUtil.PrecacheSound( "GEGamePlay.Token_Drop_Enemy" )
		
		# Make sure our variables are reset
		self.ForceDMMode = False
		self.InTeamplay = False
		self.TeamplayLimit = 5
		self.CPSpawnCount = 0
		self.InWaitTime = True
		
		self.CreateCVar("ctk_teamplaylimit", "5", "Sets the number of players required to initiate teamplay on round end (set to 0 to disable DM mode)")
		self.CreateCVar("ctk_overridetime", "5", "Sets the amount of time in seconds that a player has to stay on a capture point to override capture")
		self.CreateCVar("ge_velocity", "1.5", "Velocity (speed) multiplier, range from 0.5 to 1.5.")
		
		# Make sure we don't start out in wait time if we changed gameplay mid-match
		if GEMPGameRules.GetNumActivePlayers() >= 2:
			self.InWaitTime = False
		
		GEMPGameRules.GetRadar().SetForceRadar( True )
		self.LoadConfig()
		
	def OnCVarChanged(self, name, oldvalue, newvalue):
		if name == "ctk_overridetime":
			for i in range(3):
				self.tokenlist[i].SetOverrideTimeout( float(newvalue) )
		elif name == "ctk_teamplaylimit":
			self.TeamplayLimit = int(newvalue)
		elif name == "ge_velocity":
			for i in range(32):
				if not GEUtil.IsValidPlayerIndex(i):
					continue
				player = GEUtil.GetMPPlayer(i)
				player.SetSpeedMultiplier( float(newvalue) )

	def OnRoundBegin(self):
		GEMPGameRules.ResetAllPlayersScores()
		self.NextForceDMCheck = GEUtil.GetTime() + 3.0
		
	def OnRoundEnd(self):
		GEMPGameRules.GetRadar().DropAllContacts()
		
		self.CPSpawnCount = 0

		# Enforce teamplay conditions
		plrcnt = GEMPGameRules.GetNumActivePlayers()
		if self.ForceDMMode or plrcnt < self.TeamplayLimit:
			self.InTeamplay = False
			GEMPGameRules.GetTokenMgr().SetTokenSpawnLimit( self.TokenClassDM, self.GetDMTokenLimit() )
			GEMPGameRules.GetTokenMgr().SetTokenSpawnLimit( self.TokenClassMI6, 0 )
			GEMPGameRules.GetTokenMgr().SetTokenSpawnLimit( self.TokenClassJanus, 0 )			
		else:
			self.InTeamplay = True
			GEMPGameRules.GetTokenMgr().SetTokenSpawnLimit( self.TokenClassDM, 0 )
			GEMPGameRules.GetTokenMgr().SetTokenSpawnLimit( self.TokenClassMI6, 1 )
			GEMPGameRules.GetTokenMgr().SetTokenSpawnLimit( self.TokenClassJanus, 1 )
			
	def OnPlayerSpawn(self, player):
		player.SetSpeedMultiplier( float(GEUtil.GetCVarValue("ge_velocity")) )
		
	def OnThink(self):
		# Update token counters
		for i in range(3):
			self.tokenlist[i].CalcCaptureTime()
			
		# Check for CP issues
		if self.InTeamplay and GEUtil.GetTime() > self.NextForceDMCheck and self.CPSpawnCount < 2:
			# We didn't successfully spawn capture points, force DM mode
			GEUtil.HudMessage( None, "No Team Spawns Present, Forcing Deathmatch Mode!", -1, -1, GEUtil.CColor(255,255,255,255), 1.5 )
			self.ForceDMMode = True
			GEMPGameRules.EndRound(False)
			return
		
		plrcnt = GEMPGameRules.GetNumActivePlayers()
		
		# Enter "wait time" if we only have 1 player
		if plrcnt < 2:
			# Restart the round and count the scores if we were previously not in wait time
			if not self.InWaitTime:
				GEMPGameRules.EndRound()
				
			self.InWaitTime = True
			return
			
		elif not self.ForceDMMode and (((plrcnt >= (self.TeamplayLimit + 2) or self.TeamplayLimit == 0) and not self.InTeamplay) or (plrcnt <= (self.TeamplayLimit - 2) and self.InTeamplay)):
			# Change our teamplay mode immediately if we violate these bounds
			# otherwise the change occurs on official round end
			GEMPGameRules.EndRound()
			
		# Restart the round (not counting scores) if we were in wait time
		if self.InWaitTime:
			GEUtil.HudMessage( None, "Get ready to start!", -1, -1, GEUtil.CColor(255,255,255,255), 2.5 )
			GEMPGameRules.EndRound(False)
			self.InWaitTime = False

	def OnPlayerKilled(self, victim, killer, weapon):
		#what exactly got killed?
		if not victim or not self.InTeamplay:
			return

		#death by world
		if not killer:
			victim.IncrementScore( -1 )
			return

		if victim.GetIndex() == killer.GetIndex():
			killer.IncrementScore( -1 )
		else:
			killer.IncrementScore( 1 )
			
	def OnTokenSpawned(self, token):
		GEMPGameRules.GetRadar().AddRadarContact( token, GEGlobal.RADAR_TYPE_TOKEN, True, "", self.GetColorForTeam( token.GetTeamNumber() ) )
		self.SetTokenPicked( token.GetTeamNumber(), False, None )
		
	def OnTokenPicked(self, token, player):
		GEMPGameRules.GetRadar().DropRadarContact( token )
		GEMPGameRules.GetRadar().AddRadarContact( player, GEGlobal.RADAR_TYPE_PLAYER, True, "", self.GetPlayerColorForTeam( player.GetTeamNumber() ) );
		
		tokenTeam = token.GetTeamNumber()
		otherTeam = self.GetOppositeTeam( tokenTeam )
		
		self.SetTokenPicked( tokenTeam, True, player )
		
		if self.InTeamplay:
			msgFriend = "%s has grabbed the %s!"
			msgEnemy = "%s has stolen your %s!"
			
			if tokenTeam == GEGlobal.TEAM_MI6:
				tokenName = "Intelligence"
			else:
				tokenName = "Key"
			
			GEUtil.HudMessageTeam( tokenTeam, msgFriend % (player.GetPlayerName(), tokenName), -1, 0.45, self.GetColorForTeam( tokenTeam ), 2.0 )
			GEUtil.HudMessageTeam( otherTeam, msgEnemy % (player.GetPlayerName(), tokenName), -1, 0.55, self.GetColorForTeam( tokenTeam ), 2.0 )
			
			GEUtil.PlaySoundToTeam( tokenTeam, "GEGamePlay.Token_Grab", True )
			GEUtil.PlaySoundToTeam( otherTeam, "GEGamePlay.Token_Grab_Enemy", True )
		else:
			# In DM Mode give the player full HP/AP
			player.SetArmor( int(GEGlobal.GE_MAX_ARMOR) )
			player.SetHealth( int(GEGlobal.GE_MAX_HEALTH) )
			player.SwitchToWeapon( self.TokenClassDM )
			
			GEUtil.PlaySoundToPlayer( player, "GEGamePlay.Token_Grab", True )
			GEUtil.InitHudProgressBarPlayer( player, 0, "You Have a Key!", 0, 1.0, -1, 0.75, 120, 15, self.GetColorForTeam( tokenTeam ) )
					
	def OnCapturePointSpawned(self, capture):
		GEMPGameRules.GetRadar().AddRadarContact( capture, GEGlobal.RADAR_TYPE_TOKEN, True, "sprites/hud/radar/capture_point", self.GetColorForTeam( capture.GetTeamNumber() ) )
		self.CPSpawnCount += 1
		
	def CanTokenBeCaptured(self, token, player):
		tokenteam = token.GetTeamNumber()
		otherteam = self.GetOppositeTeam( player.GetTeamNumber() )
		
		if self.IsTokenPicked( otherteam ):
			self.GetToken(tokenteam).CalcCaptureTime( True )
		
			if self.GetToken(tokenteam).IsCapturable():
				return True
			
			return False
		else:
			return True
		
	def OnTokenCapture(self, token, player):
		self.SetTokenPicked( token.GetTeamNumber(), False, None )
		GEMPGameRules.GetRadar().DropRadarContact( token )
		GEMPGameRules.GetRadar().DropRadarContact( player )
		
		tokenTeam = token.GetTeamNumber()
		otherTeam = self.GetOppositeTeam( tokenTeam )
		
		self.GetToken( tokenTeam ).OnDropped()
		
		if self.InTeamplay:
			msg = "%s has captured the %s!"
			if tokenTeam == GEGlobal.TEAM_MI6:
				tokenName = "Intelligence"
			else:
				tokenName = "Key"
			
			GEUtil.HudMessage( None, msg % (player.GetPlayerName(), tokenName), -1, -1, self.GetColorForTeam( tokenTeam ), 3.0 )
			
			GEUtil.PlaySoundToTeam( tokenTeam, "GEGameplay.Token_Capture_Friend", True )
			GEUtil.PlaySoundToTeam( otherTeam, "GEGamePlay.Token_Capture_Enemy", True )
			
			# Give the team and capturer points
			GEMPGameRules.GetTeam(tokenTeam).IncrementRoundScore( 1 )
			player.IncrementScore( 5 )
		else:
			# In DM mode we force the token to find a new home
			GEMPGameRules.GetTokenMgr().RemoveTokenEnt( token )
			GEMPGameRules.GetTokenMgr().SetTokenSpawnLimit( self.TokenClassDM, self.GetDMTokenLimit() )
			
			GEUtil.HudMessage( player, "You captured a key!", -1, -1, self.GetColorForTeam( tokenTeam ), 2.0 )
			GEUtil.PlaySoundToPlayer( player, "GEGameplay.Token_Capture_Friend", True )
			GEUtil.RemoveHudProgressBarPlayer( player, 0 )
			
			player.IncrementScore( 1 )
		
	def OnTokenDropped(self, token, player):
		tokenTeam = token.GetTeamNumber()
		otherTeam = self.GetOppositeTeam( tokenTeam )
		
		self.GetToken( tokenTeam ).OnDropped()
		
		GEMPGameRules.GetRadar().AddRadarContact( token, GEGlobal.RADAR_TYPE_TOKEN, True, "", self.GetColorForTeam( tokenTeam ) )
		GEMPGameRules.GetRadar().DropRadarContact( player )
		
		if self.InTeamplay:
			msg = "%s has dropped the %s!"
			if tokenTeam == GEGlobal.TEAM_MI6:
				tokenName = "Intelligence"
			else:
				tokenName = "Key"
			
			GEUtil.HudMessageTeam( tokenTeam, msg % (player.GetPlayerName(), tokenName), -1, 0.45, self.GetColorForTeam( tokenTeam ), 2.0 )
			GEUtil.HudMessageTeam( otherTeam, msg % (player.GetPlayerName(), tokenName), -1, 0.55, self.GetColorForTeam( tokenTeam ), 2.0 )
			
			GEUtil.PlaySoundToTeam( tokenTeam, "GEGamePlay.Token_Drop_Friend", True )
			GEUtil.PlaySoundToTeam( otherTeam, "GEGamePlay.Token_Drop_Enemy", True )
		else:
			GEUtil.PlaySoundToPlayer( player, "GEGamePlay.Token_Drop_Enemy", True )
			GEUtil.RemoveHudProgressBarPlayer( player, 0 )
			
	def OnTokenRemoved(self, token):
		GEMPGameRules.GetRadar().DropRadarContact( token )
		self.SetTokenPicked( token.GetTeamNumber(), False, None )


#-------------------#
# Utility Functions #
#-------------------#
	
	def GetColorForTeam( self, team ):
		if team == GEGlobal.TEAM_JANUS:
			return self.TokenJanusRadar
		elif team == GEGlobal.TEAM_MI6:
			return self.TokenMI6Radar
		else:
			return self.TokenDMRadar
			
	def GetPlayerColorForTeam( self, team ):
		if team == GEGlobal.TEAM_JANUS or team == GEGlobal.TEAM_MI6:
			return self.GetColorForTeam( team )
		else:
			return self.PlayerDMRadar
		
	def GetToken( self, team ):
		if team == GEGlobal.TEAM_MI6:
			return self.tokenlist[1]
		elif team == GEGlobal.TEAM_JANUS:
			return self.tokenlist[2]
		else:
			return self.tokenlist[0]
			
	def GetDMTokenLimit( self ):
		return int( math.floor(GEMPGameRules.GetNumActivePlayers() / 3) + 1 )
		
	def SetTokenPicked( self, team, state, owner ):
		self.GetToken( team ).SetPicked(state, owner)
			
	def IsTokenPicked( self, team ):
		return self.GetToken(team).IsPicked()
			
	def GetOppositeTeam( self, team ):
		return GEGlobal.TEAM_MI6 if ( team == GEGlobal.TEAM_JANUS ) else GEGlobal.TEAM_JANUS
		
	