CTF_CAPTURE_LIMIT = 3
CTF_SCORE_STEAL = 2
CTF_SCORE_DEFEND = 1
CTF_SCORE_RETURN = 4
CTF_SCORE_CAPTURE = 10
CTF_SCORE_KILLED_CARRIER = 2

CTF_RETURN_UNHELD_FLAG_COUNT = 15 # seconds ~= secureflaginterval * returnunheldcount

CTF_USE_LARGE_SERVER_UNLAG = 1
CTF_UNLAG_PLAYER_COUNT = 20 #Cuts carried flag position update interval in half if this many players are connected

# DO NOT CHANGE ANYTHING BELOW HERE -----

CTF_SECURE_FLAG_INTERVAL = 3.0 

CTF_BLINK_COUNT = 5
CTF_PICKUP_RADIUS = 2
CTF_HACK_RADIUS = 10.0
CTF_FLAG_UPDATE_INTERVAL = 0.1

CTF_BASE_TICKETS = 1000
SOUND_REPAIR_INTERVAL = 0.5
MARKER_SHOWOFF_INTERVAL = 0.3

TAKEOVERTYPE_CAPTURE = 1
TAKEOVERTYPE_NEUTRALIZE = 2

SCORE_CAPTURE = 2
SCORE_NEUTRALIZE = 2
SCORE_CAPTUREASSIST = 1
SCORE_NEUTRALIZEASSIST = 1
SCORE_DEFEND = 1

Top = 0
Middle = 1
Bottom = 2

import host
import bf2
import math
import gpm_cq
from game.scoringCommon import addScore, RPL
from bf2 import g_debug

g_controlPoints = [] 


class CTF_Game:
	def __init__(self):
		self.setupInit = 0
		self.flagUpdateTimer = None
		self.secureFlagTimer = None
		self.team1Carrier = -1
		self.team2Carrier = -1
		self.team1FlagIsTaken = 0
		self.team2FlagIsTaken = 0
		self.team1DefaultPos = None
		self.team2DefaultPos = None
		self.team1UncapTrigId = -1
		self.team1PhysTrigId = -1
		self.team2UncapTrigId = -1
		self.team2PhysTrigId = -1
		self.oppFlagUnheldRemaining = CTF_RETURN_UNHELD_FLAG_COUNT
		self.usFlagUnheldRemaining = CTF_RETURN_UNHELD_FLAG_COUNT
		self.blinkCount = CTF_BLINK_COUNT
		self.blinkDamage = 1
		self.usFlagNoPhys = None
		self.usFlagHasPhys = None
		self.usFlagHousePos = (-4000.0,4000.0,0.0)
		self.oppFlagNoPhys = None
		self.oppFlagHasPhys = None
		self.oppFlagHousePos = (4000.0,4000.0,0.0)
		self.team1CarrierInVehicle = 0
		self.team2CarrierInVehicle = 0


		
class CTF_Event_Sounds:
	def __init__(self):
		self.needRepair = []
		self.oppFlagTaken = None
		self.oppFlagCap = None
		self.oppFlagDrop = None
		self.oppFlagSave = None
		self.oppFlagReset = None
		self.usFlagTaken = None
		self.usFlagCap = None
		self.usFlagDrop = None
		self.usFlagSave = None
		self.usFlagReset = None



		
CTF_Events = (	(1031119,1,'oppFlagTaken'),
				(1031119,2,'oppFlagCap'),
				(1031121,1,'usFlagSave'),
				(1031120,1,'oppFlagDrop'),
				(1031120,2,'usFlagTaken'),
				(1031120,3,'usFlagCap'),
				(1031119,3,'oppFlagSave'),
				(1031121,2,'usFlagDrop') )


CTF = CTF_Game()
CTFSounds = CTF_Event_Sounds()
CTF_CurMarkNum = 1
CTF_FixMarkerList = []



def init():
	# events hook
	host.registerGameStatusHandler(onGameStatusChanged)
	if host.sgl_getIsAIGame() == 1:
		host.sh_setEnableCommander(1)
	else:
		host.sh_setEnableCommander(0)
		
	host.registerHandler('TimeLimitReached', onTimeLimitReached, 1)
	
	if g_debug: print "gpm_ctf.py initialized... all your flags are belong to us"
	#print'active mod: '+str(host.sgl_getModDirectory())
		
				
def deinit():
	bf2.triggerManager.destroyAllTriggers()
	global g_controlPoints
	g_controlPoints = []
	host.unregisterGameStatusHandler(onGameStatusChanged)
	host.sh_setEnableCommander(0) 
	if g_debug: print "gpm_ctf.py uninitialized"


