Official BF Editor Forums: Squadcapture - Gamemode For 2142 - Official BF Editor Forums

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

Squadcapture - Gamemode For 2142

#1 User is offline   aPantomimeHorse Icon

  • Newbie
  • Pip
  • Group: Members
  • Posts: 4
  • Joined: 28-October 06

Posted 28 October 2006 - 04:32 PM

I've written a modification for the conquest gametype that modifies the way control points are captured:

1) neutralizing a flag can only be done with the presence of certain squad leaders
2) capturing a neutral flag can only be done with the presence of certain squad leaders (this group is a superset of those that can neutralize)
3) a team must have a greater number of players at a flag by a certain surplus to neutralize or capture a flag

Which squad leaders and the number of soldiers needed varies by the number of players on the team.

I've tested it reasonably well, I think, but I only started BF modding yesterday, and I have a few concerns:

1) Do we have any good idea what among the rcon stuff works and how to call it?

2) How should I go about testing? The way I did my testing was really awkward; it involved running BF in a window and restarting a single player game or local network conquest game, and every time I made a change, I had to disconnect and start it up again [heh, it took me a while to figure out I didn't have to shut down the game completely]. I've read it should be possible to reinitialize the scripts with:

rcon pythonHost.reinitialize

...but this doesn't do anything, as far as I can tell.

3) I'd like to have some kind of HUD-based text, such as text in the middle of the screen. Is this feasible? If so, can it be done just in script (or, at least, in some way that doesn't necessitate client downloads).

4) How should a gamemode mod be run? I haven't tested my mode except on my local machine. I take it you can't run them on ranked servers, right?



So here's the code:

# conquest mod: SquadCapture
''' 
A squad leader must be present to capture a flag. Only the squadleaders of the first 
few squads (the exact number is defined by NUM_SQUADLEADERS_WHO_CAN_CAPTURE_OCCUPIED) can 
neutralize an enemy flag. The remaining squad leaders can capture neutralized flags. 

Author: Brian Will

Permissions: If you wish to distribute a derivitive of this mod, add your name to the author's list, and please 
try to use a different name for your mod if it significantly differs from SquadCapture.
'''

TAKEOVERTYPE_CAPTURE = 1
TAKEOVERTYPE_NEUTRALIZE = 2

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

#begin--added for SquadCapture

SQUAD_NAMES = ('ALPHA', 'BRAVO', 'CHARLIE', 'DELTA', 'ECHO', 'FOXTROT', 'GOLF', 'HOTEL')   # not sure I got the last 4 names right

# default capture settings
capSettingsTeam1 = {
	'numNeutralizingSquadleaders' : 1,   # e.g. setting this to 3 means the first 3 squadleaders (alpha, bravo, gamma) can neutralize an enemy flag
	'numRaisingSquadleaders' : 3,        # e.g. setting this to 3 means the first 3 squadleaders (alpha, bravo, gamma) can raise a neutral flag
	
	'minNeutralizeFlag' :  1,      # min number of soldiers present at cp needed to neutralize the flag
	'minRecoverFlag' : 1,         # number of soldiers required to raise back up your own team's flag if your team still controls the flag
	'minRaiseFlag' : 1,           # min number of soldiers present at cp needed to raise the flag
	
	'lastTeamSize' : 0
}

# same thing for the other team
capSettingsTeam2 = {
	'numNeutralizingSquadleaders' : 1,
	'numRaisingSquadleaders' : 3,
	
	'minNeutralizeFlag' :  1,
	'minRecoverFlag' : 1,    
	'minRaiseFlag' : 1,        
	
	'lastTeamSize' : 0
}

CANNOT_CAP = 0
CAN_RAISE = 1
CAN_NEUTRALIZE = 2

CAPTURE_SETTINGS_BROADCAST_RATE = 60 # interval (in seconds) to tell players the capture settings via their team talk

# these rates, strangely, are measured in 'how many flags can you cap a second', e.g. a NEUTRALIZE_RATE of 2.0 means you'll neutralize a flag in half a second
NEUTRALIZE_RATE = 0.35     # the neutralize rate is meant to be quite fast to help mitigate annoying spawn kills and being killed by sudden spawners
RAISE_RATE = 0.08    # this base raise rate should be something low to encourage teams to use more players at a flag
RECOVER_RATE = 0.13  # how fast the flag goes up when defending it
NEUTRAL_FALL_RATE = 0.08
NATURAL_RECOVER_RATE = 0.06
#--end

