Last active
August 20, 2025 17:37
-
-
Save cetteup/45e24e2bf64656c4056b63797fef3342 to your computer and use it in GitHub Desktop.
Battlefield 2 ModManager module to modify control points at runtime
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| """ | |
| ControlPointManager module | |
| ====================== | |
| Modify control point settings without modifying map files. | |
| ===== Config ===== | |
| # Add a condition | |
| # You can use any server setting/single-value-returning RCON command as a condition for enabling control point modifications | |
| mm_controlpointmanager.addCondition "<setting (including sv. prefix) or other RCON command>" "<value>" | |
| # Example | |
| mm_controlpointmanager.addCondition "sv.noVehicles" "1" | |
| ==== | |
| # Add a directive for the team of a control point to be changed | |
| # Control point identifiers need to match those from the map files (use all lower case) | |
| # You can easily find the identifiers in the localization files | |
| mm_controlpointmanager.addDirective "set-team <map name> <game mode> <control point identifier>" <team> | |
| # Example | |
| mm_controlpointmanager.addDirective "set-team iron_gator gpm_cq cp_64p_ms_controltower" 2 | |
| """ | |
| import bf2 | |
| import host | |
| import mm_utils | |
| __version__ = 1.0 | |
| __required_modules__ = { | |
| 'modmanager': 1.6 | |
| } | |
| __supports_reload__ = True | |
| __supported_games__ = { | |
| 'bf2': True, | |
| 'bf2142': False, # Not tested | |
| 'bfheroes': False, # Not tested | |
| 'bfp4f': False # Not tested | |
| } | |
| __description__ = 'ControlPointManager v%s' % __version__ | |
| configDefaults = { | |
| 'conditions': {}, | |
| 'directives': {} | |
| } | |
| class ControlPointManager(object): | |
| def __init__(self, modManager): | |
| """Create a new instance.""" | |
| self.mm = modManager | |
| self.__state = 0 | |
| def init(self): | |
| """Provides default initialisation.""" | |
| self.__config = self.mm.getModuleConfig(configDefaults) | |
| if self.__state == 0 and len(self.__config) > 0: | |
| host.registerGameStatusHandler(self.onGameStatusChanged) | |
| self.__state = 1 | |
| def onGameStatusChanged(self, status): | |
| if status != bf2.GameStatus.Playing: | |
| return | |
| if not self.__areConditionsMet(): | |
| self.mm.debug(1, 'Server settings do not meet conditions for modifying control points, skipping') | |
| return | |
| mapName = bf2.serverSettings.getMapName() | |
| gameMode = bf2.serverSettings.getGameMode() | |
| self.mm.debug(1, 'Checking for control point team changes on %s %s' % (mapName, gameMode)) | |
| changed = 0 | |
| for cp in bf2.objectManager.getObjectsOfType('dice.hfe.world.ObjectTemplate.ControlPoint'): | |
| cpName = cp.templateName.lower() | |
| current = cp.cp_getParam('team') | |
| # Use current as default to make logging and comparing cleaner/easier | |
| target = self.__config['directives'].get('set-team %s %s %s' % (mapName, gameMode, cpName), current) | |
| self.mm.debug(2, 'Control point %s team is %s (%s), should be %s (%s)' % ( | |
| cpName, | |
| current, | |
| self.__getTeamName(current), | |
| target, | |
| self.__getTeamName(target) | |
| )) | |
| if target != current: | |
| self.mm.info('Changing control point %s from team %s (%s) to %s (%s)' % ( | |
| cpName, | |
| current, | |
| self.__getTeamName(current), | |
| target, | |
| self.__getTeamName(target) | |
| )) | |
| cp.cp_setParam('team', target) | |
| cp.cp_setParam('flag', target) | |
| if target == 0: | |
| # Move control point to the "middle" when making it neutral | |
| cp.flagPosition = 1 | |
| cp.cp_setParam('takeOverChangePerSecond', -100) | |
| else: | |
| # Move control point to the top when giving it to a team | |
| cp.flagPosition = 0 | |
| cp.cp_setParam('takeOverChangePerSecond', 100) | |
| changed += 1 | |
| self.mm.debug(1, 'Changed team for %d control points on %s %s' % (changed, mapName, gameMode)) | |
| def __areConditionsMet(self): | |
| for command, want in self.__config['conditions'].items(): | |
| have = host.rcon_invoke(command).strip() | |
| self.mm.debug(2, 'Control point modification condition %s has %s, wants %s' % (command, have, want)) | |
| # Always convert to string as mod manager will even parse quoted numbers to integers | |
| # (e.g. mm_controlpointmanager.addCondition "sv.ranked" "1") | |
| if str(want) != have: | |
| return False | |
| return True | |
| def __getTeamName(self, team): | |
| if team == 0: | |
| return None | |
| return bf2.gameLogic.getTeamName(team) | |
| def shutdown(self): | |
| """Shutdown and stop processing.""" | |
| host.unregisterGameStatusHandler(self.onGameStatusChanged) | |
| self.__state = 2 | |
| # | |
| # ModManager load | |
| # | |
| def mm_load(modManager): | |
| """Creates and returns your object.""" | |
| return ControlPointManager(modManager) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Example configuration (only covers this module) | |
| # Modules | |
| modmanager.loadModule "mm_controlpointmanager" | |
| # | |
| # ControlPointManager v1.0 | |
| # | |
| mm_controlpointmanager.addCondition "sv.noVehicles" 1 | |
| mm_controlpointmanager.addDirective "set-team iron_gator gpm_cq cp_32p_ms_welldeck" 1 | |
| mm_controlpointmanager.addDirective "set-team iron_gator gpm_cq cp_32p_ms_hanger_bay_aft" 1 | |
| mm_controlpointmanager.addDirective "set-team iron_gator gpm_cq cp_32p_ms_controltower" 0 | |
| mm_controlpointmanager.addDirective "set-team iron_gator gpm_cq cp_32p_ms_controltowerexterior" 0 | |
| mm_controlpointmanager.addDirective "set-team iron_gator gpm_cq cp_32p_ms_insurgentbase" 0 | |
| mm_controlpointmanager.addDirective "set-team iron_gator gpm_cq cp_64p_ms_welldeck" 1 | |
| mm_controlpointmanager.addDirective "set-team iron_gator gpm_cq cp_64p_ms_hanger_bay_aft" 1 | |
| mm_controlpointmanager.addDirective "set-team iron_gator gpm_cq cp_64p_ms_controltower" 0 | |
| mm_controlpointmanager.addDirective "set-team iron_gator gpm_cq cp_64p_ms_controltowerexterior" 0 | |
| mm_controlpointmanager.addDirective "set-team iron_gator gpm_cq cp_64p_ms_insurgentbase" 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment