Scripts:TK punish announcer

From BF2 Technical Information Wiki
Jump to navigation Jump to search

Introduction

One of the major frustrations in BF2 is the often observed abuse of the PTK function. Since it is so easily available, many people punish others for TKs even when it's their own fault. At Battlefield.no we do not accept this behaviour, but it can be very hard for admins to take notice of people doing this. We have therefore made a modification to the tk_punish.py-script which is included with BF2.

Features

For each player a running tally of the number of forgives and punishes is kept. Whenever someone punishes a TK, a global announcement is made on the server indicating how many punishes and forgives this person has made. This makes it easy to spot people abusing the PTK-system.

This script is a drop-in replacement for the original tk_punish.py which comes with BF2. It is based on the script from the 1.12 release (build 1.1.2554-356). No functionality of the original script has been removed, so this script should be allowed on ranked servers.

Getting started

Copy the script from below and replace your current tk_punish.py which you can find under bf2/admin/standard_admin. Remember to make a backup of the original script first!

The code

The code

# tk punish system

import bf2
import host
from bf2 import g_debug

TK_PUNISH_TIME = 20
TK_PUNISH_COMMANDID = 100
TK_FORGIVE_COMMANDID = 101

hasPendingTks = {}
updateTimer = None



class TkData:
        def __init__(self):
                self.punished = 0
                self.pending = []
                self.lastTKedBy = None
                self.givenPunish = 0 # bf.no modification
                self.givenForgive = 0 # bf.no modification


def init():
        if g_debug: print "initializing tk-punish script"

        host.registerHandler('PlayerConnect', onPlayerConnect, 1)
        host.registerHandler('PlayerKilled', onPlayerKilled)
        host.registerHandler('ClientCommand', onClientCommand)

        # Connect already connected players if reinitializing
        for p in bf2.playerManager.getPlayers():
                onPlayerConnect(p)
       
        checkEnable()



def checkEnable():
        global updateTimer
       
        if not bf2.serverSettings.getTKPunishEnabled():
                if updateTimer:
                        updateTimer.destroy()
                        updateTimer = None
                return False
        else:
                if not updateTimer:
                        #if g_debug: print "Started timer"
                        updateTimer = bf2.Timer(onUpdate, 10, 1)
                        updateTimer.setRecurring(10)
                       
                return True
       

def onUpdate(data):
        if not checkEnable(): return
        global hasPendingTks

        #if len(hasPendingTks) > 0:
        #       if g_debug: print "update: Has pending tks!"
        #else:
        #       if g_debug: print "update:No pending tks."
               

        currentTime = host.timer_getWallTime()

        newPending = {}
        for attacker in hasPendingTks.iterkeys():
                newList = []
                #if g_debug: print "attacker pending list:", len(attacker.tkData.pending)
                for tk in attacker.tkData.pending:
                        tkDate = tk[0]
                        tkVictim = tk[1]
                        #if g_debug: print "check %d %s" % (tkDate, tkVictim.getName())

                        # if there is a pending TK with time expired
                        if tkDate + TK_PUNISH_TIME < currentTime:
                                if bf2.serverSettings.getTKPunishByDefault():
                                        attacker.tkData.punished += 1
                                        checkPunishLimit(attacker)
                                        # bf.no addons:
                                        tkVictim.tkData.givenPunish += 1
                                        result = host.rcon_invoke('game.sayAll "TKPUNISH: %s punishes %s for teamkill (%s has %d punishes and %d forgives)"' % (tkVictim.getName(), attacker.getName(), tkVictim.getName(), tkVictim.tkData.givenPunish, tkVictim.tkData.givenForgive))
                                        # *************
                                #       if g_debug: print "Default punished ", attacker.getName()
                                else:
                                        # bf.no addons:
                                        tkVictim.tkData.givenForgive += 1
                                #       if g_debug: print "Timeouted pending tk for ", attacker.getName()
                                        # pass

                                # remove player from global list, if it was the last tk
                                if len(attacker.tkData.pending) == 1:
                                        pass
                                else:
                                        newPending[attacker] = 1
                       
                        else:
                                newList += [tk]
                                newPending[attacker] = 1
               
                attacker.tkData.pending = newList

        hasPendingTks = newPending