Top = 0
Middle = 1
Bottom = 2

import host
import bf2
import math
from game.scoringCommon import addScore, RPL
from bf2 import g_debug

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


#begin--added for SquadCapture

settingsReportTimer = None
settingsReportSendTimer = None
messageTimer = None

# a list of 2 members: the report for team 1, and the report for team 2 (starting reports are included to prevent an exception at start of server when one or both teams may have zero players)
captureSettingsReports = [
	(
			'*** ' + 'A squadleader from ' + 'ALPHA' + ' must be present to neutralize an enemy flag',
			'*** ' + 'A squadleader from ' + 'ALPHA, or BRAVO' + ' must be present to capture a neutral flag',
			'*** ' + '1' + ' or more soldiers must be present to neutralize an enemy flag',
			'*** ' + '1' + ' or more soldiers must be present to capture a neutralized flag'
	),
	(
			'*** ' + 'A squadleader from ' + 'ALPHA' + ' must be present to neutralize an enemy flag',
			'*** ' + 'A squadleader from ' + 'ALPHA, or BRAVO' + ' must be present to capture a neutral flag',
			'*** ' + '1' + ' or more soldiers must be present to neutralize an enemy flag',
			'*** ' + '1' + ' or more soldiers must be present to capture a neutralized flag'
	)
]   

	
def dispatchCaptureReportMessages(data):
	global messageTimer
	
	messageTimer = bf2.Timer(dispatchMessage, 0, 0)
	messageTimer.setRecurring(3)
	
	# messageTimer is destroyed in dispatchMessage


message = 0
def dispatchMessage(data):
	#each call only reports one out of the five messages in the report
	global message
	global messageTimer
			
	host.rcon_invoke('game.sayTeam 1 "' + captureSettingsReports[0][message] + '"')
	host.rcon_invoke('game.sayTeam 2 "' + captureSettingsReports[1][message] + '"')
	
	message += 1
	if message > 3:
		message = 0
		messageTimer.destroy()
		messageTimer = None
		
# this is called by a timer early on to make sure the reports start off right (I'm not confident playerconnect events get triggered properly at the start of a match, and players could disconnect between rounds, I believe)
def firstCaptureReports(data):
	setCaptureSettingsForTeam(1, capSettingsTeam1)
	setCaptureSettingsForTeam(2, capSettingsTeam2)
	getCaptureSettingsReports(None)
		
#--end

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

	#begin--add for SquadCapture

	global settingsReportTimer
	global settingsReportSendTimer
	
	# the getCaptureSettingsReports function is called on player connects and disconnects, but this is here to make sure it gets called once at start of the game before the dispatchCaptureReportMessage is called
	settingsReportTimer = bf2.Timer(firstCaptureReports, 30, 0)   
	
	settingsReportSendTimer = bf2.Timer(dispatchCaptureReportMessages, 40, 0)
	settingsReportSendTimer.setRecurring(CAPTURE_SETTINGS_BROADCAST_RATE) # how often to send a message about the info (this is set inside here because the timer seems to get confused when the recurring time is less than the initial wait time)
	#--end
	
	if g_debug: print "gpm_sp.py initialized"
		

	
	if g_debug: print "gpm_cq.py initialized"
		
		
		
def deinit():
	bf2.triggerManager.destroyAllTriggers()
	global g_controlPoints
	g_controlPoints = []
	
	#begin--add for SquadCapture
	global settingsReportTimer
	global settingsReportSendTimer
	
	settingsReportTimer.destroy()
	settingsReportTimer = None
	
	settingsReportSendTimer.destroy()
	settingsReportSendTimer = None
	#--end
	
	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)

	#begin--added for SquadControl
	host.unregisterHandler('PlayerConnect', setCaptureSettings) 
	host.unregisterHandler('PlayerDisconnect', setCaptureSettings) 
	
	host.unregisterHandler('PlayerConnect', getCaptureSettingsReports) 
	host.unregisterHandler('PlayerDisconnect', getCaptureSettingsReports) 
	#--end
	
	if g_debug: print "gpm_cq.py uninitialized"



