Scripts:Vehicle Class Limit

From BF2 Technical Information Wiki
Revision as of 07:08, 3 January 2011 by Ahv (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Contents

Introduction

This ModManager script prevents use of certain vehicle classes.

Whenever a player enters one of the forbidden vehicles a 10 second timer is started if it's not already running.

When the timer is activated it checks all the players and tries to punish the trespassers. As it's almost impossible to kill a player serverside (the player could be standing near a supply drop, health pack, heli landing pack etc.) the script decreases the health of player and the occupied vehicle, hoping for a fast explosion.

The timer is deactivated if no players were in the forbidden vehicles.

Requests

I would like to add a player count to this script. I need to make it so that, if there is 10 people on one side, the 9 on the other can use a tank or whatever. For aircraft I'd like to change that to 20 people. -by Acemantura

Something where for instance the server shows the the following player counts

Team 1 player count = 9, Team 2 Player count = 10

Team 2 meets Team 1's requirement to be able to use (according to PR's python files) VEHICLE_TYPE_APC,VEHICLE_TYPE_AAV,VEHICLE_TYPE_RECON,VEHICLE_TYPE_HELI


Then when the number goes up to 20 for one team

Team 1 player count = 20, Team 2 Player count = 19


Team 1 meets Team 2's requirement to be able to use VEHICLE_TYPE_ARMOR,VEHICLE_TYPE_IFV,VEHICLE_TYPE_JET,VEHICLE_TYPE_HELIATTACK


This needs to be customizable in that we as admins would like to find out where the sweet spot is in terms of player frustration<enjoyment. So we need to be able to select the amount of players required for each setting and possibly for each vehicle type.

Thank you for your time.

Prerequisites

ModManager or BF2CC

Install

  • unzip the file (or copy and paste into mm_climit.py) to admin/modules in your Battlefield 2 server install.
  • if necessary, edit the file and change the forbidden classes (by default the forbidden classes are Armor, Helicopter and Aircraft)
  • change your modmanager.con and include the following line:
 modmanager.loadModule "mm_climit"

Code

Download

The source is included below and the current version is also available here.

Readable

# vim: ts=4 sw=4 noexpandtab
"""Vehicle class limit module.

===== About =====
 This ModManager script prevents use of certain vehicle classes.
 Whenever a player enters one of the forbidden vehicles a 10 second timer is started if
 it's not already running.
 When the timer is activated it checks all the players and tries to punish the trespassers.
 As it's almost impossible to kill a player serverside (the player could be standing near
 a supply drop, health pack, heli landing pack etc.) the script decreases the health of
 player and the occupied vehicle, hoping for a fast explosion. ;)
 The timer is deactivated if no players were in the forbidden vehicles.

===== Config =====
 Enter the forbidden classes in the ForbiddenTypes list below

===== History =====

 v1.0 - 20060119:
 Initial public version
 v0.9 - 20051224:
 Internal release

Author: graag42atgmaildotcom
You're free to use and modify this script
"""

import bf2
import host
import mm_utils
from bf2.stats.constants import *

# Set the version of your module here
__version__ = 1.0

# Set the required module versions here
__required_modules__ = {
	'modmanager': 1.0
}

# Does this module support reload ( are all its reference closed on shutdown? )
__supports_reload__ = True

# Set the description of your module here
__description__ = "VehicleClassLimit v%s" % __version__

#comma separated list of forbidden classes ( defined in bf2.stats.constants )
ForbiddenTypes = [VEHICLE_TYPE_ARMOR, VEHICLE_TYPE_AVIATOR, VEHICLE_TYPE_HELICOPTER]		


updateTimer = None
 