def checkPunishLimit(player):
        #if g_debug: print "player %s has %d punishes" % (player.getName(), player.tkData.punished)

        if player.tkData.punished >= bf2.serverSettings.getTKNumPunishToKick():
                if g_debug: print "%s reached punish limit" % player.getName()
                if g_debug: print "Banning player!"
                result = host.rcon_invoke("admin.banPlayerKey " + str(player.index) + " Round")
               
       


# event actions

def onPlayerConnect(player):
        player.tkData = TkData()



def onClientCommand(command, issuer, args):
        if not checkEnable(): return
       
        #if g_debug: print "received client command"
        if command == TK_PUNISH_COMMANDID:
                executePunishAction(issuer, True)
        elif command == TK_FORGIVE_COMMANDID:
                executePunishAction(issuer, False)

               

def onPlayerKilled(victim, attacker, weapon, assists, object):

        if not checkEnable(): return

        if not victim or not attacker or victim == attacker or victim.getTeam() != attacker.getTeam(): return
       
        # verify that TK was really given

        # no teamkills from wrecks
        if object != None and object.getIsWreck():
                return
               
        # no teamkills from artillery
        if weapon:
                attackerVehicle = bf2.objectManager.getRootParent(weapon)
                if attackerVehicle.isPlayerControlObject and attackerVehicle.getIsRemoteControlled():
                        return
               
        # ok, we have a teamkill
        currentTime = host.timer_getWallTime()
        attacker.tkData.pending += [(currentTime, victim)]
        hasPendingTks[attacker] = 1
               
        victim.tkData.lastTKedBy = attacker # can only punish / forgive the last TK'er
       
        bf2.gameLogic.sendClientCommand(victim.index, 100, (2, victim.index, attacker.index, TK_PUNISH_TIME))


def executePunishAction(victim, punish):
        if not checkEnable() or not victim or not victim.isValid(): return
        attacker = victim.tkData.lastTKedBy
        if attacker == None or not attacker.isValid(): return

        global hasPendingTks

        if punish:
                if g_debug: print "%s tkPunished %s" % (victim.getName(), attacker.getName())
        else:
                if g_debug: print "%s tkForgive %s" % (victim.getName(), attacker.getName())

        currentTime = host.timer_getWallTime()
       
        newList = []
        for tk in attacker.tkData.pending:
                tkDate = tk[0]
                tkVictim = tk[1]
               
                # if the attacker had a pending tk, and time has not run out
                if tkVictim == victim and tkDate + TK_PUNISH_TIME > currentTime:
                        if punish:
                                attacker.tkData.punished += 1
                                bf2.gameLogic.sendClientCommand(-1, 100, (0, victim.index, attacker.index)) # 100 = tkpunish event, 0 = punish
                                if g_debug: print "%s punished %s, now has %d punishes" % (victim.getName(), attacker.getName(), attacker.tkData.punished)
                                # bf.no addons:
                                victim.tkData.givenPunish += 1
                                result = host.rcon_invoke('game.sayAll "TKPUNISH: %s punishes %s for teamkill (%s has %d punishes and %d forgives)"' % (victim.getName(), attacker.getName(), victim.getName(), victim.tkData.givenPunish, victim.tkData.givenForgive))
                                # *************
                        else:
                                bf2.gameLogic.sendClientCommand(-1, 100, (1, victim.index, attacker.index)) # 100 = tkpunish event, 1 = forgive
                                if g_debug: print "%s forgave %s" % (victim.getName(), attacker.getName())
                                # bf.no addons:
                                victim.tkData.givenForgive += 1
                else:
                        newList += [tk]
                       
        attacker.tkData.pending = newList
       
        if len(attacker.tkData.pending) == 0:
                del hasPendingTks[attacker]
       
        checkPunishLimit(attacker)