def onGameStatusChanged(status):

	global g_controlPoints
	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:
				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

		host.registerHandler('ControlPointChangedOwner', onCPStatusChange)

		# setup ticket system
		ticketsTeam1 = calcStartTickets(bf2.gameLogic.getDefaultTickets(1))
		ticketsTeam2 = calcStartTickets(bf2.gameLogic.getDefaultTickets(2))
		
		bf2.gameLogic.setTickets(1, ticketsTeam1)
		bf2.gameLogic.setTickets(2, ticketsTeam2)

		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, 10)
		bf2.gameLogic.setTicketLimit(2, 2, 10)
		bf2.gameLogic.setTicketLimit(1, 3, int(ticketsTeam1*0.1))
		bf2.gameLogic.setTicketLimit(2, 3, int(ticketsTeam2*0.1))
		bf2.gameLogic.setTicketLimit(1, 4, int(ticketsTeam1*0.2))
		bf2.gameLogic.setTicketLimit(2, 4, int(ticketsTeam1*0.2))
		
		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)
		
		
		# 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)

		#begin--added for SquadCapture
		host.registerHandler('PlayerConnect', setCaptureSettings)  
		host.registerHandler('PlayerDisconnect', setCaptureSettings) 
		
		host.registerHandler('PlayerConnect', getCaptureSettingsReports)  
		host.registerHandler('PlayerDisconnect', getCaptureSettingsReports) 
		#--end
		
		if g_debug: print "Conquest gamemode initialized."
	else:
		bf2.triggerManager.destroyAllTriggers()
		g_controlPoints = []



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:
			areaValueTeam1 += obj.cp_getParam('areaValue', team)
			totalAreaValue += areaValueTeam1
			numCpsTeam1 += 1
		elif team == 2:
			areaValueTeam2 += obj.cp_getParam('areaValue', team)
			totalAreaValue += areaValueTeam2
			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

	
	# update ticket loss
	team1AreaOverweight = areaValueTeam1 - areaValueTeam2
	percentualOverweight = 1.0
	if totalAreaValue != 0:
		percentualOverweight = abs(team1AreaOverweight / totalAreaValue)
	
	ticketLossPerSecTeam1 = calcTicketLossForTeam(1, areaValueTeam2, -team1AreaOverweight)
	ticketLossPerSecTeam2 = calcTicketLossForTeam(2, areaValueTeam1, team1AreaOverweight)
	bf2.gameLogic.setTicketChangePerSecond(1, -ticketLossPerSecTeam1)
	bf2.gameLogic.setTicketChangePerSecond(2, -ticketLossPerSecTeam2)


	
# actual ticket loss calculation function
def calcTicketLossForTeam(team, otherTeamAreaValue, otherTeamAreaOverweight):
	if otherTeamAreaValue >= 100 and otherTeamAreaOverweight > 0:
		ticketLossPerSecond = (bf2.gameLogic.getDefaultTicketLossPerMin(team) / 60.0) * (otherTeamAreaOverweight / 100.0)
		return ticketLossPerSecond
	else:
		return 0


	
DOWNWARDS = -1
UPWARDS = 1	

# called when tickets reach a predetermined limit (negative 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)

#begin--added and modified functions below		
		
# returns whether a player can neutralize a flag or at least capture a flag already neutralized
def playerCaptureAbility(p):
	squad = p.getSquadId()
	
	team = p.getTeam()
	if team == 1:
		capSettings = capSettingsTeam1
	elif team == 2:
		capSettings = capSettingsTeam2
	else:
		return
	
	if p.isSquadLeader():
		if squad <= capSettings['numNeutralizingSquadleaders']:
			return CAN_NEUTRALIZE
		if squad <= capSettings['numRaisingSquadleaders']:
			return CAN_RAISE

	return CANNOT_CAP		


	
