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).

Sign In
Register
Help

MultiQuote