def onGameStatusChanged(status):

	global g_controlPoints
	global CTF_CurMarkNum
	if status == bf2.GameStatus.Playing:
		
		CTF.setupInit = 0
		CTF_CurMarkNum = 1
		
		g_controlPoints = bf2.objectManager.getObjectsOfType('dice.hfe.world.ObjectTemplate.ControlPoint')
		for obj in g_controlPoints:
			radius = float(obj.getTemplateProperty('radius'))
			isHemi = int(obj.cp_getParam('isHemisphere'))
			if int(obj.cp_getParam('unableToChangeTeam')) == 1:
				tteam = obj.cp_getParam('team')
				if  tteam == 2:
					tpos = obj.getPosition()
					CTF.team2DefaultPos = (tpos[0],tpos[1] + 2.0,tpos[2])
																
				elif tteam == 1:
					tpos = obj.getPosition()
					CTF.team1DefaultPos = (tpos[0],tpos[1] + 2.0,tpos[2])
					
				else:
					pass #print 'CANT FIND TEAM FOR UNTAKABLE setup'
					
				
				if isHemi != 0:
					id = bf2.triggerManager.createHemiSphericalTrigger(obj, onCTFUncapTrigger, '<<PCO>>', CTF_PICKUP_RADIUS, tteam)
				else:
					id = bf2.triggerManager.createRadiusTrigger(obj, onCTFUncapTrigger, '<<PCO>>', CTF_PICKUP_RADIUS, tteam)	
				obj.triggerId = id
				obj.lastAttackingTeam = 0
				obj.flagPosition = Top
									
			else:
				if isHemi != 0:
					id = bf2.triggerManager.createHemiSphericalTrigger(obj, onCPTrigger, '<<PCO>>', radius, (1, 2, 3))
				else:
					id = bf2.triggerManager.createRadiusTrigger(obj, onCPTrigger, '<<PCO>>', radius, (1, 2, 3))	
				obj.triggerId = id
				obj.lastAttackingTeam = 0
			if obj.cp_getParam('team') > 0:
				obj.flagPosition = Top
			else:
				obj.flagPosition = Bottom
				
			
			
		gpm_cq.g_controlPoints = g_controlPoints
		host.registerHandler('ControlPointChangedOwner', onCPStatusChange)

		ticketsTeam1 = CTF_BASE_TICKETS 
		ticketsTeam2 = CTF_BASE_TICKETS

		
		bf2.gameLogic.setTickets(1, ticketsTeam1)
		bf2.gameLogic.setTickets(2, ticketsTeam2)
		
		# no bleed 
		bf2.gameLogic.setTicketState(1, 0)
		bf2.gameLogic.setTicketState(2, 0)

		#end game
		bf2.gameLogic.setTicketLimit(1, 1, CTF_BASE_TICKETS + CTF_CAPTURE_LIMIT)
		bf2.gameLogic.setTicketLimit(2, 1, CTF_BASE_TICKETS + CTF_CAPTURE_LIMIT)
		
		host.registerHandler('PlayerKilled', onPlayerKilledCQ)
		host.registerHandler('PlayerRevived', onPlayerRevived)
		host.registerHandler('PlayerSpawn', onPlayerSpawn)
		host.registerHandler('EnterVehicle', onEnterVehicle)
		host.registerHandler('ExitVehicle', onExitVehicle)

		host.registerHandler('PlayerDisconnect', onPlayerDisconnect)
		#host.registerHandler('ChatMessage', onChatMessage)
		host.registerHandler('PlayerConnect', onPlayerConnect)
		
		
		#print "CTF gamemode initialized."
		
	elif status == bf2.GameStatus.PreGame:
		CTF.team1Carrier = -1
		CTF.team2Carrier = -1
		CTF.team1FlagIsTaken = 0
		CTF.team2FlagIsTaken = 0

	else:
		bf2.triggerManager.destroyAllTriggers()
		CTF.team1DefaultPos = None
		CTF.team2DefaultPos = None
		CTF.team1FlagIsTaken = 0
		CTF.team2FlagIsTaken = 0
		CTF.team1Carrier = -1
		CTF.team2Carrier = -1
		FreeExistingTimers()
		

# def onChatMessage(playerId, text, channel, flags):
	# if text.find("count") > -1:
		# CheckPlayerCount()
		

def FreeExistingTimers():
	if not CTF.flagUpdateTimer is None:
		#print'destroying flagUpdateTimer'
		CTF.flagUpdateTimer.destroy()
		CTF.flagUpdateTimer = None
	if not CTF.secureFlagTimer is None:
		#print'destroying secureFlagTimer'
		CTF.secureFlagTimer.destroy()
		CTF.secureFlagTimer = None
	for (snd,tmr) in CTFSounds.needRepair:
		try:
			#print'found residual sound timer: '#+str(snd.tamplateName)
			tmr.destroy()
			tmr = None
		except:
			pass#print 'error destroying old timer object'
	CTFSounds.needRepair = []

		
def PlaySound (obj):
	try:
		obj.setDamage(-1)
		tmr = bf2.Timer(RepairSoundPco, SOUND_REPAIR_INTERVAL, 1,obj)
		CTFSounds.needRepair.append((obj,tmr))
	except:
		pass #print'error on setdamage'
	
def RepairSoundPco(sObj):
	sObj.setDamage(1)
	found = 1
	while found: # just in case there's more than one
		found = 0
		ind = 0
		for (snd,tmr) in CTFSounds.needRepair:
			if snd is sObj:
				del CTFSounds.needRepair[ind]
				try: tmr.destroy()
				except: pass
				tmr = None
				found = 1
				break
			ind += 1