# called when someone enters or exits cp radius
# triggerId is not used, but the event expects it; vehicle is either the default soldier vehicle or some other vehicle; entere is whether the trigger is coming or going
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:  #vehicle is set to 0 when on CPTrigger is called manually instead of triggered (a manual caller doesn't have any vehicle to specify)
		playersInVehicle = vehicle.getOccupyingPlayers()
	
	if enter: # make note of the time when players entere the trigger; this is for scoring purposes below
		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()
	
	
	#set with each player whether they are inside a CP or not
	if vehicle:	
		for p in playersInVehicle: # for all the players in the vehicle that triggered the CP
			# 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)	 # enter will be false if player is leaving
			else:
				p.setIsInsideCP(0)
				if enter == 1:
					bf2.gameLogic.sendHudEvent(p, 71, 49) #71 = HEEnableHelpMessage, 49 = VHMExitToCaptureFlag;

	# count people in radius and identify if any of them can neutralize or raise flags
	team1Occupants = 0
	team2Occupants = 0

	team1CaptureAbility = 0
	team2CaptureAbility = 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
						
						playerAbility = playerCaptureAbility(p)
						if playerAbility > team1CaptureAbility:
							team1CaptureAbility = playerAbility
							
					elif p.getTeam() == 2:
						team2Occupants += 1
						
						playerAbility = playerCaptureAbility(p)
						if playerAbility > team1CaptureAbility:
							team2CaptureAbility = playerAbility
						
					
					
	# "attacking" team is the team with more players on the CP, even if it's their flag already
	team1OverWeight = team1Occupants - team2Occupants
	attackOverWeight = 0 # this is what speeds up the capture time with more players

	if team1OverWeight > 0:
		attackingTeam = 1
		attackingTeamAbility = team1CaptureAbility
		capSettings = capSettingsTeam1
	elif team1OverWeight < 0:
		attackingTeam = 2
		attackingTeamAbility = team2CaptureAbility
		capSettings = capSettingsTeam2
	else:
		# no players at cp
		if team1Occupants == 0:
			noInfluence(cp)
		# balanced number of players at each team at cp
		else:
			cp.cp_setParam('takeOverChangePerSecond', 0.0) # halt flag
		return
		
	imbalance = abs(team1OverWeight)
	
	cpTeam = cp.cp_getParam('team')
	
	# if flag not capturable by attackers
	if cp.cp_getParam('onlyTakeableByTeam') != 0 and cp.cp_getParam('onlyTakeableByTeam') != attackingTeam:
		cp.cp_setParam('takeOverChangePerSecond', 0.0) # halt flag
	# attacking neutral cp
	elif cpTeam == 0 and attackingTeamAbility >= CAN_RAISE and imbalance >= capSettings['minRaiseFlag']:
		# flag might be neutral but half raised because other team was raising it, so need to lower it back down first
		if cp.cp_getParam('flag') != attackingTeam and cp.flagPosition == Middle:
			neutralizeFlag(cp, NEUTRALIZE_RATE)
		# otherwise, just raise it
		else:
			raiseFlag(cp, attackingTeam, RAISE_RATE)
	# defending cp
	elif cpTeam == attackingTeam and imbalance >= capSettings['minRecoverFlag']:
		raiseFlag(cp, attackingTeam, RECOVER_RATE)
	# attacking enemy cp
	elif attackingTeamAbility >= CAN_NEUTRALIZE and imbalance >= capSettings['minNeutralizeFlag']:
		neutralizeFlag(cp, NEUTRALIZE_RATE)
	# attacking team without qualifications at least halts the flag
	else: 
		cp.cp_setParam('takeOverChangePerSecond', 0.0) # halt flag
	
# call this to move the flag when no players are there
def noInfluence(cp):

	flag = cp.flagPosition
	
	if flag == Top:
		speed = 0.0
	elif flag == Bottom:
		speed = 0.0
	# flag in middle
	else:
		#if flag is neutral, slowly run it down to the bottom
		if cp.cp_getParam('team') == 0:
			speed = -NEUTRAL_FALL_RATE
		# otherwise, slowly run it back up
		else:
			speed = NATURAL_RECOVER_RATE
		
	cp.cp_setParam('takeOverChangePerSecond', speed)

# [added for mod] lower a flag
def neutralizeFlag(cp, speed):
	
	speed = -speed  * 1.0 # make sure speed is a float

	if cp.flagPosition == Top:
		cp.flagPosition = Middle
	
	# don't see how we can get here, but I'm covering my bases; a flag already at the bottom shouldn't move
	elif cp.flagPosition == Bottom:
		speed = 0.0
	
	cp.cp_setParam('takeOverChangePerSecond', speed)
	
	