class NoFly( object ):

	def __init__( self, modManager ):
		# ModManager reference
		self.mm = modManager
		
		# Internal shutdown state
		self.__state = 0
		
		# Add any static initialisation here.
		# Note: Handler registration should not be done here
		# but instead in the init() method

	def onEnterVehicle( self, player, vehicle, freeSoldier):
		"""Player entered a vehicle - check if the class is allowed and start the timer in not."""
		if 1 != self.__state:
			return 0
		
		# Put your actions here
		if self.checkPlayerVehicle( player, vehicle, 0 ):
			self.StartTimer()
			

	def StartTimer( self ):
		"""Start the timer if the state allows it and the timer isn't already started"""
		if 1 != self.__state:
			return 0
		if not self.updateTimer:
			#self.mm.info( "Starting timer" )
			#mm_utils.msg_server( "Starting timer" )
			self.updateTimer = bf2.Timer(self.onUpdate, 10, 1)
			self.updateTimer.setRecurring(10)
		else:
			#self.mm.info( "Timer already enabled" )
			#mm_utils.msg_server( "Timer already enabled" )
			pass

	def StopTimer( self ):
		"""Shutdown the timer"""
		if self.updateTimer:
			#self.mm.info( "Stopping timer" )
			#mm_utils.msg_server( "Stopping timer" )
			self.updateTimer.destroy()
			self.updateTimer = None
		else:
			#self.mm.info( "Timer already stopped" )
			#mm_utils.msg_server( "Timer already stopped" )
			pass
	
	def checkPlayerVehicle( self, player, vehicle, mode ):
		"""mode 0 - player just entered vehicle, 1 - timed check
		if the vehicle class is forbidden:
			mode 0 - notify player via server message
			mode 1 - punish player
		returns True if player is in forbidden vehicle class, False othervise"""
		
		forbiddenClass = False
		try:
			vehicleType = getVehicleType(vehicle.templateName)
			vehicleDamage = vehicle.getDamage()
			body=player.getDefaultVehicle()
			bodyHealth=body.getDamage()
			
			#debug
			#if 1 == mode:
			#	self.mm.info( "Player %s (health %d) is in %s (class %d, health %d)" % ( player.getName(), bodyHealth, vehicle.templateName, vehicleType, vehicleDamage ) )
			#	#mm_utils.msg_server( "Player %s (health %d) is in %s (class %d, health %d)" % ( player.getName(), bodyHealth, vehicle.templateName, vehicleType, vehicleDamage ) )
			#else:
			#	self.mm.info( "Player %s (health %d) entered %s (class %d, health %d)" % ( player.getName(), bodyHealth, vehicle.templateName, vehicleType, vehicleDamage ) )
			#	#mm_utils.msg_server( "Player %s (health %d) entered %s (class %d, health %d)" % ( player.getName(), bodyHealth, vehicle.templateName, vehicleType, vehicleDamage ) )
			
			if vehicleType in ForbiddenTypes:
				forbiddenClass = True
				if 1 == mode:
					#punish
					mm_utils.msg_server( "Oh noes %s!" % ( player.getName() ) )
					vehicle.setDamage(0.01)
					body.setDamage(0.01)
				else:
					#notify
					mm_utils.msg_server( "%s entered %s. Somebody set up us the bomb. Get out, QUICK!" % ( player.getName(), vehicle.templateName ) )
		except:
			forbiddenClass = False
			
		return forbiddenClass
	
	def init( self ):
		"""Provides default initialisation."""
		
		# Register your game handlers and provide any
		# other dynamic initialisation here
		self.updateTimer = None
		
		if 0 == self.__state:
			# Register your host handlers here
			host.registerHandler( 'EnterVehicle', self.onEnterVehicle, 1 )
			
		# Update to the running state
		self.__state = 1
		
		# start the timer: if the module was reset during the game at least one check will be made
		# if no players are in forbidden vehicles the timer will shut down until someone enters one
		self.StartTimer()
		
	def onUpdate( self, data ):
		"""timed check of all players"""
		if 1 != self.__state:
			return
				
		needTimer = False
		for player in bf2.playerManager.getPlayers():
			try:
				vehicle=player.getVehicle();
				if self.checkPlayerVehicle(player, vehicle, 1): needTimer = True
			except:
				try:
					player_name = player.getName()
				except:
					player_name = 'unknown'
				self.mm.error( "Failed to check player '%s'" % player_name, True )
				
		#do we still need the timer (at least 1 player in a forbidden class vehicle)?
		if needTimer:
			self.StartTimer()
		else:
			self.StopTimer()
		
	def shutdown( self ):
		"""Shutdown and stop processing."""

		# Unregister game handlers and do any other
		# other actions to ensure your module no longer affects
		# the game in anyway
		
		#stop the timer
		self.StopTimer
		# Flag as shutdown as there is currently way to:
		# host.unregisterHandler
		self.__state = 2

	def update( self ):
		"""Process and update.
		Note: This is called VERY often processing in here should
		be kept to an absolute minimum.
		"""
		pass

