from GamePlay import PYBaseGamePlay
from Utils.GEPlayerTracker import GEPlayerTracker
import GEEntity, GEPlayer, GEUtil, GEWeapon, GEMPGameRules, GEGlobal

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# FOR YOUR EYES ONLY
# Version 1.0.1
# by: WNxVirtualMark
#
# Synopsis: A Briefcase is spawned somewhere on the map at the round
# start. Whoever picks up the Briefcase will be able to eliminate
# other players by killing them. Only the current Briefcase holder
# can eliminate players: if you are killed by anyone else, you will
# respawn normally. (You will also be eliminated if you commit
# suicide.) If the Briefcase holder is killed by another player, he
# or she will drop the Briefcase and respawn, and another player can
# pick up the Briefcase. The last player remaining wins the round!
#
# To score points, you must have the Briefcase. You score 1 point for
# every elimination you make while holding the Briefcase. If you win
# the round, your score will be doubled for the round!
#
# If you pick up the Briefcase, you will also be given some buffs.
# First, you will be given full health and armor upon picking up the
# Briefcase, and your speed will be slightly increased. Second, when
# you eliminate a player, you will regain 1 bar of health (or 1 bar
# of armor, if health is full).
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 

class ForYourEyesOnly(PYBaseGamePlay):

	TR_ELIMINATED = "eliminated";
	TR_SPAWNED = "spawned";
	
	def __init__(self):
		super(ForYourEyesOnly, self).__init__()

		self.CaseClass = 'token_deathmatch'
		self.CaseOwnerID = None
		self.CaseGlow = GEUtil.CColor(14,139,237,200)
		self.CaseColor = GEUtil.CColor(94,171,231,255)
		
		self.waitingForPlayers = False
		self.dmBounty = 0
		self.pltracker = GEPlayerTracker()

	def GetPrintName(self):
		return "For Your Eyes Only"

	def GetHelpString(self):
		return "At the beginning of the round, a Briefcase is spawned somewhere on the map (indicated by a blue square on the radar). Whoever picks up the Briefcase (indicated by a blue dot on the radar) will get full health and armor upon pickup, increased speed, and will eliminate players he or she kills. You will respawn normally if killed by someone without the Briefcase. For every elimination you make while holding the Briefcase, you will score 1 point and regain 1 bar of health (or armor, if health is full). The last remaining player will win the round, and have his or her score doubled for the round!"

	def GetGameDescription(self):
		return "For Your Eyes Only"

	def GetTeamPlay(self):
		return GEGlobal.TEAMPLAY_NONE

	def OnLoadGamePlay(self):
		#Spawn a Briefcase token where DM tokens normally spawn, and force radar on.
		GEMPGameRules.GetTokenMgr().AddTokenType( self.CaseClass, 1, GEGlobal.SPAWN_TOKEN )
		GEMPGameRules.GetTokenMgr().SetTokenGlow( self.CaseClass, True, self.CaseGlow )
		GEMPGameRules.GetTokenMgr().SetTokenRespawnDelay( self.CaseClass, 20 )
		GEMPGameRules.GetTokenMgr().SetCustomTokenSettings( self.CaseClass, "models/weapons/tokens/v_briefcasetoken.mdl", "models/weapons/tokens/w_briefcasetoken.mdl", "Briefcase" )
		GEMPGameRules.GetRadar().SetForceRadar( True )
		self.LoadConfig()
		
		#Precache all necessary sounds
		GEUtil.PrecacheSound("GEGamePlay.Token_Chime")
		GEUtil.PrecacheSound("Token_Capture_Enemy")
		GEUtil.PrecacheSound("GEGamePlay.Token_Drop_Friend")
		GEUtil.PrecacheSound("GEGamePlay.Token_Grab")
		
		#Help list, to keep track of which players have seen the Briefcase help popups upon case pickup.
		#When a player picks up the case, they will be added to this list.
		self.helplist = []
		
	def OnPlayerConnect(self, player):
		self.pltracker.Track(player)
		
		self.pltracker.SetValue(player, self.TR_SPAWNED, False)
		if GEMPGameRules.IsRoundLocked():
			self.pltracker.SetValue(player, self.TR_ELIMINATED, True)
			
	def OnPlayerDisconnect(self, player):
		self.pltracker.Drop(player)
		
		if GEMPGameRules.IsRoundLocked() and player.GetTeamNumber() != GEGlobal.TEAM_SPECTATOR and not self.pltracker.GetValue(player, self.TR_ELIMINATED):
			self.UpdatePlayerBounty( player )
			
	def OnPlayerTeamChange(self, player, oldTeam, newTeam):
		if GEMPGameRules.IsRoundLocked():
			if  self.IsInPlay( player ) and oldTeam != GEGlobal.TEAM_SPECTATOR:
				self.UpdatePlayerBounty( player )
			elif oldTeam == GEGlobal.TEAM_SPECTATOR:
				GEUtil.ShowPopupHelp( player, "#GES_GPH_CANTJOIN_TITLE", "#GES_GPH_CANTJOIN", "", 5.0, False )
			else:
				GEUtil.ShowPopupHelp( player, "#GES_GPH_ELIMINATED_TITLE", "#GES_GPH_ELIMINATED", "", 5.0, False )
			
			# Changing teams will automatically eliminate you
			self.pltracker.SetValue( player, self.TR_ELIMINATED, True )

	def OnRoundBegin(self):
		self.dmBounty = 0
		
		for i in range(32):
			if not GEUtil.IsValidPlayerIndex(i):
				continue
			self.pltracker.SetValue( GEUtil.GetMPPlayer(i), self.TR_ELIMINATED, False )
		
		GEMPGameRules.UnlockRound();
		GEMPGameRules.ResetAllPlayerDeaths();
		GEMPGameRules.ResetAllPlayersScores();
		
	def OnRoundEnd(self):
		GEMPGameRules.GetRadar().DropAllContacts()
		GEUtil.RemoveHudProgressBarPlayer( None, 0 )
		
	def OnPlayerSpawn(self, player, isFirstSpawn):
		if player.GetTeamNumber() != GEGlobal.TEAM_SPECTATOR:
			self.pltracker.SetValue( player, self.TR_SPAWNED, True )
		
		#Reset scoreboard color and max speed for player, and make sure they can't go above max health and armor.
		player.SetScoreBoardColor( GEGlobal.SB_COLOR_NORMAL )
		player.SetMaxHealth( int(GEGlobal.GE_MAX_HEALTH) )
		player.SetMaxArmor( int(GEGlobal.GE_MAX_ARMOR) )
		player.SetSpeedMultiplier( 1.0 )
		
		if isFirstSpawn:
			if not self.IsInPlay(player):
				GEUtil.ShowPopupHelp( player, "#GES_GPH_CANTJOIN_TITLE", "#GES_GPH_CANTJOIN", "", 5.0, False )
		
			GEUtil.ShowPopupHelp( player, "#GES_GPH_OBJECTIVE", "Pick up the Briefcase, then kill other players to eliminate them. Last agent standing wins the round!", "", 6.0)
			GEUtil.ShowPopupHelp( player, "#GES_GPH_RADAR", "Dropped Briefcase = Blue Square \nBriefcase Holder = Blue Dot", "", 6.0)

	def OnPlayerKilled(self, victim, killer, weapon):
		if not victim:
			return

		# If someone is killed by the person with the case, they are eliminated.
		if not self.waitingForPlayers and GEEntity.GetUniqueId( killer ) == self.CaseOwnerID:
			GEMPGameRules.LockRound()
			GEUtil.ClientPrintAll( GEGlobal.HUD_PRINTTALK, "#GES_GP_YOLT_ELIMINATED", victim.GetPlayerName() )
			GEUtil.EmitGameplayEvent( "fyeo_eliminated", "%i" % victim.GetUserID(), "%i" % (killer.GetUserID() if killer else -1) )
			GEUtil.ShowPopupHelp( victim, "#GES_GPH_ELIMINATED_TITLE", "#GES_GPH_ELIMINATED", "", 5.0, False )
			
			GEUtil.PlaySoundToPlayer( killer, "GEGamePlay.Token_Chime" )
			GEUtil.PlaySoundToPlayer( victim, "GEGamePlay.Token_Capture_Enemy" )
			
			# Officially eliminate the player
			self.pltracker.SetValue( victim, self.TR_ELIMINATED, True )
			# Initialize the bounty (if we need to)
			self.InitializePlayerBounty()
			# Update the bounty
			self.UpdatePlayerBounty( victim )
			
		#Death by world
		if not killer:
			if GEEntity.GetUniqueId( victim ) == self.CaseOwnerID:
				GEUtil.EmitGameplayEvent( "fyeo_suicide", "%i" % victim.GetUserID() )
				GEUtil.ClientPrintAll( GEGlobal.HUD_PRINTTALK, "^rThe Briefcase holder comitted suicide." )
			
			#Eliminate player on suicide, unless game is currently "Waiting for Players"
			if not self.waitingForPlayers:
				GEMPGameRules.LockRound()
				GEUtil.ClientPrintAll( GEGlobal.HUD_PRINTTALK, "#GES_GP_YOLT_ELIMINATED", victim.GetPlayerName() )
				GEUtil.EmitGameplayEvent( "fyeo_eliminated", "%i" % victim.GetUserID(), "%i" % (killer.GetUserID() if killer else -1) )
				GEUtil.ShowPopupHelp( victim, "#GES_GPH_ELIMINATED_TITLE", "#GES_GPH_ELIMINATED", "", 5.0, False )
			
				# Officially eliminate the player
				self.pltracker.SetValue( victim, self.TR_ELIMINATED, True )
				# Initialize the bounty (if we need to)
				self.InitializePlayerBounty()
				# Update the bounty
				self.UpdatePlayerBounty( victim )
			
			GEUtil.PlaySoundToPlayer( victim, "GEGamePlay.Token_Capture_Enemy" )
			victim.IncrementScore( -1 )
			return

		if victim.GetIndex() == killer.GetIndex():
			# Suicide
			if GEEntity.GetUniqueId( killer ) == self.CaseOwnerID:
				GEUtil.EmitGameplayEvent( "fyeo_suicide", "%i" % victim.GetUserID() )
				GEUtil.ClientPrintAll( GEGlobal.HUD_PRINTTALK, "^rThe Briefcase holder comitted suicide." )
			
			#Eliminate player on suicide, unless game is currently "Waiting for Players"
			if not self.waitingForPlayers:
				GEMPGameRules.LockRound()
				GEUtil.ClientPrintAll( GEGlobal.HUD_PRINTTALK, "#GES_GP_YOLT_ELIMINATED", victim.GetPlayerName() )
				GEUtil.EmitGameplayEvent( "fyeo_eliminated", "%i" % victim.GetUserID(), "%i" % (killer.GetUserID() if killer else -1) )
				GEUtil.ShowPopupHelp( victim, "#GES_GPH_ELIMINATED_TITLE", "#GES_GPH_ELIMINATED", "", 5.0, False )
			
				# Officially eliminate the player
				self.pltracker.SetValue( victim, self.TR_ELIMINATED, True )
				# Initialize the bounty (if we need to)
				self.InitializePlayerBounty()
				# Update the bounty
				self.UpdatePlayerBounty( victim )
			
			GEUtil.PlaySoundToPlayer( killer, "GEGamePlay.Token_Capture_Enemy" )
			killer.IncrementScore( -1 )

		else:
			
			if  GEEntity.GetUniqueId( killer ) == self.CaseOwnerID:
				#Case holder scores for every kill he or she gets.
				killer.IncrementScore( 1 )
				
				#If case holder gets a kill, he/she regains a bar of health (or armor, if health is full).
				if killer.GetHealth() >= killer.GetMaxHealth():
					killer.SetArmor(int(killer.GetArmor() + killer.GetMaxArmor() / 8))
				else:
					killer.SetHealth(int(killer.GetHealth() + killer.GetMaxHealth() / 8))
				
				#If case holder has greater than max health/armor, reset it to max.
				#(Not sure if this is necessary if max health/armor is set to GEglobal.GE_MAX_HEALTH and GEglobal.GE_MAX_ARMOR on spawn, but just in case...)
				if killer.GetHealth() > killer.GetMaxHealth():
					killer.SetHealth(int(killer.GetMaxHealth()))
				if killer.GetArmor > killer.GetMaxArmor:
					killer.SetArmor(int(killer.GetMaxArmor()))
					
			elif GEEntity.GetUniqueId( victim ) == self.CaseOwnerID:
				GEUtil.EmitGameplayEvent( "fyeo_caseholder_killed", "%i" % victim.GetUserID(), "%i" % killer.GetUserID() )
				GEUtil.ClientPrintAll( GEGlobal.HUD_PRINTTALK, "^1%s1 ^4killed the Briefcase holder.", killer.GetPlayerName() )
				GEUtil.PlaySoundToPlayer( victim, "GEGamePlay.Token_Drop_Friend" )

	def OnThink(self):			
		if GEMPGameRules.GetNumActivePlayers() < 2:
			GEMPGameRules.UnlockRound()
			self.waitingForPlayers = True
			return

		if self.waitingForPlayers:
			self.waitingForPlayers = False
			GEUtil.HudMessage( None, "#GES_GP_GETREADY", -1, -1, GEUtil.CColor(255,255,255,255), 2.5 )
			GEMPGameRules.EndRound( False )
		
		#Check to see if more than one player is around
		iPlayers = []

		for i in range(32):
			if not GEUtil.IsValidPlayerIndex(i):
				continue
					
			player = GEUtil.GetMPPlayer(i)
			if self.IsInPlay( player ):
				iPlayers.append(player)

		numPlayers = len(iPlayers)
			
		if numPlayers == 0:
			#This shouldn't happen, but just in case it does we don't want to overflow the vector...
			GEMPGameRules.EndRound()
		if numPlayers == 1:
			#Make last remaining player the winner, and double his or her score.
			GEMPGameRules.SetPlayerWinner( iPlayers[0] )
			iPlayers[0].IncrementScore(iPlayers[0].GetScore())
			GEMPGameRules.EndRound()
			
	def CanPlayerRespawn(self, player):
		if self.pltracker.GetValue(player, self.TR_ELIMINATED) and GEMPGameRules.IsRoundLocked():
			player.SetScoreBoardColor( GEGlobal.SB_COLOR_ELIMINATED )
			return False

		player.SetScoreBoardColor( GEGlobal.SB_COLOR_NORMAL )
		return True
		
	def InitializePlayerBounty(self):
			
		if self.dmBounty == 0:
			self.dmBounty = GEMPGameRules.GetNumInRoundPlayers() - 1
			GEUtil.InitHudProgressBarPlayer( None, 0, "Foes: ", GEGlobal.HUDPB_SHOWVALUE, self.dmBounty, -1, 0.02, 0, 10, GEUtil.CColor(170,170,170,220) )
			
	def UpdatePlayerBounty(self, victim):				
		self.dmBounty -= 1
			
		# Remember, we take 1 off to account for the local player
		GEUtil.UpdateHudProgressBarPlayer( None, 0, self.dmBounty )
			
	def IsInPlay(self, player):
		return player.GetTeamNumber() is not GEGlobal.TEAM_SPECTATOR and self.pltracker.GetValue(player, self.TR_SPAWNED) and not self.pltracker.GetValue(player, self.TR_ELIMINATED)
				
	def OnTokenSpawned(self, token):
		GEMPGameRules.GetRadar().AddRadarContact( token, GEGlobal.RADAR_TYPE_TOKEN, True, "", self.CaseColor )
		
	def OnTokenPicked(self, token, player):
		radar = GEMPGameRules.GetRadar()
		radar.DropRadarContact( token )
		radar.AddRadarContact( player, GEGlobal.RADAR_TYPE_PLAYER, True, "", self.CaseColor )
		
		GEUtil.PlaySoundToPlayer( player, "GEGamePlay.Token_Grab" )
		GEUtil.ClientPrintAll( GEGlobal.HUD_PRINTTALK, "^1%s1 ^ipicked up the Briefcase!", player.GetPlayerName() )
		GEUtil.HudMessage( player, "You have the Briefcase!", -1, 0.75, self.CaseColor, 3.0 )
		GEUtil.EmitGameplayEvent( "fyeo_case_picked", "%i" % player.GetUserID() )
		
		player.SetScoreBoardColor(GEGlobal.SB_COLOR_WHITE)
		self.CaseOwnerID = GEEntity.GetUniqueId( player )
		
		#Case holder gets full health and armor upon case pickup, and gets slightly increased speed.
		player.SetHealth(int(GEGlobal.GE_MAX_HEALTH))
		player.SetArmor(int(GEGlobal.GE_MAX_ARMOR))
		player.SetSpeedMultiplier( 1.15 )
		
		#Explain to player what to do, now that he or she has the case. Will only show on first case pickup.
		if self.helplist.count( GEEntity.GetUniqueId(player) ):
			return
			
		GEUtil.ShowPopupHelp( player, "Briefcase", "You have the Briefcase! Kill other players to eliminate them.", "", 6.0)
		GEUtil.ShowPopupHelp( player, "Scoring", "You score 1 point for every player you eliminate. If you win the round, your score will be doubled for the round!", "", 8.0)
		GEUtil.ShowPopupHelp( player, "Buffs", "Upon picking up the Briefcase, you received full health and armor, plus increased speed. For every player you eliminate, 1 bar of health (or armor, if health is full) will be restored.", "", 10.0)
		
		self.helplist.append( GEEntity.GetUniqueId(player) )
		
	def OnTokenDropped(self, token, player):
		radar = GEMPGameRules.GetRadar()
		
		radar.DropRadarContact( player )
		radar.AddRadarContact( token, GEGlobal.RADAR_TYPE_TOKEN, True, "", self.CaseColor )
		
		GEUtil.ClientPrintAll(GEGlobal.HUD_PRINTTALK, "^1%s1 ^idropped the Briefcase!", player.GetPlayerName() )
		player.SetScoreBoardColor( GEGlobal.SB_COLOR_NORMAL )
		self.CaseOwnerID = None
		
	def OnTokenRemoved(self, token):
		GEMPGameRules.GetRadar().DropRadarContact( token )
		GEMPGameRules.GetRadar().DropRadarContact( token.GetOwner() )
		self.CaseOwnerID = None