# [added for mod] call to move flag from neutral to captured
def raiseFlag(cp, attackingTeam, speed):

	speed = speed * 1.0  # make sure speed is a float
	
	cp.cp_setParam('flag', attackingTeam)
	
	if cp.flagPosition == Bottom:
		cp.flagPosition = Middle
	# not sure we can get here, but just in case
	elif cp.flagPosition == Top: 
		speed = 0.0
			
	cp.cp_setParam('takeOverChangePerSecond', speed)

	
def setCaptureSettings(player):
	
	attackingTeam = player.getTeam()
	
	if attackingTeam == 1:
		setCaptureSettingsForTeam(attackingTeam, capSettingsTeam1)
	elif attackingTeam == 2:
		setCaptureSettingsForTeam(attackingTeam, capSettingsTeam2)
	else:
		return # don't know what other values are possible for team, but I assume a player on neither team is on team 0, in which case nothing should be done here

# this was a part of setCaptureSettings, but I needed to be able to set the capture settings for some team without reference to any player, so I split it off
def setCaptureSettingsForTeam(team, capSettings):
		
	numPlayers = bf2.playerManager.getNumberOfPlayersInTeam(team)
	
	# 0 - 4 players on the team
	if numPlayers <= 4:
		capSettings['numNeutralizingSquadleaders'] = 1
		capSettings['numRaisingSquadleaders'] = 2
		capSettings['minRaiseFlag'] = 1
		capSettings['minNeutralizeFlag'] = 1
		capSettings['minRecoverFlag'] = 1
	# 5 - 7 players on the team
	elif numPlayers <= 7:
		capSettings['numNeutralizingSquadleaders'] = 1
		capSettings['numRaisingSquadleaders'] = 2
		capSettings['minRaiseFlag'] = 2
		capSettings['minNeutralizeFlag'] = 2
		capSettings['minRecoverFlag'] = 1
	# 8- 10 players on the team
	elif numPlayers <= 10:
		capSettings['numNeutralizingSquadleaders'] = 1
		capSettings['numRaisingSquadleaders'] = 2
		capSettings['minRaiseFlag'] = 2
		capSettings['minNeutralizeFlag'] = 2
		capSettings['minRecoverFlag'] = 1
	# 11 - 14 players on the team
	elif numPlayers <= 14:
		capSettings['numNeutralizingSquadleaders'] = 1
		capSettings['numRaisingSquadleaders'] = 3
		capSettings['minRaiseFlag'] = 3
		capSettings['minNeutralizeFlag'] = 3
		capSettings['minRecoverFlag'] = 1
	# 15 - 18 players on the team
	elif numPlayers <= 18:
		capSettings['numNeutralizingSquadleaders'] = 1
		capSettings['numRaisingSquadleaders'] = 3
		capSettings['minRaiseFlag'] = 4
		capSettings['minNeutralizeFlag'] = 3
		capSettings['minRecoverFlag'] = 2
	# 19 - 23 players on the team
	elif numPlayers <= 23:
		capSettings['numNeutralizingSquadleaders'] = 2
		capSettings['numRaisingSquadleaders'] = 3
		capSettings['minRaiseFlag'] = 4
		capSettings['minNeutralizeFlag'] = 3
		capSettings['minRecoverFlag'] = 2
	# 24+ players on the team
	else:
		capSettings['numNeutralizingSquadleaders'] = 2
		capSettings['numRaisingSquadleaders'] = 3
		capSettings['minRaiseFlag'] = 5
		capSettings['minNeutralizeFlag'] = 4
		capSettings['minRecoverFlag'] = 2
		
	#report the change to the team if team size has changed
	if numPlayers != capSettings['lastTeamSize']:
		capSettings['lastTeamSize'] = numPlayers