def GetPcosDict(targetObj,pcoD):
	try:
		pcos = bf2.objectManager.getObjectsOfType('dice.hfe.world.ObjectTemplate.PlayerControlObject')
		for obj in pcos:
			key = obj.templateName
			if key in pcoD:
				targetObj.__dict__[pcoD[key]] = obj
				#print 'FOUND: '+str(key)
				del pcoD[key]
				
		else:
			pass #print'Found all requested PCO''s'
	except:
		pass #print'error getting objs'

		
def GetCtfPcos():
	
	pcoD = {'flagctf_us' 				: 'usFlagNoPhys',
			'flagctf_us_wp'				: 'usFlagHasPhys',
			'flagctf_opp'				: 'oppFlagNoPhys',
			'flagctf_opp_wp'			: 'oppFlagHasPhys'}

	#print'Getting CTF flag objects...'
	GetPcosDict (CTF,pcoD)
	
	pcoD = {'sound_opp_flag_taken'		: 'oppFlagTaken',
			'sound_opp_flag_captured'	: 'oppFlagCap',
			'sound_opp_flag_drop'		: 'oppFlagDrop',
			'sound_opp_flag_save'		: 'oppFlagSave',
			'sound_opp_flag_reset'		: 'oppFlagReset',
			'sound_us_flag_taken'		: 'usFlagTaken',
			'sound_us_flag_captured'	: 'usFlagCap',
			'sound_us_flag_drop'		: 'usFlagDrop',
			'sound_us_flag_save'		: 'usFlagSave',
			'sound_us_flag_reset'		: 'usFlagReset'}
			
	#print'Getting CTF sound objects...'
	GetPcosDict (CTFSounds,pcoD)

		
def UpdateFlags(data):

	if CTF.team1FlagIsTaken or CTF.team2FlagIsTaken:
		if CTF.blinkCount > 0:
			CTF.blinkCount -= 1
			blinkChanged = 0
		else:
			CTF.blinkCount = CTF_BLINK_COUNT
			CTF.blinkDamage *= -1
			blinkChanged = 1				
	else:
		return
		
	
	if CTF.team1FlagIsTaken:
		if CTF.team2Carrier != -1:  #(CTF.team2Carrier != -1 or CTF.team2CarrierKilled == 1):
			pPos = bf2.playerManager.getPlayerByIndex(CTF.team2Carrier).getDefaultVehicle().getPosition()
			vehHeight = 0.0
			if CTF.team2CarrierInVehicle: vehHeight = 1.0
			fPos = (pPos[0], pPos[1] + 2.5 + vehHeight, pPos[2])
			CTF.oppFlagNoPhys.setPosition(fPos)
			if blinkChanged: CTF.oppFlagNoPhys.setDamage(CTF.blinkDamage)
		else:
			if blinkChanged: CTF.oppFlagHasPhys.setDamage(CTF.blinkDamage)

		
	if CTF.team2FlagIsTaken:
		if CTF.team1Carrier != -1: #(CTF.team1Carrier != -1 or CTF.team1CarrierKilled == 1):
			pPos = bf2.playerManager.getPlayerByIndex(CTF.team1Carrier).getDefaultVehicle().getPosition()
			vehHeight = 0.0
			if CTF.team1CarrierInVehicle: vehHeight = 1.0
			fPos = (pPos[0], pPos[1]  + 2.5, pPos[2])
			CTF.usFlagNoPhys.setPosition(fPos)
			if blinkChanged: CTF.usFlagNoPhys.setDamage(CTF.blinkDamage)
		else:
			if blinkChanged: CTF.usFlagHasPhys.setDamage(CTF.blinkDamage)

			
def SecureFlags(data):
	
	if data: CheckPendingMarkerFix(data)	

	if CTF.team1FlagIsTaken:
		#print'team1FlagIsTaken'
		if CTF.team2Carrier == -1:
			CTF.oppFlagNoPhys.setDamage(1)
			CTF.oppFlagNoPhys.setPosition(CTF.oppFlagHousePos)
			if not data:
				if CTF.oppFlagUnheldRemaining > 0:
					CTF.oppFlagUnheldRemaining -= 1
					#print 'CTF.oppFlagUnheldRemaining = '+str(CTF.oppFlagUnheldRemaining)
				else: #timed out...reset it
					ResetFlagCpos(1)
					msgStr = '*** Opposition flag has been RESET ***'
					host.rcon_invoke('game.sayall "'+ msgStr +'"')
					met = 1031119
					mev = 3
					PlaySound(CTFSounds.oppFlagReset)
					ShowOffObject(CTF.oppFlagHasPhys)
					for p in bf2.playerManager.getPlayers():
						bf2.gameLogic.sendMedalEvent(p, met, mev)
		else:
			CTF.oppFlagHasPhys.setDamage(1)
			CTF.oppFlagHasPhys.setPosition(CTF.oppFlagHousePos)	
	else:
		#print'NOT --- team1FlagIsTaken'
		CTF.oppFlagHasPhys.setDamage(1)
		CTF.oppFlagHasPhys.setPosition(CTF.oppFlagHousePos)
		CTF.oppFlagNoPhys.setDamage(1)
		CTF.oppFlagNoPhys.setPosition(CTF.team1DefaultPos)
			
	#coal flags
	if CTF.team2FlagIsTaken:
		if CTF.team1Carrier == -1:
			CTF.usFlagNoPhys.setDamage(1)
			CTF.usFlagNoPhys.setPosition(CTF.usFlagHousePos)
			if not data:
				if CTF.usFlagUnheldRemaining > 0:
					CTF.usFlagUnheldRemaining -= 1
				else: #timed out...reset it
					ResetFlagCpos(2)
					msgStr = '*** Coalition flag has been RESET ***'
					host.rcon_invoke('game.sayall "'+ msgStr +'"')
					met = 1031121
					mev = 1
					PlaySound(CTFSounds.usFlagReset)
					ShowOffObject(CTF.usFlagHasPhys)
					for p in bf2.playerManager.getPlayers():
						bf2.gameLogic.sendMedalEvent(p, met, mev)
		else:
			CTF.usFlagHasPhys.setDamage(1)
			CTF.usFlagHasPhys.setPosition(CTF.oppFlagHousePos)		
	else:
		CTF.usFlagHasPhys.setDamage(1)
		CTF.usFlagHasPhys.setPosition(CTF.usFlagHousePos)
		CTF.usFlagNoPhys.setDamage(1)
		CTF.usFlagNoPhys.setPosition(CTF.team2DefaultPos)
			
		

