# Battlefield 2142 Capture the Flag Game Mode
#Autor: Michael 'Mach10' McCormack
#E-Mail: mach10@comcast.net
#
#Purpose:
#This creates a new game mode 'Capture the Flag' for Battlefield 2142. Players must
#take the enemy flag from the enemy flag pole (main base) by using the #8 unlock.
#Players must take this flag back to their non-cap to capture the flag. Flags can only
#be captured if your team's flag is hanging on your team's flag pole (main base). Players
#may 'throw' the flag by using the #8 unlock while carrying the flag.

TAKEOVERTYPE_CAPTURE = 1
TAKEOVERTYPE_NEUTRALIZE = 2

SCORE_CAPTURE = 2
SCORE_NEUTRALIZE = 1
SCORE_CAPTUREASSIST = 1
SCORE_NEUTRALIZEASSIST = 1
SCORE_DEFEND = 1

SCORE_CTF_CAPTURE = 'capture'
SCORE_CTF_RETURN = 'return'
SCORE_CTF_STEAL = 'steal'

Top = 0
Middle = 1
Bottom = 2

PAC_TEAM_CARRIER = None
EU_TEAM_CARRIER = None

PAC_DROP_FLAG = None
EU_DROP_FLAG = None

PAC_FLAG_TEMPLATE = "pac_flag_l2"
EU_FLAG_TEMPLATE = "eu_flag_l2"

PAC_DF_TEMPLATE = "pac_dropflag_l2"
EU_DF_TEMPLATE = "eu_dropflag_l2"

S_EU_STOLE_FLAG = None
S_EU_STOLE_FLAG = None
S_EU_RETURNED_FLAG = None
S_EU_CAPTURED_FLAG = None
S_PAC_STOLE_FLAG = None
S_PAC_RETURNED_FLAG = None
S_PAC_CAPTURED_FLAG = None

CTF_GAME_STARTED = False

import host
import bf2
import math
from game.scoringCommon import addScore, RPL
from game.ctfsupports import initSupport
from game.ctfsupports import addFlag, removeFlag, resetDropFlag, addCTFScore, isDropFlag, killAllTimers, onDropTrigger
from game.ctfsupports import setInPlay, getInPlay, checkHolder, findCarrier, getClosestCP, distToFlag, dropFlag, playSound
from bf2 import g_debug

g_controlPoints = [] # cache, as this map won't change



def init():
	# events hook
	host.registerGameStatusHandler(onGameStatusChanged)
	if host.sgl_getIsAIGame() == 1:
		host.sh_setEnableCommander(0)
	else:
		host.sh_setEnableCommander(0)
		
	host.registerHandler('TimeLimitReached', onTimeLimitReached, 1)	

	if g_debug: print "gpm_ctf.py initialized"


def deinit():
	bf2.triggerManager.destroyAllTriggers()
	global g_controlPoints, PAC_TEAM_CARRIER, EU_TEAM_CARRIER
	global PAC_DROP_FLAG, EU_DROP_FLAG, CTF_GAME_STARTED
	
	g_controlPoints = []
	
	PAC_TEAM_CARRIER = None
	EU_TEAM_CARRIER = None
	PAC_DROP_FLAG = None
	EU_DROP_FLAG = None
	CTF_GAME_STARTED = False
	
	
	host.unregisterGameStatusHandler(onGameStatusChanged)
	
	host.unregisterHandler('TimeLimitReached', onTimeLimitReached)	
	host.unregisterHandler('ControlPointChangedOwner', onCPStatusChange)
	host.unregisterHandler('TicketLimitReached', onTicketLimitReached)
	host.unregisterHandler('PlayerDeath', onPlayerDeathCQ)
	host.unregisterHandler('PlayerKilled', onPlayerKilledCQ)
	host.unregisterHandler('PlayerRevived', onPlayerRevived)
	host.unregisterHandler('PlayerSpawn', onPlayerSpawn)
	host.unregisterHandler('EnterVehicle', onEnterVehicle)
	host.unregisterHandler('ExitVehicle', onExitVehicle)
	host.unregisterHandler('VehicleSpawn', onVehicleSpawn)
	host.unregisterHandler('VehicleDestroyed', onVehicleDestroyed)
	host.unregisterHandler('PlayerDisconnect', onPlayerDisconnect)
	host.unregisterHandler('PlayerChangeTeams', onPlayerChangeTeams)
	
	if g_debug: print "gpm_ctf.py uninitialized"