# the parameter is not used, but a parameter is needed to use this with event handlers and timers
def getCaptureSettingsReports(data):
	
	global captureSettingsReports
	
	for capSettings, i in ((capSettingsTeam1, 0), (capSettingsTeam2, 1)):
		
		# get the slices and then concatenate them into comma-seperated lists
		
		numNeutralizers = capSettings['numNeutralizingSquadleaders']
		numRaisers = capSettings['numRaisingSquadleaders']
		
		if numNeutralizers == 1:
			neutralizers = SQUAD_NAMES[0]
		else:
			neutralizers = ', '.join(SQUAD_NAMES[0:numNeutralizers - 1]) + ', or ' + SQUAD_NAMES[numNeutralizers - 1]
		
		if numRaisers == 1:
			raisers = SQUAD_NAMES[0]
		else:
			raisers = ', '.join(SQUAD_NAMES[0:numRaisers - 1]) + ', or ' + SQUAD_NAMES[numRaisers - 1]
		
		captureSettingsReports[i] =	(
			'*** ' + 'A squadleader from ' + neutralizers + ' must be present to neutralize an enemy flag',
			'*** ' + 'A squadleader from ' + raisers + ' must be present to capture a neutral flag',
			'*** ' + str(capSettings['minNeutralizeFlag']) + ' or more soldiers must be present to neutralize an enemy flag',
			'*** ' + str(capSettings['minRaiseFlag']) + ' or more soldiers must be present to capture a neutralized flag'
		)
#--end		


# this is registered with both PlayerConnect and the PlayerDisconnect events

# 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
					
				

	# 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()

				
				
def onPlayerDeathCQ(victim, vehicle):		

	# punish team with one ticket
	if victim == None:
		return
	team = victim.getTeam()
	teamTickets = bf2.gameLogic.getTickets(team)
	teamTickets -= 1
	bf2.gameLogic.setTickets(team, teamTickets)	

	# 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):
	if not victim: 
		return
	
	victim.killed = True
	
	# 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):
	player.killed = False
	
	
	
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])
		
		


Save this to <Battlefield 2142 directory>\mods\bf2142\python\game\gamemodes\gpm_cq.py (of course, save the original file before overwriting it).
0

#2 User is offline   aPantomimeHorse Icon

  • Newbie
  • Pip
  • Group: Members
  • Posts: 4
  • Joined: 28-October 06

Posted 30 October 2006 - 07:25 AM

I should add that implementing this mod for single player mode is as easy as pasting the bits I added/modded in the same places. I believe the same is true for titan mode, but I'll have to look more closely at that to make sure.

Also, I currently have it that the first x squad leaders can capture neutral flags while a subset of those players can also neutralize enemy flags. Perhaps I should change this so that squad leaders who can neutralize can't also capture neutral flags.
0

#3 User is offline   Sir.Darthmaster Icon

  • Member
  • PipPip
  • Group: Members
  • Posts: 165
  • Joined: 26-March 06
  • Gender:Male
  • Location:Verrebroek, Belgium

Posted 30 October 2006 - 10:07 PM

Sounds Great, Conflict Canada Might Want it :)
Posted Image
0

#4 User is offline   aPantomimeHorse Icon

  • Newbie
  • Pip
  • Group: Members
  • Posts: 4
  • Joined: 28-October 06

Posted 31 October 2006 - 12:43 AM