def CheckPendingMarkerFix(tmrId):
	ind = 0
	for (tId,tmr) in CTF_FixMarkerList:
		if tId == tmrId:
			#print 'FOUND tId == tmrId ' + str (tmrId)
			del CTF_FixMarkerList[ind]
			try: tmr.destroy()
			except: pass
			tmr = None
			break
		ind += 1
	else:
		pass #print 'couldnt MATCH!!! ::: ' + str(tmrId)

		
def ResetFlagCpos(team):
	#put stuff to original location
	if team == 1:
		CTF.team1FlagIsTaken = 0
		CTF.team2Carrier = -1
		#CTF.oppFlagNoPhys.setPosition(CTF.team1DefaultPos)
		#CTF.oppFlagHasPhys.setPosition(CTF.oppFlagHousePos)
		#CTF.oppFlagHasPhys.setRotation((0.,0.,0.))
		CTF.oppFlagNoPhys.setDamage(1)
		CTF.oppFlagHasPhys.setDamage(1)
		CTF.oppFlagUnheldRemaining = CTF_RETURN_UNHELD_FLAG_COUNT
	else:
		CTF.team2FlagIsTaken = 0
		CTF.team1Carrier = -1
		#CTF.usFlagNoPhys.setPosition(CTF.team2DefaultPos)
		#CTF.usFlagHasPhys.setPosition(CTF.usFlagHousePos)
		#CTF.usFlagHasPhys.setRotation((0.,0.,0.))
		CTF.usFlagNoPhys.setDamage(1)
		CTF.usFlagHasPhys.setDamage(1)
		CTF.usFlagUnheldRemaining = CTF_RETURN_UNHELD_FLAG_COUNT

				
def SendFlagEventMessage(playerName, playerTeam, eventType):
	hudEvent = eventType - 1
	if playerTeam == 1:
		hudEvent += 4
		otherTeam = 'Coalition'
	else:
		otherTeam = 'Opposition'
		
	PlaySound(CTFSounds.__dict__[CTF_Events[hudEvent][2]])
		
	for p in bf2.playerManager.getPlayers():
		bf2.gameLogic.sendMedalEvent(p, CTF_Events[hudEvent][0], CTF_Events[hudEvent][1]) 

		
	if eventType == 1: # stole flag
		msgStr = '===   '
		msgStr += playerName+' Stole the '+ otherTeam +' flag!'
		msgStr += '   ==='
	elif eventType == 2: # Captured flag
		msgStr = '<><><><>   '
		msgStr += playerName+' CAPTURED the '+ otherTeam +' flag!!!'
		msgStr += '   <><><><>'
	elif eventType == 3: #saved flag
		msgStr = '-=-=-=-   '
		msgStr += playerName+' saved the flag'
		msgStr += '   -=-=-=-'
	elif eventType == 4: #dropped flag
		msgStr = '###   '
		msgStr += playerName+' Dropped the '+ otherTeam +' flag!'
		msgStr += '   ###'
	else:
		return

	host.rcon_invoke('game.sayall "'+ msgStr +'"')

def onCTFWithPhysTrigger (triggerId, cp, vehicle, enter, flagTeam):
	
	if enter:
			
		if flagTeam == 1:
			if CTF.team1FlagIsTaken == 0: return
		elif flagTeam == 2:
			if CTF.team2FlagIsTaken == 0: return
		else: 
			return


		for p in vehicle.getOccupyingPlayers():
			isOk = not p.isManDown() and p.isAlive()
			if not isOk: continue
			playersTeam = p.getTeam() 

			if p.getDefaultVehicle() == p.getVehicle():

				if flagTeam == 1:	
					if CTF.team2Carrier == -1: 
						if playersTeam == 2: # and not p.isManDown ():
							#print 'if (playersTeam == 2) and p.isAlive():'
							CTF.team1FlagIsTaken = 1
							CTF.team2Carrier = p.index
							p.score.cpCaptures += 1
							addScore(p, CTF_SCORE_STEAL, RPL)

							CTF.oppFlagHasPhys.setDamage(1)
							#CTF.oppFlagHasPhys.setPosition(CTF.oppFlagHousePos)
							CTF.oppFlagUnheldRemaining = CTF_RETURN_UNHELD_FLAG_COUNT
							ShowOffObject(CTF.oppFlagHasPhys)

							SendFlagEventMessage(p.getName(), 2, 1) #ChatMessage(-1, msgStr,"Global", 10) 
						elif playersTeam == 1 and CTF.team1FlagIsTaken == 1:
							p.score.cpDefends += 1
							addScore(p, CTF_SCORE_RETURN, RPL)
							SendFlagEventMessage(p.getName(), 1, 3) #ChatMessage(-1, msgStr,"Global", 10) 
							ResetFlagCpos(1)
							
							ShowOffObject(CTF.oppFlagHasPhys)
							
						else:
							pass	

				elif flagTeam == 2:
					if CTF.team1Carrier == -1:
						if playersTeam == 1: # and not p.isManDown() # (p.isAlive():
							CTF.team2FlagIsTaken = 1
							CTF.team1Carrier = p.index
							p.score.cpCaptures += 1
							addScore(p, CTF_SCORE_STEAL, RPL)

							CTF.usFlagHasPhys.setDamage(1)
							#CTF.usFlagHasPhys.setPosition(CTF.usFlagHousePos)
							CTF.usFlagUnheldRemaining = CTF_RETURN_UNHELD_FLAG_COUNT
							ShowOffObject(CTF.usFlagHasPhys)

							
							SendFlagEventMessage(p.getName(), 1, 1) #ChatMessage(-1, msgStr,"Global", 10) 
						elif playersTeam == 2 and CTF.team2FlagIsTaken == 1: 
							p.score.cpDefends += 1
							addScore(p, CTF_SCORE_RETURN, RPL)
							SendFlagEventMessage(p.getName(), 2, 3) #ChatMessage(-1, msgStr,"Global", 10) 
							ResetFlagCpos(2)
							
							ShowOffObject(CTF.usFlagHasPhys)
							
						else:
							pass
				else:
					pass



def onCTFUncapTrigger (triggerId, cp, vehicle, enter, cpTeam):

	if enter:
						
		# if cpTeam == 1 and CTF.team1FlagIsTaken: return
		# elif cpTeam == 2 and CTF.team2FlagIsTaken: return
		# else: return #...uhh wtf?		
		if cpTeam == 1:
			if CTF.team1FlagIsTaken: return
		elif cpTeam == 2:
			if CTF.team2FlagIsTaken: return
		else: return #...uhh wtf?
					
		for p in vehicle.getOccupyingPlayers():
			isOk = not p.isManDown() and p.isAlive()
			if not isOk: continue
			playersTeam = p.getTeam() 

			if p.getDefaultVehicle() == p.getVehicle():
				if cpTeam == 1:
					if playersTeam == 2:
						if CTF.team2Carrier == -1 and CTF.team1FlagIsTaken == 0: 
							CTF.team1FlagIsTaken = 1
							CTF.team2Carrier = p.index
							p.score.cpCaptures += 1
							addScore(p, CTF_SCORE_STEAL, RPL)
							CTF.oppFlagHasPhys.setPosition(CTF.oppFlagHousePos)
							CTF.oppFlagUnheldRemaining = CTF_RETURN_UNHELD_FLAG_COUNT
							SendFlagEventMessage(p.getName(), 2, 1)
					elif playersTeam == 1:
						if CTF.team1Carrier == p.index:
							if not (CTF.team2FlagIsTaken == 1):
								return
							
							if not VerifyNoHack(cp, p): return 
							
							ResetFlagCpos(2)
							ShowOffObject(CTF.usFlagNoPhys)
							#print 'SCORED_____________'
							
							p.score.cpCaptures += 1
							addScore(p, CTF_SCORE_CAPTURE, RPL)
							onCTFTeamScore(1)
							SendFlagEventMessage(p.getName(), 1, 2) # name, team, event
					else:
						pass
						
				elif cpTeam == 2:
					if playersTeam == 1:
						if CTF.team1Carrier == -1 and CTF.team2FlagIsTaken == 0: 
							CTF.team2FlagIsTaken = 1
							CTF.team1Carrier = p.index
							p.score.cpCaptures += 1
							addScore(p, CTF_SCORE_STEAL, RPL)
							CTF.usFlagHasPhys.setPosition(CTF.usFlagHousePos)
							CTF.usFlagUnheldRemaining = CTF_RETURN_UNHELD_FLAG_COUNT
							SendFlagEventMessage(p.getName(), 1, 1)

					elif playersTeam == 2:
						if CTF.team2Carrier == p.index:
							if not (CTF.team1FlagIsTaken == 1):
								return
							
							if not VerifyNoHack(cp, p): return 
														
							ResetFlagCpos(1)
							ShowOffObject(CTF.oppFlagNoPhys)
							#print 'score ----'
							
							p.score.cpCaptures += 1
							addScore(p, CTF_SCORE_CAPTURE, RPL)
							onCTFTeamScore(2)
							SendFlagEventMessage(p.getName(), 2, 2) # name, team, event
					else:
						pass
				else:
					pass
					

def VerifyNoHack(cp, p):
	vDist = gpm_cq.getVectorDistance(cp.getPosition(),p.getDefaultVehicle().getPosition())
	#print 'dist = ' + str(vDist)
	isNotHack = vDist < CTF_HACK_RADIUS
	if not isNotHack:
		host.rcon_invoke('game.sayall "'+ p.getName() +' IS A HACKER!!!"')
	return isNotHack

def onPlayerRevived(victim, attacker):
	#CheckDropFlag(victim)
	gpm_cq.onPlayerRevived(victim, attacker)
	
	
def onEnterVehicle(player, vehicle, freeSoldier = False):
	#print player.getName() + " entered " + str(vehicle.templateName)
	if CTF.team1Carrier == player.index:
		CTF.team1CarrierInVehicle = 1
	if CTF.team2Carrier == player.index:
		CTF.team2CarrierInVehicle = 1
	
	gpm_cq.onEnterVehicle(player, vehicle, freeSoldier)

def onExitVehicle(player, vehicle):
	#print player.getName() + " left " + str(vehicle.templateName)
	if CTF.team1Carrier == player.index:
		CTF.team1CarrierInVehicle = 0
	if CTF.team2Carrier == player.index:
		CTF.team2CarrierInVehicle = 0

	gpm_cq.onExitVehicle(player, vehicle)
		
def getOccupyingCP(player):
	gpm_cq.getOccupyingCP(player)


	
	
def calcStartTickets(mapDefaultTickets):
	gpm_cq.calcStartTickets(mapDefaultTickets)
	
def onTimeLimitReached(value):
	gpm_cq.onTimeLimitReached(value)


def onTimeLimitReached(value):
	AdjustFinalScores()
	team1tickets = bf2.gameLogic.getTickets(1)
	team2tickets = bf2.gameLogic.getTickets(2)
	
	winner = 0
	victoryType = 0
	if team1tickets > team2tickets:
		winner = 1
		victoryType = 3
	elif team2tickets > team1tickets:
		winner = 2
		victoryType = 3
	
	FreeExistingTimers()
	host.sgl_endGame(winner, victoryType)

def calcTicketLossForTeam(team, otherTeamAreaValue, otherTeamAreaOverweight):
	gpm_cq.calcTicketLossForTeam(team, otherTeamAreaValue, otherTeamAreaOverweight)

	
def updateTicketWarning(team, limitId):
	gpm_cq.UpdateTicketWarning(team, limitId)

def onCPTrigger(triggerId, cp, vehicle, enter, userData):
	gpm_cq.onCPTrigger(triggerId, cp, vehicle, enter, userData)	



def onCPStatusChange(cp, top):
	playerId = -1
	takeoverType = -1
	newTeam = -1
	scoringTeam = -1
	
	if top:	cp.flagPosition = Top
	else:   cp.flagPosition = Bottom
	
	# determine capture / neutralize / defend
	if cp.cp_getParam('team') != 0:
		if top:
			# regained flag, do nothing
			pass
		else:
			# neutralize
			newTeam = 0
			if cp.cp_getParam('team') == 1:
				scoringTeam = 2
			else:
				scoringTeam = 1
			#takeoverType = TAKEOVERTYPE_NEUTRALIZE
	else:
		if top:
			# capture
			newTeam = cp.cp_getParam('flag')
			scoringTeam = newTeam
			#takeoverType = TAKEOVERTYPE_CAPTURE
		else:
			# hit bottom, but still neutral
			pass

	
	if newTeam != -1 and cp.cp_getParam('team') != newTeam:
		cp.cp_setParam('team', newTeam)
	onCPTrigger(cp.triggerId, cp, 0, 0, 0)
	return
	
def onCTFTeamScore(team):
	#print'onCTFTeamScore'
	tix = bf2.gameLogic.getTickets(team)
	tix += 1
	if tix >= CTF_BASE_TICKETS:
		tix -= CTF_BASE_TICKETS
	bf2.gameLogic.setTickets(team, tix )
	#print 'team '+str(team)+' has ' +str(tix)+' points'
	if tix == CTF_CAPTURE_LIMIT:
		#print'tix == CTF_CAPTURE_LIMIT:'
		AdjustFinalScores()
		FreeExistingTimers()
		host.sgl_endGame(team, 3)
	else:
		pass #print'not oever'
	

def AdjustFinalScores():
	t1 = bf2.gameLogic.getTickets(1)
	t2 = bf2.gameLogic.getTickets(2)
	if t1 >= CTF_BASE_TICKETS:
		t1 -= CTF_BASE_TICKETS
		bf2.gameLogic.setTickets(1, t1)
	if t2 >= CTF_BASE_TICKETS:
		t2 -= CTF_BASE_TICKETS
		bf2.gameLogic.setTickets(2, t2)