def onGameStatusChanged(status):

	global g_controlPoints
	killAllTimers()
	
	if status == bf2.GameStatus.Playing: 

		# add control point triggers
		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 isHemi != 0:
				if obj.cp_getParam('unableToChangeTeam') != 0:
					if obj.cp_getParam('team') == 1:
						id = bf2.triggerManager.createHemiSphericalTrigger(obj, onPacPoleTrigger, '<<PCO>>', 1.5, (1, 2, 3))
					
					elif obj.cp_getParam('team') == 2:
						id = bf2.triggerManager.createHemiSphericalTrigger(obj, onEuPoleTrigger, '<<PCO>>', 1.5, (1, 2, 3))
				else:
					id = bf2.triggerManager.createHemiSphericalTrigger(obj, onCPTrigger, '<<PCO>>', radius, (1, 2, 3))
			else:
				if obj.cp_getParam('unableToChangeTeam') != 0:
					if obj.cp_getParam('team') == 1:
						id = bf2.triggerManager.createRadiusTrigger(obj, onPacPoleTrigger, '<<PCO>>', 1.5, (1, 2, 3))
					
					elif obj.cp_getParam('team') == 2:
						id = bf2.triggerManager.createRadiusTrigger(obj, onEuPoleTrigger, '<<PCO>>', 1.5, (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

		host.registerHandler('ControlPointChangedOwner', onCPStatusChange)

		# setup ticket system
		
		bf2.gameLogic.setTickets(1, 10)
		bf2.gameLogic.setTickets(2, 10)

		bf2.gameLogic.setTicketState(1, 0)
		bf2.gameLogic.setTicketState(2, 0)

		bf2.gameLogic.setTicketLimit(1, 1, 0)
		bf2.gameLogic.setTicketLimit(2, 1, 0)
		bf2.gameLogic.setTicketLimit(1, 2, 1)
		bf2.gameLogic.setTicketLimit(2, 2, 1)
		bf2.gameLogic.setTicketLimit(1, 3, 3)
		bf2.gameLogic.setTicketLimit(2, 3, 3)
		bf2.gameLogic.setTicketLimit(1, 4, 4)
		bf2.gameLogic.setTicketLimit(2, 4, 4)
		
		host.registerHandler('TicketLimitReached', onTicketLimitReached)
		updateTicketLoss()

		# player events
		host.registerHandler('PlayerDeath', onPlayerDeathCQ)
		host.registerHandler('PlayerKilled', onPlayerKilledCQ)
		host.registerHandler('PlayerRevived', onPlayerRevived)
		host.registerHandler('PlayerSpawn', onPlayerSpawn)
		host.registerHandler('EnterVehicle', onEnterVehicle)
		host.registerHandler('ExitVehicle', onExitVehicle)
		host.registerHandler('VehicleSpawn', onVehicleSpawn)
		host.registerHandler('VehicleDestroyed', onVehicleDestroyed)
		host.registerHandler('PlayerDisconnect', onPlayerDisconnect)
		host.registerHandler('PlayerChangeTeams', onPlayerChangeTeams)

		if g_debug: print "Capture the Flag gamemode initialized."
	else:
		bf2.triggerManager.destroyAllTriggers()
		g_controlPoints = []

def onPlayerDisconnect(player):
	global EU_TEAM_CARRIER, PAC_TEAM_CARRIER
	
	if player.index == EU_TEAM_CARRIER:
		try:
			victim.flag.setDamage(-1)
		except: pass
		
		player.flag = None
		dropFlag(PAC_DROP_FLAG, player, player.getTeam())
		setInPlay(PAC_DROP_FLAG, 1)
		host.rcon_invoke("game.sayAll \"" + "|C1001 " + player.getName() + " dropped PAC's flag."  + "\"")
		EU_TEAM_CARRIER = None
		
	elif player.index == PAC_TEAM_CARRIER:
		try:
			player.flag.setDamage(-1)
		except: pass
		
		player.flag = None
		dropFlag(PAC_DROP_FLAG, player, player.getTeam())
		setInPlay(PAC_DROP_FLAG, 1)
		host.rcon_invoke("game.sayAll \"" + "|C1001 " + player.getName() + " dropped PAC's flag."  + "\"")
		EU_TEAM_CARRIER = None		

	
def onPlayerChangeTeams(player, humanHasSpawed):
	player.changedTeam = True

def calcStartTickets(mapDefaultTickets):
	return int(mapDefaultTickets * (bf2.serverSettings.getTicketRatio() / 100.0))
	
	

def onTimeLimitReached(value):
	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
	
	host.sgl_endGame(winner, victoryType, 0)



# update ticket system
def updateTicketLoss():
	areaValueTeam1 = 0
	areaValueTeam2 = 0
	totalAreaValue = 0
	numCpsTeam0 = 0
	numCpsTeam1 = 0
	numCpsTeam2 = 0
	
	# calculate control point area value for each team
	for obj in g_controlPoints:
		team = obj.cp_getParam('team')
		if team == 1:
			numCpsTeam1 += 1
			
		elif team == 2:
			numCpsTeam2 += 1
			
		else:
			numCpsTeam0 += 1
			totalAreaValue += 0
		
	# check if a team has no control points
	if numCpsTeam1 == 0 or numCpsTeam2 == 0:
		if numCpsTeam1 == 0:
			losingTeam = 1
			winningTeam = 2
		else:
			losingTeam = 2
			winningTeam = 1
		
		# check if there is anyone alive
		foundLivingPlayer = False
		for p in bf2.playerManager.getPlayers():
			if p.getTeam() == losingTeam and p.isAlive() and not p.isAutoController():
				foundLivingPlayer = True
				break
				
		if not foundLivingPlayer:

			# drop tickets
			ticketLossPerSecond = bf2.gameLogic.getDefaultTicketLossAtEndPerMin()
			bf2.gameLogic.setTicketChangePerSecond(losingTeam, -ticketLossPerSecond)
			bf2.gameLogic.setTicketChangePerSecond(winningTeam, 0)
			
			return

	
DOWNWARDS = -1
UPWARDS = 1	

# called when tickets reach a predetermined limit (negativ value means that the tickets have become less than the limit)
def onTicketLimitReached(team, limitId):
	if (limitId == -1):
		if (team == 1):
			winner = 2
		
		elif (team == 2):
			winner = 1
		
		bf2.gameLogic.setTicketState(1, 0)
		bf2.gameLogic.setTicketState(2, 0)
	
		host.sgl_endGame(winner, 3, 0)		

	# update ticket state
	else:
		updateTicketWarning(team, limitId)

	

# called when the ticket state should be updated (for triggering messages and sounds based on tickets left)
def updateTicketWarning(team, limitId):

	oldTicketState = bf2.gameLogic.getTicketState(team)
	newTicketState = 0
	
	if (oldTicketState >= 20):
		newTicketState = 20		

	if (limitId == -2):
		newTicketState = 20
	
	elif (limitId == 2):
		newTicketState = 0		

	elif (limitId == -3):
		newTicketState += 1

	elif (limitId == -4):
		newTicketState += 2

	elif (limitId == -5):
		newTicketState += 3

	elif (limitId == -6):
		newTicketState += 4

	elif (limitId == -7):
		newTicketState += 5

	elif (limitId == -8):
		newTicketState += 6

	if (oldTicketState != newTicketState):
		bf2.gameLogic.setTicketState(team, newTicketState)
		
	
	
# called when someone enters or exits cp radius
def onCPTrigger(triggerId, cp, vehicle, enter, userData):
	if not cp.isValid(): return

	if vehicle and vehicle.getParent(): return
	
	# can this cp be captured at all?
	if cp.cp_getParam('unableToChangeTeam') != 0:
		return					
		
	playersInVehicle = None	
	if vehicle:
		playersInVehicle = vehicle.getOccupyingPlayers()
	
	if enter:
		for p in playersInVehicle:
			cp = getOccupyingCP(p)
			if cp != None:
				if not p.getIsInsideCP():
					if g_debug: print "Resetting enterPctAt for player ", p.getName()
					p.enterCpAt = host.timer_getWallTime()
	
	if vehicle:	
		for p in playersInVehicle:
			# only count first player in a vehicle
			if p == playersInVehicle[0]:  
				if g_debug: print p.index, " is in radius. v=", vehicle.templateName
				p.setIsInsideCP(enter)	
			else:
				p.setIsInsideCP(0)
				if enter == 1:
					bf2.gameLogic.sendHudEvent(p, 71, 49) #71 = HEEnableHelpMessage, 49 = VHMExitToCaptureFlag;


	# count people in radius
	team1Occupants = 0
	team2Occupants = 0

	pcos = bf2.triggerManager.getObjects(cp.triggerId)
	for o in pcos:
		if not o: continue # you can get None in the result tuple when the host can't figure out what object left the trigger
		if o.getParent(): continue # getOccupyingPlayers returns all players downwards in the hierarchy, so dont count them twice
		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():
				
				if not p.killed:
					if g_debug: print "Player ", p.getName(), " is inside radius"

					if p.getTeam() == 1:
						team1Occupants += 1
					elif p.getTeam() == 2:
						team2Occupants += 1


	# determine who is taking control
	team1OverWeight = team1Occupants - team2Occupants
	attackOverWeight = 0

	if team1OverWeight > 0:
		attackingTeam = 1
	elif team1OverWeight < 0:
		attackingTeam = 2
	else:
		attackingTeam = 0

	
	if team1Occupants == 0 and team2Occupants == 0:

		# nobody here, slowly go back to owning team
		if cp.cp_getParam('team') == 0:
			attackOverWeight = -0.5
		else:
			attackOverWeight = 0.5
			
		timeToChangeControl = cp.cp_getParam('timeToLoseControl')

	else:

		# raise flag if already ours, or at bottom and neutral. Otherwise lower first.
		if cp.cp_getParam('flag') == attackingTeam or (cp.flagPosition == Bottom and cp.cp_getParam('team') == 0):

			# our flag, raise
			attackOverWeight = abs(team1OverWeight)
			timeToChangeControl = cp.cp_getParam('timeToGetControl')
		else:

			# other team raised flag, lower first
			attackOverWeight = - abs(team1OverWeight)
			timeToChangeControl = cp.cp_getParam('timeToLoseControl')


	if cp.cp_getParam('onlyTakeableByTeam') != 0 and cp.cp_getParam('onlyTakeableByTeam') != attackingTeam:
		return


	# flag can only be changed when at bottom
	if cp.flagPosition == Bottom:
		cp.cp_setParam('flag', attackingTeam)


	# calculate flag raising/lowering speed
	if timeToChangeControl > 0:
		takeOverChangePerSecond = 1.0 * attackOverWeight / timeToChangeControl
	else:
		takeOverChangePerSecond = 0.0

	if (cp.flagPosition == Top and takeOverChangePerSecond > 0) or (cp.flagPosition == Bottom and takeOverChangePerSecond < 0):
		takeOverChangePerSecond = 0.0

	if abs(takeOverChangePerSecond) > 0:
		cp.flagPosition = Middle
				
	cp.cp_setParam('takeOverChangePerSecond', takeOverChangePerSecond)


	
# 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
					playerId = p.index
				else:
					p.score.cpNeutralizeAssists += 1
					addScore(p, SCORE_NEUTRALIZEASSIST, RPL)
					bf2.gameLogic.sendGameEvent(p, 12, 4) #12 = Conquest, 4 = Neutralize assist
	
	# 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()


def onPlayerDeathCQ(victim, vehicle):		
	if victim == None:
		return	

	# check if it was the last player
	foundLivingPlayer = False
	for p in bf2.playerManager.getPlayers():
		if p != victim and p.getTeam() == victim.getTeam() and p.isAlive() and not p.isAutoController():
			foundLivingPlayer = True
	
	if not foundLivingPlayer:
		updateTicketLoss()
	


def onPlayerKilledCQ(victim, attacker, weapon, assists, object):
	global EU_TEAM_CARRIER, PAC_TEAM_CARRIER
	
	if not victim:
		return
	
	victim.killed = True
	team = victim.getTeam()
	
	if victim.index == PAC_TEAM_CARRIER:
		if victim.changedTeam:
			if team == 2:
				team = 1

		try:
			victim.flag.setDamage(-1)
		except: pass
		
		victim.flag = None
		dropFlag(EU_DROP_FLAG, victim, team)
		setInPlay(EU_DROP_FLAG, 1)
		host.rcon_invoke("game.sayAll \"" + "|C1001 " + victim.getName() + " dropped EU's flag."  + "\"")
		PAC_TEAM_CARRIER = None
		
		
	elif victim.index == EU_TEAM_CARRIER:
		if victim.changedTeam:
			if team == 1:
				team = 2

		try:
			victim.flag.setDamage(-1)
		except: pass
		
		victim.flag = None
		dropFlag(PAC_DROP_FLAG, victim, team)
		setInPlay(PAC_DROP_FLAG, 1)
		host.rcon_invoke("game.sayAll \"" + "|C1001 " + victim.getName() + " dropped PAC's flag."  + "\"")
		EU_TEAM_CARRIER = None
		
	# update flag takeover status if victim was in a CP radius
	cp = getOccupyingCP(victim)
	if cp != None:
		onCPTrigger(-1, cp, victim.getVehicle(), False, None)

		# give defend score if killing enemy within cp radius
		if attacker != None and attacker.getTeam() != victim.getTeam()\
		   and cp.cp_getParam('unableToChangeTeam') == 0 and cp.cp_getParam('onlyTakeableByTeam') == 0:
		
			if cp != None and cp.cp_getParam('team') == attacker.getTeam():
				attacker.score.cpDefends += 1
				addScore(attacker, SCORE_DEFEND, RPL)
				bf2.gameLogic.sendGameEvent(attacker, 12, 1) #12 = Conquest, 1 = Defend


def onPlayerRevived(victim, attacker):

	# update flag takeover status if victim was in a CP radius
	victim.killed = False
	
	cp = getOccupyingCP(victim)
	if cp != None:
		onCPTrigger(-1, cp, victim.getVehicle(), True, None)
	
	
	
def onPlayerSpawn(player, soldier):
	global CTF_GAME_STARTED
	
	player.killed = False
	player.changedTeam = False
	if not CTF_GAME_STARTED:
		CTF_GAME_STARTED = True
		setDropFlags()
		initSupport()
	
	
def onEnterVehicle(player, vehicle, freeSoldier = False):
	rootVehicle = bf2.objectManager.getRootParent(vehicle)
	# update flag takeover status if player in a CP radius
	if player == None:
		return
	cp = getOccupyingCP(player)
	playersInVehicle = rootVehicle.getOccupyingPlayers()
	if cp != None and player == playersInVehicle[0]:
		occupyingPlayers = rootVehicle.getOccupyingPlayers()
		for p in occupyingPlayers:
			p.setIsInsideCP(False)
		if cp.cp_getParam('unableToChangeTeam') == 0:
			player.setIsInsideCP(True)
	else:		
		player.setIsInsideCP(False)



def onExitVehicle(player, vehicle):
	# Player remaining in vehicle might capture CP
	playersInVehicle = vehicle.getOccupyingPlayers()
	if len(playersInVehicle) != 0:
		remainingPlayer = playersInVehicle[0]
		if remainingPlayer != None:
			cpRm = getOccupyingCP(remainingPlayer)
			if cpRm != None and cpRm.cp_getParam('unableToChangeTeam') == 0:
				remainingPlayer.setIsInsideCP(True)

	# update flag takeover status if player in a CP radius
	cp = getOccupyingCP(player)
	if cp != None and cp.cp_getParam('unableToChangeTeam') == 0:
		player.setIsInsideCP(True)
	else:		
		player.setIsInsideCP(False)


# find cp that player is occupying, if any		
def getOccupyingCP(player):	
	if player == None: return

	vehicle = player.getVehicle()
	playerPos = vehicle.getPosition()
	
	# find closest CP
	closestCP = None
	if len(g_controlPoints) == 0: return None
	for obj in g_controlPoints:
		distanceTo = getVectorDistance(playerPos, obj.getPosition())
		if closestCP == None or distanceTo < closestCPdist:
			closestCP = obj
			closestCPdist = distanceTo
	
	# is the player in radius?
	pcos = bf2.triggerManager.getObjects(closestCP.triggerId)
	for o in pcos:
		if o == player.getDefaultVehicle():
			# Player is DEFAULT vehicle - this is needed when called from onEnterVehicle
			return closestCP
		else:
			for p in o.getOccupyingPlayers():
				if p == player:
					return closestCP
	
	return None



# get distance between two positions
def getVectorDistance(pos1, pos2):
	diffVec = [0.0, 0.0, 0.0]
	diffVec[0] = math.fabs(pos1[0] - pos2[0])
	diffVec[1] = math.fabs(pos1[1] - pos2[1])
	diffVec[2] = math.fabs(pos1[2] - pos2[2])
	 
	return math.sqrt(diffVec[0] * diffVec[0] + diffVec[1] * diffVec[1] + diffVec[2] * diffVec[2])
		
#Object has spawned
def onVehicleSpawn(object):
	global EU_TEAM_CARRIER, PAC_TEAM_CARRIER
	
	if checkHolder(object):
		root = bf2.objectManager.getRootParent(object)
		carrier = findCarrier(object)
		carrierTeam = carrier.getTeam()
		cp = getOccupyingCP(carrier)
		if cp != None and cp.cp_getParam('unableToChangeTeam') == 1 and cp.cp_getParam('team') != carrierTeam:
			if carrierTeam == 1 and not getInPlay(EU_DROP_FLAG):
				PAC_TEAM_CARRIER = carrier.index
				carrier.flag = object
				removeFlag(object, PAC_FLAG_TEMPLATE, None) 
				removeFlag(EU_DROP_FLAG, EU_DF_TEMPLATE, None)
				addCTFScore(carrier, SCORE_CTF_STEAL)
				host.rcon_invoke("game.sayAll \"" + "|C1001 " +carrier.getName() + " has stolen EU's Flag!"  + "\"")
				playSound(S_PAC_STOLE_FLAG)
				
			elif carrierTeam == 2 and not getInPlay(PAC_DROP_FLAG):
				EU_TEAM_CARRIER = carrier.index
				carrier.flag = object
				removeFlag(object, EU_FLAG_TEMPLATE, None) 
				removeFlag(PAC_DROP_FLAG, PAC_DF_TEMPLATE, None)
				addCTFScore(carrier, SCORE_CTF_STEAL)
				host.rcon_invoke("game.sayAll \"" + "|C1001 " +carrier.getName() + " has stolen PAC's Flag!"  + "\"")
				playSound(S_EU_STOLE_FLAG)
				
			else:
				object.setDamage(-1)
				onVehicleDestroyed(object, carrier)	
			
		
		elif carrierTeam == 1 and getInPlay(EU_DROP_FLAG):
			distTo = distToFlag(carrier, EU_DROP_FLAG)
			if distTo < 1:
				PAC_TEAM_CARRIER = carrier.index
				carrier.flag = object
				removeFlag(object, PAC_FLAG_TEMPLATE, None)
				removeFlag(EU_DROP_FLAG, EU_DF_TEMPLATE, None)
				resetDropFlag(EU_DROP_FLAG, carrierTeam, True)
				host.rcon_invoke("game.sayAll \"" + "|C1001 " + carrier.getName() + " has stolen EU's Flag!"  + "\"")
				playSound(S_PAC_STOLE_FLAG)
			
		elif carrierTeam == 2 and getInPlay(PAC_DROP_FLAG):
			distTo = distToFlag(carrier, PAC_DROP_FLAG)
			if distTo < 1:
				EU_TEAM_CARRIER = carrier.index
				carrier.flag = object
				removeFlag(object, EU_FLAG_TEMPLATE, None)
				removeFlag(PAC_DROP_FLAG, PAC_DF_TEMPLATE, None)
				print 'picking up dropped flag, carrierTeam is', carrierTeam
				resetDropFlag(PAC_DROP_FLAG, carrierTeam, True)
				
				host.rcon_invoke("game.sayAll \"" + "|C1001 " + carrier.getName() + " has stolen PAC's Flag!"  + "\"")
				playSound(S_EU_STOLE_FLAG)
		else:
			object.setDamage(-1)
			onVehicleDestroyed(object, carrier)

def onVehicleDestroyed(vehicle, attacker):
	global EU_TEAM_CARRIER, PAC_TEAM_CARRIER
	
	if EU_TEAM_CARRIER != None:
		p = bf2.playerManager.getPlayerByIndex(EU_TEAM_CARRIER)
		if not p.flag.isValid() or vehicle.getDamage() < 1:
			p.flag = None
			dropFlag(PAC_DROP_FLAG, p, p.getTeam())
			host.rcon_invoke("game.sayAll \"" + "|C1001 " + p.getName() + " dropped PAC's flag."  + "\"")
			EU_TEAM_CARRIER = None
			
	if PAC_TEAM_CARRIER != None:
		p = bf2.playerManager.getPlayerByIndex(PAC_TEAM_CARRIER)
		if not p.flag.isValid() or vehicle.getDamage() < 1:
			p.flag = None
			dropFlag(EU_DROP_FLAG, p, p.getTeam())
			host.rcon_invoke("game.sayAll \"" + "|C1001 " + p.getName() + " dropped EU's flag."  + "\"")
			PAC_TEAM_CARRIER = None

	

def onPacPoleTrigger(triggerId, cp, vehicle, enter, userData):
	global PAC_TEAM_CARRIER
	
	if not vehicle:
		return
	
	if enter:
		for p in vehicle.getOccupyingPlayers():
			if p.isAlive() and not p.isManDown() and not p.killed:
				team = p.getTeam()
				if p.getDefaultVehicle() == p.getVehicle():
					if team == 1 and not getInPlay(PAC_DROP_FLAG) and p.index == PAC_TEAM_CARRIER:
						p.flag.setDamage(-1)
						PAC_TEAM_CARRIER = None
						addFlag(EU_DROP_FLAG, EU_DF_TEMPLATE)
						addCTFScore(p, SCORE_CTF_CAPTURE)
						host.rcon_invoke("game.sayAll \"" + "|C1001" + p.getName() + \
						" has captured EU's Flag!"  + "\"")
						playSound(S_PAC_CAPTURED_FLAG)


def onEuPoleTrigger(triggerId, cp, vehicle, enter, userData):
	global EU_TEAM_CARRIER
	
	if not vehicle:
		return
	
	if enter:
		for p in vehicle.getOccupyingPlayers():
			if p.isAlive() and not p.isManDown() and not p.killed:
				team = p.getTeam()
				if p.getDefaultVehicle() == p.getVehicle():
					if team == 2 and not getInPlay(EU_DROP_FLAG) and p.index == EU_TEAM_CARRIER:
						p.flag.setDamage(-1)
						EU_TEAM_CARRIER = None
						addFlag(PAC_DROP_FLAG, PAC_DF_TEMPLATE)
						addCTFScore(p, SCORE_CTF_CAPTURE)
						host.rcon_invoke("game.sayAll \"" + "|C1001 " + p.getName() + \
						" has captured PAC's Flag!"  + "\"")
						playSound(S_EU_CAPTURED_FLAG)

def setDropFlags():
	global EU_DROP_FLAG, PAC_DROP_FLAG
	global S_EU_STOLE_FLAG, S_EU_RETURNED_FLAG, S_EU_CAPTURED_FLAG
	global S_PAC_STOLE_FLAG, S_PAC_RETURNED_FLAG, S_PAC_CAPTURED_FLAG
	
	pcos = bf2.objectManager.getObjectsOfType('dice.hfe.world.ObjectTemplate.PlayerControlObject')
	for obj in pcos:
		
		if isDropFlag(obj):
			setInPlay(obj, 0)
			if obj.templateName == "eu_dropflag_l1":
				EU_DROP_FLAG = obj
				id = bf2.triggerManager.createHemiSphericalTrigger(obj, onDropTrigger, '<<PCO>>', 1.5, (1, 2, 3))
				obj.triggerId = id
				
			elif obj.templateName == "pac_dropflag_l1":
				PAC_DROP_FLAG = obj
				id = bf2.triggerManager.createHemiSphericalTrigger(obj, onDropTrigger, '<<PCO>>', 1.5, (1, 2, 3))
				obj.triggerId = id
				
		if obj.templateName == "eu_stole_flag":
			S_EU_STOLE_FLAG = obj
			
		elif obj.templateName == "eu_returned_flag":
			S_EU_RETURNED_FLAG = obj
			
		elif obj.templateName == "eu_captured_flag":
			S_EU_CAPTURED_FLAG = obj
			
		elif obj.templateName == "pac_stole_flag":
			S_PAC_STOLE_FLAG = obj
			
		elif obj.templateName == "pac_returned_flag":
			S_PAC_RETURNED_FLAG = obj
			
		elif obj.templateName == "pac_captured_flag":
			S_PAC_CAPTURED_FLAG = obj