def mm_load( modManager ):
	"""Creates and returns your object."""
	return NoFly( modManager ) 

Alternative Version

Alternative CLimit prevents vehicle usage by map name and size. Also it fixes some bugs of original CLimit (i.e. takes second pilot & passenger seats into account). And it provides more informative messages.

Example of modmanager.con entries

modmanager.loadModule "mm_altclimit"

#
# mm_altclimit
#
mm_altclimit.frytime 5
mm_altclimit.warntime 90
mm_altclimit.addRestriction "strike_at_karkand:16:armor,transport"
mm_altclimit.addRestriction "road_to_jalalabad:16:armor,transport"

Script source

# vim: ts=4 sw=4 noexpandtab
"""Vehicle class limit module

===== About =====
This ModManager script prevents use of certain vehicle classes.
Whenever a player enters one of the forbidden vehicles a timer is started if
it's not already running.
When the timer is activated it checks all the players and tries to punish the trespassers.
As it's almost impossible to kill a player serverside (the player could be standing near
a supply drop, health pack, heli landing pack etc.) the script decreases the health of
player and the occupied vehicle, hoping for a fast explosion.;)
The timer is deactivated if no players were in the forbidden vehicles.

Alternative CLimit notes:
1. AltCLimit is intented to use with mm_mapautosizer or alike, because it relies on size entries in maplist.
I didn't list anything in required modules, because there are more than one autosizer script.
If maplist entries don't have map sizes, AltCLimit will do nothing.
2. mm_mapautosizer doesn't check if map of needed size actually exists, so it would write things like "wake_island_2007 16" to maplist.
This means, if you want to restrict wake_island_2007 64 you will have to make 3 entries in modmanager.con: with 16, 32 and 64 for size.
Don't forget that Euro Force maps don't have 64 variant.
3. mm_mapautosizer steps in only on the second map, when server starts. So vehicles on the first map can not be restricted (But they'll can when it'll be loaded the second time).
Sort of solution: set one of the unrestricted maps to be the first map in the maplist.

===== Config =====
# Time before script destroys occupied vehicle (seconds)
mm_altclimit.frytime <time>

# Time between warning messages (seconds)
mm_altclimit.warntime <time>

# Add restriction
# Available vehicle type values: armor, aviator, helicopter, transport
mm_altclimit.addRestriction "<map_name>:<map_size>:<forbidden_vehicle_type>[,<forbidden_vehicle_type>[,...]]"

===== History =====
Alternative CLimit
v1.0 - 2009-03-17
Features:
	- modmanager.con settings
	- restrict by map size, not by number of players
	- takes into account second pilot/passenger seats too
	- disable restrictions if the round hasn't started yet
	- minor sweeties
Author: ahv (ahvsevolod[at]ya.ru)

Original CLimit
v1.0 - 20060119:
Initial public version
v0.9 - 20051224:
Internal release

Author: graag42atgmaildotcom
You're free to use and modify this script
"""

import bf2
import host
import mm_utils
from bf2.stats.constants import *
 
__version__ = 1.0

__required_modules__ = {
	'modmanager': 1.0
}