Conflict Canada is BF2, right? Well it's been a long time since I've had BF2 installed, so I don't remember the gamemode scripts for it, but if memory serves, it's very very similar (at least, all the BF2 scripting info I've seen seems to apply the same 2142).

If any one is interested, I'll install BF2 again and see about getting it to work there.
0

#5 User is offline   ice_killer Icon

  • Member
  • PipPip
  • Group: Members
  • Posts: 372
  • Joined: 29-March 06
  • Location:wezep netherlands

Posted 08 December 2006 - 05:51 PM

View PostaPantomimeHorse, on Oct 31 2006, 01:43 AM, said:

Conflict Canada is BF2, right? Well it's been a long time since I've had BF2 installed, so I don't remember the gamemode scripts for it, but if memory serves, it's very very similar (at least, all the BF2 scripting info I've seen seems to apply the same 2142).

If any one is interested, I'll install BF2 again and see about getting it to work there.

can you do that for hostile ground pm me if you want
Posted Image
0

#6 User is offline   Osis[OPK] Icon

  • Member
  • PipPip
  • Group: Members
  • Posts: 144
  • Joined: 07-August 05
  • Location:Germany

Posted 13 December 2006 - 01:56 PM

yes, sounds interesting. Nice Idea.

Would be nice if you would try this to do for BF2. ;)
0

#7 User is offline   Mach10 Icon

  • Member
  • PipPip
  • Group: Moderators
  • Posts: 423
  • Joined: 24-August 05
  • Location:Northeast New Jersey

Posted 13 December 2006 - 06:16 PM

Just remember, keep the game modes simple.... on paper, it is a nice idea, but in actual game play on public servers, it will turn into a mess. 99% of players only know how to play conquest, and of that 99% of them don't even play that well. Complex modes are usually the ones never played.
0

#8 User is offline   eggman Icon

  • Member
  • PipPip
  • Group: Members
  • Posts: 299
  • Joined: 31-December 05

Posted 14 December 2006 - 10:07 AM

View PostMach10, on Dec 13 2006, 06:16 PM, said:

Just remember, keep the game modes simple.... on paper, it is a nice idea, but in actual game play on public servers, it will turn into a mess. 99% of players only know how to play conquest, and of that 99% of them don't even play that well. Complex modes are usually the ones never played.


hehe yeah this is very true. Usability issues are tough to overcome and the HUD is really not moddable in any easy way... so yer stuck with very few tools to communicate to players. There are ways to do lots of stuff, but they are really tedious and time consuming.
Project Reality
http://www.realitymod.com
0

#9 User is offline   junk Icon

  • Expert
  • PipPipPipPip
  • Group: Members
  • Posts: 1,415
  • Joined: 07-November 05
  • Location:CA
  • Interests:Making stupid people fuckin dumber.

Posted 14 December 2006 - 06:45 PM

"99% of players only know how to play conquest, and of that 99% of them don't even play that well."

That's why we need more game modes so people can actually have a choice to not have to play with those cretins. So far, the only way to accomplish not getting sick of conquest within 10 minutes is to simply no longer play the game. It's been working like a charm for me and I highly recommend it.
Posted Image
"I don't wanna be a dick, but..."
0

#10 User is offline   Mach10 Icon

  • Member
  • PipPip
  • Group: Moderators
  • Posts: 423
  • Joined: 24-August 05
  • Location:Northeast New Jersey

Posted 19 December 2006 - 04:55 AM

View Postjunk, on Dec 14 2006, 01:45 PM, said:

"99% of players only know how to play conquest, and of that 99% of them don't even play that well."

That's why we need more game modes so people can actually have a choice to not have to play with those cretins. So far, the only way to accomplish not getting sick of conquest within 10 minutes is to simply no longer play the game. It's been working like a charm for me and I highly recommend it.


I'm all for making new game modes, but unfortunately from experience the complex ruleset will fail in an open public format. My suggestion is that you go over it again, and make it easier to play (more forgiving i.e. hard coding squad names is a VERY bad solution).

This post has been edited by Mach10: 19 December 2006 - 04:56 AM

0

#11 User is offline   aPantomimeHorse Icon

  • Newbie
  • Pip
  • Group: Members
  • Posts: 4
  • Joined: 28-October 06

Posted 08 March 2007 - 06:27 AM

I'm wondering if anyone has tried the mod.

And yes, learning curve is, of course, a paramount concern for making a successful game (just look at WoW: very simple at first, baroque by the time you get to the end game). I did think of that, which is why the mod sends everyone a reminder of who can do what every minute in team chat. It reads like:

*** A squadleader from ALPHA must be present to neutralize an enemy flag
*** A squadleader from ALPHA, or BRAVO must be present to capture a neutral flag
*** 1 or more soldiers must be present to neutralize an enemy flag
*** 1 or more soldiers must be present to capture a neutralized flag


(The number of leaders capable of capturing/neutralizing and the number of players needed increase with the size of the team, which is one reason the message needs to be spammed on a repeated basis.)

Ideally it would give players a message when they try to neutralize/capture a flag but don't have permission or need more people to help them do it, but I couldn't figure out how to put text in the middle of a particular player's screen, or at least send chat to that particular player; some advise would be appreciated.

Also noticed that cutting and pasting the code out of the text box doesn't preserve the indentation, at least with Firefox, so I made a proper distributable zip file.

This post has been edited by aPantomimeHorse: 08 March 2007 - 07:56 AM

0

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users