def PlayerDroppedFlag(p, playersTeam):

	if playersTeam == 1:
		CTF.team1Carrier = -1
		CTF.usFlagUnheldRemaining = CTF_RETURN_UNHELD_FLAG_COUNT
		CTF.usFlagNoPhys.setDamage(1)
		CTF.usFlagHasPhys.setPosition(CTF.usFlagNoPhys.getPosition())
		
		#CTF.usFlagNoPhys.setPosition(CTF.usFlagHousePos)			
		ShowOffObject(CTF.usFlagNoPhys)
		
		CTF.usFlagHasPhys.setDamage(CTF.blinkDamage)
		SendFlagEventMessage(p.getName(), 1, 4)	
	elif playersTeam == 2:
		CTF.team2Carrier = -1
		CTF.oppFlagUnheldRemaining = CTF_RETURN_UNHELD_FLAG_COUNT
		CTF.oppFlagNoPhys.setDamage(1)
		CTF.oppFlagHasPhys.setPosition(CTF.oppFlagNoPhys.getPosition())
		
		#CTF.oppFlagNoPhys.setPosition(CTF.oppFlagHousePos)			
		ShowOffObject(CTF.oppFlagNoPhys)
		
		CTF.oppFlagHasPhys.setDamage(CTF.blinkDamage)
		SendFlagEventMessage(p.getName(), 2, 4) 
	else:
		pass #print'ERROR: PlayerDroppedFlag: Cant determine team'

def onPlayerKilledCQ(victim, attacker, weapon, assists, object):
	gpm_cq.onPlayerKilledCQ(victim, attacker, weapon, assists, object)
	if not victim: return
	
	if victim.getTeam() == 2:
		if CTF.team1FlagIsTaken and CTF.team2Carrier == victim.index:
			PlayerDroppedFlag(victim,2)
			if (not attacker is None) and (attacker.getTeam() == 1):
				attacker.score.cpAssists  += 1
				addScore(attacker, CTF_SCORE_KILLED_CARRIER, RPL)
				bf2.gameLogic.sendGameEvent(attacker, 12, 2) #12 = Conquest, 2 = Assist
	elif victim.getTeam() == 1: 
		if CTF.team2FlagIsTaken and CTF.team1Carrier == victim.index:
			PlayerDroppedFlag(victim,1)
			if (not attacker is None) and (attacker.getTeam() == 2):
				attacker.score.cpAssists  += 1
				addScore(attacker, CTF_SCORE_KILLED_CARRIER, RPL)
				bf2.gameLogic.sendGameEvent(attacker, 12, 2) #12 = Conquest, 2 = Assist
	else: 
		if g_debug: print 'TEAM ===UNKNOWN== PLAYER DIED'
		
def onPlayerConnect(p):
	CheckPlayerCount()
def onPlayerDisconnect(p):
	CheckPlayerCount()
	#print 'onPlayerDisconnect'
	if p.index == CTF.team2Carrier and CTF.team1FlagIsTaken:
		PlayerDroppedFlag(p,2)
	if p.index == CTF.team1Carrier and CTF.team2FlagIsTaken:
		PlayerDroppedFlag(p,1)
			
	
def onPlayerSpawn(player, soldier):

	player.killed = False #(wtf?)from cq 
		
	if not CTF.setupInit:
		CTF.setupInit = 1
		
		#print"get pco's"
		try:
			GetCtfPcos()
		except:
			pass #print'cant: GetCtfPcos'
		ResetFlagCpos(1)
		ResetFlagCpos(2)
		
		CTF.team1PhysTrigId = bf2.triggerManager.createRadiusTrigger(CTF.oppFlagHasPhys, onCTFWithPhysTrigger, '<<PCO>>', CTF_PICKUP_RADIUS, 1)		
		CTF.team2PhysTrigId = bf2.triggerManager.createRadiusTrigger(CTF.usFlagHasPhys, onCTFWithPhysTrigger, '<<PCO>>', CTF_PICKUP_RADIUS, 2)		
		#print'Created flag triggers...'
	
	
		#FreeExistingTimers()
		
		CTF.flagUpdateTimer = bf2.Timer(UpdateFlags, 1, 1)
		CTF.flagUpdateTimer.setRecurring(CTF_FLAG_UPDATE_INTERVAL)
		#print 'created CTF.flagUpdateTimer'
		CTF.secureFlagTimer = bf2.Timer(SecureFlags, 1, 1)
		CTF.secureFlagTimer.setRecurring(CTF_SECURE_FLAG_INTERVAL)
		#print 'created CTF.secureFlagTimer'

		
# # # # # # # #  Utils  # # # # # # # # #
def FindShowOffPosition():
	avg = [0.0, 0.0]
	pCnt = 0
	high = -9000.0
	for p in bf2.playerManager.getPlayers():
		if p.isAlive():
			pCnt += 1
			pPos = p.getDefaultVehicle().getPosition()
			if pPos[1] > high: high = pPos[1]
			avg[0] += pPos[0]
			avg[1] += pPos[2]

	#print'loop done'
	if pCnt > 0:
		return (avg[0] / pCnt , high + 100.0 , avg[1] / pCnt)	
	else:
		return None
		