__supports_reload__ = True

__supported_games__ = {
	'bf2': True
}

__description__ = "Alternative CLimit v%s" % __version__

configDefaults = {
	'restrictions': [],
	'frytime': 5,
	'warntime': 90
}

class AltCLimit( object ):

	def __init__( self, modManager ):
		self.mm = modManager
		self.__state = 0


	def onEnterVehicle( self, player, vehicle, freeSoldier):
		"""Player entered a vehicle - check if the class is allowed and start the timer in not."""
		if 1 != self.__state:
			return 0
		
		if not self.__rulesEnabled:
			return
		
		if (self.checkPlayerVehicle( player, vehicle, 0 )):
			self.StartTimer()


	def StartTimer( self ):
		"""Start the timer if it isn't already started"""
		if not self.updateTimer:
			self.updateTimer = bf2.Timer(self.onUpdate, self.__config['frytime'], 1)
			self.updateTimer.setRecurring(self.__config['frytime'])


	def StopTimer( self ):
		"""Shutdown the timer"""
		if self.updateTimer:
			self.updateTimer.destroy()
			self.updateTimer = None


	def onPlayerKilled(self, victim, attacker, weapon, assists, object):
		"""If the player managed to kill someone while in forbidden vehicle
			then fry him instantly"""
		if 1 != self.__state:
			return 0
			
		if not self.__rulesEnabled:
			return
		
		if (attacker != None):
			vehicle = attacker.getVehicle()
			rootVehicle = getRootParent(vehicle)
			vehicleType = getVehicleType(rootVehicle.templateName)
			body = attacker.getDefaultVehicle()
			
			if vehicleType in self.__forbVehicles:
				rootVehicle.setDamage(0.00001)
				body.setDamage(0.00001)
				mm_utils.msg_server("ACL: §C1001%s§C1001 was fried by the script" %attacker.getName())


	def checkPlayerVehicle(self, player, vehicle, mode):
		"""mode 0 - player just entered vehicle, 1 - timed check
		if the vehicle class is forbidden:
			mode 0 - notify player via server message
			mode 1 - punish player
		returns True if player is in forbidden vehicle class, False othervise"""
		if not self.__rulesEnabled:
			return
		
		forbiddenClass = False
		rootVehicle = getRootParent(vehicle)
		vehicleType = getVehicleType(rootVehicle.templateName)
		body = player.getDefaultVehicle()
		
		if (vehicleType in self.__forbVehicles):
			forbiddenClass = True
			if 1 == mode:
				#punish
				rootVehicle.setDamage(0.00001)
				body.setDamage(0.00001)
				mm_utils.msg_server("ACL: §C1001%s§C1001 was fried by the script" %player.getName())
			else:
				#notify if player really entered the vehicle, not changed seat (or changed to 1 actually)
				if (vehicle == rootVehicle):
					mm_utils.msg_server("§3ACL: §C1001%s§C1001, §C1001LEAVE THE %s§C1001 or you will §C1001DIE§C1001" \
						" in §C1001%s§C1001 seconds!" %(player.getName(), self.__vehstr[vehicleType].upper(), self.__config['frytime']))
		
		return forbiddenClass


	def onMsgTimer(self, data):
		"""Sends out warning messages"""
		mm_utils.msg_server("ACL: §C1001DON\'T USE %s§C1001, or you will §C1001DIE§C1001!" %self.__FVstring)


	def onGameStatusChanged(self, status):
		if (status == bf2.GameStatus.PreGame) and (self.mm.lastGameStatus == bf2.GameStatus.Playing):
			self.__forbVehicles = []
			self.__rulesEnabled = False
			
			maplist = host.rcon_invoke('maplist.list').split("\n")
			cur_map = int(host.rcon_invoke('maplist.currentmap'))
			map_str = ""
			for map in maplist:
				if (str(cur_map) + ':') in map:
					map_str = map
					break
			map = map_str.split(' ')
			
			for restr in self.__restrictions:
				if (restr['map'] == map[1].strip('"')) and (restr['size'] == map[-1]):
					self.__rulesEnabled = True
					try:
						for v in restr['forb_vehicles']:
							self.__forbVehicles.append( {
								'armor':		VEHICLE_TYPE_ARMOR,
								'aviator':		VEHICLE_TYPE_AVIATOR,
								'helicopter':	VEHICLE_TYPE_HELICOPTER,
								'transport':	VEHICLE_TYPE_TRANSPORT
								} [v.strip(' ')] )
					except KeyError:
						self.__rulesEnabled = False
						continue
					break
			
			self.__FVstring = ''
			for veh in self.__forbVehicles:
				self.__FVstring += self.__vehstr_mult[veh].upper() + ' or '
			self.__FVstring = self.__FVstring[:-4]
			
			if (self.__rulesEnabled):
				# Set the warning timer.
				self.msgTimer = bf2.Timer(self.onMsgTimer, self.__config['warntime'], 1)
				self.msgTimer.setRecurring(self.__config['warntime'])

		elif status == bf2.GameStatus.EndGame:
			self.__forbVehicles = []
			self.__rulesEnabled = False
			if self.msgTimer:
				self.msgTimer.destroy()
				self.msgTimer = None
			self.StopTimer()


	def init( self ):
		"""Provides default initialisation."""
		self.__config = self.mm.getModuleConfig( configDefaults )
		self.__restrictions = []
		for restr in self.__config['restrictions']:
			try:
				(map, size, forb_vehicles) = restr.split(':', 2)
				self.__restrictions.append({
					'map': map,
					'size': size,
					'forb_vehicles': forb_vehicles.split(',')
				})
			except:
				self.mm.error( "AltCLimit: Invalid restriction '%s'" %restr)
		
		self.updateTimer = None
		self.msgTimer = None
		
		self.__vehstr = {
			VEHICLE_TYPE_ARMOR: 'Armor',
			VEHICLE_TYPE_AVIATOR: 'Aircraft',
			VEHICLE_TYPE_HELICOPTER: 'Helicopter',
			VEHICLE_TYPE_TRANSPORT: 'Car'
		}
		
		self.__vehstr_mult = {
			VEHICLE_TYPE_ARMOR: 'Armor',
			VEHICLE_TYPE_AVIATOR: 'Aircrafts',
			VEHICLE_TYPE_HELICOPTER: 'Helicopters',
			VEHICLE_TYPE_TRANSPORT: 'Cars'
		}
		
		if 0 == self.__state:
			host.registerHandler('EnterVehicle', self.onEnterVehicle, 1)
			host.registerHandler('PlayerKilled', self.onPlayerKilled)
			host.registerGameStatusHandler(self.onGameStatusChanged)
		
		self.__state = 1


	def onUpdate( self, data ):
		"""timed check of all players"""
		if 1 != self.__state:
			return
		
		needTimer = False
		for player in bf2.playerManager.getPlayers():
			try:
				vehicle = player.getVehicle();
				if self.checkPlayerVehicle(player, vehicle, 1):
					needTimer = True
			except:
				try:
					player_name = player.getName()
				except:
					player_name = 'unknown'
				self.mm.error( "Failed to check player '%s'" % player_name, True )
				
		#do we still need the timer (at least 1 player in a forbidden class vehicle)?
		if needTimer:
			self.StartTimer()
		else:
			self.StopTimer()


	def shutdown(self):
		"""Shutdown and stop processing."""
		self.StopTimer
		if self.msgTimer:
			self.msgTimer.destroy()
			self.msgTimer = None
		host.unregisterGameStatusHandler(self.onGameStatusChanged)
		self.__state = 2


def mm_load(modManager):
	"""Creates and returns your object."""
	return AltCLimit(modManager)
Personal tools
Namespaces

Variants
Actions
Navigation
Toolbox