def ShowOffObject(obj):
	pos = FindShowOffPosition()
	global CTF_CurMarkNum
	if not pos is None:
		#print 'not pos is None===' + str(pos)
		try:
			obj.setPosition(pos)
			t = CTF_CurMarkNum
			CTF_CurMarkNum += 1
			#print 'showed off ok: '+str(t)
			tmr = bf2.Timer(SecureFlags, MARKER_SHOWOFF_INTERVAL, 1, t)
			CTF_FixMarkerList.append((t,tmr))
		except:
			pass
	
def CheckPlayerCount():
	if not CTF_USE_LARGE_SERVER_UNLAG: return
	global CTF_BLINK_COUNT
	global CTF_UNLAG_PLAYER_COUNT
	
	total = bf2.playerManager.getNumberOfPlayers()
		
	if total >= CTF_UNLAG_PLAYER_COUNT:
		CTF.flagUpdateTimer.setRecurring(float(CTF_FLAG_UPDATE_INTERVAL * 2.0))
		CTF_BLINK_COUNT = 3
	else:
		CTF.flagUpdateTimer.setRecurring(CTF_FLAG_UPDATE_INTERVAL)
		CTF_BLINK_COUNT = 5





























































































TAKEOVERTYPE_CAPTURE = 1
TAKEOVERTYPE_NEUTRALIZE = 2

SCORE_CAPTURE = 2
SCORE_NEUTRALIZE = 2
SCORE_CAPTUREASSIST = 1
SCORE_NEUTRALIZEASSIST = 1
SCORE_DEFEND = 1

# called when a control point flag reached top or bottom
def onCPStatusChange(cp, top):

	playerId = -1
	takeoverType = -1
	newTeam = -1
	scoringTeam = -1
	
	if top:	cp.flagPosition = Top
	else:   cp.flagPosition = Bottom
	
	# determine capture / neutralize / defend
	if cp.cp_getParam('team') != 0:

		if top:
			# regained flag, do nothing
			pass
			
		else:
			# neutralize
			newTeam = 0
			if cp.cp_getParam('team') == 1:
				scoringTeam = 2
			else:
				scoringTeam = 1
				
			takeoverType = TAKEOVERTYPE_NEUTRALIZE

	else:

		if top:
			# capture
			newTeam = cp.cp_getParam('flag')
			scoringTeam = newTeam
			takeoverType = TAKEOVERTYPE_CAPTURE

		else:
			# hit bottom, but still neutral
			pass

	
	# scoring
	if takeoverType > 0:
		pcos = bf2.triggerManager.getObjects(cp.triggerId)
	
		# count number of players
		scoringPlayers = []
		firstPlayers = []
		for o in pcos:
			if o.getParent(): continue

			occupyingPlayers = o.getOccupyingPlayers()
			for p in occupyingPlayers:
			
				# only count first player in a vehicle
				if p != occupyingPlayers[0]: 
					continue
					
				if p.isAlive() and not p.isManDown() and p.getTeam() == scoringTeam:
					if len(firstPlayers) == 0 or p.enterCpAt < firstPlayers[0].enterCpAt:
						firstPlayers = [p]
					elif p.enterCpAt == firstPlayers[0].enterCpAt:
						firstPlayers += [p]
					
					if not p in scoringPlayers:
						scoringPlayers += [p]
	
		# deal score
		for p in scoringPlayers:
			oldScore = p.score.score;
			if takeoverType == TAKEOVERTYPE_CAPTURE:
				if p in firstPlayers:
					p.score.cpCaptures += 1
					addScore(p, SCORE_CAPTURE, RPL)
					bf2.gameLogic.sendGameEvent(p, 12, 0) #12 = Conquest, 0 = Capture
					playerId = p.index
				else:
					p.score.cpAssists += 1
					addScore(p, SCORE_CAPTUREASSIST, RPL)
					bf2.gameLogic.sendGameEvent(p, 12, 2) #12 = Conquest, 2 = Assist


			elif takeoverType == TAKEOVERTYPE_NEUTRALIZE:
				if p in firstPlayers:
					p.score.cpNeutralizes += 1
					addScore(p, SCORE_NEUTRALIZE, RPL)
					bf2.gameLogic.sendGameEvent(p, 12, 3) #12 = Conquest, 3 = Neutralize
				else:
					p.score.cpNeutralizeAssists += 1
					addScore(p, SCORE_NEUTRALIZEASSIST, RPL)
					bf2.gameLogic.sendGameEvent(p, 12, 4) #12 = Conquest, 4 = Neutralize assist
					
				

	# immediate ticket loss for opposite team
	enemyTicketLossInstant = cp.cp_getParam('enemyTicketLossWhenCaptured')
	if enemyTicketLossInstant > 0 and newTeam > 0:
		
		if newTeam == 1:
			punishedTeam = 2
		elif newTeam == 2:
			punishedTeam = 1
		
		tickets = bf2.gameLogic.getTickets(punishedTeam)
		tickets -= enemyTicketLossInstant
		bf2.gameLogic.setTickets(punishedTeam, tickets)
	
	
	# update control point	
	cp.cp_setParam('playerId', playerId) #always set player first
	if newTeam != -1 and cp.cp_getParam('team') != newTeam:
		cp.cp_setParam('team', newTeam)
	onCPTrigger(cp.triggerId, cp, 0, 0, 0)
	updateTicketLoss()

				
		














